Compare commits

...

23 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
946f60e5c3 Merge branch 'main' of http://1.117.67.95:3000/team/tydata-admin
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 13:55:47 +08:00
b392f9cf0d addanalysis 2025-12-27 13:51:08 +08:00
a718ac7874 price analysis 2025-12-26 15:18:31 +08:00
30 changed files with 3086 additions and 362 deletions

View File

@@ -1,3 +0,0 @@
# 每次 git pull 之后, 安装依赖
pnpm install

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,10 +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 {
total_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;
@@ -301,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; // 是否成功
}
} }
/** /**
@@ -336,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,
});
}
/** /**
* 获取代理奖励列表 * 获取代理奖励列表
*/ */
@@ -472,18 +599,117 @@ async function reviewBankCardWithdrawal(
); );
} }
/**
* 获取提现统计数据
*/
async function getWithdrawalStatistics() {
return requestClient.get<AgentApi.WithdrawalStatistics>(
'/agent/agent-withdrawal/statistics',
);
}
/**
* 获取代理订单统计数据
*/
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, 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

@@ -11,6 +11,7 @@ export namespace OrderApi {
payment_platform: 'alipay' | 'appleiap' | 'wechat'; payment_platform: 'alipay' | 'appleiap' | 'wechat';
payment_scene: 'app' | 'h5' | 'mini_program' | 'public_account'; payment_scene: 'app' | 'h5' | 'mini_program' | 'public_account';
amount: number; amount: number;
sales_cost: number;
status: 'closed' | 'failed' | 'paid' | 'pending' | 'refunded'; status: 'closed' | 'failed' | 'paid' | 'pending' | 'refunded';
query_state: 'cleaned' | 'failed' | 'pending' | 'processing' | 'success'; query_state: 'cleaned' | 'failed' | 'pending' | 'processing' | 'success';
create_time: string; create_time: string;
@@ -34,6 +35,26 @@ export namespace OrderApi {
refund_no: string; refund_no: string;
amount: number; amount: number;
} }
// 退款统计数据
export interface RefundStatistics {
total_refund_amount: number;
today_refund_amount: number;
}
// 收入统计数据
export interface IncomeStatistics {
total_revenue_amount: number;
today_revenue_amount: number;
total_profit_amount: number;
today_profit_amount: number;
}
// 订单来源统计数据
export interface OrderSourceStatistics {
product_name: string;
order_count: number;
}
} }
/** /**
@@ -57,4 +78,25 @@ async function refundOrder(id: number, data: OrderApi.RefundOrderRequest) {
); );
} }
export { getOrderList, refundOrder }; /**
* 获取退款统计数据
*/
async function getRefundStatistics() {
return requestClient.get<OrderApi.RefundStatistics>('/order/refund-statistics');
}
/**
* 获取收入统计数据
*/
async function getIncomeStatistics() {
return requestClient.get<OrderApi.IncomeStatistics>('/order/revenue-statistics');
}
/**
* 获取订单来源统计数据
*/
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

