|
|
@@ -7,21 +7,60 @@
|
|
|
</div>
|
|
|
<span class="s8-dept-severity__subtitle">按责任部门聚合</span>
|
|
|
</div>
|
|
|
+ <!-- TASK-013-DEPT-CARD-UI-COMPLETE-1:顶部汇总条 -->
|
|
|
+ <div class="s8-dept-severity__summary">
|
|
|
+ <div class="s8-dept-severity__summary-item">
|
|
|
+ <span class="s8-dept-severity__summary-label">严重异常总数</span>
|
|
|
+ <span class="s8-dept-severity__summary-value s8-dept-severity__summary-value--hot">{{ totalSerious }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="s8-dept-severity__summary-item">
|
|
|
+ <span class="s8-dept-severity__summary-label">涉及部门</span>
|
|
|
+ <span class="s8-dept-severity__summary-value">{{ involvedDepts }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="s8-dept-severity__summary-item">
|
|
|
+ <span class="s8-dept-severity__summary-label">平均处理时间</span>
|
|
|
+ <span class="s8-dept-severity__summary-value s8-dept-severity__summary-value--placeholder">{{ DISPLAY_PLACEHOLDER }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="s8-dept-severity__summary-item">
|
|
|
+ <span class="s8-dept-severity__summary-label">关闭率</span>
|
|
|
+ <span class="s8-dept-severity__summary-value s8-dept-severity__summary-value--placeholder">{{ DISPLAY_PLACEHOLDER }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<el-tabs v-model="activeTab" class="s8-dept-severity__tabs">
|
|
|
<el-tab-pane label="严重" name="serious">
|
|
|
<div v-if="loading" class="s8-dept-severity__empty">加载中…</div>
|
|
|
<div v-else-if="!sortedItems.length" class="s8-dept-severity__empty">暂无严重异常</div>
|
|
|
- <ul v-else class="s8-dept-severity__list">
|
|
|
- <li v-for="row in sortedItems" :key="row.deptId" class="s8-dept-severity__row">
|
|
|
- <span class="s8-dept-severity__name" :title="row.deptName">{{ row.deptName }}</span>
|
|
|
- <span
|
|
|
- class="s8-dept-severity__count"
|
|
|
- :class="row.seriousCount > 0 ? 's8-dept-severity__count--hot' : 's8-dept-severity__count--zero'"
|
|
|
+ <div v-else class="s8-dept-severity__table" role="table">
|
|
|
+ <div class="s8-dept-severity__thead" role="row">
|
|
|
+ <span class="s8-dept-severity__th s8-dept-severity__th--name" role="columnheader">部门</span>
|
|
|
+ <span class="s8-dept-severity__th s8-dept-severity__th--count" role="columnheader">严重异常数</span>
|
|
|
+ <span class="s8-dept-severity__th s8-dept-severity__th--metric" role="columnheader">平均处理时间</span>
|
|
|
+ <span class="s8-dept-severity__th s8-dept-severity__th--metric" role="columnheader">关闭率</span>
|
|
|
+ </div>
|
|
|
+ <div class="s8-dept-severity__tbody">
|
|
|
+ <div
|
|
|
+ v-for="row in sortedItems"
|
|
|
+ :key="row.deptId"
|
|
|
+ class="s8-dept-severity__row"
|
|
|
+ role="row"
|
|
|
>
|
|
|
- {{ row.seriousCount }}
|
|
|
- </span>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
+ <span class="s8-dept-severity__cell s8-dept-severity__cell--name" :title="row.deptName" role="cell">{{ row.deptName }}</span>
|
|
|
+ <span
|
|
|
+ class="s8-dept-severity__cell s8-dept-severity__cell--count"
|
|
|
+ :class="row.seriousCount > 0 ? 's8-dept-severity__cell--hot' : 's8-dept-severity__cell--zero'"
|
|
|
+ role="cell"
|
|
|
+ >
|
|
|
+ {{ row.seriousCount }}
|
|
|
+ </span>
|
|
|
+ <span class="s8-dept-severity__cell s8-dept-severity__cell--metric s8-dept-severity__cell--placeholder" role="cell">
|
|
|
+ {{ DISPLAY_PLACEHOLDER }}
|
|
|
+ </span>
|
|
|
+ <span class="s8-dept-severity__cell s8-dept-severity__cell--metric s8-dept-severity__cell--placeholder" role="cell">
|
|
|
+ {{ DISPLAY_PLACEHOLDER }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
|
</div>
|
|
|
@@ -39,16 +78,26 @@ const props = defineProps<{
|
|
|
|
|
|
const activeTab = shallowRef<'serious'>('serious');
|
|
|
|
|
|
+// TASK-013-DEPT-CARD-UI-COMPLETE-1:平均处理时间 / 关闭率后端未返回,统一占位 "--",
|
|
|
+// 不伪造 0 或 fake 计算;后续 P2 任务 TASK-013-P2-AVG-CLOSE-FOLLOW-1 接通真实计算后替换。
|
|
|
+const DISPLAY_PLACEHOLDER = '--';
|
|
|
+
|
|
|
// TASK-013-DEPT-SERIOUS-CARD-1:seriousCount desc, total desc 兜底;
|
|
|
// 全员 seriousCount=0 视为空态(模板里 empty 判定)。
|
|
|
const sortedItems = computed(() => {
|
|
|
- const filtered = (props.items ?? []).filter((item) => item.seriousCount > 0);
|
|
|
+ const filtered = (props.items ?? []).filter((item) => item && item.seriousCount > 0);
|
|
|
return [...filtered].sort((a, b) => {
|
|
|
if (b.seriousCount !== a.seriousCount) return b.seriousCount - a.seriousCount;
|
|
|
return b.total - a.total;
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+const totalSerious = computed(() =>
|
|
|
+ (props.items ?? []).reduce((acc, item) => acc + (item?.seriousCount ?? 0), 0),
|
|
|
+);
|
|
|
+
|
|
|
+const involvedDepts = computed(() => sortedItems.value.length);
|
|
|
+
|
|
|
const minHeightStyle = computed<CSSProperties>(() => {
|
|
|
if (!props.minHeight || props.minHeight <= 0) return {};
|
|
|
return { minHeight: `${props.minHeight}px` };
|
|
|
@@ -102,6 +151,46 @@ const minHeightStyle = computed<CSSProperties>(() => {
|
|
|
color: #64748b;
|
|
|
}
|
|
|
|
|
|
+.s8-dept-severity__summary {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
|
+ gap: 6px;
|
|
|
+ padding: 6px 4px;
|
|
|
+ border-radius: 6px;
|
|
|
+ background: rgba(239, 68, 68, 0.04);
|
|
|
+ border: 1px solid rgba(239, 68, 68, 0.12);
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__summary-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ min-width: 0;
|
|
|
+ line-height: 1.2;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__summary-label {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #64748b;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__summary-value {
|
|
|
+ font-family: 'Roboto Mono', monospace;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #e2e8f0;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__summary-value--hot {
|
|
|
+ color: #ef4444;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__summary-value--placeholder {
|
|
|
+ color: #475569;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
.s8-dept-severity__tabs {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
@@ -139,49 +228,90 @@ const minHeightStyle = computed<CSSProperties>(() => {
|
|
|
overflow: auto;
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__list {
|
|
|
- margin: 0;
|
|
|
- padding: 0;
|
|
|
- list-style: none;
|
|
|
+.s8-dept-severity__table {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
gap: 4px;
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__row {
|
|
|
+.s8-dept-severity__thead {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 0.9fr);
|
|
|
+ gap: 6px;
|
|
|
+ padding: 4px 6px;
|
|
|
+ font-size: 11px;
|
|
|
+ color: #94a3b8;
|
|
|
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__th {
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__th--name {
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__th--count,
|
|
|
+.s8-dept-severity__th--metric {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__tbody {
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 3px;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__row {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 0.9fr);
|
|
|
+ gap: 6px;
|
|
|
align-items: center;
|
|
|
- gap: 8px;
|
|
|
font-size: 12px;
|
|
|
padding: 4px 6px;
|
|
|
border-radius: 6px;
|
|
|
background: rgba(255, 255, 255, 0.02);
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__name {
|
|
|
- flex: 1;
|
|
|
+.s8-dept-severity__cell {
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__cell--name {
|
|
|
color: #cbd5e1;
|
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__count {
|
|
|
- min-width: 32px;
|
|
|
+.s8-dept-severity__cell--count,
|
|
|
+.s8-dept-severity__cell--metric {
|
|
|
text-align: right;
|
|
|
font-family: 'Roboto Mono', monospace;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__cell--count {
|
|
|
font-size: 14px;
|
|
|
font-weight: 700;
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__count--hot {
|
|
|
+.s8-dept-severity__cell--metric {
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.s8-dept-severity__cell--hot {
|
|
|
color: #ef4444;
|
|
|
}
|
|
|
|
|
|
-.s8-dept-severity__count--zero {
|
|
|
+.s8-dept-severity__cell--zero {
|
|
|
color: #94a3b8;
|
|
|
}
|
|
|
|
|
|
+.s8-dept-severity__cell--placeholder {
|
|
|
+ color: #475569;
|
|
|
+}
|
|
|
+
|
|
|
.s8-dept-severity__empty {
|
|
|
color: #64748b;
|
|
|
font-size: 12px;
|