【新增】大更新 v2.1 新增代码生成,具体使用看官方文档

pull/54/head v2.1.0-release
小诺 2022-11-03 03:07:44 +08:00 committed by 俞宝山
parent db0fabb069
commit f094c30e46
74 changed files with 5464 additions and 0 deletions

View File

@ -0,0 +1,45 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/gen/basic/${url}`, ...arg)
export default {
// 获取代码生成基础分页
basicPage(data) {
return request('page', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
submitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除代码生成基础
basicDelete(data) {
return request('delete', data)
},
// 获取代码生成基础详情
basicDetail(data) {
return request('detail', data, 'get')
},
// 获取所有表信息
basicTables(data) {
return request('tables', data, 'get')
},
// 获取表内所有字段信息
basicTableColumns(data) {
return request('tableColumns', data, 'get')
},
// 执行代码生成 压缩包
basicExecGenBiz(data) {
const options = {
responseType: 'blob'
}
return request('execGenZip', data, 'get', options)
},
// 执行代码生成 项目内
basicExecGenPro(data) {
return request('execGenPro', data)
},
// 预览代码生成
basicPreviewGen(data) {
return request('previewGen', data, 'get')
}
}

View File

@ -0,0 +1,26 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/gen/config/${url}`, ...arg)
export default {
// 获取代码生成详情配置列表
configList(data) {
return request('list', data, 'get')
},
// 提交表单 edit为true时为编辑默认为新增
submitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除代码生成详情配置
configDelete(data) {
return request('delete', data)
},
// 获取代码生成详情配置详情
configDetail(data) {
return request('detail', data, 'get')
},
// 批量编辑代码生成详细配置
configEditBatch(data) {
return request('editBatch', data)
}
}

View File

@ -108,6 +108,24 @@ tool.dictTypeList = (dictValue) => {
return []
}
// 获取某个code下字典的列表基于dictTypeList 改进,保留老的,逐步替换
tool.dictList = (dictValue) => {
const dictTypeTree = tool.dictDataAll()
if (!dictTypeTree) {
return []
}
const tree = dictTypeTree.find((item) => item.dictValue === dictValue)
if (tree) {
return tree.children.map((item) => {
return {
value: item['dictValue'],
label: item['name']
}
})
}
return []
}
// 生成UUID
tool.snowyUuid = () => {
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {

View File

@ -0,0 +1,378 @@
<template>
<a-card :bordered="false">
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="选择主表:" name="dbTable">
<a-select
v-model:value="formData.dbTable"
:options="tableList"
style="width: 100%"
placeholder="请选择主表"
@select="selectTableColumnsData(formData.dbTable, false)"
>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="选择主键:" name="dbTableKey">
<a-select
v-model:value="formData.dbTableKey"
:options="tableColumns"
style="width: 100%"
placeholder="选择主键"
>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="表前缀移除:" name="tablePrefix">
<a-radio-group v-model:value="formData.tablePrefix" :options="tablePrefixOptions" @change="tablePrefixChange"> </a-radio-group>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="生成方式:" name="generateType">
<a-radio-group v-model:value="formData.generateType" :options="generateTypeOptions"> </a-radio-group>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="所属模块:" name="module">
<a-select
v-model:value="formData.module"
:options="moduleOptions"
style="width: 100%"
placeholder="请选择所属模块"
@change="moduleChange(formData.module, false)"
>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="上级目录:" name="menuPid">
<a-tree-select
v-model:value="formData.menuPid"
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择上级目录"
allow-clear
tree-default-expand-all
:tree-data="menuTreeData"
:field-names="{
children: 'children',
label: 'title',
value: 'id'
}"
selectable="false"
tree-line
></a-tree-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="功能名:" name="functionName">
<a-input v-model:value="formData.functionName" placeholder="请输入功能名" allow-clear />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="业务名:" name="busName">
<a-input v-model:value="formData.busName" placeholder="请输入业务名" allow-clear />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="类名:" name="className">
<a-input v-model:value="formData.className" placeholder="请输入类名" allow-clear />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="表单布局:" name="formLayout">
<a-radio-group v-model:value="formData.formLayout" :options="formLayoutOptions" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="使用栅格:" name="gridWhether">
<a-radio-group v-model:value="formData.gridWhether" :options="gridWhetherOptions" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="排序:" name="sortCode">
<a-slider v-model:value="formData.sortCode" :max="100" style="width: 100%"/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="作者:" name="authorName">
<a-input v-model:value="formData.authorName" placeholder="请输入作者名" allow-clear />
</a-form-item>
</a-col>
<a-col :span="8" v-if="formData.generateType === 'BIZ'">
<a-form-item label="包名:" name="packageName">
<a-input v-model:value="formData.packageName" placeholder="请输入包名" allow-clear />
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
</template>
<script setup name="genBasic">
import { required } from '@/utils/formRules'
import tool from '@/utils/tool'
import genBasicApi from '@/api/gen/genBasicApi'
const formRef = ref()
//
const formData = ref({})
//
const tableList = ref([])
const tableColumns = ref([])
const menuTreeData = ref([])
const submitLoading = ref(false)
const moduleOptions = ref()
const generateTypeOptions = ref([
{
label: '压缩包',
value: 'ZIP'
},
{
label: '项目内',
value: 'PRO'
}
])
const tablePrefixOptions = ref([
{
label: '移除',
value: 'Y'
},
{
label: '不移除',
value: 'N'
}
])
const formLayoutOptions = ref([
{
label: '垂直',
value: 'vertical'
},
{
label: '水平',
value: 'horizontal'
}
])
const gridWhetherOptions = ref([
{
label: '栅格布局',
value: 'Y'
},
{
label: '不使用',
value: 'N'
},
])
//
const onOpen = (record) => {
//
moduleOptions.value = tool.data.get('MENU').map((item) => {
return {
label: item.name,
value: item.id
}
})
//
genBasicApi.basicTables().then((data) => {
tableList.value = data.map((item) => {
return {
value: item['tableName'],
label: `${item['tableRemark']}-${item['tableName']}`,
tableRemark: item['tableRemark'] || item['tableName'],
tableColumns: []
}
})
})
if (record) {
const params = {
id: record.id
}
submitLoading.value = true
genBasicApi.basicDetail(params).then((data) => {
formData.value = data
//
selectTableColumnsData(data.dbTable, true)
//
moduleChange(data.module, true)
}).finally(() => {
submitLoading.value = false
})
} else {
formData.value = {
sortCode: 99,
tablePrefix: 'Y',
generateType: 'ZIP',
packageName: 'vip.xiaonuo',
formLayout: 'vertical',
gridWhether: 'N'
}
}
}
//
const formRules = {
tablePrefix: [required('请选择是否移除表前缀')],
dbTable: [required('请选择主表')],
dbTableKey: [required('请选择主表主键')],
generateType: [required('请选择生成方式')],
module: [required('请选择所属模块')],
menuPid: [required('请选择上级目录')],
functionName: [required('请输入功能名')],
busName: [required('请输入业务名')],
className: [required('请输入类名')],
packageName: [required('请输入包名')],
sortCode: [required('请选择排序')],
formLayout: [required('请选择表单布局')],
gridWhether: [required('请选择是否使用栅格')],
authorName: [required('请输入作者名')]
}
//
const moduleChange = (value, assign) => {
if (!assign) {
//
formData.value.menuPid = undefined
}
//
const menuTree = tool.data.get('MENU').find((item) => {
if (item.id === value) {
return item
}
})
menuTreeData.value = [
{
id: '0',
title: '顶级',
menuType: 'CATALOG',
children: traverseChildren(menuTree.children)
}
]
}
//
const traverseChildren = (data = []) => {
//
const traverse = (array) => {
array.forEach((element) => {
if (element.menuType === 'CATALOG') {
traverse(element.children)
} else {
//
element.disabled = true
element.selectable = false
}
})
}
traverse(data)
return data
}
//
const selectTableColumnsData = (tableName, assign) => {
if (!assign) {
formData.value.dbTableKey = undefined
}
formFieldAssign(tableName)
// tableName
const param = {
tableName: tableName
}
genBasicApi.basicTableColumns(param).then((data) => {
tableColumns.value = data.map((item) => {
return {
value: item['columnName'],
label: item['columnRemark'] || item['columnName']
}
})
})
}
//
const tablePrefixChange = () => {
const tableName = formData.value.dbTable
if (tableName) {
const tableNameHump = getTableNameToHump(tableName)
formData.value.busName = tableNameHump.toLowerCase()
}
}
//
const formFieldAssign = (value) => {
const data = tableList.value.find((item) => item.value === value)
formData.value.functionName = data.tableRemark
const tableNameHump = getTableNameToHump(data.value)
formData.value.busName = tableNameHump.toLowerCase()
formData.value.className = getClassName(data.value)
}
//
const getTableNameToHump = (tableName) => {
if (tableName) {
const arr = tableName.toLowerCase().split('_')
if (formData.value.tablePrefix === 'Y') {
arr.splice(0, 1)
}
for (let i = 0; i < arr.length; i++) {
// charAt()slice()
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1)
}
return arr.join('')
}
return ''
}
//
const getClassName = (tableName) => {
if (tableName) {
const arr = tableName.toLowerCase().split('_')
for (let i = 0; i < arr.length; i++) {
// charAt()slice()
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1)
}
return arr.join('')
}
return ''
}
//
const onSubmit = () => {
return new Promise((resolve,reject) => {
formRef.value
.validate()
.then(() => {
submitLoading.value = true
genBasicApi.submitForm(formData.value, !formData.value.id).then((data) => {
resolve(data)
}).finally(() => {
submitLoading.value = false
})
}).catch((err) => {
reject(err)
})
})
}
//
defineExpose({
onOpen,
onSubmit
})
</script>
<style scoped>
.childAddButton {
margin-bottom: 10px;
}
.form-row {
background-color: var(--item-hover-bg);
margin-left: 0px !important;
}
.form-row-con {
padding-bottom: 5px;
padding-top: 5px;
padding-left: 15px;
}
.form-div {
padding-top: 10px;
}
</style>

View File

@ -0,0 +1,406 @@
<template>
<a-card :bordered="false">
<s-table
ref="table"
:columns="columns"
:data="loadDate"
:expand-row-by-click="true"
:showPagination="false"
bordered
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'fieldRemark'">
<a-input v-model:value="record.fieldRemark" />
</template>
<template v-if="column.dataIndex === 'fieldJavaType'">
<a-select
style="width: 100%"
v-model:value="record.fieldJavaType"
:options="fieldJavaTypeOptions"
placeholder="请选择"
:disabled="toCommonFieldEstimate(record)"
@change="fieldJavaTypeChange(record)"
/>
</template>
<template v-if="column.dataIndex === 'effectType'">
<a-select
style="width: 100%"
v-model:value="record.effectType"
:options="effectTypeOptions"
placeholder="请选择"
:disabled="toCommonFieldEstimate(record) || toFieldSelectEstimate(record)"
/>
</template>
<template v-if="column.dataIndex === 'dictTypeCode'">
<a-select
v-if="
record.effectType === 'radio' ||
record.effectType === 'select' ||
record.effectType === 'checkbox'"
style="width: 100%"
v-model:value="record.dictTypeCode"
:options="dictTypeCodeOptions"
placeholder="请选择字典"
/>
<span v-else></span>
</template>
<template v-if="column.dataIndex === 'whetherTable'">
<a-checkbox v-model:checked="record.whetherTable" />
</template>
<template v-if="column.dataIndex === 'whetherRetract'">
<a-checkbox v-model:checked="record.whetherRetract" :disabled="!record.whetherTable" />
</template>
<template v-if="column.dataIndex === 'whetherAddUpdate'">
<a-checkbox v-model:checked="record.whetherAddUpdate" :disabled="toFieldEstimate(record)" />
</template>
<template v-if="column.dataIndex === 'whetherRequired'">
<a-checkbox v-model:checked="record.whetherRequired" :disabled="toFieldEstimate(record) || !record.whetherAddUpdate" />
</template>
<template v-if="column.dataIndex === 'queryWhether'">
<a-switch v-model:checked="record.queryWhether" :disabled="!record.whetherTable" />
</template>
<template v-if="column.dataIndex === 'queryType'">
<a-select
v-if="record.queryWhether === true && record.effectType !== 'datepicker'"
style="width: 100%"
v-model:value="record.queryType"
:options="queryTypeOptions"
placeholder="请选择"
/>
<span v-else-if="record.effectType === 'datepicker' && record.queryWhether === true">时间段</span>
<span v-else></span>
</template>
</template>
</s-table>
</a-card>
</template>
<script setup name="genConfig">
import tool from '@/utils/tool'
import genConfigApi from "@/api/gen/genConfigApi";
import { cloneDeep } from 'lodash-es'
const table = ref()
const recordData = ref()
const tableData = ref()
const columns = [
{
title: '字段',
align: 'center',
dataIndex: 'fieldName',
ellipsis: true
},
{
title: '注释',
align: 'center',
dataIndex: 'fieldRemark',
ellipsis: true
},
{
title: '类型',
align: 'center',
dataIndex: 'fieldType',
ellipsis: true
},
{
title: '实体类型',
align: 'center',
dataIndex: 'fieldJavaType',
ellipsis: true
},
{
title: '作用类型',
align: 'center',
dataIndex: 'effectType',
ellipsis: true
},
{
title: '字典',
align: 'center',
dataIndex: 'dictTypeCode',
width: 140
},
{
title: '列表显示',
align: 'center',
dataIndex: 'whetherTable',
width: 80
},
{
title: '列省略',
align: 'center',
dataIndex: 'whetherRetract',
width: 80
},
{
title: '增改',
align: 'center',
dataIndex: 'whetherAddUpdate',
width: 80
},
{
title: '必填',
align: 'center',
dataIndex: 'whetherRequired',
width: 80
},
{
title: '查询',
align: 'center',
dataIndex: 'queryWhether',
width: 80
},
{
title: '查询方式',
align: 'center',
dataIndex: 'queryType'
}
]
const onOpen = (record) => {
recordData.value = record
nextTick(() => {
table.value.refresh()
})
}
// Promise
const loadDate = (parameter) => {
if (recordData.value) {
parameter.basicId = recordData.value.id
return genConfigApi.configList(parameter).then((data) => {
tableData.value = JSON.parse(JSON.stringify(data))
let deleteIndex = [];
tableData.value.forEach((item, index) => {
for (const key in item) {
if (item[key] === 'Y') {
item[key] = true
}
if (item[key] === 'N') {
item[key] = false
}
}
//
if (item.isTableKey) {
deleteIndex.push(index)
}
//
if (item.fieldName.toLowerCase().indexOf('delete_flag') > -1) {
deleteIndex.push(index)
}
//
fieldJavaTypeChange(item)
})
if (deleteIndex) {
deleteIndex.forEach((item, index) => {
if (index > 0) {
item = item - 1
}
delete tableData.value.splice(item, 1)
})
}
return tableData.value
})
} else {
return new Promise((resolve, reject) => {
resolve([])
})
}
}
//
const fieldJavaTypeOptions = ref([
{
label: 'Integer',
value: 'Integer'
},
{
label: 'Long',
value: 'Long'
},
{
label: 'String',
value: 'String'
},
{
label: 'Boolean',
value: 'Boolean'
},
{
label: 'Float',
value: 'Float'
},
{
label: 'Double',
value: 'Double'
},
{
label: 'Date',
value: 'Date'
},
{
label: 'BigDecimal',
value: 'BigDecimal'
},
])
//
const effectTypeOptions = ref([
{
label: '输入框',
value: 'input'
},
{
label: '文本框',
value: 'textarea'
},
{
label: '下拉框',
value: 'select'
},
{
label: '单选框',
value: 'radio'
},
{
label: '复选框',
value: 'checkbox'
},
{
label: '日期选择器',
value: 'datepicker'
},
{
label: '时间选择器',
value: 'timepicker'
},
{
label: '数字输入框',
value: 'inputNumber'
},
{
label: '滑动数字条',
value: 'slider'
}
])
//
const dictTypeCodeOptions = tool.dictDataAll().map((item) => {
return {
label: item.name,
value: item.dictValue
}
})
//
const queryTypeOptions = ref([
{
label: '模糊包含',
value: 'like'
},
{
label: '模糊不包含',
value: 'notLike'
},
{
label: '等于',
value: 'eq'
},
{
label: '不等于',
value: 'ne'
},
{
label: '大于',
value: 'gt'
},
{
label: '大于等于',
value: 'ge'
},
{
label: '小于',
value: 'lt'
},
{
label: '小于等于',
value: 'le'
}
])
const emit = defineEmits({ successful: null }, { close: null })
const toFieldEstimate = (data) => {
if (data.fieldName.toLowerCase().indexOf('create_user') > -1 ||
data.fieldName.toLowerCase().indexOf('create_time') > -1 ||
data.fieldName.toLowerCase().indexOf('update_user') > -1 ||
data.fieldName.toLowerCase().indexOf('update_time') > -1 ||
data.fieldName.toLowerCase().indexOf('delete_flag') > -1 ||
data.isTableKey === true) {
return true
}
return false
}
//
const toCommonFieldEstimate = (record) => {
if (record.fieldName.toLowerCase().indexOf('create_user') > -1 ||
record.fieldName.toLowerCase().indexOf('update_user') > -1 ) {
return true
}
return false
}
//
const toFieldSelectEstimate = (record) => {
if ( record.fieldJavaType === 'Date' && record.effectType === 'datepicker' ) {
return true
}
return false
}
//
const fieldJavaTypeChange = (record) => {
if (record.fieldJavaType === 'Date') {
record.effectType = 'datepicker'
}
}
//
const onSubmit = (recordData) => {
let submitParam = cloneDeep(tableData.value)
let errStatus = 100;
submitParam.forEach(item => {
//
for (const key in item) {
if (item[key] === true) {
item[key] = 'Y'
}
if (item[key] === false) {
item[key] = 'N'
}
}
if (item.queryWhether === 'Y' && !item.queryType) {
//
if (item.fieldJavaType !== 'Date' && item.effectType !== 'checkbox') {
errStatus ++
}
}
if ((item.effectType === 'select' ||
item.effectType === 'radio' ||
item.effectType === 'checkbox') && !item.dictTypeCode) {
errStatus ++
}
})
return new Promise((resolve,reject) => {
if (errStatus > 100) {
reject('校验失败,请选择对应的下拉框选项')
return
}
genConfigApi.configEditBatch(submitParam).then((data) => {
resolve(data)
}).catch((err) => {
reject(err)
})
})
}
//
defineExpose({
onOpen,
onSubmit
})
</script>
<style scoped>
.table-wrapper {
margin-top: -16px !important;
}
</style>

View File

@ -0,0 +1,213 @@
<template>
<a-card :bordered="false" v-if="indexShow">
<s-table
ref="table"
:columns="columns"
:data="loadDate"
:expand-row-by-click="true"
:alert="options.alert.show"
bordered
:row-key="(record) => record.id"
:row-selection="options.rowSelection"
:toolConfig="{ refresh: true, height: true, columnSetting: true, striped: false }"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="openConfig()">
新建
</a-button>
<a-button danger @click="deleteBatchCodeGen()"></a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'tablePrefix'">
{{tablePrefixFilter(record.tablePrefix)}}
</template>
<template v-if="column.dataIndex === 'generateType'">
{{generateTypeFilter(record.generateType)}}
</template>
<template v-if="column.dataIndex === 'action'">
<a @click="genPreviewRef.onOpen(record)"></a>
<a-divider type="vertical" />
<a-popconfirm title="确定生成代码?" @confirm="execGen(record)">
<a-button type="link" size="small">生成</a-button>
</a-popconfirm>
<a-divider type="vertical" />
<a @click="openConfig(record)"></a>
<a-divider type="vertical" />
<a-popconfirm title="删除此信息?" @confirm="deleteCodeGen(record)">
<a-button type="link" danger size="small">删除</a-button>
</a-popconfirm>
</template>
</template>
</s-table>
</a-card>
<steps v-else ref="stepsRef" @successful="table.refresh(true)" @closed="closeConfig()"/>
<genPreview ref="genPreviewRef" />
</template>
<script setup name="genIndex">
import { message } from 'ant-design-vue'
import steps from './steps.vue'
import genPreview from './preview.vue'
import genBasicApi from '@/api/gen/genBasicApi'
const table = ref()
const indexShow = ref(true)
const stepsRef = ref()
const genPreviewRef = ref()
const columns = [
{
title: '业务名',
dataIndex: 'busName',
ellipsis: true
},
{
title: '功能名',
dataIndex: 'functionName',
ellipsis: true
},
{
title: '类名',
dataIndex: 'className',
ellipsis: true
},
{
title: '包名',
dataIndex: 'packageName',
ellipsis: true
},
{
title: '作者',
dataIndex: 'authorName',
ellipsis: true
},
{
title: '移除表前缀',
dataIndex: 'tablePrefix',
ellipsis: true
},
{
title: '生成方式',
dataIndex: 'generateType',
ellipsis: true
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
width: '220px'
}
]
// Promise
const loadDate = (parameter) => {
return genBasicApi.basicPage(parameter).then((data) => {
return data
})
}
//
let selectedRowKeys = ref([])
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
const generateTypeFilter = (text) => {
const array = [
{
label: '压缩包',
value: 'ZIP'
},
{
label: '项目内',
value: 'PRO'
}
]
return array.find((f) => f.value === text).label
}
const tablePrefixFilter = (text) => {
const array = [
{
label: '移除',
value: 'Y'
},
{
label: '不移除',
value: 'N'
}
]
return array.find((f) => f.value === text).label
}
//
const execGen = (record) => {
const param = {
id: record.id
}
if (record.generateType === 'PRO') {
genBasicApi.basicExecGenPro(param).then(() => {
message.success('操作成功')
table.value.refresh()
})
} else {
//
genBasicApi.basicExecGenBiz(param).then((res) => {
const blob = new Blob([res.data],{type: 'application/octet-stream;charset=UTF-8'});
const contentDisposition = res.headers['content-disposition']
const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
const $link = document.createElement("a");
$link.href = URL.createObjectURL(blob);
$link.download = patt.exec(contentDisposition)[1]
$link.click();
document.body.appendChild($link);
document.body.removeChild($link); //
window.URL.revokeObjectURL($link.href); // blob
})
}
}
//
const deleteCodeGen = (record) => {
let params = [
{
id: record.id
}
]
genBasicApi.basicDelete(params).then(() => {
table.value.refresh()
})
}
//
const deleteBatchCodeGen = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请选择一条或多条数据')
return false
}
const params = selectedRowKeys.value.map((m) => {
return {
id: m
}
})
genBasicApi.basicDelete(params).then(() => {
table.value.refresh()
})
}
//
const openConfig = (record) => {
indexShow.value = false
nextTick(() => {
stepsRef.value.configSteps(record)
})
}
//
const closeConfig = () => {
indexShow.value = true
}
</script>

View File

@ -0,0 +1,79 @@
<template>
<a-drawer
title="预览"
:width="1200"
:visible="visible"
:destroy-on-close="true"
:body-style="{ 'padding-top': '0px' }"
@close="onClose"
>
<a-spin :spinning="loadingSpinning">
<a-tabs v-model:activeKey="codeTypeActiveKey" @change="codeTypeChange">
<a-tab-pane v-for="codeType in codeTypeArray" :key="codeType.codeTypeKey" :tab="codeType.codeTypeTitle" force-render>
<a-tabs v-model:activeKey="typeListActiveKey" tab-position="left" hide-add type="card">
<a-tab-pane v-for="pan in codeType.codeTypeList" :key="pan.codeFileName" :tab="pan.codeFileName">
<div style="height: calc(100vh - 160px); overflow: auto">
<a-textarea ref="textareaRef" v-model:value="pan.codeFileContent" :autoSize="true" />
</div>
</a-tab-pane>
</a-tabs>
</a-tab-pane>
</a-tabs>
</a-spin>
</a-drawer>
</template>
<script setup name="genPreview">
import { message } from 'ant-design-vue'
import genBasicApi from '@/api/gen/genBasicApi'
//
const visible = ref(false)
const codeTypeActiveKey = ref()
const typeListActiveKey = ref()
const loadingSpinning = ref(true)
const codeTypeArray = ref([])
//
const onOpen = (record) => {
visible.value = true
const param = {
id: record.id
}
genBasicApi.basicPreviewGen(param).then((data) => {
if (data) {
codeTypeArray.value = [
{
codeTypeKey: 'frontend',
codeTypeTitle: '前端代码',
codeTypeList: data.genBasicCodeFrontendResultList
},
{
codeTypeKey: 'backend',
codeTypeTitle: '后端代码',
codeTypeList: data.genBasicCodeBackendResultList
},
{
codeTypeKey: 'sqlend',
codeTypeTitle: 'SQL文件',
codeTypeList: data.genBasicCodeSqlResultList
}
]
} else {
message.warning('预览失败:请检查问题或反馈小诺官方')
}
}).finally(() => {
loadingSpinning.value = false
})
}
//
const onClose = () => {
visible.value = false
}
//
const codeTypeChange = (value) => {
typeListActiveKey.value = codeTypeArray.value.find((f) => f.codeTypeKey === value).codeTypeList[0].codeFileName
}
defineExpose({
onOpen
})
</script>

View File

@ -0,0 +1,164 @@
<template>
<div>
<a-card class="steps-card" :bordered="false">
<a-row class="xn-row">
<a-col :span="6"></a-col>
<a-col :span="12">
<a-steps :current="current">
<a-step v-for="item in steps" :key="item.title" :title="item.title" />
</a-steps>
</a-col>
<a-col :span="6">
<div style="float: right">
<a-button :disabled="current === 0" style="margin-left: 8px" @click="prev"> </a-button>
<a-button :disabled="current === 2" type="primary" style="margin-left: 8px" @click="next"> </a-button>
<a-button type="primary" danger ghost style="margin-left: 8px" @click="emit('closed')">
关闭
</a-button>
</div>
</a-col>
</a-row>
</a-card>
<div v-if="current === 0">
<basic ref="basicRef" />
</div>
<div v-if="current === 1">
<config ref="configRef"/>
</div>
<div v-if="current === 2">
<a-card>
<a-result status="success" title="操作成功" sub-title="">
<template #extra>
<a-space size="middle">
<a-button v-if="current > 0" style="margin-left: 8px" @click="genPreviewRef.onOpen(recordData)"></a-button>
<a-button
v-if="current === steps.length - 1"
type="primary"
:loading="submitLoading"
@click="seveGenerate"
>生成并关闭</a-button
>
</a-space>
</template>
</a-result>
</a-card>
<genPreview ref="genPreviewRef" />
</div>
</div>
</template>
<script setup name="genSteps">
import { message } from 'ant-design-vue'
import basic from './basic.vue'
import config from './config.vue'
import genPreview from './preview.vue'
import genBasicApi from "@/api/gen/genBasicApi";
const emit = defineEmits({ closed: null })
const current = ref(0)
const recordData = ref()
const submitLoading = ref(false)
const basicRef = ref()
const configRef = ref()
const genPreviewRef = ref()
//
const configSteps = (record) => {
basicRef.value.onOpen(record)
}
//
const next = () => {
current.value++
//
if (current.value === 1) {
basicRef.value.onSubmit().then((data) => {
recordData.value = data
current.value++
nextTick(() => {
configRef.value.onOpen(data)
})
})
current.value--
}
if (current.value === 2) {
configRef.value.onSubmit(recordData.value).then((data) => {
current.value++
}).catch((err) => {
message.warning(err)
})
current.value--
}
}
//
const prev = () => {
current.value--
if (current.value === 0) {
nextTick(() => {
basicRef.value.onOpen(recordData.value)
})
}
if (current.value === 1) {
nextTick(() => {
configRef.value.onOpen(recordData.value)
})
}
}
//
const steps = [
{
title: '基础信息',
content: '基础信息'
},
{
title: '详细配置',
content: '详细配置'
},
{
title: '完成',
content: '已经配置好代码生成,现在可以生成代码啦'
}
]
//
const seveGenerate = () => {
const param = {
id: recordData.value.id
}
if (recordData.value.generateType === 'PRO') {
genBasicApi.basicExecGenPro(param).then(() => {
message.success('操作成功')
emit('closed')
})
} else {
//
genBasicApi.basicExecGenBiz(param).then((res) => {
const blob = new Blob([res.data],{type: 'application/octet-stream;charset=UTF-8'});
const contentDisposition = res.headers['content-disposition']
const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
const $link = document.createElement("a");
$link.href = URL.createObjectURL(blob);
$link.download = patt.exec(contentDisposition)[1]
$link.click();
document.body.appendChild($link);
document.body.removeChild($link); //
window.URL.revokeObjectURL($link.href); // blob
emit('closed')
})
}
}
//
defineExpose({
configSteps
})
</script>
<style scoped>
.steps-card {
margin-top: -12px;
margin-left: -12px;
margin-right: -12px;
margin-bottom: 10px;
padding-top: -10px;
}
.xn-row {
margin-bottom: -10px;
margin-top: -10px;
}
</style>

View File

@ -27,6 +27,9 @@
<!-- 开发工具插件api接口 -->
<module>snowy-plugin-dev-api</module>
<!-- 代码生成插件api接口 -->
<module>snowy-plugin-gen-api</module>
<!-- 系统功能插件api接口 -->
<module>snowy-plugin-sys-api</module>
</modules>

View File

@ -0,0 +1 @@
# 代码生成插件api接口

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-api</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>snowy-plugin-gen-api</artifactId>
<packaging>jar</packaging>
<description>代码生成插件api接口</description>
<dependencies>
<!-- 每个插件接口都要引入common -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,13 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen;

View File

@ -0,0 +1,30 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.api;
/**
* API
*
* @author xuyuxiang
* @date 2022/11/1 13:45
**/
public interface SysButtonApi {
/**
*
*
* @author xuyuxiang
* @date 2022/11/1 13:48
**/
void addForGenButton(String menuId, String className, String functionName);
}

View File

@ -0,0 +1,30 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.api;
/**
* API
*
* @author xuyuxiang
* @date 2022/11/1 13:44
**/
public interface SysMenuApi {
/**
*
*
* @author xuyuxiang
* @date 2022/11/1 13:48
**/
String addForGenMenu(String parentId, String busName, String module, String title, String path);
}

View File

@ -39,4 +39,12 @@ public interface SysRoleApi {
* @date 2022/7/22 14:49
**/
List<JSONObject> roleSelector(String orgId, String category, String searchKey);
/**
*
*
* @author xuyuxiang
* @date 2022/11/1 15:58
**/
void grantForGenMenuAndButton(String menuId);
}

