796 lines
26 KiB
TypeScript
796 lines
26 KiB
TypeScript
import { useMemo, useState } from 'react'
|
||
import { useQuery } from '@tanstack/react-query'
|
||
import {
|
||
Alert,
|
||
App,
|
||
Button,
|
||
Col,
|
||
Form,
|
||
Input,
|
||
InputNumber,
|
||
Modal,
|
||
Row,
|
||
Select,
|
||
Space,
|
||
Switch,
|
||
Tag,
|
||
Typography,
|
||
type TableColumnsType,
|
||
} from 'antd'
|
||
import {
|
||
EditOutlined,
|
||
ExportOutlined,
|
||
EyeOutlined,
|
||
ReloadOutlined,
|
||
ShopOutlined,
|
||
} from '@ant-design/icons'
|
||
|
||
import { fetchAdminDistributionSites, updateAdminDistributionSite } from '@/features/admin/api'
|
||
import { AdminPageHeader } from '@/features/admin/components/AdminPageHeader'
|
||
import { DataTable } from '@/features/admin/components/DataTable'
|
||
import { DetailDrawer, type DetailSection } from '@/features/admin/components/DetailDrawer'
|
||
import { FilterBar, FilterField } from '@/features/admin/components/FilterBar'
|
||
import { StatusTag } from '@/features/admin/components/StatusTag'
|
||
import {
|
||
announcementModeMap,
|
||
distributionMemberTypeMap,
|
||
distributionSiteStatusMap,
|
||
distributionSiteStatusOptions,
|
||
readStatusMeta,
|
||
} from '@/features/admin/labels'
|
||
import type {
|
||
AdminDistributionSite,
|
||
AdminDistributionSiteUpdatePayload,
|
||
} from '@/features/admin/types'
|
||
import { useAdminSessionStore } from '@/stores/adminSession'
|
||
import { formatDateTime, formatText } from '@/shared/utils/format'
|
||
|
||
interface SiteFormValues {
|
||
site_name: string
|
||
domain: string
|
||
status: 'active' | 'disabled'
|
||
display_account_enabled: boolean
|
||
listing_qrcode_url?: string
|
||
receive_ratio_delta: number
|
||
receive_cost_delta: number
|
||
tax_enabled: boolean
|
||
tax_rate_bps: number
|
||
settlement_hold_days: number
|
||
}
|
||
|
||
function formatBps(bps?: number | null) {
|
||
if (bps == null) return '—'
|
||
return `${(bps / 100).toFixed(2)}%`
|
||
}
|
||
|
||
function hasJson(value?: string) {
|
||
const text = value?.trim()
|
||
return Boolean(text && text !== '{}' && text !== '[]' && text !== 'null')
|
||
}
|
||
|
||
function siteUrl(domain?: string) {
|
||
const text = domain?.trim()
|
||
if (!text) return ''
|
||
return /^https?:\/\//.test(text) ? text : `https://${text}`
|
||
}
|
||
|
||
function adminName(site: AdminDistributionSite) {
|
||
if (site.admin_nickname || site.admin_username) {
|
||
return site.admin_nickname || site.admin_username || ''
|
||
}
|
||
return site.admin_user_id != null ? `管理员 #${site.admin_user_id}` : '未绑定站长'
|
||
}
|
||
|
||
function buildSections(site: AdminDistributionSite): DetailSection[] {
|
||
const brandFields = [
|
||
{ key: 'logo', label: 'Logo', value: site.logo_url },
|
||
{ key: 'favicon', label: 'Favicon', value: site.favicon_url },
|
||
{ key: 'qrcode', label: '发布二维码', value: site.listing_qrcode_url },
|
||
].filter(field => field.value)
|
||
|
||
return [
|
||
{
|
||
key: 'overview',
|
||
title: '站点概览',
|
||
icon: <ShopOutlined />,
|
||
fields: [
|
||
{ key: 'name', label: '站点名称', value: site.site_name },
|
||
{ key: 'code', label: '站点标识', value: <span className="admin-mono">{site.site_code}</span> },
|
||
{
|
||
key: 'domain',
|
||
label: '专属域名',
|
||
value: site.domain ? (
|
||
<a href={siteUrl(site.domain)} target="_blank" rel="noreferrer">
|
||
{site.domain}
|
||
</a>
|
||
) : (
|
||
'—'
|
||
),
|
||
},
|
||
{
|
||
key: 'status',
|
||
label: '站点状态',
|
||
value: <StatusTag meta={readStatusMeta(distributionSiteStatusMap, site.status)} />,
|
||
},
|
||
{
|
||
key: 'display_account',
|
||
label: '展示账号',
|
||
value: site.display_account_enabled ? '开启' : '关闭',
|
||
},
|
||
{
|
||
key: 'announcement_mode',
|
||
label: '公告模式',
|
||
value: announcementModeMap[site.announcement_mode] ?? formatText(site.announcement_mode),
|
||
},
|
||
{ key: 'created', label: '创建时间', value: formatDateTime(site.created_at) },
|
||
{ key: 'updated', label: '更新时间', value: formatDateTime(site.updated_at) },
|
||
],
|
||
},
|
||
{
|
||
key: 'manager',
|
||
title: '站长与成员',
|
||
fields: [
|
||
{
|
||
key: 'admin',
|
||
label: '绑定站长',
|
||
value: (
|
||
<div className="admin-stack">
|
||
<strong>{adminName(site)}</strong>
|
||
<span className="admin-mono">
|
||
{site.admin_user_id != null ? `ID ${site.admin_user_id}` : '—'}
|
||
</span>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'member_type',
|
||
label: '成员角色',
|
||
value: site.member_type
|
||
? distributionMemberTypeMap[site.member_type] ?? site.member_type
|
||
: '平台全量可见',
|
||
},
|
||
{
|
||
key: 'support_group',
|
||
label: '默认客服群',
|
||
value:
|
||
site.default_support_group_id != null
|
||
? `群 #${site.default_support_group_id}`
|
||
: '未绑定',
|
||
},
|
||
{
|
||
key: 'counts',
|
||
label: '用户 / 下单用户',
|
||
value: `${site.user_count} / ${site.order_user_count}`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
key: 'settlement',
|
||
title: '分成与结算',
|
||
fields: [
|
||
{
|
||
key: 'ratio_delta',
|
||
label: '收号比例系数',
|
||
value: <span className="admin-mono">{site.receive_ratio_delta} 个点</span>,
|
||
},
|
||
{
|
||
key: 'cost_delta',
|
||
label: '收号成本系数',
|
||
value: <span className="admin-mono">{site.receive_cost_delta} 个点</span>,
|
||
},
|
||
{
|
||
key: 'hold_days',
|
||
label: '结算冷却',
|
||
value: `${site.settlement_hold_days} 天`,
|
||
},
|
||
{
|
||
key: 'tax',
|
||
label: '税费',
|
||
value: site.tax_enabled ? formatBps(site.tax_rate_bps) : '未启用',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
key: 'assets',
|
||
title: '品牌与页面配置',
|
||
fields: [
|
||
...(brandFields.length > 0
|
||
? brandFields.map(field => ({
|
||
key: field.key,
|
||
label: field.label,
|
||
value: (
|
||
<a href={field.value} target="_blank" rel="noreferrer" className="admin-mono">
|
||
{field.value}
|
||
</a>
|
||
),
|
||
}))
|
||
: [
|
||
{
|
||
key: 'brand_empty',
|
||
label: '品牌素材',
|
||
value: '沿用主站品牌素材',
|
||
},
|
||
]),
|
||
{
|
||
key: 'configs',
|
||
label: '页面配置',
|
||
span: 2,
|
||
value: (
|
||
<Space size={4} wrap>
|
||
<Tag color={hasJson(site.banners_json) ? 'blue' : undefined}>轮播</Tag>
|
||
<Tag color={hasJson(site.announcements_json) ? 'blue' : undefined}>公告</Tag>
|
||
<Tag color={hasJson(site.footer_info_json) ? 'blue' : undefined}>页脚</Tag>
|
||
<Tag color={hasJson(site.aw_recycle_json) ? 'blue' : undefined}>回收入口</Tag>
|
||
<Tag color={hasJson(site.cooperation_feedback_json) ? 'blue' : undefined}>
|
||
合作反馈
|
||
</Tag>
|
||
<Tag color={hasJson(site.storefront_text_json) ? 'blue' : undefined}>卖场文案</Tag>
|
||
</Space>
|
||
),
|
||
},
|
||
],
|
||
},
|
||
]
|
||
}
|
||
|
||
function buildColumns(
|
||
onOpen: (site: AdminDistributionSite) => void,
|
||
onEdit: (site: AdminDistributionSite) => void,
|
||
canManage: boolean
|
||
): TableColumnsType<AdminDistributionSite> {
|
||
return [
|
||
{
|
||
title: '站点',
|
||
dataIndex: 'site_name',
|
||
width: 280,
|
||
fixed: 'left',
|
||
render: (_, row) => (
|
||
<div className="admin-stack">
|
||
<button type="button" className="admin-order-link" onClick={() => onOpen(row)}>
|
||
{row.site_name}
|
||
</button>
|
||
<span className="admin-mono">{row.site_code}</span>
|
||
<span>{row.domain || '未绑定专属域名'}</span>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
title: '站长',
|
||
key: 'admin',
|
||
width: 190,
|
||
render: (_, row) => (
|
||
<div className="admin-stack">
|
||
<strong>{adminName(row)}</strong>
|
||
<span>
|
||
{row.member_type
|
||
? distributionMemberTypeMap[row.member_type] ?? row.member_type
|
||
: '平台账号'}
|
||
</span>
|
||
<span className="admin-mono">
|
||
{row.admin_user_id != null ? `ID ${row.admin_user_id}` : '—'}
|
||
</span>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'status',
|
||
width: 100,
|
||
render: value => <StatusTag meta={readStatusMeta(distributionSiteStatusMap, value)} />,
|
||
},
|
||
{
|
||
title: '用户',
|
||
key: 'users',
|
||
width: 130,
|
||
align: 'right',
|
||
render: (_, row) => (
|
||
<div className="admin-amount">
|
||
<strong>{row.user_count}</strong>
|
||
<span>下单 {row.order_user_count}</span>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
title: '分成 / 结算',
|
||
key: 'settlement',
|
||
width: 190,
|
||
render: (_, row) => (
|
||
<div className="admin-stack">
|
||
<span className="admin-mono">比例 {row.receive_ratio_delta} 点</span>
|
||
<span className="admin-mono">成本 {row.receive_cost_delta} 点</span>
|
||
<span>
|
||
冷却 {row.settlement_hold_days} 天 ·{' '}
|
||
{row.tax_enabled ? formatBps(row.tax_rate_bps) : '无税'}
|
||
</span>
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
dataIndex: 'created_at',
|
||
width: 160,
|
||
render: value => formatDateTime(value),
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: 150,
|
||
fixed: 'right',
|
||
render: (_, row) => (
|
||
<Space size={0}>
|
||
<Button type="link" size="small" icon={<EyeOutlined />} onClick={() => onOpen(row)}>
|
||
详情
|
||
</Button>
|
||
{canManage ? (
|
||
<Button type="link" size="small" icon={<EditOutlined />} onClick={() => onEdit(row)}>
|
||
编辑
|
||
</Button>
|
||
) : null}
|
||
</Space>
|
||
),
|
||
},
|
||
]
|
||
}
|
||
|
||
export function AdminDistributionSitesPage() {
|
||
const { message, modal } = App.useApp()
|
||
const [form] = Form.useForm<SiteFormValues>()
|
||
const [keyword, setKeyword] = useState('')
|
||
const [status, setStatus] = useState('')
|
||
const [selected, setSelected] = useState<AdminDistributionSite | null>(null)
|
||
const [detailOpen, setDetailOpen] = useState(false)
|
||
const [editing, setEditing] = useState<AdminDistributionSite | null>(null)
|
||
const [saving, setSaving] = useState(false)
|
||
const permissions = useAdminSessionStore(state => state.admin?.permissions)
|
||
const canView = Boolean(
|
||
permissions?.includes('*') ||
|
||
permissions?.includes('distribution:site_view') ||
|
||
permissions?.includes('qrcode:view')
|
||
)
|
||
const canManage = Boolean(
|
||
permissions?.includes('*') || permissions?.includes('distribution:site_manage')
|
||
)
|
||
|
||
const { data, isPending, isFetching, isError, error, refetch } = useQuery({
|
||
queryKey: ['admin-distribution-sites'],
|
||
queryFn: fetchAdminDistributionSites,
|
||
enabled: canView,
|
||
})
|
||
|
||
const sites = data ?? []
|
||
|
||
const filtered = useMemo(() => {
|
||
const text = keyword.trim().toLowerCase()
|
||
return sites.filter(site => {
|
||
if (status && site.status !== status) return false
|
||
if (!text) return true
|
||
return [site.site_name, site.site_code, site.domain, site.admin_username, site.admin_nickname]
|
||
.filter(Boolean)
|
||
.some(value => String(value).toLowerCase().includes(text))
|
||
})
|
||
}, [sites, keyword, status])
|
||
|
||
const limited = Boolean(editing?.member_type)
|
||
const errorText = error instanceof Error ? error.message : '请稍后重试或重新登录后台。'
|
||
const distributionAdminUrl = import.meta.env.VITE_DISTRIBUTION_ADMIN_URL
|
||
const hasActiveFilters = Boolean(keyword || status)
|
||
|
||
const openDetail = (site: AdminDistributionSite) => {
|
||
setSelected(site)
|
||
setDetailOpen(true)
|
||
}
|
||
|
||
const openEditor = (site: AdminDistributionSite) => {
|
||
setEditing(site)
|
||
form.setFieldsValue({
|
||
site_name: site.site_name,
|
||
domain: site.domain,
|
||
status: site.status === 'disabled' ? 'disabled' : 'active',
|
||
display_account_enabled: site.display_account_enabled,
|
||
listing_qrcode_url: site.listing_qrcode_url,
|
||
receive_ratio_delta: site.receive_ratio_delta,
|
||
receive_cost_delta: site.receive_cost_delta,
|
||
tax_enabled: site.tax_enabled,
|
||
tax_rate_bps: site.tax_rate_bps,
|
||
settlement_hold_days: site.settlement_hold_days,
|
||
})
|
||
}
|
||
|
||
const closeEditor = () => {
|
||
if (saving) return
|
||
setEditing(null)
|
||
}
|
||
|
||
const applyUpdated = (updated: AdminDistributionSite) => {
|
||
setSelected(current => (current?.id === updated.id ? updated : current))
|
||
}
|
||
|
||
const saveSite = async () => {
|
||
if (!editing) return
|
||
let values: SiteFormValues
|
||
try {
|
||
values = await form.validateFields()
|
||
} catch {
|
||
return
|
||
}
|
||
|
||
const payload: AdminDistributionSiteUpdatePayload = limited
|
||
? {
|
||
receive_ratio_delta: Number(values.receive_ratio_delta),
|
||
receive_cost_delta: Number(values.receive_cost_delta),
|
||
}
|
||
: {
|
||
site_name: values.site_name?.trim(),
|
||
domain: values.domain?.trim(),
|
||
status: values.status,
|
||
display_account_enabled: values.display_account_enabled,
|
||
listing_qrcode_url: values.listing_qrcode_url?.trim(),
|
||
receive_ratio_delta: Number(values.receive_ratio_delta),
|
||
receive_cost_delta: Number(values.receive_cost_delta),
|
||
tax_enabled: values.tax_enabled,
|
||
tax_rate_bps: values.tax_enabled ? Number(values.tax_rate_bps) : 0,
|
||
settlement_hold_days: Number(values.settlement_hold_days),
|
||
}
|
||
|
||
modal.confirm({
|
||
title: `确认更新「${editing.site_name}」?`,
|
||
content: limited
|
||
? '站长账号只能调整本站分成系数,其他站点资料不会被修改。'
|
||
: '站点名称、域名、分成系数与结算冷却会立即影响前台展示和后续订单结算,请确认已核对。',
|
||
okText: '确认更新',
|
||
cancelText: '再检查一下',
|
||
onOk: async () => {
|
||
setSaving(true)
|
||
try {
|
||
const updated = await updateAdminDistributionSite(editing.id, payload)
|
||
message.success('分销站点已更新')
|
||
applyUpdated(updated)
|
||
setEditing(null)
|
||
await refetch()
|
||
} catch (err) {
|
||
message.error(err instanceof Error ? err.message : '更新失败,请稍后重试')
|
||
} finally {
|
||
setSaving(false)
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
const toggleStatus = (site: AdminDistributionSite) => {
|
||
const next = site.status === 'active' ? 'disabled' : 'active'
|
||
const actionText = next === 'active' ? '启用' : '停用'
|
||
modal.confirm({
|
||
title: `确认${actionText}「${site.site_name}」?`,
|
||
content:
|
||
next === 'active'
|
||
? '启用后站点域名与前台页面会恢复对外服务。'
|
||
: '停用后站点前台会停止服务,请先确认站内订单与结算已经处理完毕。',
|
||
okText: `确认${actionText}`,
|
||
okButtonProps: { danger: next === 'disabled' },
|
||
cancelText: '取消',
|
||
onOk: async () => {
|
||
try {
|
||
const updated = await updateAdminDistributionSite(site.id, { status: next })
|
||
message.success(`站点已${actionText}`)
|
||
applyUpdated(updated)
|
||
await refetch()
|
||
} catch (err) {
|
||
message.error(err instanceof Error ? err.message : `${actionText}失败,请稍后重试`)
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
const columns = useMemo(
|
||
() => buildColumns(openDetail, openEditor, canManage),
|
||
[canManage]
|
||
)
|
||
|
||
const detailFooter = selected ? (
|
||
<Space>
|
||
<Button onClick={() => setDetailOpen(false)}>关闭</Button>
|
||
{canManage ? (
|
||
<Button icon={<EditOutlined />} onClick={() => openEditor(selected)}>
|
||
编辑站点
|
||
</Button>
|
||
) : null}
|
||
{canManage && !selected.member_type ? (
|
||
<Button
|
||
danger={selected.status === 'active'}
|
||
type={selected.status === 'active' ? 'default' : 'primary'}
|
||
onClick={() => toggleStatus(selected)}
|
||
>
|
||
{selected.status === 'active' ? '停用站点' : '启用站点'}
|
||
</Button>
|
||
) : null}
|
||
</Space>
|
||
) : null
|
||
|
||
return (
|
||
<div className="admin-page">
|
||
<AdminPageHeader
|
||
eyebrow="JIEYOU OPS · 分销"
|
||
title="分销站点"
|
||
description="查看分站域名、站长、分成系数与结算冷却;开通分销商沿用现有分销后台流程。"
|
||
meta={
|
||
<Space size={8} wrap>
|
||
<Tag color="geekblue">共 {sites.length} 个站点</Tag>
|
||
<Tag color="green">
|
||
运营中 {sites.filter(item => item.status === 'active').length}
|
||
</Tag>
|
||
{isFetching && !isPending ? <Tag color="processing">正在更新</Tag> : null}
|
||
</Space>
|
||
}
|
||
extra={
|
||
<Space>
|
||
{distributionAdminUrl ? (
|
||
<Button
|
||
icon={<ExportOutlined />}
|
||
href={distributionAdminUrl}
|
||
target="_blank"
|
||
rel="noreferrer"
|
||
>
|
||
前往分销后台
|
||
</Button>
|
||
) : null}
|
||
<Button
|
||
icon={<ReloadOutlined />}
|
||
onClick={() => void refetch()}
|
||
loading={isFetching}
|
||
disabled={!canView}
|
||
>
|
||
刷新数据
|
||
</Button>
|
||
</Space>
|
||
}
|
||
/>
|
||
|
||
{!canView ? (
|
||
<Alert
|
||
type="warning"
|
||
showIcon
|
||
className="admin-table-alert"
|
||
message="当前账号没有分销站点查看权限"
|
||
description="需要 distribution:site_view 或 qrcode:view 权限才能读取站点列表。"
|
||
/>
|
||
) : null}
|
||
|
||
<FilterBar
|
||
onReset={
|
||
hasActiveFilters
|
||
? () => {
|
||
setKeyword('')
|
||
setStatus('')
|
||
}
|
||
: undefined
|
||
}
|
||
loading={isFetching}
|
||
extra={
|
||
<Typography.Text type="secondary">
|
||
{filtered.length === sites.length
|
||
? '显示全部站点'
|
||
: `筛选出 ${filtered.length} / ${sites.length} 个站点`}
|
||
</Typography.Text>
|
||
}
|
||
>
|
||
<FilterField label="关键字" width={320}>
|
||
<Input
|
||
allowClear
|
||
value={keyword}
|
||
placeholder="站点名称 / 标识 / 域名 / 站长"
|
||
onChange={event => setKeyword(event.target.value)}
|
||
/>
|
||
</FilterField>
|
||
<FilterField label="站点状态" width={180}>
|
||
<Select
|
||
allowClear
|
||
value={status || undefined}
|
||
placeholder="全部状态"
|
||
options={distributionSiteStatusOptions}
|
||
onChange={value => setStatus(value ?? '')}
|
||
/>
|
||
</FilterField>
|
||
</FilterBar>
|
||
|
||
{isError ? (
|
||
<Alert
|
||
type="error"
|
||
showIcon
|
||
className="admin-table-alert"
|
||
message="分销站点没有加载出来"
|
||
description={errorText}
|
||
action={
|
||
<Button size="small" onClick={() => void refetch()}>
|
||
重试
|
||
</Button>
|
||
}
|
||
/>
|
||
) : null}
|
||
|
||
<DataTable<AdminDistributionSite>
|
||
title={<span>站点列表</span>}
|
||
extra={
|
||
<Typography.Text type="secondary">
|
||
{isPending ? '加载中' : `当前 ${filtered.length} 个站点`}
|
||
</Typography.Text>
|
||
}
|
||
rowKey="id"
|
||
columns={columns}
|
||
dataSource={filtered}
|
||
loading={isFetching}
|
||
onRowClick={openDetail}
|
||
emptyDescription={
|
||
canView
|
||
? '还没有分销站点;需要开通时请前往分销后台创建站点与站长账号'
|
||
: '当前账号没有查看权限'
|
||
}
|
||
/>
|
||
|
||
<DetailDrawer
|
||
open={detailOpen}
|
||
onClose={() => setDetailOpen(false)}
|
||
title={selected?.site_name ?? '分销站点'}
|
||
subtitle={
|
||
selected
|
||
? `${selected.site_code} · ${selected.domain || '未绑定域名'} · ${adminName(selected)}`
|
||
: undefined
|
||
}
|
||
tags={
|
||
selected ? (
|
||
<Space size={6} wrap>
|
||
<StatusTag meta={readStatusMeta(distributionSiteStatusMap, selected.status)} />
|
||
{selected.member_type ? (
|
||
<Tag>{distributionMemberTypeMap[selected.member_type] ?? selected.member_type}</Tag>
|
||
) : (
|
||
<Tag color="geekblue">平台全量</Tag>
|
||
)}
|
||
</Space>
|
||
) : undefined
|
||
}
|
||
sections={selected ? buildSections(selected) : []}
|
||
footer={detailFooter}
|
||
width={820}
|
||
emptyDescription="没有可展示的站点详情"
|
||
/>
|
||
|
||
<Modal
|
||
open={Boolean(editing)}
|
||
title={
|
||
<div className="admin-detail-drawer__head">
|
||
<div className="admin-detail-drawer__title">
|
||
{limited ? '调整分成系数' : '编辑分销站点'}
|
||
</div>
|
||
{editing ? (
|
||
<div className="admin-detail-drawer__subtitle">
|
||
{editing.site_name} · {editing.site_code}
|
||
</div>
|
||
) : null}
|
||
</div>
|
||
}
|
||
width={760}
|
||
onCancel={closeEditor}
|
||
maskClosable={!saving}
|
||
closable={!saving}
|
||
destroyOnHidden
|
||
footer={
|
||
<Space>
|
||
<Button onClick={closeEditor} disabled={saving}>
|
||
取消
|
||
</Button>
|
||
<Button type="primary" loading={saving} onClick={() => void saveSite()}>
|
||
保存站点
|
||
</Button>
|
||
</Space>
|
||
}
|
||
>
|
||
{editing ? (
|
||
<Form<SiteFormValues> form={form} layout="vertical" disabled={saving}>
|
||
{limited ? (
|
||
<Alert
|
||
type="info"
|
||
showIcon
|
||
className="admin-table-alert"
|
||
message="站长账号编辑范围"
|
||
description="当前账号是该站点成员,只能调整本站收号比例与收号成本系数,不能修改站点资料、域名或状态。"
|
||
/>
|
||
) : (
|
||
<>
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="site_name"
|
||
label="站点名称"
|
||
rules={[{ required: true, message: '请输入站点名称' }]}
|
||
>
|
||
<Input maxLength={128} />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="domain"
|
||
label="专属域名"
|
||
rules={[{ required: true, message: '请输入专属域名' }]}
|
||
>
|
||
<Input maxLength={255} placeholder="例如 sub.zuhaoc.com" />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item name="status" label="站点状态">
|
||
<Select options={distributionSiteStatusOptions} />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="display_account_enabled"
|
||
label="展示账号"
|
||
valuePropName="checked"
|
||
>
|
||
<Switch checkedChildren="开启" unCheckedChildren="关闭" />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="settlement_hold_days"
|
||
label="结算冷却天数"
|
||
rules={[{ required: true, message: '请输入结算冷却天数' }]}
|
||
>
|
||
<InputNumber min={0} max={365} precision={0} style={{ width: '100%' }} />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item name="listing_qrcode_url" label="发布二维码地址">
|
||
<Input placeholder="https://..." />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item name="tax_enabled" label="启用税费" valuePropName="checked">
|
||
<Switch checkedChildren="启用" unCheckedChildren="关闭" />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="tax_rate_bps"
|
||
label="税率(bps)"
|
||
extra="100 bps = 1%,关闭税费时保存为 0"
|
||
>
|
||
<InputNumber min={0} max={10000} precision={0} style={{ width: '100%' }} />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
</>
|
||
)}
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="receive_ratio_delta"
|
||
label="收号比例调整点数"
|
||
extra="范围 0-20,按后端分销定价规则参与结算"
|
||
rules={[{ required: true, message: '请输入收号比例调整点数' }]}
|
||
>
|
||
<InputNumber min={0} max={20} step={0.01} style={{ width: '100%' }} />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item
|
||
name="receive_cost_delta"
|
||
label="收号成本调整点数"
|
||
extra="范围 0-20,按后端分销定价规则参与结算"
|
||
rules={[{ required: true, message: '请输入收号成本调整点数' }]}
|
||
>
|
||
<InputNumber min={0} max={20} step={0.01} style={{ width: '100%' }} />
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
</Form>
|
||
) : null}
|
||
</Modal>
|
||
</div>
|
||
)
|
||
}
|