refactor: 使用 Naive UI 重构后台布局与黑白双主题

This commit is contained in:
GouJ
2026-09-01 16:31:21 +08:00
parent 55516537bf
commit db8c176b55
51 changed files with 3277 additions and 2442 deletions
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { NAlert, NButton, NCollapse, NCollapseItem, NTag } from 'naive-ui'
import { computed, ref, watch } from 'vue'
import { AssetImage, StatusBadge } from '../../../components/ui'
import { referenceImageUrl } from '../../../lib/assets'
@@ -49,14 +50,14 @@ function chooseAnchor() {
<section class="mt-5 border-t border-line pt-5" aria-label="身份参考图库">
<div class="flex items-center justify-between gap-3">
<h3 class="text-sm font-medium">身份参考图 · {{ images.length }}</h3>
<span class="tag">{{ anchor ? '已选母版' : '尚无母版' }}</span>
<NTag size="small" :bordered="false">{{ anchor ? '已选母版' : '尚无母版' }}</NTag>
</div>
<p class="mt-2 text-xs leading-6 text-muted">
身份母版确定是谁形态主图确定该造型长什么样切换母版仅影响之后的生成不会替换已有形态图分镜参考图或提示词
</p>
<p v-if="character && anchor" class="alert mt-3 text-xs leading-6">
<NAlert v-if="character && anchor" type="info" :show-icon="false" class="mt-3 text-xs leading-6">
如果要更换演员身份请生成新的选角候选并确认选角正面三分之四全身等辅助身份图会继续引用当前母版只用于保持同一演员不会重新选择人物
</p>
</NAlert>
<template v-if="selected">
<AssetImage
:src="selected.status === 'completed' ? selected.imageUrl : null"
@@ -66,13 +67,13 @@ function chooseAnchor() {
/>
<div class="mt-3 flex flex-wrap items-center justify-between gap-3">
<div class="flex flex-wrap items-center gap-2">
<StatusBadge :status="selected.status" /><span class="tag">{{
<StatusBadge :status="selected.status" /><NTag size="small" :bordered="false">{{
selected.isAnchor
? '当前身份母版'
: selected.viewType === 'primary'
? '母版候选'
: identityViewLabels[selected.viewType]
}}</span
}}</NTag
><span class="text-xs text-muted"
>{{ selected.enabled ? '启用' : '停用' }} · {{ selected.width || '—' }} ×
{{ selected.height || '—' }}</span
@@ -87,15 +88,15 @@ function chooseAnchor() {
>打开原图</a
>
</div>
<p v-if="selected.error" class="alert alert-error mt-3" role="alert">{{ selected.error }}</p>
<NAlert v-if="selected.error" role="alert" type="error" :show-icon="false" class="mt-3">{{
selected.error
}}</NAlert>
<div class="mt-3 flex flex-wrap items-center gap-3">
<button
<NButton
v-if="!selected.isAnchor || (character && !identityLocked)"
class="button button-secondary"
:disabled="!canSelect"
@click="confirming = true"
>
{{ character ? '确认选角并锁定' : '设为身份母版' }}</button
>{{ character ? '确认选角并锁定' : '设为身份母版' }}</NButton
><span class="text-[11px] text-muted"
>{{ selected.provider }} · {{ selected.model }} · {{ formatDate(selected.createdAt) }}</span
>
@@ -103,8 +104,8 @@ function chooseAnchor() {
<p v-if="selected.viewType !== 'primary'" class="mt-2 text-xs text-muted">
辅助视图不能直接设为母版它会继承当前身份母版不适合用来更换演员
</p>
<div v-if="confirming" class="alert mt-3">
<p class="text-xs">
<NAlert v-if="confirming" type="info" :show-icon="false" class="mt-3"
><p class="text-xs">
{{
character
? '确认选择这张图片作为正式演员?后端会在同一事务中切换身份母版并锁定 Identity,完成后首帧才具备稳定人物身份。'
@@ -112,15 +113,18 @@ function chooseAnchor() {
}}
</p>
<div class="mt-3 flex gap-3">
<button class="button button-primary" :disabled="!canSelect" @click="chooseAnchor">
{{ character ? '确认演员选择' : '确认切换身份母版' }}</button
><button class="text-button" @click="confirming = false">取消</button>
</div>
</div>
<details v-if="selected.prompt" class="mt-4 text-xs">
<summary class="cursor-pointer text-muted">本次实际提示词</summary>
<p class="mt-3 whitespace-pre-wrap leading-6">{{ selected.prompt }}</p>
</details>
<NButton :disabled="!canSelect" @click="chooseAnchor" type="primary">{{
character ? '确认演员选择' : '确认切换身份母版'
}}</NButton
><NButton @click="confirming = false" text size="small">取消</NButton>
</div></NAlert
>
<NCollapse v-if="selected.prompt" class="mt-4 text-xs"
><NCollapseItem name="details"
><template #header>本次实际提示词</template>
<p class="mt-3 whitespace-pre-wrap leading-6">{{ selected.prompt }}</p></NCollapseItem
></NCollapse
>
<p
v-if="readImageProvenance(selected.rawJson).referenceImageId"
class="mt-3 break-all text-[11px] text-muted"
@@ -129,16 +133,15 @@ function chooseAnchor() {
</p>
<p class="mt-2 break-all font-mono text-[10px] text-muted">Identity image ID · {{ selected.id }}</p>
<div class="image-history mt-4" aria-label="身份图片历史">
<button
<NButton
v-for="image in images"
:key="image.id"
class="image-history-item"
:class="{ selected: image.id === selected.id }"
:aria-label="`查看身份图片 ${image.id}`"
:aria-pressed="image.id === selected.id"
@click="selectedId = image.id"
>
<AssetImage
class="image-history-item"
:class="{ selected: image.id === selected.id }"
><AssetImage
:src="image.status === 'completed' ? image.imageUrl : null"
:alt="identityViewLabels[image.viewType]"
:retryable="false"
@@ -149,8 +152,8 @@ function chooseAnchor() {
: image.viewType === 'primary'
? '母版候选'
: identityViewLabels[image.viewType]
}}</span>
</button>
}}</span></NButton
>
</div>
</template>
<p v-else class="py-8 text-sm text-muted">尚无身份参考图先保存身份提示词再生成第一张母版</p>