init
This commit is contained in:
391
src/views/gen/create-table/form.vue
Normal file
391
src/views/gen/create-table/form.vue
Normal file
@@ -0,0 +1,391 @@
|
||||
<template>
|
||||
<el-dialog :title="title" v-model="visible" width="90%"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="150px" v-loading="loading"
|
||||
:disabled="operType === 'view'">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.tableName')" prop="tableName">
|
||||
<el-input v-model="form.tableName" :placeholder="t('createTable.inputTableNameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('createTable.comments')" prop="comments">
|
||||
<el-input v-model="form.comments" :placeholder="t('createTable.inputCommentsTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('createTable.columnInfo')" prop="columns">
|
||||
<el-table :data="form.columns" border style="width: 100%" max-height="500">
|
||||
<el-table-column type="index" :label="t('createTable.index')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="onAddItem"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="handleDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="t('createTable.name')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.name" :placeholder="t('createTable.name')"
|
||||
@blur="suggestedFieldType(scope.row)"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="comment" :label="t('createTable.comment')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.comment" :placeholder="t('createTable.comment')"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="typeName" :label="t('createTable.typeName')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.typeName" :placeholder="t('createTable.typeName')" clearable filterable>
|
||||
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="precision" :label="t('createTable.precision')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.precision"
|
||||
:placeholder="t('createTable.precision')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scale" :label="t('createTable.scale')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input-number :min="0" :max="10000" v-model="scope.row.scale"
|
||||
:placeholder="t('createTable.scale')"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="defaultValue" :label="t('createTable.defaultValue')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.defaultValue" :placeholder="t('createTable.defaultValue')"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.primary">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nullable" :label="t('createTable.nullable')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-radio-group v-model="scope.row.nullable">
|
||||
<el-radio v-for="(item, index) in tableDict" :key="index" :label="item.value" class="w-5">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer v-if="operType !== 'view'">
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{
|
||||
$t('common.confirmButtonText')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="CreateTableDialog">
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import {getObj, addObj, putObj} from '/@/api/gen/create-table'
|
||||
import {useI18n} from "vue-i18n"
|
||||
import {rule, validateNull} from '/@/utils/validate';
|
||||
import {useDict} from "/@/hooks/dict";
|
||||
import {list} from "/@/api/gen/fieldtype";
|
||||
import {fetchList} from '/@/api/gen/table';
|
||||
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
const {t} = useI18n();
|
||||
const {yes_no_type} = useDict('yes_no_type');
|
||||
|
||||
const tableDict = [{value: -1, label: '否'}, {value: 1, label: '是'}]
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const operType = ref();
|
||||
const title = ref('');
|
||||
const typeList = ref([]) as any;
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
tableName: '',
|
||||
dsName: '',
|
||||
comments: '',
|
||||
databaseType: '',
|
||||
pkPolicy: '',
|
||||
primary: '',
|
||||
columnsInfo: '',
|
||||
columnInfo: '',
|
||||
columns: [] as any
|
||||
});
|
||||
|
||||
/**
|
||||
* 校验数据源名
|
||||
* @param {校验数据源名} rule
|
||||
* @param {*} value
|
||||
* @param {*} callback
|
||||
*/
|
||||
let validateTableName = async (rule, value, callback) => {
|
||||
const {data} = await fetchList({tableName: value})
|
||||
if (data.total === 0) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error('表名已存在'))
|
||||
}
|
||||
}
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
tableName: [
|
||||
{required: true, message: '表名称不能为空', trigger: 'blur'},
|
||||
{max: 32, message: '长度在 32 个字符', trigger: 'blur'},
|
||||
{validator: rule.validatorLowercase, trigger: 'blur'},
|
||||
{validator: validateTableName, trigger: 'blur'}
|
||||
],
|
||||
comments: [{validator: rule.overLength, trigger: 'blur'}, {
|
||||
required: true,
|
||||
message: '表注释不能为空',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
databaseType: [{required: true, message: '数据库类型不能为空', trigger: 'blur'}],
|
||||
pkPolicy: [{required: true, message: '主键策略不能为空', trigger: 'blur'}],
|
||||
columns: [{required: true, message: '字段信息不能为空', trigger: 'blur'}],
|
||||
})
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (type: string, id: string, dsName: string) => {
|
||||
visible.value = true
|
||||
operType.value = type;
|
||||
form.id = ''
|
||||
form.dsName = dsName
|
||||
index = 1
|
||||
if (type === 'add') {
|
||||
title.value = t('common.addBtn');
|
||||
} else if (type === 'edit') {
|
||||
title.value = t('common.editBtn');
|
||||
} else if (type === 'view') {
|
||||
title.value = t('common.viewBtn');
|
||||
}
|
||||
// 获取字典值
|
||||
getFieldTypeList()
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
if (!id) onAddItem()
|
||||
});
|
||||
|
||||
// 获取CreateTable信息
|
||||
if (id) {
|
||||
form.id = id
|
||||
getCreateTableData(id)
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
if (form.id) {
|
||||
await useMessageBox().confirm("注意:目前修改会重新建表" + form.tableName);
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.columnInfo = JSON.stringify(form.columns)
|
||||
let columns = {} as any
|
||||
form.columns.forEach(each => {
|
||||
if (validateNull(each.defaultValue)) each.defaultValue = null
|
||||
columns[each.name] = each
|
||||
})
|
||||
form.columnsInfo = JSON.stringify(columns)
|
||||
await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getCreateTableData = (id: string) => {
|
||||
// 获取数据
|
||||
loading.value = true
|
||||
getObj(id).then((res: any) => {
|
||||
let columnInfo = res.data.columnInfo;
|
||||
res.data.columns = validateNull(columnInfo) ? [] : JSON.parse(columnInfo);
|
||||
Object.assign(form, res.data)
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
};
|
||||
|
||||
let index = 1;
|
||||
const onAddItem = () => {
|
||||
let find = form.columns.find(f => f.name === 'id');
|
||||
if (find) {
|
||||
let obj = {
|
||||
name: '',
|
||||
comment: '',
|
||||
typeName: 'varchar',
|
||||
precision: 255,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
|
||||
// 从 index为 1 的位置开始添加, 并且新增的字段要依次向后
|
||||
form.columns.splice(index++, 0, obj)
|
||||
return
|
||||
}
|
||||
let id = {
|
||||
name: 'id',
|
||||
comment: '主键',
|
||||
typeName: 'bigint',
|
||||
precision: 20,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: 1,
|
||||
nullable: -1
|
||||
};
|
||||
let create_user = {
|
||||
name: 'create_by',
|
||||
comment: '创建人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
let create_time = {
|
||||
name: 'create_time',
|
||||
comment: '创建时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
|
||||
let update_user = {
|
||||
name: 'update_by',
|
||||
comment: '修改人',
|
||||
typeName: 'varchar',
|
||||
precision: 64,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
|
||||
let update_time = {
|
||||
name: 'update_time',
|
||||
comment: '修改时间',
|
||||
typeName: 'datetime',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
defaultValue: null,
|
||||
primary: -1,
|
||||
nullable: 1
|
||||
};
|
||||
|
||||
let del_flag = {
|
||||
name: 'del_flag',
|
||||
comment: '删除标记',
|
||||
typeName: 'char',
|
||||
precision: 1,
|
||||
scale: 0,
|
||||
defaultValue: '0',
|
||||
primary: -1,
|
||||
nullable: -1
|
||||
};
|
||||
|
||||
let tenant_id = {
|
||||
name: 'tenant_id',
|
||||
comment: '租户ID',
|
||||
typeName: 'bigint',
|
||||
precision: 0,
|
||||
scale: 0,
|
||||
primary: -1,
|
||||
nullable: -1
|
||||
};
|
||||
|
||||
form.columns.push(id);
|
||||
form.columns.push(create_user);
|
||||
form.columns.push(create_time);
|
||||
form.columns.push(update_user);
|
||||
form.columns.push(update_time);
|
||||
form.columns.push(del_flag);
|
||||
form.columns.push(tenant_id);
|
||||
}
|
||||
|
||||
const getFieldTypeList = async () => {
|
||||
typeList.value = [];
|
||||
// 获取数据
|
||||
const {data} = await list();
|
||||
// 设置属性类型值
|
||||
const typeMap = new Map();
|
||||
data.forEach((item: any) => {
|
||||
const {attrType, columnType} = item;
|
||||
if (!typeMap.has(attrType)) {
|
||||
typeMap.set(columnType, attrType);
|
||||
typeList.value.push({label: columnType, value: columnType});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (index: number, row: any) => {
|
||||
form.columns.splice(index, 1)
|
||||
}
|
||||
|
||||
// 字段建议
|
||||
const suggestedFieldType = (row: { name: string, typeName: string, precision: number }) => {
|
||||
// 如果fieldName 包含 time,date ,则默认为时间类型, 如果包含id ,则默认是 bigint
|
||||
if (row.name.includes('time') || row.name.includes('date')) {
|
||||
row.typeName = 'datetime'
|
||||
row.precision = 0
|
||||
} else if (row.name.includes('id')) {
|
||||
row.typeName = 'bigint'
|
||||
row.precision = 20
|
||||
} else if(row.name.includes('flag') || row.name.includes('status')){
|
||||
row.typeName = 'char'
|
||||
row.precision = 1
|
||||
} else {
|
||||
row.typeName = 'varchar'
|
||||
row.precision = 255
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog
|
||||
});
|
||||
</script>
|
||||
33
src/views/gen/create-table/i18n/en.ts
Normal file
33
src/views/gen/create-table/i18n/en.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export default {
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: 'import CreateTable',
|
||||
id: 'id',
|
||||
tableName: 'tableName',
|
||||
comments: 'comments',
|
||||
comment: 'comment',
|
||||
databaseType: 'databaseType',
|
||||
pkPolicy: 'pkPolicy',
|
||||
createUser: 'createUser',
|
||||
createTime: 'createTime',
|
||||
columnInfo: 'columnInfo',
|
||||
tenantId: 'tenantId',
|
||||
inputIdTip: 'input id',
|
||||
inputTableNameTip: 'input tableName',
|
||||
inputCommentsTip: 'input comments',
|
||||
inputCommentTip: 'input comment',
|
||||
inputDatabaseTypeTip: 'input databaseType',
|
||||
inputPkPolicyTip: 'input pkPolicy',
|
||||
inputCreateUserTip: 'input createUser',
|
||||
inputCreateTimeTip: 'input createTime',
|
||||
inputColumnInfoTip: 'input columnInfo',
|
||||
inputTenantIdTip: 'input tenantId',
|
||||
name: 'name',
|
||||
typeName: 'typeName',
|
||||
precision: 'precision',
|
||||
scale: 'scale',
|
||||
defaultValue: 'defaultValue',
|
||||
primary: 'primary',
|
||||
nullable: 'nullable',
|
||||
}
|
||||
}
|
||||
33
src/views/gen/create-table/i18n/zh-cn.ts
Normal file
33
src/views/gen/create-table/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export default {
|
||||
createTable: {
|
||||
index: '#',
|
||||
importcreateTableTip: '导入自动创建表管理',
|
||||
id: '主键ID',
|
||||
tableName: '表名称',
|
||||
comments: '表注释',
|
||||
comment: '字段注释',
|
||||
databaseType: '数据库类型',
|
||||
pkPolicy: '主键策略',
|
||||
createUser: '创建人',
|
||||
createTime: '创建时间',
|
||||
columnInfo: '字段信息',
|
||||
tenantId: '租户ID',
|
||||
inputIdTip: '请输入主键ID',
|
||||
inputTableNameTip: '请输入表名称',
|
||||
inputCommentsTip: '请输入表注释',
|
||||
inputCommentTip: '请输入字段注释',
|
||||
inputDatabaseTypeTip: '请输入数据库引擎',
|
||||
inputPkPolicyTip: '请输入主键策略',
|
||||
inputCreateUserTip: '请输入创建人',
|
||||
inputCreateTimeTip: '请输入创建时间',
|
||||
inputColumnInfoTip: '请输入字段信息',
|
||||
inputTenantIdTip: '请输入租户ID',
|
||||
name: '字段名称',
|
||||
typeName: '字段类型',
|
||||
precision: '字段长度',
|
||||
scale: '小数位数',
|
||||
defaultValue: '默认值',
|
||||
primary: '主键',
|
||||
nullable: 'NULL',
|
||||
}
|
||||
}
|
||||
191
src/views/gen/create-table/index.vue
Normal file
191
src/views/gen/create-table/index.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row v-show="showSearch">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item label="数据源" prop="name">
|
||||
<el-select @change="getDataList" placeholder="请选择数据源" v-model="state.queryForm.dsName">
|
||||
<el-option label="默认数据源" value="master"></el-option>
|
||||
<el-option :key="ds.id" :label="ds.name" :value="ds.name" v-for="ds in datasourceList"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('createTable.tableName')" prop="tableName">
|
||||
<el-input :placeholder="t('createTable.inputTableNameTip')" v-model="state.queryForm.tableName"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button icon="folder-add" type="primary" class="ml10" v-auth="'codegen_table_add'"
|
||||
@click="formDialogRef.openDialog('add',null,state.queryForm.dsName)">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" v-auth="'codegen_table_add'" icon="Delete" type="primary" class="ml10"
|
||||
@click="handleDelete(selectObjs)">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="'order_createtable_export'"
|
||||
@exportExcel="exportExcel" class="ml10" style="float: right;margin-right: 20px"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
border
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="handleSelectionChange" @sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center"/>
|
||||
<el-table-column type="index" fixed="left" :label="t('createTable.index')" width="40"/>
|
||||
<el-table-column prop="tableName" :label="t('createTable.tableName')" show-overflow-tooltip/>
|
||||
<el-table-column prop="comments" :label="t('createTable.comments')" show-overflow-tooltip/>
|
||||
<el-table-column prop="primary" :label="t('createTable.primary')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<!-- 获取主键列名称-->
|
||||
{{ JSON.parse(scope.row.columnInfo).find(col => col.primary === 1)?.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" :label="t('createTable.createTime')" show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('common.action')" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button text type="primary" icon="view" @click="formDialogRef.openDialog('view', scope.row.id)">
|
||||
{{ $t('common.viewBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="FolderOpened" @click="openGen(scope.row)" text type="primary">{{
|
||||
$t('gen.genBtn')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button icon="edit-pen" text type="primary" v-auth="'order_createtable_edit'"
|
||||
@click="formDialogRef.openDialog('edit', scope.row.id)">{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" text type="primary" @click="handleDelete([scope.row.id])">{{
|
||||
$t('common.delBtn')
|
||||
}}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination"/>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemCreateTable">
|
||||
import {BasicTableProps, useTable} from "/@/hooks/table";
|
||||
import {fetchList, delObjs} from "/@/api/gen/create-table";
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {list} from "/@/api/gen/datasource";
|
||||
import {useSyncTableApi, useTableApi} from "/@/api/gen/table";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const {t} = useI18n()
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const datasourceList = ref();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
},
|
||||
pageList: fetchList,
|
||||
descs: ["create_time"]
|
||||
})
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/order/create-table/export', state.queryForm, 'create-table.xlsx')
|
||||
}
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: any) => {
|
||||
selectObjs.value = objs.map(({id}) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开生成代码页面
|
||||
* @param row
|
||||
*/
|
||||
const openGen = (row: { tableName: string }) => {
|
||||
useTableApi(state.queryForm.dsName, row.tableName)
|
||||
.then((res) => {
|
||||
if (validateNull(res.data.fieldList)) {
|
||||
useSyncTableApi(state.queryForm.dsName, row.tableName);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
router.push({
|
||||
path: '/gen/gener/index',
|
||||
query: {
|
||||
tableName: row.tableName,
|
||||
dsName: state.queryForm.dsName,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化数据
|
||||
onMounted(() => {
|
||||
list().then((res) => {
|
||||
datasourceList.value = res.data;
|
||||
// 默认去第一个数据源
|
||||
state.queryForm.dsName = datasourceList.value[0]?.name || 'master';
|
||||
getDataList();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
198
src/views/gen/datasource/form.vue
Normal file
198
src/views/gen/datasource/form.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
|
||||
:close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.dsType')" prop="dsType">
|
||||
<el-select v-model="form.dsType" :placeholder="t('datasourceconf.inputdsTypeTip')">
|
||||
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in ds_type"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.name')" prop="name">
|
||||
<el-input v-model="form.name" :placeholder="t('datasourceconf.inputnameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.username')" prop="username">
|
||||
<el-input v-model="form.username" :placeholder="t('datasourceconf.inputusernameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.password')" prop="password">
|
||||
<el-input v-model="form.password" :placeholder="t('datasourceconf.inputpasswordTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item :label="t('datasourceconf.confType')" prop="confType">
|
||||
<el-radio-group v-model="form.confType">
|
||||
<el-radio :label="Number(item.value)" v-for="(item, index) in ds_config_type" border :key="index">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0 && form.dsType === 'mssql'">
|
||||
<el-form-item :label="t('datasourceconf.instance')" prop="instance">
|
||||
<el-input v-model="form.instance" :placeholder="t('datasourceconf.inputinstanceTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.port')" prop="port">
|
||||
<el-input-number v-model="form.port" :placeholder="t('datasourceconf.inputportTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.host')" prop="host">
|
||||
<el-input v-model="form.host" :placeholder="t('datasourceconf.inputhostTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20" v-if="form.confType === 0">
|
||||
<el-form-item :label="t('datasourceconf.dsName')" prop="dsName">
|
||||
<el-input v-model="form.dsName" :placeholder="t('datasourceconf.inputdsNameTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20" v-if="form.confType === 1">
|
||||
<el-form-item :label="t('datasourceconf.url')" prop="url">
|
||||
<el-input v-model="form.url" type="textarea" :placeholder="t('datasourceconf.inputurlTip')"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDatasourceConfDialog">
|
||||
import {useMessage} from '/@/hooks/message';
|
||||
import {getObj, addObj, putObj} from '/@/api/gen/datasource';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useDict} from '/@/hooks/dict';
|
||||
import {rule} from "/@/utils/validate";
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const {t} = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 定义字典处理
|
||||
const {ds_config_type, ds_type} = useDict('ds_config_type', 'ds_type');
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
username: '',
|
||||
password: ('' as string) || undefined,
|
||||
createTime: '',
|
||||
updateTime: '',
|
||||
dsType: '',
|
||||
confType: 0,
|
||||
dsName: '',
|
||||
instance: '',
|
||||
port: 3306,
|
||||
host: '',
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {校验数据源名} rule
|
||||
* @param {*} value
|
||||
* @param {*} callback
|
||||
*/
|
||||
const validateDsName = (_rule, value, callback) => {
|
||||
var re = /(?=.*[a-z])(?=.*_)/;
|
||||
if (value && !re.test(value)) {
|
||||
callback(new Error('数据源名称不合法, 组名_数据源名形式'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
name: [
|
||||
{required: true, message: '别名不能为空', trigger: 'blur'},
|
||||
{validator: validateDsName, trigger: 'blur'},
|
||||
],
|
||||
url: [{required: true, message: 'jdbcurl不能为空', trigger: 'blur'}, {
|
||||
min: 10,
|
||||
max: 500,
|
||||
message: 'URL长度必须介于 10 和 500 字符之间',
|
||||
trigger: 'blur'
|
||||
},],
|
||||
username: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '用户名不能为空', trigger: 'blur'}],
|
||||
password: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '密码不能为空', trigger: 'blur'}],
|
||||
dsType: [{required: true, message: '数据库类型不能为空', trigger: 'blur'}],
|
||||
confType: [{required: true, message: '配置类型不能为空', trigger: 'blur'}],
|
||||
dsName: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '数据库名称不能为空', trigger: 'blur'}],
|
||||
instance: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '实例不能为空', trigger: 'blur'}],
|
||||
port: [{required: true, message: '端口不能为空', trigger: 'blur'}],
|
||||
host: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '主机不能为空', trigger: 'blur'}],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 获取DatasourceConf信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
await getDatasourceConfData(id);
|
||||
// 修改密码时候,原密码打码
|
||||
form.password = '********';
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {
|
||||
});
|
||||
if (!valid) return false;
|
||||
|
||||
form.password = form.password?.includes('******') ? undefined : form.password;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getDatasourceConfData = (id: string) => {
|
||||
// 获取数据
|
||||
return getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
37
src/views/gen/datasource/i18n/en.ts
Normal file
37
src/views/gen/datasource/i18n/en.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
export default {
|
||||
datasourceconf: {
|
||||
index: '#',
|
||||
importDatasourceConfTip: ' import DatasourceConf',
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
url: 'url',
|
||||
username: 'username',
|
||||
password: 'password',
|
||||
docBtn: 'doc',
|
||||
createTime: 'createTime',
|
||||
updateTime: 'updateTime',
|
||||
delFlag: 'delFlag',
|
||||
tenantId: 'tenantId',
|
||||
dsType: 'dsType',
|
||||
confType: 'confType',
|
||||
dsName: 'dsName',
|
||||
instance: 'instance',
|
||||
port: 'port',
|
||||
host: 'host',
|
||||
inputidTip: 'input id',
|
||||
inputnameTip: 'input name',
|
||||
inputurlTip: 'input url',
|
||||
inputusernameTip: 'input username',
|
||||
inputpasswordTip: 'input password',
|
||||
inputcreateTimeTip: 'input createTime',
|
||||
inputupdateTimeTip: 'input updateTime',
|
||||
inputdelFlagTip: 'input delFlag',
|
||||
inputtenantIdTip: 'input tenantId',
|
||||
inputdsTypeTip: 'input dsType',
|
||||
inputconfTypeTip: 'input confType',
|
||||
inputdsNameTip: 'input dsName',
|
||||
inputinstanceTip: 'input instance',
|
||||
inputportTip: 'input port',
|
||||
inputhostTip: 'input host',
|
||||
},
|
||||
};
|
||||
37
src/views/gen/datasource/i18n/zh-cn.ts
Normal file
37
src/views/gen/datasource/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
export default {
|
||||
datasourceconf: {
|
||||
index: '#',
|
||||
importDatasourceConfTip: '导入数据源',
|
||||
id: '主键',
|
||||
name: '别名',
|
||||
url: 'jdbc-url',
|
||||
username: '用户名',
|
||||
password: '密码',
|
||||
docBtn: '文档',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新',
|
||||
delFlag: '删除标记',
|
||||
tenantId: '租户ID',
|
||||
dsType: '类型',
|
||||
confType: '配置类型',
|
||||
dsName: '库名称',
|
||||
instance: '实例',
|
||||
port: '端口',
|
||||
host: '主机',
|
||||
inputidTip: '请输入主键',
|
||||
inputnameTip: '请输入别名',
|
||||
inputurlTip: '请输入jdbcurl',
|
||||
inputusernameTip: '请输入用户名',
|
||||
inputpasswordTip: '请输入密码',
|
||||
inputcreateTimeTip: '请输入创建时间',
|
||||
inputupdateTimeTip: '请输入更新',
|
||||
inputdelFlagTip: '请输入删除标记',
|
||||
inputtenantIdTip: '请输入租户ID',
|
||||
inputdsTypeTip: '请输入数据库类型',
|
||||
inputconfTypeTip: '请输入配置类型',
|
||||
inputdsNameTip: '请输入数据库名称',
|
||||
inputinstanceTip: '请输入实例',
|
||||
inputportTip: '请输入端口',
|
||||
inputhostTip: '请输入主机',
|
||||
},
|
||||
};
|
||||
128
src/views/gen/datasource/index.vue
Normal file
128
src/views/gen/datasource/index.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row class="ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('datasourceconf.dsName')" prop="dsName">
|
||||
<el-input :placeholder="$t('datasourceconf.inputdsNameTip')" v-model="state.queryForm.dsName" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" icon="search" type="primary">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button :disabled="multiple" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40" />
|
||||
<el-table-column :label="t('datasourceconf.index')" type="index" width="60" />
|
||||
<el-table-column :label="t('datasourceconf.name')" prop="name" show-overflow-tooltip />
|
||||
<el-table-column :label="t('datasourceconf.dsName')" prop="dsName" show-overflow-tooltip />
|
||||
<el-table-column :label="t('datasourceconf.dsType')" prop="dsType" show-overflow-tooltip />
|
||||
<el-table-column :label="t('datasourceconf.username')" prop="username" show-overflow-tooltip />
|
||||
<el-table-column :label="t('datasourceconf.createTime')" prop="createTime" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" width="250">
|
||||
<template #default="scope">
|
||||
<el-button icon="document" @click="downloadDoc(scope.row.name)" text type="primary">{{ $t('datasourceconf.docBtn') }} </el-button>
|
||||
|
||||
<el-button icon="edit" @click="formDialogRef.openDialog(scope.row.id)" text type="primary">{{ $t('common.editBtn') }} </el-button>
|
||||
|
||||
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary">{{ $t('common.delBtn') }} </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog @refresh="getDataList()" ref="formDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemDatasourceConf" setup>
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { delObj, fetchList } from '/@/api/gen/datasource';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { downBlobFile } from '/@/utils/other';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
descs: ['create_time'],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
|
||||
|
||||
const downloadDoc = (dsName: string) => {
|
||||
downBlobFile('/gen/dsconf/doc', { dsName }, `${dsName}.html`);
|
||||
};
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
queryRef.value.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
107
src/views/gen/field-type/form.vue
Normal file
107
src/views/gen/field-type/form.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible" width="600" :close-on-click-modal="false" draggable>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-form-item :label="t('fieldtype.columnType')" prop="columnType">
|
||||
<el-input v-model="form.columnType" :placeholder="t('fieldtype.inputcolumnTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.attrType')" prop="attrType">
|
||||
<el-input v-model="form.attrType" :placeholder="t('fieldtype.inputattrTypeTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fieldtype.packageName')" prop="packageName">
|
||||
<el-input v-model="form.packageName" :placeholder="t('fieldtype.inputpackageNameTip')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemFieldTypeDialog">
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { getObj, addObj, putObj, validateColumnType } from '/@/api/gen/fieldtype';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
columnType: '',
|
||||
attrType: '',
|
||||
packageName: '',
|
||||
createTime: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
columnType: [
|
||||
{ required: true, message: '字段类型不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateColumnType(rule, value, callback, form.id !== '');
|
||||
},
|
||||
},
|
||||
],
|
||||
attrType: [{ required: true, message: '属性类型不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
|
||||
// 如果有id参数,表示是编辑操作,需要设置form.id和获取FieldType信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getFieldTypeData(id);
|
||||
} else {
|
||||
// 否则是新增操作,需要清空form.id
|
||||
form.id = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getFieldTypeData = (id: string) => {
|
||||
// 获取数据
|
||||
getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
16
src/views/gen/field-type/i18n/en.ts
Normal file
16
src/views/gen/field-type/i18n/en.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
fieldtype: {
|
||||
index: '#',
|
||||
importFieldTypeTip: ' import FieldType',
|
||||
id: 'id',
|
||||
columnType: 'columnType',
|
||||
attrType: 'attrType',
|
||||
packageName: 'packageName',
|
||||
createTime: 'createTime',
|
||||
inputidTip: 'input id',
|
||||
inputcolumnTypeTip: 'input columnType',
|
||||
inputattrTypeTip: 'input attrType',
|
||||
inputpackageNameTip: 'input packageName',
|
||||
inputcreateTimeTip: 'input createTime',
|
||||
},
|
||||
};
|
||||
16
src/views/gen/field-type/i18n/zh-cn.ts
Normal file
16
src/views/gen/field-type/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
fieldtype: {
|
||||
index: '#',
|
||||
importFieldTypeTip: '导入列属性',
|
||||
id: 'id',
|
||||
columnType: '字段类型',
|
||||
attrType: '属性类型',
|
||||
packageName: '属性包名',
|
||||
createTime: '创建时间',
|
||||
inputidTip: '请输入id',
|
||||
inputcolumnTypeTip: '请输入字段类型',
|
||||
inputattrTypeTip: '请输入属性类型',
|
||||
inputpackageNameTip: '请输入属性包名',
|
||||
inputcreateTimeTip: '请输入创建时间',
|
||||
},
|
||||
};
|
||||
126
src/views/gen/field-type/index.vue
Normal file
126
src/views/gen/field-type/index.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row class="ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('fieldtype.columnType')" prop="columnType">
|
||||
<el-input :placeholder="$t('fieldtype.inputcolumnTypeTip')" formDialogRef style="max-width: 180px" v-model="state.queryForm.columnType" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" icon="search" type="primary">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" formDialogRef icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button plain :disabled="multiple" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary">
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="true"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40" />
|
||||
<el-table-column :label="t('fieldtype.index')" type="index" width="60" />
|
||||
<el-table-column :label="t('fieldtype.columnType')" prop="columnType" show-overflow-tooltip />
|
||||
<el-table-column :label="t('fieldtype.attrType')" prop="attrType" show-overflow-tooltip />
|
||||
<el-table-column :label="t('fieldtype.packageName')" prop="packageName" show-overflow-tooltip />
|
||||
<el-table-column :label="t('fieldtype.createTime')" prop="createTime" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.id)" text type="primary">{{ $t('common.editBtn') }} </el-button>
|
||||
|
||||
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary">{{ $t('common.delBtn') }} </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog @refresh="getDataList()" ref="formDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemFieldType" setup>
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { delObj, fetchList } from '/@/api/gen/fieldtype';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const { t } = useI18n();
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选rows
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
descs: ['create_time'],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
queryRef.value.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/gen/fieldtype/export', state.queryForm, 'fieldtype.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObj(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
125
src/views/gen/gener/index.vue
Normal file
125
src/views/gen/gener/index.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<el-card class="layout-padding-auto" shadow="hover">
|
||||
<el-steps :active="active" finish-status="success" simple>
|
||||
<el-step title="基础信息" @click="go(0)">
|
||||
<template #icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M14.25 6.087c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.036-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959v0a.64.64 0 0 1-.657.643 48.39 48.39 0 0 1-4.163-.3c.186 1.613.293 3.25.315 4.907a.656.656 0 0 1-.658.663v0c-.355 0-.676-.186-.959-.401a1.647 1.647 0 0 0-1.003-.349c-1.036 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401v0c.31 0 .555.26.532.57a48.039 48.039 0 0 1-.642 5.056c1.518.19 3.058.309 4.616.354a.64.64 0 0 0 .657-.643v0c0-.355-.186-.676-.401-.959a1.647 1.647 0 0 1-.349-1.003c0-1.035 1.008-1.875 2.25-1.875 1.243 0 2.25.84 2.25 1.875 0 .369-.128.713-.349 1.003-.215.283-.4.604-.4.959v0c0 .333.277.599.61.58a48.1 48.1 0 0 0 5.427-.63 48.05 48.05 0 0 0 .582-4.717.532.532 0 0 0-.533-.57v0c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.035 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.37 0 .713.128 1.003.349.283.215.604.401.96.401v0a.656.656 0 0 0 .658-.663 48.422 48.422 0 0 0-.37-5.36c-1.886.342-3.81.574-5.766.689a.578.578 0 0 1-.61-.58v0Z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step title="数据修改" @click="go(1)">
|
||||
<template #icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
</el-card>
|
||||
|
||||
<el-card class="layout-padding-auto mt5" shadow="hover">
|
||||
<!-- 生成基本信息设置 -->
|
||||
<generator ref="generatorRef" :tableName="tableName" :dsName="dsName" v-if="active === 0" />
|
||||
<!-- 字段编辑设置 -->
|
||||
<edit-table ref="editTableRef" :tableName="tableName" :dsName="dsName" v-if="active === 1" />
|
||||
|
||||
<div class="flex gap-4 justify-center mt-6">
|
||||
<el-button v-if="active === 0" plain type="primary" size="large" icon="ArrowRight" @click="go(1)"> 下一步 </el-button>
|
||||
<el-button v-if="active === 1" plain icon="ArrowLeft" size="large" @click="go(0)"> 上一步 </el-button>
|
||||
<el-button v-if="active === 1" plain type="success" size="large" icon="View" @click="preview"> 保存并预览 </el-button>
|
||||
<el-button v-if="active === 1" plain type="primary" size="large" icon="Download" @click="generatorHandle"> 保存并生成 </el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 预览基本信息 -->
|
||||
<preview-dialog ref="previewDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useGeneratorCodeApi } from '/@/api/gen/table';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { downBlobFile } from '/@/utils/other';
|
||||
|
||||
const { t } = useI18n();
|
||||
const Generator = defineAsyncComponent(() => import('../table/generator.vue'));
|
||||
const EditTable = defineAsyncComponent(() => import('../table/edit.vue'));
|
||||
const PreviewDialog = defineAsyncComponent(() => import('../table/preview.vue'));
|
||||
const previewDialogRef = ref();
|
||||
const generatorRef = ref();
|
||||
|
||||
const route = useRoute();
|
||||
const active = ref(0);
|
||||
const tableId = ref();
|
||||
const tableName = ref();
|
||||
const dsName = ref();
|
||||
const editTableRef = ref();
|
||||
const generatorType = ref();
|
||||
|
||||
// 跳转
|
||||
const go = async (activeNum: number) => {
|
||||
try {
|
||||
if (activeNum === 0) {
|
||||
await editTableRef.value.submitHandle();
|
||||
} else if (activeNum === 1) {
|
||||
const dataform = await generatorRef.value.submitHandle();
|
||||
tableId.value = dataform.id;
|
||||
generatorType.value = dataform.generatorType;
|
||||
}
|
||||
if (active.value === activeNum) return;
|
||||
active.value = activeNum;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
// 预览代码
|
||||
const preview = async () => {
|
||||
await editTableRef.value.submitHandle();
|
||||
previewDialogRef.value.openDialog(tableId.value);
|
||||
};
|
||||
|
||||
// 生成
|
||||
const generatorHandle = async () => {
|
||||
await editTableRef.value.submitHandle();
|
||||
// 生成代码,zip压缩包
|
||||
if (generatorType.value === '0') {
|
||||
downBlobFile(`/gen/generator/download?tableIds=${[tableId.value].join(',')}`, {}, `${tableName.value}.zip`).catch((msg) => {
|
||||
useMessage().error(msg);
|
||||
});
|
||||
}
|
||||
|
||||
// 写入到指定目录
|
||||
if (generatorType.value === '1') {
|
||||
useGeneratorCodeApi([tableId.value].join(','))
|
||||
.then(() => {
|
||||
useMessage().success(t('common.optSuccessText'));
|
||||
})
|
||||
.catch(({ msg }) => {
|
||||
useMessage().error(msg);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
tableName.value = route.query.tableName;
|
||||
dsName.value = route.query.dsName;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout-padding {
|
||||
height: auto !important;
|
||||
}
|
||||
</style>
|
||||
119
src/views/gen/group/form.vue
Normal file
119
src/views/gen/group/form.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" width="600">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||
<el-form-item :label="t('group.groupName')" prop="groupName">
|
||||
<el-input v-model="form.groupName" :placeholder="t('group.inputGroupNameTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('group.templateType')" prop="templateId">
|
||||
<el-select v-model="form.templateId" :placeholder="$t('group.selectType')" clearable multiple>
|
||||
<el-option v-for="item in templateData" :key="item.id" :label="item.templateName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('group.groupDesc')" prop="groupDesc">
|
||||
<el-input type="textarea" maxlength="100" :rows="5" v-model="form.groupDesc" :placeholder="t('group.inputGroupDescTip')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="GenGroupDialog" setup>
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { addObj, getObj, putObj } from '/@/api/gen/group';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { list as templateList } from '/@/api/gen/template';
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const templateData = ref<any[]>([]);
|
||||
// 定义字典
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
groupName: '',
|
||||
groupDesc: '',
|
||||
templateId: [] as string[],
|
||||
putList: [],
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
groupName: [{ required: true, message: '分组名称不能为空', trigger: 'blur' }],
|
||||
templateId: [{ required: true, message: '模板不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value.resetFields();
|
||||
});
|
||||
|
||||
// 如果有 id 参数,获取 genGroup 信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getgenGroupData(id);
|
||||
}
|
||||
|
||||
// 获取模板信息
|
||||
getTemplateData();
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化表单数据
|
||||
const getgenGroupData = (id: string) => {
|
||||
// 获取数据
|
||||
getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
form.templateId = [];
|
||||
if (res.data.templateList) {
|
||||
let list = res.data.templateList;
|
||||
list.forEach((item) => {
|
||||
form.templateId.push(item.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 角色数据
|
||||
const getTemplateData = () => {
|
||||
templateList().then((res) => {
|
||||
templateData.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
15
src/views/gen/group/i18n/en.ts
Normal file
15
src/views/gen/group/i18n/en.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export default {
|
||||
group: {
|
||||
index: '#',
|
||||
importgenGroupTip: 'import GenGroup',
|
||||
id: 'id',
|
||||
groupName: 'groupName',
|
||||
groupDesc: 'groupDesc',
|
||||
inputIdTip: 'input id',
|
||||
createTime: 'createTime',
|
||||
inputGroupNameTip: 'input groupName',
|
||||
inputGroupDescTip: 'input groupDesc',
|
||||
templateType: 'template Type',
|
||||
selectType: 'please select a template type',
|
||||
},
|
||||
};
|
||||
15
src/views/gen/group/i18n/zh-cn.ts
Normal file
15
src/views/gen/group/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export default {
|
||||
group: {
|
||||
index: '#',
|
||||
importgenGroupTip: '导入模板分组',
|
||||
id: ' id',
|
||||
groupName: '分组名称',
|
||||
groupDesc: '分组描述',
|
||||
createTime: '创建时间',
|
||||
inputIdTip: '请输入 id',
|
||||
inputGroupNameTip: '请输入分组名称',
|
||||
inputGroupDescTip: '请输入分组描述',
|
||||
templateType: '模板类型',
|
||||
selectType: '请选择模板类型',
|
||||
},
|
||||
};
|
||||
143
src/views/gen/group/index.vue
Normal file
143
src/views/gen/group/index.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row class="ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('group.groupName')" prop="groupName">
|
||||
<el-input :placeholder="t('group.inputGroupNameTip')" style="max-width: 180px" v-model="state.queryForm.groupName" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" formDialogRef icon="search" type="primary">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" formDialogRef icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button @click="formDialogRef.openDialog()" class="ml10" formDialogRef icon="folder-add" type="primary" v-auth="'codegen_group_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
@click="handleDelete(selectObjs)"
|
||||
class="ml10"
|
||||
formDialogRef
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'codegen_group_del'"
|
||||
>
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="'codegen_group_export'"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="sortChangeHandle"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40" />
|
||||
<el-table-column :label="t('group.index')" type="index" width="60" />
|
||||
<el-table-column :label="t('group.groupName')" prop="groupName" show-overflow-tooltip />
|
||||
<el-table-column :label="t('group.groupDesc')" prop="groupDesc" show-overflow-tooltip />
|
||||
<el-table-column :label="t('group.createTime')" prop="createTime" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" width="200">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.id)" text type="primary" v-auth="'codegen_group_edit'"
|
||||
>{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary" v-auth="'codegen_group_del'"
|
||||
>{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog @refresh="getDataList()" ref="formDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemGenGroup" setup>
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { delObjs, fetchList } from '/@/api/gen/group';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const { t } = useI18n();
|
||||
// 定义查询字典
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref();
|
||||
// 搜索变量
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
descs: ['create_time'],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/gen/group/export', state.queryForm, 'group.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
171
src/views/gen/table/add-dict.vue
Normal file
171
src/views/gen/table/add-dict.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<el-dialog title="新增字典" v-model="visible" width="600">
|
||||
<el-form :model="dataForm" :rules="dataRules" label-width="100px" ref="dicDialogFormRef" v-loading="loading">
|
||||
<el-form-item :label="$t('sysdict.systemFlag')" prop="systemFlag">
|
||||
<el-radio-group v-model="dataForm.systemFlag">
|
||||
<el-radio border :key="index" :label="item.value" v-for="(item, index) in dict_type">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysdict.dictType')" prop="dictType">
|
||||
<el-input :placeholder="$t('sysdict.inputDictTypeTip')" :disabled="dataForm.id !== ''" clearable v-model="dataForm.dictType"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('sysdict.description')" prop="description">
|
||||
<el-input :placeholder="$t('sysdict.inputDescriptionTip')" clearable v-model="dataForm.description"></el-input>
|
||||
</el-form-item>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item :label="t('dictItem.name')" prop="columns">
|
||||
<el-table :data="dataForm.columns" border style="width: 100%" max-height="500">
|
||||
<el-table-column type="index" :label="t('createTable.index')" width="50">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="onAddItem"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="handleDelete(scope.$index)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="label" :label="$t('dictItem.label')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.label" :placeholder="t('dictItem.inputLabelTip')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="value" :label="$t('dictItem.itemValue')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" :placeholder="t('dictItem.inputItemValueTip')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemDicDialog" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { addItemObj, addObj, validateDictType } from '/@/api/admin/dict';
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { rule } from '/@/utils/validate';
|
||||
|
||||
// 定义子组件向父组件传值/事件
|
||||
const emit = defineEmits(['refresh']);
|
||||
const { dict_type } = useDict('dict_type');
|
||||
const { t } = useI18n();
|
||||
// 定义变量内容
|
||||
const dicDialogFormRef = ref();
|
||||
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const selectRow = ref({});
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
dictType: '',
|
||||
description: '',
|
||||
systemFlag: '0',
|
||||
remarks: '',
|
||||
columns: [] as any,
|
||||
});
|
||||
|
||||
const dataRules = reactive({
|
||||
dictType: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '类型不能为空', trigger: 'blur' },
|
||||
{ validator: rule.validatorNameCn, trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
validateDictType(rule, value, callback, dataForm.id !== '');
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
systemFlag: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }],
|
||||
description: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '描述不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
columns: [{ required: true, message: '字典项不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = () => {
|
||||
visible.value = true;
|
||||
dataForm.id = '';
|
||||
nextTick(() => {
|
||||
dicDialogFormRef.value?.resetFields();
|
||||
});
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dicDialogFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
// 验证字典项是否为空
|
||||
if (dataForm.columns.length === 0) {
|
||||
useMessage().error(t('dictItem.emptyItemsError'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证字典项的label和value是否为空
|
||||
for (let i = 0; i < dataForm.columns.length; i++) {
|
||||
const item = dataForm.columns[i];
|
||||
if (!item.label) {
|
||||
useMessage().error(t('dictItem.labelRequired'));
|
||||
return false;
|
||||
}
|
||||
if (!item.value) {
|
||||
useMessage().error(t('dictItem.valueRequired'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
// 添加字典
|
||||
const { data } = await addObj(dataForm);
|
||||
|
||||
// 添加字典项
|
||||
const promises = dataForm.columns.map(async (item: any) => {
|
||||
item.dictId = data.id;
|
||||
item.dictType = dataForm.dictType;
|
||||
return addItemObj(item);
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
useMessage().success(t('common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh', dataForm.dictType);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
let index = 1;
|
||||
const onAddItem = () => {
|
||||
dataForm.columns.push({ sortOrder: `${index++}` });
|
||||
};
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
dataForm.columns.splice(index, 1);
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
281
src/views/gen/table/batchGenDialog.vue
Normal file
281
src/views/gen/table/batchGenDialog.vue
Normal file
@@ -0,0 +1,281 @@
|
||||
<template>
|
||||
<el-dialog :title="$t('gen.batchGenBtn')" v-model="visible" :close-on-click-modal="false" width="600px">
|
||||
<el-form :model="form" ref="dataFormRef" label-width="120px">
|
||||
<el-form-item :label="$t('gen.author')" prop="author">
|
||||
<el-input v-model="form.author" :placeholder="$t('gen.inputAuthorTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.packageName')" prop="packageName">
|
||||
<el-input v-model="form.packageName" :placeholder="$t('gen.inputPackageNameTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.moduleName')" prop="moduleName">
|
||||
<el-input v-model="form.moduleName" :placeholder="$t('gen.inputModuleNameTip')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.style')" prop="style">
|
||||
<el-select v-model="form.style" :placeholder="$t('gen.inputStyleTip')">
|
||||
<el-option v-for="item in styleList" :key="item.id" :label="item.groupName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.parentMenu')" prop="syncMenuId">
|
||||
<el-tree-select
|
||||
v-model="form.syncMenuId"
|
||||
:data="menuList"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
value-key="id"
|
||||
placeholder="选择所属菜单"
|
||||
clearable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
class="w100"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="syncRoute">
|
||||
<template #label>
|
||||
{{ $t('gen.syncRoute') }}
|
||||
<tip :content="`微服务架构下会自动创建一条【/${form.moduleName}】的网关路由,存在则跳过`" />
|
||||
</template>
|
||||
<el-radio-group v-model="form.syncRoute">
|
||||
<el-radio label="0">{{ $t('gen.syncRouteManual') }}</el-radio>
|
||||
<el-radio label="1">{{ $t('gen.syncRouteAuto') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.formLayout')" prop="formLayout">
|
||||
<el-radio-group v-model="form.formLayout">
|
||||
<el-radio :label="1">{{ $t('gen.formLayoutOne') }}</el-radio>
|
||||
<el-radio :label="2">{{ $t('gen.formLayoutTwo') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('gen.genType')" prop="generatorType">
|
||||
<el-radio-group v-model="form.generatorType">
|
||||
<el-radio label="0">{{ $t('gen.genTypeZip') }}</el-radio>
|
||||
<el-radio label="1">{{ $t('gen.genTypeCustom') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item prop="backendPath" v-if="form.generatorType === '1'">
|
||||
<template #label>
|
||||
<span>{{ $t('gen.backendPath') }}</span>
|
||||
<tip :content="$t('gen.backendPathTip')" />
|
||||
</template>
|
||||
<el-input :placeholder="$t('gen.inputBackendPathTip')" v-model="form.backendPath"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="frontendPath" v-if="form.generatorType === '1'">
|
||||
<template #label>
|
||||
<span>{{ $t('gen.frontendPath') }}</span>
|
||||
<tip :content="$t('gen.frontendPathTip')" />
|
||||
</template>
|
||||
<el-input :placeholder="$t('gen.inputFrontendPathTip')" v-model="form.frontendPath"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button type="primary" @click="debouncedHandleSubmit" :loading="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { groupList, useSyncTableApi, putObj, useGeneratorCodeApi } from '/@/api/gen/table';
|
||||
import { pageList as menuListApi } from '/@/api/admin/menu';
|
||||
import { downBlobFile } from '/@/utils/other';
|
||||
import { Local } from '/@/utils/storage';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 基础状态变量
|
||||
const visible = ref(false); // 对话框显示状态
|
||||
const loading = ref(false); // 加载状态
|
||||
const dataFormRef = ref(); // 表单引用
|
||||
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
author: 'cloud', // 作者
|
||||
packageName: 'net.cyweb.cloud', // 包名
|
||||
moduleName: 'admin', // 模块名
|
||||
style: '', // 样式
|
||||
syncMenuId: '', // 同步菜单ID
|
||||
syncRoute: '0', // 同步路由方式
|
||||
formLayout: 1, // 表单布局
|
||||
generatorType: '0', // 生成类型
|
||||
tableIds: [] as string[], // 表ID列表
|
||||
dsName: '', // 数据源名称
|
||||
frontendPath: '', // 前端路径
|
||||
backendPath: '', // 后端路径
|
||||
});
|
||||
|
||||
// 数据存储
|
||||
const styleList = ref<{ id: string; groupName: string }[]>([]); // 样式列表
|
||||
const menuList = ref([]); // 菜单列表
|
||||
const selectedTables = ref<any[]>([]); // 选中的表
|
||||
const dsName = ref(''); // 数据源名称
|
||||
const syncedTableMetas = ref<any[]>([]); // 同步后的表元数据
|
||||
|
||||
/**
|
||||
* 打开批量生成对话框
|
||||
* @param tables 选中的表列表
|
||||
* @param currentDsName 当前数据源名称
|
||||
*/
|
||||
const openDialog = async (tables: any[], currentDsName: string) => {
|
||||
// 初始化对话框状态
|
||||
visible.value = true;
|
||||
selectedTables.value = tables;
|
||||
dsName.value = currentDsName;
|
||||
syncedTableMetas.value = [];
|
||||
|
||||
// 重置表单字段
|
||||
dataFormRef.value?.resetFields();
|
||||
|
||||
// 设置动态表单值
|
||||
form.dsName = currentDsName;
|
||||
form.tableIds = tables.map((t) => t.id);
|
||||
|
||||
// 同步表结构
|
||||
if (tables?.length > 0) {
|
||||
loading.value = true;
|
||||
ElMessage.info(t('gen.syncingTables'));
|
||||
|
||||
try {
|
||||
// 并发同步所有选中的表
|
||||
const syncResults = await Promise.allSettled(
|
||||
tables.map((table) =>
|
||||
useSyncTableApi(currentDsName, table.name).then((response) => {
|
||||
// 只返回有效的表元数据
|
||||
return response.data?.id && response.data?.tableName ? response.data : null;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// 收集成功同步的表元数据
|
||||
syncedTableMetas.value = syncResults
|
||||
.filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled' && result.value !== null)
|
||||
.map((result) => result.value);
|
||||
|
||||
// 显示同步结果
|
||||
if (syncedTableMetas.value.length > 0) {
|
||||
ElMessage.success(t('gen.allTablesSyncedSuccessfully'));
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载本地存储的路径
|
||||
loadStoredPaths();
|
||||
|
||||
// 获取分组和菜单列表
|
||||
await Promise.all([getGroupList(), getMenuList()]);
|
||||
};
|
||||
|
||||
/**
|
||||
* 从本地存储加载路径配置
|
||||
*/
|
||||
const loadStoredPaths = () => {
|
||||
// 加载前端路径
|
||||
const localFrontendPath = Local.get('frontendPath');
|
||||
form.frontendPath = localFrontendPath || '';
|
||||
|
||||
// 加载后端路径
|
||||
const localBackendPath = Local.get('backendPath');
|
||||
form.backendPath = localBackendPath || '';
|
||||
};
|
||||
|
||||
// Watch for path changes and save to local storage
|
||||
watch(
|
||||
() => form.frontendPath,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
Local.set('frontendPath', newVal);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => form.backendPath,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
Local.set('backendPath', newVal);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取代码生成样式分组列表
|
||||
*/
|
||||
const getGroupList = async () => {
|
||||
const { data } = await groupList();
|
||||
styleList.value = data || [];
|
||||
|
||||
// 设置默认样式
|
||||
if (data?.length > 0) {
|
||||
form.style = data[0].id;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*/
|
||||
const getMenuList = async () => {
|
||||
const { data } = await menuListApi();
|
||||
menuList.value = data || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理表单提交
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
// 表单验证
|
||||
const valid = await dataFormRef.value.validate();
|
||||
if (!valid) return;
|
||||
|
||||
// 确保有已同步的表
|
||||
if (!syncedTableMetas.value?.length) return;
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 更新表元数据并收集成功的表ID
|
||||
const putResults = await Promise.allSettled(syncedTableMetas.value.map((meta) => putObj({ id: meta.id, ...form }).then(() => meta.id)));
|
||||
|
||||
// 筛选成功更新的表ID
|
||||
const tableIdsForGeneration = putResults
|
||||
.filter((result): result is PromiseFulfilledResult<string> => result.status === 'fulfilled' && Boolean(result.value))
|
||||
.map((result) => result.value);
|
||||
|
||||
// 没有可生成的表,直接返回
|
||||
if (!tableIdsForGeneration.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 执行代码生成
|
||||
if (form.generatorType === '0') {
|
||||
// 生成ZIP下载
|
||||
const fileName = form.moduleName ? `${form.moduleName}.zip` : 'generated_code.zip';
|
||||
await downBlobFile(`/gen/generator/download?tableIds=${tableIdsForGeneration.join(',')}`, {}, fileName);
|
||||
} else {
|
||||
// 生成到指定路径
|
||||
await useGeneratorCodeApi(tableIdsForGeneration);
|
||||
}
|
||||
|
||||
// 操作成功提示并关闭对话框
|
||||
ElMessage.success(t('common.optSuccessText'));
|
||||
visible.value = false;
|
||||
} catch (error) {
|
||||
ElMessage.error(t('gen.generationFailed'));
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const debouncedHandleSubmit = useDebounceFn(handleSubmit, 500);
|
||||
|
||||
// 向外暴露方法
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
142
src/views/gen/table/child.vue
Normal file
142
src/views/gen/table/child.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-dialog :close-on-click-modal="false" title="子表配置" draggable v-model="visible">
|
||||
<el-form :model="form" :rules="dataRules" ref="dataFormRef">
|
||||
<el-row :gutter="35">
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="childTableName">
|
||||
<template #label> 子表名<tip content="关联表的子表,例如一对多中的存储多信息的表" /> </template>
|
||||
<el-select placeholder="请选择子表" v-model="form.childTableName" filterable @change="getChildTableColumnList">
|
||||
<el-option :key="item" :label="item" :value="item" v-for="item in childTableList"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="mainField">
|
||||
<template #label> 主表字段<tip content="一般为主表的主键字段" /> </template>
|
||||
<el-select placeholder="请选关联字段" v-model="form.mainField" filterable>
|
||||
<el-option :key="item" :label="item" :value="item" v-for="item in mainTableColumnList"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="childField">
|
||||
<template #label> 子表字段<tip content="子表中对应主表主键的关联字段" /> </template>
|
||||
<el-select placeholder="请选关联字段" v-model="form.childField" filterable>
|
||||
<el-option :key="item" :label="item" :value="item" v-for="item in childTableColumnList"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="onClear">清空</el-button>
|
||||
<el-button @click="onSubmit" type="primary">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts" name="child">
|
||||
import {useListTableApi, useListTableColumnApi, useSyncTableApi} from '/@/api/gen/table';
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
defineProps({
|
||||
modelValue: Object,
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
const dataFormRef = ref();
|
||||
const form = reactive({
|
||||
childTableName: '',
|
||||
mainField: '',
|
||||
childField: '',
|
||||
});
|
||||
|
||||
const dataRules = ref({
|
||||
childTableName: [{ required: true, message: '请选择子表', trigger: 'blur' }],
|
||||
mainField: [{ required: true, message: '请选择关联字段', trigger: 'blur' }],
|
||||
childField: [{ required: true, message: '请选择关联字段', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const childTableList = ref();
|
||||
const childTableColumnList = ref();
|
||||
const mainTableColumnList = ref();
|
||||
const currentDsName = ref('');
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (row: any) => {
|
||||
currentDsName.value = row.dsName;
|
||||
visible.value = true;
|
||||
|
||||
getAllTable(row.dsName);
|
||||
getAllField(row.dsName, row.tableName);
|
||||
if (row.childTableName) {
|
||||
form.childTableName = row.childTableName;
|
||||
form.mainField = row.mainField;
|
||||
form.childField = row.childField;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前数据下的所有表
|
||||
const getAllTable = (dsName: string) => {
|
||||
useListTableApi(dsName).then((res) => {
|
||||
childTableList.value = res.data.map((item: any) => item.name);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取对应表的所有字段
|
||||
const getAllField = (dsName: string, tableName: string) => {
|
||||
useListTableColumnApi(dsName, tableName).then((res) => {
|
||||
mainTableColumnList.value = res.data.map((item: any) => {
|
||||
return item.name;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 获取子表的全部字段
|
||||
const getChildTableColumnList = (val: string) => {
|
||||
form.childField = '';
|
||||
useListTableColumnApi(currentDsName.value, val).then((res) => {
|
||||
childTableColumnList.value = res.data.map((item: any) => {
|
||||
return item.name;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 确认提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
// 同步子表数据
|
||||
useSyncTableApi(currentDsName.value,form.childTableName).then(() => {
|
||||
useMessage().success('子表信息同步成功')
|
||||
});
|
||||
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// 清空子表配置,后台当单表处理
|
||||
const onClear = () => {
|
||||
form.childTableName = '';
|
||||
form.mainField = '';
|
||||
form.childField = '';
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => form,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
onMounted(() => {});
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
371
src/views/gen/table/edit.vue
Normal file
371
src/views/gen/table/edit.vue
Normal file
@@ -0,0 +1,371 @@
|
||||
<template>
|
||||
<el-tabs v-model="activeName">
|
||||
<!-- 属性设置面板 -->
|
||||
<el-tab-pane label="属性设置" name="field">
|
||||
<sc-form-table ref="fieldTable" v-model="fieldList" :hideAdd="true" :hideDelete="true" drag-sort placeholder="暂无数据">
|
||||
<el-table-column label="主键" prop="primaryPk" width="80" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.primaryPk" true-label="1" false-label="0" disabled></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字段名" prop="fieldName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="属性名" prop="attrName" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.attrName" placeholder="请输入属性名"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="说明" prop="fieldComment" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.fieldComment" placeholder="请输入说明"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字段类型" prop="fieldType" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="属性类型" prop="attrType" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.attrType" placeholder="请选择属性类型" @change="handleChangeRow(row)">
|
||||
<el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="自动填充" prop="autoFill" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.autoFill" placeholder="请选择类型">
|
||||
<el-option v-for="item in fillList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字典名称" prop="fieldDict" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.fieldDict" placeholder="请选择类型" filterable clearable :disabled="row.primaryPk === '1'">
|
||||
<template #prefix>
|
||||
<el-button icon="Plus" type="primary" link @click.stop="handleAddDict(row)"></el-button>
|
||||
</template>
|
||||
<el-option v-for="item in fieldDictList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</sc-form-table>
|
||||
</el-tab-pane>
|
||||
<!-- 列表设置面板 -->
|
||||
<el-tab-pane label="列表查询" name="third">
|
||||
<sc-form-table ref="gridTable" v-model="fieldList" :hideAdd="true" :hideDelete="true" placeholder="暂无数据">
|
||||
<el-table-column label="属性名" prop="attrName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="说明" prop="fieldComment" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="列表显示" prop="gridItem" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.gridItem" true-label="1" false-label="0" :disabled="row.primaryPk === '1'"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否排序" prop="gridSort" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.gridSort" true-label="1" false-label="0" :disabled="row.primaryPk === '1'"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="查询显示" prop="gridSort" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.queryItem" true-label="1" false-label="0" :disabled="row.primaryPk === '1'"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="查询表单类型" prop="queryFormType" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.queryFormType" placeholder="请选择查询表单类型" :disabled="row.primaryPk === '1'">
|
||||
<el-option v-for="item in queryTypeList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="查询方式" prop="queryType" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.queryType" placeholder="请选择查询方式" :disabled="row.primaryPk === '1'">
|
||||
<el-option v-for="item in queryList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</sc-form-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表单页面" name="form">
|
||||
<sc-form-table ref="formTable" v-model="fieldList" :hideAdd="true" :hideDelete="true" placeholder="暂无数据">
|
||||
<el-table-column label="属性名" prop="attrName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="说明" prop="fieldComment" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="表单类型" prop="formType" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.formType" placeholder="请选择表单类型" :disabled="row.primaryPk === '1'">
|
||||
<el-option v-for="item in formTypeList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否显示" prop="formItem" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.formItem" true-label="1" false-label="0" :disabled="row.primaryPk === '1'"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="表单必填" prop="formRequired" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.formRequired" true-label="1" false-label="0" :disabled="row.primaryPk === '1'"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="表单效验" prop="formValidator" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.formValidator" placeholder="请选择表单效验" :disabled="row.primaryPk === '1'" clearable>
|
||||
<el-option v-for="item in formValidatorList" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</sc-form-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 新增字典 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="handleDictRefresh" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTableFieldSubmitApi, useTableApi, fetchDictList } from '/@/api/gen/table';
|
||||
import { list } from '/@/api/gen/fieldtype';
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
const scFormTable = defineAsyncComponent(() => import('/@/components/FormTable/index.vue'));
|
||||
const FormDialog = defineAsyncComponent(() => import('./add-dict.vue'));
|
||||
|
||||
const activeName = ref();
|
||||
const tableId = ref('');
|
||||
|
||||
const props = defineProps({
|
||||
tableName: {
|
||||
type: String,
|
||||
},
|
||||
dsName: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
|
||||
const sortable = ref() as any;
|
||||
|
||||
const formDialogRef = ref();
|
||||
const typeList = ref([]) as any;
|
||||
const fieldDictList = ref([]) as any;
|
||||
const selectRow = ref();
|
||||
const dsName = ref();
|
||||
const tableName = ref();
|
||||
|
||||
const fieldList = ref([]);
|
||||
const fillList = reactive([
|
||||
{ label: 'DEFAULT', value: 'DEFAULT' },
|
||||
{ label: 'INSERT', value: 'INSERT' },
|
||||
{ label: 'UPDATE', value: 'UPDATE' },
|
||||
{ label: 'INSERT_UPDATE', value: 'INSERT_UPDATE' },
|
||||
]);
|
||||
|
||||
const queryList = reactive([
|
||||
{ label: '=', value: '=' },
|
||||
{ label: '!=', value: '!=' },
|
||||
{ label: '>', value: '>' },
|
||||
{ label: '>=', value: '>=' },
|
||||
{ label: '<', value: '<' },
|
||||
{ label: '<=', value: '<=' },
|
||||
{ label: 'like', value: 'like' },
|
||||
{ label: 'left like', value: 'left like' },
|
||||
{ label: 'right like', value: 'right like' },
|
||||
]);
|
||||
|
||||
const formTypeList = reactive([
|
||||
{ label: '单行文本', value: 'text' },
|
||||
{ label: '多行文本', value: 'textarea' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '富文本编辑器', value: 'editor' },
|
||||
{ label: '下拉框', value: 'select' },
|
||||
{ label: '单选按钮', value: 'radio' },
|
||||
{ label: '复选框', value: 'checkbox' },
|
||||
{ label: '日期', value: 'date' },
|
||||
{ label: '日期时间', value: 'datetime' },
|
||||
{ label: '文件上传', value: 'upload-file' },
|
||||
{ label: '图片上传', value: 'upload-img' },
|
||||
]);
|
||||
|
||||
const queryTypeList = reactive([
|
||||
{ label: '单行文本', value: 'text' },
|
||||
{ label: '多行文本', value: 'textarea' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '下拉框', value: 'select' },
|
||||
{ label: '单选按钮', value: 'radio' },
|
||||
{ label: '复选框', value: 'checkbox' },
|
||||
{ label: '日期', value: 'date' },
|
||||
{ label: '日期时间', value: 'datetime' },
|
||||
]);
|
||||
|
||||
const formValidatorList = reactive([
|
||||
{ label: '去重', value: 'duplicate' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '字母', value: 'letter' },
|
||||
{ label: '字母和数字', value: 'letterAndNumber' },
|
||||
{ label: '手机号码', value: 'mobilePhone' },
|
||||
{ label: '字母开头,仅可包含数字', value: 'letterStartNumberIncluded' },
|
||||
{ label: '禁止中文输入', value: 'noChinese' },
|
||||
{ label: '必须中文输入', value: 'chinese' },
|
||||
{ label: '电子邮箱', value: 'email' },
|
||||
{ label: 'URL网址', value: 'url' },
|
||||
]);
|
||||
|
||||
const propToType = reactive({
|
||||
tinyint: 'number',
|
||||
smallint: 'number',
|
||||
mediumint: 'number',
|
||||
int: 'number',
|
||||
integer: 'number',
|
||||
bigint: 'number',
|
||||
float: 'number',
|
||||
datetime: 'datetime',
|
||||
LocalDateTime: 'datetime',
|
||||
date: 'date',
|
||||
LocalDate: 'date',
|
||||
Long: 'number',
|
||||
Float: 'number',
|
||||
Double: 'number',
|
||||
BigDecimal: 'number',
|
||||
text: 'textarea',
|
||||
String: 'text',
|
||||
longtext: 'editor',
|
||||
bit: 'radio',
|
||||
Boolean: 'radio',
|
||||
char: 'radio',
|
||||
varchar: 'text',
|
||||
});
|
||||
|
||||
/**
|
||||
* 属性修改触发事件
|
||||
* @param row
|
||||
*/
|
||||
const handleChangeRow = (row: any) => {
|
||||
row.queryFormType = propToType[row.attrType];
|
||||
row.formType = propToType[row.attrType];
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加字典
|
||||
* @param row
|
||||
*/
|
||||
const handleAddDict = (row: object) => {
|
||||
selectRow.value = row;
|
||||
formDialogRef.value.openDialog();
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新字典
|
||||
* @param dictType
|
||||
*/
|
||||
const handleDictRefresh = async (dictType: string) => {
|
||||
await getDictList();
|
||||
selectRow.value.fieldDict = dictType;
|
||||
};
|
||||
|
||||
const openDialog = (dName: string, tName: string) => {
|
||||
visible.value = true;
|
||||
tableName.value = tName;
|
||||
dsName.value = dName;
|
||||
|
||||
activeName.value = 'field';
|
||||
|
||||
rowDrop();
|
||||
getTable(dName, tName);
|
||||
getFieldTypeList();
|
||||
getDictList();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
tableName.value = String(props.tableName);
|
||||
dsName.value = String(props.dsName);
|
||||
activeName.value = 'field';
|
||||
rowDrop();
|
||||
getTable(dsName.value, tableName.value);
|
||||
getFieldTypeList();
|
||||
getDictList();
|
||||
});
|
||||
|
||||
const rowDrop = () => {
|
||||
nextTick(() => {
|
||||
const el: any = window.document.querySelector('#pane-field');
|
||||
sortable.value = Sortable.create(el, {
|
||||
handle: '.drag-btn',
|
||||
onEnd: (e: any) => {
|
||||
const { newIndex, oldIndex } = e;
|
||||
const currRow = fieldList.value.splice(oldIndex, 1)[0];
|
||||
fieldList.value.splice(newIndex, 0, currRow);
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
const loading = ref(false);
|
||||
|
||||
const getTable = (dsName: string, tableName: string) => {
|
||||
fieldList.value = []; // 避免第一次数据初始化, 表格显示历史数据
|
||||
loading.value = true;
|
||||
useTableApi(dsName, tableName)
|
||||
.then((res) => {
|
||||
tableId.value = res.data.id;
|
||||
fieldList.value = res.data.fieldList.map((item) => {
|
||||
item.queryFormType ? item.queryFormType : propToType[item.fieldType];
|
||||
item.formType ? item.formType : propToType[item.fieldType];
|
||||
return item;
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const getFieldTypeList = async () => {
|
||||
typeList.value = [];
|
||||
// 获取数据
|
||||
const { data } = await list();
|
||||
// 设置属性类型值
|
||||
const typeMap = new Map();
|
||||
data.forEach((item: any) => {
|
||||
const { attrType, columnType } = item;
|
||||
if (!typeMap.has(attrType)) {
|
||||
typeMap.set(attrType, columnType);
|
||||
typeList.value.push({ label: attrType, value: attrType });
|
||||
}
|
||||
});
|
||||
// 增加Object类型
|
||||
typeList.value.push({ label: 'Object', value: 'Object' });
|
||||
};
|
||||
|
||||
const getDictList = () => {
|
||||
fetchDictList().then((res) => {
|
||||
for (const item of res.data) {
|
||||
fieldDictList.value.push({ label: item.description, value: item.dictType });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 表单提交
|
||||
const submitHandle = () => {
|
||||
return new Promise((resolve) => {
|
||||
useTableFieldSubmitApi(dsName.value, tableName.value, fieldList.value).then(() => {
|
||||
resolve(tableId.value);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
submitHandle,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sortable-row-gen .drag-btn {
|
||||
cursor: move;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.sortable-row-gen .vxe-body--row.sortable-ghost,
|
||||
.sortable-row-gen .vxe-body--row.sortable-chosen {
|
||||
background-color: #dfecfb;
|
||||
}
|
||||
|
||||
.vxe-select–panel {
|
||||
z-index: 9997 !important;
|
||||
}
|
||||
</style>
|
||||
412
src/views/gen/table/generator.vue
Normal file
412
src/views/gen/table/generator.vue
Normal file
@@ -0,0 +1,412 @@
|
||||
<template>
|
||||
<el-form :model="dataForm" :rules="dataRules" label-width="120px" ref="dataFormRef" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="表名" prop="tableName">
|
||||
<div style="display: flex; width: 100%">
|
||||
<el-input disabled placeholder="表名" :value="tableNameStr" style="flex-grow: 1; margin-right: 10px"></el-input>
|
||||
<el-button plain icon="Search" @click="childTableRef.openDialog(dataForm)"> 子表</el-button>
|
||||
<!-- 配置子表 -->
|
||||
<child-table-config v-model="childForm" ref="childTableRef" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="注释" prop="tableComment">
|
||||
<el-input placeholder="说明" v-model="dataForm.tableComment"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="类名" prop="className">
|
||||
<el-input placeholder="类名" v-model="dataForm.className"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="作者" prop="author">
|
||||
<el-input placeholder="默认作者" v-model="dataForm.author"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="项目包名" prop="packageName">
|
||||
<el-input placeholder="项目包名" v-model="dataForm.packageName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item prop="moduleName">
|
||||
<template #label>
|
||||
<span>模块名</span>
|
||||
<tip content="所属微服务模块名称,对应微服务路由前缀 (单体固定 admin)" />
|
||||
</template>
|
||||
<el-input placeholder="模块名" v-model="dataForm.moduleName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item prop="functionName">
|
||||
<template #label>
|
||||
<span>功能名</span>
|
||||
<tip content="对应生成的Controller @RequestMapping 请求路径" />
|
||||
</template>
|
||||
<el-input placeholder="功能名" v-model="dataForm.functionName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="代码风格" prop="style">
|
||||
<el-select v-model="dataForm.style">
|
||||
<el-option :key="index" :label="item.groupName" :value="item.id" v-for="(item, index) in groupDataList"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item prop="syncMenuId">
|
||||
<template #label>
|
||||
所属菜单
|
||||
<tip :content="`生成的 【${dataForm.tableComment}管理】菜单挂载在哪个目录下 `" />
|
||||
</template>
|
||||
<el-tree-select
|
||||
filterable
|
||||
v-model="dataForm.syncMenuId"
|
||||
:data="menuData"
|
||||
:render-after-expand="false"
|
||||
:props="{ value: 'id', label: 'name', children: 'children' }"
|
||||
class="w100"
|
||||
clearable
|
||||
check-strictly
|
||||
:placeholder="$t('sysmenu.inputParentIdTip')"
|
||||
>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item prop="syncRoute">
|
||||
<template #label>
|
||||
同步路由
|
||||
<tip :content="`微服务架构下会自动创建一条【/${dataForm.moduleName}】的网关路由,存在则跳过`" />
|
||||
</template>
|
||||
<el-radio-group v-model="dataForm.syncRoute">
|
||||
<el-radio border label="0">手动添加</el-radio>
|
||||
<el-radio border label="1">自动创建</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="表单布局" prop="formLayout">
|
||||
<el-radio-group v-model="dataForm.formLayout">
|
||||
<el-radio border :label="1">一列</el-radio>
|
||||
<el-radio border :label="2">两列</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" class="mb20">
|
||||
<el-form-item label="生成方式" prop="generatorType">
|
||||
<el-radio-group v-model="dataForm.generatorType">
|
||||
<el-radio border label="1">自定义路径</el-radio>
|
||||
<el-radio border label="0">ZIP 压缩包</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item prop="backendPath" v-if="dataForm.generatorType === '1'">
|
||||
<template #label>
|
||||
<span>后端生成路径</span>
|
||||
<tip content="后端模块biz所在文件全路径比如:D:\data\cloud\cloud-upms\cloud-upms-biz" />
|
||||
</template>
|
||||
<el-input placeholder="后端生成路径" v-model="dataForm.backendPath"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="frontendPath" v-if="dataForm.generatorType === '1'">
|
||||
<template #label>
|
||||
<span>前端生成路径</span>
|
||||
<tip content="前端所在文件全路径比如:D:\data\cloud-ui" />
|
||||
</template>
|
||||
<el-input placeholder="前端生成路径" v-model="dataForm.frontendPath"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { putObj, useTableApi } from '/@/api/gen/table';
|
||||
import { list as groupList } from '/@/api/gen/group';
|
||||
import { Local } from '/@/utils/storage';
|
||||
import { rule } from '/@/utils/validate';
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||||
import { checkVersion, online } from '/@/api/gen/template';
|
||||
import mittBus from '/@/utils/mitt';
|
||||
import { pageList } from '/@/api/admin/menu';
|
||||
import Tip from '/@/components/Tip/index.vue';
|
||||
|
||||
const ChildTableConfig = defineAsyncComponent(() => import('./child.vue'));
|
||||
|
||||
const props = defineProps({
|
||||
tableName: {
|
||||
type: String,
|
||||
},
|
||||
dsName: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
const isMicro = import.meta.env.VITE_IS_MICRO;
|
||||
const emit = defineEmits(['refreshDataList']);
|
||||
const route = useRoute();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
const dataFormRef = ref();
|
||||
const childTableRef = ref();
|
||||
const childForm = ref();
|
||||
const tableNameStr = ref('');
|
||||
const dataForm = reactive({
|
||||
id: '',
|
||||
generatorType: '0',
|
||||
formLayout: 1,
|
||||
backendPath: '',
|
||||
frontendPath: '',
|
||||
packageName: '',
|
||||
email: '',
|
||||
author: '',
|
||||
version: '',
|
||||
moduleName: '',
|
||||
functionName: '',
|
||||
className: '',
|
||||
tableComment: '',
|
||||
tableName: '' as string,
|
||||
dsName: '' as string,
|
||||
style: '', // 默认风格 element-plus
|
||||
childTableName: '',
|
||||
syncRoute: '0',
|
||||
syncMenuId: '',
|
||||
});
|
||||
|
||||
const groupDataList = ref([]);
|
||||
const getTable = (dsName: string, tableName: string) => {
|
||||
loading.value = true;
|
||||
useTableApi(dsName, tableName)
|
||||
.then((res) => {
|
||||
Object.assign(dataForm, res.data);
|
||||
let list = res.data.groupList;
|
||||
dataForm.style = list[0]?.id;
|
||||
|
||||
// 如果是保存路径的形式,有限使用本地配置项
|
||||
const frontendPath = Local.get('frontendPath');
|
||||
const backendPath = Local.get('backendPath');
|
||||
|
||||
if (frontendPath && backendPath) {
|
||||
dataForm.frontendPath = frontendPath;
|
||||
dataForm.backendPath = backendPath;
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
if (isMicro === 'false') {
|
||||
dataForm.syncRoute = '0';
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const dataRules = ref({
|
||||
tableName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
tableComment: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
className: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
packageName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
author: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ required: true, message: '必填项不能为空', trigger: 'blur' },
|
||||
],
|
||||
moduleName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{ validator: rule.letter, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
functionName: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
generatorType: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
formLayout: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
backendPath: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
frontendPath: [
|
||||
{ validator: rule.overLength, trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
style: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 保存
|
||||
const submitHandle = async () => {
|
||||
try {
|
||||
const valid = await dataFormRef.value.validate(); // 表单校验
|
||||
if (!valid) return false;
|
||||
|
||||
loading.value = true;
|
||||
await putObj(Object.assign(dataForm, childForm.value));
|
||||
visible.value = false;
|
||||
emit('refreshDataList');
|
||||
return dataForm;
|
||||
} catch {
|
||||
return Promise.reject();
|
||||
} finally {
|
||||
//保存路径至Local 中方便下次使用
|
||||
if (dataForm.generatorType === '1') {
|
||||
Local.set('frontendPath', dataForm.frontendPath);
|
||||
Local.set('backendPath', dataForm.backendPath);
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取风格列表
|
||||
*/
|
||||
const genGroupList = () => {
|
||||
groupList().then(({ data }) => {
|
||||
if (data && data.length > 0) {
|
||||
groupDataList.value = data.filter((group: { groupName: String }) => !group.groupName.includes('vform'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查模板版本
|
||||
*/
|
||||
const checkTemplateVersion = async () => {
|
||||
try {
|
||||
const { data } = await checkVersion();
|
||||
if (!data) {
|
||||
const shouldUpdate = await useMessageBox()
|
||||
.confirm('模板发现新版本,是否更新?')
|
||||
.catch(() => false);
|
||||
if (shouldUpdate) {
|
||||
await online();
|
||||
useMessage().success('更新成功');
|
||||
genGroupList();
|
||||
} else {
|
||||
mittBus.emit('onCurrentContextmenuClick', { contextMenuClickId: 1, ...route });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查版本失败', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 从后端获取菜单信息(含层级)
|
||||
const menuData = reactive([] as any[]);
|
||||
const getAllMenuData = () => {
|
||||
pageList({
|
||||
type: '0',
|
||||
}).then((res) => {
|
||||
let menu = {
|
||||
id: '-1',
|
||||
name: '根菜单',
|
||||
children: [],
|
||||
};
|
||||
menu.children = res.data;
|
||||
menuData.push(menu);
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => childForm,
|
||||
() => {
|
||||
const { childTableName } = childForm.value || {};
|
||||
tableNameStr.value = childTableName ? `${props.tableName} + ${childTableName}` : props.tableName;
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
// 重置表单数据
|
||||
if (dataFormRef.value) {
|
||||
dataFormRef.value.resetFields();
|
||||
}
|
||||
dataForm.id = '';
|
||||
dataForm.tableName = String(props.tableName);
|
||||
dataForm.dsName = String(props.dsName);
|
||||
|
||||
getTable(dataForm.dsName, dataForm.tableName);
|
||||
genGroupList();
|
||||
checkTemplateVersion();
|
||||
getAllMenuData();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
submitHandle,
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.generator-code .el-dialog__body {
|
||||
padding: 15px 30px 0 20px;
|
||||
}
|
||||
</style>
|
||||
107
src/views/gen/table/i18n/en.ts
Normal file
107
src/views/gen/table/i18n/en.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
export default {
|
||||
gen: {
|
||||
syncBtn: 'Sync',
|
||||
designBtn: 'design',
|
||||
genBtn: 'Generate',
|
||||
prewBtn: 'preview',
|
||||
batchGenBtn: 'Batch Generate',
|
||||
author: 'Author',
|
||||
email: 'email',
|
||||
packageName: 'Package Name',
|
||||
version: 'version',
|
||||
generatorType: 'generatorType',
|
||||
moduleName: 'Module Name',
|
||||
functionName: 'functionName',
|
||||
formLayout: 'Form Layout',
|
||||
datasourceId: 'datasourceId',
|
||||
baseclassId: 'baseclassId',
|
||||
createTime: 'Creation Time',
|
||||
inputidTip: 'input id',
|
||||
inputtableNameTip: 'input tableName',
|
||||
inputclassNameTip: 'input className',
|
||||
inputtableCommentTip: 'input tableComment',
|
||||
inputauthorTip: 'input author',
|
||||
inputemailTip: 'input email',
|
||||
inputpackageNameTip: 'Enter package name',
|
||||
inputversionTip: 'input version',
|
||||
inputgeneratorTypeTip: 'input generatorType',
|
||||
inputmoduleNameTip: 'Enter module name',
|
||||
inputfunctionNameTip: 'input functionName',
|
||||
inputformLayoutTip: 'input formLayout',
|
||||
inputdatasourceIdTip: 'input datasourceId',
|
||||
inputbaseclassIdTip: 'input baseclassId',
|
||||
inputcreateTimeTip: 'input createTime',
|
||||
inputAuthorTip: 'Enter author name',
|
||||
inputStyleTip: 'Select code style',
|
||||
parentMenu: 'Parent Menu',
|
||||
syncRoute: 'Sync Route',
|
||||
syncRouteManual: 'Manual Add',
|
||||
syncRouteAuto: 'Auto Create',
|
||||
formLayoutOne: 'One Column',
|
||||
formLayoutTwo: 'Two Columns',
|
||||
genType: 'Generation Method',
|
||||
genTypeZip: 'Download Zip',
|
||||
genTypeCustom: 'Custom Path',
|
||||
style: 'Code Style',
|
||||
backendPath: 'Backend Path',
|
||||
backendPathTip: 'Full path to the backend module biz directory, e.g., D:\\data\\cloud\\cloud-upms\\cloud-upms-biz',
|
||||
inputBackendPathTip: 'Enter backend path',
|
||||
frontendPath: 'Frontend Path',
|
||||
frontendPathTip: 'Full path to the frontend directory, e.g., D:\\data\\cloud-ui',
|
||||
inputFrontendPathTip: 'Enter frontend path',
|
||||
selectionLimitFive: 'You can select a maximum of 5 tables.',
|
||||
selectAtLeastOneTable: 'Please select at least one table to generate.',
|
||||
syncingTables: 'Syncing selected tables...',
|
||||
syncFailedForTables: 'Sync failed for tables',
|
||||
allTablesSyncedSuccessfully: 'All selected tables synced successfully.',
|
||||
syncProcessFailed: 'Table synchronization process failed.',
|
||||
someTablesSyncedSuccessfully: 'Some tables synced successfully, some failed. Check details.',
|
||||
selectAtLeastOneTableAfterSync: 'Please select at least one table (after successful sync and update) to generate.',
|
||||
noTablesSyncedSuccessfully: 'No tables were synced successfully. Cannot proceed with metadata update or generation.',
|
||||
noSyncedTablesToProcess: 'No synced table metadata available to process for update or generation.',
|
||||
updatingTableMetadata: 'Updating metadata for synced tables...',
|
||||
metaUpdateFailedForTables: 'Metadata update failed for tables',
|
||||
proceedingWithSuccessfullyUpdatedTables: 'Proceeding with code generation for tables with successfully updated metadata.',
|
||||
noTablesForGenerationAfterMetaUpdate: 'No tables available for code generation after metadata update step.',
|
||||
generationFailed: 'Generation Failed',
|
||||
},
|
||||
table: {
|
||||
index: '#',
|
||||
importTableTip: ' import Table',
|
||||
id: 'id',
|
||||
tableName: 'Table Name',
|
||||
className: 'className',
|
||||
tableComment: 'tableComment',
|
||||
tableDesc: 'Description',
|
||||
author: 'author',
|
||||
email: 'email',
|
||||
packageName: 'Package Name',
|
||||
version: 'version',
|
||||
generatorType: 'generatorType',
|
||||
backendPath: 'backendPath',
|
||||
frontendPath: 'frontendPath',
|
||||
moduleName: 'moduleName',
|
||||
functionName: 'functionName',
|
||||
formLayout: 'formLayout',
|
||||
datasourceId: 'datasourceId',
|
||||
baseclassId: 'baseclassId',
|
||||
createTime: 'Creation Time',
|
||||
inputidTip: 'input id',
|
||||
inputtableNameTip: 'input tableName',
|
||||
inputclassNameTip: 'input className',
|
||||
inputtableCommentTip: 'input tableComment',
|
||||
inputauthorTip: 'input author',
|
||||
inputemailTip: 'input email',
|
||||
inputpackageNameTip: 'input packageName',
|
||||
inputversionTip: 'input version',
|
||||
inputgeneratorTypeTip: 'input generatorType',
|
||||
inputbackendPathTip: 'input backendPath',
|
||||
inputfrontendPathTip: 'input frontendPath',
|
||||
inputmoduleNameTip: 'input moduleName',
|
||||
inputfunctionNameTip: 'input functionName',
|
||||
inputformLayoutTip: 'input formLayout',
|
||||
inputdatasourceIdTip: 'input datasourceId',
|
||||
inputbaseclassIdTip: 'input baseclassId',
|
||||
inputcreateTimeTip: 'input createTime',
|
||||
},
|
||||
};
|
||||
70
src/views/gen/table/i18n/zh-cn.ts
Normal file
70
src/views/gen/table/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
export default {
|
||||
gen: {
|
||||
syncBtn: '同步',
|
||||
designBtn: '设计',
|
||||
genBtn: '生成',
|
||||
prewBtn: '预览',
|
||||
batchGenBtn: '批量生成',
|
||||
author: '作者',
|
||||
inputAuthorTip: '请输入作者',
|
||||
packageName: '包名',
|
||||
inputPackageNameTip: '请输入包名',
|
||||
moduleName: '模块名',
|
||||
inputModuleNameTip: '请输入模块名',
|
||||
style: '风格',
|
||||
inputStyleTip: '请选择风格',
|
||||
parentMenu: '所属菜单',
|
||||
syncRoute: '同步路由',
|
||||
syncRouteManual: '手动添加',
|
||||
syncRouteAuto: '自动创建',
|
||||
formLayout: '表单布局',
|
||||
formLayoutOne: '单列',
|
||||
formLayoutTwo: '双列',
|
||||
genType: '生成方式',
|
||||
genTypeZip: '生成压缩包',
|
||||
genTypeCustom: '自定义路径',
|
||||
backendPath: '后端生成路径',
|
||||
backendPathTip: '后端模块biz所在文件全路径比如:D:datacloudcloud-upmscloud-upms-biz',
|
||||
inputBackendPathTip: '请输入后端生成路径',
|
||||
frontendPath: '前端生成路径',
|
||||
frontendPathTip: '前端所在文件全路径比如:D:datacloud-ui',
|
||||
inputFrontendPathTip: '请输入前端生成路径',
|
||||
selectionLimitFive: '最多只能选择5张表。',
|
||||
selectAtLeastOneTable: '请至少选择一张表进行生成。',
|
||||
syncingTables: '正在同步选中的表...',
|
||||
syncFailedForTables: '表同步失败',
|
||||
allTablesSyncedSuccessfully: '所有选中的表同步成功。',
|
||||
syncProcessFailed: '表同步过程失败。',
|
||||
someTablesSyncedSuccessfully: '部分表同步成功,部分失败。请检查详情。',
|
||||
selectAtLeastOneTableAfterSync: '请至少选择一个(在成功同步和更新后)表进行生成。',
|
||||
noTablesSyncedSuccessfully: '没有表成功同步。无法继续元数据更新或生成。',
|
||||
noSyncedTablesToProcess: '没有已同步的表元数据可供处理以进行更新或生成。',
|
||||
updatingTableMetadata: '正在更新已同步表的元数据...',
|
||||
metaUpdateFailedForTables: '表元数据更新失败',
|
||||
proceedingWithSuccessfullyUpdatedTables: '正在为元数据更新成功的表继续生成代码。',
|
||||
noTablesForGenerationAfterMetaUpdate: '元数据更新步骤后没有可用于代码生成的表。',
|
||||
generationFailed: '生成失败',
|
||||
},
|
||||
table: {
|
||||
index: '#',
|
||||
importTableTip: '导入列属性',
|
||||
id: 'id',
|
||||
tableName: '表名',
|
||||
className: '类名',
|
||||
tableComment: '说明',
|
||||
tableDesc: '注释',
|
||||
email: '邮箱',
|
||||
inputemailTip: '请输入邮箱',
|
||||
inputtableNameTip: '请输入表名',
|
||||
inputclassNameTip: '请输入类名',
|
||||
inputtableCommentTip: '请输入说明',
|
||||
inputauthorTip: '请输入作者',
|
||||
inputpackageNameTip: '请输入项目包名',
|
||||
inputversionTip: '请输入项目版本号',
|
||||
inputgeneratorTypeTip: '请输入生成方式 0:zip压缩包 1:自定义目录',
|
||||
inputdatasourceIdTip: '请输入数据源ID',
|
||||
inputbaseclassIdTip: '请输入基类ID',
|
||||
inputcreateTimeTip: '请输入创建时间',
|
||||
inputDsNameTip: '请输入数据源名称',
|
||||
},
|
||||
};
|
||||
178
src/views/gen/table/index.vue
Normal file
178
src/views/gen/table/index.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row class="ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item label="数据源" prop="name">
|
||||
<el-select @change="getDataList" placeholder="请选择数据源" v-model="state.queryForm.dsName">
|
||||
<el-option label="默认数据源" value="master"></el-option>
|
||||
<el-option :key="ds.id" :label="ds.name" :value="ds.name" v-for="ds in datasourceList"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('table.tableName')" prop="tableName">
|
||||
<el-input :placeholder="$t('table.inputtableNameTip')" v-model="state.queryForm.tableName" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" icon="search" type="primary">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button
|
||||
icon="Plus"
|
||||
type="primary"
|
||||
class="ml10"
|
||||
@click="openBatchGenDialog"
|
||||
:disabled="(state.selectObjs || []).length === 0 || (state.selectObjs || []).length > 5"
|
||||
>
|
||||
{{ $t('gen.batchGenBtn') }}
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="true"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="state.dataList"
|
||||
row-key="id"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column :label="t('table.index')" type="index" width="60" />
|
||||
<el-table-column :label="t('table.tableName')" prop="name" show-overflow-tooltip />
|
||||
<el-table-column :label="t('table.tableDesc')" prop="comment" show-overflow-tooltip />
|
||||
<el-table-column :label="t('table.createTime')" prop="createTime" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('common.action')" width="250">
|
||||
<template #default="scope">
|
||||
<el-button icon="Refresh" @click="syncTable(scope.row)" text type="primary">
|
||||
{{ $t('gen.syncBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="FolderOpened" @click="openGen(scope.row)" text type="primary">{{ $t('gen.genBtn') }} </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
|
||||
</div>
|
||||
<BatchGenDialog ref="batchGenDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemTable" setup>
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||||
import { fetchList, useSyncTableApi, useTableApi } from '/@/api/gen/table';
|
||||
import { list } from '/@/api/gen/datasource';
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { validateNull } from '/@/utils/validate';
|
||||
import BatchGenDialog from './BatchGenDialog.vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
// 定义变量内容
|
||||
const router = useRouter();
|
||||
// 引入组件
|
||||
const { t } = useI18n();
|
||||
// const { currentRoute } = useRoute();
|
||||
|
||||
// 搜索变量
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const tableRef = ref();
|
||||
// 多选变量
|
||||
const datasourceList = ref();
|
||||
const batchGenDialogRef = ref();
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {
|
||||
dsName: 'master',
|
||||
},
|
||||
pageList: fetchList,
|
||||
createdIsNeed: false,
|
||||
selectObjs: [],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
|
||||
|
||||
// 初始化数据
|
||||
onMounted(() => {
|
||||
list().then((res) => {
|
||||
datasourceList.value = res.data;
|
||||
// 默认去第一个数据源
|
||||
if (datasourceList.value.length > 0) {
|
||||
state.queryForm.dsName = datasourceList.value[0].name;
|
||||
}
|
||||
getDataList();
|
||||
});
|
||||
});
|
||||
|
||||
const openGen = (row: any) => {
|
||||
useTableApi(state.queryForm.dsName, row.name)
|
||||
.then((res) => {
|
||||
if (validateNull(res.data.fieldList)) {
|
||||
syncTable(row);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
router.push({
|
||||
path: '/gen/gener/index',
|
||||
query: {
|
||||
tableName: row.name,
|
||||
dsName: state.queryForm.dsName,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 同步表数据
|
||||
const syncTable = (row: any) => {
|
||||
useSyncTableApi(state.queryForm.dsName, row.name).then(() => {
|
||||
useMessage().success(t('common.optSuccessText'));
|
||||
});
|
||||
};
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
queryRef.value.resetFields();
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/gen/table/export', state.queryForm, 'table.xlsx');
|
||||
};
|
||||
|
||||
const handleRowClick = (row: any) => {
|
||||
tableRef.value.toggleRowSelection(row);
|
||||
};
|
||||
|
||||
// 处理表格选中
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
state.selectObjs = selection;
|
||||
if (selection.length > 5) {
|
||||
ElMessage.warning(t('gen.selectionLimitFive'));
|
||||
}
|
||||
};
|
||||
|
||||
// 打开批量生成弹窗
|
||||
const openBatchGenDialog = () => {
|
||||
batchGenDialogRef.value.openDialog(state.selectObjs, state.queryForm.dsName);
|
||||
};
|
||||
</script>
|
||||
158
src/views/gen/table/preview.vue
Normal file
158
src/views/gen/table/preview.vue
Normal file
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<el-dialog fullscreen title="代码预览" v-model="visible" width="90%" top="3vh" append-to-body :close-on-click-modal="false">
|
||||
<splitpanes>
|
||||
<pane size="25">
|
||||
<el-scrollbar height="calc(100vh - 100px)" class="mt20">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
node-key="id"
|
||||
:data="preview.fileTree"
|
||||
:expand-on-click-node="false"
|
||||
highlight-current
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
</el-scrollbar>
|
||||
</pane>
|
||||
<pane>
|
||||
<el-tabs v-model="preview.activeName" @tab-click="handleTabClick">
|
||||
<el-tab-pane
|
||||
v-for="item in previewCodegen"
|
||||
:label="item.codePath.substring(item.codePath.lastIndexOf('/') + 1)"
|
||||
:name="item.codePath"
|
||||
:key="item.codePath"
|
||||
>
|
||||
<SvgIcon name="ele-CopyDocument" :size="25" class="copy_btn" @click="copyText(item.code)" />
|
||||
</el-tab-pane>
|
||||
<code-editor ref="codeEditorRef" theme="darcula" v-model="previewCodeStr" mode="go" readOnly height="calc(100vh - 100px)"></code-editor>
|
||||
</el-tabs>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts" name="preview">
|
||||
import { useGeneratorPreviewApi } from '/@/api/gen/table';
|
||||
import { handleTree } from '/@/utils/other';
|
||||
import commonFunction from '/@/utils/commonFunction';
|
||||
const CodeEditor = defineAsyncComponent(() => import('/@/components/CodeEditor/index.vue'));
|
||||
|
||||
const { copyText } = commonFunction();
|
||||
|
||||
const visible = ref(false);
|
||||
// ======== 显示页面 ========
|
||||
const preview = reactive({
|
||||
open: false,
|
||||
titel: '代码预览',
|
||||
fileTree: [],
|
||||
activeName: '',
|
||||
});
|
||||
|
||||
const previewCodegen = ref([]);
|
||||
const previewCodeStr = ref('');
|
||||
const fileTreeOriginal = ref([] as any[]);
|
||||
|
||||
const openDialog = async (id: string) => {
|
||||
await getGenCodeFile(id);
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
const codeEditorRef = ref();
|
||||
|
||||
/**
|
||||
* 获取特定资源的代码生成文件,显示在页面上。
|
||||
* @param id 需要渲染的资源 ID。
|
||||
*/
|
||||
const getGenCodeFile = (id: string) => {
|
||||
loading.value = true;
|
||||
fileTreeOriginal.value = [];
|
||||
useGeneratorPreviewApi(id)
|
||||
.then((res: any) => {
|
||||
previewCodegen.value = res;
|
||||
for (let index in res) {
|
||||
fileTreeOriginal.value.push(res[index].codePath);
|
||||
}
|
||||
// 默认选中第一个 选项卡
|
||||
previewCodeStr.value = res[0].code;
|
||||
preview.activeName = res[0].codePath;
|
||||
const files = handleFiles(fileTreeOriginal);
|
||||
preview.fileTree = handleTree(files, 'id', 'parentId', 'children', '/');
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleNodeClick = async (data: any, node: any) => {
|
||||
if (node && !node.isLeaf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
preview.activeName = data.id;
|
||||
|
||||
const filteredCode = previewCodegen.value.filter((code: any) => code.codePath === data.id);
|
||||
if (filteredCode.length > 0) {
|
||||
previewCodeStr.value = filteredCode[0].code;
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabClick = (item: any) => {
|
||||
const filteredCode = previewCodegen.value.filter((code: any) => code.codePath === item.paneName);
|
||||
if (filteredCode.length > 0) {
|
||||
previewCodeStr.value = filteredCode[0].code;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成 files 目录
|
||||
* @param fileTreeOriginal
|
||||
* @returns {*[]}
|
||||
*/
|
||||
const handleFiles = (fileTreeOriginal: any) => {
|
||||
const exists = {};
|
||||
const files = [] as any[];
|
||||
|
||||
// 遍历每个元素
|
||||
for (const data of fileTreeOriginal.value) {
|
||||
let paths = [];
|
||||
if (data.includes('\\')) {
|
||||
paths = data.split('\\');
|
||||
} else {
|
||||
paths = data.split('/');
|
||||
}
|
||||
let fullPath = ''; // 从头开始的路径,用于生成 id
|
||||
// 遍历每个 path, 拼接成树
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
// 已经添加到 files 中,则跳过
|
||||
const oldFullPath = fullPath;
|
||||
// 下面的 replaceAll 的原因,是因为上面包处理了,导致和 tabs 不匹配,所以 replaceAll 下
|
||||
fullPath = fullPath.length === 0 ? paths[i] : fullPath.replaceAll('.', '/') + '/' + paths[i];
|
||||
if (exists[fullPath]) {
|
||||
continue;
|
||||
}
|
||||
// 添加到 files 中
|
||||
exists[fullPath] = true;
|
||||
files.push({
|
||||
id: fullPath,
|
||||
label: paths[i],
|
||||
parentId: oldFullPath || '/',
|
||||
templateName: data.k,
|
||||
});
|
||||
}
|
||||
}
|
||||
return files;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.copy_btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
z-index: 9;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
126
src/views/gen/template/form.vue
Normal file
126
src/views/gen/template/form.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<el-dialog fullscreen :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible">
|
||||
<el-form :model="form" :rules="dataRules" formDialogRef ref="dataFormRef" v-loading="loading">
|
||||
<el-container>
|
||||
<el-aside width="80%">
|
||||
<code-editor v-model="form.templateCode" theme="darcula" mode="velocity" height="700"></code-editor>
|
||||
</el-aside>
|
||||
<el-main>
|
||||
<el-row>
|
||||
<el-form-item :label="t('template.templateName')" prop="templateName">
|
||||
<el-input :placeholder="t('template.inputTemplateNameTip')" v-model="form.templateName" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('template.desc')" prop="templateDesc">
|
||||
<el-input :placeholder="t('template.inputDescTip')" v-model="form.templateDesc" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('template.generatorPath')" prop="generatorPath">
|
||||
<el-input :placeholder="t('template.inputGeneratorPathTip')" v-model="form.generatorPath" />
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
|
||||
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="GenTemplateDialog" setup>
|
||||
// 定义子组件向父组件传值/事件
|
||||
import { useMessage } from '/@/hooks/message';
|
||||
import { addObj, getObj, putObj } from '/@/api/gen/template';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {rule} from "/@/utils/validate";
|
||||
|
||||
const CodeEditor = defineAsyncComponent(() => import('/@/components/CodeEditor/index.vue'));
|
||||
const emit = defineEmits(['refresh']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 定义变量内容
|
||||
const dataFormRef = ref();
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 定义字典
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
id: '',
|
||||
templateName: '',
|
||||
generatorPath: '',
|
||||
templateDesc: '',
|
||||
templateCode: '',
|
||||
});
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
templateName: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板名称不能为空', trigger: 'blur' }],
|
||||
generatorPath: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板路径不能为空', trigger: 'blur' }],
|
||||
templateDesc: [{ validator: rule.overLength, trigger: 'blur' },{ required: true, message: '模板描述不能为空', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = (id: string) => {
|
||||
visible.value = true;
|
||||
form.id = '';
|
||||
|
||||
// 重置表单数据
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields();
|
||||
});
|
||||
// 获取genTemplate信息
|
||||
if (id) {
|
||||
form.id = id;
|
||||
getgenTemplateData(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onSubmit = async () => {
|
||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||
if (!valid) return false;
|
||||
|
||||
// 校验模板是否为空
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
form.id ? await putObj(form) : await addObj(form);
|
||||
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
|
||||
visible.value = false;
|
||||
emit('refresh');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
// 初始化表单数据
|
||||
const getgenTemplateData = (id: string) => {
|
||||
// 获取数据
|
||||
getObj(id).then((res: any) => {
|
||||
Object.assign(form, res.data);
|
||||
});
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.splitpanes__pane {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 5em;
|
||||
}
|
||||
</style>
|
||||
17
src/views/gen/template/i18n/en.ts
Normal file
17
src/views/gen/template/i18n/en.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
template: {
|
||||
index: '#',
|
||||
importgenTemplateTip: 'import GenTemplate',
|
||||
id: 'id',
|
||||
templateName: 'templateName',
|
||||
generatorPath: 'generatorPath',
|
||||
desc: 'templateDesc',
|
||||
createTime: 'createTime',
|
||||
inputIdTip: 'input id',
|
||||
inputTemplateNameTip: 'input templateName',
|
||||
inputGeneratorPathTip: 'input generatorPath',
|
||||
inputDescTip: 'input templateDesc',
|
||||
templateCode: 'template code',
|
||||
inputTemplateCode: 'input template Code',
|
||||
},
|
||||
};
|
||||
17
src/views/gen/template/i18n/zh-cn.ts
Normal file
17
src/views/gen/template/i18n/zh-cn.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
template: {
|
||||
index: '#',
|
||||
importgenTemplateTip: '导入模板',
|
||||
id: '主键',
|
||||
templateName: '模板名称',
|
||||
generatorPath: '模板路径',
|
||||
desc: '模板描述',
|
||||
createTime: '创建时间',
|
||||
inputIdTip: '请输入主键',
|
||||
inputTemplateNameTip: '请输入模板名称',
|
||||
inputGeneratorPathTip: '请输入模板路径',
|
||||
inputDescTip: '请输入模板描述',
|
||||
templateCode: '模板代码',
|
||||
inputTemplateCode: '请输入模板代码',
|
||||
},
|
||||
};
|
||||
164
src/views/gen/template/index.vue
Normal file
164
src/views/gen/template/index.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row class="ml10" v-show="showSearch">
|
||||
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
|
||||
<el-form-item :label="$t('template.templateName')" prop="templateName">
|
||||
<el-input :placeholder="t('template.inputTemplateNameTip')" style="max-width: 180px"
|
||||
v-model="state.queryForm.templateName"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="getDataList" formDialogRef icon="search" type="primary">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" formDialogRef icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary"
|
||||
v-auth="'codegen_template_add'">
|
||||
{{ $t('common.addBtn') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
:disabled="multiple"
|
||||
@click="handleDelete(selectObjs)"
|
||||
class="ml10"
|
||||
icon="Delete"
|
||||
type="primary"
|
||||
v-auth="'codegen_template_del'"
|
||||
>
|
||||
{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
<el-button @click="onlineUpdate" class="ml10" icon="download" plain :disabled="updateDisabled"
|
||||
v-auth="'codegen_template_add'">
|
||||
更新
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
:export="'codegen_template_export'"
|
||||
@exportExcel="exportExcel"
|
||||
@queryTable="getDataList"
|
||||
class="ml10"
|
||||
style="float: right; margin-right: 20px"
|
||||
v-model:showSearch="showSearch"
|
||||
></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table
|
||||
:data="state.dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
v-loading="state.loading"
|
||||
border
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
>
|
||||
<el-table-column align="center" type="selection" width="40"/>
|
||||
<el-table-column :label="t('template.index')" type="index" width="60"/>
|
||||
<el-table-column :label="t('template.templateName')" prop="templateName" show-overflow-tooltip/>
|
||||
<el-table-column :label="t('template.generatorPath')" prop="generatorPath" show-overflow-tooltip/>
|
||||
<el-table-column :label="t('template.desc')" prop="templateDesc" show-overflow-tooltip/>
|
||||
<el-table-column :label="t('template.createTime')" prop="createTime" show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('common.action')" width="150">
|
||||
<template #default="scope">
|
||||
<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.id)" text type="primary"
|
||||
v-auth="'codegen_template_edit'"
|
||||
>{{ $t('common.editBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary"
|
||||
v-auth="'codegen_template_del'"
|
||||
>{{ $t('common.delBtn') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination"/>
|
||||
</div>
|
||||
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog @refresh="getDataList()" ref="formDialogRef"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="systemGenTemplate" setup>
|
||||
import {BasicTableProps, useTable} from '/@/hooks/table';
|
||||
import {delObjs, fetchList, online} from '/@/api/gen/template';
|
||||
import {useMessage, useMessageBox} from '/@/hooks/message';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||
const {t} = useI18n();
|
||||
// 定义查询字典
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref();
|
||||
const updateDisabled = ref(false);
|
||||
// 搜索变量
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any;
|
||||
const multiple = ref(true);
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
queryForm: {},
|
||||
pageList: fetchList,
|
||||
descs: ['create_time'],
|
||||
});
|
||||
|
||||
// table hook
|
||||
const {getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle} = useTable(state);
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value.resetFields();
|
||||
// 清空多选
|
||||
selectObjs.value = [];
|
||||
getDataList();
|
||||
};
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/gen/template/export', state.queryForm, 'template.xlsx');
|
||||
};
|
||||
|
||||
// 多选事件
|
||||
const handleSelectionChange = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({id}) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (ids: string[]) => {
|
||||
try {
|
||||
await useMessageBox().confirm(t('common.delConfirmText'));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await delObjs(ids);
|
||||
getDataList();
|
||||
useMessage().success(t('common.delSuccessText'));
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
const onlineUpdate = async () => {
|
||||
try {
|
||||
updateDisabled.value = true;
|
||||
const {data} = await online();
|
||||
getDataList();
|
||||
useMessage().success(data);
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
updateDisabled.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user