Compare commits

...

8 Commits

Author SHA1 Message Date
bunny 32e84f5433 feat: 更新表单内容 2025-04-15 20:26:48 +08:00
bunny 782f709bd1 🎉 ci: 推送脚本更新 2025-04-11 22:08:48 +08:00
bunny 06d199f701 feat: 生成提交表单持久化 2025-04-10 23:31:35 +08:00
bunny c6b961bc40 feat: 使用zip打包下载生成内容 2025-04-09 22:21:36 +08:00
bunny 3589c1dad2 perf: 优化代码 2025-04-09 21:25:23 +08:00
bunny 0451fc89f6 🎉 feat: push脚本 2025-04-06 19:16:35 +08:00
bunny 5eddcf947d docs: 添加文档 2025-04-06 14:25:02 +08:00
bunny cba2f545dd perf: 格式化代码 2025-04-06 14:00:32 +08:00
30 changed files with 326 additions and 139 deletions

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# 代码生成器
## 功能展示
点击 表名 或 注释内容 跳转到另一个页面
![屏幕截图_6-4-2025_1486_localhost](./images/屏幕截图_6-4-2025_1486_localhost.jpeg)
![image-20250406140934864](./images/image-20250406140934864.png)
![屏幕截图_6-4-2025_1486_localhost](./images/屏幕截图_6-4-2025_1486_localhost-1743920303637-1.jpeg)
<video src="./images/QQ202546-141117.mp4"></video>

View File

@ -1,7 +1,5 @@
import type {AcceptedPlugin} from 'postcss';
import type { CSSOptions } from 'vite';
import {wrapperEnv} from './utils';
export const css = (mode: string): CSSOptions => {
return {
@ -12,5 +10,3 @@ export const css = (mode: string): CSSOptions => {
},
};
};

View File

