<script lang="ts" setup>
|
import type { ActionItem, BasicColumn } from '@jnpf/ui/vxeTable';
|
|
import type { LocalTemplateForm } from './templateDetail';
|
|
import type { TemplateCatalogItem, TemplateCategoryTreeNode, TemplatePageQuery } from '#/api/x/eln/templates';
|
|
import { onMounted, ref } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicLeftTree } from '@jnpf/ui';
|
import { useDrawer } from '@jnpf/ui/drawer';
|
import { BasicForm, useForm } from '@jnpf/ui/form';
|
import { BasicVxeTable, TableAction, useVxeTable } from '@jnpf/ui/vxeTable';
|
|
import { getTemplateCategoryTree, getTemplateDirectory } from '#/api/x/eln/templates';
|
import GlobalFormModal from '#/components/GlobalFormModal/index.vue';
|
|
import VersionDrawer from './VersionDrawer.vue';
|
|
defineOptions({ name: 'ElnTemplateCatalog' });
|
|
const { createMessage } = useMessage();
|
const [registerVersionDrawer, { openDrawer: openVersionDrawer }] = useDrawer();
|
const localFormRef = ref<LocalTemplateForm>();
|
const templateCategoryTree = ref<TemplateCategoryTreeNode[]>([]);
|
const templateCategoryTreeLoading = ref(false);
|
const selectedTemplateCategoryId = ref('');
|
|
const columns: BasicColumn[] = [
|
{ dataIndex: 'mubanBianhao', minWidth: 150, title: '模板编号' },
|
{ dataIndex: 'jianyanXiangmuMingcheng', minWidth: 160, slots: { default: 'jianyanXiangmu' }, title: '检验项目' },
|
{ dataIndex: 'mubanFenleiMingcheng', minWidth: 140, slots: { default: 'mubanFenlei' }, title: '模板分类' },
|
{ dataIndex: 'shengxiaoMubanBanben', minWidth: 110, slots: { default: 'shengxiaoMubanBanben' }, title: '生效版本' },
|
{ dataIndex: 'bizStatus', slots: { default: 'bizStatus' }, title: '发布状态', width: 100 },
|
{ dataIndex: 'bizEnabled', slots: { default: 'bizEnabled' }, title: '启用状态', width: 100 },
|
{ dataIndex: 'shengxiaoRiqi', format: 'date|YYYY-MM-DD', title: '生效时间', width: 120 },
|
{ align: 'right', dataIndex: 'ziduanShu', slots: { default: 'ziduanShu' }, title: '字段数', width: 90 },
|
{ dataIndex: 'gengxinShijian', format: 'date|YYYY-MM-DD HH:mm:ss', title: '更新时间', width: 165 },
|
{ dataIndex: 'chuangjianShijian', format: 'date|YYYY-MM-DD HH:mm:ss', title: '创建时间', width: 165 },
|
];
|
|
const [registerSearchForm, { getFieldsValue, resetFields }] = useForm({
|
baseColProps: { lg: 8, md: 12, sm: 12, xl: 6, xs: 24 },
|
compact: true,
|
labelWidth: 76,
|
schemas: [
|
{
|
component: 'Input',
|
componentProps: { placeholder: '模板编号或检验项目', submitOnPressEnter: true },
|
field: 'keyword',
|
label: '关键字',
|
},
|
{
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
options: [
|
{ fullName: '草稿', id: 'DRAFT' },
|
{ fullName: '已发布', id: 'PUBLISHED' },
|
],
|
placeholder: '全部',
|
},
|
field: 'bizStatus',
|
label: '发布状态',
|
},
|
{
|
component: 'Select',
|
componentProps: {
|
allowClear: true,
|
options: [
|
{ fullName: '启用', id: 'enabled' },
|
{ fullName: '停用', id: 'disabled' },
|
],
|
placeholder: '全部',
|
},
|
field: 'bizEnabled',
|
label: '启用状态',
|
},
|
],
|
showActionButtonGroup: true,
|
showAdvancedButton: false,
|
});
|
|
const [registerTable, { reload }] = useVxeTable({
|
actionColumn: { dataIndex: 'action', fixed: 'right', title: '操作', width: 90 },
|
api: fetchTemplatePage,
|
beforeFetch: normalizeQuery,
|
columns,
|
pagination: {
|
pageSize: 20,
|
pageSizeOptions: ['20', '50', '100'],
|
showQuickJumper: true,
|
showSizeChanger: true,
|
showTotal: (total) => `共 ${total} 个模板`,
|
},
|
rowKey: 'mubanBianhao',
|
showIndexColumn: false,
|
});
|
|
function normalizeQuery(raw: Record<string, unknown>): TemplatePageQuery {
|
const query: Record<string, unknown> = { ...raw };
|
for (const key of ['keyword', 'mubanBianhao', 'mubanFenlei']) {
|
if (typeof query[key] === 'string') query[key] = query[key].trim();
|
if (!query[key]) delete query[key];
|
}
|
for (const key of ['bizEnabled', 'bizStatus']) {
|
if (!query[key]) delete query[key];
|
}
|
query.currentPage = Math.max(1, Number(query.currentPage) || 1);
|
query.pageSize = Math.max(1, Number(query.pageSize) || 20);
|
return query as unknown as TemplatePageQuery;
|
}
|
|
async function fetchTemplatePage(query: TemplatePageQuery) {
|
const response = await getTemplateDirectory(query);
|
return { data: response.data };
|
}
|
|
async function loadTemplateCategoryTree() {
|
templateCategoryTreeLoading.value = true;
|
try {
|
const response = await getTemplateCategoryTree();
|
templateCategoryTree.value = normalizeTemplateCategoryTree(response.data);
|
} catch (error) {
|
createMessage.error(formatRequestError(error));
|
} finally {
|
templateCategoryTreeLoading.value = false;
|
}
|
}
|
|
function normalizeTemplateCategoryTree(data: string | TemplateCategoryTreeNode[]) {
|
const tree = typeof data === 'string' ? JSON.parse(data) : data;
|
return Array.isArray(tree) ? (tree as TemplateCategoryTreeNode[]) : [];
|
}
|
|
function handleSearch() {
|
reload({ page: 1, searchInfo: withSelectedTemplateCategory(getFieldsValue()) });
|
}
|
|
function handleTemplateCategorySelect(id: string) {
|
selectedTemplateCategoryId.value = id;
|
reload({ page: 1, searchInfo: withSelectedTemplateCategory(getFieldsValue()) });
|
}
|
|
function handleTemplateCategoryReset() {
|
selectedTemplateCategoryId.value = '';
|
reload({ page: 1, searchInfo: getFieldsValue() });
|
}
|
|
function withSelectedTemplateCategory(searchInfo: Record<string, unknown>) {
|
return selectedTemplateCategoryId.value ? { ...searchInfo, mubanFenlei: selectedTemplateCategoryId.value } : searchInfo;
|
}
|
|
async function handleReset() {
|
await resetFields();
|
reload({ page: 1, searchInfo: withSelectedTemplateCategory({}) });
|
}
|
|
function getTableActions(row: TemplateCatalogItem): ActionItem[] {
|
return [{ label: '版本', onClick: () => openVersionDrawer(true, { mubanBianhao: row.mubanBianhao }) }];
|
}
|
|
function openCreateTemplate() {
|
void localFormRef.value?.open({
|
modelId: '854727805680747141',
|
onConfirm: () => reload(),
|
title: '新增电子记录模板',
|
});
|
}
|
|
function formatRequestError(error: unknown) {
|
return error instanceof Error && error.message ? error.message : '操作失败,请稍后重试';
|
}
|
|
onMounted(loadTemplateCategoryTree);
|
</script>
|
|
<template>
|
<div class="jnpf-content-wrapper">
|
<div class="jnpf-content-wrapper-left">
|
<BasicLeftTree
|
title="电子记录分类"
|
:field-names="{ children: 'children', key: 'f_id', title: 'fenlei_mingcheng' }"
|
:loading="templateCategoryTreeLoading"
|
:tree-data="templateCategoryTree"
|
show-reset
|
@reload="loadTemplateCategoryTree"
|
@reset="handleTemplateCategoryReset"
|
@select="handleTemplateCategorySelect" />
|
</div>
|
<div class="jnpf-content-wrapper-center">
|
<div class="jnpf-content-wrapper-search-box">
|
<BasicForm @register="registerSearchForm" @reset="handleReset" @submit="handleSearch" />
|
</div>
|
<div class="jnpf-content-wrapper-content">
|
<BasicVxeTable @register="registerTable">
|
<template #tableTitle>
|
<a-button type="primary" pre-icon="icon-ym icon-ym-btn-add" @click="openCreateTemplate">新增模板</a-button>
|
</template>
|
<template #bizStatus="{ record }">
|
<a-tag v-if="record.bizStatus" :color="record.bizStatus === 'PUBLISHED' ? 'success' : 'processing'">
|
{{ record.bizStatus === 'PUBLISHED' ? '已发布' : '草稿' }}
|
</a-tag>
|
<span v-else>-</span>
|
</template>
|
<template #bizEnabled="{ record }">
|
<a-tag v-if="record.bizEnabled" :color="record.bizEnabled === 'enabled' ? 'success' : 'default'">
|
{{ record.bizEnabled === 'enabled' ? '启用' : '停用' }}
|
</a-tag>
|
<span v-else>-</span>
|
</template>
|
<template #jianyanXiangmu="{ record }">
|
{{ record.jianyanXiangmuMingcheng || record.jianyanXiangmu || '-' }}
|
</template>
|
<template #mubanFenlei="{ record }">
|
{{ record.mubanFenleiMingcheng || record.mubanFenlei || '-' }}
|
</template>
|
<template #shengxiaoMubanBanben="{ record }">{{ record.shengxiaoMubanBanben || '未生效' }}</template>
|
<template #ziduanShu="{ record }">{{ record.ziduanShu == null ? '-' : record.ziduanShu }}</template>
|
<template #action="{ record }"><TableAction :actions="getTableActions(record)" /></template>
|
</BasicVxeTable>
|
</div>
|
</div>
|
|
<GlobalFormModal ref="localFormRef" :listen-global="false" />
|
|
<VersionDrawer @register="registerVersionDrawer" @reload="reload" />
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
:deep(.jnpf-vxe-table) {
|
min-width: 0;
|
}
|
</style>
|