Trim frontend build for lightweight AI agent admin

This commit is contained in:
Codex
2026-06-08 19:48:47 +08:00
parent e164840f43
commit 2e7099cb6d
15 changed files with 1336 additions and 270 deletions
@@ -1,16 +1,29 @@
<script lang="ts" setup>
import type { WorkflowRunListItem } from '#/api/ai-platform/ai-platform';
import { ref } from 'vue';
import { computed, onMounted, ref } from 'vue';
import { Page } from '@vben/common-ui';
import { Eye } from '@vben/icons';
import { Eye, RefreshCw, Search } from '@vben/icons';
import { $t } from '@vben/locales';
import { ElButton, ElTag } from 'element-plus';
import {
ElButton,
ElCard,
ElForm,
ElFormItem,
ElOption,
ElPagination,
ElSelect,
ElTable,
ElTableColumn,
ElTag,
} from 'element-plus';
import { getAllWorkflowRunsApi } from '#/api/ai-platform/ai-platform';
import { useZqTable } from '#/components/zq-table';
import {
getAllWorkflowRunsApi,
getWorkflowListApi,
} from '#/api/ai-platform/ai-platform';
import RunStatusTag from './components/RunStatusTag.vue';
import {
@@ -18,97 +31,245 @@ import {
formatTime,
getTagLabel,
getTagType,
getStatusOptions,
getTriggerOptions,
useSearchFormSchema,
useZqTableColumns,
} from './data';
import DetailDialog from './modules/detail-dialog.vue';
defineOptions({ name: 'WorkflowRunHistory' });
const detailRef = ref<InstanceType<typeof DetailDialog>>();
const triggerOptions = getTriggerOptions();
const fetchRunList = async (params: any) => {
const res = await getAllWorkflowRunsApi({
page: params.page.currentPage,
pageSize: params.page.pageSize,
workflowId: params.form?.workflowId || undefined,
status: params.form?.status || undefined,
triggerType: params.form?.triggerType || undefined,
});
return {
items: res.items,
total: res.total,
};
};
const [Grid] = useZqTable({
gridOptions: {
columns: useZqTableColumns(),
border: true,
stripe: true,
showIndex: true,
proxyConfig: {
autoLoad: true,
ajax: {
query: fetchRunList,
},
},
pagerConfig: {
enabled: true,
pageSize: 20,
},
toolbarConfig: {
search: true,
refresh: true,
zoom: true,
custom: true,
},
},
formOptions: {
schema: useSearchFormSchema(),
showCollapseButton: true,
submitOnChange: true,
},
const loading = ref(false);
const rows = ref<WorkflowRunListItem[]>([]);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(20);
const workflowOptions = ref<Array<{ label: string; value: string }>>([]);
const filters = ref({
workflowId: '',
status: '',
triggerType: '',
});
const statusOptions = getStatusOptions();
const triggerOptions = getTriggerOptions();
const rowIndex = computed(() => (currentPage.value - 1) * pageSize.value);
async function loadWorkflowOptions() {
const res = await getWorkflowListApi({ page: 1, pageSize: 200 });
workflowOptions.value = (res.items || []).map((item) => ({
label: item.name,
value: item.id,
}));
}
async function loadRuns() {
loading.value = true;
try {
const res = await getAllWorkflowRunsApi({
page: currentPage.value,
pageSize: pageSize.value,
workflowId: filters.value.workflowId || undefined,
status: filters.value.status || undefined,
triggerType: filters.value.triggerType || undefined,
});
rows.value = res.items || [];
total.value = res.total || 0;
} finally {
loading.value = false;
}
}
function handleSearch() {
currentPage.value = 1;
loadRuns();
}
function handleSizeChange(size: number) {
pageSize.value = size;
currentPage.value = 1;
loadRuns();
}
function handlePageChange(page: number) {
currentPage.value = page;
loadRuns();
}
function openDetail(row: WorkflowRunListItem) {
detailRef.value?.open(row.id);
}
onMounted(() => {
loadWorkflowOptions();
loadRuns();
});
</script>
<template>
<Page auto-content-height>
<DetailDialog ref="detailRef" />
<Grid>
<template #cell-status="{ row }">
<RunStatusTag :status="row.status" />
</template>
<ElCard shadow="never" class="h-full">
<ElForm :model="filters" inline class="mb-3">
<ElFormItem :label="$t('ai-platform.workflowRuns.filters.workflow')">
<ElSelect
v-model="filters.workflowId"
clearable
filterable
style="width: 220px"
:placeholder="$t('ai-platform.workflowRuns.filters.allWorkflows')"
>
<ElOption
v-for="item in workflowOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem :label="$t('ai-platform.workflowRuns.filters.status')">
<ElSelect
v-model="filters.status"
clearable
style="width: 150px"
:placeholder="$t('ai-platform.workflowRuns.filters.allStatus')"
>
<ElOption
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem :label="$t('ai-platform.workflowRuns.filters.trigger')">
<ElSelect
v-model="filters.triggerType"
clearable
style="width: 160px"
:placeholder="$t('ai-platform.workflowRuns.filters.allTriggers')"
>
<ElOption
v-for="item in triggerOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" :icon="Search" @click="handleSearch">
{{ $t('common.search') }}
</ElButton>
<ElButton :icon="RefreshCw" @click="loadRuns">
{{ $t('common.refresh') }}
</ElButton>
</ElFormItem>
</ElForm>
<template #cell-trigger_type="{ row }">
<ElTag
:type="getTagType(row.trigger_type, triggerOptions)"
size="small"
<ElTable
v-loading="loading"
:data="rows"
border
stripe
height="calc(100vh - 285px)"
>
<ElTableColumn type="index" width="60" :index="rowIndex + 1" />
<ElTableColumn
prop="workflow_name"
:label="$t('ai-platform.workflowRuns.columns.workflow')"
min-width="160"
show-overflow-tooltip
/>
<ElTableColumn
:label="$t('ai-platform.workflowRuns.columns.status')"
width="110"
align="center"
>
{{ getTagLabel(row.trigger_type, triggerOptions) }}
</ElTag>
</template>
<template #default="{ row }">
<RunStatusTag :status="row.status" />
</template>
</ElTableColumn>
<ElTableColumn
:label="$t('ai-platform.workflowRuns.columns.trigger')"
width="140"
align="center"
>
<template #default="{ row }">
<ElTag
:type="getTagType(row.trigger_type, triggerOptions)"
size="small"
>
{{ getTagLabel(row.trigger_type, triggerOptions) }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn
prop="total_steps"
:label="$t('ai-platform.workflowRuns.columns.steps')"
width="80"
align="center"
/>
<ElTableColumn
prop="total_tokens"
:label="$t('ai-platform.workflowRuns.columns.tokens')"
width="90"
align="center"
/>
<ElTableColumn
:label="$t('ai-platform.workflowRuns.columns.duration')"
width="100"
align="center"
>
<template #default="{ row }">
{{ formatDuration(row.elapsed_time) }}
</template>
</ElTableColumn>
<ElTableColumn
:label="$t('ai-platform.workflowRuns.columns.startedAt')"
width="180"
>
<template #default="{ row }">
{{ formatTime(row.started_at) }}
</template>
</ElTableColumn>
<ElTableColumn
prop="error_message"
:label="$t('ai-platform.workflowRuns.columns.error')"
min-width="180"
show-overflow-tooltip
/>
<ElTableColumn
:label="$t('ai-platform.workflowRuns.columns.actions')"
width="120"
fixed="right"
align="center"
>
<template #default="{ row }">
<ElButton
link
type="primary"
:icon="Eye"
@click.stop="openDetail(row)"
>
{{ $t('common.view') }}
</ElButton>
</template>
</ElTableColumn>
</ElTable>
<template #cell-elapsed_time="{ row }">
{{ formatDuration(row.elapsed_time) }}
</template>
<template #cell-started_at="{ row }">
{{ formatTime(row.started_at) }}
</template>
<template #cell-actions="{ row }">
<ElButton link type="primary" :icon="Eye" @click.stop="openDetail(row)">
{{ $t('common.view') }}
</ElButton>
</template>
</Grid>
<div class="mt-4 flex justify-end">
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
background
layout="total, sizes, prev, pager, next, jumper"
:page-sizes="[10, 20, 50, 100]"
:total="total"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</div>
</ElCard>
</Page>
</template>