|
|
@@ -1,17 +1,24 @@
|
|
|
<script setup lang="ts" name="aidopS8ExceptionTypeConfig">
|
|
|
-import S8CrudConfigPage from '../components/config/S8CrudConfigPage.vue';
|
|
|
-import { s8ConfigApi } from '../api/s8ConfigApi';
|
|
|
-
|
|
|
-// S8-CONFIG-CLEANUP-DEMO-1:列表只展示生效字段;不展示 severityDefault / slaMinutes / ownerRoleCode。
|
|
|
-// 这些列在 entity / DB / API / fields / buildDefault 全部保留,仅列表渲染层不显示。
|
|
|
-const columns = [
|
|
|
- { key: 'typeCode', label: '类型编码', width: 180 },
|
|
|
- { key: 'typeName', label: '类型名称', width: 180 },
|
|
|
- { key: 'sceneCode', label: '场景编码', width: 150 },
|
|
|
- { key: 'monitoringCategoryKey', label: '大屏统计类别', width: 160 },
|
|
|
- { key: 'enabled', label: '启用', width: 90 },
|
|
|
- { key: 'sortNo', label: '排序', width: 90 },
|
|
|
-];
|
|
|
+// TASK-015-TREE-DEV-1:异常类型管理页改为 2 层树形结构。
|
|
|
+// - 顶层 5 个真实分组父节点(isGroup=true)由 SeedData 维护,不可编辑/删除/切换启用,仅作展开容器。
|
|
|
+// - 子节点(isGroup=false)继续支持新建 / 编辑 / 启用 / 删除。
|
|
|
+// - 未归类(parentId=null && isGroup=false)由前端组装虚拟根 __VIRTUAL_UNCLASSIFIED__,DB 内无真实未归类父节点。
|
|
|
+import { computed, onMounted, reactive, ref } from 'vue';
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import AidopDemoShell from '../components/AidopDemoShell.vue';
|
|
|
+import {
|
|
|
+ s8ConfigApi,
|
|
|
+ type S8ExceptionTypeConfigPayload,
|
|
|
+ type S8ExceptionTypeConfigRow,
|
|
|
+ type S8ExceptionTypeTreeNode,
|
|
|
+} from '../api/s8ConfigApi';
|
|
|
+
|
|
|
+const VIRTUAL_UNCLASSIFIED_CODE = '__VIRTUAL_UNCLASSIFIED__';
|
|
|
+
|
|
|
+interface TreeRow extends S8ExceptionTypeConfigRow {
|
|
|
+ children?: TreeRow[];
|
|
|
+ isVirtual?: boolean;
|
|
|
+}
|
|
|
|
|
|
const MONITORING_CATEGORY_OPTIONS = [
|
|
|
{ label: '订单评审', value: 'ORDER_REVIEW' },
|
|
|
@@ -21,48 +28,35 @@ const MONITORING_CATEGORY_OPTIONS = [
|
|
|
{ label: '总装发货', value: 'FINAL_ASSEMBLY_DELIVERY' },
|
|
|
];
|
|
|
|
|
|
-// S8-CONFIG-CLEANUP-DEMO-1:以下 7 个字段标记 hidden=true:
|
|
|
-// severityDefault / slaMinutes / ownerRoleCode / escalateRoleCode / statsMode / icon / mobileVisible
|
|
|
-// 渲染层隐藏,但保留在 fields / buildDefault / form / PUT payload,旧值原样回写不丢。
|
|
|
-// required 字段一并去掉以避免新建场景必填校验阻塞(实际值由 buildDefault 提供默认)。
|
|
|
-const fields = [
|
|
|
- { key: 'typeCode', label: '类型编码', type: 'input', required: true, placeholder: '如 ORDER_CHANGE' },
|
|
|
- { key: 'typeName', label: '类型名称', type: 'input', required: true },
|
|
|
- { key: 'sceneCode', label: '场景编码', type: 'select', required: true, optionsKey: 'scenes' },
|
|
|
- { key: 'monitoringCategoryKey', label: '大屏统计类别', type: 'select', options: MONITORING_CATEGORY_OPTIONS },
|
|
|
- { key: 'severityDefault', label: '默认严重度', type: 'select', optionsKey: 'severities', hidden: true },
|
|
|
- { key: 'slaMinutes', label: 'SLA(分钟)', type: 'number', hidden: true },
|
|
|
- { key: 'ownerRoleCode', label: '责任角色', type: 'select', optionsKey: 'roles', hidden: true },
|
|
|
- { key: 'escalateRoleCode', label: '升级角色', type: 'select', optionsKey: 'roles', hidden: true },
|
|
|
- {
|
|
|
- key: 'statsMode',
|
|
|
- label: '统计模式',
|
|
|
- type: 'select',
|
|
|
- options: [
|
|
|
- { label: '全部', value: 'ALL' },
|
|
|
- { label: '频率', value: 'FREQUENCY' },
|
|
|
- { label: '时长', value: 'DURATION' },
|
|
|
- { label: '关闭率', value: 'CLOSE_RATE' },
|
|
|
- ],
|
|
|
- hidden: true,
|
|
|
- },
|
|
|
- { key: 'mobileVisible', label: '移动端展示', type: 'switch', hidden: true },
|
|
|
- { key: 'enabled', label: '启用', type: 'switch' },
|
|
|
- { key: 'sortNo', label: '排序', type: 'number' },
|
|
|
- { key: 'icon', label: '图标标识', type: 'input', hidden: true },
|
|
|
- { key: 'remark', label: '备注', type: 'textarea' },
|
|
|
-] as const;
|
|
|
-
|
|
|
-const buildDefault = () => ({
|
|
|
+const SCENE_ORDER = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'];
|
|
|
+
|
|
|
+const loading = ref(false);
|
|
|
+const treeRows = ref<TreeRow[]>([]);
|
|
|
+const parentOptions = ref<{ id: number; typeCode: string; typeName: string }[]>([]);
|
|
|
+const sceneOptions = ref<{ label: string; value: string }[]>([]);
|
|
|
+const roleOptions = ref<{ label: string; value: string }[]>([]);
|
|
|
+
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const dialogMode = ref<'create' | 'edit'>('create');
|
|
|
+const editingId = ref<number | null>(null);
|
|
|
+const saving = ref(false);
|
|
|
+
|
|
|
+const SEVERITY_OPTIONS = [
|
|
|
+ { value: 'FOLLOW', label: '关注' },
|
|
|
+ { value: 'SERIOUS', label: '严重' },
|
|
|
+];
|
|
|
+
|
|
|
+const form = reactive({
|
|
|
typeCode: '',
|
|
|
typeName: '',
|
|
|
sceneCode: '',
|
|
|
- monitoringCategoryKey: '',
|
|
|
+ parentId: null as number | null,
|
|
|
severityDefault: 'FOLLOW',
|
|
|
slaMinutes: 60,
|
|
|
ownerRoleCode: '',
|
|
|
escalateRoleCode: '',
|
|
|
statsMode: 'ALL',
|
|
|
+ monitoringCategoryKey: '',
|
|
|
mobileVisible: true,
|
|
|
enabled: true,
|
|
|
sortNo: 0,
|
|
|
@@ -70,28 +64,30 @@ const buildDefault = () => ({
|
|
|
remark: '',
|
|
|
});
|
|
|
|
|
|
-async function loadOptions() {
|
|
|
- const [scenes, severities, roles] = await Promise.all([
|
|
|
- s8ConfigApi.scenes({ tenantId: 1, factoryId: 1 }),
|
|
|
- s8ConfigApi.severities(),
|
|
|
- s8ConfigApi.list('/api/aidop/s8/config/roles', { tenantId: 1, factoryId: 1 }),
|
|
|
- ]);
|
|
|
-
|
|
|
- return {
|
|
|
- scenes: scenes.map((item: any) => ({ label: `${item.sceneName} (${item.sceneCode})`, value: item.sceneCode })),
|
|
|
- severities,
|
|
|
- roles: roles.map((item: any) => ({ label: item.roleCode, value: item.roleCode })),
|
|
|
- };
|
|
|
+function resetForm() {
|
|
|
+ form.typeCode = '';
|
|
|
+ form.typeName = '';
|
|
|
+ form.sceneCode = '';
|
|
|
+ form.parentId = null;
|
|
|
+ form.severityDefault = 'FOLLOW';
|
|
|
+ form.slaMinutes = 60;
|
|
|
+ form.ownerRoleCode = '';
|
|
|
+ form.escalateRoleCode = '';
|
|
|
+ form.statsMode = 'ALL';
|
|
|
+ form.monitoringCategoryKey = '';
|
|
|
+ form.mobileVisible = true;
|
|
|
+ form.enabled = true;
|
|
|
+ form.sortNo = 0;
|
|
|
+ form.icon = '';
|
|
|
+ form.remark = '';
|
|
|
}
|
|
|
|
|
|
-// S8-CONFIG-POLISH-SCENE-RULE-LIST-1:列表按 S1→S7 / sort_no / type_code 稳定排序。
|
|
|
-// 仅展示层排序,不参与保存 payload;未在序列内的 scene 排到最末。
|
|
|
-const SCENE_ORDER = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'];
|
|
|
function sceneIdx(code: unknown) {
|
|
|
const i = SCENE_ORDER.indexOf(String(code ?? ''));
|
|
|
return i >= 0 ? i : SCENE_ORDER.length;
|
|
|
}
|
|
|
-function sortRows(rows: readonly Record<string, unknown>[]): Record<string, unknown>[] {
|
|
|
+
|
|
|
+function sortChildren<T extends { sceneCode?: string; sortNo?: number; typeCode?: string }>(rows: T[]): T[] {
|
|
|
return [...rows].sort((a, b) => {
|
|
|
const sa = sceneIdx(a.sceneCode);
|
|
|
const sb = sceneIdx(b.sceneCode);
|
|
|
@@ -102,17 +98,348 @@ function sortRows(rows: readonly Record<string, unknown>[]): Record<string, unkn
|
|
|
return String(a.typeCode ?? '').localeCompare(String(b.typeCode ?? ''));
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+function categoryLabel(key?: string | null): string {
|
|
|
+ if (!key) return '';
|
|
|
+ return MONITORING_CATEGORY_OPTIONS.find((o) => o.value === key)?.label ?? key;
|
|
|
+}
|
|
|
+
|
|
|
+async function loadTree() {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ // 管理页需要看到 disabled 子节点,因此 enabledOnly=false。
|
|
|
+ const tree = await s8ConfigApi.exceptionTypes.tree({ tenantId: 1, factoryId: 1, enabledOnly: false });
|
|
|
+ const roots: TreeRow[] = (tree.roots ?? []).map((r) => ({
|
|
|
+ ...(r as S8ExceptionTypeConfigRow),
|
|
|
+ children: sortChildren((r.children ?? []) as TreeRow[]),
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 未归类虚拟根:仅当存在 orphan 子节点时呈现,避免空根扰动 UI。
|
|
|
+ const orphans = (tree.orphans ?? []).map((o) => ({ ...(o as S8ExceptionTypeConfigRow) })) as TreeRow[];
|
|
|
+ const sortedRoots = sortChildren(roots) as TreeRow[];
|
|
|
+ if (orphans.length > 0) {
|
|
|
+ sortedRoots.push({
|
|
|
+ id: -1,
|
|
|
+ tenantId: 0,
|
|
|
+ factoryId: 0,
|
|
|
+ typeCode: VIRTUAL_UNCLASSIFIED_CODE,
|
|
|
+ typeName: '未归类',
|
|
|
+ sceneCode: '',
|
|
|
+ severityDefault: '',
|
|
|
+ slaMinutes: 0,
|
|
|
+ statsMode: '',
|
|
|
+ mobileVisible: false,
|
|
|
+ enabled: true,
|
|
|
+ sortNo: 9999,
|
|
|
+ parentId: null,
|
|
|
+ isGroup: true,
|
|
|
+ isVirtual: true,
|
|
|
+ children: sortChildren(orphans) as TreeRow[],
|
|
|
+ createdAt: '',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ treeRows.value = sortedRoots;
|
|
|
+
|
|
|
+ parentOptions.value = (tree.roots ?? []).map((r) => ({
|
|
|
+ id: Number(r.id),
|
|
|
+ typeCode: r.typeCode,
|
|
|
+ typeName: r.typeName,
|
|
|
+ }));
|
|
|
+ } catch (e: any) {
|
|
|
+ ElMessage.error(e?.message ?? '加载异常类型失败');
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function loadOptions() {
|
|
|
+ try {
|
|
|
+ const [scenes, roles] = await Promise.all([
|
|
|
+ s8ConfigApi.scenes({ tenantId: 1, factoryId: 1 }),
|
|
|
+ s8ConfigApi.list('/api/aidop/s8/config/roles', { tenantId: 1, factoryId: 1 }),
|
|
|
+ ]);
|
|
|
+ sceneOptions.value = (scenes as any[]).map((it) => ({
|
|
|
+ label: `${it.sceneName} (${it.sceneCode})`,
|
|
|
+ value: it.sceneCode,
|
|
|
+ }));
|
|
|
+ roleOptions.value = (roles as any[]).map((it) => ({ label: it.roleCode, value: it.roleCode }));
|
|
|
+ } catch (e: any) {
|
|
|
+ ElMessage.warning('部分下拉选项加载失败');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function openCreate(parentId: number | null) {
|
|
|
+ resetForm();
|
|
|
+ form.parentId = parentId;
|
|
|
+ if (parentId != null) {
|
|
|
+ const parent = parentOptions.value.find((p) => p.id === parentId);
|
|
|
+ // 子节点新建:以父节点 monitoringCategoryKey 自动回填。
|
|
|
+ const parentRow = treeRows.value.find((r) => r.id === parentId);
|
|
|
+ if (parentRow?.monitoringCategoryKey) form.monitoringCategoryKey = parentRow.monitoringCategoryKey;
|
|
|
+ // 备注里提示父节点编码,避免错放。
|
|
|
+ form.remark = parent ? `归属:${parent.typeName}` : '';
|
|
|
+ }
|
|
|
+ dialogMode.value = 'create';
|
|
|
+ editingId.value = null;
|
|
|
+ dialogVisible.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+function openEdit(row: TreeRow) {
|
|
|
+ if (row.isGroup || row.isVirtual) return;
|
|
|
+ resetForm();
|
|
|
+ form.typeCode = row.typeCode;
|
|
|
+ form.typeName = row.typeName;
|
|
|
+ form.sceneCode = row.sceneCode;
|
|
|
+ form.parentId = row.parentId ?? null;
|
|
|
+ form.severityDefault = row.severityDefault || 'FOLLOW';
|
|
|
+ form.slaMinutes = row.slaMinutes;
|
|
|
+ form.ownerRoleCode = row.ownerRoleCode ?? '';
|
|
|
+ form.escalateRoleCode = row.escalateRoleCode ?? '';
|
|
|
+ form.statsMode = row.statsMode || 'ALL';
|
|
|
+ form.monitoringCategoryKey = row.monitoringCategoryKey ?? '';
|
|
|
+ form.mobileVisible = row.mobileVisible;
|
|
|
+ form.enabled = row.enabled;
|
|
|
+ form.sortNo = row.sortNo;
|
|
|
+ form.icon = row.icon ?? '';
|
|
|
+ form.remark = row.remark ?? '';
|
|
|
+ dialogMode.value = 'edit';
|
|
|
+ editingId.value = row.id;
|
|
|
+ dialogVisible.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+async function handleSave() {
|
|
|
+ if (!form.typeCode.trim() || !form.typeName.trim()) {
|
|
|
+ ElMessage.warning('类型编码和名称必填');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!form.sceneCode) {
|
|
|
+ ElMessage.warning('请选择场景编码');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (dialogMode.value === 'create' && form.parentId == null) {
|
|
|
+ ElMessage.warning('请选择所属分组父节点');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const payload: S8ExceptionTypeConfigPayload = {
|
|
|
+ tenantId: 1,
|
|
|
+ factoryId: 1,
|
|
|
+ typeCode: form.typeCode.trim().toUpperCase().replace(/\s+/g, ''),
|
|
|
+ typeName: form.typeName.trim(),
|
|
|
+ sceneCode: form.sceneCode,
|
|
|
+ severityDefault: form.severityDefault,
|
|
|
+ slaMinutes: Number(form.slaMinutes) || 0,
|
|
|
+ ownerRoleCode: form.ownerRoleCode || null,
|
|
|
+ escalateRoleCode: form.escalateRoleCode || null,
|
|
|
+ statsMode: form.statsMode || 'ALL',
|
|
|
+ monitoringCategoryKey: form.monitoringCategoryKey || null,
|
|
|
+ mobileVisible: form.mobileVisible,
|
|
|
+ enabled: form.enabled,
|
|
|
+ sortNo: Number(form.sortNo) || 0,
|
|
|
+ icon: form.icon || null,
|
|
|
+ remark: form.remark || null,
|
|
|
+ parentId: form.parentId,
|
|
|
+ isGroup: false,
|
|
|
+ };
|
|
|
+ saving.value = true;
|
|
|
+ try {
|
|
|
+ if (dialogMode.value === 'create') {
|
|
|
+ await s8ConfigApi.exceptionTypes.create(payload);
|
|
|
+ ElMessage.success('新增异常类型成功');
|
|
|
+ } else if (editingId.value != null) {
|
|
|
+ await s8ConfigApi.exceptionTypes.update(editingId.value, payload);
|
|
|
+ ElMessage.success('保存成功');
|
|
|
+ }
|
|
|
+ dialogVisible.value = false;
|
|
|
+ await loadTree();
|
|
|
+ } catch (e: any) {
|
|
|
+ const msg = e?.response?.data?.message ?? e?.message ?? '保存失败';
|
|
|
+ ElMessage.error(msg);
|
|
|
+ } finally {
|
|
|
+ saving.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function handleToggleEnabled(row: TreeRow, next: boolean) {
|
|
|
+ if (row.isGroup || row.isVirtual) return;
|
|
|
+ try {
|
|
|
+ await s8ConfigApi.exceptionTypes.setEnabled(row.id, next);
|
|
|
+ row.enabled = next;
|
|
|
+ } catch (e: any) {
|
|
|
+ ElMessage.error(e?.response?.data?.message ?? '切换启用状态失败');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function handleDelete(row: TreeRow) {
|
|
|
+ if (row.isGroup || row.isVirtual) return;
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确认删除异常类型「${row.typeName}」?`, '删除确认', { type: 'warning' });
|
|
|
+ } catch {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await s8ConfigApi.exceptionTypes.remove(row.id);
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ await loadTree();
|
|
|
+ } catch (e: any) {
|
|
|
+ ElMessage.error(e?.response?.data?.message ?? '删除失败');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const parentLabelOfForm = computed(() => {
|
|
|
+ if (form.parentId == null) return '—';
|
|
|
+ return parentOptions.value.find((p) => p.id === form.parentId)?.typeName ?? '—';
|
|
|
+});
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await Promise.all([loadTree(), loadOptions()]);
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <S8CrudConfigPage
|
|
|
- title="异常类型配置"
|
|
|
- subtitle="S8 / 配置 / 异常类型"
|
|
|
- endpoint="/api/aidop/s8/config/exception-types"
|
|
|
- :columns="columns"
|
|
|
- :fields="fields"
|
|
|
- :build-default="buildDefault"
|
|
|
- :load-options="loadOptions"
|
|
|
- :sort-rows="sortRows"
|
|
|
- />
|
|
|
+ <AidopDemoShell title="异常类型配置" subtitle="S8 / 配置 / 异常类型(2 层树形)">
|
|
|
+ <div class="mb12">
|
|
|
+ <el-button type="primary" :disabled="parentOptions.length === 0" @click="openCreate(null)">新建子类型</el-button>
|
|
|
+ <span class="config-hint">新建时需选择所属分组父节点;分组父节点由 SeedData 维护,无法在此页编辑。</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ v-loading="loading"
|
|
|
+ :data="treeRows"
|
|
|
+ row-key="typeCode"
|
|
|
+ border
|
|
|
+ stripe
|
|
|
+ default-expand-all
|
|
|
+ :tree-props="{ children: 'children' }"
|
|
|
+ >
|
|
|
+ <el-table-column prop="typeName" label="类型名称" min-width="220" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-tag v-if="row.isGroup" type="info" size="small" effect="plain" class="config-tag">分组</el-tag>
|
|
|
+ <span>{{ row.typeName }}</span>
|
|
|
+ <el-tag v-if="row.isVirtual" type="warning" size="small" effect="plain" class="config-tag">虚拟根</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="typeCode" label="类型编码" width="220" show-overflow-tooltip />
|
|
|
+ <el-table-column label="大屏统计类别" width="140">
|
|
|
+ <template #default="{ row }">{{ categoryLabel(row.monitoringCategoryKey) || '—' }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="场景" width="100">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span v-if="row.isGroup || row.isVirtual">—</span>
|
|
|
+ <span v-else>{{ row.sceneCode || '—' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="启用" width="90" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-switch
|
|
|
+ v-if="!row.isGroup && !row.isVirtual"
|
|
|
+ :model-value="row.enabled"
|
|
|
+ @change="(v: any) => handleToggleEnabled(row, !!v)"
|
|
|
+ />
|
|
|
+ <span v-else>—</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="sortNo" label="排序" width="80">
|
|
|
+ <template #default="{ row }">{{ row.isVirtual ? '—' : row.sortNo }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="240">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <template v-if="row.isGroup && !row.isVirtual">
|
|
|
+ <el-button size="small" type="primary" link @click="openCreate(row.id)">在此分组下新建</el-button>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="row.isVirtual">
|
|
|
+ <span class="config-hint">未归类节点无法在此新增;调整子节点 parentId 后将自动归类。</span>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <el-button size="small" type="primary" link @click="openEdit(row)">编辑</el-button>
|
|
|
+ <el-button size="small" type="danger" link @click="handleDelete(row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ v-model="dialogVisible"
|
|
|
+ :title="dialogMode === 'create' ? '新建子类型' : '编辑子类型'"
|
|
|
+ width="640px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <el-form label-width="120px" size="small">
|
|
|
+ <el-form-item label="所属父节点" required>
|
|
|
+ <el-select v-model="form.parentId" placeholder="选择分组父节点" filterable style="width: 100%">
|
|
|
+ <el-option v-for="p in parentOptions" :key="p.id" :label="p.typeName" :value="p.id" />
|
|
|
+ </el-select>
|
|
|
+ <span class="config-hint">当前归属:{{ parentLabelOfForm }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="类型编码" required>
|
|
|
+ <el-input v-model="form.typeCode" placeholder="如 ORDER_CHANGE" maxlength="64" show-word-limit />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="类型名称" required>
|
|
|
+ <el-input v-model="form.typeName" maxlength="128" show-word-limit />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="场景编码" required>
|
|
|
+ <el-select v-model="form.sceneCode" placeholder="选择场景" style="width: 100%">
|
|
|
+ <el-option v-for="o in sceneOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="大屏统计类别">
|
|
|
+ <el-select v-model="form.monitoringCategoryKey" clearable placeholder="可选" style="width: 100%">
|
|
|
+ <el-option
|
|
|
+ v-for="o in MONITORING_CATEGORY_OPTIONS"
|
|
|
+ :key="o.value"
|
|
|
+ :label="o.label"
|
|
|
+ :value="o.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="默认严重度">
|
|
|
+ <el-select v-model="form.severityDefault" style="width: 100%">
|
|
|
+ <el-option v-for="o in SEVERITY_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="SLA(分钟)">
|
|
|
+ <el-input-number v-model="form.slaMinutes" :min="0" :max="100000" :step="60" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="责任角色">
|
|
|
+ <el-select v-model="form.ownerRoleCode" clearable placeholder="可选" style="width: 100%">
|
|
|
+ <el-option v-for="o in roleOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="升级角色">
|
|
|
+ <el-select v-model="form.escalateRoleCode" clearable placeholder="可选" style="width: 100%">
|
|
|
+ <el-option v-for="o in roleOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="启用">
|
|
|
+ <el-switch v-model="form.enabled" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="排序">
|
|
|
+ <el-input-number v-model="form.sortNo" :min="0" :max="9999" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="form.remark" type="textarea" :rows="2" maxlength="500" show-word-limit />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </AidopDemoShell>
|
|
|
</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.mb12 {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+.config-hint {
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.config-tag {
|
|
|
+ margin-right: 6px;
|
|
|
+}
|
|
|
+</style>
|