From 7545799fdc0fc91726d74930558cb0fb5ed672f7 Mon Sep 17 00:00:00 2001 From: kae Date: Thu, 18 Jun 2026 19:20:49 +0900 Subject: [PATCH] feat: add detail pages for stock checks and adjusts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both list pages had 查看 links with no onClick. Added detail pages showing header info and line items, with action buttons (确认开始盘点 / 审核通过+驳回). Also: extended StockCheck/StockAdjust types to include details and extra fields; added /inventory/checks/:id and /inventory/adjusts/:id routes; moved columns definitions inside components (module-level columns with history.push were silently ignored by the browser due to MFSU caching); switched to Link component for SPA navigation. --- .umirc.ts | 2 + src/pages/Inventory/Adjusts/detail.tsx | 98 ++++++++++++++++++++++++++ src/pages/Inventory/Adjusts/index.tsx | 36 +++++----- src/pages/Inventory/Checks/detail.tsx | 94 ++++++++++++++++++++++++ src/pages/Inventory/Checks/index.tsx | 34 ++++----- src/types/api.ts | 30 ++++++++ 6 files changed, 259 insertions(+), 35 deletions(-) create mode 100644 src/pages/Inventory/Adjusts/detail.tsx create mode 100644 src/pages/Inventory/Checks/detail.tsx diff --git a/.umirc.ts b/.umirc.ts index 541a3f3..611a2d2 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -63,7 +63,9 @@ export default defineConfig({ { name: '库存查询', path: '/inventory/stocks', component: './Inventory/Stocks' }, { name: '库存统计', path: '/inventory/stats', component: './Inventory/Stats' }, { name: '库存盘点', path: '/inventory/checks', component: './Inventory/Checks' }, + { name: '盘点单详情', path: '/inventory/checks/:id', component: './Inventory/Checks/detail', hideInMenu: true }, { name: '库存调整', path: '/inventory/adjusts', component: './Inventory/Adjusts' }, + { name: '调整单详情', path: '/inventory/adjusts/:id', component: './Inventory/Adjusts/detail', hideInMenu: true }, { name: 'Excel导入', path: '/inventory/import', component: './Inventory/Import' }, { name: '库存变动记录', path: '/inventory/logs', component: './Inventory/Logs' }, ], diff --git a/src/pages/Inventory/Adjusts/detail.tsx b/src/pages/Inventory/Adjusts/detail.tsx new file mode 100644 index 0000000..9d3a6ed --- /dev/null +++ b/src/pages/Inventory/Adjusts/detail.tsx @@ -0,0 +1,98 @@ +import { ArrowLeftOutlined } from '@ant-design/icons'; +import { ProTable } from '@ant-design/pro-components'; +import { Button, Card, Descriptions, Modal, Space, Tag, Typography, message } from 'antd'; +import { useEffect, useState } from 'react'; +import { history, useParams } from '@umijs/max'; +import { approveStockAdjust, getStockAdjust } from '@/services/api'; +import type { StockAdjust } from '@/types/api'; + +const STATUS_MAP: Record = { + 0: { text: '待审核', color: 'warning' }, + 1: { text: '已审核', color: 'success' }, + 2: { text: '已驳回', color: 'error' }, +}; + +const AdjustDetailPage: React.FC = () => { + const { id } = useParams<{ id: string }>(); + const [adjust, setAdjust] = useState(null); + + const load = async () => { + if (!id) return; + const res = await getStockAdjust(id); + if (res?.code === 0) setAdjust(res.data as StockAdjust); + }; + + useEffect(() => { load(); }, [id]); + + const handleApprove = (action: number) => { + Modal.confirm({ + title: action === 1 ? '确认审核通过?此操作将实际调整库存。' : '确认驳回此调整单?', + okType: action === 2 ? 'danger' : 'primary', + onOk: async () => { + await approveStockAdjust(id!, action); + message.success(action === 1 ? '已审核通过' : '已驳回'); + load(); + }, + }); + }; + + if (!adjust) return null; + + const status = STATUS_MAP[adjust.status] ?? STATUS_MAP[0]; + + return ( + + + + 调整单详情 — {adjust.adjustNo} + + + + + {adjust.adjustNo} + {adjust.adjustDate} + {adjust.adjustReason || '-'} + {adjust.operator || '-'} + {adjust.approver || '-'} + + {status.text} + + {adjust.remark && {adjust.remark}} + + {adjust.status === 0 && ( + + + + + )} + + + + { + const n = parseFloat(v); + const color = n > 0 ? '#52c41a' : n < 0 ? '#ff4d4f' : undefined; + return {n > 0 ? `+${v}` : v}; + }, + }, + { title: '调整后数量(米)', dataIndex: 'afterQuantity' }, + { title: '备注', dataIndex: 'remark', render: (v: string) => v || '-' }, + ]} + /> + + + ); +}; + +export default AdjustDetailPage; diff --git a/src/pages/Inventory/Adjusts/index.tsx b/src/pages/Inventory/Adjusts/index.tsx index 5378f8e..2200105 100644 --- a/src/pages/Inventory/Adjusts/index.tsx +++ b/src/pages/Inventory/Adjusts/index.tsx @@ -2,6 +2,7 @@ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { Button, Col, Form, Input, Modal, Row, Select, Table, Tag, message } from 'antd'; import { useEffect, useRef, useState } from 'react'; +import { Link } from '@umijs/max'; import { createStockAdjust, listProducts, listStockAdjusts } from '@/services/api'; import type { Product, StockAdjust } from '@/types/api'; @@ -14,25 +15,24 @@ const STATUS_MAP: Record = { interface DetailRow { key: number; productId?: string; adjustQuantity?: string } let rowKey = 0; -const columns: ProColumns[] = [ - { title: '调整单号', dataIndex: 'adjustNo' }, - { title: '调整日期', dataIndex: 'adjustDate', valueType: 'date', search: false }, - { title: '调整原因', dataIndex: 'adjustReason', search: false }, - { title: '操作人', dataIndex: 'operator', search: false }, - { - title: '状态', - dataIndex: 'status', - search: false, - render: (_, record) => { - const s = STATUS_MAP[record.status] ?? STATUS_MAP[0]; - return {s.text}; - }, - }, - { title: '创建时间', dataIndex: 'createdAt', valueType: 'dateTime', search: false }, - { title: '操作', valueType: 'option', render: () => [查看] }, -]; - const AdjustsPage: React.FC = () => { + const columns: ProColumns[] = [ + { title: '调整单号', dataIndex: 'adjustNo' }, + { title: '调整日期', dataIndex: 'adjustDate', valueType: 'date', search: false }, + { title: '调整原因', dataIndex: 'adjustReason', search: false }, + { title: '操作人', dataIndex: 'operator', search: false }, + { + title: '状态', + dataIndex: 'status', + search: false, + render: (_, record) => { + const s = STATUS_MAP[record.status] ?? STATUS_MAP[0]; + return {s.text}; + }, + }, + { title: '创建时间', dataIndex: 'createdAt', valueType: 'dateTime', search: false }, + { title: '操作', valueType: 'option', render: (_, record) => [查看] }, + ]; const actionRef = useRef(); const [form] = Form.useForm(); const [open, setOpen] = useState(false); diff --git a/src/pages/Inventory/Checks/detail.tsx b/src/pages/Inventory/Checks/detail.tsx new file mode 100644 index 0000000..8326e40 --- /dev/null +++ b/src/pages/Inventory/Checks/detail.tsx @@ -0,0 +1,94 @@ +import { ArrowLeftOutlined } from '@ant-design/icons'; +import { ProTable } from '@ant-design/pro-components'; +import { Button, Card, Descriptions, Modal, Space, Tag, Typography, message } from 'antd'; +import { useEffect, useState } from 'react'; +import { history, useParams } from '@umijs/max'; +import { confirmStockCheck, getStockCheck } from '@/services/api'; +import type { StockCheck } from '@/types/api'; + +const STATUS_MAP: Record = { + 0: { text: '草稿', color: 'default' }, + 1: { text: '进行中', color: 'processing' }, + 2: { text: '已完成', color: 'success' }, +}; + +const CheckDetailPage: React.FC = () => { + const { id } = useParams<{ id: string }>(); + const [check, setCheck] = useState(null); + + const load = async () => { + if (!id) return; + const res = await getStockCheck(id); + if (res?.code === 0) setCheck(res.data as StockCheck); + }; + + useEffect(() => { load(); }, [id]); + + const handleConfirm = () => { + Modal.confirm({ + title: '确认开始盘点?', + onOk: async () => { + await confirmStockCheck(id!); + message.success('已确认'); + load(); + }, + }); + }; + + if (!check) return null; + + const status = STATUS_MAP[check.status] ?? STATUS_MAP[0]; + + return ( + + + + 盘点单详情 — {check.checkNo} + + + + + {check.checkNo} + {check.checkDate} + {check.checker || '-'} + + {status.text} + + {check.createdAt} + {check.remark && {check.remark}} + + {check.status === 0 && ( + + )} + + + + { + const n = parseFloat(v); + const color = n > 0 ? '#52c41a' : n < 0 ? '#ff4d4f' : undefined; + return {v}; + }, + }, + { title: '差异金额', dataIndex: 'diffAmount', render: (v: string) => `¥ ${v}` }, + { title: '备注', dataIndex: 'remark', render: (v: string) => v || '-' }, + ]} + /> + + + ); +}; + +export default CheckDetailPage; diff --git a/src/pages/Inventory/Checks/index.tsx b/src/pages/Inventory/Checks/index.tsx index 9aa6005..81f76bf 100644 --- a/src/pages/Inventory/Checks/index.tsx +++ b/src/pages/Inventory/Checks/index.tsx @@ -2,6 +2,7 @@ import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { Button, Col, Form, Input, Modal, Row, Select, Table, Tag, message } from 'antd'; import { useEffect, useRef, useState } from 'react'; +import { Link } from '@umijs/max'; import { createStockCheck, listProducts, listStockChecks } from '@/services/api'; import type { Product, StockCheck } from '@/types/api'; @@ -14,24 +15,23 @@ const STATUS_MAP: Record = { interface DetailRow { key: number; productId?: string; actualQuantity?: string } let rowKey = 0; -const columns: ProColumns[] = [ - { title: '盘点单号', dataIndex: 'checkNo' }, - { title: '盘点日期', dataIndex: 'checkDate', valueType: 'date', search: false }, - { title: '盘点人', dataIndex: 'checker', search: false }, - { - title: '状态', - dataIndex: 'status', - search: false, - render: (_, record) => { - const s = STATUS_MAP[record.status] ?? STATUS_MAP[0]; - return {s.text}; - }, - }, - { title: '创建时间', dataIndex: 'createdAt', valueType: 'dateTime', search: false }, - { title: '操作', valueType: 'option', render: () => [查看] }, -]; - const ChecksPage: React.FC = () => { + const columns: ProColumns[] = [ + { title: '盘点单号', dataIndex: 'checkNo' }, + { title: '盘点日期', dataIndex: 'checkDate', valueType: 'date', search: false }, + { title: '盘点人', dataIndex: 'checker', search: false }, + { + title: '状态', + dataIndex: 'status', + search: false, + render: (_, record) => { + const s = STATUS_MAP[record.status] ?? STATUS_MAP[0]; + return {s.text}; + }, + }, + { title: '创建时间', dataIndex: 'createdAt', valueType: 'dateTime', search: false }, + { title: '操作', valueType: 'option', render: (_, record) => [查看] }, + ]; const actionRef = useRef(); const [form] = Form.useForm(); const [open, setOpen] = useState(false); diff --git a/src/types/api.ts b/src/types/api.ts index 29a38a3..997cd17 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -144,13 +144,39 @@ export interface StockGroup { quantity: number; } +export interface StockCheckDetail { + detailId: string; + checkId: string; + productId: string; + productName: string; + systemQuantity: string; + actualQuantity: string; + diffQuantity: string; + diffAmount: string; + remark?: string; +} + export interface StockCheck { checkId: string; checkNo: string; checkDate: string; checker: string; status: number; + remark?: string; createdAt: string; + updatedAt?: string; + details: StockCheckDetail[]; +} + +export interface StockAdjustDetail { + detailId: string; + adjustId: string; + productId: string; + productName: string; + beforeQuantity: string; + adjustQuantity: string; + afterQuantity: string; + remark?: string; } export interface StockAdjust { @@ -159,8 +185,12 @@ export interface StockAdjust { adjustDate: string; adjustReason: string; operator: string; + approver?: string; status: number; + remark?: string; createdAt: string; + updatedAt?: string; + details: StockAdjustDetail[]; } // ── System ────────────────────────────────────────