【新增】新增移动端【压缩包】代码生成,mysql数据库gen_basic表更新,但Oracle未更新

pull/135/MERGE
877617829 2023-07-16 15:28:58 +08:00
parent 266c0ffbf5
commit 50c953709c
25 changed files with 861 additions and 33 deletions

View File

@ -41,5 +41,9 @@ export default {
// 预览代码生成
basicPreviewGen(data) {
return request('previewGen', data, 'get')
},
// 获取所有移动端模块
basicMobileModuleSelector(data) {
return request('mobileModuleSelector', data, 'get')
}
}

View File

@ -36,7 +36,14 @@
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="生成方式:" name="generateType">
<a-form-item name="generateType">
<template #label>
<a-tooltip>
<template #title>移动端代码生成目前只支持压缩包方式</template>
<question-circle-outlined />
生成方式
</a-tooltip>
</template>
<a-radio-group v-model:value="formData.generateType" :options="generateTypeOptions"> </a-radio-group>
</a-form-item>
</a-col>
@ -72,6 +79,17 @@
></a-tree-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="移动端所属模块:" name="mobileModule">
<a-select
v-model:value="formData.mobileModule"
:options="mobileModuleList"
style="width: 100%"
placeholder="请选择移动端所属模块"
>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item name="pluginName">
<template #label>
@ -172,6 +190,7 @@
//
const formData = ref({})
//
const mobileModuleList = ref([])
const tableList = ref([])
const tableColumns = ref([])
const menuTreeData = ref([])
@ -266,6 +285,22 @@
}
}
})
//
submitLoading.value = true
genBasicApi
.basicMobileModuleSelector()
.then((data) => {
mobileModuleList.value = data.map((item) => {
return {
value: item['id'],
label: item['name']
}
})
})
.finally(() => {
submitLoading.value = false
})
}
//
const formRules = {
@ -277,6 +312,7 @@
generateType: [required('请选择生成方式')],
module: [required('请选择所属模块')],
menuPid: [required('请选择上级目录')],
mobileModule: [required('请选择移动端所属模块')],
functionName: [required('请输入功能名')],
busName: [required('请输入业务名')],
className: [required('请输入类名')],

View File

@ -54,6 +54,11 @@
codeTypeTitle: '前端代码',
codeTypeList: data.genBasicCodeFrontendResultList
},
{
codeTypeKey: 'mobile',
codeTypeTitle: '移动端代码',
codeTypeList: data.genBasicCodeMobileResultList
},
{
codeTypeKey: 'backend',
codeTypeTitle: '后端代码',
@ -85,9 +90,12 @@
onOpen
})
</script>
<style type="less" scoped>
<style lang="less" scoped>
.gen-preview-content {
height: calc(100vh - 160px);
overflow: auto;
}
:deep(.hljs) {
max-height: 600px!important;
}
</style>

View File

@ -0,0 +1,33 @@
/*
* 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.mobile.api;
import cn.hutool.json.JSONObject;
import java.util.List;
/**
* API
*
* @author xuyuxiang
* @date 2023/1/31 10:09
**/
public interface MobileModuleApi {
/**
*
*
* @author xuyuxiang
* @date 2023/7/15 22:01
**/
List<JSONObject> mobileModuleSelector();
}

View File

@ -27,6 +27,12 @@
<artifactId>snowy-plugin-sys-api</artifactId>
</dependency>
<!-- 引入移动端接口,用于选择模块功能 -->
<dependency>
<groupId>vip.xiaonuo</groupId>
<artifactId>snowy-plugin-mobile-api</artifactId>
</dependency>
<!-- beetl模板引擎 -->
<dependency>
<groupId>com.ibeetl</groupId>

View File

@ -28,6 +28,7 @@ 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.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
@ -193,5 +194,18 @@ public class GenBasicController {
public CommonResult<GenBasicPreviewResult> previewGen(@Valid GenBasicIdParam genBasicIdParam) {
return CommonResult.data(genBasicService.previewGen(genBasicIdParam));
}
/**
*
*
* @author
* @date 2023/7/15 22:36
*/
@ApiOperationSupport(order = 11)
@ApiOperation("获取所有移动端模块")
@GetMapping("/gen/basic/mobileModuleSelector")
public CommonResult<List<GenBasicMobileModuleSelectorResult>> mobileModuleSelector() {
return CommonResult.data(genBasicService.mobileModuleSelector());
}
}

View File

