feat(订阅): 新增订阅管理模块和列表页面

添加订阅管理路由分组并复用现有权限
实现订阅列表页面,包含查询、筛选和同步功能
This commit is contained in:
tikkhun 2025-11-17 17:54:05 +08:00
parent 721ccac46f
commit 737cfef733
2 changed files with 215 additions and 0 deletions

View File

@ -124,6 +124,19 @@ export default defineConfig({
},
],
},
// 新增:订阅管理路由分组(权限复用 canSeeOrder
{
name: '订阅管理',
path: '/subscription',
access: 'canSeeOrder',
routes: [
{
name: '订阅列表',
path: '/subscription/list',
component: './Subscription/List',
},
],
},
{
name: '客户管理',
path: '/customer',

View File

@ -0,0 +1,202 @@
import React, { useRef } from 'react';
import {
ActionType,
DrawerForm,
PageContainer,
ProColumns,
ProFormSelect,
ProTable,
} from '@ant-design/pro-components';
import { App, Button, Tag } from 'antd';
import {
subscriptioncontrollerList,
subscriptioncontrollerSync,
} from '@/servers/api/subscription';
import { sitecontrollerAll } from '@/servers/api/site';
/**
*
*
*/
const SUBSCRIPTION_STATUS_ENUM: Record<string, { text: string }> = {
active: { text: '激活' },
cancelled: { text: '已取消' },
expired: { text: '已过期' },
pending: { text: '待处理' },
'on-hold': { text: '暂停' },
};
/**
*
*/
const ListPage: React.FC = () => {
// 表格操作引用:用于在同步后触发表格刷新
const actionRef = useRef<ActionType>();
// 表格列定义(尽量与项目风格保持一致)
const columns: ProColumns<API.Subscription>[] = [
{
title: '站点',
dataIndex: 'siteId',
valueType: 'select',
// 动态加载站点选项
request: async () => {
const { data = [] } = await sitecontrollerAll();
return data.map((item) => ({
label: item.siteName,
value: item.id,
}));
},
render: (_, row) => row?.siteId ?? '-',
},
{
title: '订阅ID',
dataIndex: 'externalSubscriptionId',
hideInSearch: true,
width: 120,
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: SUBSCRIPTION_STATUS_ENUM,
// 以 Tag 形式展示,更易辨识
render: (_, row) =>
row?.status ? <Tag>{SUBSCRIPTION_STATUS_ENUM[row.status]?.text || row.status}</Tag> : '-',
width: 120,
},
{
title: '客户邮箱',
dataIndex: 'customer_email',
width: 180,
},
{
title: '金额',
dataIndex: 'total',
hideInSearch: true,
width: 100,
},
{
title: '币种',
dataIndex: 'currency',
hideInSearch: true,
width: 80,
},
{
title: '开始时间',
dataIndex: 'start_date',
hideInSearch: true,
width: 160,
},
{
title: '下次支付',
dataIndex: 'next_payment_date',
hideInSearch: true,
width: 160,
},
{
title: '结束时间',
dataIndex: 'end_date',
hideInSearch: true,
width: 160,
},
{
title: '创建时间',
dataIndex: 'createdAt',
valueType: 'dateTime',
hideInSearch: true,
width: 160,
},
{
title: '更新时间',
dataIndex: 'updatedAt',
valueType: 'dateTime',
hideInSearch: true,
width: 160,
},
];
return (
<PageContainer header={{ title: '订阅列表' }}>
<ProTable<API.Subscription>
headerTitle="查询表格"
rowKey="id"
actionRef={actionRef}
/**
*
* data.items data.list
*/
request={async (params) => {
const { data, success } = await subscriptioncontrollerList(params);
return {
total: data?.total || 0,
data: data?.items || data?.list || [],
success,
};
}}
columns={columns}
// 工具栏:订阅同步入口
toolBarRender={() => [<SyncForm key="sync" tableRef={actionRef} />]}
/>
</PageContainer>
);
};
/**
*
*/
const SyncForm: React.FC<{
tableRef: React.MutableRefObject<ActionType | undefined>;
}> = ({ tableRef }) => {
const { message } = App.useApp();
return (
<DrawerForm<API.subscriptioncontrollerSyncParams>
title="同步订阅"
trigger={
<Button key="syncSite" type="primary">
</Button>
}
autoFocusFirstInput
drawerProps={{ destroyOnHidden: true }}
/**
*
* 1. ProForm + rules
* 2.
* 3.
*/
onFinish={async (values) => {
try {
const { success, message: errMsg } = await subscriptioncontrollerSync(values);
if (!success) {
throw new Error(errMsg);
}
message.success('同步成功');
tableRef.current?.reload();
return true;
} catch (error: any) {
message.error(error.message || '同步失败');
}
}}
>
<ProFormSelect
name="siteId"
width="lg"
label="站点"
placeholder="请选择站点"
// 动态加载站点选项
request={async () => {
const { data = [] } = await sitecontrollerAll();
return data.map((item) => ({
label: item.siteName,
value: item.id,
}));
}}
rules={[{ required: true, message: '请选择站点' }]}
/>
</DrawerForm>
);
};
export default ListPage;