feat(distribution): 完善分销收号资产双视图、商户提现、自主加价、品牌装修与数据大盘
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import { useEffect, useState, useMemo } from 'react'
|
||||
import { Card, Table, Typography, Space, Select, Tag, message, Button, Input, Modal } from 'antd'
|
||||
import { SyncOutlined, SearchOutlined, CheckCircleOutlined, StopOutlined } from '@ant-design/icons'
|
||||
import { Card, Table, Typography, Space, Select, Tag, message, Button, Input, Modal, InputNumber } from 'antd'
|
||||
import { SyncOutlined, SearchOutlined, CheckCircleOutlined, StopOutlined, EditOutlined, DollarCircleOutlined } from '@ant-design/icons'
|
||||
import {
|
||||
listAccountDisplays,
|
||||
listSites,
|
||||
updateAccountDisplay,
|
||||
syncSiteAccounts,
|
||||
updateAccountMarkup,
|
||||
batchUpdateAccountMarkup,
|
||||
formatMoney,
|
||||
type AccountDisplay,
|
||||
type Site,
|
||||
@@ -28,6 +30,12 @@ export default function Accounts() {
|
||||
const [syncing, setSyncing] = useState(false)
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
|
||||
|
||||
// Markup modal state
|
||||
const [markupModalVisible, setMarkupModalVisible] = useState(false)
|
||||
const [targetAccount, setTargetAccount] = useState<AccountDisplay | null>(null)
|
||||
const [markupYuan, setMarkupYuan] = useState<number>(0)
|
||||
const [markupSaving, setMarkupSaving] = useState(false)
|
||||
|
||||
async function load(site?: number, statusFilter?: string) {
|
||||
if (!site) return
|
||||
setLoading(true)
|
||||
@@ -111,6 +119,51 @@ export default function Accounts() {
|
||||
})
|
||||
}
|
||||
|
||||
function handleOpenMarkup(item?: AccountDisplay) {
|
||||
if (item) {
|
||||
setTargetAccount(item)
|
||||
setMarkupYuan((item.markup_amount_cent ?? 0) / 100)
|
||||
} else {
|
||||
if (selectedRowKeys.length === 0) {
|
||||
message.warning('请先勾选需要批量加价的账号商品')
|
||||
return
|
||||
}
|
||||
setTargetAccount(null)
|
||||
setMarkupYuan(0)
|
||||
}
|
||||
setMarkupModalVisible(true)
|
||||
}
|
||||
|
||||
async function handleSaveMarkup() {
|
||||
if (!siteID) return
|
||||
const markupCent = Math.round(markupYuan * 100)
|
||||
if (markupCent < 0) {
|
||||
message.error('加价金额不能小于0')
|
||||
return
|
||||
}
|
||||
setMarkupSaving(true)
|
||||
try {
|
||||
if (targetAccount) {
|
||||
await updateAccountMarkup(targetAccount.id, markupCent)
|
||||
message.success('商品加价设置成功!')
|
||||
} else {
|
||||
const listingIDs = items
|
||||
.filter((it) => selectedRowKeys.includes(it.id))
|
||||
.map((it) => it.listing_id)
|
||||
await batchUpdateAccountMarkup(siteID, listingIDs, markupCent)
|
||||
message.success(`已成功为选中的 ${listingIDs.length} 个商品批量设置加价!`)
|
||||
setSelectedRowKeys([])
|
||||
}
|
||||
setMarkupModalVisible(false)
|
||||
void load(siteID, status)
|
||||
} catch (error: unknown) {
|
||||
const respMessage = (error as { response?: { data?: { message?: string } } })?.response?.data?.message
|
||||
message.error(respMessage || '加价设置保存失败')
|
||||
} finally {
|
||||
setMarkupSaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
const kw = keyword.trim().toLowerCase()
|
||||
if (!kw) return items
|
||||
@@ -191,6 +244,13 @@ export default function Accounts() {
|
||||
{selectedRowKeys.length > 0 && (
|
||||
<Space>
|
||||
<Typography.Text type="secondary">已勾选 {selectedRowKeys.length} 项</Typography.Text>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<DollarCircleOutlined />}
|
||||
onClick={() => handleOpenMarkup()}
|
||||
>
|
||||
批量加价
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<CheckCircleOutlined />}
|
||||
@@ -285,6 +345,21 @@ export default function Accounts() {
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '自主加价',
|
||||
dataIndex: 'markup_amount_cent',
|
||||
width: 120,
|
||||
render: (v: number | undefined) => {
|
||||
if (v && v > 0) {
|
||||
return (
|
||||
<Tag color="gold" style={{ fontWeight: 'bold' }}>
|
||||
+{formatMoney(v)}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
return <span style={{ color: '#aaa', fontSize: 12 }}>无加价</span>
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '主站状态',
|
||||
dataIndex: 'listing_status',
|
||||
@@ -306,21 +381,69 @@ export default function Accounts() {
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 120,
|
||||
width: 160,
|
||||
render: (_: unknown, row: AccountDisplay) => (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
danger={row.display_status === 'enabled'}
|
||||
onClick={() => toggle(row)}
|
||||
>
|
||||
{row.display_status === 'enabled' ? '下架' : '恢复展示'}
|
||||
</Button>
|
||||
<Space size={2}>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleOpenMarkup(row)}
|
||||
>
|
||||
加价
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
danger={row.display_status === 'enabled'}
|
||||
onClick={() => toggle(row)}
|
||||
>
|
||||
{row.display_status === 'enabled' ? '下架' : '展示'}
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
title={targetAccount ? `设置加价 - ${targetAccount.title || targetAccount.listing_no}` : `批量加价 (${selectedRowKeys.length} 个账号商品)`}
|
||||
open={markupModalVisible}
|
||||
onCancel={() => setMarkupModalVisible(false)}
|
||||
onOk={handleSaveMarkup}
|
||||
confirmLoading={markupSaving}
|
||||
okText="保存加价"
|
||||
destroyOnClose
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%', padding: '12px 0' }}>
|
||||
<Typography.Paragraph type="secondary" style={{ marginBottom: 8 }}>
|
||||
自主加价金额将直接叠加在分销前台展示的每小时租金上,该部分溢价产生的收益将在成单结算时归当前分销商所有。
|
||||
</Typography.Paragraph>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<Typography.Text strong>每小时加价金额:</Typography.Text>
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={1000}
|
||||
precision={2}
|
||||
style={{ width: 180 }}
|
||||
value={markupYuan}
|
||||
onChange={(val) => setMarkupYuan(val ?? 0)}
|
||||
addonAfter="元/小时"
|
||||
placeholder="0.00"
|
||||
/>
|
||||
</div>
|
||||
{markupYuan > 0 && targetAccount && (
|
||||
<div style={{ marginTop: 8, padding: '8px 12px', background: '#f6ffed', borderRadius: 4, border: '1px solid #b7eb8f', fontSize: 12 }}>
|
||||
原租金 {formatMoney(targetAccount.price_cent)}/时 ➔ 分销前台标价为{' '}
|
||||
<strong style={{ color: '#cf1322' }}>
|
||||
¥{(((targetAccount.price_cent ?? 0) + Math.round(markupYuan * 100)) / 100).toFixed(2)}
|
||||
</strong>
|
||||
/时
|
||||
</div>
|
||||
)}
|
||||
</Space>
|
||||
</Modal>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user