diff --git a/.umirc.ts b/.umirc.ts index ea983aa..34b8c2e 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -97,7 +97,7 @@ export default defineConfig({ path: '/product/attribute', component: './Product/Attribute', }, - + { name: 'WP商品列表', path: '/product/wp_list', diff --git a/package.json b/package.json index 8d155d5..f71e51f 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "scripts": { "build": "max build", "dev": "max dev", + "fix:openapi2ts": "sed -i '' 's/\r$//' /Users/zksu/Developer/work/workcode/web/node_modules/@umijs/openapi/dist/cli.js", "format": "prettier --cache --write .", "postinstall": "max setup", "openapi2ts": "openapi2ts", - "fix:openapi2ts": "sed -i '' 's/\r$//' /Users/zksu/Developer/work/workcode/web/node_modules/@umijs/openapi/dist/cli.js", "prepare": "husky", "setup": "max setup", "start": "npm run dev" diff --git a/src/access.ts b/src/access.ts index 965ae92..b8004b8 100644 --- a/src/access.ts +++ b/src/access.ts @@ -1,17 +1,47 @@ export default (initialState: any) => { const isSuper = initialState?.user?.isSuper ?? false; const isAdmin = initialState?.user?.Admin ?? false; - const canSeeOrganiza = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('organiza') ?? false); - const canSeeProduct = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('product') ?? false); - const canSeeStock = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('stock') ?? false); - const canSeeOrder = (isSuper || isAdmin) || - ((initialState?.user?.permissions?.includes('order') ?? false) || (initialState?.user?.permissions?.includes('order-10-days') ?? false)); - const canSeeCustomer = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('customer') ?? false); - const canSeeLogistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('logistics') ?? false); - const canSeeStatistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('statistics') ?? false); - const canSeeSite = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('site') ?? false); - const canSeeDict = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('dict') ?? false); - const canSeeTemplate = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('template') ?? false); + const canSeeOrganiza = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('organiza') ?? false); + const canSeeProduct = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('product') ?? false); + const canSeeStock = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('stock') ?? false); + const canSeeOrder = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('order') ?? false) || + (initialState?.user?.permissions?.includes('order-10-days') ?? false); + const canSeeCustomer = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('customer') ?? false); + const canSeeLogistics = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('logistics') ?? false); + const canSeeStatistics = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('statistics') ?? false); + const canSeeSite = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('site') ?? false); + const canSeeDict = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('dict') ?? false); + const canSeeTemplate = + isSuper || + isAdmin || + (initialState?.user?.permissions?.includes('template') ?? false); return { canSeeOrganiza, canSeeProduct, diff --git a/src/constants/index.ts b/src/constants/index.ts index d0708c5..a2e78b4 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -116,5 +116,5 @@ export const ORDER_STATUS_ENUM: ProSchemaValueEnumObj = { refund_cancelled: { text: '已取消退款', status: 'refund_cancelled', - } + }, }; diff --git a/src/pages/Dict/List/index.tsx b/src/pages/Dict/List/index.tsx index ba37e97..93b925d 100644 --- a/src/pages/Dict/List/index.tsx +++ b/src/pages/Dict/List/index.tsx @@ -213,7 +213,9 @@ const DictPage: React.FC = () => { const handleDownloadDictItemTemplate = async () => { try { // 使用带有认证拦截的 request 发起下载请求(后端鉴权通过) - const blob = await request('/dict/item/template', { responseType: 'blob' }); + const blob = await request('/dict/item/template', { + responseType: 'blob', + }); // 创建临时链接并触发下载 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); @@ -247,7 +249,7 @@ const DictPage: React.FC = () => { render: (_: any, record: any) => ( @@ -349,7 +353,9 @@ const DictPage: React.FC = () => { } }} > - + diff --git a/src/pages/Organiza/User/index.tsx b/src/pages/Organiza/User/index.tsx index 1e97f3f..3f209eb 100644 --- a/src/pages/Organiza/User/index.tsx +++ b/src/pages/Organiza/User/index.tsx @@ -27,7 +27,7 @@ const ListPage: React.FC = () => { title: '用户名', dataIndex: 'username', }, - + { title: '超管', dataIndex: 'isSuper', @@ -37,9 +37,9 @@ const ListPage: React.FC = () => { false: { text: '否' }, }, }, - { + { title: '激活', - dataIndex: 'isActive', + dataIndex: 'isActive', valueEnum: { true: { text: '是', @@ -72,7 +72,11 @@ const ListPage: React.FC = () => { onClick={async () => { // 中文注释:软删除为禁用(isActive=false),再次点击可启用 const next = !record.isActive; - const { success, message: errMsg } = await usercontrollerToggleactive({ userId: record.id, isActive: next }); + const { success, message: errMsg } = + await usercontrollerToggleactive({ + userId: record.id, + isActive: next, + }); if (!success) return message.error(errMsg); actionRef.current?.reload(); }} @@ -89,23 +93,32 @@ const ListPage: React.FC = () => { headerTitle="查询表格" actionRef={actionRef} rowKey="id" - request={async (params) => { - const { current = 1, pageSize = 10, username, isActive, isSuper, remark } = params as any; - console.log(`params`,params) + const { + current = 1, + pageSize = 10, + username, + isActive, + isSuper, + remark, + } = params as any; + console.log(`params`, params); const qp: any = { current, pageSize }; if (username) qp.username = username; - if (typeof isActive !== 'undefined' && isActive !== '') qp.isActive = String(isActive); - if (typeof isSuper !== 'undefined' && isSuper !== '') qp.isSuper = String(isSuper); + if (typeof isActive !== 'undefined' && isActive !== '') + qp.isActive = String(isActive); + if (typeof isSuper !== 'undefined' && isSuper !== '') + qp.isSuper = String(isSuper); if (remark) qp.remark = remark; - const { data, success } = await usercontrollerListusers({ params: qp }); + const { data, success } = await usercontrollerListusers({ + params: qp, + }); return { total: data?.total || 0, data: data?.items || [], success, }; }} - columns={columns} toolBarRender={() => []} /> @@ -145,27 +158,32 @@ const CreateForm: React.FC<{ message.error(error.message); } }} - > - - - - - - - - + > + + + + + + + + ); }; @@ -187,7 +205,10 @@ const EditForm: React.FC<{ onFinish={async (values: any) => { try { // 中文注释:更新用户,密码可选填 - const { success, message: err } = await usercontrollerUpdateuser({ id: record.id }, values); + const { success, message: err } = await usercontrollerUpdateuser( + { id: record.id }, + values, + ); if (!success) throw new Error(err); tableRef.current?.reload(); message.success('更新成功'); @@ -214,7 +235,12 @@ const EditForm: React.FC<{ /> - + ); diff --git a/src/pages/Product/Attribute/components/AttributeFormItem.tsx b/src/pages/Product/Attribute/components/AttributeFormItem.tsx index 8a966d5..e891f98 100644 --- a/src/pages/Product/Attribute/components/AttributeFormItem.tsx +++ b/src/pages/Product/Attribute/components/AttributeFormItem.tsx @@ -1,7 +1,6 @@ - +import { productcontrollerGetattributelist } from '@/servers/api/product'; import { ProFormSelect } from '@ant-design/pro-components'; import { useState } from 'react'; -import { productcontrollerGetattributeall, productcontrollerGetattributelist } from '@/servers/api/product'; interface AttributeFormItemProps { dictName: string; @@ -11,12 +10,25 @@ interface AttributeFormItemProps { } const fetchDictOptions = async (dictName: string, keyword?: string) => { - const { data } = await productcontrollerGetattributelist({ dictName, name: keyword }); - return (data?.items || []).map((item: any) => ({ label: item.name, value: item.name })); + const { data } = await productcontrollerGetattributelist({ + dictName, + name: keyword, + }); + return (data?.items || []).map((item: any) => ({ + label: item.name, + value: item.name, + })); }; -const AttributeFormItem: React.FC = ({ dictName, name, label, isTag = false }) => { - const [options, setOptions] = useState<{ label: string; value: string }[]>([]); +const AttributeFormItem: React.FC = ({ + dictName, + name, + label, + isTag = false, +}) => { + const [options, setOptions] = useState<{ label: string; value: string }[]>( + [], + ); if (isTag) { return ( diff --git a/src/pages/Product/Attribute/consts.ts b/src/pages/Product/Attribute/consts.ts index 9f5c4c4..8f60d34 100644 --- a/src/pages/Product/Attribute/consts.ts +++ b/src/pages/Product/Attribute/consts.ts @@ -1,2 +1,9 @@ // 中文注释:限定允许管理的字典名称集合 -export const attributes = new Set(['brand', 'strength', 'flavor', 'size', 'humidity','category']); \ No newline at end of file +export const attributes = new Set([ + 'brand', + 'strength', + 'flavor', + 'size', + 'humidity', + 'category', +]); diff --git a/src/pages/Product/Attribute/index.tsx b/src/pages/Product/Attribute/index.tsx index 9951179..cd84b59 100644 --- a/src/pages/Product/Attribute/index.tsx +++ b/src/pages/Product/Attribute/index.tsx @@ -1,7 +1,17 @@ import { UploadOutlined } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; import { request } from '@umijs/max'; -import { Button, Form, Input, Layout, Modal, Space, Table, Upload, message } from 'antd'; +import { + Button, + Form, + Input, + Layout, + Modal, + Space, + Table, + Upload, + message, +} from 'antd'; import React, { useEffect, useState } from 'react'; const { Sider, Content } = Layout; @@ -132,8 +142,21 @@ const AttributePage: React.FC = () => { key: 'action', render: (_: any, record: any) => ( - - + + ), }, @@ -144,7 +167,11 @@ const AttributePage: React.FC = () => { { } }, })} - rowClassName={(record) => (selectedDict?.id === record.id ? 'ant-table-row-selected' : '')} + rowClassName={(record) => + selectedDict?.id === record.id ? 'ant-table-row-selected' : '' + } pagination={false} /> -
- +
+ { } }} > - @@ -219,11 +266,23 @@ const AttributePage: React.FC = () => { onCancel={() => setIsDictItemModalVisible(false)} destroyOnClose > -
- + + - + @@ -239,4 +298,3 @@ const AttributePage: React.FC = () => { }; export default AttributePage; - diff --git a/src/pages/Product/List/index.tsx b/src/pages/Product/List/index.tsx index 991d33b..87b9d04 100644 --- a/src/pages/Product/List/index.tsx +++ b/src/pages/Product/List/index.tsx @@ -1,16 +1,14 @@ import { + productcontrollerAutobindcomponents, productcontrollerCreateproduct, productcontrollerDeleteproduct, - productcontrollerGetproductlist, - productcontrollerUpdateproductnamecn, - productcontrollerUpdateproduct, productcontrollerGetproductcomponents, + productcontrollerGetproductlist, productcontrollerSetproductcomponents, - productcontrollerAutobindcomponents, - productcontrollerGetattributelist, + productcontrollerUpdateproduct, + productcontrollerUpdateproductnamecn, } from '@/servers/api/product'; import { stockcontrollerGetstocks } from '@/servers/api/stock'; -import { request } from '@umijs/max'; import { templatecontrollerRendertemplate } from '@/servers/api/template'; import { PlusOutlined } from '@ant-design/icons'; import { @@ -19,6 +17,7 @@ import { PageContainer, ProColumns, ProForm, + ProFormDigit, ProFormInstance, ProFormList, ProFormSelect, @@ -26,6 +25,7 @@ import { ProFormTextArea, ProTable, } from '@ant-design/pro-components'; +import { request } from '@umijs/max'; import { App, Button, Popconfirm, Tag, Upload } from 'antd'; import AttributeFormItem from '@/pages/Product/Attribute/components/AttributeFormItem'; @@ -82,12 +82,13 @@ const AttributesCell: React.FC<{ record: any }> = ({ record }) => { ); }; - const ComponentsCell: React.FC<{ productId: number }> = ({ productId }) => { const [components, setComponents] = React.useState([]); React.useEffect(() => { (async () => { - const { data = [] } = await productcontrollerGetproductcomponents({ id: productId }); + const { data = [] } = await productcontrollerGetproductcomponents({ + id: productId, + }); setComponents(data || []); })(); }, [productId]); @@ -96,8 +97,11 @@ const ComponentsCell: React.FC<{ productId: number }> = ({ productId }) => { {components && components.length ? ( components.map((component: any) => ( - {(component.productSku) || `#${component.id}`} × {component.quantity}(库存: - {component.stock?.map((s: any) => `${s.name}:${s.quantity}`).join(', ') || '-'} + {component.productSku || `#${component.id}`} × {component.quantity} + (库存: + {component.stock + ?.map((s: any) => `${s.name}:${s.quantity}`) + .join(', ') || '-'} ) )) @@ -122,7 +126,9 @@ const List: React.FC = () => { // 中文注释:构建下载文件名 const d = new Date(); const pad = (n: number) => String(n).padStart(2, '0'); - const filename = `products-${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}.csv`; + const filename = `products-${d.getFullYear()}${pad( + d.getMonth() + 1, + )}${pad(d.getDate())}.csv`; // 中文注释:创建临时链接并触发下载 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); @@ -288,8 +294,9 @@ const CreateForm: React.FC<{ const { message } = App.useApp(); // 表单引用 const formRef = useRef(); - const [productType, setProductType] = useState<'single' | 'bundle' | null>(null); - + const [stockStatus, setStockStatus] = useState< + 'in-stock' | 'out-of-stock' | null + >(null); /** * @description 生成 SKU @@ -298,9 +305,15 @@ const CreateForm: React.FC<{ try { // 从表单引用中获取当前表单的值 const formValues = formRef.current?.getFieldsValue(); - const { humidityValues, brandValues, strengthValues, flavorValues } = formValues; + const { humidityValues, brandValues, strengthValues, flavorValues } = + formValues; // 检查是否所有必需的字段都已选择 - if (!brandValues?.length || !strengthValues?.length || !flavorValues?.length || !humidityValues?.length) { + if ( + !brandValues?.length || + !strengthValues?.length || + !flavorValues?.length || + !humidityValues?.length + ) { message.warning('请先选择品牌、强度、口味和干湿'); return; } @@ -312,10 +325,14 @@ const CreateForm: React.FC<{ const humidityName: string = String(humidityValues[0]); // 调用模板渲染API来生成SKU - const { data: rendered, message: msg, success } = await templatecontrollerRendertemplate( + const { + data: rendered, + message: msg, + success, + } = await templatecontrollerRendertemplate( { name: 'product.sku' }, { - brand: brandName || "", + brand: brandName || '', strength: strengthName || '', flavor: flavorName || '', humidity: humidityName ? capitalize(humidityName) : '', @@ -339,9 +356,15 @@ const CreateForm: React.FC<{ try { // 从表单引用中获取当前表单的值 const formValues = formRef.current?.getFieldsValue(); - const { humidityValues, brandValues, strengthValues, flavorValues } = formValues; + const { humidityValues, brandValues, strengthValues, flavorValues } = + formValues; // 检查是否所有必需的字段都已选择 - if (!brandValues?.length || !strengthValues?.length || !flavorValues?.length || !humidityValues?.length) { + if ( + !brandValues?.length || + !strengthValues?.length || + !flavorValues?.length || + !humidityValues?.length + ) { message.warning('请先选择品牌、强度、口味和干湿'); return; } @@ -355,14 +378,23 @@ const CreateForm: React.FC<{ const flavorTitle = flavorName; // 调用模板渲染API来生成产品名称 - const { message: msg, data: rendered, success } = await templatecontrollerRendertemplate( + const { + message: msg, + data: rendered, + success, + } = await templatecontrollerRendertemplate( { name: 'product.title' }, { brand: brandTitle, strength: strengthTitle, flavor: flavorTitle, model: '', - humidity: humidityName === 'dry' ? 'Dry' : humidityName === 'moisture' ? 'Moisture' : capitalize(humidityName), + humidity: + humidityName === 'dry' + ? 'Dry' + : humidityName === 'moisture' + ? 'Moisture' + : capitalize(humidityName), }, ); if (!success) { @@ -390,31 +422,62 @@ const CreateForm: React.FC<{ destroyOnHidden: true, }} onValuesChange={async (changedValues) => { + // 当 SKU 发生变化时 if ('sku' in changedValues) { const sku = changedValues.sku; + // 如果 sku 存在 if (sku) { - const { data } = await stockcontrollerGetstocks({ productSku: sku } as any); + // 获取库存信息 + const { data } = await stockcontrollerGetstocks({ + productSku: sku, + } as any); + // 如果库存信息存在且不为空 if (data && data.items && data.items.length > 0) { - setProductType('single'); + // 设置在库状态 + setStockStatus('in-stock'); + // 设置产品类型为单品 + formRef.current?.setFieldsValue({ productType: 'single' }); } else { - setProductType('bundle'); + // 设置未在库状态 + setStockStatus('out-of-stock'); + // 设置产品类型为套装 + formRef.current?.setFieldsValue({ productType: 'bundle' }); } } else { - setProductType(null); + // 如果 sku 不存在,则重置状态 + setStockStatus(null); + formRef.current?.setFieldsValue({ productType: null }); } } }} - onFinish={async (values) => { + onFinish={async (values: any) => { // 中文注释:组装 attributes(支持输入新值,按标题传入创建/绑定) const attributes = [ - ...(values.brandValues || []).map((v: string) => ({ dictName: 'brand', name: v })), - ...(values.strengthValues || []).map((v: string) => ({ dictName: 'strength', name: v })), - ...(values.flavorValues || []).map((v: string) => ({ dictName: 'flavor', name: v })), - ...(values.humidityValues || []).map((v: string) => ({ dictName: 'humidity', name: v })), - ...(values.sizeValues || []).map((v: string) => ({ dictName: 'size', name: v })), - ...(values.category ? [{ dictName: 'category', name: values.category }] : []), - ]; + ...(values.brandValues || []).map((v: string) => ({ + dictName: 'brand', + name: v, + })), + ...(values.strengthValues || []).map((v: string) => ({ + dictName: 'strength', + name: v, + })), + ...(values.flavorValues || []).map((v: string) => ({ + dictName: 'flavor', + name: v, + })), + ...(values.humidityValues || []).map((v: string) => ({ + dictName: 'humidity', + name: v, + })), + ...(values.sizeValues || []).map((v: string) => ({ + dictName: 'size', + name: v, + })), + ...(values.category + ? [{ dictName: 'category', name: values.category }] + : []), + ]; const payload: any = { name: (values as any).name, description: (values as any).description, @@ -422,6 +485,8 @@ const CreateForm: React.FC<{ price: (values as any).price, promotionPrice: (values as any).promotionPrice, attributes, + components: + values.productType === 'bundle' ? values.components : undefined, }; const { success, message: errMsg } = await productcontrollerCreateproduct(payload); @@ -434,7 +499,6 @@ const CreateForm: React.FC<{ return false; }} > - 自动生成 - {productType && ( - - {productType === 'single' ? '单品' : '套装'} + {stockStatus && ( + + {stockStatus === 'in-stock' ? '在库' : '未在库'} )} @@ -464,12 +531,83 @@ const CreateForm: React.FC<{ 自动生成 - - - - + + + prevValues.productType !== curValues.productType + } + noStyle + > + {({ getFieldValue }: { getFieldValue: (name: string) => any }) => + getFieldValue('productType') === 'bundle' ? ( + + + + + + + ) : null + } + + + + + - + ; record: API.Product; -}> = ({ tableRef, record }) => { + tableRef: React.MutableRefObject; +}> = ({ record, tableRef }) => { const { message } = App.useApp(); const formRef = useRef(); - const [components, setComponents] = useState<{ productSku: string; quantity: number }[]>([]); - const [productType, setProductType] = useState<'single' | 'bundle' | null>(null); + const [components, setComponents] = useState< + { productSku: string; quantity: number }[] + >([]); + const [productType, setProductType] = useState<'single' | 'bundle' | null>( + null, + ); React.useEffect(() => { - // 中文注释:加载当前产品的组成 (async () => { - const { data = [] } = await productcontrollerGetproductcomponents({ id: (record as any).id }); - const items = (data || []).map((c: any) => ({ productSku: c.productSku, quantity: c.quantity })); - setComponents(items as any); - formRef.current?.setFieldsValue({ components: items }); - - // 检查产品类型 - if (record.sku) { - const { data: stockData } = await stockcontrollerGetstocks({ productSku: record.sku } as any); - if (stockData && stockData.items && stockData.items.length > 0) { - setProductType('single'); - } else { - setProductType('bundle'); - } + const { data: stockData } = await stockcontrollerGetstocks({ + productSku: record.sku, + } as any); + if (stockData && stockData.items && stockData.items.length > 0) { + setProductType('single'); + formRef.current?.setFieldsValue({ productType: 'single' }); + } else { + setProductType('bundle'); + formRef.current?.setFieldsValue({ productType: 'bundle' }); } + const { data: componentsData } = + await productcontrollerGetproductcomponents({ id: record.id }); + setComponents(componentsData || []); })(); }, [record]); - const initialValues = useMemo(() => { - if (!record) return {}; - const attributes = record.attributes || []; - const attributesGroupedByName = (attributes as any[]).reduce((group, attr) => { - const dictName = attr.dict.name; - if (!group[dictName]) { - group[dictName] = []; + const initialValues = useMemo(() => { + return { + ...record, + ...((record as any).attributes || []).reduce((acc: any, cur: any) => { + const dictName = cur.dict?.name; + if (dictName) { + const key = `${dictName}Values`; + if (!acc[key]) { + acc[key] = []; } - group[dictName].push(attr.name); - return group; - }, {} as Record); + acc[key].push(cur.name); + } + return acc; + }, {} as any), + components: components, + productType: productType, + }; + }, [record, components, productType]); - const values: any = { - ...record, - brandValues: attributesGroupedByName.brand || [], - strengthValues: attributesGroupedByName.strength || [], - flavorValues: attributesGroupedByName.flavor || [], - humidityValues: attributesGroupedByName.humidity || [], - sizeValues: attributesGroupedByName.size || [], - category: attributesGroupedByName.category?.[0] || '', - }; - return values; - }, [record]); return ( - formRef={formRef} title="编辑" + formRef={formRef} trigger={} + autoFocusFirstInput + drawerProps={{ + destroyOnHidden: true, + }} initialValues={initialValues} onValuesChange={async (changedValues) => { + // 当 SKU 发生变化时 if ('sku' in changedValues) { const sku = changedValues.sku; + // 如果 sku 存在 if (sku) { - const { data } = await stockcontrollerGetstocks({ productSku: sku } as any); + // 获取库存信息 + const { data } = await stockcontrollerGetstocks({ + productSku: sku, + } as any); + // 如果库存信息存在且不为空 if (data && data.items && data.items.length > 0) { - setProductType('single'); + // 设置产品类型为单品 + formRef.current?.setFieldsValue({ productType: 'single' }); } else { - setProductType('bundle'); + // 设置产品类型为套装 + formRef.current?.setFieldsValue({ productType: 'bundle' }); } } else { - setProductType(null); + // 如果 sku 不存在,则重置状态 + formRef.current?.setFieldsValue({ productType: null }); } } }} onFinish={async (values) => { const attributes = [ - ...(values.brandValues || []).map((v: string) => ({ dictName: 'brand', name: v })), - ...(values.strengthValues || []).map((v: string) => ({ dictName: 'strength', name: v })), - ...(values.flavorValues || []).map((v: string) => ({ dictName: 'flavor', name: v })), - ...(values.humidityValues || []).map((v: string) => ({ dictName: 'humidity', name: v })), - ...(values.sizeValues || []).map((v: string) => ({ dictName: 'size', name: v })), - ...(values.category ? [{ dictName: 'category', name: values.category }] : []), + ...(values.brandValues || []).map((v: string) => ({ + dictName: 'brand', + name: v, + })), + ...(values.strengthValues || []).map((v: string) => ({ + dictName: 'strength', + name: v, + })), + ...(values.flavorValues || []).map((v: string) => ({ + dictName: 'flavor', + name: v, + })), + ...(values.humidityValues || []).map((v: string) => ({ + dictName: 'humidity', + name: v, + })), + ...(values.sizeValues || []).map((v: string) => ({ + dictName: 'size', + name: v, + })), + ...(values.category + ? [{ dictName: 'category', name: values.category }] + : []), ]; - const updatePayload: any = { - name: values.name, - sku: values.sku, - description: values.description, - price: values.price, - promotionPrice: values.promotionPrice, + + const payload: any = { + name: (values as any).name, + description: (values as any).description, + sku: (values as any).sku, + price: (values as any).price, + promotionPrice: (values as any).promotionPrice, attributes, }; - const { success, message: errMsg } = await productcontrollerUpdateproduct( - { id: (record as any).id }, - updatePayload, - ); - if (success) { - // 中文注释:同步更新组成(覆盖式) - const items = (values as any)?.components || []; - if (Array.isArray(items)) { - const payloadItems = items - .filter((i: any) => i && i.productSku && i.quantity && i.quantity > 0) - .map((i: any) => ({ productSku: i.productSku, quantity: Number(i.quantity) })); - await productcontrollerSetproductcomponents({ id: (record as any).id }, { items: payloadItems as any }); + + const { success, message: errMsg } = + await productcontrollerUpdateproduct({ id: record.id }, payload); + + if (values.productType === 'bundle') { + const { success: success2, message: errMsg2 } = + await productcontrollerSetproductcomponents( + { id: record.id }, + { + items: (values.components || []).map((c: any) => ({ + sku: c.sku, + quantity: Number(c.quantity), + })), + }, + ); + if (!success2) { + message.error(errMsg2); + return false; } - message.success('更新成功'); + } + + if (success) { + message.success('提交成功'); tableRef.current?.reloadAndRest?.(); return true; } @@ -607,7 +783,6 @@ const EditForm: React.FC<{ return false; }} > - {/* 在这里列举attribute字段 */} - {productType && ( - - {productType === 'single' ? '单品' : '套装'} - - )} + + {() => { + const productType = formRef.current?.getFieldValue('productType'); + return ( + productType && ( + + {productType === 'single' ? '单品' : '套装'} + + ) + ); + }} + + + - - - - - - - - - - {/* 中文注释:编辑产品组成(库存ID + 数量) */} + + + + + + + -