feat(web): статусы DocStatusBadge на всех списках документов + кнопка «Сгенерировать» ШК
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
П.9: DocStatusBadge (Черновик/Проведён с подсказкой) раскатан на Оприходования, Списания, Перемещения, Возвраты поставщикам, Отгрузки (было: приёмки/продажи/инвент.). П.4: в карточке товара рядом с полем штрихкода — кнопка «Сгенерировать» (внутренний EAN-13). Группа по умолчанию — «Все товары», единица — «шт» (уже было). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8c163e63fc
commit
18752497a8
|
|
@ -1,4 +1,5 @@
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { DocStatusBadge } from '@/components/DocStatusBadge'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { Plus, Truck } from 'lucide-react'
|
import { Plus, Truck } from 'lucide-react'
|
||||||
import { ListPageShell } from '@/components/ListPageShell'
|
import { ListPageShell } from '@/components/ListPageShell'
|
||||||
|
|
@ -67,9 +68,7 @@ export function DemandsPage() {
|
||||||
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
||||||
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
||||||
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
||||||
r.status === DemandStatus.Posted
|
<DocStatusBadge status={r.status === DemandStatus.Posted ? 'posted' : 'draft'} />
|
||||||
? <span className="text-xs px-2 py-0.5 rounded bg-green-50 text-green-700">Проведён</span>
|
|
||||||
: <span className="text-xs px-2 py-0.5 rounded bg-slate-100 text-slate-600">Черновик</span>
|
|
||||||
)},
|
)},
|
||||||
{ header: 'Контрагент', sortKey: 'customer', cell: (r) => r.customerName },
|
{ header: 'Контрагент', sortKey: 'customer', cell: (r) => r.customerName },
|
||||||
{ header: 'Склад', width: '160px', cell: (r) => r.storeName },
|
{ header: 'Склад', width: '160px', cell: (r) => r.storeName },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { DocStatusBadge } from '@/components/DocStatusBadge'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { Plus, PackagePlus } from 'lucide-react'
|
import { Plus, PackagePlus } from 'lucide-react'
|
||||||
import { ListPageShell } from '@/components/ListPageShell'
|
import { ListPageShell } from '@/components/ListPageShell'
|
||||||
|
|
@ -67,9 +68,7 @@ export function EntersPage() {
|
||||||
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
||||||
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
||||||
{ header: 'Статус', width: '130px', sortKey: 'status', cell: (r) => (
|
{ header: 'Статус', width: '130px', sortKey: 'status', cell: (r) => (
|
||||||
r.status === EnterStatus.Posted
|
<DocStatusBadge status={r.status === EnterStatus.Posted ? 'posted' : 'draft'} />
|
||||||
? <span className="text-xs px-2 py-0.5 rounded bg-green-50 text-green-700">Проведён</span>
|
|
||||||
: <span className="text-xs px-2 py-0.5 rounded bg-slate-100 text-slate-600">Черновик</span>
|
|
||||||
)},
|
)},
|
||||||
{ header: 'Склад', sortKey: 'store', cell: (r) => r.storeName },
|
{ header: 'Склад', sortKey: 'store', cell: (r) => r.storeName },
|
||||||
{ header: 'Позиций', width: '100px', className: 'text-right', cell: (r) => r.lineCount },
|
{ header: 'Позиций', width: '100px', className: 'text-right', cell: (r) => r.lineCount },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { DocStatusBadge } from '@/components/DocStatusBadge'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { Plus, Trash2 } from 'lucide-react'
|
import { Plus, Trash2 } from 'lucide-react'
|
||||||
import { ListPageShell } from '@/components/ListPageShell'
|
import { ListPageShell } from '@/components/ListPageShell'
|
||||||
|
|
@ -67,9 +68,7 @@ export function LossesPage() {
|
||||||
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
||||||
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
||||||
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
||||||
r.status === LossStatus.Posted
|
<DocStatusBadge status={r.status === LossStatus.Posted ? 'posted' : 'draft'} />
|
||||||
? <span className="text-xs px-2 py-0.5 rounded bg-green-50 text-green-700">Проведён</span>
|
|
||||||
: <span className="text-xs px-2 py-0.5 rounded bg-slate-100 text-slate-600">Черновик</span>
|
|
||||||
)},
|
)},
|
||||||
{ header: 'Причина', width: '140px', sortKey: 'reason', cell: (r) => lossReasonLabel[r.reason] ?? r.reason },
|
{ header: 'Причина', width: '140px', sortKey: 'reason', cell: (r) => lossReasonLabel[r.reason] ?? r.reason },
|
||||||
{ header: 'Склад', sortKey: 'store', cell: (r) => r.storeName },
|
{ header: 'Склад', sortKey: 'store', cell: (r) => r.storeName },
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useState, useEffect, type FormEvent, type ReactNode } from 'react'
|
import { useState, useEffect, type FormEvent, type ReactNode } from 'react'
|
||||||
import { useNavigate, useParams, Link } from 'react-router-dom'
|
import { useNavigate, useParams, Link } from 'react-router-dom'
|
||||||
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
|
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
|
||||||
import { ArrowLeft, Plus, Trash2, Save } from 'lucide-react'
|
import { ArrowLeft, Plus, Trash2, Save, RefreshCw } from 'lucide-react'
|
||||||
import { api, humanizeError } from '@/lib/api'
|
import { api, humanizeError } from '@/lib/api'
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
import { Field, TextInput, TextArea, Select, AsyncSelect, Checkbox, MoneyInput, NumberInput } from '@/components/Field'
|
import { Field, TextInput, TextArea, Select, AsyncSelect, Checkbox, MoneyInput, NumberInput } from '@/components/Field'
|
||||||
|
|
@ -329,8 +329,16 @@ export function ProductEditPage() {
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{form.barcodes.map((b, i) => (
|
{form.barcodes.map((b, i) => (
|
||||||
<div key={i} className="grid grid-cols-12 gap-2 items-center">
|
<div key={i} className="grid grid-cols-12 gap-2 items-center">
|
||||||
<div className="col-span-6">
|
<div className="col-span-6 flex gap-1.5">
|
||||||
<TextInput placeholder="Код" value={b.code} onChange={(e) => updateBarcode(i, { code: e.target.value })} />
|
<TextInput placeholder="Код" value={b.code} onChange={(e) => updateBarcode(i, { code: e.target.value })} className="flex-1" />
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => updateBarcode(i, { code: generateBarcode(b.type) })}
|
||||||
|
className="shrink-0 px-2 rounded-md border border-slate-200 dark:border-slate-700 text-slate-500 hover:text-slate-800 hover:bg-slate-50 dark:hover:bg-slate-800"
|
||||||
|
title="Сгенерировать внутренний штрихкод"
|
||||||
|
>
|
||||||
|
<RefreshCw className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-3">
|
<div className="col-span-3">
|
||||||
<Select value={b.type} onChange={(e) => {
|
<Select value={b.type} onChange={(e) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { DocStatusBadge } from '@/components/DocStatusBadge'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { Plus, Undo2 } from 'lucide-react'
|
import { Plus, Undo2 } from 'lucide-react'
|
||||||
import { ListPageShell } from '@/components/ListPageShell'
|
import { ListPageShell } from '@/components/ListPageShell'
|
||||||
|
|
@ -67,9 +68,7 @@ export function SupplierReturnsPage() {
|
||||||
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
{ header: '№', width: '160px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600">{r.number}</span> },
|
||||||
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
||||||
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
||||||
r.status === SupplierReturnStatus.Posted
|
<DocStatusBadge status={r.status === SupplierReturnStatus.Posted ? 'posted' : 'draft'} />
|
||||||
? <span className="text-xs px-2 py-0.5 rounded bg-green-50 text-green-700">Проведён</span>
|
|
||||||
: <span className="text-xs px-2 py-0.5 rounded bg-slate-100 text-slate-600">Черновик</span>
|
|
||||||
)},
|
)},
|
||||||
{ header: 'Поставщик', sortKey: 'supplier', cell: (r) => r.supplierName },
|
{ header: 'Поставщик', sortKey: 'supplier', cell: (r) => r.supplierName },
|
||||||
{ header: 'По приёмке', width: '140px', cell: (r) => r.referenceSupplyNumber ? <span className="font-mono text-xs text-slate-500">{r.referenceSupplyNumber}</span> : '—' },
|
{ header: 'По приёмке', width: '140px', cell: (r) => r.referenceSupplyNumber ? <span className="font-mono text-xs text-slate-500">{r.referenceSupplyNumber}</span> : '—' },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { DocStatusBadge } from '@/components/DocStatusBadge'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import { Plus, ArrowRight, ArrowLeftRight } from 'lucide-react'
|
import { Plus, ArrowRight, ArrowLeftRight } from 'lucide-react'
|
||||||
import { ListPageShell } from '@/components/ListPageShell'
|
import { ListPageShell } from '@/components/ListPageShell'
|
||||||
|
|
@ -67,9 +68,7 @@ export function TransfersPage() {
|
||||||
{ header: '№', width: '180px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600 dark:text-slate-300">{r.number}</span> },
|
{ header: '№', width: '180px', sortKey: 'number', cell: (r) => <span className="font-mono text-slate-600 dark:text-slate-300">{r.number}</span> },
|
||||||
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
{ header: 'Дата', width: '120px', sortKey: 'date', cell: (r) => new Date(r.date).toLocaleDateString('ru') },
|
||||||
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
{ header: 'Статус', width: '110px', sortKey: 'status', cell: (r) => (
|
||||||
r.status === TransferStatus.Posted
|
<DocStatusBadge status={r.status === TransferStatus.Posted ? 'posted' : 'draft'} />
|
||||||
? <span className="text-xs px-2 py-0.5 rounded bg-green-50 text-green-700">Проведён</span>
|
|
||||||
: <span className="text-xs px-2 py-0.5 rounded bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300">Черновик</span>
|
|
||||||
)},
|
)},
|
||||||
{ header: 'Откуда → Куда', cell: (r) => (
|
{ header: 'Откуда → Куда', cell: (r) => (
|
||||||
<span className="inline-flex items-center gap-2 text-slate-700 dark:text-slate-200">
|
<span className="inline-flex items-center gap-2 text-slate-700 dark:text-slate-200">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue