新增后端接口代码生成器【应用开发-接口生成】

master
tanyp 2024-02-02 12:39:13 +08:00
parent aa55770dea
commit 02426cb982
4 changed files with 660 additions and 4 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,84 @@
import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/page',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/delete/' + id,
method: 'delete',
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/save',
method: 'post',
data
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function execute(data:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/execute',
method: 'post',
data
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function tables(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/tables',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function columns(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/generator/columns',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}

View File

@ -4,6 +4,7 @@
const gzh = new URL('../assets/image/gzh.jpg', import.meta.url).href
const state = reactive({
versionList: [
{timestamp:'2024-02-02', icon:'CircleCheckFilled', color:'#409EFF', content: ['新增后端接口代码生成器【应用开发-接口生成】']},
{timestamp:'2024-01-12', icon:'CircleCheckFilled', color:'#409EFF', content: ['解决 amis 城市选择无法使用问题']},
{timestamp:'2024-01-11', icon:'CircleCloseFilled', color:'#F56C6C', content: [
'1、token 过期页面重复提示 “用户凭证已过期,请重新登录!” 问题处理;',

View File

@ -0,0 +1,413 @@
<script setup lang="ts">
import { reactive, onMounted, ref } from "vue"
import {ElMessage, ElMessageBox} from 'element-plus'
import type {FormInstance} from 'element-plus'
import Table from '@/components/Table.vue'
import { page, del, save, execute, tables, columns } from "@/api/lowcode/codeGen"
const searchForm = reactive({
tableName: null
})
const table = reactive({
loading: false,
page: {
current: 1,
size: 10,
total: 1,
},
operation:{
isShow: true,
width: '240'
},
tableTitle: [
{prop:'dataSource',label:'数据源'},
{prop:'tableName',label:'表名'},
{prop:'tableComment',label:'表注释'},
{prop:'subTableName',label:'子表名称'},
{prop:'subTableComment',label:'子表注释'},
{prop:'updateTime',label:'更新时间'},
{prop:'createTime',label:'创建时间'}
],
tableData:[],
})
onMounted(()=>{
onCodeGenPage()
})
function onCodeGenPage(){
table.loading = true;
page(Object.assign(table.page, searchForm)).then((res:any)=>{
if(res){
table.loading = false;
table.tableData = res.result.records;
table.page.current = res.result.current;
table.page.size = res.result.size;
table.page.total = res.result.total;
}
})
}
function onSizeChange(e){
table.page.size = e;
onCodeGenPage();
}
function onCurrentChange(e){
table.page.current = e;
onCodeGenPage();
}
function onRefresh(){
searchForm.tableName = null
onCodeGenPage();
}
function onSearch(){
onCodeGenPage();
}
var validatePath = (rule:any, value:any, callback:any) => {
if(!value.startsWith('/')){
callback(new Error('请以“/”开头'));
}else if(value.endsWith('/')){
callback(new Error('不能以“/”结尾'));
}else{
callback();
}
}
const formRef = ref<FormInstance>()
const form = reactive({
tableList: [],
primary:'',
tabsActive: 'table',
codeVisible: false,
templates: [
{ label: '单表(增删改查)', value: 'single' },
{ label: '树表(增删改查)', value: 'tree' },
{ label: '主子表(增删改查)', value: 'subTable' }
],
codeForm: {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
})
function onTables(){
tables({name: 'tansci_boot'}).then((res:any)=>{
form.tableList = res.result
})
}
function onDelete(val:any){
ElMessageBox.confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
del(val.column.row.id).then(res=>{
if(res){
ElMessage.success('删除成功!');
onCodeGenPage();
}
})
}).catch(e=>{
console.log(e)
})
}
function onAdd(){
onTables()
form.tabsActive = 'table'
form.codeForm = {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
form.codeVisible = true
}
function onTablechange(){
let _table = form.tableList.find(item => form.codeForm.tableName == item.tableName )
form.codeForm.tableComment = _table.tableComment
form.codeForm.dataSource = _table.tableSchema
columns({name: form.codeForm.tableName}).then((res:any)=>{
// form.codeForm.columns = res.result
let _columns = res.result
form.codeForm.columns = []
_columns.forEach((it:any) => {
form.codeForm.columns.push({
columnName: it.columnName.replace(/\_(\w)/g, (all, letter) => letter.toUpperCase()),
columnComment: it.columnComment,
columnType: it.columnType,
component: `component: 'input'`,
where: '=',
save: true,
query: true,
list: true,
required: it.required == 1
})
})
})
}
function onSubTableChange(){
columns({name: form.codeForm.info.subTable}).then((res:any)=>{
// form.codeForm.subColumns = res.result
let _columns = res.result
form.codeForm.subColumns = []
_columns.forEach((it:any) => {
form.codeForm.subColumns.push({
columnName: it.columnName.replace(/\_(\w)/g, (all, letter) => letter.toUpperCase()),
columnComment: it.columnComment,
columnType: it.columnType,
component: `component: 'input'`,
where: '=',
save: true,
query: true,
list: true,
required: it.required == 1
})
})
})
}
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid)=>{
if(valid){
ElMessageBox.confirm('此操作会生成代码并覆盖, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let formData = new FormData()
formData.append("tableName", form.codeForm.tableName)
formData.append("tableComment", form.codeForm.tableComment)
formData.append("dataSource", form.codeForm.dataSource)
formData.append("info", JSON.stringify(form.codeForm.info))
formData.append("columns", JSON.stringify(form.codeForm.columns))
formData.append("subTableName", form.codeForm.info.subTable)
formData.append("subColumns", JSON.stringify(form.codeForm.subColumns))
execute(formData).then((res:any)=>{
formData.append("interfaceId", res.result)
save(formData).then((res:any)=>{
ElMessage.success("添加成功!");
onCodeGenPage()
form.codeVisible = false
})
})
})
}
})
}
</script>
<template>
<div class="codegen-container">
<Table :data="table.tableData" :column="table.tableTitle" :operation="table.operation" :page="table.page" :loading="table.loading"
@onSizeChange="onSizeChange" @onCurrentChange="onCurrentChange">
<template #search>
<div><el-button type="primary" @click="onAdd"></el-button></div>
<div><el-input v-model="searchForm.tableName" placeholder="请输入表名"></el-input></div>
<div><el-button @click="onRefresh" icon="RefreshRight" circle></el-button></div>
<div><el-button @click="onSearch" type="primary" icon="Search">查询</el-button></div>
</template>
<template #column="scope">
<el-button @click="onDelete(scope)" type='primary' link style="color:var(--delete); padding:0;">删除</el-button>
</template>
</Table>
<el-dialog v-model="form.codeVisible" title="接口生成" :show-close="false" width="60%" >
<el-form ref="formRef" :model="form.codeForm" :rules="rules" status-icon label-width="100px">
<div style="padding-bottom: 1rem;">数据源信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="表 名" prop="tableName" :rules="[{ required: true, message: '请选择表', trigger: 'change' }]">
<el-select v-model="form.codeForm.tableName" @change="onTablechange()" placeholder="请选择表" style="width:100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableName" :value="item.tableName">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.tableComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="描 述" prop="tableComment" :rules="[{ required: true, message: '请输入描述', trigger: 'change' }]">
<el-input v-model="form.codeForm.tableComment" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<div style="padding: 1rem ;">生成接口信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="生成模板" prop="info.template" :rules="[{ required: true, message: '请选择模板', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.template" placeholder="请选择模板" style="width:100%">
<el-option v-for="item in form.templates" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模板单表树表主子表增删改查</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.moduleName" label="模块名称" :rules="[{ required: true, message: '请输入模块名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.moduleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块名称第一级分组名称例如系统功能</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.modulePath" label="模块路径" :rules="[{ required: true, message: '请输入模块路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.modulePath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块路径第一级分组的路径例如/system</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessName" label="功能名称" :rules="[{ required: true, message: '请输入功能名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.businessName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能名称第二级分组名称例如菜单管理</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessPath" label="功能路径" :rules="[{ required: true, message: '请输入功能路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.businessPath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能路径第二级分组路径例如/menu</span>
</el-col>
</el-row>
<div v-if="form.codeForm.info.template == 'tree'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treeId" label="树编码" :rules="[{ required: true, message: '请选择树编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treeId" placeholder="请选择树编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树编码树显示的编码字段名称例如id</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treePid" label="父编码" :rules="[{ required: true, message: '请选择树父编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treePid" placeholder="请选择树父编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树父编码树显示的父编码字段名称例如pid</span>
</el-col>
</el-row>
</div>
<div v-if="form.codeForm.info.template == 'subTable'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTable" label="关联子表名" :rules="[{ required: true, message: '请选择关联子表名称', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTable" @change="onSubTableChange()" placeholder="请选择表" style="width:100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableComment" :value="item.tableName">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.tableComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>关联子表名关联字表的名称例如sys_menu_role</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTableKey" label="子表外键名" :rules="[{ required: true, message: '请选择子表关联的外键名', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTableKey" placeholder="请选择子表关联的外键名" style="width:100%">
<el-option v-for="item in form.codeForm.subColumns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>子表关联的外键名子表关联的外键名例如menu_id</span>
</el-col>
</el-row>
</div>
</el-card>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="form.codeVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit(formRef)"></el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<style lang="scss" scoped>
.codegen-container{
}
</style>