feat: enhance code generation page with preview functionality

pull/53/head
chenminjie 2024-11-29 02:35:18 +08:00
parent 462b434973
commit 8197f4dfc3
4 changed files with 240 additions and 10 deletions

View File

@ -280,7 +280,7 @@ export function syncCodegenFromDB(id: number) {
}
// 预览生成代码
export function previewCodegen(id: number) {
export function getPreviewCodegen(id: number) {
return requestClient.get(`/infra/codegen/preview?tableId=${id}`);
}

View File

@ -13,10 +13,12 @@ export namespace CodegenDefaultData {
export const tableColumns: VxeGridProps<CodegenApi.CodegenTableRespVO>['columns'] =
[
{
fixed: 'left',
type: 'checkbox',
width: 50,
},
{
fixed: 'left',
type: 'seq',
width: 50,
},

View File

@ -0,0 +1,206 @@
<script lang="ts" setup>
import type { CodegenApi } from '#/api/infra/codegen';
import { computed, onMounted, reactive, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Card, Tree, type TreeProps } from 'ant-design-vue';
import hljs from 'highlight.js'; //
import java from 'highlight.js/lib/languages/java';
import javascript from 'highlight.js/lib/languages/javascript';
import sql from 'highlight.js/lib/languages/sql';
import typescript from 'highlight.js/lib/languages/typescript';
import xml from 'highlight.js/lib/languages/xml';
import { getPreviewCodegen } from '#/api/infra/codegen';
import 'highlight.js/styles/github.css'; //
defineOptions({ name: 'PreviewCodeModal' });
const fileTreeLoading = ref(false);
const fileTreeRef = ref();
const tabList = ref([]);
//
const previewData = reactive({
fileTree: [] as any[], //
activeName: '', //
});
//
const treeSelectedKeys = ref<string[]>();
//
const expandedKeys = ref<string[]>();
//
const previewCodegenDataList = ref<CodegenApi.CodegenPreviewRespVO[]>();
/**
* 将路径转换为树形结构
* @param data 路径数据
* @returns 树形结构
*/
const convertPathToTreeData = (
data: CodegenApi.CodegenPreviewRespVO[],
): TreeProps['treeData'] => {
const filePaths = data.map((item) => item.filePath);
const treeData: TreeProps['treeData'] = [];
filePaths.forEach((path) => {
//
const parts = path.split('/');
let currentNode = treeData;
parts.forEach((part, index) => {
//
let node = currentNode.find((n) => n.title === part);
//
const isLastLevel = index === parts.length - 1;
if (!node) {
//
node = {
title: part,
key: parts.slice(0, index + 1).join('/'),
selectable: isLastLevel,
expandable: !isLastLevel,
children: [],
};
currentNode.push(node);
}
//
currentNode = node.children!;
});
});
return treeData;
};
/**
* 将文件路径转换为文件名
* @param path 文件路径
* @returns 文件名
*/
const convertPathToFileName = (path: string) => {
return path.split('/').pop()!;
};
/**
* 切换文件
*/
const handleChangeFile = (key: any) => {
previewData.activeName = key;
treeSelectedKeys.value = [key];
fileTreeRef.value?.scrollTo(key);
};
/**
* tree 节点点击事件
*/
const handleTreeSelect = (keys: any) => {
handleChangeFile(keys[0]);
};
/**
* 代码高亮
*/
const highlightedCode = (item: CodegenApi.CodegenPreviewRespVO) => {
const language = item.filePath.slice(item.filePath.lastIndexOf('.') + 1);
const result = hljs.highlight(item.code, { language, ignoreIllegals: true });
return result.value || '&nbsp;';
};
const [Modal, modalApi] = useVbenModal({
title: '预览代码',
class: 'w-[90%] h-[90%]',
closeOnClickModal: false,
closeOnPressEscape: false,
showCancelButton: false,
showConfirmButton: false,
onOpenChange: async (isOpen) => {
if (isOpen) {
const sharedData = modalApi.getData();
fileTreeLoading.value = true;
const res = await getPreviewCodegen(sharedData.id);
previewCodegenDataList.value = res;
// tab
tabList.value = res.map((item: CodegenApi.CodegenPreviewRespVO) => ({
key: item.filePath,
tab: convertPathToFileName(item.filePath),
}));
//
const treeData = convertPathToTreeData(res);
previewData.fileTree = treeData ?? [];
fileTreeLoading.value = false;
//
handleChangeFile(res[0].filePath);
}
},
});
/**
* 获取预览代码
*/
const getPreviewCode = computed(() => {
if (!previewData.activeName || !previewCodegenDataList.value) {
return '&nbsp;';
}
const item = previewCodegenDataList.value?.find(
(item) => item.filePath === previewData.activeName,
) as CodegenApi.CodegenPreviewRespVO;
return highlightedCode(item) || '&nbsp;';
});
//
onMounted(() => {
//
hljs.registerLanguage('java', java);
hljs.registerLanguage('xml', xml);
hljs.registerLanguage('html', xml);
hljs.registerLanguage('vue', xml);
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('sql', sql);
hljs.registerLanguage('typescript', typescript);
});
</script>
<template>
<Modal>
<div class="flex h-full gap-4 overflow-hidden">
<Card
:body-style="{ height: 'inherit', padding: '1px 16px' }"
:loading="fileTreeLoading"
class="h-full w-5/12"
title="文件目录"
>
<div class="h-[calc(100%-58px)] w-full overflow-auto">
<Tree
v-model:expanded-keys="expandedKeys"
v-model:selected-keys="treeSelectedKeys"
:tree-data="previewData.fileTree"
default-expand-all
show-line
@select="handleTreeSelect"
/>
</div>
</Card>
<Card
v-model:active-tab-key="previewData.activeName"
:body-style="{ height: 'inherit', padding: '1px 16px' }"
:tab-list="tabList"
class="h-full w-7/12"
title="代码预览"
@tab-change="handleChangeFile"
>
<div class="h-[calc(100%-58px)] w-full overflow-auto">
<pre>
<code v-dompurify-html="getPreviewCode"></code>
</pre>
</div>
</Card>
</div>
</Modal>
</template>

View File

@ -16,13 +16,6 @@ import { CodegenDefaultData } from './codegen.data';
// checked
const checkedStatus = ref<boolean>(false);
/**
* 查看详情
*/
const handleView = (_row: CodegenApi.CodegenTableRespVO) => {
// console.log('', row);
};
/**
* 编辑
*/
@ -96,7 +89,13 @@ const gridOptions = reactive<any>({
height: 'auto',
checkboxConfig: {
reserve: true,
highlight: true,
// labelField: 'id',
},
rowConfig: {
keyField: 'id',
},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, params) => {
@ -138,6 +137,28 @@ const [ImportTableModal, importTableModalApi] = useVbenModal({
gridApi.reload(formOptions.values);
},
});
// 使
const [PreviewCodeModal, previewCodeModalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(
() => import('./components/preview-code-modal.vue'),
),
});
/**
* 打开导入表弹窗
*/
const handleOpenImportTableModal = () => {
importTableModalApi.open();
};
/**
* 打开预览代码弹窗
*/
const handleOpenPreviewCodeModal = (row: CodegenApi.CodegenTableRespVO) => {
previewCodeModalApi.setData(row);
previewCodeModalApi.open();
};
</script>
<template>
@ -150,7 +171,7 @@ const [ImportTableModal, importTableModalApi] = useVbenModal({
type: 'primary',
label: '导入表',
icon: IconEnum.ADD,
onClick: () => importTableModalApi.open(),
onClick: handleOpenImportTableModal,
},
{
label: '批量同步',
@ -187,7 +208,7 @@ const [ImportTableModal, importTableModalApi] = useVbenModal({
type: 'link',
label: '查看',
icon: 'ant-design:eye-outlined',
onClick: handleView.bind(null, row),
onClick: handleOpenPreviewCodeModal.bind(null, row),
},
{
type: 'link',
@ -219,5 +240,6 @@ const [ImportTableModal, importTableModalApi] = useVbenModal({
</template>
</Grid>
<ImportTableModal />
<PreviewCodeModal />
</Page>
</template>