@@ -7,6 +7,7 @@ export namespace FeatureApi {
id: number; id: number;
api_id: string; api_id: string;
name: string; name: string;
cost_price: number;
create_time: string; create_time: string;
update_time: string; update_time: string;
} }
@@ -19,11 +20,13 @@ export namespace FeatureApi {
export interface CreateFeatureRequest { export interface CreateFeatureRequest {
api_id: string; api_id: string;
name: string; name: string;
cost_price: number;
} }
export interface UpdateFeatureRequest { export interface UpdateFeatureRequest {
api_id?: string; api_id?: string;
name?: string; name?: string;
cost_price?: number;
} }
export interface FeatureExampleItem { export interface FeatureExampleItem {

View File

@@ -61,6 +61,10 @@ export namespace ProductApi {
export interface UpdateProductFeaturesRequest { export interface UpdateProductFeaturesRequest {
features: ProductFeatureItem[]; features: ProductFeatureItem[];
} }
export interface UpdateProductFeaturesResponse {
success: boolean;
}
} }
/** /**

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,8 +45,9 @@ const [Form, formApi] = useVbenForm({
addonBefore: '¥', addonBefore: '¥',
}, },
}, },
// 银行卡和支付宝通用字段:扣税金额
{ {
component: 'InputNumber', component: 'InputNumber' ,
fieldName: 'tax_amount', fieldName: 'tax_amount',
label: '扣税金额', label: '扣税金额',
componentProps: { componentProps: {
@@ -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

@@ -5,10 +5,80 @@ import { onMounted, ref } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts'; import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { statsHistory, statsTotal } from '#/api/promotion/analytics';
const chartRef = ref<EchartsUIType>(); const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef); const { renderEcharts } = useEcharts(chartRef);
onMounted(() => { // 获取30天前的日期
const getDateString = (daysAgo: number) => {
const date = new Date();
date.setDate(date.getDate() - daysAgo);
return date.toISOString().split('T')[0];
};
onMounted(async () => {
try {
// 获取趋势数据
const endDate = getDateString(0); // 今天
const startDate = getDateString(29); // 29天前
const trendData = await statsHistory({ start_date: startDate, end_date: endDate });
// 获取统计数据
const statsData = await statsTotal();
// 准备图表数据
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' });
});
// 如果有历史数据,使用历史数据;否则使用模拟数据
let clickData = Array(30).fill(0);
if (trendData && trendData.length > 0) {
// 将历史数据按日期排序并映射到数组
const sortedData = trendData.sort((a, b) =>
new Date(a.stats_date).getTime() - new Date(b.stats_date).getTime()
);
sortedData.forEach((item) => {
const itemDate = new Date(item.stats_date);
const today = new Date();
const daysDiff = Math.floor((today.getTime() - itemDate.getTime()) / (1000 * 60 * 60 * 24));
if (daysDiff >= 0 && daysDiff < 30) {
// 使用实际日期索引
clickData[29 - daysDiff] = item.click_count || 0;
}
});
} else {
// 没有历史数据时,使用统计数据生成模拟数据
const todayClickCount = statsData?.today_click_count || 0;
const totalClickCount = statsData?.total_click_count || 0;
// 简单的线性分布模拟数据
for (let i = 0; i < 30; i++) {
// 最后一天使用今日数据,其他天按比例分布
if (i === 29) {
clickData[i] = todayClickCount;
} else {
// 按指数衰减模拟历史数据
clickData[i] = Math.max(0, Math.floor(todayClickCount * Math.exp(-0.05 * (29 - i))));
}
}
// 确保总和不超过总计数
const sum = clickData.reduce((a, b) => a + b, 0);
if (sum > totalClickCount && totalClickCount > 0) {
const ratio = totalClickCount / sum;
clickData = clickData.map(val => Math.floor(val * ratio));
}
}
// 计算Y轴最大值
const maxValue = Math.max(...clickData) || 10;
renderEcharts({ renderEcharts({
grid: { grid: {
bottom: 0, bottom: 0,
@@ -20,17 +90,79 @@ onMounted(() => {
series: [ series: [
{ {
areaStyle: {}, areaStyle: {},
data: [ data: clickData,
120, 300, 500, 800, 1200, 1800, 2500, 3000, 2800, 2600, 2400, 2200,
2000, 1800, 1600, 1400, 1200, 1000, 800, 600, 400, 200, 100, 50, 30,
20, 10, 5, 2, 1,
],
itemStyle: { itemStyle: {
color: '#5ab1ef', color: '#5ab1ef',
}, },
smooth: true, smooth: true,
type: 'line', type: 'line',
name: '访问量', name: '推广访问量',
},
],
tooltip: {
axisPointer: {
lineStyle: {
color: '#5ab1ef',
width: 1,
},
},
trigger: 'axis',
formatter: (params: any) => {
const param = params[0];
return `${param.axisValue}<br/>${param.seriesName}: ${param.value}`;
},
},
xAxis: {
axisTick: {
show: false,
},
boundaryGap: false,
data: dates,
splitLine: {
lineStyle: {
type: 'solid',
width: 1,
},
show: true,
},
type: 'category',
},
yAxis: [
{
axisTick: {
show: false,
},
max: Math.ceil(maxValue * 1.2), // 比最大值大20%作为Y轴上限
splitArea: {
show: true,
},
splitNumber: 4,
type: 'value',
},
],
});
} catch (error) {
console.error('获取推广趋势数据失败:', error);
// 发生错误时显示默认图表
renderEcharts({
grid: {
bottom: 0,
containLabel: true,
left: '1%',
right: '1%',
top: '2%',
},
series: [
{
areaStyle: {},
data: Array(30).fill(0),
itemStyle: {
color: '#5ab1ef',
},
smooth: true,
type: 'line',
name: '推广访问量',
}, },
], ],
tooltip: { tooltip: {
@@ -47,9 +179,11 @@ onMounted(() => {
show: false, show: false,
}, },
boundaryGap: false, boundaryGap: false,
data: Array.from({ length: 30 }).map( data: Array.from({ length: 30 }).map((_, index) => {
(_item, index) => `Day ${index + 1}`, const date = new Date();
), date.setDate(date.getDate() - 29 + index);
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
}),
splitLine: { splitLine: {
lineStyle: { lineStyle: {
type: 'solid', type: 'solid',
@@ -64,7 +198,7 @@ onMounted(() => {
axisTick: { axisTick: {
show: false, show: false,
}, },
max: 3000, max: 10,
splitArea: { splitArea: {
show: true, show: true,
}, },
@@ -73,6 +207,7 @@ onMounted(() => {
}, },
], ],
}); });
}
}); });
</script> </script>

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,31 +1,183 @@
<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 { getOrderStatistics } from '#/api/order/order-statistics';
const chartRef = ref<EchartsUIType>(); const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef); const { renderEcharts } = useEcharts(chartRef);
onMounted(() => { // 时间维度状态
const timeDimension = ref<'day' | 'month' | 'year' | 'all'>('day');
// 获取订单统计数据
async function fetchOrderStatistics() {
try {
console.log('Fetching order statistics with dimension:', timeDimension.value);
// 使用后端API获取数据
const response = await getOrderStatistics(timeDimension.value);
console.log('Order statistics response:', response);
let items = response.items || [];
// 如果后端返回空数据,显示空状态
if (items.length === 0) {
console.log('No data from backend, showing empty chart');
items = [];
}
console.log('Items for chart:', items);
// 按日期排序
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 amountData = items.map((item: any) => item.amount);
// 计算Y轴最大值
const maxOrderValue = Math.max(...orderData) || 10;
const maxAmountValue = Math.max(...amountData) || 10;
renderEcharts({ renderEcharts({
grid: { grid: {
bottom: 0, bottom: 0,
containLabel: true, containLabel: true,
left: '1%', left: '1%',
right: '1%', right: '1%',
top: '2%', top: '10%',
},
legend: {
data: ['订单数', '订单金额'],
top: 0,
}, },
series: [ series: [
{ {
barMaxWidth: 80, data: orderData,
data: [ type: 'line',
30, 20, 33, 50, 32, 42, 32, 21, 30, 51, 60, 32, 48, 40, 35, 28, 22,
18, 15, 10, 8, 6, 4, 2, 1, 1, 0, 0, 0, 0,
],
type: 'bar',
name: '订单数', name: '订单数',
smooth: true,
itemStyle: {
color: '#4f9cff',
},
areaStyle: {
opacity: 0.3,
color: '#4f9cff',
},
},
{
data: amountData,
type: 'line',
name: '订单金额',
smooth: true,
itemStyle: {
color: '#52c41a',
},
areaStyle: {
opacity: 0.3,
color: '#52c41a',
},
},
],
tooltip: {
axisPointer: {
lineStyle: {
width: 1,
},
},
trigger: 'axis',
formatter: (params: any) => {
let result = `${params[0].axisValue}<br/>`;
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: {
data: dates,
type: 'category',
boundaryGap: false,
},
yAxis: [
{
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) {
console.error('获取订单趋势数据失败:', error);
// 发生错误时显示默认图表
renderEcharts({
grid: {
bottom: 0,
containLabel: true,
left: '1%',
right: '1%',
top: '10%',
},
legend: {
data: ['订单数', '订单金额'],
top: 0,
},
series: [
{
data: Array(30).fill(0),
type: 'line',
name: '订单数',
smooth: true,
itemStyle: {
color: '#4f9cff',
},
areaStyle: {
opacity: 0.3,
color: '#4f9cff',
},
},
{
data: Array(30).fill(0),
type: 'line',
name: '订单金额',
smooth: true,
itemStyle: {
color: '#52c41a',
},
areaStyle: {
opacity: 0.3,
color: '#52c41a',
},
}, },
], ],
tooltip: { tooltip: {
@@ -37,20 +189,74 @@ onMounted(() => {
trigger: 'axis', trigger: 'axis',
}, },
xAxis: { xAxis: {
data: Array.from({ length: 30 }).map( data: Array.from({ length: 30 }).map((_, index) => {
(_item, index) => `Day ${index + 1}`, const date = new Date();
), date.setDate(date.getDate() - 29 + index);
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
}),
type: 'category', type: 'category',
boundaryGap: false,
}, },
yAxis: { yAxis: [
max: 80, {
splitNumber: 4,
type: 'value', type: 'value',
name: '订单数',
position: 'left',
max: 10,
splitNumber: 4,
}, },
{
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

@@ -14,68 +14,221 @@ import {
SvgDownloadIcon, SvgDownloadIcon,
} from '@vben/icons'; } from '@vben/icons';
import { onMounted, ref } from 'vue';
import AnalyticsTrends from './analytics-trends.vue'; import AnalyticsTrends from './analytics-trends.vue';
import AnalyticsVisitsData from './analytics-visits-data.vue'; import AnalyticsVisitsData from './analytics-visits-data.vue';
import AnalyticsVisitsSales from './analytics-visits-sales.vue'; 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';
const overviewItems: AnalysisOverviewItem[] = [ import { getAgentStatistics, getWithdrawalStatistics, getAgentOrderStatistics } from '#/api/agent';
import { getOrderList, getRefundStatistics, getIncomeStatistics } from '#/api/order/order';
import { getPlatformUserList } from '#/api/platform-user';
// 初始化概览数据
const overviewItems = ref<AnalysisOverviewItem[]>([
{ {
icon: SvgCardIcon, icon: SvgCardIcon,
title: '平台用户数', title: '用户数',
totalTitle: '总用户数', value: 0,
totalValue: 120_000, todaytitle: '今日新增用户数',
value: 2000, todayValue: 0,
Subtitle: '总代理数',
SubValue: 0,
todaySubtitle: '今日新增代理数',
todaySubValue: 0,
}, },
{ {
icon: SvgCakeIcon, icon: SvgCakeIcon,
title: '推广访问量', title: '总订单数',
totalTitle: '总推广访问量', value: 0,
totalValue: 500_000, todaytitle: '今日新增订单数',
value: 20_000, todayValue: 0,
Subtitle: '代理总订单量',
SubValue: 0,
todaySubtitle: '今日新增代理订单量',
todaySubValue: 0,
}, },
{ {
icon: SvgDownloadIcon, icon: SvgDownloadIcon,
title: '产品数量', title: '总收入流水金额',
totalTitle: '总产品数量', value: 0,
totalValue: 120, todaytitle: '今日新增收入流水金额',
value: 8, todayValue: 0,
Subtitle: '总利润',
SubValue: 0,
todaySubtitle: '今日新增利润',
todaySubValue: 0,
}, },
{ {
icon: SvgBellIcon, icon: SvgBellIcon,
title: '代理数量', title: '总提现金额',
totalTitle: '总代理数量', value: 0,
totalValue: 5000, SubValue: 0,
value: 500, todaySubtitle: '总实际到账金额',
todaySubValue: 0,
extraTitle: '总扣税金额',
extraValue: 0,
todaytitle: '今日新增提现金额',
todayValue: 0,
Subtitle: '总退款金额',
extra2Title: '今日新增退款金额',
extra2Value: 0,
}, },
]; ]);
const chartTabs: TabOption[] = [ const chartTabs: TabOption[] = [
{
label: '推广访问趋势',
value: 'trends',
},
{ {
label: '订单趋势', label: '订单趋势',
value: 'visits', value: 'visits',
}, },
{
label: '推广访问趋势',
value: 'trends',
},
]; ];
// 获取统计数据
async function fetchStatistics() {
try {
// 获取今日的开始和结束时间
const today = new Date();
// 将时间格式化为后端期望的格式 (YYYY-MM-DD HH:MM:SS)
const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate()).toISOString().replace('T', ' ').substring(0, 19);
const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1).toISOString().replace('T', ' ').substring(0, 19);
// 获取平台用户数据(总数)
const platformUserResponse = await getPlatformUserList({ page: 1, pageSize: 1 });
const platformUserTotal = platformUserResponse.total || 0;
// 获取今日新增用户数
// 由于平台用户API不支持时间过滤我们需要获取更多数据并在前端过滤
const newUserResponse = await getPlatformUserList({ page: 1, pageSize: 1000 });
const newUserCount = newUserResponse.items?.filter(user => {
const userCreateTime = new Date(user.create_time);
return userCreateTime >= new Date(startTime) && userCreateTime < new Date(endTime);
}).length || 0;
// 获取订单数据
const orderResponse = await getOrderList({ page: 1, pageSize: 1 });
const orderTotal = orderResponse.total || 0;
// 获取代理订单数据
const agentOrderResponse = await getAgentOrderStatistics();
const agentOrderTotal = agentOrderResponse.total_agent_order_count || 0;
// 获取今日新增订单数
const todayOrderResponse = await getOrderList({
page: 1,
pageSize: 1000,
create_time_start: startTime,
create_time_end: endTime
});
const todayOrderTotal = todayOrderResponse.total || 0;
// 获取今日新增代理订单数
const todayAgentOrderResponse = await getAgentOrderStatistics();
const todayAgentOrderTotal = todayAgentOrderResponse.today_agent_order_count || 0;
// Product data is no longer needed for order statistics
// 获取代理统计数据
const agentStatsResponse = await getAgentStatistics();
const agentTotal = agentStatsResponse.total_agent_count || 0;
const newAgentCount = agentStatsResponse.today_agent_count || 0;
// 获取提现统计数据
const withdrawalStatsResponse = await getWithdrawalStatistics();
const totalWithdrawalAmount = withdrawalStatsResponse.total_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 totalRefundAmount = refundStatsResponse.total_refund_amount || 0;
const todayRefundAmount = refundStatsResponse.today_refund_amount || 0;
// 获取收入统计数据
const incomeStatsResponse = await getIncomeStatistics();
const totalIncome = incomeStatsResponse.total_revenue_amount || 0;
const todayIncome = incomeStatsResponse.today_revenue_amount || 0;
const totalProfit = incomeStatsResponse.total_profit_amount || 0;
const todayProfit = incomeStatsResponse.today_profit_amount || 0;
// 更新概览数据
overviewItems.value = [
{
icon: SvgCardIcon,
title: '总用户数',
value: platformUserTotal,
todaytitle: '今日新增用户数',
todayValue: newUserCount,
Subtitle: '总代理数',
SubValue: agentTotal,
todaySubtitle: '今日新增代理数',
todaySubValue: newAgentCount,
},
{
icon: SvgCakeIcon,
title: '总订单数',
value: orderTotal,
todaytitle: '今日新增订单数',
todayValue: todayOrderTotal,
Subtitle: '总代理订单量',
SubValue: agentOrderTotal,
todaySubtitle: '今日新增代理订单量',
todaySubValue: todayAgentOrderTotal,
},
{
icon: SvgDownloadIcon,
title: '总收入流水金额',
value: totalIncome,
todaytitle: '今日新增收入流水金额',
todayValue: todayIncome,
Subtitle: '总利润',
SubValue: totalProfit,
todaySubtitle: '今日新增利润',
todaySubValue: todayProfit,
},
{
icon: SvgBellIcon,
title: '总提现金额',
value: totalWithdrawalAmount,
todaytitle: '今日新增提现金额',
todayValue: todayWithdrawalAmount,
extra2Title: '今日新增退款金额',
extra2Value: todayRefundAmount,
Subtitle: '总退款金额',
SubValue: totalRefundAmount,
todaySubtitle: '总实际到账金额',
todaySubValue: totalActualAmount,
extraTitle: '总扣税金额',
extraValue: totalTaxAmount,
},
];
} catch (error) {
console.error('获取统计数据失败:', error);
}
}
// 组件挂载时获取数据
onMounted(() => {
fetchStatistics();
});
</script> </script>
<template> <template>
<div class="p-5"> <div class="p-5">
<div class="mb-4 ml-4 text-lg text-gray-500">
该数据为演示模拟生成不为真实数据
</div>
<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

@@ -53,6 +53,14 @@ export function useColumns<T = OrderApi.Order>(
return sceneMap[row.payment_scene] || row.payment_scene; return sceneMap[row.payment_scene] || row.payment_scene;
}, },
}, },
{
field: 'sales_cost',
title: '成本价',
width: 120,
formatter: ({ row }) => {
return `¥${row.sales_cost.toFixed(2)}`;
},
},
{ {
field: 'amount', field: 'amount',
title: '金额', title: '金额',
@@ -165,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

@@ -17,6 +17,27 @@ export function useFormSchema(): VbenFormSchema[] {
label: '描述', label: '描述',
rules: 'required', rules: 'required',
}, },
{
component: 'InputNumber',
fieldName: 'cost_price',
label: '成本价',
rules: 'required',
componentProps: {
min: 0,
precision: 2,
step: 0.01,
formatter: (value: number) => {
// 格式化为带千分位分隔符的货币
const parts = value.toString().split('.');
parts[0] = (parts[0] || '0').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return `¥ ${parts.join('.')}`;
},
parser: (value: string) => {
// 移除货币符号和千分位分隔符
return value.replace(/[¥,\s]/g, '');
},
},
},
]; ];
} }
@@ -33,6 +54,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'name', fieldName: 'name',
label: '描述', label: '描述',
}, },
]; ];
} }
@@ -51,6 +73,18 @@ export function useColumns<T = FeatureApi.FeatureItem>(
title: '描述', title: '描述',
minWidth: 200, minWidth: 200,
}, },
{
field: 'cost_price',
title: '成本价',
minWidth: 120,
formatter: ({ cellValue }) => {
// 格式化为带千分位分隔符的货币
const value = cellValue?.toFixed(2) || '0.00';
const parts = value.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return `¥ ${parts.join('.')}`;
},
},
{ {
field: 'create_time', field: 'create_time',
title: '创建时间', title: '创建时间',

View File

@@ -28,6 +28,7 @@ import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getFeatureList } from '#/api/product-manage/feature'; import { getFeatureList } from '#/api/product-manage/feature';
import { import {
getProductFeatureList, getProductFeatureList,
updateProduct,
updateProductFeatures, updateProductFeatures,
} from '#/api/product-manage/product'; } from '#/api/product-manage/product';
@@ -71,11 +72,28 @@ const [Modal, modalApi] = useVbenModal({
// 更新产品模块关联 // 更新产品模块关联
await updateProductFeatures(productId, { features }); await updateProductFeatures(productId, { features });
message.success('保存成功');
// 计算关联模块的总成本(只计算启用的模块)
let totalCost = 0;
const enabledFeatures = tempFeatureList.value.filter(item => item.enable === 1);
// 使用缓存的模块数据计算总成本
for (const feature of enabledFeatures) {
const featureDetail = allFeaturesCache.value.find(f => f.id === feature.feature_id);
if (featureDetail) {
totalCost += featureDetail.cost_price || 0;
}
}
// 更新产品成本价
await updateProduct(productId, { cost_price: totalCost });
message.success(`保存成功,产品成本已更新为: ¥${totalCost.toFixed(2)}`);
emit('success'); emit('success');
modalApi.close(); // 保存成功后关闭Modal modalApi.close(); // 保存成功后关闭Modal
return true; return true;
} catch { } catch (error) {
console.error('保存失败:', error);
message.error('保存失败'); message.error('保存失败');
return false; return false;
} }
@@ -84,6 +102,8 @@ const [Modal, modalApi] = useVbenModal({
const loading = ref(false); const loading = ref(false);
const tempFeatureList = ref<TempFeatureItem[]>([]); const tempFeatureList = ref<TempFeatureItem[]>([]);
// 存储模块详细信息,用于成本计算
const allFeaturesCache = ref<FeatureApi.FeatureItem[]>([]);
// 表格配置 // 表格配置
const [Grid] = useVbenVxeGrid({ const [Grid] = useVbenVxeGrid({
@@ -219,6 +239,7 @@ async function loadFeatureList() {
loading.value = true; loading.value = true;
try { try {
// 获取产品已关联的模块列表
const res = await getProductFeatureList(productId); const res = await getProductFeatureList(productId);
// 转换为临时数据格式 // 转换为临时数据格式
let tempList = res.map((item) => ({ let tempList = res.map((item) => ({
@@ -237,6 +258,11 @@ async function loadFeatureList() {
.map((item, idx) => ({ ...item, sort: idx + 1 })); .map((item, idx) => ({ ...item, sort: idx + 1 }));
} }
tempFeatureList.value = tempList; tempFeatureList.value = tempList;
// 获取并缓存所有模块数据(用于成本计算)
const allFeaturesRes = await getFeatureList({ page: 1, pageSize: 1000 });
allFeaturesCache.value = allFeaturesRes.items || [];
initSortable(); initSortable();
} finally { } finally {
loading.value = false; loading.value = false;
@@ -326,6 +352,22 @@ function handleRemoveFeature(record: TempFeatureItem) {
}, },
}); });
} }
// 计算已启用模块的总成本
function calculateTotalCost() {
let totalCost = 0;
const enabledFeatures = tempFeatureList.value.filter(item => item.enable === 1);
// 使用缓存的模块数据计算总成本
for (const feature of enabledFeatures) {
const featureDetail = allFeaturesCache.value.find(f => f.id === feature.feature_id);
if (featureDetail) {
totalCost += featureDetail.cost_price || 0;
}
}
return totalCost;
}
</script> </script>
<template> <template>
@@ -343,6 +385,12 @@ function handleRemoveFeature(record: TempFeatureItem) {
<!-- 右侧已关联模块列表 --> <!-- 右侧已关联模块列表 -->
<div class="flex-1"> <div class="flex-1">
<div class="mb-2 text-base font-medium">已关联模块</div> <div class="mb-2 text-base font-medium">已关联模块</div>
<div class="mb-2 p-3 bg-gray-50 rounded">
<div class="flex justify-between items-center">
<span class="text-sm font-medium">已启用模块总成本</span>
<span class="text-lg font-bold text-red-600">¥{{ calculateTotalCost().toFixed(2) }}</span>
</div>
</div>
<div class="mb-4 text-sm text-gray-500"> <div class="mb-4 text-sm text-gray-500">
提示可以通过拖拽行来调整模块顺序通过开关控制模块的启用状态和重要程度 提示可以通过拖拽行来调整模块顺序通过开关控制模块的启用状态和重要程度
</div> </div>

View File

@@ -81,6 +81,7 @@
"autoprefixer": "catalog:", "autoprefixer": "catalog:",
"cross-env": "catalog:", "cross-env": "catalog:",
"cspell": "catalog:", "cspell": "catalog:",
"cssnano": "^7.1.2",
"happy-dom": "catalog:", "happy-dom": "catalog:",
"husky": "catalog:", "husky": "catalog:",
"is-ci": "catalog:", "is-ci": "catalog:",

View File

@@ -4,7 +4,6 @@ import type { AnalysisOverviewItem } from '../typing';
import { import {
Card, Card,
CardContent, CardContent,
CardFooter,
CardHeader, CardHeader,
CardTitle, CardTitle,
VbenCountToAnimator, VbenCountToAnimator,
@@ -26,32 +25,50 @@ withDefaults(defineProps<Props>(), {
<template> <template>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
<template v-for="item in items" :key="item.title"> <Card v-for="(item, index) in items" :key="index" class="relative overflow-hidden">
<Card :title="item.title" class="w-full"> <CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
<CardHeader> <CardTitle class="text-sm font-medium">
<CardTitle class="text-xl">{{ item.title }}</CardTitle> {{ item.title }}
</CardTitle>
<VbenIcon :icon="item.icon" class="h-4 w-4 text-muted-foreground" />
</CardHeader> </CardHeader>
<CardContent>
<CardContent class="flex items-center justify-between"> <div class="text-2xl font-bold">
<VbenCountToAnimator <VbenCountToAnimator :end-val="item.value" />
:end-val="item.value" </div>
:start-val="1" <p class="text-xs text-muted-foreground">
class="text-xl" {{ item.todaytitle }}
prefix="" <span class="font-medium text-foreground">
:decimals="item.decimals ?? 0" +<VbenCountToAnimator :end-val="item.todayValue" />
/> </span>
<VbenIcon :icon="item.icon" class="size-8 flex-shrink-0" /> </p>
<div class="mt-3 border-t pt-3">
<p class="text-xs text-muted-foreground flex justify-between">
<span>{{ item.Subtitle }}</span>
<span class="font-medium text-foreground">
<VbenCountToAnimator :end-val="item.SubValue" />
</span>
</p>
<p class="text-xs text-muted-foreground flex justify-between mt-1">
<span>{{ item.todaySubtitle }}</span>
<span class="font-medium text-foreground">
+<VbenCountToAnimator :end-val="item.todaySubValue" />
</span>
</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>
</CardContent> </CardContent>
<CardFooter class="justify-between">
<span>{{ item.totalTitle }}</span>
<VbenCountToAnimator
:end-val="item.totalValue"
:start-val="1"
prefix=""
:decimals="item.decimals ?? 0"
/>
</CardFooter>
</Card> </Card>
</template>
</div> </div>
</template> </template>

View File

@@ -3,10 +3,17 @@ import type { Component } from 'vue';
interface AnalysisOverviewItem { interface AnalysisOverviewItem {
icon: Component | string; icon: Component | string;
title: string; title: string;
totalTitle: string;
totalValue: number;
value: number; value: number;
decimals?: number; todaytitle: string;
todayValue: number;
Subtitle: string;
SubValue: number;
todaySubtitle: string;
todaySubValue: number;
extraTitle?: string;
extraValue?: number;
extra2Title?: string;
extra2Value?: number;
} }
interface WorkbenchProjectItem { interface WorkbenchProjectItem {

View File

@@ -43,10 +43,12 @@
"@vben/request": "workspace:*", "@vben/request": "workspace:*",
"@vben/stores": "workspace:*", "@vben/stores": "workspace:*",
"@vben/styles": "workspace:*", "@vben/styles": "workspace:*",
"@vben/tailwind-config": "workspace:*",
"@vben/types": "workspace:*", "@vben/types": "workspace:*",
"@vben/utils": "workspace:*", "@vben/utils": "workspace:*",
"@vueuse/core": "catalog:", "@vueuse/core": "catalog:",
"ant-design-vue": "catalog:", "ant-design-vue": "catalog:",
"cssnano": "catalog:",
"dayjs": "catalog:", "dayjs": "catalog:",
"pinia": "catalog:", "pinia": "catalog:",
"vue": "catalog:", "vue": "catalog:",

View File

@@ -1 +1,12 @@
export { default } from '@vben/tailwind-config/postcss'; import config from '@vben/tailwind-config';
export default {
plugins: {
autoprefixer: {},
'postcss-antd-fixes': { prefixes: ['ant', 'el'] },
'postcss-import': {},
'postcss-preset-env': {},
tailwindcss: { config },
'tailwindcss/nesting': {},
},
};

458
pnpm-lock.yaml generated
View File

@@ -593,6 +593,9 @@ importers:
cspell: cspell:
specifier: 'catalog:' specifier: 'catalog:'
version: 8.19.4 version: 8.19.4
cssnano:
specifier: ^7.1.2
version: 7.1.2(postcss@8.5.3)
happy-dom: happy-dom:
specifier: 'catalog:' specifier: 'catalog:'
version: 16.8.1 version: 16.8.1
@@ -1757,6 +1760,9 @@ importers:
'@vben/styles': '@vben/styles':
specifier: workspace:* specifier: workspace:*
version: link:../packages/styles version: link:../packages/styles
'@vben/tailwind-config':
specifier: workspace:*
version: link:../internal/tailwind-config
'@vben/types': '@vben/types':
specifier: workspace:* specifier: workspace:*
version: link:../packages/types version: link:../packages/types
@@ -1769,6 +1775,9 @@ importers:
ant-design-vue: ant-design-vue:
specifier: 'catalog:' specifier: 'catalog:'
version: 4.2.6(vue@3.5.13(typescript@5.8.3)) version: 4.2.6(vue@3.5.13(typescript@5.8.3))
cssnano:
specifier: 'catalog:'
version: 7.0.6(postcss@8.5.3)
dayjs: dayjs:
specifier: 'catalog:' specifier: 'catalog:'
version: 1.11.13 version: 1.11.13
@@ -5120,6 +5129,10 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.9.11:
resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==}
hasBin: true
better-path-resolve@1.0.0: better-path-resolve@1.0.0:
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -5159,6 +5172,11 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true hasBin: true
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
buffer-crc32@1.0.0: buffer-crc32@1.0.0:
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@@ -5243,6 +5261,9 @@ packages:
caniuse-lite@1.0.30001702: caniuse-lite@1.0.30001702:
resolution: {integrity: sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==} resolution: {integrity: sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==}
caniuse-lite@1.0.30001761:
resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==}
ccount@2.0.1: ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -5400,6 +5421,10 @@ packages:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'} engines: {node: '>=14'}
commander@11.1.0:
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
engines: {node: '>=16'}
commander@12.1.0: commander@12.1.0:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -5680,6 +5705,12 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
hasBin: true hasBin: true
cssnano-preset-default@7.0.10:
resolution: {integrity: sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
cssnano-preset-default@7.0.6: cssnano-preset-default@7.0.6:
resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==} resolution: {integrity: sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
@@ -5692,12 +5723,24 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
cssnano-utils@5.0.1:
resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
cssnano@7.0.6: cssnano@7.0.6:
resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==} resolution: {integrity: sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
cssnano@7.1.2:
resolution: {integrity: sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
csso@5.0.5: csso@5.0.5:
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
@@ -6017,6 +6060,9 @@ packages:
electron-to-chromium@1.5.113: electron-to-chromium@1.5.113:
resolution: {integrity: sha512-wjT2O4hX+wdWPJ76gWSkMhcHAV2PTMX+QetUCPYEdCIe+cxmgzzSSiGRCKW8nuh4mwKZlpv0xvoW7OF2X+wmHg==} resolution: {integrity: sha512-wjT2O4hX+wdWPJ76gWSkMhcHAV2PTMX+QetUCPYEdCIe+cxmgzzSSiGRCKW8nuh4mwKZlpv0xvoW7OF2X+wmHg==}
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
emoji-regex-xs@1.0.0: emoji-regex-xs@1.0.0:
resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
@@ -7952,6 +7998,9 @@ packages:
node-releases@2.0.19: node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
nopt@7.2.1: nopt@7.2.1:
resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -8363,12 +8412,24 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-colormin@7.0.5:
resolution: {integrity: sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-convert-values@7.0.4: postcss-convert-values@7.0.4:
resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==} resolution: {integrity: sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-convert-values@7.0.8:
resolution: {integrity: sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-custom-media@11.0.5: postcss-custom-media@11.0.5:
resolution: {integrity: sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==} resolution: {integrity: sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -8399,24 +8460,48 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-discard-comments@7.0.5:
resolution: {integrity: sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-discard-duplicates@7.0.1: postcss-discard-duplicates@7.0.1:
resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==} resolution: {integrity: sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-discard-duplicates@7.0.2:
resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-discard-empty@7.0.0: postcss-discard-empty@7.0.0:
resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==} resolution: {integrity: sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-discard-empty@7.0.1:
resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-discard-overridden@7.0.0: postcss-discard-overridden@7.0.0:
resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==} resolution: {integrity: sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-discard-overridden@7.0.1:
resolution: {integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-double-position-gradients@6.0.0: postcss-double-position-gradients@6.0.0:
resolution: {integrity: sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==} resolution: {integrity: sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -8507,36 +8592,72 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-merge-longhand@7.0.5:
resolution: {integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-merge-rules@7.0.4: postcss-merge-rules@7.0.4:
resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==} resolution: {integrity: sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-merge-rules@7.0.7:
resolution: {integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-minify-font-values@7.0.0: postcss-minify-font-values@7.0.0:
resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==} resolution: {integrity: sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-minify-font-values@7.0.1:
resolution: {integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-minify-gradients@7.0.0: postcss-minify-gradients@7.0.0:
resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==} resolution: {integrity: sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-minify-gradients@7.0.1:
resolution: {integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-minify-params@7.0.2: postcss-minify-params@7.0.2:
resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==} resolution: {integrity: sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-minify-params@7.0.5:
resolution: {integrity: sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-minify-selectors@7.0.4: postcss-minify-selectors@7.0.4:
resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==} resolution: {integrity: sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-minify-selectors@7.0.5:
resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-nested@5.0.6: postcss-nested@5.0.6:
resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
engines: {node: '>=12.0'} engines: {node: '>=12.0'}
@@ -8567,54 +8688,108 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-charset@7.0.1:
resolution: {integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-display-values@7.0.0: postcss-normalize-display-values@7.0.0:
resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==} resolution: {integrity: sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-display-values@7.0.1:
resolution: {integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-positions@7.0.0: postcss-normalize-positions@7.0.0:
resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==} resolution: {integrity: sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-positions@7.0.1:
resolution: {integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-repeat-style@7.0.0: postcss-normalize-repeat-style@7.0.0:
resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==} resolution: {integrity: sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-repeat-style@7.0.1:
resolution: {integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-string@7.0.0: postcss-normalize-string@7.0.0:
resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==} resolution: {integrity: sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-string@7.0.1:
resolution: {integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-timing-functions@7.0.0: postcss-normalize-timing-functions@7.0.0:
resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==} resolution: {integrity: sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-timing-functions@7.0.1:
resolution: {integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-unicode@7.0.2: postcss-normalize-unicode@7.0.2:
resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==} resolution: {integrity: sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-unicode@7.0.5:
resolution: {integrity: sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-url@7.0.0: postcss-normalize-url@7.0.0:
resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==} resolution: {integrity: sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-url@7.0.1:
resolution: {integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-normalize-whitespace@7.0.0: postcss-normalize-whitespace@7.0.0:
resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==} resolution: {integrity: sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-normalize-whitespace@7.0.1:
resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-opacity-percentage@3.0.0: postcss-opacity-percentage@3.0.0:
resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==} resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -8627,6 +8802,12 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-ordered-values@7.0.2:
resolution: {integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-overflow-shorthand@6.0.0: postcss-overflow-shorthand@6.0.0:
resolution: {integrity: sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==} resolution: {integrity: sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -8662,12 +8843,24 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-reduce-initial@7.0.5:
resolution: {integrity: sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-reduce-transforms@7.0.0: postcss-reduce-transforms@7.0.0:
resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==} resolution: {integrity: sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-reduce-transforms@7.0.1:
resolution: {integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-replace-overflow-wrap@4.0.0: postcss-replace-overflow-wrap@4.0.0:
resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==} resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==}
peerDependencies: peerDependencies:
@@ -8723,12 +8916,24 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-svgo@7.1.0:
resolution: {integrity: sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==}
engines: {node: ^18.12.0 || ^20.9.0 || >= 18}
peerDependencies:
postcss: ^8.4.32
postcss-unique-selectors@7.0.3: postcss-unique-selectors@7.0.3:
resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==} resolution: {integrity: sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
postcss-unique-selectors@7.0.4:
resolution: {integrity: sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
postcss-value-parser@4.2.0: postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
@@ -9553,6 +9758,12 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.4.31 postcss: ^8.4.31
stylehacks@7.0.7:
resolution: {integrity: sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g==}
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
peerDependencies:
postcss: ^8.4.32
stylelint-config-html@1.1.0: stylelint-config-html@1.1.0:
resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==} resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==}
engines: {node: ^12 || >=14} engines: {node: ^12 || >=14}
@@ -9660,6 +9871,11 @@ packages:
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
hasBin: true hasBin: true
svgo@4.0.0:
resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==}
engines: {node: '>=16'}
hasBin: true
synckit@0.11.3: synckit@0.11.3:
resolution: {integrity: sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==} resolution: {integrity: sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@@ -10116,6 +10332,12 @@ packages:
peerDependencies: peerDependencies:
browserslist: '>= 4.21.0' browserslist: '>= 4.21.0'
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
update-notifier@7.3.1: update-notifier@7.3.1:
resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -10925,7 +11147,7 @@ snapshots:
'@babel/core': 7.26.9 '@babel/core': 7.26.9
'@babel/helper-compilation-targets': 7.26.5 '@babel/helper-compilation-targets': 7.26.5
'@babel/helper-plugin-utils': 7.26.5 '@babel/helper-plugin-utils': 7.26.5
debug: 4.4.0 debug: 4.4.3
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
resolve: 1.22.10 resolve: 1.22.10
transitivePeerDependencies: transitivePeerDependencies:
@@ -14453,6 +14675,8 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
baseline-browser-mapping@2.9.11: {}
better-path-resolve@1.0.0: better-path-resolve@1.0.0:
dependencies: dependencies:
is-windows: 1.0.2 is-windows: 1.0.2
@@ -14500,6 +14724,14 @@ snapshots:
node-releases: 2.0.19 node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4) update-browserslist-db: 1.1.3(browserslist@4.24.4)
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.11
caniuse-lite: 1.0.30001761
electron-to-chromium: 1.5.267
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.28.1)
buffer-crc32@1.0.0: {} buffer-crc32@1.0.0: {}
buffer-equal-constant-time@1.0.1: {} buffer-equal-constant-time@1.0.1: {}
@@ -14600,13 +14832,15 @@ snapshots:
caniuse-api@3.0.0: caniuse-api@3.0.0:
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.28.1
caniuse-lite: 1.0.30001702 caniuse-lite: 1.0.30001702
lodash.memoize: 4.1.2 lodash.memoize: 4.1.2
lodash.uniq: 4.5.0 lodash.uniq: 4.5.0
caniuse-lite@1.0.30001702: {} caniuse-lite@1.0.30001702: {}
caniuse-lite@1.0.30001761: {}
ccount@2.0.1: {} ccount@2.0.1: {}
chai@5.2.0: chai@5.2.0:
@@ -14788,6 +15022,8 @@ snapshots:
commander@10.0.1: {} commander@10.0.1: {}
commander@11.1.0: {}
commander@12.1.0: {} commander@12.1.0: {}
commander@13.1.0: {} commander@13.1.0: {}
@@ -15097,6 +15333,40 @@ snapshots:
cssesc@3.0.0: {} cssesc@3.0.0: {}
cssnano-preset-default@7.0.10(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
css-declaration-sorter: 7.2.0(postcss@8.5.3)
cssnano-utils: 5.0.1(postcss@8.5.3)
postcss: 8.5.3
postcss-calc: 10.1.1(postcss@8.5.3)
postcss-colormin: 7.0.5(postcss@8.5.3)
postcss-convert-values: 7.0.8(postcss@8.5.3)
postcss-discard-comments: 7.0.5(postcss@8.5.3)
postcss-discard-duplicates: 7.0.2(postcss@8.5.3)
postcss-discard-empty: 7.0.1(postcss@8.5.3)
postcss-discard-overridden: 7.0.1(postcss@8.5.3)
postcss-merge-longhand: 7.0.5(postcss@8.5.3)
postcss-merge-rules: 7.0.7(postcss@8.5.3)
postcss-minify-font-values: 7.0.1(postcss@8.5.3)
postcss-minify-gradients: 7.0.1(postcss@8.5.3)
postcss-minify-params: 7.0.5(postcss@8.5.3)
postcss-minify-selectors: 7.0.5(postcss@8.5.3)
postcss-normalize-charset: 7.0.1(postcss@8.5.3)
postcss-normalize-display-values: 7.0.1(postcss@8.5.3)
postcss-normalize-positions: 7.0.1(postcss@8.5.3)
postcss-normalize-repeat-style: 7.0.1(postcss@8.5.3)
postcss-normalize-string: 7.0.1(postcss@8.5.3)
postcss-normalize-timing-functions: 7.0.1(postcss@8.5.3)
postcss-normalize-unicode: 7.0.5(postcss@8.5.3)
postcss-normalize-url: 7.0.1(postcss@8.5.3)
postcss-normalize-whitespace: 7.0.1(postcss@8.5.3)
postcss-ordered-values: 7.0.2(postcss@8.5.3)
postcss-reduce-initial: 7.0.5(postcss@8.5.3)
postcss-reduce-transforms: 7.0.1(postcss@8.5.3)
postcss-svgo: 7.1.0(postcss@8.5.3)
postcss-unique-selectors: 7.0.4(postcss@8.5.3)
cssnano-preset-default@7.0.6(postcss@8.5.3): cssnano-preset-default@7.0.6(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
@@ -15135,12 +15405,22 @@ snapshots:
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
cssnano-utils@5.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
cssnano@7.0.6(postcss@8.5.3): cssnano@7.0.6(postcss@8.5.3):
dependencies: dependencies:
cssnano-preset-default: 7.0.6(postcss@8.5.3) cssnano-preset-default: 7.0.6(postcss@8.5.3)
lilconfig: 3.1.3 lilconfig: 3.1.3
postcss: 8.5.3 postcss: 8.5.3
cssnano@7.1.2(postcss@8.5.3):
dependencies:
cssnano-preset-default: 7.0.10(postcss@8.5.3)
lilconfig: 3.1.3
postcss: 8.5.3
csso@5.0.5: csso@5.0.5:
dependencies: dependencies:
css-tree: 2.2.1 css-tree: 2.2.1
@@ -15408,6 +15688,8 @@ snapshots:
electron-to-chromium@1.5.113: {} electron-to-chromium@1.5.113: {}
electron-to-chromium@1.5.267: {}
emoji-regex-xs@1.0.0: {} emoji-regex-xs@1.0.0: {}
emoji-regex@10.4.0: {} emoji-regex@10.4.0: {}
@@ -17396,7 +17678,7 @@ snapshots:
dependencies: dependencies:
autoprefixer: 10.4.21(postcss@8.5.3) autoprefixer: 10.4.21(postcss@8.5.3)
citty: 0.1.6 citty: 0.1.6
cssnano: 7.0.6(postcss@8.5.3) cssnano: 7.1.2(postcss@8.5.3)
defu: 6.1.4 defu: 6.1.4
esbuild: 0.24.0 esbuild: 0.24.0
jiti: 1.21.7 jiti: 1.21.7
@@ -17594,6 +17876,8 @@ snapshots:
node-releases@2.0.19: {} node-releases@2.0.19: {}
node-releases@2.0.27: {}
nopt@7.2.1: nopt@7.2.1:
dependencies: dependencies:
abbrev: 2.0.0 abbrev: 2.0.0
@@ -18001,12 +18285,26 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-colormin@7.0.5(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
caniuse-api: 3.0.0
colord: 2.9.3
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-convert-values@7.0.4(postcss@8.5.3): postcss-convert-values@7.0.4(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-convert-values@7.0.8(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-custom-media@11.0.5(postcss@8.5.3): postcss-custom-media@11.0.5(postcss@8.5.3):
dependencies: dependencies:
'@csstools/cascade-layer-name-parser': 2.0.4(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) '@csstools/cascade-layer-name-parser': 2.0.4(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
@@ -18042,18 +18340,35 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
postcss-discard-comments@7.0.5(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-selector-parser: 7.1.0
postcss-discard-duplicates@7.0.1(postcss@8.5.3): postcss-discard-duplicates@7.0.1(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-discard-duplicates@7.0.2(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-discard-empty@7.0.0(postcss@8.5.3): postcss-discard-empty@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-discard-empty@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-discard-overridden@7.0.0(postcss@8.5.3): postcss-discard-overridden@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-discard-overridden@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-double-position-gradients@6.0.0(postcss@8.5.3): postcss-double-position-gradients@6.0.0(postcss@8.5.3):
dependencies: dependencies:
'@csstools/postcss-progressive-custom-properties': 4.0.0(postcss@8.5.3) '@csstools/postcss-progressive-custom-properties': 4.0.0(postcss@8.5.3)
@@ -18140,6 +18455,12 @@ snapshots:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
stylehacks: 7.0.4(postcss@8.5.3) stylehacks: 7.0.4(postcss@8.5.3)
postcss-merge-longhand@7.0.5(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
stylehacks: 7.0.7(postcss@8.5.3)
postcss-merge-rules@7.0.4(postcss@8.5.3): postcss-merge-rules@7.0.4(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
@@ -18148,11 +18469,24 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
postcss-merge-rules@7.0.7(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
caniuse-api: 3.0.0
cssnano-utils: 5.0.1(postcss@8.5.3)
postcss: 8.5.3
postcss-selector-parser: 7.1.0
postcss-minify-font-values@7.0.0(postcss@8.5.3): postcss-minify-font-values@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-minify-font-values@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-minify-gradients@7.0.0(postcss@8.5.3): postcss-minify-gradients@7.0.0(postcss@8.5.3):
dependencies: dependencies:
colord: 2.9.3 colord: 2.9.3
@@ -18160,6 +18494,13 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-minify-gradients@7.0.1(postcss@8.5.3):
dependencies:
colord: 2.9.3
cssnano-utils: 5.0.1(postcss@8.5.3)
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-minify-params@7.0.2(postcss@8.5.3): postcss-minify-params@7.0.2(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
@@ -18167,12 +18508,25 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-minify-params@7.0.5(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
cssnano-utils: 5.0.1(postcss@8.5.3)
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-minify-selectors@7.0.4(postcss@8.5.3): postcss-minify-selectors@7.0.4(postcss@8.5.3):
dependencies: dependencies:
cssesc: 3.0.0 cssesc: 3.0.0
postcss: 8.5.3 postcss: 8.5.3
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
postcss-minify-selectors@7.0.5(postcss@8.5.3):
dependencies:
cssesc: 3.0.0
postcss: 8.5.3
postcss-selector-parser: 7.1.0
postcss-nested@5.0.6(postcss@8.5.3): postcss-nested@5.0.6(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
@@ -18199,47 +18553,92 @@ snapshots:
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-normalize-charset@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-normalize-display-values@7.0.0(postcss@8.5.3): postcss-normalize-display-values@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-display-values@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-positions@7.0.0(postcss@8.5.3): postcss-normalize-positions@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-positions@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-repeat-style@7.0.0(postcss@8.5.3): postcss-normalize-repeat-style@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-repeat-style@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-string@7.0.0(postcss@8.5.3): postcss-normalize-string@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-string@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-timing-functions@7.0.0(postcss@8.5.3): postcss-normalize-timing-functions@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-timing-functions@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-unicode@7.0.2(postcss@8.5.3): postcss-normalize-unicode@7.0.2(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-unicode@7.0.5(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-url@7.0.0(postcss@8.5.3): postcss-normalize-url@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-url@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-normalize-whitespace@7.0.0(postcss@8.5.3): postcss-normalize-whitespace@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-normalize-whitespace@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-opacity-percentage@3.0.0(postcss@8.5.3): postcss-opacity-percentage@3.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
@@ -18250,6 +18649,12 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-ordered-values@7.0.2(postcss@8.5.3):
dependencies:
cssnano-utils: 5.0.1(postcss@8.5.3)
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-overflow-shorthand@6.0.0(postcss@8.5.3): postcss-overflow-shorthand@6.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
@@ -18342,11 +18747,22 @@ snapshots:
caniuse-api: 3.0.0 caniuse-api: 3.0.0
postcss: 8.5.3 postcss: 8.5.3
postcss-reduce-initial@7.0.5(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
caniuse-api: 3.0.0
postcss: 8.5.3
postcss-reduce-transforms@7.0.0(postcss@8.5.3): postcss-reduce-transforms@7.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
postcss-reduce-transforms@7.0.1(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
postcss-replace-overflow-wrap@4.0.0(postcss@8.5.3): postcss-replace-overflow-wrap@4.0.0(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
@@ -18395,11 +18811,22 @@ snapshots:
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
svgo: 3.3.2 svgo: 3.3.2
postcss-svgo@7.1.0(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
svgo: 4.0.0
postcss-unique-selectors@7.0.3(postcss@8.5.3): postcss-unique-selectors@7.0.3(postcss@8.5.3):
dependencies: dependencies:
postcss: 8.5.3 postcss: 8.5.3
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
postcss-unique-selectors@7.0.4(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-selector-parser: 7.1.0
postcss-value-parser@4.2.0: {} postcss-value-parser@4.2.0: {}
postcss@8.5.3: postcss@8.5.3:
@@ -18838,8 +19265,7 @@ snapshots:
optionalDependencies: optionalDependencies:
'@parcel/watcher': 2.5.1 '@parcel/watcher': 2.5.1
sax@1.4.1: sax@1.4.1: {}
optional: true
scroll-into-view-if-needed@2.2.31: scroll-into-view-if-needed@2.2.31:
dependencies: dependencies:
@@ -19254,6 +19680,12 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
stylehacks@7.0.7(postcss@8.5.3):
dependencies:
browserslist: 4.28.1
postcss: 8.5.3
postcss-selector-parser: 7.1.0
stylelint-config-html@1.1.0(postcss-html@1.8.0)(stylelint@16.18.0(typescript@5.8.3)): stylelint-config-html@1.1.0(postcss-html@1.8.0)(stylelint@16.18.0(typescript@5.8.3)):
dependencies: dependencies:
postcss-html: 1.8.0 postcss-html: 1.8.0
@@ -19407,6 +19839,16 @@ snapshots:
csso: 5.0.5 csso: 5.0.5
picocolors: 1.1.1 picocolors: 1.1.1
svgo@4.0.0:
dependencies:
commander: 11.1.0
css-select: 5.1.0
css-tree: 3.1.0
css-what: 6.1.0
csso: 5.0.5
picocolors: 1.1.1
sax: 1.4.1
synckit@0.11.3: synckit@0.11.3:
dependencies: dependencies:
'@pkgr/core': 0.2.1 '@pkgr/core': 0.2.1
@@ -19888,6 +20330,12 @@ snapshots:
escalade: 3.2.0 escalade: 3.2.0
picocolors: 1.1.1 picocolors: 1.1.1
update-browserslist-db@1.2.3(browserslist@4.28.1):
dependencies:
browserslist: 4.28.1
escalade: 3.2.0
picocolors: 1.1.1
update-notifier@7.3.1: update-notifier@7.3.1:
dependencies: dependencies:
boxen: 8.0.1 boxen: 8.0.1