Compare commits

...

20 Commits

Author SHA1 Message Date
Mrx
2d50c57ef0 add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-02-27 12:07:00 +08:00
Mrx
7634cf8bf1 up seo
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-02-14 11:15:22 +08:00
Mrx
8f08614a17 2026-02-02 14:55:34 +08:00
Mrx
3bf38a294e -f
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-01-26 15:06:30 +08:00
1bba187cf3 f add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-01-07 16:50:52 +08:00
90353094ab f
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-01-05 15:11:02 +08:00
e4b2a1d35a add button
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-01-05 12:50:10 +08:00
f70d33a7d3 fixadd
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-01-05 10:48:05 +08:00
1d17926c70 fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-01-04 18:58:18 +08:00
d3c32c23fd fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-01-04 17:19:01 +08:00
d722860e71 add 修改余额
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-01-04 16:11:11 +08:00
27d63095a9 fix and add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2026-01-03 17:53:43 +08:00
c80d8383c3 fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2025-12-31 15:00:14 +08:00
26b637eef2 fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2025-12-31 14:56:34 +08:00
9f511cba43 add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2025-12-31 12:40:55 +08:00
107b28752c gitadd.
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2025-12-30 18:01:01 +08:00
05b568bc93 fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2025-12-29 18:29:26 +08:00
00523bae4c fix and add
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2025-12-29 16:13:31 +08:00
48a102b0a5 fixadd
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
2025-12-27 16:04:49 +08:00
822d92bee4 fix
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2025-12-27 14:02:37 +08:00
20 changed files with 2026 additions and 305 deletions

View File

@@ -78,6 +78,7 @@ export namespace AgentApi {
page: number; page: number;
pageSize: number; pageSize: number;
agent_id?: number; agent_id?: number;
order_id?: number;
product_name?: string; product_name?: string;
status?: number; status?: number;
} }
@@ -134,16 +135,42 @@ export namespace AgentApi {
agent_id?: number; agent_id?: number;
status?: number; status?: number;
withdraw_no?: string; withdraw_no?: string;
status?: number;
withdraw_no?: string;
} }
// 提现统计数据 // 提现统计数据
export interface WithdrawalStatistics { export interface WithdrawalStatistics {
total_withdrawal_amount: number; total_withdrawal_amount: number;
today_withdrawal_amount: number; today_withdrawal_amount: number;
total_actual_amount: number;
total_tax_amount: number;
} }
// 代理订单统计数据
export interface AgentOrderStatistics {
total_agent_order_count: number; // 总代理订单数
today_agent_order_count: number; // 今日代理订单数
}
// 代理统计数据
export interface AgentStatistics {
total_agent_count: number; // 总代理数
today_agent_count: number; // 今日新增代理数
}
// 代理链接产品统计项
export interface AgentLinkProductStatisticsItem {
product_name: string;
link_count: number;
}
// 代理链接产品统计响应
export interface AgentLinkProductStatisticsResp {
items: AgentLinkProductStatisticsItem[];
}
// 代理链接产品统计请求参数
export interface GetAgentLinkProductStatisticsParams {}
// 代理上级抽佣相关接口 // 代理上级抽佣相关接口
export interface AgentCommissionDeductionListItem { export interface AgentCommissionDeductionListItem {
id: number; id: number;
@@ -307,6 +334,69 @@ export namespace AgentApi {
price_ratio?: null | number; // 提价区间收取比例 price_ratio?: null | number; // 提价区间收取比例
price_increase_amount?: null | number; // 在原本成本上加价的金额 price_increase_amount?: null | number; // 在原本成本上加价的金额
} }
// 代理钱包信息
export interface AgentWalletInfo {
balance: number; // 可用余额
frozen_balance: number; // 冻结余额
total_earnings: number; // 总收益
}
// 修改代理钱包余额请求
export interface UpdateAgentWalletBalanceReq {
agent_id: number; // 代理ID
amount: number; // 修改金额(正数增加,负数减少)
}
// 修改代理钱包余额响应
export interface UpdateAgentWalletBalanceResp {
success: boolean; // 是否成功
balance: number; // 修改后的余额
}
// 代理钱包流水相关接口
export interface WalletTransactionListItem {
id: number;
agent_id: number;
transaction_type: string;
amount: number;
balance_before: number;
balance_after: number;
frozen_balance_before: number;
frozen_balance_after: number;
transaction_id?: string;
related_user_id?: number;
remark?: string;
create_time: string;
}
export interface WalletTransactionList {
total: number;
items: WalletTransactionListItem[];
}
export interface GetWalletTransactionListParams {
page: number;
pageSize: number;
agent_id: number;
transaction_type?: string;
create_time_start?: string;
create_time_end?: string;
}
// 系统配置相关接口
export interface SystemConfig {
commission_safe_mode: boolean; // 佣金安全防御模式
}
export interface UpdateSystemConfigReq {
commission_safe_mode: boolean; // 佣金安全防御模式true-冻结模式false-直接结算模式
}
export interface UpdateSystemConfigResp {
success: boolean; // 是否成功
}
} }
/** /**
@@ -342,6 +432,37 @@ async function getAgentCommissionList(
); );
} }
/**
* 更新代理佣金状态
*/
async function updateAgentCommissionStatus(
id: number,
status: number,
) {
return requestClient.post<{ success: boolean }>(
'/agent/agent-commission/update-status',
{
id,
status,
},
);
}
/**
* 批量解冻代理佣金
*/
async function batchUnfreezeAgentCommission(
agentId?: number,
) {
return requestClient.post<{
success: boolean;
count: number;
amount: number;
}>('/agent/agent-commission/batch-unfreeze', {
agent_id: agentId,
});
}
/** /**
* 获取代理奖励列表 * 获取代理奖励列表
*/ */
@@ -487,17 +608,108 @@ async function getWithdrawalStatistics() {
); );
} }
/**
* 获取代理订单统计数据
*/
async function getAgentOrderStatistics() {
return requestClient.get<AgentApi.AgentOrderStatistics>(
'/agent/agent-order/statistics',
);
}
/**
* 获取代理统计数据
*/
async function getAgentStatistics() {
return requestClient.get<AgentApi.AgentStatistics>(
'/agent/statistics',
);
}
/**
* 获取代理链接产品统计数据
*/
async function getAgentLinkProductStatistics() {
return requestClient.get<AgentApi.AgentLinkProductStatisticsResp>(
'/agent/agent-link/product-statistics',
);
}
/**
* 获取代理钱包信息
*/
async function getAgentWallet(agentId: number) {
return requestClient.get<AgentApi.AgentWalletInfo>(
`/agent/wallet/${agentId}`,
);
}
/**
* 修改代理钱包余额
*/
async function updateAgentWalletBalance(params: AgentApi.UpdateAgentWalletBalanceReq) {
return requestClient.post<AgentApi.UpdateAgentWalletBalanceResp>(
'/agent/wallet/update-balance',
params,
);
}
/**
* 获取系统配置
*/
async function getSystemConfig() {
return requestClient.get<AgentApi.SystemConfig>(
'/agent/system-config',
);
}
/**
* 更新系统配置
*/
async function updateSystemConfig(params: AgentApi.UpdateSystemConfigReq) {
return requestClient.post<AgentApi.UpdateSystemConfigResp>(
'/agent/system-config',
params,
);
}
/**
* 获取代理钱包流水列表
*/
async function getWalletTransactionList(
params: AgentApi.GetWalletTransactionListParams,
) {
return requestClient.get<AgentApi.WalletTransactionList>(
'/agent/wallet-transaction/list',
{ params },
);
}
export { export {
batchUnfreezeAgentCommission,
getAgentCommissionDeductionList, getAgentCommissionDeductionList,
getAgentCommissionList, getAgentCommissionList,
getAgentLinkList, getAgentLinkList,
getAgentLinkProductStatistics,
getAgentList, getAgentList,
getAgentMembershipConfigList, getAgentMembershipConfigList,
getAgentOrderStatistics,
getAgentPlatformDeductionList, getAgentPlatformDeductionList,
getAgentProductionConfigList, getAgentProductionConfigList,
getAgentRewardList, getAgentRewardList,
getAgentStatistics,
getAgentWallet,
getAgentWithdrawalList, getAgentWithdrawalList,
getMembershipRechargeOrderList, getMembershipRechargeOrderList,
getWithdrawalStatistics,
reviewBankCardWithdrawal,
updateAgentCommissionStatus,
updateAgentMembershipConfig, updateAgentMembershipConfig,
updateAgentProductionConfig, updateAgentProductionConfig,
updateAgentWalletBalance,
getSystemConfig,
updateSystemConfig,
getWalletTransactionList,
}; };

View File

@@ -0,0 +1,28 @@
import { requestClient } from '#/api/request';
export namespace OrderStatisticsApi {
// 订单统计数据项
export interface OrderStatisticsItem {
date: string; // 日期
count: number; // 订单数量
amount: number; // 订单金额
}
// 订单统计响应
export interface OrderStatisticsResponse {
items: OrderStatisticsItem[];
}
// 时间维度类型
export type TimeDimension = 'day' | 'month' | 'year' | 'all';
}
/**
* 获取订单统计数据
* @param dimension 时间维度day-日(当月1号到今天)month-月(今年1月到当月)year-年(过去5年)all-全部(按日统计)
*/
export function getOrderStatistics(dimension: OrderStatisticsApi.TimeDimension) {
return requestClient.get<OrderStatisticsApi.OrderStatisticsResponse>('/order/statistics', {
params: { dimension }
});
}

View File

