refactor(platform): remove deprecated reporting and audit modules

This commit is contained in:
2026-07-27 15:31:22 +08:00
parent e88734c0fd
commit a98fdd0fca
42 changed files with 86 additions and 674 deletions

View File

@@ -43,12 +43,6 @@ export function buildResourcePayload(
case 'boolean':
payload[field.key] = value === true || value === 'true';
break;
case 'json':
if (typeof value !== 'string')
throw new Error(`${field.label}必须是有效 JSON`);
JSON.parse(value);
payload[field.key] = value;
break;
case 'date':
case 'datetime': {
const date = new Date(String(value));

View File

@@ -10,7 +10,6 @@ export type ResourceFieldType =
| 'boolean'
| 'date'
| 'datetime'
| 'json'
| 'textarea';
export type ResourceField = {
key: string;
@@ -175,14 +174,17 @@ const datetimeFields = new Set([
'handled_at',
'created_at',
]);
const jsonFields = new Set([
// 大文本字段按普通文本处理,不再要求或解析 JSON。
const textareaFields = new Set([
'body',
'content',
'reason',
'opinion',
'payload',
'threshold',
'gray_scope',
'product_snapshot',
'field_scope',
]);
const textareaFields = new Set(['body', 'content', 'reason', 'opinion']);
const fieldType = (key: string): ResourceFieldType => {
if (key === 'platform_role_code') return 'role-code';
if (key === 'menu_identities') return 'menu-identities';
@@ -192,7 +194,6 @@ const fieldType = (key: string): ResourceFieldType => {
if (booleanFields.has(key)) return 'boolean';
if (dateFields.has(key)) return 'date';
if (datetimeFields.has(key)) return 'datetime';
if (jsonFields.has(key)) return 'json';
if (textareaFields.has(key)) return 'textarea';
return 'text';
};
@@ -237,8 +238,7 @@ const titles: Record<string, string> = {
fin_payment: '支付记录',
fin_settlement: '财务结算',
fin_reconciliation: '财务对账',
cnt_content: '内容管理',
ntf_template: '通知模板',
cms_content: '内容管理',
cs_ticket: '客服工单',
platfrom_account: '平台账户',
platform_role: '平台角色',
@@ -247,12 +247,6 @@ const titles: Record<string, string> = {
wallet_ledger: '钱包流水',
wallet_recharge: '钱包充值',
wallet_withdrawal: '钱包提现',
report: '报表',
report_item: '报表项目',
report_metric_snapshot: '指标快照',
audit_operation_log: '操作审计',
audit_export_log: '导出审计',
audit_approval: '审批审计',
};
const define = (
name: string,
@@ -523,18 +517,13 @@ export const resources: ResourceUiDefinition[] = [
'list',
['channel!', 'bill_date!', 'difference_amount!'],
),
define('cnt_content', '/content/cnt_content', 'writable', 'list', [
define('cms_content', '/content/cms_content', 'writable', 'list', [
'content_type!',
'title!',
'body!',
'version_no',
'publish_status',
]),
define('ntf_template', '/notification/ntf_template', 'writable', 'list', [
'template_code!',
'channel!',
'content!',
]),
define('cs_ticket', '/customer_service/cs_ticket', 'writable', 'list', [
'user_account_identity!',
'ticket_no!',
@@ -592,62 +581,6 @@ export const resources: ResourceUiDefinition[] = [
'amount',
'status',
]),
define('report', '/report/report', 'readonly', 'list', [
'report_code',
'report_type',
'stat_period',
'generated_at',
'status',
]),
define('report_item', '/report/report_item', 'readonly', 'list', [
'report_identity',
'dimension',
'metric_code',
'metric_value',
]),
define(
'report_metric_snapshot',
'/report/report_metric_snapshot',
'readonly',
'list',
['metric_code', 'scope_type', 'stat_at', 'metric_value'],
),
define('audit_operation_log', '/audit/audit_operation_log', 'readonly', 'list', [
'operator_identity',
'action',
'object_identity',
'created_at',
]),
define('audit_export_log', '/audit/audit_export_log', 'readonly', 'list', [
'applicant_identity',
'purpose',
'field_scope',
'approved_at',
'file_uri',
]),
define(
'audit_approval',
'/audit/audit_approval',
'readonly',
'list',
[
'business_type',
'business_identity',
'applicant_identity',
'opinion',
'handler_identity',
'status',
'handled_at',
],
[
action('同意', '/audit/audit_approval/:identity/approve', ['opinion'], {
status: 'approved',
}),
action('驳回', '/audit/audit_approval/:identity/approve', ['opinion!'], {
status: 'rejected',
}),
],
),
];
export const resourceByName = Object.fromEntries(

View File

@@ -1,12 +0,0 @@
import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types';
const routes: AppRouteRecordRaw[] = [{
path: '/audit', name: 'audit', component: DEFAULT_LAYOUT,
meta: { locale: 'menu.platform.audit', requiresAuth: true, icon: 'icon-apps', order: 22 },
children: [
{ path: 'audit-operation-log', name: 'audit-audit-operation-log', component: () => import('@/views/audit/audit_operation_log/ListPage.vue'), meta: { locale: 'menu.platform.audit.audit_operation_log', requiresAuth: true, menuCode: 'audit' } },
{ path: 'audit-export-log', name: 'audit-audit-export-log', component: () => import('@/views/audit/audit_export_log/ListPage.vue'), meta: { locale: 'menu.platform.audit.audit_export_log', requiresAuth: true, menuCode: 'audit' } },
{ path: 'audit-approval', name: 'audit-audit-approval', component: () => import('@/views/audit/audit_approval/ListPage.vue'), meta: { locale: 'menu.platform.audit.audit_approval', requiresAuth: true, menuCode: 'audit' } }
],
}];
export default routes;

View File

@@ -4,7 +4,7 @@ const routes: AppRouteRecordRaw[] = [{
path: '/content', name: 'content', component: DEFAULT_LAYOUT,
meta: { locale: 'menu.platform.content', requiresAuth: true, icon: 'icon-apps', order: 17 },
children: [
{ path: 'cnt-content', name: 'content-cnt-content', component: () => import('@/views/content/cnt_content/ListPage.vue'), meta: { locale: 'menu.platform.content.cnt_content', requiresAuth: true, menuCode: 'content' } }
{ path: 'cms-content', name: 'content-cms-content', component: () => import('@/views/content/cms_content/ListPage.vue'), meta: { locale: 'menu.platform.content.cms_content', requiresAuth: true, menuCode: 'content' } }
],
}];
export default routes;

View File

@@ -1,10 +0,0 @@
import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types';
const routes: AppRouteRecordRaw[] = [{
path: '/notification', name: 'notification', component: DEFAULT_LAYOUT,
meta: { locale: 'menu.platform.notification', requiresAuth: true, icon: 'icon-apps', order: 18 },
children: [
{ path: 'ntf-template', name: 'notification-ntf-template', component: () => import('@/views/notification/ntf_template/ListPage.vue'), meta: { locale: 'menu.platform.notification.ntf_template', requiresAuth: true, menuCode: 'notification' } }
],
}];
export default routes;

View File

@@ -9,11 +9,8 @@ import safetyRoutes from './safety';
import ecRoutes from './ec';
import financeRoutes from './finance';
import contentRoutes from './content';
import notificationRoutes from './notification';
import customerServiceRoutes from './customer_service';
import walletRoutes from './wallet';
import reportRoutes from './report';
import auditRoutes from './audit';
const platformRoutes: AppRouteRecordRaw[] = [
{ path: '/dashboard', name: 'dashboard', component: DEFAULT_LAYOUT, meta: { locale: 'menu.dashboard', requiresAuth: true, icon: 'icon-dashboard', order: 0 }, children: [{ path: 'overview', name: 'DashboardOverview', component: () => import('@/views/dashboard/DashboardPage.vue'), meta: { locale: 'menu.platform.dashboard', requiresAuth: true, menuCode: 'dashboard' } }] },
{ path: '/platform', name: 'platform', component: DEFAULT_LAYOUT, meta: { locale: 'menu.platform.config', requiresAuth: true, icon: 'icon-settings', order: 30 }, children: [
@@ -22,4 +19,4 @@ const platformRoutes: AppRouteRecordRaw[] = [
{ path: 'platform-menu', name: 'platform-platform-menu', component: () => import('@/views/platform/platform_menu/TreePage.vue'), meta: { locale: 'menu.platform.platform.platform_menu', requiresAuth: true, menuCode: 'platform' } },
] },
];
export default [...platformRoutes, ...gasRoutes, ...deliveryRoutes, ...staffRoutes, ...userRoutes, ...deviceRoutes, ...safetyRoutes, ...ecRoutes, ...financeRoutes, ...contentRoutes, ...notificationRoutes, ...customerServiceRoutes, ...walletRoutes, ...reportRoutes, ...auditRoutes];
export default [...platformRoutes, ...gasRoutes, ...deliveryRoutes, ...staffRoutes, ...userRoutes, ...deviceRoutes, ...safetyRoutes, ...ecRoutes, ...financeRoutes, ...contentRoutes, ...customerServiceRoutes, ...walletRoutes];

View File

@@ -1,12 +0,0 @@
import { DEFAULT_LAYOUT } from '../base';
import type { AppRouteRecordRaw } from '../types';
const routes: AppRouteRecordRaw[] = [{
path: '/report', name: 'report', component: DEFAULT_LAYOUT,
meta: { locale: 'menu.platform.report', requiresAuth: true, icon: 'icon-apps', order: 21 },
children: [
{ path: 'report', name: 'report-report', component: () => import('@/views/report/report/ListPage.vue'), meta: { locale: 'menu.platform.report.report', requiresAuth: true, menuCode: 'report' } },
{ path: 'report-item', name: 'report-report-item', component: () => import('@/views/report/report_item/ListPage.vue'), meta: { locale: 'menu.platform.report.report_item', requiresAuth: true, menuCode: 'report' } },
{ path: 'report-metric-snapshot', name: 'report-report-metric-snapshot', component: () => import('@/views/report/report_metric_snapshot/ListPage.vue'), meta: { locale: 'menu.platform.report.report_metric_snapshot', requiresAuth: true, menuCode: 'report' } }
],
}];
export default routes;

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/audit/audit_approval');
</script>

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/audit/audit_export_log');
</script>

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/audit/audit_operation_log');
</script>

View File

@@ -2,5 +2,5 @@
<script setup lang="ts">
import CrudListPage from '@/views/shared/CrudListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/content/cnt_content');
const definition = getResource('/content/cms_content');
</script>

View File

@@ -1,6 +0,0 @@
<template><CrudListPage :definition="definition" /></template>
<script setup lang="ts">
import CrudListPage from '@/views/shared/CrudListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/notification/ntf_template');
</script>

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/report/report');
</script>

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/report/report_item');
</script>

View File

@@ -1,6 +0,0 @@
<template><ReadOnlyListPage :definition="definition" /></template>
<script setup lang="ts">
import ReadOnlyListPage from '@/views/shared/ReadOnlyListPage.vue';
import { getResource } from '@/api/resources';
const definition = getResource('/report/report_metric_snapshot');
</script>

View File

@@ -37,7 +37,7 @@
<a-input-number v-else-if="field.type === 'number'" v-model="form[field.key]" />
<a-date-picker v-else-if="field.type === 'date'" v-model="form[field.key]" value-format="YYYY-MM-DD" />
<a-date-picker v-else-if="field.type === 'datetime'" v-model="form[field.key]" show-time value-format="YYYY-MM-DDTHH:mm:ssZ" />
<a-textarea v-else-if="field.type === 'json' || field.type === 'textarea'" v-model="form[field.key]" :auto-size="{ minRows: 3, maxRows: 8 }" />
<a-textarea v-else-if="field.type === 'textarea'" v-model="form[field.key]" :auto-size="{ minRows: 3, maxRows: 8 }" />
<a-input-password v-else-if="field.type === 'password'" v-model="form[field.key]" />
<a-select v-else-if="field.type === 'role-code'" v-model="form[field.key]">
<a-option v-for="role in roleOptions" :key="role.role_code" :value="role.role_code">{{ role.name }}</a-option>
@@ -61,7 +61,7 @@
<a-form-item v-for="field in activeAction?.fields" :key="field.key" :label="field.label" :required="field.required">
<a-input-number v-if="field.type === 'number'" v-model="actionForm[field.key]" />
<a-switch v-else-if="field.type === 'boolean'" v-model="actionForm[field.key]" />
<a-textarea v-else-if="field.type === 'json' || field.type === 'textarea'" v-model="actionForm[field.key]" />
<a-textarea v-else-if="field.type === 'textarea'" v-model="actionForm[field.key]" />
<a-select v-else-if="field.type === 'menu-identities'" v-model="actionForm[field.key]" multiple allow-search>
<a-option v-for="menu in menuOptions" :key="menu.identity" :value="menu.identity">{{ menu.name }}</a-option>
</a-select>
@@ -124,12 +124,7 @@ const detailEntries = computed(() =>
function resetForm(data?: Row) {
for (const field of props.definition.fields) {
const value = data?.[field.key];
form[field.key] =
field.type === 'json' && value != null && typeof value !== 'string'
? JSON.stringify(value, null, 2)
: value == null
? undefined
: value;
form[field.key] = value == null ? undefined : value;
}
}

View File

@@ -23,7 +23,7 @@
<a-modal :visible="actionVisible" :title="activeAction?.name" @cancel="actionVisible = false" @ok="submitDetailAction">
<a-form :model="actionForm" layout="vertical">
<a-form-item v-for="field in activeAction?.fields" :key="field.key" :label="field.label" :required="field.required">
<a-textarea v-if="field.type === 'textarea' || field.type === 'json'" v-model="actionForm[field.key]" />
<a-textarea v-if="field.type === 'textarea'" v-model="actionForm[field.key]" />
<a-input v-else v-model="actionForm[field.key]" />
</a-form-item>
</a-form>