优化打手端我的订单与个人中心界面布局
This commit is contained in:
@@ -9,18 +9,15 @@ import {
|
|||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Col,
|
|
||||||
Descriptions,
|
Descriptions,
|
||||||
Drawer,
|
Drawer,
|
||||||
Empty,
|
Empty,
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
Row,
|
|
||||||
Segmented,
|
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Table,
|
Table,
|
||||||
|
Tabs,
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
@@ -40,24 +37,14 @@ import { formatDateTime } from '@/utils/date-time'
|
|||||||
|
|
||||||
const STATUS_OPTIONS = [
|
const STATUS_OPTIONS = [
|
||||||
{ value: '', label: '全部订单' },
|
{ value: '', label: '全部订单' },
|
||||||
{ value: 'open', label: '已超时' },
|
|
||||||
{ value: 'in_progress', label: '代练中' },
|
{ value: 'in_progress', label: '代练中' },
|
||||||
{ value: 'pending_acceptance', label: '待验收' },
|
{ value: 'pending_acceptance', label: '待验收' },
|
||||||
{ value: 'problem', label: '问题单' },
|
{ value: 'problem', label: '问题单' },
|
||||||
|
{ value: 'open', label: '已超时' },
|
||||||
{ value: 'accepted', label: '已验收' },
|
{ value: 'accepted', label: '已验收' },
|
||||||
{ value: 'cancelled', label: '已取消' },
|
{ value: 'cancelled', label: '已取消' },
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
const STATUS_SUMMARY_ITEMS = [
|
|
||||||
{ key: 'all', label: '全部订单', note: '当前账号历史接单总数' },
|
|
||||||
{ key: 'in_progress', label: '代练中', note: '正在执行中的订单' },
|
|
||||||
{ key: 'pending_acceptance', label: '待验收', note: '已提交,等待审核' },
|
|
||||||
{ key: 'problem', label: '问题单', note: '需要补充或重新处理' },
|
|
||||||
{ key: 'open', label: '已超时', note: '超时被系统退回的订单数' },
|
|
||||||
{ key: 'accepted', label: '已验收', note: '已完成并结算的订单' },
|
|
||||||
{ key: 'cancelled', label: '已取消', note: '已结束且不再继续' },
|
|
||||||
] as const
|
|
||||||
|
|
||||||
type AcceptanceFormValues = {
|
type AcceptanceFormValues = {
|
||||||
note?: string
|
note?: string
|
||||||
}
|
}
|
||||||
@@ -171,7 +158,7 @@ export default function WorkerOrdersPage() {
|
|||||||
const columns: TableColumnsType<WorkOrder> = [
|
const columns: TableColumnsType<WorkOrder> = [
|
||||||
{
|
{
|
||||||
title: '订单信息',
|
title: '订单信息',
|
||||||
minWidth: 320,
|
minWidth: 280,
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<div className="cell-stack">
|
<div className="cell-stack">
|
||||||
<Typography.Link onClick={() => setDetailOrder(row)}>
|
<Typography.Link onClick={() => setDetailOrder(row)}>
|
||||||
@@ -179,12 +166,10 @@ export default function WorkerOrdersPage() {
|
|||||||
</Typography.Link>
|
</Typography.Link>
|
||||||
<Space size={[6, 6]} wrap>
|
<Space size={[6, 6]} wrap>
|
||||||
{row.categoryName ? <Tag>{row.categoryName}</Tag> : null}
|
{row.categoryName ? <Tag>{row.categoryName}</Tag> : null}
|
||||||
<Typography.Text type="secondary">
|
{row.myShare ? <Tag color="purple">拼单</Tag> : null}
|
||||||
工单号:{row.workOrderNo}
|
|
||||||
</Typography.Text>
|
|
||||||
</Space>
|
</Space>
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
订单号:{row.platformOrderId || '-'}
|
{row.workOrderNo} · {row.platformOrderId || '-'}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
接单时间:{formatDateTime(row.assignedAt)}
|
接单时间:{formatDateTime(row.assignedAt)}
|
||||||
@@ -192,6 +177,25 @@ export default function WorkerOrdersPage() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
width: 170,
|
||||||
|
render: (_, row) => (
|
||||||
|
<div className="cell-stack">
|
||||||
|
<Space wrap size={6}>
|
||||||
|
<Tag color={resolveStatusColor(row.status)}>{formatStatus(row.status)}</Tag>
|
||||||
|
{row.status === 'in_progress' && row.deadlineAt ? (
|
||||||
|
<DeadlineCountdown deadlineAt={row.deadlineAt} />
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
|
{row.status === 'problem' && String(row.problemNote || '').trim() ? (
|
||||||
|
<Typography.Text type="danger" ellipsis>
|
||||||
|
{row.problemNote}
|
||||||
|
</Typography.Text>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '奖励 / 押金',
|
title: '奖励 / 押金',
|
||||||
width: 150,
|
width: 150,
|
||||||
@@ -201,77 +205,46 @@ export default function WorkerOrdersPage() {
|
|||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
冻结押金:{formatMoney(row.freezeDepositAmount)}
|
冻结押金:{formatMoney(row.freezeDepositAmount)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
{row.myShare ? (
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '我的拼单',
|
|
||||||
width: 170,
|
|
||||||
render: (_, row) =>
|
|
||||||
row.myShare ? (
|
|
||||||
<div className="cell-stack">
|
|
||||||
<Tag color="purple">
|
|
||||||
{formatSharingShareStatus(row.myShare.status)}
|
|
||||||
</Tag>
|
|
||||||
<Typography.Text>
|
|
||||||
{row.myShare.quantity} 份 × {formatMoney(row.myShare.unitReward)}
|
|
||||||
</Typography.Text>
|
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
份额报酬:{formatMoney(row.myShare.shareReward)}
|
{row.myShare.quantity} 份 · 份额 {formatMoney(row.myShare.shareReward)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Typography.Text type="secondary">-</Typography.Text>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '当前状态',
|
|
||||||
width: 180,
|
|
||||||
render: (_, row) => (
|
|
||||||
<div className="cell-stack">
|
|
||||||
<Tag color={resolveStatusColor(row.status)}>{formatStatus(row.status)}</Tag>
|
|
||||||
{row.status === 'in_progress' && row.deadlineAt ? (
|
|
||||||
<DeadlineCountdown deadlineAt={row.deadlineAt} />
|
|
||||||
) : null}
|
) : null}
|
||||||
<Typography.Text type="secondary">
|
|
||||||
{getStatusHint(row.status)}
|
|
||||||
</Typography.Text>
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '验收信息',
|
title: '验收信息',
|
||||||
minWidth: 210,
|
minWidth: 200,
|
||||||
render: (_, row) => (
|
render: (_, row) => {
|
||||||
|
const submittedAt = getAcceptanceSubmittedAt(row)
|
||||||
|
const hasAcceptance =
|
||||||
|
getAcceptanceFiles(row).length > 0 || getAcceptanceImageUrls(row).length > 0
|
||||||
|
if (!hasAcceptance && !submittedAt) {
|
||||||
|
return <Typography.Text type="secondary">未提交</Typography.Text>
|
||||||
|
}
|
||||||
|
return (
|
||||||
<div className="cell-stack">
|
<div className="cell-stack">
|
||||||
<ImagePreviewList
|
<ImagePreviewList
|
||||||
files={getAcceptanceFiles(row)}
|
files={getAcceptanceFiles(row)}
|
||||||
imageUrls={getAcceptanceImageUrls(row)}
|
imageUrls={getAcceptanceImageUrls(row)}
|
||||||
size={46}
|
size={40}
|
||||||
/>
|
/>
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
提交时间:{formatDateTime(getAcceptanceSubmittedAt(row))}
|
提交时间:{formatDateTime(submittedAt)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
{row.acceptance?.note ? (
|
{row.acceptance?.note ? (
|
||||||
<Typography.Text ellipsis>{row.acceptance.note}</Typography.Text>
|
<Typography.Text type="secondary" ellipsis>
|
||||||
) : (
|
{row.acceptance.note}
|
||||||
<Typography.Text type="secondary">暂无验收说明</Typography.Text>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '问题备注',
|
|
||||||
minWidth: 180,
|
|
||||||
render: (_, row) => (
|
|
||||||
<Typography.Text ellipsis>
|
|
||||||
{String(row.problemNote || '').trim() || '-'}
|
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
),
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 280,
|
width: 260,
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<Button icon={<EyeOutlined />} onClick={() => setDetailOrder(row)}>
|
<Button icon={<EyeOutlined />} onClick={() => setDetailOrder(row)}>
|
||||||
@@ -287,10 +260,7 @@ export default function WorkerOrdersPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
{canCancelOrder(row) ? (
|
{canCancelOrder(row) ? (
|
||||||
<Button
|
<Button danger onClick={() => openCancelModal(row)}>
|
||||||
danger
|
|
||||||
onClick={() => openCancelModal(row)}
|
|
||||||
>
|
|
||||||
取消接单
|
取消接单
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -312,27 +282,33 @@ export default function WorkerOrdersPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Row gutter={[16, 16]}>
|
|
||||||
{STATUS_SUMMARY_ITEMS.map((item) => (
|
|
||||||
<Col key={item.key} xs={24} sm={12} xl={8} xxl={4}>
|
|
||||||
<Card size="small">
|
|
||||||
<Statistic
|
|
||||||
title={item.label}
|
|
||||||
value={Number(overviewQuery.data?.[item.key] || 0)}
|
|
||||||
suffix="单"
|
|
||||||
loading={overviewQuery.isLoading}
|
|
||||||
/>
|
|
||||||
<Typography.Text type="secondary">{item.note}</Typography.Text>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
))}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Card bordered={false}>
|
<Card bordered={false}>
|
||||||
<Space direction="vertical" size={16} style={{ width: '100%' }}>
|
<Space direction="vertical" size={16} style={{ width: '100%' }}>
|
||||||
<Space direction="vertical" size={12} style={{ width: '100%' }}>
|
<Tabs
|
||||||
<Space wrap size={12}>
|
activeKey={status || 'all'}
|
||||||
<Space.Compact style={{ width: '100%', maxWidth: 520 }}>
|
items={STATUS_OPTIONS.map((item) => {
|
||||||
|
const countKey = item.value || 'all'
|
||||||
|
const count = Number(overviewQuery.data?.[countKey] || 0)
|
||||||
|
return {
|
||||||
|
key: item.value || 'all',
|
||||||
|
label: (
|
||||||
|
<span>
|
||||||
|
{item.label}
|
||||||
|
{count > 0 ? (
|
||||||
|
<span className="worker-order-tab-count">{count}</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
onChange={(nextKey) => {
|
||||||
|
const nextStatus = nextKey === 'all' ? '' : nextKey
|
||||||
|
setStatus(nextStatus)
|
||||||
|
setPage(1)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Space.Compact style={{ width: '100%', maxWidth: 460 }}>
|
||||||
<Input
|
<Input
|
||||||
allowClear
|
allowClear
|
||||||
value={keywordInput}
|
value={keywordInput}
|
||||||
@@ -356,29 +332,6 @@ export default function WorkerOrdersPage() {
|
|||||||
搜索
|
搜索
|
||||||
</Button>
|
</Button>
|
||||||
</Space.Compact>
|
</Space.Compact>
|
||||||
<Typography.Text type="secondary">
|
|
||||||
当前筛选:
|
|
||||||
{STATUS_OPTIONS.find((item) => item.value === status)?.label || '全部订单'}
|
|
||||||
</Typography.Text>
|
|
||||||
</Space>
|
|
||||||
|
|
||||||
<Segmented
|
|
||||||
block
|
|
||||||
value={status || 'all'}
|
|
||||||
options={STATUS_OPTIONS.map((item) => {
|
|
||||||
const countKey = item.value || 'all'
|
|
||||||
return {
|
|
||||||
value: item.value || 'all',
|
|
||||||
label: `${item.label} (${Number(overviewQuery.data?.[countKey] || 0)})`,
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
onChange={(value) => {
|
|
||||||
const nextStatus = String(value) === 'all' ? '' : String(value)
|
|
||||||
setStatus(nextStatus)
|
|
||||||
setPage(1)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
|
|
||||||
<Table<WorkOrder>
|
<Table<WorkOrder>
|
||||||
rowKey="workOrderId"
|
rowKey="workOrderId"
|
||||||
@@ -417,7 +370,7 @@ export default function WorkerOrdersPage() {
|
|||||||
setPageSize(nextPageSize)
|
setPageSize(nextPageSize)
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
scroll={{ x: 1160 }}
|
scroll={{ x: 1060 }}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -762,13 +715,3 @@ function resolveStatusColor(status: string) {
|
|||||||
if (status === 'open') return 'red'
|
if (status === 'open') return 'red'
|
||||||
return 'blue'
|
return 'blue'
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatSharingShareStatus(status: string) {
|
|
||||||
const labels: Record<string, string> = {
|
|
||||||
joined: '已参与',
|
|
||||||
submitted: '已提交验收',
|
|
||||||
accepted: '已验收',
|
|
||||||
cancelled: '已取消',
|
|
||||||
}
|
|
||||||
return labels[status] || status
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ import {
|
|||||||
BankOutlined,
|
BankOutlined,
|
||||||
CopyOutlined,
|
CopyOutlined,
|
||||||
CustomerServiceOutlined,
|
CustomerServiceOutlined,
|
||||||
HistoryOutlined,
|
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
SafetyCertificateOutlined,
|
|
||||||
WalletOutlined,
|
WalletOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
@@ -16,7 +14,6 @@ import {
|
|||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Col,
|
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
Empty,
|
Empty,
|
||||||
@@ -26,10 +23,8 @@ import {
|
|||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Progress,
|
Progress,
|
||||||
Row,
|
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
Tabs,
|
||||||
Tag,
|
Tag,
|
||||||
@@ -80,16 +75,6 @@ type PasswordFormValues = {
|
|||||||
confirmPassword?: string
|
confirmPassword?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MetricCardItem = {
|
|
||||||
label: string
|
|
||||||
value: number
|
|
||||||
note: string
|
|
||||||
prefix?: string
|
|
||||||
suffix?: string
|
|
||||||
precision?: number
|
|
||||||
danger?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function WorkerProfilePage() {
|
export default function WorkerProfilePage() {
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@@ -510,23 +495,38 @@ export default function WorkerProfilePage() {
|
|||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Row gutter={[16, 16]}>
|
<Card size="small" className="worker-profile-wallet-card">
|
||||||
{buildMetricCards(worker, summary).map((item) => (
|
<div className="worker-profile-wallet-strip">
|
||||||
<Col key={item.label} xs={24} sm={12} xl={8}>
|
<div className="worker-profile-wallet-item">
|
||||||
<Card size="small">
|
<span className="worker-profile-wallet-label">可用余额</span>
|
||||||
<Statistic
|
<strong className="worker-profile-wallet-value">
|
||||||
title={item.label}
|
{formatMoney(worker.wallet.availableAmount)}
|
||||||
value={item.value}
|
</strong>
|
||||||
prefix={item.prefix}
|
<small className="worker-profile-wallet-note">可用于抢单冻结或提现申请</small>
|
||||||
suffix={item.suffix}
|
</div>
|
||||||
precision={item.precision}
|
<div className="worker-profile-wallet-item">
|
||||||
valueStyle={item.danger ? { color: '#cf1322' } : undefined}
|
<span className="worker-profile-wallet-label">冻结押金</span>
|
||||||
/>
|
<strong className="worker-profile-wallet-value">
|
||||||
<Typography.Text type="secondary">{item.note}</Typography.Text>
|
{formatMoney(worker.wallet.frozenDepositAmount)}
|
||||||
|
</strong>
|
||||||
|
<small className="worker-profile-wallet-note">抢单后冻结,验收后进入待解冻</small>
|
||||||
|
</div>
|
||||||
|
<div className="worker-profile-wallet-item">
|
||||||
|
<span className="worker-profile-wallet-label">待解冻押金</span>
|
||||||
|
<strong className="worker-profile-wallet-value">
|
||||||
|
{formatMoney(worker.wallet.pendingUnfreezeAmount)}
|
||||||
|
</strong>
|
||||||
|
<small className="worker-profile-wallet-note">验收后按配置天数解冻到账</small>
|
||||||
|
</div>
|
||||||
|
<div className="worker-profile-wallet-item">
|
||||||
|
<span className="worker-profile-wallet-label">累计结算</span>
|
||||||
|
<strong className="worker-profile-wallet-value">
|
||||||
|
{formatMoney(worker.wallet.totalSettledAmount)}
|
||||||
|
</strong>
|
||||||
|
<small className="worker-profile-wallet-note">已结算入账的报酬合计</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
|
||||||
))}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Card title="快捷操作" size="small">
|
<Card title="快捷操作" size="small">
|
||||||
<Space wrap size={[12, 12]}>
|
<Space wrap size={[12, 12]}>
|
||||||
@@ -546,18 +546,6 @@ export default function WorkerProfilePage() {
|
|||||||
>
|
>
|
||||||
提现申请
|
提现申请
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
icon={<HistoryOutlined />}
|
|
||||||
onClick={() => jumpToLedgerSection()}
|
|
||||||
>
|
|
||||||
查看资金流水
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
icon={<SafetyCertificateOutlined />}
|
|
||||||
onClick={() => jumpToRequestSection('withdraw')}
|
|
||||||
>
|
|
||||||
查看提现记录
|
|
||||||
</Button>
|
|
||||||
<Button icon={<LockOutlined />} onClick={() => setPasswordOpen(true)}>
|
<Button icon={<LockOutlined />} onClick={() => setPasswordOpen(true)}>
|
||||||
修改密码
|
修改密码
|
||||||
</Button>
|
</Button>
|
||||||
@@ -617,6 +605,15 @@ export default function WorkerProfilePage() {
|
|||||||
<Descriptions.Item label="已累计完成">
|
<Descriptions.Item label="已累计完成">
|
||||||
{summary?.acceptedOrderCount || 0} 单
|
{summary?.acceptedOrderCount || 0} 单
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="超时订单">
|
||||||
|
{summary?.timeoutOrderCount || 0} 单
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="累计充值">
|
||||||
|
{formatMoney(worker.wallet.totalCreditedAmount)}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="提现中金额">
|
||||||
|
{formatMoney(summary?.pendingWithdrawAmount)}
|
||||||
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="免押额度">
|
<Descriptions.Item label="免押额度">
|
||||||
{formatMoney(worker.level?.permissions.depositFreeAmount || 0)}
|
{formatMoney(worker.level?.permissions.depositFreeAmount || 0)}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
@@ -1055,66 +1052,6 @@ export default function WorkerProfilePage() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildMetricCards(worker: WorkerUser, summary?: WorkerProfileSummary): MetricCardItem[] {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: '账户余额',
|
|
||||||
value: toYuan(worker.wallet.availableAmount),
|
|
||||||
note: '可用于抢单冻结或提现申请',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '冻结押金',
|
|
||||||
value: toYuan(worker.wallet.frozenDepositAmount),
|
|
||||||
note: '抢单后冻结,验收通过后 3 天自动解冻',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '待解冻押金',
|
|
||||||
value: toYuan(worker.wallet.pendingUnfreezeAmount),
|
|
||||||
note: '验收通过后待 3 天解冻到账的押金',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '累计充值',
|
|
||||||
value: toYuan(worker.wallet.totalCreditedAmount),
|
|
||||||
note: '管理员已处理的累计充值金额',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '累计结算',
|
|
||||||
value: toYuan(worker.wallet.totalSettledAmount),
|
|
||||||
note: '已经结算入账的报酬金额',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '提现中金额',
|
|
||||||
value: toYuan(summary?.pendingWithdrawAmount),
|
|
||||||
note: '待管理员处理的提现申请金额',
|
|
||||||
prefix: '¥',
|
|
||||||
precision: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '累计成单',
|
|
||||||
value: Number(summary?.acceptedOrderCount || 0),
|
|
||||||
note: '已完成并验收通过的工单数量',
|
|
||||||
suffix: '单',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '超时订单',
|
|
||||||
value: Number(summary?.timeoutOrderCount || 0),
|
|
||||||
note: '因任务超时被系统判定失败的工单数量',
|
|
||||||
suffix: '单',
|
|
||||||
danger: Number(summary?.timeoutOrderCount || 0) > 0,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveAvailableForWithdraw(
|
function resolveAvailableForWithdraw(
|
||||||
worker: WorkerUser | undefined,
|
worker: WorkerUser | undefined,
|
||||||
summary: WorkerProfileSummary | undefined,
|
summary: WorkerProfileSummary | undefined,
|
||||||
@@ -1137,10 +1074,6 @@ function formatMoney(value: number | undefined) {
|
|||||||
return `¥${((Number(value || 0) || 0) / 100).toFixed(2)}`
|
return `¥${((Number(value || 0) || 0) / 100).toFixed(2)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function toYuan(value: number | undefined) {
|
|
||||||
return Number(((Number(value || 0) || 0) / 100).toFixed(2))
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatWorkerStatus(status: string) {
|
function formatWorkerStatus(status: string) {
|
||||||
if (status === 'active') return '已审核'
|
if (status === 'active') return '已审核'
|
||||||
if (status === 'pending_review') return '待审核'
|
if (status === 'pending_review') return '待审核'
|
||||||
|
|||||||
@@ -1685,6 +1685,91 @@ select {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.worker-order-summary-card {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-order-summary-card.active {
|
||||||
|
border-color: #1677ff;
|
||||||
|
box-shadow: 0 0 0 1px #1677ff inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-order-summary-card .ant-statistic-title {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-order-tab-count {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin-left: 6px;
|
||||||
|
border-radius: 9px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
color: #595959;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-order-tabs .ant-tabs-nav {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-card .ant-card-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-strip {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-item {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 14px 16px;
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-item + .worker-profile-wallet-item {
|
||||||
|
border-left: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-label {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-value {
|
||||||
|
color: #0f172a;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-profile-wallet-note {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.worker-profile-wallet-strip {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
.worker-profile-wallet-item:nth-child(3) {
|
||||||
|
border-left: 0;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.worker-profile-wallet-item:nth-child(4) {
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.worker-hall-head-copy {
|
.worker-hall-head-copy {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|||||||
Reference in New Issue
Block a user