@@ -49,6 +49,12 @@ export namespace OrderApi {
total_profit_amount: number; total_profit_amount: number;
today_profit_amount: number; today_profit_amount: number;
} }
// 订单来源统计数据
export interface OrderSourceStatistics {
product_name: string;
order_count: number;
}
} }
/** /**
@@ -86,4 +92,11 @@ async function getIncomeStatistics() {
return requestClient.get<OrderApi.IncomeStatistics>('/order/revenue-statistics'); return requestClient.get<OrderApi.IncomeStatistics>('/order/revenue-statistics');
} }
export { getOrderList, refundOrder, getRefundStatistics, getIncomeStatistics }; /**
* 获取订单来源统计数据
*/
async function getOrderSourceStatistics() {
return requestClient.get<{ items: OrderApi.OrderSourceStatistics[] }>('/order/source-statistics');
}
export { getOrderList, refundOrder, getRefundStatistics, getIncomeStatistics, getOrderSourceStatistics };

View File

@@ -9,6 +9,7 @@ export namespace PlatformUserApi {
nickname: string; nickname: string;
info: string; info: string;
inside: number; inside: number;
disable: number; // 0 可用 1 禁用
create_time: string; create_time: string;
update_time: string; update_time: string;
} }
@@ -19,10 +20,11 @@ export namespace PlatformUserApi {
} }
export interface UpdatePlatformUserRequest { export interface UpdatePlatformUserRequest {
mobile: string; mobile?: string;
nickname: string; nickname?: string;
info: string; info?: string;
inside: number; inside?: number;
disable?: number; // 0 可用 1 禁用
} }
} }

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form'; import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { AgentApi } from '#/api';
// 佣金记录列表列配置 // 佣金记录列表列配置
export function useCommissionColumns(): VxeTableGridOptions['columns'] { export function useCommissionColumns(
onActionClick?: (params: { code: string; row: AgentApi.AgentCommissionListItem }) => void,
): VxeTableGridOptions['columns'] {
return [ return [
{ {
field: 'agent_id', field: 'agent_id',
@@ -32,9 +35,9 @@ export function useCommissionColumns(): VxeTableGridOptions['columns'] {
width: 100, width: 100,
formatter: ({ cellValue }: { cellValue: number }) => { formatter: ({ cellValue }: { cellValue: number }) => {
const statusMap: Record<number, string> = { const statusMap: Record<number, string> = {
0: '结算', 0: '结算',
1: '已结算', 1: '冻结中',
2: '已取消', 2: '已退款',
}; };
return statusMap[cellValue] || '未知'; return statusMap[cellValue] || '未知';
}, },
@@ -46,16 +49,73 @@ export function useCommissionColumns(): VxeTableGridOptions['columns'] {
sortable: true, sortable: true,
sortType: 'string' as const, sortType: 'string' as const,
}, },
{
align: 'center',
cellRender: {
name: 'CellOperation',
attrs: {
nameField: 'id',
nameTitle: '操作',
onClick: onActionClick,
},
options: [
{
code: 'freeze',
text: '冻结',
type: 'warning',
disabled: (row: AgentApi.AgentCommissionListItem) =>
row?.status !== 0,
class: (row: AgentApi.AgentCommissionListItem) =>
row?.status !== 0 ? '!text-gray-400 !cursor-not-allowed' : '',
tooltip: (row: AgentApi.AgentCommissionListItem) => {
if (row?.status === 1) return '该佣金已处于冻结中';
if (row?.status === 2) return '已取消的佣金无法操作';
return '';
},
},
{
code: 'unfreeze',
text: '解冻',
type: 'primary',
disabled: (row: AgentApi.AgentCommissionListItem) =>
row?.status !== 1,
class: (row: AgentApi.AgentCommissionListItem) =>
row?.status !== 1 ? '!text-gray-400 !cursor-not-allowed' : '',
tooltip: (row: AgentApi.AgentCommissionListItem) => {
if (row?.status === 0) return '已结算的佣金无需解冻';
if (row?.status === 2) return '已退款的佣金无法操作';
return '';
},
},
],
},
field: 'operation',
fixed: 'right',
title: '操作',
width: 300,
},
]; ];
} }
// 佣金记录搜索表单配置 // 佣金记录搜索表单配置
export function useCommissionFormSchema(): VbenFormSchema[] { export function useCommissionFormSchema(): VbenFormSchema[] {
return [ return [
{
component: 'InputNumber',
fieldName: 'order_id',
label: '订单ID',
componentProps: {
placeholder: '请输入订单ID',
style: { width: '100%' },
},
},
{ {
component: 'Input', component: 'Input',
fieldName: 'product_name', fieldName: 'product_name',
label: '产品名称', label: '产品名称',
componentProps: {
placeholder: '请输入产品名称(支持模糊搜索)',
},
}, },
{ {
component: 'Select', component: 'Select',
@@ -63,10 +123,11 @@ export function useCommissionFormSchema(): VbenFormSchema[] {
label: '状态', label: '状态',
componentProps: { componentProps: {
allowClear: true, allowClear: true,
placeholder: '请选择状态',
options: [ options: [
{ label: '结算', value: 0 }, { label: '结算', value: 0 },
{ label: '已结算', value: 1 }, { label: '冻结中', value: 1 },
{ label: '已取消', value: 2 }, { label: '已退款', value: 2 },
], ],
}, },
}, },

View File

@@ -1,10 +1,20 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed } from 'vue'; import { computed, h, onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui'; import { Page } from '@vben/common-ui';
import { Button, message, Modal, Select, Switch, Tooltip } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getAgentCommissionList } from '#/api/agent'; import {
batchUnfreezeAgentCommission,
getAgentCommissionList,
getAgentList,
getAgentWallet,
updateAgentCommissionStatus,
getSystemConfig,
updateSystemConfig,
} from '#/api/agent';
import type { AgentApi } from '#/api';
import { useCommissionColumns, useCommissionFormSchema } from './data'; import { useCommissionColumns, useCommissionFormSchema } from './data';
@@ -12,37 +22,371 @@ interface Props {
agentId?: number; agentId?: number;
} }
interface QueryParams {
currentPage: number;
pageSize: number;
[key: string]: any;
}
const props = defineProps<Props>(); const props = defineProps<Props>();
// 用于一键解冻筛选的代理商ID
const unfreezeAgentId = ref<number | undefined>();
// 佣金安全防御模式配置
const commissionSafeMode = ref<boolean>(false);
const safeModeLoading = ref<boolean>(false);
// 代理商列表(完整列表)
const allAgentList = ref<AgentApi.AgentListItem[]>([]);
// 显示在下拉框中的代理商列表(可能是过滤后的)
const agentList = ref<AgentApi.AgentListItem[]>([]);
const queryParams = computed(() => ({ const queryParams = computed(() => ({
...(props.agentId ? { agent_id: props.agentId } : {}), ...(props.agentId ? { agent_id: props.agentId } : {}),
...(unfreezeAgentId.value ? { agent_id: unfreezeAgentId.value } : {}),
})); }));
const [Grid] = useVbenVxeGrid({ // 加载代理商列表
async function loadAgentList() {
try {
const result = await getAgentList({ page: 1, pageSize: 10000 });
allAgentList.value = result.items || [];
agentList.value = result.items || [];
} catch (error) {
console.error('加载代理商列表失败:', error);
message.error('加载代理商列表失败,请刷新页面重试');
}
}
// 搜索时动态过滤代理商支持ID和手机号
function onAgentSearch(value: string) {
if (!value || value.trim() === '') {
// 如果输入为空,显示所有代理商
agentList.value = allAgentList.value;
return;
}
const searchValue = value.trim();
// 从完整列表中过滤匹配的代理商
const filtered = allAgentList.value.filter(agent => {
// 匹配代理ID
if (agent.id.toString().includes(searchValue)) {
return true;
}
// 匹配手机号
if (agent.mobile && agent.mobile.includes(searchValue)) {
return true;
}
// 匹配姓名(如果存在)
if (agent.real_name && agent.real_name.includes(searchValue)) {
return true;
}
return false;
});
agentList.value = filtered;
}
// 获取未找到时的提示文案
function getNotFoundContent() {
if (unfreezeAgentId.value) {
return '点击确认使用此ID';
}
return '暂无代理商';
}
// 页面加载时获取代理商列表和系统配置
onMounted(async () => {
loadAgentList();
await loadSystemConfig();
});
// 加载系统配置
async function loadSystemConfig() {
try {
const config = await getSystemConfig();
commissionSafeMode.value = config.commission_safe_mode;
} catch (error: any) {
console.error('加载系统配置失败:', error);
message.error('加载系统配置失败');
}
}
// 切换安全防御模式
async function onSafeModeChange(checked: boolean | string | number) {
const isChecked = Boolean(checked);
safeModeLoading.value = true;
try {
await updateSystemConfig({ commission_safe_mode: isChecked });
commissionSafeMode.value = isChecked;
message.success(`佣金安全防御模式已${isChecked ? '开启' : '关闭'}`);
} catch (error: any) {
const errorMsg = error?.response?.data?.msg || error?.message || '操作失败,请重试';
message.error(errorMsg);
// 恢复原状态
commissionSafeMode.value = !isChecked;
} finally {
safeModeLoading.value = false;
}
}
// 操作处理函数
function onActionClick({ code, row }: { code: string; row: any }) {
switch (code) {
case 'freeze':
onFreeze(row);
break;
case 'unfreeze':
onUnfreeze(row);
break;
}
}
// 冻结佣金
async function onFreeze(row: any) {
try {
// 先获取代理商钱包信息,检查余额是否充足
const hideChecking = message.loading({
content: '正在检查余额...',
duration: 0,
key: 'check_balance',
});
const wallet = await getAgentWallet(row.agent_id);
hideChecking();
// 检查余额是否充足
if (wallet.balance < row.amount) {
Modal.warning({
title: '余额不足',
content: `该代理商当前可用余额为 ¥${wallet.balance.toFixed(2)},不足以冻结佣金 ¥${row.amount.toFixed(2)}\n缺少金额¥${(row.amount - wallet.balance).toFixed(2)}`,
okText: '我知道了',
});
return;
}
// 余额充足,继续冻结操作
Modal.confirm({
title: '确认冻结',
content: `确定要冻结佣金金额 ¥${row.amount.toFixed(2)} 吗?\n当前可用余额¥${wallet.balance.toFixed(2)},冻结后可用余额:¥${(wallet.balance - row.amount).toFixed(2)}`,
okText: '确认冻结',
cancelText: '取消',
onOk: async () => {
try {
await updateAgentCommissionStatus(row.id, 1);
message.success('佣金已冻结');
onRefresh();
} catch (error: any) {
const errorMsg = error?.response?.data?.msg || error?.message || '操作失败,请重试';
message.error(errorMsg);
}
},
});
} catch (error: any) {
const errorMsg = error?.response?.data?.msg || error?.message || '获取钱包信息失败,请重试';
message.error(errorMsg);
}
}
// 解冻佣金到用户余额
async function onUnfreeze(row: any) {
try {
// 获取代理商钱包信息用于显示
const hideChecking = message.loading({
content: '正在获取钱包信息...',
duration: 0,
key: 'get_wallet',
});
const wallet = await getAgentWallet(row.agent_id);
hideChecking();
Modal.confirm({
title: '确认解冻',
content: `确定要解冻佣金金额 ¥${row.amount.toFixed(2)} 吗?\n解冻后将转入用户钱包余额。\n当前可用余额¥${wallet.balance.toFixed(2)},解冻后可用余额:¥${(wallet.balance + row.amount).toFixed(2)}`,
okText: '确认解冻',
cancelText: '取消',
onOk: async () => {
try {
await updateAgentCommissionStatus(row.id, 0);
message.success('佣金已解冻并转入用户钱包余额');
onRefresh();
} catch (error: any) {
const errorMsg = error?.response?.data?.msg || error?.message || '操作失败,请重试';
message.error(errorMsg);
}
},
});
} catch (error: any) {
const errorMsg = error?.response?.data?.msg || error?.message || '获取钱包信息失败,请重试';
message.error(errorMsg);
}
}
// 刷新列表
function onRefresh() {
gridApi.query();
}
// 选中代理商后刷新表格
function onAgentSelect(value: any) {
console.log('选中代理商:', value);
// 如果是清空选择value 为 undefined
// 如果有值,转换为数字
unfreezeAgentId.value = value ? parseInt(String(value), 10) : undefined;
// 延迟一点让 computed 更新后再刷新
setTimeout(() => {
onRefresh();
}, 100);
}
// 批量解冻佣金
async function onBatchUnfreeze() {
const targetAgentId = unfreezeAgentId.value || props.agentId;
const hideChecking = message.loading({
content: '正在检查数据,请稍候...',
duration: 0,
key: 'check_frozen_data',
});
try {
// 1. 查询所有冻结中的佣金记录
const frozenCommissions = await getAgentCommissionList({
page: 1,
pageSize: 10000,
status: 1,
...(targetAgentId ? { agent_id: targetAgentId } : {}),
});
hideChecking();
// 如果没有冻结的佣金,直接返回
if (!frozenCommissions.items || frozenCommissions.items.length === 0) {
message.info({
content: '没有需要解冻的冻结佣金',
key: 'check_frozen_data',
});
return;
}
// 2. 统计每个代理商的佣金冻结金额
const commissionFrozenMap = new Map<number, number>();
frozenCommissions.items.forEach((item: any) => {
const currentAmount = commissionFrozenMap.get(item.agent_id) || 0;
commissionFrozenMap.set(item.agent_id, currentAmount + item.amount);
});
// 3. 检查每个代理商的钱包冻结余额是否足够
let insufficientAgents: string[] = [];
let totalFrozenAmount = 0;
for (const [agentId, commissionAmount] of commissionFrozenMap) {
totalFrozenAmount += commissionAmount;
// 获取该代理商的钱包信息
const wallet = await getAgentWallet(agentId);
if (wallet.frozen_balance < commissionAmount) {
// 找到该代理商的信息
const agent = allAgentList.value.find(a => a.id === agentId);
const agentInfo = agent ? `${agent.real_name || agent.mobile} (ID: ${agentId})` : `ID: ${agentId}`;
insufficientAgents.push(
`${agentInfo}:钱包冻结余额 ¥${wallet.frozen_balance.toFixed(2)},需要解冻 ¥${commissionAmount.toFixed(2)},缺少 ¥${(commissionAmount - wallet.frozen_balance).toFixed(2)}`
);
}
}
// 如果有余额不足的代理商,显示错误信息
if (insufficientAgents.length > 0) {
Modal.error({
title: '冻结余额不足,无法解冻',
width: 600,
content: h('div', [
h('p', '以下代理商的钱包冻结余额不足以解冻其冻结的佣金:'),
h('ul', { style: { 'max-height': '300px', 'overflow-y': 'auto', 'padding-left': '20px' } },
insufficientAgents.map(msg => h('li', { style: { marginBottom: '8px' } }, msg))
),
h('p', { style: { marginTop: '16px', color: '#999' } }, '请先核实钱包冻结余额数据,或联系技术支持。'),
]),
okText: '我知道了',
});
return;
}
// 4. 余额检查通过,确认解冻
const content = targetAgentId
? `确定要一键解冻代理商 ID: ${targetAgentId} 所有冻结中的佣金吗?\n\n共 ${frozenCommissions.items.length} 条记录,总金额 ¥${totalFrozenAmount.toFixed(2)}\n解冻后将全部转入用户钱包余额。`
: `确定要一键解冻所有冻结中的佣金吗?\n\n共 ${frozenCommissions.items.length} 条记录,总金额 ¥${totalFrozenAmount.toFixed(2)}\n解冻后将全部转入用户钱包余额。`;
Modal.confirm({
title: '批量解冻确认',
content,
okText: '确认解冻',
cancelText: '取消',
onOk: async () => {
const hideLoading = message.loading({
content: '正在批量解冻佣金,请稍候...',
duration: 0,
key: 'batch_unfreeze',
});
try {
const result = await batchUnfreezeAgentCommission(targetAgentId);
message.success({
content: `批量解冻成功!共解冻 ${result.count} 条记录,总金额 ¥${result.amount.toFixed(2)}`,
key: 'batch_unfreeze',
});
onRefresh();
} catch (error: any) {
hideLoading();
const errorMsg = error?.response?.data?.msg || error?.message || '批量解冻失败,请重试';
// 如果是版本冲突错误,给出更友好的提示
if (errorMsg.includes('update db no rows change') || errorMsg.includes('版本冲突') || errorMsg.includes('状态已被其他操作修改')) {
message.error({
content: '批量解冻失败:部分佣金或钱包数据已被其他操作修改,请稍后重试。如果问题持续,请联系管理员。',
key: 'batch_unfreeze',
});
} else {
message.error({
content: `批量解冻失败:${errorMsg}`,
key: 'batch_unfreeze',
});
}
}
},
});
} catch (error: any) {
hideChecking();
const errorMsg = error?.response?.data?.msg || error?.message || '数据检查失败,请重试';
message.error({
content: `检查失败:${errorMsg}`,
key: 'check_frozen_data',
});
}
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: { formOptions: {
schema: useCommissionFormSchema(), schema: useCommissionFormSchema(),
submitOnChange: true, submitOnChange: true,
}, },
gridOptions: { gridOptions: {
columns: useCommissionColumns(), columns: useCommissionColumns(onActionClick),
height: 'auto',
keepSource: true,
rowConfig: {
keyField: 'id',
},
toolbarConfig: {
custom: true,
export: false,
refresh: { code: 'query' },
search: true,
zoom: true,
},
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ query: async ({ page, form, sort }: any, formValues: Record<string, any>) => {
page,
form,
}: {
form: Record<string, any>;
page: QueryParams;
}) => {
return await getAgentCommissionList({ return await getAgentCommissionList({
...queryParams.value, ...queryParams.value,
...form, ...formValues,
page: page.currentPage, page: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
}); });
@@ -52,6 +396,7 @@ const [Grid] = useVbenVxeGrid({
result: 'items', result: 'items',
total: 'total', total: 'total',
}, },
autoLoad: true,
}, },
}, },
}); });
@@ -59,6 +404,53 @@ const [Grid] = useVbenVxeGrid({
<template> <template>
<Page :auto-content-height="!agentId"> <Page :auto-content-height="!agentId">
<Grid :table-title="agentId ? '佣金记录列表' : '所有佣金记录'" /> <Grid :table-title="agentId ? '佣金记录列表' : '所有佣金记录'">
<template #toolbar-tools>
<div class="flex items-center">
<Tooltip placement="top" title="开启后,佣金结算时将先冻结到钱包冻结余额,需要手动解冻才能使用;关闭后,佣金将直接结算到可用余额">
<div class="flex items-center gap-2 mr-4">
<span class="text-sm text-gray-600">安全防御机制:</span>
<Switch
v-model:checked="commissionSafeMode"
:loading="safeModeLoading"
checked-children="开启"
un-checked-children="关闭"
@change="onSafeModeChange"
/>
</div>
</Tooltip>
<div class="w-px h-6 bg-gray-300 mx-2"></div>
<div class="flex items-center gap-2">
<span class="text-sm text-gray-600">选择代理商:</span>
<Select
v-model:value="unfreezeAgentId"
placeholder="全部代理商 / 输入代理ID或手机号"
:allow-clear="true"
:loading="agentList.length === 0"
style="width: 260px"
show-search
:filter-option="false"
:show-arrow="true"
:not-found-content="getNotFoundContent()"
@search="onAgentSearch"
@change="onAgentSelect"
>
<Select.Option
v-for="agent in agentList"
:key="agent.id"
:value="agent.id"
:label="`${agent.real_name || agent.mobile} (ID: ${agent.id})`"
>
{{ agent.real_name || agent.mobile }} (ID: {{ agent.id }})
</Select.Option>
</Select>
<Button type="primary" @click="onBatchUnfreeze">
<span class="mr-1"></span>
一键解冻
</Button>
</div>
</div>
</template>
</Grid>
</Page> </Page>
</template> </template>

View File

@@ -19,11 +19,14 @@ import { getAgentList } from '#/api/agent';
import { useColumns, useGridFormSchema } from './data'; import { useColumns, useGridFormSchema } from './data';
import CommissionDeductionModal from './modules/commission-deduction-modal.vue'; import CommissionDeductionModal from './modules/commission-deduction-modal.vue';
import CommissionModal from './modules/commission-modal.vue'; import CommissionModal from './modules/commission-modal.vue';
import CommissionHistoryModal from './modules/commission-history-modal.vue';
import Form from './modules/form.vue'; import Form from './modules/form.vue';
import LinkModal from './modules/link-modal.vue'; import LinkModal from './modules/link-modal.vue';
import PlatformDeductionModal from './modules/platform-deduction-modal.vue'; import PlatformDeductionModal from './modules/platform-deduction-modal.vue';
import RewardModal from './modules/reward-modal.vue'; import RewardModal from './modules/reward-modal.vue';
import WithdrawalModal from './modules/withdrawal-modal.vue'; import WithdrawalModal from './modules/withdrawal-modal.vue';
import BalanceModal from './modules/balance-modal.vue';
import WalletTransactionModal from './modules/wallet-transaction-modal.vue';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@@ -72,6 +75,24 @@ const [PlatformDeductionModalComponent, platformDeductionModalApi] =
destroyOnClose: true, destroyOnClose: true,
}); });
// 修改余额弹窗
const [BalanceModalComponent, balanceModalApi] = useVbenModal({
connectedComponent: BalanceModal,
destroyOnClose: true,
});
// 钱包流水记录弹窗
const [WalletTransactionModalComponent, walletTransactionModalApi] = useVbenModal({
connectedComponent: WalletTransactionModal,
destroyOnClose: true,
});
// 历史佣金记录弹窗
const [CommissionHistoryModalComponent, commissionHistoryModalApi] = useVbenModal({
connectedComponent: CommissionHistoryModal,
destroyOnClose: true,
});
// 表格配置 // 表格配置
const [Grid, gridApi] = useVbenVxeGrid({ const [Grid, gridApi] = useVbenVxeGrid({
formOptions: { formOptions: {
@@ -144,10 +165,23 @@ const [Grid, gridApi] = useVbenVxeGrid({
// 更多操作菜单项 // 更多操作菜单项
const moreMenuItems = [ const moreMenuItems = [
{
key: 'update-balance',
label: '修改余额',
},
{
key: 'commission-history',
label: '历史佣金记录',
},
{
key: 'wallet-transaction',
label: '钱包流水记录',
},
{ {
key: 'links', key: 'links',
label: '推广链接', label: '推广链接',
}, },
// { // {
// key: 'commission', // key: 'commission',
// label: '佣金记录', // label: '佣金记录',
@@ -194,6 +228,10 @@ function onActionClick(
onViewCommission(e.row); onViewCommission(e.row);
break; break;
} }
case 'commission-history': {
onViewCommissionHistory(e.row);
break;
}
case 'commission-deduction': { case 'commission-deduction': {
onViewCommissionDeduction(e.row); onViewCommissionDeduction(e.row);
break; break;
@@ -214,6 +252,10 @@ function onActionClick(
onViewReward(e.row); onViewReward(e.row);
break; break;
} }
case 'update-balance': {
onUpdateBalance(e.row);
break;
}
case 'view-sub-agent': { case 'view-sub-agent': {
router.replace({ router.replace({
query: { query: {
@@ -227,6 +269,10 @@ function onActionClick(
onViewWithdrawal(e.row); onViewWithdrawal(e.row);
break; break;
} }
case 'wallet-transaction': {
onViewWalletTransaction(e.row);
break;
}
} }
} }
@@ -240,6 +286,16 @@ function onViewLinks(row: AgentApi.AgentListItem) {
linkModalApi.setData({ agentId: row.id }).open(); linkModalApi.setData({ agentId: row.id }).open();
} }
// 修改余额
function onUpdateBalance(row: AgentApi.AgentListItem) {
balanceModalApi.setData({ agentId: row.id }).open();
}
// 查看钱包流水记录
function onViewWalletTransaction(row: AgentApi.AgentListItem) {
walletTransactionModalApi.setData({ agentId: row.id }).open();
}
// 查看佣金记录 // 查看佣金记录
function onViewCommission(row: AgentApi.AgentListItem) { function onViewCommission(row: AgentApi.AgentListItem) {
commissionModalApi.setData({ agentId: row.id }).open(); commissionModalApi.setData({ agentId: row.id }).open();
@@ -265,6 +321,11 @@ function onViewPlatformDeduction(row: AgentApi.AgentListItem) {
platformDeductionModalApi.setData({ agentId: row.id }).open(); platformDeductionModalApi.setData({ agentId: row.id }).open();
} }
// 查看历史佣金记录
function onViewCommissionHistory(row: AgentApi.AgentListItem) {
commissionHistoryModalApi.setData({ agentId: row.id }).open();
}
// 刷新处理 // 刷新处理
function onRefresh() { function onRefresh() {
gridApi.query(); gridApi.query();
@@ -276,10 +337,13 @@ function onRefresh() {
<FormDrawer @success="onRefresh" /> <FormDrawer @success="onRefresh" />
<LinkModalComponent /> <LinkModalComponent />
<CommissionModalComponent /> <CommissionModalComponent />
<CommissionHistoryModalComponent />
<CommissionDeductionModalComponent /> <CommissionDeductionModalComponent />
<PlatformDeductionModalComponent /> <PlatformDeductionModalComponent />
<RewardModalComponent /> <RewardModalComponent />
<WithdrawalModalComponent /> <WithdrawalModalComponent />
<BalanceModalComponent @success="onRefresh" />
<WalletTransactionModalComponent />
<!-- 上级代理信息卡片 --> <!-- 上级代理信息卡片 -->
<Card v-if="parentAgentId" class="mb-4"> <Card v-if="parentAgentId" class="mb-4">

View File

@@ -0,0 +1,161 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { useVbenModal } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';
import { getAgentWallet, updateAgentWalletBalance } from '#/api/agent';
import type { AgentApi } from '#/api/agent';
interface ModalData {
agentId: number;
}
// 钱包信息
const walletInfo = ref<AgentApi.AgentWalletInfo>({
balance: 0,
frozen_balance: 0,
total_earnings: 0,
});
const loading = ref(false);
const emit = defineEmits<{
(e: 'success'): void;
}>();
const [ModalComponent, modalApi] = useVbenModal({
title: '修改余额',
destroyOnClose: true,
onOpenChange(isOpen) {
if (isOpen) {
fetchWalletInfo();
// 重置表单
formApi.setValues({
operation_type: 'add',
amount: undefined,
});
}
},
});
const modalData = computed(() => modalApi.getData<ModalData>());
// 获取钱包信息
async function fetchWalletInfo() {
const agentId = modalData.value?.agentId;
if (!agentId) return;
try {
loading.value = true;
const data = await getAgentWallet(agentId);
walletInfo.value = data;
} catch (error: any) {
message.error(error.message || '获取钱包信息失败');
} finally {
loading.value = false;
}
}
// 表单引用
const [Form, formApi] = useVbenForm({
schema: [
{
component: 'RadioGroup',
fieldName: 'operation_type',
label: '操作类型',
componentProps: {
options: [
{ label: '增加余额', value: 'add' },
{ label: '减少余额', value: 'subtract' },
],
},
rules: 'required',
defaultValue: 'add',
},
{
component: 'InputNumber',
fieldName: 'amount',
label: '金额',
componentProps: {
precision: 2,
min: 0.01,
placeholder: '请输入金额',
style: { width: '100%' },
},
rules: 'required',
},
],
showDefaultActions: false,
});
// 提交前确认
async function handleSubmit() {
try {
const { valid } = await formApi.validate();
if (!valid) return;
const values = await formApi.getValues();
if (!values) return;
// 根据操作类型确定金额正负
const finalAmount = values.operation_type === 'subtract' ? -Math.abs(values.amount) : Math.abs(values.amount);
// 二次确认
Modal.confirm({
title: '确认修改余额',
content: `您确定要${values.operation_type === 'add' ? '增加' : '减少'} ¥${Math.abs(values.amount).toFixed(2)} 的余额吗?`,
onOk: async () => {
try {
await updateAgentWalletBalance({
agent_id: modalData.value?.agentId || 0,
amount: finalAmount,
});
message.success('修改余额成功');
modalApi.close();
emit('success');
} catch (error: any) {
message.error(error.message || '修改余额失败');
}
},
});
} catch (error) {
// 表单验证失败,不处理
}
}
// 重置表单
function handleReset() {
formApi.setValues({
operation_type: 'add',
amount: undefined,
});
}
</script>
<template>
<ModalComponent width="500px" :footer="false">
<div class="balance-modal">
<Form />
<div class="form-actions">
<a-button @click="handleReset">重置</a-button>
<a-button type="primary" @click="handleSubmit">确认修改</a-button>
</div>
</div>
</ModalComponent>
</template>
<style lang="less" scoped>
.balance-modal {
padding: 16px 0;
.form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
}
}
</style>

View File

@@ -0,0 +1,323 @@
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Card, Statistic, Row, Col, DatePicker, Button, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getAgentCommissionList } from '#/api/agent';
import type { AgentApi } from '#/api';
import dayjs, { Dayjs } from 'dayjs';
interface ModalData {
agentId: number;
}
const [Modal, modalApi] = useVbenModal({
title: '历史佣金记录',
destroyOnClose: true,
footer: false,
});
const modalData = computed(() => modalApi.getData<ModalData>());
// 时间范围选择
const dateRange = ref<[Dayjs, Dayjs] | undefined>(undefined);
// 统计数据
const statistics = ref({
totalAmount: 0,
settledAmount: 0,
frozenAmount: 0,
refundedAmount: 0,
totalCount: 0,
settledCount: 0,
frozenCount: 0,
refundedCount: 0,
});
// 快捷时间范围选择
function selectTimeRange(range: string) {
const now = dayjs();
let startDate: Dayjs;
switch (range) {
case '7d':
startDate = now.subtract(7, 'day');
break;
case '1m':
startDate = now.subtract(1, 'month');
break;
case '3m':
startDate = now.subtract(3, 'month');
break;
case '1y':
startDate = now.subtract(1, 'year');
break;
default:
dateRange.value = undefined;
return;
}
dateRange.value = [startDate, now];
}
// 重置时间范围
function resetTimeRange() {
dateRange.value = undefined;
}
// 表格配置
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
fieldMappingTime: [['create_time', ['create_time_start', 'create_time_end']]],
schema: [
{
component: 'InputNumber',
fieldName: 'order_id',
label: '订单ID',
componentProps: {
placeholder: '请输入订单ID',
style: { width: '100%' },
},
},
{
component: 'Input',
fieldName: 'product_name',
label: '产品名称',
componentProps: {
placeholder: '请输入产品名称',
},
},
{
component: 'Select',
fieldName: 'status',
label: '状态',
componentProps: {
allowClear: true,
placeholder: '请选择状态',
options: [
{ label: '已结算', value: 0 },
{ label: '冻结中', value: 1 },
{ label: '已退款', value: 2 },
],
},
},
],
submitOnChange: true,
},
gridOptions: {
columns: [
{
field: 'id',
title: 'ID',
width: 80,
},
{
field: 'order_id',
title: '订单ID',
width: 100,
},
{
field: 'amount',
title: '佣金金额',
width: 120,
formatter: ({ cellValue }: { cellValue: number }) =>
`¥${cellValue.toFixed(2)}`,
},
{
field: 'product_name',
title: '产品名称',
width: 180,
},
{
field: 'status',
title: '状态',
width: 100,
formatter: ({ cellValue }: { cellValue: number }) => {
const statusMap: Record<number, string> = {
0: '已结算',
1: '冻结中',
2: '已退款',
};
return statusMap[cellValue] || '未知';
},
className: ({ cellValue }: { cellValue: number }) => {
if (cellValue === 0) return 'text-green-600';
if (cellValue === 1) return 'text-orange-600';
if (cellValue === 2) return 'text-red-600';
return '';
},
},
{
field: 'create_time',
title: '创建时间',
width: 160,
sortable: true,
},
],
height: 600,
maxHeight: 800,
keepSource: true,
pagerConfig: {
enabled: true,
pageSize: 20,
pageSizes: [10, 20, 50, 100],
layouts: ['Total', 'Sizes', 'PrevJump', 'Number', 'NextJump', 'FullJump'],
},
rowConfig: {
keyField: 'id',
},
toolbarConfig: {
custom: true,
export: false,
refresh: { code: 'query' },
search: true,
zoom: true,
},
proxyConfig: {
ajax: {
query: async ({ page }: { page: { currentPage: number; pageSize: number } }, formValues: Record<string, any>) => {
const params: any = {
agent_id: modalData.value?.agentId,
...formValues,
page: page.currentPage,
pageSize: page.pageSize,
};
// 添加时间范围参数
if (dateRange.value && dateRange.value[0] && dateRange.value[1]) {
params.create_time_start = dateRange.value[0].format('YYYY-MM-DD HH:mm:ss');
params.create_time_end = dateRange.value[1].format('YYYY-MM-DD HH:mm:ss');
}
const result = await getAgentCommissionList(params);
// 更新统计数据
updateStatistics(result.items || []);
return result;
},
},
props: {
result: 'items',
total: 'total',
},
autoLoad: true,
},
},
});
// 更新统计数据
function updateStatistics(items: AgentApi.AgentCommissionListItem[]) {
statistics.value = {
totalCount: items.length,
totalAmount: items.reduce((sum, item) => sum + item.amount, 0),
settledCount: items.filter(item => item.status === 0).length,
settledAmount: items.filter(item => item.status === 0).reduce((sum, item) => sum + item.amount, 0),
frozenCount: items.filter(item => item.status === 1).length,
frozenAmount: items.filter(item => item.status === 1).reduce((sum, item) => sum + item.amount, 0),
refundedCount: items.filter(item => item.status === 2).length,
refundedAmount: items.filter(item => item.status === 2).reduce((sum, item) => sum + item.amount, 0),
};
}
// 监听时间范围变化,自动刷新表格
watch(dateRange, () => {
if (gridApi) {
gridApi.query();
}
});
</script>
<template>
<Modal class="w-[calc(100vw-200px)]">
<div class="commission-history-modal">
<!-- 时间范围选择 -->
<Card class="mb-4" title="时间范围选择">
<Space :size="12">
<span class="text-sm text-gray-600">快速选择</span>
<Button size="small" @click="selectTimeRange('7d')">近7日</Button>
<Button size="small" @click="selectTimeRange('1m')">近1月</Button>
<Button size="small" @click="selectTimeRange('3m')">近3月</Button>
<Button size="small" @click="selectTimeRange('1y')">近1年</Button>
<Button size="small" type="default" @click="resetTimeRange">全部</Button>
<span class="text-sm text-gray-400 ml-4">|</span>
<span class="text-sm text-gray-600">自定义</span>
<DatePicker.RangePicker
v-model:value="dateRange"
show-time
format="YYYY-MM-DD HH:mm:ss"
:placeholder="['开始时间', '结束时间']"
style="width: 380px"
/>
</Space>
</Card>
<!-- 统计卡片 -->
<Card class="mb-4" title="统计信息">
<Row :gutter="[16, 16]">
<Col :span="6">
<Statistic title="总记录数" :value="statistics.totalCount" />
</Col>
<Col :span="6">
<Statistic
title="总佣金金额"
:value="statistics.totalAmount"
:precision="2"
prefix="¥"
:value-style="{ color: '#1890ff' }"
/>
</Col>
<Col :span="6">
<Statistic
title="已结算金额"
:value="statistics.settledAmount"
:precision="2"
prefix="¥"
:value-style="{ color: '#52c41a' }"
/>
<div class="text-sm text-gray-500 mt-1">
{{ statistics.settledCount }} 条记录
</div>
</Col>
<Col :span="6">
<Statistic
title="冻结中金额"
:value="statistics.frozenAmount"
:precision="2"
prefix="¥"
:value-style="{ color: '#fa8c16' }"
/>
<div class="text-sm text-gray-500 mt-1">
{{ statistics.frozenCount }} 条记录
</div>
</Col>
</Row>
<Row :gutter="[16, 16]" class="mt-4">
<Col :span="12">
<Statistic
title="已退款金额"
:value="statistics.refundedAmount"
:precision="2"
prefix="¥"
:value-style="{ color: '#f5222d' }"
/>
<div class="text-sm text-gray-500 mt-1">
{{ statistics.refundedCount }} 条记录
</div>
</Col>
</Row>
</Card>
<!-- 佣金记录列表 -->
<Grid :table-title="`代理商 ID: ${modalData?.agentId} 的历史佣金记录`" />
</div>
</Modal>
</template>
<style lang="less" scoped>
.commission-history-modal {
padding: 16px;
}
</style>

View File

@@ -0,0 +1,202 @@
<script lang="ts" setup>
import { computed, h } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getWalletTransactionList } from '#/api/agent';
interface ModalData {
agentId: number;
}
const [Modal, modalApi] = useVbenModal({
title: '钱包流水记录',
destroyOnClose: true,
});
const modalData = computed(() => modalApi.getData<ModalData>());
// 交易类型映射
const transactionTypeMap: Record<string, { label: string; color: string }> = {
commission: { label: '佣金收入', color: 'green' },
withdraw: { label: '提现', color: 'red' },
freeze: { label: '冻结', color: 'orange' },
unfreeze: { label: '解冻', color: 'blue' },
reward: { label: '奖励', color: 'green' },
refund: { label: '退款', color: 'purple' },
adjust: { label: '调整', color: 'cyan' },
};
// 获取交易类型标签
function getTransactionTypeTag(type: string) {
const config = transactionTypeMap[type] || { label: type, color: 'default' };
return h(Tag, { color: config.color }, config.label);
}
// 获取金额显示
function getAmountCellRender(params: any) {
const amount = params.row.amount;
const isPositive = amount >= 0;
const color = isPositive ? '#52c41a' : '#ff4d4f';
const sign = isPositive ? '+' : '';
return h('span', { style: { color, fontWeight: 'bold' } }, `${sign}${amount.toFixed(2)}`);
}
// 表格列配置
const columns = [
{
field: 'id',
title: '流水ID',
width: 80,
},
{
field: 'transaction_type',
title: '交易类型',
width: 120,
cellRender: {
name: 'CustomRender',
render: getTransactionTypeTag,
},
},
{
field: 'amount',
title: '变动金额',
width: 120,
cellRender: {
name: 'CustomRender',
render: getAmountCellRender,
},
},
{
field: 'balance_before',
title: '变动前余额',
width: 120,
formatter: ({ cellValue }: any) => `¥${Number(cellValue || 0).toFixed(2)}`,
},
{
field: 'balance_after',
title: '变动后余额',
width: 120,
formatter: ({ cellValue }: any) => `¥${Number(cellValue || 0).toFixed(2)}`,
},
{
field: 'frozen_balance_before',
title: '变动前冻结',
width: 120,
formatter: ({ cellValue }: any) => `¥${Number(cellValue || 0).toFixed(2)}`,
},
{
field: 'frozen_balance_after',
title: '变动后冻结',
width: 120,
formatter: ({ cellValue }: any) => `¥${Number(cellValue || 0).toFixed(2)}`,
},
{
field: 'transaction_id',
title: '关联交易ID',
width: 150,
formatter: ({ cellValue }: any) => cellValue || '-',
},
{
field: 'remark',
title: '备注',
width: 200,
formatter: ({ cellValue }: any) => cellValue || '-',
},
{
field: 'create_time',
title: '创建时间',
width: 180,
},
];
const [Grid] = useVbenVxeGrid({
formOptions: {
schema: [
{
component: 'Input',
fieldName: 'transaction_type',
label: '交易类型',
help: '如: commission, withdraw, freeze, unfreeze, reward, refund, adjust',
},
{
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm:ss',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'create_time_start',
label: '开始时间',
},
{
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm:ss',
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
fieldName: 'create_time_end',
label: '结束时间',
},
],
submitOnChange: true,
},
gridOptions: {
columns,
height: 600,
maxHeight: 800,
keepSource: true,
pagerConfig: {
enabled: true,
pageSize: 20,
pageSizes: [10, 20, 50, 100],
layouts: ['Total', 'Sizes', 'PrevJump', 'Number', 'NextJump', 'FullJump'],
},
proxyConfig: {
ajax: {
query: async ({ page }: { page: { currentPage: number; pageSize: number } }, formValues: Record<string, any>) => {
return await getWalletTransactionList({
agent_id: modalData.value?.agentId || 0,
...formValues,
page: page.currentPage,
pageSize: page.pageSize,
});
},
},
props: {
result: 'items',
total: 'total',
},
autoLoad: true,
},
rowConfig: {
keyField: 'id',
},
toolbarConfig: {
custom: true,
export: false,
refresh: { code: 'query' },
search: true,
zoom: true,
},
},
});
</script>
<template>
<Modal class="w-[calc(100vw-200px)]" :footer="false">
<div class="wallet-transaction-modal">
<Grid table-title="钱包流水记录" />
</div>
</Modal>
</template>
<style lang="less" scoped>
.wallet-transaction-modal {
padding: 16px;
}
</style>

View File

@@ -14,6 +14,18 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
width: 120, width: 120,
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`, formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
}, },
{
title: '扣税金额',
field: 'tax_amount',
width: 120,
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
},
{
title: '实际转账金额',
field: 'actual_amount',
width: 120,
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
},
{ {
title: '提现类型', title: '提现类型',
field: 'withdraw_type', field: 'withdraw_type',

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from 'vue'; import { computed } from 'vue';
import { Page, useVbenDrawer } from '@vben/common-ui'; import { Page, useVbenDrawer } from '@vben/common-ui';
import { Button, Space } from 'ant-design-vue'; import { Button, Space } from 'ant-design-vue';
@@ -54,19 +54,16 @@ const [Grid, gridApi] = useVbenVxeGrid({
submitOnChange: true, submitOnChange: true,
}, },
gridOptions: { gridOptions: {
columns: useWithdrawalColumns(onActionClick), columns: useWithdrawalColumns(),
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ query: async ({
page, page,
form,
}: { }: {
page: QueryParams; page: QueryParams;
form: Record<string, any>;
}) => { }) => {
return await getAgentWithdrawalList({ return await getAgentWithdrawalList({
...queryParams.value, ...queryParams.value,
...form,
page: page.currentPage, page: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
}); });
@@ -95,7 +92,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template #operation="{ row }"> <template #operation="{ row }">
<Space> <Space>
<Button <Button
v-if="row.withdraw_type === 2 && row.status === 1" v-if="row.status === 1"
type="link" type="link"
@click="onActionClick({ code: 'review', row })" @click="onActionClick({ code: 'review', row })"
> >

View File

@@ -7,6 +7,7 @@ import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { reviewBankCardWithdrawal } from '#/api/agent'; import { reviewBankCardWithdrawal } from '#/api/agent';
import type { VbenFormSchema } from '#/adapter/form';
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'success'): void; (e: 'success'): void;
@@ -14,8 +15,8 @@ const emit = defineEmits<{
const formData = ref<any>(null); const formData = ref<any>(null);
const [Form, formApi] = useVbenForm({ // 表单配置(包含所有字段)
schema: [ const getFormSchema = (): VbenFormSchema[] => [
{ {
component: 'Input', component: 'Input',
fieldName: 'withdraw_no', fieldName: 'withdraw_no',
@@ -24,6 +25,14 @@ const [Form, formApi] = useVbenForm({
disabled: true, disabled: true,
}, },
}, },
{
component: 'Input',
fieldName: 'withdraw_type',
label: '提现类型',
componentProps: {
disabled: true,
},
},
{ {
component: 'InputNumber', component: 'InputNumber',
fieldName: 'amount', fieldName: 'amount',
@@ -36,6 +45,7 @@ const [Form, formApi] = useVbenForm({
addonBefore: '¥', addonBefore: '¥',
}, },
}, },
// 银行卡和支付宝通用字段:扣税金额
{ {
component: 'InputNumber' , component: 'InputNumber' ,
fieldName: 'tax_amount', fieldName: 'tax_amount',
@@ -48,6 +58,7 @@ const [Form, formApi] = useVbenForm({
addonBefore: '¥', addonBefore: '¥',
}, },
}, },
// 银行卡和支付宝通用字段:实际转账金额
{ {
component: 'InputNumber', component: 'InputNumber',
fieldName: 'actual_amount', fieldName: 'actual_amount',
@@ -60,14 +71,16 @@ const [Form, formApi] = useVbenForm({
addonBefore: '¥', addonBefore: '¥',
}, },
}, },
// 银行卡和支付宝都有:收款账号
{ {
component: 'Input', component: 'Input',
fieldName: 'bank_card_no', fieldName: 'payee_account',
label: '银行卡号', label: '收款账号',
componentProps: { componentProps: {
disabled: true, disabled: true,
}, },
}, },
// 银行卡提现特有字段:开户支行
{ {
component: 'Input', component: 'Input',
fieldName: 'bank_name', fieldName: 'bank_name',
@@ -75,7 +88,12 @@ const [Form, formApi] = useVbenForm({
componentProps: { componentProps: {
disabled: true, disabled: true,
}, },
dependencies: {
show: (values) => values.withdraw_type === '银行卡',
triggerFields: ['withdraw_type'],
}, },
},
// 银行卡提现特有字段:收款人姓名
{ {
component: 'Input', component: 'Input',
fieldName: 'payee_name', fieldName: 'payee_name',
@@ -83,6 +101,10 @@ const [Form, formApi] = useVbenForm({
componentProps: { componentProps: {
disabled: true, disabled: true,
}, },
dependencies: {
show: (values) => values.withdraw_type === '银行卡',
triggerFields: ['withdraw_type'],
},
}, },
{ {
component: 'RadioGroup', component: 'RadioGroup',
@@ -109,11 +131,16 @@ const [Form, formApi] = useVbenForm({
style: { width: '100%' }, style: { width: '100%' },
}, },
}, },
], ];
const [Form, formApi] = useVbenForm({
schema: getFormSchema(),
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'agent-withdrawal-form-wrapper',
}); });
const [Drawer, drawerApi] = useVbenDrawer({ const [Drawer, drawerApi] = useVbenDrawer({
class: 'agent-withdrawal-review-drawer',
async onConfirm() { async onConfirm() {
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
if (!valid) return; if (!valid) return;
@@ -153,30 +180,70 @@ const [Drawer, drawerApi] = useVbenDrawer({
formApi.resetForm(); formApi.resetForm();
if (data) { if (data) {
formData.value = data; formData.value = data;
// 设置表单初始值
formApi.setValues({ // 根据提现类型设置不同的表单初始值
const typeMap: Record<number, string> = {
1: '支付宝',
2: '银行卡',
};
const initialValues: any = {
withdraw_no: data.withdraw_no || '', withdraw_no: data.withdraw_no || '',
withdraw_type: typeMap[data.withdraw_type] || '未知',
amount: data.amount || 0, amount: data.amount || 0,
tax_amount: data.tax_amount || 0,
actual_amount: data.actual_amount || 0,
bank_card_no: data.bank_card_no || '',
bank_name: data.bank_name || '',
payee_name: data.payee_name || '',
action: 1, // 默认选择确认 action: 1, // 默认选择确认
remark: '', remark: '',
}); };
// 银行卡提现特有字段
if (data.withdraw_type === 2) {
initialValues.tax_amount = data.tax_amount || 0;
initialValues.actual_amount = data.actual_amount || 0;
initialValues.payee_account = data.bank_card_no || '';
initialValues.bank_name = data.bank_name || '';
initialValues.payee_name = data.payee_name || '';
} else {
// 支付宝提现
initialValues.tax_amount = data.tax_amount || 0;
initialValues.actual_amount = data.actual_amount || 0;
initialValues.payee_account = data.payee_account || '';
}
formApi.setValues(initialValues);
} }
} }
}, },
}); });
const getDrawerTitle = computed(() => { const getDrawerTitle = computed(() => {
return `银行卡提现审核 ${formData.value?.withdraw_no || ''}`; const typeMap: Record<number, string> = {
1: '支付宝',
2: '银行卡',
};
const typeName = typeMap[formData.value?.withdraw_type] || '未知';
return `${typeName}提现审核 ${formData.value?.withdraw_no || ''}`;
}); });
</script> </script>
<template> <template>
<Drawer :title="getDrawerTitle" width="600"> <Drawer :title="getDrawerTitle" :width="800">
<div class="agent-withdrawal-review-content">
<Form /> <Form />
</div>
</Drawer> </Drawer>
</template> </template>
<style scoped>
.agent-withdrawal-review-content {
padding: 0 4px;
max-height: calc(100vh - 120px);
overflow-y: auto;
}
.agent-withdrawal-review-content :deep(.ant-form-item) {
margin-bottom: 16px;
}
.agent-withdrawal-review-content :deep(.ant-form-item-label) {
padding-bottom: 4px;
}
</style>

View File

@@ -4,16 +4,31 @@ import type { EchartsUIType } from '@vben/plugins/echarts';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts'; import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { getOrderSourceStatistics } from '#/api/order/order';
const chartRef = ref<EchartsUIType>(); const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef); const { renderEcharts } = useEcharts(chartRef);
const loading = ref(false);
onMounted(() => { // 获取订单来源统计数据
async function fetchOrderSourceStatistics() {
try {
loading.value = true;
const response = await getOrderSourceStatistics();
// 提取产品名称和订单数量
const data = response.items.map(item => ({
name: item.product_name,
value: item.order_count,
}));
// 如果有数据,则渲染图表
if (data && data.length > 0) {
renderEcharts({ renderEcharts({
legend: { legend: {
bottom: '2%', bottom: '2%',
left: 'center', left: 'center',
data: ['产品A', '产品B', '产品C', '产品D'], data: data.map(item => item.name),
}, },
series: [ series: [
{ {
@@ -23,13 +38,13 @@ onMounted(() => {
animationEasing: 'exponentialInOut', animationEasing: 'exponentialInOut',
animationType: 'scale', animationType: 'scale',
avoidLabelOverlap: false, avoidLabelOverlap: false,
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'], color: [
data: [ '#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9',
{ name: '产品A', value: 1048 }, '#ffb980', '#d87a80', '#8d98b3', '#e5cf0d',
{ name: '产品B', value: 735 }, '#97b552', '#95706d', '#dc69aa', '#07a2a4',
{ name: '产品C', value: 580 }, '#9a7fd1', '#588dd5', '#f5994e', '#c05050'
{ name: '产品D', value: 484 },
], ],
data: data,
emphasis: { emphasis: {
label: { label: {
fontSize: '12', fontSize: '12',
@@ -38,7 +53,6 @@ onMounted(() => {
}, },
}, },
itemStyle: { itemStyle: {
// borderColor: '#fff',
borderRadius: 10, borderRadius: 10,
borderWidth: 2, borderWidth: 2,
}, },
@@ -56,11 +70,25 @@ onMounted(() => {
], ],
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: '{b}: {c} ({d}%)',
}, },
}); });
}
} catch (error) {
console.error('获取订单来源统计数据失败:', error);
} finally {
loading.value = false;
}
}
onMounted(() => {
fetchOrderSourceStatistics();
}); });
</script> </script>
<template> <template>
<EchartsUI ref="chartRef" /> <div v-if="loading" class="flex justify-center items-center h-64">
加载中...
</div>
<EchartsUI v-else ref="chartRef" />
</template> </template>

View File

@@ -1,59 +1,59 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { EchartsUIType } from '@vben/plugins/echarts'; import type { EchartsUIType } from '@vben/plugins/echarts';
import { onMounted, ref } from 'vue'; import { onMounted, ref, watch } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts'; import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { Button } from 'ant-design-vue';
import { getOrderList } from '#/api/order/order'; import { getOrderStatistics } from '#/api/order/order-statistics';
const chartRef = ref<EchartsUIType>(); const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef); const { renderEcharts } = useEcharts(chartRef);
// 时间维度状态
const timeDimension = ref<'day' | 'month' | 'year' | 'all'>('day');
onMounted(async () => { // 获取订单统计数据
async function fetchOrderStatistics() {
try { try {
// 准备图表数据 console.log('Fetching order statistics with dimension:', timeDimension.value);
const dates = Array.from({ length: 30 }).map((_, index) => {
const date = new Date();
date.setDate(date.getDate() - 29 + index);
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
});
// 准备日期数组,用于查询订单数据 // 使用后端API获取数据
const queryDates = Array.from({ length: 30 }).map((_, index) => { const response = await getOrderStatistics(timeDimension.value);
const date = new Date(); console.log('Order statistics response:', response);
date.setDate(date.getDate() - 29 + index);
return date.toISOString().split('T')[0]; // YYYY-MM-DD格式
});
// 获取每日订单数据 let items = response.items || [];
const orderDataPromises = queryDates.map(async (date) => {
try {
// 获取当天的开始和结束时间
const startTime = `${date} 00:00:00`;
const endTime = `${date} 23:59:59`;
// 获取当天的订单数据 // 如果后端返回空数据,显示空状态
const response = await getOrderList({ if (items.length === 0) {
page: 1, console.log('No data from backend, showing empty chart');
pageSize: 1, items = [];
create_time_start: startTime, }
create_time_end: endTime
});
return response.total || 0; console.log('Items for chart:', items);
} catch (error) {
console.error(`获取${date}的订单数据失败:`, error); // 按日期排序
return 0; items.sort((a: any, b: any) => a.date.localeCompare(b.date));
// 提取日期和数量
const dates = items.map((item: any) => {
// 根据时间维度格式化日期显示
const date = new Date(item.date);
if (timeDimension.value === 'year') {
return `${date.getFullYear()}`;
} else if (timeDimension.value === 'month') {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
} else {
return `${date.getMonth() + 1}-${String(date.getDate()).padStart(2, '0')}`;
} }
}); });
// 等待所有请求完成 const orderData = items.map((item: any) => item.count);
const orderData = await Promise.all(orderDataPromises); const amountData = items.map((item: any) => item.amount);
// 计算Y轴最大值 // 计算Y轴最大值
const maxValue = Math.max(...orderData) || 10; const maxOrderValue = Math.max(...orderData) || 10;
const maxAmountValue = Math.max(...amountData) || 10;
renderEcharts({ renderEcharts({
grid: { grid: {
@@ -61,7 +61,11 @@ onMounted(async () => {
containLabel: true, containLabel: true,
left: '1%', left: '1%',
right: '1%', right: '1%',
top: '2%', top: '10%',
},
legend: {
data: ['订单数', '订单金额'],
top: 0,
}, },
series: [ series: [
{ {
@@ -77,6 +81,19 @@ onMounted(async () => {
color: '#4f9cff', color: '#4f9cff',
}, },
}, },
{
data: amountData,
type: 'line',
name: '订单金额',
smooth: true,
itemStyle: {
color: '#52c41a',
},
areaStyle: {
opacity: 0.3,
color: '#52c41a',
},
},
], ],
tooltip: { tooltip: {
axisPointer: { axisPointer: {
@@ -86,8 +103,15 @@ onMounted(async () => {
}, },
trigger: 'axis', trigger: 'axis',
formatter: (params: any) => { formatter: (params: any) => {
const param = params[0]; let result = `${params[0].axisValue}<br/>`;
return `${param.axisValue}<br/>${param.seriesName}: ${param.value}`; params.forEach((param: any) => {
if (param.seriesName === '订单金额') {
result += `${param.seriesName}: ¥${param.value.toFixed(2)}<br/>`;
} else {
result += `${param.seriesName}: ${param.value}<br/>`;
}
});
return result;
}, },
}, },
xAxis: { xAxis: {
@@ -95,11 +119,22 @@ onMounted(async () => {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
}, },
yAxis: { yAxis: [
max: Math.ceil(maxValue * 1.2), // 比最大值大20%作为Y轴上限 {
splitNumber: 4,
type: 'value', type: 'value',
name: '订单数',
position: 'left',
max: Math.ceil(maxOrderValue * 1.2),
splitNumber: 4,
}, },
{
type: 'value',
name: '金额(¥)',
position: 'right',
max: Math.ceil(maxAmountValue * 1.2),
splitNumber: 4,
},
],
}); });
} catch (error) { } catch (error) {
console.error('获取订单趋势数据失败:', error); console.error('获取订单趋势数据失败:', error);
@@ -111,7 +146,11 @@ onMounted(async () => {
containLabel: true, containLabel: true,
left: '1%', left: '1%',
right: '1%', right: '1%',
top: '2%', top: '10%',
},
legend: {
data: ['订单数', '订单金额'],
top: 0,
}, },
series: [ series: [
{ {
@@ -127,6 +166,19 @@ onMounted(async () => {
color: '#4f9cff', color: '#4f9cff',
}, },
}, },
{
data: Array(30).fill(0),
type: 'line',
name: '订单金额',
smooth: true,
itemStyle: {
color: '#52c41a',
},
areaStyle: {
opacity: 0.3,
color: '#52c41a',
},
},
], ],
tooltip: { tooltip: {
axisPointer: { axisPointer: {
@@ -145,16 +197,66 @@ onMounted(async () => {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
}, },
yAxis: { yAxis: [
{
type: 'value',
name: '订单数',
position: 'left',
max: 10, max: 10,
splitNumber: 4, splitNumber: 4,
type: 'value',
}, },
{
type: 'value',
name: '金额(¥)',
position: 'right',
max: 10,
splitNumber: 4,
},
],
}); });
} }
}
// 组件挂载时获取数据
onMounted(() => {
fetchOrderStatistics();
});
// 监听时间维度变化
watch(timeDimension, () => {
fetchOrderStatistics();
}); });
</script> </script>
<template> <template>
<div>
<div class="mb-4 flex justify-end space-x-2">
<Button
:type="timeDimension === 'day' ? 'primary' : 'default'"
@click="timeDimension = 'day'"
>
</Button>
<Button
:type="timeDimension === 'month' ? 'primary' : 'default'"
@click="timeDimension = 'month'"
>
</Button>
<Button
:type="timeDimension === 'year' ? 'primary' : 'default'"
@click="timeDimension = 'year'"
>
</Button>
<Button
:type="timeDimension === 'all' ? 'primary' : 'default'"
@click="timeDimension = 'all'"
>
全部
</Button>
</div>
<EchartsUI ref="chartRef" /> <EchartsUI ref="chartRef" />
</div>
</template> </template>

View File

@@ -22,7 +22,7 @@ import AnalyticsVisitsSales from './analytics-visits-sales.vue';
import AnalyticsVisitsSource from './analytics-visits-source.vue'; import AnalyticsVisitsSource from './analytics-visits-source.vue';
import AnalyticsVisits from './analytics-visits.vue'; import AnalyticsVisits from './analytics-visits.vue';
import { getAgentList, getWithdrawalStatistics } from '#/api/agent'; import { getAgentStatistics, getWithdrawalStatistics, getAgentOrderStatistics } from '#/api/agent';
import { getOrderList, getRefundStatistics, getIncomeStatistics } from '#/api/order/order'; import { getOrderList, getRefundStatistics, getIncomeStatistics } from '#/api/order/order';
import { getPlatformUserList } from '#/api/platform-user'; import { getPlatformUserList } from '#/api/platform-user';
@@ -52,9 +52,9 @@ const overviewItems = ref<AnalysisOverviewItem[]>([
}, },
{ {
icon: SvgDownloadIcon, icon: SvgDownloadIcon,
title: '总收入', title: '总收入流水金额',
value: 0, value: 0,
todaytitle: '今日新增收入', todaytitle: '今日新增收入流水金额',
todayValue: 0, todayValue: 0,
Subtitle: '总利润', Subtitle: '总利润',
SubValue: 0, SubValue: 0,
@@ -65,24 +65,28 @@ const overviewItems = ref<AnalysisOverviewItem[]>([
icon: SvgBellIcon, icon: SvgBellIcon,
title: '总提现金额', title: '总提现金额',
value: 0, value: 0,
SubValue: 0,
todaySubtitle: '总实际到账金额',
todaySubValue: 0,
extraTitle: '总扣税金额',
extraValue: 0,
todaytitle: '今日新增提现金额', todaytitle: '今日新增提现金额',
todayValue: 0, todayValue: 0,
Subtitle: '总退款金额', Subtitle: '总退款金额',
SubValue: 0, extra2Title: '今日新增退款金额',
todaySubtitle: '今日新增退款金额', extra2Value: 0,
todaySubValue: 0,
}, },
]); ]);
const chartTabs: TabOption[] = [ const chartTabs: TabOption[] = [
{
label: '推广访问趋势',
value: 'trends',
},
{ {
label: '订单趋势', label: '订单趋势',
value: 'visits', value: 'visits',
}, },
{
label: '推广访问趋势',
value: 'trends',
},
]; ];
// 获取统计数据 // 获取统计数据
@@ -111,8 +115,8 @@ async function fetchStatistics() {
const orderTotal = orderResponse.total || 0; const orderTotal = orderResponse.total || 0;
// 获取代理订单数据 // 获取代理订单数据
const agentOrderResponse = await getOrderList({ page: 1, pageSize: 1, is_agent_order: true }); const agentOrderResponse = await getAgentOrderStatistics();
const agentOrderTotal = agentOrderResponse.total || 0; const agentOrderTotal = agentOrderResponse.total_agent_order_count || 0;
// 获取今日新增订单数 // 获取今日新增订单数
const todayOrderResponse = await getOrderList({ const todayOrderResponse = await getOrderList({
@@ -124,34 +128,22 @@ async function fetchStatistics() {
const todayOrderTotal = todayOrderResponse.total || 0; const todayOrderTotal = todayOrderResponse.total || 0;
// 获取今日新增代理订单数 // 获取今日新增代理订单数
const todayAgentOrderResponse = await getOrderList({ const todayAgentOrderResponse = await getAgentOrderStatistics();
page: 1, const todayAgentOrderTotal = todayAgentOrderResponse.today_agent_order_count || 0;
pageSize: 1000,
is_agent_order: true,
create_time_start: startTime,
create_time_end: endTime
});
const todayAgentOrderTotal = todayAgentOrderResponse.total || 0;
// Product data is no longer needed for order statistics // Product data is no longer needed for order statistics
// 获取代理数据(总数) // 获取代理统计数据
const agentResponse = await getAgentList({ page: 1, pageSize: 1 }); const agentStatsResponse = await getAgentStatistics();
const agentTotal = agentResponse.total || 0; const agentTotal = agentStatsResponse.total_agent_count || 0;
const newAgentCount = agentStatsResponse.today_agent_count || 0;
// 获取今日新增代理数
const newAgentResponse = await getAgentList({
page: 1,
pageSize: 100,
create_time_start: startTime,
create_time_end: endTime
});
const newAgentCount = newAgentResponse.total || 0;
// 获取提现统计数据 // 获取提现统计数据
const withdrawalStatsResponse = await getWithdrawalStatistics(); const withdrawalStatsResponse = await getWithdrawalStatistics();
const totalWithdrawalAmount = withdrawalStatsResponse.total_withdrawal_amount || 0; const totalWithdrawalAmount = withdrawalStatsResponse.total_withdrawal_amount || 0;
const todayWithdrawalAmount = withdrawalStatsResponse.today_withdrawal_amount || 0; const todayWithdrawalAmount = withdrawalStatsResponse.today_withdrawal_amount || 0;
const totalActualAmount = withdrawalStatsResponse.total_actual_amount || 0;
const totalTaxAmount = withdrawalStatsResponse.total_tax_amount || 0;
// 获取退款统计数据 // 获取退款统计数据
const refundStatsResponse = await getRefundStatistics(); const refundStatsResponse = await getRefundStatistics();
@@ -191,9 +183,9 @@ async function fetchStatistics() {
}, },
{ {
icon: SvgDownloadIcon, icon: SvgDownloadIcon,
title: '总收入', title: '总收入流水金额',
value: totalIncome, value: totalIncome,
todaytitle: '今日新增收入', todaytitle: '今日新增收入流水金额',
todayValue: todayIncome, todayValue: todayIncome,
Subtitle: '总利润', Subtitle: '总利润',
SubValue: totalProfit, SubValue: totalProfit,
@@ -206,10 +198,14 @@ async function fetchStatistics() {
value: totalWithdrawalAmount, value: totalWithdrawalAmount,
todaytitle: '今日新增提现金额', todaytitle: '今日新增提现金额',
todayValue: todayWithdrawalAmount, todayValue: todayWithdrawalAmount,
extra2Title: '今日新增退款金额',
extra2Value: todayRefundAmount,
Subtitle: '总退款金额', Subtitle: '总退款金额',
SubValue: totalRefundAmount, SubValue: totalRefundAmount,
todaySubtitle: '今日新增退款金额', todaySubtitle: '总实际到账金额',
todaySubValue: todayRefundAmount, todaySubValue: totalActualAmount,
extraTitle: '总扣税金额',
extraValue: totalTaxAmount,
}, },
]; ];
} catch (error) { } catch (error) {
@@ -227,12 +223,12 @@ onMounted(() => {
<div class="p-5"> <div class="p-5">
<AnalysisOverview :items="overviewItems" /> <AnalysisOverview :items="overviewItems" />
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5"> <AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
<template #trends>
<AnalyticsTrends />
</template>
<template #visits> <template #visits>
<AnalyticsVisits /> <AnalyticsVisits />
</template> </template>
<template #trends>
<AnalyticsTrends />
</template>
</AnalysisChartsTabs> </AnalysisChartsTabs>
<div class="mt-5 w-full md:flex"> <div class="mt-5 w-full md:flex">

View File

@@ -173,6 +173,21 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'platform_order_id', fieldName: 'platform_order_id',
label: '支付订单号', label: '支付订单号',
}, },
{
component: 'Input',
fieldName: 'query_name',
label: '被查询人姓名',
},
{
component: 'Input',
fieldName: 'query_id_card',
label: '被查询人身份证',
},
{
component: 'Input',
fieldName: 'query_mobile',
label: '被查询人手机号',
},
{ {
component: 'Input', component: 'Input',
fieldName: 'product_name', fieldName: 'product_name',

View File

@@ -36,6 +36,18 @@ export function useFormSchema(): VbenFormSchema[] {
}, },
defaultValue: 0, defaultValue: 0,
}, },
{
component: 'Switch',
fieldName: 'disable',
label: '是否封禁',
componentProps: {
checkedChildren: '已封禁',
unCheckedChildren: '正常',
checkedValue: 1,
unCheckedValue: 0,
},
defaultValue: 0,
},
]; ];
} }
@@ -64,6 +76,18 @@ export function useGridFormSchema(): VbenFormSchema[] {
], ],
}, },
}, },
{
component: 'Select',
fieldName: 'disable',
label: '封禁状态',
componentProps: {
allowClear: true,
options: [
{ label: '正常', value: 0 },
{ label: '已封禁', value: 1 },
],
},
},
{ {
component: 'RangePicker', component: 'RangePicker',
fieldName: 'create_time', fieldName: 'create_time',
@@ -104,6 +128,12 @@ export function useColumns<T = PlatformUserApi.PlatformUserItem>(
width: 100, width: 100,
formatter: ({ cellValue }) => (cellValue === 1 ? '是' : '否'), formatter: ({ cellValue }) => (cellValue === 1 ? '是' : '否'),
}, },
{
field: 'disable',
title: '封禁状态',
width: 100,
formatter: ({ cellValue }) => (cellValue === 1 ? '已封禁' : '正常'),
},
{ {
field: 'create_time', field: 'create_time',
title: '创建时间', title: '创建时间',

View File

@@ -55,6 +55,18 @@ withDefaults(defineProps<Props>(), {
+<VbenCountToAnimator :end-val="item.todaySubValue" /> +<VbenCountToAnimator :end-val="item.todaySubValue" />
</span> </span>
</p> </p>
<p v-if="item.extraTitle" class="text-xs text-muted-foreground flex justify-between mt-1">
<span>{{ item.extraTitle }}</span>
<span class="font-medium text-foreground">
<VbenCountToAnimator :end-val="item.extraValue || 0" />
</span>
</p>
<p v-if="item.extra2Title" class="text-xs text-muted-foreground flex justify-between mt-1">
<span>{{ item.extra2Title }}</span>
<span class="font-medium text-foreground">
+<VbenCountToAnimator :end-val="item.extra2Value || 0" />
</span>
</p>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>

View File

@@ -10,6 +10,10 @@ interface AnalysisOverviewItem {
SubValue: number; SubValue: number;
todaySubtitle: string; todaySubtitle: string;
todaySubValue: number; todaySubValue: number;
extraTitle?: string;
extraValue?: number;
extra2Title?: string;
extra2Value?: number;
} }
interface WorkbenchProjectItem { interface WorkbenchProjectItem {