feat(ui06): B3d governance + B3e closing — page headings, stat cards, info strip, embed slots

- 治理页通用层(ui06.scss):.ui06-page 工作区 / .ui06-page-heading 27px 页头 / .ui06-stats
  三列统计卡 / .ui06-info-strip 提示条 / .ui06-card-title 17px 卡头
- 10 账号:页头(查看同步入口)+ 来源提示条;分页/同步档案列/G4 功能零改动
- 11 同步:页头(手动补拉上移);状态卡/历史/失败明细抽屉保留
- 12 用量:页头(阈值设置上移)+ 统计卡对齐示例(数字 27px + 注脚 10px)
- 13 展示位:页头 + 卡片标题(配置对话框沿用 UI-04 真实组件)
- 17-19 异常页:沿用 ArtException(大数字+文案+回退,语义等同示例;登记偏差)
- i18n zh/en;typecheck/lint/vitest/build 全绿

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-23 07:04:18 +08:00
parent 352d7405c2
commit 9471562f67
28 changed files with 254 additions and 51 deletions
@@ -3,14 +3,24 @@
文案)+ 嵌入代码卡。启停与任何管理面变更一样递增 configVersion——toast
携带新版本号提示(嵌入端轮询发现版本升即整体重置渲染)。 -->
<template>
<div class="p-5">
<div class="ui06-page">
<!-- 页头(示例 13 .page-heading) -->
<div class="ui06-page-heading">
<div>
<h1>{{ $t('embedSlotsManage.list.title') }}</h1>
<p>{{ $t('embedSlotsManage.list.subtitle') }}</p>
</div>
<div class="actions">
<ElButton type="primary" data-test="slot-create-btn" @click="openCreate">
{{ $t('embedSlotsManage.list.create') }}
</ElButton>
</div>
</div>
<ElCard data-test="embed-slots-card">
<template #header>
<div class="flex items-center justify-between">
<span>{{ $t('embedSlotsManage.list.title') }}</span>
<ElButton type="primary" data-test="slot-create-btn" @click="openCreate">
{{ $t('embedSlotsManage.list.create') }}
</ElButton>
<span class="ui06-card-title">{{ $t('embedSlotsManage.list.tableTitle') }}</span>
</div>
</template>
+33 -27
View File
@@ -2,24 +2,37 @@
相册用量表(title/photoCount/originalBytes/variantBytes/totalBytes
人类可读)+ 阈值设置对话框 + 告警列表(未解决红/已解决灰,含信息与时间)。 -->
<template>
<div class="p-5">
<!-- ── 合计头卡 ── -->
<div class="grid gap-4 mb-4 sm:grid-cols-3" data-test="usage-totals">
<ElCard shadow="never">
<div class="text-gray-500 text-sm">{{ $t('usage.totals.photoCount') }}</div>
<div class="text-2xl font-medium mt-1" data-test="usage-total-photos">
{{ summary?.totals.photoCount ?? '-' }}
</div>
</ElCard>
<ElCard shadow="never">
<div class="text-gray-500 text-sm">{{ $t('usage.totals.totalBytes') }}</div>
<div class="text-2xl font-medium mt-1" data-test="usage-total-bytes">
<div class="ui06-page">
<!-- 页头(示例 12 .page-heading:标题 + 副文 + 阈值设置入口上移) -->
<div class="ui06-page-heading">
<div>
<h1>{{ $t('usage.page.title') }}</h1>
<p>{{ $t('usage.page.subtitle') }}</p>
</div>
<div class="actions">
<ElButton plain data-test="usage-thresholds-btn" @click="thresholdsVisible = true">
{{ $t('usage.thresholds.entry') }}
</ElButton>
</div>
</div>
<!-- ── 合计头卡(示例 .stats / .stat 三列统计) ── -->
<div class="ui06-stats" data-test="usage-totals">
<div class="ui06-stat">
<p>{{ $t('usage.totals.photoCount') }}</p>
<strong data-test="usage-total-photos">{{ summary?.totals.photoCount ?? '-' }}</strong>
<small>{{ $t('usage.totals.photoCountNote') }}</small>
</div>
<div class="ui06-stat">
<p>{{ $t('usage.totals.totalBytes') }}</p>
<strong data-test="usage-total-bytes">
{{ summary ? formatBytes(summary.totals.totalBytes) : '-' }}
</div>
</ElCard>
<ElCard shadow="never">
<div class="text-gray-500 text-sm">{{ $t('usage.totals.thresholds') }}</div>
<div class="mt-1 flex flex-wrap gap-2" data-test="usage-threshold-tags">
</strong>
<small>{{ $t('usage.totals.totalBytesNote') }}</small>
</div>
<div class="ui06-stat">
<p>{{ $t('usage.totals.thresholds') }}</p>
<div class="mt-2 flex flex-wrap gap-2" data-test="usage-threshold-tags">
<ElTag size="small" :type="summary?.thresholds.storageBytes ? 'success' : 'info'">
{{ $t('usage.thresholds.storageShort') }}
{{
@@ -37,22 +50,15 @@
}}
</ElTag>
</div>
</ElCard>
<small>{{ $t('usage.totals.thresholdsNote') }}</small>
</div>
</div>
<!-- ── 相册用量 + 告警 ── -->
<ElCard data-test="usage-albums-card">
<template #header>
<div class="flex items-center justify-between">
<span>{{ $t('usage.albums.title') }}</span>
<ElButton
type="primary"
plain
data-test="usage-thresholds-btn"
@click="thresholdsVisible = true"
>
{{ $t('usage.thresholds.entry') }}
</ElButton>
<span class="ui06-card-title">{{ $t('usage.albums.title') }}</span>
</div>
</template>
+21 -11
View File
@@ -2,21 +2,31 @@
运行历史(游标累积)、失败明细抽屉(点行打开)。页面存续期间 10s 自动
刷新状态(onUnmounted 清理);手动补拉 202 受理后轮询至批次离开 running。 -->
<template>
<div class="p-5">
<div class="ui06-page">
<!-- 页头(示例 11 .page-heading:标题 + 副文 + 手动补拉入口上移) -->
<div class="ui06-page-heading">
<div>
<h1>{{ $t('userSync.page.title') }}</h1>
<p>{{ $t('userSync.page.subtitle') }}</p>
</div>
<div class="actions">
<ElButton
type="primary"
:loading="triggering"
:disabled="status?.state === 'running'"
data-test="sync-trigger-btn"
@click="triggerSync"
>
{{ $t('userSync.status.trigger') }}
</ElButton>
</div>
</div>
<!-- ── 状态卡 ── -->
<ElCard data-test="sync-status-card" class="mb-4">
<template #header>
<div class="flex items-center justify-between">
<span>{{ $t('userSync.status.title') }}</span>
<ElButton
type="primary"
:loading="triggering"
:disabled="status?.state === 'running'"
data-test="sync-trigger-btn"
@click="triggerSync"
>
{{ $t('userSync.status.trigger') }}
</ElButton>
<span class="ui06-card-title">{{ $t('userSync.status.title') }}</span>
</div>
</template>
+24 -2
View File
@@ -3,11 +3,30 @@
公司)展示 + 行内治理操作(编辑/重置密码/激活/停用/解锁)。自我保护双
保险:UI 对自身行禁用角色/锁定编辑,服务端 400 仍会经 http 层本地化弹出。 -->
<template>
<div class="p-5">
<div class="ui06-page">
<!-- 页头(示例 10 .page-heading:标题 + 副文 + 查看同步入口) -->
<div class="ui06-page-heading">
<div>
<h1>{{ $t('usersManage.list.title') }}</h1>
<p>{{ $t('usersManage.list.subtitle') }}</p>
</div>
<div class="actions">
<ElButton plain data-test="users-goto-sync" @click="router.push('/system/user-sync')">
{{ $t('usersManage.list.viewSync') }}
</ElButton>
</div>
</div>
<!-- 来源提示条(示例 .info-strip:来源状态与本地锁定相互独立) -->
<div class="ui06-info-strip">
<ElIcon><InfoFilled /></ElIcon>
<span>{{ $t('usersManage.list.sourceHint') }}</span>
</div>
<ElCard data-test="users-card">
<template #header>
<div class="flex items-center justify-between">
<span>{{ $t('usersManage.list.title') }}</span>
<span class="ui06-card-title">{{ $t('usersManage.list.tableTitle') }}</span>
<!-- 过滤栏:前缀查询(account/displayName)+ 治理状态单选 -->
<div class="flex flex-wrap items-center gap-2">
<ElInput
@@ -196,8 +215,10 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import { InfoFilled } from '@element-plus/icons-vue'
import UserEditDialog from './UserEditDialog.vue'
import ResetPasswordDialog from './ResetPasswordDialog.vue'
import {
@@ -213,6 +234,7 @@
defineOptions({ name: 'SystemUsers' })
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
// ── 过滤(查询即整页重载:游标键集依赖过滤条件稳定) ──