😎1、优化前端页面 2、调整代码生成页面

This commit is contained in:
zuohuaijun 2025-09-14 14:36:57 +08:00
parent 51400baea5
commit 71236007ee
18 changed files with 1332 additions and 2074 deletions

View File

@ -0,0 +1,272 @@
import { defineStore } from 'pinia';
import {
AddCodeGenInput,
ColumnOutput,
DatabaseOutput,
DefaultColumnConfigInput,
EffectTreeConfigInput,
SysCodeGenApi,
SysDictType,
SysDictTypeApi,
SysMenu,
SysMenuApi,
SysPrint,
SysPrintApi,
TableOutput,
UpdateCodeGenInput,
} from '/@/api-services/system';
import { getAPI } from '/@/utils/axios-utils';
import { useUserInfo } from '/@/stores/userInfo';
import { watch } from 'vue';
const apiManager = {
detail: (id: number) => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenDetailGet(id)
.then((res) => res.data.result);
},
add: (body: AddCodeGenInput) => {
return getAPI(SysCodeGenApi).apiSysCodeGenAddPost(body);
},
update: (body: UpdateCodeGenInput) => {
return getAPI(SysCodeGenApi).apiSysCodeGenUpdatePost(body);
},
getColumnConfigList: (id: number) => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenTableDetailGet(id)
.then((res) => res.data.result);
},
getPrintList: () => {
return getAPI(SysPrintApi)
.apiSysPrintPagePost()
.then((res) => res.data.result?.items ?? []);
},
getMenuList: () => {
return getAPI(SysMenuApi)
.apiSysMenuListGet()
.then((res) => res.data.result ?? []);
},
getDictTypeList: () => {
return getAPI(SysDictTypeApi)
.apiSysDictTypeListGet()
.then((res) => res.data.result ?? []);
},
getQuickConfigMap: () => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenQuickConfigMapGet()
.then((res) => res.data.result ?? {});
},
getNamespaceList: () => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenApplicationNamespacesGet()
.then((res) => res.data.result ?? []);
},
getDatabaseList: () => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenDatabaseListGet()
.then((res) => res.data.result ?? []);
},
getTableList: (configId: string) => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenTableListConfigIdGet(configId)
.then((res) => res.data.result ?? []);
},
getColumnList: (configId: string, tableName: string) => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(tableName, configId)
.then((res) => res.data.result ?? []);
},
getDefaultColumnConfigList: (body: DefaultColumnConfigInput) => {
return getAPI(SysCodeGenApi)
.apiSysCodeGenDefaultColumnConfigListPost(body)
.then((res) => res.data.result ?? []);
},
};
interface CodeGenStore {
enabledWatch: boolean;
loading: boolean;
constList: any[];
menuList?: SysMenu[];
printList?: SysPrint[];
dictList: SysDictType[];
enumList: SysDictType[];
namespaceList?: string[];
databaseList?: DatabaseOutput[];
tableMap: { [key: string]: TableOutput[] };
columnMap: { [key: string]: ColumnOutput[] };
quickConfigMap?: { [key: string]: EffectTreeConfigInput };
ruleForm: UpdateCodeGenInput;
apiManager: typeof apiManager;
}
const useStore = useUserInfo();
export const useCodeGenStore = defineStore('codeGenStore', {
state: (): CodeGenStore => ({
enabledWatch: false,
loading: false,
dictList: [],
enumList: [],
constList: [],
tableMap: {},
columnMap: {},
ruleForm: {} as any,
apiManager: apiManager,
}),
getters: {
sceneLabel: (state) => useStore.dictList['CodeGenSceneEnum'].find((u: any) => u.value === state.ruleForm.scene)?.label,
tableListBy: (state) => {
return async (configId: string) => {
if (configId && !state.tableMap[configId]) state.tableMap[configId] = await state.apiManager.getTableList(configId);
return state.tableMap[configId];
};
},
columnListBy: (state) => {
return async (configId: string, tableName: string) => {
const key = `${configId}:${tableName}`;
if (tableName && configId && !state.columnMap[key]) state.columnMap[key] = await state.apiManager.getColumnList(configId, tableName);
return state.columnMap[key];
};
},
},
actions: {
async init() {
this.menuList ??= await this.apiManager.getMenuList();
this.printList ??= await this.apiManager.getPrintList();
this.databaseList ??= await this.apiManager.getDatabaseList();
this.namespaceList ??= await this.apiManager.getNamespaceList();
this.quickConfigMap ??= await this.apiManager.getQuickConfigMap();
this.constList = useUserInfo().constList;
const dictList = await this.apiManager.getDictTypeList();
this.dictList = dictList.filter((item) => !item.code.endsWith('Enum'));
this.enumList = dictList.filter((item) => item.code.endsWith('Enum'));
// 监听场景改变
watch(
() => this.ruleForm.scene,
(val: any) => {
if (!this.enabledWatch) return;
val = parseInt(val ?? '1000');
const tableList = [{} as any, {} as any];
this.ruleForm!.treeConfig = (val! % 100 == 10 ? { multiple: false } : undefined) as any;
//this.ruleForm.configObj = undefined;
switch (val) {
case 1000: //单表
this.ruleForm.tableList = [tableList[0]];
break;
case 1010: //单表树组件
this.ruleForm.tableList = [tableList[0]];
break;
case 2000: //主从表
this.ruleForm.tableList = tableList;
this.ruleForm.isHorizontal = false;
break;
case 2010: //主从表树组件
this.ruleForm.tableList = tableList;
this.ruleForm.isHorizontal = false;
break;
case 3000: //关系对照
//this.ruleForm.configObj = {};
this.ruleForm.tableList = tableList;
this.ruleForm.isHorizontal = false;
break;
case 3010: //关系对照树组件
//this.ruleForm.configObj = {};
this.ruleForm.tableList = tableList;
this.ruleForm.isHorizontal = false;
break;
default:
this.ruleForm.tableList = [];
this.ruleForm.treeConfig = undefined;
}
}
);
},
showTree() {
return this.ruleForm.treeConfig && this.ruleForm.scene! % 100 === 10;
},
showRela() {
//return this.ruleForm.configObj && Math.round(this.ruleForm.scene! / 1000) === 3;
return Math.round(this.ruleForm.scene! / 1000) === 3;
},
showMaster() {
return (this.showRela() || Math.round(this.ruleForm.scene! / 1000) <= 2) && this.ruleForm.tableList?.[0];
},
showSlave() {
return (this.showRela() || Math.round(this.ruleForm.scene! / 1000) == 2) && this.ruleForm.tableList?.[1];
},
getLastLinkLabel(index: number) {
if (index == 0) {
return this.ruleForm.scene! % 1000 === 10 ? '树联表字段' : undefined;
} else if (index == 1) {
return [2000, 2010, 3000, 3010].includes(this.ruleForm.scene!) ? '主表联表字段' : undefined;
}
},
getNextLinkLabel(index: number) {
return index == 0 && [2000, 2010, 3000, 3010].includes(this.ruleForm.scene!) ? '从表联表字段' : undefined;
},
getSyncColumnListButtonDisabled(index: number) {
const data = this.ruleForm.tableList?.[index];
return !(data?.configId && data?.tableName);
},
async getDetail(id: number) {
this.loading = true;
try {
const res = await this.apiManager.detail(id);
res?.tableList?.forEach((item: any) => {
item.columnList?.forEach((item2: any) => {
try {
item2.config = JSON.parse(item2.config);
} catch (e) {}
});
});
return res;
} finally {
this.loading = false;
}
},
async getColumnConfigList(id: number) {
this.loading = true;
try {
return (await this.apiManager.getColumnConfigList(id)) as any;
} finally {
this.loading = false;
}
},
async getDefaultColumnConfigList(index: number) {
this.loading = true;
try {
const data = this.ruleForm.tableList?.[index];
if (data?.configId && data?.tableName) {
data!.columnList = (await this.apiManager.getDefaultColumnConfigList({
configId: data?.configId,
tableName: data?.tableName,
})) as any[];
data!.columnList?.forEach((item: any) => {
if (item.config) item.config = JSON.parse(item.config);
item.config ??= {};
});
}
return data?.columnList ?? [];
} finally {
this.loading = false;
}
},
async save(data: any) {
this.loading = true;
try {
for (const item of data.tableList) {
item.columnList.forEach((column: any) => {
try {
column.config = JSON.stringify(column.config);
} catch (e) {}
});
}
return data?.id ? await this.apiManager.update(data) : await this.apiManager.add(data);
} finally {
this.loading = false;
}
},
},
});

View File

@ -0,0 +1,79 @@
<template>
<div class="sys-codeGenUpload-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" :width="400" :max-height="'100px'">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 时间数据配置 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="时间格式" prop="format" :rules="[{ required: true, message: '时间格式不能为空', trigger: 'blur' }]">
<el-select v-model="state.ruleForm.format" filterable clearable class="w100">
<el-option label="YYYY-mm-dd HH:MM:SS" value="datetime" />
<el-option label="YYYY-dd-MM" value="date" />
<el-option label="HH:MM:SS" value="time" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit" v-reclick="1000"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="sysPreviewCode">
import { onMounted, reactive, ref } from 'vue';
let rowData = {} as any;
const emits = defineEmits(['submitData']);
const ruleFormRef = ref();
const state = reactive({
isShowDialog: false,
ruleForm: {} as any,
});
onMounted(async () => {});
//
const openDialog = async (row: any) => {
rowData = row;
state.isShowDialog = true;
state.ruleForm = Object.assign({}, row.config);
};
//
const closeDialog = () => {
rowData.config = Object.assign({}, state.ruleForm);
emits('submitData', rowData);
cancel();
};
//
const cancel = () => {
ruleFormRef.value?.resetFields();
state.isShowDialog = false;
state.ruleForm = {};
};
//
const submit = () => {
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
closeDialog();
});
};
//
defineExpose({ openDialog });
</script>
<style scoped></style>

View File