@ -65,35 +65,39 @@ public class GenBasic extends CommonEntity {
@ApiModelProperty(value = "上级目录", position = 9)
private String menuPid;
/** 移动端所属模块 */
@ApiModelProperty(value = "移动端所属模块", position = 10)
private String mobileModule;
/** 功能名 */
@ApiModelProperty(value = "功能名", position = 10)
@ApiModelProperty(value = "功能名", position = 11)
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", position = 11)
@ApiModelProperty(value = "业务名", position = 12)
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", position = 12)
@ApiModelProperty(value = "类名", position = 13)
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", position = 13)
@ApiModelProperty(value = "表单布局", position = 14)
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", position = 14)
@ApiModelProperty(value = "使用栅格", position = 15)
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", position = 15)
@ApiModelProperty(value = "排序", position = 16)
private Integer sortCode;
/** 包名 */
@ApiModelProperty(value = "包名", position = 16)
@ApiModelProperty(value = "包名", position = 17)
private String packageName;
/** 作者 */
@ApiModelProperty(value = "作者", position = 17)
@ApiModelProperty(value = "作者", position = 18)
private String authorName;
}

View File

@ -68,41 +68,46 @@ public class GenBasicAddParam {
@NotNull(message = "menuPid不能为空")
private String menuPid;
/** 移动端所属模块 */
@ApiModelProperty(value = "移动端所属模块", required = true, position = 9)
@NotNull(message = "mobileModule不能为空")
private String mobileModule;
/** 功能名 */
@ApiModelProperty(value = "功能名", required = true, position = 8)
@ApiModelProperty(value = "功能名", required = true, position = 10)
@NotNull(message = "functionName不能为空")
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", required = true, position = 10)
@ApiModelProperty(value = "业务名", required = true, position = 11)
@NotNull(message = "busName不能为空")
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", required = true, position = 11)
@ApiModelProperty(value = "类名", required = true, position = 12)
@NotNull(message = "className不能为空")
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", required = true, position = 12)
@ApiModelProperty(value = "表单布局", required = true, position = 13)
@NotNull(message = "formLayout不能为空")
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", required = true, position = 13)
@ApiModelProperty(value = "使用栅格", required = true, position = 14)
@NotNull(message = "gridWhether不能为空")
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", required = true, position = 14)
@ApiModelProperty(value = "排序", required = true, position = 15)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/** 作者名 */
@ApiModelProperty(value = "作者名", required = true, position = 15)
@ApiModelProperty(value = "作者名", required = true, position = 16)
private String authorName;
/** 包名 */
@ApiModelProperty(value = "包名", required = true, position = 16)
@ApiModelProperty(value = "包名", required = true, position = 17)
private String packageName;
}

View File

