feat(forms): MoneyInput для поля «Оклад» в карточке сотрудника
Раньше Salary был <input type=number> с примитивной валидацией. Заменено на MoneyInput (как в ценах товаров и др. денежных полях), который: - читает org-setting allowFractionalPrices (копейки или нет); - показывает символ валюты (₸/$/€) справа; - хранит draft-string для бесшовного ввода 100.50 без потери точки; - onBlur нормализует значение. Тип формы изменён: `salary: string` → `salary: number | null`, сохранение payload берёт значение напрямую без Number() парсинга. Других денежных полей в формах сотрудников/контрагентов (зарплаты, авансы, штрафы, доплаты) сейчас НЕТ — есть только Salary в Employee и MoneyInput уже используется в ProductEditPage (цены) и SupplyEditPage (себестоимость и сумма по позициям). Поэтому пункт закрыт одной правкой EmployeesPage.
This commit is contained in:
parent
dcb28a9811
commit
a6ecc65b97
|
|
@ -8,7 +8,7 @@ import { Pagination } from '@/components/Pagination'
|
||||||
import { SearchBar } from '@/components/SearchBar'
|
import { SearchBar } from '@/components/SearchBar'
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
import { Modal } from '@/components/Modal'
|
import { Modal } from '@/components/Modal'
|
||||||
import { Field, TextInput, TextArea, Checkbox } from '@/components/Field'
|
import { Field, TextInput, TextArea, Checkbox, MoneyInput } from '@/components/Field'
|
||||||
import { PhoneInput } from '@/components/PhoneInput'
|
import { PhoneInput } from '@/components/PhoneInput'
|
||||||
import { useCatalogList, useCatalogMutations } from '@/lib/useCatalog'
|
import { useCatalogList, useCatalogMutations } from '@/lib/useCatalog'
|
||||||
import type { PagedResult, RetailPoint } from '@/lib/types'
|
import type { PagedResult, RetailPoint } from '@/lib/types'
|
||||||
|
|
@ -51,7 +51,10 @@ interface Form {
|
||||||
position: string
|
position: string
|
||||||
email: string
|
email: string
|
||||||
phone: string
|
phone: string
|
||||||
salary: string
|
/** Денежное значение в валюте организации (берётся из useOrgSettings).
|
||||||
|
* Используется MoneyInput, который сам формирует с копейками или без
|
||||||
|
* в зависимости от org-setting allowFractionalPrices. */
|
||||||
|
salary: number | null
|
||||||
taxNumber: string
|
taxNumber: string
|
||||||
description: string
|
description: string
|
||||||
imageUrl: string
|
imageUrl: string
|
||||||
|
|
@ -64,7 +67,7 @@ interface Form {
|
||||||
const blankForm = (): Form => ({
|
const blankForm = (): Form => ({
|
||||||
lastName: '', firstName: '', middleName: '', position: '',
|
lastName: '', firstName: '', middleName: '', position: '',
|
||||||
email: '', phone: '',
|
email: '', phone: '',
|
||||||
salary: '', taxNumber: '', description: '', imageUrl: '',
|
salary: null, taxNumber: '', description: '', imageUrl: '',
|
||||||
roleId: '', isActive: true,
|
roleId: '', isActive: true,
|
||||||
retailPointIds: [],
|
retailPointIds: [],
|
||||||
createAccount: true,
|
createAccount: true,
|
||||||
|
|
@ -113,7 +116,7 @@ export function EmployeesPage() {
|
||||||
const payload = {
|
const payload = {
|
||||||
lastName: form.lastName, firstName: form.firstName, middleName: form.middleName || null,
|
lastName: form.lastName, firstName: form.firstName, middleName: form.middleName || null,
|
||||||
position: form.position || null, email: form.email || null, phone: form.phone || null,
|
position: form.position || null, email: form.email || null, phone: form.phone || null,
|
||||||
salary: form.salary ? Number(form.salary) : null,
|
salary: form.salary,
|
||||||
taxNumber: form.taxNumber || null,
|
taxNumber: form.taxNumber || null,
|
||||||
description: form.description || null,
|
description: form.description || null,
|
||||||
imageUrl: form.imageUrl || null,
|
imageUrl: form.imageUrl || null,
|
||||||
|
|
@ -178,7 +181,7 @@ export function EmployeesPage() {
|
||||||
setForm({
|
setForm({
|
||||||
id: r.id, lastName: r.lastName, firstName: r.firstName, middleName: r.middleName ?? '',
|
id: r.id, lastName: r.lastName, firstName: r.firstName, middleName: r.middleName ?? '',
|
||||||
position: r.position ?? '', email: r.email ?? '', phone: r.phone ?? '',
|
position: r.position ?? '', email: r.email ?? '', phone: r.phone ?? '',
|
||||||
salary: r.salary != null ? String(r.salary) : '',
|
salary: r.salary,
|
||||||
taxNumber: r.taxNumber ?? '', description: r.description ?? '', imageUrl: r.imageUrl ?? '',
|
taxNumber: r.taxNumber ?? '', description: r.description ?? '', imageUrl: r.imageUrl ?? '',
|
||||||
roleId: r.roleId, isActive: r.isActive, retailPointIds: r.retailPointIds,
|
roleId: r.roleId, isActive: r.isActive, retailPointIds: r.retailPointIds,
|
||||||
createAccount: false,
|
createAccount: false,
|
||||||
|
|
@ -296,7 +299,7 @@ export function EmployeesPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<Field label="Оклад">
|
<Field label="Оклад">
|
||||||
<TextInput type="number" value={form.salary} onChange={(e) => setForm({ ...form, salary: e.target.value })} placeholder="—" />
|
<MoneyInput value={form.salary} onChange={(v) => setForm({ ...form, salary: v })} />
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="ИИН">
|
<Field label="ИИН">
|
||||||
<TextInput value={form.taxNumber} onChange={(e) => setForm({ ...form, taxNumber: e.target.value })} placeholder="12 цифр" maxLength={12} inputMode="numeric" />
|
<TextInput value={form.taxNumber} onChange={(e) => setForm({ ...form, taxNumber: e.target.value })} placeholder="12 цифр" maxLength={12} inputMode="numeric" />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue