列表显示字典数据(方案1)
template里面的vue代码
<el-table-column label="性别" align="center" prop="sex">
<template #default="scope">
<!-- <dict-tag :options=sysUserSex :value="scope.row.sex"/>-->
{{dictDataLabel( scope.row.sex,sysUserSex )}}
</template>
</el-table-column>
<el-table-column label="婚姻状况" align="center" prop="maritalStatus">
<template #default="scope">
<!-- <dict-tag :options="sys_status" :value="scope.row.maritalStatus"/>-->
{{dictDataLabel( scope.row.maritalStatus,maritalStatusList )}}
</template>
</el-table-column>
<el-table-column label="民族" align="center" prop="nation">
<template #default="scope">
<!-- <dict-tag :options="sys_user_sex" :value="scope.row.nation"/>-->
{{dictDataLabel( scope.row.nation,nationList )}}
</template>
</el-table-column>
<el-table-column label="政治面貌" align="center" prop="politicalOutlook">
<template #default="scope">
<!-- <dict-tag :options="sys_status" :value="scope.row.politicalOutlook"/>-->
{{dictDataLabel( scope.row.politicalOutlook,politicalOutlookList )}}
</template>
</el-table-column>
获取数据(手动查询字典数据)
// 查询字典集合,
const sysUserSex = ref();
dictByType();
// 手动查询字典数据
function dictByType(){
selectDictByKey( 'sys_user_sex' ).then(res => {
sysUserSex.value = res.data;
})
}
// 查询字典集合,
const maritalStatusList = ref();
maritalStatusByType();
function maritalStatusByType(){
selectDictByKey( 'marital_status' ).then(res => {
maritalStatusList.value = res.data;
})
}
// 查询字典集合,
const nationList = ref();
nationListByType();
function nationListByType(){
selectDictByKey( 'nation' ).then(res => {
nationList.value = res.data;
})
}
// 查询字典集合,
const politicalOutlookList = ref();
politicalOutlookListByType();
function politicalOutlookListByType(){
selectDictByKey( 'political_outlook' ).then(res => {
politicalOutlookList.value = res.data;
})
}
// 获取字典数据和业务表的数据比对,如果是同一个key,会显示对应字典的value
function dictDataLabel(dataValue, dataList) {
if (dataValue) {
let dictData = dataList;
let item = dictData.find(item => item.dictValue == dataValue)
if (item) {
return item.dictLabel;
}
}
}
// 获取字典数据和业务表的数据比对,如果是同一个key,会显示对应字典的value
function dictDataLabel( dataValue ,dataList ){
if( dataValue ){
let dictData = dataList ;
let item = dictData.find( item=>item.dictValue == dataValue )
if( item){
return item.dictLabel;
}
}
}
校验文件上传大小
<el-row justify="center">
<el-col :span="24">
<el-form-item class="display-flex" label="企业LOGO" prop="companyLogoUr">
<el-upload
class="avatar-uploader logo-img"
:action=action
:show-file-list="false"
:on-success="uploadImgCompanyLogoUr"
>
<el-image v-if="companyLogoUr" :src="companyLogoUr" class="avatar logo-img"/>
<el-icon v-else class="avatar-uploader-icon logo-img">
<Plus/>
</el-icon>
</el-upload>
</el-form-item>
</el-col>
</el-row>
// 上传前校检格式和大小
function handleBeforeUpload(file) {
// 校验文件名长度
if( file.name.length > 50 ){
ElMessage.error('上传文件名长度不能超过50个汉字!')
return false
}
// 校检文件大小
if( file.size / 1024 / 1024 > 10 ) {
ElMessage.error('上传图片大小不能超过 10MB!')
return false
}
return true;
}
若依树结构下载选择添加
添加下拉框的标签; dictOptionsShowAppType是数据
<el-form-item label="app移动端渲染类型" prop="showAppType">
<treeselect v-model="form.showAppType" :options="dictOptionsShowAppType" :show-count="true" placeholder="请选择app移动端渲染类型" />
</el-form-item>
定义数据: dictOptionsShowAppType: undefined,
引入jd
import { getToken } from "@/utils/auth";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { dictTreeSelect,dictListSelect } from '@/api/lowCode/modelDict'
获取数据
getDictTreeShowAppType() {
let param = {
dictCode: 'render_type',
}
dictTreeSelect(param).then(response => {
this.dictOptionsShowAppType = response.data;
});
},
// 查询下拉树结构
export function dictTreeSelect(query) {
return request({
url: '/system/modelDict/dictTree',
method: 'get',
params: query
})
}
自定义form表单下拉树结构添加数据后,列表显示id或者key,不显示树的名字(方案2)
解决方案: modelCategory是列表显示字段;sexFormat定义点击事件
<el-table-column label="模型分类" prop='modelCategory' :formatter="sexFormat" >
</el-table-column>
<el-table-column label="模型类型" prop='modelType' :formatter="sexFormatModelType" >
</el-table-column>
先查询字典树的所有列表数据,注意是列表,不是树结构
dictListOptions: [],
/** 查询所有字典数据列表 */
getDictList() {
dictListSelect().then(response => {
this.dictListOptions = response.data;
});
},
// 编辑字典和列表返回的id或者字典key去比较,如果相同则发返回对应字典的dictLabel名字,然后渲染到列表
sexFormat(row) {
let obj = ''
this.dictListOptions.forEach((item) => {
if (row.modelCategory == item.id) {
obj = item.dictLabel
}
})
return obj
},
// 编辑字典和列表返回的id或者字典key去比较,如果相同则发返回对应字典的dictLabel名字,然后渲染到列表
sexFormatModelType(row) {
let obj = ''
this.dictListOptions.forEach((item) => {
if (row.modelType == item.id) {
obj = item.dictLabel
}
})
return obj
},
后端自定义树结构
control代码/** * 获取字典树列表 */ @GetMapping("/dictTree") public AjaxResult deptTree(LowModelDict dept) { return success(lowModelDictService.selectLowModelDictTreeList(dept)); }
service实现类
@Override public List<TreeSelect> selectLowModelDictTreeList(LowModelDict dept) { // 如果不传父级结构,指定一个父级结构 if( StringUtils.isBlank( dept.getDictCode() )){ dept.setDictCode("increment_type"); } // 查询单条父级数据 LowModelDict lowModelDict = lowModelDictMapper.selectOneModelDict(dept); // 查询全部数据 List<LowModelDict> depts = lowModelDictMapper.selectLowModelDictList(dept); List<TreeSelect> treeSelects = buildDeptTreeSelect(depts, lowModelDict ); return treeSelects; } public List<TreeSelect> buildDeptTreeSelect(List<LowModelDict> depts, LowModelDict lowModelDict ) { List<LowModelDict> deptTrees = buildDeptTree(depts , lowModelDict ); return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); } public List<LowModelDict> buildDeptTree(List<LowModelDict> depts, LowModelDict lowModelDict) { List<LowModelDict> returnList = new ArrayList<LowModelDict>(); // List<Long> tempList = depts.stream().map(LowModelDict::getId).collect(Collectors.toList()); // 获取所有的树结构数据 Long id = lowModelDict.getId(); for (LowModelDict dept : depts) { // 如果是顶级节点, 遍历该父节点的所有子节点 // if (!tempList.contains(dept.getParentId())) { // 获取所有的树结构数据 // if ( id.longValue() == dept.getParentId().longValue() ) { // 不包括父级 if ( id.longValue() == dept.getId().longValue() ) { // 包括父级 recursionFn(depts, dept); returnList.add(dept); } } if (returnList.isEmpty()) { returnList = depts; } return returnList; } /** * 递归列表 */ private void recursionFn(List<LowModelDict> list, LowModelDict t) { // 得到子节点列表 List<LowModelDict> childList = getChildList(list, t); t.setChildren(childList); for (LowModelDict tChild : childList) { if (hasChild(list, tChild)) { recursionFn(list, tChild); } } } private boolean hasChild(List<LowModelDict> list, LowModelDict t) { return getChildList(list, t).size() > 0; } /** * 得到子节点列表 */ private List<LowModelDict> getChildList(List<LowModelDict> list, LowModelDict t) { List<LowModelDict> tlist = new ArrayList<LowModelDict>(); Iterator<LowModelDict> it = list.iterator(); while (it.hasNext()) { LowModelDict n = (LowModelDict) it.next(); if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getId().longValue()) { tlist.add(n); } } return tlist; }
mapper接口
/** * 查询数据字典列表 * * @param lowModelDict 数据字典 * @return 数据字典集合 */ public List<LowModelDict> selectLowModelDictList(LowModelDict lowModelDict);// 查询单条父级数据 LowModelDict selectOneModelDict(LowModelDict lowModelDict);
xml的sql
// 查询单条父级数据 <select id="selectOneModelDict" parameterType="LowModelDict" resultMap="LowModelDictResult"> SELECT * FROM low_model_dict where dict_code = #{dictCode} </select>查询数据字典列表
<sql id="selectLowModelDictVo"> select id, parent_id, dict_code, dict_label, dict_sort, dict_flag, dict_1, dict_2, dict_3, dict_4, dict_5, dict_seq, status, create_by, create_date, update_by, update_date, remarks from low_model_dict </sql> <select id="selectLowModelDictList" parameterType="LowModelDict" resultMap="LowModelDictResult"> <include refid="selectLowModelDictVo"/> <where> <if test="dictLabel != null and dictLabel != ''"> and dict_label like concat('%', #{dictLabel}, '%')</if> <if test="remarks != null and remarks != ''"> and remarks = #{remarks}</if> </where> </select>
实体类;注意这里是继承 BaseEntity
package com.ruoyi.common.core.domain.entity;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.TreeEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 数据字典对象 low_model_dict
*
* @author ruoyi
* @date 2023-10-24
*/
public class LowModelDict extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 字典编号主键
*/
private Long id;
/** 父部门ID */
private Long parentId;
/**
* 字典代码 唯一
*/
@Excel(name = "字典代码 唯一")
private String dictCode;
/**
* 字典名称
*/
@Excel(name = "字典名称")
private String dictLabel;
/**
* 字典顺序
*/
private Long dictSort;
/**
* 字典标记 1 有效 0 失效
*/
private Long dictFlag;
/**
* 扩展字段1
*/
private String dict1;
/**
* 扩展字段2
*/
private String dict2;
/**
* 扩展字段3
*/
private String dict3;
/**
* 扩展字段4
*/
private String dict4;
/**
* 扩展字段5
*/
private String dict5;
/**
* 字典序列
*/
@Excel(name = "字典序列")
private String dictSeq;
/**
* 状态(0正常 1删除 2停用)
*/
private String status;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新时间
*/
private Date updateDate;
/**
* 备注信息
*/
private String remarks;
private List<LowModelDict> children = new ArrayList<LowModelDict>();
public List<LowModelDict> getChildren() {
return children;
}
public void setChildren(List<LowModelDict> children) {
this.children = children;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setDictCode(String dictCode) {
this.dictCode = dictCode;
}
public String getDictCode() {
return dictCode;
}
public void setDictLabel(String dictLabel) {
this.dictLabel = dictLabel;
}
public String getDictLabel() {
return dictLabel;
}
public void setDictSort(Long dictSort) {
this.dictSort = dictSort;
}
public Long getDictSort() {
return dictSort;
}
public void setDictFlag(Long dictFlag) {
this.dictFlag = dictFlag;
}
public Long getDictFlag() {
return dictFlag;
}
public void setDict1(String dict1) {
this.dict1 = dict1;
}
public String getDict1() {
return dict1;
}
public void setDict2(String dict2) {
this.dict2 = dict2;
}
public String getDict2() {
return dict2;
}
public void setDict3(String dict3) {
this.dict3 = dict3;
}
public String getDict3() {
return dict3;
}
public void setDict4(String dict4) {
this.dict4 = dict4;
}
public String getDict4() {
return dict4;
}
public void setDict5(String dict5) {
this.dict5 = dict5;
}
public String getDict5() {
return dict5;
}
public void setDictSeq(String dictSeq) {
this.dictSeq = dictSeq;
}
public String getDictSeq() {
return dictSeq;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getCreateDate() {
return createDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
public String getRemarks() {
return remarks;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("parentId", getParentId())
.append("dictCode", getDictCode())
.append("dictLabel", getDictLabel())
.append("dictSort", getDictSort())
.append("dictFlag", getDictFlag())
.append("dict1", getDict1())
.append("dict2", getDict2())
.append("dict3", getDict3())
.append("dict4", getDict4())
.append("dict5", getDict5())
.append("dictSeq", getDictSeq())
.append("status", getStatus())
.append("createBy", getCreateBy())
.append("createDate", getCreateDate())
.append("updateBy", getUpdateBy())
.append("updateDate", getUpdateDate())
.append("remarks", getRemarks())
.toString();
}
}
主键是 Long 类型的时候数据库字段是 bigint 由于长度超过16;返回前端会有精度丢失,导致后端返回的时间id和前端接受的实际id不一致,导致修改失败,需要在启动类添加配置代码
// 处理Long 类型 返回前端精度丢失问题 @Bean public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); return objectMapper; }
若依框架集成 MybatisPlusConfig 添加依赖
commin 模块 pom.xml
<!-- 新增依赖 --> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency>
最外层的pom.xml
<!-- 新增依赖 --> <!-- mybatis plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- pagehelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.boot.version}</version> <exclusions> <exclusion> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </exclusion> </exclusions> </dependency>
注释原来 MyBatisConfig
添加 MybatisPlus 的配置类 MybatisPlusConfig
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
/**
* Mybatis Plus 配置
*
* @author ruoyi
*/
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
// 乐观锁插件
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
// 阻断插件
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
return interceptor;
}
/**
* 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
*/
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置数据库类型为mysql
paginationInnerInterceptor.setDbType(DbType.MYSQL);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
return paginationInnerInterceptor;
}
/**
* 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
*/
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}
/**
* 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
*/
public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
return new BlockAttackInnerInterceptor();
}
}
修改 BaseEntity 类 ;移除部分不用的字段;不移除 mp 查询会报错;因为数据库没相关字段 @TableField(exist = false)
修改配置 application.yml 文件;移除mybatis的配置,添加mybatisPlus的配置
# MyBatis配置
#mybatis:
# # 搜索指定包别名
# typeAliasesPackage: com.ruoyi.**.domain
# # 配置mapper的扫描,找到所有的mapper.xml映射文件
# mapperLocations: classpath*:mapper/**/*Mapper.xml
# # 加载全局的配置文件
# configLocation: classpath:mybatis/mybatis-config.xml
# MyBatis Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain.**
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
集成 mybatisplus 的分页查询 IPage
基础实体类继承分页参数类;BaseEntity extends PageDomain
注意、注意、注意
PageDomain 分页类要移除相关字段,数据库表没有相关字段,否则mp查询报错
集成创建时间、创建人、修改时间、修改人等自动填充
添加依赖 ruoyi-framework
<!-- 新增依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency>
添加自动填充配置类 MyMetaObjectHandler;注意 createTime、createDate等字段在实体类要配置注解;
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
String operator = null;
try {
operator = SecurityUtils.getUsername();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
this.setFieldValByName("createBy", operator, metaObject);
this.setFieldValByName("createDate", new Date(), metaObject);
this.setFieldValByName("updateBy", operator, metaObject);
this.setFieldValByName("updateDate", new Date(), metaObject);
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
String operator = null;
try {
operator = SecurityUtils.getUsername();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
this.setFieldValByName("updateBy", operator, metaObject);
this.setFieldValByName("updateData", new Date(), metaObject);
}
}
基础实体类 BaseEntity 字段要添加注解;
@TableField(value = "create_time",fill = FieldFill.INSERT) // 要和数据库一致
如果业务实体类 LowModelCode 里面有需要自动填充的字段;也要添加注解
@TableField(value = "create_time",fill = FieldFill.INSERT) // 要和数据库一致
一个vue文件里面执行方法(包括有异步的情况)
在 onMounted 里面先执行 singleLogin 登录方法,等登录成功后再执行 init() 初始化的方法,登录的同时判断是否有token ,有直接返回,没有就执行登录方法获取token
onMounted(() => {
singleLogin().then(() => {
// singleLogin 执行完毕后再执行 init()
init();
});
});
// 登录
function singleLogin() {
return new Promise((resolve, reject) => {
if (getToken() == undefined || getToken() == null || getToken() == '') {
let param = {
"encryptionStr": getEncryptionStr()
}
singlePointLogin(param).then(res => {
setToken(res.token);
// 注意:在此上下文中,可能无法使用 "this" 来引用当前组件实例
// 如果需要,可以修改为适当的方式引用组件实例
resolve();
}).catch(error => {
// 如果登录过程中发生错误,可以在这里处理
reject(error);
});
} else {
// 如果已经有 Token,直接 resolve
resolve();
}
});
}
若依前端 form表单多tab页
<!--人脸识别服务tab页--> <el-tab-pane label="人脸识别服务配置" name="successUrl" v-if="callbackUrl"> <el-form-item label="成功回调" prop="successUrl" required> <el-input v-model="form.successUrl" placeholder="请输入人脸识别成功回调地址" /> </el-form-item> <el-form-item label="失败回调" prop="failedUrl" required> <el-input v-model="form.failedUrl" placeholder="请输入人脸识别失败回调地址" /> </el-form-item> </el-tab-pane> js 代码 定义 const callbackUrl = ref(false); // 取消按钮 未保存,去掉已经选择的人脸服务数据 使 人脸识别服务tab页 变为默认空值 function cancel() { open.value = false; callbackUrl.value=false; reset(); } 点击下拉框 动态获取数据,并根据是否选中人脸服务 决定是否显示 人脸识别服务tab页 function getChangeClick(data) { let ids = form.value.serviceArr?.map(item => item.value); getChargeType(ids).then(res => { listDict.value = res.data.list; isExitEiis.value=res.data.isExitEiis; }); let label = form.value.serviceArr?.map(item => item.label); if( label.includes('人脸识别') || label.includes('人脸识别服务') || label.includes('人脸') ){ callbackUrl.value=true; }else { callbackUrl.value=false; } } 修改按钮操作 根据返回数据判断是否已经选择人脸服务选项 决定是否显示 人脸识别服务tab页 function handleUpdate(row) { reset(); const _id = row.id || ids.value; getAppinfo(_id).then((response) => { form.value = response.data; let label = form.value.serviceArr?.map(item => item.label); if( label.includes('人脸识别') || label.includes('人脸识别服务') || label.includes('人脸') ){ callbackUrl.value=true; }else { callbackUrl.value=false; } open.value = true; title.value = "修改企业应用"; listDict.value = response.data.listDict; }); callbackUrl.value=true; }