WEB/src/pages/Site/List/index.tsx

312 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
ActionType,
DrawerForm,
ProColumns,
ProFormInstance,
ProFormSelect,
ProFormSwitch,
ProFormText,
ProTable,
} from '@ant-design/pro-components';
import { request } from '@umijs/max';
import { Button, message, Popconfirm, Space, Tag } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
// 站点数据项类型(前端不包含密钥字段,后端列表不返回密钥)
interface SiteItem {
id: number;
siteName: string;
apiUrl?: string;
type?: 'woocommerce' | 'shopyy';
skuPrefix?: string;
isDisabled: number;
}
// 创建/更新表单的值类型,包含可选的密钥字段
interface SiteFormValues {
siteName: string;
apiUrl?: string;
type?: 'woocommerce' | 'shopyy';
isDisabled?: boolean;
consumerKey?: string; // WooCommerce REST API 的 consumer key
consumerSecret?: string; // WooCommerce REST API 的 consumer secret
skuPrefix?: string;
}
const SiteList: React.FC = () => {
const actionRef = useRef<ActionType>();
const formRef = useRef<ProFormInstance>();
const [open, setOpen] = useState(false);
const [editing, setEditing] = useState<SiteItem | null>(null);
useEffect(() => {
if (!open) return;
if (editing) {
formRef.current?.setFieldsValue({
siteName: editing.siteName,
apiUrl: editing.apiUrl,
type: editing.type,
skuPrefix: editing.skuPrefix,
isDisabled: !!editing.isDisabled,
consumerKey: undefined,
consumerSecret: undefined,
});
} else {
formRef.current?.setFieldsValue({
siteName: undefined,
apiUrl: undefined,
type: 'woocommerce',
skuPrefix: undefined,
isDisabled: false,
consumerKey: undefined,
consumerSecret: undefined,
});
}
}, [open, editing]);
// 表格列定义
const columns: ProColumns<SiteItem>[] = [
{
title: 'ID',
dataIndex: 'id',
width: 80,
sorter: true,
hideInSearch: true,
},
{ title: '站点名称', dataIndex: 'siteName', width: 220 },
{ title: 'API 地址', dataIndex: 'apiUrl', width: 280, hideInSearch: true },
{
title: 'SKU 前缀',
dataIndex: 'skuPrefix',
width: 160,
hideInSearch: true,
},
{
title: '平台',
dataIndex: 'type',
width: 140,
valueType: 'select',
request: async () => [
{ label: 'WooCommerce', value: 'woocommerce' },
{ label: 'Shopyy', value: 'shopyy' },
],
},
{
title: '状态',
dataIndex: 'isDisabled',
width: 120,
hideInSearch: true,
render: (_, row) => (
<Tag color={row.isDisabled ? 'red' : 'green'}>
{row.isDisabled ? '已禁用' : '启用中'}
</Tag>
),
},
{
title: '操作',
dataIndex: 'actions',
width: 240,
hideInSearch: true,
render: (_, row) => (
<Space>
<Button
size="small"
onClick={() => {
setEditing(row);
setOpen(true);
}}
>
</Button>
<Popconfirm
title={row.isDisabled ? '启用站点' : '禁用站点'}
description={
row.isDisabled ? '确认启用该站点?' : '确认禁用该站点?'
}
onConfirm={async () => {
try {
await request(`/site/disable/${row.id}`, {
method: 'PUT',
data: { disabled: !row.isDisabled },
});
message.success('更新成功');
actionRef.current?.reload();
} catch (e: any) {
message.error(e?.message || '更新失败');
}
}}
>
<Button size="small" type="primary" danger={!row.isDisabled}>
{row.isDisabled ? '启用' : '禁用'}
</Button>
</Popconfirm>
</Space>
),
},
];
// 表格数据请求
const tableRequest = async (params: Record<string, any>) => {
try {
const { current = 1, pageSize = 10, siteName, type } = params;
const resp = await request('/site/list', {
method: 'GET',
params: {
current,
pageSize,
keyword: siteName || undefined,
type: type || undefined,
},
});
const { success, data, message: errMsg } = resp as any;
if (!success) throw new Error(errMsg || '获取失败');
return {
data: (data?.items ?? []) as SiteItem[],
total: data?.total ?? 0,
success: true,
};
} catch (e: any) {
message.error(e?.message || '获取失败');
return { data: [], total: 0, success: false };
}
};
// 提交创建/更新逻辑;编辑时未填写密钥则不提交(保持原值)
const handleSubmit = async (values: SiteFormValues) => {
try {
if (editing) {
const payload: Record<string, any> = {
// 仅提交存在的字段,避免覆盖为 null/空
...(values.siteName ? { siteName: values.siteName } : {}),
...(values.apiUrl ? { apiUrl: values.apiUrl } : {}),
...(values.type ? { type: values.type } : {}),
...(typeof values.isDisabled === 'boolean'
? { isDisabled: values.isDisabled }
: {}),
...(values.skuPrefix ? { skuPrefix: values.skuPrefix } : {}),
};
// 仅当输入了新密钥时才提交,未输入则保持原本值
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,
});
} else {
// 新增站点时要求填写 consumerKey 和 consumerSecret
if (!values.consumerKey || !values.consumerSecret) {
throw new Error('Consumer Key and Secret are required');
}
await request('/site/create', {
method: 'POST',
data: {
siteName: values.siteName,
apiUrl: values.apiUrl,
type: values.type || 'woocommerce',
consumerKey: values.consumerKey,
consumerSecret: values.consumerSecret,
skuPrefix: values.skuPrefix,
},
});
}
message.success('提交成功');
setOpen(false);
setEditing(null);
actionRef.current?.reload();
return true;
} catch (e: any) {
message.error(e?.message || '提交失败');
return false;
}
};
return (
<>
<ProTable<SiteItem>
actionRef={actionRef}
rowKey="id"
columns={columns}
request={tableRequest}
toolBarRender={() => [
<Button
key="new"
type="primary"
onClick={() => {
setEditing(null);
setOpen(true);
}}
>
</Button>,
// 同步包括 orders subscriptions 等等
// <Button key='new' type='primary' onClick={()=> {
//
// }}}>
// 同步站点数据
// </Button>
]}
/>
<DrawerForm<SiteFormValues>
title={editing ? '编辑站点' : '新增站点'}
open={open}
onOpenChange={setOpen}
formRef={formRef}
onFinish={handleSubmit}
>
{/* 站点名称,必填 */}
<ProFormText
name="siteName"
label="站点名称"
placeholder="例如:本地商店"
rules={[{ required: true, message: '站点名称为必填项' }]}
/>
{/* API 地址,可选 */}
<ProFormText
name="apiUrl"
label="API 地址"
placeholder="例如https://shop.example.com"
/>
{/* 平台类型选择 */}
<ProFormSelect
name="type"
label="平台"
options={[
{ label: 'WooCommerce', value: 'woocommerce' },
{ label: 'Shopyy', value: 'shopyy' },
]}
/>
{/* 是否禁用 */}
<ProFormSwitch name="isDisabled" label="禁用" />
<ProFormText
name="skuPrefix"
label="SKU 前缀"
placeholder={editing ? '留空表示不修改' : '可选'}
/>
{/* WooCommerce REST consumer key新增必填编辑不填则保持原值 */}
<ProFormText
name="consumerKey"
label="Key"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={editing ? [] : [{ required: true, message: 'Key 为必填项' }]}
/>
{/* WooCommerce REST consumer secret新增必填编辑不填则保持原值 */}
<ProFormText
name="consumerSecret"
label="Secret"
placeholder={editing ? '留空表示不修改' : '必填'}
rules={
editing ? [] : [{ required: true, message: 'Secret 为必填项' }]
}
/>
</DrawerForm>
</>
);
};
export default SiteList;