@ -29,17 +29,17 @@ import javax.validation.constraints.NotNull;
public class GenBasicEditParam {
/** id */
@ApiModelProperty(value = "id", position = 1)
@ApiModelProperty(value = "id", required = true, position = 1)
@NotNull(message = "id不能为空")
private String id;
/** 主表名称 */
@ApiModelProperty(value = "主表名称", position = 2)
@ApiModelProperty(value = "主表名称", required = true, position = 2)
@NotNull(message = "dbTable不能为空")
private String dbTable;
/** 主表主键 */
@ApiModelProperty(value = "主表主键", position = 3)
@ApiModelProperty(value = "主表主键", required = true, position = 3)
@NotNull(message = "dbTableKey不能为空")
private String dbTableKey;
@ -54,61 +54,66 @@ public class GenBasicEditParam {
private String moduleName;
/** 表前缀移除 */
@ApiModelProperty(value = "表前缀移除", position = 6)
@ApiModelProperty(value = "表前缀移除", required = true, position = 6)
@NotNull(message = "tablePrefix不能为空")
private String tablePrefix;
/** 生成方式 */
@ApiModelProperty(value = "生成方式", position = 7)
@ApiModelProperty(value = "生成方式", required = true, position = 7)
@NotNull(message = "generateType不能为空")
private String generateType;
/** 所属模块 */
@ApiModelProperty(value = "所属模块", position = 8)
@ApiModelProperty(value = "所属模块", required = true, position = 8)
@NotNull(message = "module不能为空")
private String module;
/** 上级目录 */
@ApiModelProperty(value = "上级目录", position = 9)
@ApiModelProperty(value = "上级目录", required = true, position = 9)
@NotNull(message = "menuPid不能为空")
private String menuPid;
/** 移动端所属模块 */
@ApiModelProperty(value = "移动端所属模块", required = true, position = 10)
@NotNull(message = "mobileModule不能为空")
private String mobileModule;
/** 功能名 */
@ApiModelProperty(value = "功能名", position = 10)
@ApiModelProperty(value = "功能名", required = true, position = 11)
@NotNull(message = "functionName不能为空")
private String functionName;
/** 业务名 */
@ApiModelProperty(value = "业务名", position = 11)
@ApiModelProperty(value = "业务名", required = true, position = 12)
@NotNull(message = "busName不能为空")
private String busName;
/** 类名 */
@ApiModelProperty(value = "类名", position = 12)
@ApiModelProperty(value = "类名", required = true, position = 13)
@NotNull(message = "className不能为空")
private String className;
/** 表单布局 */
@ApiModelProperty(value = "表单布局", position = 13)
@ApiModelProperty(value = "表单布局", required = true, position = 14)
@NotNull(message = "formLayout不能为空")
private String formLayout;
/** 使用栅格 */
@ApiModelProperty(value = "使用栅格", position = 14)
@ApiModelProperty(value = "使用栅格", required = true, position = 15)
@NotNull(message = "gridWhether不能为空")
private String gridWhether;
/** 排序 */
@ApiModelProperty(value = "排序", position = 15)
@ApiModelProperty(value = "排序", required = true, position = 16)
@NotNull(message = "sortCode不能为空")
private Integer sortCode;
/** 作者名 */
@ApiModelProperty(value = "作者名", required = true, position = 16)
@ApiModelProperty(value = "作者名", required = true, position = 17)
@NotNull(message = "authorName不能为空")
private String authorName;
/** 包名 */
@ApiModelProperty(value = "包名 */", position = 17)
@ApiModelProperty(value = "包名 */", required = true, position = 17)
private String packageName;
}

View File

@ -0,0 +1,23 @@
package vip.xiaonuo.gen.modular.basic.result;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author
* @date 2023/7/15 22:28
**/
@Getter
@Setter
public class GenBasicMobileModuleSelectorResult {
/** id */
@ApiModelProperty(value = "id", position = 1)
private String id;
/** 名称 */
@ApiModelProperty(value = "名称", position = 2)
private String name;
}

View File

@ -40,6 +40,10 @@ public class GenBasicPreviewResult {
@ApiModelProperty(value = "后端代码结果集", position = 3)
private List<GenBasicCodeResult> genBasicCodeBackendResultList;
/** 前端代码结果集 */
@ApiModelProperty(value = "移动端代码结果集", position = 4)
private List<GenBasicCodeResult> genBasicCodeMobileResultList;
@Getter
@Setter
public static class GenBasicCodeResult {

View File

@ -16,6 +16,7 @@ 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.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
@ -119,4 +120,12 @@ public interface GenBasicService extends IService<GenBasic> {
* @date 2022/10/28 17:08
**/
GenBasicPreviewResult previewGen(GenBasicIdParam genBasicIdParam);
/**
*
*
* @author
* @date 2023/7/15 22:28
**/
List<GenBasicMobileModuleSelectorResult> mobileModuleSelector();
}

View File

@ -49,6 +49,7 @@ 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.GenBasicMobileModuleSelectorResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicPreviewResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableColumnResult;
import vip.xiaonuo.gen.modular.basic.result.GenBasicTableResult;
@ -56,6 +57,7 @@ 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.mobile.api.MobileModuleApi;
import vip.xiaonuo.sys.api.SysButtonApi;
import vip.xiaonuo.sys.api.SysMenuApi;
import vip.xiaonuo.sys.api.SysRoleApi;
@ -69,6 +71,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* Service
@ -98,6 +101,15 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
JSONUtil.createObj().set("name", "form.vue.btl").set("path", "views"),
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "views"));
private static final List<JSONObject> GEN_MOBILE_FILE_LIST = CollectionUtil.newArrayList(
JSONUtil.createObj().set("name", "page.json.btl"),
JSONUtil.createObj().set("name", "Api.js.btl").set("path", "api"),
JSONUtil.createObj().set("name", "search.vue.btl").set("path", "pages"),
JSONUtil.createObj().set("name", "form.vue.btl").set("path", "pages"),
JSONUtil.createObj().set("name", "more.vue.btl").set("path", "pages"),
JSONUtil.createObj().set("name", "index.vue.btl").set("path", "pages"));
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"),
@ -141,6 +153,9 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
@Resource
private SysRoleApi sysRoleApi;
@Resource
private MobileModuleApi mobileModuleApi;
@Override
public Page<GenBasic> page(GenBasicPageParam genBasicPageParam) {
QueryWrapper<GenBasic> queryWrapper = new QueryWrapper<>();
@ -443,6 +458,10 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
genBasicPreviewResult.getGenBasicCodeBackendResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "backend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
// 生成移动端代码到临时目录
genBasicPreviewResult.getGenBasicCodeMobileResultList().forEach(genBasicCodeResult ->
FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+ "mobile" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
return tempFolder;
}
@ -520,6 +539,37 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
genBasicCodeBackendResultList.add(genBasicCodeBackendResult);
});
genBasicPreviewResult.setGenBasicCodeBackendResultList(genBasicCodeBackendResultList);
// 移动端基础路径
String genMobileBasicPath = "";
// 移动端
GroupTemplate groupTemplateMobile = new GroupTemplate(new ClasspathResourceLoader("mobile"), Configuration.defaultConfiguration());
List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeMobileResultList = CollectionUtil.newArrayList();
GEN_MOBILE_FILE_LIST.forEach(fileJsonObject -> {
String fileTemplateName = fileJsonObject.getStr("name");
String fileTemplatePath = "";
if (!"page.json.btl".equals(fileTemplateName)){
fileTemplatePath = fileJsonObject.getStr("path") + File.separator + genBasic.getModuleName();
}
GenBasicPreviewResult.GenBasicCodeResult genBasicCodeMobileResult = new GenBasicPreviewResult.GenBasicCodeResult();
Template templateMobile = groupTemplateMobile.getTemplate(fileTemplateName);
templateMobile.binding(bindingJsonObject);
String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
if(fileTemplateName.equalsIgnoreCase("Api.js.btl")) {
resultName = StrUtil.lowerFirst(genBasic.getClassName()) + resultName;
genBasicCodeMobileResult.setCodeFileName(resultName);
genBasicCodeMobileResult.setCodeFileWithPathName(genMobileBasicPath + fileTemplatePath + File.separator + resultName);
} else if("page.json.btl".equals(fileTemplateName)) {
genBasicCodeMobileResult.setCodeFileName(resultName);
genBasicCodeMobileResult.setCodeFileWithPathName(genMobileBasicPath + fileTemplatePath + File.separator + resultName);
} else {
genBasicCodeMobileResult.setCodeFileName(resultName);
genBasicCodeMobileResult.setCodeFileWithPathName(genMobileBasicPath + fileTemplatePath + File.separator + genBasic.getBusName() + File.separator + resultName);
}
genBasicCodeMobileResult.setCodeFileContent(templateMobile.render());
genBasicCodeMobileResultList.add(genBasicCodeMobileResult);
});
genBasicPreviewResult.setGenBasicCodeMobileResultList(genBasicCodeMobileResultList);
} catch (Exception e) {
log.error(">>> 代码生成异常:", e);
throw new CommonException("代码生成异常");
@ -527,6 +577,17 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
return genBasicPreviewResult;
}
/**
*
* @author
* @date 2023/7/15 22:38
*/
@Override
public List<GenBasicMobileModuleSelectorResult> mobileModuleSelector() {
return mobileModuleApi.mobileModuleSelector().stream()
.map(jsonObject -> JSONUtil.toBean(jsonObject, GenBasicMobileModuleSelectorResult.class)).collect(Collectors.toList());
}
/**
*
*
@ -575,6 +636,8 @@ public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> i
bindingJsonObject.set("menuComponent", genBasic.getModuleName() + StrUtil.SLASH + genBasic.getBusName() + StrUtil.SLASH + "index");
// 模块ID
bindingJsonObject.set("moduleId", genBasic.getModule());
// 移动端模块ID
bindingJsonObject.set("mobileModuleId", genBasic.getMobileModule());
// 添加按钮ID
bindingJsonObject.set("addButtonId", IdWorker.getIdStr());
// 编辑按钮ID

View File

@ -0,0 +1,42 @@
import request from '@/utils/request'
// 获取${functionName}分页
export function ${classNameFirstLower}Page(data) {
return request({
url: '/${moduleName}/${busName}/page',
method: 'get',
data: data
})
}
// 获取${functionName}列表
export function ${classNameFirstLower}List(data) {
return request({
url: '/${moduleName}/${busName}/list',
method: 'get',
data: data
})
}
// 提交${functionName}表单 add为false时为编辑默认为新增
export function ${classNameFirstLower}SubmitForm(data, add = true) {
return request({
url: '/${moduleName}/${busName}/'+ (add ? 'add' : 'edit'),
method: 'post',
data: data
})
}
// 删除${functionName}
export function ${classNameFirstLower}Delete(data) {
return request({
url: '/${moduleName}/${busName}/delete',
method: 'post',
data: data
})
}
// 获取${functionName}详情
export function ${classNameFirstLower}Detail(data) {
return request({
url: '/${moduleName}/${busName}/detail',
method: 'get',
data: data
})
}

View File

@ -0,0 +1,119 @@
<template>
<view class="container">
<uni-forms ref="formRef" :model="formData" label-position="top" :rules="rules" validate-trigger="blur" labelWidth="100px">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherAddUpdate && configList[i].fieldNameCamelCase != 'tenantId') { %>
<% if(configList[i].effectType == 'input') { %>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请输入${configList[i].fieldRemark}' }]">
<uni-easyinput v-model="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}"></uni-easyinput>
</uni-forms-item>
<% } else if (configList[i].effectType == 'textarea') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请输入${configList[i].fieldRemark}' }]">
<uni-easyinput type="textarea" v-model="formData.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}"></uni-easyinput>
</uni-forms-item>
<% } else if (configList[i].effectType == 'select') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请输入${configList[i].fieldRemark}' }]">
<snowy-sel-picker :map="{key: 'value', label: 'text'}" v-model="formData.${configList[i].fieldNameCamelCase}" :rangeData="${configList[i].fieldNameCamelCase}Options" placeholder="请选择${configList[i].fieldRemark}"></snowy-sel-picker>
</uni-forms-item>
<% } else if (configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请选择${configList[i].fieldRemark}' }]">
<uni-data-checkbox :multiple="${configList[i].effectType == 'checkbox'?true:false}" :map="{key: 'value', label: 'text'}" v-model="searchFormState.${configList[i].fieldNameCamelCase}" :rangeData="${configList[i].fieldNameCamelCase}Options" placeholder="请选择${configList[i].fieldRemark}"> </uni-data-checkbox>
</uni-forms-item>
<% } else if (configList[i].effectType == 'datepicker' || configList[i].effectType == 'timepicker') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请选择${configList[i].fieldRemark}' }]">
<uni-datetime-picker type=${configList[i].effectType == 'timepicker'?'datetime':'date'} v-model="formData.${configList[i].fieldNameCamelCase}" > </uni-datetime-picker>
</uni-forms-item>
<% } else if (configList[i].effectType == 'inputNumber') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请输入${configList[i].fieldRemark}' }]">
<uni-number-box v-model="formData.${configList[i].fieldNameCamelCase}" :min="1" :max="100"></uni-number-box>
</uni-forms-item>
<% } else if (configList[i].effectType == 'slider') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}" :required="${configList[i].required}" :rules="[{ required: ${configList[i].required}, errorMessage: '请输入${configList[i].fieldRemark}' }]">
<slider :value="formData.${configList[i].fieldNameCamelCase}" :min="1" :max="100" :step="1" @change="(e)=>{formData.${configList[i].fieldNameCamelCase} = e.detail.value}"></slider>
</uni-forms-item>
<% } %>
<% } %>
<% } %>
</uni-forms>
<button class="btn-sub" type="primary" @click="submit">提交</button>
</view>
</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 '@/plugins/tool'
import SnowySelPicker from '@/components/snowy-sel-picker.vue'
<% } %>
import XEUtils from "xe-utils"
import { onLoad } from "@dcloudio/uni-app"
import { ${classNameFirstLower}Detail, ${classNameFirstLower}SubmitForm } from '@/api/${moduleName}/${classNameFirstLower}Api'
import { reactive, ref, getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance()
const formRef = ref()
const formData = ref({})
// 常用正则规则大全https://any86.github.io/any-rule/
// 去pages/biz/user/form.vue中寻找示例
const rules = reactive({
})
<% 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([])
<% } %>
<% } %>
<% } %>
onLoad((option) => {
<% 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}')
<% } %>
<% } %>
<% } %>
if(!option.id){
return
}
${classNameFirstLower}Detail({
id: option.id
}).then(res => {
formData.value = res?.data
})
})
const submit = () => {
formRef.value.validate().then(res => {
${classNameFirstLower}SubmitForm(formData.value, !formData.value.id).then(respond => {
uni.$emit('formBack', {
data: respond.data
})
uni.navigateBack({
delta: 1
})
})
})
}
</script>
<style lang="scss" scoped>
.container {
margin: 15upx;
border-radius: 5upx;
padding: 25upx;
background-color: $uni-white;
.btn-sub {
background-color: $uni-primary;
}
}
</style>

View File

@ -0,0 +1,157 @@
<template>
<%
var searchCount = 0;
var row = 0;
%>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { searchCount ++; }%>
<% } %>
<view>
<% if (searchCount > 0) { %>
<view class="sticky">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { row ++; %>
<% if(row <= 1) { %>
<uni-row>
<view style="display: flex; align-items: center; justify-content: center;">
<uni-col :span="22">
<uni-search-bar v-model="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}" @confirm="loadData(true)" cancelButton="none"></uni-search-bar>
</uni-col>
<uni-col :span="2">
<view style="color: #2979ff;" @click="$refs.searchRef.open()">
<text>高级\n搜索</text>
</view>
</uni-col>
</view>
</uni-row>
<% } %>
<% } %>
<% } %>
</view>
<search ref="searchRef" :searchFormState="searchFormState" @confirm="loadData(true)"></search>
<% } %>
<view class="${busName}-list">
<uni-list>
<uni-list-item v-for="(item, index) in ${classNameFirstLower}Data" :key="index" :showArrow="false" :clickable="true" @tap="moreTapItem(item, index)">
<template v-slot:body>
<view class="item">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].whetherTable && configList[i].fieldNameCamelCase != 'tenantId') { %>
<view class="item-row">
<uni-row>
<uni-col :span="4">
<view class="item-row-title">${configList[i].fieldRemark}</view>
</uni-col>
<uni-col :span="20">
<view class="item-row-content">{{ item.${configList[i].fieldNameCamelCase} }}</view>
</uni-col>
</uni-row>
</view>
<% } %>
<% } %>
</view>
</template>
</uni-list-item>
</uni-list>
<snowy-empty v-if="$utils.isEmpty(${classNameFirstLower}Data)" />
</view>
<!-- 新增悬浮按钮 -->
<uni-fab
v-if="hasPerm('mobile${className}Add')"
horizontal="right"
vertical="bottom"
direction="horizontal"
@fabClick="add"
:pattern="{
color: '#7A7E83',
backgroundColor: '#fff',
selectedColor: '#007AFF',
buttonColor: '#007AFF',
iconColor: '#fff'
}">
</uni-fab>
<more ref="moreRef" @handleOk="loadData(true)"></more>
</view>
</template>
<script setup name="${busName}">
<% if (searchCount > 0) { %>
import search from './search.vue'
<% } %>
import SnowyEmpty from "@/components/snowy-empty.vue"
import { ${classNameFirstLower}Page } from '@/api/${moduleName}/${classNameFirstLower}Api'
import more from './more.vue'
import XEUtils from 'xe-utils'
import { onLoad, onShow, onReady, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app"
import { reactive, ref, getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance()
const searchFormState = reactive({})
const parameter = reactive({
current: 1,
size: 10
})
const ${classNameFirstLower}Data = ref([])
const loadData = (isReset) => {
if (isReset) {
parameter.current = 1
${classNameFirstLower}Data.value = []
}
Object.assign(parameter, searchFormState)
${classNameFirstLower}Page(parameter).then(res => {
if (XEUtils.isEmpty(res?.data?.records)){
return
}
${classNameFirstLower}Data.value = ${classNameFirstLower}Data.value.concat(res.data.records)
parameter.current++
}).finally(()=>{
uni.stopPullDownRefresh()
})
}
loadData(true)
onShow(() => {
uni.$once('formBack', (data) => {
loadData(true)
})
})
// 下拉刷新
onPullDownRefresh(() => {
loadData(true)
})
// 上拉加载
onReachBottom(() => {
loadData()
})
// 新增
const add = () => {
uni.navigateTo({
url: '/pages/${moduleName}/${busName}/form'
})
}
// 更多操作
const moreRef = ref()
const moreClick = (record) => {
moreRef.value.open(record)
}
</script>
<style lang="scss" scoped>
.${classNameFirstLower}-list {
margin: 15upx;
border-radius: 5upx;
.item {
width: 100vw;
.item-row {
margin: 20upx 10upx;
.item-row-title {
font-size: 25upx;
color: #999;
}
.item-row-content {
font-size: 25upx;
text-align: right;
}
}
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<uni-popup ref="popupRef" type="bottom" safeArea>
<view class="container">
<uni-list :border="false">
<uni-list-item v-if="hasPerm('mobile${className}Edit')" title="编辑" class="item" :clickable="true" @click="edit"/>
<uni-list-item v-if="hasPerm('mobile${className}Delete')" title="刪除" class="item" :clickable="true" @click="del"/>
<uni-list-item title="取消" class="item" :clickable="true" @click="cancel"/>
</uni-list>
</view>
</uni-popup>
</template>
<script setup name="${classNameFirstLower}More">
import { ${classNameFirstLower}Delete } from '@/api/${moduleName}/${classNameFirstLower}Api'
import modal from '@/plugins/modal'
import { reactive, ref, getCurrentInstance } from "vue"
const emits = defineEmits(['handleOk'])
const popupRef = ref()
const record = ref({})
const open = (data) => {
record.value = data
popupRef.value.open("bottom")
}
// 编辑
const edit = () => {
uni.navigateTo({
url: '/pages/${moduleName}/${busName}/form?id=' + record.value.id
})
popupRef.value.close()
}
// 删除
const del = () => {
modal.confirm(`确定要删除吗?`).then(() => {
${classNameFirstLower}Delete([{
id: record.value.id
}]).then(res => {
emits('handleOk')
popupRef.value.close()
})
})
}
// 取消
const cancel = () => {
popupRef.value.close()
}
defineExpose({
open
})
</script>
<style lang="scss" scoped>
.container {
margin: 15upx;
border-radius: 5upx;
padding: 5upx;
background-color: $uni-white;
.item {
text-align:center;
}
}
</style>

View File

@ -0,0 +1,47 @@
// 二选一 将代码复制到page.json文件中
// 不使用分包
{
"path": "pages/${moduleName}/${busName}/index",
"style": {
"navigationBarTitleText": "${functionName}管理",
"enablePullDownRefresh": true,
//#ifdef H5
"navigationStyle": "custom"
//#endif
}
}, {
"path": "pages/${moduleName}/${busName}/form",
"style": {
"navigationBarTitleText": "${functionName}管理",
"enablePullDownRefresh": false,
//#ifdef H5
"navigationStyle": "custom"
//#endif
}
},
// 使用分包微信小程序开发主包不能超过2m所以建议使用分包
{
"root": "pages/${moduleName}/${busName}",
"pages": [{
"path": "index",
"style": {
"navigationBarTitleText": "${functionName}管理",
"enablePullDownRefresh": true,
//#ifdef H5
"navigationStyle": "custom"
//#endif
}
},{
"path": "form",
"style": {
"navigationBarTitleText": "${functionName}管理",
"enablePullDownRefresh": false,
//#ifdef H5
"navigationStyle": "custom"
//#endif
}
}]
}

View File

@ -0,0 +1,123 @@
<template>
<%
var searchCount = 0;
var row = 0;
%>
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { searchCount ++; }%>
<% } %>
<uni-popup ref="popupRef" type="bottom" safeArea background-color="#ffffff">
<view class="container">
<% if (searchCount > 0) { %>
<uni-forms ref="formRef" :model="searchFormState" label-position="top" labelWidth="100px">
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { %>
<% if(configList[i].effectType == 'input' || configList[i].effectType == 'textarea') { %>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<uni-easyinput v-model="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}"></uni-easyinput>
</uni-forms-item>
<% } else if (configList[i].effectType == 'select' || configList[i].effectType == 'radio' || configList[i].effectType == 'checkbox') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<snowy-sel-picker :map="{key: 'value', label: 'text'}" v-model="searchFormState.${configList[i].fieldNameCamelCase}" :rangeData="${configList[i].fieldNameCamelCase}Options" placeholder="请选择${configList[i].fieldRemark}"></snowy-sel-picker>
</uni-forms-item>
<% } else if (configList[i].effectType == 'inputNumber' || configList[i].effectType == 'slider') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<uni-number-box v-model="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}"/>
</uni-forms-item>
<% } else if (configList[i].effectType == 'datepicker') {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<uni-datetime-picker v-model="searchFormState.${configList[i].fieldNameCamelCase}" type="datetimerange"/>
</uni-forms-item>
<% } else {%>
<uni-forms-item label="${configList[i].fieldRemark}" name="${configList[i].fieldNameCamelCase}">
<uni-easyinput v-model="searchFormState.${configList[i].fieldNameCamelCase}" placeholder="请输入${configList[i].fieldRemark}"></uni-easyinput>
</uni-forms-item>
<% } %>
<% } %>
<% } %>
</uni-forms>
<% } %>
<uni-row :gutter="10">
<uni-col :span="12">
<button class="btn-reset" type="default" @click="reset">重置</button>
</uni-col>
<uni-col :span="12">
<button class="btn-sub" type="primary" @click="confirm">确认</button>
</uni-col>
</uni-row>
</view>
</uni-popup>
</template>
<script setup name="${classNameFirstLower}Search">
<%
var iptTool = 0;
if (searchCount > 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 '@/plugins/tool'
import SnowySelPicker from '@/components/snowy-sel-picker.vue'
<% } %>
import { ref } from "vue"
const emits = defineEmits(['reset', 'confirm'])
const props = defineProps({
searchFormState: {
type: Object,
required: true
},
})
<% 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}')
<% } %>
<% } %>
<% } %>
<% } %>
// 弹出ref
const popupRef = ref()
// 打开
const open = () => {
popupRef.value.open()
}
const reset = () =>{
// 重置数据
<% for(var i = 0; i < configList.~size; i++) { %>
<% if(!configList[i].needTableId && configList[i].needPage) { %>
props.searchFormState.${configList[i].fieldNameCamelCase} = ''
<% } %>
<% } %>
emits('reset', props.searchFormState)
}
const confirm = () => {
popupRef.value.close()
emits('confirm', props.searchFormState)
}
defineExpose({
open
})
</script>
<style lang="scss" scoped>
.container {
margin: 15upx;
border-radius: 5upx;
padding: 5upx;
background-color: $uni-white;
.btn-reset {
}
.btn-sub {
background-color: $uni-primary;
}
}
</style>

View File

@ -12,3 +12,12 @@ INSERT INTO `SYS_RESOURCE` VALUES ('${batchDeleteButtonId}', '${menuId}', '批
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);
INSERT INTO `MOBILE_RESOURCE` VALUES ('${menuId}', '0', '${functionName}管理', NULL, 'MENU', '${mobileModuleId}', 'MENU', '/pages/${moduleName}/${busName}/index', 'apartment-outlined', '#1890ff', 'YES', 'ENABLE', 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `MOBILE_RESOURCE` VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', 'mobile${className}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `MOBILE_RESOURCE` VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', 'mobile${className}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO `MOBILE_RESOURCE` VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', 'mobile${className}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -12,3 +12,12 @@ INSERT INTO "SNOWY"."SYS_RESOURCE" VALUES ('${batchDeleteButtonId}', '${menuId}'
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);
INSERT INTO "SNOWY"."MOBILE_RESOURCE" VALUES ('${menuId}', '0', '${functionName}管理', NULL, 'MENU', '${moduleId}', 'MENU', '/pages/${moduleName}/${busName}/index', 'apartment-outlined', '#1890ff', 'YES', 'ENABLE', 99, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."MOBILE_RESOURCE" VALUES ('${addButtonId}', '${menuId}', '新增${functionName}', 'mobile${className}Add', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."MOBILE_RESOURCE" VALUES ('${editButtonId}', '${menuId}', '编辑${functionName}', 'mobile${className}Edit', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
INSERT INTO "SNOWY"."MOBILE_RESOURCE" VALUES ('${deleteButtonId}', '${menuId}', '删除${functionName}', 'mobile${className}Delete', 'BUTTON', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 3, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);

View File

@ -0,0 +1,26 @@
package vip.xiaonuo.mobile.modular.resource.provider;
import cn.hutool.json.JSONObject;
import org.springframework.stereotype.Service;
import vip.xiaonuo.mobile.api.MobileModuleApi;
import vip.xiaonuo.mobile.modular.resource.service.MobileModuleService;
import javax.annotation.Resource;
import java.util.List;
/**
* API
*
* @author
* @date 2023/7/15 22:38
*/
@Service
public class MobileModuleApiProvider implements MobileModuleApi {
@Resource
private MobileModuleService mobileModuleService;
@Override
public List<JSONObject> mobileModuleSelector() {
return mobileModuleService.mobileModuleSelector();
}
}

