diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..85ba500 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: require.resolve('@umijs/max/eslint'), +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57ceb29 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +/node_modules +/.env.local +/.umirc.local.ts +/config/config.local.ts +/src/.umi +/src/.umi-production +/src/.umi-test +/.umi +/.umi-production +/.umi-test +/dist +/.mfsu +.swc +/package-lock.json +/package.json +/yarn.lock \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..8f46dd2 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +registry=https://registry.npmmirror.com/ + diff --git a/.openapi2tsrc.ts b/.openapi2tsrc.ts new file mode 100644 index 0000000..27c6e5c --- /dev/null +++ b/.openapi2tsrc.ts @@ -0,0 +1,4 @@ +export default { + schemaPath: 'http://127.0.0.1:7001/swagger-ui/index.json', + serversPath: './src/servers', +}; diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5892e28 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +node_modules +.umi +.umi-production diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..70767cd --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "printWidth": 80, + "singleQuote": true, + "trailingComma": "all", + "proseWrap": "never", + "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }], + "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"] +} diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000..08bc02c --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: require.resolve('@umijs/max/stylelint'), +}; diff --git a/.umirc.ts b/.umirc.ts new file mode 100644 index 0000000..9073e10 --- /dev/null +++ b/.umirc.ts @@ -0,0 +1,172 @@ +import { defineConfig } from '@umijs/max'; + +const isDev = process.env.NODE_ENV === 'development'; +const UMI_APP_API_URL = isDev + ? 'http://localhost:7001' + : 'https://api.yoone.ca'; + +export default defineConfig({ + antd: {}, + access: {}, + model: {}, + initialState: {}, + request: {}, + layout: { + title: 'YOONE', + }, + define: { + UMI_APP_API_URL, + }, + routes: [ + { path: '/', redirect: '/home' }, + { name: '追踪', path: '/track', component: './Track', layout: false }, + { name: '登录', path: '/login', component: './Login', layout: false }, + { name: '首页', path: '/home', component: './Home' }, + { + name: '组织架构', + path: '/organiza', + access: 'canSeeSuper', + routes: [ + { + name: '用户管理', + path: '/organiza/user', + component: './Organiza/User', + }, + ], + }, + { + name: '商品管理', + path: '/product', + routes: [ + { + name: '商品分类', + path: '/product/category', + component: './Product/Category', + }, + { + name: '强度', + path: '/product/strength', + component: './Product/Strength', + }, + { + name: '口味', + path: '/product/flavors', + component: './Product/Flavors', + }, + { + name: '产品列表', + path: '/product/list', + component: './Product/List', + }, + { + name: 'WP商品列表', + path: '/product/wp_list', + component: './Product/WpList', + }, + ], + }, + { + name: '库存管理', + path: '/stock', + routes: [ + { + name: '库存列表', + path: '/stock/list', + component: './Stock/List', + }, + { + name: '仓库点', + path: '/stock/warehouse', + component: './Stock/Warehouse', + }, + { + name: '入库管理', + path: '/stock/purchaseOrder', + component: './Stock/PurchaseOrder', + }, + { + name: '调拨管理', + path: '/stock/transfer', + component: './Stock/Transfer', + }, + { + name: '库存记录', + path: '/stock/record', + component: './Stock/Record', + }, + ], + }, + { + name: '订单管理', + path: '/order', + access: 'canSeeAdmin', + routes: [ + { + name: '订单列表', + path: '/order/list', + component: './Order/List', + }, + ], + }, + // { + // name: '物流管理', + // path: '/logistics', + // routes: [ + // { + // name: '服务商', + // path: '/logistics/services', + // component: './Logistics/Services', + // }, + // { + // name: '地址管理', + // path: '/logistics/address', + // component: './Logistics/Address', + // }, + // { + // name: '物流列表', + // path: '/logistics/list', + // component: './Logistics/List', + // }, + // ], + // }, + { + name: '数据统计', + path: '/statistics', + routes: [ + { + name: '销售统计', + path: '/statistics/sales', + component: './Statistics/Sales', + access: 'canSeeSuper', + }, + { + name: '订单统计', + path: '/statistics/order', + component: './Statistics/Order', + access: 'canSeeSuper', + }, + { + name: '客户统计', + path: '/statistics/customer', + component: './Statistics/Customer', + access: 'canSeeSuper', + }, + { + name: '库存预测', + path: '/statistics/inventoryForecast', + component: './Statistics/InventoryForecast', + }, + { + name: '补货', + path: '/statistics/restocking', + component: './Statistics/Restocking', + }, + ], + }, + // { + // path: '*', + // component: './404', + // }, + ], + npmClient: 'pnpm', +}); diff --git a/mock/userAPI.ts b/mock/userAPI.ts new file mode 100644 index 0000000..7ef8011 --- /dev/null +++ b/mock/userAPI.ts @@ -0,0 +1,20 @@ +const users = [ + { id: 0, name: 'Umi', nickName: 'U', gender: 'MALE' }, + { id: 1, name: 'Fish', nickName: 'B', gender: 'FEMALE' }, +]; + +export default { + 'GET /api/v1/queryUserList': (req: any, res: any) => { + res.json({ + success: true, + data: { list: users }, + errorCode: 0, + }); + }, + 'PUT /api/v1/user/': (req: any, res: any) => { + res.json({ + success: true, + errorCode: 0, + }); + }, +}; diff --git a/src/access.ts b/src/access.ts new file mode 100644 index 0000000..fbe171f --- /dev/null +++ b/src/access.ts @@ -0,0 +1,9 @@ +export default (initialState: any) => { + const canSeeSuper = initialState?.user?.isSuper; + const canSeeAdmin = + initialState?.user?.isSuper || initialState?.user?.isAdmin; + return { + canSeeSuper, + canSeeAdmin, + }; +}; diff --git a/src/app.tsx b/src/app.tsx new file mode 100644 index 0000000..ad17b86 --- /dev/null +++ b/src/app.tsx @@ -0,0 +1,128 @@ +// 运行时配置 + +import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; +import { + ProLayoutProps, + ProSchemaValueEnumObj, + ProTable, +} from '@ant-design/pro-components'; +import { RequestConfig, history, useModel } from '@umijs/max'; +import { App, Avatar, ConfigProvider, Dropdown, MenuProps } from 'antd'; +import dayjs from 'dayjs'; +import 'dayjs/locale/zh-cn'; +import { usercontrollerGetuser } from './servers/api/user'; + +// 设置 dayjs 全局语言为中文 +dayjs.locale('zh-cn'); + +// 全局初始化数据配置,用于 Layout 用户信息和权限初始化 +// 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate +export async function getInitialState(): Promise<{ + user?: Record; + categoryList?: ProSchemaValueEnumObj; + sites?: API.SiteConfig[]; +}> { + if (!localStorage.getItem('token') || history.location.pathname === '/login') + return {}; + + const { data: user } = await usercontrollerGetuser(); + return { user }; +} + +export const layout = (): ProLayoutProps => { + const { initialState } = useModel('@@initialState'); + const items: MenuProps['items'] = [ + { + key: '1', + label: '我的账号', + disabled: true, + }, + { + type: 'divider', + }, + { + key: '3', + label: '退出登录', + icon: , + onClick: async () => { + //TODO 清理服务器登陆状态 + localStorage.removeItem('token'); + history.push('/login'); + }, + }, + ]; + + return { + menu: { + locale: false, + }, + layout: 'mix', + actionsRender: () => ( + +
+ } /> + {initialState?.name} +
+
+ ), + }; +}; + +export const request: RequestConfig = { + baseURL: UMI_APP_API_URL, + requestInterceptors: [ + (url: string, options: any) => { + const token = localStorage.getItem('token'); + return { + url, + options: { + ...options, + headers: { + ...options.headers, + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }, + }; + }, + ], + errorConfig: { + errorHandler: (error: any) => { + if (error?.response?.status === 401) { + localStorage.removeItem('token'); + history.push('/login'); + } + }, + }, +}; + +export const onRouteChange = ({ location }: { location: Location }) => { + const token = localStorage.getItem('token'); + + // 白名单,不需要登录的页面 + const whiteList = ['/login', '/track']; + + if (!token && !whiteList.includes(location.pathname)) { + // 没有 token 且不在白名单内,跳转到登录页 + history.push('/login'); + } +}; + +export function rootContainer(container: React.ReactNode) { + // 全局过滤空字段逻辑 + (ProTable as any).defaultProps = { + ...(ProTable as any).defaultProps, + beforeSearchSubmit: (params: any) => { + return Object.fromEntries( + Object.entries(params).filter( + ([_, value]) => value !== undefined && value !== null && value !== '', + ), + ); + }, + }; + return ( + + {container} + + ); +} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/components/InternationalPhoneInput.tsx b/src/components/InternationalPhoneInput.tsx new file mode 100644 index 0000000..8241636 --- /dev/null +++ b/src/components/InternationalPhoneInput.tsx @@ -0,0 +1,84 @@ +import { Input, Select } from 'antd'; +import React, { useEffect } from 'react'; + +const { Option } = Select; + +// 定义国家代码和扩展码的映射关系 +const phoneExtensions: { [key: string]: string } = { + CA: '1', + CN: '86', + US: '1', +}; + +interface InternationalPhoneInputProps { + value?: { country?: string; phone?: string; extension?: string }; + onChange?: (value: { + country: string; + phone: string; + extension?: string; + }) => void; +} + +const InternationalPhoneInput: React.FC = ({ + value = {}, + onChange, +}) => { + const { + country = 'CA', + phone = '', + extension = phoneExtensions['CA'], + } = value || {}; + + useEffect(() => { + triggerChange({ extension }); + }, []); + const triggerChange = ( + changedValue: Partial<{ + country: string; + phone: string; + extension?: string; + }>, + ) => { + if (onChange) { + onChange({ + country, + phone, + ...value, + ...changedValue, + }); + } + }; + + const onCountryChange = (newCountry: string) => { + triggerChange({ + country: newCountry, + extension: phoneExtensions[newCountry], + }); + }; + + const onPhoneChange: React.ChangeEventHandler = (e) => { + triggerChange({ phone: e.target.value }); + }; + + return ( + + + + + {/* 添加更多国家代码 */} + + } + value={phone} + onChange={onPhoneChange} + placeholder="请输入联系电话" + /> + ); +}; + +export default InternationalPhoneInput; diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 0000000..0360a09 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1,93 @@ +import { ProSchemaValueEnumObj } from '@ant-design/pro-components'; + +export const DEFAULT_NAME = 'YOONE'; + +export const PRODUCT_STATUS_ENUM: ProSchemaValueEnumObj = { + publish: { + text: '已发布', + status: 'success', + }, + draft: { + text: '草稿', + status: 'default', + }, + pending: { + text: '待审核', + status: 'warning', + }, + private: { + text: '私有', + status: 'warning', + }, + trash: { + text: '已删除', + status: 'error', + }, + 'auto-draft': { + text: '字段草稿', + status: 'default', + }, + future: { + text: '定时发布', + status: 'success', + }, + inherit: { + text: '继承状态', + status: 'default', + }, +}; + +export const Purchase_Order_STATUS_ENUM: ProSchemaValueEnumObj = { + draft: { + text: '草稿', + status: 'default', + }, + submitted: { + text: '已发货', + status: 'warning', + }, + received: { + text: '已到达', + status: 'success', + disabled: true, + }, +}; + +export const ORDER_STATUS_ENUM: ProSchemaValueEnumObj = { + pending: { + text: '待确认', + status: 'default', + }, + processing: { + text: '待发货', + status: 'success', + }, + completed: { + text: '已完成', + status: 'success', + }, + cancelled: { + text: '已取消', + status: 'error', + }, + refunded: { + text: '已退款', + status: 'warning', + }, + failed: { + text: '失败', + status: 'error', + }, + after_sale_pending: { + text: '售后处理中', + status: 'warning', + }, + pending_reshipment: { + text: '待补发', + status: 'warning', + }, + pending_refund: { + text: '待退款', + status: 'warning', + }, +}; diff --git a/src/models/global.ts b/src/models/global.ts new file mode 100644 index 0000000..708ccff --- /dev/null +++ b/src/models/global.ts @@ -0,0 +1,13 @@ +// 全局共享数据示例 +import { DEFAULT_NAME } from '@/constants'; +import { useState } from 'react'; + +const useUser = () => { + const [name, setName] = useState(DEFAULT_NAME); + return { + name, + setName, + }; +}; + +export default useUser; diff --git a/src/pages/Home/index.less b/src/pages/Home/index.less new file mode 100644 index 0000000..06fdb67 --- /dev/null +++ b/src/pages/Home/index.less @@ -0,0 +1,3 @@ +.container { + padding-top: 80px; +} diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx new file mode 100644 index 0000000..2b2cf42 --- /dev/null +++ b/src/pages/Home/index.tsx @@ -0,0 +1,14 @@ +import { PageContainer } from '@ant-design/pro-components'; +import { useModel } from '@umijs/max'; +import styles from './index.less'; + +const HomePage: React.FC = () => { + const { name } = useModel('global'); + return ( + +
+
+ ); +}; + +export default HomePage; diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx new file mode 100644 index 0000000..14bc2e3 --- /dev/null +++ b/src/pages/Login/index.tsx @@ -0,0 +1,116 @@ +import { usercontrollerGetuser, usercontrollerLogin } from '@/servers/api/user'; +import { LockOutlined, UserOutlined } from '@ant-design/icons'; +import { + LoginFormPage, + ProConfigProvider, + ProFormText, +} from '@ant-design/pro-components'; +import { history, useModel } from '@umijs/max'; +import { App, theme } from 'antd'; + +const Page = () => { + const { setInitialState } = useModel('@@initialState'); + const { token } = theme.useToken(); + const { message } = App.useApp(); + + const onFinish = async (values: { username: string; password: string }) => { + try { + const { data, success } = await usercontrollerLogin(values); + if (success) { + message.success('登录成功'); + localStorage.setItem('token', data?.token as string); + const { data: user } = await usercontrollerGetuser(); + setInitialState({ user }); + history.push('/'); + } + } catch { + message.error('登录失败'); + } + }; + return ( +
+ + + ), + }} + placeholder={'请输入用户名!'} + rules={[ + { + required: true, + message: '请输入用户名!', + }, + ]} + /> + + ), + }} + placeholder={'请输入密码!'} + rules={[ + { + required: true, + message: '请输入密码!', + }, + ]} + /> + {/*
+ + 自动登录 + + + 忘记密码 + +
*/} +
+
+ ); +}; + +export default () => { + return ( + + + + ); +}; diff --git a/src/pages/Logistics/Address/index.tsx b/src/pages/Logistics/Address/index.tsx new file mode 100644 index 0000000..375703b --- /dev/null +++ b/src/pages/Logistics/Address/index.tsx @@ -0,0 +1,405 @@ +import InternationalPhoneInput from '@/components/InternationalPhoneInput'; +import { + logisticscontrollerCreateshippingaddress, + logisticscontrollerDelshippingaddress, + logisticscontrollerGetshippingaddresslist, + logisticscontrollerUpdateshippingaddress, +} from '@/servers/api/logistics'; +import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormItem, + ProFormSelect, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Divider, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + + const columns: ProColumns[] = [ + { + title: '仓库点', + dataIndex: 'stockPointId', + hideInSearch: true, + valueType: 'select', + request: async () => { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + }, + { + title: '地区', + dataIndex: ['address', 'region'], + hideInSearch: true, + }, + { + title: '城市', + dataIndex: ['address', 'city'], + hideInSearch: true, + }, + { + title: '邮编', + dataIndex: ['address', 'postal_code'], + hideInSearch: true, + }, + { + title: '详细地址', + dataIndex: ['address', 'address_line_1'], + hideInSearch: true, + }, + { + title: '联系电话', + render: (_, record) => + `+${record.phone_number_extension} ${record.phone_number}`, + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + + + { + try { + const { success, message: errMsg } = + await logisticscontrollerDelshippingaddress({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + return ( + + []} + request={async () => { + const { data, success } = + await logisticscontrollerGetshippingaddresslist(); + if (success) { + return { + data: data, + }; + } + return { + data: [], + }; + }} + columns={columns} + /> + + ); +}; + +const region = { + AB: 'Alberta', + BC: 'British', + MB: 'Manitoba', + NB: 'New', + NL: 'Newfoundland', + NS: 'Nova', + ON: 'Ontario', + PE: 'Prince', + QC: 'Quebec', + SK: 'Saskatchewan', + NT: 'Northwest', + NU: 'Nunavut', + YT: 'Yukon', +}; +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + + 新建 + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + const { contact, ...params } = values; + try { + const { success, message: errMsg } = + await logisticscontrollerCreateshippingaddress({ + ...params, + phone_number: contact?.phone, + phone_number_extension: contact?.extension, + phone_number_country: contact?.country, + } as API.ShippingAddress); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + /> + + + + + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + value: API.ShippingAddress; +}> = ({ tableRef, value }) => { + const { message } = App.useApp(); + const { + id, + phone_number, + phone_number_country, + phone_number_extension, + ...initialValue + } = value; + return ( + + + 编辑 + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + const { contact, ...params } = values; + try { + const { success, message: errMsg } = + await logisticscontrollerUpdateshippingaddress( + { id: id as number }, + { + ...params, + phone_number: contact?.phone, + phone_number_extension: contact?.extension, + phone_number_country: contact?.country, + } as API.ShippingAddress, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + initialValues={{ + ...initialValue, + contact: { + phone: phone_number, + extension: phone_number_extension, + country: phone_number_country, + }, + }} + > + + { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + /> + + + + + + + ); +}; + +export default ListPage; diff --git a/src/pages/Logistics/List/index.tsx b/src/pages/Logistics/List/index.tsx new file mode 100644 index 0000000..b2d6176 --- /dev/null +++ b/src/pages/Logistics/List/index.tsx @@ -0,0 +1,146 @@ +import { logisticscontrollerGetlist } from '@/servers/api/logistics'; +import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; +import { formatShipmentState } from '@/utils/format'; +import { printPDF } from '@/utils/util'; +import { CopyOutlined } from '@ant-design/icons'; +import { + ActionType, + PageContainer, + ProColumns, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button } from 'antd'; +import { useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + const [selectedRows, setSelectedRows] = useState([]); + + const columns: ProColumns[] = [ + { + title: '服务商', + dataIndex: 'tracking_provider', + hideInSearch: true, + }, + { + title: '仓库', + dataIndex: 'stockPointId', + hideInTable: true, + valueType: 'select', + request: async () => { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + }, + { + title: '快递单号', + dataIndex: 'primary_tracking_number', + render(_, record) { + return ( + <> + {record.primary_tracking_number} + { + try { + await navigator.clipboard.writeText(record.tracking_url); + message.success('复制成功!'); + } catch (err) { + message.error('复制失败!'); + } + }} + /> + + ); + }, + }, + { + title: '状态', + dataIndex: 'state', + hideInSearch: true, + render(_, record) { + return formatShipmentState(record.state); + }, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + hideInSearch: true, + valueType: 'dateTime', + }, + { + title: '操作', + dataIndex: 'operation', + hideInSearch: true, + render(_, record) { + if (!record?.labels?.length) return null; + return ( + + ); + }, + }, + ]; + + const handleBatchPrint = async () => { + if (selectedRows.length === 0) { + message.warning('请选择要打印的项'); + return; + } + await printPDF( + selectedRows.map((row) => row.labels[row.labels.length - 1].url), + ); + + setSelectedRows([]); + }; + return ( + + { + console.log(values); + const { data, success } = await logisticscontrollerGetlist({ + params: values, + }); + if (success) { + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + return { + data: [], + }; + }} + // rowSelection={{ + // selectedRowKeys: selectedRows.map((row) => row.id), + // onChange: (_, selectedRows) => setSelectedRows(selectedRows), + // }} + columns={columns} + tableAlertOptionRender={() => { + return ( + + ); + }} + /> + + ); +}; +export default ListPage; diff --git a/src/pages/Logistics/Services/index.tsx b/src/pages/Logistics/Services/index.tsx new file mode 100644 index 0000000..79f1594 --- /dev/null +++ b/src/pages/Logistics/Services/index.tsx @@ -0,0 +1,110 @@ +import { + logisticscontrollerGetservicelist, + logisticscontrollerSyncservices, + logisticscontrollerToggleactive, +} from '@/servers/api/logistics'; +import { + ActionType, + PageContainer, + ProColumns, + ProFormSwitch, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button } from 'antd'; +import { useRef } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + + const columns: ProColumns[] = [ + { + title: '服务商 ID', + dataIndex: 'id', + hideInSearch: true, + }, + { + title: '运营商名称', + dataIndex: 'carrier_name', + }, + { + title: '服务商名称', + dataIndex: 'service_name', + hideInSearch: true, + }, + { + title: '启用', + dataIndex: 'isActive', + valueType: 'switch', + render(_, record) { + return ( + { + try { + const { success } = await logisticscontrollerToggleactive({ + id: record.id, + isActive: value, + }); + if (!success) { + throw new Error('启动失败'); + } + actionRef.current?.reload(); + } catch (e: any) { + message.error(e?.message || '启动失败'); + } + }, + }} + /> + ); + }, + }, + ]; + return ( + + [ + , + ]} + request={async (values) => { + console.log(values); + const { data, success } = await logisticscontrollerGetservicelist( + values, + ); + if (success) { + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + return { + data: [], + }; + }} + columns={columns} + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Order/List/index.tsx b/src/pages/Order/List/index.tsx new file mode 100644 index 0000000..45d85df --- /dev/null +++ b/src/pages/Order/List/index.tsx @@ -0,0 +1,2051 @@ +import InternationalPhoneInput from '@/components/InternationalPhoneInput'; +import { ORDER_STATUS_ENUM } from '@/constants'; +import { + logisticscontrollerCreateshipment, + logisticscontrollerDelshipment, + logisticscontrollerGetpaymentmethods, + logisticscontrollerGetratelist, + logisticscontrollerGetshippingaddresslist, +} from '@/servers/api/logistics'; +import { + ordercontrollerCancelorder, + ordercontrollerChangestatus, + ordercontrollerCompletedorder, + ordercontrollerCreatenote, + ordercontrollerCreateorder, + ordercontrollerGetorderbynumber, + ordercontrollerGetorderdetail, + ordercontrollerGetorders, + ordercontrollerRefundorder, + ordercontrollerSyncorder, + ordercontrollerSyncorderbyid, +} from '@/servers/api/order'; +import { productcontrollerSearchproducts } from '@/servers/api/product'; +import { sitecontrollerAll } from '@/servers/api/site'; +import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; +import { formatShipmentState, formatSource } from '@/utils/format'; +import { + CodeSandboxOutlined, + CopyOutlined, + DeleteFilled, + DownOutlined, + FileDoneOutlined, + SyncOutlined, + TagsOutlined, +} from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + ModalForm, + PageContainer, + ProColumns, + ProDescriptions, + ProForm, + ProFormDatePicker, + ProFormDependency, + ProFormDigit, + ProFormInstance, + ProFormItem, + ProFormList, + ProFormRadio, + ProFormSelect, + ProFormText, + ProFormTextArea, + ProTable, +} from '@ant-design/pro-components'; +import { + App, + Button, + Card, + Col, + Divider, + Drawer, + Dropdown, + Empty, + Popconfirm, + Radio, + Row, + Space, + Tabs, + TabsProps, +} from 'antd'; +import dayjs from 'dayjs'; +import React, { useMemo, useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const [activeKey, setActiveKey] = useState('all'); + const [count, setCount] = useState([]); + const tabs: TabsProps['items'] = useMemo(() => { + const total = count.reduce((acc, cur) => acc + Number(cur.count), 0); + const tabs = [ + { + key: 'pending', + label: '待确认', + }, + { + key: 'processing', + label: '待发货', + }, + { + key: 'completed', + label: '已完成', + }, + { + key: 'cancelled', + label: '已取消', + }, + { + key: 'refunded', + label: '已退款', + }, + { + key: 'failed', + label: '失败', + }, + { + key: 'after_sale_pending', + label: '售后处理中', + }, + { + key: 'pending_reshipment', + label: '待补发', + }, + // { + // key: 'pending_refund', + // label: '待退款', + // }, + ].map((v) => { + const number = count.find((el) => el.status === v.key)?.count || '0'; + return { + label: `${v.label}(${number})`, + key: v.key, + }; + }); + + return [ + { + key: 'all', + label: `全部(${total})`, + }, + ...tabs, + ]; + }, [count]); + const { message } = App.useApp(); + + const columns: ProColumns[] = [ + { + title: 'ID', + dataIndex: 'id', + hideInSearch: true, + }, + { + title: '日期', + dataIndex: 'date', + hideInTable: true, + valueType: 'dateRange', + }, + { + title: '订单号', + dataIndex: 'externalOrderId', + }, + { + title: '站点', + dataIndex: 'siteId', + valueType: 'select', + request: async () => { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }, + }, + { + title: '订单包含', + dataIndex: 'keyword', + hideInTable: true, + }, + { + title: '订单日期', + dataIndex: 'date_created', + hideInSearch: true, + valueType: 'dateTime', + }, + { + title: '金额', + dataIndex: 'total', + hideInSearch: true, + }, + { + title: '总订单数', + dataIndex: 'order_count', + hideInSearch: true, + }, + { + title: '总订单金额', + dataIndex: 'total_spent', + hideInSearch: true, + }, + { + title: '客户邮箱', + dataIndex: 'customer_email', + }, + { + title: '州', + hideInSearch: true, + render: (_, record) => record.shipping?.state || record.billing?.state, + }, + { + title: '状态', + dataIndex: 'orderStatus', + hideInSearch: true, + valueType: 'select', + valueEnum: ORDER_STATUS_ENUM, + }, + { + title: '物流', + dataIndex: 'shipmentList', + hideInSearch: true, + render: (_, record) => { + return ( +
+ {record?.shipmentList?.map((item) => { + if (!item) return; + return ( +
+ {item.tracking_provider}:{item.primary_tracking_number} ( + {formatShipmentState(item.state)}) +
+ ); + })} +
+ ); + }, + }, + { + title: 'IP', + dataIndex: 'customer_ip_address', + hideInSearch: true, + }, + { + title: '设备', + dataIndex: 'device_type', + hideInSearch: true, + }, + { + title: '来源', + hideInSearch: true, + render: (_, record) => + formatSource(record.source_type, record.utm_source), + }, + { + title: '客户备注', + dataIndex: 'customer_note', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + fixed: 'right', + width: '200', + render: (_, record) => { + return ( + <> + {['processing', 'pending_reshipment'].includes( + record.orderStatus, + ) ? ( + <> + + + + ) : ( + <> + )} + + + { + try { + const { success, message: errMsg } = + await ordercontrollerSyncorderbyid({ + siteId: record.siteId as string, + orderId: record.externalOrderId as string, + }); + if (!success) { + throw new Error(errMsg); + } + message.success('同步成功'); + actionRef.current?.reload(); + } catch (error) { + message.error(error?.message || '同步失败'); + } + }} + > + 同步订单 + + ), + style: { + display: [ + 'after_sale_pending', + 'pending_reshipment', + ].includes(record.orderStatus) + ? 'none' + : 'block', + }, + }, + { + key: 'note', + label: , + }, + { + key: 'cancel', + label: ( + { + try { + const { success, message: errMsg } = + await ordercontrollerChangestatus( + { + id: record.id, + }, + { + status: 'after_sale_pending', + }, + ); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + ), + style: { + display: [ + 'processing', + 'pending_reshipment', + 'completed', + 'pending_refund', + ].includes(record.orderStatus) + ? 'block' + : 'none', + }, + }, + ], + }} + > + e.preventDefault()}> + + 更多 + + + + + + ); + }, + }, + ]; + return ( + + + [ + , + , + ]} + request={async ({ date, ...param }) => { + if (param.status === 'all') { + delete param.status; + } + if (date) { + const [startDate, endDate] = date; + param.startDate = `${startDate} 00:00:00`; + param.endDate = `${endDate} 23:59:59`; + } + const { data, success } = await ordercontrollerGetorders(param); + if (success) { + setCount(data?.count || []); + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + return { + data: [], + }; + }} + columns={columns} + /> + + ); +}; + +const SyncForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="同步订单" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = await ordercontrollerSyncorder( + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('同步成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + /> + + + ); +}; + +const Detail: React.FC<{ + tableRef: React.MutableRefObject; + orderId: number; + record: API.Order; +}> = ({ tableRef, orderId, record }) => { + const [visiable, setVisiable] = useState(false); + const { message } = App.useApp(); + const ref = useRef(); + + const initRequest = async () => { + const { data, success }: API.OrderDetailRes = + await ordercontrollerGetorderdetail({ + orderId, + }); + if (!success || !data) return { data: {} }; + data.sales = data.sales?.reduce( + (acc: API.OrderSale[], cur: API.OrderSale) => { + let idx = acc.findIndex((v: any) => v.productId === cur.productId); + if (idx === -1) { + acc.push(cur); + } else { + acc[idx].quantity += cur.quantity; + } + return acc; + }, + [], + ); + return { + data, + }; + }; + + return ( + <> + + setVisiable(false)} + footer={[ + , + ...(['after_sale_pending', 'pending_reshipment'].includes( + record.orderStatus, + ) + ? [] + : [ + , + , + ]), + // ...(['processing', 'pending_reshipment'].includes(record.orderStatus) + // ? [ + // , + // , + // ] + // : []), + ...([ + 'processing', + 'pending_reshipment', + 'completed', + 'pending_refund', + ].includes(record.orderStatus) + ? [ + , + { + try { + const { success, message: errMsg } = + await ordercontrollerChangestatus( + { + id: record.id, + }, + { + status: 'after_sale_pending', + }, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + ] + : []), + ...(record.orderStatus === 'after_sale_pending' + ? [ + , + { + try { + const { success, message: errMsg } = + await ordercontrollerCancelorder({ + id: record.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerRefundorder({ + id: record.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerCompletedorder({ + id: record.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + , + { + try { + const { success, message: errMsg } = + await ordercontrollerChangestatus( + { + id: record.id, + }, + { + status: 'pending_reshipment', + }, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + , + ] + : []), + ]} + > + + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + /> + + + + + + + + + formatSource(record.source_type, record.utm_source) + } + /> + + + + { + return ( +
+
+ company: + + {record?.shipping?.company || + record?.billing?.company || + '-'} + +
+
+ first_name: + + {record?.shipping?.first_name || + record?.billing?.first_name || + '-'} + +
+
+ last_name: + + {record?.shipping?.last_name || + record?.billing?.last_name || + '-'} + +
+
+ country: + + {record?.shipping?.country || + record?.billing?.country || + '-'} + +
+
+ state: + + {record?.shipping?.state || record?.billing?.state || '-'} + +
+
+ city: + + {record?.shipping?.city || record?.billing?.city || '-'} + +
+
+ postcode: + + {record?.shipping?.postcode || + record?.billing?.postcode || + '-'} + +
+
+ phone: + + {record?.shipping?.phone || record?.billing?.phone || '-'} + +
+
+ address_1: + + {record?.shipping?.address_1 || + record?.billing?.address_1 || + '-'} + +
+
+ ); + }} + /> + { + return ( +
    + {record?.items?.map((item: any) => ( +
  • + {item.name}:{item.quantity} +
  • + ))} +
+ ); + }} + /> + { + return ( +
    + {record?.sales?.map((item: any) => ( +
  • + {item.name}:{item.quantity} +
  • + ))} +
+ ); + }} + /> + { + if (!record.notes || record.notes.length === 0) + return ; + return ( +
+ {record.notes.map((note: any) => ( +
+
+ {note.username} + {note.createdAt} +
+
{note.content}
+
+ ))} +
+ ); + }} + /> + { + if (!record.shipment || record.shipment.length === 0) { + return ; + } + return ( +
+ {record.shipment.map((v) => ( + + {v.tracking_provider} + {v.primary_tracking_number} + { + try { + await navigator.clipboard.writeText( + v.tracking_url, + ); + message.success('复制成功!'); + } catch (err) { + message.error('复制失败!'); + } + }} + /> + + } + actions={ + v.state === 'waiting-for-scheduling' || + v.state === 'waiting-for-transit' + ? [ + { + try { + const { success, message: errMsg } = + await logisticscontrollerDelshipment({ + id: v.id, + }); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + initRequest(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + 取消运单 + , + ] + : [] + } + > +
订单号: {v?.orderIds?.join(',')}
+ {v?.items?.map((item) => ( +
+ {item.name}: {item.quantity} +
+ ))} +
+ ))} +
+ ); + }} + /> +
+
+ + ); +}; + +const OrderNote: React.FC<{ + id: number; + descRef?: React.MutableRefObject; +}> = ({ id, descRef }) => { + const { message } = App.useApp(); + return ( + + + 备注 + + } + onFinish={async (values: any) => { + try { + const { success, message: errMsg } = await ordercontrollerCreatenote({ + ...values, + orderId: id, + }); + if (!success) { + throw new Error(errMsg); + } + descRef?.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + ); +}; + +const region = { + AB: 'Alberta', + BC: 'British', + MB: 'Manitoba', + NB: 'New', + NL: 'Newfoundland', + NS: 'Nova', + ON: 'Ontario', + PE: 'Prince', + QC: 'Quebec', + SK: 'Saskatchewan', + NT: 'Northwest', + NU: 'Nunavut', + YT: 'Yukon', +}; +const Shipping: React.FC<{ + id: number; + tableRef?: React.MutableRefObject; + descRef?: React.MutableRefObject; + reShipping?: boolean; +}> = ({ id, tableRef, descRef, reShipping = false }) => { + const [options, setOptions] = useState([]); + const formRef = useRef(); + + const [rates, setRates] = useState([]); + const [ratesLoading, setRatesLoading] = useState(false); + const { message } = App.useApp(); + const [serviceType, setServiceType] = useState(''); + + return ( + + + 创建运单 + + } + request={async () => { + const { data, success }: API.OrderDetailRes = + await ordercontrollerGetorderdetail({ + orderId: id, + }); + if (!success || !data) return {}; + data.sales = data.sales?.reduce( + (acc: API.OrderSale[], cur: API.OrderSale) => { + let idx = acc.findIndex((v: any) => v.productId === cur.productId); + if (idx === -1) { + acc.push(cur); + } else { + acc[idx].quantity += cur.quantity; + } + return acc; + }, + [], + ); + setOptions( + data.sales?.map((item) => ({ + label: item.name, + value: item.sku, + })) || [], + ); + if (reShipping) data.sales = [{}]; + let shipmentInfo = localStorage.getItem('shipmentInfo'); + if (shipmentInfo) shipmentInfo = JSON.parse(shipmentInfo); + return { + ...data, + payment_method_id: shipmentInfo?.payment_method_id, + stockPointId: shipmentInfo?.stockPointId, + details: { + destination: { + name: data?.shipping?.company || data?.billing?.company || ' ', + address: { + address_line_1: + data?.shipping?.address_1 || data?.billing?.address_1, + city: data?.shipping?.city || data?.billing?.city, + region: data?.shipping?.state || data?.billing?.state, + postal_code: + data?.shipping?.postcode || data?.billing?.postcode, + }, + contact_name: + data?.shipping?.first_name || data?.shipping?.last_name + ? `${data?.shipping?.first_name} ${data?.shipping?.last_name}` + : `${data?.billing?.first_name} ${data?.billing?.last_name}`, + phone_number: { + phone: data?.shipping?.phone || data?.billing?.phone, + }, + email_addresses: data?.shipping?.email || data?.billing?.email, + signature_requirement: 'not-required', + }, + origin: { + name: data?.siteName, + email_addresses: data?.email, + contact_name: data?.siteName, + phone_number: shipmentInfo?.phone_number, + address: { + region: shipmentInfo?.region, + city: shipmentInfo?.city, + postal_code: shipmentInfo?.postal_code, + address_line_1: shipmentInfo?.address_line_1, + }, + }, + packaging_type: 'package', + expected_ship_date: dayjs(), + packaging_properties: { + packages: [ + { + measurements: { + weight: { + unit: 'lb', + value: 1, + }, + cuboid: { + unit: 'in', + l: 6, + w: 4, + h: 4, + }, + }, + description: 'food', + }, + ], + }, + }, + }; + }} + onFinish={async ({ customer_note, notes, items, details, ...data }) => { + details.origin.email_addresses = + details.origin.email_addresses.split(','); + details.destination.email_addresses = + details.destination.email_addresses.split(','); + details.destination.phone_number.number = + details.destination.phone_number.phone; + details.origin.phone_number.number = details.origin.phone_number.phone; + try { + const { success, message: errMsg } = + await logisticscontrollerCreateshipment( + { orderId: id }, + { + service_type: serviceType, + details, + ...data, + }, + ); + if (!success) throw new Error(errMsg); + message.success('创建成功'); + tableRef?.current?.reload(); + descRef?.current?.reload(); + + localStorage.setItem( + 'shipmentInfo', + JSON.stringify({ + payment_method_id: data.payment_method_id, + stockPointId: data.stockPointId, + region: details.origin.address.region, + city: details.origin.address.city, + postal_code: details.origin.address.postal_code, + address_line_1: details.origin.address.address_line_1, + phone_number: details.origin.phone_number, + }), + ); + return true; + } catch (error) { + message.error(error?.message || '创建失败'); + } + }} + onFinishFailed={() => { + const element = document.querySelector('.ant-form-item-explain-error'); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + }} + > + + []} + readonly + > + + + + + { + if (!number) return []; + const { data, success } = await ordercontrollerGetorderbynumber({ + number, + }); + if (success) { + return data.map((v) => ({ + label: `${v.siteName} ${v.externalOrderId}`, + value: v.id, + })); + } + return []; + }} + /> + + + { + const { data, success } = + await logisticscontrollerGetpaymentmethods(); + if (success) { + return data.map((v) => ({ + label: v.label, + value: v.id, + })); + } + return []; + }} + /> + + + + + []} + > + + + + + + + + + // value && value.length > 0 + // ? Promise.resolve() + // : Promise.reject('至少需要一个商品'), + // }, + // ]} + > + + { + if (!keyWords || keyWords.length < 3) return options; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item?.name, + value: item?.sku, + }; + }) || options + ); + } catch (error) { + return options; + } + }} + name="sku" + label="产品" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + /> + + + + + + + + { + formRef?.current?.setFieldsValue({ + stockPointId, + details: { + origin: { + address, + phone_number: { + phone: phone_number, + extension: phone_number_extension, + }, + }, + }, + }); + }} + /> + } + > + { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + /> + + + + + + + + + + + { + return current && current < dayjs().startOf('day'); + }, + }} + transform={(value) => { + return { + details: { + expected_ship_date: { + year: dayjs(value).year(), + month: dayjs(value).month() + 1, + day: dayjs(value).date(), + }, + }, + }; + }} + /> + + + {({ details: { packaging_type } }) => { + if (packaging_type === 'package') { + return ( + + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少选择一个包裹'), + }, + ]} + > + {(f, idx, action) => { + return ( + + + { + action.setCurrentRowData({ + measurements: { + weight: { + unit: 'lb', + value: 1, + }, + cuboid: { + unit: 'in', + l: 6, + w: 4, + h: 4, + }, + }, + }); + }} + > + 尺寸1 + + { + action.setCurrentRowData({ + measurements: { + weight: { + unit: 'lb', + value: 5, + }, + cuboid: { + unit: 'in', + l: 8, + w: 6, + h: 6, + }, + }, + }); + }} + > + 尺寸2 + + { + action.setCurrentRowData({ + measurements: { + weight: { + unit: 'lb', + value: 5, + }, + cuboid: { + unit: 'in', + l: 12, + w: 8, + h: 6, + }, + }, + }); + }} + > + 尺寸3 + + + + ); + }} + + + + + + + + + + + + + ); + } + if (packaging_type === 'courier-pak') { + return ( + + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少选择一个'), + }, + ]} + > + + + + + + + ); + } + }} + + + { + console.log(e.target.value); + const type = rates.find( + (v) => v.service_id === e.target.value, + )?.type; + setServiceType(type); + }, + }} + options={rates + ?.sort((a, b) => Number(a?.total?.value) - Number(b?.total?.value)) + ?.map((rate) => { + return { + label: `${rate.carrier_name} ${rate.service_name} : ${ + rate?.total?.value / 100 + }${rate?.total?.currency}(${rate.transit_time_days}天)`, + value: rate.service_id, + }; + })} + /> + + ); +}; + +const CreateOrder: React.FC<{ + tableRef?: React.MutableRefObject; +}> = ({ tableRef }) => { + const formRef = useRef(); + const { message } = App.useApp(); + + return ( + + + 创建订单 + + } + params={{ + source_type: 'admin', + }} + onFinish={async ({ items, details, ...data }) => { + try { + const { success, message: errMsg } = await ordercontrollerCreateorder( + { + ...data, + customer_email: data?.billing?.email, + }, + ); + if (!success) throw new Error(errMsg); + message.success('创建成功'); + tableRef?.current?.reload(); + + return true; + } catch (error) { + message.error(error?.message || '创建失败'); + } + }} + onFinishFailed={() => { + const element = document.querySelector('.ant-form-item-explain-error'); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + }} + > + + + { + if (!keyWords || keyWords.length < 3) return options; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item?.name, + value: item?.sku, + }; + }) || options + ); + } catch (error) { + return options; + } + }} + name="sku" + label="产品" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + /> + + + + + + + + {/* */} + + ); +}; + +const AddressPicker: React.FC<{ + value?: any; + onChange?: (value: any) => void; +}> = ({ onChange, value }) => { + const [selectedRow, setSelectedRow] = useState(null); + const { message } = App.useApp(); + const columns: ProColumns[] = [ + { + title: '仓库点', + dataIndex: 'stockPointId', + hideInSearch: true, + valueType: 'select', + request: async () => { + const { data = [] } = await stockcontrollerGetallstockpoints(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }, + }, + { + title: '地区', + dataIndex: ['address', 'region'], + hideInSearch: true, + }, + { + title: '城市', + dataIndex: ['address', 'city'], + hideInSearch: true, + }, + { + title: '邮编', + dataIndex: ['address', 'postal_code'], + hideInSearch: true, + }, + { + title: '详细地址', + dataIndex: ['address', 'address_line_1'], + hideInSearch: true, + }, + { + title: '联系电话', + render: (_, record) => + `+${record.phone_number_extension} ${record.phone_number}`, + hideInSearch: true, + }, + ]; + return ( + 选择地址} + modalProps={{ destroyOnClose: true }} + onFinish={async () => { + if (!selectedRow) { + message.error('请选择地址'); + return false; + } + if (onChange) onChange(selectedRow); + return true; + }} + > + { + const { data, success } = + await logisticscontrollerGetshippingaddresslist(); + if (success) { + return { + data: data, + }; + } + return { + data: [], + }; + }} + columns={columns} + search={false} + rowSelection={{ + type: 'radio', + onChange: (_, selectedRows) => { + setSelectedRow(selectedRows[0]); + }, + }} + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Organiza/User/index.tsx b/src/pages/Organiza/User/index.tsx new file mode 100644 index 0000000..8a13c3d --- /dev/null +++ b/src/pages/Organiza/User/index.tsx @@ -0,0 +1,125 @@ +import { + usercontrollerAdduser, + usercontrollerListusers, +} from '@/servers/api/user'; +import { PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button } from 'antd'; +import { useRef } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '用户名', + dataIndex: 'username', + }, + { + title: '激活', + dataIndex: 'isActive', + valueEnum: { + true: { + text: '是', + }, + false: { + text: '否', + }, + }, + }, + { + title: '超管', + dataIndex: 'isSuper', + valueEnum: { + true: { + text: '是', + }, + false: { + text: '否', + }, + }, + }, + ]; + return ( + + { + const { data, success } = await usercontrollerListusers(params); + + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + toolBarRender={() => []} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + + 新建 + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = await usercontrollerAdduser( + values, + ); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + + ); +}; + +export default ListPage; diff --git a/src/pages/Product/Category/index.tsx b/src/pages/Product/Category/index.tsx new file mode 100644 index 0000000..38f04b7 --- /dev/null +++ b/src/pages/Product/Category/index.tsx @@ -0,0 +1,210 @@ +import { + productcontrollerCreatecategory, + productcontrollerDeletecategory, + productcontrollerGetcategories, + productcontrollerUpdatecategory, +} from '@/servers/api/product'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const List: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + tip: '名称是唯一的 key', + formItemProps: { + rules: [ + { + required: true, + message: '名称为必填项', + }, + ], + }, + }, + { + title: '标识', + dataIndex: 'unique_key', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + {/* + */} + { + try { + const { success, message: errMsg } = + await productcontrollerDeletecategory({ id: record.id }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + toolBarRender={() => []} + request={async (params) => { + const { data, success } = await productcontrollerGetcategories( + params, + ); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="新建" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerCreatecategory(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.Category; +}> = ({ tableRef, values: initialValues }) => { + const { message } = App.useApp(); + return ( + + title="编辑" + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerUpdatecategory( + { id: initialValues.id }, + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + ); +}; + +export default List; diff --git a/src/pages/Product/Flavors/index.tsx b/src/pages/Product/Flavors/index.tsx new file mode 100644 index 0000000..40c8f7e --- /dev/null +++ b/src/pages/Product/Flavors/index.tsx @@ -0,0 +1,208 @@ +import { + productcontrollerCreateflavors, + productcontrollerDeleteflavors, + productcontrollerGetflavors, + productcontrollerUpdateflavors, +} from '@/servers/api/product'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const List: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + tip: '名称是唯一的 key', + formItemProps: { + rules: [ + { + required: true, + message: '名称为必填项', + }, + ], + }, + }, + { + title: '标识', + dataIndex: 'unique_key', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + {/* + */} + { + try { + const { success, message: errMsg } = + await productcontrollerDeleteflavors({ id: record.id }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + toolBarRender={() => []} + request={async (params) => { + const { data, success } = await productcontrollerGetflavors(params); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="新建" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerCreateflavors(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.Category; +}> = ({ tableRef, values: initialValues }) => { + const { message } = App.useApp(); + return ( + + title="编辑" + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerUpdateflavors( + { id: initialValues.id }, + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + ); +}; + +export default List; diff --git a/src/pages/Product/List/index.tsx b/src/pages/Product/List/index.tsx new file mode 100644 index 0000000..6399b03 --- /dev/null +++ b/src/pages/Product/List/index.tsx @@ -0,0 +1,232 @@ +import { + productcontrollerCreateproduct, + productcontrollerDeleteproduct, + productcontrollerGetcategorieall, + productcontrollerGetflavorsall, + productcontrollerGetproductlist, + productcontrollerGetstrengthall, +} from '@/servers/api/product'; +import { PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormSelect, + ProFormText, + ProFormTextArea, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Popconfirm } from 'antd'; +import React, { useRef } from 'react'; + +const List: React.FC = () => { + const actionRef = useRef(); + + const { message } = App.useApp(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + }, + { + title: '产品描述', + dataIndex: 'description', + hideInSearch: true, + }, + { + title: '产品分类', + dataIndex: 'categoryName', + }, + { + title: '强度', + dataIndex: 'strengthName', + }, + { + title: '口味', + dataIndex: 'flavorsName', + }, + { + title: '湿度', + dataIndex: 'humidity', + }, + { + title: 'sku', + dataIndex: 'sku', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + { + try { + const { success, message: errMsg } = + await productcontrollerDeleteproduct({ id: record.id }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + toolBarRender={() => []} + request={async (params) => { + const { data, success } = await productcontrollerGetproductlist( + params, + ); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + rowSelection={{ + onChange: (_, selectedRows) => setSelectedRows(selectedRows), + }} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="新建" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerCreateproduct(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + { + const { data = [] } = await productcontrollerGetcategorieall(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + rules={[{ required: true, message: '请选择产品分类' }]} + /> + { + const { data = [] } = await productcontrollerGetstrengthall(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + rules={[{ required: true, message: '请选择强度' }]} + /> + { + const { data = [] } = await productcontrollerGetflavorsall(); + return data.map((item) => ({ + label: item.name, + value: item.id, + })); + }} + rules={[{ required: true, message: '请选择口味' }]} + /> + + + + ); +}; + +export default List; diff --git a/src/pages/Product/Strength/index.tsx b/src/pages/Product/Strength/index.tsx new file mode 100644 index 0000000..d7eb539 --- /dev/null +++ b/src/pages/Product/Strength/index.tsx @@ -0,0 +1,206 @@ +import { + productcontrollerCreatestrength, + productcontrollerDeletestrength, + productcontrollerGetstrength, +} from '@/servers/api/product'; +import { PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const List: React.FC = () => { + const actionRef = useRef(); + const { message } = App.useApp(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + tip: '名称是唯一的 key', + formItemProps: { + rules: [ + { + required: true, + message: '名称为必填项', + }, + ], + }, + }, + { + title: '标识', + dataIndex: 'unique_key', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + {/* + */} + { + try { + const { success, message: errMsg } = + await productcontrollerDeletestrength({ id: record.id }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + toolBarRender={() => []} + request={async (params) => { + const { data, success } = await productcontrollerGetstrength(params); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="新建" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await productcontrollerCreatestrength(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ); +}; + +// const UpdateForm: React.FC<{ +// tableRef: React.MutableRefObject; +// values: API.Category; +// }> = ({ tableRef, values: initialValues }) => { +// const { message } = App.useApp(); +// return ( +// +// title="编辑" +// initialValues={initialValues} +// trigger={ +// +// } +// autoFocusFirstInput +// drawerProps={{ +// destroyOnClose: true, +// }} +// onFinish={async (values) => { +// try { +// const { success, message: errMsg } = +// await productcontrollerUpdatestrength( +// { id: initialValues.id }, +// values, +// ); +// if (!success) { +// throw new Error(errMsg); +// } +// message.success('提交成功'); +// tableRef.current?.reload(); +// return true; +// } catch (error: any) { +// message.error(error.message); +// } +// }} +// > +// +// +// +// +// ); +// }; + +export default List; diff --git a/src/pages/Product/WpList/index.tsx b/src/pages/Product/WpList/index.tsx new file mode 100644 index 0000000..c57bb13 --- /dev/null +++ b/src/pages/Product/WpList/index.tsx @@ -0,0 +1,540 @@ +import { PRODUCT_STATUS_ENUM } from '@/constants'; +import { + productcontrollerProductbysku, + productcontrollerSearchproducts, +} from '@/servers/api/product'; +import { sitecontrollerAll } from '@/servers/api/site'; +import { + wpproductcontrollerGetwpproducts, + wpproductcontrollerSetconstitution, + wpproductcontrollerSyncproducts, + wpproductcontrollerUpdateproduct, + wpproductcontrollerUpdatevariation, +} from '@/servers/api/wpProduct'; +import { EditOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormDigit, + ProFormList, + ProFormSelect, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Divider, Form } from 'antd'; +import { useRef } from 'react'; + +const List: React.FC = () => { + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + }, + { + title: '站点', + dataIndex: 'siteId', + valueType: 'select', + request: async () => { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }, + }, + { + title: 'sku', + dataIndex: 'sku', + hideInSearch: true, + }, + { + title: '产品状态', + dataIndex: 'status', + valueType: 'select', + valueEnum: PRODUCT_STATUS_ENUM, + }, + { + title: '常规价格', + dataIndex: 'regular_price', + hideInSearch: true, + }, + { + title: '销售价格', + dataIndex: 'sale_price', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + + {record.type === 'simple' && record.sku ? ( + <> + + + + ) : ( + <> + )} + + ), + }, + ]; + const varColumns: ProColumns[] = [ + { + title: '变体名', + dataIndex: 'name', + }, + { + title: 'sku', + dataIndex: 'sku', + hideInSearch: true, + }, + { + title: '常规价格', + dataIndex: 'regular_price', + hideInSearch: true, + }, + { + title: '销售价格', + dataIndex: 'sale_price', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + + {record.sku ? ( + <> + + + + ) : ( + <> + )} + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + request={async (params) => { + const { data, success } = await wpproductcontrollerGetwpproducts( + params, + ); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + toolBarRender={() => []} + expandable={{ + rowExpandable: (record) => record.type === 'variable', + expandedRowRender: (record) => ( + + rowKey="id" + dataSource={record.variations} + pagination={false} + search={false} + options={false} + columns={varColumns} + /> + ), + }} + /> + + ); +}; + +const SyncForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="同步产品" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await wpproductcontrollerSyncproducts(values); + if (!success) { + throw new Error(errMsg); + } + message.success('同步成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + /> + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.WpProductDTO; +}> = ({ tableRef, values: initialValues }) => { + const { message } = App.useApp(); + return ( + + title="编辑产品" + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + const { siteId, ...params } = values; + try { + const { success, message: errMsg } = + await wpproductcontrollerUpdateproduct( + { + productId: initialValues.externalProductId, + siteId, + }, + params, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + name="siteId" + disabled + /> + + {initialValues.type === 'simple' ? ( + <> + + + + ) : ( + <> + )} + + + ); +}; + +const UpdateVaritation: React.FC<{ + tableRef: React.MutableRefObject; + values: API.VariationDTO; +}> = ({ tableRef, values: initialValues }) => { + const { message } = App.useApp(); + return ( + + title="编辑变体" + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + const { ...params } = values; + try { + const { success, message: errMsg } = + await wpproductcontrollerUpdatevariation( + { + siteId: initialValues.siteId, + productId: initialValues.externalProductId, + variationId: initialValues.externalVariationId, + }, + params, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + + + + ); +}; + +const SetComponent: React.FC<{ + tableRef: React.MutableRefObject; + values: API.VariationDTO | API.WpProductDTO; + isProduct: boolean; +}> = ({ tableRef, values: { id, constitution, name }, isProduct = false }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + + const fetchInitialValues = async () => { + const initData = await Promise.all( + constitution?.map?.(async (item) => { + const { data } = await productcontrollerProductbysku({ + sku: item.sku as string, + }); + return { + quantity: item.quantity, + sku: { + label: data?.name, + value: item.sku, + }, + }; + }) || [], + ); + form.setFieldsValue({ + constitution: initData, + }); + }; + + return ( + + title={name} + form={form} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async ({ constitution }) => { + try { + const { success, message: errMsg } = + await wpproductcontrollerSetconstitution( + { + id, + }, + { + isProduct, + constitution, + }, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + onOpenChange={(visiable) => { + if (visiable) fetchInitialValues(); + }} + > + + + name="constitution" + rules={[ + { + required: true, + message: '至少需要一个商品', + validator: (_, value) => + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增' }} + > + {(fields, idx, { remove }) => ( +
+ { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + const arr = + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || []; + return arr; + } catch (error) { + console.log(error); + return []; + } + }} + name="sku" + label="产品" + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + /> + + +
+ )} + +
+ + ); +}; + +export default List; diff --git a/src/pages/Statistics/Customer/index.tsx b/src/pages/Statistics/Customer/index.tsx new file mode 100644 index 0000000..c47680b --- /dev/null +++ b/src/pages/Statistics/Customer/index.tsx @@ -0,0 +1,236 @@ +import { statisticscontrollerGetcustomerorders } from '@/servers/api/statistics'; +import { + PageContainer, + ProDescriptions, + ProForm, + ProFormDateMonthRangePicker, +} from '@ant-design/pro-components'; +import { Space } from 'antd'; +import { useState } from 'react'; + +const ListPage: React.FC = () => { + const [month, setMonth] = useState(''); + return ( + + + { + setMonth(values.month); + }} + > + + + { + const { data, success } = + await statisticscontrollerGetcustomerorders(params); + return { data }; + }} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + return ( +
+ {record?.first_hot_purchase?.map((v) => ( +
+ 产品名称:{v.name} 用户数:{v.user_count} +
+ ))} +
+ ); + }} + /> + { + return ( +
+ {record?.second_hot_purchase?.map((v) => ( +
+ 产品名称:{v.name} 用户数:{v.user_count} +
+ ))} +
+ ); + }} + /> + { + return ( +
+ {record?.third_hot_purchase?.map((v) => ( +
+ 产品名称:{v.name} 用户数:{v.user_count} +
+ ))} +
+ ); + }} + /> +
+
+
+ ); +}; + +export default ListPage; diff --git a/src/pages/Statistics/InventoryForecast/index.tsx b/src/pages/Statistics/InventoryForecast/index.tsx new file mode 100644 index 0000000..401f5de --- /dev/null +++ b/src/pages/Statistics/InventoryForecast/index.tsx @@ -0,0 +1,201 @@ +import { statisticscontrollerStockforecast } from '@/servers/api/statistics'; +import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; +import { + ActionType, + PageContainer, + ProColumns, + ProFormDatePicker, + ProFormDigit, + ProTable, +} from '@ant-design/pro-components'; +import dayjs from 'dayjs'; +import { useEffect, useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const [points, setPoints] = useState([]); + useEffect(() => { + stockcontrollerGetallstockpoints().then(({ data }) => { + setPoints(data as API.StockPoint[]); + }); + }, []); + + const [real, setReal] = useState({}); + + const columns: ProColumns[] = [ + { + title: '产品名称', + dataIndex: 'productName', + }, + { + title: 'SKU', + dataIndex: 'productSku', + hideInSearch: true, + }, + ...points + ?.filter((point: API.StockPoint) => !point.ignore) + ?.map((point: API.StockPoint) => ({ + title: point.name, + dataIndex: `point_${point.name}`, + hideInSearch: true, + render(_: any, record: any) { + const quantity = record.stockDetails?.find( + (item: any) => item.id === point.id, + )?.quantity; + return quantity || 0; + }, + })), + { + title: '途中库存', + dataIndex: 'transitStock', + hideInSearch: true, + }, + { + title: '加拿大库存', + dataIndex: 'caTotalStock', + hideInSearch: true, + render(_, record) { + if (!record.caTotalStock || record.caTotalStock > 400) { + return record.caTotalStock; + } + return {record.caTotalStock}; + }, + }, + { + title: '总库存', + dataIndex: 'totalStock', + hideInSearch: true, + }, + { + title: '30天', + dataIndex: 'totalSales_30', + hideInSearch: true, + }, + { + title: '2*15天', + dataIndex: 'totalSales_15', + hideInSearch: true, + }, + { + title: '补货数量', + dataIndex: 'restockQuantity', + hideInSearch: true, + }, + { + title: '实补数量', + dataIndex: 'restockQuantityReal', + hideInSearch: true, + render(_, record) { + return ( + + ); + }, + }, + { + title: 'B端实补数量', + dataIndex: 'restockQuantityReal', + hideInSearch: true, + render(_, record) { + return ; + }, + }, + { + title: '加拿大剩余天数', + dataIndex: 'caAvailableDays', + hideInSearch: true, + render(_, record) { + if (!record.caAvailableDays || record.caAvailableDays > 40) { + return record.caAvailableDays; + } + return {record.caAvailableDays}; + }, + }, + { + title: '剩余天数', + dataIndex: 'availableDays', + hideInSearch: true, + render(_, record) { + if (!record.availableDays || record.availableDays > 70) { + return record.availableDays; + } + return {record.availableDays}; + }, + }, + { + title: '实补后剩余天数', + hideInSearch: true, + render(_, record) { + if (!record.availableDays) return '-'; + const availableDays = Number(record.availableDays); + const quantity = real?.[record.productSku] || 0; + const day = + availableDays + + Math.floor( + quantity / + (Math.max(record.totalSales_30, record.totalSales_15) / 30), + ); + return day; + }, + }, + { + title: '实补后日期', + hideInSearch: true, + render(_, record) { + if (!record.availableDays) return '-'; + const availableDays = Number(record.availableDays); + const quantity = real?.[record.productSku] || 0; + const day = + availableDays + + Math.floor( + quantity / + (Math.max(record.totalSales_30, record.totalSales_15) / 30), + ); + return ( + + ); + }, + }, + ]; + return ( + + { + const { data, success } = await statisticscontrollerStockforecast( + param, + ); + if (success) { + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + return { + data: [], + }; + }} + columns={columns} + dateFormatter="number" + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Statistics/Order/index.tsx b/src/pages/Statistics/Order/index.tsx new file mode 100644 index 0000000..fed66cc --- /dev/null +++ b/src/pages/Statistics/Order/index.tsx @@ -0,0 +1,887 @@ +import { ORDER_STATUS_ENUM } from '@/constants'; +import { sitecontrollerAll } from '@/servers/api/site'; +import { + statisticscontrollerGetorderbydate, + statisticscontrollerGetorderbyemail, + statisticscontrollerGetorderstatistics, +} from '@/servers/api/statistics'; +import { formatSource } from '@/utils/format'; +import { + ModalForm, + PageContainer, + ProForm, + ProFormDateRangePicker, + ProFormSelect, + ProTable, +} from '@ant-design/pro-components'; +import { Button } from 'antd'; +import dayjs from 'dayjs'; +import ReactECharts from 'echarts-for-react'; +import { useEffect, useMemo, useState } from 'react'; + +const highlightText = (text: string, keyword: string) => { + if (!keyword) return text; + const parts = text.split(new RegExp(`(${keyword})`, 'gi')); + return parts.map((part, index) => + part.toLowerCase() === keyword.toLowerCase() ? ( + + {part} + + ) : ( + part + ), + ); +}; + +const ListPage: React.FC = () => { + const [xAxis, setXAxis] = useState([]); + const [series, setSeries] = useState([]); + const [selectedDate, setSelectedDate] = useState(null); + + const option = useMemo( + () => ({ + tooltip: { + trigger: 'axis', + formatter: function (params) { + const items = params.map((item) => { + return `${item.marker} ${item.seriesName}: ${item.value}`; + }); + + // 每4个一行 + const rows = []; + for (let i = 0; i < items.length; i += 4) { + rows.push(items.slice(i, i + 4).join('')); + } + + return rows.join('
'); + }, + }, + legend: { + data: ['订单数', '总金额', '平均金额', '盒数'], + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true, + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: xAxis, + }, + yAxis: [ + { + type: 'value', + name: '订单数', + position: 'left', + }, + { + type: 'value', + name: '总金额', + position: 'right', + offset: 60, + }, + { + type: 'value', + name: '平均金额', + position: 'right', + }, + { + type: 'value', + name: '盒数', + position: 'left', + offset: 60, + }, + ], + series, + }), + [xAxis, series], + ); + + return ( + + { + setXAxis([]); + setSeries([]); + setSelectedDate(null); + // setKeyword(values?.keyword || ''); + const { date, ...params } = values; + const [startDate, endDate] = date; + const { data, success } = + await statisticscontrollerGetorderstatistics({ + startDate, + endDate, + ...params, + }); + if (success) { + const res = data?.sort(() => -1); + setXAxis(res?.map((v) => dayjs(v.order_date).format('YYYY-MM-DD'))); + setSeries([ + { + name: '首购订单数', + type: 'line', + data: res?.map((v) => v.first_purchase_orders), + }, + { + name: '首购金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.first_purchase_total), + }, + { + name: '复购订单数', + type: 'line', + data: res?.map((v) => v.repeat_purchase_orders), + }, + { + name: '复购金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.repeat_purchase_total), + }, + { + name: 'TOGO CPC订单数', + type: 'line', + data: res?.map((v) => v.togo_cpc_orders), + }, + { + name: 'TOGO 非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_togo_cpc_orders), + }, + { + name: 'CAN CPC订单数', + type: 'line', + data: res?.map((v) => v.can_cpc_orders), + }, + { + name: 'CAN 非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_can_cpc_orders), + }, + { + name: 'CPC订单数', + type: 'line', + data: res?.map((v) => v.cpc_orders), + }, + { + name: 'ZYN CPC订单数', + type: 'line', + data: res?.map((v) => v.zyn_orders), + }, + { + name: 'YOONE CPC订单数', + type: 'line', + data: res?.map((v) => v.yoone_orders), + }, + { + name: 'ZEX CPC订单数', + type: 'line', + data: res?.map((v) => v.zex_orders), + }, + { + name: 'CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.cpc_total), + }, + { + name: 'ZYN CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.zyn_total), + }, + { + name: 'YOONE CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_total), + }, + { + name: 'ZEX CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.zex_total), + }, + { + name: '非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_cpc_orders), + }, + { + name: 'ZYN 非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_zyn_orders), + }, + { + name: 'YOONE 非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_yoone_orders), + }, + { + name: 'ZEX 非CPC订单数', + type: 'line', + data: res?.map((v) => v.non_zex_orders), + }, + { + name: '非CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.non_cpc_total), + }, + { + name: 'ZYN 非CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.non_zyn_total), + }, + { + name: 'YOONE 非CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.non_yoone_total), + }, + { + name: 'ZEX 非CPC金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.non_zex_total), + }, + { + name: 'ZYN 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.zyn_amount), + }, + { + name: 'ZYN 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.zyn_quantity), + }, + { + name: 'ZYN CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_zyn_quantity), + }, + { + name: 'ZYN 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_zyn_quantity), + }, + { + name: 'YOONE 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_amount), + }, + { + name: 'YOONE 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_quantity), + }, + { + name: 'YOONE CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_quantity), + }, + { + name: 'YOONE 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_quantity), + }, + { + name: 'YOONE套装金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_G_amount), + }, + { + name: 'YOONE套装盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_G_quantity), + }, + { + name: 'YOONE套装CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_G_quantity), + }, + { + name: 'YOONE套装非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_G_quantity), + }, + { + name: 'YOONE单盒金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_S_amount), + }, + { + name: 'YOONE单盒盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_S_quantity), + }, + { + name: 'YOONE单盒CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_S_quantity), + }, + { + name: 'YOONE单盒非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_S_quantity), + }, + { + name: 'YOONE 3MG 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_3_amount), + }, + { + name: 'YOONE 3MG 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_3_quantity), + }, + { + name: 'YOONE 3MG CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_3_quantity), + }, + { + name: 'YOONE 3MG 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_3_quantity), + }, + { + name: 'YOONE 6MG 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_6_amount), + }, + { + name: 'YOONE 6MG 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_6_quantity), + }, + { + name: 'YOONE 6MG CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_6_quantity), + }, + { + name: 'YOONE 6MG 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_6_quantity), + }, + { + name: 'YOONE 9MG 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_9_amount), + }, + { + name: 'YOONE 9MG 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_9_quantity), + }, + { + name: 'YOONE 9MG CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_9_quantity), + }, + { + name: 'YOONE 9MG 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_9_quantity), + }, + { + name: 'YOONE 12MG 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_12_amount), + }, + { + name: 'YOONE 12MG 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_12_quantity), + }, + { + name: 'YOONE 12MG CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_12_quantity), + }, + { + name: 'YOONE 12MG 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_12_quantity), + }, + { + name: 'YOONE 15MG 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.yoone_15_amount), + }, + { + name: 'YOONE 15MG 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.yoone_15_quantity), + }, + { + name: 'YOONE 15MG CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_yoone_15_quantity), + }, + { + name: 'YOONE 15MG 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_yoone_15_quantity), + }, + { + name: 'ZEX 盒数金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.zex_amount), + }, + { + name: 'ZEX 盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.zex_quantity), + }, + { + name: 'ZEX CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.cpc_zex_quantity), + }, + { + name: 'ZEX 非CPC盒数', + type: 'line', + yAxisIndex: 3, + data: res?.map((v) => v.non_cpc_zex_quantity), + }, + { + name: '订单数', + type: 'line', + data: res?.map((v) => v.total_orders), + }, + { + name: 'TOGO订单数', + type: 'line', + data: res?.map((v) => v.togo_total_orders), + }, + { + name: 'CAN订单数', + type: 'line', + data: res?.map((v) => v.can_total_orders), + }, + { + name: '总金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.total_amount), + }, + { + name: 'TOGO总金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.togo_total_amount), + }, + { + name: 'CAN总金额', + type: 'line', + yAxisIndex: 1, + data: res?.map((v) => v.can_total_amount), + }, + { + name: '平均金额', + type: 'line', + yAxisIndex: 2, + data: res?.map((v) => v.avg_total_amount), + }, + { + name: 'TOGO平均金额', + type: 'line', + yAxisIndex: 2, + data: res?.map((v) => v.avg_togo_total_amount), + }, + { + name: 'CAN平均金额', + type: 'line', + yAxisIndex: 2, + data: res?.map((v) => v.avg_can_total_amount), + }, + ]); + } + }} + > + + {/* */} + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }} + /> + {/* + + */} + + {series?.length ? ( + { + if (params.componentType === 'series') { + setSelectedDate(params.name); + } + }, + }} + /> + ) : ( + <> + )} + + + ); +}; + +const DailyOrders: React.FC<{ + selectedDate; +}> = ({ selectedDate }) => { + const [orders, setOrders] = useState([]); + useEffect(() => { + if (!selectedDate) { + setOrders([]); + return; + } + statisticscontrollerGetorderbydate({ + date: selectedDate, + }).then(({ data, success }) => { + if (success) { + setOrders(data); + } + }); + }, [selectedDate]); + + const handleTableChange = (pagination, filters, sorter) => { + // 获取排序字段和排序方式 + const { field, order } = sorter || {}; + + if (field && order) { + const sortedData = [...orders].sort((a, b) => { + if (['total', 'order_count', 'total_spent'].includes(field)) { + const valA = Number(a[field]); + const valB = Number(b[field]); + if (isNaN(valA)) return 1; + if (isNaN(valB)) return -1; + if (order === 'ascend') { + return valA - valB; + } + return valB - valA; + } + if (order === 'ascend') { + return a[field] > b[field] ? 1 : -1; + } + return a[field] < b[field] ? 1 : -1; + }); + + setOrders(sortedData); + } + }; + + if (!selectedDate) return <>; + return ( + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }, + }, + { + title: '首单时间', + dataIndex: 'first_purchase_date', + valueType: 'dateTime', + sorter: true, + }, + { + title: '支付时间', + dataIndex: 'date_paid', + valueType: 'dateTime', + sorter: true, + }, + { + title: '订单金额', + dataIndex: 'total', + sorter: true, + }, + { + title: '总订单数', + dataIndex: 'order_count', + sorter: true, + }, + { + title: '总订单金额', + dataIndex: 'total_spent', + sorter: true, + }, + { + title: '订单类型', + dataIndex: 'purchase_type', + sorter: true, + render: (_, record) => { + if (record.purchase_type === 'first_purchase') return '首单'; + return '复购单'; + }, + filters: [ + { text: '首单', value: 'first_purchase' }, + { text: '复购单', value: 'repeat_purchase' }, + ], + onFilter: (value, record) => { + return record.purchase_type === value; + }, + }, + { + title: '状态', + dataIndex: 'orderStatus', + hideInSearch: true, + valueType: 'select', + valueEnum: ORDER_STATUS_ENUM, + sorter: true, + }, + { + title: '来源', + hideInSearch: true, + sorter: true, + render: (_, record) => + formatSource(record.source_type, record.utm_source), + filters: [ + { text: 'google广告', value: 'source' }, + { text: 'google搜索', value: 'organic' }, + { text: '直达', value: 'direct' }, + { text: '其他', value: 'other' }, + ], + onFilter: (value, record) => { + if (value === 'source') { + return ( + record.source_type === 'utm' && record.utm_source === 'google' + ); + } + if (value === 'organic') { + return ( + record.source_type === 'organic' && + record.utm_source === 'google' + ); + } + if (value === 'direct') { + return record.source_type === 'typein'; + } + if (value === '其他') { + return !['utm', 'organic', 'typein'].includes(record.source_type); + } + }, + }, + { + title: '订单内容', + dataIndex: 'orderItems', + render: (_, record) => { + return ( +
+ {record.orderItems?.map((item) => ( + //
{highlightText(item.name, keyword)}
+
{item.name}
+ ))} +
+ ); + }, + filters: [ + { text: 'ZYN', value: 'zyn' }, + { text: 'YOONE', value: 'yoone' }, + { text: 'ZEX', value: 'zex' }, + ], + onFilter: (value, record) => { + return record.orderItems?.some((v) => + v?.name?.toLowerCase().includes(value), + ); + }, + }, + { + title: '操作', + dataIndex: 'action', + valueType: 'option', + render: (_, record) => { + return ; + }, + }, + ]} + dataSource={orders} + onChange={handleTableChange} + /> + ); +}; + +const HistoryOrder: React.FC<{ + email: string; +}> = ({ email }) => { + return ( + 历史订单} + modalProps={{ destroyOnClose: true, footer: null }} + width="80vw" + > + { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }, + }, + { + title: '支付时间', + dataIndex: 'date_paid', + valueType: 'dateTime', + }, + { + title: '订单金额', + dataIndex: 'total', + }, + { + title: '状态', + dataIndex: 'orderStatus', + hideInSearch: true, + valueType: 'select', + valueEnum: ORDER_STATUS_ENUM, + }, + { + title: '来源', + hideInSearch: true, + render: (_, record) => + formatSource(record.source_type, record.utm_source), + }, + { + title: '订单内容', + dataIndex: 'orderItems', + render: (_, record) => { + return ( +
+ {record.orderItems?.map((item) => ( +
+ ${item.total} : {item.name} * {item.quantity} +
+ ))} +
+ ); + }, + }, + ]} + request={async () => { + const { data, success } = await statisticscontrollerGetorderbyemail({ + email, + }); + return { + data, + success, + }; + }} + /> +
+ ); +}; + +export default ListPage; diff --git a/src/pages/Statistics/Restocking/index.tsx b/src/pages/Statistics/Restocking/index.tsx new file mode 100644 index 0000000..94d2e16 --- /dev/null +++ b/src/pages/Statistics/Restocking/index.tsx @@ -0,0 +1,187 @@ +import { statisticscontrollerRestocking } from '@/servers/api/statistics'; +import { + ActionType, + PageContainer, + ProColumns, + ProFormDigit, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import dayjs from 'dayjs'; +import { useMemo, useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const [count, setCount] = useState(4); + const history = useMemo( + () => + Array.from({ length: Math.min(!!count ? count : 5, 10) }).map((_, i) => { + if (dayjs().date() > 20) i++; + return dayjs().add(i, 'month').format('YYYY-MM'); + }), + [count], + ); + + const [savety, setSavety] = useState({}); + + const columns: ProColumns[] = [ + { + title: '产品名称', + dataIndex: 'productName', + }, + { + title: '30天销量', + dataIndex: 'last30DaysSales', + hideInSearch: true, + }, + { + title: '2*15天销量', + dataIndex: 'last15DaysSales', + hideInSearch: true, + render(_, record) { + return 2 * record.last15DaysSales; + }, + }, + { + title: '库存', + dataIndex: 'totalStock', + hideInSearch: true, + }, + ...history.map((v, i) => ({ + title: v, + onCell: () => ({ style: { padding: 0 } }), + align: 'center' as any, + hideInSearch: true, + render(_, record) { + const base = record.lastMonthSales; + return ( +
+
+
{base}
+
{base}
+
{base}
+
+
+
+ ); + }, + })), + { + title: '安全补充系数', + hideInSearch: true, + render(_, record) { + return ( + + ); + }, + }, + { + title: '', + hideInSearch: true, + render(_, record) { + const base = record.lastMonthSales; + return ( +
+
{count * base}
+
{2 * count * base}
+
+ ); + }, + }, + { + title: '合计', + hideInSearch: true, + render(_, record) { + const base = record.lastMonthSales; + return 3 * count * base + (savety[record.productSku] || 0); + }, + }, + { + title: '修正数', + hideInSearch: true, + render(_, record) { + const base = record.lastMonthSales; + return ( + + ); + }, + }, + ]; + return ( + + { + const { data, success } = await statisticscontrollerRestocking(param); + if (success) { + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + return { + data: [], + }; + }} + columns={columns} + dateFormatter="number" + toolBarRender={() => [ + setCount(e.target.value), + value: count, + }} + />, + ]} + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Statistics/Sales/index.tsx b/src/pages/Statistics/Sales/index.tsx new file mode 100644 index 0000000..64ad8cb --- /dev/null +++ b/src/pages/Statistics/Sales/index.tsx @@ -0,0 +1,185 @@ +import { ordercontrollerGetordersales } from '@/servers/api/order'; +import { sitecontrollerAll } from '@/servers/api/site'; +import { + ActionType, + PageContainer, + ProColumns, + ProFormSwitch, + ProTable, +} from '@ant-design/pro-components'; +import dayjs from 'dayjs'; +import { useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const actionRef = useRef(); + const [total, setTotal] = useState(0); + const [isSource, setIsSource] = useState(false); + const [yooneTotal, setYooneTotal] = useState({}); + + const columns: ProColumns[] = [ + { + title: '时间段', + dataIndex: 'dateRange', + valueType: 'dateTimeRange', + hideInTable: true, + formItemProps: { + rules: [ + { + required: true, + message: '请选择时间段', + }, + ], + }, + }, + { + title: '产品名称', + dataIndex: 'name', + }, + { + title: '站点', + dataIndex: 'siteId', + valueType: 'select', + request: async () => { + const { data = [] } = await sitecontrollerAll(); + return data.map((item) => ({ + label: item.siteName, + value: item.id, + })); + }, + hideInTable: true, + }, + { + title: '分类', + dataIndex: 'categoryName', + hideInSearch: true, + hideInTable: isSource, + }, + { + title: '数量', + dataIndex: 'totalQuantity', + hideInSearch: true, + }, + { + title: '一单订单数', + dataIndex: 'firstOrderCount', + hideInSearch: true, + render(_, record) { + if (isSource) return record.firstOrderCount; + return `${record.firstOrderCount}(${record.firstOrderYOONEBoxCount})`; + }, + }, + { + title: '两单订单数', + dataIndex: 'secondOrderCount', + hideInSearch: true, + render(_, record) { + if (isSource) return record.secondOrderCount; + return `${record.secondOrderCount}(${record.secondOrderYOONEBoxCount})`; + }, + }, + { + title: '三单订单数', + dataIndex: 'thirdOrderCount', + hideInSearch: true, + render(_, record) { + if (isSource) return record.thirdOrderCount; + return `${record.thirdOrderCount}(${record.thirdOrderYOONEBoxCount})`; + }, + }, + { + title: '三单以上订单数', + dataIndex: 'moreThirdOrderCount', + hideInSearch: true, + render(_, record) { + if (isSource) return record.moreThirdOrderCount; + return `${record.moreThirdOrderCount}(${record.moreThirdOrderYOONEBoxCount})`; + }, + }, + { + title: '订单数', + dataIndex: 'totalOrders', + hideInSearch: true, + }, + ]; + return ( + + { + const [startDate, endDate] = dateRange.values(); + const { data, success } = await ordercontrollerGetordersales({ + startDate, + endDate, + ...param, + }); + if (success) { + setTotal(data?.totalQuantity || 0); + setYooneTotal({ + yoone3Quantity: data?.yoone3Quantity || 0, + yoone6Quantity: data?.yoone6Quantity || 0, + yoone9Quantity: data?.yoone9Quantity || 0, + yoone12Quantity: data?.yoone12Quantity || 0, + yoone15Quantity: data?.yoone15Quantity || 0, + }); + return { + total: data?.total || 0, + data: data?.items || [], + }; + } + setTotal(0); + setYooneTotal({}); + return { + data: [], + }; + }} + columns={columns} + dateFormatter="number" + footer={() => `总计: ${total}`} + toolBarRender={() => [ + setIsSource(!isSource), + }} + />, + ]} + /> +
+
+ YOONE:{' '} + {(yooneTotal.yoone3Quantity || 0) + + (yooneTotal.yoone6Quantity || 0) + + (yooneTotal.yoone9Quantity || 0) + + (yooneTotal.yoone12Quantity || 0) + + (yooneTotal.yoone15Quantity || 0)} +
+
YOONE 3MG: {yooneTotal.yoone3Quantity || 0}
+
YOONE 6MG: {yooneTotal.yoone6Quantity || 0}
+
YOONE 9MG: {yooneTotal.yoone9Quantity || 0}
+
YOONE 12MG: {yooneTotal.yoone12Quantity || 0}
+
YOONE 15MG: {yooneTotal.yoone15Quantity || 0}
+
+
+ ); +}; + +export default ListPage; diff --git a/src/pages/Stock/List/index.tsx b/src/pages/Stock/List/index.tsx new file mode 100644 index 0000000..e51b62c --- /dev/null +++ b/src/pages/Stock/List/index.tsx @@ -0,0 +1,85 @@ +import { + stockcontrollerGetallstockpoints, + stockcontrollerGetstocks, +} from '@/servers/api/stock'; +import { + ActionType, + PageContainer, + ProColumns, + ProTable, +} from '@ant-design/pro-components'; +import { App } from 'antd'; +import { useEffect, useRef, useState } from 'react'; + +const ListPage: React.FC = () => { + const { message } = App.useApp(); + const actionRef = useRef(); + const [points, setPoints] = useState([]); + useEffect(() => { + stockcontrollerGetallstockpoints().then(({ data }) => { + setPoints(data as API.StockPoint[]); + }); + }, []); + const columns: ProColumns[] = [ + { + title: '产品名称', + dataIndex: 'productName', + }, + { + title: 'SKU', + dataIndex: 'productSku', + hideInSearch: true, + }, + ...points?.map((point: API.StockPoint) => ({ + title: point.name, + dataIndex: `point_${point.name}`, + hideInSearch: true, + render(_: any, record: API.StockDTO) { + const quantity = record.stockPoint?.find( + (item) => item.id === point.id, + )?.quantity; + return quantity || 0; + }, + })), + { + title: '运输中', + dataIndex: 'inTransitQuantity', + hideInSearch: true, + }, + // { + // title: '更新时间', + // dataIndex: 'updatedAt', + // valueType: 'dateTime', + // hideInSearch: true, + // }, + // { + // title: '创建时间', + // dataIndex: 'createdAt', + // valueType: 'dateTime', + // hideInSearch: true, + // }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + request={async (params) => { + const { data, success } = await stockcontrollerGetstocks(params); + + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + // toolBarRender={() => []} + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Stock/PurchaseOrder/index.tsx b/src/pages/Stock/PurchaseOrder/index.tsx new file mode 100644 index 0000000..79b54ef --- /dev/null +++ b/src/pages/Stock/PurchaseOrder/index.tsx @@ -0,0 +1,682 @@ +import { Purchase_Order_STATUS_ENUM } from '@/constants'; +import { productcontrollerSearchproducts } from '@/servers/api/product'; +import { + stockcontrollerCreatepurchaseorder, + stockcontrollerDelpurchaseorder, + stockcontrollerGetallstockpoints, + stockcontrollerGetpurchaseorders, + stockcontrollerReceivepurchaseorder, + stockcontrollerUpdatepurchaseorder, +} from '@/servers/api/stock'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormDatePicker, + ProFormDependency, + ProFormDigit, + ProFormList, + ProFormSelect, + ProFormText, + ProFormTextArea, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Divider, Form, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const PurchaseOrderPage: React.FC = () => { + const { message } = App.useApp(); + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '订单编号', + dataIndex: 'orderNumber', + }, + { + title: '仓库', + dataIndex: 'stockPointName', + hideInSearch: true, + }, + { + title: '状态', + dataIndex: 'status', + valueType: 'select', + valueEnum: Purchase_Order_STATUS_ENUM, + hideInSearch: true, + }, + { + title: '预计到货时间', + dataIndex: 'expectedArrivalTime', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '数量', + hideInSearch: true, + render(_, record) { + return record.items.reduce((cur, next) => { + return cur + next.quantity; + }, 0); + }, + }, + { + title: '备注', + dataIndex: 'note', + hideInSearch: true, + }, + { + title: '更新时间', + dataIndex: 'updatedAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + {record.status !== 'received' && ( + + )} + {record.status === 'draft' ? ( + <> + + { + try { + const { success, message: errMsg } = + await stockcontrollerDelpurchaseorder({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ) : record.status === 'submitted' ? ( + <> + + { + try { + const { success, message: errMsg } = + await stockcontrollerReceivepurchaseorder({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ) : ( + + )} + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + request={async (params) => { + const { data, success } = await stockcontrollerGetpurchaseorders( + params, + ); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + toolBarRender={() => []} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + return ( + + title="新建" + trigger={ + + } + form={form} + autoFocusFirstInput + layout="vertical" + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await stockcontrollerCreatepurchaseorder(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="stockPointId" + label="仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择仓库' }]} + /> + + + + + {({ items }) => { + return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); + }} + + + name="items" + label="产品" + rules={[ + { + required: true, + message: '至少需要一个商品', + validator: (_, value) => + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label={'产品' + (idx + 1)} + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option.title, + ); + }} + /> +
+ )} + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.UpdatePurchaseOrderDTO & { + id: number; + }; +}> = ({ tableRef, values }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + const initialValues = { + ...values, + items: values?.items?.map((item: API.PurchaseOrderItem) => ({ + ...item, + productSku: { + label: item.productName, + value: item.productSku, + }, + })), + }; + return ( + + title="编辑" + form={form} + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await stockcontrollerUpdatepurchaseorder( + { id: initialValues.id }, + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="stockPointId" + label="仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择仓库' }]} + /> + + + + + {({ items }) => { + return ( + '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0) + ); + }} + + + name="items" + rules={[ + { + required: true, + message: '至少需要一个商品', + validator: (_, value) => + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label="产品" + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option?.title, + ); + }} + /> +
+ )} + +
+ + ); +}; + +const DetailForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.UpdatePurchaseOrderDTO & { + id: number; + }; +}> = ({ tableRef, values }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + const initialValues = { + ...values, + items: values?.items?.map((item: API.PurchaseOrderItem) => ({ + ...item, + productSku: { + label: item.productName, + value: item.productSku, + }, + })), + }; + return ( + + title="详情" + form={form} + initialValues={initialValues} + trigger={} + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + readonly={true} + layout="vertical" + > + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="stockPointId" + label="仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择仓库' }]} + /> + + + + + + name="items" + rules={[ + { + required: true, + message: '至少需要一个商品', + validator: (_, value) => + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ + { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label="产品" + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + filterOption: false, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option?.title, + ); + }} + /> + +
+ )} + + + ); +}; + +export default PurchaseOrderPage; diff --git a/src/pages/Stock/Record/index.tsx b/src/pages/Stock/Record/index.tsx new file mode 100644 index 0000000..244c3f1 --- /dev/null +++ b/src/pages/Stock/Record/index.tsx @@ -0,0 +1,81 @@ +import { stockcontrollerGetstockrecords } from '@/servers/api/stock'; +import { + ActionType, + PageContainer, + ProColumns, + ProTable, +} from '@ant-design/pro-components'; +import { App } from 'antd'; +import { useRef } from 'react'; + +const ListPage: React.FC = () => { + const { message } = App.useApp(); + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '仓库', + dataIndex: 'stockPointName', + hideInSearch: true, + }, + { + title: '产品名称', + dataIndex: 'productName', + }, + { + title: 'SKU', + dataIndex: 'productSku', + hideInSearch: true, + }, + { + title: '库存', + hideInSearch: true, + render: (_, record: API.StockRecordDTO) => ( + + {record?.operationType === 'in' ? '+' : '-'} + {record.quantityChange} + + ), + }, + { + title: '操作人', + dataIndex: 'operatorName', + hideInSearch: true, + }, + { + title: '备注', + dataIndex: 'note', + hideInSearch: true, + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + hideInSearch: true, + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + request={async (params) => { + const { data, success } = await stockcontrollerGetstockrecords( + params, + ); + + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + // toolBarRender={() => []} + /> + + ); +}; + +export default ListPage; diff --git a/src/pages/Stock/Transfer/index.tsx b/src/pages/Stock/Transfer/index.tsx new file mode 100644 index 0000000..5b19845 --- /dev/null +++ b/src/pages/Stock/Transfer/index.tsx @@ -0,0 +1,688 @@ +import { productcontrollerSearchproducts } from '@/servers/api/product'; +import { + stockcontrollerCanceltransfer, + stockcontrollerCreatetransfer, + stockcontrollerGetallstockpoints, + stockcontrollerGettransfers, + stockcontrollerLosttransfer, + stockcontrollerReceivetransfer, + stockcontrollerUpdatetransfer, +} from '@/servers/api/stock'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormDatePicker, + ProFormDependency, + ProFormDigit, + ProFormList, + ProFormSelect, + ProFormText, + ProFormTextArea, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Divider, Form, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const TransferPage: React.FC = () => { + const { message } = App.useApp(); + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '订单编号', + dataIndex: 'orderNumber', + }, + { + title: '源仓库', + dataIndex: 'sourceStockPointName', + hideInSearch: true, + }, + { + title: '目标仓库', + dataIndex: 'destStockPointName', + hideInSearch: true, + }, + { + title: '状态', + dataIndex: 'status', + hideInSearch: true, + render(_, record) { + if (record.isLost) return '已丢失'; + if (record.isCancel) return '已取消'; + if (record.isArrived) return '已到达'; + return '运输中'; + }, + }, + { + title: '数量', + hideInSearch: true, + render(_, record) { + return record.items.reduce((cur, next) => { + return cur + next.quantity; + }, 0); + }, + }, + { + title: '备注', + dataIndex: 'note', + hideInSearch: true, + }, + { + title: '到货时间', + dataIndex: 'arriveAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '发货时间', + dataIndex: 'sendAt', + valueType: 'dateTime', + hideInSearch: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + {!record.isCancel && !record.isArrived && !record.isLost ? ( + <> + + + { + try { + const { success, message: errMsg } = + await stockcontrollerReceivetransfer({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + { + try { + const { success, message: errMsg } = + await stockcontrollerLosttransfer({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + { + try { + const { success, message: errMsg } = + await stockcontrollerCanceltransfer({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ) : ( + + )} + + ), + }, + ]; + + return ( + + { + const { data, success } = await stockcontrollerGettransfers(params); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + toolBarRender={() => []} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + return ( + + + 新建 + + } + form={form} + autoFocusFirstInput + layout="vertical" + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + console.log(values); + const { success, message: errMsg } = + await stockcontrollerCreatetransfer(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="sourceStockPointId" + label="源仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源仓库' }]} + /> + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="destStockPointId" + label="目标仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源目标仓库' }]} + /> + + + {({ items }) => { + return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); + }} + + + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label={'产品' + (idx + 1)} + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option.title, + ); + }} + /> +
+ )} +
+
+ ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.UpdatePurchaseOrderDTO & { + id: number; + }; +}> = ({ tableRef, values }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + const initialValues = { + ...values, + items: values?.items?.map((item: API.PurchaseOrderItem) => ({ + ...item, + productSku: { + label: item.productName, + value: item.productSku, + }, + })), + }; + return ( + + title="编辑" + form={form} + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await stockcontrollerUpdatetransfer( + { id: initialValues.id }, + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="sourceStockPointId" + label="源仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源仓库' }]} + /> + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="destStockPointId" + label="目标仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源目标仓库' }]} + /> + + + {({ items }) => { + return '数量:' + items?.reduce((acc, cur) => acc + cur.quantity, 0); + }} + + + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label={'产品' + (idx + 1)} + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option.title, + ); + }} + /> +
+ )} +
+ + ); +}; + +const DetailForm: React.FC<{ + tableRef: React.MutableRefObject; + values: Record; +}> = ({ tableRef, values }) => { + const { message } = App.useApp(); + const [form] = Form.useForm(); + const initialValues = { + ...values, + items: values?.items?.map( + (item: { productName: string; productSku: string }) => ({ + ...item, + productSku: { + label: item.productName, + value: item.productSku, + }, + }), + ), + }; + return ( + 详情} + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + readonly={true} + layout="vertical" + > + + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="sourceStockPointId" + label="源仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源仓库' }]} + /> + { + try { + const { data } = await stockcontrollerGetallstockpoints(); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.id, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="destStockPointId" + label="目标仓库" + width="lg" + placeholder="请选择仓库" + rules={[{ required: true, message: '请选择源目标仓库' }]} + /> + + + name="items" + rules={[ + { + required: true, + message: '至少需要一个商品', + validator: (_, value) => + value && value.length > 0 + ? Promise.resolve() + : Promise.reject('至少需要一个商品'), + }, + ]} + creatorButtonProps={{ children: '新增', size: 'large' }} + wrapperCol={{ span: 24 }} + > + {(fields, idx, { remove }) => ( +
+ + { + if (keyWords.length < 3) return []; + try { + const { data } = await productcontrollerSearchproducts({ + name: keyWords, + }); + return ( + data?.map((item) => { + return { + label: item.name, + value: item.sku, + }; + }) || [] + ); + } catch (error) { + return []; + } + }} + name="productSku" + label="产品" + width="lg" + placeholder="请选择产品" + tooltip="至少输入3个字符" + fieldProps={{ + showSearch: true, + }} + transform={(value) => { + return value?.value || value; + }} + debounceTime={300} // 防抖,减少请求频率 + rules={[{ required: true, message: '请选择产品' }]} + onChange={(_, option) => { + form.setFieldValue( + ['items', fields.key, 'productName'], + option?.title, + ); + }} + /> + +
+ )} + +
+ ); +}; + +export default TransferPage; diff --git a/src/pages/Stock/Warehouse/index.tsx b/src/pages/Stock/Warehouse/index.tsx new file mode 100644 index 0000000..544334d --- /dev/null +++ b/src/pages/Stock/Warehouse/index.tsx @@ -0,0 +1,239 @@ +import { + stockcontrollerCreatestockpoint, + stockcontrollerDelstockpoints, + stockcontrollerGetstockpoints, + stockcontrollerUpdatestockpoint, +} from '@/servers/api/stock'; +import { EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { + ActionType, + DrawerForm, + PageContainer, + ProColumns, + ProForm, + ProFormText, + ProTable, +} from '@ant-design/pro-components'; +import { App, Button, Divider, Popconfirm } from 'antd'; +import { useRef } from 'react'; + +const ListPage: React.FC = () => { + const { message } = App.useApp(); + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'name', + }, + { + title: '地址', + dataIndex: 'location', + }, + { + title: '联系人', + dataIndex: 'contactPerson', + }, + { + title: '联系电话', + dataIndex: 'contactPhone', + }, + { + title: '创建时间', + dataIndex: 'createdAt', + valueType: 'dateTime', + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => ( + <> + + + { + try { + const { success, message: errMsg } = + await stockcontrollerDelstockpoints({ + id: record.id as number, + }); + if (!success) { + throw new Error(errMsg); + } + actionRef.current?.reload(); + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + ), + }, + ]; + + return ( + + + headerTitle="查询表格" + actionRef={actionRef} + rowKey="id" + request={async (params) => { + const { data, success } = await stockcontrollerGetstockpoints(params); + return { + total: data?.total || 0, + data: data?.items || [], + success, + }; + }} + columns={columns} + toolBarRender={() => []} + search={false} + /> + + ); +}; + +const CreateForm: React.FC<{ + tableRef: React.MutableRefObject; +}> = ({ tableRef }) => { + const { message } = App.useApp(); + return ( + + title="新建" + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await stockcontrollerCreatestockpoint(values); + if (!success) { + throw new Error(errMsg); + } + tableRef.current?.reload(); + message.success('提交成功'); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + + + + ); +}; + +const UpdateForm: React.FC<{ + tableRef: React.MutableRefObject; + values: API.StockPoint; +}> = ({ tableRef, values: initialValues }) => { + const { message } = App.useApp(); + return ( + + title="编辑" + initialValues={initialValues} + trigger={ + + } + autoFocusFirstInput + drawerProps={{ + destroyOnClose: true, + }} + onFinish={async (values) => { + try { + const { success, message: errMsg } = + await stockcontrollerUpdatestockpoint( + { id: initialValues.id as number }, + values, + ); + if (!success) { + throw new Error(errMsg); + } + message.success('提交成功'); + tableRef.current?.reload(); + return true; + } catch (error: any) { + message.error(error.message); + } + }} + > + + + + + + + + ); +}; + +export default ListPage; diff --git a/src/pages/Track/index.tsx b/src/pages/Track/index.tsx new file mode 100644 index 0000000..be6b401 --- /dev/null +++ b/src/pages/Track/index.tsx @@ -0,0 +1,82 @@ +import { + logisticscontrollerGetlistbytrackingid, + logisticscontrollerGettrackingnumber, +} from '@/servers/api/logistics'; +import { SearchOutlined } from '@ant-design/icons'; +import { PageContainer, ProFormSelect } from '@ant-design/pro-components'; +import { Col, Row } from 'antd'; +import { useState } from 'react'; + +const TrackPage: React.FC = () => { + const [id, setId] = useState(); + const [data, setData] = useState([]); + return ( + + { + if (!keyWords || keyWords.length < 3) return []; + const { data: trackList } = + await logisticscontrollerGettrackingnumber({ number: keyWords }); + return trackList?.map( + (v: { + tracking_provider: string; + primary_tracking_number: string; + id: string; + }) => { + return { + label: v.tracking_provider + ' ' + v.primary_tracking_number, + value: v.id, + }; + }, + ); + }} + fieldProps={{ + prefix: '追踪号', + onChange(value: string) { + setId(value); + }, + allowClear: false, + suffixIcon: ( + { + if (!id) { + return; + } + const { data } = await logisticscontrollerGetlistbytrackingid({ + shipment_id: id, + }); + setData(data); + }} + /> + ), + }} + /> + + 原订单 + 产品 + 数量 + {data?.orderItem?.map((v: any) => ( + <> + {v.name} + {v.quantity} + + ))} + + + + 产品 + 数量 + {data?.shipmentItem?.map((v: any) => ( + <> + {v.name} + {v.quantity} + + ))} + + + ); +}; + +export default TrackPage; diff --git a/src/servers/api/index.ts b/src/servers/api/index.ts new file mode 100644 index 0000000..800eb60 --- /dev/null +++ b/src/servers/api/index.ts @@ -0,0 +1,24 @@ +// @ts-ignore +/* eslint-disable */ +// API 更新时间: +// API 唯一标识: +import * as logistics from './logistics'; +import * as order from './order'; +import * as product from './product'; +import * as site from './site'; +import * as statistics from './statistics'; +import * as stock from './stock'; +import * as user from './user'; +import * as webhook from './webhook'; +import * as wpProduct from './wpProduct'; +export default { + logistics, + order, + product, + site, + statistics, + stock, + user, + webhook, + wpProduct, +}; diff --git a/src/servers/api/logistics.ts b/src/servers/api/logistics.ts new file mode 100644 index 0000000..8a4c32d --- /dev/null +++ b/src/servers/api/logistics.ts @@ -0,0 +1,202 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 POST /logistics/createShipment/${param0} */ +export async function logisticscontrollerCreateshipment( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerCreateshipmentParams, + body: API.ShipmentBookDTO, + options?: { [key: string]: any }, +) { + const { orderId: param0, ...queryParams } = params; + return request(`/logistics/createShipment/${param0}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/createShippingAddress */ +export async function logisticscontrollerCreateshippingaddress( + body: API.ShippingAddress, + options?: { [key: string]: any }, +) { + return request('/logistics/createShippingAddress', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /logistics/delShippingAddress/${param0} */ +export async function logisticscontrollerDelshippingaddress( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerDelshippingaddressParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/logistics/delShippingAddress/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/getListByTrackingId */ +export async function logisticscontrollerGetlistbytrackingid( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerGetlistbytrackingidParams, + options?: { [key: string]: any }, +) { + return request('/logistics/getListByTrackingId', { + method: 'POST', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/getPaymentMethods */ +export async function logisticscontrollerGetpaymentmethods(options?: { + [key: string]: any; +}) { + return request('/logistics/getPaymentMethods', { + method: 'POST', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/getRateList */ +export async function logisticscontrollerGetratelist( + body: API.ShippingDetailsDTO, + options?: { [key: string]: any }, +) { + return request('/logistics/getRateList', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /logistics/getServiceList */ +export async function logisticscontrollerGetservicelist( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerGetservicelistParams, + options?: { [key: string]: any }, +) { + return request('/logistics/getServiceList', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /logistics/getShippingAddressList */ +export async function logisticscontrollerGetshippingaddresslist(options?: { + [key: string]: any; +}) { + return request( + '/logistics/getShippingAddressList', + { + method: 'GET', + ...(options || {}), + }, + ); +} + +/** 此处后端没有提供注释 POST /logistics/getTrackingNumber */ +export async function logisticscontrollerGettrackingnumber( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerGettrackingnumberParams, + options?: { [key: string]: any }, +) { + return request('/logistics/getTrackingNumber', { + method: 'POST', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /logistics/list */ +export async function logisticscontrollerGetlist(options?: { + [key: string]: any; +}) { + return request('/logistics/list', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /logistics/shipment/${param0} */ +export async function logisticscontrollerDelshipment( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerDelshipmentParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/logistics/shipment/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/syncServices */ +export async function logisticscontrollerSyncservices(options?: { + [key: string]: any; +}) { + return request('/logistics/syncServices', { + method: 'POST', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /logistics/toggleActive */ +export async function logisticscontrollerToggleactive( + body: Record, + options?: { [key: string]: any }, +) { + return request('/logistics/toggleActive', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /logistics/updateShippingAddress/${param0} */ +export async function logisticscontrollerUpdateshippingaddress( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.logisticscontrollerUpdateshippingaddressParams, + body: API.ShippingAddress, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/logistics/updateShippingAddress/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/order.ts b/src/servers/api/order.ts new file mode 100644 index 0000000..5f9efb5 --- /dev/null +++ b/src/servers/api/order.ts @@ -0,0 +1,195 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 GET /order/${param0} */ +export async function ordercontrollerGetorderdetail( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerGetorderdetailParams, + options?: { [key: string]: any }, +) { + const { orderId: param0, ...queryParams } = params; + return request(`/order/${param0}`, { + method: 'GET', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /order/${param0} */ +export async function ordercontrollerDelorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerDelorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/order/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/createNote */ +export async function ordercontrollerCreatenote( + body: API.CreateOrderNoteDTO, + options?: { [key: string]: any }, +) { + return request('/order/createNote', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/getOrderByNumber */ +export async function ordercontrollerGetorderbynumber( + body: string, + options?: { [key: string]: any }, +) { + return request('/order/getOrderByNumber', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /order/getOrders */ +export async function ordercontrollerGetorders( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerGetordersParams, + options?: { [key: string]: any }, +) { + return request('/order/getOrders', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /order/getOrderSales */ +export async function ordercontrollerGetordersales( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerGetordersalesParams, + options?: { [key: string]: any }, +) { + return request('/order/getOrderSales', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/order/cancel/${param0} */ +export async function ordercontrollerCancelorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerCancelorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/order/order/cancel/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/order/completed/${param0} */ +export async function ordercontrollerCompletedorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerCompletedorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/order/order/completed/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/order/create */ +export async function ordercontrollerCreateorder( + body: Record, + options?: { [key: string]: any }, +) { + return request('/order/order/create', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/order/refund/${param0} */ +export async function ordercontrollerRefundorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerRefundorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/order/order/refund/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /order/order/status/${param0} */ +export async function ordercontrollerChangestatus( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerChangestatusParams, + body: string, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/order/order/status/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'text/plain', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/syncOrder/${param0} */ +export async function ordercontrollerSyncorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerSyncorderParams, + options?: { [key: string]: any }, +) { + const { siteId: param0, ...queryParams } = params; + return request(`/order/syncOrder/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /order/syncOrder/${param1}/order/${param0} */ +export async function ordercontrollerSyncorderbyid( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ordercontrollerSyncorderbyidParams, + options?: { [key: string]: any }, +) { + const { orderId: param0, siteId: param1, ...queryParams } = params; + return request(`/order/syncOrder/${param1}/order/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} diff --git a/src/servers/api/product.ts b/src/servers/api/product.ts new file mode 100644 index 0000000..1ca3032 --- /dev/null +++ b/src/servers/api/product.ts @@ -0,0 +1,329 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 POST /product/ */ +export async function productcontrollerCreateproduct( + body: API.CreateProductDTO, + options?: { [key: string]: any }, +) { + return request('/product/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /product/${param0} */ +export async function productcontrollerUpdateproduct( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerUpdateproductParams, + body: API.UpdateProductDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /product/${param0} */ +export async function productcontrollerDeleteproduct( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerDeleteproductParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /product/batchSetSku */ +export async function productcontrollerBatchsetsku( + body: API.BatchSetSkuDTO, + options?: { [key: string]: any }, +) { + return request('/product/batchSetSku', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/categorieAll */ +export async function productcontrollerGetcategorieall(options?: { + [key: string]: any; +}) { + return request('/product/categorieAll', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/categories */ +export async function productcontrollerGetcategories( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerGetcategoriesParams, + options?: { [key: string]: any }, +) { + return request('/product/categories', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /product/category */ +export async function productcontrollerCreatecategory( + body: API.CreateCategoryDTO, + options?: { [key: string]: any }, +) { + return request('/product/category', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /product/category/${param0} */ +export async function productcontrollerUpdatecategory( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerUpdatecategoryParams, + body: API.UpdateCategoryDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/category/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /product/category/${param0} */ +export async function productcontrollerDeletecategory( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerDeletecategoryParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/category/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/flavors */ +export async function productcontrollerGetflavors( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerGetflavorsParams, + options?: { [key: string]: any }, +) { + return request('/product/flavors', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /product/flavors */ +export async function productcontrollerCreateflavors( + body: API.CreateFlavorsDTO, + options?: { [key: string]: any }, +) { + return request('/product/flavors', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /product/flavors/${param0} */ +export async function productcontrollerUpdateflavors( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerUpdateflavorsParams, + body: API.UpdateFlavorsDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/flavors/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /product/flavors/${param0} */ +export async function productcontrollerDeleteflavors( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerDeleteflavorsParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/flavors/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/flavorsAll */ +export async function productcontrollerGetflavorsall(options?: { + [key: string]: any; +}) { + return request('/product/flavorsAll', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/list */ +export async function productcontrollerGetproductlist( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerGetproductlistParams, + options?: { [key: string]: any }, +) { + return request('/product/list', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/search */ +export async function productcontrollerSearchproducts( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerSearchproductsParams, + options?: { [key: string]: any }, +) { + return request('/product/search', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/sku/${param0} */ +export async function productcontrollerProductbysku( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerProductbyskuParams, + options?: { [key: string]: any }, +) { + const { sku: param0, ...queryParams } = params; + return request(`/product/sku/${param0}`, { + method: 'GET', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/strength */ +export async function productcontrollerGetstrength( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerGetstrengthParams, + options?: { [key: string]: any }, +) { + return request('/product/strength', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /product/strength */ +export async function productcontrollerCreatestrength( + body: API.CreateStrengthDTO, + options?: { [key: string]: any }, +) { + return request('/product/strength', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /product/strength/${param0} */ +export async function productcontrollerUpdatestrength( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerUpdatestrengthParams, + body: API.UpdateStrengthDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/strength/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /product/strength/${param0} */ +export async function productcontrollerDeletestrength( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.productcontrollerDeletestrengthParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/product/strength/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /product/strengthAll */ +export async function productcontrollerGetstrengthall(options?: { + [key: string]: any; +}) { + return request('/product/strengthAll', { + method: 'GET', + ...(options || {}), + }); +} diff --git a/src/servers/api/site.ts b/src/servers/api/site.ts new file mode 100644 index 0000000..a234ee2 --- /dev/null +++ b/src/servers/api/site.ts @@ -0,0 +1,11 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 GET /site/all */ +export async function sitecontrollerAll(options?: { [key: string]: any }) { + return request('/site/all', { + method: 'GET', + ...(options || {}), + }); +} diff --git a/src/servers/api/statistics.ts b/src/servers/api/statistics.ts new file mode 100644 index 0000000..17884ae --- /dev/null +++ b/src/servers/api/statistics.ts @@ -0,0 +1,93 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 POST /statistics/getCustomerOrders */ +export async function statisticscontrollerGetcustomerorders( + body: Record, + options?: { [key: string]: any }, +) { + return request('/statistics/getCustomerOrders', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /statistics/order */ +export async function statisticscontrollerGetorderstatistics( + body: API.OrderStatisticsParams, + options?: { [key: string]: any }, +) { + return request('/statistics/order', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /statistics/orderByDate */ +export async function statisticscontrollerGetorderbydate( + body: string, + options?: { [key: string]: any }, +) { + return request('/statistics/orderByDate', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /statistics/orderByEmail */ +export async function statisticscontrollerGetorderbyemail( + body: string, + options?: { [key: string]: any }, +) { + return request('/statistics/orderByEmail', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /statistics/restocking */ +export async function statisticscontrollerRestocking( + body: Record, + options?: { [key: string]: any }, +) { + return request('/statistics/restocking', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /statistics/stockForecast */ +export async function statisticscontrollerStockforecast( + body: Record, + options?: { [key: string]: any }, +) { + return request('/statistics/stockForecast', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/stock.ts b/src/servers/api/stock.ts new file mode 100644 index 0000000..dcee54e --- /dev/null +++ b/src/servers/api/stock.ts @@ -0,0 +1,284 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 GET /stock/ */ +export async function stockcontrollerGetstocks( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerGetstocksParams, + options?: { [key: string]: any }, +) { + return request('/stock/', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/cancelTransfer/${param0} */ +export async function stockcontrollerCanceltransfer( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerCanceltransferParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/cancelTransfer/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/lostTransfer/${param0} */ +export async function stockcontrollerLosttransfer( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerLosttransferParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/lostTransfer/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /stock/purchase-order */ +export async function stockcontrollerGetpurchaseorders( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerGetpurchaseordersParams, + options?: { [key: string]: any }, +) { + return request('/stock/purchase-order', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/purchase-order */ +export async function stockcontrollerCreatepurchaseorder( + body: API.CreatePurchaseOrderDTO, + options?: { [key: string]: any }, +) { + return request('/stock/purchase-order', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /stock/purchase-order/${param0} */ +export async function stockcontrollerUpdatepurchaseorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerUpdatepurchaseorderParams, + body: API.UpdatePurchaseOrderDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/purchase-order/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/purchase-order/${param0} */ +export async function stockcontrollerReceivepurchaseorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerReceivepurchaseorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/purchase-order/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /stock/purchase-order/${param0} */ +export async function stockcontrollerDelpurchaseorder( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerDelpurchaseorderParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/purchase-order/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /stock/receiveTransfer/${param0} */ +export async function stockcontrollerUpdatetransfer( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerUpdatetransferParams, + body: Record, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/receiveTransfer/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'text/plain', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/receiveTransfer/${param0} */ +export async function stockcontrollerReceivetransfer( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerReceivetransferParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/receiveTransfer/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /stock/records */ +export async function stockcontrollerGetstockrecords( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerGetstockrecordsParams, + options?: { [key: string]: any }, +) { + return request('/stock/records', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /stock/stock-point */ +export async function stockcontrollerGetstockpoints( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerGetstockpointsParams, + options?: { [key: string]: any }, +) { + return request('/stock/stock-point', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/stock-point */ +export async function stockcontrollerCreatestockpoint( + body: API.CreateStockPointDTO, + options?: { [key: string]: any }, +) { + return request('/stock/stock-point', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /stock/stock-point/${param0} */ +export async function stockcontrollerUpdatestockpoint( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerUpdatestockpointParams, + body: API.UpdateStockPointDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/stock-point/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /stock/stock-point/${param0} */ +export async function stockcontrollerDelstockpoints( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.stockcontrollerDelstockpointsParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/stock/stock-point/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /stock/stock-point/all */ +export async function stockcontrollerGetallstockpoints(options?: { + [key: string]: any; +}) { + return request('/stock/stock-point/all', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /stock/transfer */ +export async function stockcontrollerGettransfers(options?: { + [key: string]: any; +}) { + return request('/stock/transfer', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/transfer */ +export async function stockcontrollerCreatetransfer( + body: Record, + options?: { [key: string]: any }, +) { + return request('/stock/transfer', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /stock/update */ +export async function stockcontrollerUpdatestock( + body: API.UpdateStockDTO, + options?: { [key: string]: any }, +) { + return request('/stock/update', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts new file mode 100644 index 0000000..2b78cad --- /dev/null +++ b/src/servers/api/typings.d.ts @@ -0,0 +1,1469 @@ +declare namespace API { + type Address = { + address_line_1?: string; + city?: string; + region?: string; + country?: string; + postal_code?: string; + }; + + type BatchSetSkuDTO = { + /** sku 数据列表 */ + skus?: SkuItemDTO[]; + }; + + type BooleanRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: boolean; + }; + + type Category = { + /** 分类 ID */ + id: number; + /** 分类名称 */ + name: string; + /** 唯一识别key */ + unique_key: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type CategoryPaginatedResponse = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: Category[]; + }; + + type CreateCategoryDTO = { + /** 分类名称 */ + name: string; + }; + + type CreateFlavorsDTO = { + /** 分类名称 */ + name: string; + }; + + type CreateOrderNoteDTO = { + orderId?: number; + content?: string; + }; + + type CreateProductDTO = { + /** 产品名称 */ + name: string; + /** 产品描述 */ + description?: string; + /** sku */ + sku?: string; + /** 分类 ID */ + categoryId?: number; + }; + + type CreatePurchaseOrderDTO = { + stockPointId?: number; + expectedArrivalTime?: string; + status?: 'draft' | 'submitted' | 'received'; + note?: string; + items?: PurchaseOrderItem[]; + }; + + type CreateStockPointDTO = { + name?: string; + location?: string; + contactPerson?: string; + contactPhone?: string; + }; + + type CreateStrengthDTO = { + /** 分类名称 */ + name: string; + }; + + type Cubid = { + w?: number; + h?: number; + l?: number; + unit?: string; + }; + + type Date = { + year?: string; + month?: string; + day?: string; + }; + + type Destination = { + name?: string; + address?: Address; + phone_number?: PhoneNumber; + email_addresses?: any; + ready_at?: Time; + ready_until?: Time; + SignatureRequirementEnum?: any; + }; + + type Location = { + name?: string; + address?: Address; + phone_number?: PhoneNumber; + email_addresses?: any; + }; + + type LoginDTO = { + username?: string; + password?: string; + }; + + type LoginRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: LoginResDTO; + }; + + type LoginResDTO = { + token?: string; + userId?: number; + username?: string; + permissions?: string[]; + }; + + type logisticscontrollerCreateshipmentParams = { + orderId: number; + }; + + type logisticscontrollerDelshipmentParams = { + id: string; + }; + + type logisticscontrollerDelshippingaddressParams = { + id: number; + }; + + type logisticscontrollerGetlistbytrackingidParams = { + shipment_id?: string; + }; + + type logisticscontrollerGetservicelistParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + carrier_name?: string; + isActive?: boolean; + }; + + type logisticscontrollerGettrackingnumberParams = { + number?: string; + }; + + type logisticscontrollerUpdateshippingaddressParams = { + id: number; + }; + + type Measurements = { + cuboid?: Cubid; + weight?: Cubid; + }; + + type Money = { + currency?: string; + value?: string; + }; + + type Order = { + id?: number; + siteId?: string; + externalOrderId?: string; + status?: any; + orderStatus?: any; + currency?: string; + currency_symbol?: string; + prices_include_tax?: boolean; + date_created?: string; + date_modified?: string; + discount_total?: number; + discount_tax?: number; + shipping_total?: number; + shipping_tax?: number; + cart_tax?: number; + total?: number; + total_tax?: number; + customer_id?: number; + customer_email?: string; + order_key?: string; + billing?: OrderAddress; + shipping?: OrderAddress; + payment_method?: string; + payment_method_title?: string; + transaction_id?: string; + customer_ip_address?: string; + customer_user_agent?: string; + created_via?: string; + customer_note?: string; + date_completed?: string; + date_paid?: string; + cart_hash?: string; + number?: string; + meta_data?: any; + payment_url?: string; + is_editable?: boolean; + needs_payment?: boolean; + needs_processing?: boolean; + device_type?: string; + source_type?: string; + utm_source?: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type OrderAddress = { + first_name?: string; + last_name?: string; + company?: string; + address_1?: string; + address_2?: string; + city?: string; + state?: string; + postcode?: string; + country?: string; + email?: string; + phone?: string; + }; + + type ordercontrollerCancelorderParams = { + id: number; + }; + + type ordercontrollerChangestatusParams = { + id: number; + }; + + type ordercontrollerCompletedorderParams = { + id: number; + }; + + type ordercontrollerDelorderParams = { + id: number; + }; + + type ordercontrollerGetorderdetailParams = { + orderId: number; + }; + + type ordercontrollerGetordersalesParams = { + isSource?: boolean; + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + siteId?: string; + name?: string; + startDate?: string; + endDate?: string; + }; + + type ordercontrollerGetordersParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + externalOrderId?: string; + siteId?: string; + customer_email?: string; + keyword?: string; + startDate?: string; + endDate?: string; + status?: + | 'pending' + | 'processing' + | 'completed' + | 'cancelled' + | 'refunded' + | 'failed' + | 'after_sale_pending' + | 'pending_reshipment' + | 'pending_refund'; + }; + + type ordercontrollerRefundorderParams = { + id: number; + }; + + type ordercontrollerSyncorderbyidParams = { + orderId: string; + siteId: string; + }; + + type ordercontrollerSyncorderParams = { + siteId: string; + }; + + type OrderDetail = { + id?: number; + siteId?: string; + externalOrderId?: string; + status?: any; + orderStatus?: any; + currency?: string; + currency_symbol?: string; + prices_include_tax?: boolean; + date_created?: string; + date_modified?: string; + discount_total?: number; + discount_tax?: number; + shipping_total?: number; + shipping_tax?: number; + cart_tax?: number; + total?: number; + total_tax?: number; + customer_id?: number; + customer_email?: string; + order_key?: string; + billing?: OrderAddress; + shipping?: OrderAddress; + payment_method?: string; + payment_method_title?: string; + transaction_id?: string; + customer_ip_address?: string; + customer_user_agent?: string; + created_via?: string; + customer_note?: string; + date_completed?: string; + date_paid?: string; + cart_hash?: string; + number?: string; + meta_data?: any; + payment_url?: string; + is_editable?: boolean; + needs_payment?: boolean; + needs_processing?: boolean; + device_type?: string; + source_type?: string; + utm_source?: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + items?: OrderItem[]; + sales?: OrderSale[]; + refundItems?: OrderRefundItem[]; + trackings?: Tracking[]; + notes?: OrderNote[]; + }; + + type OrderDetailRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: OrderDetail; + }; + + type OrderItem = { + id?: number; + name?: string; + siteId?: string; + orderId?: number; + externalOrderId?: string; + externalOrderItemId?: string; + externalProductId?: string; + externalVariationId?: string; + quantity?: number; + subtotal?: number; + subtotal_tax?: number; + total?: number; + total_tax?: number; + sku?: string; + price?: number; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type OrderListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: OrderPaginatedRespone; + }; + + type OrderNote = { + userId?: number; + orderId?: number; + content?: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type OrderPaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: Order[]; + count?: OrderStatusCountDTO[]; + }; + + type OrderRefundItem = { + id?: number; + refundId?: number; + siteId?: string; + externalRefundId?: string; + externalRefundItemId?: string; + externalProductId?: string; + externalVariationId?: string; + name?: string; + quantity?: number; + tax_class?: string; + subtotal?: number; + subtotal_tax?: number; + total?: number; + total_tax?: number; + sku?: string; + price?: number; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type OrderSale = { + id?: number; + orderId?: number; + siteId?: string; + externalOrderItemId?: string; + productId?: number; + name?: string; + /** sku */ + sku?: string; + quantity?: number; + isPackage?: boolean; + /** 创建时间 */ + createdAt?: string; + /** 更新时间 */ + updatedAt?: string; + }; + + type OrderSaleDTO = { + id?: number; + orderId?: number; + siteId?: string; + externalOrderItemId?: string; + productId?: number; + name?: string; + /** sku */ + sku?: string; + quantity?: number; + isPackage?: boolean; + /** 创建时间 */ + createdAt?: string; + /** 更新时间 */ + updatedAt?: string; + totalQuantity?: number; + }; + + type OrderSaleListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: OrderSalePaginatedRespone; + }; + + type OrderSalePaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: OrderSaleDTO[]; + }; + + type OrderStatisticsParams = { + startDate?: string; + endDate?: string; + keyword?: string; + siteId?: string; + purchaseType?: 'all' | 'first_purchase' | 'repeat_purchase'; + orderType?: 'all' | 'cpc' | 'non_cpc'; + brand?: 'all' | 'zyn' | 'yoone' | 'zolt'; + }; + + type OrderStatusCountDTO = { + status?: string; + count?: number; + }; + + type Package = { + measurements?: Measurements; + description?: string; + }; + + type PackagingPackage = { + packages?: Package[]; + }; + + type PhoneNumber = { + number?: string; + extension?: string; + }; + + type Product = { + /** ID */ + id: number; + /** 产品名称 */ + name: string; + /** 产品描述 */ + description?: string; + /** 分类 ID */ + categoryId?: number; + flavorsId?: number; + strengthId?: number; + /** sku */ + sku?: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type ProductCatListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: CategoryPaginatedResponse; + }; + + type ProductCatRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: Category; + }; + + type productcontrollerDeletecategoryParams = { + id: number; + }; + + type productcontrollerDeleteflavorsParams = { + id: number; + }; + + type productcontrollerDeleteproductParams = { + id: number; + }; + + type productcontrollerDeletestrengthParams = { + id: number; + }; + + type productcontrollerGetcategoriesParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type productcontrollerGetflavorsParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type productcontrollerGetproductlistParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + /** 分类 ID */ + categoryId?: number; + }; + + type productcontrollerGetstrengthParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type productcontrollerProductbyskuParams = { + sku: string; + }; + + type productcontrollerSearchproductsParams = { + name?: string; + }; + + type productcontrollerUpdatecategoryParams = { + id: number; + }; + + type productcontrollerUpdateflavorsParams = { + id: number; + }; + + type productcontrollerUpdateproductParams = { + id: number; + }; + + type productcontrollerUpdatestrengthParams = { + id: number; + }; + + type ProductListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: ProductPaginatedResponse; + }; + + type ProductPaginatedResponse = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: Product[]; + }; + + type ProductRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: Product; + }; + + type ProductsRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: Product[]; + }; + + type PurchaseOrderDTO = { + id?: number; + stockPointId?: number; + orderNumber?: string; + status?: any; + note?: string; + /** 预计时间 */ + expectedArrivalTime: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + items?: PurchaseOrderItem[]; + }; + + type PurchaseOrderItem = { + id?: number; + productSku?: string; + productName?: string; + quantity?: number; + price?: number; + purchaseOrderId?: number; + }; + + type PurchaseOrderListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: PurchaseOrderPaginatedRespone; + }; + + type PurchaseOrderPaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: PurchaseOrderDTO[]; + }; + + type QueryCategoryDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type QueryFlavorsDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type QueryOrderDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + externalOrderId?: string; + siteId?: string; + customer_email?: string; + keyword?: string; + startDate?: string; + endDate?: string; + status?: + | 'pending' + | 'processing' + | 'completed' + | 'cancelled' + | 'refunded' + | 'failed' + | 'after_sale_pending' + | 'pending_reshipment' + | 'pending_refund'; + }; + + type QueryOrderSalesDTO = { + isSource?: boolean; + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + siteId?: string; + name?: string; + startDate?: string; + endDate?: string; + }; + + type QueryPointDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + }; + + type QueryProductDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + /** 分类 ID */ + categoryId?: number; + }; + + type QueryPurchaseOrderDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + orderNumber?: string; + stockPointId?: number; + }; + + type QueryServiceDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + carrier_name?: string; + isActive?: boolean; + }; + + type QueryStockDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + productName?: string; + }; + + type QueryStockRecordDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + stockPointId?: number; + productSku?: string; + productName?: string; + }; + + type QueryStrengthDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + name?: string; + }; + + type QueryWpProductDTO = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 产品名 */ + name?: string; + /** 站点ID */ + siteId?: string; + /** 产品状态 */ + status?: + | 'publish' + | 'draft' + | 'pending' + | 'private' + | 'trash' + | 'auto-draft' + | 'future' + | 'inherit'; + }; + + type RateDTO = { + carrier_name?: string; + service_name?: string; + service_id?: string; + valid_until?: Date; + total?: Money; + base?: Money; + surcharges?: Surcharges[]; + taxes?: Money[]; + transit_time_days?: number; + transit_time_not_available?: boolean; + }; + + type RateLitRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: RateDTO[]; + }; + + type Service = { + id?: string; + carrier_name?: string; + service_name?: string; + isActive?: boolean; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type ServiceListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: Service[]; + }; + + type SetConstitutionDTO = { + isProduct?: boolean; + /** 构成成分 */ + constitution?: { sku?: string; quantity?: number }[]; + }; + + type ShipmentBookDTO = { + sales?: OrderSale[]; + payment_method_id?: string; + service_id?: string; + service_type?: string; + details?: ShippingDetailsDTO; + stockPointId?: number; + orderIds?: number[]; + }; + + type ShipmentItem = { + id?: number; + shipment_id?: string; + productId?: number; + name?: string; + /** sku */ + sku?: string; + quantity?: number; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type ShippingAddress = { + id?: number; + name?: string; + stockPointId?: number; + address?: Address; + phone_number?: string; + phone_number_extension?: string; + phone_number_country?: string; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type ShippingAddressListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: ShippingAddress[]; + }; + + type ShippingDetailsDTO = { + origin?: Location; + destination?: Destination; + expected_ship_date?: Date; + packaging_type?: 'pallet' | 'package' | 'courier-pak' | 'envelope'; + packaging_properties?: PackagingPackage[]; + reference_codes?: any; + }; + + type SiteConfig = { + /** 站点 ID */ + id?: string; + /** 站点 URL */ + wpApiUrl?: string; + /** 站点 rest key */ + consumerKey?: string; + /** 站点 rest 秘钥 */ + consumerSecret?: string; + /** 站点名 */ + siteName?: string; + /** 站点邮箱 */ + email?: string; + /** 站点邮箱密码 */ + emailPswd?: string; + }; + + type SkuItemDTO = { + /** 产品 ID */ + productId?: number; + /** sku 编码 */ + sku?: string; + }; + + type stockcontrollerCanceltransferParams = { + id: number; + }; + + type stockcontrollerDelpurchaseorderParams = { + id: number; + }; + + type stockcontrollerDelstockpointsParams = { + id: number; + }; + + type stockcontrollerGetpurchaseordersParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + orderNumber?: string; + stockPointId?: number; + }; + + type stockcontrollerGetstockpointsParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + }; + + type stockcontrollerGetstockrecordsParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + stockPointId?: number; + productSku?: string; + productName?: string; + }; + + type stockcontrollerGetstocksParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + productName?: string; + }; + + type stockcontrollerLosttransferParams = { + id: number; + }; + + type stockcontrollerReceivepurchaseorderParams = { + id: number; + }; + + type stockcontrollerReceivetransferParams = { + id: number; + }; + + type stockcontrollerUpdatepurchaseorderParams = { + id: number; + }; + + type stockcontrollerUpdatestockpointParams = { + id: number; + }; + + type stockcontrollerUpdatetransferParams = { + id: number; + }; + + type StockDTO = { + id?: number; + stockPointId?: number; + productSku?: string; + quantity?: number; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + productName?: string; + stockPoint?: Record[]; + }; + + type StockListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: StockPaginatedRespone; + }; + + type StockPaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: StockDTO[]; + }; + + type StockPoint = { + id?: number; + name?: string; + location?: string; + contactPerson?: string; + contactPhone?: string; + ignore?: boolean; + inCanada?: boolean; + isB?: boolean; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + }; + + type StockPointAllRespone = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: StockPoint[]; + }; + + type StockPointListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: StockPointPaginatedRespone; + }; + + type StockPointPaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: StockPoint[]; + }; + + type StockRecordDTO = { + id?: number; + stockPointId?: number; + productSku?: string; + operationType?: any; + quantityChange?: number; + operatorId?: number; + /** 创建时间 */ + createdAt: string; + note?: string; + productName?: string; + }; + + type StockRecordListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: StockRecordPaginatedRespone; + }; + + type StockRecordPaginatedRespone = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: StockRecordDTO[]; + }; + + type Surcharges = { + type?: string; + amount?: Money; + }; + + type Time = { + hour?: string; + minute?: string; + }; + + type Tracking = { + id?: string; + tracking_provider?: string; + unique_id?: string; + transaction_number?: string; + primary_tracking_number?: string; + tracking_numbers?: string[]; + tracking_url?: string; + return_tracking_number?: string; + bol_number?: string; + pickup_confirmation_number?: string; + customs_invoice_url?: string; + rate?: Record; + labels?: any; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + products?: ShipmentItem[]; + }; + + type UpdateCategoryDTO = { + /** 分类名称 */ + name?: string; + }; + + type UpdateFlavorsDTO = { + /** 分类名称 */ + name?: string; + }; + + type UpdateProductDTO = { + /** 产品名称 */ + name?: string; + /** 产品描述 */ + description?: string; + /** sku */ + sku?: string; + /** 分类 ID */ + categoryId?: number; + }; + + type UpdatePurchaseOrderDTO = { + stockPointId?: number; + expectedArrivalTime?: string; + status?: 'draft' | 'submitted' | 'received'; + note?: string; + items?: PurchaseOrderItem[]; + }; + + type UpdateStockDTO = { + stockPointId?: number; + productSku?: string; + quantityChange?: number; + operationType?: 'in' | 'out'; + operatorId?: number; + note?: string; + }; + + type UpdateStockPointDTO = { + name?: string; + location?: string; + contactPerson?: string; + contactPhone?: string; + }; + + type UpdateStrengthDTO = { + /** 分类名称 */ + name?: string; + }; + + type UpdateVariationDTO = { + /** 产品名称 */ + name?: string; + /** SKU */ + sku?: string; + /** 常规价格 */ + regular_price?: number; + /** 销售价格 */ + sale_price?: number; + /** 是否促销中 */ + on_sale?: boolean; + }; + + type UpdateWpProductDTO = { + /** 变体名称 */ + name?: string; + /** SKU */ + sku?: string; + /** 常规价格 */ + regular_price?: number; + /** 销售价格 */ + sale_price?: number; + /** 是否促销中 */ + on_sale?: boolean; + }; + + type VariationDTO = { + /** ID */ + id: number; + /** wp网站ID */ + siteId: string; + /** wp产品ID */ + externalProductId: string; + /** wp变体ID */ + externalVariationId: string; + /** 对应WP产品表的ID */ + productId: number; + /** sku */ + sku?: string; + /** 变体名称 */ + name: string; + /** 常规价格 */ + regular_price?: number; + /** 销售价格 */ + sale_price?: number; + /** 是否促销中 */ + on_sale?: boolean; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + /** 变体构成成分 */ + constitution?: { sku?: string; quantity?: number }[]; + }; + + type webhookcontrollerHandlewoowebhookParams = { + siteId?: string; + }; + + type wpproductcontrollerGetwpproductsParams = { + /** 页码 */ + current?: number; + /** 每页大小 */ + pageSize?: number; + /** 产品名 */ + name?: string; + /** 站点ID */ + siteId?: string; + /** 产品状态 */ + status?: + | 'publish' + | 'draft' + | 'pending' + | 'private' + | 'trash' + | 'auto-draft' + | 'future' + | 'inherit'; + }; + + type wpproductcontrollerSetconstitutionParams = { + id: number; + }; + + type wpproductcontrollerSyncproductsParams = { + siteId: string; + }; + + type wpproductcontrollerUpdateproductParams = { + productId: string; + siteId: string; + }; + + type wpproductcontrollerUpdatevariationParams = { + variationId: string; + productId: string; + siteId: string; + }; + + type WpProductDTO = { + /** ID */ + id: number; + /** wp网站ID */ + siteId: string; + /** wp产品ID */ + externalProductId: string; + /** sku */ + sku?: string; + /** 产品名称 */ + name: string; + /** 产品状态 */ + status?: + | 'publish' + | 'draft' + | 'pending' + | 'private' + | 'trash' + | 'auto-draft' + | 'future' + | 'inherit'; + /** 常规价格 */ + regular_price?: number; + /** 销售价格 */ + sale_price?: number; + /** 是否促销中 */ + on_sale?: boolean; + /** 产品类型 */ + type?: 'simple' | 'variable'; + /** 创建时间 */ + createdAt: string; + /** 更新时间 */ + updatedAt: string; + /** 产品构成成分 */ + constitution?: { sku?: string; quantity?: number }[]; + /** 变体列表 */ + variations?: VariationDTO[]; + }; + + type WpProductListRes = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: WpProductPaginatedResponse; + }; + + type WpProductPaginatedResponse = { + /** 当前页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 总记录数 */ + total?: number; + /** 数据列表 */ + items?: WpProductDTO[]; + }; + + type WpSitesResponse = { + /** 状态码 */ + code?: number; + /** 是否成功 */ + success?: boolean; + /** 消息内容 */ + message?: string; + /** 响应数据 */ + data?: SiteConfig[]; + }; +} diff --git a/src/servers/api/user.ts b/src/servers/api/user.ts new file mode 100644 index 0000000..e264b03 --- /dev/null +++ b/src/servers/api/user.ts @@ -0,0 +1,74 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 GET /user/ */ +export async function usercontrollerGetuser(options?: { [key: string]: any }) { + return request('/user/', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /user/add */ +export async function usercontrollerAdduser( + body: Record, + options?: { [key: string]: any }, +) { + return request('/user/add', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /user/list */ +export async function usercontrollerListusers(options?: { + [key: string]: any; +}) { + return request('/user/list', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /user/login */ +export async function usercontrollerLogin( + body: API.LoginDTO, + options?: { [key: string]: any }, +) { + return request('/user/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /user/logout */ +export async function usercontrollerLogout(options?: { [key: string]: any }) { + return request('/user/logout', { + method: 'POST', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /user/toggleActive */ +export async function usercontrollerToggleactive( + body: Record, + options?: { [key: string]: any }, +) { + return request('/user/toggleActive', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/webhook.ts b/src/servers/api/webhook.ts new file mode 100644 index 0000000..7bc69dd --- /dev/null +++ b/src/servers/api/webhook.ts @@ -0,0 +1,31 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 GET /webhook/ */ +export async function webhookcontrollerTest(options?: { [key: string]: any }) { + return request('/webhook/', { + method: 'GET', + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 POST /webhook/woocommerce */ +export async function webhookcontrollerHandlewoowebhook( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.webhookcontrollerHandlewoowebhookParams, + body: Record, + options?: { [key: string]: any }, +) { + return request('/webhook/woocommerce', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + params: { + ...params, + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/wpProduct.ts b/src/servers/api/wpProduct.ts new file mode 100644 index 0000000..c1bcb06 --- /dev/null +++ b/src/servers/api/wpProduct.ts @@ -0,0 +1,100 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 此处后端没有提供注释 PUT /wp_product/${param0}/constitution */ +export async function wpproductcontrollerSetconstitution( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.wpproductcontrollerSetconstitutionParams, + body: API.SetConstitutionDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/wp_product/${param0}/constitution`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /wp_product/list */ +export async function wpproductcontrollerGetwpproducts( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.wpproductcontrollerGetwpproductsParams, + options?: { [key: string]: any }, +) { + return request('/wp_product/list', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /wp_product/siteId/${param1}/products/${param0} */ +export async function wpproductcontrollerUpdateproduct( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.wpproductcontrollerUpdateproductParams, + body: API.UpdateWpProductDTO, + options?: { [key: string]: any }, +) { + const { productId: param0, siteId: param1, ...queryParams } = params; + return request( + `/wp_product/siteId/${param1}/products/${param0}`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }, + ); +} + +/** 此处后端没有提供注释 PUT /wp_product/siteId/${param2}/products/${param1}/variations/${param0} */ +export async function wpproductcontrollerUpdatevariation( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.wpproductcontrollerUpdatevariationParams, + body: API.UpdateVariationDTO, + options?: { [key: string]: any }, +) { + const { + variationId: param0, + productId: param1, + siteId: param2, + ...queryParams + } = params; + return request( + `/wp_product/siteId/${param2}/products/${param1}/variations/${param0}`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }, + ); +} + +/** 此处后端没有提供注释 POST /wp_product/sync/${param0} */ +export async function wpproductcontrollerSyncproducts( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.wpproductcontrollerSyncproductsParams, + options?: { [key: string]: any }, +) { + const { siteId: param0, ...queryParams } = params; + return request(`/wp_product/sync/${param0}`, { + method: 'POST', + params: { ...queryParams }, + ...(options || {}), + }); +} diff --git a/src/utils/format.ts b/src/utils/format.ts new file mode 100644 index 0000000..53120bf --- /dev/null +++ b/src/utils/format.ts @@ -0,0 +1,61 @@ +import { ProSchemaValueEnumObj } from '@ant-design/pro-components'; +import { BaseType } from 'typings'; + +/** + * 将数组转换成 valueEnum 格式 + * @param array 数据源数组 + * @param options 转换配置 + * @returns valueEnum 对象 + */ +export function transformToValueEnum( + array: T[], + options: BaseType.EnumTransformOptions = { + value: 'id', + label: 'name', + status: 'status', + color: 'color', + }, +): ProSchemaValueEnumObj { + const { value, label, status, color } = options; + + return array.reduce((acc, item: any) => { + const key = String(item[value]); + acc[key] = { + text: String(item[label]), + ...(status && item[status] ? { status: String(item[status]) } : {}), + ...(color && item[color] ? { color: String(item[color]) } : {}), + }; + return acc; + }, {} as ProSchemaValueEnumObj); +} + +export function formatSource(type: string | undefined, utm?: string) { + if (!type) return 'Unknon'; + if (type === 'admin') return 'Web Admin'; + if (type === 'typein') return 'Direct'; + if (type === 'utm') return 'Source: ' + utm; + return type + ': ' + utm; +} + +export function formatShipmentState(state: string) { + switch (state) { + case 'draft': + return '草稿'; + case 'waiting-for-scheduling': + return '等待调度'; + case 'waiting-for-transit': + return '等待运输'; + case 'in-transit': + return '运输中'; + case 'delivered': + return '已到达'; + case 'exception': + return '异常'; + case 'missing': + return '丢失'; + case 'cancelled': + return '取消'; + default: + return ''; + } +} diff --git a/src/utils/util.ts b/src/utils/util.ts new file mode 100644 index 0000000..c5ddf9d --- /dev/null +++ b/src/utils/util.ts @@ -0,0 +1,25 @@ +import printJS from 'print-js'; + +export async function printPDF(urls: string[]) { + let index = 0; + + function next() { + if (index >= urls.length) return; + printJS({ + printable: urls[index], + type: 'pdf', + showModal: true, + onPrintDialogClose: () => { + index++; + setTimeout(next, 1000); // 等待下一个 + }, + onError: (err) => { + console.error('打印失败:', err); + index++; + next(); + }, + }); + } + + next(); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..133cfd8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./src/.umi/tsconfig.json" +} diff --git a/typings.d.ts b/typings.d.ts new file mode 100644 index 0000000..82c7dc7 --- /dev/null +++ b/typings.d.ts @@ -0,0 +1,16 @@ +import '@umijs/max/typings'; + +declare namespace BaseType { + + type EnumTransformOptions { + value: string; // 用于作为 value 的字段名 + label: string; // 用于作为 text 的字段名 + status?: string | undefined; // 可选:用于设置状态的字段名 + color?: string | undefined; // 可选:用于设置颜色的字段名 + } + +} + +declare global { + const UMI_APP_API_URL: string; + } \ No newline at end of file