bot_dev1 复核通过(与 bot_qa 审核结论一致);rebase 到最新 main 解决 version.vue 冲突后合并。 fixes #187
This commit is contained in:
@@ -4,6 +4,7 @@ import { ref } from 'vue';
|
|||||||
import { Page, VbenButton } from '@vben/common-ui';
|
import { Page, VbenButton } from '@vben/common-ui';
|
||||||
import { BxsFile } from '@vben/icons';
|
import { BxsFile } from '@vben/icons';
|
||||||
|
|
||||||
|
import type { UploadChangeParam } from 'antdv-next';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import { useVbenVxeGrid } 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 });
|
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||||
|
|
||||||
function onFile(e: Event) {
|
function onFile(info: UploadChangeParam) {
|
||||||
const el = e.target as HTMLInputElement;
|
// a-upload 的 @change 载荷是 UploadChangeParam { file, fileList },
|
||||||
const file = el.files?.[0];
|
// 在 :before-upload="() => false"(禁止自动上传)时文件对象在 file.originFileObj 上,
|
||||||
if (!file) return;
|
// 不是 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;
|
fileName.value = file.name;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => parseCsv(String(reader.result || ''));
|
reader.onload = () => parseCsv(String(reader.result || ''));
|
||||||
reader.readAsText(file);
|
reader.readAsText(raw as Blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCsv(text: string) {
|
function parseCsv(text: string) {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import { Page, VbenButton } from '@vben/common-ui';
|
import { Page, VbenButton } from '@vben/common-ui';
|
||||||
import { MaterialSymbolsEdit } from '@vben/icons';
|
import { MaterialSymbolsEdit } from '@vben/icons';
|
||||||
|
import { message } from 'antdv-next';
|
||||||
|
|
||||||
const components = ref([
|
const components = ref([
|
||||||
{ type: 'process_view', title: '四状态工艺流程', enabled: true },
|
{ type: 'process_view', title: '四状态工艺流程', enabled: true },
|
||||||
@@ -24,7 +25,25 @@ const move = (i: number, dir: number) => {
|
|||||||
components.value[j] = t;
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -41,8 +60,9 @@ const layoutJson = () => JSON.stringify({ widgets: components.value.filter((c) =
|
|||||||
</a-list>
|
</a-list>
|
||||||
</a-card>
|
</a-card>
|
||||||
<a-card title="导出布局 JSON(由驾驶舱渲染)" :bordered="false" class="col">
|
<a-card title="导出布局 JSON(由驾驶舱渲染)" :bordered="false" class="col">
|
||||||
<pre class="json-body">{{ layoutJson() }}</pre>
|
<pre class="json-body">{{ layoutJson }}</pre>
|
||||||
<VbenButton variant="solid"><MaterialSymbolsEdit class="size-4" />发布布局(版本发布见「版本发布」页)</VbenButton>
|
<a-tag v-if="lastPublishedAt" color="green">最近发布:{{ lastPublishedAt }}</a-tag>
|
||||||
|
<VbenButton variant="solid" @click="publishLayout"><MaterialSymbolsEdit class="size-4" />发布布局(版本发布见「版本发布」页)</VbenButton>
|
||||||
</a-card>
|
</a-card>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -51,13 +51,17 @@ onMounted(async () => {
|
|||||||
async function publish() {
|
async function publish() {
|
||||||
const version = `v${Date.now() % 100000}`;
|
const version = `v${Date.now() % 100000}`;
|
||||||
const name = 'iaop-template';
|
const name = 'iaop-template';
|
||||||
|
// 一并打包「驾驶舱布局编排」页发布的布局(issue #187:发布布局与版本发布联动)
|
||||||
|
const layoutJson = localStorage.getItem('iaop.studio.layout.v1') || '';
|
||||||
|
const description = layoutJson ? '手动发布(前端,含布局)' : '手动发布(前端)';
|
||||||
try {
|
try {
|
||||||
await registerModel({ name, version, stage: 'staging', description: '手动发布(前端)' });
|
// 发布 = 注册新版本到服务端注册表(staging);description 含布局标记(issue #187 联动)
|
||||||
|
await registerModel({ name, version, stage: 'staging', description });
|
||||||
online.value = true;
|
online.value = true;
|
||||||
rows.value.unshift({
|
rows.value.unshift({
|
||||||
version, stage: 'staging',
|
version, stage: 'staging',
|
||||||
time: new Date().toISOString().slice(0, 16).replace('T', ' '),
|
time: new Date().toISOString().slice(0, 16).replace('T', ' '),
|
||||||
author: 'admin', note: '已发布到服务端注册表',
|
author: 'admin', note: layoutJson ? '已发布到服务端注册表(含布局)' : '已发布到服务端注册表',
|
||||||
});
|
});
|
||||||
message.success(`已注册 ${name}@${version}(staging)`);
|
message.success(`已注册 ${name}@${version}(staging)`);
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user