优化商户管理, 增加商户名重置密码等等

This commit is contained in:
yml2213
2026-08-14 13:09:56 +08:00
parent ee3e427ab7
commit 99a33675b0
7 changed files with 488 additions and 2 deletions
+5
View File
@@ -19,6 +19,7 @@ import type {
Merchant,
MerchantMember,
MerchantMemberGroup,
MerchantOwnerAccount,
MerchantRole,
MerchantProduct,
PageResult,
@@ -217,6 +218,10 @@ export const platformApi = {
request.post(`/platform/merchants/${merchantId}/products/assign`, { catalog_ids: catalogIds }).then((r) => r.data.data as { assigned: number }),
wallet: (merchantId: number) =>
request.get(`/platform/merchants/${merchantId}/wallet`).then((r) => r.data.data as WalletAccount),
merchantAccount: (merchantId: number) =>
request.get(`/platform/merchants/${merchantId}/account`).then((r) => r.data.data as MerchantOwnerAccount[]),
updateMerchantAccount: (merchantId: number, data: { user_id: number; username: string; nickname?: string; password?: string; status?: number }) =>
request.patch(`/platform/merchants/${merchantId}/account`, data).then((r) => r.data.data as MerchantOwnerAccount),
walletLedger: (merchantId: number, params?: Record<string, unknown>) =>
request.get(`/platform/merchants/${merchantId}/wallet/ledger`, { params }).then((r) => r.data.data as PageResult<WalletLedgerEntry>),
adjustWallet: (merchantId: number, data: { amount: number; idempotency_key: string; note?: string }) =>
+136 -2
View File
@@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'
import {
Button,
Checkbox,
Divider,
Form,
Input,
InputNumber,
@@ -10,15 +11,16 @@ import {
Select,
Space,
Spin,
Switch,
Table,
Tag,
Typography,
message,
} from 'antd'
import { GiftOutlined, PlusOutlined, ReloadOutlined, WalletOutlined } from '@ant-design/icons'
import { GiftOutlined, PlusOutlined, ReloadOutlined, UserOutlined, WalletOutlined } from '@ant-design/icons'
import type { ColumnsType } from 'antd/es/table'
import { platformApi } from '../api'
import type { Merchant, PageResult, ProductCatalogItem, WalletAccount } from '../types'
import type { Merchant, MerchantOwnerAccount, PageResult, ProductCatalogItem, WalletAccount } from '../types'
import { formatDateTime } from '../utils/time'
import { PageHeader } from '../components/PageHeader'
@@ -50,10 +52,16 @@ export default function PlatformMerchants() {
const [editProduct, setEditProduct] = useState<ProductCatalogItem | null>(null)
const [editProductOpen, setEditProductOpen] = useState(false)
const [editProductSubmitting, setEditProductSubmitting] = useState(false)
const [accounts, setAccounts] = useState<MerchantOwnerAccount[]>([])
const [accountsLoading, setAccountsLoading] = useState(false)
const [accountModalOpen, setAccountModalOpen] = useState(false)
const [editingAccount, setEditingAccount] = useState<MerchantOwnerAccount | null>(null)
const [accountSubmitting, setAccountSubmitting] = useState(false)
const [createForm] = Form.useForm()
const [settingsForm] = Form.useForm()
const [adjustForm] = Form.useForm()
const [editProductForm] = Form.useForm()
const [accountForm] = Form.useForm()
const load = useCallback(async (page = data.page, size = data.size) => {
setLoading(true)
@@ -112,6 +120,52 @@ export default function PlatformMerchants() {
}
}
const loadAccounts = useCallback(async (merchantId: number) => {
setAccountsLoading(true)
try {
setAccounts(await platformApi.merchantAccount(merchantId))
} catch (e) {
message.error(e instanceof Error ? e.message : '加载商户账号失败')
setAccounts([])
} finally {
setAccountsLoading(false)
}
}, [])
const openAccountEdit = (account: MerchantOwnerAccount) => {
setEditingAccount(account)
accountForm.resetFields()
accountForm.setFieldsValue({
username: account.username,
nickname: account.nickname,
password: '',
status: account.status === 1,
})
setAccountModalOpen(true)
}
const submitAccount = async () => {
if (!selectedMerchant || !editingAccount) return
const values = await accountForm.validateFields()
setAccountSubmitting(true)
try {
await platformApi.updateMerchantAccount(selectedMerchant.id, {
user_id: editingAccount.user_id,
username: values.username,
nickname: values.nickname || '',
password: values.password || undefined,
status: values.status ? 1 : 0,
})
message.success(values.password ? '商户账号已更新,密码已重置' : '商户账号已更新')
setAccountModalOpen(false)
void loadAccounts(selectedMerchant.id)
} catch (e) {
message.error(e instanceof Error ? e.message : '保存失败')
} finally {
setAccountSubmitting(false)
}
}
const openAdjust = async (record: Merchant) => {
setSelectedMerchant(record)
setAdjustOpen(true)
@@ -308,6 +362,7 @@ export default function PlatformMerchants() {
fee_fixed_amount: record.fee_fixed_amount,
})
setSettingsOpen(true)
void loadAccounts(record.id)
}}
>
@@ -467,6 +522,85 @@ export default function PlatformMerchants() {
}
</Form.Item>
</Form>
<Divider plain style={{ margin: '8px 0 16px' }}>
<Space size={6}>
<UserOutlined style={{ color: '#64748b' }} />
</Space>
</Divider>
<Spin spinning={accountsLoading}>
{accounts.length === 0 ? (
<Typography.Text type="secondary"></Typography.Text>
) : (
<Table
rowKey="user_id"
size="small"
pagination={false}
dataSource={accounts}
columns={[
{ title: '登录用户名', dataIndex: 'username', render: (v) => <Typography.Text strong>{v}</Typography.Text> },
{ title: '昵称', dataIndex: 'nickname', render: (v) => v || '-' },
{
title: '账号状态',
dataIndex: 'status',
width: 90,
render: (v) => (v === 1 ? <Tag color="green"></Tag> : <Tag></Tag>),
},
{
title: '操作',
key: 'action',
width: 70,
render: (_, record: MerchantOwnerAccount) => (
<Button type="link" size="small" onClick={() => openAccountEdit(record)}></Button>
),
},
]}
/>
)}
</Spin>
<Typography.Text type="secondary" style={{ display: 'block', marginTop: 8, fontSize: 12.5 }}>
</Typography.Text>
</Modal>
<Modal
title={editingAccount ? `编辑商户账号:${editingAccount.username}` : '编辑商户账号'}
open={accountModalOpen}
onOk={submitAccount}
onCancel={() => setAccountModalOpen(false)}
destroyOnClose
width={520}
confirmLoading={accountSubmitting}
okText="保存"
>
<Form form={accountForm} layout="vertical" style={{ marginTop: 16 }}>
<Form.Item
name="username"
label="登录用户名"
rules={[
{ required: true, message: '请输入用户名' },
{ min: 3, message: '用户名至少 3 位' },
{ max: 64, message: '用户名不能超过 64 个字符' },
]}
>
<Input autoComplete="off" placeholder="修改后负责人需使用新用户名登录" />
</Form.Item>
<Form.Item name="nickname" label="昵称" rules={[{ max: 64, message: '昵称不能超过 64 个字符' }]}>
<Input autoComplete="off" />
</Form.Item>
<Form.Item
name="password"
label="重置密码"
rules={[{ min: 6, message: '密码至少 6 位' }]}
extra="留空表示不修改密码"
>
<Input.Password autoComplete="new-password" placeholder="留空不修改" />
</Form.Item>
<Form.Item name="status" label="账号状态" valuePropName="checked" extra="停用后该负责人将无法登录商户后台">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
</Form.Item>
</Form>
</Modal>
<Modal
+9
View File
@@ -39,6 +39,15 @@ export interface MerchantMemberGroup {
members: MerchantMember[]
}
export interface MerchantOwnerAccount {
user_id: number
member_id: number
username: string
nickname: string
status: number
is_default: boolean
}
export interface MerchantRole {
id: number
merchant_id: number