feat: wire template stores and linkage
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { computed, reactive, ref, watch } from "vue";
|
||||
import { CloseOutlined, PlusOutlined, SaveOutlined } from "@ant-design/icons-vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { useSelectionStore } from "@/stores/selectionStore";
|
||||
import { type BlockConfig, type RegionType, useTemplateStore } from "@/stores/templateStore";
|
||||
import { useUiStore } from "@/stores/uiStore";
|
||||
|
||||
type RegionType = "ai_generate" | "manual" | "fixed" | "table";
|
||||
|
||||
const selectedBlock = ref({
|
||||
block_id: "block_003",
|
||||
text_preview: "一、经营概况",
|
||||
});
|
||||
const templateStore = useTemplateStore();
|
||||
const selectionStore = useSelectionStore();
|
||||
const uiStore = useUiStore();
|
||||
const selectedBlock = computed(() => templateStore.blockById(selectionStore.selectedBlockId));
|
||||
const saving = ref(false);
|
||||
|
||||
const dataSourceOptions = [
|
||||
@@ -17,11 +18,11 @@ const dataSourceOptions = [
|
||||
{ code: "research", name: "调研材料" },
|
||||
];
|
||||
|
||||
const form = reactive({
|
||||
region_name: selectedBlock.value.text_preview,
|
||||
const form = reactive<BlockConfig>({
|
||||
region_name: "",
|
||||
region_type: "ai_generate" as RegionType,
|
||||
data_sources: ["business_data"],
|
||||
prompt: "请基于业务数据生成经营概况,突出核心指标变化和原因。",
|
||||
data_sources: [],
|
||||
prompt: "",
|
||||
output_format: "formal_paragraph",
|
||||
need_review: 1,
|
||||
remark: "",
|
||||
@@ -45,10 +46,29 @@ function sourceName(code: string) {
|
||||
return dataSourceOptions.find((item) => item.code === code)?.name ?? code;
|
||||
}
|
||||
|
||||
function loadSelectedConfig() {
|
||||
const block = selectedBlock.value;
|
||||
if (!block) return;
|
||||
|
||||
const config = templateStore.configById(block.block_id);
|
||||
form.region_name = config?.region_name || block.text_preview;
|
||||
form.region_type = config?.region_type || (block.block_type === "table" ? "table" : "ai_generate");
|
||||
form.data_sources = [...(config?.data_sources ?? [])];
|
||||
form.prompt = config?.prompt ?? "";
|
||||
form.output_format = config?.output_format || "formal_paragraph";
|
||||
form.need_review = config?.need_review ?? 1;
|
||||
form.remark = config?.remark ?? "";
|
||||
form.enabled = config?.enabled ?? 1;
|
||||
}
|
||||
|
||||
async function saveConfig() {
|
||||
const block = selectedBlock.value;
|
||||
if (!block) return;
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 500));
|
||||
await templateStore.saveBlockConfig(block.block_id, { ...form, data_sources: [...form.data_sources] });
|
||||
uiStore.markSaved();
|
||||
message.success("配置已保存");
|
||||
} catch {
|
||||
message.error("配置保存失败");
|
||||
@@ -56,6 +76,8 @@ async function saveConfig() {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => selectionStore.selectedBlockId, loadSelectedConfig, { immediate: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,29 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue";
|
||||
import { reactive } from "vue";
|
||||
|
||||
import StructureTreeNode, { type StructureNode } from "./StructureTreeNode.vue";
|
||||
import { useSelectionStore } from "@/stores/selectionStore";
|
||||
import { useTemplateStore } from "@/stores/templateStore";
|
||||
|
||||
const nodes: StructureNode[] = [
|
||||
{
|
||||
id: "block_001",
|
||||
name: "企业经营分析报告",
|
||||
status: "done",
|
||||
children: [
|
||||
{ id: "block_002", name: "报告说明", status: "review" },
|
||||
{
|
||||
id: "block_003",
|
||||
name: "一、经营概况",
|
||||
status: "done",
|
||||
children: [
|
||||
{ id: "block_004", name: "经营概况段落", status: "empty" },
|
||||
{ id: "block_005", name: "经营指标表", status: "disabled" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const activeId = ref("block_003");
|
||||
const templateStore = useTemplateStore();
|
||||
const selectionStore = useSelectionStore();
|
||||
const expandedKeys = reactive<Record<string, boolean>>({
|
||||
block_001: true,
|
||||
block_003: true,
|
||||
@@ -34,7 +17,7 @@ function toggleNode(id: string) {
|
||||
}
|
||||
|
||||
function selectNode(node: StructureNode) {
|
||||
activeId.value = node.id;
|
||||
selectionStore.selectBlock(node.id);
|
||||
const target = document.querySelector<HTMLElement>(`[data-block-id="${node.id}"]`);
|
||||
if (!target) return;
|
||||
|
||||
@@ -48,14 +31,14 @@ function selectNode(node: StructureNode) {
|
||||
<aside class="structure-tree">
|
||||
<header>
|
||||
<span>文档结构</span>
|
||||
<span class="count">{{ nodes.length }}</span>
|
||||
<span class="count">{{ templateStore.blocks.length }}</span>
|
||||
</header>
|
||||
<ul class="tree-list">
|
||||
<StructureTreeNode
|
||||
v-for="node in nodes"
|
||||
v-for="node in templateStore.tree"
|
||||
:key="node.id"
|
||||
:node="node"
|
||||
:active-id="activeId"
|
||||
:active-id="selectionStore.selectedBlockId"
|
||||
:expanded-keys="expandedKeys"
|
||||
@select="selectNode"
|
||||
@toggle="toggleNode"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import {
|
||||
DownloadOutlined,
|
||||
EyeOutlined,
|
||||
@@ -7,21 +6,19 @@ import {
|
||||
PlayCircleOutlined,
|
||||
SaveOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { useTemplateStore } from "@/stores/templateStore";
|
||||
import { useUiStore } from "@/stores/uiStore";
|
||||
|
||||
const breadcrumbs = ["模板管理", "模板标注"];
|
||||
const templateInfo = {
|
||||
name: "企业经营分析报告模板",
|
||||
version: "v1.0.0",
|
||||
};
|
||||
const isSaved = ref(true);
|
||||
const saveStatusText = computed(() => (isSaved.value ? "已保存" : "未保存"));
|
||||
const templateStore = useTemplateStore();
|
||||
const uiStore = useUiStore();
|
||||
|
||||
function markDirty() {
|
||||
isSaved.value = false;
|
||||
uiStore.markDirty();
|
||||
}
|
||||
|
||||
function saveTemplate() {
|
||||
isSaved.value = true;
|
||||
uiStore.markSaved();
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -32,9 +29,11 @@ function saveTemplate() {
|
||||
<span v-for="item in breadcrumbs" :key="item">{{ item }}</span>
|
||||
</div>
|
||||
<div class="template-meta">
|
||||
<strong>{{ templateInfo.name }}</strong>
|
||||
<a-tag color="blue">{{ templateInfo.version }}</a-tag>
|
||||
<span class="save-status" :class="{ dirty: !isSaved }">{{ saveStatusText }}</span>
|
||||
<strong>{{ templateStore.template.name }}</strong>
|
||||
<a-tag color="blue">{{ templateStore.template.version }}</a-tag>
|
||||
<span class="save-status" :class="{ dirty: !uiStore.isSaved }">
|
||||
{{ uiStore.saveStatusText }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,50 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, ref } from "vue";
|
||||
import { nextTick, onMounted, ref, watch } from "vue";
|
||||
import { useSelectionStore } from "@/stores/selectionStore";
|
||||
import { useTemplateStore } from "@/stores/templateStore";
|
||||
import { useUiStore } from "@/stores/uiStore";
|
||||
|
||||
type RegionType = "ai_generate" | "manual" | "fixed" | "table" | "none";
|
||||
|
||||
const selectedBlockId = ref("block_003");
|
||||
const showLabels = ref(true);
|
||||
const zoom = ref(100);
|
||||
const zoomOptions = [70, 100, 150];
|
||||
|
||||
const regionTypes: Record<string, RegionType> = {
|
||||
block_001: "fixed",
|
||||
block_002: "manual",
|
||||
block_003: "ai_generate",
|
||||
block_004: "ai_generate",
|
||||
block_005: "table",
|
||||
};
|
||||
|
||||
const previewHtml = `
|
||||
<h1 data-block-id="block_001" style="margin:0 0 28px;text-align:center;font-size:20px;">企业经营分析报告</h1>
|
||||
<p data-block-id="block_002" style="margin:8px 0;text-align:justify;text-indent:2em;">本报告用于展示 Word 模板解析后的 A4 预览效果,后续会由后端返回的 preview_html 驱动渲染。</p>
|
||||
<h2 data-block-id="block_003" style="margin:24px 0 12px;padding-bottom:6px;border-bottom:2px solid #1a1d24;font-size:16px;">一、经营概况</h2>
|
||||
<p data-block-id="block_004" style="margin:8px 0;text-align:justify;text-indent:2em;">点击预览区块后,左侧配置面板将展示对应区域的提示词、数据源和输出格式配置。</p>
|
||||
<table data-block-id="block_005" style="width:100%;margin:14px 0;border-collapse:collapse;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">指标</th>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">本期</th>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">同比</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">营业收入</td>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">利润率</td>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td>
|
||||
<td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const previewRef = ref<HTMLElement | null>(null);
|
||||
const templateStore = useTemplateStore();
|
||||
const selectionStore = useSelectionStore();
|
||||
const uiStore = useUiStore();
|
||||
|
||||
function enhancePreviewBlocks() {
|
||||
const root = previewRef.value;
|
||||
@@ -52,11 +17,13 @@ function enhancePreviewBlocks() {
|
||||
|
||||
root.querySelectorAll<HTMLElement>("[data-block-id]").forEach((element) => {
|
||||
const blockId = element.dataset.blockId ?? "";
|
||||
const regionType = regionTypes[blockId] ?? "none";
|
||||
const block = templateStore.blockById(blockId);
|
||||
const config = templateStore.configById(blockId);
|
||||
const regionType = config?.region_type ?? (block?.block_type === "table" ? "table" : "none");
|
||||
element.classList.add("doc-block", `region-${regionType}`);
|
||||
element.classList.toggle("active", blockId === selectedBlockId.value);
|
||||
element.classList.toggle("active", blockId === selectionStore.selectedBlockId);
|
||||
element.dataset.blockLabel = blockId;
|
||||
element.dataset.labels = showLabels.value ? "on" : "off";
|
||||
element.dataset.labels = uiStore.showBlockLabels ? "on" : "off";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,19 +32,19 @@ async function selectBlock(event: MouseEvent) {
|
||||
const block = target?.closest<HTMLElement>("[data-block-id]");
|
||||
if (!block) return;
|
||||
|
||||
selectedBlockId.value = block.dataset.blockId ?? "";
|
||||
selectionStore.selectBlock(block.dataset.blockId ?? "");
|
||||
await nextTick();
|
||||
enhancePreviewBlocks();
|
||||
}
|
||||
|
||||
async function setZoom(value: number) {
|
||||
zoom.value = value;
|
||||
uiStore.setZoom(value);
|
||||
await nextTick();
|
||||
enhancePreviewBlocks();
|
||||
}
|
||||
|
||||
async function toggleLabels(checked: boolean) {
|
||||
showLabels.value = checked;
|
||||
uiStore.setShowBlockLabels(checked);
|
||||
await nextTick();
|
||||
enhancePreviewBlocks();
|
||||
}
|
||||
@@ -85,19 +52,33 @@ async function toggleLabels(checked: boolean) {
|
||||
onMounted(() => {
|
||||
enhancePreviewBlocks();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [
|
||||
templateStore.previewHtml,
|
||||
selectionStore.selectedBlockId,
|
||||
uiStore.showBlockLabels,
|
||||
uiStore.zoom,
|
||||
Object.keys(templateStore.configs).join(","),
|
||||
],
|
||||
async () => {
|
||||
await nextTick();
|
||||
enhancePreviewBlocks();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="preview-shell">
|
||||
<header class="preview-toolbar">
|
||||
<a-switch size="small" :checked="showLabels" @change="toggleLabels" />
|
||||
<a-switch size="small" :checked="uiStore.showBlockLabels" @change="toggleLabels" />
|
||||
<span>显示标签</span>
|
||||
<div class="zoom-group">
|
||||
<button
|
||||
v-for="item in zoomOptions"
|
||||
:key="item"
|
||||
type="button"
|
||||
:class="{ active: zoom === item }"
|
||||
:class="{ active: uiStore.zoom === item }"
|
||||
@click="setZoom(item)"
|
||||
>
|
||||
{{ item }}%
|
||||
@@ -109,9 +90,9 @@ onMounted(() => {
|
||||
<div
|
||||
ref="previewRef"
|
||||
class="doc-page"
|
||||
:style="{ transform: `scale(${zoom / 100})` }"
|
||||
:style="{ transform: `scale(${uiStore.zoom / 100})` }"
|
||||
@click="selectBlock"
|
||||
v-html="previewHtml"
|
||||
v-html="templateStore.previewHtml"
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useSelectionStore = defineStore("selection", {
|
||||
state: () => ({
|
||||
selectedBlockId: "block_003",
|
||||
}),
|
||||
actions: {
|
||||
selectBlock(blockId: string) {
|
||||
this.selectedBlockId = blockId;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export type RegionType = "ai_generate" | "manual" | "fixed" | "table";
|
||||
|
||||
export type TemplateBlock = {
|
||||
block_id: string;
|
||||
block_type: "title" | "heading" | "paragraph" | "table";
|
||||
text_preview: string;
|
||||
level: number;
|
||||
sort_order: number;
|
||||
table_rows?: number;
|
||||
table_cols?: number;
|
||||
};
|
||||
|
||||
export type TreeNode = {
|
||||
id: string;
|
||||
name: string;
|
||||
status: "done" | "review" | "disabled" | "empty";
|
||||
children?: TreeNode[];
|
||||
};
|
||||
|
||||
export type BlockConfig = {
|
||||
region_name: string;
|
||||
region_type: RegionType;
|
||||
data_sources: string[];
|
||||
prompt: string;
|
||||
output_format: string;
|
||||
need_review: number;
|
||||
remark: string;
|
||||
enabled: number;
|
||||
};
|
||||
|
||||
const mockPreviewHtml = `
|
||||
<h1 data-block-id="block_001" style="margin:0 0 28px;text-align:center;font-size:20px;">企业经营分析报告</h1>
|
||||
<p data-block-id="block_002" style="margin:8px 0;text-align:justify;text-indent:2em;">本报告用于展示 Word 模板解析后的 A4 预览效果,后续会由后端返回的 preview_html 驱动渲染。</p>
|
||||
<h2 data-block-id="block_003" style="margin:24px 0 12px;padding-bottom:6px;border-bottom:2px solid #1a1d24;font-size:16px;">一、经营概况</h2>
|
||||
<p data-block-id="block_004" style="margin:8px 0;text-align:justify;text-indent:2em;">点击预览区块后,左侧配置面板将展示对应区域的提示词、数据源和输出格式配置。</p>
|
||||
<table data-block-id="block_005" style="width:100%;margin:14px 0;border-collapse:collapse;">
|
||||
<thead><tr>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">指标</th>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">本期</th>
|
||||
<th style="padding:7px 10px;border:1px solid #e0e2e6;text-align:left;background:#f0f1f3;">同比</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr><td style="padding:7px 10px;border:1px solid #e0e2e6;">营业收入</td><td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td><td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td></tr>
|
||||
<tr><td style="padding:7px 10px;border:1px solid #e0e2e6;">利润率</td><td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td><td style="padding:7px 10px;border:1px solid #e0e2e6;">-</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
export const useTemplateStore = defineStore("template", {
|
||||
state: () => ({
|
||||
loading: false,
|
||||
error: "",
|
||||
template: {
|
||||
id: 1,
|
||||
name: "企业经营分析报告模板",
|
||||
version: "v1.0.0",
|
||||
},
|
||||
previewHtml: mockPreviewHtml,
|
||||
blocks: [
|
||||
{ block_id: "block_001", block_type: "title", text_preview: "企业经营分析报告", level: 0, sort_order: 1 },
|
||||
{ block_id: "block_002", block_type: "paragraph", text_preview: "报告说明", level: 0, sort_order: 2 },
|
||||
{ block_id: "block_003", block_type: "heading", text_preview: "一、经营概况", level: 1, sort_order: 3 },
|
||||
{ block_id: "block_004", block_type: "paragraph", text_preview: "经营概况段落", level: 0, sort_order: 4 },
|
||||
{ block_id: "block_005", block_type: "table", text_preview: "经营指标表", level: 0, sort_order: 5, table_rows: 3, table_cols: 3 },
|
||||
] as TemplateBlock[],
|
||||
tree: [
|
||||
{
|
||||
id: "block_001",
|
||||
name: "企业经营分析报告",
|
||||
status: "done",
|
||||
children: [
|
||||
{ id: "block_002", name: "报告说明", status: "review" },
|
||||
{
|
||||
id: "block_003",
|
||||
name: "一、经营概况",
|
||||
status: "done",
|
||||
children: [
|
||||
{ id: "block_004", name: "经营概况段落", status: "empty" },
|
||||
{ id: "block_005", name: "经营指标表", status: "disabled" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
] as TreeNode[],
|
||||
configs: {
|
||||
block_003: {
|
||||
region_name: "一、经营概况",
|
||||
region_type: "ai_generate",
|
||||
data_sources: ["business_data"],
|
||||
prompt: "请基于业务数据生成经营概况,突出核心指标变化和原因。",
|
||||
output_format: "formal_paragraph",
|
||||
need_review: 1,
|
||||
remark: "",
|
||||
enabled: 1,
|
||||
},
|
||||
block_005: {
|
||||
region_name: "经营指标表",
|
||||
region_type: "table",
|
||||
data_sources: ["business_data"],
|
||||
prompt: "",
|
||||
output_format: "table_summary",
|
||||
need_review: 1,
|
||||
remark: "",
|
||||
enabled: 0,
|
||||
},
|
||||
} as Record<string, BlockConfig>,
|
||||
}),
|
||||
getters: {
|
||||
blockById: (state) => (blockId: string) => state.blocks.find((block) => block.block_id === blockId),
|
||||
configById: (state) => (blockId: string) => state.configs[blockId],
|
||||
},
|
||||
actions: {
|
||||
async loadTemplate() {
|
||||
this.loading = true;
|
||||
this.error = "";
|
||||
try {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 200));
|
||||
} catch {
|
||||
this.error = "模板加载失败";
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async saveBlockConfig(blockId: string, config: BlockConfig) {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, 400));
|
||||
this.configs[blockId] = { ...config };
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useUiStore = defineStore("ui", {
|
||||
state: () => ({
|
||||
showBlockLabels: true,
|
||||
zoom: 100,
|
||||
isSaved: true,
|
||||
}),
|
||||
getters: {
|
||||
saveStatusText: (state) => (state.isSaved ? "已保存" : "未保存"),
|
||||
},
|
||||
actions: {
|
||||
setZoom(value: number) {
|
||||
this.zoom = value;
|
||||
},
|
||||
setShowBlockLabels(value: boolean) {
|
||||
this.showBlockLabels = value;
|
||||
},
|
||||
markDirty() {
|
||||
this.isSaved = false;
|
||||
},
|
||||
markSaved() {
|
||||
this.isSaved = true;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,9 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
import ConfigPanel from "@/components/TemplateEdit/ConfigPanel.vue";
|
||||
import LeftMenu from "@/components/TemplateEdit/LeftMenu.vue";
|
||||
import StructureTree from "@/components/TemplateEdit/StructureTree.vue";
|
||||
import TopToolbar from "@/components/TemplateEdit/TopToolbar.vue";
|
||||
import WordPreview from "@/components/TemplateEdit/WordPreview.vue";
|
||||
import { useTemplateStore } from "@/stores/templateStore";
|
||||
|
||||
const templateStore = useTemplateStore();
|
||||
|
||||
onMounted(() => {
|
||||
templateStore.loadTemplate();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -11,7 +19,17 @@ import WordPreview from "@/components/TemplateEdit/WordPreview.vue";
|
||||
<LeftMenu />
|
||||
<section class="edit-main">
|
||||
<TopToolbar />
|
||||
<div class="edit-workspace">
|
||||
<div v-if="templateStore.loading" class="state-view">
|
||||
<a-spin size="large" />
|
||||
</div>
|
||||
<div v-else-if="templateStore.error" class="state-view">
|
||||
<a-result status="error" title="加载失败" :sub-title="templateStore.error">
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="templateStore.loadTemplate()">重新加载</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
<div v-else class="edit-workspace">
|
||||
<ConfigPanel />
|
||||
<WordPreview />
|
||||
<StructureTree />
|
||||
@@ -41,4 +59,11 @@ import WordPreview from "@/components/TemplateEdit/WordPreview.vue";
|
||||
grid-template-columns: 380px minmax(520px, 1fr) 240px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.state-view {
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
place-items: center;
|
||||
background: var(--c-bg);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user