This commit is contained in:
27
src/api/modules/assetWallet.ts
Normal file
27
src/api/modules/assetWallet.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { BaseService } from '../BaseService'
|
||||
import type {
|
||||
BaseResponse,
|
||||
AssetAutoRenewalConfig,
|
||||
UpdateAssetAutoRenewalConfigRequest
|
||||
} from '@/types/api'
|
||||
|
||||
/**
|
||||
* 资产钱包相关服务
|
||||
*/
|
||||
export class AssetWalletService extends BaseService {
|
||||
/**
|
||||
* 查询自动续费配置
|
||||
*/
|
||||
static getAutoRenewalConfig(): Promise<BaseResponse<AssetAutoRenewalConfig>> {
|
||||
return this.get<BaseResponse<AssetAutoRenewalConfig>>('/api/admin/asset-auto-renewal-config')
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存自动续费配置
|
||||
*/
|
||||
static saveAutoRenewalConfig(
|
||||
data: UpdateAssetAutoRenewalConfigRequest
|
||||
): Promise<BaseResponse<AssetAutoRenewalConfig>> {
|
||||
return this.put<BaseResponse<AssetAutoRenewalConfig>>('/api/admin/asset-auto-renewal-config', data)
|
||||
}
|
||||
}
|
||||
@@ -53,3 +53,7 @@ export { H5PopupConfigurationService } from './h5PopupConfiguration'
|
||||
// export { SettingService } from './setting'
|
||||
|
||||
export { PackageTrafficAlertService } from './packageTrafficAlert'
|
||||
|
||||
export { PollingPriorityQueueService } from './pollingPriorityQueue'
|
||||
|
||||
export { AssetWalletService } from './assetWallet'
|
||||
|
||||
53
src/api/modules/pollingPriorityQueue.ts
Normal file
53
src/api/modules/pollingPriorityQueue.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 轮询优先队列 API
|
||||
*/
|
||||
import { BaseService } from '../BaseService'
|
||||
import type {
|
||||
BaseResponse,
|
||||
PollingPriorityItem,
|
||||
PollingPriorityItemPageResult,
|
||||
PollingPriorityItemQueryParams,
|
||||
CreatePollingPriorityItemRequest,
|
||||
CreatePollingPriorityItemResponse
|
||||
} from '@/types/api'
|
||||
|
||||
/**
|
||||
* 轮询优先队列服务
|
||||
*/
|
||||
export class PollingPriorityQueueService extends BaseService {
|
||||
/**
|
||||
* 获取优先轮询项列表
|
||||
* GET /api/admin/polling-priority-items
|
||||
* 按创建时间倒序返回,支持卡ID、任务类型、状态、触发类型筛选
|
||||
*/
|
||||
static getPriorityItems(
|
||||
params?: PollingPriorityItemQueryParams
|
||||
): Promise<BaseResponse<PollingPriorityItemPageResult>> {
|
||||
return this.get<BaseResponse<PollingPriorityItemPageResult>>(
|
||||
'/api/admin/polling-priority-items',
|
||||
params
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 人工优先入队
|
||||
* POST /api/admin/polling-priority-items
|
||||
* 请求体 { card_id, reason },为卡片全部范围内的轮询任务类型创建或合并优先项
|
||||
*/
|
||||
static createPriorityItems(
|
||||
data: CreatePollingPriorityItemRequest
|
||||
): Promise<BaseResponse<CreatePollingPriorityItemResponse>> {
|
||||
return this.post<BaseResponse<CreatePollingPriorityItemResponse>>(
|
||||
'/api/admin/polling-priority-items',
|
||||
data
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优先轮询项详情
|
||||
* GET /api/admin/polling-priority-items/{id}
|
||||
*/
|
||||
static getPriorityItemDetail(id: number): Promise<BaseResponse<PollingPriorityItem>> {
|
||||
return this.get<BaseResponse<PollingPriorityItem>>(`/api/admin/polling-priority-items/${id}`)
|
||||
}
|
||||
}
|
||||
@@ -43,3 +43,6 @@ export * from './packageTrafficAlert'
|
||||
export * from './bulkPurchase'
|
||||
export * from './julyIteration'
|
||||
export * from './augustIteration'
|
||||
|
||||
// 轮询优先队列相关
|
||||
export * from './pollingPriorityQueue'
|
||||
|
||||
71
src/config/constants/pollingPriorityQueue.ts
Normal file
71
src/config/constants/pollingPriorityQueue.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 轮询优先队列相关常量
|
||||
* 对应 docs/产品迭代8月份/优先队列.md
|
||||
*/
|
||||
|
||||
import type {
|
||||
PollingPriorityTaskType,
|
||||
PollingPriorityItemStatus,
|
||||
PollingPriorityTriggerType,
|
||||
PollingPriorityResult
|
||||
} from '@/types/api'
|
||||
|
||||
/** 任务类型选项 */
|
||||
export const POLLING_PRIORITY_TASK_TYPE_OPTIONS: Array<{
|
||||
label: string
|
||||
value: PollingPriorityTaskType
|
||||
}> = [
|
||||
{ label: '实名检查', value: 'polling:realname' },
|
||||
{ label: '流量检查', value: 'polling:carddata' },
|
||||
{ label: '套餐检查', value: 'polling:package' },
|
||||
{ label: '卡状态检查', value: 'polling:card_status' }
|
||||
]
|
||||
|
||||
export const getPollingPriorityTaskTypeName = (
|
||||
taskType?: PollingPriorityTaskType | string | null
|
||||
) =>
|
||||
POLLING_PRIORITY_TASK_TYPE_OPTIONS.find((item) => item.value === taskType)?.label ||
|
||||
String(taskType || '-')
|
||||
|
||||
/** 状态选项 */
|
||||
export const POLLING_PRIORITY_STATUS_OPTIONS: Array<{
|
||||
label: string
|
||||
value: PollingPriorityItemStatus
|
||||
}> = [
|
||||
{ label: '待处理', value: 'pending' },
|
||||
{ label: '处理中', value: 'processing' },
|
||||
{ label: '已完成', value: 'completed' },
|
||||
{ label: '失败', value: 'failed' }
|
||||
]
|
||||
|
||||
export const getPollingPriorityStatusName = (
|
||||
status?: PollingPriorityItemStatus | string | null
|
||||
) =>
|
||||
POLLING_PRIORITY_STATUS_OPTIONS.find((item) => item.value === status)?.label ||
|
||||
String(status || '-')
|
||||
|
||||
/** 触发类型选项 */
|
||||
export const POLLING_PRIORITY_TRIGGER_TYPE_OPTIONS: Array<{
|
||||
label: string
|
||||
value: PollingPriorityTriggerType
|
||||
}> = [
|
||||
{ label: '购买激活', value: 'purchase_activated' },
|
||||
{ label: '续费激活', value: 'renewal_activated' },
|
||||
{ label: '队列激活', value: 'queue_activated' },
|
||||
{ label: '附加套餐激活', value: 'addon_activated' },
|
||||
{ label: '无有效套餐', value: 'no_valid_package' },
|
||||
{ label: '人工触发', value: 'manual_trigger' }
|
||||
]
|
||||
|
||||
export const getPollingPriorityTriggerTypeName = (
|
||||
triggerType?: PollingPriorityTriggerType | string | null
|
||||
) =>
|
||||
POLLING_PRIORITY_TRIGGER_TYPE_OPTIONS.find((item) => item.value === triggerType)?.label ||
|
||||
String(triggerType || '-')
|
||||
|
||||
/** 执行结果名称(result 为空时展示为未出结果) */
|
||||
export const getPollingPriorityResultName = (result?: PollingPriorityResult | string | null) => {
|
||||
if (result === 'success') return '成功'
|
||||
if (result === 'failed') return '失败'
|
||||
return '未出结果'
|
||||
}
|
||||
@@ -1216,6 +1216,16 @@ export const asyncRoutes: AppRouteRecord[] = [
|
||||
title: '轮询监控',
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
// 优先队列
|
||||
{
|
||||
path: 'priority-queue',
|
||||
name: 'PollingPriorityQueue',
|
||||
component: RoutesAlias.PollingPriorityQueue,
|
||||
meta: {
|
||||
title: '优先队列',
|
||||
keepAlive: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ export enum RoutesAlias {
|
||||
PollingConfig = '/polling-management/config', // 轮询配置
|
||||
ManualTrigger = '/polling-management/manual-trigger', // 手动触发
|
||||
PollingMonitor = '/polling-management/monitor', // 轮询监控
|
||||
PollingPriorityQueue = '/polling-management/priority-queue', // 优先队列
|
||||
|
||||
// 公共组件
|
||||
Success = '/result/success', // 成功
|
||||
|
||||
46
src/types/api/assetWallet.ts
Normal file
46
src/types/api/assetWallet.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 资产钱包相关类型定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 自动续费适用范围
|
||||
*/
|
||||
export type AssetAutoRenewalScope = 'all' | 'specified'
|
||||
|
||||
/**
|
||||
* 资产钱包自动续费配置对象
|
||||
*/
|
||||
export interface AssetAutoRenewalConfig {
|
||||
/** 总开关(1:开启,0:关闭) */
|
||||
enabled: 0 | 1
|
||||
/** 总开关名称 */
|
||||
enabled_name: string
|
||||
/** 适用范围(all:全部主套餐,specified:指定主套餐) */
|
||||
scope: AssetAutoRenewalScope
|
||||
/** 适用范围名称 */
|
||||
scope_name: string
|
||||
/** 指定主套餐ID列表(scope=specified 时非空) */
|
||||
package_ids: number[]
|
||||
/** 统一到期前天数(1-90) */
|
||||
days_before_expiry: number
|
||||
/** 配置版本 */
|
||||
config_version: number
|
||||
/** 最近保存操作者 */
|
||||
updater: string
|
||||
/** 最近保存时间 */
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新资产钱包自动续费配置请求参数
|
||||
*/
|
||||
export interface UpdateAssetAutoRenewalConfigRequest {
|
||||
/** 总开关(0/1,必填) */
|
||||
enabled: 0 | 1
|
||||
/** 适用范围(all/specified,必填) */
|
||||
scope: AssetAutoRenewalScope
|
||||
/** 指定主套餐ID列表(scope=specified 时必填非空且仅当前可售主套餐) */
|
||||
package_ids: number[]
|
||||
/** 统一到期前天数(1-90,必填) */
|
||||
days_before_expiry: number
|
||||
}
|
||||
@@ -147,3 +147,9 @@ export * from './h5PopupConfiguration'
|
||||
|
||||
// 套餐真流量预警相关
|
||||
export * from './packageTrafficAlert'
|
||||
|
||||
// 轮询优先队列相关
|
||||
export * from './pollingPriorityQueue'
|
||||
|
||||
// 资产钱包自动续费相关
|
||||
export * from './assetWallet'
|
||||
|
||||
171
src/types/api/pollingPriorityQueue.ts
Normal file
171
src/types/api/pollingPriorityQueue.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* 轮询优先队列相关类型定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 优先轮询任务类型
|
||||
*/
|
||||
export type PollingPriorityTaskType =
|
||||
| 'polling:realname'
|
||||
| 'polling:carddata'
|
||||
| 'polling:package'
|
||||
| 'polling:card_status'
|
||||
|
||||
/**
|
||||
* 优先轮询项状态
|
||||
*/
|
||||
export type PollingPriorityItemStatus = 'pending' | 'processing' | 'completed' | 'failed'
|
||||
|
||||
/**
|
||||
* 优先轮询项触发类型
|
||||
*/
|
||||
export type PollingPriorityTriggerType =
|
||||
| 'purchase_activated'
|
||||
| 'renewal_activated'
|
||||
| 'queue_activated'
|
||||
| 'addon_activated'
|
||||
| 'no_valid_package'
|
||||
| 'manual_trigger'
|
||||
|
||||
/**
|
||||
* 优先轮询执行结果
|
||||
*/
|
||||
export type PollingPriorityResult = 'success' | 'failed' | ''
|
||||
|
||||
/**
|
||||
* 优先轮询项对象
|
||||
*/
|
||||
export interface PollingPriorityItem {
|
||||
/** 优先轮询项ID */
|
||||
id: number
|
||||
/** 卡ID */
|
||||
card_id: number
|
||||
/** 卡ICCID */
|
||||
iccid: string
|
||||
/** 任务类型 */
|
||||
task_type: PollingPriorityTaskType
|
||||
/** 任务类型名称 */
|
||||
task_type_name: string
|
||||
/** 状态 */
|
||||
status: PollingPriorityItemStatus
|
||||
/** 状态名称 */
|
||||
status_name: string
|
||||
/** 触发类型 */
|
||||
trigger_type: PollingPriorityTriggerType
|
||||
/** 触发类型名称 */
|
||||
trigger_type_name: string
|
||||
/** 触发类型列表 */
|
||||
trigger_types: PollingPriorityTriggerType[]
|
||||
/** 触发次数 */
|
||||
trigger_count: number
|
||||
/** 尝试次数 */
|
||||
attempt_count: number
|
||||
/** 执行结果 */
|
||||
result: PollingPriorityResult
|
||||
/** 执行结果名称 */
|
||||
result_name: string
|
||||
/** 失败原因 */
|
||||
failure_reason: string | null
|
||||
/** 店铺快照ID */
|
||||
shop_id_snapshot: number | null
|
||||
/** 来源订单ID */
|
||||
source_order_id: number | null
|
||||
/** 来源套餐使用记录ID */
|
||||
source_package_usage_id: number | null
|
||||
/** 人工操作者ID */
|
||||
manual_operator_id: number | null
|
||||
/** 人工操作者名称 */
|
||||
manual_operator_name: string | null
|
||||
/** 人工入队原因 */
|
||||
manual_reason: string | null
|
||||
/** 认领时间 */
|
||||
claimed_at: string | null
|
||||
/** 最后触发时间 */
|
||||
last_triggered_at: string | null
|
||||
/** 创建时间 */
|
||||
created_at: string
|
||||
/** 更新时间 */
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先轮询项查询参数
|
||||
*/
|
||||
export interface PollingPriorityItemQueryParams {
|
||||
/** 页码(默认1,最小1) */
|
||||
page?: number
|
||||
/** 每页数量(默认20,最大100) */
|
||||
page_size?: number
|
||||
/** 卡ID筛选 */
|
||||
card_id?: number
|
||||
/** 任务类型筛选 */
|
||||
task_type?: PollingPriorityTaskType
|
||||
/** 状态筛选 */
|
||||
status?: PollingPriorityItemStatus
|
||||
/** 触发类型筛选 */
|
||||
trigger_type?: PollingPriorityTriggerType
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先轮询项分页响应
|
||||
*/
|
||||
export interface PollingPriorityItemPageResult {
|
||||
/** 优先轮询项列表 */
|
||||
items: PollingPriorityItem[]
|
||||
/** 当前页 */
|
||||
page: number
|
||||
/** 每页数量 */
|
||||
size: number
|
||||
/** 总数 */
|
||||
total: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 人工优先入队请求参数
|
||||
*/
|
||||
export interface CreatePollingPriorityItemRequest {
|
||||
/** 卡ID */
|
||||
card_id: number
|
||||
/** 入队原因(必填,最长500字符) */
|
||||
reason: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 人工入队结果项
|
||||
*/
|
||||
export interface PriorityItemResult {
|
||||
/** 优先轮询项ID */
|
||||
id: number
|
||||
/** 卡ID */
|
||||
card_id: number
|
||||
/** 卡ICCID */
|
||||
iccid: string
|
||||
/** 任务类型 */
|
||||
task_type: PollingPriorityTaskType
|
||||
/** 任务类型名称 */
|
||||
task_type_name: string
|
||||
/** 状态 */
|
||||
status: PollingPriorityItemStatus
|
||||
/** 状态名称 */
|
||||
status_name: string
|
||||
/** 触发次数 */
|
||||
trigger_count: number
|
||||
/** 创建时间 */
|
||||
created_at: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 人工优先入队响应
|
||||
*/
|
||||
export interface CreatePollingPriorityItemResponse {
|
||||
/** 新建数量 */
|
||||
created_count: number
|
||||
/** 合并数量 */
|
||||
merged_count: number
|
||||
/** 涉及任务类型列表 */
|
||||
task_types: PollingPriorityTaskType[]
|
||||
/** 涉及任务类型名称列表 */
|
||||
task_type_names: string[]
|
||||
/** 入队结果项列表 */
|
||||
items: PriorityItemResult[]
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
label-width="110"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
label-width="110"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
|
||||
@@ -300,7 +300,7 @@
|
||||
<ElFormItem label="主体类型" prop="subject_type">
|
||||
<ElRadioGroup v-model="qualificationForm.subject_type">
|
||||
<ElRadio label="enterprise">企业</ElRadio>
|
||||
<ElRadio label="individual">个人</ElRadio>
|
||||
<ElRadio label="personal">个人</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="主体证件号" prop="subject_code">
|
||||
@@ -367,11 +367,7 @@
|
||||
</ElFormItem>
|
||||
<div class="qualification-row">
|
||||
<ElFormItem label="发票抬头">
|
||||
<ElInput
|
||||
v-model="qualificationForm.invoice_title"
|
||||
placeholder="选填"
|
||||
maxlength="100"
|
||||
/>
|
||||
<ElInput v-model="qualificationForm.invoice_title" placeholder="选填" maxlength="100" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="发票主体证件号">
|
||||
<ElInput
|
||||
@@ -399,18 +395,28 @@
|
||||
<div v-loading="detailLoading" class="withdrawal-detail">
|
||||
<template v-if="withdrawalDetail">
|
||||
<ElDescriptions :column="1" border>
|
||||
<ElDescriptionsItem label="提现单号">{{ withdrawalDetail.withdrawal_no }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现单号">{{
|
||||
withdrawalDetail.withdrawal_no
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="状态">{{ withdrawalDetail.status_name }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现金额">{{ formatMoney(withdrawalDetail.amount) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="实际到账">{{ formatMoney(withdrawalDetail.actual_amount) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="手续费">{{ formatMoney(withdrawalDetail.fee) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现金额">{{
|
||||
formatMoney(withdrawalDetail.amount)
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="实际到账">{{
|
||||
formatMoney(withdrawalDetail.actual_amount)
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="手续费">{{
|
||||
formatMoney(withdrawalDetail.fee)
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现方式">
|
||||
{{ withdrawalMethodLabel(withdrawalDetail.withdrawal_method) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="收款账户">
|
||||
{{ withdrawalDetail.account_name }} / {{ withdrawalDetail.account_number }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="驳回原因">{{ withdrawalDetail.reject_reason || '-' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="驳回原因">{{
|
||||
withdrawalDetail.reject_reason || '-'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="异常标记">
|
||||
<ElTag :type="withdrawalDetail.anomaly_flag ? 'danger' : 'success'">
|
||||
{{ withdrawalDetail.anomaly_name }}
|
||||
@@ -442,12 +448,7 @@
|
||||
</ElDrawer>
|
||||
|
||||
<!-- 重新提交被驳回的提现 -->
|
||||
<ElDialog
|
||||
v-model="resubmitDialogVisible"
|
||||
title="重新提交提现"
|
||||
width="560px"
|
||||
destroy-on-close
|
||||
>
|
||||
<ElDialog v-model="resubmitDialogVisible" title="重新提交提现" width="560px" destroy-on-close>
|
||||
<ElForm
|
||||
ref="resubmitFormRef"
|
||||
:model="resubmitForm"
|
||||
@@ -503,11 +504,7 @@
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="resubmitDialogVisible = false">取消</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
:loading="resubmitSubmitting"
|
||||
@click="handleSubmitResubmit"
|
||||
>
|
||||
<ElButton type="primary" :loading="resubmitSubmitting" @click="handleSubmitResubmit">
|
||||
提交
|
||||
</ElButton>
|
||||
</template>
|
||||
@@ -529,7 +526,6 @@
|
||||
confirm-permission="commission_record:export"
|
||||
title="导出佣金记录"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -549,7 +545,7 @@
|
||||
WithdrawalQualificationSubmitParams,
|
||||
WithdrawalRequestDetail,
|
||||
ResubmitWithdrawalRequestParams,
|
||||
ShopCommissionRecordSource,
|
||||
ShopCommissionRecordSource
|
||||
} from '@/types/api/commission'
|
||||
import { WithdrawalMethod, WithdrawalStatus } from '@/types/api/commission'
|
||||
import type { Order, OrderQueryParams } from '@/types/api/order'
|
||||
@@ -1336,7 +1332,6 @@
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// ==================== 提现资料资格 ====================
|
||||
|
||||
const qualificationLoading = ref(false)
|
||||
@@ -1371,54 +1366,52 @@
|
||||
return labels.length > 0 ? labels.join('、') : '-'
|
||||
}
|
||||
|
||||
const {
|
||||
columnChecks: qualificationColumnChecks,
|
||||
columns: qualificationColumns
|
||||
} = useCheckedColumns(() => [
|
||||
{ prop: 'subject_type_name', label: '主体类型', width: 90 },
|
||||
{ prop: 'subject_code_masked', label: '主体证件号', minWidth: 160 },
|
||||
{ prop: 'legal_person_id_card_masked', label: '法人身份证', minWidth: 170 },
|
||||
{
|
||||
prop: 'status_name',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: WithdrawalQualificationItem) => {
|
||||
const tagType = row.status === 0 ? 'warning' : row.status === 1 ? 'success' : 'danger'
|
||||
return h(ElTag, { type: tagType }, () => row.status_name || String(row.status))
|
||||
const { columnChecks: qualificationColumnChecks, columns: qualificationColumns } =
|
||||
useCheckedColumns(() => [
|
||||
{ prop: 'subject_type_name', label: '主体类型', width: 90 },
|
||||
{ prop: 'subject_code_masked', label: '主体证件号', minWidth: 160 },
|
||||
{ prop: 'legal_person_id_card_masked', label: '法人身份证', minWidth: 170 },
|
||||
{
|
||||
prop: 'status_name',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
formatter: (row: WithdrawalQualificationItem) => {
|
||||
const tagType = row.status === 0 ? 'warning' : row.status === 1 ? 'success' : 'danger'
|
||||
return h(ElTag, { type: tagType }, () => row.status_name || String(row.status))
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'approval_status_name',
|
||||
label: '审批状态',
|
||||
width: 100,
|
||||
formatter: (row: WithdrawalQualificationItem) => row.approval_status_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'attachments',
|
||||
label: '附件',
|
||||
minWidth: 200,
|
||||
formatter: (row: WithdrawalQualificationItem) => qualificationAttachmentLabels(row)
|
||||
},
|
||||
{
|
||||
prop: 'invalid_reason',
|
||||
label: '作废原因',
|
||||
minWidth: 160,
|
||||
formatter: (row: WithdrawalQualificationItem) => row.invalid_reason || '-'
|
||||
},
|
||||
{
|
||||
prop: 'invalidated_at',
|
||||
label: '作废时间',
|
||||
width: 170,
|
||||
formatter: (row: WithdrawalQualificationItem) =>
|
||||
row.invalidated_at ? formatDateTime(row.invalidated_at) : '-'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 170,
|
||||
formatter: (row: WithdrawalQualificationItem) => formatDateTime(row.created_at)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'approval_status_name',
|
||||
label: '审批状态',
|
||||
width: 100,
|
||||
formatter: (row: WithdrawalQualificationItem) => row.approval_status_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'attachments',
|
||||
label: '附件',
|
||||
minWidth: 200,
|
||||
formatter: (row: WithdrawalQualificationItem) => qualificationAttachmentLabels(row)
|
||||
},
|
||||
{
|
||||
prop: 'invalid_reason',
|
||||
label: '作废原因',
|
||||
minWidth: 160,
|
||||
formatter: (row: WithdrawalQualificationItem) => row.invalid_reason || '-'
|
||||
},
|
||||
{
|
||||
prop: 'invalidated_at',
|
||||
label: '作废时间',
|
||||
width: 170,
|
||||
formatter: (row: WithdrawalQualificationItem) =>
|
||||
row.invalidated_at ? formatDateTime(row.invalidated_at) : '-'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 170,
|
||||
formatter: (row: WithdrawalQualificationItem) => formatDateTime(row.created_at)
|
||||
}
|
||||
])
|
||||
])
|
||||
|
||||
const getQualificationList = async () => {
|
||||
if (!currentShopId.value) return
|
||||
@@ -1562,8 +1555,7 @@
|
||||
confirmButtonText: '确认作废',
|
||||
cancelButtonText: '取消',
|
||||
inputPlaceholder: '作废原因(必填)',
|
||||
inputValidator: (reason: string) =>
|
||||
reason && reason.trim() ? true : '作废原因必填',
|
||||
inputValidator: (reason: string) => (reason && reason.trim() ? true : '作废原因必填'),
|
||||
type: 'warning'
|
||||
})
|
||||
await CommissionService.voidWithdrawalQualification(row.id, { reason: value.trim() })
|
||||
@@ -1571,8 +1563,8 @@
|
||||
getQualificationList()
|
||||
} catch {
|
||||
// 取消或请求失败
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 提现详情与重提 ====================
|
||||
|
||||
@@ -1591,10 +1583,7 @@
|
||||
detailLoading.value = true
|
||||
withdrawalDetail.value = null
|
||||
try {
|
||||
const res = await CommissionService.getWithdrawalRequestDetail(
|
||||
currentShopId.value,
|
||||
row.id
|
||||
)
|
||||
const res = await CommissionService.getWithdrawalRequestDetail(currentShopId.value, row.id)
|
||||
if (res.code === 0) {
|
||||
withdrawalDetail.value = res.data
|
||||
}
|
||||
@@ -1606,7 +1595,11 @@
|
||||
}
|
||||
|
||||
const getWithdrawalActions = (row: WithdrawalRequestItem) => {
|
||||
const actions: Array<{ label: string; handler: (row: any) => void; type?: 'primary' | 'danger' }> = [
|
||||
const actions: Array<{
|
||||
label: string
|
||||
handler: (row: any) => void
|
||||
type?: 'primary' | 'danger'
|
||||
}> = [
|
||||
{
|
||||
label: '详情',
|
||||
handler: () => openWithdrawalDetail(row),
|
||||
@@ -1755,7 +1748,6 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.qualification-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
]
|
||||
}
|
||||
if (isActing.value) {
|
||||
base.acting_reason = [{ required: true, message: '请填写代办原因', trigger: 'blur' }]
|
||||
base.acting_reason = [{ required: false, message: '请填写代办原因', trigger: 'blur' }]
|
||||
}
|
||||
return base
|
||||
})
|
||||
|
||||
492
src/views/polling-management/priority-queue/index.vue
Normal file
492
src/views/polling-management/priority-queue/index.vue
Normal file
@@ -0,0 +1,492 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="priority-queue-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
:show-expand="false"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
|
||||
<el-card shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<el-button type="primary" @click="showCreateDialog">人工优先入队</el-button>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.page"
|
||||
:pageSize="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
:actions="getActions"
|
||||
:actionsWidth="100"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<el-table-column v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 人工优先入队 -->
|
||||
<el-dialog
|
||||
v-model="createDialogVisible"
|
||||
title="人工优先入队"
|
||||
width="520px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="createFormRef" :model="createForm" :rules="createRules" label-width="100px">
|
||||
<el-form-item label="卡ICCID" prop="card_id">
|
||||
<el-select
|
||||
v-model="createForm.card_id"
|
||||
placeholder="请输入ICCID搜索"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="remoteSearchCard"
|
||||
clearable
|
||||
no-data-text="暂无卡数据,请输入ICCID搜索"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="card in cardList"
|
||||
:key="card.id"
|
||||
:label="card.iccid"
|
||||
:value="card.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="入队原因" prop="reason">
|
||||
<el-input
|
||||
v-model="createForm.reason"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入入队原因(最多500字)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="createDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="createLoading" @click="handleCreateSubmit">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 入队结果 -->
|
||||
<el-dialog v-model="resultDialogVisible" title="入队结果" width="620px">
|
||||
<div class="result-summary">
|
||||
<el-tag type="success" class="result-item">新建 {{ createResult?.created_count ?? 0 }} 条</el-tag>
|
||||
<el-tag type="warning" class="result-item">合并 {{ createResult?.merged_count ?? 0 }} 条</el-tag>
|
||||
<span class="result-item">
|
||||
任务类型:{{ (createResult?.task_type_names || []).join('、') || '-' }}
|
||||
</span>
|
||||
</div>
|
||||
<el-table :data="createResult?.items || []" border stripe size="small" max-height="360">
|
||||
<el-table-column prop="iccid" label="卡ICCID" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="task_type_name" label="任务类型" min-width="120" />
|
||||
<el-table-column prop="status_name" label="状态" width="100" />
|
||||
<el-table-column prop="trigger_count" label="触发次数" width="100" />
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 优先轮询项详情 -->
|
||||
<el-dialog
|
||||
v-model="detailDialogVisible"
|
||||
title="优先轮询项详情"
|
||||
width="640px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-descriptions v-if="detailData" :column="2" border>
|
||||
<el-descriptions-item label="ID">{{ detailData.id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="卡ICCID">{{ detailData.iccid }}</el-descriptions-item>
|
||||
<el-descriptions-item label="任务类型">
|
||||
{{ detailData.task_type_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="getStatusTagType(detailData.status)">{{
|
||||
detailData.status_name
|
||||
}}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="触发类型">
|
||||
{{ detailData.trigger_type_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="触发次数">{{ detailData.trigger_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="尝试次数">{{ detailData.attempt_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="执行结果">
|
||||
{{ detailData.result_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="失败原因" :span="2">
|
||||
{{ detailData.failure_reason || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="人工操作者">
|
||||
{{ detailData.manual_operator_name || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="入队原因">
|
||||
{{ detailData.manual_reason || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="认领时间">
|
||||
{{ formatDateTime(detailData.claimed_at) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最后触发时间">
|
||||
{{ formatDateTime(detailData.last_triggered_at) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ formatDateTime(detailData.created_at) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">
|
||||
{{ formatDateTime(detailData.updated_at) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted, h } from 'vue'
|
||||
import { ElMessage, ElTag, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { PollingPriorityQueueService, CardService } from '@/api/modules'
|
||||
import type {
|
||||
PollingPriorityItem,
|
||||
PollingPriorityItemQueryParams,
|
||||
CreatePollingPriorityItemResponse
|
||||
} from '@/types/api'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import {
|
||||
POLLING_PRIORITY_TASK_TYPE_OPTIONS,
|
||||
POLLING_PRIORITY_STATUS_OPTIONS,
|
||||
POLLING_PRIORITY_TRIGGER_TYPE_OPTIONS,
|
||||
getPollingPriorityResultName
|
||||
} from '@/config/constants'
|
||||
|
||||
defineOptions({ name: 'PollingPriorityQueue' })
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref<PollingPriorityItem[]>([])
|
||||
const tableRef = ref()
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
card_id: undefined as number | undefined,
|
||||
task_type: undefined as string | undefined,
|
||||
status: undefined as string | undefined,
|
||||
trigger_type: undefined as string | undefined
|
||||
})
|
||||
|
||||
// 搜索表单配置
|
||||
const searchFormItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '卡ID',
|
||||
prop: 'card_id',
|
||||
type: 'input',
|
||||
config: { clearable: true, placeholder: '请输入卡ID' }
|
||||
},
|
||||
{
|
||||
label: '任务类型',
|
||||
prop: 'task_type',
|
||||
type: 'select',
|
||||
options: POLLING_PRIORITY_TASK_TYPE_OPTIONS,
|
||||
config: { clearable: true, placeholder: '请选择任务类型' }
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
options: POLLING_PRIORITY_STATUS_OPTIONS,
|
||||
config: { clearable: true, placeholder: '请选择状态' }
|
||||
},
|
||||
{
|
||||
label: '触发类型',
|
||||
prop: 'trigger_type',
|
||||
type: 'select',
|
||||
options: POLLING_PRIORITY_TRIGGER_TYPE_OPTIONS,
|
||||
config: { clearable: true, placeholder: '请选择触发类型' }
|
||||
}
|
||||
]
|
||||
|
||||
const getStatusTagType = (status: string) => {
|
||||
const types: Record<string, 'success' | 'info' | 'warning' | 'danger'> = {
|
||||
pending: 'info',
|
||||
processing: 'warning',
|
||||
completed: 'success',
|
||||
failed: 'danger'
|
||||
}
|
||||
return types[status] || 'info'
|
||||
}
|
||||
|
||||
const getResultTagType = (result: string) => {
|
||||
if (result === 'success') return 'success'
|
||||
if (result === 'failed') return 'danger'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'iccid',
|
||||
label: '卡ICCID',
|
||||
minWidth: 170,
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'task_type_name',
|
||||
label: '任务类型',
|
||||
width: 130,
|
||||
formatter: (row: PollingPriorityItem) => row.task_type_name
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
width: 100,
|
||||
slots: {
|
||||
default: ({ row }: any) =>
|
||||
h(ElTag, { type: getStatusTagType(row.status) }, () => row.status_name)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'trigger_type_name',
|
||||
label: '触发类型',
|
||||
width: 130,
|
||||
formatter: (row: PollingPriorityItem) => row.trigger_type_name
|
||||
},
|
||||
{
|
||||
prop: 'trigger_count',
|
||||
label: '触发次数',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'attempt_count',
|
||||
label: '尝试次数',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'result',
|
||||
label: '执行结果',
|
||||
width: 110,
|
||||
slots: {
|
||||
default: ({ row }: any) =>
|
||||
h(ElTag, { type: getResultTagType(row.result) }, () =>
|
||||
getPollingPriorityResultName(row.result)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'manual_operator_name',
|
||||
label: '操作者',
|
||||
width: 120,
|
||||
formatter: (row: PollingPriorityItem) => row.manual_operator_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: PollingPriorityItem) => formatDateTime(row.created_at)
|
||||
}
|
||||
])
|
||||
|
||||
const columnOptions = computed(() =>
|
||||
columns.value.map((col) => ({
|
||||
label: col.label,
|
||||
prop: col.prop || col.label,
|
||||
visible: true
|
||||
}))
|
||||
)
|
||||
|
||||
const getActions = () => [{ label: '详情', handler: showDetail, type: 'primary' as const }]
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const queryParams: PollingPriorityItemQueryParams = {
|
||||
page: pagination.page,
|
||||
page_size: pagination.page_size,
|
||||
card_id: searchForm.card_id,
|
||||
task_type: searchForm.task_type as never,
|
||||
status: searchForm.status as never,
|
||||
trigger_type: searchForm.trigger_type as never
|
||||
}
|
||||
const { data } = await PollingPriorityQueueService.getPriorityItems(queryParams)
|
||||
tableData.value = data.items || []
|
||||
pagination.total = data.total || 0
|
||||
} catch (error) {
|
||||
console.error('加载优先轮询项列表失败', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
Object.assign(searchForm, {
|
||||
card_id: undefined,
|
||||
task_type: undefined,
|
||||
status: undefined,
|
||||
trigger_type: undefined
|
||||
})
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.page_size = size
|
||||
loadData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.page = page
|
||||
loadData()
|
||||
}
|
||||
|
||||
// 人工优先入队
|
||||
const createDialogVisible = ref(false)
|
||||
const createLoading = ref(false)
|
||||
const createFormRef = ref<FormInstance>()
|
||||
const createResult = ref<CreatePollingPriorityItemResponse | null>(null)
|
||||
const resultDialogVisible = ref(false)
|
||||
const cardList = ref<Array<{ id: number; iccid: string }>>([])
|
||||
|
||||
const createForm = reactive({
|
||||
card_id: undefined as number | undefined,
|
||||
reason: ''
|
||||
})
|
||||
|
||||
const createRules: FormRules = {
|
||||
card_id: [{ required: true, message: '请选择卡', trigger: 'change' }],
|
||||
reason: [
|
||||
{ required: true, message: '请输入入队原因', trigger: 'blur' },
|
||||
{ max: 500, message: '入队原因不能超过500个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const showCreateDialog = () => {
|
||||
createForm.card_id = undefined
|
||||
createForm.reason = ''
|
||||
createResult.value = null
|
||||
createDialogVisible.value = true
|
||||
cardList.value = []
|
||||
loadCards()
|
||||
}
|
||||
|
||||
const loadCards = async (iccid?: string) => {
|
||||
try {
|
||||
const { data } = await CardService.getStandaloneIotCards({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
iccid
|
||||
})
|
||||
cardList.value = data.items || []
|
||||
} catch (error) {
|
||||
console.error('加载卡列表失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
const remoteSearchCard = (query: string) => {
|
||||
loadCards(query)
|
||||
}
|
||||
|
||||
const handleCreateSubmit = async () => {
|
||||
if (!createFormRef.value) return
|
||||
const valid = await createFormRef.value.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
if (createForm.card_id === undefined) {
|
||||
ElMessage.warning('请选择卡')
|
||||
return
|
||||
}
|
||||
createLoading.value = true
|
||||
try {
|
||||
const { data } = await PollingPriorityQueueService.createPriorityItems({
|
||||
card_id: createForm.card_id,
|
||||
reason: createForm.reason.trim()
|
||||
})
|
||||
createResult.value = data
|
||||
createDialogVisible.value = false
|
||||
resultDialogVisible.value = true
|
||||
await loadData()
|
||||
} catch (error) {
|
||||
console.error('人工优先入队失败', error)
|
||||
} finally {
|
||||
createLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 详情
|
||||
const detailDialogVisible = ref(false)
|
||||
const detailLoading = ref(false)
|
||||
const detailData = ref<PollingPriorityItem | null>(null)
|
||||
|
||||
const showDetail = async (row: PollingPriorityItem) => {
|
||||
detailData.value = null
|
||||
detailDialogVisible.value = true
|
||||
detailLoading.value = true
|
||||
try {
|
||||
const { data } = await PollingPriorityQueueService.getPriorityItemDetail(row.id)
|
||||
detailData.value = data
|
||||
} catch (error) {
|
||||
console.error('加载优先轮询项详情失败', error)
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.priority-queue-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.result-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.result-item {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user