@ -11,4 +11,4 @@ const include = ['vue', 'vue-router', 'dayjs', 'axios', 'pinia', 'vue-types', 'j
*/
const exclude: string[] = [];
export { include, exclude };
export { exclude, include };

View File

@ -9,7 +9,7 @@ import Inspector from 'vite-plugin-vue-inspector';
import { useCDN } from './cdn';
import { viteConsoleLog } from './info';
import { compressPack, report, wrapperEnv } from './utils';
import { compressPack, report } from './utils';
export const plugins = (mode: string): PluginOption[] => {
return [
@ -43,4 +43,3 @@ export const plugins = (mode: string): PluginOption[] => {
compressPack(mode),
];
};

BIN
images/QQ202546-141117.mp4 Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link href="/favicon.ico" rel="icon" type="image/svg+xml"/>
<link href="/favicon.png" rel="icon" type="image/svg+xml"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>%VITE_APP_TITLE%</title>
</head>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

8
push.sh Normal file
View File

@ -0,0 +1,8 @@
git init
git add .
git commit -m "🎉 ci: 推送脚本更新"
git checkout master
git merge dev
git push --all
git push --tags
git checkout dev

View File

@ -43,22 +43,18 @@ service.interceptors.response.use(
return response.data;
}
// ElMessage.error(msg || '系统出错');
// 系统出错
return Promise.reject(response.data.message || 'Error');
},
(error: any) => {
// 异常处理
if (error.response.data) {
// const { code, msg } = error.response.data;
// if (code === ResultEnum.TOKEN_INVALID) {
// ElNotification({
// title: '提示',
// message: '您的会话已过期,请重新登录',
// type: 'info',
// });
// } else {
// ElMessage.error(msg || '系统出错');
// }
const { code, message } = error.response.data;
if (code === 500) {
(window as any).$message.error(message);
} else {
(window as any).$message.error(message || '系统出错');
}
}
return Promise.reject(error.message);
}

View File

@ -1,9 +1,14 @@
import request from '@/api/server/request';
import type { BaseResult } from '@/types/request';
/* 获取所有数据表 */
export const getAllTableMetaData = () => {
return request<any, BaseResult<any>>({ url: '/table/getAllTableMetaData', method: 'get' });
/* 所有的数据库 */
export const getDbList = () => {
return request<any, any>({ url: '/table/getDbList', method: 'GET' });
};
/* 数据库所有的表 */
export const getDbTables = (params: any) => {
return request<any, BaseResult<any>>({ url: '/table/getDbTables', method: 'get', params });
};
/* 获取表属性 */

View File

@ -10,3 +10,13 @@ export const generator = (data: any) => {
export const getVmsPathList = () => {
return request<any, BaseResult<any>>({ url: '/vms/getVmsPathList', method: 'get' });
};
/* 打包成zip下载 */
export const downloadByZip = (data: any) => {
return request<any, any>({
url: '/vms/downloadByZip',
method: 'POST',
data,
responseType: 'blob',
});
};

View File

@ -1,9 +1,11 @@
import { createPinia } from 'pinia';
import piniaPluginPersistedState from 'pinia-plugin-persistedstate';
import type { App } from 'vue';
const store = createPinia();
const pinia = createPinia();
// 全局注册 store
export function setupStore(app: App<Element>) {
app.use(store);
pinia.use(piniaPluginPersistedState);
app.use(pinia);
}

View File

@ -1,17 +1,45 @@
import { defineStore } from 'pinia';
import { getAllTableMetaData, getColumnInfo, getTableMetaData } from '@/api/table';
import { getColumnInfo, getDbList, getDbTables, getTableMetaData } from '@/api/table';
export const useTableStore = defineStore('tableStore', {
state: () => ({
// 数据库所有的表
tableList: [],
tableListLoading: false,
// 数据列表
dbList: [],
}),
getters: {},
actions: {
/* 获取所有数据表 */
async getAllTableMetaData() {
const result = await getAllTableMetaData();
/* 所有的数据库 */
async getDbList() {
this.tableListLoading = true;
const result = await getDbList();
if (result.code !== 200) {
(window as any).$message.error(result.message);
this.tableListLoading = false;
return;
}
// 整理返回数据格式
const list = result.data.map((db: any) => ({
label: db.tableCat,
value: db.tableCat,
comment: db.comment,
}));
// 在开头添加
list.unshift({ label: '无', value: undefined, comment: '查询全部' });
this.dbList = list;
this.tableListLoading = false;
},
/* 数据库所有的表 */
async getDbTables(data: any) {
const result = await getDbTables(data);
if (result.code !== 200) {
(window as any).$message.error(result.message);
}

View File

@ -3,12 +3,38 @@ import { defineStore } from 'pinia';
import { generator, getVmsPathList } from '@/api/vms';
export const useVmsStore = defineStore('vmsStore', {
// 开启持久化
// persist: true,
// persist: {
// paths: ['formValue', 'formOption'],
// },
state: () => ({
generators: [],
// 生成服务端内容
serverOptions: [],
// 生成前端内容
webOptions: [],
// 查询的表单
formValue: {
author: 'Bunny',
packageName: 'cn.bunny.services',
requestMapping: '/api',
className: '',
tableName: '',
simpleDateFormat: 'yyyy-MM-dd HH:mm:ss',
tablePrefixes: 't_,sys_,qrtz_,log_',
comment: '',
path: [],
},
// 表单选择内容
formOption: {
generatorServer: [],
generatorWeb: [],
},
}),
getters: {},
actions: {
@ -20,7 +46,7 @@ export const useVmsStore = defineStore('vmsStore', {
(window as any).$message.error(result.message);
}
this.generators = result.data.map((i) => ({ ...i, path: i.path.replace('.vm', '') }));
this.generators = result.data.map((i: any) => ({ ...i, path: i.path.replace('.vm', '') }));
(window as any).$message.success(`生成成功,共 ${this.generators.length} 数据`);
},
@ -36,5 +62,10 @@ export const useVmsStore = defineStore('vmsStore', {
this.webOptions = result.data.web;
this.serverOptions = result.data.server;
},
/* 晴空已生成 */
clearGenerators() {
this.generators = [];
},
},
});

View File

@ -18,3 +18,28 @@ export function downloadTextAsFile(text: string, filename: string) {
URL.revokeObjectURL(a.href);
});
}
export const downloadBlob = (response: any) => {
try {
// 从响应头获取文件名
const contentDisposition = response.headers['content-disposition'];
let fileName = 'download.zip';
if (contentDisposition) {
const fileNameMatch = contentDisposition.match(/filename="?(.+)"?/);
if (fileNameMatch && fileNameMatch[1]) {
fileName = fileNameMatch[1];
}
}
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
} catch (error) {
console.error(error);
}
};

View File

@ -4,6 +4,7 @@
import { useMessage } from 'naive-ui';
import { defineComponent } from 'vue';
// naive ui https://www.naiveui.com/zh-CN/light/components/message
export default defineComponent({
setup() {
window.$message = useMessage();

View File

@ -24,7 +24,6 @@ onMounted(() => {
</script>
<template>
<!-- 当前表的列字段 -->
<n-data-table :bordered="true" :columns="columns" :data="datalist" />
</template>
<style scoped></style>

View File

@ -1,43 +1,52 @@
<script lang="ts" setup>
import { NCheckbox, NCheckboxGroup, NFormItemGi, NGrid, NInput, NSpace } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { useVmsStore } from '@/store/modules/vms';
import SelectButtonGroup from '@/views/generator-code/components/generator/components/select-button-group.vue';
import { formOption, formValue } from '@/views/generator-code/components/generator/option';
const vmsStore = useVmsStore();
const { formValue, formOption } = storeToRefs(vmsStore);
</script>
<template>
<!-- 需要提交的生成表单 -->
<n-grid :cols="24" :x-gap="24">
<n-form-item-gi :span="8" label="作者名称" path="author">
<n-input v-model:value="formValue.author" placeholder="输入姓名" />
<n-input v-model:value="formValue.author" placeholder="作者名称" />
</n-form-item-gi>
<n-form-item-gi :span="8" label="requestMapping名称" path="requestMapping">
<n-input v-model:value="formValue.requestMapping" placeholder="输入年龄" />
<n-input v-model:value="formValue.requestMapping" placeholder="requestMapping名称" />
</n-form-item-gi>
<n-form-item-gi :span="8" label="表名称" path="tableName">
<n-input v-model:value="formValue.tableName" placeholder="电话号码" />
<n-input v-model:value="formValue.tableName" placeholder="表名称" />
</n-form-item-gi>
</n-grid>
<n-grid :cols="24" :x-gap="24">
<n-form-item-gi :span="8" label="类名称" path="className">
<n-input v-model:value="formValue.className" placeholder="电话号码" />
<n-input v-model:value="formValue.className" placeholder="类名称" />
</n-form-item-gi>
<n-form-item-gi :span="8" label="包名称" path="packageName">
<n-input v-model:value="formValue.packageName" placeholder="电话号码" />
<n-input v-model:value="formValue.packageName" placeholder="包名称" />
</n-form-item-gi>
<n-form-item-gi :span="8" label="时间格式" path="simpleDateFormat">
<n-input v-model:value="formValue.simpleDateFormat" placeholder="电话号码" />
<n-input v-model:value="formValue.simpleDateFormat" placeholder="时间格式" />
</n-form-item-gi>
</n-grid>
<n-grid :cols="24" :x-gap="24">
<n-form-item-gi :span="8" label="去除开头前缀" path="tablePrefixes">
<n-input v-model:value="formValue.tablePrefixes" placeholder="电话号码" />
<n-input v-model:value="formValue.tablePrefixes" placeholder="去除开头前缀" />
</n-form-item-gi>
<n-form-item-gi :span="8" label="生成后端" path="generatorServer">
<n-form-item-gi :span="8" label="修改注释名称" path="comment">
<n-input v-model:value="formValue.comment" placeholder="修改注释名称" />
</n-form-item-gi>
</n-grid>
<n-grid :cols="24" :x-gap="24">
<n-form-item-gi :span="12" label="生成后端" path="generatorServer">
<n-checkbox-group v-model:value="formOption.generatorServer">
<n-space>
<n-checkbox
@ -57,7 +66,8 @@ const vmsStore = useVmsStore();
</n-space>
</n-checkbox-group>
</n-form-item-gi>
<n-form-item-gi :span="8" label="生成前端" path="generatorWeb">
<n-form-item-gi :span="12" label="生成前端" path="generatorWeb">
<n-checkbox-group v-model:value="formOption.generatorWeb">
<n-space>
<n-checkbox

View File

@ -26,6 +26,7 @@ const download = (code: string, filename: string) => {
/>
),
onPositiveClick: () => {
//
downloadTextAsFile(code, inputValue.value);
},
onNegativeClick: () => {
@ -36,6 +37,7 @@ const download = (code: string, filename: string) => {
</script>
<template>
<!-- 生成好之后下面的预览文件 -->
<n-collapse>
<n-collapse-item
v-for="(item, index) in vmsStore.generators"

View File

@ -1,61 +1,59 @@
import { reactive } from 'vue';
import { storeToRefs } from 'pinia';
import { useVmsStore } from '@/store/modules/vms';
const vmsStore = useVmsStore();
export const formOption = reactive({
generatorServer: [],
generatorWeb: [],
});
export const formValue = reactive({
author: 'Bunny',
packageName: 'cn.bunny.services',
requestMapping: '/api',
className: '',
tableName: '',
simpleDateFormat: 'yyyy-MM-dd HH:mm:ss',
tablePrefixes: 't_,sys_,qrtz_,log_',
path: [],
});
const { formValue, formOption } = storeToRefs(vmsStore);
/* 初始化表单信息 */
export const formValueInit = (tableName: any) => {
formValue.tableName = tableName.toString();
formValue.value.tableName = tableName.toString();
// 替换类名称
let className: any = tableName as any;
formValue.tablePrefixes.split(/[,]/).forEach((item) => {
formValue.value.tablePrefixes.split(/[,]/).forEach((item) => {
className = className.replace(item, '');
});
formValue.className = className;
formValue.value.className = className;
};
/* 全部选择 */
export const selectAll = () => {
formOption.generatorServer = vmsStore.serverOptions.map((option: any) => option.name);
formOption.generatorWeb = vmsStore.webOptions.map((option: any) => option.name);
formOption.value.generatorServer = vmsStore.serverOptions.map((option: any) => option.name);
formOption.value.generatorWeb = vmsStore.webOptions.map((option: any) => option.name);
};
/* 全部反选 */
export const selectAllInvert = () => {
// 反选server
const serverNames: string[] = vmsStore.serverOptions.map((item) => item['name']);
const generatorServer = formOption.generatorServer;
formOption.generatorServer = serverNames.filter(
const generatorServer = formOption.value.generatorServer;
formOption.value.generatorServer = serverNames.filter(
(name: string) => !generatorServer.includes(name)
);
// 反选web
const webNames: string[] = vmsStore.webOptions.map((item) => item['name']);
const generatorWeb = formOption.generatorWeb;
formOption.generatorWeb = webNames.filter((name) => !generatorWeb.includes(name));
const generatorWeb = formOption.value.generatorWeb;
formOption.value.generatorWeb = webNames.filter((name) => !generatorWeb.includes(name));
};
/* 取消全部选择 */
export const selectCancelAll = () => {
formOption.generatorServer = [];
formOption.generatorWeb = [];
formValue.path = [];
formOption.value.generatorServer = [];
formOption.value.generatorWeb = [];
formValue.value.path = [];
};
/* 验证 formValue.path 是否为空 */
export const validateFormValue = () => {
// 选择要生成的模板
const web = formOption.value.generatorWeb;
const server = formOption.value.generatorServer;
// 整理好数据
formValue.value.path = [...server, ...web];
if (formValue.value.path.length <= 0) {
(window as any).$message.error(`选择要生成的模板`);
return;
}
};

View File

@ -1,45 +1,13 @@
<template>
<n-form ref="formRef" :label-width="80" :model="formValue" :rules="rules">
<generator-form />
<n-form-item>
<n-grid class="justify-items-center" cols="3" x-gap="24">
<n-gi>
<n-button attr-type="button" type="success" @click="selectAll">全部选择</n-button>
<n-button attr-type="button" type="warning" @click="selectAllInvert">全部反选</n-button>
<n-button attr-type="button" type="error" @click="selectCancelAll">全选取消</n-button>
</n-gi>
<n-gi>
<n-button attr-type="button" type="success" @click="onSubmit">开始生成</n-button>
<n-button attr-type="button" type="error" @click="() => (vmsStore.generators = [])">
清空已生成
</n-button>
<n-button
:disabled="!(vmsStore.generators.length > 0)"
attr-type="button"
type="primary"
@click="downloadAll"
>
下载全部 {{ vmsStore.generators.length }}
</n-button>
</n-gi>
</n-grid>
</n-form-item>
</n-form>
<!-- 生成好的数据 -->
<generator-preview />
</template>
<script lang="tsx" setup>
import { NButton, NForm, NFormItem, NGi, NGrid, useMessage } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { onMounted, ref } from 'vue';
import { toRaw } from 'vue-demi';
import { computed } from 'vue-demi';
import { useRoute } from 'vue-router';
import { downloadByZip } from '@/api/vms';
import { useVmsStore } from '@/store/modules/vms';
import { downloadTextAsFile } from '@/utils/file';
import { downloadBlob, downloadTextAsFile } from '@/utils/file';
import GeneratorForm from '@/views/generator-code/components/generator/components/generator-form.vue';
import GeneratorPreview from '@/views/generator-code/components/generator/components/generator-preview.vue';
import {
@ -47,13 +15,20 @@ import {
selectAll,
selectAllInvert,
selectCancelAll,
validateFormValue,
} from '@/views/generator-code/components/generator/hook';
import { formOption, formValue, rules } from '@/views/generator-code/components/generator/option';
import { rules } from '@/views/generator-code/components/generator/option';
const route = useRoute();
const vmsStore = useVmsStore();
const { formValue, formOption } = storeToRefs(vmsStore);
const message = useMessage();
const formRef = ref();
const hasDownloadZip = computed(
() => !(formOption.value.generatorWeb.length > 0 || formOption.value.generatorServer.length > 0)
);
/* 提交表单 */
const onSubmit = (e: MouseEvent) => {
@ -61,19 +36,10 @@ const onSubmit = (e: MouseEvent) => {
formRef.value?.validate(async (errors: any) => {
if (!errors) {
//
const web = formOption.generatorWeb;
const server = formOption.generatorServer;
//
formValue.path = [...server, ...web];
if (formValue.path.length <= 0) {
message.error(`选择要生成的模板`);
return;
}
validateFormValue();
//
await vmsStore.generator(toRaw(formValue));
await vmsStore.generator(formValue.value);
} else {
errors.forEach((error: any) => {
error.forEach((err: any) => {
@ -94,6 +60,14 @@ const downloadAll = () => {
});
};
/* 下载zip文件 */
const downloadZipFile = async () => {
validateFormValue();
const result = await downloadByZip(formValue.value);
downloadBlob(result);
};
onMounted(() => {
//
const tableName: any = route.query.tableName;
@ -102,3 +76,49 @@ onMounted(() => {
vmsStore.getVmsPathList();
});
</script>
<template>
<n-form ref="formRef" :label-width="80" :model="formValue" :rules="rules">
<generator-form />
<n-form-item>
<n-grid class="justify-items-center" cols="3" x-gap="24">
<n-gi>
<n-button attr-type="button" type="success" @click="selectAll">全部选择</n-button>
<n-button attr-type="button" type="warning" @click="selectAllInvert">全部反选</n-button>
<n-button attr-type="button" type="error" @click="selectCancelAll">全选取消</n-button>
</n-gi>
<n-gi>
<n-button attr-type="button" type="success" @click="onSubmit">开始生成</n-button>
<n-button attr-type="button" type="error" @click="vmsStore.clearGenerators()">
清空已生成
</n-button>
<n-button
:disabled="!(vmsStore.generators.length > 0)"
attr-type="button"
type="primary"
@click="downloadAll"
>
下载全部 {{ vmsStore.generators.length }}
</n-button>
</n-gi>
<n-gi class="w-full">
<n-button
:disabled="hasDownloadZip"
attr-type="button"
class="w-full"
type="success"
@click="downloadZipFile"
>
下载zip
</n-button>
</n-gi>
</n-grid>
</n-form-item>
</n-form>
<!-- 生成好的数据 -->
<generator-preview />
</template>

View File

@ -1,10 +1,14 @@
import type { FormRules } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { formOption, formValue } from '@/views/generator-code/components/generator/hook';
import { useVmsStore } from '@/store/modules/vms';
const vmsStore = useVmsStore();
const { formOption } = storeToRefs(vmsStore);
/* 验证生成前后端内容是否合法 */
const validatorFormOption = () => {
return formOption.generatorServer.length > 0 || formOption.generatorWeb.length > 0;
return formOption.value.generatorServer.length > 0 || formOption.value.generatorWeb.length > 0;
};
// 表单验证
@ -40,5 +44,3 @@ export const rules: FormRules = {
},
],
};
export { formOption, formValue };

View File

@ -1,21 +1,29 @@
<script lang="ts" setup>
import { NCard, NTabPane, NTabs } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { onMounted, reactive } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useTableStore } from '@/store/modules/table';
import { useVmsStore } from '@/store/modules/vms';
import Index from '@/views/generator-code/components/column-field/index.vue';
import GeneratorForm from '@/views/generator-code/components/generator/index.vue';
const router = useRouter();
const route = useRoute();
const tableStore = useTableStore();
const vmsStore = useVmsStore();
const { formValue, formOption } = storeToRefs(vmsStore);
//
const tableInfo = reactive({
/* 表名称 */
tableName: '',
/* 注释内容 */
comment: '',
/* 数据库内容 */
tableCat: '',
/* 通常是 "TABLE" */
tableType: '',
});
@ -24,6 +32,9 @@ const getTableData = async () => {
const tableName: any = route.query.tableName;
const tableMetaData = await tableStore.getTableMetaData(tableName);
Object.assign(tableInfo, tableMetaData);
//
formValue.value.comment = tableInfo.comment;
};
onMounted(() => {
@ -34,7 +45,7 @@ onMounted(() => {
<n-card>
<template #header>
<n-card title="数据库信息">
<span class="color-blue" @click="router.push('/')">回到首页</span>
<span class="color-blue cursor-pointer" @click="router.push('/')">回到首页</span>
<ul>
<li>表名{{ route.query.tableName }}</li>
<li>表注释{{ tableInfo.comment }}</li>

View File

@ -1,14 +1,30 @@
<script lang="tsx" setup>
import { NCard, NDataTable, NTag } from 'naive-ui';
import { onMounted } from 'vue';
import type { SelectOption } from 'naive-ui';
import { NCard, NDataTable, NSelect, NTag, NTooltip } from 'naive-ui';
import type { VNode } from 'vue';
import { h, onMounted } from 'vue';
import { useTableStore } from '@/store/modules/table';
import { columns } from '@/views/home/columns';
const tableStore = useTableStore();
/* 数据库所有的表 */
const getDbTables = (dbName: string) => {
tableStore.getDbTables({ dbName: dbName ?? undefined });
};
/* 为select添加 提示 */
const renderOptions = ({ node, option }: { node: VNode; option: SelectOption }) => {
return h(NTooltip, null, {
trigger: () => node,
default: () => option.comment,
});
};
onMounted(() => {
tableStore.getAllTableMetaData();
getDbTables(undefined);
tableStore.getDbList();
});
</script>
@ -26,9 +42,23 @@ onMounted(() => {
<n-tag type="info">{{ tableStore.tableList.length }}</n-tag>
张表
</p>
<!-- 选择数据库 -->
<n-select
:on-update-value="getDbTables"
:options="tableStore.dbList"
:render-option="renderOptions"
class="mt-2 w-[200px]"
clear-filter-after-select
clearable
placeholder="选择数据库"
/>
</n-card>
<n-data-table :bordered="true" :columns="columns()" :data="tableStore.tableList" />
<n-data-table
:bordered="true"
:columns="columns()"
:data="tableStore.tableList"
:loading="tableStore.tableListLoading"
/>
</template>
<style scoped></style>

View File

@ -35,6 +35,7 @@
]
},
"include": [
"build/**",
"mock/*.ts",
"src/**/*.ts",
"src/**/*.tsx",