From 07fca92ef382415f0a2bc138d83b3b1b6beb6a04 Mon Sep 17 00:00:00 2001 From: tikkhun Date: Mon, 1 Dec 2025 19:06:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8C=BA=E5=9F=9F=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8C=BA=E5=9F=9F=E7=AE=A1=E7=90=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=8F=8A=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加区域列表页面及增删改查功能 - 在菜单中新增区域管理入口 - 更新权限控制添加区域访问权限 - 调整产品列表字段名从productName改为name - 优化库存SKU选择器支持搜索和展示名称 - 修复类型定义中siteId类型不一致问题 --- .umirc.ts | 12 ++ src/access.ts | 7 +- src/app.tsx | 12 +- src/pages/Area/List/index.tsx | 194 +++++++++++++++++++++++++++++++ src/pages/Area/Map/index.tsx | 0 src/pages/Product/List/index.tsx | 49 ++++++-- src/pages/Stock/List/index.tsx | 4 +- src/servers/api/dict.ts | 15 +++ src/servers/api/product.ts | 4 +- src/servers/api/typings.d.ts | 61 +++++----- 10 files changed, 317 insertions(+), 41 deletions(-) create mode 100644 src/pages/Area/List/index.tsx create mode 100644 src/pages/Area/Map/index.tsx diff --git a/.umirc.ts b/.umirc.ts index 34b8c2e..4bef20c 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -69,6 +69,18 @@ export default defineConfig({ component: './Template', // 对应 src/pages/Template/index.tsx }, ], + }, + { + name: '地点管理', + path: '/area', + access: 'canSeeArea', + routes: [ + { + name: '地点列表', + path: '/area/list', + component: './Area/List', + }, + ], }, { name: '站点管理', diff --git a/src/access.ts b/src/access.ts index b8004b8..a4c8180 100644 --- a/src/access.ts +++ b/src/access.ts @@ -38,10 +38,14 @@ export default (initialState: any) => { isSuper || isAdmin || (initialState?.user?.permissions?.includes('dict') ?? false); - const canSeeTemplate = + const canSeeTemplate = isSuper || isAdmin || (initialState?.user?.permissions?.includes('template') ?? false); + const canSeeArea = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('area') ?? false); return { canSeeOrganiza, canSeeProduct, @@ -53,5 +57,6 @@ export default (initialState: any) => { canSeeSite, canSeeDict, canSeeTemplate, + canSeeArea, }; }; diff --git a/src/app.tsx b/src/app.tsx index 50ea763..2307ffd 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,6 +1,6 @@ // 运行时配置 -import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; +import { GlobalOutlined, LogoutOutlined, UserOutlined } from '@ant-design/icons'; import { ProLayoutProps, ProSchemaValueEnumObj, @@ -56,12 +56,20 @@ export const layout = (): ProLayoutProps => { menu: { locale: false, }, + menuDataRender: (menuData) => { + menuData.unshift({ + path: '/area', + name: '区域管理', + icon: , + }); + return menuData; + }, layout: 'mix', actionsRender: () => (
} /> - {initialState?.name} + {initialState?.user?.name}
), diff --git a/src/pages/Area/List/index.tsx b/src/pages/Area/List/index.tsx new file mode 100644 index 0000000..ab6059d --- /dev/null +++ b/src/pages/Area/List/index.tsx @@ -0,0 +1,194 @@ + +import { + ActionType, + DrawerForm, + ProColumns, + ProFormInstance, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { request } from '@umijs/max'; +import { Button, message, Popconfirm, Space } from 'antd'; +import React, { useEffect, useRef, useState } from 'react'; + +interface AreaItem { + id: number; + name: string; + latitude?: number; + longitude?: number; +} + +const AreaList: React.FC = () => { + const actionRef = useRef(); + const formRef = useRef(); + const [open, setOpen] = useState(false); + const [editing, setEditing] = useState(null); + + useEffect(() => { + if (!open) return; + if (editing) { + formRef.current?.setFieldsValue(editing); + } else { + formRef.current?.resetFields(); + } + }, [open, editing]); + + const columns: ProColumns[] = [ + { + title: 'ID', + dataIndex: 'id', + width: 80, + sorter: true, + hideInSearch: true, + }, + { title: '名称', dataIndex: 'name', width: 220 }, + { + title: '纬度', + dataIndex: 'latitude', + width: 160, + hideInSearch: true, + }, + { + title: '经度', + dataIndex: 'longitude', + width: 160, + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'actions', + width: 240, + hideInSearch: true, + render: (_, row) => ( + + + { + try { + await request(`/area/${row.id}`, { + method: 'DELETE', + }); + message.success('删除成功'); + actionRef.current?.reload(); + } catch (e: any) { + message.error(e?.message || '删除失败'); + } + }} + > + + + + ), + }, + ]; + + const tableRequest = async (params: Record) => { + try { + const { current = 1, pageSize = 10, name } = params; + const resp = await request('/area', { + method: 'GET', + params: { + currentPage: current, + pageSize, + name: name || undefined, + }, + }); + const { success, data, message: errMsg } = resp as any; + if (!success) throw new Error(errMsg || '获取失败'); + return { + data: (data?.list ?? []) as AreaItem[], + total: data?.total ?? 0, + success: true, + }; + } catch (e: any) { + message.error(e?.message || '获取失败'); + return { data: [], total: 0, success: false }; + } + }; + + const handleSubmit = async (values: AreaItem) => { + try { + if (editing) { + await request(`/area/${editing.id}`, { + method: 'PUT', + data: values, + }); + } else { + await request('/area', { + method: 'POST', + data: values, + }); + } + message.success('提交成功'); + setOpen(false); + setEditing(null); + actionRef.current?.reload(); + return true; + } catch (e: any) { + message.error(e?.message || '提交失败'); + return false; + } + }; + + return ( + <> + + actionRef={actionRef} + rowKey="id" + columns={columns} + request={tableRequest} + toolBarRender={() => [ + , + ]} + /> + + + title={editing ? '编辑区域' : '新增区域'} + open={open} + onOpenChange={setOpen} + formRef={formRef} + onFinish={handleSubmit} + > + + + + + + ); +}; + +export default AreaList; diff --git a/src/pages/Area/Map/index.tsx b/src/pages/Area/Map/index.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/Product/List/index.tsx b/src/pages/Product/List/index.tsx index c6d04c1..6e26e0b 100644 --- a/src/pages/Product/List/index.tsx +++ b/src/pages/Product/List/index.tsx @@ -5,9 +5,9 @@ import { productcontrollerGetproductlist, productcontrollerSetproductcomponents, productcontrollerUpdateproduct, - productcontrollerUpdateproductnamecn, + productcontrollerUpdatenamecn, } from '@/servers/api/product'; -import { stockcontrollerGetstocks } from '@/servers/api/stock'; +import { stockcontrollerGetstocks as getStocks } from '@/servers/api/stock'; import { templatecontrollerRendertemplate } from '@/servers/api/template'; import { PlusOutlined } from '@ant-design/icons'; import { @@ -49,7 +49,7 @@ const NameCn: React.FC<{ onBlur: async (e: React.FocusEvent) => { if (!e.target.value) return setEditable(false); const { success, message: errMsg } = - await productcontrollerUpdateproductnamecn({ + await productcontrollerUpdatenamecn({ id, nameCn: e.target.value, }); @@ -444,7 +444,7 @@ const CreateForm: React.FC<{ // 如果 sku 存在 if (sku) { // 获取库存信息 - const { data } = await stockcontrollerGetstocks({ + const { data } = await getStocks({ sku: sku, } as any); // 如果库存信息存在且不为空 @@ -523,6 +523,9 @@ const CreateForm: React.FC<{ placeholder="请输入SKU" rules={[{ required: true, message: '请输入SKU' }]} /> + {stockStatus && ( - { + const params = keyWords ? { sku: keyWords, name: keyWords } : { pageSize: 9999 }; + const { data } = await getStocks(params as any); + if (!data || !data.items) { + return []; + } + return data.items + .filter(item => item.sku) + .map(item => ({ + label: `${item.sku} - ${item.name}`, + value: item.sku, + })); + }} /> { (async () => { - const { data: stockData } = await stockcontrollerGetstocks({ + const { data: stockData } = await getStocks({ sku: record.sku, } as any); if (stockData && stockData.items && stockData.items.length > 0) { @@ -719,7 +737,7 @@ const EditForm: React.FC<{ // 如果 sku 存在 if (sku) { // 获取库存信息 - const { data } = await stockcontrollerGetstocks({ + const { data } = await getStocks({ sku: sku, } as any); // 如果库存信息存在且不为空 @@ -867,12 +885,27 @@ const EditForm: React.FC<{ )} > - { + const params = keyWords ? { sku: keyWords, name: keyWords } : { pageSize: 9999 }; + const { data } = await getStocks(params as any); + if (!data || !data.items) { + return []; + } + return data.items + .filter(item => item.sku) + .map(item => ({ + label: `${item.sku} - ${item.name}`, + value: item.sku, + })); + }} /> { }, { title: '产品名称', - dataIndex: 'productName', + dataIndex: 'name', sorter: true, }, { title: '中文名', - dataIndex: 'productNameCn', + dataIndex: 'nameCn', hideInSearch: true, }, diff --git a/src/servers/api/dict.ts b/src/servers/api/dict.ts index fb04002..ae7c520 100644 --- a/src/servers/api/dict.ts +++ b/src/servers/api/dict.ts @@ -191,6 +191,21 @@ export async function dictcontrollerGetdictitems( }); } +/** 此处后端没有提供注释 GET /dict/items-by-name */ +export async function dictcontrollerGetdictitemsbydictname( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.dictcontrollerGetdictitemsbydictnameParams, + options?: { [key: string]: any }, +) { + return request('/dict/items-by-name', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + /** 此处后端没有提供注释 GET /dict/list */ export async function dictcontrollerGetdicts( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) diff --git a/src/servers/api/product.ts b/src/servers/api/product.ts index f817da1..557f97e 100644 --- a/src/servers/api/product.ts +++ b/src/servers/api/product.ts @@ -588,9 +588,9 @@ export async function productcontrollerCompatstrengthall(options?: { } /** 此处后端没有提供注释 PUT /productupdateNameCn/${param1}/${param0} */ -export async function productcontrollerUpdateproductnamecn( +export async function productcontrollerUpdatenamecn( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.productcontrollerUpdateproductnamecnParams, + params: API.productcontrollerUpdatenamecnParams, options?: { [key: string]: any }, ) { const { nameCn: param0, id: param1, ...queryParams } = params; diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts index ba3d620..763c57f 100644 --- a/src/servers/api/typings.d.ts +++ b/src/servers/api/typings.d.ts @@ -19,7 +19,6 @@ declare namespace API { createdAt: string; /** 更新时间 */ updatedAt: string; - attributes?: any[]; }; type areacontrollerDeleteareaParams = { @@ -87,6 +86,8 @@ declare namespace API { promotionPrice?: number; /** 商品类型 */ type?: 'simple' | 'bundle'; + /** 产品组成 */ + components?: any[]; }; type CreatePurchaseOrderDTO = { @@ -161,7 +162,13 @@ declare namespace API { id: number; }; + type dictcontrollerGetdictitemsbydictnameParams = { + name?: string; + }; + type dictcontrollerGetdictitemsParams = { + title?: string; + name?: string; dictId?: number; }; @@ -270,7 +277,7 @@ declare namespace API { type Order = { id?: number; - siteId?: string; + siteId?: number; externalOrderId?: string; status?: any; orderStatus?: any; @@ -358,7 +365,7 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - siteId?: string; + siteId?: number; name?: string; externalProductId?: string; externalVariationId?: string; @@ -373,7 +380,7 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - siteId?: string; + siteId?: number; name?: string; startDate?: string; endDate?: string; @@ -386,7 +393,7 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - siteId?: string; + siteId?: number; name?: string; startDate?: string; endDate?: string; @@ -398,7 +405,7 @@ declare namespace API { /** 每页大小 */ pageSize?: number; externalOrderId?: string; - siteId?: string; + siteId?: number; customer_email?: string; billing_phone?: string; keyword?: string; @@ -445,7 +452,7 @@ declare namespace API { type OrderDetail = { id?: number; - siteId?: string; + siteId?: number; externalOrderId?: string; status?: any; orderStatus?: any; @@ -512,7 +519,7 @@ declare namespace API { type OrderItem = { id?: number; name?: string; - siteId?: string; + siteId?: number; orderId?: number; externalOrderId?: string; externalOrderItemId?: string; @@ -576,7 +583,7 @@ declare namespace API { type OrderRefundItem = { id?: number; refundId?: number; - siteId?: string; + siteId?: number; externalRefundId?: string; externalRefundItemId?: string; externalProductId?: string; @@ -599,7 +606,7 @@ declare namespace API { type OrderSale = { id?: number; orderId?: number; - siteId?: string; + siteId?: number; externalOrderItemId?: string; productId?: number; name?: string; @@ -620,7 +627,7 @@ declare namespace API { type OrderSaleDTO = { id?: number; orderId?: number; - siteId?: string; + siteId?: number; externalOrderItemId?: string; productId?: number; name?: string; @@ -693,6 +700,8 @@ declare namespace API { type Product = { /** ID */ id: number; + /** 类型 */ + type?: string; /** 产品名称 */ name: string; /** 产品中文名称 */ @@ -703,8 +712,6 @@ declare namespace API { sku?: string; /** 价格 */ price?: number; - /** 类型 */ - type?: string; /** 促销价格 */ promotionPrice?: number; /** 库存 */ @@ -841,7 +848,7 @@ declare namespace API { id: number; }; - type productcontrollerUpdateproductnamecnParams = { + type productcontrollerUpdatenamecnParams = { nameCn: string; id: number; }; @@ -925,7 +932,7 @@ declare namespace API { type PurchaseOrderItem = { id?: number; sku?: string; - productName?: string; + name?: string; quantity?: number; price?: number; purchaseOrderId?: number; @@ -980,7 +987,7 @@ declare namespace API { /** 每页大小 */ pageSize?: number; externalOrderId?: string; - siteId?: string; + siteId?: number; customer_email?: string; billing_phone?: string; keyword?: string; @@ -1009,7 +1016,7 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - siteId?: string; + siteId?: number; name?: string; externalProductId?: string; externalVariationId?: string; @@ -1024,7 +1031,7 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - siteId?: string; + siteId?: number; name?: string; startDate?: string; endDate?: string; @@ -1073,7 +1080,8 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - productName?: string; + name?: string; + sku?: string; /** 按库存点ID排序 */ sortPointId?: number; /** 排序对象,格式如 { productName: "asc", sku: "desc" } */ @@ -1087,7 +1095,7 @@ declare namespace API { pageSize?: number; stockPointId?: number; sku?: string; - productName?: string; + name?: string; operationType?: string; startDate?: string; endDate?: string; @@ -1329,7 +1337,7 @@ declare namespace API { pageSize?: number; stockPointId?: number; sku?: string; - productName?: string; + name?: string; operationType?: string; startDate?: string; endDate?: string; @@ -1340,7 +1348,8 @@ declare namespace API { current?: number; /** 每页大小 */ pageSize?: number; - productName?: string; + name?: string; + sku?: string; /** 按库存点ID排序 */ sortPointId?: number; /** 排序对象,格式如 { productName: "asc", sku: "desc" } */ @@ -1384,7 +1393,7 @@ declare namespace API { createdAt: string; /** 更新时间 */ updatedAt: string; - productName?: string; + name?: string; stockPoint?: Record[]; }; @@ -1496,7 +1505,7 @@ declare namespace API { type Subscription = { id?: number; /** 来源站点唯一标识 */ - siteId?: string; + siteId?: number; /** WooCommerce 订阅 ID */ externalSubscriptionId?: string; status?: any; @@ -1704,8 +1713,8 @@ declare namespace API { type VariationDTO = { /** ID */ id: number; - /** wp网站ID */ - siteId: number; + /** 站点 id */ + siteId?: number; /** wp产品ID */ externalProductId: string; /** wp变体ID */