fix: id兼容, 通知入口
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m0s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m0s
This commit is contained in:
@@ -34,7 +34,7 @@ export class AccountService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
static createAccount(
|
static createAccount(
|
||||||
data: CreatePlatformAccountParams
|
data: CreatePlatformAccountParams
|
||||||
): Promise<BaseResponse<{ ID?: number; id?: number }>> {
|
): Promise<BaseResponse<{ id?: number; ID?: number }>> {
|
||||||
return this.create('/api/admin/accounts', data)
|
return this.create('/api/admin/accounts', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<ArtTable
|
<ArtTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
row-key="ID"
|
row-key="id"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:data="accountList"
|
:data="accountList"
|
||||||
height="60vh"
|
height="60vh"
|
||||||
|
|||||||
@@ -66,7 +66,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 通知 -->
|
<!-- 通知 -->
|
||||||
<div
|
<div
|
||||||
v-if="hasAuth(NOTIFICATION_PERMISSIONS.page)"
|
|
||||||
class="btn-box notice-btn"
|
class="btn-box notice-btn"
|
||||||
@click.stop="showNotice = !showNotice"
|
@click.stop="showNotice = !showNotice"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -432,7 +432,7 @@
|
|||||||
"standaloneCardList": "IoT Card Management",
|
"standaloneCardList": "IoT Card Management",
|
||||||
"iotCardTask": "IoT Card Tasks",
|
"iotCardTask": "IoT Card Tasks",
|
||||||
"deviceTask": "Device Tasks",
|
"deviceTask": "Device Tasks",
|
||||||
"deviceBatchAllocation": "Device Batch Allocation",
|
"deviceBatchAllocation": "Device Batch Tasks",
|
||||||
"bulkPurchase": "Bulk Package Purchase",
|
"bulkPurchase": "Bulk Package Purchase",
|
||||||
"bulkPurchaseDetail": "Bulk Purchase Task Detail",
|
"bulkPurchaseDetail": "Bulk Purchase Task Detail",
|
||||||
"orderPackageInvalidateTask": "Order Package Void Tasks",
|
"orderPackageInvalidateTask": "Order Package Void Tasks",
|
||||||
|
|||||||
@@ -370,7 +370,7 @@
|
|||||||
"standaloneCardList": "IoT卡管理",
|
"standaloneCardList": "IoT卡管理",
|
||||||
"iotCardTask": "IoT卡任务",
|
"iotCardTask": "IoT卡任务",
|
||||||
"deviceTask": "设备任务",
|
"deviceTask": "设备任务",
|
||||||
"deviceBatchAllocation": "设备批量分配",
|
"deviceBatchAllocation": "设备批量任务",
|
||||||
"bulkPurchase": "批量订购套餐",
|
"bulkPurchase": "批量订购套餐",
|
||||||
"bulkPurchaseDetail": "批量订购任务详情",
|
"bulkPurchaseDetail": "批量订购任务详情",
|
||||||
"orderPackageInvalidateTask": "订单套餐批量作废",
|
"orderPackageInvalidateTask": "订单套餐批量作废",
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ export const asyncRoutes: AppRouteRecord[] = [
|
|||||||
keepAlive: true
|
keepAlive: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 设备批量分配任务
|
// 设备批量任务
|
||||||
{
|
{
|
||||||
path: 'device-batch-allocation',
|
path: 'device-batch-allocation',
|
||||||
name: 'DeviceBatchAllocation',
|
name: 'DeviceBatchAllocation',
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export enum RoutesAlias {
|
|||||||
// 任务管理
|
// 任务管理
|
||||||
IotCardTask = '/asset-management/task-management/iot-card-task', // IoT卡任务
|
IotCardTask = '/asset-management/task-management/iot-card-task', // IoT卡任务
|
||||||
DeviceTask = '/asset-management/task-management/device-task', // 设备任务
|
DeviceTask = '/asset-management/task-management/device-task', // 设备任务
|
||||||
DeviceBatchAllocation = '/asset-management/task-management/device-batch-allocation', // 设备批量分配
|
DeviceBatchAllocation = '/asset-management/task-management/device-batch-allocation', // 设备批量任务
|
||||||
BulkPurchase = '/asset-management/task-management/bulk-purchase', // 批量订购套餐
|
BulkPurchase = '/asset-management/task-management/bulk-purchase', // 批量订购套餐
|
||||||
BulkPurchaseDetail = '/asset-management/task-management/bulk-purchase/detail', // 批量订购套餐详情
|
BulkPurchaseDetail = '/asset-management/task-management/bulk-purchase/detail', // 批量订购套餐详情
|
||||||
OrderPackageInvalidateTask = '/asset-management/task-management/order-package-invalidate-task', // 订单套餐批量作废任务
|
OrderPackageInvalidateTask = '/asset-management/task-management/order-package-invalidate-task', // 订单套餐批量作废任务
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export enum AccountStatus {
|
|||||||
|
|
||||||
// 账号实体(统一账号模型,匹配后端 ModelAccountResponse)
|
// 账号实体(统一账号模型,匹配后端 ModelAccountResponse)
|
||||||
export interface PlatformAccount {
|
export interface PlatformAccount {
|
||||||
ID: number
|
id?: number
|
||||||
|
ID?: number
|
||||||
CreatedAt?: string
|
CreatedAt?: string
|
||||||
UpdatedAt?: string
|
UpdatedAt?: string
|
||||||
DeletedAt?: string | null
|
DeletedAt?: string | null
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ export enum PermissionStatus {
|
|||||||
|
|
||||||
// 权限实体(匹配后端 ModelPermission)
|
// 权限实体(匹配后端 ModelPermission)
|
||||||
export interface Permission {
|
export interface Permission {
|
||||||
ID: number
|
id?: number
|
||||||
|
ID?: number
|
||||||
CreatedAt?: string
|
CreatedAt?: string
|
||||||
UpdatedAt?: string
|
UpdatedAt?: string
|
||||||
DeletedAt?: string | null
|
DeletedAt?: string | null
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export enum RoleStatus {
|
|||||||
// 角色实体(匹配后端 ModelRole)
|
// 角色实体(匹配后端 ModelRole)
|
||||||
export interface PlatformRole {
|
export interface PlatformRole {
|
||||||
id?: number
|
id?: number
|
||||||
ID: number
|
ID?: number
|
||||||
CreatedAt?: string
|
CreatedAt?: string
|
||||||
UpdatedAt?: string
|
UpdatedAt?: string
|
||||||
DeletedAt?: string | null
|
DeletedAt?: string | null
|
||||||
|
|||||||
58
src/utils/business/id.ts
Normal file
58
src/utils/business/id.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* 兼容后端实体 ID 字段的大小写差异。
|
||||||
|
* 后端历史接口可能返回 `ID`,新接口返回 `id`,前端统一优先使用小写 id。
|
||||||
|
*/
|
||||||
|
export type CompatibleId = number | string
|
||||||
|
|
||||||
|
export interface CompatibleIdFields {
|
||||||
|
id?: CompatibleId | null
|
||||||
|
ID?: CompatibleId | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从实体中读取兼容的 ID 字段。0 也是有效 ID,不能使用 ||。 */
|
||||||
|
export const getCompatibleId = (value: CompatibleIdFields | null | undefined) => {
|
||||||
|
const id = value?.id ?? value?.ID
|
||||||
|
return id === null || id === undefined || id === '' ? undefined : id
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 读取并转换为数字 ID,供只接受 number 的接口参数使用。 */
|
||||||
|
export const getCompatibleNumericId = (
|
||||||
|
value: CompatibleIdFields | null | undefined
|
||||||
|
): number | undefined => {
|
||||||
|
const id = getCompatibleId(value)
|
||||||
|
if (id === undefined) return undefined
|
||||||
|
|
||||||
|
const numericId = Number(id)
|
||||||
|
return Number.isFinite(numericId) ? numericId : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
||||||
|
if (value === null || typeof value !== 'object') return false
|
||||||
|
const prototype = Object.getPrototypeOf(value)
|
||||||
|
return prototype === Object.prototype || prototype === null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 递归补齐响应中的 id/ID 别名,不影响 Blob、FormData、Date 等特殊数据。 */
|
||||||
|
export const syncCompatibleIdFields = <T>(value: T): T => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach((item) => syncCompatibleIdFields(item))
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPlainObject(value)) return value
|
||||||
|
|
||||||
|
const record = value as Record<string, unknown>
|
||||||
|
const hasId = Object.prototype.hasOwnProperty.call(record, 'id')
|
||||||
|
const hasUpperId = Object.prototype.hasOwnProperty.call(record, 'ID')
|
||||||
|
|
||||||
|
if (hasId || hasUpperId) {
|
||||||
|
const id = record.id ?? record.ID
|
||||||
|
if (id !== null && id !== undefined && id !== '') {
|
||||||
|
if (!hasId) record.id = id
|
||||||
|
if (!hasUpperId) record.ID = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.values(record).forEach((item) => syncCompatibleIdFields(item))
|
||||||
|
return value
|
||||||
|
}
|
||||||
@@ -9,3 +9,4 @@ export * from './voucher'
|
|||||||
export * from './apiRateLimit'
|
export * from './apiRateLimit'
|
||||||
export * from './approvalSummary'
|
export * from './approvalSummary'
|
||||||
export * from './expiryEstimate'
|
export * from './expiryEstimate'
|
||||||
|
export * from './id'
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useUserStore } from '@/store/modules/user'
|
|||||||
import { ApiStatus } from './status'
|
import { ApiStatus } from './status'
|
||||||
import type { RequestOptions, ErrorMessageMode } from '@/types/api'
|
import type { RequestOptions, ErrorMessageMode } from '@/types/api'
|
||||||
import { normalizeApiError } from '@/utils/business/apiError'
|
import { normalizeApiError } from '@/utils/business/apiError'
|
||||||
|
import { syncCompatibleIdFields } from '@/utils/business/id'
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
timeout: 15000, // 请求超时时间(毫秒)
|
timeout: 15000, // 请求超时时间(毫秒)
|
||||||
@@ -90,6 +91,9 @@ const processQueue = (error: any, token: string | null = null) => {
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
|
// 兼容历史接口返回的 ID 与新接口返回的 id。
|
||||||
|
syncCompatibleIdFields(response.data)
|
||||||
|
|
||||||
// 401 未授权 - 尝试刷新 token
|
// 401 未授权 - 尝试刷新 token
|
||||||
if (response.data.code === ApiStatus.unauthorized) {
|
if (response.data.code === ApiStatus.unauthorized) {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|||||||
@@ -82,9 +82,9 @@
|
|||||||
>
|
>
|
||||||
<ElOption
|
<ElOption
|
||||||
v-for="role in availableRolesForCreate"
|
v-for="role in availableRolesForCreate"
|
||||||
:key="role.ID"
|
:key="getRoleId(role)"
|
||||||
:label="role.role_name"
|
:label="role.role_name"
|
||||||
:value="role.ID"
|
:value="getRoleId(role)"
|
||||||
>
|
>
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||||
<span>{{ role.role_name }}</span>
|
<span>{{ role.role_name }}</span>
|
||||||
@@ -133,8 +133,15 @@
|
|||||||
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
||||||
<template v-else-if="isPlatformUser">
|
<template v-else-if="isPlatformUser">
|
||||||
<ElCheckboxGroup v-model="rolesToAdd" class="role-list">
|
<ElCheckboxGroup v-model="rolesToAdd" class="role-list">
|
||||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
<div
|
||||||
<ElCheckbox :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
v-for="role in filteredAvailableRoles"
|
||||||
|
:key="getRoleId(role)"
|
||||||
|
class="role-item"
|
||||||
|
>
|
||||||
|
<ElCheckbox
|
||||||
|
:label="getRoleId(role)"
|
||||||
|
:disabled="selectedRoles.includes(getRoleId(role))"
|
||||||
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
<span>{{ role.role_name }}</span>
|
<span>{{ role.role_name }}</span>
|
||||||
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
||||||
@@ -147,8 +154,15 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<ElRadioGroup v-model="roleToAdd" class="role-list">
|
<ElRadioGroup v-model="roleToAdd" class="role-list">
|
||||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
<div
|
||||||
<ElRadio :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
v-for="role in filteredAvailableRoles"
|
||||||
|
:key="getRoleId(role)"
|
||||||
|
class="role-item"
|
||||||
|
>
|
||||||
|
<ElRadio
|
||||||
|
:label="getRoleId(role)"
|
||||||
|
:disabled="selectedRoles.includes(getRoleId(role))"
|
||||||
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
<span>{{ role.role_name }}</span>
|
<span>{{ role.role_name }}</span>
|
||||||
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
||||||
@@ -190,7 +204,7 @@
|
|||||||
<div class="role-list">
|
<div class="role-list">
|
||||||
<div
|
<div
|
||||||
v-for="role in filteredAssignedRoles"
|
v-for="role in filteredAssignedRoles"
|
||||||
:key="role.ID"
|
:key="getRoleId(role)"
|
||||||
class="role-item assigned-role-item"
|
class="role-item assigned-role-item"
|
||||||
>
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
@@ -199,7 +213,12 @@
|
|||||||
{{ role.role_type === 1 ? '平台角色' : '客户角色' }}
|
{{ role.role_type === 1 ? '平台角色' : '客户角色' }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</span>
|
</span>
|
||||||
<ElButton type="danger" size="small" link @click="removeSingleRole(role.ID)">
|
<ElButton
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="removeSingleRole(getRoleId(role))"
|
||||||
|
>
|
||||||
移除
|
移除
|
||||||
</ElButton>
|
</ElButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -310,6 +329,7 @@
|
|||||||
import type { SearchFormItem } from '@/types'
|
import type { SearchFormItem } from '@/types'
|
||||||
import type { PlatformRole, WecomApplication, WecomMember } from '@/types/api'
|
import type { PlatformRole, WecomApplication, WecomMember } from '@/types/api'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
|
import { getCompatibleNumericId } from '@/utils/business/id'
|
||||||
import {
|
import {
|
||||||
CommonStatus,
|
CommonStatus,
|
||||||
getStatusText,
|
getStatusText,
|
||||||
@@ -356,6 +376,9 @@
|
|||||||
// 是否为平台用户(平台用户可多选,其他单选)
|
// 是否为平台用户(平台用户可多选,其他单选)
|
||||||
const isPlatformUser = computed(() => currentAccountType.value === 2)
|
const isPlatformUser = computed(() => currentAccountType.value === 2)
|
||||||
|
|
||||||
|
const getAccountId = (account: any) => getCompatibleNumericId(account) ?? 0
|
||||||
|
const getRoleId = (role: PlatformRole | any) => getCompatibleNumericId(role) ?? 0
|
||||||
|
|
||||||
// 定义表单搜索初始值
|
// 定义表单搜索初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -631,14 +654,6 @@
|
|||||||
const getActions = (row: any) => {
|
const getActions = (row: any) => {
|
||||||
const actions: any[] = []
|
const actions: any[] = []
|
||||||
|
|
||||||
if (row.user_type === 2 && hasAuth(JULY_PERMISSIONS.wecom.binding)) {
|
|
||||||
actions.push({
|
|
||||||
label: '绑定账号',
|
|
||||||
handler: () => showWecomBindingDialog(row),
|
|
||||||
type: 'primary'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasAuth('account:patch_role')) {
|
if (hasAuth('account:patch_role')) {
|
||||||
actions.push({
|
actions.push({
|
||||||
label: '分配角色',
|
label: '分配角色',
|
||||||
@@ -647,6 +662,14 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (row.user_type === 2 && hasAuth(JULY_PERMISSIONS.wecom.binding)) {
|
||||||
|
actions.push({
|
||||||
|
label: '绑定账号',
|
||||||
|
handler: () => showWecomBindingDialog(row),
|
||||||
|
type: 'primary'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (hasAuth('account:edit')) {
|
if (hasAuth('account:edit')) {
|
||||||
actions.push({
|
actions.push({
|
||||||
label: '编辑',
|
label: '编辑',
|
||||||
@@ -716,7 +739,7 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountId = Number(currentWecomAccount.value.id ?? currentWecomAccount.value.ID)
|
const accountId = getAccountId(currentWecomAccount.value)
|
||||||
if (!accountId) {
|
if (!accountId) {
|
||||||
ElMessage.error('当前账号缺少账号标识,无法绑定企微')
|
ElMessage.error('当前账号缺少账号标识,无法绑定企微')
|
||||||
return
|
return
|
||||||
@@ -823,7 +846,9 @@
|
|||||||
|
|
||||||
// 计算属性:过滤后的已分配角色
|
// 计算属性:过滤后的已分配角色
|
||||||
const filteredAssignedRoles = computed(() => {
|
const filteredAssignedRoles = computed(() => {
|
||||||
const assignedRolesList = allRoles.value.filter((role) => selectedRoles.value.includes(role.ID))
|
const assignedRolesList = allRoles.value.filter((role) =>
|
||||||
|
selectedRoles.value.includes(getRoleId(role))
|
||||||
|
)
|
||||||
if (!rightRoleFilter.value) return assignedRolesList
|
if (!rightRoleFilter.value) return assignedRolesList
|
||||||
const keyword = rightRoleFilter.value.toLowerCase()
|
const keyword = rightRoleFilter.value.toLowerCase()
|
||||||
return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword))
|
return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword))
|
||||||
@@ -835,7 +860,12 @@
|
|||||||
ElMessage.warning('超级管理员无法分配角色')
|
ElMessage.warning('超级管理员无法分配角色')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentAccountId.value = row.id
|
const accountId = getAccountId(row)
|
||||||
|
if (!accountId) {
|
||||||
|
ElMessage.error('当前账号缺少账号标识,无法分配角色')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentAccountId.value = accountId
|
||||||
currentAccountName.value = row.username
|
currentAccountName.value = row.username
|
||||||
currentAccountType.value = row.user_type
|
currentAccountType.value = row.user_type
|
||||||
selectedRoles.value = []
|
selectedRoles.value = []
|
||||||
@@ -852,12 +882,12 @@
|
|||||||
await loadAllRoles('', roleType)
|
await loadAllRoles('', roleType)
|
||||||
|
|
||||||
// 先加载当前账号的角色,再打开对话框
|
// 先加载当前账号的角色,再打开对话框
|
||||||
const res = await AccountService.getAccountRoles(row.id)
|
const res = await AccountService.getAccountRoles(accountId)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// 提取角色ID数组
|
// 提取角色ID数组
|
||||||
const roles = res.data || []
|
const roles = res.data || []
|
||||||
// 兼容 ID 和 id 两种字段名
|
// 兼容 ID 和 id 两种字段名
|
||||||
selectedRoles.value = roles.map((role: any) => role.ID || role.id)
|
selectedRoles.value = roles.map((role: any) => getRoleId(role)).filter(Boolean)
|
||||||
// 数据加载完成后再打开对话框
|
// 数据加载完成后再打开对话框
|
||||||
roleDialogVisible.value = true
|
roleDialogVisible.value = true
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1043,7 @@
|
|||||||
|
|
||||||
// 创建成功后分配角色(如果选择了)
|
// 创建成功后分配角色(如果选择了)
|
||||||
if (createRes.code === 0) {
|
if (createRes.code === 0) {
|
||||||
const accountId = createRes.data?.ID || createRes.data?.id
|
const accountId = getCompatibleNumericId(createRes.data)
|
||||||
if (formData.role_id && accountId) {
|
if (formData.role_id && accountId) {
|
||||||
try {
|
try {
|
||||||
await AccountService.assignRolesToAccount(accountId, [formData.role_id])
|
await AccountService.assignRolesToAccount(accountId, [formData.role_id])
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<template v-if="!props.seriesId">
|
<template v-if="!props.seriesId">
|
||||||
<ElOption value="__NO_PACKAGE__" disabled>
|
<ElOption value="__NO_PACKAGE__" disabled>
|
||||||
<span style="color: var(--el-text-color-warning)">
|
<span style="color: var(--el-text-color-warning)">
|
||||||
该设备未关联套餐系列,无法购买套餐
|
{{ noSeriesMessage }}
|
||||||
</span>
|
</span>
|
||||||
</ElOption>
|
</ElOption>
|
||||||
</template>
|
</template>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</ElSelect>
|
</ElSelect>
|
||||||
<template v-if="noSeriesId">
|
<template v-if="noSeriesId">
|
||||||
<div style="margin-top: 4px; font-size: 12px; color: var(--el-text-color-warning)">
|
<div style="margin-top: 4px; font-size: 12px; color: var(--el-text-color-warning)">
|
||||||
该设备未关联套餐系列,无法购买套餐
|
{{ noSeriesMessage }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="packagesEmptyWithSeriesId">
|
<template v-else-if="packagesEmptyWithSeriesId">
|
||||||
@@ -182,6 +182,9 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const noSeriesId = computed(() => !props.seriesId)
|
const noSeriesId = computed(() => !props.seriesId)
|
||||||
|
const noSeriesMessage = computed(
|
||||||
|
() => `该${props.assetType === 'card' ? '卡' : '设备'}未关联套餐系列,无法购买套餐`
|
||||||
|
)
|
||||||
|
|
||||||
const selectedPackageIsGift = computed(() => {
|
const selectedPackageIsGift = computed(() => {
|
||||||
if (!form.package_id) return false
|
if (!form.package_id) return false
|
||||||
|
|||||||
@@ -11,6 +11,28 @@
|
|||||||
@closed="handleCreateDrawerClosed"
|
@closed="handleCreateDrawerClosed"
|
||||||
>
|
>
|
||||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="110px" class="create-form">
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="110px" class="create-form">
|
||||||
|
<ElFormItem label="套餐系列" prop="series_id">
|
||||||
|
<ElSelect
|
||||||
|
v-model="form.series_id"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
clearable
|
||||||
|
:remote-method="handleSeriesSearch"
|
||||||
|
:loading="seriesLoading"
|
||||||
|
placeholder="请输入系列名称搜索"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleSeriesChange"
|
||||||
|
@visible-change="handleSeriesVisibleChange"
|
||||||
|
>
|
||||||
|
<ElOption
|
||||||
|
v-for="series in seriesOptions"
|
||||||
|
:key="series.id"
|
||||||
|
:label="series.series_name"
|
||||||
|
:value="series.id"
|
||||||
|
/>
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
|
||||||
<ElFormItem label="套餐" prop="package_id">
|
<ElFormItem label="套餐" prop="package_id">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="form.package_id"
|
v-model="form.package_id"
|
||||||
@@ -19,7 +41,8 @@
|
|||||||
clearable
|
clearable
|
||||||
:remote-method="handlePackageSearch"
|
:remote-method="handlePackageSearch"
|
||||||
:loading="packageLoading"
|
:loading="packageLoading"
|
||||||
placeholder="请输入套餐名称搜索"
|
:disabled="!form.series_id"
|
||||||
|
placeholder="请先选择套餐系列"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@visible-change="handlePackageVisibleChange"
|
@visible-change="handlePackageVisibleChange"
|
||||||
>
|
>
|
||||||
@@ -223,8 +246,13 @@
|
|||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||||||
import { BulkPurchaseService, PackageManageService } from '@/api/modules'
|
import { BulkPurchaseService, PackageManageService, PackageSeriesService } from '@/api/modules'
|
||||||
import type { BulkPurchasePaymentMethod, BulkPurchaseTask, PackageResponse } from '@/types/api'
|
import type {
|
||||||
|
BulkPurchasePaymentMethod,
|
||||||
|
BulkPurchaseTask,
|
||||||
|
PackageResponse,
|
||||||
|
PackageSeriesResponse
|
||||||
|
} from '@/types/api'
|
||||||
import { BulkPurchaseTaskStatus } from '@/types/api'
|
import { BulkPurchaseTaskStatus } from '@/types/api'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
@@ -244,6 +272,8 @@
|
|||||||
const orderFileUploading = ref(false)
|
const orderFileUploading = ref(false)
|
||||||
const voucherFileKeys = ref<string[]>([])
|
const voucherFileKeys = ref<string[]>([])
|
||||||
const voucherUploading = ref(false)
|
const voucherUploading = ref(false)
|
||||||
|
const seriesOptions = ref<PackageSeriesResponse[]>([])
|
||||||
|
const seriesLoading = ref(false)
|
||||||
const packageOptions = ref<PackageResponse[]>([])
|
const packageOptions = ref<PackageResponse[]>([])
|
||||||
const packageLoading = ref(false)
|
const packageLoading = ref(false)
|
||||||
const taskList = ref<BulkPurchaseTask[]>([])
|
const taskList = ref<BulkPurchaseTask[]>([])
|
||||||
@@ -257,14 +287,17 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
const form = reactive<{
|
const form = reactive<{
|
||||||
|
series_id?: number
|
||||||
package_id?: number
|
package_id?: number
|
||||||
payment_method: BulkPurchasePaymentMethod
|
payment_method: BulkPurchasePaymentMethod
|
||||||
}>({
|
}>({
|
||||||
|
series_id: undefined,
|
||||||
package_id: undefined,
|
package_id: undefined,
|
||||||
payment_method: 'wallet'
|
payment_method: 'wallet'
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = computed<FormRules>(() => ({
|
const rules = computed<FormRules>(() => ({
|
||||||
|
series_id: [{ required: true, message: '请选择套餐系列', trigger: 'change' }],
|
||||||
package_id: [{ required: true, message: '请选择套餐', trigger: 'change' }],
|
package_id: [{ required: true, message: '请选择套餐', trigger: 'change' }],
|
||||||
payment_method: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
payment_method: [{ required: true, message: '请选择支付方式', trigger: 'change' }],
|
||||||
orderFile: [
|
orderFile: [
|
||||||
@@ -289,12 +322,18 @@
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const loadPackages = async (query = '') => {
|
const loadPackages = async (query = '') => {
|
||||||
|
if (!form.series_id) {
|
||||||
|
packageOptions.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
packageLoading.value = true
|
packageLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await PackageManageService.getPackages({
|
const res = await PackageManageService.getPackages({
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 20,
|
page_size: 20,
|
||||||
package_name: query.trim() || undefined,
|
package_name: query.trim() || undefined,
|
||||||
|
series_id: form.series_id,
|
||||||
status: 1,
|
status: 1,
|
||||||
shelf_status: 1
|
shelf_status: 1
|
||||||
})
|
})
|
||||||
@@ -314,20 +353,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handlePackageSearch = (query: string) => {
|
const handlePackageSearch = (query: string) => {
|
||||||
void loadPackages(query)
|
if (form.series_id) void loadPackages(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePackageVisibleChange = (visible: boolean) => {
|
const handlePackageVisibleChange = (visible: boolean) => {
|
||||||
if (visible && packageOptions.value.length === 0) void loadPackages()
|
if (visible && form.series_id && packageOptions.value.length === 0) void loadPackages()
|
||||||
}
|
}
|
||||||
|
|
||||||
const openCreateDrawer = () => {
|
const openCreateDrawer = () => {
|
||||||
createDrawerVisible.value = true
|
createDrawerVisible.value = true
|
||||||
if (packageOptions.value.length === 0) void loadPackages()
|
if (seriesOptions.value.length === 0) void loadSeries()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCreateDrawerClosed = () => {
|
const handleCreateDrawerClosed = () => {
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
|
form.series_id = undefined
|
||||||
form.package_id = undefined
|
form.package_id = undefined
|
||||||
form.payment_method = 'wallet'
|
form.payment_method = 'wallet'
|
||||||
orderFileKeys.value = []
|
orderFileKeys.value = []
|
||||||
@@ -338,6 +378,41 @@
|
|||||||
voucherUploading.value = false
|
voucherUploading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadSeries = async (query = '') => {
|
||||||
|
seriesLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await PackageSeriesService.getPackageSeries({
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
series_name: query.trim() || undefined,
|
||||||
|
status: 1
|
||||||
|
})
|
||||||
|
if (res.code !== 0) {
|
||||||
|
ElMessage.error(res.msg || '获取套餐系列失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seriesOptions.value = res.data?.items || []
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '获取套餐系列失败')
|
||||||
|
} finally {
|
||||||
|
seriesLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSeriesSearch = (query: string) => {
|
||||||
|
void loadSeries(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSeriesVisibleChange = (visible: boolean) => {
|
||||||
|
if (visible && seriesOptions.value.length === 0) void loadSeries()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSeriesChange = () => {
|
||||||
|
form.package_id = undefined
|
||||||
|
packageOptions.value = []
|
||||||
|
if (form.series_id) void loadPackages()
|
||||||
|
}
|
||||||
|
|
||||||
const handlePaymentMethodChange = (value: string | number | boolean | undefined) => {
|
const handlePaymentMethodChange = (value: string | number | boolean | undefined) => {
|
||||||
if (value === 'wallet') {
|
if (value === 'wallet') {
|
||||||
voucherFileKeys.value = []
|
voucherFileKeys.value = []
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="device-batch-allocation-page" id="table-full-screen">
|
<div class="device-batch-allocation-page" id="table-full-screen">
|
||||||
<ElDrawer
|
<ElDrawer
|
||||||
v-model="createDrawerVisible"
|
v-model="createDrawerVisible"
|
||||||
title="设备批量分配"
|
title="设备批量任务"
|
||||||
direction="rtl"
|
direction="rtl"
|
||||||
size="520px"
|
size="520px"
|
||||||
:close-on-click-modal="!createDrawerBusy"
|
:close-on-click-modal="!createDrawerBusy"
|
||||||
@@ -102,13 +102,13 @@
|
|||||||
<ElCard shadow="never" class="art-table-card task-list-card">
|
<ElCard shadow="never" class="art-table-card task-list-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="task-list-header">
|
<div class="task-list-header">
|
||||||
<span>设备批量分配任务</span>
|
<span>设备批量任务</span>
|
||||||
<div class="task-list-toolbar">
|
<div class="task-list-toolbar">
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAuth(JULY_PERMISSIONS.deviceAllocation.create)"
|
v-if="hasAuth(JULY_PERMISSIONS.deviceAllocation.create)"
|
||||||
tag="a"
|
tag="a"
|
||||||
href="/templates/device-batch-allocation-template.csv"
|
href="/templates/device-batch-allocation-template.csv"
|
||||||
download="设备批量分配模板.csv"
|
download="设备批量任务模板.csv"
|
||||||
>
|
>
|
||||||
下载模板
|
下载模板
|
||||||
</ElButton>
|
</ElButton>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
type="primary"
|
type="primary"
|
||||||
@click="openCreateDrawer"
|
@click="openCreateDrawer"
|
||||||
>
|
>
|
||||||
设备批量分配
|
设备批量任务
|
||||||
</ElButton>
|
</ElButton>
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="taskListOperationType"
|
v-model="taskListOperationType"
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
if (res.code === 0) seriesOptions.value = res.data.items || []
|
if (res.code === 0) seriesOptions.value = res.data.items || []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取批量分配目标失败:', error)
|
console.error('获取设备批量任务目标失败:', error)
|
||||||
ElMessage.error(normalizeApiError(error).message)
|
ElMessage.error(normalizeApiError(error).message)
|
||||||
} finally {
|
} finally {
|
||||||
targetLoading.value = false
|
targetLoading.value = false
|
||||||
@@ -399,13 +399,13 @@
|
|||||||
operation_type: taskListOperationType.value
|
operation_type: taskListOperationType.value
|
||||||
})
|
})
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
ElMessage.error(res.msg || '获取设备批量分配任务失败')
|
ElMessage.error(res.msg || '获取设备批量任务失败')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
taskList.value = (res.data.items || []).filter((item) => item.operation_type !== 'import')
|
taskList.value = (res.data.items || []).filter((item) => item.operation_type !== 'import')
|
||||||
taskListTotal.value = res.data.total || 0
|
taskListTotal.value = res.data.total || 0
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取设备批量分配任务失败:', error)
|
console.error('获取设备批量任务失败:', error)
|
||||||
ElMessage.error(normalizeApiError(error).message)
|
ElMessage.error(normalizeApiError(error).message)
|
||||||
} finally {
|
} finally {
|
||||||
taskListLoading.value = false
|
taskListLoading.value = false
|
||||||
@@ -445,14 +445,14 @@
|
|||||||
try {
|
try {
|
||||||
const res = await DeviceService.createAllocationTask(request)
|
const res = await DeviceService.createAllocationTask(request)
|
||||||
if (res.code !== 0) {
|
if (res.code !== 0) {
|
||||||
ElMessage.error(res.msg || '创建设备批量分配任务失败')
|
ElMessage.error(res.msg || '创建设备批量任务失败')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
createDrawerVisible.value = false
|
createDrawerVisible.value = false
|
||||||
await loadTaskList()
|
await loadTaskList()
|
||||||
ElMessage.success(`任务已创建:${res.data.task_no}`)
|
ElMessage.success(`任务已创建:${res.data.task_no}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建设备批量分配任务失败:', error)
|
console.error('创建设备批量任务失败:', error)
|
||||||
ElMessage.error(normalizeApiError(error).message)
|
ElMessage.error(normalizeApiError(error).message)
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false
|
submitting.value = false
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<ArtTable
|
<ArtTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
row-key="ID"
|
row-key="id"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:data="accountList"
|
:data="accountList"
|
||||||
:currentPage="pagination.page"
|
:currentPage="pagination.page"
|
||||||
@@ -120,8 +120,11 @@
|
|||||||
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
<ElEmpty v-if="filteredAvailableRoles.length === 0" description="暂无角色" />
|
||||||
<template v-else-if="isPlatformUser">
|
<template v-else-if="isPlatformUser">
|
||||||
<ElCheckboxGroup v-model="rolesToAdd" class="role-list">
|
<ElCheckboxGroup v-model="rolesToAdd" class="role-list">
|
||||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
<div v-for="role in filteredAvailableRoles" :key="getRoleId(role)" class="role-item">
|
||||||
<ElCheckbox :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
<ElCheckbox
|
||||||
|
:label="getRoleId(role)"
|
||||||
|
:disabled="selectedRoles.includes(getRoleId(role))"
|
||||||
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
<span>{{ role.role_name }}</span>
|
<span>{{ role.role_name }}</span>
|
||||||
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
||||||
@@ -134,8 +137,11 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<ElRadioGroup v-model="roleToAdd" class="role-list">
|
<ElRadioGroup v-model="roleToAdd" class="role-list">
|
||||||
<div v-for="role in filteredAvailableRoles" :key="role.ID" class="role-item">
|
<div v-for="role in filteredAvailableRoles" :key="getRoleId(role)" class="role-item">
|
||||||
<ElRadio :label="role.ID" :disabled="selectedRoles.includes(role.ID)">
|
<ElRadio
|
||||||
|
:label="getRoleId(role)"
|
||||||
|
:disabled="selectedRoles.includes(getRoleId(role))"
|
||||||
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
<span>{{ role.role_name }}</span>
|
<span>{{ role.role_name }}</span>
|
||||||
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
<ElTag :type="role.role_type === 1 ? 'primary' : 'success'" size="small">
|
||||||
@@ -177,7 +183,7 @@
|
|||||||
<div class="role-list">
|
<div class="role-list">
|
||||||
<div
|
<div
|
||||||
v-for="role in filteredAssignedRoles"
|
v-for="role in filteredAssignedRoles"
|
||||||
:key="role.ID"
|
:key="getRoleId(role)"
|
||||||
class="role-item assigned-role-item"
|
class="role-item assigned-role-item"
|
||||||
>
|
>
|
||||||
<span class="role-info">
|
<span class="role-info">
|
||||||
@@ -186,7 +192,12 @@
|
|||||||
{{ role.role_type === 1 ? '平台角色' : '客户角色' }}
|
{{ role.role_type === 1 ? '平台角色' : '客户角色' }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</span>
|
</span>
|
||||||
<ElButton type="danger" size="small" link @click="removeSingleRole(role.ID)">
|
<ElButton
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="removeSingleRole(getRoleId(role))"
|
||||||
|
>
|
||||||
移除
|
移除
|
||||||
</ElButton>
|
</ElButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -231,6 +242,7 @@
|
|||||||
import type { SearchFormItem } from '@/types'
|
import type { SearchFormItem } from '@/types'
|
||||||
import type { PlatformAccount, PlatformRole } from '@/types/api'
|
import type { PlatformAccount, PlatformRole } from '@/types/api'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
|
import { getCompatibleNumericId } from '@/utils/business/id'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
|
||||||
defineOptions({ name: 'CommonAccountList' })
|
defineOptions({ name: 'CommonAccountList' })
|
||||||
@@ -287,6 +299,9 @@
|
|||||||
// 是否为平台用户(平台用户可多选,其他单选)
|
// 是否为平台用户(平台用户可多选,其他单选)
|
||||||
const isPlatformUser = computed(() => currentAccountType.value === 2)
|
const isPlatformUser = computed(() => currentAccountType.value === 2)
|
||||||
|
|
||||||
|
const getAccountId = (account: PlatformAccount | any) => getCompatibleNumericId(account) ?? 0
|
||||||
|
const getRoleId = (role: PlatformRole | any) => getCompatibleNumericId(role) ?? 0
|
||||||
|
|
||||||
// 搜索表单初始值
|
// 搜索表单初始值
|
||||||
const initialSearchState = {
|
const initialSearchState = {
|
||||||
username: '',
|
username: '',
|
||||||
@@ -646,7 +661,9 @@
|
|||||||
|
|
||||||
// 计算属性:过滤后的已分配角色
|
// 计算属性:过滤后的已分配角色
|
||||||
const filteredAssignedRoles = computed(() => {
|
const filteredAssignedRoles = computed(() => {
|
||||||
const assignedRolesList = allRoles.value.filter((role) => selectedRoles.value.includes(role.ID))
|
const assignedRolesList = allRoles.value.filter((role) =>
|
||||||
|
selectedRoles.value.includes(getRoleId(role))
|
||||||
|
)
|
||||||
if (!rightRoleFilter.value) return assignedRolesList
|
if (!rightRoleFilter.value) return assignedRolesList
|
||||||
const keyword = rightRoleFilter.value.toLowerCase()
|
const keyword = rightRoleFilter.value.toLowerCase()
|
||||||
return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword))
|
return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword))
|
||||||
@@ -654,7 +671,12 @@
|
|||||||
|
|
||||||
// 显示分配角色对话框
|
// 显示分配角色对话框
|
||||||
const showRoleDialog = async (row: PlatformAccount) => {
|
const showRoleDialog = async (row: PlatformAccount) => {
|
||||||
currentAccountId.value = (row as any).id
|
const accountId = getAccountId(row)
|
||||||
|
if (!accountId) {
|
||||||
|
ElMessage.error('当前账号缺少账号标识,无法分配角色')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentAccountId.value = accountId
|
||||||
currentAccountName.value = row.username
|
currentAccountName.value = row.username
|
||||||
currentAccountType.value = row.user_type
|
currentAccountType.value = row.user_type
|
||||||
selectedRoles.value = []
|
selectedRoles.value = []
|
||||||
@@ -671,12 +693,12 @@
|
|||||||
await loadAllRoles('', roleType)
|
await loadAllRoles('', roleType)
|
||||||
|
|
||||||
// 先加载当前账号的角色,再打开对话框
|
// 先加载当前账号的角色,再打开对话框
|
||||||
const res = await AccountService.getAccountRoles((row as any).id)
|
const res = await AccountService.getAccountRoles(accountId)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// 提取角色ID数组
|
// 提取角色ID数组
|
||||||
const roles = res.data || []
|
const roles = res.data || []
|
||||||
// 兼容 ID 和 id 两种字段名
|
// 兼容 ID 和 id 两种字段名
|
||||||
selectedRoles.value = roles.map((role: any) => role.ID || role.id)
|
selectedRoles.value = roles.map((role: any) => getRoleId(role)).filter((id) => id > 0)
|
||||||
// 数据加载完成后再打开对话框
|
// 数据加载完成后再打开对话框
|
||||||
roleDialogVisible.value = true
|
roleDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
</ElSelect>
|
</ElSelect>
|
||||||
<template v-if="noSeriesId">
|
<template v-if="noSeriesId">
|
||||||
<div style="margin-top: 4px; font-size: 12px; color: var(--el-text-color-warning)">
|
<div style="margin-top: 4px; font-size: 12px; color: var(--el-text-color-warning)">
|
||||||
该设备未关联套餐系列,无法购买套餐
|
{{ noSeriesMessage }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="packagesEmptyWithSeriesId">
|
<template v-else-if="packagesEmptyWithSeriesId">
|
||||||
@@ -616,6 +616,10 @@
|
|||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const noSeriesMessage = computed(
|
||||||
|
() => `该${createForm.order_type === 'single_card' ? '卡' : '设备'}未关联套餐系列,无法购买套餐`
|
||||||
|
)
|
||||||
|
|
||||||
// 检查是否选择了赠送套餐
|
// 检查是否选择了赠送套餐
|
||||||
const selectedPackageIsGift = computed(() => {
|
const selectedPackageIsGift = computed(() => {
|
||||||
if (!createForm.package_id) return false
|
if (!createForm.package_id) return false
|
||||||
@@ -892,7 +896,8 @@
|
|||||||
prop: 'is_expired',
|
prop: 'is_expired',
|
||||||
label: '是否过期',
|
label: '是否过期',
|
||||||
width: 100,
|
width: 100,
|
||||||
formatter: (row: Order) => (row.is_expired === undefined ? '-' : row.is_expired ? '是' : '否')
|
formatter: (row: Order) =>
|
||||||
|
row.is_expired === undefined ? '-' : row.is_expired ? '是' : '否'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'expires_at',
|
prop: 'expires_at',
|
||||||
|
|||||||
@@ -337,6 +337,7 @@
|
|||||||
} from '@/types/api'
|
} from '@/types/api'
|
||||||
import { RoleType, RoleStatus } from '@/types/api'
|
import { RoleType, RoleStatus } from '@/types/api'
|
||||||
import { formatDateTime } from '@/utils/business/format'
|
import { formatDateTime } from '@/utils/business/format'
|
||||||
|
import { getCompatibleNumericId } from '@/utils/business/id'
|
||||||
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'
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
@@ -1144,7 +1145,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: getCompatibleNumericId(role) ?? 0,
|
||||||
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,
|
||||||
|
|||||||
@@ -255,6 +255,7 @@
|
|||||||
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'
|
||||||
|
import { getCompatibleNumericId } from '@/utils/business/id'
|
||||||
import {
|
import {
|
||||||
CommonStatus,
|
CommonStatus,
|
||||||
getStatusText,
|
getStatusText,
|
||||||
@@ -415,7 +416,7 @@
|
|||||||
|
|
||||||
const roleList = ref<PlatformRole[]>([])
|
const roleList = ref<PlatformRole[]>([])
|
||||||
|
|
||||||
const getRoleId = (role: PlatformRole | any) => role.id ?? role.ID
|
const getRoleId = (role: PlatformRole | any) => getCompatibleNumericId(role) ?? 0
|
||||||
|
|
||||||
const handleNameClick = (row: PlatformRole) => {
|
const handleNameClick = (row: PlatformRole) => {
|
||||||
if (hasAuth('role:detail')) {
|
if (hasAuth('role:detail')) {
|
||||||
@@ -1037,12 +1038,9 @@
|
|||||||
if (Array.isArray(permissions) && permissions.length > 0) {
|
if (Array.isArray(permissions) && permissions.length > 0) {
|
||||||
// 如果返回的是权限对象数组,提取ID或id字段
|
// 如果返回的是权限对象数组,提取ID或id字段
|
||||||
if (typeof permissions[0] === 'object') {
|
if (typeof permissions[0] === 'object') {
|
||||||
// 优先使用ID字段,如果没有则使用id字段
|
selectedPermissions.value = permissions
|
||||||
if ('ID' in permissions[0]) {
|
.map((perm: any) => getCompatibleNumericId(perm))
|
||||||
selectedPermissions.value = permissions.map((perm: any) => perm.ID)
|
.filter((id): id is number => id !== undefined)
|
||||||
} else if ('id' in permissions[0]) {
|
|
||||||
selectedPermissions.value = permissions.map((perm: any) => perm.id)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 如果返回的是ID数组
|
// 如果返回的是ID数组
|
||||||
selectedPermissions.value = permissions
|
selectedPermissions.value = permissions
|
||||||
@@ -1189,7 +1187,9 @@
|
|||||||
status: form.status
|
status: form.status
|
||||||
}
|
}
|
||||||
const res = await RoleService.createRole(data)
|
const res = await RoleService.createRole(data)
|
||||||
const createdRoleId = res.data?.ID ?? res.data?.id ?? res.data?.role_id
|
const createdRoleId =
|
||||||
|
getCompatibleNumericId(res.data) ??
|
||||||
|
(res.data?.role_id !== undefined ? Number(res.data.role_id) : undefined)
|
||||||
if (form.role_type === RoleType.CUSTOMER && createdRoleId) {
|
if (form.role_type === RoleType.CUSTOMER && createdRoleId) {
|
||||||
await RoleService.updateRoleDefaultCredit(createdRoleId, getDefaultCreditPayload())
|
await RoleService.updateRoleDefaultCredit(createdRoleId, getDefaultCreditPayload())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user