Files
JuYou/WEB/src/components/creative/RedrawAssetPanel.vue
T
2026-08-25 17:59:42 +08:00

176 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 重绘资产面板负责资产信息编辑保存和空状态展示 -->
<script setup lang="ts">
import { computed, reactive, watch } from "vue";
import { Box, Delete, OfficeBuilding, UserFilled } from "@element-plus/icons-vue";
import type { ProjectAsset } from "@/api/creative";
const props = defineProps<{ assets: ProjectAsset[]; busy?: boolean }>();
const emit = defineEmits<{
save: [assetId: string, payload: Partial<ProjectAsset>];
delete: [asset: ProjectAsset];
}>();
const names = reactive<Record<string, string>>({});
const groups = [
{ type: "character", label: "角色", icon: UserFilled },
{ type: "scene", label: "场景", icon: OfficeBuilding },
{ type: "prop", label: "道具", icon: Box },
];
const grouped = computed(() =>
groups.map((group) => ({ ...group, items: props.assets.filter((asset) => asset.asset_type === group.type) })),
);
watch(
() => props.assets,
(assets) => assets.forEach((asset) => (names[asset.id] = asset.name)),
{ immediate: true, deep: true },
);
watch(
() => props.busy,
(busy, wasBusy) => {
if (wasBusy && !busy) props.assets.forEach((asset) => (names[asset.id] = asset.name));
},
);
/** 合并当前编辑值并提交资产更新。 */
function save(asset: ProjectAsset) {
const name = (names[asset.id] || "").trim();
if (!name) {
names[asset.id] = asset.name;
return;
}
if (name !== asset.name) emit("save", asset.id, { name });
}
/** 触发资产删除确认,由工作台负责调用后端并刷新数据。 */
function remove(asset: ProjectAsset) {
emit("delete", asset);
}
</script>
<template>
<section class="redraw-column asset-column">
<header>
<strong>资产</strong><small>{{ assets.length }}</small>
</header>
<div
v-loading="busy"
class="asset-list"
>
<template
v-for="group in grouped"
:key="group.type"
>
<div
v-if="group.items.length"
class="asset-group"
>
<div class="asset-group-title">
<el-icon><component :is="group.icon" /></el-icon><span>{{ group.label }}</span
><small>{{ group.items.length }}</small>
</div>
<label
v-for="asset in group.items"
:key="asset.id"
class="asset-name"
>
<span>{{ group.label }}</span>
<div class="asset-edit-row">
<el-input
v-model="names[asset.id]"
maxlength="80"
@blur="save(asset)"
/>
<el-button
class="asset-delete-button"
text
:icon="Delete"
:disabled="busy"
title="删除资产"
@click="remove(asset)"
/>
</div>
</label>
</div>
</template>
<div
v-if="!assets.length"
class="column-empty"
>
反推完成后将在这里显示资产
</div>
</div>
</section>
</template>
<style scoped lang="scss">
.asset-column {
min-width: 0;
display: flex;
flex-direction: column;
}
.asset-list {
min-height: 0;
padding: 12px;
flex: 1;
overflow: auto;
}
.column-empty {
width: 100%;
height: 100%;
min-height: 240px;
padding: 24px;
display: grid;
place-items: center;
color: var(--web-muted);
font-size: 13px;
line-height: 1.6;
text-align: center;
}
.asset-group + .asset-group {
margin-top: 16px;
}
.asset-group-title {
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 7px;
color: var(--web-accent-dark);
font-size: 13px;
}
.asset-group-title small {
margin-left: auto;
color: var(--web-panel-hint);
}
.asset-name {
margin-bottom: 8px;
padding: 9px;
display: block;
background: var(--web-surface);
border: 1px solid var(--web-line-strong);
border-radius: 7px;
}
.asset-name > span {
margin-bottom: 6px;
display: block;
color: var(--web-text-tertiary);
font-size: 11px;
}
.asset-name :deep(.el-input__wrapper) {
background: var(--web-surface-soft);
box-shadow: 0 0 0 1px var(--web-line-strong) inset;
}
.asset-edit-row {
display: flex;
align-items: center;
gap: 6px;
}
.asset-edit-row .el-input {
min-width: 0;
flex: 1;
}
.asset-delete-button {
flex: 0 0 auto;
color: var(--web-danger);
}
</style>