View File

@ -12,6 +12,7 @@
*/
package vip.xiaonuo.mobile.modular.resource.service;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.mobile.modular.resource.entity.MobileModule;
@ -77,4 +78,12 @@ public interface MobileModuleService extends IService<MobileModule> {
* @date 2022/4/24 21:18
*/
MobileModule queryEntity(String id);
/**
*
*
* @author
* @date 2023/7/15 21:52
*/
List<JSONObject> mobileModuleSelector();
}

View File

@ -18,6 +18,8 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -136,4 +138,14 @@ public class MobileModuleServiceImpl extends ServiceImpl<MobileModuleMapper, Mob
}
return mobileModule;
}
@Override
public List<JSONObject> mobileModuleSelector() {
LambdaQueryWrapper<MobileModule> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.select(MobileModule::getId, MobileModule::getTitle);
lambdaQueryWrapper.eq(MobileModule::getCategory, MobileResourceCategoryEnum.MODULE.getValue());
lambdaQueryWrapper.orderByAsc(MobileModule::getSortCode);
return this.list(lambdaQueryWrapper).stream().map(item -> JSONUtil.createObj().set("id", item.getId()).set("name", item.getTitle()))
.collect(Collectors.toList());
}
}

View File

@ -525,6 +525,7 @@ CREATE TABLE `GEN_BASIC` (
`GENERATE_TYPE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成方式',
`MODULE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属模块',
`MENU_PID` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '上级目录',
`MOBILE_MODULE` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '移动端所属模块',
`FUNCTION_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '功能名',
`BUS_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '业务名',
`CLASS_NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类名',