This commit is contained in:
61
src/api/modules/agentRecharge.ts
Normal file
61
src/api/modules/agentRecharge.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 代理充值相关 API
|
||||
*/
|
||||
|
||||
import { BaseService } from '../BaseService'
|
||||
import type {
|
||||
AgentRecharge,
|
||||
AgentRechargeQueryParams,
|
||||
AgentRechargeListResponse,
|
||||
CreateAgentRechargeRequest,
|
||||
ConfirmOfflinePaymentRequest,
|
||||
BaseResponse
|
||||
} from '@/types/api'
|
||||
|
||||
export class AgentRechargeService extends BaseService {
|
||||
/**
|
||||
* 获取代理充值订单列表
|
||||
* @param params 查询参数
|
||||
*/
|
||||
static getAgentRecharges(
|
||||
params?: AgentRechargeQueryParams
|
||||
): Promise<BaseResponse<AgentRechargeListResponse>> {
|
||||
return this.get<BaseResponse<AgentRechargeListResponse>>(
|
||||
'/api/admin/agent-recharges',
|
||||
params
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代理充值订单详情
|
||||
* @param id 充值订单ID
|
||||
*/
|
||||
static getAgentRechargeById(id: number): Promise<BaseResponse<AgentRecharge>> {
|
||||
return this.getOne<AgentRecharge>(`/api/admin/agent-recharges/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建代理充值订单
|
||||
* @param data 创建充值订单请求参数
|
||||
*/
|
||||
static createAgentRecharge(
|
||||
data: CreateAgentRechargeRequest
|
||||
): Promise<BaseResponse<AgentRecharge>> {
|
||||
return this.post<BaseResponse<AgentRecharge>>('/api/admin/agent-recharges', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认线下充值
|
||||
* @param id 充值订单ID
|
||||
* @param data 确认线下充值请求参数
|
||||
*/
|
||||
static confirmOfflinePayment(
|
||||
id: number,
|
||||
data: ConfirmOfflinePaymentRequest
|
||||
): Promise<BaseResponse<AgentRecharge>> {
|
||||
return this.post<BaseResponse<AgentRecharge>>(
|
||||
`/api/admin/agent-recharges/${id}/offline-pay`,
|
||||
data
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ export { PackageManageService } from './packageManage'
|
||||
export { ShopSeriesGrantService } from './shopSeriesGrant'
|
||||
export { OrderService } from './order'
|
||||
export { AssetService } from './asset'
|
||||
export { AgentRechargeService } from './agentRecharge'
|
||||
export { WechatConfigService } from './wechatConfig'
|
||||
|
||||
// TODO: 按需添加其他业务模块
|
||||
// export { SettingService } from './setting'
|
||||
|
||||
@@ -9,6 +9,8 @@ import type {
|
||||
OrderListResponse,
|
||||
CreateOrderRequest,
|
||||
CreateOrderResponse,
|
||||
PurchaseCheckRequest,
|
||||
PurchaseCheckResponse,
|
||||
BaseResponse
|
||||
} from '@/types/api'
|
||||
|
||||
@@ -44,4 +46,17 @@ export class OrderService extends BaseService {
|
||||
static cancelOrder(id: number): Promise<BaseResponse> {
|
||||
return this.post<BaseResponse>(`/api/admin/orders/${id}/cancel`, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* 套餐购买预检
|
||||
* @param data 预检请求参数
|
||||
*/
|
||||
static purchaseCheck(
|
||||
data: PurchaseCheckRequest
|
||||
): Promise<BaseResponse<PurchaseCheckResponse>> {
|
||||
return this.post<BaseResponse<PurchaseCheckResponse>>(
|
||||
'/api/admin/orders/purchase-check',
|
||||
data
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
78
src/api/modules/wechatConfig.ts
Normal file
78
src/api/modules/wechatConfig.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 微信支付配置管理 API
|
||||
*/
|
||||
|
||||
import { BaseService } from '../BaseService'
|
||||
import type { BaseResponse } from '@/types/api'
|
||||
import type {
|
||||
WechatConfig,
|
||||
WechatConfigQueryParams,
|
||||
WechatConfigListResponse,
|
||||
CreateWechatConfigRequest,
|
||||
UpdateWechatConfigRequest
|
||||
} from '@/types/api/wechatConfig'
|
||||
|
||||
export class WechatConfigService extends BaseService {
|
||||
/**
|
||||
* 获取支付配置列表
|
||||
*/
|
||||
static getWechatConfigs(
|
||||
params?: WechatConfigQueryParams
|
||||
): Promise<BaseResponse<WechatConfigListResponse>> {
|
||||
return this.get<BaseResponse<WechatConfigListResponse>>('/api/admin/wechat-configs', params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付配置详情
|
||||
*/
|
||||
static getWechatConfigById(id: number): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.get<BaseResponse<WechatConfig>>(`/api/admin/wechat-configs/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付配置
|
||||
*/
|
||||
static createWechatConfig(
|
||||
data: CreateWechatConfigRequest
|
||||
): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.post<BaseResponse<WechatConfig>>('/api/admin/wechat-configs', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付配置
|
||||
*/
|
||||
static updateWechatConfig(
|
||||
id: number,
|
||||
data: UpdateWechatConfigRequest
|
||||
): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.put<BaseResponse<WechatConfig>>(`/api/admin/wechat-configs/${id}`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付配置
|
||||
*/
|
||||
static deleteWechatConfig(id: number): Promise<BaseResponse<void>> {
|
||||
return this.delete<BaseResponse<void>>(`/api/admin/wechat-configs/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活支付配置
|
||||
*/
|
||||
static activateWechatConfig(id: number): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.post<BaseResponse<WechatConfig>>(`/api/admin/wechat-configs/${id}/activate`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用支付配置
|
||||
*/
|
||||
static deactivateWechatConfig(id: number): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.post<BaseResponse<WechatConfig>>(`/api/admin/wechat-configs/${id}/deactivate`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前生效的支付配置
|
||||
*/
|
||||
static getActiveWechatConfig(): Promise<BaseResponse<WechatConfig>> {
|
||||
return this.get<BaseResponse<WechatConfig>>('/api/admin/wechat-configs/active')
|
||||
}
|
||||
}
|
||||
@@ -1146,6 +1146,37 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/finance',
|
||||
name: 'FinanceManagement',
|
||||
component: RoutesAlias.Home,
|
||||
meta: {
|
||||
title: '财务管理',
|
||||
icon: ''
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'agent-recharge',
|
||||
name: 'AgentRecharge',
|
||||
component: RoutesAlias.AgentRecharge,
|
||||
meta: {
|
||||
title: '代理充值',
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'agent-recharge/detail/:id',
|
||||
name: 'AgentRechargeDetailRoute',
|
||||
component: RoutesAlias.AgentRechargeDetail,
|
||||
meta: {
|
||||
title: '充值详情',
|
||||
isHide: true,
|
||||
keepAlive: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/commission',
|
||||
name: 'CommissionManagement',
|
||||
@@ -1196,44 +1227,63 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// {
|
||||
// path: '/settings',
|
||||
// name: 'Settings',
|
||||
// component: RoutesAlias.Home,
|
||||
// meta: {
|
||||
// title: 'menus.settings.title',
|
||||
// icon: ''
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: 'payment-merchant',
|
||||
// name: 'PaymentMerchant',
|
||||
// component: RoutesAlias.PaymentMerchant,
|
||||
// meta: {
|
||||
// title: 'menus.settings.paymentMerchant',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'developer-api',
|
||||
// name: 'DeveloperApi',
|
||||
// component: RoutesAlias.DeveloperApi,
|
||||
// meta: {
|
||||
// title: 'menus.settings.developerApi',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'commission-template',
|
||||
// name: 'CommissionTemplate',
|
||||
// component: RoutesAlias.CommissionTemplate,
|
||||
// meta: {
|
||||
// title: 'menus.settings.commissionTemplate',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: RoutesAlias.Home,
|
||||
meta: {
|
||||
title: '设置管理',
|
||||
icon: ''
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'wechat-config',
|
||||
name: 'WechatConfig',
|
||||
component: RoutesAlias.WechatConfig,
|
||||
meta: {
|
||||
title: '微信支付配置',
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'wechat-config/detail/:id',
|
||||
name: 'WechatConfigDetailRoute',
|
||||
component: RoutesAlias.WechatConfigDetail,
|
||||
meta: {
|
||||
title: '支付配置详情',
|
||||
isHide: true,
|
||||
keepAlive: false
|
||||
}
|
||||
}
|
||||
// {
|
||||
// path: 'payment-merchant',
|
||||
// name: 'PaymentMerchant',
|
||||
// component: RoutesAlias.PaymentMerchant,
|
||||
// meta: {
|
||||
// title: 'menus.settings.paymentMerchant',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'developer-api',
|
||||
// name: 'DeveloperApi',
|
||||
// component: RoutesAlias.DeveloperApi,
|
||||
// meta: {
|
||||
// title: 'menus.settings.developerApi',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'commission-template',
|
||||
// name: 'CommissionTemplate',
|
||||
// component: RoutesAlias.CommissionTemplate,
|
||||
// meta: {
|
||||
// title: 'menus.settings.commissionTemplate',
|
||||
// keepAlive: true
|
||||
// }
|
||||
// }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -113,6 +113,8 @@ export enum RoutesAlias {
|
||||
CarrierManagement = '/finance/carrier-management', // 运营商管理
|
||||
OrderList = '/account/orders', // 订单管理
|
||||
OrderDetail = '/account/orders/detail', // 订单详情
|
||||
AgentRecharge = '/finance/agent-recharge', // 代理充值
|
||||
AgentRechargeDetail = '/finance/agent-recharge/detail', // 代理充值详情
|
||||
|
||||
// 佣金管理
|
||||
WithdrawalApproval = '/finance/commission/withdrawal-approval', // 提现审批
|
||||
@@ -123,7 +125,9 @@ export enum RoutesAlias {
|
||||
// 设置管理
|
||||
PaymentMerchant = '/settings/payment-merchant', // 支付商户
|
||||
DeveloperApi = '/settings/developer-api', // 开发者API
|
||||
CommissionTemplate = '/settings/commission-template' // 分佣模板
|
||||
CommissionTemplate = '/settings/commission-template', // 分佣模板
|
||||
WechatConfig = '/settings/wechat-config', // 微信支付配置
|
||||
WechatConfigDetail = '/settings/wechat-config/detail' // 微信支付配置详情
|
||||
}
|
||||
|
||||
// 主页路由
|
||||
|
||||
65
src/types/api/agentRecharge.ts
Normal file
65
src/types/api/agentRecharge.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 代理充值相关类型定义
|
||||
*/
|
||||
|
||||
// 充值状态
|
||||
export enum AgentRechargeStatus {
|
||||
PENDING = 1, // 待支付
|
||||
COMPLETED = 2, // 已完成
|
||||
CANCELLED = 3 // 已取消
|
||||
}
|
||||
|
||||
// 支付方式
|
||||
export type AgentRechargePaymentMethod = 'wechat' | 'offline'
|
||||
|
||||
// 支付通道
|
||||
export type AgentRechargePaymentChannel = 'wechat_direct' | 'fuyou' | 'offline'
|
||||
|
||||
// 代理充值订单
|
||||
export interface AgentRecharge {
|
||||
id: number
|
||||
recharge_no: string
|
||||
agent_wallet_id: number
|
||||
shop_id: number
|
||||
shop_name: string
|
||||
amount: number // 充值金额(单位:分)
|
||||
status: AgentRechargeStatus
|
||||
payment_method: AgentRechargePaymentMethod
|
||||
payment_channel: AgentRechargePaymentChannel
|
||||
payment_config_id: number | null
|
||||
payment_transaction_id: string
|
||||
created_at: string
|
||||
paid_at: string | null
|
||||
completed_at: string | null
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 查询代理充值订单列表参数
|
||||
export interface AgentRechargeQueryParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
shop_id?: number
|
||||
status?: AgentRechargeStatus
|
||||
start_date?: string
|
||||
end_date?: string
|
||||
}
|
||||
|
||||
// 代理充值订单列表响应
|
||||
export interface AgentRechargeListResponse {
|
||||
page: number
|
||||
page_size: number
|
||||
total: number
|
||||
list: AgentRecharge[]
|
||||
}
|
||||
|
||||
// 创建代理充值订单请求
|
||||
export interface CreateAgentRechargeRequest {
|
||||
amount: number // 充值金额(单位:分),范围 10000 ~ 100000000
|
||||
payment_method: AgentRechargePaymentMethod
|
||||
shop_id: number
|
||||
}
|
||||
|
||||
// 确认线下充值请求
|
||||
export interface ConfirmOfflinePaymentRequest {
|
||||
operation_password: string
|
||||
}
|
||||
@@ -79,3 +79,9 @@ export * from './order'
|
||||
|
||||
// 资产管理相关
|
||||
export * from './asset'
|
||||
|
||||
// 代理充值相关
|
||||
export * from './agentRecharge'
|
||||
|
||||
// 微信支付配置相关
|
||||
export * from './wechatConfig'
|
||||
|
||||
@@ -17,7 +17,7 @@ export type OrderType = 'single_card' | 'device'
|
||||
export type BuyerType = 'personal' | 'agent'
|
||||
|
||||
// 订单支付方式
|
||||
export type OrderPaymentMethod = 'wallet' | 'wechat' | 'alipay'
|
||||
export type OrderPaymentMethod = 'wallet' | 'wechat' | 'alipay' | 'offline'
|
||||
|
||||
// 订单佣金状态
|
||||
export enum OrderCommissionStatus {
|
||||
@@ -84,7 +84,25 @@ export interface CreateOrderRequest {
|
||||
package_ids: number[]
|
||||
iot_card_id?: number | null
|
||||
device_id?: number | null
|
||||
payment_method: OrderPaymentMethod // 支付方式
|
||||
}
|
||||
|
||||
// 创建订单响应 (返回订单详情)
|
||||
export type CreateOrderResponse = Order
|
||||
|
||||
// 套餐购买预检请求
|
||||
export interface PurchaseCheckRequest {
|
||||
order_type: OrderType // 订单类型 (single_card:单卡购买, device:设备购买)
|
||||
package_ids: number[] // 套餐ID列表
|
||||
resource_id: number // 资源ID (IoT卡ID或设备ID)
|
||||
}
|
||||
|
||||
// 套餐购买预检响应
|
||||
export interface PurchaseCheckResponse {
|
||||
need_force_recharge: boolean // 是否需要强充
|
||||
force_recharge_amount?: number // 强充金额(分)
|
||||
total_package_amount?: number // 套餐总价(分)
|
||||
actual_payment?: number // 实际支付金额(分)
|
||||
wallet_credit?: number // 钱包到账金额(分)
|
||||
message?: string // 提示信息
|
||||
}
|
||||
|
||||
135
src/types/api/wechatConfig.ts
Normal file
135
src/types/api/wechatConfig.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 微信支付配置管理相关类型定义
|
||||
*/
|
||||
|
||||
// 支付渠道类型
|
||||
export type PaymentProviderType = 'wechat' | 'fuiou'
|
||||
|
||||
// 微信支付配置
|
||||
export interface WechatConfig {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
provider_type: PaymentProviderType
|
||||
is_active: boolean
|
||||
|
||||
// 小程序配置
|
||||
miniapp_app_id: string
|
||||
miniapp_app_secret: string
|
||||
|
||||
// 公众号配置
|
||||
oa_app_id: string
|
||||
oa_app_secret: string
|
||||
oa_token: string
|
||||
oa_aes_key: string
|
||||
oa_oauth_redirect_url: string
|
||||
|
||||
// 微信支付配置
|
||||
wx_mch_id: string
|
||||
wx_api_v2_key: string
|
||||
wx_api_v3_key: string
|
||||
wx_notify_url: string
|
||||
wx_serial_no: string
|
||||
wx_cert_content: string
|
||||
wx_key_content: string
|
||||
|
||||
// 富友支付配置
|
||||
fy_api_url: string
|
||||
fy_ins_cd: string
|
||||
fy_mchnt_cd: string
|
||||
fy_term_id: string
|
||||
fy_notify_url: string
|
||||
fy_private_key: string
|
||||
fy_public_key: string
|
||||
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 查询参数
|
||||
export interface WechatConfigQueryParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
provider_type?: PaymentProviderType
|
||||
is_active?: boolean
|
||||
}
|
||||
|
||||
// 列表响应
|
||||
export interface WechatConfigListResponse {
|
||||
items: WechatConfig[]
|
||||
page: number
|
||||
page_size: number
|
||||
total: number
|
||||
}
|
||||
|
||||
// 创建微信支付配置请求
|
||||
export interface CreateWechatConfigRequest {
|
||||
name: string
|
||||
provider_type: PaymentProviderType
|
||||
description?: string
|
||||
|
||||
// 小程序配置
|
||||
miniapp_app_id?: string
|
||||
miniapp_app_secret?: string
|
||||
|
||||
// 公众号配置
|
||||
oa_app_id?: string
|
||||
oa_app_secret?: string
|
||||
oa_token?: string
|
||||
oa_aes_key?: string
|
||||
oa_oauth_redirect_url?: string
|
||||
|
||||
// 微信支付配置
|
||||
wx_mch_id?: string
|
||||
wx_api_v2_key?: string
|
||||
wx_api_v3_key?: string
|
||||
wx_notify_url?: string
|
||||
wx_serial_no?: string
|
||||
wx_cert_content?: string
|
||||
wx_key_content?: string
|
||||
|
||||
// 富友支付配置
|
||||
fy_api_url?: string
|
||||
fy_ins_cd?: string
|
||||
fy_mchnt_cd?: string
|
||||
fy_term_id?: string
|
||||
fy_notify_url?: string
|
||||
fy_private_key?: string
|
||||
fy_public_key?: string
|
||||
}
|
||||
|
||||
// 更新微信支付配置请求
|
||||
export interface UpdateWechatConfigRequest {
|
||||
name?: string
|
||||
description?: string
|
||||
provider_type?: PaymentProviderType
|
||||
|
||||
// 小程序配置
|
||||
miniapp_app_id?: string
|
||||
miniapp_app_secret?: string
|
||||
|
||||
// 公众号配置
|
||||
oa_app_id?: string
|
||||
oa_app_secret?: string
|
||||
oa_token?: string
|
||||
oa_aes_key?: string
|
||||
oa_oauth_redirect_url?: string
|
||||
|
||||
// 微信支付配置
|
||||
wx_mch_id?: string
|
||||
wx_api_v2_key?: string
|
||||
wx_api_v3_key?: string
|
||||
wx_notify_url?: string
|
||||
wx_serial_no?: string
|
||||
wx_cert_content?: string
|
||||
wx_key_content?: string
|
||||
|
||||
// 富友支付配置
|
||||
fy_api_url?: string
|
||||
fy_ins_cd?: string
|
||||
fy_mchnt_cd?: string
|
||||
fy_term_id?: string
|
||||
fy_notify_url?: string
|
||||
fy_private_key?: string
|
||||
fy_public_key?: string
|
||||
}
|
||||
@@ -8,6 +8,10 @@
|
||||
<div class="section-title">提现配置</div>
|
||||
<WithdrawalSettings />
|
||||
|
||||
<!-- 支付配置 -->
|
||||
<div class="section-title">支付配置</div>
|
||||
<ActiveWechatConfig />
|
||||
|
||||
<!--<el-row :gutter="20">-->
|
||||
<!-- <el-col :xl="14" :lg="15" :xs="24">-->
|
||||
<!-- <TodaySales />-->
|
||||
@@ -54,6 +58,7 @@
|
||||
import VolumeServiceLevel from './widget/VolumeServiceLevel.vue'
|
||||
import CommissionSummary from './widget/CommissionSummary.vue'
|
||||
import WithdrawalSettings from './widget/WithdrawalSettings.vue'
|
||||
import ActiveWechatConfig from './widget/ActiveWechatConfig.vue'
|
||||
|
||||
defineOptions({ name: 'Analysis' })
|
||||
</script>
|
||||
|
||||
238
src/views/dashboard/analysis/widget/ActiveWechatConfig.vue
Normal file
238
src/views/dashboard/analysis/widget/ActiveWechatConfig.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<ElCard shadow="never" class="active-wechat-config-widget" v-if="activeConfig">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-left">
|
||||
<span class="header-title">当前生效支付配置</span>
|
||||
<ElTag type="success" effect="dark" size="small">生效中</ElTag>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<span class="creator-info">创建于 {{ formatDateTime(activeConfig.created_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="config-info">
|
||||
<div class="info-card">
|
||||
<div
|
||||
class="info-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">{{ activeConfig.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<div
|
||||
class="info-icon"
|
||||
style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
|
||||
>
|
||||
<i class="el-icon">💳</i>
|
||||
</div>
|
||||
<div class="info-content">
|
||||
<div class="info-label">支付渠道类型</div>
|
||||
<div class="info-value">{{ getProviderTypeText(activeConfig.provider_type) }}</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">{{ getMerchantId(activeConfig) }}</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">{{ activeConfig.is_active ? '已激活' : '未激活' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" v-else class="active-wechat-config-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 { WechatConfigService } from '@/api/modules'
|
||||
import { ElTag } from 'element-plus'
|
||||
import type { WechatConfig, PaymentProviderType } from '@/types/api'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
|
||||
defineOptions({ name: 'ActiveWechatConfigWidget' })
|
||||
|
||||
// 当前生效的支付配置
|
||||
const activeConfig = ref<WechatConfig | null>(null)
|
||||
|
||||
// 获取支付渠道类型文本
|
||||
const getProviderTypeText = (type: PaymentProviderType): string => {
|
||||
const typeMap: Record<PaymentProviderType, string> = {
|
||||
wechat: '微信直连',
|
||||
fuiou: '富友支付'
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
|
||||
// 获取商户号
|
||||
const getMerchantId = (config: WechatConfig): string => {
|
||||
if (config.provider_type === 'wechat') {
|
||||
return config.wx_mch_id || '-'
|
||||
}
|
||||
if (config.provider_type === 'fuiou') {
|
||||
return config.fy_mchnt_cd || '-'
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
// 加载当前生效配置
|
||||
const loadActiveConfig = async () => {
|
||||
try {
|
||||
const res = await WechatConfigService.getActiveWechatConfig()
|
||||
if (res.code === 0 && res.data) {
|
||||
activeConfig.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取当前生效支付配置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadActiveConfig()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.active-wechat-config-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;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
.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 {
|
||||
.creator-info {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-info {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 16px;
|
||||
|
||||
.info-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: var(--el-fill-color-blank);
|
||||
border-radius: 8px;
|
||||
|
||||
.info-icon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.info-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.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 (max-width: 768px) {
|
||||
.active-wechat-config-widget {
|
||||
.card-header {
|
||||
.header-left,
|
||||
.header-right {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.config-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<ElRow :gutter="20" class="commission-summary-widget">
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="8" :xl="4">
|
||||
<!-- 错误状态 -->
|
||||
<ElCard shadow="never" v-if="errorMsg" 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
|
||||
@@ -15,8 +24,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="8" :xl="4">
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
@@ -31,8 +38,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="8" :xl="4">
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
@@ -47,8 +52,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="8" :xl="4">
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
@@ -63,8 +66,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :md="12" :lg="8" :xl="4">
|
||||
<ElCard shadow="hover" class="stat-card-wrapper">
|
||||
<div class="stat-card">
|
||||
<div
|
||||
@@ -79,8 +80,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -90,6 +91,9 @@
|
||||
|
||||
defineOptions({ name: 'CommissionSummaryWidget' })
|
||||
|
||||
// 错误信息
|
||||
const errorMsg = ref<string>('')
|
||||
|
||||
// 佣金概览
|
||||
const summary = ref<MyCommissionSummary>({
|
||||
total_commission: 0,
|
||||
@@ -105,9 +109,19 @@
|
||||
const res = await CommissionService.getMyCommissionSummary()
|
||||
if (res.code === 0) {
|
||||
summary.value = res.data
|
||||
errorMsg.value = ''
|
||||
} else {
|
||||
// 显示错误信息
|
||||
errorMsg.value = res.msg || '获取佣金概览失败'
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('获取佣金概览失败:', error)
|
||||
// 尝试从错误响应中提取 msg
|
||||
if (error?.response?.data?.msg) {
|
||||
errorMsg.value = error.response.data.msg
|
||||
} else {
|
||||
errorMsg.value = '获取佣金概览失败'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,26 +132,50 @@
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.commission-summary-widget {
|
||||
&.error-state {
|
||||
.error-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;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.stat-card-wrapper {
|
||||
margin-bottom: 20px;
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
|
||||
.stat-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
font-size: 24px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0;
|
||||
@@ -148,13 +186,14 @@
|
||||
min-width: 0;
|
||||
|
||||
.stat-label {
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
overflow: hidden;
|
||||
@@ -165,10 +204,52 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@media (max-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 (max-width: 1200px) {
|
||||
.commission-summary-widget {
|
||||
.stat-card-wrapper {
|
||||
margin-bottom: 12px;
|
||||
flex: 1 1 calc(33.333% - 12px);
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.commission-summary-widget {
|
||||
.stats-container {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stat-card-wrapper {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.commission-summary-widget {
|
||||
.stat-card-wrapper {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
235
src/views/finance/agent-recharge/detail.vue
Normal file
235
src/views/finance/agent-recharge/detail.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<ArtDataViewer
|
||||
:service="loadDetailData"
|
||||
:card-title="pageTitle"
|
||||
@back="handleBack"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<ElDescriptions :column="2" border>
|
||||
<ElDescriptionsItem label="充值单号">
|
||||
{{ data.recharge_no }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="充值记录ID">
|
||||
{{ data.id }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="代理钱包ID">
|
||||
{{ data.agent_wallet_id }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="店铺ID">
|
||||
{{ data.shop_id }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="店铺名称">
|
||||
{{ data.shop_name }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="充值金额">
|
||||
<span style="color: var(--el-color-success); font-weight: bold">
|
||||
{{ formatCurrency(data.amount) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="状态">
|
||||
<ElTag :type="getStatusType(data.status)">
|
||||
{{ getStatusText(data.status) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="支付方式">
|
||||
{{ getPaymentMethodText(data.payment_method) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="支付通道">
|
||||
{{ data.payment_channel }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="支付配置ID">
|
||||
{{ data.payment_config_id || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="第三方支付流水号" :span="2">
|
||||
{{ data.payment_transaction_id || '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="创建时间">
|
||||
{{ formatDateTime(data.created_at) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="支付时间">
|
||||
{{ data.paid_at ? formatDateTime(data.paid_at) : '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="完成时间">
|
||||
{{ data.completed_at ? formatDateTime(data.completed_at) : '-' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="更新时间">
|
||||
{{ formatDateTime(data.updated_at) }}
|
||||
</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div style="margin-top: 20px; text-align: right">
|
||||
<ElButton v-if="data.status === 1 && data.payment_method === 'offline'" type="primary" @click="handleConfirmPay(data)">
|
||||
确认支付
|
||||
</ElButton>
|
||||
<ElButton @click="handleBack">返回列表</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ArtDataViewer>
|
||||
|
||||
<!-- 确认线下支付对话框 -->
|
||||
<ElDialog
|
||||
v-model="confirmPayDialogVisible"
|
||||
title="确认线下充值"
|
||||
width="400px"
|
||||
@closed="handleConfirmPayDialogClosed"
|
||||
>
|
||||
<ElForm
|
||||
ref="confirmPayFormRef"
|
||||
:model="confirmPayForm"
|
||||
:rules="confirmPayRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<ElFormItem label="充值单号">
|
||||
<span>{{ currentRecharge?.recharge_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="充值金额">
|
||||
<span>{{ formatCurrency(currentRecharge?.amount || 0) }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="操作密码" prop="operation_password">
|
||||
<ElInput
|
||||
v-model="confirmPayForm.operation_password"
|
||||
type="password"
|
||||
placeholder="请输入操作密码"
|
||||
show-password
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="confirmPayDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirmPaySubmit" :loading="confirmPayLoading">
|
||||
确认支付
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { AgentRechargeService } from '@/api/modules'
|
||||
import { ElMessage, ElTag } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
AgentRecharge,
|
||||
AgentRechargeStatus,
|
||||
AgentRechargePaymentMethod,
|
||||
ConfirmOfflinePaymentRequest
|
||||
} from '@/types/api'
|
||||
import ArtDataViewer from '@/components/core/views/ArtDataViewer.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'AgentRechargeDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const rechargeId = computed(() => Number(route.params.id))
|
||||
const pageTitle = computed(() => `充值订单详情 #${rechargeId.value}`)
|
||||
|
||||
const confirmPayDialogVisible = ref(false)
|
||||
const confirmPayLoading = ref(false)
|
||||
const currentRecharge = ref<AgentRecharge | null>(null)
|
||||
const confirmPayFormRef = ref<FormInstance>()
|
||||
|
||||
const confirmPayRules = reactive<FormRules>({
|
||||
operation_password: [{ required: true, message: '请输入操作密码', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const confirmPayForm = reactive<ConfirmOfflinePaymentRequest>({
|
||||
operation_password: ''
|
||||
})
|
||||
|
||||
// 格式化货币 - 将分转换为元
|
||||
const formatCurrency = (amount: number): string => {
|
||||
return `¥${(amount / 100).toFixed(2)}`
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: AgentRechargeStatus): 'warning' | 'success' | 'info' => {
|
||||
const statusMap: Record<AgentRechargeStatus, 'warning' | 'success' | 'info'> = {
|
||||
1: 'warning', // 待支付
|
||||
2: 'success', // 已完成
|
||||
3: 'info' // 已取消
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: AgentRechargeStatus): string => {
|
||||
const statusMap: Record<AgentRechargeStatus, string> = {
|
||||
1: '待支付',
|
||||
2: '已完成',
|
||||
3: '已取消'
|
||||
}
|
||||
return statusMap[status] || '-'
|
||||
}
|
||||
|
||||
// 获取支付方式文本
|
||||
const getPaymentMethodText = (method: AgentRechargePaymentMethod): string => {
|
||||
const methodMap: Record<AgentRechargePaymentMethod, string> = {
|
||||
wechat: '微信在线支付',
|
||||
offline: '线下转账'
|
||||
}
|
||||
return methodMap[method] || method
|
||||
}
|
||||
|
||||
// 加载详情数据
|
||||
const loadDetailData = async () => {
|
||||
const res = await AgentRechargeService.getAgentRechargeById(rechargeId.value)
|
||||
if (res.code === 0) {
|
||||
return res.data
|
||||
}
|
||||
throw new Error(res.msg || '加载失败')
|
||||
}
|
||||
|
||||
// 返回列表
|
||||
const handleBack = () => {
|
||||
router.push(RoutesAlias.AgentRecharge)
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
const handleRefresh = () => {
|
||||
// ArtDataViewer 会自动重新加载数据
|
||||
}
|
||||
|
||||
// 显示确认支付对话框
|
||||
const handleConfirmPay = (data: AgentRecharge) => {
|
||||
currentRecharge.value = data
|
||||
confirmPayDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认支付对话框关闭后的清理
|
||||
const handleConfirmPayDialogClosed = () => {
|
||||
confirmPayFormRef.value?.resetFields()
|
||||
confirmPayForm.operation_password = ''
|
||||
currentRecharge.value = null
|
||||
}
|
||||
|
||||
// 确认线下支付
|
||||
const handleConfirmPaySubmit = async () => {
|
||||
if (!confirmPayFormRef.value || !currentRecharge.value) return
|
||||
|
||||
await confirmPayFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
confirmPayLoading.value = true
|
||||
try {
|
||||
await AgentRechargeService.confirmOfflinePayment(currentRecharge.value!.id, {
|
||||
operation_password: confirmPayForm.operation_password
|
||||
})
|
||||
ElMessage.success('确认支付成功')
|
||||
confirmPayDialogVisible.value = false
|
||||
confirmPayFormRef.value.resetFields()
|
||||
// 刷新页面数据
|
||||
handleRefresh()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
confirmPayLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
642
src/views/finance/agent-recharge/index.vue
Normal file
642
src/views/finance/agent-recharge/index.vue
Normal file
@@ -0,0 +1,642 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="agent-recharge-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton type="primary" @click="showCreateDialog">创建充值订单</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="rechargeList"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 创建充值订单对话框 -->
|
||||
<ElDialog
|
||||
v-model="createDialogVisible"
|
||||
title="创建充值订单"
|
||||
width="500px"
|
||||
@closed="handleCreateDialogClosed"
|
||||
>
|
||||
<ElForm ref="createFormRef" :model="createForm" :rules="createRules" label-width="100px">
|
||||
<ElFormItem label="充值金额" prop="amount">
|
||||
<ElInputNumber
|
||||
v-model="createForm.amount"
|
||||
:min="100"
|
||||
:max="1000000"
|
||||
:precision="2"
|
||||
:step="100"
|
||||
style="width: 100%"
|
||||
placeholder="请输入充值金额(元)"
|
||||
/>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
||||
充值范围: ¥100 ~ ¥1,000,000
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="支付方式" prop="payment_method">
|
||||
<ElSelect
|
||||
v-model="createForm.payment_method"
|
||||
placeholder="请选择支付方式"
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="微信在线支付" value="wechat" />
|
||||
<!-- 只有平台用户才显示线下转账选项 -->
|
||||
<ElOption
|
||||
v-if="userStore.info.user_type === 1 || userStore.info.user_type === 2"
|
||||
label="线下转账"
|
||||
value="offline"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="目标店铺" prop="shop_id">
|
||||
<ElTreeSelect
|
||||
v-model="createForm.shop_id"
|
||||
:data="shopTreeData"
|
||||
placeholder="请选择店铺"
|
||||
filterable
|
||||
clearable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
:props="{
|
||||
label: 'shop_name',
|
||||
value: 'id',
|
||||
children: 'children'
|
||||
}"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="createDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleCreateRecharge" :loading="createLoading">
|
||||
确认创建
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 确认线下支付对话框 -->
|
||||
<ElDialog
|
||||
v-model="confirmPayDialogVisible"
|
||||
title="确认线下充值"
|
||||
width="400px"
|
||||
@closed="handleConfirmPayDialogClosed"
|
||||
>
|
||||
<ElForm
|
||||
ref="confirmPayFormRef"
|
||||
:model="confirmPayForm"
|
||||
:rules="confirmPayRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<ElFormItem label="充值单号">
|
||||
<span>{{ currentRecharge?.recharge_no }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="充值金额">
|
||||
<span>{{ formatCurrency(currentRecharge?.amount || 0) }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="操作密码" prop="operation_password">
|
||||
<ElInput
|
||||
v-model="confirmPayForm.operation_password"
|
||||
type="password"
|
||||
placeholder="请输入操作密码"
|
||||
show-password
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="confirmPayDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirmPay" :loading="confirmPayLoading">
|
||||
确认支付
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { AgentRechargeService, ShopService } from '@/api/modules'
|
||||
import { ElMessage, ElTag, ElTreeSelect } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
AgentRecharge,
|
||||
AgentRechargeQueryParams,
|
||||
AgentRechargeStatus,
|
||||
AgentRechargePaymentMethod,
|
||||
CreateAgentRechargeRequest,
|
||||
ConfirmOfflinePaymentRequest,
|
||||
ShopResponse
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'AgentRechargeList' })
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const loading = ref(false)
|
||||
const createLoading = ref(false)
|
||||
const confirmPayLoading = ref(false)
|
||||
const tableRef = ref()
|
||||
const createDialogVisible = ref(false)
|
||||
const confirmPayDialogVisible = ref(false)
|
||||
const currentRecharge = ref<AgentRecharge | null>(null)
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState: AgentRechargeQueryParams = {
|
||||
shop_id: undefined,
|
||||
status: undefined,
|
||||
start_date: '',
|
||||
end_date: ''
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive<AgentRechargeQueryParams>({ ...initialSearchState })
|
||||
|
||||
// 店铺选项
|
||||
const shopOptions = ref<any[]>([])
|
||||
const shopTreeData = ref<ShopResponse[]>([])
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '店铺',
|
||||
prop: 'shop_id',
|
||||
type: 'select',
|
||||
placeholder: '请选择店铺',
|
||||
options: () =>
|
||||
shopOptions.value.map((shop) => ({
|
||||
label: shop.shop_name,
|
||||
value: shop.id
|
||||
})),
|
||||
config: {
|
||||
clearable: true,
|
||||
filterable: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
placeholder: '请选择状态',
|
||||
options: [
|
||||
{ label: '待支付', value: 1 },
|
||||
{ label: '已完成', value: 2 },
|
||||
{ label: '已取消', value: 3 }
|
||||
],
|
||||
config: {
|
||||
clearable: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'dateRange',
|
||||
type: 'daterange',
|
||||
config: {
|
||||
clearable: true,
|
||||
startPlaceholder: '开始日期',
|
||||
endPlaceholder: '结束日期',
|
||||
valueFormat: 'YYYY-MM-DD'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '充值单号', prop: 'recharge_no' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '充值金额', prop: 'amount' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '支付方式', prop: 'payment_method' },
|
||||
{ label: '支付通道', prop: 'payment_channel' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '支付时间', prop: 'paid_at' },
|
||||
{ label: '完成时间', prop: 'completed_at' },
|
||||
{ label: '操作', prop: 'actions' }
|
||||
]
|
||||
|
||||
const createFormRef = ref<FormInstance>()
|
||||
const confirmPayFormRef = ref<FormInstance>()
|
||||
|
||||
const createRules = reactive<FormRules>({
|
||||
amount: [{ required: true, message: '请输入充值金额', trigger: 'blur' }],
|
||||
payment_method: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||||
shop_id: [{ required: true, message: '请选择目标店铺', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const confirmPayRules = reactive<FormRules>({
|
||||
operation_password: [{ required: true, message: '请输入操作密码', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const createForm = reactive<{ amount: number; payment_method: string; shop_id: number | null }>({
|
||||
amount: 100,
|
||||
payment_method: 'wechat',
|
||||
shop_id: null
|
||||
})
|
||||
|
||||
const confirmPayForm = reactive<ConfirmOfflinePaymentRequest>({
|
||||
operation_password: ''
|
||||
})
|
||||
|
||||
const rechargeList = ref<AgentRecharge[]>([])
|
||||
|
||||
// 格式化货币 - 将分转换为元
|
||||
const formatCurrency = (amount: number): string => {
|
||||
return `¥${(amount / 100).toFixed(2)}`
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
const getStatusType = (status: AgentRechargeStatus): 'warning' | 'success' | 'info' => {
|
||||
const statusMap: Record<AgentRechargeStatus, 'warning' | 'success' | 'info'> = {
|
||||
1: 'warning', // 待支付
|
||||
2: 'success', // 已完成
|
||||
3: 'info' // 已取消
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: AgentRechargeStatus): string => {
|
||||
const statusMap: Record<AgentRechargeStatus, string> = {
|
||||
1: '待支付',
|
||||
2: '已完成',
|
||||
3: '已取消'
|
||||
}
|
||||
return statusMap[status] || '-'
|
||||
}
|
||||
|
||||
// 获取支付方式文本
|
||||
const getPaymentMethodText = (method: AgentRechargePaymentMethod): string => {
|
||||
const methodMap: Record<AgentRechargePaymentMethod, string> = {
|
||||
wechat: '微信在线支付',
|
||||
offline: '线下转账'
|
||||
}
|
||||
return methodMap[method] || method
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'recharge_no',
|
||||
label: '充值单号',
|
||||
minWidth: 200,
|
||||
formatter: (row: AgentRecharge) => {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||||
onClick: (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
handleViewDetail(row)
|
||||
}
|
||||
},
|
||||
row.recharge_no
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
minWidth: 150
|
||||
},
|
||||
{
|
||||
prop: 'amount',
|
||||
label: '充值金额',
|
||||
width: 120,
|
||||
formatter: (row: AgentRecharge) => formatCurrency(row.amount)
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: AgentRecharge) => {
|
||||
return h(ElTag, { type: getStatusType(row.status) }, () => getStatusText(row.status))
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'payment_method',
|
||||
label: '支付方式',
|
||||
width: 120,
|
||||
formatter: (row: AgentRecharge) => getPaymentMethodText(row.payment_method)
|
||||
},
|
||||
{
|
||||
prop: 'payment_channel',
|
||||
label: '支付通道',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: AgentRecharge) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'paid_at',
|
||||
label: '支付时间',
|
||||
width: 180,
|
||||
formatter: (row: AgentRecharge) => (row.paid_at ? formatDateTime(row.paid_at) : '-')
|
||||
},
|
||||
{
|
||||
prop: 'completed_at',
|
||||
label: '完成时间',
|
||||
width: 180,
|
||||
formatter: (row: AgentRecharge) => (row.completed_at ? formatDateTime(row.completed_at) : '-')
|
||||
},
|
||||
{
|
||||
prop: 'actions',
|
||||
label: '操作',
|
||||
width: 150,
|
||||
fixed: 'right',
|
||||
formatter: (row: AgentRecharge) => {
|
||||
const buttons: any[] = []
|
||||
|
||||
// 待支付且线下转账的订单可以确认支付
|
||||
if (row.status === 1 && row.payment_method === 'offline') {
|
||||
buttons.push(
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: 'primary',
|
||||
link: true,
|
||||
size: 'small',
|
||||
onClick: () => handleShowConfirmPay(row)
|
||||
},
|
||||
() => '确认支付'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: 'primary',
|
||||
link: true,
|
||||
size: 'small',
|
||||
onClick: () => handleViewDetail(row)
|
||||
},
|
||||
() => '查看详情'
|
||||
)
|
||||
)
|
||||
|
||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
loadShops()
|
||||
})
|
||||
|
||||
// 构建树形数据
|
||||
const buildTreeData = (items: ShopResponse[]) => {
|
||||
const map = new Map<number, ShopResponse & { children?: ShopResponse[] }>()
|
||||
const tree: ShopResponse[] = []
|
||||
|
||||
// 先将所有项放入 map
|
||||
items.forEach((item) => {
|
||||
map.set(item.id, { ...item, children: [] })
|
||||
})
|
||||
|
||||
// 构建树形结构
|
||||
items.forEach((item) => {
|
||||
const node = map.get(item.id)!
|
||||
if (item.parent_id && map.has(item.parent_id)) {
|
||||
// 有父节点,添加到父节点的 children 中
|
||||
const parent = map.get(item.parent_id)!
|
||||
if (!parent.children) parent.children = []
|
||||
parent.children.push(node)
|
||||
} else {
|
||||
// 没有父节点或父节点不存在,作为根节点
|
||||
tree.push(node)
|
||||
}
|
||||
})
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
// 加载店铺列表
|
||||
const loadShops = async () => {
|
||||
try {
|
||||
const params: any = {
|
||||
page: 1,
|
||||
page_size: 9999 // 获取所有数据用于构建树形结构
|
||||
}
|
||||
const res = await ShopService.getShops(params)
|
||||
if (res.code === 0) {
|
||||
const items = res.data.items || []
|
||||
// 保留平铺列表用于搜索
|
||||
shopOptions.value = items
|
||||
// 构建树形数据用于创建对话框
|
||||
shopTreeData.value = buildTreeData(items)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Load shops failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取充值订单列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: AgentRechargeQueryParams = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.page_size,
|
||||
shop_id: searchForm.shop_id,
|
||||
status: searchForm.status,
|
||||
start_date: searchForm.start_date || undefined,
|
||||
end_date: searchForm.end_date || undefined
|
||||
}
|
||||
const res = await AgentRechargeService.getAgentRecharges(params)
|
||||
if (res.code === 0) {
|
||||
rechargeList.value = res.data.list || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const handleReset = () => {
|
||||
Object.assign(searchForm, { ...initialSearchState })
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
// 处理日期范围
|
||||
if (searchForm.dateRange && Array.isArray(searchForm.dateRange)) {
|
||||
searchForm.start_date = searchForm.dateRange[0]
|
||||
searchForm.end_date = searchForm.dateRange[1]
|
||||
} else {
|
||||
searchForm.start_date = ''
|
||||
searchForm.end_date = ''
|
||||
}
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 刷新表格
|
||||
const handleRefresh = () => {
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.page_size = newPageSize
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.page = newCurrentPage
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 显示创建订单对话框
|
||||
const showCreateDialog = async () => {
|
||||
createDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 对话框关闭后的清理
|
||||
const handleCreateDialogClosed = () => {
|
||||
createFormRef.value?.resetFields()
|
||||
createForm.amount = 100
|
||||
createForm.payment_method = 'wechat'
|
||||
createForm.shop_id = null
|
||||
}
|
||||
|
||||
// 创建充值订单
|
||||
const handleCreateRecharge = async () => {
|
||||
if (!createFormRef.value) return
|
||||
|
||||
await createFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
createLoading.value = true
|
||||
try {
|
||||
const data: CreateAgentRechargeRequest = {
|
||||
amount: createForm.amount * 100, // 元转分
|
||||
payment_method: createForm.payment_method as AgentRechargePaymentMethod,
|
||||
shop_id: createForm.shop_id!
|
||||
}
|
||||
|
||||
await AgentRechargeService.createAgentRecharge(data)
|
||||
ElMessage.success('充值订单创建成功')
|
||||
createDialogVisible.value = false
|
||||
createFormRef.value.resetFields()
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
createLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示确认支付对话框
|
||||
const handleShowConfirmPay = (row: AgentRecharge) => {
|
||||
currentRecharge.value = row
|
||||
confirmPayDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认支付对话框关闭后的清理
|
||||
const handleConfirmPayDialogClosed = () => {
|
||||
confirmPayFormRef.value?.resetFields()
|
||||
confirmPayForm.operation_password = ''
|
||||
currentRecharge.value = null
|
||||
}
|
||||
|
||||
// 确认线下支付
|
||||
const handleConfirmPay = async () => {
|
||||
if (!confirmPayFormRef.value || !currentRecharge.value) return
|
||||
|
||||
await confirmPayFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
confirmPayLoading.value = true
|
||||
try {
|
||||
await AgentRechargeService.confirmOfflinePayment(currentRecharge.value.id, {
|
||||
operation_password: confirmPayForm.operation_password
|
||||
})
|
||||
ElMessage.success('确认支付成功')
|
||||
confirmPayDialogVisible.value = false
|
||||
confirmPayFormRef.value.resetFields()
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
confirmPayLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleViewDetail = (row: AgentRecharge) => {
|
||||
router.push({
|
||||
path: `${RoutesAlias.AgentRecharge}/detail/${row.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.agent-recharge-page {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -177,7 +177,12 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="钱包支付" value="wallet" />
|
||||
<ElOption label="线下支付" value="offline" />
|
||||
<!-- 只有平台用户(user_type 1:超级管理员, 2:平台用户)才显示线下支付选项 -->
|
||||
<ElOption
|
||||
v-if="userStore.info.user_type === 1 || userStore.info.user_type === 2"
|
||||
label="线下支付"
|
||||
value="offline"
|
||||
/>
|
||||
</ElSelect>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--el-text-color-secondary)">
|
||||
<template v-if="createForm.payment_method === 'wallet'">
|
||||
@@ -312,12 +317,15 @@
|
||||
OrderCommissionStatus,
|
||||
StandaloneIotCard,
|
||||
Device,
|
||||
PackageResponse
|
||||
PackageResponse,
|
||||
PurchaseCheckRequest,
|
||||
PurchaseCheckResponse
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useTableContextMenu } from '@/composables/useTableContextMenu'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
@@ -330,6 +338,7 @@
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const { hasAuth } = useAuth()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
@@ -1000,6 +1009,43 @@
|
||||
if (valid) {
|
||||
createLoading.value = true
|
||||
try {
|
||||
// 获取资源ID (IoT卡ID或设备ID)
|
||||
const resourceId =
|
||||
createForm.order_type === 'single_card'
|
||||
? createForm.iot_card_id
|
||||
: createForm.device_id
|
||||
|
||||
if (!resourceId) {
|
||||
ElMessage.error('请选择IoT卡或设备')
|
||||
return
|
||||
}
|
||||
|
||||
// 调用套餐购买预检接口
|
||||
const checkData: PurchaseCheckRequest = {
|
||||
order_type: createForm.order_type,
|
||||
package_ids: createForm.package_ids,
|
||||
resource_id: resourceId
|
||||
}
|
||||
|
||||
const checkResponse = await OrderService.purchaseCheck(checkData)
|
||||
|
||||
// 检查预检结果
|
||||
if (checkResponse.code === 0 && checkResponse.data) {
|
||||
const checkResult = checkResponse.data
|
||||
|
||||
// 如果需要强充,显示确认对话框
|
||||
if (checkResult.need_force_recharge) {
|
||||
const confirmMessage = `${checkResult.message || '钱包余额不足'}\n\n套餐总价: ¥${(checkResult.total_package_amount! / 100).toFixed(2)}\n需要强充: ¥${(checkResult.force_recharge_amount! / 100).toFixed(2)}\n钱包到账: ¥${(checkResult.wallet_credit! / 100).toFixed(2)}\n实际支付: ¥${(checkResult.actual_payment! / 100).toFixed(2)}\n\n是否继续创建订单?`
|
||||
|
||||
await ElMessageBox.confirm(confirmMessage, '购买预检提示', {
|
||||
confirmButtonText: '继续创建',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 预检通过或用户确认后,创建订单
|
||||
const data: CreateOrderRequest = {
|
||||
order_type: createForm.order_type,
|
||||
package_ids: createForm.package_ids,
|
||||
@@ -1020,7 +1066,11 @@
|
||||
createDialogVisible.value = false
|
||||
formEl.resetFields()
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
// 用户取消确认对话框
|
||||
if (error === 'cancel') {
|
||||
return
|
||||
}
|
||||
console.error(error)
|
||||
} finally {
|
||||
createLoading.value = false
|
||||
|
||||
@@ -72,10 +72,7 @@
|
||||
clearable
|
||||
style="flex: 1"
|
||||
/>
|
||||
<CodeGeneratorButton
|
||||
code-type="shop"
|
||||
@generated="handleCodeGenerated"
|
||||
/>
|
||||
<CodeGeneratorButton code-type="shop" @generated="handleCodeGenerated" />
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
@@ -241,14 +238,14 @@
|
||||
<div v-if="selectedRoleId" class="current-role-display">
|
||||
<div class="current-role-label">当前默认角色</div>
|
||||
<div class="current-role-value">
|
||||
{{ availableRoles.find((r) => r.role_id === selectedRoleId)?.role_name || '未知角色' }}
|
||||
{{
|
||||
availableRoles.find((r) => r.role_id === selectedRoleId)?.role_name || '未知角色'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="current-role-display no-role">
|
||||
<div class="current-role-label">当前默认角色</div>
|
||||
<div class="current-role-value">
|
||||
暂未设置
|
||||
</div>
|
||||
<div class="current-role-value"> 暂未设置 </div>
|
||||
</div>
|
||||
|
||||
<!-- 默认角色选择 -->
|
||||
@@ -463,7 +460,7 @@
|
||||
]
|
||||
|
||||
// 显示对话框
|
||||
const showDialog = (type: string, row?: ShopResponse) => {
|
||||
const showDialog = async (type: string, row?: ShopResponse) => {
|
||||
dialogType.value = type
|
||||
|
||||
// 先清除验证状态
|
||||
@@ -492,6 +489,9 @@
|
||||
formData.init_phone = ''
|
||||
formData.default_role_id = undefined
|
||||
} else {
|
||||
// 新增模式下重新获取上级店铺列表
|
||||
await loadParentShopList()
|
||||
|
||||
formData.id = 0
|
||||
formData.shop_name = ''
|
||||
formData.shop_code = ''
|
||||
@@ -529,7 +529,9 @@
|
||||
try {
|
||||
await ShopService.deleteShop(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
getShopList()
|
||||
await getShopList()
|
||||
// 删除成功后也更新上级店铺列表
|
||||
await loadParentShopList()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
@@ -544,13 +546,13 @@
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
minWidth: 160,
|
||||
width: 160,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'shop_code',
|
||||
label: '店铺编号',
|
||||
width: 140,
|
||||
minWidth: 160,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
@@ -865,7 +867,9 @@
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
getShopList()
|
||||
await getShopList()
|
||||
// 提交成功后也更新上级店铺列表
|
||||
await loadParentShopList()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
|
||||
307
src/views/settings/wechat-config/detail.vue
Normal file
307
src/views/settings/wechat-config/detail.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div class="wechat-config-detail-page">
|
||||
<ElCard shadow="never">
|
||||
<!-- 页面头部 -->
|
||||
<div class="detail-header">
|
||||
<ElButton @click="handleBack">
|
||||
<template #icon>
|
||||
<ElIcon><ArrowLeft /></ElIcon>
|
||||
</template>
|
||||
返回
|
||||
</ElButton>
|
||||
<h2 class="detail-title">{{ pageTitle }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
<DetailPage v-if="detailData" :sections="detailSections" :data="detailData" />
|
||||
|
||||
<!-- 加载中 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<ElIcon class="is-loading"><Loading /></ElIcon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElCard, ElButton, ElIcon, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import DetailPage from '@/components/common/DetailPage.vue'
|
||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||
import { WechatConfigService } from '@/api/modules'
|
||||
import type { WechatConfig, PaymentProviderType } from '@/types/api'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'WechatConfigDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
const detailData = ref<WechatConfig | null>(null)
|
||||
|
||||
const configId = computed(() => Number(route.params.id))
|
||||
const pageTitle = computed(() => `支付配置详情 #${configId.value}`)
|
||||
|
||||
// 获取支付渠道类型文本
|
||||
const getProviderTypeText = (type: PaymentProviderType): string => {
|
||||
const typeMap: Record<PaymentProviderType, string> = {
|
||||
wechat: '微信直连',
|
||||
fuiou: '富友支付'
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
|
||||
// 获取配置状态文本
|
||||
const getConfigStatus = (value: string | undefined | null): string => {
|
||||
if (!value) return '未配置'
|
||||
return value === 'configured' ? '已配置' : value
|
||||
}
|
||||
|
||||
// 基础详情配置
|
||||
const baseSection: DetailSection = {
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '配置ID', prop: 'id' },
|
||||
{ label: '配置名称', prop: 'name' },
|
||||
{
|
||||
label: '支付渠道类型',
|
||||
formatter: (_, data) => getProviderTypeText(data.provider_type)
|
||||
},
|
||||
{
|
||||
label: '激活状态',
|
||||
formatter: (_, data) => (data.is_active ? '已激活' : '未激活')
|
||||
},
|
||||
{
|
||||
label: '配置描述',
|
||||
prop: 'description',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
prop: 'created_at',
|
||||
formatter: (value) => formatDateTime(value)
|
||||
},
|
||||
{
|
||||
label: '更新时间',
|
||||
prop: 'updated_at',
|
||||
formatter: (value) => formatDateTime(value)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 微信小程序配置
|
||||
const miniappSection: DetailSection = {
|
||||
title: '小程序配置',
|
||||
fields: [
|
||||
{
|
||||
label: '小程序AppID',
|
||||
prop: 'miniapp_app_id',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '小程序AppSecret',
|
||||
prop: 'miniapp_app_secret',
|
||||
formatter: (value) => value || '-'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 微信公众号配置
|
||||
const oaSection: DetailSection = {
|
||||
title: '公众号配置',
|
||||
fields: [
|
||||
{
|
||||
label: '公众号AppID',
|
||||
prop: 'oa_app_id',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '公众号AppSecret',
|
||||
prop: 'oa_app_secret',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '公众号Token',
|
||||
prop: 'oa_token',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '公众号AES Key',
|
||||
prop: 'oa_aes_key',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: 'OAuth回调地址',
|
||||
prop: 'oa_oauth_redirect_url',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 微信支付配置
|
||||
const wechatPaySection: DetailSection = {
|
||||
title: '微信支付配置',
|
||||
fields: [
|
||||
{
|
||||
label: '微信商户号',
|
||||
prop: 'wx_mch_id',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '证书序列号',
|
||||
prop: 'wx_serial_no',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: 'APIv2密钥',
|
||||
prop: 'wx_api_v2_key',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: 'APIv3密钥',
|
||||
prop: 'wx_api_v3_key',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '支付回调地址',
|
||||
prop: 'wx_notify_url',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '支付证书',
|
||||
prop: 'wx_cert_content',
|
||||
formatter: (value) => getConfigStatus(value)
|
||||
},
|
||||
{
|
||||
label: '支付密钥',
|
||||
prop: 'wx_key_content',
|
||||
formatter: (value) => getConfigStatus(value)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 富友支付配置
|
||||
const fuiouSection: DetailSection = {
|
||||
title: '富友支付配置',
|
||||
fields: [
|
||||
{
|
||||
label: '富友API地址',
|
||||
prop: 'fy_api_url',
|
||||
formatter: (value) => value || '-',
|
||||
fullWidth: true
|
||||
},
|
||||
{
|
||||
label: '富友机构号',
|
||||
prop: 'fy_ins_cd',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '富友商户号',
|
||||
prop: 'fy_mchnt_cd',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '富友终端号',
|
||||
prop: 'fy_term_id',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '支付回调地址',
|
||||
prop: 'fy_notify_url',
|
||||
formatter: (value) => value || '-'
|
||||
},
|
||||
{
|
||||
label: '富友私钥',
|
||||
prop: 'fy_private_key',
|
||||
formatter: (value) => getConfigStatus(value)
|
||||
},
|
||||
{
|
||||
label: '富友公钥',
|
||||
prop: 'fy_public_key',
|
||||
formatter: (value) => getConfigStatus(value)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 根据支付类型动态构建详情配置
|
||||
const detailSections = computed<DetailSection[]>(() => {
|
||||
if (!detailData.value) return [baseSection]
|
||||
|
||||
const sections = [baseSection]
|
||||
|
||||
if (detailData.value.provider_type === 'wechat') {
|
||||
sections.push(miniappSection, oaSection, wechatPaySection)
|
||||
} else if (detailData.value.provider_type === 'fuiou') {
|
||||
sections.push(fuiouSection)
|
||||
}
|
||||
|
||||
return sections
|
||||
})
|
||||
|
||||
// 返回列表
|
||||
const handleBack = () => {
|
||||
router.push(RoutesAlias.WechatConfig)
|
||||
}
|
||||
|
||||
// 获取详情数据
|
||||
const fetchDetail = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await WechatConfigService.getWechatConfigById(configId.value)
|
||||
if (res.code === 0) {
|
||||
detailData.value = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
ElMessage.error('获取支付配置详情失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchDetail()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wechat-config-detail-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.detail-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
gap: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
863
src/views/settings/wechat-config/index.vue
Normal file
863
src/views/settings/wechat-config/index.vue
Normal file
@@ -0,0 +1,863 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="wechat-config-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
label-width="100"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton type="primary" @click="showCreateDialog">新增支付配置</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="configList"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:row-class-name="getRowClassName"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-contextmenu="handleRowContextMenu"
|
||||
@cell-mouse-enter="handleCellMouseEnter"
|
||||
@cell-mouse-leave="handleCellMouseLeave"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 鼠标悬浮提示 -->
|
||||
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
|
||||
|
||||
<!-- 支付配置操作右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="configOperationMenuRef"
|
||||
:menu-items="configOperationMenuItems"
|
||||
:menu-width="140"
|
||||
@select="handleConfigOperationMenuSelect"
|
||||
/>
|
||||
|
||||
<!-- 创建/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增支付配置' : '编辑支付配置'"
|
||||
width="800px"
|
||||
@closed="handleDialogClosed"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="130px">
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="配置名称" prop="name">
|
||||
<ElInput v-model="form.name" placeholder="请输入配置名称" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="支付渠道类型" prop="provider_type">
|
||||
<ElSelect
|
||||
v-model="form.provider_type"
|
||||
placeholder="请选择支付渠道类型"
|
||||
style="width: 100%"
|
||||
:disabled="dialogType === 'edit'"
|
||||
>
|
||||
<ElOption label="微信直连" value="wechat" />
|
||||
<ElOption label="富友支付" value="fuiou" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElFormItem label="配置描述" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入配置描述"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<!-- 微信相关配置 -->
|
||||
<template v-if="form.provider_type === 'wechat'">
|
||||
<ElDivider content-position="left">小程序配置</ElDivider>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="小程序AppID" prop="miniapp_app_id">
|
||||
<ElInput v-model="form.miniapp_app_id" placeholder="请输入小程序AppID" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="小程序AppSecret" prop="miniapp_app_secret">
|
||||
<ElInput
|
||||
v-model="form.miniapp_app_secret"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入小程序AppSecret"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElDivider content-position="left">公众号配置</ElDivider>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="公众号AppID" prop="oa_app_id">
|
||||
<ElInput v-model="form.oa_app_id" placeholder="请输入公众号AppID" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="公众号AppSecret" prop="oa_app_secret">
|
||||
<ElInput
|
||||
v-model="form.oa_app_secret"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入公众号AppSecret"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="公众号Token" prop="oa_token">
|
||||
<ElInput
|
||||
v-model="form.oa_token"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入公众号Token"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="公众号AES Key" prop="oa_aes_key">
|
||||
<ElInput
|
||||
v-model="form.oa_aes_key"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入公众号AES加密Key"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElFormItem label="OAuth回调地址" prop="oa_oauth_redirect_url">
|
||||
<ElInput v-model="form.oa_oauth_redirect_url" placeholder="请输入OAuth回调地址" />
|
||||
</ElFormItem>
|
||||
|
||||
<ElDivider content-position="left">微信支付配置</ElDivider>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="微信商户号" prop="wx_mch_id">
|
||||
<ElInput v-model="form.wx_mch_id" placeholder="请输入微信商户号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="证书序列号" prop="wx_serial_no">
|
||||
<ElInput v-model="form.wx_serial_no" placeholder="请输入微信证书序列号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="APIv2密钥" prop="wx_api_v2_key">
|
||||
<ElInput
|
||||
v-model="form.wx_api_v2_key"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入微信APIv2密钥"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="APIv3密钥" prop="wx_api_v3_key">
|
||||
<ElInput
|
||||
v-model="form.wx_api_v3_key"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入微信APIv3密钥"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElFormItem label="支付回调地址" prop="wx_notify_url">
|
||||
<ElInput v-model="form.wx_notify_url" placeholder="请输入微信支付回调地址" />
|
||||
</ElFormItem>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="支付证书" prop="wx_cert_content">
|
||||
<ElInput
|
||||
v-model="form.wx_cert_content"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请粘贴PEM格式证书内容"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="支付密钥" prop="wx_key_content">
|
||||
<ElInput
|
||||
v-model="form.wx_key_content"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请粘贴PEM格式密钥内容"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</template>
|
||||
|
||||
<!-- 富友支付配置 -->
|
||||
<template v-if="form.provider_type === 'fuiou'">
|
||||
<ElDivider content-position="left">富友支付配置</ElDivider>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友API地址" prop="fy_api_url">
|
||||
<ElInput v-model="form.fy_api_url" placeholder="请输入富友API地址" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友机构号" prop="fy_ins_cd">
|
||||
<ElInput v-model="form.fy_ins_cd" placeholder="请输入富友机构号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友商户号" prop="fy_mchnt_cd">
|
||||
<ElInput v-model="form.fy_mchnt_cd" placeholder="请输入富友商户号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友终端号" prop="fy_term_id">
|
||||
<ElInput v-model="form.fy_term_id" placeholder="请输入富友终端号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElFormItem label="支付回调地址" prop="fy_notify_url">
|
||||
<ElInput v-model="form.fy_notify_url" placeholder="请输入富友支付回调地址" />
|
||||
</ElFormItem>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友私钥" prop="fy_private_key">
|
||||
<ElInput
|
||||
v-model="form.fy_private_key"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请粘贴PEM格式私钥内容"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="富友公钥" prop="fy_public_key">
|
||||
<ElInput
|
||||
v-model="form.fy_public_key"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请粘贴PEM格式公钥内容"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit" :loading="submitLoading">
|
||||
提交
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { WechatConfigService } from '@/api/modules'
|
||||
import { ElMessage, ElTag, ElMessageBox, ElSwitch, ElButton } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
WechatConfig,
|
||||
WechatConfigQueryParams,
|
||||
PaymentProviderType,
|
||||
CreateWechatConfigRequest,
|
||||
UpdateWechatConfigRequest
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useTableContextMenu } from '@/composables/useTableContextMenu'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'WechatConfigList' })
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const tableRef = ref()
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref<'add' | 'edit'>('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
// 右键菜单
|
||||
const configOperationMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentOperatingConfig = ref<WechatConfig | null>(null)
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
provider_type: undefined as PaymentProviderType | undefined,
|
||||
is_active: undefined as number | undefined
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({ ...initialSearchState })
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '支付渠道类型',
|
||||
prop: 'provider_type',
|
||||
type: 'select',
|
||||
placeholder: '请选择支付渠道类型',
|
||||
options: [
|
||||
{ label: '微信直连', value: 'wechat' },
|
||||
{ label: '富友支付', value: 'fuiou' }
|
||||
],
|
||||
config: {
|
||||
clearable: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '激活状态',
|
||||
prop: 'is_active',
|
||||
type: 'select',
|
||||
placeholder: '请选择激活状态',
|
||||
options: [
|
||||
{ label: '已激活', value: 1 },
|
||||
{ label: '未激活', value: 0 }
|
||||
],
|
||||
config: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '配置名称', prop: 'name' },
|
||||
{ label: '支付渠道类型', prop: 'provider_type' },
|
||||
{ label: '激活状态', prop: 'is_active' },
|
||||
{ label: '商户号', prop: 'merchant_id' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '更新时间', prop: 'updated_at' }
|
||||
]
|
||||
|
||||
// 动态表单验证规则
|
||||
const rules = computed<FormRules>(() => {
|
||||
const baseRules: FormRules = {
|
||||
name: [{ required: true, message: '请输入配置名称', trigger: 'blur' }],
|
||||
provider_type: [{ required: true, message: '请选择支付渠道类型', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 只在创建模式下添加必填验证
|
||||
if (dialogType.value === 'add') {
|
||||
if (form.provider_type === 'wechat') {
|
||||
// 微信直连必填字段
|
||||
baseRules.wx_mch_id = [{ required: true, message: '请输入微信商户号', trigger: 'blur' }]
|
||||
baseRules.wx_api_v3_key = [
|
||||
{ required: true, message: '请输入微信APIv3密钥', trigger: 'blur' }
|
||||
]
|
||||
baseRules.wx_cert_content = [
|
||||
{ required: true, message: '请输入微信支付证书内容', trigger: 'blur' }
|
||||
]
|
||||
baseRules.wx_key_content = [
|
||||
{ required: true, message: '请输入微信支付密钥内容', trigger: 'blur' }
|
||||
]
|
||||
baseRules.wx_serial_no = [
|
||||
{ required: true, message: '请输入微信证书序列号', trigger: 'blur' }
|
||||
]
|
||||
baseRules.wx_notify_url = [
|
||||
{ required: true, message: '请输入微信支付回调地址', trigger: 'blur' }
|
||||
]
|
||||
} else if (form.provider_type === 'fuiou') {
|
||||
// 富友支付必填字段
|
||||
baseRules.fy_api_url = [{ required: true, message: '请输入富友API地址', trigger: 'blur' }]
|
||||
baseRules.fy_ins_cd = [{ required: true, message: '请输入富友机构号', trigger: 'blur' }]
|
||||
baseRules.fy_mchnt_cd = [{ required: true, message: '请输入富友商户号', trigger: 'blur' }]
|
||||
baseRules.fy_term_id = [{ required: true, message: '请输入富友终端号', trigger: 'blur' }]
|
||||
baseRules.fy_private_key = [{ required: true, message: '请输入富友私钥', trigger: 'blur' }]
|
||||
baseRules.fy_public_key = [{ required: true, message: '请输入富友公钥', trigger: 'blur' }]
|
||||
baseRules.fy_notify_url = [
|
||||
{ required: true, message: '请输入富友支付回调地址', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
return baseRules
|
||||
})
|
||||
|
||||
const initialFormState = {
|
||||
name: '',
|
||||
provider_type: 'wechat' as PaymentProviderType,
|
||||
description: '',
|
||||
miniapp_app_id: '',
|
||||
miniapp_app_secret: '',
|
||||
oa_app_id: '',
|
||||
oa_app_secret: '',
|
||||
oa_token: '',
|
||||
oa_aes_key: '',
|
||||
oa_oauth_redirect_url: '',
|
||||
wx_mch_id: '',
|
||||
wx_api_v2_key: '',
|
||||
wx_api_v3_key: '',
|
||||
wx_notify_url: '',
|
||||
wx_serial_no: '',
|
||||
wx_cert_content: '',
|
||||
wx_key_content: '',
|
||||
fy_api_url: '',
|
||||
fy_ins_cd: '',
|
||||
fy_mchnt_cd: '',
|
||||
fy_term_id: '',
|
||||
fy_notify_url: '',
|
||||
fy_private_key: '',
|
||||
fy_public_key: ''
|
||||
}
|
||||
|
||||
const form = reactive({ id: 0, ...initialFormState })
|
||||
|
||||
const configList = ref<WechatConfig[]>([])
|
||||
|
||||
// 获取支付渠道类型文本
|
||||
const getProviderTypeText = (type: PaymentProviderType): string => {
|
||||
const typeMap: Record<PaymentProviderType, string> = {
|
||||
wechat: '微信直连',
|
||||
fuiou: '富友支付'
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
|
||||
// 获取商户号
|
||||
const getMerchantId = (row: WechatConfig): string => {
|
||||
if (row.provider_type === 'wechat') {
|
||||
return row.wx_mch_id || '-'
|
||||
}
|
||||
if (row.provider_type === 'fuiou') {
|
||||
return row.fy_mchnt_cd || '-'
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'name',
|
||||
label: '配置名称',
|
||||
minWidth: 180,
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: WechatConfig) => {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||||
onClick: (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
handleNameClick(row)
|
||||
}
|
||||
},
|
||||
row.name
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'provider_type',
|
||||
label: '支付渠道类型',
|
||||
width: 130,
|
||||
formatter: (row: WechatConfig) => getProviderTypeText(row.provider_type)
|
||||
},
|
||||
{
|
||||
prop: 'is_active',
|
||||
label: '激活状态',
|
||||
width: 100,
|
||||
formatter: (row: WechatConfig) => {
|
||||
return h(ElSwitch, {
|
||||
modelValue: row.is_active,
|
||||
activeText: '已激活',
|
||||
inactiveText: '未激活',
|
||||
inlinePrompt: true,
|
||||
'onUpdate:modelValue': (val) => handleStatusChange(row, val)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'merchant_id',
|
||||
label: '商户号',
|
||||
width: 150,
|
||||
formatter: (row: WechatConfig) => getMerchantId(row)
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: WechatConfig) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'updated_at',
|
||||
label: '更新时间',
|
||||
width: 180,
|
||||
formatter: (row: WechatConfig) => formatDateTime(row.updated_at)
|
||||
}
|
||||
])
|
||||
|
||||
// 监听支付渠道类型变化,清除表单验证
|
||||
watch(
|
||||
() => form.provider_type,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
getTableData()
|
||||
})
|
||||
|
||||
// 获取配置列表
|
||||
const getTableData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: WechatConfigQueryParams = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.page_size,
|
||||
provider_type: searchForm.provider_type,
|
||||
is_active: searchForm.is_active !== undefined ? searchForm.is_active === 1 : undefined
|
||||
}
|
||||
const res = await WechatConfigService.getWechatConfigs(params)
|
||||
if (res.code === 0) {
|
||||
configList.value = res.data.items || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const handleReset = () => {
|
||||
Object.assign(searchForm, { ...initialSearchState })
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 刷新表格
|
||||
const handleRefresh = () => {
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.page_size = newPageSize
|
||||
getTableData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.page = newCurrentPage
|
||||
getTableData()
|
||||
}
|
||||
|
||||
// 显示创建对话框
|
||||
const showCreateDialog = () => {
|
||||
dialogType.value = 'add'
|
||||
Object.assign(form, { id: 0, ...initialFormState })
|
||||
dialogVisible.value = true
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
// 显示编辑对话框
|
||||
const showEditDialog = (row: WechatConfig) => {
|
||||
dialogType.value = 'edit'
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
provider_type: row.provider_type,
|
||||
description: row.description,
|
||||
miniapp_app_id: row.miniapp_app_id,
|
||||
miniapp_app_secret: '',
|
||||
oa_app_id: row.oa_app_id,
|
||||
oa_app_secret: '',
|
||||
oa_token: '',
|
||||
oa_aes_key: '',
|
||||
oa_oauth_redirect_url: row.oa_oauth_redirect_url,
|
||||
wx_mch_id: row.wx_mch_id,
|
||||
wx_api_v2_key: '',
|
||||
wx_api_v3_key: '',
|
||||
wx_notify_url: row.wx_notify_url,
|
||||
wx_serial_no: row.wx_serial_no,
|
||||
wx_cert_content: '',
|
||||
wx_key_content: '',
|
||||
fy_api_url: row.fy_api_url,
|
||||
fy_ins_cd: row.fy_ins_cd,
|
||||
fy_mchnt_cd: row.fy_mchnt_cd,
|
||||
fy_term_id: row.fy_term_id,
|
||||
fy_notify_url: row.fy_notify_url,
|
||||
fy_private_key: '',
|
||||
fy_public_key: ''
|
||||
})
|
||||
dialogVisible.value = true
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
// 对话框关闭后的清理
|
||||
const handleDialogClosed = () => {
|
||||
formRef.value?.resetFields()
|
||||
Object.assign(form, { id: 0, ...initialFormState })
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
const data: CreateWechatConfigRequest = {
|
||||
name: form.name,
|
||||
provider_type: form.provider_type,
|
||||
description: form.description || undefined,
|
||||
miniapp_app_id: form.miniapp_app_id || undefined,
|
||||
miniapp_app_secret: form.miniapp_app_secret || undefined,
|
||||
oa_app_id: form.oa_app_id || undefined,
|
||||
oa_app_secret: form.oa_app_secret || undefined,
|
||||
oa_token: form.oa_token || undefined,
|
||||
oa_aes_key: form.oa_aes_key || undefined,
|
||||
oa_oauth_redirect_url: form.oa_oauth_redirect_url || undefined,
|
||||
wx_mch_id: form.wx_mch_id || undefined,
|
||||
wx_api_v2_key: form.wx_api_v2_key || undefined,
|
||||
wx_api_v3_key: form.wx_api_v3_key || undefined,
|
||||
wx_notify_url: form.wx_notify_url || undefined,
|
||||
wx_serial_no: form.wx_serial_no || undefined,
|
||||
wx_cert_content: form.wx_cert_content || undefined,
|
||||
wx_key_content: form.wx_key_content || undefined,
|
||||
fy_api_url: form.fy_api_url || undefined,
|
||||
fy_ins_cd: form.fy_ins_cd || undefined,
|
||||
fy_mchnt_cd: form.fy_mchnt_cd || undefined,
|
||||
fy_term_id: form.fy_term_id || undefined,
|
||||
fy_notify_url: form.fy_notify_url || undefined,
|
||||
fy_private_key: form.fy_private_key || undefined,
|
||||
fy_public_key: form.fy_public_key || undefined
|
||||
}
|
||||
await WechatConfigService.createWechatConfig(data)
|
||||
ElMessage.success('创建成功')
|
||||
} else {
|
||||
const data: UpdateWechatConfigRequest = {
|
||||
name: form.name,
|
||||
description: form.description || undefined
|
||||
}
|
||||
// 只有填写了新值才更新敏感字段
|
||||
if (form.miniapp_app_secret) data.miniapp_app_secret = form.miniapp_app_secret
|
||||
if (form.oa_app_secret) data.oa_app_secret = form.oa_app_secret
|
||||
if (form.oa_token) data.oa_token = form.oa_token
|
||||
if (form.oa_aes_key) data.oa_aes_key = form.oa_aes_key
|
||||
if (form.wx_api_v2_key) data.wx_api_v2_key = form.wx_api_v2_key
|
||||
if (form.wx_api_v3_key) data.wx_api_v3_key = form.wx_api_v3_key
|
||||
if (form.wx_cert_content) data.wx_cert_content = form.wx_cert_content
|
||||
if (form.wx_key_content) data.wx_key_content = form.wx_key_content
|
||||
if (form.fy_private_key) data.fy_private_key = form.fy_private_key
|
||||
if (form.fy_public_key) data.fy_public_key = form.fy_public_key
|
||||
|
||||
// 非敏感字段总是更新
|
||||
if (form.miniapp_app_id) data.miniapp_app_id = form.miniapp_app_id
|
||||
if (form.oa_app_id) data.oa_app_id = form.oa_app_id
|
||||
if (form.oa_oauth_redirect_url) data.oa_oauth_redirect_url = form.oa_oauth_redirect_url
|
||||
if (form.wx_mch_id) data.wx_mch_id = form.wx_mch_id
|
||||
if (form.wx_notify_url) data.wx_notify_url = form.wx_notify_url
|
||||
if (form.wx_serial_no) data.wx_serial_no = form.wx_serial_no
|
||||
if (form.fy_api_url) data.fy_api_url = form.fy_api_url
|
||||
if (form.fy_ins_cd) data.fy_ins_cd = form.fy_ins_cd
|
||||
if (form.fy_mchnt_cd) data.fy_mchnt_cd = form.fy_mchnt_cd
|
||||
if (form.fy_term_id) data.fy_term_id = form.fy_term_id
|
||||
if (form.fy_notify_url) data.fy_notify_url = form.fy_notify_url
|
||||
|
||||
await WechatConfigService.updateWechatConfig(form.id, data)
|
||||
ElMessage.success('更新成功')
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
formRef.value?.resetFields()
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 激活/停用状态切换
|
||||
const handleStatusChange = async (row: WechatConfig, newStatus: string | number | boolean) => {
|
||||
const newBoolStatus = Boolean(newStatus)
|
||||
const oldStatus = row.is_active
|
||||
row.is_active = newBoolStatus
|
||||
try {
|
||||
if (newBoolStatus) {
|
||||
await WechatConfigService.activateWechatConfig(row.id)
|
||||
ElMessage.success('激活成功')
|
||||
} else {
|
||||
await WechatConfigService.deactivateWechatConfig(row.id)
|
||||
ElMessage.success('停用成功')
|
||||
}
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
row.is_active = oldStatus
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除配置
|
||||
const handleDelete = async (row: WechatConfig) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要删除支付配置"${row.name}"吗?`, '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
await WechatConfigService.deleteWechatConfig(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
await getTableData()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleViewDetail = (row: WechatConfig) => {
|
||||
router.push({
|
||||
path: `${RoutesAlias.WechatConfig}/detail/${row.id}`
|
||||
})
|
||||
}
|
||||
|
||||
// 处理名称点击
|
||||
const handleNameClick = (row: WechatConfig) => {
|
||||
handleViewDetail(row)
|
||||
}
|
||||
|
||||
// 支付配置操作菜单项配置
|
||||
const configOperationMenuItems = computed((): MenuItemType[] => {
|
||||
const items: MenuItemType[] = []
|
||||
|
||||
// 编辑
|
||||
items.push({
|
||||
key: 'edit',
|
||||
label: '编辑'
|
||||
})
|
||||
|
||||
// 删除
|
||||
items.push({
|
||||
key: 'delete',
|
||||
label: '删除'
|
||||
})
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
// 显示支付配置操作右键菜单
|
||||
const showConfigOperationMenu = (e: MouseEvent, row: WechatConfig) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
currentOperatingConfig.value = row
|
||||
configOperationMenuRef.value?.show(e)
|
||||
}
|
||||
|
||||
// 处理表格行右键菜单
|
||||
const handleRowContextMenu = (row: WechatConfig, column: any, event: MouseEvent) => {
|
||||
showConfigOperationMenu(event, row)
|
||||
}
|
||||
|
||||
// 处理支付配置操作菜单选择
|
||||
const handleConfigOperationMenuSelect = (item: MenuItemType) => {
|
||||
if (!currentOperatingConfig.value) return
|
||||
|
||||
switch (item.key) {
|
||||
case 'edit':
|
||||
showEditDialog(currentOperatingConfig.value)
|
||||
break
|
||||
case 'delete':
|
||||
handleDelete(currentOperatingConfig.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 使用表格右键菜单功能
|
||||
const {
|
||||
showContextMenuHint,
|
||||
hintPosition,
|
||||
getRowClassName,
|
||||
handleCellMouseEnter,
|
||||
handleCellMouseLeave
|
||||
} = useTableContextMenu()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.wechat-config-page {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-table__row.table-row-with-context-menu) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user