diff --git a/.umirc.ts b/.umirc.ts index a04289d..aa54802 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -310,11 +310,6 @@ export default defineConfig({ changeOrigin: true, pathRewrite: { '^/api': '' }, }, - '/site-api': { - target: UMI_APP_API_URL, - changeOrigin: true, - pathRewrite: { '^/site-api': '/site-api' }, - }, }, npmClient: 'pnpm', }); diff --git a/src/app.tsx b/src/app.tsx index fc9f857..6144a5f 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -72,7 +72,7 @@ export const layout = (): ProLayoutProps => { }; export const request: RequestConfig = { - baseURL: UMI_APP_API_URL, + baseURL: '/api', // baseURL: UMI_APP_API_URL, requestInterceptors: [ (url: string, options: any) => { const token = localStorage.getItem('token'); diff --git a/src/pages/Product/Permutation/index.tsx b/src/pages/Product/Permutation/index.tsx index 06f40ca..033ccc9 100644 --- a/src/pages/Product/Permutation/index.tsx +++ b/src/pages/Product/Permutation/index.tsx @@ -296,45 +296,7 @@ const PermutationPage: React.FC = () => { }} scroll={{ x: 'max-content' }} search={false} - toolBarRender={() => [ - { - const exportColumns = columns.filter((c: any) => c.key !== 'action'); - const headers = exportColumns.map((c: any) => String(c.title ?? '')); - const escapeCsv = (val: any) => { - const s = val === undefined || val === null ? '' : String(val); - if (/[",\n]/.test(s)) { - return '"' + s.replace(/"/g, '""') + '"'; - } - return s; - }; - const rows: string[][] = permutations.map((record: any) => { - return exportColumns.map((c: any) => { - if (c.key === 'sku') { - const key = generateKeyFromPermutation(record); - const product = existingProducts.get(key); - const value = product?.sku || ''; - return escapeCsv(value); - } - const valueItem = c.dataIndex ? record[c.dataIndex] : undefined; - const value = valueItem?.name || ''; - return escapeCsv(value); - }); - }); - const csvContent = [headers, ...rows].map(row => row.join(',')).join('\n'); - const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - const categoryName = categories.find(c => c.id === categoryId)?.name || 'Export'; - link.href = url; - link.download = categoryName + '-permutations.csv'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); - }}> - 导出CSV - - ]} + toolBarRender={false} /> )} diff --git a/src/pages/Site/List/index.tsx b/src/pages/Site/List/index.tsx index 36ab559..76211c6 100644 --- a/src/pages/Site/List/index.tsx +++ b/src/pages/Site/List/index.tsx @@ -1,17 +1,21 @@ import { ActionType, - DrawerForm, ProColumns, - ProFormDependency, - ProFormInstance, - ProFormSelect, - ProFormSwitch, - ProFormText, ProTable, } from '@ant-design/pro-components'; +import { + sitecontrollerCreate, + sitecontrollerDisable, + sitecontrollerList, + sitecontrollerUpdate, +} from '@/servers/api/site'; +import { wpproductcontrollerSyncproducts } from '@/servers/api/wpProduct'; +import { ordercontrollerSyncorder } from '@/servers/api/order'; +import { subscriptioncontrollerSync } from '@/servers/api/subscription'; import { request } from '@umijs/max'; import { Button, message, notification, Popconfirm, Space, Tag } from 'antd'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useRef, useState } from 'react'; +import EditSiteForm from '../Shop/EditSiteForm'; // 引入重构后的表单组件 // 区域数据项类型 interface AreaItem { @@ -26,11 +30,12 @@ interface StockPointItem { } // 站点数据项类型(前端不包含密钥字段,后端列表不返回密钥) -interface SiteItem { +export interface SiteItem { id: number; name: string; description?: string; apiUrl?: string; + websiteUrl?: string; // 网站地址 type?: 'woocommerce' | 'shopyy'; skuPrefix?: string; isDisabled: number; @@ -38,24 +43,8 @@ interface SiteItem { stockPoints?: StockPointItem[]; } -// 创建/更新表单的值类型,包含可选的密钥字段 -interface SiteFormValues { - name: string; - description?: string; - apiUrl?: string; - type?: 'woocommerce' | 'shopyy'; - isDisabled?: boolean; - consumerKey?: string; // WooCommerce REST API 的 consumer key - consumerSecret?: string; // WooCommerce REST API 的 consumer secret - token?: string; // Shopyy token - skuPrefix?: string; - areas?: string[]; - stockPointIds?: number[]; -} - const SiteList: React.FC = () => { const actionRef = useRef(); - const formRef = useRef(); const [open, setOpen] = useState(false); const [editing, setEditing] = useState(null); const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -73,24 +62,27 @@ const SiteList: React.FC = () => { try { for (const id of ids) { // 同步产品 - const prodRes = await request(`/wp_product/sync/${id}`, { method: 'POST' }); - if (prodRes) { - stats.products.success += prodRes.successCount || 0; - stats.products.fail += prodRes.failureCount || 0; + const prodRes = await wpproductcontrollerSyncproducts({ siteId: id }); + if (prodRes.success) { + stats.products.success += 1; + } else { + stats.products.fail += 1; } // 同步订单 - const orderRes = await request(`/order/syncOrder/${id}`, { method: 'POST' }); - if (orderRes) { - stats.orders.success += orderRes.successCount || 0; - stats.orders.fail += orderRes.failureCount || 0; + const orderRes = await ordercontrollerSyncorder({ siteId: id }); + if (orderRes.success) { + stats.orders.success += 1; + } else { + stats.orders.fail += 1; } // 同步订阅 - const subRes = await request(`/subscription/sync/${id}`, { method: 'POST' }); - if (subRes) { - stats.subscriptions.success += subRes.successCount || 0; - stats.subscriptions.fail += subRes.failureCount || 0; + const subRes = await subscriptioncontrollerSync({ siteId: id }); + if (subRes.success) { + stats.subscriptions.success += 1; + } else { + stats.subscriptions.fail += 1; } } hide(); @@ -115,39 +107,6 @@ const SiteList: React.FC = () => { } }; - useEffect(() => { - if (!open) return; - if (editing) { - formRef.current?.setFieldsValue({ - name: editing.name, - description: editing.description, - apiUrl: editing.apiUrl, - type: editing.type, - skuPrefix: editing.skuPrefix, - isDisabled: !!editing.isDisabled, - consumerKey: undefined, - consumerSecret: undefined, - token: undefined, - areas: editing.areas?.map((area) => area.code) ?? [], - stockPointIds: editing.stockPoints?.map((sp) => sp.id) ?? [], - }); - } else { - formRef.current?.setFieldsValue({ - name: undefined, - description: undefined, - apiUrl: undefined, - type: 'woocommerce', - skuPrefix: undefined, - isDisabled: false, - consumerKey: undefined, - consumerSecret: undefined, - token: undefined, - areas: [], - stockPointIds: [], - }); - } - }, [open, editing]); - // 表格列定义 const columns: ProColumns[] = [ { @@ -160,6 +119,13 @@ const SiteList: React.FC = () => { { title: '名称', dataIndex: 'name', width: 220 }, { title: '描述', dataIndex: 'description', width: 220, hideInSearch: true }, { title: 'API 地址', dataIndex: 'apiUrl', width: 280, hideInSearch: true }, + { + title: '网站地址', + dataIndex: 'websiteUrl', + width: 280, + hideInSearch: true, + render: (text) => {text} + }, { title: 'SKU 前缀', dataIndex: 'skuPrefix', @@ -176,24 +142,6 @@ const SiteList: React.FC = () => { { label: 'Shopyy', value: 'shopyy' }, ], }, - // { - // title: '区域', - // dataIndex: 'areas', - // width: 200, - // hideInSearch: true, - // render: (_, row) => { - // if (!row.areas || row.areas.length === 0) { - // return 全球; - // } - // return ( - // - // {row.areas.map((area) => ( - // {area.name} - // ))} - // - // ); - // }, - // }, { title: '关联仓库', dataIndex: 'stockPoints', @@ -254,10 +202,7 @@ const SiteList: React.FC = () => { } onConfirm={async () => { try { - await request(`/site/disable/${row.id}`, { - method: 'PUT', - data: { disabled: !row.isDisabled }, - }); + await sitecontrollerDisable({ id: String(row.id) }, { disabled: !row.isDisabled }); message.success('更新成功'); actionRef.current?.reload(); } catch (e: any) { @@ -277,21 +222,17 @@ const SiteList: React.FC = () => { // 表格数据请求 const tableRequest = async (params: Record) => { try { - const { current = 1, pageSize = 10, name, type } = params; - const resp = await request('/site/list', { - method: 'GET', - params: { - current, - pageSize, - keyword: name || undefined, - type: type || undefined, - }, + const { current, pageSize, name, type } = params; + const resp = await sitecontrollerList({ + current, + pageSize, + keyword: name || undefined, + type: type || undefined, }); - const { success, data, message: errMsg } = resp as any; - if (!success) throw new Error(errMsg || '获取失败'); + // 假设 resp 直接就是后端返回的结构,包含 items 和 total return { - data: (data?.items ?? []) as SiteItem[], - total: data?.total ?? 0, + data: (resp?.data?.items ?? []) as SiteItem[], + total: resp?.data?.total ?? 0, success: true, }; } catch (e: any) { @@ -300,80 +241,20 @@ const SiteList: React.FC = () => { } }; - // 提交创建/更新逻辑;编辑时未填写密钥则不提交(保持原值) - const handleSubmit = async (values: SiteFormValues) => { + const handleFinish = async (values: any) => { try { - const isShopyy = values.type === 'shopyy'; - const apiUrl = isShopyy ? 'https://openapi.oemapps.com' : values.apiUrl; - if (editing) { - const payload: Record = { - // 仅提交存在的字段,避免覆盖为 null/空 - ...(values.name ? { name: values.name } : {}), - ...(values.description ? { description: values.description } : {}), - ...(apiUrl ? { apiUrl: apiUrl } : {}), - ...(values.type ? { type: values.type } : {}), - ...(typeof values.isDisabled === 'boolean' - ? { isDisabled: values.isDisabled } - : {}), - ...(values.skuPrefix ? { skuPrefix: values.skuPrefix } : {}), - areas: values.areas ?? [], - stockPointIds: values.stockPointIds ?? [], - }; - - if (isShopyy) { - if (values.token && values.token.trim()) { - payload.token = values.token.trim(); - } - } else { - // 仅当输入了新密钥时才提交,未输入则保持原本值 - if (values.consumerKey && values.consumerKey.trim()) { - payload.consumerKey = values.consumerKey.trim(); - } - if (values.consumerSecret && values.consumerSecret.trim()) { - payload.consumerSecret = values.consumerSecret.trim(); - } - } - - await request(`/site/update/${editing.id}`, { - method: 'PUT', - data: payload, - }); + await sitecontrollerUpdate({ id: String(editing.id) }, values); + message.success('更新成功'); } else { - if (isShopyy) { - if (!values.token) { - throw new Error('Token is required for Shopyy'); - } - } else { - // 新增站点时要求填写 consumerKey 和 consumerSecret - if (!values.consumerKey || !values.consumerSecret) { - throw new Error('Consumer Key and Secret are required for WooCommerce'); - } - } - - await request('/site/create', { - method: 'POST', - data: { - name: values.name, - description: values.description, - apiUrl: apiUrl, - type: values.type || 'woocommerce', - consumerKey: isShopyy ? undefined : values.consumerKey, - consumerSecret: isShopyy ? undefined : values.consumerSecret, - token: isShopyy ? values.token : undefined, - skuPrefix: values.skuPrefix, - areas: values.areas ?? [], - stockPointIds: values.stockPointIds ?? [], - }, - }); + await sitecontrollerCreate(values); + message.success('创建成功'); } - message.success('提交成功'); setOpen(false); - setEditing(null); actionRef.current?.reload(); return true; - } catch (e: any) { - message.error(e?.message || '提交失败'); + } catch (error: any) { + message.error(error.message || '操作失败'); return false; } }; @@ -381,7 +262,7 @@ const SiteList: React.FC = () => { return ( <> - scroll={{ x: 'max-content' }} + scroll={{ x: 'max-content' }} actionRef={actionRef} rowKey="id" columns={columns} @@ -392,161 +273,35 @@ const SiteList: React.FC = () => { }} toolBarRender={() => [ { setEditing(null); setOpen(true); }} > - 新增站点 + 新建站点 , - // 同步包括 orders subscriptions 等等 handleSync(selectedRowKeys as number[])} > - 同步站点数据 + 批量同步 , ]} /> - - title={editing ? '编辑站点' : '新增站点'} + - {/* 站点名称,必填 */} - - - - - {/* 仓库选择 */} - { - try { - const resp = await request('/stock/stock-point/all', { - method: 'GET', - }); - if (resp.success) { - return resp.data.map((item: any) => ({ - label: item.name, - value: item.id, - })); - } - return []; - } catch (e) { - return []; - } - }} - /> - - {/* 区域选择 - 暂时隐藏 */} - {/* { - try { - const resp = await request('/area', { - method: 'GET', - params: { pageSize: 1000 }, - }); - if (resp.success) { - return resp.data.list.map((area: AreaItem) => ({ - label: area.name, - value: area.code, - })); - } - return []; - } catch (e) { - return []; - } - }} - /> */} - - {/* 平台类型选择 */} - - - - {({ type }) => { - const isShopyy = type === 'shopyy'; - return isShopyy ? ( - <> - - - > - ) : ( - <> - - {/* WooCommerce REST consumer key */} - - {/* WooCommerce REST consumer secret */} - - > - ); - }} - - - {editing && } - - - + onOpenChange={(visible) => { + setOpen(visible); + if (!visible) { + setEditing(null); + } + }} + initialValues={editing} + isEdit={!!editing} + onFinish={handleFinish} + /> > ); }; diff --git a/src/pages/Site/Shop/Customers/index.tsx b/src/pages/Site/Shop/Customers/index.tsx index 7d6e414..e95618a 100644 --- a/src/pages/Site/Shop/Customers/index.tsx +++ b/src/pages/Site/Shop/Customers/index.tsx @@ -144,18 +144,6 @@ const CustomerPage: React.FC = () => { return {role}; }, }, - { - title: '订单数', - dataIndex: 'orders', - sorter: true, - hideInSearch: true, - }, - { - title: '总花费', - dataIndex: 'total_spend', - sorter: true, - hideInSearch: true, - }, { title: '账单地址', dataIndex: 'billing', @@ -173,23 +161,6 @@ const CustomerPage: React.FC = () => { ); }, }, - { - title: '收货地址', - dataIndex: 'shipping', - hideInSearch: true, - render: (_, record) => { - const { shipping } = record; - if (!shipping) return '-'; - return ( - - {shipping.address_1} {shipping.address_2} - {shipping.city}, {shipping.state}, {shipping.postcode} - {shipping.country} - {shipping.phone} - - ); - }, - }, { title: '注册时间', dataIndex: 'date_created', @@ -268,21 +239,9 @@ const CustomerPage: React.FC = () => { } const data = response.data; - let items = (data?.items || []) as any[]; - if (sort && typeof sort === 'object') { - const [field, dir] = Object.entries(sort)[0] || []; - if (field === 'orders' || field === 'total_spend') { - const isDesc = dir === 'descend'; - items = items.slice().sort((a, b) => { - const av = Number(a?.[field] ?? 0); - const bv = Number(b?.[field] ?? 0); - return isDesc ? bv - av : av - bv; - }); - } - } return { total: data?.total || 0, - data: items, + data: data?.items || [], success: true, }; }} @@ -411,19 +370,42 @@ const CustomerPage: React.FC = () => { search={false} pagination={{ pageSize: 20 }} columns={[ - { title: '订单ID', dataIndex: 'id' }, - { title: '订单号', dataIndex: 'number' }, - { title: '状态', dataIndex: 'status' }, - { title: '币种', dataIndex: 'currency' }, - { title: '金额', dataIndex: 'total' }, - { title: '创建时间', dataIndex: 'date_created', valueType: 'dateTime' }, + { title: '订单号', dataIndex: 'number', copyable: true }, + { + title: '客户邮箱', + dataIndex: 'email', + copyable: true, + render: () => { + return ordersCustomer?.email; + }, + }, + { title: '支付时间', dataIndex: 'date_paid', valueType: 'dateTime', hideInSearch: true }, + { title: '订单金额', dataIndex: 'total', hideInSearch: true }, + { title: '状态', dataIndex: 'status', hideInSearch: true }, + { title: '来源', dataIndex: 'created_via', hideInSearch: true }, + { + title: '订单内容', + dataIndex: 'line_items', + hideInSearch: true, + render: (_, record) => { + return ( + + {record.line_items?.map((item: any) => ( + + {item.name} x {item.quantity} + + ))} + + ); + }, + }, ]} request={async (params) => { if (!siteId || !ordersCustomer?.id) return { data: [], total: 0, success: true }; const res = await request(`/site-api/${siteId}/customers/${ordersCustomer.id}/orders`, { params: { page: params.current, - page_size: params.pageSize, + per_page: params.pageSize, }, }); if (!res?.success) { diff --git a/src/pages/Site/Shop/EditSiteForm.tsx b/src/pages/Site/Shop/EditSiteForm.tsx new file mode 100644 index 0000000..de5ca03 --- /dev/null +++ b/src/pages/Site/Shop/EditSiteForm.tsx @@ -0,0 +1,158 @@ + +import { + DrawerForm, + ProFormDependency, + ProFormSelect, + ProFormSwitch, + ProFormText, + ProFormTextArea, +} from '@ant-design/pro-components'; +import { Form } from 'antd'; +import React, { useEffect } from 'react'; +import { areacontrollerGetarealist } from '@/servers/api/area'; +import { stockcontrollerGetallstockpoints } from '@/servers/api/stock'; + +// 定义组件的 props 类型 +interface EditSiteFormProps { + open: boolean; // 控制抽屉表单的显示和隐藏 + onOpenChange: (visible: boolean) => void; // 当抽屉表单显示状态改变时调用 + onFinish: (values: any) => Promise; // 表单提交成功时的回调 + initialValues?: any; // 表单的初始值 + isEdit: boolean; // 标记当前是编辑模式还是新建模式 +} + +const EditSiteForm: React.FC = ({ + open, + onOpenChange, + onFinish, + initialValues, + isEdit, +}) => { + const [form] = Form.useForm(); + + // 当 initialValues 或 open 状态变化时, 更新表单的值 + useEffect(() => { + // 如果抽屉是打开的 + if (open) { + // 如果是编辑模式并且有初始值 + if (isEdit && initialValues) { + // 编辑模式下, 设置表单值为初始值 + form.setFieldsValue({ + ...initialValues, + isDisabled: initialValues.isDisabled === 1, // 将后端的 1/0 转换成 true/false + }); + } else { + // 新建模式或抽屉关闭时, 重置表单 + form.resetFields(); + } + } + }, [initialValues, isEdit, open, form]); + + return ( + { + // 直接将表单值传递给 onFinish 回调 + // 后端需要布尔值, 而 ProFormSwitch 已经提供了布尔值 + return onFinish(values); + }} + layout="vertical" + > + + + + + + {/* 根据选择的平台动态显示不同的认证字段 */} + + {({ type }) => { + // 如果平台是 woocommerce + if (type === 'woocommerce') { + return ( + <> + + + > + ); + } + // 如果平台是 shopyy + if (type === 'shopyy') { + return ( + + ); + } + return null; + }} + + + { + // 从后端接口获取区域数据 + const res = await areacontrollerGetarealist({ pageSize: 1000 }); + // areacontrollerGetarealist 直接返回数组, 所以不需要 .data.list + return res.map((area: any) => ({ label: area.name, value: area.code })); + }} + /> + { + // 从后端接口获取仓库数据 + const res = await stockcontrollerGetallstockpoints(); + // 使用可选链和空值合并运算符来安全地处理可能未定义的数据 + return res?.data?.map((sp: any) => ({ label: sp.name, value: sp.id })) ?? []; + }} + /> + + + ); +}; + +export default EditSiteForm; diff --git a/src/pages/Site/Shop/Layout.tsx b/src/pages/Site/Shop/Layout.tsx index 79ef6f7..018d853 100644 --- a/src/pages/Site/Shop/Layout.tsx +++ b/src/pages/Site/Shop/Layout.tsx @@ -1,52 +1,51 @@ +import { EditOutlined } from '@ant-design/icons'; +import { request } from '@umijs/max'; import { sitecontrollerAll } from '@/servers/api/site'; import { PageContainer, } from '@ant-design/pro-components'; import { Outlet, history, useLocation, useParams } from '@umijs/max'; -import { App, Button, Card, Col, Menu, Row, Select, Spin } from 'antd'; +import { Button, Card, Col, Menu, Row, Select, Spin, message } from 'antd'; import React, { useEffect, useState } from 'react'; +import EditSiteForm from './EditSiteForm'; +import type { SiteItem } from '../List/index'; const ShopLayout: React.FC = () => { - const [sites, setSites] = useState<{ label: string; value: number }[]>([]); + const [sites, setSites] = useState([]); const [loading, setLoading] = useState(true); const { siteId } = useParams<{ siteId: string }>(); const location = useLocation(); - const { message } = App.useApp(); + + const [editModalOpen, setEditModalOpen] = useState(false); + const [editingSite, setEditingSite] = useState(null); + + const fetchSites = async () => { + try { + setLoading(true); + const { data = [] } = await sitecontrollerAll(); + setSites(data); + + if (!siteId && data.length > 0) { + history.replace(`/site/shop/${data[0].id}/products`); + } + } catch (error) { + console.error('Failed to fetch sites', error); + } finally { + setLoading(false); + } + }; useEffect(() => { - const fetchSites = async () => { - try { - const { data = [] } = await sitecontrollerAll(); - const siteOptions = data.map((item: any) => ({ - label: item.name, - value: item.id, - })); - setSites(siteOptions); - - // 如果 URL 中没有 siteId,且有站点数据,默认跳转到第一个站点的 products 页面 - if (!siteId && siteOptions.length > 0) { - history.replace(`/site/shop/${siteOptions[0].value}/products`); - } - } catch (error) { - console.error('Failed to fetch sites', error); - } finally { - setLoading(false); - } - }; fetchSites(); }, []); const handleSiteChange = (value: number) => { - // 切换站点时,保持当前的功能模块(products/orders/etc),只改变 siteId const currentPath = location.pathname; const parts = currentPath.split('/'); - // 假设路径结构是 /site/shop/:siteId/module... - // parts: ['', 'site', 'shop', '123', 'products'] if (parts.length >= 5) { parts[3] = String(value); history.push(parts.join('/')); } else { - // Fallback history.push(`/site/shop/${value}/products`); } }; @@ -56,18 +55,14 @@ const ShopLayout: React.FC = () => { history.push(`/site/shop/${siteId}/${e.key}`); }; - // 获取当前选中的菜单项 const getSelectedKey = () => { const parts = location.pathname.split('/'); - // /site/shop/:siteId/:module if (parts.length >= 5) { - return parts[4]; // products, orders, subscriptions, logistics + return parts[4]; } return 'products'; }; - // 已移除店铺同步逻辑,页面加载即从站点实时拉取数据 - if (loading) { return ( { ); } + const handleFinish = async (values: any) => { + if (!editingSite) { + message.error('未找到要编辑的站点'); + return false; + } + try { + await request(`/site/${editingSite.id}`, { + method: 'PUT', + data: values, + }); + message.success('更新成功'); + setEditModalOpen(false); + fetchSites(); // 重新获取站点列表以更新数据 + return true; + } catch (error: any) { + message.error(error.message || '操作失败'); + return false; + } + }; + return ( - + { style={{ height: '100%', overflow: 'hidden' }} > - 选择店铺: - - {/* 店铺同步功能已废弃 */} + + ({ label: site.name, value: site.id }))} + value={siteId ? Number(siteId) : undefined} + onChange={handleSiteChange} + showSearch + optionFilterProp="label" + /> + } + style={{ marginLeft: 8 }} + onClick={() => { + const currentSite = sites.find(site => site.id === Number(siteId)); + if (currentSite) { + setEditingSite(currentSite); + setEditModalOpen(true); + } else { + message.warning('请先选择一个店铺'); + } + }} + /> + { { key: 'products', label: '产品管理' }, { key: 'orders', label: '订单管理' }, { key: 'subscriptions', label: '订阅管理' }, - { key: 'logistics', label: '物流管理' }, { key: 'media', label: '媒体管理' }, { key: 'customers', label: '客户管理' }, + { key: 'reviews', label: '评论管理' }, ]} /> - {/* 这里的 Outlet 会渲染子路由组件,如 Products, Orders 等 */} {siteId ? : 请选择店铺} - {/* 店铺同步弹窗已移除 */} + { + setEditModalOpen(visible); + if (!visible) { + setEditingSite(null); + } + }} + initialValues={editingSite} + isEdit={!!editingSite} + onFinish={handleFinish} + /> ); }; diff --git a/src/pages/Site/Shop/Logistics/index.tsx b/src/pages/Site/Shop/Logistics/index.tsx index 70789c4..228fa9f 100644 --- a/src/pages/Site/Shop/Logistics/index.tsx +++ b/src/pages/Site/Shop/Logistics/index.tsx @@ -209,41 +209,28 @@ const LogisticsPage: React.FC = () => { 批量打印 - { - // 条件判断 如果当前未选择任何行则直接返回 - if (!selectedRows || selectedRows.length === 0) return; + { try { - // 进入批量删除处理流程 setIsLoading(true); - let successCount = 0; + let ok = 0; for (const row of selectedRows) { - // 逐条删除 每次调用服务端删除接口 - const { success } = await logisticscontrollerDeleteshipment({ id: row.id }); - // 条件判断 累计成功次数 - if (success) successCount++; + const { success } = await logisticscontrollerDeleteshipment({ id: row.id }); + if (success) ok++; } - // 删除完成后提示成功条数 - message.success(`成功删除 ${successCount} 条`); - // 结束加载状态 + message.success(`成功删除 ${ok} 条`); setIsLoading(false); - // 刷新表格数据 actionRef.current?.reload(); - // 清空选择列表 setSelectedRows([]); } catch (e) { - // 异常处理 结束加载状态 setIsLoading(false); } }} > - - 批量删除 - - + 批量删除 + ); }} diff --git a/src/pages/Site/Shop/Orders/index.tsx b/src/pages/Site/Shop/Orders/index.tsx index 3f94fe6..1ee3b26 100644 --- a/src/pages/Site/Shop/Orders/index.tsx +++ b/src/pages/Site/Shop/Orders/index.tsx @@ -113,6 +113,30 @@ const OrdersPage: React.FC = () => { dataIndex: 'customer_name', hideInSearch: true, }, + { + title: '商品', + dataIndex: 'line_items', + hideInSearch: true, + width: 200, + ellipsis: true, + render: (_, record) => { + // 检查 record.line_items 是否是数组并且有内容 + if (Array.isArray(record.line_items) && record.line_items.length > 0) { + // 遍历 line_items 数组, 显示每个商品的名称和数量 + return ( + + {record.line_items.map((item: any) => ( + + {`${item.name} x ${item.quantity}`} + + ))} + + ); + } + // 如果 line_items 不存在或不是数组, 则显示占位符 + return '-'; + }, + }, { title: '支付方式', dataIndex: 'payment_method', @@ -372,7 +396,7 @@ const OrdersPage: React.FC = () => { const res = await request(`/site-api/${siteId}/orders`, { params: { page: 1, - page_size: 1, + per_page: 1, where: { ...baseWhere, status: rawStatus }, }, }); diff --git a/src/pages/Site/Shop/Products/index.tsx b/src/pages/Site/Shop/Products/index.tsx index 0914125..a4e1b9e 100644 --- a/src/pages/Site/Shop/Products/index.tsx +++ b/src/pages/Site/Shop/Products/index.tsx @@ -8,7 +8,7 @@ import { ProTable, } from '@ant-design/pro-components'; import { App, Button, Divider, Popconfirm, Tag } from 'antd'; -import { DeleteFilled } from '@ant-design/icons'; +import { DeleteFilled, LinkOutlined } from '@ant-design/icons'; import React, { useEffect, useRef, useState } from 'react'; import { BatchEditProducts, @@ -21,13 +21,13 @@ import { CreateProduct, } from '../components/Product/Forms'; import { TagConfig } from '../components/Product/utils'; - const ProductsPage: React.FC = () => { const { message } = App.useApp(); const actionRef = useRef(); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRows, setSelectedRows] = useState([]); // Use any or unified DTO type const { siteId } = useParams<{ siteId: string }>(); + const [siteInfo, setSiteInfo] = useState(); const [config, setConfig] = useState({ brands: [], fruits: [], @@ -43,6 +43,20 @@ const ProductsPage: React.FC = () => { actionRef.current?.reload(); }, [siteId]); + useEffect(() => { + const loadSiteInfo = async () => { + try { + const res = await request(`/site/get/${siteId}`); + if (res?.success && res?.data) { + setSiteInfo(res.data); + } + } catch (e) {} + }; + if (siteId) { + loadSiteInfo(); + } + }, [siteId]); + useEffect(() => { const fetchAllConfigs = async () => { try { @@ -86,8 +100,9 @@ const ProductsPage: React.FC = () => { fetchAllConfigs(); }, []); - const columns: ProColumns[] = [ + const columns: ProColumns[] = [ { + // ID title: 'ID', dataIndex: 'id', hideInSearch: true, @@ -98,36 +113,43 @@ const ProductsPage: React.FC = () => { } }, { + // sku title: 'sku', dataIndex: 'sku', fixed: 'left', }, { + // 名称 title: '名称', dataIndex: 'name', }, { + // 产品状态 title: '产品状态', dataIndex: 'status', valueType: 'select', valueEnum: PRODUCT_STATUS_ENUM, }, { + // 产品类型 title: '产品类型', dataIndex: 'type', }, { + // 库存状态 title: '库存状态', dataIndex: 'stock_status', valueType: 'select', valueEnum: PRODUCT_STOCK_STATUS_ENUM, }, { + // 库存 title: '库存', dataIndex: 'stock_quantity', hideInSearch: true, }, { + // 图片 title: '图片', dataIndex: 'images', hideInSearch: true, @@ -139,16 +161,101 @@ const ProductsPage: React.FC = () => { }, }, { + // 常规价格 title: '常规价格', dataIndex: 'regular_price', hideInSearch: true, }, { + // 销售价格 title: '销售价格', dataIndex: 'sale_price', hideInSearch: true, }, { + // 标签 + title: '标签', + dataIndex: 'tags', + hideInSearch: true, + width: 250, + render: (_, record) => { + // 检查 record.tags 是否存在并且是一个数组 + if (record.tags && Array.isArray(record.tags)) { + // 遍历 tags 数组并为每个 tag 对象渲染一个 Tag 组件 + return ( + + {record.tags.map((tag: any) => ( + // 使用 tag.name 作为 key, 因为 tag.id 可能是对象, 会导致 React key 错误 + {tag.name} + ))} + + ); + } + // 如果 record.tags 不是一个有效的数组,则不渲染任何内容 + return null; + }, + }, + { + // 分类 + title: '分类', + dataIndex: 'categories', + hideInSearch: true, + width: 250, + render: (_, record) => { + // 检查 record.categories 是否存在并且是一个数组 + if (record.categories && Array.isArray(record.categories)) { + // 遍历 categories 数组并为每个 category 对象渲染一个 Tag 组件 + return ( + + {record.categories.map((cat: any) => ( + // 使用 cat.name 作为 key + {cat.name} + ))} + + ); + } + // 如果 record.categories 不是一个有效的数组,则不渲染任何内容 + return null; + }, + }, + { + // 属性 + title: '属性', + dataIndex: 'attributes', + hideInSearch: true, + width: 250, + render: (_, record) => { + // 检查 record.attributes 是否存在并且是一个数组 + if (record.attributes && Array.isArray(record.attributes)) { + return ( + + {(record.attributes as any[]).map((attr: any) => ( + + {attr.name}: {Array.isArray(attr.options) ? attr.options.join(', ') : ''} + + ))} + + ); + } + return null; + }, + }, + { + // 创建时间 + title: '创建时间', + dataIndex: 'date_created', + valueType: 'dateTime', + hideInSearch: true, + }, + { + // 修改时间 + title: '修改时间', + dataIndex: 'date_modified', + valueType: 'dateTime', + hideInSearch: true, + }, + { + // 操作 title: '操作', dataIndex: 'option', valueType: 'option', @@ -158,6 +265,19 @@ const ProductsPage: React.FC = () => { + } + disabled={!record.frontendUrl} + onClick={() => { + if (record.frontendUrl) { + window.open(record.frontendUrl, '_blank', 'noopener,noreferrer'); + } else { + message.warning('未能生成店铺链接'); + } + }} + /> { return ( - + scroll={{ x: 'max-content' }} pagination={{ - pageSizeOptions: ['10', '20', '50', '100', '1000'], + pageSizeOptions: ['10', '20', '50', '100', '1000','2000'], showSizeChanger: true, defaultPageSize: 10, }} @@ -209,21 +329,24 @@ const ProductsPage: React.FC = () => { }, }} request={async (params, sort, filter) => { - const { current, pageSize, ...rest } = params || {}; + // 从参数中解构分页和筛选条件, ProTable 使用 current 作为页码, 但后端需要 page, 所以在这里进行重命名 + const { current: page, pageSize, ...rest } = params || {}; const where = { ...rest, ...(filter || {}) }; let orderObj: Record | undefined = undefined; + // 如果存在排序条件, 则进行处理 if (sort && typeof sort === 'object') { const [field, dir] = Object.entries(sort)[0] || []; if (field && dir) { orderObj = { [field]: dir === 'descend' ? 'desc' : 'asc' }; } } + // 发起获取产品列表的请求 const response = await request(`/site-api/${siteId}/products`, { params: { - page: current, - page_size: pageSize, - where, - ...(orderObj ? { order: orderObj } : {}), + page, + per_page: pageSize, + ...where, + ...(orderObj ? { sortField: Object.keys(orderObj)[0], sortOrder: Object.values(orderObj)[0] } : {}), } }); @@ -279,7 +402,7 @@ const ProductsPage: React.FC = () => { expandable={{ rowExpandable: (record) => record.type === 'variable', expandedRowRender: (record) => { - const productExternalId = record.externalProductId || record.external_product_id || record.id; + const productExternalId = (record as any).externalProductId || (record as any).external_product_id || record.id; const innerColumns: ProColumns[] = [ { title: 'ID', @@ -294,6 +417,26 @@ const ProductsPage: React.FC = () => { { title: 'sku', dataIndex: 'sku' }, { title: '常规价格', dataIndex: 'regular_price', hideInSearch: true }, { title: '销售价格', dataIndex: 'sale_price', hideInSearch: true }, + { + title: 'Attributes', + dataIndex: 'attributes', + hideInSearch: true, + render: (_, row) => { + // 检查 row.attributes 是否存在并且是一个数组 + if (row.attributes && Array.isArray(row.attributes)) { + return ( + + {(row.attributes as any[]).map((attr: any) => ( + + {attr.name}: {attr.option} + + ))} + + ); + } + return null; + }, + }, { title: '操作', dataIndex: 'option', diff --git a/src/pages/Site/Shop/Reviews/ReviewForm.tsx b/src/pages/Site/Shop/Reviews/ReviewForm.tsx new file mode 100644 index 0000000..402869b --- /dev/null +++ b/src/pages/Site/Shop/Reviews/ReviewForm.tsx @@ -0,0 +1,29 @@ + +import React from 'react'; + +interface ReviewFormProps { + open: boolean; + editing: any; + siteId: number; + onClose: () => void; + onSuccess: () => void; +} + +const ReviewForm: React.FC = ({ open, editing, siteId, onClose, onSuccess }) => { + // // 这是一个临时的占位符组件 + // // 你可以在这里实现表单逻辑 + if (!open) { + return null; + } + + return ( + + Review Form + Site ID: {siteId} + Editing: {editing ? 'Yes' : 'No'} + Close + + ); +}; + +export default ReviewForm; diff --git a/src/pages/Site/Shop/Reviews/index.tsx b/src/pages/Site/Shop/Reviews/index.tsx new file mode 100644 index 0000000..e6aa23d --- /dev/null +++ b/src/pages/Site/Shop/Reviews/index.tsx @@ -0,0 +1,101 @@ +import React, { useRef, useState } from 'react'; +import { ActionType, ProTable, ProColumns, ProCard } from '@ant-design/pro-components'; +import { Button, Popconfirm, message, Space } from 'antd'; +import { siteapicontrollerGetreviews, siteapicontrollerDeletereview } from '@/servers/api/siteApi'; +import ReviewForm from './ReviewForm'; +import { useParams } from '@umijs/max'; + +const ReviewsPage: React.FC = () => { + const params = useParams(); + const siteId = Number(params.siteId); + const actionRef = useRef(); + const [open, setOpen] = useState(false); + const [editing, setEditing] = useState(null); + + const columns: ProColumns[] = [ + { title: 'ID', dataIndex: 'id', key: 'id', width: 50 }, + { title: '产品ID', dataIndex: 'product_id', key: 'product_id', width: 80 }, + { title: '作者', dataIndex: 'author', key: 'author' }, + { title: '评分', dataIndex: 'rating', key: 'rating', width: 80 }, + { title: '状态', dataIndex: 'status', key: 'status', width: 100 }, + { + title: '创建时间', + dataIndex: 'date_created', + key: 'date_created', + valueType: 'dateTime', + width: 150, + }, + { + title: '操作', + key: 'action', + width: 150, + render: (_, record) => ( + + { + setEditing(record); + setOpen(true); + }}>编辑 + { + if (record.id) { + try { + const response = await siteapicontrollerDeletereview({ siteId, id: String(record.id) }); + if (response.success) { + message.success('删除成功'); + actionRef.current?.reload(); + } else { + message.error('删除失败'); + } + } catch (error) { + message.error('删除失败'); + } + } + }}> + 删除 + + + ), + }, + ]; + + return ( + + + columns={columns} + actionRef={actionRef} + request={async (params) => { + const response = await siteapicontrollerGetreviews({ ...params, siteId, page: params.current, per_page: params.pageSize }); + return { + data: response.data.items, + success: true, + total: response.data.total, + }; + }} + rowKey="id" + search={{ + labelWidth: 'auto', + }} + headerTitle="评论列表" + toolBarRender={() => [ + { + setEditing(null); + setOpen(true); + }}> + 新建评论 + , + ]} + /> + setOpen(false)} + onSuccess={() => { + setOpen(false); + actionRef.current?.reload(); + }} + /> + + ); +}; + +export default ReviewsPage; diff --git a/src/pages/Site/Shop/Subscriptions/index.tsx b/src/pages/Site/Shop/Subscriptions/index.tsx index 7073fda..4899e08 100644 --- a/src/pages/Site/Shop/Subscriptions/index.tsx +++ b/src/pages/Site/Shop/Subscriptions/index.tsx @@ -56,7 +56,6 @@ const SubscriptionsPage: React.FC = () => { title: '订阅ID', dataIndex: 'id', hideInSearch: true, - width: 120, }, { title: '状态', @@ -70,25 +69,21 @@ const SubscriptionsPage: React.FC = () => { ) : ( '-' ), - width: 120, }, { title: '客户ID', dataIndex: 'customer_id', hideInSearch: true, - width: 120, }, { title: '计费周期', dataIndex: 'billing_period', hideInSearch: true, - width: 120, }, { title: '计费间隔', dataIndex: 'billing_interval', hideInSearch: true, - width: 120, }, { title: '开始时间', @@ -102,10 +97,23 @@ const SubscriptionsPage: React.FC = () => { hideInSearch: true, width: 160, }, + { + // 创建时间 + title: '创建时间', + dataIndex: 'date_created', + valueType: 'dateTime', + hideInSearch: true, + }, + { + // 修改时间 + title: '修改时间', + dataIndex: 'date_modified', + valueType: 'dateTime', + hideInSearch: true, + }, { title: '操作', valueType: 'option', - width: 120, render: (_, row) => ( } onClick={() => setEditing(row)} /> @@ -127,23 +135,13 @@ const SubscriptionsPage: React.FC = () => { * 列表数据请求;保持与后端分页参数一致 * 兼容后端 data.items 或 data.list 返回字段 */ - request={async (params, sort, filter) => { + request={async (params) => { if (!siteId) return { data: [], success: true }; - const { current, pageSize, ...rest } = params || {}; - const where = { ...rest, ...(filter || {}) }; - let orderObj: Record | undefined = undefined; - if (sort && typeof sort === 'object') { - const [field, dir] = Object.entries(sort)[0] || []; - if (field && dir) { - orderObj = { [field]: dir === 'descend' ? 'desc' : 'asc' }; - } - } const response = await request(`/site-api/${siteId}/subscriptions`, { params: { - page: current, - page_size: pageSize, - where, - ...(orderObj ? { order: orderObj } : {}), + ...params, + page: params.current, + per_page: params.pageSize, } }); @@ -173,8 +171,7 @@ const SubscriptionsPage: React.FC = () => { title="批量导出" onClick={async () => { if (!siteId) return; - const idsParam = selectedRowKeys.length ? (selectedRowKeys as any[]).join(',') : undefined; - const res = await request(`/site-api/${siteId}/subscriptions/export`, { params: { ids: idsParam } }); + const res = await request(`/site-api/${siteId}/subscriptions/export`, { params: {} }); if (res?.success && res?.data?.csv) { const blob = new Blob([res.data.csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); @@ -188,23 +185,8 @@ const SubscriptionsPage: React.FC = () => { } }} />, - { - // 条件判断 如果当前未选择任何行则直接返回 - if (!selectedRowKeys || selectedRowKeys.length === 0) { - message.warning('请选择要删除的订阅'); - return; - } - // 暂未实现批量删除接口 进行用户提示 - message.info('订阅删除未实现'); - }} - > - } /> - - ]} /> + } onClick={() => message.info('订阅删除未实现')} /> + ]} /> }> + }> 创建订单 } diff --git a/src/pages/Site/Shop/components/Product/Forms.tsx b/src/pages/Site/Shop/components/Product/Forms.tsx index 35e0f23..8aff04f 100644 --- a/src/pages/Site/Shop/components/Product/Forms.tsx +++ b/src/pages/Site/Shop/components/Product/Forms.tsx @@ -355,16 +355,17 @@ export const UpdateForm: React.FC<{ placeholder="请输入SKU" rules={[{ required: true, message: '请输入SKU' }]} /> - + + {initialValues.type === 'simple' ? ( <> ('/review/create', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 DELETE /review/delete/${param0} */ +export async function reviewcontrollerDelete( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.reviewcontrollerDeleteParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/review/delete/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /review/get/${param0} */ +export async function reviewcontrollerGet( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.reviewcontrollerGetParams, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/review/get/${param0}`, { + method: 'GET', + params: { ...queryParams }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 GET /review/list */ +export async function reviewcontrollerList( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.reviewcontrollerListParams, + options?: { [key: string]: any }, +) { + return request('/review/list', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 此处后端没有提供注释 PUT /review/update/${param0} */ +export async function reviewcontrollerUpdate( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.reviewcontrollerUpdateParams, + body: API.UpdateReviewDTO, + options?: { [key: string]: any }, +) { + const { id: param0, ...queryParams } = params; + return request(`/review/update/${param0}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} diff --git a/src/servers/api/siteApi.ts b/src/servers/api/siteApi.ts index 39b8d5f..898c33f 100644 --- a/src/servers/api/siteApi.ts +++ b/src/servers/api/siteApi.ts @@ -15,6 +15,10 @@ export async function siteapicontrollerGetcustomers( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }, @@ -70,6 +74,10 @@ export async function siteapicontrollerExportcustomers( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -105,6 +113,10 @@ export async function siteapicontrollerGetmedia( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -162,6 +174,10 @@ export async function siteapicontrollerExportmedia( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -178,6 +194,10 @@ export async function siteapicontrollerGetorders( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -232,6 +252,10 @@ export async function siteapicontrollerExportorders( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -269,6 +293,10 @@ export async function siteapicontrollerGetproducts( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }, @@ -324,6 +352,10 @@ export async function siteapicontrollerExportproducts( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -340,6 +372,10 @@ export async function siteapicontrollerExportproductsspecial( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -386,6 +422,48 @@ export async function siteapicontrollerImportproductsspecial( ); } +/** 此处后端没有提供注释 GET /site-api/${param0}/reviews */ +export async function siteapicontrollerGetreviews( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.siteapicontrollerGetreviewsParams, + options?: { [key: string]: any }, +) { + const { siteId: param0, ...queryParams } = params; + return request( + `/site-api/${param0}/reviews`, + { + method: 'GET', + params: { + ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], + }, + ...(options || {}), + }, + ); +} + +/** 此处后端没有提供注释 POST /site-api/${param0}/reviews */ +export async function siteapicontrollerCreatereview( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.siteapicontrollerCreatereviewParams, + body: API.CreateReviewDTO, + options?: { [key: string]: any }, +) { + const { siteId: param0, ...queryParams } = params; + return request(`/site-api/${param0}/reviews`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }); +} + /** 此处后端没有提供注释 GET /site-api/${param0}/subscriptions */ export async function siteapicontrollerGetsubscriptions( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) @@ -399,6 +477,10 @@ export async function siteapicontrollerGetsubscriptions( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }, @@ -416,6 +498,10 @@ export async function siteapicontrollerExportsubscriptions( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }); @@ -490,6 +576,10 @@ export async function siteapicontrollerGetcustomerorders( method: 'GET', params: { ...queryParams, + where: undefined, + ...queryParams['where'], + order: undefined, + ...queryParams['order'], }, ...(options || {}), }, @@ -671,6 +761,42 @@ export async function siteapicontrollerDeleteproduct( ); } +/** 此处后端没有提供注释 PUT /site-api/${param1}/reviews/${param0} */ +export async function siteapicontrollerUpdatereview( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.siteapicontrollerUpdatereviewParams, + body: API.UpdateReviewDTO, + options?: { [key: string]: any }, +) { + const { id: param0, siteId: param1, ...queryParams } = params; + return request( + `/site-api/${param1}/reviews/${param0}`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + params: { ...queryParams }, + data: body, + ...(options || {}), + }, + ); +} + +/** 此处后端没有提供注释 DELETE /site-api/${param1}/reviews/${param0} */ +export async function siteapicontrollerDeletereview( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.siteapicontrollerDeletereviewParams, + options?: { [key: string]: any }, +) { + const { id: param0, siteId: param1, ...queryParams } = params; + return request>(`/site-api/${param1}/reviews/${param0}`, { + method: 'DELETE', + params: { ...queryParams }, + ...(options || {}), + }); +} + /** 此处后端没有提供注释 PUT /site-api/${param2}/products/${param1}/variations/${param0} */ export async function siteapicontrollerUpdatevariation( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts index bd94d7e..66294c8 100644 --- a/src/servers/api/typings.d.ts +++ b/src/servers/api/typings.d.ts @@ -184,6 +184,25 @@ declare namespace API { items?: PurchaseOrderItem[]; }; + type CreateReviewDTO = { + /** 站点ID */ + siteId?: number; + /** 产品ID */ + productId?: number; + /** 客户ID */ + customerId?: number; + /** 评论者姓名 */ + author?: string; + /** 评论者电子邮件 */ + email?: string; + /** 评论内容 */ + content?: string; + /** 评分 (1-5) */ + rating?: number; + /** 状态 */ + status?: 'pending' | 'approved' | 'rejected'; + }; + type CreateSiteDTO = { /** 区域 */ areas?: any; @@ -1211,6 +1230,19 @@ declare namespace API { stockPointId?: number; }; + type QueryReviewDTO = { + /** 当前页码 */ + current?: number; + /** 每页数量 */ + pageSize?: number; + /** 站点ID */ + siteId?: number; + /** 产品ID */ + productId?: number; + /** 状态 */ + status?: string; + }; + type QueryServiceDTO = { /** 页码 */ current?: number; @@ -1316,6 +1348,31 @@ declare namespace API { data?: RateDTO[]; }; + type reviewcontrollerDeleteParams = { + id: number; + }; + + type reviewcontrollerGetParams = { + id: number; + }; + + type reviewcontrollerListParams = { + /** 当前页码 */ + current?: number; + /** 每页数量 */ + pageSize?: number; + /** 站点ID */ + siteId?: number; + /** 产品ID */ + productId?: number; + /** 状态 */ + status?: string; + }; + + type reviewcontrollerUpdateParams = { + id: number; + }; + type Service = { id?: string; carrier_name?: string; @@ -1442,6 +1499,10 @@ declare namespace API { siteId: number; }; + type siteapicontrollerCreatereviewParams = { + siteId: number; + }; + type siteapicontrollerDeletecustomerParams = { id: string; siteId: number; @@ -1462,6 +1523,11 @@ declare namespace API { siteId: number; }; + type siteapicontrollerDeletereviewParams = { + id: number; + siteId: number; + }; + type siteapicontrollerExportcustomersParams = { /** 页码 */ page?: number; @@ -1476,9 +1542,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1502,9 +1568,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1528,9 +1594,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1554,9 +1620,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1580,9 +1646,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1606,9 +1672,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1632,9 +1698,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1664,9 +1730,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1690,9 +1756,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1726,9 +1792,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1757,9 +1823,35 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; + /** 排序字段(兼容旧入参) */ + orderby?: string; + /** 排序方式(兼容旧入参) */ + orderDir?: string; + /** 选中ID列表,逗号分隔 */ + ids?: string; + siteId: number; + }; + + type siteapicontrollerGetreviewsParams = { + /** 页码 */ + page?: number; + /** 每页数量 */ + per_page?: number; + /** 每页数量别名 */ + page_size?: number; + /** 搜索关键词 */ + search?: string; + /** 状态 */ + status?: string; + /** 客户ID,用于筛选订单 */ + customer_id?: number; + /** 过滤条件对象 */ + where?: Record; + /** 排序对象,例如 { "sku": "desc" } */ + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1783,9 +1875,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -1831,6 +1923,11 @@ declare namespace API { siteId: number; }; + type siteapicontrollerUpdatereviewParams = { + id: number; + siteId: number; + }; + type siteapicontrollerUpdatevariationParams = { variationId: string; productId: string; @@ -2193,6 +2290,40 @@ declare namespace API { minute?: string; }; + type UnifiedAddressDTO = { + /** 名 */ + first_name?: string; + /** 姓 */ + last_name?: string; + /** 全名 */ + fullname?: string; + /** 公司 */ + company?: string; + /** 地址1 */ + address_1?: string; + /** 地址2 */ + address_2?: string; + /** 城市 */ + city?: string; + /** 省/州 */ + state?: string; + /** 邮政编码 */ + postcode?: string; + /** 国家 */ + country?: string; + /** 邮箱 */ + email?: string; + /** 电话 */ + phone?: string; + }; + + type UnifiedCategoryDTO = { + /** 分类ID */ + id?: Record; + /** 分类名称 */ + name?: string; + }; + type UnifiedCustomerDTO = { /** 客户ID */ id?: Record; @@ -2219,11 +2350,11 @@ declare namespace API { /** 电话 */ phone?: string; /** 账单地址 */ - billing?: any; + billing?: UnifiedAddressDTO; /** 收货地址 */ - shipping?: any; + shipping?: UnifiedAddressDTO; /** 原始数据 */ - raw?: any; + raw?: Record; }; type UnifiedCustomerPaginationDTO = { @@ -2301,14 +2432,14 @@ declare namespace API { customer_name?: string; /** 客户邮箱 */ email?: string; - /** 订单项 */ - line_items?: any; + /** 订单项(具体的商品) */ + line_items?: UnifiedOrderLineItemDTO[]; /** 销售项(兼容前端) */ - sales?: any; + sales?: UnifiedOrderLineItemDTO[]; /** 账单地址 */ - billing?: any; + billing?: UnifiedAddressDTO; /** 收货地址 */ - shipping?: any; + shipping?: UnifiedAddressDTO; /** 账单地址全称 */ billing_full_address?: string; /** 收货地址全称 */ @@ -2320,7 +2451,24 @@ declare namespace API { /** 更新时间 */ date_modified?: string; /** 原始数据 */ - raw?: any; + raw?: Record; + }; + + type UnifiedOrderLineItemDTO = { + /** 订单项ID */ + id?: Record; + /** 产品名称 */ + name?: string; + /** 产品ID */ + product_id?: Record; + /** 变体ID */ + variation_id?: Record; + /** 数量 */ + quantity?: number; + /** 总计 */ + total?: string; + /** SKU */ + sku?: string; }; type UnifiedOrderPaginationDTO = { @@ -2338,6 +2486,21 @@ declare namespace API { totalPages?: number; }; + type UnifiedProductAttributeDTO = { + /** 属性ID */ + id?: Record; + /** 属性名称 */ + name?: string; + /** 属性位置 */ + position?: number; + /** 对变体是否可见 */ + visible?: boolean; + /** 是否为变体属性 */ + variation?: boolean; + /** 属性选项 */ + options?: string[]; + }; + type UnifiedProductDTO = { /** 产品ID */ id?: Record; @@ -2362,17 +2525,21 @@ declare namespace API { /** 产品图片 */ images?: UnifiedImageDTO[]; /** 产品标签 */ - tags?: any; + tags?: UnifiedTagDTO[]; + /** 产品分类 */ + categories?: UnifiedCategoryDTO[]; /** 产品属性 */ - attributes?: any; + attributes?: UnifiedProductAttributeDTO[]; /** 产品变体 */ - variations?: any; + variations?: UnifiedProductVariationDTO[]; /** 创建时间 */ date_created?: string; /** 更新时间 */ date_modified?: string; + /** 产品链接 */ + frontendUrl?: string; /** 原始数据(保留备用) */ - raw?: any; + raw?: Record; }; type UnifiedProductPaginationDTO = { @@ -2390,6 +2557,59 @@ declare namespace API { totalPages?: number; }; + type UnifiedProductVariationDTO = { + /** 变体ID */ + id?: Record; + /** 变体SKU */ + sku?: string; + /** 常规价格 */ + regular_price?: string; + /** 销售价格 */ + sale_price?: string; + /** 当前价格 */ + price?: string; + /** 库存状态 */ + stock_status?: string; + /** 库存数量 */ + stock_quantity?: number; + /** 变体图片 */ + image?: UnifiedImageDTO; + }; + + type UnifiedReviewDTO = { + /** 评论ID */ + id?: Record; + /** 产品ID */ + product_id?: Record; + /** 评论者 */ + author?: string; + /** 评论者邮箱 */ + email?: string; + /** 评论内容 */ + content?: string; + /** 评分 */ + rating?: number; + /** 状态 */ + status?: string; + /** 创建时间 */ + date_created?: string; + }; + + type UnifiedReviewPaginationDTO = { + /** 列表数据 */ + items?: UnifiedReviewDTO[]; + /** 总数 */ + total?: number; + /** 当前页 */ + page?: number; + /** 每页数量 */ + per_page?: number; + /** 每页数量别名 */ + page_size?: number; + /** 总页数 */ + totalPages?: number; + }; + type UnifiedSearchParamsDTO = { /** 页码 */ page?: number; @@ -2404,9 +2624,9 @@ declare namespace API { /** 客户ID,用于筛选订单 */ customer_id?: number; /** 过滤条件对象 */ - where?: any; + where?: Record; /** 排序对象,例如 { "sku": "desc" } */ - order?: any; + order?: Record; /** 排序字段(兼容旧入参) */ orderby?: string; /** 排序方式(兼容旧入参) */ @@ -2435,9 +2655,9 @@ declare namespace API { /** 下次支付时间 */ next_payment_date?: string; /** 订单项 */ - line_items?: any; + line_items?: UnifiedOrderLineItemDTO[]; /** 原始数据 */ - raw?: any; + raw?: Record; }; type UnifiedSubscriptionPaginationDTO = { @@ -2455,6 +2675,13 @@ declare namespace API { totalPages?: number; }; + type UnifiedTagDTO = { + /** 标签ID */ + id?: Record; + /** 标签名称 */ + name?: string; + }; + type UpdateAreaDTO = { /** 编码 */ code?: string; @@ -2499,6 +2726,15 @@ declare namespace API { items?: PurchaseOrderItem[]; }; + type UpdateReviewDTO = { + /** 评论内容 */ + content?: string; + /** 评分 (1-5) */ + rating?: number; + /** 状态 */ + status?: 'pending' | 'approved' | 'rejected'; + }; + type UpdateSiteDTO = { /** 区域 */ areas?: any;
Site ID: {siteId}
Editing: {editing ? 'Yes' : 'No'}