This commit is contained in:
@@ -7,9 +7,9 @@
|
||||
"apiKey": "sk-ZBGcMXCdwtSK7G35s"
|
||||
}
|
||||
},
|
||||
"google": {
|
||||
"minimax": {
|
||||
"options": {
|
||||
"baseURL": "http://45.155.220.179:8317/v1beta",
|
||||
"baseURL": "http://45.155.220.179:8317/v1",
|
||||
"apiKey": "sk-ZBGcMXCdwtSK7G35s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,12 @@
|
||||
### 1. 套餐管理模块 (Package Management) ✅
|
||||
|
||||
- [x] **套餐系列页面** (`/package-management/package-series`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增套餐系列"按钮添加 `v-permission="'package_series:add'"`
|
||||
- ✅ 为状态切换添加 `disabled: !hasAuth('package_series:update_status')`
|
||||
- ✅ 在操作列中使用 `hasAuth()` 判断编辑权限 (`package_series:edit`)和删除权限 (`package_series:delete`)
|
||||
|
||||
- [x] **套餐列表页面** (`/package-management/package-list`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增套餐"按钮添加 `v-permission="'package:add'"`
|
||||
- ✅ 为上/下架切换添加 `disabled: !hasAuth('package:update_away')`
|
||||
@@ -24,7 +22,6 @@
|
||||
- ✅ 在操作列中使用 `hasAuth()` 判断编辑 (`package:edit`) 和删除 (`package:delete`) 权限
|
||||
|
||||
- [x] **单套餐分配页面** (`/package-management/package-assign`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增分配"按钮添加 `v-permission="'package_assign:add'"`
|
||||
- ✅ 为状态切换添加 `disabled: !hasAuth('package_assign:update_status')`
|
||||
@@ -53,7 +50,6 @@
|
||||
### 3. 账号管理模块 (Account Management) ✅
|
||||
|
||||
- [x] **账号列表页面** (`/account-management/account`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增账号"按钮添加 `v-permission="'account:add'"`
|
||||
- ✅ 在操作列中使用 `hasAuth()` 判断以下权限:
|
||||
@@ -61,11 +57,9 @@
|
||||
- 编辑: `account:edit`
|
||||
- 删除: `account:delete`
|
||||
|
||||
|
||||
### 4. 资产管理模块 (Asset Management) ✅
|
||||
|
||||
- [x] **IoT卡管理页面** (`/asset-management/iot-card-management`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为表格头部操作按钮添加权限控制:
|
||||
- 批量分配: `v-permission="'iot_card:batch_allocation'"`
|
||||
@@ -79,19 +73,16 @@
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **IoT卡任务页面** (`/asset-management/iot-card-task`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"批量导入IoT卡"按钮添加 `v-permission="''"`
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **设备任务页面** (`/asset-management/device-task`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"批量导入设备"按钮添加 `v-permission="'device_task:bulk_import'"`
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **设备管理页面** (`/asset-management/device-list`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为表格头部操作按钮添加权限控制:
|
||||
- 批量分配: `v-permission="'devices:batch_allocation'"`
|
||||
@@ -110,7 +101,6 @@
|
||||
### 5. 账户管理模块 (Account Module) ✅
|
||||
|
||||
- [x] **企业客户页面** (`/account/enterprise-customer`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增企业客户"按钮添加 `v-permission="'enterprise_customer:add'"`
|
||||
- ✅ 在操作列中使用 `hasAuth()` 判断以下权限:
|
||||
@@ -121,7 +111,6 @@
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **运营商管理页面** (`/account/carrier-management`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增运营商"按钮添加 `v-permission="'carrier:add'"`
|
||||
- ✅ 为状态切换添加 `disabled: !hasAuth('carrier:update_status')`
|
||||
@@ -129,24 +118,21 @@
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **订单管理页面** (`/account/orders`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"创建订单"按钮添加 `v-permission="'orders:add'"`
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **提现配置页面** (`/account/commission/withdrawal-settings`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"新增配置"按钮添加 `v-permission="'withdrawal_settings:add'"`
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **我的佣金页面** (`/account/commission/my-commission`)
|
||||
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 为"发起提现"按钮添加 `v-permission="'my_commission:add'"`
|
||||
- ✅ 验证权限控制正确工作
|
||||
|
||||
- [x] **代理商佣金管理页面** (`/account/commission/agent-commission`)
|
||||
- [x] **代理商资金概况页面** (`/account/commission/agent-fund-overview`)
|
||||
- ✅ 引入 `useAuth` composable
|
||||
- ✅ 在操作列中使用 `hasAuth()` 判断查看详情权限 (`agent_commission:detail`)
|
||||
- ✅ 验证权限控制正确工作
|
||||
@@ -162,7 +148,6 @@
|
||||
### 7. 测试与文档
|
||||
|
||||
- [ ] **权限控制测试**
|
||||
|
||||
- 创建不同权限组合的测试用户
|
||||
- 验证每个页面的按钮显示/隐藏符合预期
|
||||
- 验证状态切换的启用/禁用符合预期
|
||||
|
||||
@@ -93,10 +93,10 @@ export class CommissionService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
// ==================== 代理商佣金管理 ====================
|
||||
// ==================== 代理商资金概况 ====================
|
||||
|
||||
/**
|
||||
* 获取代理商佣金明细
|
||||
* 获取代理商资金明细
|
||||
* GET /api/admin/shops/{shop_id}/commission-records
|
||||
*/
|
||||
static getShopCommissionRecords(
|
||||
@@ -137,7 +137,7 @@ export class CommissionService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代理商佣金统计
|
||||
* 获取代理商资金统计
|
||||
* GET /api/admin/shops/{shop_id}/commission-stats
|
||||
*/
|
||||
static getShopCommissionStats(
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
try {
|
||||
const params: any = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
page_size: pagination.pageSize,
|
||||
username: searchForm.username || undefined,
|
||||
phone: searchForm.phone || undefined,
|
||||
user_type: searchForm.user_type,
|
||||
|
||||
@@ -58,9 +58,15 @@ export const WithdrawalMethodMap = {
|
||||
bank: { label: '银行卡', icon: 'bank' }
|
||||
}
|
||||
|
||||
// ========== 佣金类型映射 ==========
|
||||
// ========== 佣金来源映射 ==========
|
||||
|
||||
// 佣金类型映射 (one_time:一次性佣金, long_term:长期佣金)
|
||||
// 佣金来源映射 (cost_diff:成本差价, one_time:一次性佣金)
|
||||
export const CommissionSourceMap = {
|
||||
cost_diff: { label: '成本差价', type: 'primary' as const },
|
||||
one_time: { label: '一次性佣金', type: 'success' as const }
|
||||
}
|
||||
|
||||
// 佣金类型映射 (one_time:一次性佣金, long_term:长期佣金) - 兼容旧字段
|
||||
export const CommissionTypeMap = {
|
||||
one_time: { label: '一次性佣金', type: 'primary' as const },
|
||||
long_term: { label: '长期佣金', type: 'success' as const }
|
||||
|
||||
@@ -395,14 +395,14 @@
|
||||
"commission": {
|
||||
"title": "佣金管理",
|
||||
"withdrawal": "提现审批",
|
||||
"withdrawalSettings": "提现配置",
|
||||
"myCommission": "我的佣金",
|
||||
"agentCommission": "代理商佣金"
|
||||
"agentCommission": "代理商资金概况"
|
||||
},
|
||||
"settings": {
|
||||
"title": "设置管理",
|
||||
"wechatPayConfiguration": "微信支付配置",
|
||||
"detailsOfPaymentConfiguration": "支付配置详情"
|
||||
"detailsOfPaymentConfiguration": "支付配置详情",
|
||||
"withdrawalSettings": "提现配置"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
|
||||
@@ -543,17 +543,6 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
roles: ['R_SUPER', 'R_ADMIN']
|
||||
}
|
||||
},
|
||||
// 提现配置
|
||||
{
|
||||
path: 'withdrawal-settings',
|
||||
name: 'CommissionWithdrawalSettings',
|
||||
component: RoutesAlias.CommissionWithdrawalSettings,
|
||||
meta: {
|
||||
title: 'menus.commission.withdrawalSettings',
|
||||
keepAlive: true,
|
||||
roles: ['R_SUPER', 'R_ADMIN']
|
||||
}
|
||||
},
|
||||
// 我的佣金
|
||||
{
|
||||
path: 'my-commission',
|
||||
@@ -565,11 +554,11 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
roles: ['R_AGENT']
|
||||
}
|
||||
},
|
||||
// 代理商佣金
|
||||
// 代理商资金概况
|
||||
{
|
||||
path: 'agent-commission',
|
||||
name: 'AgentCommission',
|
||||
component: RoutesAlias.AgentCommission,
|
||||
path: 'agent-fund-overview',
|
||||
name: 'AgentFundOverview',
|
||||
component: RoutesAlias.AgentFundOverview,
|
||||
meta: {
|
||||
title: 'menus.commission.agentCommission',
|
||||
keepAlive: true,
|
||||
@@ -599,6 +588,17 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
// 提现配置
|
||||
{
|
||||
path: 'withdrawal-settings',
|
||||
name: 'WithdrawalSettings',
|
||||
component: RoutesAlias.WithdrawalSettings,
|
||||
meta: {
|
||||
title: 'menus.settings.withdrawalSettings',
|
||||
keepAlive: true,
|
||||
roles: ['R_SUPER', 'R_ADMIN']
|
||||
}
|
||||
},
|
||||
// 微信支付配置详情
|
||||
{
|
||||
path: 'wechat-config/detail/:id',
|
||||
|
||||
@@ -72,11 +72,11 @@ export enum RoutesAlias {
|
||||
|
||||
// 佣金管理
|
||||
WithdrawalApproval = '/commission-management/withdrawal-approval', // 提现审批
|
||||
CommissionWithdrawalSettings = '/commission-management/withdrawal-settings', // 提现配置
|
||||
MyCommission = '/commission-management/my-commission', // 我的佣金
|
||||
AgentCommission = '/commission-management/agent-commission', // 代理商佣金管理
|
||||
AgentFundOverview = '/commission-management/agent-fund-overview', // 代理商资金概况
|
||||
|
||||
// 设置管理
|
||||
WithdrawalSettings = '/settings/withdrawal-settings', // 提现配置
|
||||
WechatConfig = '/settings/wechat-config', // 微信支付配置
|
||||
WechatConfigDetail = '/settings/wechat-config/detail', // 微信支付配置详情
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ export interface WithdrawalRequestItem {
|
||||
account_number: string // 收款账号
|
||||
bank_name?: string // 银行名称
|
||||
status: WithdrawalStatus // 状态
|
||||
status_name: string // 状态名称
|
||||
payment_type: PaymentType // 放款类型
|
||||
applicant_id: number // 申请人账号ID
|
||||
applicant_name: string // 申请人用户名
|
||||
@@ -68,12 +69,14 @@ export interface WithdrawalRequestItem {
|
||||
remark?: string // 备注
|
||||
created_at: string // 申请时间
|
||||
processed_at?: string // 处理时间
|
||||
paid_at?: string // 到账时间
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现申请查询参数
|
||||
*/
|
||||
export interface WithdrawalRequestQueryParams extends PaginationParams {
|
||||
page_size?: number // 每页数量
|
||||
status?: WithdrawalStatus // 状态筛选
|
||||
withdrawal_no?: string // 提现单号
|
||||
shop_name?: string // 店铺名称
|
||||
@@ -141,10 +144,14 @@ export interface MyCommissionRecordItem {
|
||||
* 佣金记录查询参数
|
||||
*/
|
||||
export interface CommissionRecordQueryParams extends PaginationParams {
|
||||
commission_type?: CommissionType // 佣金类型
|
||||
status?: CommissionStatus // 状态
|
||||
page_size?: number // 每页数量
|
||||
commission_source?: string // 佣金来源(cost_diff:成本差价,one_time:一次性佣金)
|
||||
status?: number // 状态(1已入账,2已失效)
|
||||
start_time?: string // 开始时间
|
||||
end_time?: string // 结束时间
|
||||
iccid?: string // ICCID(模糊查询)
|
||||
virtual_no?: string // 设备虚拟号(模糊查询)
|
||||
order_no?: string // 订单号(模糊查询)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,23 +178,26 @@ export interface SubmitWithdrawalParams {
|
||||
remark?: string // 备注
|
||||
}
|
||||
|
||||
// ==================== 代理商佣金相关 ====================
|
||||
// ==================== 代理商资金概况相关 ====================
|
||||
|
||||
/**
|
||||
* 代理商佣金记录项
|
||||
* 代理商资金记录项
|
||||
*/
|
||||
export interface ShopCommissionRecordItem {
|
||||
id: number // 佣金记录ID
|
||||
amount: number // 佣金金额(分)
|
||||
balance_after: number // 入账后佣金余额(分)
|
||||
commission_type: CommissionType // 佣金类型
|
||||
status: CommissionStatus // 状态
|
||||
commission_source: string // 佣金来源(cost_diff:成本差价,one_time:一次性佣金)
|
||||
status: number // 状态(1已冻结, 2解冻中, 3已发放, 4已失效)
|
||||
status_name: string // 状态名称
|
||||
order_id?: number // 订单ID
|
||||
order_no?: string // 订单号
|
||||
order_created_at?: string // 订单创建时间
|
||||
iccid?: string // ICCID
|
||||
virtual_no?: string // 虚拟号(原 device_no)
|
||||
created_at: string // 佣金入账时间
|
||||
seller_shop_id?: number // 卖家店铺ID
|
||||
seller_shop_name?: string // 卖家店铺名称
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,7 +324,7 @@ export interface MainWalletTransactionPageResult {
|
||||
// ==================== 我的佣金统计相关 ====================
|
||||
|
||||
/**
|
||||
* 代理商佣金统计查询参数(shop_id 通过路径参数传递,不再在 query 中)
|
||||
* 代理商资金统计查询参数(shop_id 通过路径参数传递,不再在 query 中)
|
||||
*/
|
||||
export interface ShopCommissionStatsQueryParams {
|
||||
start_time?: string // 开始时间
|
||||
@@ -327,7 +337,7 @@ export interface ShopCommissionStatsQueryParams {
|
||||
export type MyCommissionStatsQueryParams = ShopCommissionStatsQueryParams
|
||||
|
||||
/**
|
||||
* 代理商佣金统计响应
|
||||
* 代理商资金统计响应
|
||||
*/
|
||||
export interface CommissionStatsResponse {
|
||||
total_amount: number // 总收入(分)
|
||||
@@ -346,7 +356,7 @@ export interface CommissionStatsResponse {
|
||||
export type MyCommissionStatsResponse = CommissionStatsResponse
|
||||
|
||||
/**
|
||||
* 代理商每日佣金统计查询参数(shop_id 通过路径参数传递)
|
||||
* 代理商每日资金统计查询参数(shop_id 通过路径参数传递)
|
||||
*/
|
||||
export interface DailyCommissionStatsQueryParams {
|
||||
start_date?: string // 开始日期(YYYY-MM-DD)
|
||||
@@ -360,7 +370,7 @@ export interface DailyCommissionStatsQueryParams {
|
||||
export type MyDailyCommissionStatsQueryParams = DailyCommissionStatsQueryParams
|
||||
|
||||
/**
|
||||
* 每日佣金统计项
|
||||
* 每日资金统计项
|
||||
*/
|
||||
export interface DailyCommissionStatsItem {
|
||||
date: string // 日期(YYYY-MM-DD)
|
||||
|
||||
@@ -12,10 +12,6 @@ export interface BaseResponse<T = any> {
|
||||
|
||||
// 分页请求参数
|
||||
export interface PaginationParams {
|
||||
current?: number
|
||||
size?: number
|
||||
pageNum?: number
|
||||
pageSize?: number
|
||||
page?: number
|
||||
page_size?: number
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface OrderItem {
|
||||
quantity: number
|
||||
unit_price: number // 单价(分)
|
||||
amount: number // 小计金额(分)
|
||||
package_type?: string // 套餐类型快照:formal(正式套餐)或 addon(加油包)
|
||||
}
|
||||
|
||||
// 订单响应
|
||||
@@ -43,6 +44,8 @@ export interface Order {
|
||||
order_type: OrderType
|
||||
buyer_id: number
|
||||
buyer_type: BuyerType
|
||||
buyer_phone?: string // 买家手机号快照(个人客户下单时填充,代理商订单为空)
|
||||
buyer_nickname?: string // 买家微信昵称快照(个人客户下单时填充,代理商订单为空)
|
||||
payment_status: PaymentStatus
|
||||
payment_status_text: string
|
||||
payment_method: OrderPaymentMethod
|
||||
@@ -72,6 +75,7 @@ export interface OrderQueryParams {
|
||||
order_no?: string
|
||||
identifier?: string // 按资产标识符过滤
|
||||
purchase_role?: string // 订单渠道
|
||||
buyer_phone?: string // 按买家手机号精确过滤
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
dateRange?: string[] | any // For date range picker in UI
|
||||
|
||||
@@ -130,7 +130,8 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ElRadioGroup v-model="roleToAdd" class="role-list">
|
||||
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
||||
<ElRadioGroup v-else v-model="roleToAdd" class="role-list">
|
||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
||||
<ElRadio :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
||||
<span class="role-info">
|
||||
@@ -204,7 +205,7 @@
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { FormInstance, ElSwitch, ElCheckbox, ElCheckboxGroup, ElTag } from 'element-plus'
|
||||
import { FormInstance, ElSwitch, ElCheckbox, ElCheckboxGroup, ElTag, ElEmpty } from 'element-plus'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
@@ -551,7 +552,6 @@
|
||||
}
|
||||
|
||||
getAccountList()
|
||||
loadAllRoles()
|
||||
loadShopList()
|
||||
loadEnterpriseList()
|
||||
})
|
||||
@@ -561,7 +561,7 @@
|
||||
try {
|
||||
const params: any = {
|
||||
page: 1,
|
||||
pageSize: keyword ? 100 : 20 // 搜索时加载更多,默认20条
|
||||
page_size: keyword ? 100 : 20 // 搜索时加载更多,默认20条
|
||||
}
|
||||
if (keyword) {
|
||||
params.role_name = keyword
|
||||
@@ -713,8 +713,8 @@
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
username: formFilters.name || undefined,
|
||||
phone: formFilters.phone || undefined,
|
||||
user_type: formFilters.user_type,
|
||||
|
||||
@@ -216,6 +216,12 @@
|
||||
// fetchAssetDetail 内部已经会并行加载所有相关数据,不需要重复调用
|
||||
await fetchAssetDetail(identifier)
|
||||
|
||||
// 如果是设备类型,需要再次调用搜索接口获取完整数据
|
||||
if (cardInfo.value?.asset_type === 'device') {
|
||||
const deviceIdentifier = cardInfo.value.virtual_no || cardInfo.value.iccid || identifier
|
||||
await fetchAssetDetail(deviceIdentifier)
|
||||
}
|
||||
|
||||
// 从接口数据初始化轮询开关,不触发更新接口
|
||||
pollingInitializing = true
|
||||
pollingEnabled.value = cardInfo.value?.enable_polling ?? false
|
||||
@@ -224,7 +230,7 @@
|
||||
|
||||
// 重置分页并加载套餐列表
|
||||
packagePagination.value.page = 1
|
||||
const result = await loadPackageList(identifier, 1, packagePagination.value.pageSize)
|
||||
const result = await loadPackageList(identifier, 1, packagePagination.pageSize)
|
||||
packagePagination.value.total = result.total
|
||||
}
|
||||
|
||||
|
||||
@@ -671,6 +671,7 @@
|
||||
virtual_no: string
|
||||
device_virtual_no: string
|
||||
is_distributed: undefined | number
|
||||
is_standalone: undefined | boolean
|
||||
[key: string]: any
|
||||
} = {
|
||||
status: undefined,
|
||||
@@ -679,7 +680,8 @@
|
||||
msisdn: '',
|
||||
virtual_no: '',
|
||||
device_virtual_no: '',
|
||||
is_distributed: undefined
|
||||
is_distributed: undefined,
|
||||
is_standalone: undefined
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
@@ -858,6 +860,19 @@
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '独立卡',
|
||||
prop: 'is_standalone',
|
||||
type: 'select',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '全部'
|
||||
},
|
||||
options: () => [
|
||||
{ label: '是(未绑定设备)', value: true },
|
||||
{ label: '否(已绑定设备)', value: false }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -95,22 +95,24 @@
|
||||
{{ formatMoney(scope.row.balance_after) }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金类型" prop="commission_type" width="120">
|
||||
<ElTableColumn label="佣金来源" prop="commission_source" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag
|
||||
:type="
|
||||
CommissionTypeMap[scope.row.commission_type as keyof typeof CommissionTypeMap]
|
||||
?.type || 'info'
|
||||
CommissionSourceMap[
|
||||
scope.row.commission_source as keyof typeof CommissionSourceMap
|
||||
]?.type || 'info'
|
||||
"
|
||||
>
|
||||
{{
|
||||
CommissionTypeMap[scope.row.commission_type as keyof typeof CommissionTypeMap]
|
||||
?.label || scope.row.commission_type
|
||||
CommissionSourceMap[
|
||||
scope.row.commission_source as keyof typeof CommissionSourceMap
|
||||
]?.label || scope.row.commission_source
|
||||
}}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<ElTableColumn label="状态" prop="status_name" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag
|
||||
:type="
|
||||
@@ -119,13 +121,18 @@
|
||||
"
|
||||
>
|
||||
{{
|
||||
CommissionStatusMap[scope.row.status as keyof typeof CommissionStatusMap]
|
||||
?.label || scope.row.status
|
||||
scope.row.status_name || CommissionStatusMap[scope.row.status]?.label || '-'
|
||||
}}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="订单号" prop="order_no" min-width="180" show-overflow-tooltip />
|
||||
<ElTableColumn
|
||||
label="卖家店铺"
|
||||
prop="seller_shop_name"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<ElTableColumn label="ICCID" prop="iccid" min-width="150" show-overflow-tooltip />
|
||||
<ElTableColumn
|
||||
label="设备号"
|
||||
@@ -369,7 +376,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h, watch, onBeforeUnmount } from 'vue'
|
||||
import { h, watch, onBeforeUnmount, ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { CommissionService } from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
|
||||
@@ -389,7 +396,7 @@
|
||||
CommissionStatusMap,
|
||||
WithdrawalStatusMap,
|
||||
WithdrawalMethodMap,
|
||||
CommissionTypeMap
|
||||
CommissionSourceMap
|
||||
} from '@/config/constants/commission'
|
||||
|
||||
defineOptions({ name: 'AgentCommission' })
|
||||
@@ -605,13 +612,13 @@
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 获取代理商佣金汇总列表
|
||||
// 获取代理商资金汇总列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
page_size: pagination.pageSize,
|
||||
shop_name: searchForm.shop_name || undefined,
|
||||
shop_code: searchForm.shop_code || undefined
|
||||
}
|
||||
@@ -724,7 +731,7 @@
|
||||
try {
|
||||
const params = {
|
||||
page: commissionPagination.page,
|
||||
pageSize: commissionPagination.pageSize
|
||||
page_size: commissionPagination.pageSize
|
||||
}
|
||||
const res = await CommissionService.getShopCommissionRecords(
|
||||
currentShop.value.shop_id,
|
||||
@@ -761,7 +768,7 @@
|
||||
try {
|
||||
const params = {
|
||||
page: withdrawalPagination.page,
|
||||
pageSize: withdrawalPagination.pageSize
|
||||
page_size: withdrawalPagination.pageSize
|
||||
}
|
||||
const res = await CommissionService.getShopWithdrawalRequests(
|
||||
currentShop.value.shop_id,
|
||||
@@ -798,7 +805,7 @@
|
||||
try {
|
||||
const params = {
|
||||
page: mainWalletPagination.page,
|
||||
pageSize: mainWalletPagination.pageSize
|
||||
page_size: mainWalletPagination.pageSize
|
||||
}
|
||||
const res = await CommissionService.getMainWalletTransactions(
|
||||
currentShop.value.shop_id,
|
||||
@@ -199,22 +199,15 @@
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
MyCommissionSummary,
|
||||
MyCommissionRecordItem,
|
||||
ShopCommissionRecordItem,
|
||||
WithdrawalRequestItem,
|
||||
CommissionRecordQueryParams,
|
||||
WithdrawalRequestQueryParams,
|
||||
SubmitWithdrawalParams,
|
||||
CommissionType,
|
||||
CommissionStatus,
|
||||
WithdrawalStatus
|
||||
} from '@/types/api/commission'
|
||||
import { WithdrawalMethod } from '@/types/api/commission'
|
||||
import {
|
||||
CommissionStatusMap,
|
||||
CommissionTypeMap,
|
||||
WithdrawalStatusMap,
|
||||
WithdrawalMethodMap
|
||||
} from '@/config/constants/commission'
|
||||
import { WithdrawalStatusMap, WithdrawalMethodMap } from '@/config/constants/commission'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
@@ -227,7 +220,7 @@
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 获取当前用户的 shop_id
|
||||
const currentShopId = computed(() => userStore.userInfo?.shop_id)
|
||||
const currentShopId = computed(() => userStore.info?.shop_id)
|
||||
|
||||
// 如果没有 shop_id,显示提示
|
||||
const hasShopId = computed(() => !!currentShopId.value)
|
||||
@@ -237,6 +230,7 @@
|
||||
|
||||
// 佣金概览
|
||||
const summary = ref<MyCommissionSummary>({
|
||||
main_balance: 0,
|
||||
total_commission: 0,
|
||||
available_commission: 0,
|
||||
frozen_commission: 0,
|
||||
@@ -251,10 +245,13 @@
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialCommissionSearchState = {
|
||||
commission_type: undefined as CommissionType | undefined,
|
||||
status: undefined as CommissionStatus | undefined,
|
||||
commission_source: undefined as string | undefined,
|
||||
status: undefined as number | undefined,
|
||||
start_time: '',
|
||||
end_time: ''
|
||||
end_time: '',
|
||||
iccid: '',
|
||||
virtual_no: '',
|
||||
order_no: ''
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
@@ -263,16 +260,16 @@
|
||||
// 搜索表单配置
|
||||
const commissionSearchItems = computed<SearchFormItem[]>(() => [
|
||||
{
|
||||
label: '佣金类型',
|
||||
prop: 'commission_type',
|
||||
label: '佣金来源',
|
||||
prop: 'commission_source',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '一次性佣金', value: 'one_time' },
|
||||
{ label: '长期佣金', value: 'long_term' }
|
||||
{ label: '成本差价', value: 'cost_diff' },
|
||||
{ label: '一次性佣金', value: 'one_time' }
|
||||
],
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请选择佣金类型'
|
||||
placeholder: '请选择佣金来源'
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -290,6 +287,33 @@
|
||||
placeholder: '请选择状态'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'ICCID',
|
||||
prop: 'iccid',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入ICCID'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '虚拟号',
|
||||
prop: 'virtual_no',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入虚拟号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '订单号',
|
||||
prop: 'order_no',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入订单号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '时间范围',
|
||||
prop: 'dateRange',
|
||||
@@ -322,64 +346,95 @@
|
||||
|
||||
// 列配置
|
||||
const commissionColumnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '佣金金额', prop: 'amount' },
|
||||
{ label: '佣金类型', prop: 'commission_type' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '订单ID', prop: 'order_id' },
|
||||
{ label: '佣金来源', prop: 'commission_source' },
|
||||
{ label: '状态', prop: 'status_name' },
|
||||
{ label: 'ICCID', prop: 'iccid' },
|
||||
{ label: '虚拟号', prop: 'virtual_no' },
|
||||
{ label: '订单号', prop: 'order_no' },
|
||||
{ label: '卖家店铺', prop: 'seller_shop_name' },
|
||||
{ label: '入账后余额', prop: 'balance_after' },
|
||||
{ label: '创建时间', prop: 'created_at' }
|
||||
]
|
||||
|
||||
const commissionList = ref<MyCommissionRecordItem[]>([])
|
||||
const commissionList = ref<ShopCommissionRecordItem[]>([])
|
||||
|
||||
// 佣金来源映射
|
||||
const CommissionSourceMap = {
|
||||
cost_diff: { label: '成本差价', type: 'primary' as const },
|
||||
one_time: { label: '一次性佣金', type: 'success' as const }
|
||||
}
|
||||
|
||||
// 状态映射
|
||||
const CommissionRecordStatusMap = {
|
||||
1: { label: '已冻结', type: 'info' as const },
|
||||
2: { label: '解冻中', type: 'warning' as const },
|
||||
3: { label: '已发放', type: 'success' as const },
|
||||
4: { label: '已失效', type: 'danger' as const }
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks: commissionColumnChecks, columns: commissionColumns } = useCheckedColumns(
|
||||
() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'amount',
|
||||
label: '佣金金额',
|
||||
width: 140,
|
||||
formatter: (row: MyCommissionRecordItem) => formatMoney(row.amount)
|
||||
width: 120,
|
||||
formatter: (row: ShopCommissionRecordItem) => formatMoney(row.amount)
|
||||
},
|
||||
{
|
||||
prop: 'commission_type',
|
||||
label: '佣金类型',
|
||||
prop: 'commission_source',
|
||||
label: '佣金来源',
|
||||
width: 120,
|
||||
formatter: (row: MyCommissionRecordItem) => {
|
||||
const config = CommissionTypeMap[row.commission_type as keyof typeof CommissionTypeMap]
|
||||
formatter: (row: ShopCommissionRecordItem) => {
|
||||
const config =
|
||||
CommissionSourceMap[row.commission_source as keyof typeof CommissionSourceMap]
|
||||
if (!config) return String(row.commission_source ?? '-')
|
||||
return h(ElTag, { type: config.type }, () => config.label)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
prop: 'status_name',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: MyCommissionRecordItem) => {
|
||||
const config = CommissionStatusMap[row.status as keyof typeof CommissionStatusMap]
|
||||
return h(ElTag, { type: config.type }, () => config.label)
|
||||
formatter: (row: ShopCommissionRecordItem) => {
|
||||
return String(row.status_name ?? '-')
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'order_id',
|
||||
label: '订单ID',
|
||||
width: 100,
|
||||
formatter: (row: MyCommissionRecordItem) => row.order_id || '-'
|
||||
prop: 'iccid',
|
||||
label: 'ICCID',
|
||||
formatter: (row: ShopCommissionRecordItem) => row.iccid || '-'
|
||||
},
|
||||
{
|
||||
prop: 'shop_id',
|
||||
label: '店铺ID',
|
||||
width: 100
|
||||
prop: 'virtual_no',
|
||||
label: '虚拟号',
|
||||
width: 130,
|
||||
formatter: (row: ShopCommissionRecordItem) => row.virtual_no || '-'
|
||||
},
|
||||
{
|
||||
prop: 'order_no',
|
||||
label: '订单号',
|
||||
width: 160,
|
||||
formatter: (row: ShopCommissionRecordItem) => row.order_no || '-'
|
||||
},
|
||||
{
|
||||
prop: 'seller_shop_name',
|
||||
label: '卖家店铺',
|
||||
width: 150,
|
||||
formatter: (row: ShopCommissionRecordItem) => row.seller_shop_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'balance_after',
|
||||
label: '入账后余额',
|
||||
width: 120,
|
||||
formatter: (row: ShopCommissionRecordItem) => formatMoney(row.balance_after)
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: MyCommissionRecordItem) => formatDateTime(row.created_at)
|
||||
formatter: (row: ShopCommissionRecordItem) => formatDateTime(row.created_at)
|
||||
}
|
||||
]
|
||||
)
|
||||
@@ -393,14 +448,17 @@
|
||||
|
||||
commissionLoading.value = true
|
||||
try {
|
||||
const params = {
|
||||
pageSize: commissionPagination.pageSize,
|
||||
current: commissionPagination.page,
|
||||
commission_type: commissionSearchForm.commission_type,
|
||||
const params: CommissionRecordQueryParams = {
|
||||
page_size: commissionPagination.pageSize,
|
||||
page: commissionPagination.page,
|
||||
commission_source: commissionSearchForm.commission_source,
|
||||
status: commissionSearchForm.status,
|
||||
start_time: commissionSearchForm.start_time || undefined,
|
||||
end_time: commissionSearchForm.end_time || undefined
|
||||
} as CommissionRecordQueryParams
|
||||
end_time: commissionSearchForm.end_time || undefined,
|
||||
iccid: commissionSearchForm.iccid || undefined,
|
||||
virtual_no: commissionSearchForm.virtual_no || undefined,
|
||||
order_no: commissionSearchForm.order_no || undefined
|
||||
}
|
||||
const res = await CommissionService.getShopCommissionRecords(currentShopId.value, params)
|
||||
if (res.code === 0) {
|
||||
commissionList.value = res.data.items || []
|
||||
@@ -512,8 +570,10 @@
|
||||
{ label: '手续费', prop: 'fee' },
|
||||
{ label: '实际到账', prop: 'actual_amount' },
|
||||
{ label: '提现方式', prop: 'withdrawal_method' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '申请时间', prop: 'created_at' }
|
||||
{ label: '状态', prop: 'status_name' },
|
||||
{ label: '拒绝原因', prop: 'reject_reason' },
|
||||
{ label: '申请时间', prop: 'created_at' },
|
||||
{ label: '到账时间', prop: 'paid_at' }
|
||||
]
|
||||
|
||||
const withdrawalList = ref<WithdrawalRequestItem[]>([])
|
||||
@@ -560,19 +620,33 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
prop: 'status_name',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: WithdrawalRequestItem) => {
|
||||
const config = WithdrawalStatusMap[row.status as keyof typeof WithdrawalStatusMap]
|
||||
return h(ElTag, { type: config.type }, () => config.label)
|
||||
const tagType = config?.type || 'info'
|
||||
const label = row.status_name || config?.label || String(row.status)
|
||||
return h(ElTag, { type: tagType }, () => label)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'reject_reason',
|
||||
label: '拒绝原因',
|
||||
minWidth: 120,
|
||||
formatter: (row: WithdrawalRequestItem) => row.reject_reason || '-'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '申请时间',
|
||||
width: 180,
|
||||
formatter: (row: WithdrawalRequestItem) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'paid_at',
|
||||
label: '到账时间',
|
||||
width: 180,
|
||||
formatter: (row: WithdrawalRequestItem) => (row.paid_at ? formatDateTime(row.paid_at) : '-')
|
||||
}
|
||||
]
|
||||
)
|
||||
@@ -586,13 +660,13 @@
|
||||
|
||||
withdrawalLoading.value = true
|
||||
try {
|
||||
const params = {
|
||||
pageSize: withdrawalPagination.pageSize,
|
||||
current: withdrawalPagination.page,
|
||||
const params: WithdrawalRequestQueryParams = {
|
||||
page_size: withdrawalPagination.pageSize,
|
||||
page: withdrawalPagination.page,
|
||||
status: withdrawalSearchForm.status,
|
||||
start_time: withdrawalSearchForm.start_time || undefined,
|
||||
end_time: withdrawalSearchForm.end_time || undefined
|
||||
} as WithdrawalRequestQueryParams
|
||||
}
|
||||
const res = await CommissionService.getShopWithdrawalRequests(currentShopId.value, params)
|
||||
if (res.code === 0) {
|
||||
withdrawalList.value = res.data.items || []
|
||||
@@ -655,7 +729,7 @@
|
||||
amount: [
|
||||
{ required: true, message: '请输入提现金额', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
validator: (_rule, value, callback) => {
|
||||
if (value < 100) {
|
||||
callback(new Error('提现金额不能小于100分(1元)'))
|
||||
} else if (value > summary.value.available_commission) {
|
||||
@@ -678,7 +752,7 @@
|
||||
],
|
||||
bank_name: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
validator: (_rule, value, callback) => {
|
||||
if (withdrawalForm.withdrawal_method === WithdrawalMethod.BANK && !value) {
|
||||
callback(new Error('请选择银行名称'))
|
||||
} else {
|
||||
@@ -740,9 +814,9 @@
|
||||
withdrawalDialogVisible.value = false
|
||||
|
||||
// 刷新数据
|
||||
loadSummary()
|
||||
await loadSummary()
|
||||
if (activeTab.value === 'withdrawal') {
|
||||
getWithdrawalList()
|
||||
await getWithdrawalList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
@@ -765,13 +839,14 @@
|
||||
// 调用 fund-summary 接口,通过 shop_id 过滤获取自己的数据
|
||||
const res = await CommissionService.getShopFundSummary({
|
||||
page: 1,
|
||||
pageSize: 1
|
||||
page_size: 1
|
||||
})
|
||||
if (res.code === 0 && res.data.items && res.data.items.length > 0) {
|
||||
// 从结果中找到当前用户的店铺数据
|
||||
const myShopData = res.data.items.find(item => item.shop_id === currentShopId.value)
|
||||
const myShopData = res.data.items.find((item) => item.shop_id === currentShopId.value)
|
||||
if (myShopData) {
|
||||
summary.value = {
|
||||
main_balance: myShopData.main_balance || 0,
|
||||
total_commission: myShopData.total_commission,
|
||||
available_commission: myShopData.available_commission,
|
||||
frozen_commission: myShopData.frozen_commission,
|
||||
@@ -803,9 +878,3 @@
|
||||
getCommissionList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-commission-page {
|
||||
// 样式已移动到分析页的佣金概览组件
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,11 +38,7 @@
|
||||
</ArtTable>
|
||||
|
||||
<!-- 拒绝提现对话框 -->
|
||||
<ElDialog
|
||||
v-model="rejectDialogVisible"
|
||||
title="拒绝提现申请"
|
||||
width="500px"
|
||||
>
|
||||
<ElDialog v-model="rejectDialogVisible" title="拒绝提现申请" width="500px">
|
||||
<ElForm ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="100px">
|
||||
<ElFormItem label="拒绝原因" prop="reject_reason">
|
||||
<ElInput
|
||||
@@ -199,12 +195,8 @@
|
||||
const rejectFormRef = ref<FormInstance>()
|
||||
|
||||
const rejectRules = reactive<FormRules>({
|
||||
reject_reason: [
|
||||
{ required: true, message: '请输入拒绝原因', trigger: 'blur' }
|
||||
],
|
||||
remark: [
|
||||
{ required: true, message: '请输入备注', trigger: 'blur' }
|
||||
]
|
||||
reject_reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }],
|
||||
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const rejectForm = reactive({
|
||||
@@ -318,7 +310,7 @@
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
page_size: pagination.pageSize,
|
||||
withdrawal_no: searchForm.withdrawal_no || undefined,
|
||||
shop_name: searchForm.shop_name || undefined,
|
||||
status: searchForm.status,
|
||||
|
||||
@@ -113,10 +113,12 @@
|
||||
clearable
|
||||
size="small"
|
||||
style="width: 180px"
|
||||
@input="handleLeftRoleSearch"
|
||||
/>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ElCheckboxGroup v-model="rolesToAdd" class="role-list">
|
||||
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
||||
<ElCheckboxGroup v-else v-model="rolesToAdd" class="role-list">
|
||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
||||
<ElCheckbox :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
||||
<span class="role-info">
|
||||
@@ -201,7 +203,8 @@
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElCheckbox,
|
||||
ElCheckboxGroup
|
||||
ElCheckboxGroup,
|
||||
ElEmpty
|
||||
} from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
@@ -407,7 +410,7 @@
|
||||
const entityId = Number(route.params.id)
|
||||
const params: any = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
page_size: pagination.pageSize,
|
||||
username: searchForm.username || undefined,
|
||||
phone: searchForm.phone || undefined,
|
||||
user_type: isShopType.value ? 3 : 4, // 根据页面类型自动设置: 3:代理账号, 4:企业账号
|
||||
@@ -553,9 +556,16 @@
|
||||
}
|
||||
|
||||
// 加载所有角色列表
|
||||
const loadAllRoles = async () => {
|
||||
const loadAllRoles = async (keyword: string = '') => {
|
||||
try {
|
||||
const res = await RoleService.getRoles({ page: 1, pageSize: 100 })
|
||||
const params: any = {
|
||||
page: 1,
|
||||
page_size: 20
|
||||
}
|
||||
if (keyword) {
|
||||
params.role_name = keyword
|
||||
}
|
||||
const res = await RoleService.getRoles(params)
|
||||
if (res.code === 0) {
|
||||
allRoles.value = res.data.items || []
|
||||
}
|
||||
@@ -564,6 +574,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 左侧角色搜索防抖
|
||||
let leftSearchTimer: ReturnType<typeof setTimeout> | null = null
|
||||
const handleLeftRoleSearch = (val: string) => {
|
||||
if (leftSearchTimer) {
|
||||
clearTimeout(leftSearchTimer)
|
||||
}
|
||||
leftSearchTimer = setTimeout(() => {
|
||||
loadAllRoles(val)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 计算属性:过滤后的可分配角色(根据账号类型过滤)
|
||||
const filteredAvailableRoles = computed(() => {
|
||||
let roles = allRoles.value
|
||||
@@ -580,10 +601,7 @@
|
||||
roles = roles.filter((role) => role.role_type === 2)
|
||||
}
|
||||
|
||||
// 根据搜索关键词过滤
|
||||
if (!leftRoleFilter.value) return roles
|
||||
const keyword = leftRoleFilter.value.toLowerCase()
|
||||
return roles.filter((role) => role.role_name.toLowerCase().includes(keyword))
|
||||
return roles
|
||||
})
|
||||
|
||||
// 计算属性:过滤后的已分配角色
|
||||
@@ -675,7 +693,6 @@
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
loadAllRoles()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
<template>
|
||||
<div class="analysis-dashboard">
|
||||
<!-- 轮询统计 -->
|
||||
<div class="section-title">轮询统计</div>
|
||||
<PollingStats />
|
||||
|
||||
<!-- 佣金概览 -->
|
||||
<div class="section-title">佣金概览</div>
|
||||
<CommissionSummary />
|
||||
|
||||
<!-- 提现配置 -->
|
||||
<div class="section-title">提现配置</div>
|
||||
<CommissionStats />
|
||||
<WithdrawalSettings />
|
||||
|
||||
<!-- 支付配置 -->
|
||||
<div class="section-title">支付配置</div>
|
||||
<ActiveWechatConfig />
|
||||
|
||||
<!--<el-row :gutter="20">-->
|
||||
@@ -52,16 +42,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TodaySales from './widget/TodaySales.vue'
|
||||
import VisitorInsights from './widget/VisitorInsights.vue'
|
||||
import TotalRevenue from './widget/TotalRevenue.vue'
|
||||
import CustomerSatisfaction from './widget/CustomerSatisfaction.vue'
|
||||
import TargetVsReality from './widget/TargetVsReality.vue'
|
||||
import TopProducts from './widget/TopProducts.vue'
|
||||
import SalesMappingByCountry from './widget/SalesMappingByCountry.vue'
|
||||
import VolumeServiceLevel from './widget/VolumeServiceLevel.vue'
|
||||
import PollingStats from './widget/PollingStats.vue'
|
||||
import CommissionSummary from './widget/CommissionSummary.vue'
|
||||
import CommissionStats from './widget/CommissionStats.vue'
|
||||
import WithdrawalSettings from './widget/WithdrawalSettings.vue'
|
||||
import ActiveWechatConfig from './widget/ActiveWechatConfig.vue'
|
||||
|
||||
@@ -71,15 +54,9 @@
|
||||
<style lang="scss" scoped>
|
||||
@use './style';
|
||||
|
||||
.section-title {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.analysis-dashboard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<ElCard shadow="never" class="active-wechat-config-widget" v-if="activeConfig">
|
||||
<ElCard shadow="never" class="active-wechat-config-widget">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<span class="header-title">当前生效支付配置</span>
|
||||
<ElTag type="success" effect="dark" size="small">生效中</ElTag>
|
||||
<ElTag v-if="activeConfig" type="success" effect="dark" size="small">生效中</ElTag>
|
||||
<ElTag v-else type="info" effect="plain" size="small">未配置</ElTag>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div v-if="activeConfig" class="header-right">
|
||||
<span class="creator-info">创建于 {{ formatDateTime(activeConfig.created_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="config-info">
|
||||
<div v-if="activeConfig" class="config-info">
|
||||
<div class="info-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
@@ -61,9 +62,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" v-else class="active-wechat-config-widget empty-state">
|
||||
<div class="empty-content">
|
||||
<div v-else class="empty-content">
|
||||
<i class="el-icon-info" style="font-size: 48px; color: var(--el-text-color-placeholder)"></i>
|
||||
<p>暂无生效的支付配置</p>
|
||||
</div>
|
||||
@@ -203,19 +202,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-state {
|
||||
.empty-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
.empty-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
p {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
p {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
267
src/views/dashboard/analysis/widget/CommissionStats.vue
Normal file
267
src/views/dashboard/analysis/widget/CommissionStats.vue
Normal file
@@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<ElCard shadow="never" class="commission-stats-widget" v-if="stats">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<span class="header-title">佣金资金统计</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<span class="date-range">{{ startTime }} ~ {{ endTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="stats-info">
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||
>
|
||||
<i class="el-icon">💰</i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">总收入</div>
|
||||
<div class="stats-value">{{ formatMoney(stats.total_amount) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||||
>
|
||||
<i class="el-icon">📊</i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">总笔数</div>
|
||||
<div class="stats-value">{{ stats.total_count }} 笔</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
|
||||
>
|
||||
<i class="el-icon">📈</i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">成本价差收入</div>
|
||||
<div class="stats-value">{{ formatMoney(stats.cost_diff_amount) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||||
>
|
||||
<i class="el-icon">⚡</i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">一次性佣金收入</div>
|
||||
<div class="stats-value">{{ formatMoney(stats.one_time_amount) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-breakdown">
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">成本价差占比</span>
|
||||
<span class="breakdown-value">{{ formatPercent(stats.cost_diff_percent) }}</span>
|
||||
</div>
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">一次性佣金占比</span>
|
||||
<span class="breakdown-value">{{ formatPercent(stats.one_time_percent) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" v-else class="commission-stats-widget empty-state">
|
||||
<div class="empty-content">
|
||||
<i class="el-icon-info" style="font-size: 48px; color: var(--el-text-color-placeholder)"></i>
|
||||
<p>暂无佣金统计数据</p>
|
||||
</div>
|
||||
</ElCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CommissionService } from '@/api/modules'
|
||||
import type { CommissionStatsResponse } from '@/types/api/commission'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { formatMoney } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'CommissionStatsWidget' })
|
||||
|
||||
const userStore = useUserStore()
|
||||
const currentShopId = computed(() => userStore.info?.shop_id)
|
||||
|
||||
const stats = ref<CommissionStatsResponse | null>(null)
|
||||
const startTime = ref('')
|
||||
const endTime = ref('')
|
||||
|
||||
const formatPercent = (value: number) => {
|
||||
return (value / 10).toFixed(1) + '%'
|
||||
}
|
||||
|
||||
const loadCommissionStats = async () => {
|
||||
if (!currentShopId.value) return
|
||||
|
||||
try {
|
||||
const res = await CommissionService.getShopCommissionStats(currentShopId.value)
|
||||
if (res.code === 0 && res.data) {
|
||||
stats.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取佣金资金统计失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCommissionStats()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.commission-stats-widget {
|
||||
:deep(.el-card__header) {
|
||||
padding: 18px 20px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.header-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
.date-range {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.stats-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: var(--el-fill-color-blank);
|
||||
border-radius: 8px;
|
||||
|
||||
.stats-icon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stats-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.stats-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-breakdown {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
padding: 16px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 8px;
|
||||
|
||||
.breakdown-item {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
.breakdown-label {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.breakdown-value {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-state {
|
||||
.empty-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
p {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
.commission-stats-widget {
|
||||
.card-header {
|
||||
.header-left,
|
||||
.header-right {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stats-breakdown {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,101 +1,116 @@
|
||||
<template>
|
||||
<!-- 错误状态 -->
|
||||
<ElCard shadow="never" v-if="errorMsg" class="commission-summary-widget error-state">
|
||||
<ElCard shadow="never" class="commission-summary-widget" v-if="!errorMsg">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<span class="header-title">我的佣金概览</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="stats-info">
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #ff6b6b 0%, #ff8e53 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">预充值余额</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.main_balance) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">总佣金</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.total_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">可提现佣金</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.available_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">冻结佣金</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.frozen_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">提现中佣金</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.withdrawing_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">已提现佣金</div>
|
||||
<div class="stats-value">{{ formatMoney(summary.withdrawn_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stats-breakdown" v-if="withdrawalSetting">
|
||||
<div class="breakdown-title">当前提现配置</div>
|
||||
<div class="breakdown-content">
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">最低提现金额</span>
|
||||
<span class="breakdown-value">{{
|
||||
formatMoney(withdrawalSetting.min_withdrawal_amount)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">手续费率</span>
|
||||
<span class="breakdown-value">{{ (withdrawalSetting.fee_rate / 100).toFixed(2) }}%</span>
|
||||
</div>
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">每日提现次数</span>
|
||||
<span class="breakdown-value">{{ withdrawalSetting.daily_withdrawal_limit }} 次</span>
|
||||
</div>
|
||||
<div class="breakdown-item">
|
||||
<span class="breakdown-label">到账天数</span>
|
||||
<span class="breakdown-value">{{ withdrawalSetting.arrival_days }} 天</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" v-else class="commission-summary-widget error-state">
|
||||
<div class="error-content">
|
||||
<i class="el-icon-warning" style="font-size: 48px; color: var(--el-color-warning)"></i>
|
||||
<p>{{ errorMsg }}</p>
|
||||
</div>
|
||||
</ElCard>
|
||||
|
||||
<!-- 正常显示 -->
|
||||
<div v-else class="commission-summary-widget">
|
||||
<div class="stats-container">
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #ff6b6b 0%, #ff8e53 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">预充值余额</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.main_balance) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">总佣金</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.total_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">可提现佣金</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.available_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">冻结佣金</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.frozen_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">提现中佣金</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.withdrawing_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
class="stat-icon"
|
||||
style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
|
||||
>
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">已提现佣金</div>
|
||||
<div class="stat-value">{{ formatMoney(summary.withdrawn_commission) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -108,13 +123,10 @@
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 获取当前用户的 shop_id
|
||||
const currentShopId = computed(() => userStore.userInfo?.shop_id)
|
||||
const currentShopId = computed(() => userStore.info?.shop_id)
|
||||
|
||||
// 错误信息
|
||||
const errorMsg = ref<string>('')
|
||||
|
||||
// 佣金概览
|
||||
const summary = ref<MyCommissionSummary>({
|
||||
main_balance: 0,
|
||||
total_commission: 0,
|
||||
@@ -124,7 +136,13 @@
|
||||
withdrawn_commission: 0
|
||||
})
|
||||
|
||||
// 加载佣金概览
|
||||
const withdrawalSetting = ref<{
|
||||
min_withdrawal_amount: number
|
||||
fee_rate: number
|
||||
daily_withdrawal_limit: number
|
||||
arrival_days: number
|
||||
} | null>(null)
|
||||
|
||||
const loadSummary = async () => {
|
||||
if (!currentShopId.value) {
|
||||
errorMsg.value = '当前账号未关联店铺'
|
||||
@@ -132,14 +150,12 @@
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用 fund-summary 接口,通过 shop_id 过滤获取自己的数据
|
||||
const res = await CommissionService.getShopFundSummary({
|
||||
page: 1,
|
||||
pageSize: 1
|
||||
page_size: 1
|
||||
})
|
||||
if (res.code === 0 && res.data.items && res.data.items.length > 0) {
|
||||
// 从结果中找到当前用户的店铺数据
|
||||
const myShopData = res.data.items.find(item => item.shop_id === currentShopId.value)
|
||||
const myShopData = res.data.items.find((item) => item.shop_id === currentShopId.value)
|
||||
if (myShopData) {
|
||||
summary.value = {
|
||||
main_balance: myShopData.main_balance || 0,
|
||||
@@ -158,7 +174,6 @@
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('获取佣金概览失败:', error)
|
||||
// 尝试从错误响应中提取 msg
|
||||
if (error?.response?.data?.msg) {
|
||||
errorMsg.value = error.response.data.msg
|
||||
} else {
|
||||
@@ -167,13 +182,144 @@
|
||||
}
|
||||
}
|
||||
|
||||
const loadWithdrawalSetting = async () => {
|
||||
try {
|
||||
const res = await CommissionService.getCurrentWithdrawalSetting()
|
||||
if (res.code === 0 && res.data) {
|
||||
withdrawalSetting.value = {
|
||||
min_withdrawal_amount: res.data.min_withdrawal_amount,
|
||||
fee_rate: res.data.fee_rate,
|
||||
daily_withdrawal_limit: res.data.daily_withdrawal_limit,
|
||||
arrival_days: res.data.arrival_days
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取提现设置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSummary()
|
||||
loadWithdrawalSetting()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.commission-summary-widget {
|
||||
:deep(.el-card__header) {
|
||||
padding: 18px 20px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
|
||||
.header-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.stats-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: var(--el-fill-color-blank);
|
||||
border-radius: 8px;
|
||||
|
||||
.stats-icon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stats-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.stats-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-breakdown {
|
||||
padding: 16px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 8px;
|
||||
|
||||
.breakdown-title {
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.breakdown-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
|
||||
.breakdown-item {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
.breakdown-label {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.breakdown-value {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.error-state {
|
||||
.error-content {
|
||||
display: flex;
|
||||
@@ -190,108 +336,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.stat-card-wrapper {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
.stat-icon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.stat-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
overflow: hidden;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 1400px) {
|
||||
.commission-summary-widget {
|
||||
.stats-container {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stat-card-wrapper {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
.stat-content {
|
||||
.stat-value {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 1200px) {
|
||||
.commission-summary-widget {
|
||||
.stat-card-wrapper {
|
||||
flex: 1 1 calc(33.333% - 12px);
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
.commission-summary-widget {
|
||||
.stats-container {
|
||||
.stats-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stat-card-wrapper {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 480px) {
|
||||
.commission-summary-widget {
|
||||
.stat-card-wrapper {
|
||||
flex: 1 1 100%;
|
||||
.stats-breakdown {
|
||||
.breakdown-content {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +1,136 @@
|
||||
<template>
|
||||
<ElCard shadow="never" class="withdrawal-settings-widget" v-if="currentSetting">
|
||||
<ElCard shadow="never" class="daily-commission-stats-widget" v-if="statsList.length > 0">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<span class="header-title">当前生效配置</span>
|
||||
<ElTag type="success" effect="dark" size="small">生效中</ElTag>
|
||||
<span class="header-title">每日佣金统计</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<span class="creator-info"
|
||||
>{{ currentSetting.creator_name || '-' }} 创建于
|
||||
{{ formatDateTime(currentSetting.created_at) }}</span
|
||||
<span class="date-range"
|
||||
>{{ formatDateRange(startDate) }} ~ {{ formatDateRange(endDate) }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="setting-info">
|
||||
<div class="info-card">
|
||||
<div class="stats-info">
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||
>
|
||||
<i class="el-icon">💰</i>
|
||||
</div>
|
||||
<div class="info-content">
|
||||
<div class="info-label">最低提现金额</div>
|
||||
<div class="info-value">{{ formatMoney(currentSetting.min_withdrawal_amount) }}</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">总收入</div>
|
||||
<div class="stats-value">{{ formatMoney(totalAmount) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div class="stats-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||||
class="stats-icon"
|
||||
style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||||
>
|
||||
<i class="el-icon">📊</i>
|
||||
</div>
|
||||
<div class="info-content">
|
||||
<div class="info-label">手续费率</div>
|
||||
<div class="info-value">{{ formatFeeRate(currentSetting.fee_rate) }}</div>
|
||||
<div class="stats-content">
|
||||
<div class="stats-label">总笔数</div>
|
||||
<div class="stats-value">{{ totalCount }} 笔</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
|
||||
>
|
||||
<i class="el-icon">🔢</i>
|
||||
</div>
|
||||
<div class="info-content">
|
||||
<div class="info-label">每日提现次数</div>
|
||||
<div class="info-value">{{ currentSetting.daily_withdrawal_limit }} 次</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
|
||||
>
|
||||
<i class="el-icon">⏰</i>
|
||||
</div>
|
||||
<div class="info-content">
|
||||
<div class="info-label">到账天数</div>
|
||||
<div class="info-value">{{
|
||||
currentSetting.arrival_days === 0 ? '实时到账' : `${currentSetting.arrival_days} 天`
|
||||
}}</div>
|
||||
</div>
|
||||
<div class="stats-chart">
|
||||
<div class="chart-bar" v-for="item in statsList" :key="item.date">
|
||||
<div class="bar-label">{{ formatDateShort(item.date) }}</div>
|
||||
<div class="bar-value" :style="{ height: getBarHeight(item.total_amount) + 'px' }">
|
||||
<ElTooltip :content="formatMoney(item.total_amount)" placement="top">
|
||||
<div class="bar-fill"></div>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" v-else class="withdrawal-settings-widget empty-state">
|
||||
<ElCard shadow="never" v-else class="daily-commission-stats-widget empty-state">
|
||||
<div class="empty-content">
|
||||
<i class="el-icon-info" style="font-size: 48px; color: var(--el-text-color-placeholder)"></i>
|
||||
<p>暂无提现配置</p>
|
||||
<p>暂无佣金统计数据</p>
|
||||
</div>
|
||||
</ElCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CommissionService } from '@/api/modules'
|
||||
import { ElTag } from 'element-plus'
|
||||
import type { WithdrawalSettingItem } from '@/types/api/commission'
|
||||
import { formatDateTime, formatMoney, formatFeeRate } from '@/utils/business/format'
|
||||
import { ElTooltip } from 'element-plus'
|
||||
import type { DailyCommissionStatsItem } from '@/types/api/commission'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { formatMoney } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'WithdrawalSettingsWidget' })
|
||||
defineOptions({ name: 'DailyCommissionStatsWidget' })
|
||||
|
||||
// 当前生效的配置
|
||||
const currentSetting = ref<WithdrawalSettingItem | null>(null)
|
||||
const userStore = useUserStore()
|
||||
const currentShopId = computed(() => userStore.info?.shop_id)
|
||||
|
||||
// 加载当前生效配置
|
||||
const loadCurrentSetting = async () => {
|
||||
const statsList = ref<DailyCommissionStatsItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const startDate = ref('')
|
||||
const endDate = ref('')
|
||||
|
||||
const totalAmount = computed(() =>
|
||||
statsList.value.reduce((sum, item) => sum + item.total_amount, 0)
|
||||
)
|
||||
const totalCount = computed(() =>
|
||||
statsList.value.reduce((sum, item) => sum + item.total_count, 0)
|
||||
)
|
||||
|
||||
const maxAmount = computed(() => {
|
||||
if (statsList.value.length === 0) return 0
|
||||
return Math.max(...statsList.value.map((item) => item.total_amount))
|
||||
})
|
||||
|
||||
const getBarHeight = (amount: number) => {
|
||||
if (maxAmount.value === 0) return 0
|
||||
return Math.max(4, (amount / maxAmount.value) * 100)
|
||||
}
|
||||
|
||||
const formatDateShort = (dateStr: string) => {
|
||||
if (!dateStr) return '-'
|
||||
return dateStr.slice(5) // MM-DD
|
||||
}
|
||||
|
||||
const formatDateRange = (dateStr: string) => {
|
||||
if (!dateStr) return '-'
|
||||
return dateStr // API already returns YYYY-MM-DD format
|
||||
}
|
||||
|
||||
const loadDailyStats = async () => {
|
||||
if (!currentShopId.value) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await CommissionService.getCurrentWithdrawalSetting()
|
||||
const res = await CommissionService.getShopDailyCommissionStats(currentShopId.value, {
|
||||
days: 30
|
||||
})
|
||||
if (res.code === 0 && res.data) {
|
||||
currentSetting.value = res.data
|
||||
statsList.value = res.data
|
||||
if (res.data.length > 0) {
|
||||
startDate.value = res.data[res.data.length - 1]?.date || ''
|
||||
endDate.value = res.data[0]?.date || ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取当前配置失败:', error)
|
||||
console.error('获取每日佣金统计失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCurrentSetting()
|
||||
loadDailyStats()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.withdrawal-settings-widget {
|
||||
.daily-commission-stats-widget {
|
||||
:deep(.el-card__header) {
|
||||
padding: 18px 20px;
|
||||
background: var(--el-fill-color-light);
|
||||
@@ -135,19 +161,20 @@
|
||||
}
|
||||
|
||||
.header-right {
|
||||
.creator-info {
|
||||
.date-range {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.setting-info {
|
||||
.stats-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.info-card {
|
||||
.stats-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
@@ -155,7 +182,7 @@
|
||||
background: var(--el-fill-color-blank);
|
||||
border-radius: 8px;
|
||||
|
||||
.info-icon {
|
||||
.stats-icon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
@@ -166,17 +193,17 @@
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
.stats-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.info-label {
|
||||
.stats-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
.stats-value {
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
@@ -188,6 +215,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
.stats-chart {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 8px;
|
||||
height: 120px;
|
||||
padding-top: 10px;
|
||||
|
||||
.chart-bar {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.bar-label {
|
||||
font-size: 11px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.bar-value {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.bar-fill {
|
||||
width: 80%;
|
||||
max-width: 24px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 4px 4px 0 0;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-state {
|
||||
.empty-content {
|
||||
display: flex;
|
||||
@@ -206,7 +273,7 @@
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
.withdrawal-settings-widget {
|
||||
.daily-commission-stats-widget {
|
||||
.card-header {
|
||||
.header-left,
|
||||
.header-right {
|
||||
@@ -214,10 +281,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.setting-info {
|
||||
.stats-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stats-chart {
|
||||
overflow-x: auto;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
<h3 class="section-title">订单项列表</h3>
|
||||
<ElTable :data="detailData.items" border style="margin-top: 10px">
|
||||
<ElTableColumn prop="package_name" label="套餐名称" min-width="150" />
|
||||
<ElTableColumn prop="package_type" label="套餐类型" width="120">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.package_type === 'formal'
|
||||
? '正式套餐'
|
||||
: row.package_type === 'addon'
|
||||
? '加油包'
|
||||
: '-'
|
||||
}}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="quantity" label="数量" width="100" />
|
||||
<ElTableColumn prop="unit_price" label="单价" width="120">
|
||||
<template #default="{ row }">
|
||||
@@ -145,6 +156,16 @@
|
||||
label: '买家类型',
|
||||
formatter: (_, data) => (data.buyer_type ? getBuyerTypeText(data.buyer_type) : '-')
|
||||
},
|
||||
{
|
||||
label: '买家手机号',
|
||||
prop: 'buyer_phone',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '买家昵称',
|
||||
prop: 'buyer_nickname',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '买家ID',
|
||||
prop: 'buyer_id',
|
||||
|
||||
@@ -234,6 +234,12 @@
|
||||
<ElDescriptionsItem :label="'买家类型'">
|
||||
{{ getBuyerTypeText(currentOrder.buyer_type) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem :label="'买家手机号'">
|
||||
{{ currentOrder.buyer_phone || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem :label="'买家昵称'">
|
||||
{{ currentOrder.buyer_nickname || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem :label="'佣金状态'">
|
||||
{{ getCommissionStatusText(currentOrder.commission_status) }}
|
||||
</ElDescriptionsItem>
|
||||
@@ -256,6 +262,17 @@
|
||||
<h4>{{ '订单项' }}</h4>
|
||||
<ElTable :data="currentOrder.items" border style="margin-top: 10px">
|
||||
<ElTableColumn prop="package_name" :label="'套餐名称'" min-width="150" />
|
||||
<ElTableColumn prop="package_type" :label="'套餐类型'" width="120">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.package_type === 'formal'
|
||||
? '正式套餐'
|
||||
: row.package_type === 'addon'
|
||||
? '加油包'
|
||||
: '-'
|
||||
}}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="quantity" :label="'数量'" width="100" />
|
||||
<ElTableColumn prop="unit_price" :label="'单价'" width="120">
|
||||
<template #default="{ row }">
|
||||
@@ -330,6 +347,7 @@
|
||||
// 搜索表单初始值
|
||||
const initialSearchState: OrderQueryParams = {
|
||||
order_no: '',
|
||||
buyer_phone: '',
|
||||
payment_status: undefined,
|
||||
order_type: undefined,
|
||||
purchase_role: undefined,
|
||||
@@ -353,6 +371,16 @@
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '买家手机号',
|
||||
prop: 'buyer_phone',
|
||||
type: 'input',
|
||||
placeholder: '请输入买家手机号',
|
||||
config: {
|
||||
maxlength: 20,
|
||||
clearable: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '支付状态',
|
||||
prop: 'payment_status',
|
||||
@@ -419,6 +447,8 @@
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '订单编号', prop: 'order_no' },
|
||||
{ label: '买家手机号', prop: 'buyer_phone' },
|
||||
{ label: '买家昵称', prop: 'buyer_nickname' },
|
||||
{ label: '订单类型', prop: 'order_type' },
|
||||
{ label: '买家类型', prop: 'buyer_type' },
|
||||
{ label: '订单渠道', prop: 'purchase_role' },
|
||||
@@ -707,6 +737,18 @@
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'buyer_phone',
|
||||
label: '买家手机号',
|
||||
width: 130,
|
||||
formatter: (row: Order) => row.buyer_phone || '-'
|
||||
},
|
||||
{
|
||||
prop: 'buyer_nickname',
|
||||
label: '买家昵称',
|
||||
width: 130,
|
||||
formatter: (row: Order) => row.buyer_nickname || '-'
|
||||
},
|
||||
{
|
||||
prop: 'order_type',
|
||||
label: '订单类型',
|
||||
@@ -854,6 +896,7 @@
|
||||
page: pagination.page,
|
||||
page_size: pagination.page_size,
|
||||
order_no: searchForm.order_no || undefined,
|
||||
buyer_phone: searchForm.buyer_phone || undefined,
|
||||
payment_status: searchForm.payment_status,
|
||||
order_type: searchForm.order_type,
|
||||
purchase_role: searchForm.purchase_role,
|
||||
|
||||
@@ -977,38 +977,47 @@
|
||||
}
|
||||
|
||||
// 显示新增/编辑对话框
|
||||
const showDialog = (type: string, row?: PackageResponse) => {
|
||||
const showDialog = async (type: string, row?: PackageResponse) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
|
||||
if (type === 'edit' && row) {
|
||||
form.id = row.id
|
||||
form.package_code = row.package_code
|
||||
form.package_name = row.package_name
|
||||
form.series_id = row.series_id
|
||||
form.package_type = row.package_type
|
||||
form.calendar_type = row.calendar_type || undefined
|
||||
form.duration_days = row.duration_days || undefined
|
||||
form.duration_months = row.duration_months
|
||||
form.data_reset_cycle = row.data_reset_cycle || undefined
|
||||
form.enable_virtual_data = row.enable_virtual_data || false
|
||||
form.expiry_base = row.expiry_base || 'from_activation'
|
||||
form.real_data_mb = row.real_data_mb || 0
|
||||
form.virtual_data_mb = row.virtual_data_mb || 0
|
||||
// MB 转换为 GB 显示
|
||||
realDataGb.value = form.real_data_mb ? Number((form.real_data_mb / 1024).toFixed(2)) : 0
|
||||
// 从虚流量额度反推比例:比例 = (1 - 虚流量/真流量) × 100%
|
||||
if (form.real_data_mb > 0 && form.virtual_data_mb > 0) {
|
||||
const ratio = (1 - form.virtual_data_mb / form.real_data_mb) * 100
|
||||
virtualRatioPercent.value = Number(ratio.toFixed(2))
|
||||
} else {
|
||||
virtualRatioPercent.value = null
|
||||
try {
|
||||
const res = await PackageManageService.getPackageDetail(row.id)
|
||||
if (res.code === 0 && res.data) {
|
||||
const data = res.data
|
||||
form.id = data.id
|
||||
form.package_code = data.package_code
|
||||
form.package_name = data.package_name
|
||||
form.series_id = data.series_id
|
||||
form.package_type = data.package_type
|
||||
form.calendar_type = data.calendar_type || undefined
|
||||
form.duration_days = data.duration_days
|
||||
form.duration_months = data.duration_months
|
||||
form.data_reset_cycle = data.data_reset_cycle || undefined
|
||||
form.enable_virtual_data = data.enable_virtual_data || false
|
||||
form.expiry_base = data.expiry_base || 'from_activation'
|
||||
form.real_data_mb = data.real_data_mb || 0
|
||||
form.virtual_data_mb = data.virtual_data_mb || 0
|
||||
// MB 转换为 GB 显示
|
||||
realDataGb.value = form.real_data_mb ? Number((form.real_data_mb / 1024).toFixed(2)) : 0
|
||||
// 从虚流量额度反推比例:比例 = (1 - 虚流量/真流量) × 100%
|
||||
if (form.real_data_mb > 0 && form.virtual_data_mb > 0) {
|
||||
const ratio = (1 - form.virtual_data_mb / form.real_data_mb) * 100
|
||||
virtualRatioPercent.value = Number(ratio.toFixed(2))
|
||||
} else {
|
||||
virtualRatioPercent.value = null
|
||||
}
|
||||
form.cost_price = (data.cost_price ?? 0) / 100 // 分转换为元显示
|
||||
form.suggested_retail_price = data.suggested_retail_price
|
||||
? data.suggested_retail_price / 100
|
||||
: undefined
|
||||
form.description = data.description || ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取套餐详情失败:', error)
|
||||
ElMessage.error('获取套餐详情失败')
|
||||
}
|
||||
form.cost_price = (row.cost_price ?? 0) / 100 // 分转换为元显示
|
||||
form.suggested_retail_price = row.suggested_retail_price
|
||||
? row.suggested_retail_price / 100
|
||||
: undefined
|
||||
form.description = row.description || ''
|
||||
} else {
|
||||
form.id = 0
|
||||
form.package_code = ''
|
||||
@@ -1126,7 +1135,7 @@
|
||||
if (form.data_reset_cycle) {
|
||||
data.data_reset_cycle = form.data_reset_cycle
|
||||
}
|
||||
if (form.duration_days !== undefined && form.duration_days !== null) {
|
||||
if (form.duration_days !== undefined) {
|
||||
data.duration_days = form.duration_days
|
||||
}
|
||||
if (form.enable_virtual_data !== undefined) {
|
||||
|
||||
@@ -286,20 +286,14 @@
|
||||
</div>
|
||||
</ElFormItem>
|
||||
|
||||
<!-- 强充配置 -->
|
||||
<div class="form-section-title">
|
||||
<span class="title-text">强充配置</span>
|
||||
</div>
|
||||
<!-- 强充配置 - 仅累计充值时显示 -->
|
||||
<template
|
||||
v-if="form.one_time_commission_config.trigger_type === 'accumulated_recharge'"
|
||||
>
|
||||
<div class="form-section-title">
|
||||
<span class="title-text">强充配置</span>
|
||||
</div>
|
||||
|
||||
<ElFormItem label="启用强充">
|
||||
<ElSwitch
|
||||
v-model="form.one_time_commission_config.enable_force_recharge"
|
||||
active-text="启用"
|
||||
inactive-text="不启用"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<template v-if="form.one_time_commission_config.enable_force_recharge">
|
||||
<ElFormItem label="强充金额">
|
||||
<ElInputNumber
|
||||
v-model="form.one_time_commission_config.force_amount"
|
||||
@@ -967,8 +961,8 @@
|
||||
commissionConfig.tiers = convertedTiers.length > 0 ? convertedTiers : null
|
||||
}
|
||||
|
||||
// 添加强充配置:元 -> 分
|
||||
if (form.one_time_commission_config.enable_force_recharge) {
|
||||
// 添加强充配置:元 -> 分(仅累计充值时需要)
|
||||
if (form.one_time_commission_config.trigger_type === 'accumulated_recharge') {
|
||||
commissionConfig.enable_force_recharge = true
|
||||
commissionConfig.force_amount =
|
||||
form.one_time_commission_config.force_amount != null
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { formatDateTime, formatMoney, formatFeeRate } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'CommissionWithdrawalSettings' })
|
||||
defineOptions({ name: 'WithdrawalSettings' })
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
@@ -728,7 +728,7 @@
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.currentPage,
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
shop_name: searchForm.shop_name || undefined,
|
||||
shop_code: searchForm.shop_code || undefined,
|
||||
|
||||
@@ -939,7 +939,7 @@
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
page_size: pagination.pageSize,
|
||||
role_name: searchForm.role_name || undefined,
|
||||
role_type: searchForm.role_type,
|
||||
status: searchForm.status
|
||||
|
||||
Reference in New Issue
Block a user