From 4470a4ef04f43daa82f3e170a7e70975ca2d341d Mon Sep 17 00:00:00 2001 From: sexygoat <1538832180@qq.com> Date: Fri, 27 Feb 2026 17:40:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9:=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/api/common.ts | 22 +- src/types/api/packageManagement.ts | 88 ++++--- .../account-management/account/index.vue | 98 ++++---- .../enterprise-customer/index.vue | 16 +- .../authorization-records/index.vue | 78 ++++--- .../asset-management/device-task/index.vue | 83 ++++--- .../iot-card-management/index.vue | 24 +- .../asset-management/iot-card-task/index.vue | 83 ++++--- .../commission/agent-commission/index.vue | 64 +++-- .../order-management/order-list/index.vue | 77 ++++-- .../package-assign/index.vue | 125 ++++++---- .../package-list/detail.vue | 45 +++- .../package-management/package-list/index.vue | 221 +++++++++++++----- .../package-series/index.vue | 150 ++++++------ .../series-assign/index.vue | 113 +++++---- src/views/system/permission/index.vue | 64 +++-- src/views/system/role/index.vue | 101 ++++---- 17 files changed, 908 insertions(+), 544 deletions(-) diff --git a/src/types/api/common.ts b/src/types/api/common.ts index 4d55699..c36dc16 100644 --- a/src/types/api/common.ts +++ b/src/types/api/common.ts @@ -22,19 +22,10 @@ export interface PaginationParams { // 分页响应数据 export interface PaginationData { - items: T[] // 后端实际返回的是 items,不是 records - total: number - size: number - page: number // 后端返回的是 page,不是 current - pages?: number -} - -// 新版分页响应数据(使用 list 字段) -export interface PaginationDataV2 { - list: T[] // 新版API使用 list 字段 - total: number - page_size: number - page: number + items: T[] // 数据列表 + total: number // 总数 + page_size: number // 每页数量 + page: number // 当前页 total_pages: number // 总页数 } @@ -43,11 +34,6 @@ export interface PaginationResponse extends BaseResponse { data: PaginationData } -// 新版分页响应(使用 list 字段) -export interface PaginationResponseV2 extends BaseResponse { - data: PaginationDataV2 -} - // 列表响应 export interface ListResponse extends BaseResponse { data: T[] diff --git a/src/types/api/packageManagement.ts b/src/types/api/packageManagement.ts index e05e8aa..7f11054 100644 --- a/src/types/api/packageManagement.ts +++ b/src/types/api/packageManagement.ts @@ -86,6 +86,15 @@ export interface UpdatePackageSeriesStatusRequest { // ==================== 套餐管理 ==================== +/** + * 返佣档位信息 + */ +export interface CommissionTierInfo { + current_rate?: string // 当前返佣比例 + next_rate?: string // 下一档位返佣比例 + next_threshold?: number | null // 下一档位阈值 +} + /** * 套餐响应 */ @@ -93,22 +102,28 @@ export interface PackageResponse { id: number package_code: string package_name: string - series_id: number - series_name?: string - package_type: string // 'formal':正式套餐, 'addon':加油包 - data_type: string // 'real':真实流量, 'virtual':虚拟流量 - real_data_mb: number // 真流量额度(MB) - virtual_data_mb: number // 虚流量额度(MB) - duration_months: number // 有效期(月) - price: number // 价格(分) - cost_price: number // 成本价(分) - suggested_retail_price: number // 建议零售价(分) - enable_virtual_data: boolean // 是否启用虚流量 - shelf_status: number // 上架状态 (1:上架, 2:下架) - status: number // 状态 (1:启用, 2:禁用) + series_id: number | null + series_name?: string | null + package_type: string // 'formal':正式套餐, 'addon':附加套餐 + calendar_type?: string // 套餐周期类型 (natural_month:自然月, by_day:按天) + duration_days?: number | null // 套餐天数(calendar_type=by_day时有值) + duration_months?: number // 套餐时长(月数) + data_reset_cycle?: string // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置) + real_data_mb?: number // 真流量额度(MB) + virtual_data_mb?: number // 虚流量额度(MB) + enable_virtual_data?: boolean // 是否启用虚流量 + enable_realname_activation?: boolean // 是否启用实名激活 (true:需实名后激活, false:立即激活) + cost_price?: number // 成本价(分) + suggested_retail_price?: number // 建议零售价(分) + current_commission_rate?: string // 当前返佣比例(仅代理用户可见) + one_time_commission_amount?: number | null // 一次性佣金金额(分,代理视角) + profit_margin?: number | null // 利润空间(分,仅代理用户可见) + tier_info?: CommissionTierInfo // 返佣档位信息 + shelf_status?: number // 上架状态 (1:上架, 2:下架) + status?: number // 状态 (1:启用, 2:禁用) description?: string - created_at: string - updated_at: string + created_at?: string + updated_at?: string } /** @@ -129,30 +144,37 @@ export interface PackageQueryParams extends PaginationParams { export interface CreatePackageRequest { package_code: string // 套餐编码,必填 package_name: string // 套餐名称,必填 - series_id: number // 所属系列ID,必填 - package_type: string // 套餐类型,必填 - data_type: string // 流量类型,必填 - real_data_mb: number // 真流量额度(MB),必填 - virtual_data_mb: number // 虚流量额度(MB),必填 - duration_months: number // 有效期(月),必填 - price: number // 价格(分),必填 - description?: string // 描述,可选 + series_id?: number | null // 所属系列ID,可选 + package_type: string // 套餐类型,必填 (formal:正式套餐, addon:附加套餐) + calendar_type?: string | null // 套餐周期类型 (natural_month:自然月, by_day:按天),可选 + duration_days?: number | null // 套餐天数(calendar_type=by_day时必填),可选 + duration_months: number // 套餐时长(月数),必填 + data_reset_cycle?: string | null // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置),可选 + real_data_mb?: number | null // 真流量额度(MB),可选 + virtual_data_mb?: number | null // 虚流量额度(MB),可选 + enable_virtual_data?: boolean // 是否启用虚流量,可选 + enable_realname_activation?: boolean | null // 是否启用实名激活 (true:需实名后激活, false:立即激活),可选 + cost_price: number // 成本价(分),必填 + suggested_retail_price?: number | null // 建议零售价(分),可选 } /** * 更新套餐请求 */ export interface UpdatePackageRequest { - package_code?: string - package_name?: string - series_id?: number - package_type?: string - data_type?: string - real_data_mb?: number - virtual_data_mb?: number - duration_months?: number - price?: number - description?: string + package_name?: string | null // 套餐名称,可选 + series_id?: number | null // 所属系列ID,可选 + package_type?: string | null // 套餐类型,可选 (formal:正式套餐, addon:附加套餐) + calendar_type?: string | null // 套餐周期类型 (natural_month:自然月, by_day:按天),可选 + duration_days?: number | null // 套餐天数(calendar_type=by_day时必填),可选 + duration_months?: number | null // 套餐时长(月数),可选 + data_reset_cycle?: string | null // 流量重置周期 (daily:每日, monthly:每月, yearly:每年, none:不重置),可选 + real_data_mb?: number | null // 真流量额度(MB),可选 + virtual_data_mb?: number | null // 虚流量额度(MB),可选 + enable_virtual_data?: boolean | null // 是否启用虚流量,可选 + enable_realname_activation?: boolean | null // 是否启用实名激活,可选 + cost_price?: number | null // 成本价(分),可选 + suggested_retail_price?: number | null // 建议零售价(分),可选 } /** diff --git a/src/views/account-management/account/index.vue b/src/views/account-management/account/index.vue index 5265995..0a94818 100644 --- a/src/views/account-management/account/index.vue +++ b/src/views/account-management/account/index.vue @@ -34,12 +34,21 @@ @selection-change="handleSelectionChange" @size-change="handleSizeChange" @current-change="handleCurrentChange" + @row-contextmenu="handleRowContextMenu" > + + + (0) const currentAccountName = ref('') const currentAccountType = ref(0) + const contextMenuRef = ref>() + const currentRow = ref(null) const selectedRoles = ref([]) const allRoles = ref([]) const rolesToAdd = ref([]) @@ -355,8 +368,7 @@ { label: '店铺名称', prop: 'shop_name' }, { label: '企业名称', prop: 'enterprise_name' }, { label: '状态', prop: 'status' }, - { label: '创建时间', prop: 'created_at' }, - { label: '操作', prop: 'operation' } + { label: '创建时间', prop: 'created_at' } ] // 显示对话框 @@ -473,44 +485,6 @@ label: '创建时间', width: 180, formatter: (row: any) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 240, - fixed: 'right', - formatter: (row: any) => { - const buttons = [] - - if (hasAuth('account:patch_role')) { - buttons.push( - h(ArtButtonTable, { - text: '分配角色', - onClick: () => showRoleDialog(row) - }) - ) - } - - if (hasAuth('account:edit')) { - buttons.push( - h(ArtButtonTable, { - text: '编辑', - onClick: () => showDialog('edit', row) - }) - ) - } - - if (hasAuth('account:delete')) { - buttons.push( - h(ArtButtonTable, { - text: '删除', - onClick: () => deleteAccount(row) - }) - ) - } - - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) - } } ]) @@ -851,6 +825,50 @@ const handleEnterpriseSearch = (query: string) => { loadEnterpriseList(query) } + + // 右键菜单项配置 + const contextMenuItems = computed((): MenuItemType[] => { + const items: MenuItemType[] = [] + + if (hasAuth('account:patch_role')) { + items.push({ key: 'assignRole', label: '分配角色' }) + } + + if (hasAuth('account:edit')) { + items.push({ key: 'edit', label: '编辑' }) + } + + if (hasAuth('account:delete')) { + items.push({ key: 'delete', label: '删除' }) + } + + return items + }) + + // 处理表格行右键菜单 + const handleRowContextMenu = (row: any, column: any, event: MouseEvent) => { + event.preventDefault() + event.stopPropagation() + currentRow.value = row + contextMenuRef.value?.show(event) + } + + // 处理右键菜单选择 + const handleContextMenuSelect = (item: MenuItemType) => { + if (!currentRow.value) return + + switch (item.key) { + case 'assignRole': + showRoleDialog(currentRow.value) + break + case 'edit': + showDialog('edit', currentRow.value) + break + case 'delete': + deleteAccount(currentRow.value) + break + } + } diff --git a/src/views/package-management/series-assign/index.vue b/src/views/package-management/series-assign/index.vue index a0469a4..6888c21 100644 --- a/src/views/package-management/series-assign/index.vue +++ b/src/views/package-management/series-assign/index.vue @@ -37,12 +37,21 @@ :marginTop="10" @size-change="handleSizeChange" @current-change="handleCurrentChange" + @row-contextmenu="handleRowContextMenu" > + + + () + const contextMenuRef = ref>() + const currentRow = ref(null) const seriesOptions = ref([]) const shopOptions = ref([]) const shopTreeData = ref([]) @@ -340,8 +353,7 @@ { label: '强充金额', prop: 'force_recharge_amount' }, { label: '强充触发类型', prop: 'force_recharge_trigger_type' }, { label: '状态', prop: 'status' }, - { label: '创建时间', prop: 'created_at' }, - { label: '操作', prop: 'operation' } + { label: '创建时间', prop: 'created_at' } ] // 表单数据 @@ -563,43 +575,6 @@ label: '创建时间', width: 180, formatter: (row: ShopSeriesAllocationResponse) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 220, - fixed: 'right', - formatter: (row: ShopSeriesAllocationResponse) => { - const buttons = [] - - // 详情按钮 - buttons.push( - h(ArtButtonTable, { - text: '详情', - onClick: () => handleViewDetail(row) - }) - ) - - if (hasAuth('series_assign:edit')) { - buttons.push( - h(ArtButtonTable, { - text: '编辑', - onClick: () => showDialog('edit', row) - }) - ) - } - - if (hasAuth('series_assign:delete')) { - buttons.push( - h(ArtButtonTable, { - text: '删除', - onClick: () => deleteAllocation(row) - }) - ) - } - - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) - } } ]) @@ -653,7 +628,7 @@ } const res = await PackageSeriesService.getPackageSeries(params) if (res.code === 0) { - seriesOptions.value = res.data.items || [] + seriesOptions.value = res.data.items } } catch (error) { console.error('加载系列选项失败:', error) @@ -672,7 +647,7 @@ page_size: 10000 // 使用较大的值获取所有店铺 }) if (res.code === 0) { - shopOptions.value = res.data.items || [] + shopOptions.value = res.data.items // 构建树形结构数据 shopTreeData.value = buildTreeData(shopOptions.value) } @@ -692,7 +667,7 @@ status: 1 }) if (res.code === 0) { - searchSeriesOptions.value = res.data.items || [] + searchSeriesOptions.value = res.data.items } } catch (error) { console.error('加载搜索栏系列选项失败:', error) @@ -704,7 +679,7 @@ try { const res = await ShopService.getShops({ page: 1, page_size: 10 }) if (res.code === 0) { - searchShopOptions.value = res.data.items || [] + searchShopOptions.value = res.data.items } } catch (error) { console.error('加载搜索栏店铺选项失败:', error) @@ -716,7 +691,7 @@ try { const res = await ShopService.getShops({ page: 1, page_size: 10 }) if (res.code === 0) { - searchAllocatorShopOptions.value = res.data.items || [] + searchAllocatorShopOptions.value = res.data.items } } catch (error) { console.error('加载搜索栏分配者店铺选项失败:', error) @@ -746,7 +721,7 @@ status: 1 }) if (res.code === 0) { - searchSeriesOptions.value = res.data.items || [] + searchSeriesOptions.value = res.data.items } } catch (error) { console.error('搜索系列失败:', error) @@ -766,7 +741,7 @@ shop_name: query }) if (res.code === 0) { - searchShopOptions.value = res.data.items || [] + searchShopOptions.value = res.data.items } } catch (error) { console.error('搜索店铺失败:', error) @@ -786,7 +761,7 @@ shop_name: query }) if (res.code === 0) { - searchAllocatorShopOptions.value = res.data.items || [] + searchAllocatorShopOptions.value = res.data.items } } catch (error) { console.error('搜索分配者店铺失败:', error) @@ -808,7 +783,7 @@ } const res = await ShopSeriesAllocationService.getShopSeriesAllocations(params) if (res.code === 0) { - allocationList.value = res.data.items || [] + allocationList.value = res.data.items pagination.total = res.data.total || 0 } } catch (error) { @@ -1011,6 +986,48 @@ console.error(error) } } + + // 右键菜单项配置 + const contextMenuItems = computed((): MenuItemType[] => { + const items: MenuItemType[] = [] + + items.push({ key: 'detail', label: '详情' }) + + if (hasAuth('series_assign:edit')) { + items.push({ key: 'edit', label: '编辑' }) + } + + if (hasAuth('series_assign:delete')) { + items.push({ key: 'delete', label: '删除' }) + } + + return items + }) + + // 处理表格行右键菜单 + const handleRowContextMenu = (row: ShopSeriesAllocationResponse, column: any, event: MouseEvent) => { + event.preventDefault() + event.stopPropagation() + currentRow.value = row + contextMenuRef.value?.show(event) + } + + // 处理右键菜单选择 + const handleContextMenuSelect = (item: MenuItemType) => { + if (!currentRow.value) return + + switch (item.key) { + case 'detail': + handleViewDetail(currentRow.value) + break + case 'edit': + showDialog('edit', currentRow.value) + break + case 'delete': + deleteAllocation(currentRow.value) + break + } + }