View File

@ -27,6 +27,9 @@
<!-- 开发工具插件 -->
<module>snowy-plugin-dev</module>
<!-- 代码生成插件 -->
<module>snowy-plugin-gen</module>
<!-- 系统功能插件 -->
<module>snowy-plugin-sys</module>
</modules>

View File

@ -0,0 +1 @@
# 代码生成插件

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>snowy-plugin-gen</artifactId>
<packaging>jar</packaging>
<description>代码生成插件</description>
<properties>
<sa.token.version>1.31.0</sa.token.version>
<beetl.version>1.2.40.Beetl.RELEASE</beetl.version>
</properties>
<dependencies>
<!-- 每个插件都要引入自己的对外接口 -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-gen-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- 引入系统接口,用于菜单生成等功能 -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-sys-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- beetl模板引擎 -->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl-framework-starter</artifactId>
<version>${beetl.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,68 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.core.config;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.annotation.Resource;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Configuration
public class GenConfigure {
@Resource
private OpenApiExtensionResolver openApiExtensionResolver;
/**
* API
*
* @author xuyuxiang
* @date 2022/7/7 16:18
**/
@Bean(value = "genDocApi")
public Docket sysDocApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("代码生成GEN")
.description("代码生成GEN")
.termsOfServiceUrl("https://www.xiaonuo.vip")
.contact(new Contact("SNOWY_TEAM","https://www.xiaonuo.vip", "xiaonuobase@qq.com"))
.version("2.0.0")
.build())
.globalResponseMessage(RequestMethod.GET, CommonResult.responseList())
.globalResponseMessage(RequestMethod.POST, CommonResult.responseList())
.groupName("代码生成GEN")
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.apis(RequestHandlerSelectors.basePackage("vip.xiaonuo.gen"))
.paths(PathSelectors.any())
.build().extensions(openApiExtensionResolver.buildExtensions("代码生成GEN"));
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.core.enums;
import lombok.Getter;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
public enum GenBuildInEnum {
}

View File

@ -0,0 +1,91 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.core.util;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import vip.xiaonuo.gen.modular.basic.enums.GenJavaTypeEnum;
/**
*
*
* @author xuyuxiang
* @date 2022/10/26 16:33
**/
@Slf4j
public class GenDbTypeUtil {
/**
* Java
*
* @author xuyuxiang
* @date 2022/10/26 16:34
**/
public static String getJavaTypeBySqlType(String dataType) {
if(ObjectUtil.isEmpty(dataType)) {
log.info(">>> 字段的数据库类型为空使用默认值String");
return GenJavaTypeEnum.String.getValue();
}
dataType = dataType.toUpperCase();
if(dataType.startsWith("INT")) {
//如果以int开头则直接返回int兼容pgsql中int2 int8等
return GenJavaTypeEnum.Integer.getValue();
}
switch(dataType){
case "NVARCHAR":
case "NVARCHAR2":
case "CHAR":
case "VARCHAR":
case "ENUM":
case "SET":
case "TEXT":
case "LONGTEXT":
case "NCHAR":
case "BLOB":
case "NCLOB":
case "IMAGE":
return GenJavaTypeEnum.String.getValue();
case "INTEGER":
case "BIGINT":
case "NUMBER":
case "ID":
return GenJavaTypeEnum.Long.getValue();
case "TINYINT":
case "SMALLINT":
case "MEDIUMINT":
return GenJavaTypeEnum.Integer.getValue();
case "BIT":
case "BOOLEAN":
return GenJavaTypeEnum.Boolean.getValue();
case "FLOAT":
return GenJavaTypeEnum.Float.getValue();
case "DOUBLE":
case "MONEY":
case "SMALLMONEY":
return GenJavaTypeEnum.Double.getValue();
case "DECIMAL":
case "NUMERIC":
case "REAL":
return GenJavaTypeEnum.BigDecimal.getValue();
case "DATE":
case "DATETIME":
case "YEAR":
case "TIME":
case "TIMESTAMP":
return GenJavaTypeEnum.Date.getValue();
default:
log.info(">>> 字段的数据库类型:{}无法匹配使用默认值String", dataType);
return GenJavaTypeEnum.String.getValue();
}
}
}

View File

@ -0,0 +1,197 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.common.pojo.CommonValidList;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.util.List;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Api(tags = "代码生成基础控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 1)
@RestController
@Validated
public class GenBasicController {
@Resource
private GenBasicService genBasicService;
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@ApiOperation("获取代码生成基础分页")
@GetMapping("/gen/basic/page")
public CommonResult<Page<GenBasic>> page(GenBasicPageParam genBasicPageParam) {
return CommonResult.data(genBasicService.page(genBasicPageParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 2)
@ApiOperation("添加代码生成基础")
@CommonLog("添加代码生成基础")
@PostMapping("/gen/basic/add")
public CommonResult<GenBasic> add(@RequestBody @Valid GenBasicAddParam genBasicAddParam) {
return CommonResult.data(genBasicService.add(genBasicAddParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 3)
@ApiOperation("编辑代码生成基础")
@CommonLog("编辑代码生成基础")
@PostMapping("/gen/basic/edit")
public CommonResult<GenBasic> edit(@RequestBody @Valid GenBasicEditParam genBasicEditParam) {
return CommonResult.data(genBasicService.edit(genBasicEditParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 4)
@ApiOperation("删除代码生成基础")
@CommonLog("删除代码生成基础")
@PostMapping("/gen/basic/delete")
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<GenBasicIdParam> genBasicIdParamList) {
genBasicService.delete(genBasicIdParamList);
return CommonResult.ok();
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 5)
@ApiOperation("获取代码生成基础详情")
@GetMapping("/gen/basic/detail")
public CommonResult<GenBasic> detail(@Valid GenBasicIdParam genBasicIdParam) {
return CommonResult.data(genBasicService.detail(genBasicIdParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 6)
@ApiOperation("获取所有表信息")
@GetMapping("/gen/basic/tables")
public CommonResult<List<GenBasicTableResult>> dbsTable() {
return CommonResult.data(genBasicService.tables());
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 7)
@ApiOperation("获取表内所有字段信息")
@GetMapping("/gen/basic/tableColumns")
public CommonResult<List<GenBasicTableColumnResult>> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam) {
return CommonResult.data(genBasicService.tableColumns(genBasicTableColumnParam));
}
/**
*
*
* @author xuyuxiang
* @date 2022/6/21 15:44
**/
@ApiOperationSupport(order = 8)
@ApiOperation("执行代码生成(压缩包)")
@CommonLog("执行代码生成(压缩包)")
@GetMapping(value = "/gen/basic/execGenZip", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void execGenZip(@Valid GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
genBasicService.execGenZip(genBasicIdParam, response);
}
/**
*
*
* @author yubaoshan
* @date 2022/10/31 02:17
**/
@ApiOperationSupport(order = 9)
@ApiOperation("执行代码生成(项目内)")
@CommonLog("执行代码生成(项目内)")
@PostMapping(value = "/gen/basic/execGenPro")
public CommonResult<String> execGenPro(@RequestBody @Valid GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
genBasicService.execGenPro(genBasicIdParam, response);
return CommonResult.ok();
}
/**
*
*
* @author xuyuxiang
* @date 2022/6/21 15:44
**/
@ApiOperationSupport(order = 10)
@ApiOperation("预览代码生成")
@CommonLog("预览代码生成")
@GetMapping(value = "/gen/basic/previewGen")
public CommonResult<GenBasicPreviewResult> previewGen(@Valid GenBasicIdParam genBasicIdParam) {
return CommonResult.data(genBasicService.previewGen(genBasicIdParam));
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import vip.xiaonuo.common.pojo.CommonEntity;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
@TableName("GEN_BASIC")
public class GenBasic extends CommonEntity {
/** id */
@ApiModelProperty(value = "id", position = 1)
private String id;
/** 主表名称 */
@ApiModelProperty(value = "主表名称", position = 2)
private String dbTable;
/** 主表主键 */
@ApiModelProperty(value = "主表主键", position = 3)
private String dbTableKey;
/** 表前缀移除 */
@ApiModelProperty(value = "表前缀移除", position = 4)
private String tablePrefix;
/** 生成方式 */
@ApiModelProperty(value = "生成方式", position = 5)
private String generateType;
/** 所属模块 */
@ApiModelProperty(value = "所属模块", position = 6)
private String module;
/** 上级目录 */
@ApiModelProperty(value = "上级目录", position = 7)
private String menuPid;
/** 功能名 */
@ApiModelProperty(value = "功能名", position = 8)
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", position = 9)
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", position = 10)
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", position = 11)
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", position = 12)
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", position = 13)
private Integer sortCode;
/** 包名 */
@ApiModelProperty(value = "包名", position = 14)
private String packageName;
/** 作者 */
@ApiModelProperty(value = "作者", position = 15)
private String authorName;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.enums;
import lombok.Getter;
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 9:57
**/
@Getter
public enum GenEffectTypeEnum {
/** 输入框 */
INPUT("INPUT"),
/** 文本框 */
TEXTAREA("TEXTAREA"),
/** 下拉框 */
SELECT("SELECT"),
/** 单选框 */
RADIO("RADIO"),
/** 复选框 */
CHECKBOX("CHECKBOX"),
/** 日期选择器 */
DATEPICKER("DATEPICKER"),
/** 时间选择器 */
TIMEPICKER("TIMEPICKER"),
/** 数字输入框 */
INPUTNUMBER("INPUTNUMBER"),
/** 滑动数字条 */
SLIDER("SLIDER");
private final String value;
GenEffectTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.enums;
import lombok.Getter;
/**
* Java
*
* @author xuyuxiang
* @date 2022/10/28 9:57
**/
@Getter
public enum GenJavaTypeEnum {
/** Integer */
Integer("Integer"),
/** Long */
Long("Long"),
/** String */
String("String"),
/** Boolean */
Boolean("Boolean"),
/** Float */
Float("Float"),
/** Double */
Double("Double"),
/** Date */
Date("Date"),
/** BigDecimal */
BigDecimal("BigDecimal");
private final String value;
GenJavaTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.enums;
import lombok.Getter;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
public enum GenTypeEnum {
/** 压缩包 */
ZIP("ZIP"),
/** 项目内 */
PRO("PRO");
private final String value;
GenTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.enums;
import lombok.Getter;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
public enum GenYesNoEnum {
/** 是 */
Y("Y"),
/** 否 */
N("N");
private final String value;
GenYesNoEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
/**
* Mapper
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
public interface GenBasicMapper extends BaseMapper<GenBasic> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper">
</mapper>

View File

@ -0,0 +1,98 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenBasicAddParam {
/** 主表名称 */
@ApiModelProperty(value = "主表名称", required = true, position = 1)
@NotNull(message = "dbTable不能为空")
private String dbTable;
/** 主表主键 */
@ApiModelProperty(value = "主表主键", required = true, position = 2)
@NotNull(message = "dbTableKey不能为空")
private String dbTableKey;
/** 表前缀移除 */
@ApiModelProperty(value = "表前缀移除", required = true, position = 3)
@NotNull(message = "tablePrefix不能为空")
private String tablePrefix;
/** 生成方式 */
@ApiModelProperty(value = "生成方式", required = true, position = 4)
@NotNull(message = "generateType不能为空")
private String generateType;
/** 所属模块 */
@ApiModelProperty(value = "所属模块", required = true, position = 5)
@NotNull(message = "module不能为空")
private String module;
/** 上级目录 */
@ApiModelProperty(value = "上级目录", required = true, position = 6)
@NotNull(message = "menuPid不能为空")
private String menuPid;
/** 功能名 */
@ApiModelProperty(value = "功能名", required = true, position = 7)
@NotNull(message = "functionName不能为空")
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", required = true, position = 8)
@NotNull(message = "busName不能为空")
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", required = true, position = 9)
@NotNull(message = "className不能为空")
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", required = true, position = 10)
@NotNull(message = "formLayout不能为空")
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", required = true, position = 11)
@NotNull(message = "gridWhether不能为空")
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", required = true, position = 12)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/** 作者名 */
@ApiModelProperty(value = "作者名", required = true, position = 13)
private String authorName;
/** 包名 */
@ApiModelProperty(value = "包名", required = true, position = 14)
private String packageName;
}

View File

@ -0,0 +1,104 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenBasicEditParam {
/** id */
@ApiModelProperty(value = "id", position = 1)
@NotNull(message = "id不能为空")
private String id;
/** 主表名称 */
@ApiModelProperty(value = "主表名称", position = 2)
@NotNull(message = "dbTable不能为空")
private String dbTable;
/** 主表主键 */
@ApiModelProperty(value = "主表主键", position = 3)
@NotNull(message = "dbTableKey不能为空")
private String dbTableKey;
/** 表前缀移除 */
@ApiModelProperty(value = "表前缀移除", position = 4)
@NotNull(message = "tablePrefix不能为空")
private String tablePrefix;
/** 生成方式 */
@ApiModelProperty(value = "生成方式", position = 5)
@NotNull(message = "generateType不能为空")
private String generateType;
/** 所属模块 */
@ApiModelProperty(value = "所属模块", position = 6)
@NotNull(message = "module不能为空")
private String module;
/** 上级目录 */
@ApiModelProperty(value = "上级目录", position = 7)
@NotNull(message = "menuPid不能为空")
private String menuPid;
/** 功能名 */
@ApiModelProperty(value = "功能名", position = 8)
@NotNull(message = "functionName不能为空")
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", position = 9)
@NotNull(message = "busName不能为空")
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", position = 10)
@NotNull(message = "className不能为空")
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", position = 11)
@NotNull(message = "formLayout不能为空")
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", position = 12)
@NotNull(message = "gridWhether不能为空")
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", position = 13)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/** 作者名 */
@ApiModelProperty(value = "作者名", required = true, position = 14)
@NotNull(message = "authorName不能为空")
private String authorName;
/** 包名 */
@ApiModelProperty(value = "包名 */", position = 15)
private String packageName;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* Id
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenBasicIdParam {
/** id */
@ApiModelProperty(value = "id", required = true)
@NotBlank(message = "id不能为空")
private String id;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
@Getter
@Setter
public class GenBasicPageParam {
/** 当前页 */
@ApiModelProperty(value = "当前页码")
private Integer current;
/** 每页条数 */
@ApiModelProperty(value = "每页条数")
private Integer size;
/** 排序字段 */
@ApiModelProperty(value = "排序字段字段驼峰名称userName")
private String sortField;
/** 排序方式 */
@ApiModelProperty(value = "排序方式升序ASCEND降序DESCEND")
private String sortOrder;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
*
* @author xuyuxiang
* @date 2022/7/29 9:59
*/
@Getter
@Setter
public class GenBasicTableColumnParam {
/** 表名称 */
@ApiModelProperty(value = "表名称", required = true)
@NotBlank(message = "表名称不能为空")
private String tableName;
}

View File

@ -0,0 +1,59 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.result;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 17:03
**/
@Getter
@Setter
public class GenBasicPreviewResult {
/** SQL代码结果集 */
@ApiModelProperty(value = "SQL代码结果集", position = 1)
private List<GenBasicCodeResult> genBasicCodeSqlResultList;
/** 前端代码结果集 */
@ApiModelProperty(value = "前端代码结果集", position = 2)
private List<GenBasicCodeResult> genBasicCodeFrontendResultList;
/** 后端代码结果集 */
@ApiModelProperty(value = "后端代码结果集", position = 3)
private List<GenBasicCodeResult> genBasicCodeBackendResultList;
@Getter
@Setter
public static class GenBasicCodeResult {
/** 代码文件名称 */
@ApiModelProperty(value = "代码文件名称", position = 1)
private String codeFileName;
/** 代码文件带路径名称 */
@ApiModelProperty(value = "代码文件带路径名称", position = 2)
private String codeFileWithPathName;
/** 代码文件内容 */
@ApiModelProperty(value = "代码文件内容", position = 2)
private String codeFileContent;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.result;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author xuyuxiang
* @date 2022/7/19 19:06
**/
@Getter
@Setter
public class GenBasicTableColumnResult {
/** 字段名称 */
@ApiModelProperty(value = "字段名称", position = 1)
private String columnName;
/** 字段类型 */
@ApiModelProperty(value = "字段类型", position = 2)
private String typeName;
/** 字段注释 */
@ApiModelProperty(value = "字段注释", position = 3)
private String columnRemark;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.result;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author xuyuxiang
* @date 2022/7/19 19:06
**/
@Getter
@Setter
public class GenBasicTableResult {
/** 表名称 */
@ApiModelProperty(value = "表名称", position = 1)
private String tableName;
/** 表注释 */
@ApiModelProperty(value = "表注释", position = 2)
private String tableRemark;
}

View File

@ -0,0 +1,122 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* Service
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
public interface GenBasicService extends IService<GenBasic> {
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
Page<GenBasic> page(GenBasicPageParam genBasicPageParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
GenBasic add(GenBasicAddParam genBasicAddParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
GenBasic edit(GenBasicEditParam genBasicEditParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
void delete(List<GenBasicIdParam> genBasicIdParamList);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
GenBasic detail(GenBasicIdParam genBasicIdParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
GenBasic queryEntity(String id);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
List<GenBasicTableResult> tables();
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
List<GenBasicTableColumnResult> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam);
/**
*
*
* @author xuyuxiang yubaoshan
* @date 2022/10/28 9:37
**/
void execGenZip(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException;
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 9:37
**/
void execGenPro(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException;
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 17:08
**/
GenBasicPreviewResult previewGen(GenBasicIdParam genBasicIdParam);
}

View File

@ -0,0 +1,640 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.basic.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.common.util.CommonDownloadUtil;
import vip.xiaonuo.common.util.CommonResponseUtil;
import vip.xiaonuo.gen.core.util.GenDbTypeUtil;
import vip.xiaonuo.gen.modular.basic.entity.GenBasic;
import vip.xiaonuo.gen.modular.basic.enums.GenEffectTypeEnum;
import vip.xiaonuo.gen.modular.basic.enums.GenYesNoEnum;
import vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper;
import vip.xiaonuo.gen.modular.basic.param.*;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
import vip.xiaonuo.gen.modular.basic.service.GenBasicService;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.param.GenConfigAddParam;
import vip.xiaonuo.gen.modular.config.service.GenConfigService;
import vip.xiaonuo.sys.api.SysButtonApi;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.api.SysRoleApi;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Service
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Service
public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> implements GenBasicService {
private static final String DB_URL_KEY = "spring.datasource.dynamic.datasource.master.url";
private static final String DB_USERNAME_KEY = "spring.datasource.dynamic.datasource.master.username";
private static final String DB_PASSWORD_KEY = "spring.datasource.dynamic.datasource.master.password";
private static final String MODULE_KEY = "biz";
private static final String GEN_PROJECT_FRONT_PLUGIN_KEY = "snowy-admin-web";
private static final String GEN_PROJECT_PLUGIN_KEY = "snowy-plugin";
private static final String GEN_PROJECT_PLUGIN_BIZ_KEY = GEN_PROJECT_PLUGIN_KEY + File.separator + "snowy-plugin-biz";
private static final List<JSONObject> GEN_SQL_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Mysql.sql.btl"),
JSONUtil.createObj().set("name", "Oracle.sql.btl"));
private static final List<JSONObject> GEN_FRONT_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Api.js.btl").set("path", "api" + File.separator + MODULE_KEY),
JSONUtil.createObj().set("name", "form.vue.btl").set("path", "views" + File.separator + MODULE_KEY),
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "views" + File.separator + MODULE_KEY));
private static final List<JSONObject> GEN_BACKEND_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "Controller.java.btl").set("path", "controller"),
JSONUtil.createObj().set("name", "Entity.java.btl").set("path", "entity"),
JSONUtil.createObj().set("name", "Enum.java.btl").set("path", "enums"),
JSONUtil.createObj().set("name", "Mapper.java.btl").set("path", "mapper"),
JSONUtil.createObj().set("name", "Mapper.xml.btl").set("path", "mapper" + File.separator + "mapping"),
JSONUtil.createObj().set("name", "AddParam.java.btl").set("path", "param"),
JSONUtil.createObj().set("name", "EditParam.java.btl").set("path", "param"),
JSONUtil.createObj().set("name", "IdParam.java.btl").set("path", "param"),
JSONUtil.createObj().set("name", "PageParam.java.btl").set("path", "param"),
JSONUtil.createObj().set("name", "Service.java.btl").set("path", "service"),
JSONUtil.createObj().set("name", "ServiceImpl.java.btl").set("path", "service" + File.separator + "impl"));
private static final String SORT_CODE_KEY = "SORT_CODE";
private static final String CREATE_USER_KEY = "CREATE_USER";
private static final String CREATE_TIME_KEY = "CREATE_TIME";
private static final String UPDATE_USER_KEY = "UPDATE_USER";
private static final String UPDATE_TIME_KEY = "UPDATE_TIME";
@Resource
private Environment environment;
@Resource
private MybatisPlusProperties mybatisPlusProperties;
@Resource
private GenConfigService genConfigService;
@Resource
private SysMenuApi sysMenuApi;
@Resource
private SysButtonApi sysButtonApi;
@Resource
private SysRoleApi sysRoleApi;
@Override
public Page<GenBasic> page(GenBasicPageParam genBasicPageParam) {
QueryWrapper<GenBasic> queryWrapper = new QueryWrapper<>();
if(ObjectUtil.isAllNotEmpty(genBasicPageParam.getSortField(), genBasicPageParam.getSortOrder())) {
CommonSortOrderEnum.validate(genBasicPageParam.getSortOrder());
queryWrapper.orderBy(true, genBasicPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
StrUtil.toUnderlineCase(genBasicPageParam.getSortField()));
} else {
queryWrapper.lambda().orderByAsc(GenBasic::getSortCode);
}
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
}
@Transactional(rollbackFor = Exception.class)
@Override
public GenBasic add(GenBasicAddParam genBasicAddParam) {
GenBasic genBasic = BeanUtil.toBean(genBasicAddParam, GenBasic.class);
this.save(genBasic);
GenBasicTableColumnParam tableColumnParam = new GenBasicTableColumnParam();
tableColumnParam.setTableName(genBasic.getDbTable());
List<GenBasicTableColumnResult> resultList = this.tableColumns(tableColumnParam);
for (int i = 0; i < resultList.size(); i++) {
GenBasicTableColumnResult item = resultList.get(i);
GenConfigAddParam addParam = new GenConfigAddParam();
addParam.setBasicId(genBasic.getId());
if (item.getColumnName().equals(genBasic.getDbTableKey())) {
addParam.setIsTableKey(GenYesNoEnum.Y.getValue());
} else {
addParam.setIsTableKey(GenYesNoEnum.N.getValue());
}
addParam.setFieldName(item.getColumnName());
addParam.setFieldType(item.getTypeName());
addParam.setFieldRemark(item.getColumnRemark());
addParam.setFieldJavaType(GenDbTypeUtil.getJavaTypeBySqlType(item.getTypeName()));
addParam.setEffectType(GenEffectTypeEnum.INPUT.getValue().toLowerCase());
// 除主键、删除标志、创建人、创建时间、修改人和修改时间外,所有默认在列表显示、在增改显示、非列省略、非必填,非查询
String logicDeleteField = mybatisPlusProperties.getGlobalConfig().getDbConfig().getLogicDeleteField();
if(ObjectUtil.isEmpty(logicDeleteField)) {
logicDeleteField = "DELETE_FLAG";
}
if(genBasic.getDbTableKey().equalsIgnoreCase(item.getColumnName()) ||
logicDeleteField.equalsIgnoreCase(item.getColumnName()) ||
CREATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
CREATE_TIME_KEY.equalsIgnoreCase(item.getColumnName()) ||
UPDATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
UPDATE_TIME_KEY.equalsIgnoreCase(item.getColumnName())) {
addParam.setWhetherTable(GenYesNoEnum.N.getValue());
addParam.setWhetherAddUpdate(GenYesNoEnum.N.getValue());
} else {
addParam.setWhetherTable(GenYesNoEnum.Y.getValue());
addParam.setWhetherAddUpdate(GenYesNoEnum.Y.getValue());
}
addParam.setWhetherRetract(GenYesNoEnum.N.getValue());
addParam.setWhetherRequired(GenYesNoEnum.N.getValue());
addParam.setQueryWhether(GenYesNoEnum.N.getValue());
addParam.setSortCode(i);
GenConfig genConfig = BeanUtil.toBean(addParam, GenConfig.class);
genConfigService.save(genConfig);
}
return genBasic;
}
@Transactional(rollbackFor = Exception.class)
@Override
public GenBasic edit(GenBasicEditParam genBasicEditParam) {
GenBasic genBasic = this.queryEntity(genBasicEditParam.getId());
BeanUtil.copyProperties(genBasicEditParam, genBasic);
this.updateById(genBasic);
return genBasic;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<GenBasicIdParam> genBasicIdParamList) {
List<String> basicIdIdList = CollStreamUtil.toList(genBasicIdParamList, GenBasicIdParam::getId);
if(ObjectUtil.isNotEmpty(basicIdIdList)) {
// 级联删除配置
genConfigService.remove(new LambdaQueryWrapper<GenConfig>().in(GenConfig::getBasicId, basicIdIdList));
// 执行删除
this.removeBatchByIds(basicIdIdList);
}
}
@Override
public GenBasic detail(GenBasicIdParam genBasicIdParam) {
return this.queryEntity(genBasicIdParam.getId());
}
@Override
public GenBasic queryEntity(String id) {
GenBasic genBasic = this.getById(id);
if(ObjectUtil.isEmpty(genBasic)) {
throw new CommonException("代码生成基础不存在id值为{}", id);
}
return genBasic;
}
@Override
public List<GenBasicTableResult> tables() {
Connection conn = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
DatabaseMetaData metaData = conn.getMetaData();
String url = metaData.getURL();
String schema = null;
if (url.toLowerCase().contains("oracle")) {
schema = metaData.getUserName();
}
List<GenBasicTableResult> tables = new ArrayList<>();
rs = metaData.getTables(null, schema, "%", new String[]{"TABLE", "VIEW"});
while (rs.next()) {
String tableName = rs.getString("TABLE_NAME").toUpperCase();
if (!tableName.startsWith("ACT_")) {
GenBasicTableResult genBasicTableResult = new GenBasicTableResult();
genBasicTableResult.setTableName(tableName);
String remarks = rs.getString("REMARKS");
if(ObjectUtil.isEmpty(remarks)) {
genBasicTableResult.setTableRemark(tableName);
} else {
genBasicTableResult.setTableRemark(remarks);
}
tables.add(genBasicTableResult);
}
}
return tables;
} catch (SQLException sqlException) {
sqlException.printStackTrace();
throw new CommonException("获取数据库表失败");
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeConnection(conn);
}
}
@Override
public List<GenBasicTableColumnResult> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam) {
Connection conn = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
DatabaseMetaData metaData = conn.getMetaData();
String url = metaData.getURL();
String schema = null;
if (url.toLowerCase().contains("oracle")) {
schema = metaData.getUserName();
}
List<GenBasicTableColumnResult> columns = new ArrayList<>();
rs = metaData.getColumns(null, schema, genBasicTableColumnParam.getTableName(), "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME").toUpperCase();
GenBasicTableColumnResult genBasicTableColumnResult = new GenBasicTableColumnResult();
genBasicTableColumnResult.setColumnName(columnName);
String remarks = rs.getString("REMARKS");
if(ObjectUtil.isEmpty(remarks)) {
genBasicTableColumnResult.setColumnRemark(columnName);
} else {
genBasicTableColumnResult.setColumnRemark(remarks);
}
String typeName = rs.getString("TYPE_NAME").toUpperCase();
if(ObjectUtil.isEmpty(typeName)) {
genBasicTableColumnResult.setTypeName("NONE");
} else {
genBasicTableColumnResult.setTypeName(typeName);
}
columns.add(genBasicTableColumnResult);
}
return columns;
} catch (SQLException sqlException) {
sqlException.printStackTrace();
throw new CommonException("获取数据库表字段失败,表名称:{}", genBasicTableColumnParam.getTableName());
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeConnection(conn);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public void execGenZip(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
File tempFolder = this.genTempFolder(genBasicIdParam, response, true);
if(tempFolder == null) {
CommonResponseUtil.renderError(response, "代码生成基础不存在id值为" + genBasicIdParam.getId());
return;
}
// 压缩
File zip = ZipUtil.zip(tempFolder);
// 压缩完毕删除临时目录
FileUtil.del(tempFolder);
// 下载
CommonDownloadUtil.download(zip, response);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void execGenPro(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
File tempFolder = this.genTempFolder(genBasicIdParam, response, false);
// 定义前端生成的目录
String genProjectFrontendPath = System.getProperty("user.dir") + File.separator + GEN_PROJECT_FRONT_PLUGIN_KEY + File.separator + "src";
if(!FileUtil.exist(genProjectFrontendPath)) {
throw new CommonException("前端代码生成位置:{}不存在,请检查位置", genProjectFrontendPath);
}
// 定义后端生成的目录
String genProjectBackendPath = System.getProperty("user.dir") + File.separator + GEN_PROJECT_PLUGIN_BIZ_KEY + File.separator + "src" +
File.separator + "main" + File.separator + "java";
if(!FileUtil.exist(genProjectFrontendPath)) {
throw new CommonException("后端代码生成位置:{}不存在,请检查位置", genProjectBackendPath);
}
try {
GenBasic genBasic = this.queryEntity(genBasicIdParam.getId());
// 生成菜单
String menuId = sysMenuApi.addForGenMenu(genBasic.getMenuPid(), genBasic.getBusName(), genBasic.getModule(), genBasic.getFunctionName() + "管理",
StrUtil.SLASH + MODULE_KEY + StrUtil.SLASH + genBasic.getBusName());
// 生成按钮
sysButtonApi.addForGenButton(menuId, genBasic.getClassName(), genBasic.getFunctionName());
// 授权菜单
sysRoleApi.grantForGenMenuAndButton(menuId);
//前端代码移动到前端
FileUtil.moveContent(FileUtil.file(tempFolder + File.separator + "frontend"), FileUtil.file(genProjectFrontendPath), true);
// 后端代码移动到后端
FileUtil.moveContent(FileUtil.file(tempFolder + File.separator + "backend"), FileUtil.file(genProjectBackendPath), true);
// 移动完毕删除临时目录
FileUtil.del(tempFolder);
} catch (Exception e) {
e.printStackTrace();
throw new CommonException("代码生成异常");
}
}
/**
*
*
* @author xuyuxiang yubaoshan
* @date 2022/10/28 21:36
*/
private File genTempFolder(GenBasicIdParam genBasicIdParam, HttpServletResponse response, boolean isZip) throws IOException {
GenBasic genBasic = this.getById(genBasicIdParam.getId());
if(ObjectUtil.isEmpty(genBasic)) {
// 如果是压缩包下载应该使用CommonResponseUtil渲染异常
if(isZip) {
return null;
} else {
// 否则可以直接抛出异常
throw new CommonException("代码生成基础不存在id值为{}", genBasicIdParam.getId());
}
}
GenBasicPreviewResult genBasicPreviewResult = this.previewGen(genBasicIdParam);
// 先删除压缩包
FileUtil.del(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName() + ".zip");
// 生成临时目录
File tempFolder = FileUtil.file(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName());
// 生成前端代码到临时目录
genBasicPreviewResult.getGenBasicCodeFrontendResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "frontend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
// 生成后端代码到临时目录
genBasicPreviewResult.getGenBasicCodeBackendResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "backend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
return tempFolder;
}
@Override
public GenBasicPreviewResult previewGen(GenBasicIdParam genBasicIdParam) {
GenBasic genBasic = this.queryEntity(genBasicIdParam.getId());
JSONObject bindingJsonObject = this.getBindingJsonObject(genBasic);
GenBasicPreviewResult genBasicPreviewResult = new GenBasicPreviewResult();
try {
// SQL基础路径
String genSqlBasicPath = "sql";
// 前端
GroupTemplate groupTemplateSql = new GroupTemplate(new ClasspathResourceLoader("sqlend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeSqlResultList = CollectionUtil.newArrayList();
GEN_SQL_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
GenBasicPreviewResult.GenBasicCodeResult genBasicCodeSqlResult = new GenBasicPreviewResult.GenBasicCodeResult();
Template templateFront = groupTemplateSql.getTemplate(fileTemplateName);
templateFront.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
genBasicCodeSqlResult.setCodeFileName(resultName);
genBasicCodeSqlResult.setCodeFileWithPathName(genSqlBasicPath + File.separator + resultName);
genBasicCodeSqlResult.setCodeFileContent(templateFront.render());
genBasicCodeSqlResultList.add(genBasicCodeSqlResult);
});
genBasicPreviewResult.setGenBasicCodeSqlResultList(genBasicCodeSqlResultList);
// 前端基础路径
String genFrontBasicPath = "";
// 前端
GroupTemplate groupTemplateFront = new GroupTemplate(new ClasspathResourceLoader("frontend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeFrontendResultList = CollectionUtil.newArrayList();
GEN_FRONT_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
String fileTemplatePath = fileJsonObject.getStr("path");
GenBasicPreviewResult.GenBasicCodeResult genBasicCodeFrontResult = new GenBasicPreviewResult.GenBasicCodeResult();
Template templateFront = groupTemplateFront.getTemplate(fileTemplateName);
templateFront.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
if(fileTemplateName.equalsIgnoreCase("Api.js.btl")) {
resultName = StrUtil.lowerFirst(genBasic.getClassName()) + resultName;
genBasicCodeFrontResult.setCodeFileName(resultName);
genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + resultName);
} else {
genBasicCodeFrontResult.setCodeFileName(resultName);
genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + genBasic.getBusName() + File.separator + resultName);
}
genBasicCodeFrontResult.setCodeFileContent(templateFront.render());
genBasicCodeFrontendResultList.add(genBasicCodeFrontResult);
});
genBasicPreviewResult.setGenBasicCodeFrontendResultList(genBasicCodeFrontendResultList);
// 后端基础路径
String genBackendBasicPath = StrUtil.replace(genBasic.getPackageName(), StrUtil.DOT, File.separator) +
File.separator + MODULE_KEY + File.separator + "modular" + File.separator + genBasic.getBusName() + File.separator;
// 后端
GroupTemplate groupTemplateBackEnd = new GroupTemplate(new ClasspathResourceLoader("backend"),
Configuration.defaultConfiguration());
List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeBackendResultList = CollectionUtil.newArrayList();
GEN_BACKEND_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
String fileTemplatePath = fileJsonObject.getStr("path");
GenBasicPreviewResult.GenBasicCodeResult genBasicCodeBackendResult = new GenBasicPreviewResult.GenBasicCodeResult();
Template templateBackend = groupTemplateBackEnd.getTemplate(fileTemplateName);
templateBackend.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
if(fileTemplateName.equalsIgnoreCase("Entity.java.btl")) {
resultName = ".java";
}
genBasicCodeBackendResult.setCodeFileName(genBasic.getClassName() + resultName);
genBasicCodeBackendResult.setCodeFileWithPathName(genBackendBasicPath + fileTemplatePath + File.separator + genBasic.getClassName() + resultName);
genBasicCodeBackendResult.setCodeFileContent(templateBackend.render());
genBasicCodeBackendResultList.add(genBasicCodeBackendResult);
});
genBasicPreviewResult.setGenBasicCodeBackendResultList(genBasicCodeBackendResultList);
} catch (Exception e) {
e.printStackTrace();
throw new CommonException("代码生成异常");
}
return genBasicPreviewResult;
}
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 21:36
*/
public JSONObject getBindingJsonObject(GenBasic genBasic) {
JSONObject bindingJsonObject = JSONUtil.createObj();
// 代码模块名
bindingJsonObject.set("moduleName", MODULE_KEY);
// 功能名
bindingJsonObject.set("functionName", genBasic.getFunctionName());
// 业务名
bindingJsonObject.set("busName", genBasic.getBusName());
// 包名
bindingJsonObject.set("packageName", genBasic.getPackageName());
// 库名
bindingJsonObject.set("dbTable", genBasic.getDbTable());
// 类名
bindingJsonObject.set("className", genBasic.getClassName());
// 类首字母小写名
bindingJsonObject.set("classNameFirstLower", StrUtil.lowerFirst(genBasic.getClassName()));
// 主键名
bindingJsonObject.set("dbTableKey", genBasic.getDbTableKey());
// 主键Java类型
bindingJsonObject.set("dbTableKeyJavaType", "String");
// 主键名驼峰
bindingJsonObject.set("dbTableKeyCamelCase", StrUtil.toCamelCase(genBasic.getDbTableKey().toLowerCase()));
// 主键首字母大写名
bindingJsonObject.set("dbTableKeyFirstUpper", StrUtil.upperFirst(genBasic.getDbTableKey().toLowerCase()));
// 主键注释
bindingJsonObject.set("dbTableKeyRemark", genBasic.getDbTableKey());
// 表单布局
bindingJsonObject.set("formLayout", genBasic.getFormLayout());
// 使用栅格
bindingJsonObject.set("gridWhether", genBasic.getGridWhether().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
// 父菜单ID
bindingJsonObject.set("parentId", genBasic.getMenuPid());
// 菜单ID
bindingJsonObject.set("menuId", IdWorker.getIdStr());
// 菜单编码
bindingJsonObject.set("menuCode", RandomUtil.randomString(10));
// 菜单路径
bindingJsonObject.set("menuPath", StrUtil.SLASH + MODULE_KEY + StrUtil.SLASH + genBasic.getBusName());
// 菜单组件
bindingJsonObject.set("menuComponent", MODULE_KEY + StrUtil.SLASH + genBasic.getBusName() + StrUtil.SLASH + "index");
// 模块ID
bindingJsonObject.set("moduleId", genBasic.getModule());
// 添加按钮ID
bindingJsonObject.set("addButtonId", IdWorker.getIdStr());
// 编辑按钮ID
bindingJsonObject.set("editButtonId", IdWorker.getIdStr());
// 删除按钮ID
bindingJsonObject.set("deleteButtonId", IdWorker.getIdStr());
// 批量删除按钮ID
bindingJsonObject.set("batchDeleteButtonId", IdWorker.getIdStr());
// 作者
bindingJsonObject.set("authorName", genBasic.getAuthorName());
// 生成时间
bindingJsonObject.set("genTime", DateUtil.format(DateTime.now(), " yyyy/MM/dd HH:mm"));
// 定义配置详情列表
List<JSONObject> configList = CollectionUtil.newArrayList();
// 定义是否有排序字段
AtomicBoolean hasSortCodeField = new AtomicBoolean(false);
genConfigService.list(new LambdaQueryWrapper<GenConfig>().eq(GenConfig::getBasicId, genBasic.getId()))
.forEach(genConfig -> {
// 定义字段信息
JSONObject configItem = JSONUtil.createObj();
if(genConfig.getFieldName().equalsIgnoreCase(SORT_CODE_KEY)) {
hasSortCodeField.set(true);
}
// 如果是主键,则无需作为添加参数,需要作为编辑参数,需要主键注解
if(genConfig.getFieldName().equalsIgnoreCase(genBasic.getDbTableKey())) {
configItem.set("needAdd", false);
configItem.set("needEdit", true);
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", true);
configItem.set("needTableId", true);
bindingJsonObject.set("dbTableKeyJavaType", genConfig.getFieldJavaType());
bindingJsonObject.set("dbTableKeyRemark", genConfig.getFieldRemark());
} else {
// 排除删除标志
String logicDeleteField = mybatisPlusProperties.getGlobalConfig().getDbConfig().getLogicDeleteField();
if(ObjectUtil.isEmpty(logicDeleteField)) {
logicDeleteField = "DELETE_FLAG";
}
if(genConfig.getFieldName().equalsIgnoreCase(logicDeleteField)) {
configItem.set("needAdd", false);
configItem.set("needEdit", false);
configItem.set("needPage", false);
configItem.set("needPageType", "none");
configItem.set("required", false);
configItem.set("needTableId", false);
} else {
boolean needAddAndUpdate = genConfig.getWhetherAddUpdate().equalsIgnoreCase(GenYesNoEnum.Y.getValue());
configItem.set("needAdd", needAddAndUpdate);
configItem.set("needEdit", needAddAndUpdate);
configItem.set("needPage", genConfig.getQueryWhether().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
configItem.set("needPageType", genConfig.getQueryType());
configItem.set("required", genConfig.getWhetherRequired().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
configItem.set("needTableId", false);
}
}
// 列显示
configItem.set("whetherTable", genConfig.getWhetherTable().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
// 列省略
configItem.set("whetherRetract", genConfig.getWhetherRetract().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
// 增改
configItem.set("whetherAddUpdate", genConfig.getWhetherAddUpdate().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
// 作用类型
configItem.set("effectType", genConfig.getEffectType());
// 字典值
configItem.set("dictTypeCode", genConfig.getDictTypeCode());
// 实体类型
configItem.set("fieldJavaType", genConfig.getFieldJavaType());
// 字段驼峰名
configItem.set("fieldNameCamelCase", StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase()));
// 字段驼峰首字母大写名
configItem.set("fieldNameCamelCaseFirstUpper", StrUtil.upperFirst(StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase())));
// 字段注释
configItem.set("fieldRemark", genConfig.getFieldRemark());
// 是否需要自动插入
configItem.set("needAutoInsert", CREATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
CREATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
// 是否需要自动更新
configItem.set("needAutoUpdate", UPDATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
UPDATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
configList.add(configItem);
});
// 配置信息
bindingJsonObject.set("configList", configList);
// 有排序字段
bindingJsonObject.set("hasSortCodeField", hasSortCodeField.get());
return bindingJsonObject;
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.common.pojo.CommonValidList;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.param.GenConfigEditParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigIdParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigListParam;
import vip.xiaonuo.gen.modular.config.service.GenConfigService;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Api(tags = "代码生成详细配置控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 2)
@RestController
@Validated
public class GenConfigController {
@Resource
private GenConfigService genConfigService;
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@ApiOperation("获取代码生成详细配置分页")
@GetMapping("/gen/config/list")
public CommonResult<List<GenConfig>> list(GenConfigListParam genConfigListParam) {
return CommonResult.data(genConfigService.list(genConfigListParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 2)
@ApiOperation("编辑代码生成详细配置")
@CommonLog("编辑代码生成详细配置")
@PostMapping("/gen/config/edit")
public CommonResult<String> edit(@RequestBody @Valid GenConfigEditParam genConfigEditParam) {
genConfigService.edit(genConfigEditParam);
return CommonResult.ok();
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 3)
@ApiOperation("删除代码生成详细配置")
@CommonLog("删除代码生成详细配置")
@PostMapping("/gen/config/delete")
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<GenConfigIdParam> genConfigIdParamList) {
genConfigService.delete(genConfigIdParamList);
return CommonResult.ok();
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 4)
@ApiOperation("获取代码生成详细配置详情")
@GetMapping("/gen/config/detail")
public CommonResult<GenConfig> detail(@Valid GenConfigIdParam genConfigIdParam) {
return CommonResult.data(genConfigService.detail(genConfigIdParam));
}
/**
*
*
* @author yubaoshan
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 5)
@ApiOperation("批量编辑代码生成详细配置")
@CommonLog("批量编辑代码生成详细配置")
@PostMapping("/gen/config/editBatch")
public CommonResult<String> editBatch(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<GenConfigEditParam> genConfigEditParamList) {
genConfigService.editBatch(genConfigEditParamList);
return CommonResult.ok();
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import vip.xiaonuo.common.pojo.CommonEntity;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
@TableName("GEN_CONFIG")
public class GenConfig extends CommonEntity {
/** id */
@ApiModelProperty(value = "id", position = 1)
private String id;
/** 基础ID */
@ApiModelProperty(value = "基础ID", position = 2)
private String basicId;
/** 是否主键 */
@ApiModelProperty(value = "是否主键", position = 3)
private String isTableKey;
/** 字段 */
@ApiModelProperty(value = "字段", position = 4)
private String fieldName;
/** 注释 */
@ApiModelProperty(value = "注释", position = 5)
private String fieldRemark;
/** 类型 */
@ApiModelProperty(value = "类型", position = 6)
private String fieldType;
/** 实体类型 */
@ApiModelProperty(value = "实体类型", position = 7)
private String fieldJavaType;
/** 作用类型 */
@ApiModelProperty(value = "作用类型", position = 8)
private String effectType;
/** 字典 */
@ApiModelProperty(value = "字典", position = 9)
private String dictTypeCode;
/** 列表显示 */
@ApiModelProperty(value = "列表显示", position = 10)
private String whetherTable;
/** 列省略 */
@ApiModelProperty(value = "列省略", position = 11)
private String whetherRetract;
/** 增改 */
@ApiModelProperty(value = "增改", position = 12)
private String whetherAddUpdate;
/** 必填 */
@ApiModelProperty(value = "必填", position = 13)
private String whetherRequired;
/** 查询 */
@ApiModelProperty(value = "查询", position = 14)
private String queryWhether;
/** 查询方式 */
@ApiModelProperty(value = "查询方式", position = 15)
private String queryType;
/** 排序 */
@ApiModelProperty(value = "排序", position = 16)
private String sortCode;
}

View File

@ -0,0 +1,25 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
/**
* Mapper
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
public interface GenConfigMapper extends BaseMapper<GenConfig> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.gen.modular.config.mapper.GenConfigMapper">
</mapper>

View File

@ -0,0 +1,95 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenConfigAddParam {
/** 基础ID */
@ApiModelProperty(value = "基础ID", required = true, position = 1)
@NotBlank(message = "basicId不能为空")
private String basicId;
/** 是否是主键 */
@ApiModelProperty(value = "是否是主键", required = true, position = 2)
@NotBlank(message = "isTableKey不能为空")
private String isTableKey;
/** 字段 */
@ApiModelProperty(value = "字段", required = true, position = 3)
@NotBlank(message = "fieldName不能为空")
private String fieldName;
/** 注释 */
@ApiModelProperty(value = "注释", required = true, position = 4)
@NotBlank(message = "fieldRemark不能为空")
private String fieldRemark;
/** 类型 */
@ApiModelProperty(value = "类型", required = true, position = 5)
@NotBlank(message = "fieldType不能为空")
private String fieldType;
/** 实体类型 */
@ApiModelProperty(value = "实体类型", position = 6)
private String fieldJavaType;
/** 作用类型 */
@ApiModelProperty(value = "作用类型", position = 7)
private String effectType;
/** 字典 */
@ApiModelProperty(value = "字典", position = 8)
private String dictTypeCode;
/** 列表显示 */
@ApiModelProperty(value = "列表显示", position = 9)
private String whetherTable;
/** 列省略 */
@ApiModelProperty(value = "列省略", position = 10)
private String whetherRetract;
/** 增改 */
@ApiModelProperty(value = "增改", position = 11)
private String whetherAddUpdate;
/** 必填 */
@ApiModelProperty(value = "必填", position = 12)
private String whetherRequired;
/** 查询 */
@ApiModelProperty(value = "查询", position = 13)
private String queryWhether;
/** 查询方式 */
@ApiModelProperty(value = "查询方式", position = 14)
private String queryType;
/** 排序 */
@ApiModelProperty(value = "排序", position = 15)
private Integer sortCode;
}

View File

@ -0,0 +1,107 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenConfigEditParam {
/** id */
@ApiModelProperty(value = "id", required = true, position = 1)
@NotBlank(message = "id不能为空")
private String id;
/** 基础ID */
@ApiModelProperty(value = "基础ID", required = true, position = 2)
@NotBlank(message = "basicId不能为空")
private String basicId;
/** 是否主键 */
@ApiModelProperty(value = "是否主键", required = true, position = 3)
@NotBlank(message = "isTableKey不能为空")
private String isTableKey;
/** 字段 */
@ApiModelProperty(value = "字段", required = true, position = 4)
@NotBlank(message = "fieldName不能为空")
private String fieldName;
/** 注释 */
@ApiModelProperty(value = "注释", required = true, position = 5)
@NotBlank(message = "fieldRemark不能为空")
private String fieldRemark;
/** 类型 */
@ApiModelProperty(value = "类型", required = true, position = 6)
@NotBlank(message = "fieldType不能为空")
private String fieldType;
/** 实体类型 */
@ApiModelProperty(value = "实体类型", required = true, position = 7)
@NotBlank(message = "fieldJavaType不能为空")
private String fieldJavaType;
/** 作用类型 */
@ApiModelProperty(value = "作用类型", required = true, position = 8)
@NotBlank(message = "effectType不能为空")
private String effectType;
/** 字典 */
@ApiModelProperty(value = "字典", required = true, position = 9)
private String dictTypeCode;
/** 列表显示 */
@ApiModelProperty(value = "列表显示", required = true, position = 10)
@NotBlank(message = "whetherTable不能为空")
private String whetherTable;
/** 列省略 */
@ApiModelProperty(value = "列省略", required = true, position = 11)
@NotBlank(message = "whetherRetract不能为空")
private String whetherRetract;
/** 增改 */
@ApiModelProperty(value = "增改", required = true, position = 12)
@NotBlank(message = "whetherAddUpdate不能为空")
private String whetherAddUpdate;
/** 必填 */
@ApiModelProperty(value = "必填", required = true, position = 13)
@NotBlank(message = "whetherRequired不能为空")
private String whetherRequired;
/** 查询 */
@ApiModelProperty(value = "查询", required = true, position = 14)
@NotBlank(message = "queryWhether不能为空")
private String queryWhether;
/** 查询方式 */
@ApiModelProperty(value = "查询方式", required = true, position = 15)
private String queryType;
/** 排序 */
@ApiModelProperty(value = "排序", required = true, position = 16)
private Integer sortCode;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* Id
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Getter
@Setter
public class GenConfigIdParam {
/** id */
@ApiModelProperty(value = "id", required = true)
@NotBlank(message = "id不能为空")
private String id;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
@Getter
@Setter
public class GenConfigListParam {
/** 排序字段 */
@ApiModelProperty(value = "排序字段字段驼峰名称userName")
private String sortField;
/** 排序方式 */
@ApiModelProperty(value = "排序方式升序ASCEND降序DESCEND")
private String sortOrder;
/** 基础ID */
@ApiModelProperty(value = "基础ID")
@NotBlank(message = "basicId不能为空")
private String basicId;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
@Getter
@Setter
public class GenConfigPageParam {
/** 当前页 */
@ApiModelProperty(value = "当前页码")
private Integer current;
/** 每页条数 */
@ApiModelProperty(value = "每页条数")
private Integer size;
/** 排序字段 */
@ApiModelProperty(value = "排序字段字段驼峰名称userName")
private String sortField;
/** 排序方式 */
@ApiModelProperty(value = "排序方式升序ASCEND降序DESCEND")
private String sortOrder;
/** 基础ID */
@ApiModelProperty(value = "基础ID")
@NotBlank(message = "basicId不能为空")
private String basicId;
}

View File

@ -0,0 +1,79 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.common.pojo.CommonValidList;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.param.GenConfigEditParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigIdParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigListParam;
import java.util.List;
/**
* Service
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
public interface GenConfigService extends IService<GenConfig> {
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
List<GenConfig> list(GenConfigListParam genConfigListParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
void edit(GenConfigEditParam genConfigEditParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
void delete(List<GenConfigIdParam> genConfigIdParamList);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
*/
GenConfig detail(GenConfigIdParam genConfigIdParam);
/**
*
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
GenConfig queryEntity(String id);
/**
*
*
* @author xuyuxiang
* @date 2022/10/28 13:49
**/
void editBatch(List<GenConfigEditParam> genConfigEditParamList);
}

View File

@ -0,0 +1,95 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.gen.modular.config.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.gen.modular.config.entity.GenConfig;
import vip.xiaonuo.gen.modular.config.mapper.GenConfigMapper;
import vip.xiaonuo.gen.modular.config.param.GenConfigEditParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigIdParam;
import vip.xiaonuo.gen.modular.config.param.GenConfigListParam;
import vip.xiaonuo.gen.modular.config.service.GenConfigService;
import java.util.List;
/**
* Service
*
* @author yubaoshan
* @date 2022/10/25 22:33
**/
@Service
public class GenConfigServiceImpl extends ServiceImpl<GenConfigMapper, GenConfig> implements GenConfigService {
@Override
public List<GenConfig> list(GenConfigListParam genConfigListParam) {
QueryWrapper<GenConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(GenConfig::getBasicId, genConfigListParam.getBasicId());
if(ObjectUtil.isAllNotEmpty(genConfigListParam.getSortField(), genConfigListParam.getSortOrder())) {
CommonSortOrderEnum.validate(genConfigListParam.getSortOrder());
queryWrapper.orderBy(true, genConfigListParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
StrUtil.toUnderlineCase(genConfigListParam.getSortField()));
} else {
queryWrapper.lambda().orderByAsc(GenConfig::getSortCode);
}
return this.list(queryWrapper);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void edit(GenConfigEditParam genConfigEditParam) {
GenConfig genConfig = this.queryEntity(genConfigEditParam.getId());
BeanUtil.copyProperties(genConfigEditParam, genConfig);
this.updateById(genConfig);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<GenConfigIdParam> genConfigIdParamList) {
List<String> basicIdIdList = CollStreamUtil.toList(genConfigIdParamList, GenConfigIdParam::getId);
if(ObjectUtil.isNotEmpty(basicIdIdList)) {
// 执行删除
this.removeBatchByIds(basicIdIdList);
}
}
@Override
public GenConfig detail(GenConfigIdParam genConfigIdParam) {
return this.queryEntity(genConfigIdParam.getId());
}
@Override
public GenConfig queryEntity(String id) {
GenConfig genConfig = this.getById(id);
if(ObjectUtil.isEmpty(genConfig)) {
throw new CommonException("代码生成详情配置不存在id值为{}", id);
}
return genConfig;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void editBatch(List<GenConfigEditParam> genConfigEditParamList) {
genConfigEditParamList.forEach(this::edit);
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* ${functionName}添加参数
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
@Setter
public class ${className}AddParam {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needAdd) { %>
/** ${configList[i].fieldRemark} */
@ApiModelProperty(value = "${configList[i].fieldRemark}",<% if(configList[i].required) { %> required = true,<% } %> position = ${i + 1})
<% if(configList[i].required) { %>
<% if(configList[i].fieldJavaType == 'String') { %>@NotBlank<% } else { %>@NotNull<% } %>(message = "${configList[i].fieldNameCamelCase}不能为空")
<% } else { %><% } %>
private ${configList[i].fieldJavaType} ${configList[i].fieldNameCamelCase};
<% } %>
<% } %>
}

View File

@ -0,0 +1,125 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ${packageName}.common.annotation.CommonLog;
import ${packageName}.common.pojo.CommonResult;
import ${packageName}.common.pojo.CommonValidList;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
import ${packageName}.${moduleName}.modular.${busName}.param.${className}AddParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}EditParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}IdParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}PageParam;
import ${packageName}.${moduleName}.modular.${busName}.service.${className}Service;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
/**
* ${functionName}控制器
*
* @author ${authorName}
* @date ${genTime}
*/
@Api(tags = "${functionName}控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 1)
@RestController
@Validated
public class ${className}Controller {
@Resource
private ${className}Service ${classNameFirstLower}Service;
/**
* 获取${functionName}分页
*
* @author ${authorName}
* @date ${genTime}
*/
@ApiOperationSupport(order = 1)
@ApiOperation("获取${functionName}分页")
@GetMapping("/${moduleName}/${busName}/page")
public CommonResult<Page<${className}>> page(${className}PageParam ${classNameFirstLower}PageParam) {
return CommonResult.data(${classNameFirstLower}Service.page(${classNameFirstLower}PageParam));
}
/**
* 添加${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
@ApiOperationSupport(order = 2)
@ApiOperation("添加${functionName}")
@CommonLog("添加${functionName}")
@PostMapping("/${moduleName}/${busName}/add")
public CommonResult<String> add(@RequestBody @Valid ${className}AddParam ${classNameFirstLower}AddParam) {
${classNameFirstLower}Service.add(${classNameFirstLower}AddParam);
return CommonResult.ok();
}
/**
* 编辑${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
@ApiOperationSupport(order = 3)
@ApiOperation("编辑${functionName}")
@CommonLog("编辑${functionName}")
@PostMapping("/${moduleName}/${busName}/edit")
public CommonResult<String> edit(@RequestBody @Valid ${className}EditParam ${classNameFirstLower}EditParam) {
${classNameFirstLower}Service.edit(${classNameFirstLower}EditParam);
return CommonResult.ok();
}
/**
* 删除${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
@ApiOperationSupport(order = 4)
@ApiOperation("删除${functionName}")
@CommonLog("删除${functionName}")
@PostMapping("/${moduleName}/${busName}/delete")
public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
CommonValidList<${className}IdParam> ${classNameFirstLower}IdParamList) {
${classNameFirstLower}Service.delete(${classNameFirstLower}IdParamList);
return CommonResult.ok();
}
/**
* 获取${functionName}详情
*
* @author ${authorName}
* @date ${genTime}
*/
@ApiOperationSupport(order = 5)
@ApiOperation("获取${functionName}详情")
@GetMapping("/${moduleName}/${busName}/detail")
public CommonResult<${className}> detail(@Valid ${className}IdParam ${classNameFirstLower}IdParam) {
return CommonResult.data(${classNameFirstLower}Service.detail(${classNameFirstLower}IdParam));
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* ${functionName}编辑参数
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
@Setter
public class ${className}EditParam {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needEdit) { %>
/** ${configList[i].fieldRemark} */
@ApiModelProperty(value = "${configList[i].fieldRemark}",<% if(configList[i].required) { %> required = true,<% } %> position = ${i + 1})
<% if(configList[i].required) { %>
<% if(configList[i].fieldJavaType == 'String') { %>@NotBlank<% } else { %>@NotNull<% } %>(message = "${configList[i].fieldNameCamelCase}不能为空")
<% } else { %><% } %>
private ${configList[i].fieldJavaType} ${configList[i].fieldNameCamelCase};
<% } %>
<% } %>
}

View File

@ -0,0 +1,52 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* ${functionName}实体
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
@Setter
@TableName("${dbTable}")
public class ${className} {
<% for(var i = 0; i < configList.~size; i++) { %>
/** ${configList[i].fieldRemark} */
<% if(configList[i].needTableId) { %>
@TableId
<% } else { %><% } %>
@ApiModelProperty(value = "${configList[i].fieldRemark}", position = ${i + 1})
<% if(configList[i].needAutoInsert) { %>
@TableField(fill = FieldFill.INSERT)
<% } else { %><% } %>
<% if(configList[i].needAutoUpdate) { %>
@TableField(fill = FieldFill.UPDATE)
<% } else { %><% } %>
private ${configList[i].fieldJavaType} ${configList[i].fieldNameCamelCase};
<% if(i == configList.~size - 1) { %><% } else { %>
<% } %>
<% } %>
}

View File

@ -0,0 +1,34 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.enums;
import lombok.Getter;
/**
* ${functionName}枚举
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
public enum ${className}Enum {
/** 测试 */
TEST("TEST");
private final String value;
${className}Enum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* ${functionName}Id参数
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
@Setter
public class ${className}IdParam {
/** ${dbTableKeyRemark} */
@ApiModelProperty(value = "${dbTableKeyRemark}", required = true)
@NotBlank(message = "${dbTableKeyCamelCase}不能为空")
private ${dbTableKeyJavaType} ${dbTableKeyCamelCase};
}

View File

@ -0,0 +1,25 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
/**
* ${functionName}Mapper接口
*
* @author ${authorName}
* @date ${genTime}
**/
public interface ${className}Mapper extends BaseMapper<${className}> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.${moduleName}.modular.${busName}.mapper.${className}Mapper">
</mapper>

View File

@ -0,0 +1,69 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* ${functionName}查询参数
*
* @author ${authorName}
* @date ${genTime}
**/
@Getter
@Setter
public class ${className}PageParam {
/** 当前页 */
@ApiModelProperty(value = "当前页码")
private Integer current;
/** 每页条数 */
@ApiModelProperty(value = "每页条数")
private Integer size;
/** 排序字段 */
@ApiModelProperty(value = "排序字段字段驼峰名称userName")
private String sortField;
/** 排序方式 */
@ApiModelProperty(value = "排序方式升序ASCEND降序DESCEND")
private String sortOrder;
/** 关键词 */
@ApiModelProperty(value = "关键词")
private String searchKey;
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needPage) { %>
<% if(configList[i].effectType == 'datepicker') { %>
/** ${configList[i].fieldRemark}开始 */
@ApiModelProperty(value = "${configList[i].fieldRemark}开始")
private String start${configList[i].fieldNameCamelCaseFirstUpper};
/** ${configList[i].fieldRemark}结束 */
@ApiModelProperty(value = "${configList[i].fieldRemark}结束")
private String end${configList[i].fieldNameCamelCaseFirstUpper};
<% } else { %>
/** ${configList[i].fieldRemark} */
@ApiModelProperty(value = "${configList[i].fieldRemark}")
private ${configList[i].fieldJavaType} ${configList[i].fieldNameCamelCase};
<% } %>
<% } %>
<% } %>
}

View File

@ -0,0 +1,80 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
import ${packageName}.${moduleName}.modular.${busName}.param.${className}AddParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}EditParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}IdParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}PageParam;
import java.util.List;
/**
* ${functionName}Service接口
*
* @author ${authorName}
* @date ${genTime}
**/
public interface ${className}Service extends IService<${className}> {
/**
* 获取${functionName}分页
*
* @author ${authorName}
* @date ${genTime}
*/
Page<${className}> page(${className}PageParam ${classNameFirstLower}PageParam);
/**
* 添加${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
void add(${className}AddParam ${classNameFirstLower}AddParam);
/**
* 编辑${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
void edit(${className}EditParam ${classNameFirstLower}EditParam);
/**
* 删除${functionName}
*
* @author ${authorName}
* @date ${genTime}
*/
void delete(List<${className}IdParam> ${classNameFirstLower}IdParamList);
/**
* 获取${functionName}详情
*
* @author ${authorName}
* @date ${genTime}
*/
${className} detail(${className}IdParam ${classNameFirstLower}IdParam);
/**
* 获取${functionName}详情
*
* @author ${authorName}
* @date ${genTime}
**/
${className} queryEntity(String id);
}

View File

@ -0,0 +1,109 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package ${packageName}.${moduleName}.modular.${busName}.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ${packageName}.common.enums.CommonSortOrderEnum;
import ${packageName}.common.exception.CommonException;
import ${packageName}.common.page.CommonPageRequest;
import ${packageName}.${moduleName}.modular.${busName}.entity.${className};
import ${packageName}.${moduleName}.modular.${busName}.mapper.${className}Mapper;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}AddParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}EditParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}IdParam;
import ${packageName}.${moduleName}.modular.${busName}.param.${className}PageParam;
import ${packageName}.${moduleName}.modular.${busName}.service.${className}Service;
import java.util.List;
/**
* ${functionName}Service接口实现类
*
* @author ${authorName}
* @date ${genTime}
**/
@Service
public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${className}> implements ${className}Service {
@Override
public Page<${className}> page(${className}PageParam ${classNameFirstLower}PageParam) {
QueryWrapper<${className}> queryWrapper = new QueryWrapper<>();
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needPage) { %>
<% if(configList[i].effectType == 'datepicker') { %>
if(ObjectUtil.isNotEmpty(${classNameFirstLower}PageParam.getStart${configList[i].fieldNameCamelCaseFirstUpper}()) && ObjectUtil.isNotEmpty(${classNameFirstLower}PageParam.getEnd${configList[i].fieldNameCamelCaseFirstUpper}())) {
queryWrapper.lambda().between(${className}::get${configList[i].fieldNameCamelCaseFirstUpper}, ${classNameFirstLower}PageParam.getStart${configList[i].fieldNameCamelCaseFirstUpper}(), ${classNameFirstLower}PageParam.getEnd${configList[i].fieldNameCamelCaseFirstUpper}());
}
<% } else { %>
if(ObjectUtil.isNotEmpty(${classNameFirstLower}PageParam.get${configList[i].fieldNameCamelCaseFirstUpper}())) {
queryWrapper.lambda().${configList[i].needPageType}(${className}::get${configList[i].fieldNameCamelCaseFirstUpper}, ${classNameFirstLower}PageParam.get${configList[i].fieldNameCamelCaseFirstUpper}());
}
<% } %>
<% } %>
<% } %>
if(ObjectUtil.isAllNotEmpty(${classNameFirstLower}PageParam.getSortField(), ${classNameFirstLower}PageParam.getSortOrder())) {
CommonSortOrderEnum.validate(${classNameFirstLower}PageParam.getSortOrder());
queryWrapper.orderBy(true, ${classNameFirstLower}PageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
StrUtil.toUnderlineCase(${classNameFirstLower}PageParam.getSortField()));
} else {
<% if(hasSortCodeField) { %>
queryWrapper.lambda().orderByAsc(${className}::getSortCode);
<% } else { %>
queryWrapper.lambda().orderByAsc(${className}::get${dbTableKeyFirstUpper});
<% } %>
}
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
}
@Override
public void add(${className}AddParam ${classNameFirstLower}AddParam) {
${className} ${classNameFirstLower} = BeanUtil.toBean(${classNameFirstLower}AddParam, ${className}.class);
this.save(${classNameFirstLower});
}
@Override
public void edit(${className}EditParam ${classNameFirstLower}EditParam) {
${className} ${classNameFirstLower} = this.queryEntity(${classNameFirstLower}EditParam.getId());
BeanUtil.copyProperties(${classNameFirstLower}EditParam, ${classNameFirstLower});
this.updateById(${classNameFirstLower});
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<${className}IdParam> ${classNameFirstLower}IdParamList) {
// 执行删除
this.removeBatchByIds(CollStreamUtil.toList(${classNameFirstLower}IdParamList, ${className}IdParam::getId));
}
@Override
public ${className} detail(${className}IdParam ${classNameFirstLower}IdParam) {
return this.queryEntity(${classNameFirstLower}IdParam.getId());
}
@Override
public ${className} queryEntity(String id) {
${className} ${classNameFirstLower} = this.getById(id);
if(ObjectUtil.isEmpty(${classNameFirstLower})) {
throw new CommonException("${functionName}不存在id值为{}", id);
}
return ${classNameFirstLower};
}
}

View File

@ -0,0 +1,32 @@
import { baseRequest } from '@/utils/request'
const request = (url, ...arg) => baseRequest(`/${moduleName}/${busName}/` + url, ...arg)
/**
* ${functionName}Api接口管理器
*
* @author ${authorName}
* @date ${genTime}
**/
export default {
// 获取${functionName}分页
${classNameFirstLower}Page(data) {
return request('page', data, 'get')
},
// 获取${functionName}列表
${classNameFirstLower}List(data) {
return request('list', data, 'get')
},
// 提交${functionName}表单 edit为true时为编辑默认为新增
${classNameFirstLower}SubmitForm(data, edit = false) {
return request(edit ? 'add' : 'edit', data)
},
// 删除${functionName}
${classNameFirstLower}Delete(data) {
return request('delete', data)
},
// 获取${functionName}详情
${classNameFirstLower}Detail(data) {
return request('detail', data, 'get')
}
}

View File

@ -0,0 +1,175 @@
<template>
<a-drawer
:title="formData.id ? '编辑${functionName}' : '增加${functionName}'"
:width="600"
:visible="visible"
:destroy-on-close="true"
:footer-style="{ textAlign: 'right' }"
@close="onClose"
>
<a-form ref="formRef" :model="formData" :rules="formRules" layout="${formLayout}">
<% if(gridWhether) { %>
<a-row :gutter="16">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherAddUpdate) { %>
<a-col :span="12">
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<% if(configList[i].effectType == 'input') { %>
<a-input v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" allow-clear />
<% } else if (configList[i].effectType == 'textarea') {%>
<a-textarea v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" :auto-size="{ minRows: 3, maxRows: 5 }" />
<% } else if (configList[i].effectType == 'select') {%>
<a-select v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="categoryOptions" />
<% } else if (configList[i].effectType == 'radio') {%>
<a-radio-group v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="formData.${configList[i].fieldNameCamelCase}Options" />
<% } else if (configList[i].effectType == 'checkbox') {%>
<a-checkbox-group v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
<% } else if (configList[i].effectType == 'datepicker') {%>
<a-date-picker v-model:value="formData.${configList[i].fieldNameCamelCase}" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择${configList[i].fieldRemark}" style="width: 100%" />
<% } else if (configList[i].effectType == 'timepicker') {%>
<a-time-picker v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" style="width: 100%" />
<% } else if (configList[i].effectType == 'inputNumber') {%>
<a-input-number v-model:value="formData.${configList[i].fieldNameCamelCase}" :min="1" :max="100" style="width: 100%" />
<% } else if (configList[i].effectType == 'slider') {%>
<a-slider v-model:value="formData.${configList[i].fieldNameCamelCase}" :max="100" style="width: 100%" />
<% } %>
</a-form-item>
</a-col>
<% } %>
<% } %>
</a-row>
<% } else { %>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherAddUpdate) { %>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<% if(configList[i].effectType == 'input') { %>
<a-input v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" allow-clear />
<% } else if (configList[i].effectType == 'textarea') {%>
<a-textarea v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" :auto-size="{ minRows: 3, maxRows: 5 }" />
<% } else if (configList[i].effectType == 'select') {%>
<a-select v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
<% } else if (configList[i].effectType == 'radio') {%>
<a-radio-group v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
<% } else if (configList[i].effectType == 'checkbox') {%>
<a-checkbox-group v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
<% } else if (configList[i].effectType == 'datepicker') {%>
<a-date-picker v-model:value="formData.${configList[i].fieldNameCamelCase}" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择${configList[i].fieldRemark}" style="width: 100%" />
<% } else if (configList[i].effectType == 'timepicker') {%>
<a-time-picker v-model:value="formData.${configList[i].fieldNameCamelCase}" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择${configList[i].fieldRemark}" style="width: 100%" />
<% } else if (configList[i].effectType == 'inputNumber') {%>
<a-input-number v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" :min="1" :max="100" style="width: 100%" />
<% } else if (configList[i].effectType == 'slider') {%>
<a-slider v-model:value="formData.${configList[i].fieldNameCamelCase}" placeholder="请滑动${configList[i].fieldRemark}" :max="100" style="width: 100%" />
<% } %>
</a-form-item>
<% } %>
<% } %>
<% } %>
</a-form>
<template #footer>
<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
</template>
</a-drawer>
</template>
<script setup name="${classNameFirstLower}Form">
<%
var iptTool = 0;
for(var i = 0; i < configList.~size; i++) {
if(!configList[i].needTableId) {
if(configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') {
iptTool++;
}
}
}
%>
<% if(iptTool > 0) { %>
import tool from '@/utils/tool'
<% } %>
import { cloneDeep } from 'lodash-es'
import { required } from '@/utils/formRules'
import ${classNameFirstLower}Api from '@/api/${moduleName}/${classNameFirstLower}Api'
// 抽屉状态
const visible = ref(false)
const emit = defineEmits({ successful: null })
const formRef = ref()
// 表单数据
const formData = ref({})
const submitLoading = ref(false)
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId) { %>
<% if(configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') { %>
const ${configList[i].fieldNameCamelCase}Options = ref([])
<% } %>
<% } %>
<% } %>
// 打开抽屉
const onOpen = (record) => {
visible.value = true
if (record) {
let recordData = cloneDeep(record)
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherAddUpdate && configList[i].effectType == 'checkbox') { %>
recordData.${configList[i].fieldNameCamelCase} = JSON.parse(recordData.${configList[i].fieldNameCamelCase})
<% } %>
<% } %>
formData.value = Object.assign({}, recordData)
}
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId) { %>
<% if(configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') { %>
${configList[i].fieldNameCamelCase}Options.value = tool.dictList('${configList[i].dictTypeCode}')
<% } %>
<% } %>
<% } %>
}
// 关闭抽屉
const onClose = () => {
formRef.value.resetFields()
formData.value = {}
visible.value = false
}
// 默认要校验的
const formRules = {
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId) { %>
<% if(configList[i].required) { %>
${configList[i].fieldNameCamelCase}: [required('请输入${configList[i].fieldRemark}')],
<% } %>
<% } %>
<% } %>
}
// 验证并提交数据
const onSubmit = () => {
formRef.value
.validate()
.then(() => {
submitLoading.value = true
const formDataParam = cloneDeep(formData.value)
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].whetherAddUpdate && configList[i].effectType == 'checkbox') { %>
formDataParam.${configList[i].fieldNameCamelCase} = JSON.stringify(formDataParam.${configList[i].fieldNameCamelCase})
<% } %>
<% } %>
${classNameFirstLower}Api
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
.${classNameFirstLower}SubmitForm(formDataParam, !formDataParam.${configList[i].fieldNameCamelCase})
<% } %>
<% } %>
.then(() => {
onClose()
emit('successful')
})
.finally(() => {
submitLoading.value = false
})
})
}
// 抛出函数
defineExpose({
onOpen
})
</script>

