Compare commits

..

6 Commits

Author SHA1 Message Date
linkeyu 0040c5795d 优化提现审核页原因列展示 (#90)
## 改动内容
- 已到账页签隐藏无关的失败/拒绝原因列
- 打款中页签隐藏无关的失败/拒绝原因列
- 待审核、已拒绝、打款失败及全部页签继续保留原因列
- 详情抽屉中的失败/拒绝原因保持不变

## 验证
- npm run build 通过
- git diff --check 通过

---------

Co-authored-by: guke <guke@wonderable.ai>
Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #90
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-28 10:04:21 +08:00
linkeyu 5acfb05c57 优化提现审核侧页基础信息展示 (#91)
## 改动内容
- 删除提现详情侧页的提现类型
- 删除提现单区域重复展示的累计成功提现
- 用户详情和邀请详情中的累计成功提现继续保留
- 两类累计金额继续按 coin_cash / invite_cash 账户分别统计

## 验证
- 前端 npm run build 通过
- 后端账户隔离相关测试 2 passed
- 线上数据库抽查确认两类提现金额独立
- git diff --check 通过

---------

Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #91
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-28 10:04:04 +08:00
linkeyu bea35fb707 在比价记录中展示是否下单 (#88)
## 改动说明
- 在“省”列后新增“是否下单”列
- 使用“已下单/未下单”标签展示
- 同步补充前端接口类型

## 验证
- Next.js 生产构建和类型检查通过

---------

Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #88
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-27 17:33:23 +08:00
linkeyu 93c3daa784 优化比价记录设备信息展示 (#87)
## 改动说明
- 机型优先显示可读商品名,同时保留原始设备编码
- 列表和详情展示 ROM 厂商、名称与版本
- 同步补充前端接口类型

## 验证
- Next.js 生产构建通过
- 本地页面列表与详情抽屉已检查

---------

Co-authored-by: guke <guke@wonderable.ai>
Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #87
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-27 16:38:35 +08:00
linkeyu 63538ddee2 修复提现审核状态汇总与列表条数不一致 (#89)
## 问题

奖励审核页面只有待审核、打款中和打款失败显示数量,已到账、已拒绝和全部没有数字;同时两个提现审核页面的页签数字及顶部“待审核/待审核金额”收到后端全局汇总后发生混合。

## 改动

- 补充已到账、已拒绝和全部三个汇总字段类型
- 六个状态页签全部展示对应的小框数字
- 页签数字及顶部待审核数量、金额均使用当前页面的提现来源参数

## 验证

- `npm run build` 通过
- Next.js 编译、类型检查及静态页面生成全部通过
- 结合线上数据库确认普通提现和邀请提现的状态、顶部待审核数量与金额应分别展示

## 后端依赖

需配合后端 PR WonderableAI/shaguabijia-app-server#185 一起合入部署:
WonderableAI/shaguabijia-app-server#185

---------

Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #89
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-27 16:26:07 +08:00
linkeyu d057f75b90 修复低价审核红点与列表数据不同步 (#84)
## 问题
低价审核记录被处理后,左侧红点可能继续显示进入后台时的旧数量;页面长时间打开时,顶部统计和列表也不会自动同步新状态。

## 改动
- 进入或切换后台页面时重新获取审核红点数量。
- 窗口重新聚焦、标签页恢复可见时立即刷新。
- 页面可见期间每 60 秒同步一次红点、低价审核统计和当前列表。
- 组件卸载时清理定时器与事件监听,隐藏标签页不发起轮询。

## 验证
- `tsc --noEmit`
- `npm run build`
- 人工 review:仅修改导航红点和低价审核页刷新逻辑,未包含其他工作区改动。

---------

Co-authored-by: guke <guke@wonderable.ai>
Co-authored-by: linkeyu <798648091@qq.com>
Reviewed-on: #84
Co-authored-by: linkeyu <linkeyu@wonderable.ai>
Co-committed-by: linkeyu <linkeyu@wonderable.ai>
2026-07-27 16:03:13 +08:00
3 changed files with 69 additions and 12 deletions
+54 -4
View File
@@ -46,6 +46,41 @@ const fmtTok = (inTok: number | null, outTok: number | null) =>
inTok == null && outTok == null ? '-' : `${inTok ?? 0}/${outTok ?? 0}`;
const fmtRate = (value: number | null) => (value == null ? '-' : `${(value * 100).toFixed(1)}%`);
function deviceName(record: ComparisonRecordListItem): string {
return record.device_model_name || record.device_model || '-';
}
function romName(record: ComparisonRecordListItem): string {
return [
record.rom_vendor,
record.rom_name,
record.rom_version != null ? String(record.rom_version) : null,
]
.filter(Boolean)
.join(' ') || '-';
}
function renderDevice(record: ComparisonRecordListItem): ReactNode {
const readableName = deviceName(record);
const showRawModel =
record.device_model_name
&& record.device_model
&& record.device_model_name !== record.device_model;
return (
<Space direction="vertical" size={0}>
<span>{readableName}</span>
{showRawModel ? (
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{record.device_model}
</Typography.Text>
) : null}
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{romName(record)}
</Typography.Text>
</Space>
);
}
// LLM 价格快照只展示 prices 里各模型的单价(元/每百万 token),忽略 mode/_source 等元字段。
function llmPriceRows(snapshot: Record<string, unknown> | null): string[] {
const prices = snapshot?.prices;
@@ -298,6 +333,14 @@ export default function ComparisonRecordsPage() {
<b style={{ color: r.saved_amount_cents > 0 ? '#3f8600' : '#999' }}>{yuan(r.saved_amount_cents)}</b>
),
},
{
title: '是否下单',
dataIndex: 'ordered',
width: 84,
render: (ordered: boolean) => (
<Tag color={ordered ? 'green' : 'default'}>{ordered ? '已下单' : '未下单'}</Tag>
),
},
{ title: 'LLM', dataIndex: 'llm_call_count', width: 56, render: (v) => v ?? '-' },
{
title: 'TOKEN',
@@ -308,9 +351,9 @@ export default function ComparisonRecordsPage() {
{
title: '机型/ROM',
key: 'device',
width: 150,
width: 180,
ellipsis: true,
render: (_, r) => [r.device_model, r.rom_name].filter(Boolean).join(' / ') || '-',
render: (_, r) => renderDevice(r),
},
{
title: 'traceid',
@@ -499,8 +542,15 @@ export default function ComparisonRecordsPage() {
<Card size="small" title="设备环境">
<Descriptions size="small" column={2}>
<Descriptions.Item label="机型">{detail.device_model || '-'}{detail.device_manufacturer || '-'}</Descriptions.Item>
<Descriptions.Item label="ROM">{[detail.rom_vendor, detail.rom_name, detail.rom_version].filter(Boolean).join(' ') || '-'}</Descriptions.Item>
<Descriptions.Item label="机型">
{deviceName(detail)}
{detail.device_model_name && detail.device_model_name !== detail.device_model
? `${[detail.device_manufacturer, detail.device_model].filter(Boolean).join(' · ')}`
: detail.device_manufacturer
? `${detail.device_manufacturer}`
: ''}
</Descriptions.Item>
<Descriptions.Item label="ROM">{romName(detail)}</Descriptions.Item>
<Descriptions.Item label="Android">{detail.android_version || '-'}SDK {detail.android_sdk ?? '-'}</Descriptions.Item>
<Descriptions.Item label="App 版本">{detail.app_version || '-'}{detail.app_version_code ?? '-'}</Descriptions.Item>
<Descriptions.Item label="源 App 版本" span={2}>{detail.source_app_version || '-'}</Descriptions.Item>
@@ -124,7 +124,10 @@ function summaryCount(summary: WithdrawSummary | null, key: string) {
if (!summary) return undefined;
if (key === 'reviewing') return summary.reviewing_count;
if (key === 'pending') return summary.pending_count;
if (key === 'success') return summary.success_count;
if (key === 'rejected') return summary.rejected_count;
if (key === 'failed') return summary.failed_count;
if (key === 'all') return summary.total_count;
return undefined;
}
@@ -567,6 +570,7 @@ export function WithdrawReviewPage({ mode = 'other' }: { mode?: WithdrawReviewMo
},
{
title: '失败/拒绝原因',
key: 'fail_reason',
dataIndex: 'fail_reason',
ellipsis: true,
render: (v: string | null) => v || <Text type="secondary">-</Text>,
@@ -644,6 +648,10 @@ export function WithdrawReviewPage({ mode = 'other' }: { mode?: WithdrawReviewMo
},
},
];
const visibleColumns =
activeStatus === 'pending' || activeStatus === 'success'
? columns.filter((column) => column.key !== 'fail_reason')
: columns;
const inviteeColumns: ColumnsType<InviteeDetail> = [
{ title: '手机号', dataIndex: 'phone', width: 130 },
@@ -942,7 +950,7 @@ export function WithdrawReviewPage({ mode = 'other' }: { mode?: WithdrawReviewMo
}
: undefined
}
columns={columns}
columns={visibleColumns}
dataSource={items}
loading={loading}
pagination={{
@@ -986,12 +994,6 @@ export function WithdrawReviewPage({ mode = 'other' }: { mode?: WithdrawReviewMo
<Descriptions.Item label="金额">
<Text strong>{yuan(detail.order.amount_cents)}</Text>
</Descriptions.Item>
<Descriptions.Item label="提现类型">
{detail.order.source === 'invite_cash' ? '邀请奖励提现' : '福利页提现'}
</Descriptions.Item>
<Descriptions.Item label="累计成功提现">
{yuan(detail.cumulative_success_cents)}
</Descriptions.Item>
<Descriptions.Item label="提交时间">
{dt(detail.order.created_at)}
</Descriptions.Item>
+6 -1
View File
@@ -167,7 +167,10 @@ export interface WithdrawSummary {
reviewing_count: number;
reviewing_amount_cents: number;
pending_count: number;
success_count: number;
rejected_count: number;
failed_count: number;
total_count: number;
today_success_count: number;
today_success_amount_cents: number;
today_rejected_count: number;
@@ -454,6 +457,7 @@ export interface ComparisonRecordListItem {
source_price_cents: number | null;
best_price_cents: number | null;
saved_amount_cents: number | null;
ordered: boolean;
total_ms: number | null;
step_count: number | null;
llm_call_count: number | null;
@@ -462,8 +466,10 @@ export interface ComparisonRecordListItem {
output_tokens: number | null;
llm_cost_yuan: number | null; // 后端按「当时价」冻结的实际成本(元);旧记录 null → 「成本」列回退估算
device_model: string | null;
device_model_name: string | null;
rom_vendor: string | null;
rom_name: string | null;
rom_version: number | null;
android_version: string | null;
app_version: string | null;
ad_revenue_yuan: number; // 本次比价看的信息流广告预估收益(元)
@@ -514,7 +520,6 @@ export interface ComparisonRecordDetail extends ComparisonRecordListItem {
comparison_results: Record<string, unknown>[];
skipped_dish_names: string[];
device_manufacturer: string | null;
rom_version: number | null;
android_sdk: number | null;
app_version_code: number | null;
source_app_version: string | null;