fix(#187): 修复模板配置台两处交互失效 #191

Closed
bot_dev1 wants to merge 1 commits from feature/issue-187 into main
3 changed files with 40 additions and 11 deletions
@@ -4,6 +4,7 @@ import { ref } from 'vue';
import { Page, VbenButton } from '@vben/common-ui';
import { BxsFile } from '@vben/icons';
import type { UploadChangeParam } from 'antdv-next';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
@@ -33,14 +34,19 @@ const gridOptions: VxeTableGridOptions<Record<string, string>> = {
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
function onFile(e: Event) {
const el = e.target as HTMLInputElement;
const file = el.files?.[0];
if (!file) return;
function onFile(info: UploadChangeParam) {
// a-upload 的 @change 载荷是 UploadChangeParam { file, fileList },
// 在 :before-upload="() => false"(禁止自动上传)时文件对象在 file.originFileObj 上,
// 不是 DOM Event,不能用 e.target.files(会抛 TypeError 导致无响应)。
const { file } = info;
// 仅在选中文件后处理一次(removed 状态时跳过,避免清空预览)
if (file.status === 'removed') return;
const raw = file.originFileObj ?? file;
if (!raw) return;
fileName.value = file.name;
const reader = new FileReader();
reader.onload = () => parseCsv(String(reader.result || ''));
reader.readAsText(file);
reader.readAsText(raw as Blob);
}
function parseCsv(text: string) {
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { Page, VbenButton } from '@vben/common-ui';
import { MaterialSymbolsEdit } from '@vben/icons';
import { message } from 'antdv-next';
const components = ref([
{ type: 'process_view', title: '四状态工艺流程', enabled: true },
@@ -24,7 +25,25 @@ const move = (i: number, dir: number) => {
components.value[j] = t;
};
const layoutJson = () => JSON.stringify({ widgets: components.value.filter((c) => c.enabled) }, null, 2);
const layoutJson = computed(() =>
JSON.stringify({ widgets: components.value.filter((c) => c.enabled) }, null, 2),
);
// 发布布局:将布局 JSON 暂存到 localStorage(与版本发布页联动——
// version.vue 发布时一并打包该布局),注册表服务落地后可改为注册到服务端。
const LAYOUT_STORAGE_KEY = 'iaop.studio.layout.v1';
const lastPublishedAt = ref('');
async function publishLayout() {
const payload = layoutJson.value;
try {
localStorage.setItem(LAYOUT_STORAGE_KEY, payload);
lastPublishedAt.value = new Date().toISOString().slice(0, 19).replace('T', ' ');
message.success('布局已发布(暂存本地,将在「版本发布」时一并打包)');
} catch {
message.error('布局发布失败:本地存储不可用');
}
}
</script>
<template>
@@ -41,8 +60,9 @@ const layoutJson = () => JSON.stringify({ widgets: components.value.filter((c) =
</a-list>
</a-card>
<a-card title="导出布局 JSON(由驾驶舱渲染)" :bordered="false" class="col">
<pre class="json-body">{{ layoutJson() }}</pre>
<VbenButton variant="solid"><MaterialSymbolsEdit class="size-4" />发布布局(版本发布见「版本发布」页)</VbenButton>
<pre class="json-body">{{ layoutJson }}</pre>
<a-tag v-if="lastPublishedAt" color="green">最近发布:{{ lastPublishedAt }}</a-tag>
<VbenButton variant="solid" @click="publishLayout"><MaterialSymbolsEdit class="size-4" />发布布局(版本发布见「版本发布」页)</VbenButton>
</a-card>
</div>
</Page>
@@ -52,14 +52,17 @@ const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
async function publish() {
const version = `v${Date.now() % 100000}`;
const name = 'iaop-template';
// 一并打包「驾驶舱布局编排」页发布的布局(issue #187:发布布局与版本发布联动)
const layoutJson = localStorage.getItem('iaop.studio.layout.v1') || '';
const description = layoutJson ? '手动发布(前端,含布局)' : '手动发布(前端)';
try {
// 发布 = 注册新版本到服务端注册表(staging)
await registerModel({ name, version, stage: 'staging', description: '手动发布(前端)' });
await registerModel({ name, version, stage: 'staging', description });
online.value = true;
rows.value.unshift({
version, stage: 'staging',
time: new Date().toISOString().slice(0, 16).replace('T', ' '),
author: 'admin', note: '已发布到服务端注册表',
author: 'admin', note: layoutJson ? '已发布到服务端注册表(含布局)' : '已发布到服务端注册表',
});
message.success(`已注册 ${name}@${version}(staging)`);
} catch {