View File

@ -0,0 +1,254 @@
<template>
<%
var searchCount = 0;
var row = 0;
%>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { searchCount ++; }%>
<% } %>
<a-card :bordered="false">
<% if (searchCount > 0) { %>
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form mb-4">
<a-row :gutter="24">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { row ++; %>
<% if(row <= 3) { %>
<a-col :span="6">
<% if(configList[i].effectType == 'input' || configList[i].effectType == 'textarea') { %>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" />
</a-form-item>
<% } else if (configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-select v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
</a-form-item>
<% } else if (configList[i].effectType == 'inputNumber' || configList[i].effectType == 'slider') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input-number v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" style="width: 100%" />
</a-form-item>
<% } else if (configList[i].effectType == 'datepicker') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-range-picker v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" value-format="YYYY-MM-DD HH:mm:ss" show-time />
</a-form-item>
<% } else {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" />
</a-form-item>
<% } %>
</a-col>
<% } else { %>
<template v-if="advanced">
<a-col :span="6">
<% if(configList[i].effectType == 'input' || configList[i].effectType == 'textarea') { %>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" />
</a-form-item>
<% } else if (configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-select v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请选择${configList[i].fieldRemark}" :options="${configList[i].fieldNameCamelCase}Options" />
</a-form-item>
<% } else if (configList[i].effectType == 'inputNumber' || configList[i].effectType == 'slider') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input-number v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" style="width: 100%" />
</a-form-item>
<% } else if (configList[i].effectType == 'datepicker') {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-range-picker v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" show-time />
</a-form-item>
<% } else {%>
<a-form-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<a-input v-model:value="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" />
</a-form-item>
<% } %>
</a-col>
</template>
<% } %>
<% } %>
<% } %>
<a-col :span="6">
<a-button type="primary" @click="table.refresh(true)">查询</a-button>
<a-button style="margin: 0 8px" @click="() => searchFormRef.resetFields()">重置</a-button>
<% if(searchCount > 3) { %>
<a @click="toggleAdvanced" style="margin-left: 8px">
{{ advanced ? '收起' : '展开' }}
<component :is="advanced ? 'up-outlined' : 'down-outlined'"/>
</a>
<% }%>
</a-col>
</a-row>
</a-form>
<% } %>
<s-table
ref="table"
:columns="columns"
:data="loadData"
:alert="options.alert.show"
bordered
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(configList[i].needTableId) { %>
:row-key="(record) => record.${configList[i].fieldNameCamelCase}"
<% } %>
<% } %>
:tool-config="toolConfig"
:row-selection="options.rowSelection"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('${classNameFirstLower}Add')">
<template #icon><plus-outlined /></template>
新增
</a-button>
<a-button danger @click="deleteBatch${className}()" v-if="hasPerm('${classNameFirstLower}BatchDelete')">删除</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherTable) { %>
<% if (configList[i].effectType == 'select' || configList[i].effectType == 'radio') { %>
<template v-if="column.dataIndex === '${configList[i].fieldNameCamelCase}'">
{{ $TOOL.dictTypeData('${configList[i].dictTypeCode}', record.${configList[i].fieldNameCamelCase}) }}
</template>
<% } else if (configList[i].effectType == 'checkbox') { %>
<template v-if="column.dataIndex === '${configList[i].fieldNameCamelCase}'">
<a-tag v-for="textValue in JSON.parse(record.${configList[i].fieldNameCamelCase})" :key="textValue" color="green">{{ $TOOL.dictTypeData('${configList[i].dictTypeCode}', textValue) }}</a-tag>
</template>
<% } %>
<% } %>
<% } %>
<template v-if="column.dataIndex === 'action'">
<a-space>
<a @click="formRef.onOpen(record)" v-if="hasPerm('${classNameFirstLower}Edit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['${classNameFirstLower}Edit', '${classNameFirstLower}Delete'], 'and')" />
<a-popconfirm title="确定要删除吗?" @confirm="delete${className}(record)">
<a-button type="link" danger size="small" v-if="hasPerm('${classNameFirstLower}Delete')">删除</a-button>
</a-popconfirm>
</a-space>
</template>
</template>
</s-table>
</a-card>
<Form ref="formRef" @successful="table.refresh(true)" />
</template>
<script setup name="${busName}">
import { message } from 'ant-design-vue'
<% if (searchCount > 0) { %>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { %>
<% if (configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') { %>
import tool from '@/utils/tool'
<% } %>
<% } %>
<% } %>
<% } %>
import Form from './form.vue'
import ${classNameFirstLower}Api from '@/api/${moduleName}/${classNameFirstLower}Api'
<% if (searchCount > 0) { %>
let searchFormState = reactive({})
const searchFormRef = ref()
<% } %>
const table = ref()
const formRef = ref()
const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
<% if(searchCount > 3) { %>
// 查询区域显示更多控制
const advanced = ref(false)
const toggleAdvanced = () => {
advanced.value = !advanced.value
}
<% } %>
const columns = [
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherTable) { %>
{
title: '${configList[i].fieldRemark}',
dataIndex: '${configList[i].fieldNameCamelCase}'<% if(configList[i].whetherRetract) { %>,<% } %>
<% if(configList[i].whetherRetract) { %>
ellipsis: true
<% } %>
},
<% } %>
<% } %>
]
// 操作栏通过权限判断是否显示
if (hasPerm(['${classNameFirstLower}Edit', '${classNameFirstLower}Delete'])) {
columns.push({
title: '操作',
dataIndex: 'action',
align: 'center',
width: '150px'
})
}
let selectedRowKeys = ref([])
// 列表选择配置
const options = {
alert: {
show: false,
clear: () => {
selectedRowKeys = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
const loadData = (parameter) => {
<% if (searchCount > 0) { %>
const searchFormParam = JSON.parse(JSON.stringify(searchFormState))
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { %>
<% if (configList[i].effectType == 'datepicker') {%>
// ${configList[i].fieldNameCamelCase}范围查询条件重载
if (searchFormParam.${configList[i].fieldNameCamelCase}) {
searchFormParam.start${configList[i].fieldNameCamelCaseFirstUpper} = searchFormParam.${configList[i].fieldNameCamelCase}[0]
searchFormParam.end${configList[i].fieldNameCamelCaseFirstUpper} = searchFormParam.${configList[i].fieldNameCamelCase}[1]
delete searchFormParam.${configList[i].fieldNameCamelCase}
}
<% } %>
<% } %>
<% } %>
return ${classNameFirstLower}Api.${classNameFirstLower}Page(Object.assign(parameter, searchFormParam)).then((data) => {
<% } else { %>
return ${classNameFirstLower}Api.${classNameFirstLower}Page(parameter).then((data) => {
<% } %>
return data
})
}
// 删除
const delete${className} = (record) => {
let params = [
{
id: record.id
}
]
${classNameFirstLower}Api.${classNameFirstLower}Delete(params).then(() => {
table.value.refresh(true)
})
}
// 批量删除
const deleteBatch${className} = () => {
if (selectedRowKeys.value.length < 1) {
message.warning('请选择一条或多条数据')
return false
}
const params = selectedRowKeys.value.map((m) => {
return {
id: m
}
})
${classNameFirstLower}Api.${classNameFirstLower}Delete(params).then(() => {
table.value.clearRefreshSelected()
})
}
<% if (searchCount > 0) { %>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { %>
<% if (configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') { %>
const ${configList[i].fieldNameCamelCase}Options = tool.dictList('${configList[i].dictTypeCode}')
<% } %>
<% } %>
<% } %>
<% } %>
</script>

View File

@ -0,0 +1,14 @@
/*
Source Server Type : MySQL
Date: ${genTime}
*/
INSERT INTO `SYS_RESOURCE` VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, 2, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, 3, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `SYS_RESOURCE` VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, 4, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -0,0 +1,14 @@
/*
Source Server Type: Oracle
Date: ${genTime}
*/
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${menuId}', '${parentId}', '${functionName}管理', '${busName}', '${menuCode}', 'MENU', '${moduleId}', 'MENU', '${menuPath}', '${menuComponent}', NULL, NULL, '99', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', NULL, '${classNameFirstLower}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, '1', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${batchDeleteButtonId}', '${menuId}', '批量删除${functionName}', NULL, '${classNameFirstLower}BatchDelete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, '2', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', NULL, '${classNameFirstLower}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, '3', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', NULL, '${classNameFirstLower}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, '4', NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -0,0 +1,39 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.modular.resource.provider;
import org.springframework.stereotype.Service;
import vip.xiaonuo.sys.api.SysButtonApi;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.modular.resource.service.SysButtonService;
import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
import javax.annotation.Resource;
/**
* API
*
* @author xuyuxiang
* @date 2022/11/1 13:50
**/
@Service
public class SysButtonApiProvider implements SysButtonApi {
@Resource
private SysButtonService sysButtonService;
@Override
public void addForGenButton(String menuId, String className, String functionName) {
sysButtonService.addForGenButton(menuId, className, functionName);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.modular.resource.provider;
import org.springframework.stereotype.Service;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
import javax.annotation.Resource;
/**
* API
*
* @author xuyuxiang
* @date 2022/11/1 13:50
**/
@Service
public class SysMenuApiProvider implements SysMenuApi {
@Resource
private SysMenuService sysMenuService;
@Override
public String addForGenMenu(String parentId, String busName, String module, String title, String path) {
return sysMenuService.addForGenMenu(parentId, busName, title, module, path);
}
}

View File

@ -46,6 +46,15 @@ public interface SysButtonService extends IService<SysButton> {
*/
void add(SysButtonAddParam sysButtonAddParam);
/**
*
*
* @author xuyuxiang
* @date 2022/11/1 15:34
* @return java.lang.String
**/
void addForGenButton(String menuId, String className, String functionName);
/**
*
*

View File

@ -54,6 +54,14 @@ public interface SysMenuService extends IService<SysMenu> {
*/
void add(SysMenuAddParam sysMenuAddParam);
/**
*
*
* @author xuyuxiang
* @date 2022/11/1 14:06
**/
String addForGenMenu(String parentId, String busName, String title, String module, String path);
/**
*
*

View File

@ -96,6 +96,21 @@ public class SysButtonServiceImpl extends ServiceImpl<SysButtonMapper, SysButton
this.save(sysButton);
}
@Override
public void addForGenButton(String menuId, String className, String functionName) {
SysMenu sysMenu = sysMenuService.queryEntity(menuId);
String classNameFirstLower = StrUtil.lowerFirst(className);
CollectionUtil.newArrayList(JSONUtil.createObj().set("title", "新增" + functionName).set("code", classNameFirstLower + "Add").set("sortCode", 1),
JSONUtil.createObj().set("title", "编辑" + functionName).set("code", classNameFirstLower + "Edit").set("sortCode", 2),
JSONUtil.createObj().set("title", "删除" + functionName).set("code", classNameFirstLower + "Delete").set("sortCode", 3),
JSONUtil.createObj().set("title", "批量删除").set("code", classNameFirstLower + "BatchDelete").set("sortCode", 4)).forEach(jsonObject -> {
SysButtonAddParam sysButtonAddParam = new SysButtonAddParam();
BeanUtil.copyProperties(jsonObject, sysButtonAddParam);
sysButtonAddParam.setParentId(sysMenu.getId());
this.add(sysButtonAddParam);
});
}
@Override
public void edit(SysButtonEditParam sysButtonEditParam) {
SysButton sysButton = this.queryEntity(sysButtonEditParam.getId());

View File

@ -28,6 +28,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
@ -125,6 +126,45 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
this.save(sysMenu);
}
@Transactional(rollbackFor = Exception.class)
@Override
public String addForGenMenu(String parentId, String busName, String title, String module, String path) {
// 参数校验
if(!parentId.equals("0")) {
SysMenu parentMenu = this.queryEntity(parentId);
if(ObjectUtil.isEmpty(parentMenu)) {
throw new CommonException("上级菜单不存在id值为{}", parentId);
}
if(!parentMenu.getModule().equals(module)) {
throw new CommonException("module与上级菜单不一致");
}
}
// 删除老菜单(同时删除其下面的菜单、按钮,清除对应的角色与资源信息
SysMenu sysOldMenu = this.getOne(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getTitle, title)
.eq(SysMenu::getCategory, SysResourceCategoryEnum.MENU.getValue())
.eq(SysMenu::getMenuType, SysResourceMenuTypeEnum.MENU.getValue()).eq(SysMenu::getPath, path));
if(ObjectUtil.isNotEmpty(sysOldMenu)) {
SysMenuIdParam sysMenuIdParam = new SysMenuIdParam();
sysMenuIdParam.setId(sysOldMenu.getId());
this.delete(CollectionUtil.newArrayList(sysMenuIdParam));
}
// 插入新菜单
SysMenu sysMenu = new SysMenu();
sysMenu.setParentId(parentId);
sysMenu.setTitle(title);
sysMenu.setName(busName);
sysMenu.setCode(RandomUtil.randomString(10));
sysMenu.setCategory(SysResourceCategoryEnum.MENU.getValue());
sysMenu.setModule(module);
sysMenu.setMenuType(SysResourceMenuTypeEnum.MENU.getValue());
sysMenu.setPath(path);
sysMenu.setComponent(StrUtil.removePrefix(path, StrUtil.SLASH) + StrUtil.SLASH + "index");
sysMenu.setIcon("appstore-outlined");
sysMenu.setSortCode(99);
this.save(sysMenu);
return sysMenu.getId();
}
private void checkParam(SysMenuAddParam sysMenuAddParam) {
SysResourceMenuTypeEnum.validate(sysMenuAddParam.getMenuType());
if(SysResourceMenuTypeEnum.MENU.getValue().equals(sysMenuAddParam.getMenuType())) {

View File

@ -12,12 +12,26 @@
*/
package vip.xiaonuo.sys.modular.role.provider;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.sys.api.SysRoleApi;
import vip.xiaonuo.sys.core.enums.SysBuildInEnum;
import vip.xiaonuo.sys.modular.relation.entity.SysRelation;
import vip.xiaonuo.sys.modular.relation.enums.SysRelationCategoryEnum;
import vip.xiaonuo.sys.modular.relation.service.SysRelationService;
import vip.xiaonuo.sys.modular.resource.entity.SysButton;
import vip.xiaonuo.sys.modular.resource.entity.SysMenu;
import vip.xiaonuo.sys.modular.resource.enums.SysResourceCategoryEnum;
import vip.xiaonuo.sys.modular.resource.service.SysButtonService;
import vip.xiaonuo.sys.modular.resource.service.SysMenuService;
import vip.xiaonuo.sys.modular.role.entity.SysRole;
import vip.xiaonuo.sys.modular.role.enums.SysRoleCategoryEnum;
import vip.xiaonuo.sys.modular.role.param.SysRoleGrantResourceParam;
import vip.xiaonuo.sys.modular.role.param.SysRoleSelectorRoleParam;
import vip.xiaonuo.sys.modular.role.service.SysRoleService;
@ -37,6 +51,15 @@ public class SysRoleApiProvider implements SysRoleApi {
@Resource
private SysRoleService sysRoleService;
@Resource
private SysMenuService sysMenuService;
@Resource
private SysButtonService sysButtonService;
@Resource
private SysRelationService sysRelationService;
@Override
public boolean orgHasRole(List<String> orgIdList) {
return sysRoleService.count(new LambdaQueryWrapper<SysRole>().in(SysRole::getOrgId, orgIdList)) > 0;
@ -50,4 +73,34 @@ public class SysRoleApiProvider implements SysRoleApi {
sysRoleSelectorRoleParam.setSearchKey(searchKey);
return sysRoleService.roleSelector(sysRoleSelectorRoleParam).stream().map(JSONUtil::parseObj).collect(Collectors.toList());
}
@Transactional(rollbackFor = Exception.class)
@Override
public void grantForGenMenuAndButton(String menuId) {
String superAdminRoleId = sysRoleService.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getCode, SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue())
.eq(SysRole::getCategory, SysRoleCategoryEnum.GLOBAL.getValue())).getId();
SysRoleGrantResourceParam sysRoleGrantResourceParam = new SysRoleGrantResourceParam();
sysRoleGrantResourceParam.setId(superAdminRoleId);
SysMenu sysMenu = sysMenuService.queryEntity(menuId);
SysRoleGrantResourceParam.SysRoleGrantResource sysRoleGrantResource = new SysRoleGrantResourceParam.SysRoleGrantResource();
sysRoleGrantResource.setMenuId(sysMenu.getId());
List<String> buttonIdList = sysButtonService.list(new LambdaQueryWrapper<SysButton>().eq(SysButton::getParentId,
sysMenu.getId()).eq(SysButton::getCategory, SysResourceCategoryEnum.BUTTON.getValue())).stream()
.map(SysButton::getId).collect(Collectors.toList());
sysRoleGrantResource.setButtonInfo(buttonIdList);
sysRoleGrantResourceParam.setGrantInfoList(CollectionUtil.newArrayList(sysRoleGrantResource));
List<String> menuIdList = sysRoleGrantResourceParam.getGrantInfoList().stream()
.map(SysRoleGrantResourceParam.SysRoleGrantResource::getMenuId).collect(Collectors.toList());
List<String> extJsonList = sysRoleGrantResourceParam.getGrantInfoList().stream()
.map(JSONUtil::toJsonStr).collect(Collectors.toList());
List<String> existMenuIdList = sysMenuService.list(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getCategory,
SysResourceCategoryEnum.MENU.getValue())).stream().map(SysMenu::getId).collect(Collectors.toList());
if(ObjectUtil.isNotEmpty(existMenuIdList)) {
sysRelationService.remove(new LambdaQueryWrapper<SysRelation>().eq(SysRelation::getObjectId, superAdminRoleId)
.eq(SysRelation::getCategory, SysRelationCategoryEnum.SYS_ROLE_HAS_RESOURCE.getValue()).notIn(SysRelation::getTargetId, existMenuIdList));
}
sysRelationService.saveRelationBatchWithAppend(superAdminRoleId, menuIdList, SysRelationCategoryEnum.SYS_ROLE_HAS_RESOURCE.getValue(), extJsonList);
}
}

View File

@ -120,6 +120,13 @@
<version>${project.parent.version}</version>
</dependency>
<!-- 代码生成插件 -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-gen</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- 系统功能插件 -->
<dependency>
<groupId>vip.xiaonuo</groupId>