feat(新增): 🔧 多语言修改
This commit is contained in:
parent
e817494645
commit
94a9937707
|
@ -0,0 +1,33 @@
|
|||
package cn.bunny.common.generator.entity;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "BaseEntity对象", description = "生成类基础内容")
|
||||
public class BaseField {
|
||||
@ApiModelProperty("字段名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("注释内容")
|
||||
private String annotation;
|
||||
|
||||
@ApiModelProperty("TS类型")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty("注释解释")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty("是否必须参数")
|
||||
private Boolean require;
|
||||
|
||||
@ApiModelProperty("是否必须参数消息内容")
|
||||
private String requireMessage;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package cn.bunny.common.generator.entity;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "ColumnsField对象", description = "columns列字段名称")
|
||||
public class ColumnsField {
|
||||
@ApiModelProperty("列字段名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("列字段值")
|
||||
private String value;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.bunny.common.generator.entity;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "StoreTypeField对象", description = "仓库类型生成内容")
|
||||
public class StoreTypeField {
|
||||
|
||||
private List<BaseField> baseFieldList;
|
||||
|
||||
@ApiModelProperty("接口名称")
|
||||
private String interfaceName;
|
||||
|
||||
@ApiModelProperty("接口注释内容")
|
||||
private String interfaceAnnotation;
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package cn.bunny.common.generator.generator;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class AdminCodeGenerator {
|
||||
// 数据连接
|
||||
public static final String sqlHost = "jdbc:mysql://106.15.251.123:3305/bunny_docs?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
|
||||
// 作者名称
|
||||
public static final String author = "Bunny";
|
||||
// 公共路径
|
||||
public static final String outputDir = "D:\\MyFolder\\Bunny\\BunnyBBS\\BunnyBBS-server-admin\\service";
|
||||
// public static final String outputDir = "D:\\Project\\web\\PC\\BunnyNote\\BunnyBBS-server-admin\\service";
|
||||
// 实体类名称
|
||||
public static final String entity = "Bunny";
|
||||
|
||||
public static void main(String[] args) {
|
||||
Generation("system_menu_icon");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名生成相应结构代码
|
||||
*
|
||||
* @param tableName 表名
|
||||
*/
|
||||
public static void Generation(String... tableName) {
|
||||
// 修改数据库路径、账户、密码
|
||||
FastAutoGenerator.create(sqlHost, "root", "02120212")
|
||||
.globalConfig(builder -> {
|
||||
// 添加作者名称
|
||||
builder.author(author)
|
||||
// 启用swagger
|
||||
.enableSwagger()
|
||||
// 指定输出目录
|
||||
.outputDir(outputDir + "/src/main/java");
|
||||
})
|
||||
.packageConfig(builder -> builder.entity(entity)// 实体类包名
|
||||
// 父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名
|
||||
.parent("cn.bunny.service.admin")
|
||||
.controller("controller.main.system")// 控制层包名
|
||||
.mapper("mapper.main.system")// mapper层包名
|
||||
.service("service.main.system")// service层包名
|
||||
.serviceImpl("service.system.impl")// service实现类包名
|
||||
// 自定义mapper.xml文件输出目录
|
||||
.pathInfo(Collections.singletonMap(OutputFile.xml, outputDir + "/src/main/resources/mapper/main/system")))
|
||||
.strategyConfig(builder -> {
|
||||
// 设置要生成的表名
|
||||
builder.addInclude(tableName)
|
||||
//.addTablePrefix("sys_")// 设置表前缀过滤
|
||||
.entityBuilder()
|
||||
.enableLombok()
|
||||
.enableChainModel()
|
||||
.naming(NamingStrategy.underline_to_camel)// 数据表映射实体命名策略:默认下划线转驼峰underline_to_camel
|
||||
.columnNaming(NamingStrategy.underline_to_camel)// 表字段映射实体属性命名规则:默认null,不指定按照naming执行
|
||||
.idType(IdType.AUTO)// 添加全局主键类型
|
||||
.formatFileName("%s")// 格式化实体名称,%s取消首字母I,
|
||||
.mapperBuilder()
|
||||
.mapperAnnotation(Mapper.class)// 开启mapper注解
|
||||
.enableBaseResultMap()// 启用xml文件中的BaseResultMap 生成
|
||||
.enableBaseColumnList()// 启用xml文件中的BaseColumnList
|
||||
.formatMapperFileName("%sMapper")// 格式化Dao类名称
|
||||
.formatXmlFileName("%sMapper")// 格式化xml文件名称
|
||||
.serviceBuilder()
|
||||
.formatServiceFileName("%sService")// 格式化 service 接口文件名称
|
||||
.formatServiceImplFileName("%sServiceImpl")// 格式化 service 接口文件名称
|
||||
.controllerBuilder()
|
||||
.enableRestStyle();
|
||||
})
|
||||
// .injectionConfig(consumer -> {
|
||||
// Map<String, String> customFile = new HashMap<>();
|
||||
// // 配置DTO(需要的话)但是需要有能配置Dto的模板引擎,比如freemarker,但是这里我们用的VelocityEngine,因此不多作介绍
|
||||
// customFile.put(outputDir, "/src/main/resources/templates/entityDTO.java.ftl");
|
||||
// consumer.customFile(customFile);
|
||||
// })
|
||||
.execute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package cn.bunny.common.generator.generator;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class I18nCodeGenerator {
|
||||
// 数据连接
|
||||
public static final String sqlHost = "jdbc:mysql://106.15.251.123:3305/bunny_docs_i18n?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
|
||||
// 作者名称
|
||||
public static final String author = "Bunny";
|
||||
// 公共路径
|
||||
public static final String outputDir = "D:\\MyFolder\\Bunny\\BunnyBBS\\BunnyBBS-server-admin\\service";
|
||||
// 实体类名称
|
||||
public static final String entity = "Bunny";
|
||||
|
||||
public static void main(String[] args) {
|
||||
Generation("language");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名生成相应结构代码
|
||||
*
|
||||
* @param tableName 表名
|
||||
*/
|
||||
public static void Generation(String... tableName) {
|
||||
FastAutoGenerator.create(sqlHost, "root", "02120212")
|
||||
.globalConfig(builder -> {
|
||||
// 添加作者名称
|
||||
builder.author(author)
|
||||
// 启用swagger
|
||||
.enableSwagger()
|
||||
// 指定输出目录
|
||||
.outputDir(outputDir + "/src/main/java");
|
||||
})
|
||||
.packageConfig(builder -> {
|
||||
builder.entity(entity)// 实体类包名
|
||||
.parent("cn.bunny.service.admin")
|
||||
.controller("controller.i18n")// 控制层包名
|
||||
.mapper("mapper.i18n")// mapper层包名
|
||||
.service("service.i18n")// service层包名
|
||||
.serviceImpl("service.i18n.impl")// service实现类包名
|
||||
// 自定义mapper.xml文件输出目录
|
||||
.pathInfo(Collections.singletonMap(OutputFile.xml, outputDir + "/src/main/resources/mapper/i18n"));
|
||||
})
|
||||
.strategyConfig(builder -> {
|
||||
// 设置要生成的表名
|
||||
builder.addInclude(tableName)
|
||||
//.addTablePrefix("sys_")// 设置表前缀过滤
|
||||
.entityBuilder()
|
||||
.enableLombok()
|
||||
.enableChainModel()
|
||||
.naming(NamingStrategy.underline_to_camel)// 数据表映射实体命名策略:默认下划线转驼峰underline_to_camel
|
||||
.columnNaming(NamingStrategy.underline_to_camel)// 表字段映射实体属性命名规则:默认null,不指定按照naming执行
|
||||
.idType(IdType.AUTO)// 添加全局主键类型
|
||||
.formatFileName("%s")// 格式化实体名称,%s取消首字母I,
|
||||
.mapperBuilder()
|
||||
.mapperAnnotation(Mapper.class)// 开启mapper注解
|
||||
.enableBaseResultMap()// 启用xml文件中的BaseResultMap 生成
|
||||
.enableBaseColumnList()// 启用xml文件中的BaseColumnList
|
||||
.formatMapperFileName("%sMapper")// 格式化Dao类名称
|
||||
.formatXmlFileName("%sMapper")// 格式化xml文件名称
|
||||
.serviceBuilder()
|
||||
.formatServiceFileName("%sService")// 格式化 service 接口文件名称
|
||||
.formatServiceImplFileName("%sServiceImpl")// 格式化 service 接口文件名称
|
||||
.controllerBuilder()
|
||||
.enableRestStyle();
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
package cn.bunny.common.generator.generator;
|
||||
|
||||
import cn.bunny.admin.dto.admin.AdminPowerAddDto;
|
||||
import cn.bunny.admin.dto.admin.AdminPowerDto;
|
||||
import cn.bunny.admin.dto.admin.AdminPowerUpdateDto;
|
||||
import cn.bunny.admin.entity.admin.AdminPower;
|
||||
import cn.bunny.admin.vo.admin.AdminPowerVo;
|
||||
import cn.bunny.common.entity.BaseField;
|
||||
import cn.bunny.common.entity.ColumnsField;
|
||||
import cn.bunny.common.entity.StoreTypeField;
|
||||
import cn.bunny.common.utils.GeneratorCodeUtils;
|
||||
import com.google.common.base.CaseFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.velocity.Template;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* * 代码生成器入口点
|
||||
*/
|
||||
@Service
|
||||
public class WebGeneratorCode {
|
||||
// 公共路径
|
||||
public static String commonPath = "D:\\MyFolder\\Bunny\\BunnyBBS\\BunnyBBS-admin\\";
|
||||
// public static String commonPath = "D:\\Project\\web\\PC\\BunnyNote\\BunnyBBS-admin\\";
|
||||
// 生成API请求路径
|
||||
public static String apiPath = commonPath + "src\\api\\api-v1\\user\\";
|
||||
// 生成的表格列表路径
|
||||
public static String columnsPath = commonPath + "src\\views\\user\\admin\\admin-power-management\\utils\\";
|
||||
// 生成vue路径
|
||||
public static String vuePath = commonPath + "src\\views\\user\\admin\\admin-power-management\\";
|
||||
// 生成仓库路径
|
||||
public static String storePath = commonPath + "src\\store\\user\\";
|
||||
// 生成仓库类型
|
||||
public static String storeTypePath = commonPath + "src\\types\\store\\user\\admin\\";
|
||||
// 公共i18n字段前缀
|
||||
public static String commonPreFix = "adminPower";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Class<?> aClass = AdminPower.class;
|
||||
Class<?> dtoClass = AdminPowerDto.class;
|
||||
Class<?> addDtoClass = AdminPowerAddDto.class;
|
||||
Class<?> updateDtoClass = AdminPowerUpdateDto.class;
|
||||
Class<?> voClass = AdminPowerVo.class;
|
||||
|
||||
ArrayList<Class<?>> classList = new ArrayList<>();
|
||||
classList.add(voClass);
|
||||
classList.add(dtoClass);
|
||||
classList.add(addDtoClass);
|
||||
classList.add(updateDtoClass);
|
||||
|
||||
// 开始生成内容
|
||||
generatorCode(aClass, voClass, dtoClass, addDtoClass, classList);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 代码生成
|
||||
*/
|
||||
public static void generatorCode(Class<?> aClass, Class<?> voClass, Class<?> dtoClass, Class<?> addDtoClass, ArrayList<Class<?>> classList) throws Exception {
|
||||
// 设置velocity资源加载器
|
||||
Properties prop = new Properties();
|
||||
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
Velocity.init(prop);
|
||||
// 创建Velocity容器
|
||||
VelocityContext context = new VelocityContext();
|
||||
|
||||
// 原始类名称
|
||||
String originalName = aClass.getSimpleName();
|
||||
// 转成开头小写类名称,作为文件名
|
||||
String lowercaseName = originalName.substring(0, 1).toLowerCase() + originalName.substring(1);
|
||||
// 转成中划线,做vue命名使用
|
||||
String lowerHyphen = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, originalName);
|
||||
// 基础TS 的 interface 注释内容
|
||||
String interfaceDescription = aClass.getAnnotation(ApiModel.class).description();
|
||||
|
||||
Field[] fields = voClass.getDeclaredFields();
|
||||
// 生成 Columns 字段
|
||||
List<ColumnsField> columnsField = Arrays.stream(fields)
|
||||
.map(field -> ColumnsField.builder().name(field.getName()).value(field.getAnnotation(ApiModelProperty.class).value()).build())
|
||||
.toList();
|
||||
// 整合仓库集合 interface 集合列表
|
||||
List<StoreTypeField> fieldList = classList.stream().map(GeneratorCodeUtils::handleGenerator).toList();
|
||||
|
||||
// 生成 Store 中 form 表单内容
|
||||
List<BaseField> formList = Arrays.stream(dtoClass.getDeclaredFields())
|
||||
.filter(field -> !field.getName().equals("id"))
|
||||
.map(field -> BaseField.builder().name(field.getName()).annotation(field.getAnnotation(ApiModelProperty.class).name()).build())
|
||||
.toList();
|
||||
|
||||
// 生成dialog字段
|
||||
List<BaseField> addDtoFormList = Arrays.stream(addDtoClass.getDeclaredFields())
|
||||
.map(addDto -> {
|
||||
BaseField baseField = new BaseField();
|
||||
baseField.setName(addDto.getName());
|
||||
baseField.setAnnotation(addDto.getAnnotation(ApiModelProperty.class).name());
|
||||
|
||||
// 是否有验证内容
|
||||
List<Annotation> validationList = Arrays.stream(addDto.getAnnotations())
|
||||
.filter(annotation -> {
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
return annotationType.getTypeName().contains("jakarta.validation.constraints");
|
||||
})
|
||||
.peek(annotation -> {
|
||||
try {
|
||||
String message = annotation.annotationType().getMethod("message").invoke(annotation).toString();
|
||||
baseField.setRequireMessage(message);
|
||||
baseField.setRequire(true);
|
||||
} catch (Exception e) {
|
||||
baseField.setRequireMessage(null);
|
||||
baseField.setRequire(false);
|
||||
}
|
||||
}).toList();
|
||||
|
||||
baseField.setRequire(!validationList.isEmpty());
|
||||
|
||||
return baseField;
|
||||
})
|
||||
.toList();
|
||||
|
||||
context.put("columnsField", columnsField);
|
||||
context.put("fields", fieldList);
|
||||
context.put("annotationName", aClass.getAnnotation(ApiModel.class).description());
|
||||
context.put("storeId", GeneratorCodeUtils.lowercaseFirstLetter(originalName));
|
||||
context.put("formList", formList);
|
||||
context.put("addDtoFormList", addDtoFormList);
|
||||
context.put("className", originalName);
|
||||
context.put("interfaceDescription", interfaceDescription);
|
||||
context.put("lowerHyphen", lowerHyphen);
|
||||
context.put("lowercaseName", lowercaseName);
|
||||
context.put("commonPreFix", commonPreFix);
|
||||
|
||||
// 添加路径内
|
||||
context.put("columnsPath", GeneratorCodeUtils.ReplacePathHandle(columnsPath));
|
||||
context.put("vuePath", GeneratorCodeUtils.ReplacePathHandle(vuePath));
|
||||
context.put("storePath", GeneratorCodeUtils.ReplacePathHandle(storePath));
|
||||
context.put("storeTypePath", GeneratorCodeUtils.ReplacePathHandle(storeTypePath));
|
||||
context.put("apiPath", GeneratorCodeUtils.ReplacePathHandle(apiPath));
|
||||
|
||||
// 写入文件
|
||||
writeFiles(lowercaseName, lowerHyphen, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 写入文件
|
||||
*
|
||||
* @param lowercaseName 文件名称,开头小写
|
||||
* @param context VelocityContext上下文信息
|
||||
*/
|
||||
public static void writeFiles(String lowercaseName, String lowerHyphen, VelocityContext context) throws IOException {
|
||||
// 加载模板
|
||||
Template columnsTemplate = Velocity.getTemplate("vms/web/columns.vm", "UTF-8");
|
||||
Template handlerTemplate = Velocity.getTemplate("vms/web/handler.vm", "UTF-8");
|
||||
Template apiFileTemplate = Velocity.getTemplate("vms/web/fetchAPi.vm", "UTF-8");
|
||||
Template storeFileTemplate = Velocity.getTemplate("vms/web/store.vm", "UTF-8");
|
||||
Template storeTypeTemplate = Velocity.getTemplate("vms/web/storeType.vm", "UTF-8");
|
||||
Template indexTemplate = Velocity.getTemplate("vms/web/vue/index.vm", "UTF-8");
|
||||
Template dialogTemplate = Velocity.getTemplate("vms/web/vue/dialog.vm", "UTF-8");
|
||||
Template addDialogTemplate = Velocity.getTemplate("vms/web/vue/addDialog.vm", "UTF-8");
|
||||
Template dialogUpdateTemplate = Velocity.getTemplate("vms/web/vue/dialogUpdate.vm", "UTF-8");
|
||||
|
||||
// 写入模板
|
||||
FileWriter columnsTemplateFileWriter = new FileWriter(columnsPath + "columns.ts");
|
||||
FileWriter handlerTemplateFileWriter = new FileWriter(columnsPath + "handler.ts");
|
||||
FileWriter apiFileTemplateFileWrite = new FileWriter(apiPath + lowercaseName + ".ts");
|
||||
FileWriter storeFileTemplateFileWriter = new FileWriter(storePath + lowercaseName + ".ts");
|
||||
FileWriter storeTypeTemplateFileWriter = new FileWriter(storeTypePath + lowercaseName + ".ts");
|
||||
FileWriter indexTemplateFileWriter = new FileWriter(vuePath + "index.vue");
|
||||
FileWriter dialogTemplateFileWriter = new FileWriter(vuePath + lowerHyphen + "-dialog.vue");
|
||||
FileWriter addDialogTemplateFileWriter = new FileWriter(vuePath + lowerHyphen + "-add.vue");
|
||||
FileWriter dialogUpdateTemplateFileWriter = new FileWriter(vuePath + lowerHyphen + "-update.vue");
|
||||
|
||||
// 合并数据到模板
|
||||
dialogUpdateTemplate.merge(context, dialogUpdateTemplateFileWriter);
|
||||
addDialogTemplate.merge(context, addDialogTemplateFileWriter);
|
||||
dialogTemplate.merge(context, dialogTemplateFileWriter);
|
||||
indexTemplate.merge(context, indexTemplateFileWriter);
|
||||
columnsTemplate.merge(context, columnsTemplateFileWriter);
|
||||
handlerTemplate.merge(context, handlerTemplateFileWriter);
|
||||
apiFileTemplate.merge(context, apiFileTemplateFileWrite);
|
||||
storeFileTemplate.merge(context, storeFileTemplateFileWriter);
|
||||
storeTypeTemplate.merge(context, storeTypeTemplateFileWriter);
|
||||
|
||||
// 释放资源
|
||||
columnsTemplateFileWriter.close();
|
||||
handlerTemplateFileWriter.close();
|
||||
apiFileTemplateFileWrite.close();
|
||||
storeFileTemplateFileWriter.close();
|
||||
storeTypeTemplateFileWriter.close();
|
||||
indexTemplateFileWriter.close();
|
||||
dialogTemplateFileWriter.close();
|
||||
addDialogTemplateFileWriter.close();
|
||||
dialogUpdateTemplateFileWriter.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package cn.bunny.common.generator.utils;
|
||||
|
||||
import cn.bunny.common.entity.BaseField;
|
||||
import cn.bunny.common.entity.StoreTypeField;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.bunny.common.generator.WebGeneratorCode.commonPath;
|
||||
|
||||
public class GeneratorCodeUtils {
|
||||
public static String convertJavaTypeToTypeScript(Class<?> javaType) {
|
||||
if (javaType.isPrimitive()) {
|
||||
return getPrimitiveTypeMapping(javaType.getSimpleName());
|
||||
} else if (javaType.isArray()) {
|
||||
return "Array<" + convertJavaTypeToTypeScript(javaType.getComponentType()) + ">";
|
||||
} else if (javaType.equals(List.class) || javaType.equals(Set.class) || javaType.equals(Map.class)) {
|
||||
return "any";
|
||||
} else {
|
||||
return getPrimitiveTypeMapping(javaType.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 将Java类型转成JS/TS类型
|
||||
*
|
||||
* @param primitiveType Java的类型
|
||||
* @return 转换后的类型
|
||||
*/
|
||||
private static String getPrimitiveTypeMapping(String primitiveType) {
|
||||
return switch (primitiveType) {
|
||||
case "int", "long", "short", "byte", "float", "double", "Byte", "Integer", "Long", "Float", "Double" ->
|
||||
"number";
|
||||
case "boolean", "Boolean" -> "boolean";
|
||||
case "char", "Character", "String" -> "string";
|
||||
default -> "any";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* * 将首字符变小写
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return 变小写后字符串
|
||||
*/
|
||||
public static String lowercaseFirstLetter(String str) {
|
||||
if (str == null || str.isEmpty()) return str;
|
||||
// 将首字母转换为小写,其余部分保持原样
|
||||
return str.substring(0, 1).toLowerCase() + str.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 生成返回对象类字段
|
||||
* 返回字段包含:TS接口名称,TS接口名称注释,TS接口字段、TS字段类型、TS字段注释、TS字段注释解释
|
||||
*
|
||||
* @param voClass 返回对象类
|
||||
* @return 整理好返回字段
|
||||
*/
|
||||
public static StoreTypeField handleGenerator(Class<?> voClass) {
|
||||
// 类的详细信息
|
||||
String interfaceAnnotation = voClass.getAnnotation(ApiModel.class).description();
|
||||
|
||||
// 字段
|
||||
List<Field> fields = new ArrayList<>(Arrays.stream(voClass.getDeclaredFields()).toList());
|
||||
List<Field> superList = Arrays.stream(voClass.getSuperclass().getDeclaredFields()).toList();
|
||||
fields.addAll(superList);
|
||||
|
||||
List<BaseField> list = fields.stream()
|
||||
.map(field -> {
|
||||
field.setAccessible(true);
|
||||
|
||||
// 将类型转成TS
|
||||
Class<?> type = field.getType();
|
||||
String convertJavaTypeToTypeScript = GeneratorCodeUtils.convertJavaTypeToTypeScript(type);
|
||||
|
||||
// 注释内容
|
||||
String annotationName = Objects.requireNonNull(field.getAnnotation(ApiModelProperty.class).name());
|
||||
// 注释解释
|
||||
String value = field.getAnnotation(ApiModelProperty.class).value();
|
||||
|
||||
// 构建返回内容
|
||||
BaseField storeTypeField = new BaseField();
|
||||
storeTypeField.setName(field.getName());
|
||||
storeTypeField.setAnnotation(annotationName);
|
||||
storeTypeField.setType(convertJavaTypeToTypeScript);
|
||||
storeTypeField.setDescription(value);
|
||||
|
||||
return storeTypeField;
|
||||
}).toList();
|
||||
|
||||
StoreTypeField storeTypeField = new StoreTypeField();
|
||||
storeTypeField.setBaseFieldList(list);
|
||||
storeTypeField.setInterfaceName(voClass.getSimpleName());
|
||||
storeTypeField.setInterfaceAnnotation(interfaceAnnotation);
|
||||
|
||||
return storeTypeField;
|
||||
}
|
||||
|
||||
/**
|
||||
* * 通用处理路径内容
|
||||
*
|
||||
* @param path 路径
|
||||
* @return 处理好的路径
|
||||
*/
|
||||
public static String ReplacePathHandle(String path) {
|
||||
return path.replace(commonPath, "").replace("\\", "/").replace("src", "@");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// ${className}
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { reactive } from 'vue';
|
||||
import type { FormRules } from 'element-plus';
|
||||
|
||||
// ${annotationName}表格列字段
|
||||
export const columns = [
|
||||
{ type: 'selection' },
|
||||
{ label: $t('table.id'), prop: 'id' },
|
||||
#foreach($item in $columnsField)
|
||||
#if($item.name == 'avatar')
|
||||
{ label: $t('user.${item.getName()}'), prop: '${item.getName()}',slot: '${item.getName()}' },
|
||||
#elseif($item.name == 'image')
|
||||
{ label: $t('user.${item.getName()}'), prop: '${item.getName()}',slot: '${item.getName()}' },
|
||||
#elseif($item.name == 'status')
|
||||
{ label: $t('user.${item.getName()}'), prop: '${item.getName()}',slot: '${item.getName()}' },
|
||||
#else
|
||||
// ${item.getValue()}
|
||||
{ label: $t('${commonPreFix}.${item.getName()}'), prop: '${item.getName()}' },
|
||||
#end
|
||||
#end
|
||||
{ label: $t('table.createTime'), prop: 'createTime', sortable: true, width: 160 },
|
||||
{ label: $t('table.updateTime'), prop: 'updateTime', sortable: true, width: 160 },
|
||||
{ label: $t('table.createUser'), prop: 'createUser', width: 100, slot: 'createUser' },
|
||||
{ label: $t('table.updateUser'), prop: 'updateUser', width: 100, slot: 'updateUser' },
|
||||
{ label: $t('table.operation'), prop: 'operation', slot: 'operation', width: 150, fixed: 'right' },
|
||||
];
|
||||
|
||||
|
||||
// ${annotationName}表格规则
|
||||
export const rules = reactive({
|
||||
#foreach($item in $addDtoFormList)
|
||||
#if($item.require)
|
||||
#if($item.name == 'email')
|
||||
// 邮件不能为空
|
||||
email: [
|
||||
{ required: true, message: '邮件不能为空', trigger: 'blur' },
|
||||
{ type: 'email', message: '邮箱格式错误' },
|
||||
],
|
||||
#elseif($item.name == 'nickName')
|
||||
// 昵称不能为空
|
||||
nickName: [{ required: true, message: '昵称不能为空', trigger: 'blur' }],
|
||||
#elseif($item.name == 'username')
|
||||
username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
|
||||
#elseif($item.name == 'status')
|
||||
// 状态不能为空
|
||||
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
|
||||
#else
|
||||
// $item.annotation
|
||||
$item.name: [{ required: true, message: '$item.requireMessage', trigger: 'blur' }],
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
});
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import Request from '@/api/service/request';
|
||||
|
||||
/**
|
||||
* * 查询内容${annotationName}
|
||||
*/
|
||||
export const fetchGet${className}ListByPage = (data: any) => {
|
||||
const page = data.page;
|
||||
const limit = data.limit;
|
||||
return Request({
|
||||
url: `/${commonPreFix}/get${className}ListByPage/${page}/${limit}`,
|
||||
method: 'GET',
|
||||
params: data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加${annotationName}
|
||||
* @param data
|
||||
*/
|
||||
export const fetchAdd${className} = (data: any) => {
|
||||
return Request({ url: '/${commonPreFix}/add${className}', method: 'POST', data });
|
||||
};
|
||||
|
||||
/**
|
||||
* * 更新${annotationName}
|
||||
* @param data
|
||||
*/
|
||||
export const fetchUpdate${className} = (data: any) => {
|
||||
return Request({ url: '/${commonPreFix}/update${className}', method: 'PUT', data });
|
||||
};
|
||||
|
||||
/**
|
||||
* * 删除用户${annotationName}
|
||||
* @param data
|
||||
*/
|
||||
export const fetchDelete${className}ByIds = (data: any) => {
|
||||
return Request({ url: '/${commonPreFix}/delete${className}ByIds', method: 'DELETE', data });
|
||||
};
|
|
@ -0,0 +1,98 @@
|
|||
import {reactive, ref} from 'vue';
|
||||
import {messageBox} from '@/utils/message';
|
||||
import { use${className}Store } from '${storePath}${lowercaseName}';
|
||||
import { ${className}AddDto, ${className}State, ${className}UpdateDto, ${className}Vo } from '${storeTypePath}${lowercaseName}';
|
||||
|
||||
const ${storeId}Store = use${className}Store();
|
||||
export const ids = ref([]);
|
||||
export const updateForm = reactive<${className}UpdateDto>({});
|
||||
|
||||
/**
|
||||
* * 获取用户数据
|
||||
*/
|
||||
export const getDataList = async (flag: boolean = true) => {
|
||||
if (flag) {
|
||||
${storeId}Store.loading = true;
|
||||
await ${storeId}Store.get${className}List();
|
||||
${storeId}Store.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当前页改变时
|
||||
*/
|
||||
export const onCurrentPageChange = async (value: number) => {
|
||||
${storeId}Store.pagination.currentPage = value;
|
||||
await getDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当分页发生变化
|
||||
* @param value
|
||||
*/
|
||||
export const onPageSizeChange = (value: number) => {
|
||||
${storeId}Store.pagination.pageSize = value;
|
||||
getDataList().then();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 选择行
|
||||
* @param itemList
|
||||
*/
|
||||
export const handleSelectionChange = (itemList: ${className}Vo[]) => {
|
||||
ids.value = itemList.map(item => item.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加操作
|
||||
*/
|
||||
export const onAdd = () => {
|
||||
${storeId}Store.addDialogVisible = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当更新时
|
||||
*/
|
||||
export const onUpdate = ({row}): void => {
|
||||
// 合并数据
|
||||
Object.assign(updateForm, row);
|
||||
|
||||
#foreach($item in $addDtoFormList)
|
||||
#if($item.name == 'sex')
|
||||
// 设置基础数据格式
|
||||
updateForm.sex = row.sex === '女' ? 0 : 1;
|
||||
#end
|
||||
#end
|
||||
|
||||
// 打开弹窗
|
||||
${storeId}Store.updateDialogVisible = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当删除时
|
||||
*/
|
||||
export const onDelete = async ({row}) => {
|
||||
const result = await ${storeId}Store.delete${className}([row.id]).then();
|
||||
// 成功刷新数据
|
||||
await getDataList(result)
|
||||
};
|
||||
|
||||
/**
|
||||
* * 批量删除
|
||||
*/
|
||||
export const onDeleteBatch = async () => {
|
||||
const isConfirm = await messageBox({
|
||||
message: '是否确认批量删除',
|
||||
title: '删除警告',
|
||||
showMessage: false,
|
||||
confirmMessage: '删除成功',
|
||||
cancelMessage: '取消删除',
|
||||
});
|
||||
// 确认删除时执行
|
||||
if (isConfirm) {
|
||||
const result = await ${storeId}Store.delete${className}(ids.value);
|
||||
|
||||
// 成功刷新数据
|
||||
await getDataList(result)
|
||||
}
|
||||
};
|
|
@ -0,0 +1,99 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { pageSizes } from '@/enum/baseConstant';
|
||||
import { storePagination } from '@/hooks/system/useStorePagination';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import type { Option } from '../../../types/enum/options';
|
||||
import {fetchGet${className}ListByPage,fetchAdd${className},fetchUpdate${className},fetchDelete${className}ByIds} from "${apiPath}${lowercaseName}";
|
||||
import { ${className}AddDto, ${className}State, ${className}UpdateDto } from '${storeTypePath}${lowercaseName}';
|
||||
|
||||
/**
|
||||
* * 前台用户相关
|
||||
*/
|
||||
export const use${className}Store = defineStore('${storeId}Store}', {
|
||||
state(): ${className}State {
|
||||
return {
|
||||
dataList: [],
|
||||
// ? 表单内容
|
||||
form: {
|
||||
#foreach($item in $formList)
|
||||
#if(${item.name})
|
||||
// ? $!{item.annotation}
|
||||
$!{item.name}: void 0,
|
||||
#end
|
||||
#end
|
||||
},
|
||||
// ? 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSizes,
|
||||
},
|
||||
// ? 是否加载中
|
||||
loading: false,
|
||||
// ? 是否显示添加弹窗
|
||||
addDialogVisible: false,
|
||||
// ? 是否显示更新弹窗
|
||||
updateDialogVisible: false,
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
actions: {
|
||||
|
||||
/**
|
||||
* * 查询内容${annotationName}
|
||||
*/
|
||||
async get${className}List() {
|
||||
const data = {
|
||||
page: this.pagination.currentPage,
|
||||
limit: this.pagination.pageSize,
|
||||
...this.form,
|
||||
};
|
||||
const response: any = await fetchGet${className}ListByPage(data);
|
||||
|
||||
// 公共页面函数hook
|
||||
const pagination = storePagination.bind(this);
|
||||
return pagination(response);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 添加${annotationName}
|
||||
* @param form
|
||||
*/
|
||||
async add${className}(form: ${className}AddDto) {
|
||||
const response: any = await fetchAdd${className}(form);
|
||||
|
||||
if (response.code == 200) {
|
||||
ElMessage.success(response.message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* * 更新${annotationName}
|
||||
* @param form
|
||||
*/
|
||||
async update${className}(form: ${className}UpdateDto) {
|
||||
const response: any = await fetchUpdate${className} (form);
|
||||
if (response.code == 200) {
|
||||
ElMessage.success(response.message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* * 删除用户${annotationName}
|
||||
* @param ids
|
||||
*/
|
||||
async delete${className}(ids: string[]) {
|
||||
const response: any = await fetchDelete${className}ByIds(ids);
|
||||
if (response.code == 200) {
|
||||
ElMessage.success(response.message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
import type { BaseStoreState } from '@/types/store/baseStoreState';
|
||||
import type { Option } from '@/types/enum/options';
|
||||
|
||||
#foreach($item in $fields)
|
||||
|
||||
// ${item.interfaceAnnotation}
|
||||
export interface ${item.interfaceName} {
|
||||
|
||||
#foreach($field in ${item.baseFieldList})
|
||||
// $field.annotation【$field.description】
|
||||
$field.name: $field.type;
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
// ${interfaceDescription}State
|
||||
export interface ${className}State extends BaseStoreState {
|
||||
// 返回用户数据列表
|
||||
dataList: ${className}Vo[];
|
||||
// 查询表单信息
|
||||
form: ${className}Dto;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<script lang="ts" setup>
|
||||
import ${className}Dialog from '${vuePath}${lowerHyphen}-dialog.vue';
|
||||
import { reactive } from 'vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import type { FileDetails } from '@/types/common/file';
|
||||
import { use${className}Store } from '${storePath}${lowercaseName}';
|
||||
import { ${className}AddDto, ${className}State, ${className}UpdateDto } from '${storeTypePath}${lowercaseName}';
|
||||
|
||||
const ${storeId}Store = use${className}Store();
|
||||
const form = reactive<${className}AddDto>({});
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
const data = {
|
||||
|
||||
};
|
||||
Object.assign(form, data);
|
||||
${storeId}Store.addDialogVisible = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 提交表单
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await ${storeId}Store.add${className}(form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
${storeId}Store.addDialogVisible = false;
|
||||
await ${storeId}Store.get${className}List();
|
||||
} else {
|
||||
ElMessage.closeAll();
|
||||
ElMessage.warning($t('status.requiredFields'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
#foreach($item in $addDtoFormList)
|
||||
#if($item.name == 'avatar')
|
||||
/**
|
||||
* * 图片上传成功回调
|
||||
* @param fileDetails
|
||||
*/
|
||||
const onUploadImage = (fileDetails: FileDetails) => {
|
||||
form.avatar = fileDetails.filepath;
|
||||
};
|
||||
#end
|
||||
#if($item.name == 'image')
|
||||
/**
|
||||
* * 图片上传成功回调
|
||||
* @param fileDetails
|
||||
*/
|
||||
const onUploadImage = (fileDetails: FileDetails) => {
|
||||
form.image = fileDetails.filepath;
|
||||
};
|
||||
#end
|
||||
#end
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<${lowerHyphen}-dialog :form="form" :on-close="onClose" :on-submit="onSubmit"
|
||||
#foreach($item in $addDtoFormList)
|
||||
#if($item.name == 'avatar' || $item.name == 'image')
|
||||
:on-upload-callback="onUploadImage"
|
||||
#end
|
||||
#end
|
||||
:visible="${storeId}Store.addDialogVisible" title="添加信息" />
|
||||
</template>
|
|
@ -0,0 +1,91 @@
|
|||
<script lang="ts" setup>
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { sexConstant } from '@/enum/baseConstant';
|
||||
import SimpleDialog from '@/components/Dialog/SimpleDialog.vue';
|
||||
import { ref } from 'vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { rules } from '${columnsPath}columns';
|
||||
import { userStatus } from '@/enum/views/userConstant';
|
||||
import UploadDialogImage from '@/components/Upload/UploadDialogImage.vue';
|
||||
import { ${className}AddDto, ${className}State, ${className}UpdateDto } from '${storeTypePath}${lowercaseName}';
|
||||
import { use${className}Store } from '${storePath}${lowercaseName}';
|
||||
|
||||
defineProps({
|
||||
// 是否显示弹窗
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 标题内容
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
// 表单内容
|
||||
form: {
|
||||
type: Object as PropType<${className}AddDto>,
|
||||
},
|
||||
// 关闭弹窗
|
||||
onClose: {
|
||||
type: Function as PropType<any>,
|
||||
default: () => {},
|
||||
},
|
||||
// 提交呢内容
|
||||
onSubmit: {
|
||||
type: Function as PropType<any>,
|
||||
},
|
||||
// 上传成功后毁掉
|
||||
onUploadCallback: {
|
||||
type: Function as PropType<any>,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SimpleDialog :show="visible" :title="title" width="600" @onCancel="onClose" @onConfirm="onSubmit(ruleFormRef)">
|
||||
<el-form ref="ruleFormRef" :model="form" :rules="rules" class="grid" isDefault-icon label-position="left">
|
||||
#foreach($item in $addDtoFormList)
|
||||
#if($item.name == 'image')
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('user.image')" prop="image">
|
||||
<UploadDialogImage :image-url="form.image" type="avatar" @uploadCallback="onUploadCallback" />
|
||||
</el-form-item>
|
||||
|
||||
#elseif($item.name == 'avatar')
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('user.avatar')" prop="avatar">
|
||||
<UploadDialogImage :image-url="form.avatar" type="avatar" @uploadCallback="onUploadCallback" />
|
||||
</el-form-item>
|
||||
|
||||
#elseif($item.name == 'sex')
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('user.sex')" prop="sex">
|
||||
<el-select v-model="form.sex!" :placeholder="$t('user.sex')" clearable filterable>
|
||||
<el-option v-for="(item, index) in sexConstant" :key="index" :label="item.label" :navigationBar="false" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
#elseif($item.name == 'status')
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('user.status')" prop="status">
|
||||
<el-select v-model="form.status!" :placeholder="$t('user.$item.name')" clearable filterable>
|
||||
<el-option v-for="(item, index) in userStatus" :key="index" :label="item.label" :navigationBar="false" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
#else
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('${commonPreFix}.$item.name')" prop="$item.name">
|
||||
<el-input v-model="form.$item.name!" :placeholder="$t('${commonPreFix}.$item.name')" clearable />
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
</el-form>
|
||||
|
||||
<template #footer-add>
|
||||
<slot name="footer" />
|
||||
</template>
|
||||
</SimpleDialog>
|
||||
</template>
|
|
@ -0,0 +1,52 @@
|
|||
<script lang="ts" setup>
|
||||
import ${className}Dialog from '${vuePath}${lowerHyphen}-dialog.vue';
|
||||
import { updateForm } from '${columnsPath}handler';
|
||||
import type { FileDetails } from '@/types/common/file';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { use${className}Store } from '${storePath}${lowercaseName}';
|
||||
|
||||
const ${storeId}Store = use${className}Store();
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
Object.assign(updateForm, {});
|
||||
${storeId}Store.updateDialogVisible = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当提交更新用户
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 更新数据
|
||||
const isSuccess = await ${storeId}Store.update${className}(updateForm);
|
||||
if (!isSuccess) return;
|
||||
// 关闭弹窗
|
||||
Object.assign(updateForm, {});
|
||||
${storeId}Store.updateDialogVisible = false;
|
||||
// 获取用户数据
|
||||
await ${storeId}Store.get${className}List();
|
||||
} else {
|
||||
ElMessage.closeAll();
|
||||
ElMessage.warning($t('status.requiredFields'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* * 图片上传成功回调
|
||||
* @param fileDetails
|
||||
*/
|
||||
const onUploadImage = (fileDetails: FileDetails) => {
|
||||
updateForm.avatar = fileDetails.filepath;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<${lowerHyphen}-dialog :form="updateForm" :on-close="onClose" :on-submit="onSubmit" :on-upload-callback="onUploadImage" :visible="${storeId}Store.updateDialogVisible" title="更新信息" />
|
||||
</template>
|
|
@ -0,0 +1,104 @@
|
|||
<script lang="ts" setup>
|
||||
import TablePlusBar from '@/components/TableBar/src/TablePlusBar.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { columns } from '${columnsPath}columns';
|
||||
import { getDataList, handleSelectionChange, ids, onAdd, onCurrentPageChange, onDelete, onDeleteBatch, onPageSizeChange, onUpdate } from '${columnsPath}handler';
|
||||
import TableImage from '@/components/Table/TableImage.vue';
|
||||
import { DeleteFilled, Plus } from '@element-plus/icons-vue';
|
||||
import ${className}Add from '${vuePath}${lowerHyphen}-add.vue';
|
||||
import ${className}Update from '${vuePath}${lowerHyphen}-update.vue';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { articleModeConstant, layoutConstant, userStatus } from '@/enum/views/userConstant';
|
||||
import { sexConstant } from '@/enum/baseConstant';
|
||||
import UserStatusTag from '@/components/Table/Userinfo/UserStatusTag.vue';
|
||||
import { selectUserinfo } from '@/components/Table/Userinfo/columns';
|
||||
import { use${className}Store } from '${storePath}${lowercaseName}';
|
||||
|
||||
|
||||
const ${storeId}Store = use${className}Store();
|
||||
const column = ref(columns);
|
||||
|
||||
onMounted(() => {
|
||||
getDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<${lowerHyphen}-add />
|
||||
<${lowerHyphen}-update />
|
||||
<TablePlusBar
|
||||
:column="column"
|
||||
:data-list="${storeId}Store.dataList"
|
||||
:handle-current-change="onCurrentPageChange"
|
||||
:handle-selection-change="handleSelectionChange"
|
||||
:handle-size-change="onPageSizeChange"
|
||||
:loading="${storeId}Store.loading"
|
||||
:model="${storeId}Store.form"
|
||||
:on-re-fresh="getDataList"
|
||||
:on-search="getDataList"
|
||||
:pagination="${storeId}Store.pagination"
|
||||
:table-delete="onDelete"
|
||||
:table-edit="onUpdate"
|
||||
class="flex-1"
|
||||
@change-column="args => (column = args)"
|
||||
>
|
||||
<!-- 表单搜索 -->
|
||||
<template #tableForm>
|
||||
#foreach($item in $formList)
|
||||
|
||||
#if($item.name == 'status')
|
||||
<el-form-item :label="$t('user.status')" prop="status" style="width: 240px">
|
||||
<el-select v-model="${storeId}Store.form.status!" :placeholder="$t('user.status')" clearable filterable>
|
||||
<el-option v-for="(item, index) in userStatus" :key="index" :label="item.label" :navigationBar="false" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
#elseif($item.name == 'sex')
|
||||
<el-form-item :label="$t('user.sex')" prop="sex" style="width: 240px">
|
||||
<el-select v-model="${storeId}Store.form.sex!" :placeholder="$t('user.sex')" clearable filterable>
|
||||
<el-option v-for="(item, index) in sexConstant" :key="index" :label="item.label" :navigationBar="false" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
#else
|
||||
<!-- $item.annotation -->
|
||||
<el-form-item :label="$t('${commonPreFix}.$item.name')" prop="nickName">
|
||||
<el-input v-model="${storeId}Store.form.$item.name!" :placeholder="$t('${commonPreFix}.$item.name')" clearable />
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
</template>
|
||||
|
||||
<!-- 表单头部操作按钮 -->
|
||||
<template #tableButtons>
|
||||
<el-button :icon="Plus" type="primary" @click="onAdd">{{ $t('buttons.add') }}</el-button>
|
||||
<el-button v-show="ids.length > 0" :icon="DeleteFilled" type="danger" @click="onDeleteBatch">
|
||||
{{ $t('buttons.deleteBatches') }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
#foreach($item in $columnsField)
|
||||
#if($item.name == 'avatar')
|
||||
<template #avatar="{ row }">
|
||||
<TableImage :image="row.avatar" />
|
||||
</template>
|
||||
#elseif($item.name == 'image')
|
||||
<template #image="{ row }">
|
||||
<TableImage :image="row.image" />
|
||||
</template>
|
||||
#elseif($item.name == 'status')
|
||||
<template #status="{ row }">
|
||||
<UserStatusTag :status="row.status == 1" />
|
||||
</template>
|
||||
#end
|
||||
#end
|
||||
<template #createUser="{ row }">
|
||||
<el-button link type="primary" @click="selectUserinfo(row.createUser)">{{ $t('table.createUser') }}</el-button>
|
||||
</template>
|
||||
<template #updateUser="{ row }">
|
||||
<el-button link type="primary" @click="selectUserinfo(row.updateUser)">{{ $t('table.updateUser') }}</el-button>
|
||||
</template>
|
||||
</TablePlusBar>
|
||||
</div>
|
||||
</template>
|
|
@ -36,9 +36,6 @@ public class Router extends BaseEntity {
|
|||
@Schema(name = "frameSrc", title = "frame路径")
|
||||
private String frameSrc;
|
||||
|
||||
@Schema(name = "redirect", title = "重定向")
|
||||
private String redirect;
|
||||
|
||||
@Schema(name = "routeName", title = "路由名称")
|
||||
private String routeName;
|
||||
|
||||
|
@ -51,24 +48,9 @@ public class Router extends BaseEntity {
|
|||
@Schema(name = "icon", title = "图标")
|
||||
private String icon;
|
||||
|
||||
@Schema(name = "enterTransition", title = "进入动画")
|
||||
private String enterTransition;
|
||||
|
||||
@Schema(name = "leaveTransition", title = "退出动画")
|
||||
private String leaveTransition;
|
||||
|
||||
@Schema(name = "routerRank", title = "等级")
|
||||
private Integer routerRank;
|
||||
|
||||
@Schema(name = "hiddenTag", title = "是否隐藏标签")
|
||||
private Boolean hiddenTag;
|
||||
|
||||
@Schema(name = "fixedTag", title = "是否固定标签")
|
||||
private Boolean fixedTag;
|
||||
|
||||
@Schema(name = "showParent", title = "是否显示父级")
|
||||
private Boolean showParent;
|
||||
|
||||
@Schema(name = "visible", title = "是否显示 返给前端为 showLink")
|
||||
private Boolean visible;
|
||||
|
||||
|
|
|
@ -35,9 +35,6 @@ public class RouterManageVo extends BaseVo {
|
|||
@ApiModelProperty("frame路径")
|
||||
private String frameSrc;
|
||||
|
||||
@ApiModelProperty("重定向")
|
||||
private String redirect;
|
||||
|
||||
@ApiModelProperty("路由名称")
|
||||
@NotBlank(message = "路由名称不能为空")
|
||||
@JsonProperty("name")
|
||||
|
@ -52,25 +49,10 @@ public class RouterManageVo extends BaseVo {
|
|||
@ApiModelProperty("图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty("进入动画")
|
||||
private String enterTransition;
|
||||
|
||||
@ApiModelProperty("退出动画")
|
||||
private String leaveTransition;
|
||||
|
||||
@ApiModelProperty("等级")
|
||||
@JsonProperty("rank")
|
||||
private Integer routerRank;
|
||||
|
||||
@ApiModelProperty("是否隐藏标签")
|
||||
private Boolean hiddenTag;
|
||||
|
||||
@ApiModelProperty("是否固定标签")
|
||||
private Boolean fixedTag;
|
||||
|
||||
@ApiModelProperty("是否显示父级")
|
||||
private Boolean showParent;
|
||||
|
||||
@ApiModelProperty("是否显示 返给前端为 showLink")
|
||||
private Boolean visible;
|
||||
|
||||
|
|
|
@ -32,22 +32,11 @@ public class RouterMeta {
|
|||
@ApiModelProperty(value = "权限列表")
|
||||
private List<String> auths;
|
||||
|
||||
@ApiModelProperty("是否显示父级")
|
||||
private Boolean showParent;
|
||||
|
||||
@ApiModelProperty("是否显示 返给前端为 showLink")
|
||||
@JsonProperty("showLink")
|
||||
private Boolean visible;
|
||||
|
||||
@ApiModelProperty("路由动画")
|
||||
private RouterTransition transition;
|
||||
|
||||
@ApiModelProperty("frame路径")
|
||||
private String frameSrc;
|
||||
|
||||
@ApiModelProperty("是否隐藏标签")
|
||||
private Boolean hiddenTag;
|
||||
|
||||
@ApiModelProperty("是否固定标签")
|
||||
private Boolean fixedTag;
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package cn.bunny.dao.vo.router;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@ApiModel(value = "RouterTransition对象", description = "路由动画")
|
||||
public class RouterTransition {
|
||||
|
||||
@ApiModelProperty("进入动画")
|
||||
private String enterTransition;
|
||||
|
||||
@ApiModelProperty("退出动画")
|
||||
private String leaveTransition;
|
||||
|
||||
}
|
|
@ -26,7 +26,7 @@ public class UserRouterVo {
|
|||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
@JSONField(serializeUsing = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
|
||||
@ApiModelProperty("菜单类型")
|
||||
private Integer menuType;
|
||||
|
||||
|
@ -53,9 +53,6 @@ public class UserRouterVo {
|
|||
@JsonProperty("rank")
|
||||
private Integer routerRank;
|
||||
|
||||
@ApiModelProperty("重定向")
|
||||
private String redirect;
|
||||
|
||||
@ApiModelProperty("路由Meta")
|
||||
private RouterMeta meta;
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package cn.bunny.dao.vo.user;
|
||||
|
||||
import cn.bunny.dao.vo.BaseVo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容")
|
||||
public class UserVo extends BaseVo {
|
||||
|
||||
@Schema(name = "nickName", title = "昵称")
|
||||
private String nickName;
|
||||
|
||||
@Schema(name = "username", title = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(name = "email", title = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(name = "phone", title = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(name = "avatar", title = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(name = "sex", title = "0:女 1:男")
|
||||
private Byte sex;
|
||||
|
||||
@Schema(name = "personDescription", title = "个人描述")
|
||||
private String personDescription;
|
||||
|
||||
@Schema(name = "status", title = "1:禁用 0:正常")
|
||||
private Byte status;
|
||||
|
||||
}
|
|
@ -4,15 +4,14 @@ import cn.bunny.dao.dto.user.RefreshTokenDto;
|
|||
import cn.bunny.dao.pojo.result.Result;
|
||||
import cn.bunny.dao.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.dao.vo.user.RefreshTokenVo;
|
||||
import cn.bunny.dao.vo.user.UserVo;
|
||||
import cn.bunny.services.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
||||
@Tag(name = "系统用户", description = "系统用户相关接口")
|
||||
|
@ -43,4 +42,11 @@ public class UserController {
|
|||
userService.logout();
|
||||
return Result.success(ResultCodeEnum.LOGOUT_SUCCESS);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户信息", description = "获取用户信息")
|
||||
@GetMapping("getUserinfoById")
|
||||
public Mono<Result<UserVo>> getUserinfoById(Long id) {
|
||||
UserVo vo = userService.getUserinfoById(id);
|
||||
return Mono.just(Result.success(vo));
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package cn.bunny.services.service;
|
|||
import cn.bunny.dao.dto.user.RefreshTokenDto;
|
||||
import cn.bunny.dao.entity.system.AdminUser;
|
||||
import cn.bunny.dao.vo.user.RefreshTokenVo;
|
||||
import cn.bunny.dao.vo.user.UserVo;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -36,4 +37,12 @@ public interface UserService extends IService<AdminUser> {
|
|||
* * 退出登录
|
||||
*/
|
||||
void logout();
|
||||
|
||||
/**
|
||||
* * 获取用户信息
|
||||
*
|
||||
* @param id 用户id
|
||||
* @return 用户信息
|
||||
*/
|
||||
UserVo getUserinfoById(Long id);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import cn.bunny.dao.pojo.result.PageResult;
|
|||
import cn.bunny.dao.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.dao.vo.router.RouterManageVo;
|
||||
import cn.bunny.dao.vo.router.RouterMeta;
|
||||
import cn.bunny.dao.vo.router.RouterTransition;
|
||||
import cn.bunny.dao.vo.router.UserRouterVo;
|
||||
import cn.bunny.dao.vo.user.LoginVo;
|
||||
import cn.bunny.services.factory.RouterServiceFactory;
|
||||
|
@ -88,10 +87,6 @@ public class RouterServiceImpl extends ServiceImpl<RouterMapper, Router> impleme
|
|||
UserRouterVo routerVo = new UserRouterVo();
|
||||
BeanUtils.copyProperties(router, routerVo);
|
||||
|
||||
// 复制路由动画
|
||||
RouterTransition transition = new RouterTransition();
|
||||
BeanUtils.copyProperties(router, transition);
|
||||
|
||||
// 设置
|
||||
RouterMeta meta = RouterMeta.builder()
|
||||
.rank(router.getRouterRank())
|
||||
|
@ -99,7 +94,6 @@ public class RouterServiceImpl extends ServiceImpl<RouterMapper, Router> impleme
|
|||
.title(router.getTitle())
|
||||
.roles(roleList)
|
||||
.auths(powerCodeList)
|
||||
.transition(transition)
|
||||
.build();
|
||||
|
||||
routerVo.setMeta(meta);
|
||||
|
|
|
@ -3,6 +3,7 @@ package cn.bunny.services.service.impl;
|
|||
import cn.bunny.common.service.context.BaseContext;
|
||||
import cn.bunny.common.service.exception.BunnyException;
|
||||
import cn.bunny.common.service.utils.JwtHelper;
|
||||
import cn.bunny.common.service.utils.minio.MinioUtil;
|
||||
import cn.bunny.dao.dto.user.RefreshTokenDto;
|
||||
import cn.bunny.dao.entity.system.AdminUser;
|
||||
import cn.bunny.dao.entity.system.EmailUsers;
|
||||
|
@ -11,6 +12,7 @@ import cn.bunny.dao.pojo.constant.RedisUserConstant;
|
|||
import cn.bunny.dao.pojo.result.ResultCodeEnum;
|
||||
import cn.bunny.dao.vo.user.LoginVo;
|
||||
import cn.bunny.dao.vo.user.RefreshTokenVo;
|
||||
import cn.bunny.dao.vo.user.UserVo;
|
||||
import cn.bunny.services.factory.EmailFactory;
|
||||
import cn.bunny.services.factory.UserFactory;
|
||||
import cn.bunny.services.mapper.EmailUsersMapper;
|
||||
|
@ -24,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -47,6 +50,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
|||
|
||||
@Autowired
|
||||
private EmailFactory emailFactory;
|
||||
@Autowired
|
||||
private MinioUtil minioUtil;
|
||||
|
||||
/**
|
||||
* 登录发送邮件验证码
|
||||
|
@ -97,4 +102,23 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
|||
LoginVo loginVo = BaseContext.getLoginVo();
|
||||
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(loginVo.getUsername()));
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取用户信息
|
||||
*
|
||||
* @param id 用户id
|
||||
* @return 用户信息
|
||||
*/
|
||||
@Override
|
||||
public UserVo getUserinfoById(Long id) {
|
||||
if (id == null) throw new BunnyException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||
AdminUser user = getById(id);
|
||||
String avatar = user.getAvatar();
|
||||
|
||||
UserVo userVo = new UserVo();
|
||||
BeanUtils.copyProperties(user, userVo);
|
||||
|
||||
if (StringUtils.hasText(avatar)) userVo.setAvatar(minioUtil.getObjectNameFullPath(avatar));
|
||||
return userVo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,17 +9,11 @@
|
|||
<result column="path" property="path"/>
|
||||
<result column="component" property="component"/>
|
||||
<result column="frame_src" property="frameSrc"/>
|
||||
<result column="redirect" property="redirect"/>
|
||||
<result column="route_name" property="routeName"/>
|
||||
<result column="title" property="title"/>
|
||||
<result column="menu_type" property="menuType"/>
|
||||
<result column="icon" property="icon"/>
|
||||
<result column="enter_transition" property="enterTransition"/>
|
||||
<result column="leave_transition" property="leaveTransition"/>
|
||||
<result column="router_rank" property="routerRank"/>
|
||||
<result column="hidden_tag" property="hiddenTag"/>
|
||||
<result column="fixed_tag" property="fixedTag"/>
|
||||
<result column="show_parent" property="showParent"/>
|
||||
<result column="visible" property="visible"/>
|
||||
<result column="create_user" property="createUser"/>
|
||||
<result column="update_user" property="updateUser"/>
|
||||
|
@ -30,7 +24,7 @@
|
|||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, parent_id, path, component, frame_src, redirect, route_name, title, menuType, icon, enter_transition, leave_transition, router_rank, hidden_tag, fixed_tag, show_parent, visible, create_user, update_user, update_time, create_time, is_deleted
|
||||
id, parent_id, path, component, frame_src, route_name, title, menuType, icon, router_rank, visible, create_user, update_user, update_time, create_time, is_deleted
|
||||
</sql>
|
||||
|
||||
<!-- 物理删除路由菜单 -->
|
||||
|
|
Loading…
Reference in New Issue