fix: models 页改 antd a-table(响应式 :data-source,规避 vben Grid proxy 异步时序导致 0 条)
This commit is contained in:
@@ -2,16 +2,15 @@
|
|||||||
/**
|
/**
|
||||||
* 模型管理(issue #183 [E2] 前端接入注册表 API)
|
* 模型管理(issue #183 [E2] 前端接入注册表 API)
|
||||||
* - 数据源:服务端注册表 API(list/promote/rollback 全走服务端,多用户共享);
|
* - 数据源:服务端注册表 API(list/promote/rollback 全走服务端,多用户共享);
|
||||||
* - 降级:API 不可达时回退 localStorage(iaop.admin.models.v1,旧版 key),UI 标注「离线演示模式」;
|
* - 降级:API 不可达时回退 localStorage(iaop.admin.models.v1),UI 标注「离线演示模式」;
|
||||||
* - 迁移:检测 localStorage 有数据且服务端在线时提示导入。
|
* - 迁移:检测 localStorage 有数据且服务端在线时提示导入。
|
||||||
|
* - 表格:antd a-table(响应式 :data-source 直绑,规避 vxe-grid proxy 异步时序问题)。
|
||||||
*/
|
*/
|
||||||
import { onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { Page, VbenButton } from '@vben/common-ui';
|
import { Page, VbenButton } from '@vben/common-ui';
|
||||||
import { message } from 'antdv-next';
|
import { message } from 'antdv-next';
|
||||||
|
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
|
||||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
||||||
import {
|
import {
|
||||||
fetchRegistryModels,
|
fetchRegistryModels,
|
||||||
promoteModel,
|
promoteModel,
|
||||||
@@ -45,36 +44,25 @@ function saveLocal(list: LocalModel[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const online = ref(false); // 注册表服务在线?
|
const online = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const models = ref<RegistryModel[]>([]);
|
const models = ref<RegistryModel[]>([]);
|
||||||
const migrateVisible = ref(false);
|
const migrateVisible = ref(false);
|
||||||
|
|
||||||
const gridOptions: VxeTableGridOptions = {
|
const columns = [
|
||||||
rowConfig: { keyField: 'name' },
|
{ title: '模型', dataIndex: 'name', key: 'name', width: 200 },
|
||||||
height: 'auto',
|
{ title: '版本', dataIndex: 'version', key: 'version', width: 120 },
|
||||||
stripe: true,
|
{ title: '阶段', dataIndex: 'stage', key: 'stage', width: 110 },
|
||||||
columns: [
|
{ title: '说明', dataIndex: 'description', key: 'description' },
|
||||||
{ title: '模型', field: 'name', minWidth: 180 },
|
{ title: '操作', key: 'action', width: 180 },
|
||||||
{ title: '版本', field: 'version', width: 120 },
|
];
|
||||||
{ title: '阶段', field: 'stage', width: 110, slots: { default: 'stage' } },
|
|
||||||
{ title: '说明', field: 'description', minWidth: 220 },
|
|
||||||
{ title: '操作', field: 'action', width: 170, slots: { default: 'action' } },
|
|
||||||
],
|
|
||||||
// 数据直接绑定 :data(响应式自动渲染,规避 proxy 分页就绪时序)
|
|
||||||
data: models,
|
|
||||||
};
|
|
||||||
|
|
||||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
const tagColor = (stage: string) =>
|
||||||
|
stage === 'prod' ? 'green' : stage === 'staging' ? 'orange' : 'blue';
|
||||||
|
|
||||||
async function refresh() {
|
|
||||||
// :data 响应式绑定,数据变化自动渲染
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadFromServer() {
|
async function loadFromServer() {
|
||||||
const resp = await fetchRegistryModels();
|
const resp = await fetchRegistryModels();
|
||||||
models.value = resp.models;
|
models.value = resp.models || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
@@ -82,8 +70,7 @@ async function init() {
|
|||||||
try {
|
try {
|
||||||
await loadFromServer();
|
await loadFromServer();
|
||||||
online.value = true;
|
online.value = true;
|
||||||
refresh();
|
// 迁移提示:本地有服务端没有的模型
|
||||||
// 迁移提示:本地有数据且服务端在线(且本地有服务端没有的模型)
|
|
||||||
const local = loadLocal();
|
const local = loadLocal();
|
||||||
const serverNames = new Set(models.value.map((m) => `${m.name}@${m.version}`));
|
const serverNames = new Set(models.value.map((m) => `${m.name}@${m.version}`));
|
||||||
const localExtra = local.filter((m) => !serverNames.has(`${m.name}@${m.version}`));
|
const localExtra = local.filter((m) => !serverNames.has(`${m.name}@${m.version}`));
|
||||||
@@ -99,7 +86,6 @@ async function init() {
|
|||||||
}));
|
}));
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,17 +94,14 @@ async function promote(m: RegistryModel) {
|
|||||||
try {
|
try {
|
||||||
await promoteModel(m.name, m.version);
|
await promoteModel(m.name, m.version);
|
||||||
await loadFromServer();
|
await loadFromServer();
|
||||||
refresh();
|
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message.error(`提升失败:${(e as Error).message}`);
|
message.error(`提升失败:${(e as Error).message}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 离线降级
|
|
||||||
m.stage = m.stage === 'staging' ? 'prod' : m.stage === 'dev' ? 'staging' : m.stage;
|
m.stage = m.stage === 'staging' ? 'prod' : m.stage === 'dev' ? 'staging' : m.stage;
|
||||||
saveLocal(models.value.map((x) => ({ name: x.name, version: x.version, stage: x.stage, desc: x.description })));
|
saveLocal(models.value.map((x) => ({ name: x.name, version: x.version, stage: x.stage, desc: x.description })));
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rollback(m: RegistryModel) {
|
async function rollback(m: RegistryModel) {
|
||||||
@@ -126,7 +109,6 @@ async function rollback(m: RegistryModel) {
|
|||||||
try {
|
try {
|
||||||
await rollbackModel(m.name, 'prod', m.version);
|
await rollbackModel(m.name, 'prod', m.version);
|
||||||
await loadFromServer();
|
await loadFromServer();
|
||||||
refresh();
|
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message.error(`回滚失败:${(e as Error).message}`);
|
message.error(`回滚失败:${(e as Error).message}`);
|
||||||
@@ -135,7 +117,6 @@ async function rollback(m: RegistryModel) {
|
|||||||
}
|
}
|
||||||
m.stage = 'staging';
|
m.stage = 'staging';
|
||||||
saveLocal(models.value.map((x) => ({ name: x.name, version: x.version, stage: x.stage, desc: x.description })));
|
saveLocal(models.value.map((x) => ({ name: x.name, version: x.version, stage: x.stage, desc: x.description })));
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function migrateLocal() {
|
async function migrateLocal() {
|
||||||
@@ -151,7 +132,6 @@ async function migrateLocal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await loadFromServer();
|
await loadFromServer();
|
||||||
refresh();
|
|
||||||
migrateVisible.value = false;
|
migrateVisible.value = false;
|
||||||
if (fail === 0) {
|
if (fail === 0) {
|
||||||
localStorage.removeItem(MODELS_KEY);
|
localStorage.removeItem(MODELS_KEY);
|
||||||
@@ -161,9 +141,6 @@ async function migrateLocal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagColor = (stage: string) =>
|
|
||||||
stage === 'prod' ? 'green' : stage === 'staging' ? 'orange' : 'blue';
|
|
||||||
|
|
||||||
onMounted(init);
|
onMounted(init);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -173,15 +150,17 @@ onMounted(init);
|
|||||||
<a-tag :color="online ? 'green' : 'orange'">{{ online ? '● 服务端在线' : '● 离线演示模式' }}</a-tag>
|
<a-tag :color="online ? 'green' : 'orange'">{{ online ? '● 服务端在线' : '● 离线演示模式' }}</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
<Grid :data="models">
|
<a-table :data-source="models" :columns="columns" row-key="name" size="small" :pagination="{ pageSize: 10 }">
|
||||||
<template #stage="{ row }">
|
<template #bodyCell="{ column, record }">
|
||||||
<a-tag :color="tagColor(row.stage)">{{ row.stage }}</a-tag>
|
<template v-if="column.key === 'stage'">
|
||||||
|
<a-tag :color="tagColor(record.stage)">{{ record.stage }}</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<VbenButton size="small" :disabled="record.stage === 'prod'" @click="promote(record)">提升</VbenButton>
|
||||||
|
<VbenButton size="small" variant="outline" :disabled="record.stage !== 'prod'" @click="rollback(record)">回滚</VbenButton>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #action="{ row }">
|
</a-table>
|
||||||
<VbenButton size="small" :disabled="row.stage === 'prod'" @click="promote(row)">提升</VbenButton>
|
|
||||||
<VbenButton size="small" variant="outline" :disabled="row.stage !== 'prod'" @click="rollback(row)">回滚</VbenButton>
|
|
||||||
</template>
|
|
||||||
</Grid>
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
<a-modal v-model:open="migrateVisible" title="本地模型导入注册表"
|
<a-modal v-model:open="migrateVisible" title="本地模型导入注册表"
|
||||||
:on-ok="migrateLocal" ok-text="导入服务端" cancel-text="暂不">
|
:on-ok="migrateLocal" ok-text="导入服务端" cancel-text="暂不">
|
||||||
|
|||||||
Reference in New Issue
Block a user