style: 全局 UI 主题皮肤重构与样式模块化
引入 Element Plus 主题定制和主题皮肤 composable,将全局 样式拆分为组件级独立 CSS 文件(侧边栏、顶栏、工作台等), 统一色彩变量和间距规范,重构所有视图和组件样式以适配新 主题系统,优化图表和知识图谱组件视觉表现,提取审计和差 旅报销相关子组件。
This commit is contained in:
334
web/src/components/audit/AuditAssetList.vue
Normal file
334
web/src/components/audit/AuditAssetList.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<article class="skill-list panel">
|
||||
<nav class="status-tabs" aria-label="能力类型">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
type="button"
|
||||
:class="{ active: activeType === tab.id }"
|
||||
@click="emit('update:activeType', tab.id)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="list-toolbar">
|
||||
<div class="filter-set">
|
||||
<label class="search-filter">
|
||||
<i class="mdi mdi-magnify"></i>
|
||||
<input
|
||||
:value="keyword"
|
||||
type="search"
|
||||
:placeholder="searchPlaceholder"
|
||||
@input="emit('update:keyword', $event.target.value)"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<AuditPickerFilter
|
||||
id="domain"
|
||||
title="选择业务域"
|
||||
close-label="关闭业务域选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedDomainLabel"
|
||||
:options="domainOptions"
|
||||
:selected-value="selectedDomain"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('domain', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showOwnerFilter"
|
||||
id="owner"
|
||||
title="选择负责人"
|
||||
close-label="关闭负责人选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedOwnerLabel"
|
||||
:options="ownerOptions"
|
||||
:selected-value="selectedOwner"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('owner', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showRiskLevelFilter"
|
||||
id="riskLevel"
|
||||
title="选择风险等级"
|
||||
close-label="关闭风险等级选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedRiskLevelLabel"
|
||||
:options="riskLevelOptions"
|
||||
:selected-value="selectedRiskLevel"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('riskLevel', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showRiskScenarioFilter"
|
||||
id="riskScenario"
|
||||
title="选择使用场景"
|
||||
close-label="关闭使用场景选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedRiskScenarioLabel"
|
||||
:options="riskScenarioOptions"
|
||||
:selected-value="selectedRiskScenario"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('riskScenario', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showOnlineFilter"
|
||||
id="online"
|
||||
title="选择上线状态"
|
||||
close-label="关闭上线状态选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedOnlineStateLabel"
|
||||
:options="onlineStateOptions"
|
||||
:selected-value="selectedOnlineState"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('online', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showEnabledFilter"
|
||||
id="enabled"
|
||||
title="选择启用状态"
|
||||
close-label="关闭启用状态选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedEnabledStateLabel"
|
||||
:options="enabledStateOptions"
|
||||
:selected-value="selectedEnabledState"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('enabled', $event)"
|
||||
/>
|
||||
|
||||
<AuditPickerFilter
|
||||
v-if="showStatusFilter"
|
||||
id="status"
|
||||
title="选择状态"
|
||||
close-label="关闭状态选择"
|
||||
:active-filter-popover="activeFilterPopover"
|
||||
:label="selectedStatusLabel"
|
||||
:options="statusOptions"
|
||||
:selected-value="selectedStatus"
|
||||
@toggle="emit('toggle-filter-popover', $event)"
|
||||
@close="emit('close-filter-popover')"
|
||||
@select="selectFilter('status', $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="toolbar-actions">
|
||||
<button
|
||||
v-if="activeFilterTokens.length"
|
||||
class="ghost-filter-btn"
|
||||
type="button"
|
||||
@click="emit('reset-filters')"
|
||||
>
|
||||
<i class="mdi mdi-filter-remove-outline"></i>
|
||||
<span>清空筛选</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="create-btn"
|
||||
type="button"
|
||||
:disabled="!canCreateRiskRule"
|
||||
@click="emit('create-risk-rule')"
|
||||
>
|
||||
<i class="mdi mdi-plus"></i>
|
||||
<span>{{ createButtonLabel }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="hint"><i class="mdi mdi-information-outline"></i> {{ hintText }}</p>
|
||||
|
||||
<div v-if="activeFilterTokens.length" class="active-filter-strip">
|
||||
<span v-for="token in activeFilterTokens" :key="token" class="active-filter-chip">
|
||||
{{ token }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="table-wrap"
|
||||
:class="{ 'is-empty': !loading && !errorMessage && !visibleSkills.length }"
|
||||
>
|
||||
<div v-if="loading" class="table-state">
|
||||
<TableLoadingState
|
||||
variant="panel"
|
||||
:title="`${activeTabLabel}资产同步中`"
|
||||
:message="`正在加载${activeTabLabel}资产`"
|
||||
icon="mdi mdi-view-list-outline"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="errorMessage" class="table-state error">
|
||||
<i class="mdi mdi-alert-circle-outline"></i>
|
||||
<p>{{ errorMessage }}</p>
|
||||
</div>
|
||||
|
||||
<TableEmptyState
|
||||
v-else-if="!visibleSkills.length"
|
||||
:eyebrow="auditEmptyState.eyebrow"
|
||||
:title="auditEmptyState.title"
|
||||
:description="auditEmptyState.desc"
|
||||
:icon="auditEmptyState.icon"
|
||||
:action-label="auditEmptyState.actionLabel"
|
||||
:action-icon="auditEmptyState.actionIcon"
|
||||
:tone="auditEmptyState.tone"
|
||||
:art-label="auditEmptyState.artLabel"
|
||||
:tips="auditEmptyState.tips"
|
||||
@action="emit('empty-action')"
|
||||
/>
|
||||
|
||||
<table v-else>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ tableColumns.name }}</th>
|
||||
<th>{{ tableColumns.category }}</th>
|
||||
<th>{{ tableColumns.owner }}</th>
|
||||
<th>{{ tableColumns.scope }}</th>
|
||||
<th v-if="showRuntimeColumn">{{ tableColumns.runtime }}</th>
|
||||
<th v-if="showVersionColumn">{{ tableColumns.version }}</th>
|
||||
<th v-if="showStatusColumn">{{ tableColumns.status || '状态' }}</th>
|
||||
<th v-if="showMetricColumn">{{ tableColumns.metric }}</th>
|
||||
<th v-if="showOnlineColumn">是否上线</th>
|
||||
<th v-if="showEnabledColumn">是否启用</th>
|
||||
<th>{{ tableColumns.updatedAt || '最近更新' }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="skill in visibleSkills"
|
||||
:key="skill.id"
|
||||
:class="{ 'is-disabled': skill.usesJsonRiskRule && skill.statusValue === 'generating' }"
|
||||
@click="emit('open-asset-detail', skill)"
|
||||
>
|
||||
<td>
|
||||
<div class="skill-name-cell">
|
||||
<span class="skill-avatar" :class="skill.badgeTone">{{ skill.short }}</span>
|
||||
<div>
|
||||
<strong>{{ skill.name }}</strong>
|
||||
<span class="skill-list-subtitle">{{ skill.listSubtitle || skill.summary }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ skill.category }}</td>
|
||||
<td>
|
||||
<span
|
||||
v-if="skill.usesJsonRiskRule"
|
||||
class="json-risk-meta-badge"
|
||||
:class="skill.riskLevelTone"
|
||||
>
|
||||
{{ skill.riskLevelLabel || '-' }}
|
||||
</span>
|
||||
<template v-else>{{ skill.owner }}</template>
|
||||
</td>
|
||||
<td><span class="scope-pill">{{ skill.scope }}</span></td>
|
||||
<td v-if="showRuntimeColumn">{{ skill.model }}</td>
|
||||
<td v-if="showVersionColumn">{{ skill.versionDisplay || skill.version }}</td>
|
||||
<td v-if="showStatusColumn">
|
||||
<span class="status-pill" :class="skill.statusTone">{{ skill.status }}</span>
|
||||
</td>
|
||||
<td v-if="showMetricColumn">{{ skill.hitRate }}</td>
|
||||
<td v-if="showOnlineColumn">
|
||||
<span class="status-pill" :class="skill.isOnlineTone">{{ skill.isOnlineLabel }}</span>
|
||||
</td>
|
||||
<td v-if="showEnabledColumn">
|
||||
<span class="status-pill" :class="skill.isEnabledTone">{{ skill.isEnabledLabel }}</span>
|
||||
</td>
|
||||
<td>{{ skill.updatedAt }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<footer v-if="!loading && !errorMessage && visibleSkills.length" class="list-foot">
|
||||
<span class="page-summary">当前展示 {{ visibleSkills.length }} 条资产</span>
|
||||
</footer>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AuditPickerFilter from './AuditPickerFilter.vue'
|
||||
import TableEmptyState from '../shared/TableEmptyState.vue'
|
||||
import TableLoadingState from '../shared/TableLoadingState.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'AuditAssetList'
|
||||
})
|
||||
|
||||
defineProps({
|
||||
tabs: { type: Array, default: () => [] },
|
||||
activeType: { type: String, default: '' },
|
||||
activeTabLabel: { type: String, default: '' },
|
||||
keyword: { type: String, default: '' },
|
||||
searchPlaceholder: { type: String, default: '' },
|
||||
createButtonLabel: { type: String, default: '' },
|
||||
hintText: { type: String, default: '' },
|
||||
tableColumns: { type: Object, default: () => ({}) },
|
||||
showRuntimeColumn: { type: Boolean, default: false },
|
||||
showVersionColumn: { type: Boolean, default: false },
|
||||
showMetricColumn: { type: Boolean, default: false },
|
||||
showStatusColumn: { type: Boolean, default: false },
|
||||
showOnlineColumn: { type: Boolean, default: false },
|
||||
showEnabledColumn: { type: Boolean, default: false },
|
||||
visibleSkills: { type: Array, default: () => [] },
|
||||
auditEmptyState: { type: Object, default: () => ({}) },
|
||||
loading: { type: Boolean, default: false },
|
||||
errorMessage: { type: String, default: '' },
|
||||
selectedDomain: { type: String, default: '' },
|
||||
selectedOwner: { type: String, default: '' },
|
||||
selectedRiskLevel: { type: String, default: '' },
|
||||
selectedStatus: { type: String, default: '' },
|
||||
selectedRiskScenario: { type: String, default: '' },
|
||||
selectedOnlineState: { type: String, default: '' },
|
||||
selectedEnabledState: { type: String, default: '' },
|
||||
selectedDomainLabel: { type: String, default: '' },
|
||||
selectedOwnerLabel: { type: String, default: '' },
|
||||
selectedRiskLevelLabel: { type: String, default: '' },
|
||||
selectedStatusLabel: { type: String, default: '' },
|
||||
selectedRiskScenarioLabel: { type: String, default: '' },
|
||||
selectedOnlineStateLabel: { type: String, default: '' },
|
||||
selectedEnabledStateLabel: { type: String, default: '' },
|
||||
showRiskScenarioFilter: { type: Boolean, default: false },
|
||||
showOwnerFilter: { type: Boolean, default: false },
|
||||
showRiskLevelFilter: { type: Boolean, default: false },
|
||||
showStatusFilter: { type: Boolean, default: false },
|
||||
showOnlineFilter: { type: Boolean, default: false },
|
||||
showEnabledFilter: { type: Boolean, default: false },
|
||||
domainOptions: { type: Array, default: () => [] },
|
||||
ownerOptions: { type: Array, default: () => [] },
|
||||
riskLevelOptions: { type: Array, default: () => [] },
|
||||
statusOptions: { type: Array, default: () => [] },
|
||||
riskScenarioOptions: { type: Array, default: () => [] },
|
||||
onlineStateOptions: { type: Array, default: () => [] },
|
||||
enabledStateOptions: { type: Array, default: () => [] },
|
||||
activeFilterPopover: { type: String, default: '' },
|
||||
activeFilterTokens: { type: Array, default: () => [] },
|
||||
canCreateRiskRule: { type: Boolean, default: false }
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:activeType',
|
||||
'update:keyword',
|
||||
'toggle-filter-popover',
|
||||
'close-filter-popover',
|
||||
'select-filter',
|
||||
'reset-filters',
|
||||
'create-risk-rule',
|
||||
'empty-action',
|
||||
'open-asset-detail'
|
||||
])
|
||||
|
||||
function selectFilter(type, value) {
|
||||
emit('select-filter', type, value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped src="../../assets/styles/views/audit-view.css"></style>
|
||||
<style scoped src="../../assets/styles/views/audit-view-part2.css"></style>
|
||||
Reference in New Issue
Block a user