feat: 完善15- 角色默认信用与店铺实际额度管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m8s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m8s
This commit is contained in:
@@ -20,7 +20,7 @@ Non-Goals:
|
|||||||
|
|
||||||
- 角色默认信用保存到 `PUT /api/admin/roles/{id}/default-credit`,请求体为 `credit_enabled` 和 `credit_limit`。
|
- 角色默认信用保存到 `PUT /api/admin/roles/{id}/default-credit`,请求体为 `credit_enabled` 和 `credit_limit`。
|
||||||
- 店铺实际信用额度保存到 `PUT /api/admin/shops/{id}/credit-limit`,请求体为 `credit_enabled`、`credit_limit` 和 `version`。
|
- 店铺实际信用额度保存到 `PUT /api/admin/shops/{id}/credit-limit`,请求体为 `credit_enabled`、`credit_limit` 和 `version`。
|
||||||
- 资金概况继续通过 `GET /api/admin/shops/fund-summary` 获取,前端展示 `balance`、`frozen_balance`、`credit_enabled`、`credit_limit`、`available_balance`、`is_in_debt`、`debt_amount` 和 `version`。
|
- 资金概况继续通过 `GET /api/admin/shops/fund-summary` 获取,前端展示 `main_balance`、`main_frozen_balance`、`cash_available_balance`、`credit_enabled`、`credit_limit`、`available_balance`、`is_in_debt`、`debt_amount` 和 `version`。
|
||||||
- 调整弹框展示修改前后金额预览,但最终可用金额、欠款金额和欠款状态仍以后端刷新后的资金概况为准。
|
- 调整弹框展示修改前后金额预览,但最终可用金额、欠款金额和欠款状态仍以后端刷新后的资金概况为准。
|
||||||
|
|
||||||
## Risks / Trade-offs
|
## Risks / Trade-offs
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ The agent fund overview page SHALL display shop actual credit and fund summary f
|
|||||||
|
|
||||||
- **GIVEN** 用户进入代理商资金概况页
|
- **GIVEN** 用户进入代理商资金概况页
|
||||||
- **WHEN** `GET /api/admin/shops/fund-summary` 返回资金概况记录
|
- **WHEN** `GET /api/admin/shops/fund-summary` 返回资金概况记录
|
||||||
- **THEN** 页面 MUST 展示现金余额 `balance`
|
- **THEN** 页面 MUST 展示账面余额 `main_balance`
|
||||||
- **AND** 页面 MUST 展示冻结金额 `frozen_balance`
|
- **AND** 页面 MUST 展示冻结金额 `main_frozen_balance`
|
||||||
- **AND** 页面 MUST 展示实际信用额度 `credit_limit`
|
- **AND** 页面 MUST 展示实际信用额度 `credit_limit`
|
||||||
- **AND** 页面 MUST 展示可用金额 `available_balance`
|
- **AND** 页面 MUST 展示可用金额 `available_balance`
|
||||||
- **AND** 页面 MUST 展示欠款金额 `debt_amount`
|
- **AND** 页面 MUST 展示欠款金额 `debt_amount`
|
||||||
@@ -74,8 +74,9 @@ The frontend SHALL read actual credit fields from `GET /api/admin/shops/fund-sum
|
|||||||
#### Scenario: Read actual credit response fields
|
#### Scenario: Read actual credit response fields
|
||||||
|
|
||||||
- **WHEN** 前端请求 `GET /api/admin/shops/fund-summary`
|
- **WHEN** 前端请求 `GET /api/admin/shops/fund-summary`
|
||||||
- **THEN** 前端 MUST read `balance`
|
- **THEN** 前端 MUST read `main_balance`
|
||||||
- **AND** 前端 MUST read `frozen_balance`
|
- **AND** 前端 MUST read `main_frozen_balance`
|
||||||
|
- **AND** 前端 MUST read `cash_available_balance`
|
||||||
- **AND** 前端 MUST read `credit_enabled`
|
- **AND** 前端 MUST read `credit_enabled`
|
||||||
- **AND** 前端 MUST read `credit_limit`
|
- **AND** 前端 MUST read `credit_limit`
|
||||||
- **AND** 前端 MUST read `available_balance`
|
- **AND** 前端 MUST read `available_balance`
|
||||||
|
|||||||
@@ -37,6 +37,6 @@
|
|||||||
|
|
||||||
- 角色默认信用保存只调用角色默认信用接口,店铺资金概况只读取后端返回的实际额度,未发现前端同步历史店铺额度的逻辑。
|
- 角色默认信用保存只调用角色默认信用接口,店铺资金概况只读取后端返回的实际额度,未发现前端同步历史店铺额度的逻辑。
|
||||||
- 店铺创建参数未包含信用额度字段,实际额度初始化由后端按所选客户角色处理。
|
- 店铺创建参数未包含信用额度字段,实际额度初始化由后端按所选客户角色处理。
|
||||||
- 资金概况列表直接展示 `balance`、`frozen_balance`、`credit_limit`、`available_balance`、`debt_amount`、`version` 和后端欠款状态字段。
|
- 资金概况列表直接展示 `main_balance`、`main_frozen_balance`、`credit_limit`、`available_balance`、`debt_amount`、`version` 和后端欠款状态字段。
|
||||||
- 关闭信用时角色配置和店铺调额表单均将额度归零,并以 `credit_limit=0` 提交。
|
- 关闭信用时角色配置和店铺调额表单均将额度归零,并以 `credit_limit=0` 提交。
|
||||||
- 调额响应或异常命中版本冲突时,页面提示并重新加载资金概况。
|
- 调额响应或异常命中版本冲突时,页面提示并重新加载资金概况。
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
## 4. Verification
|
## 4. Verification
|
||||||
|
|
||||||
- [ ] 4.1 验证创建、编辑、清空业务员和无可选账号状态。
|
- [x] 4.1 验证创建、编辑、清空业务员和无可选账号状态。
|
||||||
- [ ] 4.2 验证列表业务员展示和按业务员筛选正确。
|
- [x] 4.2 验证列表业务员展示和按业务员筛选正确。
|
||||||
- [ ] 4.3 验证详情对历史停用业务员仍能展示名称和手机号摘要。
|
- [x] 4.3 验证详情对历史停用业务员仍能展示名称和手机号摘要。
|
||||||
- [x] 4.4 确认页面不引入分销、佣金或发展层级文案。
|
- [x] 4.4 确认页面不引入分销、佣金或发展层级文案。
|
||||||
- [x] 4.5 运行相关前端校验,并执行 `openspec validate update-shop-salesperson-selection --strict`。
|
- [x] 4.5 运行相关前端校验,并执行 `openspec validate update-shop-salesperson-selection --strict`。
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {
|
|||||||
RoleQueryParams,
|
RoleQueryParams,
|
||||||
PlatformRoleFormData,
|
PlatformRoleFormData,
|
||||||
UpdateRoleDefaultCreditRequest,
|
UpdateRoleDefaultCreditRequest,
|
||||||
|
UpdateRoleDefaultCreditResponse,
|
||||||
BaseResponse,
|
BaseResponse,
|
||||||
PaginationResponse
|
PaginationResponse
|
||||||
} from '@/types/api'
|
} from '@/types/api'
|
||||||
@@ -47,7 +48,7 @@ export class RoleService extends BaseService {
|
|||||||
* @param id 角色ID
|
* @param id 角色ID
|
||||||
* @param data 角色数据
|
* @param data 角色数据
|
||||||
*/
|
*/
|
||||||
static updateRole(id: number, data: PlatformRoleFormData): Promise<BaseResponse> {
|
static updateRole(id: number, data: Partial<PlatformRoleFormData>): Promise<BaseResponse> {
|
||||||
return this.update(`/api/admin/roles/${id}`, data)
|
return this.update(`/api/admin/roles/${id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +61,11 @@ export class RoleService extends BaseService {
|
|||||||
static updateRoleDefaultCredit(
|
static updateRoleDefaultCredit(
|
||||||
id: number,
|
id: number,
|
||||||
data: UpdateRoleDefaultCreditRequest
|
data: UpdateRoleDefaultCreditRequest
|
||||||
): Promise<BaseResponse> {
|
): Promise<BaseResponse<UpdateRoleDefaultCreditResponse>> {
|
||||||
return this.put<BaseResponse>(`/api/admin/roles/${id}/default-credit`, data)
|
return this.put<BaseResponse<UpdateRoleDefaultCreditResponse>>(
|
||||||
|
`/api/admin/roles/${id}/default-credit`,
|
||||||
|
data
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type {
|
|||||||
ShopRolesResponse,
|
ShopRolesResponse,
|
||||||
AssignShopRolesRequest,
|
AssignShopRolesRequest,
|
||||||
UpdateShopCreditLimitRequest,
|
UpdateShopCreditLimitRequest,
|
||||||
|
UpdateShopCreditLimitResponse,
|
||||||
BaseResponse,
|
BaseResponse,
|
||||||
PaginationResponse,
|
PaginationResponse,
|
||||||
ShopBusinessOwnerCandidate,
|
ShopBusinessOwnerCandidate,
|
||||||
@@ -148,7 +149,10 @@ export class ShopService extends BaseService {
|
|||||||
static updateShopCreditLimit(
|
static updateShopCreditLimit(
|
||||||
shopId: number,
|
shopId: number,
|
||||||
data: UpdateShopCreditLimitRequest
|
data: UpdateShopCreditLimitRequest
|
||||||
): Promise<BaseResponse> {
|
): Promise<BaseResponse<UpdateShopCreditLimitResponse>> {
|
||||||
return this.put<BaseResponse>(`/api/admin/shops/${shopId}/credit-limit`, data)
|
return this.put<BaseResponse<UpdateShopCreditLimitResponse>>(
|
||||||
|
`/api/admin/shops/${shopId}/credit-limit`,
|
||||||
|
data
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,18 @@ export const asyncRoutes: AppRouteRecord[] = [
|
|||||||
roles: ['R_SUPER']
|
roles: ['R_SUPER']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'role/detail/:id',
|
||||||
|
name: 'RoleDetail',
|
||||||
|
component: RoutesAlias.RoleDetail,
|
||||||
|
meta: {
|
||||||
|
title: '角色详情',
|
||||||
|
permissions: ['role:detail'],
|
||||||
|
isHide: true,
|
||||||
|
keepAlive: false,
|
||||||
|
roles: ['R_SUPER']
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'permission',
|
path: 'permission',
|
||||||
name: 'PermissionManagement',
|
name: 'PermissionManagement',
|
||||||
@@ -261,6 +273,17 @@ export const asyncRoutes: AppRouteRecord[] = [
|
|||||||
title: 'menus.shopManagement.shopList',
|
title: 'menus.shopManagement.shopList',
|
||||||
keepAlive: true
|
keepAlive: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// 店铺详情
|
||||||
|
{
|
||||||
|
path: 'detail/:id',
|
||||||
|
name: 'ShopDetail',
|
||||||
|
component: RoutesAlias.ShopDetail,
|
||||||
|
meta: {
|
||||||
|
title: '店铺详情',
|
||||||
|
isHide: true,
|
||||||
|
keepAlive: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export enum RoutesAlias {
|
|||||||
|
|
||||||
// 系统管理
|
// 系统管理
|
||||||
Role = '/system/role', // 角色
|
Role = '/system/role', // 角色
|
||||||
|
RoleDetail = '/system/role/detail', // 角色详情
|
||||||
Permission = '/system/permission', // 权限管理
|
Permission = '/system/permission', // 权限管理
|
||||||
CarrierManagement = '/system/carrier-management', // 运营商管理
|
CarrierManagement = '/system/carrier-management', // 运营商管理
|
||||||
UserCenter = '/system/user-center', // 用户中心
|
UserCenter = '/system/user-center', // 用户中心
|
||||||
@@ -33,6 +34,7 @@ export enum RoutesAlias {
|
|||||||
|
|
||||||
// 店铺管理
|
// 店铺管理
|
||||||
Shop = '/shop-management/list', // 店铺列表
|
Shop = '/shop-management/list', // 店铺列表
|
||||||
|
ShopDetail = '/shop-management/detail', // 店铺详情
|
||||||
|
|
||||||
// 通用页面(店铺账号-企业账号)
|
// 通用页面(店铺账号-企业账号)
|
||||||
EnterpriseCustomerAccounts = '/common/account-list', // 企业客户账号列表和店铺账号列表共用
|
EnterpriseCustomerAccounts = '/common/account-list', // 企业客户账号列表和店铺账号列表共用
|
||||||
|
|||||||
@@ -211,10 +211,8 @@ export interface ShopFundSummaryItem {
|
|||||||
phone?: string // 主账号手机号
|
phone?: string // 主账号手机号
|
||||||
main_balance: number // 预充值余额(分)
|
main_balance: number // 预充值余额(分)
|
||||||
main_frozen_balance: number // 预充值冻结余额(分)
|
main_frozen_balance: number // 预充值冻结余额(分)
|
||||||
balance: number // 现金余额(分)
|
cash_available_balance: number // 现金可用余额(分)
|
||||||
frozen_balance: number // 现金冻结金额(分)
|
low_balance_warning?: boolean // 现金可用余额不足100元预警
|
||||||
cash_available: number // 现金可用余额(分)
|
|
||||||
low_balance_warning: boolean // 现金可用余额不足100元预警
|
|
||||||
credit_enabled: boolean // 实际信用额度是否启用
|
credit_enabled: boolean // 实际信用额度是否启用
|
||||||
credit_limit: number // 实际信用额度(分)
|
credit_limit: number // 实际信用额度(分)
|
||||||
available_balance: number // 可用金额(分),以后端返回为准
|
available_balance: number // 可用金额(分),以后端返回为准
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export enum RoleStatus {
|
|||||||
|
|
||||||
// 角色实体(匹配后端 ModelRole)
|
// 角色实体(匹配后端 ModelRole)
|
||||||
export interface PlatformRole {
|
export interface PlatformRole {
|
||||||
|
id?: number
|
||||||
ID: number
|
ID: number
|
||||||
CreatedAt?: string
|
CreatedAt?: string
|
||||||
UpdatedAt?: string
|
UpdatedAt?: string
|
||||||
@@ -30,6 +31,19 @@ export interface PlatformRole {
|
|||||||
status: RoleStatus // 状态
|
status: RoleStatus // 状态
|
||||||
credit_enabled?: boolean // 新建代理默认信用是否启用(仅客户角色)
|
credit_enabled?: boolean // 新建代理默认信用是否启用(仅客户角色)
|
||||||
credit_limit?: number // 新建代理默认信用额度(分,仅客户角色)
|
credit_limit?: number // 新建代理默认信用额度(分,仅客户角色)
|
||||||
|
default_credit_enabled?: boolean // 接口返回的新建代理默认信用状态
|
||||||
|
default_credit_limit?: number // 接口返回的新建代理默认信用额度(分)
|
||||||
|
default_credit_scope?: string // 接口返回的信用模板生效范围
|
||||||
|
created_at?: string // 接口返回的创建时间
|
||||||
|
updated_at?: string // 接口返回的更新时间
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateRoleDefaultCreditResponse {
|
||||||
|
affects_existing_wallets: boolean
|
||||||
|
credit_enabled: boolean
|
||||||
|
credit_limit: number
|
||||||
|
role_id: number
|
||||||
|
scope: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 角色查询参数
|
// 角色查询参数
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface ShopResponse {
|
|||||||
contact_name: string // 联系人姓名
|
contact_name: string // 联系人姓名
|
||||||
contact_phone: string // 联系人电话
|
contact_phone: string // 联系人电话
|
||||||
status: number // 状态 (0:禁用, 1:启用)
|
status: number // 状态 (0:禁用, 1:启用)
|
||||||
|
status_name?: string // 状态名称
|
||||||
business_owner_account_id: number | null // 平台业务员账号ID
|
business_owner_account_id: number | null // 平台业务员账号ID
|
||||||
business_owner_username: string // 平台业务员账号名
|
business_owner_username: string // 平台业务员账号名
|
||||||
business_owner_phone_summary: string // 平台业务员手机号摘要
|
business_owner_phone_summary: string // 平台业务员手机号摘要
|
||||||
@@ -49,6 +50,7 @@ export interface CreateShopParams {
|
|||||||
init_username: string // 初始账号用户名(必填)
|
init_username: string // 初始账号用户名(必填)
|
||||||
init_password: string // 初始账号密码(必填)
|
init_password: string // 初始账号密码(必填)
|
||||||
init_phone: string // 初始账号手机号(必填)
|
init_phone: string // 初始账号手机号(必填)
|
||||||
|
default_role_id: number // 初始账号默认客户角色(必填)
|
||||||
parent_id?: number | null // 上级店铺ID(一级店铺可不填)
|
parent_id?: number | null // 上级店铺ID(一级店铺可不填)
|
||||||
province?: string // 省份
|
province?: string // 省份
|
||||||
city?: string // 城市
|
city?: string // 城市
|
||||||
@@ -121,3 +123,15 @@ export interface UpdateShopCreditLimitRequest {
|
|||||||
credit_limit: number // 实际信用额度(分)
|
credit_limit: number // 实际信用额度(分)
|
||||||
version: number // 资金概况版本,用于并发控制
|
version: number // 资金概况版本,用于并发控制
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新店铺实际信用额度响应
|
||||||
|
export interface UpdateShopCreditLimitResponse {
|
||||||
|
available_balance: number // 总可用金额(分)
|
||||||
|
balance: number // 账面余额(分)
|
||||||
|
credit_enabled: boolean // 是否启用实际信用额度
|
||||||
|
credit_limit: number // 实际信用额度(分)
|
||||||
|
frozen_balance: number // 冻结金额(分)
|
||||||
|
shop_id: number // 店铺 ID
|
||||||
|
version: number // 更新后的钱包版本
|
||||||
|
wallet_id: number // 主钱包 ID
|
||||||
|
}
|
||||||
|
|||||||
@@ -618,8 +618,8 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value < 0) {
|
if (value <= 0) {
|
||||||
callback(new Error('实际信用额度不能小于0'))
|
callback(new Error('实际信用额度必须大于0'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,12 +655,13 @@
|
|||||||
{ label: '店铺名称', prop: 'shop_name' },
|
{ label: '店铺名称', prop: 'shop_name' },
|
||||||
{ label: '用户名', prop: 'username' },
|
{ label: '用户名', prop: 'username' },
|
||||||
{ label: '手机号', prop: 'phone' },
|
{ label: '手机号', prop: 'phone' },
|
||||||
{ label: '现金余额', prop: 'balance' },
|
{ label: '账面余额', prop: 'main_balance' },
|
||||||
{ label: '冻结金额', prop: 'frozen_balance' },
|
{ label: '冻结金额', prop: 'main_frozen_balance' },
|
||||||
|
{ label: '现金可用', prop: 'cash_available_balance' },
|
||||||
{ label: '实际信用额度', prop: 'credit_limit' },
|
{ label: '实际信用额度', prop: 'credit_limit' },
|
||||||
{ label: '可用金额', prop: 'available_balance' },
|
{ label: '总可用金额', prop: 'available_balance' },
|
||||||
{ label: '欠款金额', prop: 'debt_amount' },
|
{ label: '欠款金额', prop: 'debt_amount' },
|
||||||
{ label: '版本', prop: 'version' },
|
{ label: '钱包版本', prop: 'version' },
|
||||||
{ label: '余额预警', prop: 'low_balance_warning' },
|
{ label: '余额预警', prop: 'low_balance_warning' },
|
||||||
{ label: '总佣金', prop: 'total_commission' },
|
{ label: '总佣金', prop: 'total_commission' },
|
||||||
{ label: '可提现', prop: 'available_commission' },
|
{ label: '可提现', prop: 'available_commission' },
|
||||||
@@ -748,22 +749,28 @@
|
|||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'balance',
|
prop: 'main_balance',
|
||||||
label: '现金余额',
|
label: '账面余额',
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
formatter: (row: ShopFundSummaryItem) => {
|
formatter: (row: ShopFundSummaryItem) => {
|
||||||
return h(
|
return h(
|
||||||
'span',
|
'span',
|
||||||
{ style: 'color: var(--el-color-primary); font-weight: 500' },
|
{ style: 'color: var(--el-color-primary); font-weight: 500' },
|
||||||
formatMoney(row.balance)
|
formatMoney(row.main_balance)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'frozen_balance',
|
prop: 'main_frozen_balance',
|
||||||
label: '冻结金额',
|
label: '冻结金额',
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
formatter: (row: ShopFundSummaryItem) => formatMoney(row.frozen_balance)
|
formatter: (row: ShopFundSummaryItem) => formatMoney(row.main_frozen_balance)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'cash_available_balance',
|
||||||
|
label: '现金可用',
|
||||||
|
minWidth: 120,
|
||||||
|
formatter: (row: ShopFundSummaryItem) => formatMoney(row.cash_available_balance)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'credit_limit',
|
prop: 'credit_limit',
|
||||||
@@ -783,7 +790,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'available_balance',
|
prop: 'available_balance',
|
||||||
label: '可用金额',
|
label: '总可用金额',
|
||||||
minWidth: 130,
|
minWidth: 130,
|
||||||
formatter: (row: ShopFundSummaryItem) => {
|
formatter: (row: ShopFundSummaryItem) => {
|
||||||
return h(
|
return h(
|
||||||
@@ -806,7 +813,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'version',
|
prop: 'version',
|
||||||
label: '版本',
|
label: '钱包版本',
|
||||||
minWidth: 90,
|
minWidth: 90,
|
||||||
formatter: (row: ShopFundSummaryItem) => row.version ?? '-'
|
formatter: (row: ShopFundSummaryItem) => row.version ?? '-'
|
||||||
},
|
},
|
||||||
@@ -957,11 +964,13 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasAuth('shop:credit-limit:manage')) {
|
||||||
actions.push({
|
actions.push({
|
||||||
label: '调整额度',
|
label: '调整额度',
|
||||||
handler: () => showCreditDialog(row),
|
handler: () => showCreditDialog(row),
|
||||||
type: 'primary'
|
type: 'primary'
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|||||||
108
src/views/shop-management/detail/index.vue
Normal file
108
src/views/shop-management/detail/index.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div class="shop-detail-page">
|
||||||
|
<ElCard shadow="never">
|
||||||
|
<div class="detail-header">
|
||||||
|
<ElButton @click="handleBack">
|
||||||
|
<template #icon>
|
||||||
|
<ElIcon><ArrowLeft /></ElIcon>
|
||||||
|
</template>
|
||||||
|
返回
|
||||||
|
</ElButton>
|
||||||
|
<h2 class="detail-title">店铺详情</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-loading="loading">
|
||||||
|
<ElDescriptions v-if="shop" :column="2" border>
|
||||||
|
<ElDescriptionsItem label="店铺名称">{{ shop.shop_name || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="店铺编号">{{ shop.shop_code || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="店铺层级">{{ shop.level }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="上级店铺">{{ shop.parent_shop_name || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="联系人">{{ shop.contact_name || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="联系电话">{{ shop.contact_phone || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="平台业务员">
|
||||||
|
{{ formatBusinessOwner(shop) }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="业务员通知状态">
|
||||||
|
{{ shop.business_owner_account_id ? (shop.business_owner_available ? '可用' : '已停用') : '-' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="省份">{{ shop.province || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="城市">{{ shop.city || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="区县">{{ shop.district || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="详细地址">{{ shop.address || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="状态">{{ shop.status_name || shop.status }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="创建时间">{{ shop.created_at || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="更新时间">{{ shop.updated_at || '-' }}</ElDescriptionsItem>
|
||||||
|
</ElDescriptions>
|
||||||
|
</div>
|
||||||
|
</ElCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { ShopService } from '@/api/modules'
|
||||||
|
import type { ShopResponse } from '@/types/api'
|
||||||
|
|
||||||
|
defineOptions({ name: 'ShopDetail' })
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = ref(false)
|
||||||
|
const shop = ref<ShopResponse | null>(null)
|
||||||
|
|
||||||
|
const formatBusinessOwner = (value: ShopResponse) => {
|
||||||
|
if (!value.business_owner_username) return '-'
|
||||||
|
return value.business_owner_phone_summary
|
||||||
|
? `${value.business_owner_username} (${value.business_owner_phone_summary})`
|
||||||
|
: value.business_owner_username
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => router.back()
|
||||||
|
|
||||||
|
const fetchDetail = async () => {
|
||||||
|
const id = Number(route.params.id)
|
||||||
|
if (!id) {
|
||||||
|
ElMessage.error('缺少店铺 ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const response = await ShopService.getShopDetail(id)
|
||||||
|
if (response.code !== 0 || !response.data) {
|
||||||
|
ElMessage.error(response.msg || '获取店铺详情失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
shop.value = response.data
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '获取店铺详情失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(fetchDetail)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.shop-detail-page {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
:items="searchFormItems"
|
:items="searchFormItems"
|
||||||
show-expand
|
show-expand
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
|
label-width="100px"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
></ArtSearchBar>
|
></ArtSearchBar>
|
||||||
|
|
||||||
@@ -203,9 +204,9 @@
|
|||||||
>
|
>
|
||||||
<ElOption
|
<ElOption
|
||||||
v-for="role in defaultRoleList"
|
v-for="role in defaultRoleList"
|
||||||
:key="role.ID"
|
:key="role.id"
|
||||||
:label="role.role_name"
|
:label="role.role_name"
|
||||||
:value="role.ID"
|
:value="role.id"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style="display: flex; align-items: center; justify-content: space-between"
|
style="display: flex; align-items: center; justify-content: space-between"
|
||||||
@@ -238,16 +239,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</ElDialog>
|
</ElDialog>
|
||||||
|
|
||||||
<ElDialog v-model="detailDialogVisible" title="店铺详情" width="500px">
|
|
||||||
<ElDescriptions v-if="detailShop" :column="1" border>
|
|
||||||
<ElDescriptionsItem label="店铺名称">{{ detailShop.shop_name }}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="店铺编号">{{ detailShop.shop_code }}</ElDescriptionsItem>
|
|
||||||
<ElDescriptionsItem label="平台业务员">
|
|
||||||
{{ formatBusinessOwner(detailShop) }}
|
|
||||||
</ElDescriptionsItem>
|
|
||||||
</ElDescriptions>
|
|
||||||
</ElDialog>
|
|
||||||
|
|
||||||
<!-- 店铺默认角色管理对话框 -->
|
<!-- 店铺默认角色管理对话框 -->
|
||||||
<ElDialog
|
<ElDialog
|
||||||
v-model="defaultRolesDialogVisible"
|
v-model="defaultRolesDialogVisible"
|
||||||
@@ -339,6 +330,7 @@
|
|||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
|
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
|
||||||
import { regionData } from '@/utils/constants/regionData'
|
import { regionData } from '@/utils/constants/regionData'
|
||||||
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
|
|
||||||
defineOptions({ name: 'Shop' })
|
defineOptions({ name: 'Shop' })
|
||||||
|
|
||||||
@@ -354,8 +346,6 @@
|
|||||||
const defaultRoleList = ref<any[]>([])
|
const defaultRoleList = ref<any[]>([])
|
||||||
const salespersonLoading = ref(false)
|
const salespersonLoading = ref(false)
|
||||||
const salespersonOptions = ref<ShopBusinessOwnerCandidate[]>([])
|
const salespersonOptions = ref<ShopBusinessOwnerCandidate[]>([])
|
||||||
const detailDialogVisible = ref(false)
|
|
||||||
const detailShop = ref<ShopResponse | null>(null)
|
|
||||||
|
|
||||||
// 级联选择相关
|
// 级联选择相关
|
||||||
const parentShopCascadeOptions = ref<any[]>([])
|
const parentShopCascadeOptions = ref<any[]>([])
|
||||||
@@ -445,19 +435,12 @@
|
|||||||
: shop.business_owner_username
|
: shop.business_owner_username
|
||||||
}
|
}
|
||||||
|
|
||||||
const showDetail = async (row: ShopResponse) => {
|
const handleNameClick = (row: ShopResponse) => {
|
||||||
try {
|
if (hasAuth('shop:detail')) {
|
||||||
const response = await ShopService.getShopDetail(row.id)
|
void router.push(`${RoutesAlias.ShopDetail}/${row.id}`)
|
||||||
if (response.code !== 0 || !response.data) {
|
} else {
|
||||||
ElMessage.error(response.msg || '获取店铺详情失败')
|
ElMessage.warning('您没有查看详情的权限')
|
||||||
return
|
|
||||||
}
|
}
|
||||||
detailShop.value = response.data
|
|
||||||
} catch (error: any) {
|
|
||||||
ElMessage.error(error?.message || '获取店铺详情失败')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
detailDialogVisible.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义表单搜索初始值
|
// 定义表单搜索初始值
|
||||||
@@ -689,7 +672,25 @@
|
|||||||
prop: 'shop_name',
|
prop: 'shop_name',
|
||||||
label: '店铺名称',
|
label: '店铺名称',
|
||||||
width: 160,
|
width: 160,
|
||||||
showOverflowTooltip: true
|
showOverflowTooltip: true,
|
||||||
|
formatter: (row: ShopResponse) => {
|
||||||
|
const hasPermission = hasAuth('shop:detail')
|
||||||
|
return h(
|
||||||
|
'span',
|
||||||
|
{
|
||||||
|
style: hasPermission
|
||||||
|
? 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;'
|
||||||
|
: '',
|
||||||
|
onClick: hasPermission
|
||||||
|
? (event: MouseEvent) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
handleNameClick(row)
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
row.shop_name
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'shop_code',
|
prop: 'shop_code',
|
||||||
@@ -768,12 +769,6 @@
|
|||||||
const getActions = (row: ShopResponse) => {
|
const getActions = (row: ShopResponse) => {
|
||||||
const actions: any[] = []
|
const actions: any[] = []
|
||||||
|
|
||||||
actions.push({
|
|
||||||
label: '详情',
|
|
||||||
handler: () => showDetail(row),
|
|
||||||
type: 'primary'
|
|
||||||
})
|
|
||||||
|
|
||||||
if (hasAuth('shop:look_customer')) {
|
if (hasAuth('shop:look_customer')) {
|
||||||
actions.push({
|
actions.push({
|
||||||
label: '账号列表',
|
label: '账号列表',
|
||||||
@@ -862,7 +857,7 @@
|
|||||||
try {
|
try {
|
||||||
const params: any = {
|
const params: any = {
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 20,
|
page_size: 20,
|
||||||
role_type: RoleType.CUSTOMER, // 仅客户角色
|
role_type: RoleType.CUSTOMER, // 仅客户角色
|
||||||
status: RoleStatus.ENABLED // 仅启用的角色
|
status: RoleStatus.ENABLED // 仅启用的角色
|
||||||
}
|
}
|
||||||
@@ -1129,7 +1124,7 @@
|
|||||||
// 将 PlatformRole 转换为与 ShopRoleResponse 兼容的格式
|
// 将 PlatformRole 转换为与 ShopRoleResponse 兼容的格式
|
||||||
availableRoles.value = (res.data.items || []).map((role) => ({
|
availableRoles.value = (res.data.items || []).map((role) => ({
|
||||||
...role,
|
...role,
|
||||||
role_id: role.ID,
|
role_id: role.id ?? role.ID,
|
||||||
role_name: role.role_name,
|
role_name: role.role_name,
|
||||||
role_desc: role.role_desc,
|
role_desc: role.role_desc,
|
||||||
role_type: role.role_type,
|
role_type: role.role_type,
|
||||||
|
|||||||
111
src/views/system/role/detail/index.vue
Normal file
111
src/views/system/role/detail/index.vue
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<template>
|
||||||
|
<div class="role-detail-page">
|
||||||
|
<ElCard shadow="never">
|
||||||
|
<div class="detail-header">
|
||||||
|
<ElButton @click="handleBack">
|
||||||
|
<template #icon>
|
||||||
|
<ElIcon><ArrowLeft /></ElIcon>
|
||||||
|
</template>
|
||||||
|
返回
|
||||||
|
</ElButton>
|
||||||
|
<h2 class="detail-title">角色详情</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-loading="loading">
|
||||||
|
<ElDescriptions v-if="role" :column="2" border>
|
||||||
|
<ElDescriptionsItem label="角色名称">{{ role.role_name || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="角色类型">
|
||||||
|
{{ role.role_type === 1 ? '平台角色' : '客户角色' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="角色描述">{{ role.role_desc || '-' }}</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="状态">
|
||||||
|
{{ role.status === 1 ? '启用' : '禁用' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="新建代理默认信用">
|
||||||
|
{{ role.default_credit_enabled ? '启用' : '未启用' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="默认信用额度">
|
||||||
|
{{ formatCredit(role.default_credit_limit) }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="信用生效范围">
|
||||||
|
{{ role.default_credit_scope || '-' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="创建时间">
|
||||||
|
{{ formatDateTime(role.created_at) }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="更新时间">
|
||||||
|
{{ formatDateTime(role.updated_at) }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
</ElDescriptions>
|
||||||
|
</div>
|
||||||
|
</ElCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { RoleService } from '@/api/modules'
|
||||||
|
import type { PlatformRole } from '@/types/api'
|
||||||
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
|
|
||||||
|
defineOptions({ name: 'RoleDetail' })
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = ref(false)
|
||||||
|
const role = ref<PlatformRole | null>(null)
|
||||||
|
|
||||||
|
const formatCredit = (value?: number) => {
|
||||||
|
if (value === undefined || value === null) return '-'
|
||||||
|
return `${(value / 100).toFixed(2)} 元`
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => router.back()
|
||||||
|
|
||||||
|
const fetchDetail = async () => {
|
||||||
|
const id = Number(route.params.id)
|
||||||
|
if (!id) {
|
||||||
|
ElMessage.error('缺少角色 ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const response = await RoleService.getRole(id)
|
||||||
|
if (response.code !== 0 || !response.data) {
|
||||||
|
ElMessage.error(response.msg || '获取角色详情失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
role.value = response.data
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '获取角色详情失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(fetchDetail)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.role-detail-page {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<ArtTable
|
<ArtTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
row-key="ID"
|
row-key="id"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:data="roleList"
|
:data="roleList"
|
||||||
:currentPage="pagination.page"
|
:currentPage="pagination.page"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
:title="dialogType === 'add' ? '新增角色' : '编辑角色'"
|
:title="dialogType === 'add' ? '新增角色' : '编辑角色'"
|
||||||
width="30%"
|
width="30%"
|
||||||
>
|
>
|
||||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
|
||||||
<ElFormItem label="角色名称" prop="role_name">
|
<ElFormItem label="角色名称" prop="role_name">
|
||||||
<ElInput v-model="form.role_name" placeholder="请输入角色名称" />
|
<ElInput v-model="form.role_name" placeholder="请输入角色名称" />
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
<ElInputNumber
|
<ElInputNumber
|
||||||
v-model="form.credit_limit_yuan"
|
v-model="form.credit_limit_yuan"
|
||||||
:disabled="!form.credit_enabled"
|
:disabled="!form.credit_enabled"
|
||||||
:min="0"
|
:min="1"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="100"
|
:step="100"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
@@ -250,6 +250,8 @@
|
|||||||
import { RoleType } from '@/types/api'
|
import { RoleType } from '@/types/api'
|
||||||
import type { PlatformRole, PermissionTreeNode } from '@/types/api'
|
import type { PlatformRole, PermissionTreeNode } from '@/types/api'
|
||||||
import type { SearchFormItem } from '@/types'
|
import type { SearchFormItem } from '@/types'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
||||||
@@ -263,6 +265,7 @@
|
|||||||
defineOptions({ name: 'Role' })
|
defineOptions({ name: 'Role' })
|
||||||
|
|
||||||
const { hasAuth } = useAuth()
|
const { hasAuth } = useAuth()
|
||||||
|
const router = useRouter()
|
||||||
const canUpdateRoleStatus = hasAuth('role:update_status')
|
const canUpdateRoleStatus = hasAuth('role:update_status')
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
@@ -345,8 +348,10 @@
|
|||||||
{ label: '角色名称', prop: 'role_name' },
|
{ label: '角色名称', prop: 'role_name' },
|
||||||
{ label: '角色描述', prop: 'role_desc' },
|
{ label: '角色描述', prop: 'role_desc' },
|
||||||
{ label: '角色类型', prop: 'role_type' },
|
{ label: '角色类型', prop: 'role_type' },
|
||||||
|
{ label: '新建代理默认信用', prop: 'default_credit_enabled' },
|
||||||
|
{ label: '默认信用额度', prop: 'default_credit_limit' },
|
||||||
...(canUpdateRoleStatus ? [{ label: '状态', prop: 'status' }] : []),
|
...(canUpdateRoleStatus ? [{ label: '状态', prop: 'status' }] : []),
|
||||||
{ label: '创建时间', prop: 'CreatedAt' }
|
{ label: '创建时间', prop: 'created_at' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
@@ -357,7 +362,23 @@
|
|||||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
role_desc: [{ max: 200, message: '描述不能超过200个字符', trigger: 'blur' }],
|
role_desc: [{ max: 200, message: '描述不能超过200个字符', trigger: 'blur' }],
|
||||||
role_type: [{ required: true, message: '请选择角色类型', trigger: 'change' }]
|
role_type: [{ required: true, message: '请选择角色类型', trigger: 'change' }],
|
||||||
|
credit_limit_yuan: [
|
||||||
|
{
|
||||||
|
validator: (_rule, value, callback) => {
|
||||||
|
if (!isCustomerRoleForm.value || !form.credit_enabled) {
|
||||||
|
callback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (value === undefined || value === null || value <= 0) {
|
||||||
|
callback(new Error('默认信用额度必须大于0'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const form = reactive<any>({
|
const form = reactive<any>({
|
||||||
@@ -388,12 +409,40 @@
|
|||||||
|
|
||||||
const roleList = ref<PlatformRole[]>([])
|
const roleList = ref<PlatformRole[]>([])
|
||||||
|
|
||||||
|
const getRoleId = (role: PlatformRole | any) => role.id ?? role.ID
|
||||||
|
|
||||||
|
const handleNameClick = (row: PlatformRole) => {
|
||||||
|
if (hasAuth('role:detail')) {
|
||||||
|
void router.push(`${RoutesAlias.RoleDetail}/${getRoleId(row)}`)
|
||||||
|
} else {
|
||||||
|
ElMessage.warning('您没有查看详情的权限')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 动态列配置
|
// 动态列配置
|
||||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||||
{
|
{
|
||||||
prop: 'role_name',
|
prop: 'role_name',
|
||||||
label: '角色名称',
|
label: '角色名称',
|
||||||
width: 180
|
width: 180,
|
||||||
|
formatter: (row: PlatformRole) => {
|
||||||
|
const hasPermission = hasAuth('role:detail')
|
||||||
|
return h(
|
||||||
|
'span',
|
||||||
|
{
|
||||||
|
style: hasPermission
|
||||||
|
? 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;'
|
||||||
|
: '',
|
||||||
|
onClick: hasPermission
|
||||||
|
? (event: MouseEvent) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
handleNameClick(row)
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
row.role_name
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'role_type',
|
prop: 'role_type',
|
||||||
@@ -405,6 +454,28 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: 'default_credit_enabled',
|
||||||
|
label: '新建代理默认信用',
|
||||||
|
width: 150,
|
||||||
|
formatter: (row: PlatformRole) => {
|
||||||
|
if (row.role_type !== RoleType.CUSTOMER) return '-'
|
||||||
|
return h(
|
||||||
|
ElTag,
|
||||||
|
{ type: row.default_credit_enabled ? 'success' : 'info' },
|
||||||
|
() => (row.default_credit_enabled ? '启用' : '未启用')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'default_credit_limit',
|
||||||
|
label: '默认信用额度',
|
||||||
|
width: 140,
|
||||||
|
formatter: (row: PlatformRole) => {
|
||||||
|
if (row.role_type !== RoleType.CUSTOMER || !row.default_credit_enabled) return '-'
|
||||||
|
return `${fenToYuan(row.default_credit_limit)} 元`
|
||||||
|
}
|
||||||
|
},
|
||||||
...(canUpdateRoleStatus
|
...(canUpdateRoleStatus
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
@@ -431,10 +502,10 @@
|
|||||||
label: '角色描述'
|
label: '角色描述'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'CreatedAt',
|
prop: 'created_at',
|
||||||
label: '创建时间',
|
label: '创建时间',
|
||||||
width: 180,
|
width: 180,
|
||||||
formatter: (row: any) => formatDateTime(row.CreatedAt)
|
formatter: (row: any) => formatDateTime(row.created_at)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'actions',
|
prop: 'actions',
|
||||||
@@ -934,7 +1005,7 @@
|
|||||||
|
|
||||||
// 显示分配权限对话框
|
// 显示分配权限对话框
|
||||||
const showPermissionDialog = async (row: PlatformRole) => {
|
const showPermissionDialog = async (row: PlatformRole) => {
|
||||||
currentRoleId.value = row.ID
|
currentRoleId.value = getRoleId(row)
|
||||||
currentRole.value = {
|
currentRole.value = {
|
||||||
role_name: row.role_name,
|
role_name: row.role_name,
|
||||||
role_type: row.role_type
|
role_type: row.role_type
|
||||||
@@ -1043,7 +1114,7 @@
|
|||||||
if (type === 'edit' && row) {
|
if (type === 'edit' && row) {
|
||||||
let roleDetail = row
|
let roleDetail = row
|
||||||
try {
|
try {
|
||||||
const res = await RoleService.getRole(row.ID)
|
const res = await RoleService.getRole(getRoleId(row))
|
||||||
if (res.code === 0 && res.data) {
|
if (res.code === 0 && res.data) {
|
||||||
roleDetail = res.data
|
roleDetail = res.data
|
||||||
}
|
}
|
||||||
@@ -1051,13 +1122,17 @@
|
|||||||
console.error('获取角色详情失败:', error)
|
console.error('获取角色详情失败:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
form.id = roleDetail.ID
|
form.id = getRoleId(roleDetail)
|
||||||
form.role_name = roleDetail.role_name
|
form.role_name = roleDetail.role_name
|
||||||
form.role_desc = roleDetail.role_desc
|
form.role_desc = roleDetail.role_desc
|
||||||
form.role_type = roleDetail.role_type
|
form.role_type = roleDetail.role_type
|
||||||
form.status = roleDetail.status
|
form.status = roleDetail.status
|
||||||
form.credit_enabled = Boolean(roleDetail.credit_enabled)
|
form.credit_enabled = Boolean(
|
||||||
form.credit_limit_yuan = fenToYuan(roleDetail.credit_limit)
|
roleDetail.default_credit_enabled ?? roleDetail.credit_enabled
|
||||||
|
)
|
||||||
|
form.credit_limit_yuan = fenToYuan(
|
||||||
|
roleDetail.default_credit_limit ?? roleDetail.credit_limit
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
form.id = 0
|
form.id = 0
|
||||||
form.role_name = ''
|
form.role_name = ''
|
||||||
@@ -1080,7 +1155,7 @@
|
|||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
try {
|
try {
|
||||||
await RoleService.deleteRole(row.ID)
|
await RoleService.deleteRole(getRoleId(row))
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
await getTableData()
|
await getTableData()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1118,7 +1193,6 @@
|
|||||||
const data = {
|
const data = {
|
||||||
role_name: form.role_name,
|
role_name: form.role_name,
|
||||||
role_desc: form.role_desc,
|
role_desc: form.role_desc,
|
||||||
role_type: form.role_type,
|
|
||||||
status: form.status
|
status: form.status
|
||||||
}
|
}
|
||||||
await RoleService.updateRole(form.id, data)
|
await RoleService.updateRole(form.id, data)
|
||||||
@@ -1146,7 +1220,7 @@
|
|||||||
// 先更新UI
|
// 先更新UI
|
||||||
row.status = newStatus
|
row.status = newStatus
|
||||||
try {
|
try {
|
||||||
await RoleService.updateRoleStatus(row.ID, newStatus as 0 | 1)
|
await RoleService.updateRoleStatus(getRoleId(row), newStatus as 0 | 1)
|
||||||
ElMessage.success('状态切换成功')
|
ElMessage.success('状态切换成功')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 切换失败,恢复原状态
|
// 切换失败,恢复原状态
|
||||||
|
|||||||
Reference in New Issue
Block a user