@ -1,601 +1,337 @@
<template>
<div class="sys-editCodeGen-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="980px">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" fullscreen>
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> {{ props.title }} </span>
<span> {{ state.title }} </span>
</div>
</template>
<el-tabs v-model="activeTab" class="demo-tabs">
<el-tab-pane label="代码生成" name="codeGen" style="height: 700px">
<div style="color: red; padding: 10px 10px; background: #faecd8; margin-bottom: 10px">
<el-icon style="transform: translateY(2px)"><ele-Bell /></el-icon>
<span> 若找不到在前端生成的实体/请检查配置文件中实体所在程序集或重启后台服务 </span>
</div>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-form :model="store.ruleForm" ref="ruleFormRef" label-width="auto" v-loading="store.loading">
<el-tabs v-model="state.activeTab" class="demo-tabs">
<el-tab-pane label="代码生成">
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="库定位器" prop="configId" :rules="[{ required: true, message: '请选择库定位器', trigger: 'blur' }]">
<el-select v-model="state.ruleForm.configId" placeholder="库名" filterable @change="dbChanged()" class="w100">
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="库类型" prop="dbType" :rules="[{ required: true, message: '库类型不能为空', trigger: 'blur' }]">
<g-sys-dict v-model="state.ruleForm.dbType" code="db_type" render-as="select" :disabled="state.ruleForm.tenantType == 0 && state.ruleForm.tenantType != undefined" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="库地址" prop="connectionString" :rules="[{ required: true, message: '库地址不能为空', trigger: 'blur' }]">
<el-input v-model="state.ruleForm.connectionString" disabled clearable type="textarea" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="生成表" prop="tableName" :rules="[{ required: true, message: '生成表不能为空', trigger: 'blur' }]">
<template v-slot:label>
<div>
生成表
<el-tooltip raw-content content="若找不到在前端生成的实体/表,请检查配置文件中实体所在程序集或重启后台服务。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.tableName" @change="tableChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.entityName + ' ( ' + item.tableName + ' ) [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="表类型" prop="busName" :rules="[{ required: true, message: '表类型不能为空', trigger: 'blur' }]">
<g-sys-dict v-model="state.ruleForm.tabType" code="code_gen_tab_type" render-as="select" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="业务名" prop="busName" :rules="[{ required: true, message: '业务名不能为空', trigger: 'blur' }]">
<el-input v-model="state.ruleForm.busName" placeholder="请输入" clearable />
<el-input v-model="store.ruleForm.busName" placeholder="请输入" class="w100" clearable />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb5">
<el-form-item label="场景类型" prop="scene" :rules="[{ required: true, message: '场景类型不能为空', trigger: 'blur' }]">
<g-sys-dict v-model="store.ruleForm.scene" code="CodeGenSceneEnum" render-as="select" :disabled="!!store.ruleForm.id" :on-item-filter="(e: any) => e.value > 0" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="Name字段" prop="treeName">
<template v-slot:label>
<div>
Name字段
<el-tooltip raw-content content="本表作为树控件的树属性Name字段。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.treeName" @change="treeNameChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
<el-form-item label="作者姓名" prop="authorName" class="flex w100">
<el-input v-model="store.ruleForm.authorName" clearable placeholder="请输入姓名" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="树key字段" prop="treeKey">
<template v-slot:label>
<div>
PidKey字段
<el-tooltip raw-content content="本表作为树控件的树属性父IDPidKey字段字段没有就请留空。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.treeKey" @change="treeKeyChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="生成菜单" prop="generateMenu">
<el-radio-group v-model="state.ruleForm.generateMenu">
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="菜单图标" prop="menuIcon">
<IconSelector v-model="state.ruleForm.menuIcon" :size="getGlobalComponentSize" placeholder="菜单图标" type="all" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="父级菜单" prop="menuPid">
<el-cascader
:options="state.menuData"
:props="cascaderProps"
placeholder="请选择上级菜单"
:disabled="!state.ruleForm.generateMenu"
filterable
clearable
class="w100"
v-model="state.ruleForm.menuPid"
@change="menuChange"
>
<template #default="{ node, data }">
<span>{{ data.title }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
<el-form-item label="作者邮箱" prop="authorName" class="flex w100">
<el-input v-model="store.ruleForm.email" clearable placeholder="请输入邮箱" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="命名空间" prop="nameSpace" :rules="[{ required: true, message: '请选择命名空间', trigger: 'blur' }]">
<!-- <el-input v-model="state.ruleForm.nameSpace" clearable placeholder="请输入" /> -->
<el-select v-model="state.ruleForm.nameSpace" filterable clearable class="w100" placeholder="命名空间">
<el-option v-for="(item, index) in props.applicationNamespaces" :key="index" :label="item" :value="item" />
<el-select v-model="store.ruleForm.nameSpace" filterable clearable class="w100" placeholder="命名空间">
<el-option v-for="(item, index) in store.namespaceList ?? []" :key="index" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="前端目录" prop="pagePath" :rules="[{ required: true, message: '前端目录不能为空', trigger: 'blur' }]">
<el-input v-model="state.ruleForm.pagePath" clearable placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="作者姓名" prop="authorName">
<el-input v-model="state.ruleForm.authorName" clearable placeholder="请输入" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="生成方式" prop="generateType">
<g-sys-dict v-model="state.ruleForm.generateType" code="code_gen_create_type" render-as="select" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="接口模式" prop="isApiService">
<template v-slot:label>
<div>
接口模式
<el-tooltip raw-content content="接口服务模式是指根据swagger自动生成前端接口请求文件推荐此模式。传统模式则是指手动编写接口请求并进行数据绑定。" placement="top">
前端目录
<el-tooltip raw-content content="指的是前端相对目录src/views/main" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-radio-group v-model="state.ruleForm.isApiService">
<el-input v-model="store.ruleForm.pagePath" clearable placeholder="请输入" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="生成方式" prop="generateMethod" :rules="[{ required: true, message: '生成方式不能为空', trigger: 'blur' }]">
<g-sys-dict v-model="store.ruleForm.generateMethod" code="CodeGenMethodEnum" render-as="select" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="支持打印" prop="printType" :rules="[{ required: true, message: '支持打印不能为空', trigger: 'blur' }]">
<g-sys-dict v-model="store.ruleForm.printType" code="CodeGenPrintTypeEnum" render-as="select" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="打印模版" prop="printName" :rules="[{ required: store.ruleForm.printType == 2, message: '打印模版不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.printName" filterable class="w100" :disabled="store.ruleForm.printType != 2">
<el-option v-for="item in store.printList" :key="item.id" :label="item.name" :value="item.name" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="接口模式" prop="isApiService" :rules="[{ required: true, message: '接口模式不能为空', trigger: 'blur' }]">
<template v-slot:label>
<div>
接口模式
<el-tooltip
raw-content
content="接口服务模式是指根据swagger自动生成前端接口请求文件(需要手动双击批处理生成目录api_build/build.bat)推荐此模式。传统模式则是指手动根据swagger编写接口请求并进行模型定义。"
placement="top"
>
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-radio-group v-model="store.ruleForm.isApiService">
<el-radio :value="true">接口服务</el-radio>
<el-radio :value="false">传统模式</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="支持打印" prop="printType">
<g-sys-dict v-model="state.ruleForm.printType" code="code_gen_print_type" render-as="select" />
<el-form-item label="生成菜单" prop="generateMenu" :rules="[{ required: true, message: '生成菜单不能为空', trigger: 'blur' }]">
<el-radio-group v-model="store.ruleForm.generateMenu">
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" v-if="state.ruleForm.printType == 'custom'">
<el-form-item label="打印模版" prop="printName">
<el-select v-model="state.ruleForm.printName" filterable class="w100">
<el-option v-for="item in state.printList" :key="item.id" :label="item.name" :value="item.name" />
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="store.ruleForm.generateMenu">
<el-row>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="父级菜单" prop="menuPid">
<el-cascader
:options="store.menuList"
:props="cascaderProps"
placeholder="请选择上级菜单"
:disabled="!store.ruleForm.generateMenu"
filterable
clearable
class="w100"
v-model="store.ruleForm.menuPid"
>
<template #default="{ node, data }">
<span>{{ data.title }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="菜单图标" prop="menuIcon" :rules="[{ required: true, message: '菜单图标不能为空', trigger: 'blur' }]">
<IconSelector v-model="store.ruleForm.menuIcon as any" :size="other.globalComponentSize()" placeholder="菜单图标" type="all" />
</el-form-item>
</el-col>
</el-row>
</el-col>
<el-col v-if="<number>store.ruleForm.scene >= 2000" :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="布局方向" prop="isHorizontal" :rules="[{ required: true, message: '水平布局不能为空', trigger: 'blur' }]">
<el-radio-group v-model="store.ruleForm.isHorizontal">
<el-radio :value="false">水平</el-radio>
<el-radio :value="true">垂直</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane v-if="store.showTree()" label="树组件配置">
<el-row>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="库定位器" prop="treeConfig.configId" :rules="[{ required: true, message: '库定位器不能为空', trigger: 'blur' }]">
<el-select clearable v-model="store.ruleForm.treeConfig!.configId" placeholder="库名" filterable @change="(val: any) => dbChanged(val)" class="w100">
<el-option v-for="item in store.databaseList ?? []" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<!-- <el-divider border-style="dashed" content-position="center">
<div style="color: #b1b3b8">数据唯一性配置</div>
</el-divider>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-button icon="ele-Plus" type="primary" plain @click="() => state.ruleForm.tableUniqueList?.push({})"> 增加配置 </el-button>
<span style="font-size: 12px; color: gray; padding-left: 5px"> 保证字段值的唯一性排除null值 </span>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<template v-if="state.ruleForm.tableUniqueList != undefined && state.ruleForm.tableUniqueList.length > 0">
<el-row :gutter="10" v-for="(v, k) in state.ruleForm.tableUniqueList" :key="k">
<el-col :xs="24" :sm="14" :md="14" :lg="14" :xl="14" class="mb20">
<el-form-item label="字段" :prop="`tableUniqueList[${k}].columns`" :rules="[{ required: true, message: `字段不能为空`, trigger: 'blur' }]">
<template #label>
<el-button icon="ele-Delete" type="danger" circle plain size="small" @click="() => state.ruleForm.tableUniqueList?.splice(k, 1)" />
<span class="ml5">字段</span>
</template>
<el-select
v-model="state.ruleForm.tableUniqueList[k].columns"
@change="(val: any) => changeTableUniqueColumn(val, k)"
multiple
filterable
clearable
collapse-tags
collapse-tags-tooltip
class="w100"
>
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="10" :md="10" :lg="10" :xl="10" class="mb20">
<el-form-item label="描述信息" :prop="`tableUniqueList[${k}].message`" :rules="[{ required: true, message: `描述信息不能为空`, trigger: 'blur' }]">
<el-input v-model="state.ruleForm.tableUniqueList[k].message" clearable placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
</template>
</el-col> -->
<el-col>
<el-divider content-position="center"> 左边布局显示树形列表右边布局上下结构显示主子表数据列表 </el-divider>
<!-- <p><el-tag style="border: 1 solid var(--el-border-color)">以下默认页面左右布局左边布局显示树形列表右边布局上下结构显示主子表数据列表</el-tag></p> -->
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane label="页面左(树列表)" name="1">
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="树 - 库定位器" prop="configId2">
<el-select v-model="state.ruleForm.configId2" placeholder="库名" filterable @change="dbChanged2()" class="w100">
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="树表名称">
<template v-slot:label>
<div>
树表名称
<el-tooltip raw-content content="若找不到在前端生成的实体/表同上如表有下划线_则因实体去掉划线取不到字段。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.leftTab" @change="leftTableChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.tableData2" :key="item.entityName" :label="item.entityName + ' ( ' + item.tableName + ' ) [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="树关联字段">
<el-select v-model="state.ruleForm.leftKey" @change="leftKeyChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.lcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="关联主表字段">
<template v-slot:label>
<div>
关联主表字段
<el-tooltip raw-content content="先选择主表才可以选择字段。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.leftPrimaryKey" @change="leftPrimaryKeyChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="树显示名称">
<el-select v-model="state.ruleForm.leftName" @change="leftNameChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.lcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="模板">
<el-input v-model="state.ruleForm.template" clearable placeholder="请输入" />
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="页面右(主子表)" name="2">
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="子表 - 库定位器" prop="configId3">
<el-select v-model="state.ruleForm.configId3" placeholder="库名" filterable @change="dbChanged3()" class="w100">
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="子表名称" prop="bottomTab">
<template v-slot:label>
<div>
子表名称
<el-tooltip raw-content content="若找不到在前端生成的实体/表同上如表有下划线_则因实体去掉划线取不到字段。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.bottomTab" @change="bottomTableChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.tableData3" :key="item.entityName" :label="item.entityName + ' ( ' + item.tableName + ' ) [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="子表关联字段" prop="bottomKey">
<el-select v-model="state.ruleForm.bottomKey" @change="bottomKeyChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.bcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="关联主表字段" prop="bottomPrimaryKey">
<template v-slot:label>
<div>
关联主表字段
<el-tooltip raw-content content="先选择主表才可以选择字段。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</div>
</template>
<el-select v-model="state.ruleForm.bottomPrimaryKey" @change="bottomPrimaryKeyChanged" value-key="value" filterable clearable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="数据库表" prop="treeConfig.tableName" :rules="[{ required: true, message: '数据库表不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.treeConfig!.tableName" filterable clearable @change="(val: any) => tableChanged(store.ruleForm.treeConfig!.configId, val, 'tree')" class="w100">
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.tableName + ' [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="显示字段" prop="treeConfig.displayPropertyNames" :rules="[{ required: true, message: '显示字段不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.treeConfig!.displayPropertyNames" filterable class="w100">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.propertyName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="值字段" prop="treeConfig.linkPropertyName" :rules="[{ required: true, message: '值字段不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.treeConfig!.linkPropertyName" filterable class="w100" @change="(val: any) => changeTreePropertyName(val, 'link')">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="父级字段" prop="treeConfig.parentPropertyName" :rules="[{ required: true, message: '父级字段不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.treeConfig!.parentPropertyName" filterable class="w100" @change="(val: any) => changeTreePropertyName(val, 'parent')">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="查询字段" prop="treeConfig.searchPropertyName" :rules="[{ required: true, message: '查询字段不能为空', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.treeConfig!.searchPropertyName" filterable class="w100" @change="(val: any) => changeTreePropertyName(val, 'search')">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="树标题" prop="treeConfig.treeTitle" :rules="[{ required: true, message: '树标题不能为空', trigger: 'blur' }]">
<el-input v-model="store.ruleForm.treeConfig!.treeTitle" clearable placeholder="请输入" class="w100" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="是否多选">
<el-radio-group v-model="store.ruleForm.treeConfig!.multiple" filterable>
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
<el-tab-pane label="选择模板" name="template" style="height: 700px">
<el-table ref="templateTableRef" :data="templateTableData" @selection-change="handleSelectionChange" style="width: 100%">
<el-table-column type="selection" width="65" />
<el-table-column property="name" label="模板文件名" width="280" />
<el-table-column property="describe" label="描述" show-overflow-tooltip />
</el-table>
</el-tab-pane>
</el-tabs>
</el-tab-pane>
<el-tab-pane v-if="store.showMaster()" label="主表配置">
<TableConfig :index="0" />
</el-tab-pane>
<el-tab-pane v-if="store.showSlave()" label="从表配置">
<TableConfig :index="1" />
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
<el-button icon="ele-CircleCloseFilled" @click="cancel" :disabled="state.loading"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit" :disabled="state.loading" v-reclick="1000"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<!-- 代码生成配置 -->
<script lang="ts" setup name="sysEditCodeGen">
import { computed, onMounted, reactive, ref, nextTick } from 'vue';
import IconSelector from '/@/components/iconSelector/index.vue';
import { defineAsyncComponent, nextTick, reactive, ref } from 'vue';
import { ElMessage } from 'element-plus';
import other from '/@/utils/other';
import IconSelector from '/@/components/iconSelector/index.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenApi, SysMenuApi, SysPrintApi, SysCodeGenTemplateApi } from '/@/api-services/system/api';
import { UpdateCodeGenInput, AddCodeGenInput, SysMenu, SysPrint } from '/@/api-services/system/models';
import { useCodeGenStore } from './codeGenStore';
const props = defineProps({
title: String,
applicationNamespaces: Array<String>,
});
const TableConfig = defineAsyncComponent(() => import('./tableConfig.vue'));
const emits = defineEmits(['handleQuery']);
const store = useCodeGenStore();
const ruleFormRef = ref();
const state = reactive({
title: '编辑代码生成',
isShowDialog: false,
ruleForm: {} as UpdateCodeGenInput | any,
tableData: [] as any,
tableData2: [] as any,
tableData3: [] as any,
dbData: [] as any,
columnData: [] as any,
lcolumnData: [] as any,
bcolumnData: [] as any,
menuData: [] as Array<SysMenu>,
printList: [] as Array<SysPrint>,
columnList: [] as any,
loading: false,
activeTab: '0',
});
const activeName = ref('1');
const activeTab = ref('codeGen');
const templateTableRef = ref();
const multipleSelection = ref([] as any);
const templateTableData = ref([] as any);
//
const cascaderProps = { checkStrictly: true, emitPath: false, value: 'id', label: 'title' };
onMounted(async () => {
state.dbData = await getAPI(SysCodeGenApi)
.apiSysCodeGenDatabaseListGet()
.then((res) => res.data.result ?? []);
state.printList = await getAPI(SysPrintApi)
.apiSysPrintPagePost()
.then((res) => res.data.result?.items ?? []);
state.menuData = await getAPI(SysMenuApi)
.apiSysMenuListGet()
.then((res) => res.data.result ?? []);
});
//
const getSysCodeGenTemplateList = async () => {
let res = await getAPI(SysCodeGenTemplateApi).apiSysCodeGenTemplateListGet();
let data = res.data.result ?? [];
templateTableData.value = data;
//
nextTick(() => {
let checkedRows = [] as any;
if (state.ruleForm.id) {
//
data.forEach((element: any) => {
if (state.ruleForm.codeGenTemplateRelations.some((ele: any) => ele.templateId == element.id)) {
checkedRows.push(element);
templateTableRef.value.toggleRowSelection(element, true);
}
});
} else {
//
data.forEach((element: any) => {
if (element.isDefault) {
checkedRows.push(element);
templateTableRef.value.toggleRowSelection(element, true);
}
});
}
multipleSelection.value = checkedRows;
});
};
//
const handleSelectionChange = (val: any[]) => {
multipleSelection.value = val;
// console.log(val);
};
// db
const dbChanged = async () => {
if (state.ruleForm.configId === '' || state.ruleForm.configId == null) return;
state.tableData = await getAPI(SysCodeGenApi)
.apiSysCodeGenTableListConfigIdGet(state.ruleForm.configId as string)
.then((res) => res.data.result ?? []);
const dbChanged = async (configId: string) => {
if (!configId) return;
state.tableData = await store.tableListBy(configId);
};
let db = state.dbData.filter((u: any) => u.configId == state.ruleForm.configId);
state.ruleForm.connectionString = db[0].connectionString;
state.ruleForm.dbType = db[0].dbType.toString();
};
const dbChanged2 = async () => {
if (state.ruleForm.configId === '' || state.ruleForm.configId == null) return;
state.tableData2 = await getAPI(SysCodeGenApi)
.apiSysCodeGenTableListConfigIdGet(state.ruleForm.configId2 as string)
.then((res) => res.data.result ?? []);
};
const dbChanged3 = async () => {
if (state.ruleForm.configId === '' || state.ruleForm.configId == null) return;
state.tableData3 = await getAPI(SysCodeGenApi)
.apiSysCodeGenTableListConfigIdGet(state.ruleForm.configId3 as string)
.then((res) => res.data.result ?? []);
};
// table
const tableChanged = (item: any) => {
state.ruleForm.tableName = item.entityName;
state.ruleForm.busName = item.tableComment;
state.ruleForm.tableUniqueList = [];
getColumnInfoList(item);
const tableChanged = async (configId: string, item: any, type: string) => {
if (typeof item === `string`) item = state.tableData.find((i: any) => i.entityName == item || i.tableName == item);
if (type == 'tree') {
store.ruleForm.treeConfig ??= {} as any;
store.ruleForm.treeConfig!.tableComment = item?.tableComment ?? undefined;
store.ruleForm.treeConfig!.entityName = item?.entityName ?? undefined;
if (store.ruleForm.treeConfig!.tableName != item?.tableName) {
store.ruleForm.treeConfig!.tableName = item?.tableName ?? undefined;
store.ruleForm.treeConfig!.displayPropertyNames = undefined as any;
store.ruleForm.treeConfig!.parentPropertyName = undefined;
store.ruleForm.treeConfig!.searchPropertyName = undefined;
store.ruleForm.treeConfig!.linkPropertyName = undefined as any;
}
}
// else if (type == 'tableRelationship') {
// store.ruleForm.configObj.entityName = item?.entityName ?? undefined;
// store.ruleForm.configObj.tableName = item?.tableName ?? undefined;
// store.ruleForm.configObj.propertyName1 = undefined;
// store.ruleForm.configObj.propertyName2 = undefined;
// }
state.columnList = (await store.columnListBy(configId, item?.tableName)) ?? [];
};
const tabTypeChanged = async (item: any) => {
state.ruleForm.tabType = item;
};
const treeNameChanged = (item: any) => {
state.ruleForm.treeName = item.columnName;
};
const treeKeyChanged = (item: any) => {
state.ruleForm.treeKey = item.columnName;
};
const leftTableChanged = (item: any) => {
state.ruleForm.leftTab = item.entityName;
console.log('leftTableChanged--', JSON.stringify(item));
getLColumnInfoList(item);
};
const leftKeyChanged = (item: any) => {
console.log('leftKeyChanged--', JSON.stringify(item));
state.ruleForm.leftKey = item.columnName;
};
const leftPrimaryKeyChanged = (item: any) => {
console.log('leftPrimaryKeyChanged--', JSON.stringify(item));
state.ruleForm.leftPrimaryKey = item.columnName;
};
const leftNameChanged = (item: any) => {
state.ruleForm.leftName = item.columnName;
};
const getLColumnInfoList = async (item: any) => {
if (state.ruleForm.configId2 == '' || state.ruleForm.configId2 == null || state.ruleForm.leftTab == '' || state.ruleForm.leftTab == null) return;
state.lcolumnData =
(await getAPI(SysCodeGenApi)
.apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(item.tableName, state.ruleForm.configId2)
.then((res) => res.data.result)) ?? [];
};
const bottomTableChanged = (item: any) => {
state.ruleForm.bottomTab = item.entityName;
getLBColumnInfoList(item);
};
const bottomKeyChanged = (item: any) => {
state.ruleForm.bottomKey = item.columnName;
};
const bottomPrimaryKeyChanged = (item: any) => {
console.log('bottomPrimaryKeyChanged--', JSON.stringify(item));
state.ruleForm.bottomPrimaryKey = item.columnName;
};
const getLBColumnInfoList = async (item: any) => {
if (state.ruleForm.configId3 == '' || state.ruleForm.configId3 == null || state.ruleForm.bottomTab == '' || state.ruleForm.bottomTab == null) return;
state.bcolumnData =
(await getAPI(SysCodeGenApi)
.apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(item.tableName, state.ruleForm.configId3)
.then((res) => res.data.result)) ?? [];
};
//
const changeTableUniqueColumn = (value: any, index: number) => {
if (value?.length === 1 && !state.ruleForm.tableUniqueList[index].message) {
state.ruleForm.tableUniqueList[index].message = state.columnData.find((u: any) => u.columnName === value[0])?.columnComment;
//
const changeTreePropertyName = (item: any, type: string) => {
if (type == 'display') {
store.ruleForm.treeConfig!.displayPropertyNames = item.propertyName;
//store.ruleForm!.treeConfig!.displayPropertyType = item.netType;
} else if (type == 'link') {
store.ruleForm.treeConfig!.linkPropertyName = item.propertyName;
store.ruleForm!.treeConfig!.linkPropertyType = item.netType;
} else if (type == 'search') {
store.ruleForm.treeConfig!.searchPropertyName = item.propertyName;
store.ruleForm!.treeConfig!.searchPropertyType = item.netType;
} else if (type == 'parent') {
store.ruleForm.treeConfig!.parentPropertyName = item.propertyName;
store.ruleForm!.treeConfig!.parentPropertyType = item.netType;
}
};
const getColumnInfoList = async (item: any) => {
if (state.ruleForm.configId == '' || state.ruleForm.configId == null || state.ruleForm.tableName == '' || state.ruleForm.tableName == null) return;
state.columnData =
(await getAPI(SysCodeGenApi)
.apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(item.tableName, state.ruleForm.configId)
.then((res) => res.data.result)) ?? [];
};
//
const menuChange = (menu: any) => {
state.ruleForm.pagePath = state.menuData.find((x) => x.id == menu)?.name;
};
// print
const printTypeChanged = () => {
if (state.ruleForm.printType === '') return;
if (state.ruleForm.printType == 'off') state.ruleForm.printName = '';
};
//
const getGlobalComponentSize = computed(() => {
return other.globalComponentSize();
});
//
const openDialog = (row: any) => {
state.ruleForm = JSON.parse(JSON.stringify(row));
dbChanged().then(() => getColumnInfoList(row));
state.isShowDialog = true;
ruleFormRef.value?.resetFields();
getSysCodeGenTemplateList();
const openDialog = async (row: any) => {
store.enabledWatch = !!row?.id;
try {
state.loading = true;
state.activeTab = '0';
ruleFormRef.value?.resetFields();
state.title = (row.id ? '编辑' : '新增') + '代码生成';
store.ruleForm = row?.id ? await store.getDetail(row.id) : row;
store.ruleForm.nameSpace ??= store.namespaceList?.[0] as any;
state.isShowDialog = true;
} finally {
nextTick(() => {
store.enabledWatch = true;
// store.ruleForm.scene ??= 1000;
});
state.loading = false;
}
};
//
const closeDialog = () => {
emits('handleQuery');
state.isShowDialog = false;
activeTab.value = 'codeGen';
};
//
const cancel = () => {
state.isShowDialog = false;
activeTab.value = 'codeGen';
};
//
const submit = () => {
//
if (multipleSelection.value.length == 0) {
ElMessage({
message: `请选择模板`,
type: 'error',
});
activeTab.value = 'template';
return;
}
let codeGenTemplateIds: any[] = [];
multipleSelection.value.forEach((item: any) => {
codeGenTemplateIds.push(item.id);
store.ruleForm.busName ??= store.ruleForm.tableList?.[0]?.busName;
const data = Object.assign(store.ruleForm, {
moduleName: store.ruleForm.moduleName ?? store.ruleForm.tableList?.[0]?.moduleName,
});
state.ruleForm.codeGenTemplateIds = codeGenTemplateIds;
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
if (state.ruleForm.tableUniqueList?.length === 0) state.ruleForm.tableUniqueList = null;
if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
await getAPI(SysCodeGenApi).apiSysCodeGenUpdatePost(state.ruleForm as UpdateCodeGenInput);
ruleFormRef.value.validate(async (isValid: boolean, fields?: any) => {
if (isValid) {
data.treeConfig = <number>data.scene % 100 == 10 ? data.treeConfig : undefined;
await store.save(data);
closeDialog();
} else {
await getAPI(SysCodeGenApi).apiSysCodeGenAddPost(state.ruleForm as AddCodeGenInput);
ElMessage({
message: `表单有${Object.keys(fields).length}处验证失败,请修改后再提交`,
type: 'error',
});
}
closeDialog();
});
};
@ -607,4 +343,7 @@ defineExpose({ openDialog });
:deep(.el-dialog__body) {
min-height: 450px;
}
:deep(.el-overlay) {
z-index: 999 !important;
}
</style>

View File

@ -0,0 +1,167 @@
<template>
<div class="sys-linkTableConfig-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span v-if="state.type == 'tree'"> 树选择配置 </span>
<span v-if="state.type == 'fk'"> 外键配置 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="库定位器" prop="configId" :rules="[{ required: true, message: '库定位器不能为空', trigger: 'blur' }]">
<el-select clearable v-model="state.ruleForm.configId" placeholder="库名" filterable @change="dbChanged()" class="w100">
<el-option v-for="item in store.databaseList" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="数据库表" prop="tableName" :rules="[{ required: true, message: '数据库表不能为空', trigger: 'blur' }]">
<el-select v-model="state.ruleForm.tableName" @change="tableChanged" filterable clearable class="w100">
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.tableName + ' [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="显示字段" prop="displayPropertyNames" :rules="[{ required: true, message: '显示字段不能为空', trigger: 'blur' }]">
<el-select v-model="state.ruleForm.displayPropertyNames" @change="(val: any) => changePropertyName(val, 'display')" filterable class="w100">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.propertyName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="值字段" prop="linkPropertyName" :rules="[{ required: true, message: '值字段不能为空', trigger: 'blur' }]">
<el-select v-model="state.ruleForm.linkPropertyName" @change="(val: any) => changePropertyName(val, 'link')" filterable class="w100">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col v-if="state.type == 'tree'" :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="父级字段" prop="parentPropertyName">
<el-select v-model="state.ruleForm.parentPropertyName" @change="(val: any) => changePropertyName(val, 'parent')" filterable clearable class="w100">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="查询字段" prop="searchPropertyName">
<el-select v-model="state.ruleForm.searchPropertyName" @change="(val: any) => changePropertyName(val, 'search')" filterable class="w100">
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="rowData.netType.startsWith('string')">
<el-form-item label="是否多选" prop="multiple" :rules="[{ required: true, message: '是否多选不能为空', trigger: 'blur' }]">
<el-radio-group v-model="state.ruleForm.multiple" filterable>
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="快捷设置">
<el-button v-if="state.type == 'tree'" type="primary" icon="ele-Search" plain @click="handelQuickConfig('sysOrg')">组织机构选择器</el-button>
<el-button v-else type="primary" icon="ele-Search" plain @click="handelQuickConfig('sysUser')">系统账号选择器</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<!-- 外键配置 -->
<script lang="ts" setup name="sysLinkTableConfig">
import { reactive, ref } from 'vue';
import { useCodeGenStore } from './codeGenStore';
let rowData = {} as any;
const store = useCodeGenStore();
const emits = defineEmits(['submitData']);
const ruleFormRef = ref();
const state = reactive({
type: 'fk' as 'fk' | 'tree',
isShowDialog: false,
ruleForm: {} as any,
dbData: [] as any,
tableData: [] as any,
columnList: [] as any,
});
const changePropertyName = (item: any, type: string) => {
state.ruleForm[type + 'PropertyName'] = item.propertyName;
state.ruleForm[type + 'PropertyType'] = item.netType;
};
const dbChanged = async () => {
state.tableData = await store.tableListBy(state.ruleForm.configId);
};
const tableChanged = async (item: any) => {
state.ruleForm.displayPropertyNames = undefined;
state.ruleForm.parentPropertyName = undefined;
state.ruleForm.searchPropertyName = undefined;
state.ruleForm.linkPropertyName = undefined;
state.ruleForm.tableComment = item.tableComment;
state.ruleForm.entityName = item.entityName;
state.ruleForm.tableName = item.tableName;
state.columnList = await store.columnListBy(state.ruleForm.configId, state.ruleForm.tableName);
};
const handelQuickConfig = (type: string) => {
if (store.quickConfigMap && store.quickConfigMap[type]) {
state.ruleForm = Object.assign({}, store.quickConfigMap[type]);
}
};
//
const openDialog = async (row: any, type: 'fk' | 'tree') => {
rowData = row;
state.type = type;
state.isShowDialog = true;
state.ruleForm.multiple ??= false;
state.ruleForm.useTable ??= false;
state.ruleForm = Object.assign({}, row.config);
if (state.ruleForm.configId) {
dbChanged().then(async () => {
if (state.ruleForm.tableName) {
state.columnList = await store.columnListBy(state.ruleForm.configId, state.ruleForm.tableName);
}
});
}
};
//
const closeDialog = () => {
if (!rowData.netType.startsWith('string')) state.ruleForm.multiple = false;
rowData.config = Object.assign({}, state.ruleForm);
emits('submitData', rowData);
cancel();
};
//
const cancel = () => {
state.isShowDialog = false;
ruleFormRef.value?.resetFields();
state.ruleForm = {};
};
//
const submit = () => {
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
closeDialog();
});
};
//
defineExpose({ openDialog });
</script>

View File

@ -1,155 +0,0 @@
<template>
<div class="sys-codeGenFk-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 外键配置 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="库定位器" prop="configId">
<el-select clearable v-model="state.ruleForm.configId" placeholder="库名" filterable @change="DbChanged()" class="w100">
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="数据库表" prop="tableName">
<el-select v-model="state.ruleForm.tableName" filterable clearable @change="TableChanged()" class="w100">
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.entityName + ' ( ' + item.tableName + ' )[' + item.tableComment + ']'" :value="item.tableName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="显示字段" prop="columnName">
<el-select v-model="state.ruleForm.columnName" filterable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="链接字段" prop="linkColumnName">
<el-select v-model="state.ruleForm.linkColumnName" filterable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="sysCodeGenFk">
import { onMounted, reactive, ref } from 'vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenApi } from '/@/api-services/system/api';
var rowdata = {} as any;
const emits = defineEmits(['submitRefreshFk']);
const ruleFormRef = ref();
const state = reactive({
isShowDialog: false,
ruleForm: {} as any,
dbData: [] as any,
tableData: [] as any,
columnData: [] as any,
});
onMounted(async () => {
await getDbList();
// 使
//state.ruleForm.configId = state.dbData[0].configId;
//await DbChanged();
});
const DbChanged = async () => {
state.tableData = [];
state.columnData = [];
await getTableInfoList();
};
const TableChanged = async () => {
state.columnData = [];
await getColumnInfoList();
};
const getDbList = async () => {
var res = await getAPI(SysCodeGenApi).apiSysCodeGenDatabaseListGet();
state.dbData = res.data.result;
};
const getTableInfoList = async () => {
if (state.ruleForm.configId == '') return;
var res = await getAPI(SysCodeGenApi).apiSysCodeGenTableListConfigIdGet(state.ruleForm.configId);
state.tableData = res.data.result;
};
const getColumnInfoList = async () => {
if (state.ruleForm.configId == '' || state.ruleForm.tableName == '') return;
console.log(state.ruleForm.configId, state.ruleForm.tableName);
var res = await getAPI(SysCodeGenApi).apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(state.ruleForm.tableName, state.ruleForm.configId);
state.columnData = res.data.result;
};
//
const openDialog = async (row: any) => {
rowdata = row;
if (rowdata.fkConfigId) {
await getDbList();
state.ruleForm.tableName = rowdata.fkTableName;
state.ruleForm.columnName = rowdata.fkColumnName;
state.ruleForm.linkColumnName = rowdata.fkLinkColumnName;
state.ruleForm.configId = rowdata.fkConfigId;
await DbChanged();
await TableChanged();
}
state.isShowDialog = true;
};
//
const closeDialog = () => {
rowdata.fkTableName = state.ruleForm.tableName;
let tableData = state.tableData.filter((x: any) => x.tableName == state.ruleForm.tableName);
rowdata.fkEntityName = tableData.length == 0 ? '' : tableData[0].entityName;
rowdata.fkColumnName = state.ruleForm.columnName;
rowdata.fkLinkColumnName = state.ruleForm.linkColumnName;
rowdata.fkConfigId = state.ruleForm.configId;
let columnData = state.columnData.filter((x: any) => x.columnName == state.ruleForm.columnName);
rowdata.fkColumnNetType = columnData.length == 0 ? '' : columnData[0].netType;
emits('submitRefreshFk', rowdata);
cancel();
};
//
const cancel = () => {
state.isShowDialog = false;
ruleFormRef.value?.resetFields();
state.ruleForm = {};
state.dbData.value = [];
state.tableData.value = [];
state.columnData.value = [];
};
//
const submit = () => {
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
closeDialog();
});
};
//
defineExpose({ openDialog });
</script>

View File

@ -1,465 +0,0 @@
<template>
<div class="sys-codeGenConfig-container">
<vxe-modal v-model="state.isShowDialog" title="生成配置" :width="800" :height="350" show-footer show-zoom resize fullscreen @close="cancel">
<template #default>
<vxe-grid ref="xGrid" class="xGrid-table-style" v-bind="options">
<template #drag_default="{}">
<span class="drag-btn">
<i class="fa fa-arrows"></i>
</span>
</template>
<template #effectType="{ row, $index }">
<vxe-select v-model="row.effectType" class="m-2" style="width: 70%" placeholder="Select" transfer :disabled="judgeColumns(row)" @change="effectTypeChange(row, $index)" filterable>
<vxe-option v-for="item in state.effectTypeList" :key="item.value" :label="item.label" :value="item.value" />
</vxe-select>
<vxe-button v-if="row.effectType === 'ApiTreeSelector' || row.effectType === 'ForeignKey'" style="width: 30%" icon="vxe-icon-edit" @click="effectTypeChange(row, $index)">修改</vxe-button>
</template>
<template #columnComment="{ row }">
<vxe-input v-model="row.columnComment" autocomplete="off" />
</template>
<template #dictType="{ row }">
<vxe-select v-model="row.dictTypeCode" class="m-2" :disabled="effectTypeEnable(row)" filterable transfer>
<vxe-option v-for="item in state.dictTypeCodeList" :key="item.code" :label="item.name" :value="item.code" />
</vxe-select>
</template>
<template #whetherTable="{ row }">
<vxe-checkbox v-model="row.whetherTable"></vxe-checkbox>
</template>
<template #whetherAddUpdate="{ row }">
<vxe-checkbox v-model="row.whetherAddUpdate" :disabled="judgeColumns(row)"></vxe-checkbox>
</template>
<template #whetherSortable="{ row }">
<vxe-checkbox v-model="row.whetherSortable"></vxe-checkbox>
</template>
<template #whetherRequired="{ row }">
<vxe-tag v-if="row.whetherRequired" status="success"></vxe-tag>
<vxe-tag v-else status="info"></vxe-tag>
</template>
<template #statistical="{ row }">
<vxe-switch v-model="row.statistical" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
</template>
<template #isGroupBy="{ row }">
<vxe-switch v-model="row.isGroupBy" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
</template>
<template #queryWhether="{ row }">
<vxe-switch v-model="row.queryWhether" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
</template>
<template #queryType="{ row }">
<vxe-select v-model="row.queryType" class="m-2" placeholder="Select" :disabled="!row.queryWhether" filterable transfer>
<vxe-option v-for="item in state.queryTypeList" :key="item.value" :label="item.label" :value="item.value" />
</vxe-select>
</template>
<template #verification="{ row }">
<vxe-button status="primary" plain v-if="row.columnKey === 'False' && !row.whetherCommon" @click="openVerifyDialog(row)">校验规则{{ row.ruleCount }}</vxe-button>
<span v-else></span>
</template>
</vxe-grid>
</template>
<template #footer>
<vxe-button icon="ele-CircleCloseFilled" @click="cancel"> </vxe-button>
<vxe-button status="primary" icon="ele-CircleCheckFilled" @click="submit"> </vxe-button>
</template>
</vxe-modal>
<fkDialog ref="fkDialogRef" @submitRefreshFk="submitRefreshFk" />
<treeDialog ref="treeDialogRef" @submitRefreshFk="submitRefreshFk" />
<verifyDialog ref="verifyDialogRef" @submitVerify="submitVerifyOk" />
</div>
</template>
<script lang="ts" setup name="sysCodeGenConfig">
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
import mittBus from '/@/utils/mitt';
import Sortable from 'sortablejs';
import { VxeGridInstance, VxeGridProps } from 'vxe-table';
import fkDialog from '/@/views/system/codeGen/component/fkDialog.vue';
import treeDialog from '/@/views/system/codeGen/component/treeDialog.vue';
import verifyDialog from '/@/views/system/codeGen/component/verifyDialog.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenConfigApi, SysConstApi, SysDictDataApi, SysDictTypeApi, SysEnumApi } from '/@/api-services/system/api';
const xGrid = ref<VxeGridInstance<any>>();
const emits = defineEmits(['handleQuery']);
const fkDialogRef = ref();
const treeDialogRef = ref();
const verifyDialogRef = ref();
const state = reactive({
isShowDialog: false,
loading: false,
EntityName: '',
ConfigId: '',
dbData: [] as any,
effectTypeList: [] as any,
dictTypeCodeList: [] as any,
dictDataAll: [] as any,
queryTypeList: [] as any,
allConstSelector: [] as any,
allEnumSelector: [] as any,
sortable: undefined as any,
});
//
const options = reactive<VxeGridProps>({
id: 'genConfigDialog',
height: 'auto',
keepSource: true,
autoResize: true,
loading: false,
align: 'center',
rowConfig: { useKey: true },
seqConfig: { seqMethod: ({ row }) => row.orderNo },
columns: [
{
width: 50,
slots: {
default: 'drag_default',
},
},
{
field: 'orderNo',
title: '排序',
minWidth: 80,
showOverflow: 'tooltip',
},
{
field: 'columnName',
title: '字段',
minWidth: 160,
showOverflow: 'tooltip',
},
{
field: 'columnComment',
title: '描述',
minWidth: 120,
showOverflow: 'tooltip',
slots: {
edit: 'columnComment',
default: 'columnComment',
},
},
{
field: 'netType',
title: '数据类型',
minWidth: 90,
},
{
field: 'effectType',
title: '作用类型',
minWidth: 160,
slots: {
edit: 'effectType',
default: 'effectType',
},
},
{
field: 'dictTypeCode',
title: '字典',
minWidth: 180,
slots: {
edit: 'dictType',
default: 'dictType',
},
},
{
field: 'whetherTable',
title: '列表显示',
minWidth: 70,
slots: {
edit: 'whetherTable',
default: 'whetherTable',
},
},
{
field: 'whetherAddUpdate',
title: '增改',
minWidth: 70,
slots: {
edit: 'whetherAddUpdate',
default: 'whetherAddUpdate',
},
},
{
field: 'whetherRequired',
title: '必填',
minWidth: 70,
slots: {
edit: 'whetherRequired',
default: 'whetherRequired',
},
},
{
field: 'whetherSortable',
title: '可排序',
minWidth: 70,
slots: {
edit: 'whetherSortable',
default: 'whetherSortable',
},
},
{
field: 'statistical',
title: '统计字段',
minWidth: 70,
slots: {
edit: 'statistical',
default: 'statistical',
},
},
{
field: 'isGroupBy',
title: 'GroupBy',
minWidth: 70,
slots: {
edit: 'isGroupBy',
default: 'isGroupBy',
},
},
{
field: 'queryWhether',
title: '是否是查询',
minWidth: 70,
slots: {
edit: 'queryWhether',
default: 'queryWhether',
},
},
{
field: 'queryType',
title: '查询方式',
minWidth: 120,
slots: {
edit: 'queryType',
default: 'queryType',
},
},
{
title: '校验规则',
width: 130,
showOverflow: true,
slots: {
edit: 'verification',
default: 'verification',
},
},
],
editConfig: { trigger: 'click', mode: 'row', showStatus: true },
});
const rowDrop = () => {
const el = document.querySelector('.xGrid-table-style .vxe-table--body tbody') as HTMLElement;
state.sortable = Sortable.create(el, {
animation: 300,
handle: '.drag-btn',
onEnd: (sortableEvent: any) => {
const fullData = xGrid.value?.getTableData().fullData || [];
const newIndex = sortableEvent.newIndex as number;
const oldIndex = sortableEvent.oldIndex as number;
var orderNo = fullData[newIndex - 1].orderNo;
fullData[newIndex].orderNo = orderNo! + 10;
const currentRow = fullData.splice(oldIndex, 1)[0];
fullData.splice(newIndex, 0, currentRow);
fullData.forEach((u, i) => (u.orderNo = 100 + i * 10));
//
xGrid.value?.loadData(fullData);
},
});
};
//
onMounted(async () => {
//
var res = await getAPI(SysDictDataApi).apiSysDictDataDataListCodeGet('code_gen_effect_type');
state.effectTypeList = res.data.result;
//
var res1 = await getAPI(SysDictTypeApi).apiSysDictTypeListGet();
state.dictTypeCodeList = res1.data.result;
state.dictDataAll = res1.data.result;
//
var res2 = await getAPI(SysDictDataApi).apiSysDictDataDataListCodeGet('code_gen_query_type');
state.queryTypeList = res2.data.result;
//
var res3 = await getAPI(SysConstApi).apiSysConstListGet();
state.allConstSelector = res3.data.result;
//
let resEnum = await getAPI(SysEnumApi).apiSysEnumEnumTypeListGet();
state.allEnumSelector = resEnum.data.result?.map((item) => ({ ...item, name: `${item.typeDescribe} [${item.typeName?.replace('Enum', '')}]`, code: item.typeName }));
mittBus.on('submitRefreshFk', (data: any) => {
let tableData = xGrid.value?.getData() || [];
tableData[data.index] = data;
xGrid.value?.loadData(tableData);
});
});
//
const submitRefreshFk = (data: any) => {
let tableData = xGrid.value?.getData() || [];
tableData[data.index] = data;
xGrid.value?.reloadData(tableData);
};
//
onUnmounted(() => {
// mittBus.off('submitRefresh', () => {});
mittBus.off('submitRefreshFk', () => {});
});
//
const effectTypeChange = (data: any, index: number) => {
let value = data.effectType;
if (value === 'ForeignKey') {
openFkDialog(data, index);
} else if (value === 'ApiTreeSelector') {
openTreeDialog(data, index);
} else if (value === 'DictSelector') {
data.dictTypeCode = '';
state.dictTypeCodeList = state.dictDataAll;
} else if (value === 'ConstSelector') {
data.dictTypeCode = '';
state.dictTypeCodeList = state.allConstSelector;
} else if (value == 'EnumSelector') {
data.dictTypeCode = '';
state.dictTypeCodeList = state.allEnumSelector;
}
};
//
const handleQuery = async (row: any) => {
state.loading = true;
var res = await getAPI(SysCodeGenConfigApi).apiSysCodeGenConfigListGet(undefined, row.id);
var data = res.data.result ?? [];
let lstWhetherColumn = ['whetherTable', 'whetherAddUpdate', 'whetherRequired', 'whetherSortable']; //checkbox
data.forEach((item: any) => {
for (const key in item) {
if (item[key] === 'Y') {
item[key] = true;
}
if (item[key] === 'N' || (lstWhetherColumn.includes(key) && item[key] === null)) {
item[key] = false;
}
}
//
let rules = new Array();
if (item.rules != '' && item.rules !== null) {
rules = JSON.parse(item.rules);
}
item.ruleCount = rules.length > 0 ? `${rules.length}` : '';
});
xGrid.value?.loadData(data);
state.loading = false;
};
//
function judgeColumns(data: any) {
return data.whetherCommon == true || data.columnKey === 'True';
}
function effectTypeEnable(data: any) {
return !['Radio', 'Checkbox', 'DictSelector', 'ConstSelector', 'EnumSelector'].some((e: any) => e === data.effectType);
}
//
const openDialog = async (addRow: any) => {
state.isShowDialog = true;
state.ConfigId = addRow.configId;
state.EntityName = addRow.tableName;
nextTick(async () => {
await handleQuery(addRow);
rowDrop();
});
};
//
const openFkDialog = (addRow: any, index: number) => {
addRow.index = index;
fkDialogRef.value.openDialog(addRow);
};
const openTreeDialog = (addRow: any, index: number) => {
addRow.index = index;
treeDialogRef.value.openDialog(addRow);
};
//
const openVerifyDialog = (row: any) => {
// handleQuery(addRow);
// state.isShowDialog = true;
verifyDialogRef.value.openDialog(row);
};
//
const submitVerifyOk = (data: any) => {
let tableData = xGrid.value?.getData() || [];
for (let i = 0; i < tableData.length; i++) {
if (tableData[i].id == data.id) {
tableData[i].rules = data.rules;
tableData[i].ruleCount = data.ruleCount;
//
let rules = new Array();
if (data.rules != '' && data.rules !== null) {
rules = JSON.parse(data.rules);
let requiredRule = rules.find((t) => t.type === 'required');
if (requiredRule) {
tableData[i].whetherRequired = true;
} else {
tableData[i].whetherRequired = false;
}
}
break;
}
}
xGrid.value?.reloadData(tableData);
};
//
const closeDialog = () => {
emits('handleQuery');
cancel();
};
//
const cancel = () => {
xGrid.value?.loadData([]);
state.isShowDialog = false;
if (state.sortable) {
state.sortable.destroy();
}
};
//
const submit = async () => {
state.loading = true;
let lst = xGrid.value?.getData() || [];
let ignoreFields = ['remoteVerify', 'anyRule', 'columnKey'];
lst.forEach((item: any) => {
//
for (var key in item) {
if (item[key] === true && !ignoreFields.includes(key)) {
item[key] = 'Y';
}
if (item[key] === false && !ignoreFields.includes(key)) {
item[key] = 'N';
}
}
});
await getAPI(SysCodeGenConfigApi).apiSysCodeGenConfigUpdatePost(lst);
state.loading = false;
closeDialog();
};
//
defineExpose({ openDialog });
</script>
<style lang="scss" scoped>
.xGrid-table-style .drag-btn {
cursor: move;
font-size: 20px;
}
</style>

View File

@ -1,343 +0,0 @@
<template>
<div class="sys-codeGenConfig-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 选择正则 </span>
</div>
</template>
<div class="pattern-box">
<div class="pattern-item" v-for="(item, index) in patternData" :key="index" :class="{ active: state.index == index }" @click="handlePatternClick(item, index)">
<div class="title">{{ item.title }}</div>
<div class="info">{{ item.info }}</div>
<div class="pattern">{{ item.pattern }}</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { ElMessage } from 'element-plus';
const patternData = ref([
{
title: '手机号',
info: '',
pattern: '/^1[3,4,5,6,7,8,9][0-9]{9}$/',
},
{
title: '邮箱',
info: '',
pattern: '/^([a-zA-Z]|[0-9])(\\w|\\-)+@[a-zA-Z0-9]+\\.([a-zA-Z]{2,4})$/',
},
{
title: '网址',
info: '',
pattern: '/^http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?$/',
},
{
title: '字母/数字/下划线',
info: '',
pattern: '/^\\w+$/',
},
{
title: '中英文/数字/下划线',
info: '',
pattern: '/^[\\u4e00-\\u9fa5_a-zA-Z0-9]+$/',
},
{
title: '中文/英文',
info: '',
pattern: '/^[\\u4e00-\\u9fa5a-zA-Z]+$/',
},
{
title: '规范金额',
info: '',
pattern: '/(^[\\d]|^[1-9][\\d]*)($|[\\.][\\d]{0,2}$)/',
},
{
title: '用户名不能全是数字',
info: '',
pattern: '/[^\\d]/g',
},
{
title: '中文',
info: '',
pattern: '/^[\\u4e00-\\u9fa5]+$/',
},
{
title: '非中文',
info: '',
pattern: '/^[^\\u4e00-\\u9fa5]*$/',
},
{
title: '限制长度',
info: '',
pattern: '/^\\d{1,20}$/',
},
{
title: '数字',
info: '',
pattern: '/^[0-9]*$/',
},
{
title: '正整数及整数',
info: '',
pattern: '/^[1-9]\\d*$/',
},
{
title: '数字(可正负)',
info: '',
pattern: '/^-[0-9]*[1-9][0-9]*$/',
},
{
title: '数字/小数点',
info: '',
pattern: '/^\\d+$|^\\d*\\.\\d+$/',
},
{
title: '合法IP地址',
info: '',
pattern: '/^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$/',
},
{
title: '手机号码或者固话',
info: '',
pattern: '/^((0\\d{2,3}-\\d{7,8})|(1[3456789]\\d{9}))$/',
},
{
title: '身份证号码',
info: '',
pattern: '/(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)/',
},
{
title: '大写字母',
info: '',
pattern: '/^[A-Z]+$/',
},
{
title: '小写字母',
info: '',
pattern: '/^[a-z]+$/',
},
{
title: '大小写混合',
info: '',
pattern: '/^[A-Za-z]+$/',
},
{
title: '多个8位数字格式(yyyyMMdd)并以逗号隔开',
info: '',
pattern: '/^\\d{8}(\\,\\d{8})*$/',
},
{
title: '数字加英文',
info: '',
pattern: '/^[a-zA-Z0-9]+$/',
},
{
title: '前两位是数字后一位是英文',
info: '',
pattern: '/^\\d{2}[a-zA-Z]+$/',
},
{
title: '1到100的数字',
info: '',
pattern: '/^[0-9]\\d{0,1}$/',
},
{
title: '1-1000两位小数',
info: '',
pattern: '/^(.*[^0-9]|)(1000|[1-9]\\d{0,2})([^0-9].*|)$/',
},
{
title: '小数点后只能有两位数(可为0)',
info: '',
pattern: '/^(-?\\d+)(\\.\\d{1,2})?$/',
},
{
title: '密码正则',
info: '以字母开头长度在6~18之间只能包含字母、数字和下划线',
pattern: '/^[a-zA-Z]\\w{5,17}$/',
},
{
title: '强密码',
info: '必须包含大小写字母和数字的组合不能使用特殊字符长度在8-10之间',
pattern: '/^(?=.\\d)(?=.[a-z])(?=.[A-Z]).{8,10}$/',
},
{
title: '强密码',
info: '最少6位包括至少1个大写字母1个小写字母1个数字1个特殊字符',
pattern: '/^.*(?=.{6,})(?=.*\\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/',
},
{
title: 'QQ号码',
info: '',
pattern: '/^[1-9][0-9]{4,12}$/',
},
{
title: '微信号码',
info: '',
pattern: '/^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/',
},
{
title: '域名',
info: '',
pattern: '/^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?$/',
},
{
title: '车牌号码',
info: '',
pattern: '/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/',
},
{
title: '护照',
info: '',
pattern: '/^(P\\d{7}|G\\d{7,8}|TH\\d{7,8}|S\\d{7,8}|A\\d{7,8}|L\\d{7,8}|\\d{9}|D\\d+|1[4,5]\\d{7})$/',
},
{
title: '固定电话',
info: '',
pattern: '/^(\\(\\d{3,4}\\)|\\d{3,4}-|\\s)?\\d{8}$/',
},
{
title: '邮政编码',
info: '',
pattern: '/^[1-9]{1}(\\d+){5}$/',
},
{
title: '经度',
info: '',
pattern: '/^(\\-|\\+)?(((\\d|[1-9]\\d|1[0-7]\\d|0{1,3})\\.\\d{0,6})|(\\d|[1-9]\\d|1[0-7]\\d|0{1,3})|180\\.0{0,6}|180)$/',
},
{
title: '纬度',
info: '',
pattern: '/^(\\-|\\+)?([0-8]?\\d{1}\\.\\d{0,6}|90\\.0{0,6}|[0-8]?\\d{1}|90)$/',
},
{
title: '正整数 + 0',
info: '',
pattern: '/^\\d+$/',
},
{
title: '正整数',
info: '',
pattern: '/^[0-9]*[1-9][0-9]*$/',
},
{
title: '负整数 + 0',
info: '',
pattern: '/^((-\\d+)|(0+))$/',
},
{
title: '负整数',
info: '',
pattern: '/^-[0-9]*[1-9][0-9]*$/',
},
{
title: '匹配整数',
info: '',
pattern: '/^-?\\d+$/',
},
]);
const state = reactive({
isShowDialog: false,
loading: false,
selectPattern: null,
index: -1,
});
const emit = defineEmits(['submitPattern']);
//
const openDialog = () => {
state.isShowDialog = true;
};
//
const closeDialog = () => {
state.isShowDialog = false;
};
//
const cancel = () => {
closeDialog();
};
const handlePatternClick = (item: any, index: number) => {
state.selectPattern = item;
state.index = index;
ElMessage({
message: `点击确定完成操作!`,
type: 'success',
});
};
//
const submit = async () => {
emit('submitPattern', state.selectPattern);
closeDialog();
};
//
defineExpose({ openDialog });
</script>
<style lang="scss" scoped>
.pattern-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
height: 400px;
overflow-y: auto;
padding: 0px 10px;
.pattern-item {
width: 48%;
border: 1px solid #d9d9d9;
box-sizing: border-box;
padding: 10px;
border-radius: 5px;
cursor: pointer;
flex-shrink: 0;
margin: 5px 0px;
.title {
font-weight: 700;
}
.info {
font-size: 12px;
margin-top: 5px;
}
.pattern {
font-size: 10px;
margin-top: 5px;
background: #1d1f21;
padding: 3px 5px;
color: #d9d9d9;
border-radius: 3px;
}
&:hover {
//border: 1px solid red;
box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.2);
}
}
}
.active {
border: 1px solid red !important;
}
</style>

View File

@ -17,10 +17,10 @@
</template>
</el-segmented>
</div>
<div ref="monacoEditorRef" style="width: 100%; height: 700px; margin-top: 6px"></div>
<div ref="monacoEditorRef" style="width: 100%; height: 80vh; margin-top: 6px"></div>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-Close" @click="cancel"></el-button>
<el-button icon="ele-CircleCloseFilled" @click="cancel"></el-button>
<el-button icon="ele-CopyDocument" type="primary" @click="handleCopy"> </el-button>
</span>
</template>
@ -28,6 +28,7 @@
</div>
</template>
<!-- 代码预览 -->
<script lang="ts" setup name="sysPreviewCode">
import { reactive, ref, nextTick } from 'vue';
import * as monaco from 'monaco-editor';
@ -38,6 +39,7 @@ import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenApi } from '/@/api-services/system/api';
const { copyText } = commonFunction();
const props = defineProps({
title: String,
});
@ -86,14 +88,14 @@ const initMonacoEditor = () => {
//
const openDialog = async (row: any) => {
state.isShowDialog = true;
const { data } = await getAPI(SysCodeGenApi).apiSysCodeGenPreviewPost(row);
const { data } = await getAPI(SysCodeGenApi).apiSysCodeGenPreviewPost({ id: row.id });
state.codes = data.result ?? [];
state.options = Object.keys(data.result as any).map((fileName: string) => ({
value: fileName,
icon: fileName?.endsWith('.cs') ? 'fa fa-hashtag' : fileName?.endsWith('.vue') ? 'fa fa-vimeo' : 'fa fa-file-code-o',
}));
state.current = state.options?.[0]?.value ?? '';
if (monacoEditor == null) initMonacoEditor();
if (!monacoEditor) initMonacoEditor();
//
nextTick(() => {
monacoEditor.setValue(state.codes[state.current]);

View File

@ -1,256 +0,0 @@
<template>
<div class="sys-codeGenConfig-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="800px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 编辑规则 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-form-item style="display: none !important">
<el-input v-model="state.ruleForm.id" />
</el-form-item>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label=""> 本字段的数据库类型是{{ state.column.dataType }}.Net类型是{{ state.column.netType }} </el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="验证类型" prop="type" :rules="rules.type">
<el-select v-model="state.ruleForm.type" placeholder="请选择类型" @change="handleTypeChange">
<el-option v-for="(item, index) in validTypeData" :key="index" :label="item.name" :value="item.code" />
</el-select>
</el-form-item>
</el-col>
<template v-if="state.ruleForm.type == 'length' && (state.column.netType.includes('int') || state.column.netType.includes('long') || state.column.netType.includes('string'))">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="最小值" prop="min" :rules="rules.min">
<el-input-number v-model="state.ruleForm.min" :min="0" :max="100000" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="最大值" prop="max" :rules="rules.max">
<el-input-number v-model="state.ruleForm.max" :min="0" :max="100000" />
</el-form-item>
</el-col>
</template>
<template v-if="state.ruleForm.type == 'length' && (state.column.netType.includes('decimal') || state.column.netType.includes('float') || state.column.netType.includes('double'))">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="最小值" prop="min" :rules="rules.minDecimal">
<el-input-number v-model="state.ruleForm.min" :min="0" :max="100000" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="最大值" prop="max" :rules="rules.maxDecimal">
<el-input-number v-model="state.ruleForm.max" :min="0" :max="100000" />
</el-form-item>
</el-col>
</template>
<template v-if="state.ruleForm.type == 'length' && state.column.netType.includes('DateTime')">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="起始日期" prop="min" :rules="rules.minDate">
<el-date-picker v-model="state.ruleForm.min" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" placeholder="请选择起始日期" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="结束日期" prop="max" :rules="rules.maxDate">
<el-date-picker v-model="state.ruleForm.max" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" placeholder="请选择结束日期" />
</el-form-item>
</el-col>
</template>
<template v-if="state.ruleForm.type == 'pattern'">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="提示信息" prop="message" :rules="rules.message">
<el-input v-model="state.ruleForm.message" placeholder="请输入提示信息" maxlength="128" show-word-limit clearable />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="正则式" prop="pattern" :rules="rules.pattern">
<el-input v-model="state.ruleForm.pattern" placeholder="请输入正则表达式">
<template #append>
<el-button @click="openPatternDialog">选择正则</el-button>
</template>
</el-input>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
<patternDialog ref="patternDialogRef" @submit-pattern="submitPatternOK" />
</div>
</template>
<style lang="scss" scoped>
.tool-box {
padding-bottom: 20px;
display: flex;
gap: 20px;
align-items: center;
// background: red;
}
</style>
<script lang="ts" setup>
import { reactive, ref, toRaw } from 'vue';
import patternDialog from '/@/views/system/codeGen/component/patternDialog.vue';
import { ElMessage } from 'element-plus';
import type { FormRules } from 'element-plus';
const emit = defineEmits(['submitRule']);
//
const rules = ref<FormRules>({
type: [
{
required: true,
message: '请选择验证类型',
trigger: 'change',
},
],
min: [
{
type: 'integer',
required: true,
pattern: /[^\d]/g,
message: '请输入正确的数字',
trigger: 'blur',
},
],
minDecimal: [
{
required: true,
message: '请输入正确的数字',
trigger: 'blur',
},
],
minDate: [
{
required: true,
pattern: /^\d{4}-\d{2}-\d{2}$/,
message: '请选择起始日期',
trigger: ['change', 'blur'],
},
],
max: [
{
type: 'integer',
required: true,
pattern: /[^\d]/g,
message: '请输入正确的数字',
trigger: 'blur',
},
],
maxDecimal: [
{
required: true,
message: '请输入正确的数字',
trigger: 'blur',
},
],
maxDate: [
{
required: true,
pattern: /^\d{4}-\d{2}-\d{2}$/,
message: '请选择结束日期',
trigger: ['change', 'blur'],
},
],
message: [
{
required: true,
message: '请输入提示信息',
trigger: 'blur',
},
],
pattern: [{ required: true, message: '请输入正则表达式', trigger: 'blur' }],
});
const ruleFormRef = ref();
const patternDialogRef = ref();
const validTypeData = ref([
{ code: 'required', name: '必填验证' },
{ code: 'remote', name: '远程验证' },
{ code: 'array', name: '数组验证' },
{ code: 'pattern', name: '正则模式' },
{ code: 'length', name: '长度限制' },
]);
const state = reactive({
isShowDialog: false,
loading: false,
ruleForm: {} as any,
id: 0,
column: {} as any,
});
//
const openDialog = (row: any) => {
// const data = JSON.parse(JSON.stringify(row));
// state.ruleForm = data;
state.id = row.id;
state.isShowDialog = true;
state.column = row;
};
//
const closeDialog = () => {
// emit("reloadTable");
ruleFormRef.value.resetFields();
state.isShowDialog = false;
};
//
const openPatternDialog = () => {
patternDialogRef.value.openDialog();
};
//
const cancel = () => {
// state.isShowDialog = false;
closeDialog();
};
const submitPatternOK = (data: any) => {
// console.log('submitPatternOK', data);
state.ruleForm.pattern = data.pattern;
};
//
const submit = async () => {
ruleFormRef.value.validate(async (isValid: boolean, fields?: any) => {
if (isValid) {
let values = toRaw(state.ruleForm);
values.key = toRaw(state.id);
emit('submitRule', Object.assign({}, values));
closeDialog();
} else {
ElMessage({
message: `表单有${Object.keys(fields).length}处验证失败,请修改后再提交`,
type: 'error',
});
}
});
};
//
const handleTypeChange = () => {
resetFields();
};
//
const resetFields = () => {
state.ruleForm.message = '';
state.ruleForm.min = 0;
state.ruleForm.max = 10;
state.ruleForm.pattern = '';
// state.ruleForm.dataType=null;
};
//
defineExpose({ openDialog });
</script>

View File

@ -0,0 +1,377 @@
<template>
<el-row :gutter="10" v-if="store.ruleForm.tableList?.[tableIndex]">
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20">
<el-form-item label="库定位器" :prop="`tableList[${tableIndex}].configId`" :rules="[{ required: true, message: '请选择库定位器', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.tableList[tableIndex].configId" :disabled="!!store.ruleForm.tableList[tableIndex].id" placeholder="库名" filterable @change="dbChanged()" class="w100">
<el-option v-for="item in store.databaseList ?? []" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20">
<el-form-item label="实体表名" :prop="`tableList[${tableIndex}].tableName`" :rules="[{ required: true, message: '请选择实体表名', trigger: 'blur' }]">
<el-select v-model="store.ruleForm.tableList[tableIndex as any].tableName" :disabled="!!store.ruleForm.tableList[tableIndex].id || !store.ruleForm.tableList[tableIndex].configId" @change="tableChanged" value-key="tableName" filterable clearable class="w100">
<template #prefix>
<el-tooltip raw-content content="若找不到在前端生成的实体/表,请检查配置文件中实体所在程序集或重启后台服务。" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</template>
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.entityName + ' ( ' + item.tableName + ' ) [' + item.tableComment + ']'" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20" v-if="store.getLastLinkLabel(tableIndex)">
<el-form-item :label="store.getLastLinkLabel(tableIndex)" :prop="`tableList[${tableIndex}].lastLinkPropertyName`" :rules="[{ required: true, message: '请选择' + store.getLastLinkLabel(tableIndex), trigger: 'blur' }]">
<el-select v-model="store.ruleForm.tableList[tableIndex].lastLinkPropertyName" :disabled="!!store.ruleForm.tableList[tableIndex].id || !store.ruleForm.tableList[tableIndex].configId" filterable clearable class="w100">
<template #prefix>
<el-tooltip raw-content content="与上级组件连表查询的字段" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</template>
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.propertyName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20" v-if="store.getNextLinkLabel(tableIndex)">
<el-form-item :label="store.getNextLinkLabel(tableIndex)" :prop="`tableList[${tableIndex}].nextLinkPropertyName`" :rules="[{ required: true, message: '请选择' + store.getNextLinkLabel(tableIndex), trigger: 'blur' }]">
<el-select v-model="store.ruleForm.tableList[tableIndex].nextLinkPropertyName" :disabled="!!store.ruleForm.tableList[tableIndex].id || !store.ruleForm.tableList[tableIndex].configId" filterable clearable class="w100">
<template #prefix>
<el-tooltip raw-content content="与下级组件连表查询的字段" placement="top">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</template>
<el-option v-for="item in state.columnList" :key="item.propertyName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.propertyName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20">
<el-form-item label="业务名" :prop="`tableList[${tableIndex}].busName`" :rules="[{ required: true, message: '业务名不能为空', trigger: 'blur' }]">
<el-input v-model="store.ruleForm.tableList[tableIndex].busName" placeholder="请输入" clearable />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="6" :md="6" :lg="6" :xl="6" class="mb20">
<el-form-item label="模块名" :prop="`tableList[${tableIndex}].moduleName`" :rules="[{ required: true, message: '模块名不能为空', trigger: 'blur' }]">
<el-input v-model="store.ruleForm.tableList[tableIndex].moduleName" :disabled="!!store.ruleForm.tableList[tableIndex].id" placeholder="请输入" clearable>
<template #prefix>
<el-tooltip raw-content content="对应后端Service接口名称前缀" placement="top">
<el-icon size="16" style="display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
</el-tooltip>
</template>
</el-input>
</el-form-item>
</el-col>
<el-divider content-position="center">
表字段配置 &ensp;&ensp; <el-button type="primary" icon="ele-Refresh" :disabled="store.getSyncColumnListButtonDisabled(tableIndex)" @click="asyncColumnList()" v-reclick="1000">同步配置</el-button>
</el-divider>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<vxe-grid ref="xGridRef" class="xGrid-table-style" v-bind="tableOptions" :data="store.ruleForm.tableList[tableIndex].columnList ?? []">
<template #drag_default="{}">
<span class="drag-btn">
<i class="fa fa-arrows"></i>
</span>
</template>
<template #orderNo="{ row }">
<vxe-input v-model="row.orderNo" autocomplete="off" @change="handelChangeOrderNo" />
</template>
<template #effectType="{ row, rowIndex }">
<vxe-select v-model="row.effectType" @change="effectTypeChange(row, rowIndex)" :disabled="disabledColumn(row)" :style="{ width: '100%' }" placeholder="Select" transfer filterable>
<vxe-option v-for="item in userInfo.dictList['CodeGenEffectTypeEnum']" :key="item.value" :label="item.label" :value="item.value" />
</vxe-select>
<!-- <vxe-button v-if="showConfigButton(row)" style="width: 30%" icon="vxe-icon-edit" @click="effectTypeChange(row, rowIndex)" v-reclick="1000">修改</vxe-button>-->
<vxe-checkbox v-if="showCheckBox(row)" v-model="row.config.multiple" style="width: 30%" icon="vxe-icon-edit">多选</vxe-checkbox>
</template>
<template #defaultValue="{ row }">
<vxe-input v-model="row.defaultValue" autocomplete="off" :disabled="disabledColumn(row)" />
</template>
<template #columnComment="{ row }">
<vxe-input v-model="row.columnComment" autocomplete="off" :disabled="disabledColumn(row)" />
</template>
<template #config="{ row, rowIndex }">
<span v-if="!row.config"></span>
<!-- 枚举字典常量 -->
<vxe-select v-else-if="useDictSelector(row)" v-model="row.config.code" class="w100 m-2" :disabled="!useDictSelector(row)" filterable transfer>
<vxe-option v-if="row.effectType == 101" v-for="item in store.dictList" :key="item.code" :label="item.name" :value="item.code" />
<vxe-option v-if="row.effectType == 102" v-for="item in store.constList" :key="item.code" :label="item.name" :value="item.code" />
<vxe-option v-if="row.effectType == 103" v-for="item in store.enumList" :key="item.code" :label="item.name" :value="item.code" />
</vxe-select>
<!-- 时间格式 -->
<vxe-select v-else-if="row.effectType == 107" v-model="row.config.format" placeholder="时间格式" class="w100">
<vxe-option label="YYYY-mm-dd HH:MM:SS" value="datetime" />
<vxe-option label="YYYY-mm-dd" value="date" />
<vxe-option label="HH:MM:SS" value="time" />
</vxe-select>
<!-- 树形选择器 -->
<vxe-input v-else-if="row.effectType == 104" v-model="row.config.entityName" readonly style="width: 67.5%"></vxe-input>
<!-- 外键 -->
<vxe-input v-else-if="row.effectType == 105" v-model="row.config.entityName" readonly style="width: 67.5%"></vxe-input>
<!-- 上传配置 -->
<vxe-input v-else-if="row.effectType == 109" readonly placeholder="上传配置" style="width: 67.5%"></vxe-input>
<vxe-button v-if="[104, 105, 109].includes(row.effectType)" @click="effectTypeChange(row, rowIndex)" style="width: 27.5%" icon="vxe-icon-edit">修改</vxe-button>
</template>
<template #isTable="{ row }">
<vxe-checkbox v-model="row.isTable"></vxe-checkbox>
</template>
<template #isCopy="{ row }">
<vxe-checkbox v-model="row.isCopy" v-if="row.isTable"></vxe-checkbox>
</template>
<template #isAddUpdate="{ row }">
<vxe-checkbox v-model="row.isAddUpdate" v-if="!disabledColumn(row)"></vxe-checkbox>
</template>
<template #isImport="{ row }">
<vxe-checkbox v-model="row.isImport" v-if="!disabledColumn(row)"></vxe-checkbox>
</template>
<template #isSortable="{ row }">
<vxe-checkbox v-model="row.isSortable" v-if="row.isTable"></vxe-checkbox>
</template>
<template #isRequired="{ row }">
<vxe-tag v-if="row.isRequired" status="success"></vxe-tag>
<vxe-tag v-else status="info"></vxe-tag>
</template>
<template #isStatistical="{ row }">
<vxe-switch v-model="row.isStatistical" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
</template>
<template #isQuery="{ row }">
<vxe-switch v-model="row.isQuery" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
</template>
<template #queryType="{ row }">
<vxe-select v-model="row.queryType" class="m-2" placeholder="Select" :disabled="!row.isQuery" filterable transfer>
<vxe-option v-for="item in userInfo.dictList['code_gen_query_type']" :key="item.value" :label="item.label" :value="item.value" />
</vxe-select>
</template>
<template #fromValid="{ row }">
<vxe-select v-model="row.fromValid" class="m-2" placeholder="Select" :disabled="!row.isAddUpdate" filterable clearable transfer>
<vxe-option v-for="item in userInfo.dictList['CodeGenFromRuleValidEnum']" :key="item.value" :label="item.label" :value="item.value" />
</vxe-select>
</template>
</vxe-grid>
</el-col>
</el-row>
<EffectLinkTableConfig ref="effectLinkTableDialogRef" @submitData="submitRefreshFk" />
<UploadConfigDialog ref="uploadConfigDialogRef" @submitData="submitRefreshFk" />
<DateTimeConfigDialog ref="dateTimeConfigDialogRef" @submitData="submitRefreshFk" />
</template>
<!-- 表配置 -->
<script lang="ts" setup name="tableConfig">
import Sortable from "sortablejs";
import { ref, reactive, watch, computed } from 'vue';
import { useUserInfo } from '/@/stores/userInfo'
import { VxeGridInstance, VxeGridProps } from "vxe-table";
import {SysCodeGenColumn, TableOutput} from '/@/api-services/system/models';
import EffectLinkTableConfig from "./effectLinkTableConfig.vue";
import DateTimeConfigDialog from "./dateTimeConfigDialog.vue";
import UploadConfigDialog from "./uploadConfigDialog.vue";
import { useCodeGenStore } from './codeGenStore';
import {debounce} from "xe-utils";
const store = useCodeGenStore();
const uploadConfigDialogRef = ref();
const dateTimeConfigDialogRef = ref();
const effectLinkTableDialogRef = ref();
const xGridRef = ref<VxeGridInstance<SysCodeGenColumn>>();
const props = defineProps<{
index: number,
}>();
const tableIndex = computed(() => props.index);
const userInfo = useUserInfo();
const state = reactive({
index: 0,
tableData: [] as TableOutput[] | any,
columnList: [] as Array<SysCodeGenColumn>,
});
//
const tableOptions = reactive<VxeGridProps<SysCodeGenColumn>>({
id: 'genConfigDialog',
height: '350px',
keepSource: true,
autoResize: true,
loading: false,
align: 'center',
rowConfig: { useKey: true },
seqConfig: { seqMethod: ({ row }) => row.orderNo as number },
columns: [
{ field: 'id', width: 40, slots: { default: 'drag_default' }, },
{ field: 'orderNo', title: '排序', minWidth: 40, showOverflow: 'tooltip', slots: { default: 'orderNo'} },
{ field: 'columnName', title: '字段', minWidth: 100, align: 'left', showOverflow: 'tooltip', },
{ field: 'defaultValue', title: '默认值', minWidth: 80, align: 'left', showOverflow: 'tooltip', slots: { default: 'defaultValue'} },
{ field: 'columnComment', title: '描述', minWidth: 100, showOverflow: 'tooltip', slots: { default: 'columnComment' },},
{ field: 'netType', title: '数据类型', minWidth: 90, align: 'left', },
{ field: 'effectType', title: '控件类型', minWidth: 160, slots: { default: 'effectType' }, },
{ field: 'config', title: '控件配置', minWidth: 180, slots: { default: 'config' }, },
{ field: 'isTable', title: '列表显示', minWidth: 70, slots: { default: 'isTable' }, },
{ field: 'isCopy', title: '复制', minWidth: 40, slots: { default: 'isCopy' }, },
{ field: 'isAddUpdate', title: '增改字段', minWidth: 70, slots: { default: 'isAddUpdate' }, },
{ field: 'isImport', title: '导入导出', minWidth: 70, slots: { default: 'isImport' }, },
{ field: 'isRequired', title: '必填字段', minWidth: 70, slots: { default: 'isRequired' }, },
{ field: 'isSortable', title: '排序字段', minWidth: 70, slots: { default: 'isSortable' }, },
{ field: 'isStatistical', title: '统计字段', minWidth: 70, slots: { default: 'isStatistical' }, },
{ field: 'isQuery', title: '查询字段', minWidth: 70, slots: { default: 'isQuery' },},
{ field: 'queryType', title: '查询方式', minWidth: 120, slots: { default: 'queryType' },},
{ field: 'fromValid', title: '校验规则', width: 130, showOverflow: true, slots: { default: 'fromValid' },},
],
editConfig: { trigger: 'click', mode: 'row', showStatus: true },
data: [],
});
const reset = (type: string) => {
if (type === 'db') {
store.ruleForm.tableList[tableIndex.value]!.busName = undefined as any;
store.ruleForm.tableList[tableIndex.value]!.moduleName = undefined as any;
store.ruleForm.tableList[tableIndex.value]!.tableName = undefined as any;
store.ruleForm.tableList[tableIndex.value]!.entityName = undefined as any;
}
store.ruleForm.tableList[tableIndex.value].lastLinkPropertyName = undefined;
store.ruleForm.tableList[tableIndex.value].nextLinkPropertyName = undefined;
};
//
watch(() => store.ruleForm.tableList?.[tableIndex.value]?.configId, () => reset('db'));
//
watch(() => store.ruleForm.tableList?.[tableIndex.value]?.tableName, () => reset('table'))
//
const dbChanged = async () => {
state.tableData = await store.tableListBy(store.ruleForm.tableList[tableIndex.value].configId) ?? [];
}
// table
const tableChanged = async (item: any) => {
tableOptions.loading = true;
try {
store.ruleForm.tableList[tableIndex.value].tableName = item.tableName;
store.ruleForm.tableList[tableIndex.value].entityName = item.entityName;
store.ruleForm.tableList[tableIndex.value].moduleName = item.entityName;
store.ruleForm.tableList[tableIndex.value].busName = item.tableComment?.replace(/表$/, '');
const data = store.ruleForm.tableList[tableIndex.value];
state.columnList = (await store.columnListBy(data.configId, data.tableName) ?? []) as any[];
await asyncColumnList();
} finally {
tableOptions.loading = false;
}
};
//
const asyncColumnList = async () => {
tableOptions.loading = true;
try {
await store.getDefaultColumnConfigList(tableIndex.value);
rowDrop();
} finally {
tableOptions.loading = false;
}
}
//
const disabledColumn = (row: any) => row.isCommon || row.isPrimarykey;
//const showConfigButton = (row: any) => useConfigButton(row) && !row.isCommon;
const showCheckBox = (row: any) => useDictSelector(row) && row.netType.startsWith('string') && !row.isCommon;
const useDictSelector = (row: any) => [101,102,103].includes(Number(row.effectType) ?? 0);
//const useConfigButton = (row: any) => [104, 105, 107, 109].includes(Number(row.effectType));
//
const effectTypeChange = (row: any, index: number) => {
row.effectType = Number(row.effectType);
if ([101, 102, 103].includes(row.effectType)) {
row.config = {};
} else if (row.effectType === 104) {
openTreeDialog(row, index);
} else if (row.effectType === 105) {
openFkDialog(row, index);
} else if (row.effectType === 107) {
openDateTimeDialog(row, index);
} else if (row.effectType === 109) {
openUploadDialog(row, index);
} else {
row.config = undefined;
}
// 使
if (row.effectType <= 105) row.queryType = '==';
};
//
const openFkDialog = (row: any, index: number) => {
row.index = index;
effectLinkTableDialogRef.value.openDialog(row, 'fk');
};
//
const openTreeDialog = (row: any, index: number) => {
row.index = index;
effectLinkTableDialogRef.value.openDialog(row, 'tree');
};
//
const openUploadDialog = (row: any, index: number) => {
row.index = index;
uploadConfigDialogRef.value.openDialog(row);
};
//
const openDateTimeDialog = (row: any, index: number) => {
row.index = index;
dateTimeConfigDialogRef.value.openDialog(row);
};
//
const submitRefreshFk = (row: any) => {
let tableData = xGridRef.value?.getFullData() || [];
tableData[row.index] = row;
xGridRef.value?.loadData(tableData);
};
//
const handelChangeOrderNo = debounce(() => {
let tableData = xGridRef.value?.getFullData() || [];
tableData = tableData.sort((a: any, b: any) => a.orderNo - b.orderNo)
xGridRef.value?.loadData(tableData);
}, 1000)
const rowDrop = () => {
const el = document.querySelector('.xGrid-table-style .vxe-table--body tbody') as HTMLElement;
Sortable.create(el, {
animation: 300,
handle: '.drag-btn',
onEnd: (sortableEvent: any) => {
const fullData = xGridRef.value?.getTableData().fullData || [];
const newIndex = sortableEvent.newIndex as number;
const oldIndex = sortableEvent.oldIndex as number;
if (newIndex === undefined || oldIndex === undefined || newIndex === oldIndex) return;
const currentRow = fullData.splice(oldIndex, 1)[0];
fullData.splice(newIndex, 0, currentRow);
fullData.forEach((u, i) => (u.orderNo = 5 + i * 5))
// orderNo
let prevOrderNo = newIndex > oldIndex ? fullData[newIndex - 1]?.orderNo : fullData[newIndex + 1]?.orderNo;
let nextOrderNo = newIndex > oldIndex ? fullData[newIndex + 1]?.orderNo : fullData[newIndex - 1]?.orderNo;
if (prevOrderNo !== undefined && nextOrderNo !== undefined) {
currentRow.orderNo = (prevOrderNo + nextOrderNo) / 2;
} else if (prevOrderNo !== undefined) {
currentRow.orderNo = prevOrderNo + 5; // 5
if (newIndex == 0) currentRow.orderNo = 5;
} else if (nextOrderNo !== undefined) {
currentRow.orderNo = nextOrderNo - 5; // 5
}
//
xGridRef.value?.loadData(fullData);
},
});
};
</script>
<style lang="scss" scoped>
.xGrid-table-style .drag-btn {
cursor: move;
font-size: 20px;
}
:deep(.vxe-cell) {
height: auto !important;
}
</style>

View File

@ -1,167 +0,0 @@
<template>
<div class="sys-codeGenTree-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 树选择配置 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="库定位器" prop="configId">
<el-select clearable v-model="state.ruleForm.configId" placeholder="库名" filterable @change="DbChanged()" class="w100">
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="数据库表" prop="tableName">
<el-select v-model="state.ruleForm.tableName" filterable clearable @change="TableChanged()" class="w100">
<el-option v-for="item in state.tableData" :key="item.entityName" :label="item.tableName + ' [' + item.tableComment + ']'" :value="item.tableName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="显示字段" prop="displayColumn">
<el-select v-model="state.ruleForm.displayColumn" filterable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="选择值字段" prop="valueColumn">
<el-select v-model="state.ruleForm.valueColumn" filterable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="父级字段" prop="pidColumn">
<el-select v-model="state.ruleForm.pidColumn" filterable class="w100">
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' [' + item.columnComment + ']'" :value="item.columnName" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="sysCodeGenTree">
import { onMounted, reactive, ref } from 'vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenApi } from '/@/api-services/system/api';
var rowdata = {} as any;
const emits = defineEmits(['submitRefreshFk']);
const ruleFormRef = ref();
const state = reactive({
isShowDialog: false,
ruleForm: {} as any,
dbData: [] as any,
tableData: [] as any,
columnData: [] as any,
});
onMounted(async () => {
await getDbList();
// 使
//state.ruleForm.configId = state.dbData[0].configId;
//await DbChanged();
});
const DbChanged = async () => {
state.tableData = [];
state.columnData = [];
await getTableInfoList();
};
const TableChanged = async () => {
state.columnData = [];
await getColumnInfoList();
};
const getDbList = async () => {
var res = await getAPI(SysCodeGenApi).apiSysCodeGenDatabaseListGet();
state.dbData = res.data.result;
};
const getTableInfoList = async () => {
if (state.ruleForm.configId == '') return;
var res = await getAPI(SysCodeGenApi).apiSysCodeGenTableListConfigIdGet(state.ruleForm.configId);
state.tableData = res.data.result;
};
const getColumnInfoList = async () => {
if (state.ruleForm.configId == '' || state.ruleForm.tableName == '') return;
var res = await getAPI(SysCodeGenApi).apiSysCodeGenColumnListByTableNameTableNameConfigIdGet(state.ruleForm.tableName, state.ruleForm.configId);
state.columnData = res.data.result;
};
//
const openDialog = async (row: any) => {
rowdata = row;
state.isShowDialog = true;
ruleFormRef.value?.resetFields();
if (rowdata.fkConfigId) {
await getDbList();
state.ruleForm.tableName = rowdata.fkTableName;
state.ruleForm.displayColumn = rowdata.displayColumn;
state.ruleForm.valueColumn = rowdata.valueColumn;
state.ruleForm.pidColumn = rowdata.pidColumn;
state.ruleForm.configId = rowdata.fkConfigId;
await DbChanged();
await TableChanged();
}
};
//
const closeDialog = () => {
rowdata.fkTableName = state.ruleForm.tableName;
// rowdata.fkEntityName = state.ruleForm.entityName;
// fkEntityName,
let tableData = state.tableData.filter((x: any) => x.tableName == state.ruleForm.tableName);
rowdata.fkEntityName = tableData.length == 0 ? '' : tableData[0].entityName;
// rowdata.fkColumnName = state.ruleForm.columnName;
// rowdata.fkColumnNetType = state.ruleForm.columnNetType;
rowdata.displayColumn = state.ruleForm.displayColumn;
rowdata.valueColumn = state.ruleForm.valueColumn;
rowdata.pidColumn = state.ruleForm.pidColumn;
rowdata.fkConfigId = state.ruleForm.configId;
emits('submitRefreshFk', rowdata);
cancel();
};
//
const cancel = () => {
state.isShowDialog = false;
ruleFormRef.value?.resetFields();
state.ruleForm = {};
state.dbData.value = [];
state.tableData.value = [];
state.columnData.value = [];
};
//
const submit = () => {
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
closeDialog();
});
};
//
defineExpose({ openDialog });
</script>

View File

@ -0,0 +1,95 @@
<template>
<div class="sys-codeGenUpload-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="700px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> 上传配置 </span>
</div>
</template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="链接预览" prop="useDownload" :rules="[{ required: true, message: '链接下载不能为空', trigger: 'blur' }]">
<el-radio-group v-model="state.ruleForm.useDownload" filterable>
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="state.ruleForm.useDownload">
<el-form-item label="链接文本" prop="downloadText" :rules="[{ required: true, message: '链接文本不能为空', trigger: 'blur' }]">
<vxe-input v-model="state.ruleForm.downloadText" placeholder="请输入" class="w100" clearable />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="图片文件" prop="isImage" :rules="[{ required: true, message: '图片文件不能为空', trigger: 'blur' }]">
<el-radio-group v-model="state.ruleForm.isImage" filterable>
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit" v-reclick="1000"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="sysPreviewCode">
import { onMounted, reactive, ref } from 'vue';
let rowData = {} as any;
const emits = defineEmits(['submitData']);
const ruleFormRef = ref();
const state = reactive({
isShowDialog: false,
ruleForm: {} as any,
});
onMounted(async () => {});
//
const openDialog = async (row: any) => {
rowData = row;
state.ruleForm = Object.assign({}, row.config);
state.ruleForm.downloadText ??= '查看文件';
state.ruleForm.useDownload ??= false;
state.ruleForm.isImage ??= false;
state.isShowDialog = true;
};
//
const closeDialog = () => {
if (!rowData.netType.startsWith('string')) state.ruleForm.multiple = false;
rowData.config = Object.assign({}, state.ruleForm);
emits('submitData', rowData);
cancel();
};
//
const cancel = () => {
state.isShowDialog = false;
ruleFormRef.value?.resetFields();
state.ruleForm = {};
};
//
const submit = () => {
ruleFormRef.value.validate(async (valid: boolean) => {
if (!valid) return;
closeDialog();
});
};
//
defineExpose({ openDialog });
</script>
<style scoped></style>

View File

@ -1,116 +0,0 @@
<template>
<div class="sys-codeGenConfig-container">
<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="800px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Edit /> </el-icon>
<span> {{ state.title }} </span>
</div>
</template>
<div class="tool-box">
<el-button type="primary" icon="ele-Plus" @click="openRuleDialog"> 新增 </el-button>
</div>
<el-table :data="state.tableData" style="width: 100%" v-loading="state.loading" border>
<el-table-column prop="type" label="类型" width="120" show-overflow-tooltip />
<el-table-column prop="message" label="提示信息" minWidth="180" show-overflow-tooltip />
<el-table-column prop="min" label="最小值" minWidth="100" show-overflow-tooltip />
<el-table-column prop="max" label="最大值" minWidth="100" show-overflow-tooltip />
<el-table-column prop="pattern" label="正则式" minWidth="120" show-overflow-tooltip />
<el-table-column prop="action" label="操作" width="100" align="center" show-overflow-tooltip>
<template #default="scope">
<el-button icon="ele-Delete" text type="danger" @click="handleDeleteRule(scope)">删除</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="cancel"> </el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="submit"> </el-button>
</span>
</template>
</el-dialog>
<ruleDialog ref="ruleDialogRef" @submitRule="submitRuleOK" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, toRaw } from 'vue';
import ruleDialog from '/@/views/system/codeGen/component/ruleDialog.vue';
const emits = defineEmits(['submitVerify']);
const ruleDialogRef = ref();
const state = reactive({
id: 0,
isShowDialog: false,
loading: false,
tableData: [] as any,
title: '',
column: {} as any,
});
//
const openDialog = (row: any) => {
state.title = `校验规则 -- ${row.columnComment}`;
state.tableData = new Array();
if (row.rules != '') {
state.tableData = JSON.parse(row.rules);
}
// state.tableData = row.rules;
state.id = row.id;
state.isShowDialog = true;
state.column = row;
// console.log('column',row);
};
//
const openRuleDialog = () => {
ruleDialogRef.value.openDialog(state.column);
};
//
const closeDialog = () => {
state.isShowDialog = false;
};
//
const cancel = () => {
state.isShowDialog = false;
};
//
const submit = async () => {
let data = toRaw(state);
let newData = Object.assign({}, data);
let ruleCount = newData.tableData.length > 0 ? `${newData.tableData.length}` : '';
emits('submitVerify', { id: newData.id, rules: JSON.stringify(newData.tableData), ruleCount: ruleCount });
closeDialog();
};
//
const submitRuleOK = (data: any) => {
let row = toRaw(data);
if (state.tableData === null) {
state.tableData = [];
}
state.tableData.push(row);
};
//
const handleDeleteRule = (scope: any) => {
state.tableData.splice(scope.$index, 1);
};
//
defineExpose({ openDialog });
</script>
<style lang="scss" scoped>
.tool-box {
padding-bottom: 20px;
display: flex;
gap: 20px;
align-items: center;
// background: red;
}
</style>

View File

@ -37,37 +37,30 @@
<template #empty>
<el-empty :image-size="200" />
</template>
<template #row_generateType="{ row }">
<el-tag v-if="row.generateType == 100"> 下载压缩包 </el-tag>
<el-tag v-else-if="row.generateType == 111"> 下载压缩包(前端) </el-tag>
<el-tag v-else-if="row.generateType == 121"> 下载压缩包(后端) </el-tag>
<el-tag v-else-if="row.generateType == 211"> 生成到本项目(前端) </el-tag>
<el-tag v-else-if="row.generateType == 221"> 生成到本项目(后端) </el-tag>
<el-tag type="danger" v-else> 生成到本项目 </el-tag>
<template #row_entityName="{ row }">
{{ row.tableList?.[0].entityName }}
</template>
<template #row_generateMethod="{ row }">
<g-sys-dict code="CodeGenMethodEnum" v-model="row.generateMethod" />
</template>
<template #row_scene="{ row }">
<g-sys-dict code="CodeGenSceneEnum" v-model="row.scene" />
</template>
<template #row_record="{ row }">
<ModifyRecord :data="row" />
</template>
<template #row_buttons="{ row }">
<el-tooltip content="编辑" placement="top">
<el-button icon="ele-Edit" text type="primary" @click="handleEdit(row)"> </el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button icon="ele-Delete" text type="danger" @click="handleDelete(row)"> </el-button>
</el-tooltip>
<el-tooltip content="配置" placement="top">
<el-button icon="ele-Setting" text type="danger" @click="handleConfig(row)">配置</el-button>
</el-tooltip>
<el-tooltip content="预览" placement="top">
<el-button icon="ele-Camera" text type="primary" @click="handlePreview(row)">预览</el-button>
</el-tooltip>
<el-tooltip content="开始生成" placement="top">
<el-button icon="ele-Cpu" text type="primary" @click="handleGenerate(row)">生成</el-button>
</el-tooltip>
<el-button icon="ele-Position" text type="primary" @click="handleGenerate(row)" title="生成" v-reclick="1000">生成</el-button>
<el-button icon="ele-Camera" text type="primary" @click="handlePreview(row)" title="预览" v-reclick="1000">预览</el-button>
<el-button icon="ele-Edit" text type="primary" @click="handleEdit(row)" title="编辑" v-reclick="1000">编辑</el-button>
<el-button icon="ele-Delete" text type="danger" @click="handleDelete(row)" title="删除" v-reclick="1000">删除</el-button>
<el-button icon="ele-CopyDocument" text type="primary" @click="handleCopy(row)" title="复制" v-reclick="1000">复制</el-button>
</template>
</vxe-grid>
</el-card>
<EditCodeGenDialog ref="EditCodeGenRef" :title="state.title" :applicationNamespaces="state.applicationNamespaces" @handleQuery="handleQuery" />
<CodeConfigDialog ref="CodeConfigRef" @handleQuery="handleQuery" />
<PreviewDialog :title="state.title" ref="PreviewRef" />
<EditCodeGenDialog ref="EditCodeGenRef" @handleQuery="handleQuery" />
<PreviewDialog :title="state.title" ref="previewRef" />
</div>
</template>
@ -77,21 +70,22 @@ import { onMounted, reactive, ref, defineAsyncComponent } from 'vue';
import { ElMessageBox, ElMessage, ElNotification } from 'element-plus';
import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { Local } from '/@/utils/storage';
import { downloadByUrl } from '/@/utils/download';
import { Local } from '/@/utils/storage';
import EditCodeGenDialog from './component/editCodeGenDialog.vue';
import CodeConfigDialog from './component/genConfigDialog.vue';
import { useCodeGenStore } from './component/codeGenStore';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysCodeGenApi } from '/@/api-services/system/api';
import { SysCodeGen, PageCodeGenInput } from '/@/api-services/system/models';
const PreviewDialog = defineAsyncComponent(() => import('./component/previewDialog.vue'));
const store = useCodeGenStore();
const xGrid = ref<VxeGridInstance>();
const previewRef = ref<InstanceType<typeof PreviewDialog>>();
const EditCodeGenRef = ref<InstanceType<typeof EditCodeGenDialog>>();
const CodeConfigRef = ref<InstanceType<typeof CodeConfigDialog>>();
const PreviewRef = ref<InstanceType<typeof PreviewDialog>>();
const state = reactive({
dbData: [] as any,
configId: '',
@ -103,7 +97,7 @@ const state = reactive({
busName: undefined,
},
localPageParam: {
pageSize: 50 as number,
pageSize: 20 as number,
defaultSort: { field: 'id', order: 'asc', descStr: 'desc' },
},
visible: false,
@ -121,13 +115,14 @@ const options = useVxeTable<SysCodeGen>(
columns: [
// { type: 'checkbox', width: 40, fixed: 'left' },
{ field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' },
{ field: 'configId', title: '库定位器', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'tableName', title: '表名称', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'busName', title: '业务名', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'nameSpace', title: '命名空间', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'authorName', title: '作者姓名', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'generateType', title: '生成方式', minWidth: 140, showOverflow: 'tooltip', slots: { default: 'row_generateType' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 280, showOverflow: true, slots: { default: 'row_buttons' } },
{ field: 'busName', title: '业务名', align: 'left', minWidth: 120, showOverflow: 'tooltip' },
{ field: 'scene', title: '模板场景', align: 'left', minWidth: 100, showOverflow: 'tooltip', slots: { default: 'row_scene' } },
{ field: 'entityName', title: '主表实体', align: 'left', minWidth: 120, showOverflow: 'tooltip', slots: { default: 'row_entityName' } },
{ field: 'nameSpace', title: '命名空间', align: 'left', showOverflow: 'tooltip' },
{ field: 'generateMethod', title: '生成方式', align: 'left', showOverflow: 'tooltip', slots: { default: 'row_generateMethod' } },
{ field: 'authorName', title: '作者姓名', align: 'left', showOverflow: 'tooltip' },
{ field: 'record', title: '修改记录', width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 300, showOverflow: true, slots: { default: 'row_buttons' } },
],
},
// vxeGrid()vxe-table
@ -139,17 +134,14 @@ const options = useVxeTable<SysCodeGen>(
//
pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize },
//
toolbarConfig: { export: true },
toolbarConfig: { export: false },
}
);
//
onMounted(async () => {
state.localPageParam = Local.get(localPageParamKey) || state.localPageParam;
//
let res = await getAPI(SysCodeGenApi).apiSysCodeGenApplicationNamespacesGet();
state.applicationNamespaces = res.data.result as Array<string>;
store.init();
});
// api
@ -174,26 +166,39 @@ const resetQuery = async () => {
//
const handleAdd = () => {
state.title = '增加代码生成';
EditCodeGenRef.value?.openDialog({
authorName: 'Admin.NET',
template: 'template',
generateType: '200',
printType: 'off',
generateMethod: 200,
printType: 1,
menuIcon: 'ele-Menu',
pagePath: 'main',
configObj: {},
nameSpace: state.applicationNamespaces[0],
generateMenu: false,
isApiService: false,
isApiService: true,
// scene: 1000,
});
};
//
const handleEdit = (row: any) => {
state.title = '编辑代码生成';
EditCodeGenRef.value?.openDialog(row);
};
//
const handleCopy = async (row: any) => {
const data = await store.getDetail(row.id);
if (data) {
data.moduleName = undefined;
data.tableList?.forEach((e) => {
e.columnList?.forEach((c) => delete c.id);
delete e.id;
});
delete data.id;
}
EditCodeGenRef.value?.openDialog(data);
};
//
const handleDelete = (row: any) => {
ElMessageBox.confirm(`确定删除吗?`, '提示', {
@ -202,7 +207,7 @@ const handleDelete = (row: any) => {
type: 'warning',
})
.then(async () => {
await getAPI(SysCodeGenApi).apiSysCodeGenDeletePost([{ id: row.id }]);
await getAPI(SysCodeGenApi).apiSysCodeGenDeletePost({ id: row.id });
await handleQuery();
ElMessage.success('操作成功');
})
@ -221,26 +226,17 @@ const gridEvents: VxeGridListeners<SysCodeGen> = {
state.localPageParam.defaultSort = { field: field, order: order!, descStr: 'desc' };
Local.set(localPageParamKey, state.localPageParam);
},
//
async cellDblclick({ row }) {
await handleEdit(row);
},
};
//
const handleConfig = (row: any) => {
CodeConfigRef.value?.openDialog(row);
};
//
const handleGenerate = (row: any) => {
ElMessageBox.confirm(`确定要生成【${row.tableName}】表吗?`, '提示', {
ElMessageBox.confirm(`确定要生成【${row.busName}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
var res = await getAPI(SysCodeGenApi).apiSysCodeGenRunLocalPost(row);
const res = await getAPI(SysCodeGenApi).apiSysCodeGenGeneratePost(row);
if (res.data.result != null && res.data.result.url != null) downloadByUrl({ url: res.data.result.url });
await handleQuery();
@ -257,6 +253,6 @@ const handleGenerate = (row: any) => {
//
const handlePreview = (row: any) => {
state.title = '预览代码';
PreviewRef.value?.openDialog(row);
previewRef.value?.openDialog(row);
};
</script>

View File

@ -359,6 +359,7 @@ const showPreviewDialog = async (row: any) => {
} else {
ElMessage.error('此文件格式不支持预览');
}
state.loading = false;
};
//

View File

@ -30,7 +30,7 @@
:data="state.allApiData"
:filter-node-method="filterNode"
node-key="route"
:props="{ children: 'children', label: 'text' }"
:props="{ children: 'children', label: 'desc' }"
show-checkbox
icon="ele-Menu"
highlight-current

View File

@ -65,6 +65,7 @@
<el-button icon="ele-Coin" size="small" text type="danger" @click="createTenantData(row)" :v-auth="'sysTenant/createDb'" v-if="row.tenantType === 0"> 创建租户数据 </el-button>
<el-button icon="ele-Coin" size="small" text type="danger" @click="createTenantDb(row)" :v-auth="'sysTenant/createDb'" v-else> 创建租户库表 </el-button>
<el-button icon="ele-Menu" size="small" text type="primary" @click="openGrantMenu(row)" v-auth="'sysTenant/grantMenu'"> 授权菜单 </el-button>
<el-button icon="ele-Position" text type="success" v-auth="'sysTenant/goLoginUser'" @click="goUserLogin(row)">{{ $t('message.list.goTenantUserLogin') }}</el-button>
<el-button icon="ele-Link" size="small" text type="primary" @click="openGrantApi(row)"> 接口黑名单 </el-button>
</template>
</vxe-grid>
@ -93,6 +94,7 @@ import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysTenantApi } from '/@/api-services/system/api';
import { PageTenantInput, TenantOutput } from '/@/api-services/system/models';
import { reLoadLoginAccessToken } from '/@/utils/request';
const xGrid = ref<VxeGridInstance>();
const editTenantRef = ref<InstanceType<typeof EditTenant>>();
@ -310,4 +312,17 @@ const syncTenantDb = () => {
})
.catch(() => {});
};
//
const goUserLogin = (row: any) => {
ElMessageBox.confirm(`确定要进入【${row.realName}】用户端?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() =>
getAPI(SysTenantApi)
.apiSysTenantGoLoginUserPost({ id: row.id })
.then((res) => reLoadLoginAccessToken(res.data.result))
);
};
</script>

View File

@ -88,6 +88,9 @@
<el-tooltip :content="$t('message.list.copy')" placement="top">
<el-button icon="ele-CopyDocument" text type="primary" v-auth="'sysUser/add'" @click="openCopyMenu(row)"> </el-button>
</el-tooltip>
<el-tooltip :content="$t('message.list.goUserLogin')" placement="top">
<el-button icon="ele-Position" text type="success" v-auth="'sysTenant/goLoginUser'" @click="goUserLogin(row)"> </el-button>
</el-tooltip>
<el-button icon="ele-RefreshLeft" text type="danger" v-auth="'sysUser/resetPwd'" @click="resetQueryPwd(row)">{{ $t('message.list.resetPassword') }}</el-button>
<el-button icon="ele-Unlock" text type="primary" v-auth="'sysUser/unlockLogin'" @click="handleUnlock(row)">{{ $t('message.list.unlockAccount') }}</el-button>
@ -119,8 +122,9 @@ import EditUser from '/@/views/system/user/component/editUser.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
import { getAPI } from '/@/utils/axios-utils';
import { SysUserApi, SysOrgApi } from '/@/api-services/system/api';
import { SysUserApi, SysOrgApi, SysTenantApi } from '/@/api-services/system/api';
import { SysOrg, PageTenantInput, UserOutput, UpdateUserInput } from '/@/api-services/system/models';
import { reLoadLoginAccessToken } from '/@/utils/request';
const { t } = useI18n();
const xGrid = ref<VxeGridInstance>();
@ -334,4 +338,17 @@ const handleNodeChange = async (node: any) => {
state.queryParams.phone = undefined;
await handleQuery();
};
//
const goUserLogin = (row: any) => {
ElMessageBox.confirm(`确定要进入【${row.realName}】用户端?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() =>
getAPI(SysTenantApi)
.apiSysTenantGoLoginUserPost({ id: row.id })
.then((res) => reLoadLoginAccessToken(res.data.result))
);
};
</script>