fix:通知和设备分配/回收
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m49s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m49s
This commit is contained in:
@@ -3,9 +3,7 @@
|
|||||||
<div class="notice" @click.stop>
|
<div class="notice" @click.stop>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="text">通知</span>
|
<span class="text">通知</span>
|
||||||
<button class="read-all" type="button" @click="handleMarkAllRead">
|
<button class="read-all" type="button" @click="handleMarkAllRead">全部已读</button>
|
||||||
全部已读
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
@@ -119,7 +117,7 @@
|
|||||||
ElMessage.info(item.body || '该通知暂无可跳转目标')
|
ElMessage.info(item.body || '该通知暂无可跳转目标')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!navigateNotificationTarget(router, targetResponse.data)) {
|
if (!navigateNotificationTarget(router, item.ref_type, targetResponse.data)) {
|
||||||
ElMessage.info(item.body || '该通知暂无可跳转目标')
|
ElMessage.info(item.body || '该通知暂无可跳转目标')
|
||||||
} else {
|
} else {
|
||||||
close()
|
close()
|
||||||
|
|||||||
@@ -739,7 +739,7 @@ export const asyncRoutes: AppRouteRecord[] = [
|
|||||||
{
|
{
|
||||||
path: 'agent-fund-overview',
|
path: 'agent-fund-overview',
|
||||||
name: 'AgentFundOverview',
|
name: 'AgentFundOverview',
|
||||||
component: RoutesAlias.AgentFundOverview,
|
component: RoutesAlias.AgentFundOverviewComponent,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'menus.commission.agentCommission',
|
title: 'menus.commission.agentCommission',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
|
|||||||
@@ -89,7 +89,8 @@ export enum RoutesAlias {
|
|||||||
// 佣金管理
|
// 佣金管理
|
||||||
WithdrawalApproval = '/commission-management/withdrawal-approval', // 提现审批
|
WithdrawalApproval = '/commission-management/withdrawal-approval', // 提现审批
|
||||||
MyCommission = '/commission-management/my-commission', // 我的佣金
|
MyCommission = '/commission-management/my-commission', // 我的佣金
|
||||||
AgentFundOverview = '/commission-management/agent-fund-overview', // 代理商资金概况
|
AgentFundOverview = '/commission/agent-fund-overview', // 代理商资金概况
|
||||||
|
AgentFundOverviewComponent = '/commission-management/agent-fund-overview', // 代理商资金概况组件路径
|
||||||
|
|
||||||
// 设置管理
|
// 设置管理
|
||||||
WithdrawalSettings = '/settings/withdrawal-settings', // 提现配置
|
WithdrawalSettings = '/settings/withdrawal-settings', // 提现配置
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
export type NotificationCategory = 'approval' | 'expiry' | 'sync' | 'system' | string
|
export type NotificationCategory = 'approval' | 'expiry' | 'sync' | 'system' | string
|
||||||
export type NotificationSeverity = 'info' | 'warning' | 'error' | 'critical' | string
|
export type NotificationSeverity = 'info' | 'warning' | 'error' | 'critical' | string
|
||||||
|
|
||||||
|
/** 后台通知引用的受控资源类型。 */
|
||||||
|
export type NotificationRefType =
|
||||||
|
| 'system_config'
|
||||||
|
| 'integration_log'
|
||||||
|
| 'package'
|
||||||
|
| 'asset'
|
||||||
|
| 'refund'
|
||||||
|
| 'agent_recharge'
|
||||||
|
| 'wecom_approval'
|
||||||
|
| 'iot_card'
|
||||||
|
| 'device'
|
||||||
|
| 'expiring_asset'
|
||||||
|
| 'shop_fund'
|
||||||
|
| 'card_sync'
|
||||||
|
| (string & {})
|
||||||
|
|
||||||
export interface NotificationItem {
|
export interface NotificationItem {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
@@ -11,7 +27,7 @@ export interface NotificationItem {
|
|||||||
is_read: boolean
|
is_read: boolean
|
||||||
created_at: string
|
created_at: string
|
||||||
read_at: string | null
|
read_at: string | null
|
||||||
ref_type: string | null
|
ref_type: NotificationRefType | null
|
||||||
ref_id: string | null
|
ref_id: string | null
|
||||||
ref_key: string | null
|
ref_key: string | null
|
||||||
}
|
}
|
||||||
@@ -63,7 +79,7 @@ export interface NotificationReadAllResponse {
|
|||||||
|
|
||||||
export interface NotificationTarget {
|
export interface NotificationTarget {
|
||||||
available: boolean
|
available: boolean
|
||||||
target_id: number | null
|
target_id: number | string | null
|
||||||
target_key: string
|
target_key: string
|
||||||
target_type: string
|
target_type: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,56 @@
|
|||||||
import type { Router } from 'vue-router'
|
import type { RouteLocationRaw, Router } from 'vue-router'
|
||||||
import type { NotificationTarget } from '@/types/api'
|
import type { NotificationRefType, NotificationTarget } from '@/types/api'
|
||||||
import { RoutesAlias } from '@/router/routesAlias'
|
import { RoutesAlias } from '@/router/routesAlias'
|
||||||
|
|
||||||
type TargetRoute = {
|
type TargetRoute = RouteLocationRaw
|
||||||
path: string
|
|
||||||
query?: Record<string, string>
|
const resolveTargetRoute = (
|
||||||
|
refType: NotificationRefType | null,
|
||||||
|
target: NotificationTarget
|
||||||
|
): TargetRoute | null => {
|
||||||
|
const targetId = target.target_id === null ? '' : String(target.target_id)
|
||||||
|
|
||||||
|
switch (refType) {
|
||||||
|
case 'system_config':
|
||||||
|
return { path: RoutesAlias.SystemConfigs }
|
||||||
|
case 'refund':
|
||||||
|
return { path: RoutesAlias.RefundManagement }
|
||||||
|
case 'agent_recharge':
|
||||||
|
return { path: RoutesAlias.AgentRecharge }
|
||||||
|
case 'iot_card':
|
||||||
|
return targetId ? { path: RoutesAlias.AssetInformation, query: { iccid: targetId } } : null
|
||||||
|
case 'device':
|
||||||
|
return targetId
|
||||||
|
? { path: RoutesAlias.AssetInformation, query: { virtual_no: targetId } }
|
||||||
|
: null
|
||||||
|
case 'expiring_asset':
|
||||||
|
return { path: RoutesAlias.ExpiringAssets }
|
||||||
|
case 'shop_fund':
|
||||||
|
return { path: RoutesAlias.AgentFundOverview }
|
||||||
|
case 'integration_log':
|
||||||
|
case 'package':
|
||||||
|
case 'asset':
|
||||||
|
case 'wecom_approval':
|
||||||
|
case 'card_sync':
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolveTargetRoute = (target: NotificationTarget): TargetRoute | null => {
|
export const navigateNotificationTarget = (
|
||||||
const targetId = target.target_id === null ? undefined : String(target.target_id)
|
router: Router,
|
||||||
const targetKey = target.target_key || ''
|
refType: NotificationRefType | null,
|
||||||
|
target?: NotificationTarget | null
|
||||||
if (target.target_type === 'refund_detail' && targetId) {
|
) => {
|
||||||
return { path: `${RoutesAlias.RefundDetail}/${targetId}` }
|
if (!target) return false
|
||||||
|
if (!target.available) {
|
||||||
|
void router.push(RoutesAlias.Exception403)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.target_type === 'agent_recharge_detail' && targetId) {
|
const route = resolveTargetRoute(refType, target)
|
||||||
return { path: `${RoutesAlias.AgentRechargeDetail}/${targetId}` }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.target_type === 'iot_card_detail' && (targetKey || targetId)) {
|
|
||||||
return {
|
|
||||||
path: RoutesAlias.AssetInformation,
|
|
||||||
query: { iccid: targetKey || targetId || '' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.target_type === 'device_detail' && (targetKey || targetId)) {
|
|
||||||
return {
|
|
||||||
path: RoutesAlias.AssetInformation,
|
|
||||||
query: { virtual_no: targetKey || targetId || '' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
target.target_type === 'expiring_asset_list' ||
|
|
||||||
target.target_key === 'expiring_assets' ||
|
|
||||||
target.target_key === 'expiring_asset_list'
|
|
||||||
) {
|
|
||||||
return { path: RoutesAlias.ExpiringAssets }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.target_type === 'shop_fund_summary') {
|
|
||||||
return {
|
|
||||||
path: RoutesAlias.AgentFundOverview,
|
|
||||||
query: targetId ? { shop_id: targetId } : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.target_type === 'system_config') {
|
|
||||||
return {
|
|
||||||
path: RoutesAlias.SystemConfigs,
|
|
||||||
query: targetKey ? { config_key: targetKey } : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const navigateNotificationTarget = (router: Router, target?: NotificationTarget | null) => {
|
|
||||||
if (!target?.available) return false
|
|
||||||
const route = resolveTargetRoute(target)
|
|
||||||
if (!route) return false
|
if (!route) return false
|
||||||
|
|
||||||
const resolved = router.resolve({ path: route.path, query: route.query })
|
void router.push(route)
|
||||||
if (!resolved.matched.length || resolved.name === 'Exception404') return false
|
|
||||||
void router.push(resolved)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -831,15 +831,20 @@
|
|||||||
try {
|
try {
|
||||||
const response = await CardService.setSpeedTier(iccid, data.code)
|
const response = await CardService.setSpeedTier(iccid, data.code)
|
||||||
if (response.code !== 0) {
|
if (response.code !== 0) {
|
||||||
|
speedLimitDialogVisible.value = false
|
||||||
|
await nextTick()
|
||||||
ElMessage.error(response.msg || '限速设置失败')
|
ElMessage.error(response.msg || '限速设置失败')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ElMessage.success(`限速设置成功:${response.data.speed_tier_name}`)
|
|
||||||
speedLimitDialogVisible.value = false
|
speedLimitDialogVisible.value = false
|
||||||
|
await nextTick()
|
||||||
|
ElMessage.success(`限速设置成功:${response.data.speed_tier_name}`)
|
||||||
await handleRefresh()
|
await handleRefresh()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('设置限速失败:', error)
|
console.error('设置限速失败:', error)
|
||||||
|
speedLimitDialogVisible.value = false
|
||||||
|
await nextTick()
|
||||||
ElMessage.error(normalizeApiError(error).message)
|
ElMessage.error(normalizeApiError(error).message)
|
||||||
} finally {
|
} finally {
|
||||||
speedTierSubmitting.value = false
|
speedTierSubmitting.value = false
|
||||||
|
|||||||
@@ -17,6 +17,21 @@
|
|||||||
@refresh="handleRefresh"
|
@refresh="handleRefresh"
|
||||||
>
|
>
|
||||||
<template #left>
|
<template #left>
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
@click="handleBatchAllocate"
|
||||||
|
:disabled="!selectedDevices.length"
|
||||||
|
v-permission="'device:batch_allocate'"
|
||||||
|
>
|
||||||
|
批量分配
|
||||||
|
</ElButton>
|
||||||
|
<ElButton
|
||||||
|
@click="handleBatchRecall"
|
||||||
|
:disabled="!selectedDevices.length"
|
||||||
|
v-permission="'device:batch_recall'"
|
||||||
|
>
|
||||||
|
批量回收
|
||||||
|
</ElButton>
|
||||||
<ElButton
|
<ElButton
|
||||||
type="primary"
|
type="primary"
|
||||||
:disabled="!selectedDevices.length"
|
:disabled="!selectedDevices.length"
|
||||||
@@ -2350,6 +2365,19 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量分配(设备列表原有操作,和设备批量任务页面并行保留)
|
||||||
|
const handleBatchAllocate = async () => {
|
||||||
|
if (selectedDevices.value.length === 0) {
|
||||||
|
ElMessage.warning('请先选择要分配的设备')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
allocateForm.target_shop_id = undefined
|
||||||
|
allocateForm.remark = ''
|
||||||
|
allocateResult.value = null
|
||||||
|
shopCascadeOptions.value = []
|
||||||
|
allocateDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 确认批量分配
|
// 确认批量分配
|
||||||
const handleConfirmAllocate = async () => {
|
const handleConfirmAllocate = async () => {
|
||||||
if (!allocateFormRef.value) return
|
if (!allocateFormRef.value) return
|
||||||
@@ -2400,6 +2428,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量回收(设备列表原有操作,和设备批量任务页面并行保留)
|
||||||
|
const handleBatchRecall = () => {
|
||||||
|
if (selectedDevices.value.length === 0) {
|
||||||
|
ElMessage.warning('请先选择要回收的设备')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recallForm.remark = ''
|
||||||
|
recallResult.value = null
|
||||||
|
recallDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 确认批量回收
|
// 确认批量回收
|
||||||
const handleConfirmRecall = async () => {
|
const handleConfirmRecall = async () => {
|
||||||
recallLoading.value = true
|
recallLoading.value = true
|
||||||
|
|||||||
Reference in New Issue
Block a user