实现多商户履约平台基础

This commit is contained in:
yml2213
2026-07-30 12:02:32 +08:00
parent dde6f2c269
commit 83429456a6
41 changed files with 5487 additions and 504 deletions
+210
View File
@@ -0,0 +1,210 @@
import { useCallback, useEffect, useState } from 'react'
import {
Button,
Form,
Input,
InputNumber,
Modal,
Select,
Space,
Table,
Tag,
Typography,
message,
} from 'antd'
import { PlusOutlined, ReloadOutlined, TeamOutlined } from '@ant-design/icons'
import type { ColumnsType } from 'antd/es/table'
import dayjs from 'dayjs'
import { useNavigate } from 'react-router-dom'
import { platformApi } from '../api'
import type { Merchant, MerchantMember, PageResult } from '../types'
const memberRoleOptions = [
{ value: 'owner', label: '负责人' },
{ value: 'operator', label: '运营' },
{ value: 'finance', label: '财务' },
{ value: 'viewer', label: '只读' },
]
export default function PlatformMerchants() {
const navigate = useNavigate()
const [data, setData] = useState<PageResult<Merchant>>({ list: [], total: 0, page: 1, size: 10 })
const [loading, setLoading] = useState(false)
const [createOpen, setCreateOpen] = useState(false)
const [memberOpen, setMemberOpen] = useState(false)
const [selectedMerchant, setSelectedMerchant] = useState<Merchant | null>(null)
const [createForm] = Form.useForm()
const [memberForm] = Form.useForm()
const load = useCallback(async (page = data.page, size = data.size) => {
setLoading(true)
try {
const result = await platformApi.merchants({ page, size })
setData(result)
} catch (e) {
message.error(e instanceof Error ? e.message : '加载失败')
} finally {
setLoading(false)
}
}, [data.page, data.size])
useEffect(() => {
load()
}, [load])
const submitCreate = async () => {
const values = await createForm.validateFields()
try {
await platformApi.createMerchant(values)
message.success('商户已创建')
setCreateOpen(false)
createForm.resetFields()
load()
} catch (e) {
message.error(e instanceof Error ? e.message : '创建失败')
}
}
const submitMember = async () => {
if (!selectedMerchant) return
const values = await memberForm.validateFields()
try {
await platformApi.addMember(selectedMerchant.id, {
user_id: values.user_id,
role: values.role as MerchantMember['role'],
is_default: values.is_default,
})
message.success('成员已添加')
setMemberOpen(false)
} catch (e) {
message.error(e instanceof Error ? e.message : '添加失败')
}
}
const columns: ColumnsType<Merchant> = [
{ title: 'ID', dataIndex: 'id', width: 80 },
{ title: '编码', dataIndex: 'code', width: 180, render: (v) => <Typography.Text code copyable>{v}</Typography.Text> },
{ title: '名称', dataIndex: 'name', ellipsis: true },
{ title: '联系人', dataIndex: 'contact_name', width: 120, render: (v) => v || '-' },
{ title: '联系方式', dataIndex: 'contact_info', width: 160, render: (v) => v || '-' },
{ title: '状态', dataIndex: 'status', width: 90, render: (v) => v === 'active' ? <Tag color="green"></Tag> : <Tag></Tag> },
{ title: '创建时间', dataIndex: 'created_at', width: 160, render: (v) => dayjs(v).format('YYYY-MM-DD HH:mm') },
{
title: '操作',
key: 'action',
width: 190,
render: (_, record) => (
<Space size={0}>
<Button
type="link"
size="small"
onClick={() => {
localStorage.setItem('merchant_id', String(record.id))
message.success('当前商户已切换')
navigate('/merchant-center')
}}
>
</Button>
<Button
type="link"
size="small"
icon={<TeamOutlined />}
onClick={() => {
setSelectedMerchant(record)
memberForm.resetFields()
memberForm.setFieldsValue({ role: 'operator', is_default: false })
setMemberOpen(true)
}}
>
</Button>
</Space>
),
},
]
return (
<div>
<Space style={{ marginBottom: 16, width: '100%', justifyContent: 'space-between' }}>
<div>
<Typography.Title level={4} style={{ margin: 0 }}>
</Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</div>
<Space>
<Button icon={<ReloadOutlined />} onClick={() => load()}>
</Button>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => {
createForm.resetFields()
setCreateOpen(true)
}}
>
</Button>
</Space>
</Space>
<Table
rowKey="id"
loading={loading}
columns={columns}
dataSource={data.list}
tableLayout="fixed"
pagination={{
current: data.page,
pageSize: data.size,
total: data.total,
showSizeChanger: true,
showTotal: (total) => `${total}`,
onChange: load,
}}
/>
<Modal title="新增商户" open={createOpen} onOk={submitCreate} onCancel={() => setCreateOpen(false)} destroyOnClose>
<Form form={createForm} layout="vertical" style={{ marginTop: 16 }}>
<Form.Item name="code" label="商户编码" rules={[{ required: true }]}>
<Input placeholder="lower-case-code" />
</Form.Item>
<Form.Item name="name" label="商户名称" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="owner_user_id" label="负责人用户 ID" rules={[{ required: true }]}>
<InputNumber min={1} precision={0} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="contact_name" label="联系人">
<Input />
</Form.Item>
<Form.Item name="contact_info" label="联系方式">
<Input />
</Form.Item>
</Form>
</Modal>
<Modal
title={selectedMerchant ? `添加成员:${selectedMerchant.name}` : '添加成员'}
open={memberOpen}
onOk={submitMember}
onCancel={() => setMemberOpen(false)}
destroyOnClose
>
<Form form={memberForm} layout="vertical" style={{ marginTop: 16 }}>
<Form.Item name="user_id" label="用户 ID" rules={[{ required: true }]}>
<InputNumber min={1} precision={0} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="role" label="角色" rules={[{ required: true }]}>
<Select options={memberRoleOptions} />
</Form.Item>
<Form.Item name="is_default" label="默认商户">
<Select options={[{ value: true, label: '是' }, { value: false, label: '否' }]} />
</Form.Item>
</Form>
</Modal>
</div>
)
}