智慧保安后台管理-外网项目备份
guoshilong
2023-12-04 f6fad9857bddebb5bfaad2074e4be73b9b5abc62
Merge remote-tracking branch 'origin/jc' into jc
12 files modified
13 files added
1780 ■■■■ changed files
src/main/java/org/springblade/common/config/MetaObjectConfig.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/excel/ExcelDictConverter.java 93 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/excel/ExcelDictItem.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/excel/ExcelDictItemLabel.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/exam/excel/ExportExamScoreExcel.java 57 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/exam/mapper/ExamScoreMapper.xml 8 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java 266 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/simulateexam/service/impl/SimulateExamRecordServiceImpl.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/controller/UserController.java 438 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/controller/UserDetailController.java 126 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/dto/UserDetailDTO.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/entity/UserDetailEntity.java 145 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/excel/SecurityExcel.java 52 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserDetailMapper.java 43 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserDetailMapper.xml 32 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserMapper.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/mapper/UserMapper.xml 16 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/IUserDetailService.java 26 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/IUserService.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/impl/UserDetailServiceImpl.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java 214 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/vo/UserDetailVO.java 35 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/vo/UserVO.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/org/springblade/modules/system/wrapper/UserDetailWrapper.java 50 ●●●●● patch | view | raw | blame | history
src/main/resources/application-dev.yml 4 ●●●● patch | view | raw | blame | history
src/main/java/org/springblade/common/config/MetaObjectConfig.java
New file
@@ -0,0 +1,31 @@
package org.springblade.common.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component
public class MetaObjectConfig implements MetaObjectHandler {
   @Override
   public void insertFill(MetaObject metaObject) {
       //设置自动插入填充
       this.setFieldValByName("createTime", new Date(), metaObject);
       this.setFieldValByName("create_user", AuthUtil.getUserId(), metaObject);
       this.setFieldValByName("updateTime", new Date(), metaObject);
       this.setFieldValByName("update_user", AuthUtil.getUserId(), metaObject);
   }
   @Override
   public void updateFill(MetaObject metaObject) {
       //设置自动修改填充
       this.setFieldValByName("updateTime", new Date(), metaObject);
       this.setFieldValByName("update_user", AuthUtil.getUserId(), metaObject);
   }
}
src/main/java/org/springblade/common/excel/ExcelDictConverter.java
New file
@@ -0,0 +1,93 @@
package org.springblade.common.excel;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import org.springblade.common.cache.DictBizCache;
import org.springblade.modules.system.entity.DictBiz;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.List;
/**
 * 字典映射
 *
 * @author zhongrj
 * @date 2023-11-17
 */
@Component
public class ExcelDictConverter implements Converter<String> {
    @Override
    public Class supportJavaTypeKey() {
        return Integer.class;
    }
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }
    /**
     * 导入excel 解析到java 对象
     * @param cellData
     * @param excelContentProperty
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public String convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 获取字典类型
        Field field = excelContentProperty.getField();
        ExcelDictItemLabel excel = field.getAnnotation(ExcelDictItemLabel.class);
        String dictType = excel.type();
        // 为空返回
        String dictLabel = cellData.getStringValue();
        if (StrUtil.isBlank(dictLabel)) {
            return dictLabel;
        }
        // 查询字典
        List<DictBiz> list = DictBizCache.getList(dictType);
        //解析返回
        String key = "";
        for (DictBiz dictBiz : list) {
            if (dictBiz.getDictValue().equals(dictLabel)){
                key = dictBiz.getDictKey();
                break;
            }
        }
        // 返回key
        return key;
    }
    /**
     * java 导出到 excel
     * @param dictValue
     * @param excelContentProperty
     * @param globalConfiguration
     * @return
     * @throws Exception
     */
    @Override
    public CellData convertToExcelData(String dictValue, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        // 获取字典类型
        Field field = excelContentProperty.getField();
        ExcelDictItem excel = field.getAnnotation(ExcelDictItem.class);
        String dictType = excel.type();
        List<DictBiz> list = DictBizCache.getList(dictType);
        String value = "";
        //解析返回
        for (DictBiz dictBiz : list) {
            if (dictBiz.getDictKey().equals(dictValue)){
                value = dictBiz.getDictValue();
                break;
            }
        }
        return new CellData(value);
    }
}
src/main/java/org/springblade/common/excel/ExcelDictItem.java
New file
@@ -0,0 +1,25 @@
package org.springblade.common.excel;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * excel导出字典转换注解
 * <p>
 * 将excel导出的字典code自动转换为字典label
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
public @interface ExcelDictItem {
    /**
     * 字典type
     */
    String type();
}
src/main/java/org/springblade/common/excel/ExcelDictItemLabel.java
New file
@@ -0,0 +1,25 @@
package org.springblade.common.excel;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * excel导入字典转换注解
 * <p>
 * 将excel导入的字典label自动转换为字典code
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
public @interface ExcelDictItemLabel {
    /**
     * 字典type
     */
    String type();
}
src/main/java/org/springblade/modules/exam/excel/ExportExamScoreExcel.java
@@ -1,19 +1,3 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.exam.excel;
import com.alibaba.excel.annotation.ExcelIgnore;
@@ -22,6 +6,9 @@
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import org.springblade.common.excel.ExcelDictConverter;
import org.springblade.common.excel.ExcelDictItem;
import org.springblade.common.excel.ExcelDictItemLabel;
import java.io.Serializable;
@@ -89,4 +76,42 @@
    @ColumnWidth(20)
    @ExcelProperty("保安员证编号")
    private String securityNumber;
    /**
     * 婚姻状态
     */
    @ExcelProperty(value = "婚姻状态*(未婚/已婚/离异/丧偶)",converter = ExcelDictConverter.class)
    @ExcelDictItem(type = "marriageStatusType")
    private String marriageStatus;
    /**
     * 报考等级
     */
    @ExcelProperty(value = "报考等级(初级/中级/高级/特级)",converter = ExcelDictConverter.class)
    @ExcelDictItem(type = "signLevelType")
    private String signLevel;
    /**
     * 户籍地址
     */
    @ExcelProperty(value = "户籍地址")
    private String permanentResidenceAddress;
    /**
     * 居住地址
     */
    @ExcelProperty(value = "居住地址")
    private String dwellAddress;
    /**
     * 家庭主要成员及联系方式
     */
    @ExcelProperty(value = "家庭主要成员及联系方式")
    private String memberOfFamily;
    /**
     * 工作经历
     */
    @ExcelProperty(value = "工作经历")
    private String workExperience;
    /**
     * 教育经历
     */
    @ExcelProperty(value = "教育经历")
    private String educationExperience;
}
src/main/java/org/springblade/modules/exam/mapper/ExamScoreMapper.xml
@@ -378,10 +378,14 @@
        case when es.qualified=0 then '合格'
            when es.qualified=1 then '不合格'
            when es.qualified=2 then '暂未录入实操成绩'
        end as qualified
        end as qualified,
        bud.marriage_status marriageStatus,bud.sign_level signLevel,
        bud.permanent_residence_address permanentResidenceAddress,bud.dwell_address dwellAddress,
        bud.member_of_family memberOfFamily,bud.work_experience workExperience,bud.education_experience educationExperience
        from exam_score es
        left join ksxt_exam ke on ke.id = es.exam_id
        left join blade_user bu on es.user_id = bu.id
        left join blade_user bu on es.user_id = bu.id and bu.is_deleted = 0
        left join blade_user_detail bud on bud.user_id = bu.id and bud.is_deleted = 0
        left join blade_dept bd on bd.id = bu.dept_id
        left join sys_training_registration str on str.id = es.apply_id
        left join sys_information si on si.departmentid = bd.id
src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java
@@ -16,6 +16,7 @@
 */
package org.springblade.modules.resource.endpoint;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.minio.*;
import io.minio.errors.*;
import io.swagger.annotations.Api;
@@ -44,6 +45,8 @@
import org.springblade.modules.resource.entity.Attach;
import org.springblade.modules.resource.service.IAttachService;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.service.IUserDetailService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.MyAsyncService;
import org.springframework.web.bind.annotation.*;
@@ -84,6 +87,8 @@
    private final IUserService userService;
    private final IUserDetailService userDetailService;
    private final ExamPaperService examPaperService;
@@ -342,109 +347,52 @@
     * 文件上传,zip
     *
     * @param file 图片对象
     * @param type 1:个人头像上传  2:健康状况图片(健康证) 3:无犯罪记录图片
     */
    @PostMapping("put-file-zip")
    public R putFileZip(@RequestParam MultipartFile file) throws Exception {
    public R putFileZip(@RequestParam MultipartFile file,@RequestParam Integer type) throws Exception {
        Map<String, Object> map = new HashMap<>(1);
        //填写你文件上传的地址以及相应信息
        String url = FileConfig.apiUrl;
        String access = FileConfig.access;
        String secret = FileConfig.secret;
        String bucket = FileConfig.bucket;
        MinioClient minioClient =
            MinioClient.builder()
                .endpoint(url)
                .credentials(access, secret)
                .build();
        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!isExist) {
            // 创建一个名为zip的存储桶,用于zip文件。
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).build());
        }
        String fileName = file.getOriginalFilename();
        String namePath = fileName.substring(0,fileName.lastIndexOf("."));
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(Locale.US);
        //判断文件是不是zip类型
        if(!fileType.equals("zip")){
            throw new ServiceException("上传文件类型不符!必须是 zip 压缩文件格式!");
        }
        // 自定义上传配置设置
        MinioClient minioClient = myUploadConfigSet();
        //FileConfig.localtion是配置文件和config类生产的,测试demo可以直接把FileConfig.localtion替换成D:/test
        String uuid = UUID.randomUUID().toString();
        String desPath = FileConfig.localtion + File.separator + uuid.replaceAll("-", "");
//        String desPath = "D:/test" + File.separator + uuid.replaceAll("-", "");
        //遗漏了这个代码,在本地测试环境不会出问题,在服务器上一定会报没有找到文件的错误
        String savePath = FileConfig.localtion + File.separator;
        FileUtil fileUtil = new FileUtil();
        //解压zip文件
        FileUtil.unZip(file, desPath,savePath);
        List<MultipartFile> fileList = new ArrayList<>();
        //获取图片文件
//        fileList = fileUtil.getSubFiles(desPath+File.separator+namePath,fileList);
        fileList = fileUtil.getSubFiles(desPath,fileList);
        String desPath = getDesPath();
        // 获取文件集合
        List<MultipartFile> fileList = getFileList(file,desPath);
        //将不能导入的保安员账号存起来
        List<String> errorList = new ArrayList<>();
        //导入状态,默认为true ,如果有一个出现问题则为 false
        AtomicBoolean status = new AtomicBoolean(true);
        //遍历
        for (MultipartFile multipartFile : fileList){
            long size = multipartFile.getSize();
            if (size<30*1024 || size>500*1024){
                status.set(false);
                //取出身份证号,查询用户信息,更新用户信息
                String pictrueName = multipartFile.getName().substring(0, multipartFile.getName().lastIndexOf("."));
                String regex ="[\u4e00-\u9fa5]";
                Pattern compile = Pattern.compile(regex);
                String idCardNo = compile.matcher(pictrueName).replaceAll("");
                //加入集合
                errorList.add(idCardNo);
            }
            // 文件大小校验
            fileSizeCheck(errorList, status, multipartFile);
            if(multipartFile.getName().toLowerCase().endsWith(".png") || multipartFile.getName().toLowerCase().endsWith(".jpg")) {
                String newName = "upload/picture/" + UUID.randomUUID().toString().replaceAll("-", "") + multipartFile.getName().substring(multipartFile.getName().lastIndexOf("."));
                InputStream in = multipartFile.getInputStream();
                String[] split = newName.split("/");
                //创建头部信息
                Map<String, String> headers = new HashMap<>(1 << 2);
                //添加自定义内容类型
                headers.put("Content-Type", "application/octet-stream");
                //上传
                minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucket).object(newName).stream(
                        in, in.available(), -1)
                        .headers(headers)
                        .build());
                String urls = FileConfig.url + "/"+ FileConfig.bucket + "/" + newName;
                //内网
                String inUrl = FtpConfig.ip + "/zhba/" + newName;
                //取出身份证号,查询用户信息,更新用户信息
                String pictrueName = multipartFile.getName().substring(0, multipartFile.getName().lastIndexOf("."));
//                String regex ="([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])|([1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})";
                String regex ="[\u4e00-\u9fa5]";
                Pattern compile = Pattern.compile(regex);
                String idCardNo = compile.matcher(pictrueName).replaceAll("");
                User user = userService.getUserInfoByIdCardNo(idCardNo);
                String newName = "upload/picture/" +
                    UUID.randomUUID().toString().replaceAll("-", "") +
                    multipartFile.getName().substring(multipartFile.getName().lastIndexOf("."));
                User user = getUserInfo(multipartFile, minioClient,newName);
                //设置用户头像url
                if (null!=user){
                    user.setAvatar(urls);
                    //更新用户信息
                    userService.updateById(user);
                    //内网数据推送
                    //数据推送
                    String s = "update blade_user set avatar = " + "'" + inUrl +
                        ",update_time = " + "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "'" +
                        "'" + "where id = " + "'" + user.getId() + "'";
                    //FtpUtil.sqlFileUpload(s);
                    myAsyncService.dataSync(s);
                    //文件推送
//                    InputStream inputStream = multipartFile.getInputStream();
//                    FtpUtil.uploadFile(FtpConfig.ftpHost, ftpPort, FtpConfig.ftpUserName, ftpPassword, ftpPath, "/", split[2], inputStream);
                    in.close();
                    String urls = FileConfig.url + "/"+ FileConfig.bucket + "/" + newName;
                    if (type==1) {
                        user.setAvatar(urls);
                        //更新用户信息
                        userService.updateById(user);
                    }
                    if (type==2) {
                        // 健康状况图片(健康证)
                        // 更新详情信息
                        UpdateWrapper<UserDetailEntity> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.in("user_id",user.getId()).set("health_certificate_url",urls);
                        userDetailService.update(updateWrapper);
                    }
                    if (type==3) {
                        // 无犯罪记录图片
                        // 更新详情信息
                        UpdateWrapper<UserDetailEntity> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.in("user_id",user.getId()).set("no_criminal_record_prove_url",urls);
                        userDetailService.update(updateWrapper);
                    }
                }
            }
        }
@@ -461,15 +409,99 @@
        return R.data(map);
    }
    /**
     * 获取临时路径
     * @return
     */
    public String getDesPath() {
        String uuid = UUID.randomUUID().toString();
        //        String desPath = "D:/test" + File.separator + uuid.replaceAll("-", "");
        return FileConfig.localtion + File.separator + uuid.replaceAll("-", "");
    }
    /**
     * 文件上传,zip , 缴费凭证
     *
     * @param file 图片对象
     * 获取文件集合
     * @param file
     * @param desPath
     * @return
     */
    @PostMapping("put-file-exam-payment-zip")
    public R putFileExamPaymentZip(@RequestParam MultipartFile file) throws Exception {
        Map<String, Object> map = new HashMap<>(1);
    public List<MultipartFile> getFileList(MultipartFile file,String desPath){
        String fileName = file.getOriginalFilename();
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(Locale.US);
        //判断文件是不是zip类型
        if(!fileType.equals("zip")){
            throw new ServiceException("上传文件类型不符!必须是 zip 压缩文件格式!");
        }
        //遗漏了这个代码,在本地测试环境不会出问题,在服务器上一定会报没有找到文件的错误
        String savePath = FileConfig.localtion + File.separator;
        FileUtil fileUtil = new FileUtil();
        //解压zip文件
        try {
            FileUtil.unZip(file, desPath,savePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<MultipartFile> fileList = new ArrayList<>();
        //获取图片文件并返回
//        fileList = fileUtil.getSubFiles(desPath+File.separator+namePath,fileList);
        return fileUtil.getSubFiles(desPath,fileList);
    }
    /**
     * 获取用户信息
     * @param multipartFile
     * @param minioClient
     * @param newName
     * @return
     * @throws Exception
     */
    public User getUserInfo(MultipartFile multipartFile,MinioClient minioClient,String newName) throws Exception{
        InputStream in = multipartFile.getInputStream();
        //创建头部信息
        Map<String, String> headers = new HashMap<>(1 << 2);
        //添加自定义内容类型
        headers.put("Content-Type", "application/octet-stream");
        //上传
        minioClient.putObject(
            PutObjectArgs.builder().bucket(FileConfig.bucket).object(newName).stream(
                in, in.available(), -1)
                .headers(headers)
                .build());
        //取出身份证号,查询用户信息,更新用户信息
        String pictrueName = multipartFile.getName().substring(0, multipartFile.getName().lastIndexOf("."));
//                String regex ="([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx])|([1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})";
        String regex ="[\u4e00-\u9fa5]";
        Pattern compile = Pattern.compile(regex);
        String idCardNo = compile.matcher(pictrueName).replaceAll("");
        in.close();
        // 查询并返回用户数据
        return userService.getUserInfoByIdCardNo(idCardNo);
    }
    /**
     * 文件大小校验
     * @param errorList
     * @param status
     * @param multipartFile
     */
    public void fileSizeCheck(List<String> errorList, AtomicBoolean status, MultipartFile multipartFile) {
        long size = multipartFile.getSize();
        if (size<30*1024 || size>500*1024){
            status.set(false);
            //取出身份证号,查询用户信息,更新用户信息
            String pictureName = multipartFile.getName().substring(0, multipartFile.getName().lastIndexOf("."));
            String regex ="[\u4e00-\u9fa5]";
            Pattern compile = Pattern.compile(regex);
            String idCardNo = compile.matcher(pictureName).replaceAll("");
            //加入集合
            errorList.add(idCardNo);
        }
    }
    /**
     * 自定义上传配置设置
     */
    public MinioClient myUploadConfigSet() throws Exception {
        //填写你文件上传的地址以及相应信息
        String url = FileConfig.apiUrl;
        String access = FileConfig.access;
@@ -487,18 +519,28 @@
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).build());
        }
        return minioClient;
    }
    /**
     * 文件上传,zip , 缴费凭证
     *
     * @param file 图片对象
     */
    @PostMapping("put-file-exam-payment-zip")
    public R putFileExamPaymentZip(@RequestParam MultipartFile file) throws Exception {
        Map<String, Object> map = new HashMap<>(1);
        MinioClient minioClient = myUploadConfigSet();
        String fileName = file.getOriginalFilename();
        String namePath = fileName.substring(0,fileName.lastIndexOf("."));
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(Locale.US);
        //判断文件是不是zip类型
        if(!fileType.equals("zip")){
//            map.put("data","上传文件类型不符!");
//            return R.data(map);
            throw new ServiceException("上传文件类型不符!必须是 zip 压缩文件格式!");
        }
        //FileConfig.localtion是配置文件和config类生产的,测试demo可以直接把FileConfig.localtion替换成D:/test
        String uuid = UUID.randomUUID().toString();
        String desPath = FileConfig.localtion + File.separator + uuid.replaceAll("-", "");
        String desPath = getDesPath();
        //遗漏了这个代码,在本地测试环境不会出问题,在服务器上一定会报没有找到文件的错误
        String savePath = FileConfig.localtion + File.separator;
@@ -520,7 +562,7 @@
                headers.put("Content-Type", "application/octet-stream");
                //上传
                minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucket).object(newName).stream(
                    PutObjectArgs.builder().bucket(FileConfig.bucket).object(newName).stream(
                        in, in.available(), -1)
                        .headers(headers)
                        .build());
@@ -587,24 +629,8 @@
     * @param file 图片对象
     */
    @PostMapping("put-files-talk")
    public R putFilestak(@RequestParam MultipartFile file) throws IOException, ServerException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, XmlParserException, ErrorResponseException {
        //填写你文件上传的地址以及相应信息
        String url = FileConfig.apiUrl;
        String access = FileConfig.access;
        String secret = FileConfig.secret;
        String bucket = FileConfig.bucket;
        MinioClient minioClient =
            MinioClient.builder()
                .endpoint(url)
                .credentials(access, secret)
                .build();
        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!isExist) {
            // 创建一个名为zip的存储桶,用于zip文件。
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
            minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).build());
        }
    public R putFilestak(@RequestParam MultipartFile file) throws Exception {
        MinioClient minioClient = myUploadConfigSet();
        String fileName = file.getOriginalFilename();
        String newName = "upload/picture/" + UUID.randomUUID().toString().replaceAll("-", "")
            + fileName.substring(fileName.lastIndexOf("."));
@@ -616,7 +642,7 @@
        headers.put("Content-Type", "application/octet-stream");
        //上传
        minioClient.putObject(
            PutObjectArgs.builder().bucket(bucket).object(newName).stream(
            PutObjectArgs.builder().bucket(FileConfig.bucket).object(newName).stream(
                in, in.available(), -1)
                .headers(headers)
                .build());
src/main/java/org/springblade/modules/simulateexam/service/impl/SimulateExamRecordServiceImpl.java
@@ -338,6 +338,9 @@
            }
            //设置总分
            simulateExamRecord.setScore(count);
            // 考试完成
            simulateExamRecord.setStatus(3);
            simulateExamRecord.setEndTime(new Date());
            //更新模拟考试信息
            this.updateById(simulateExamRecord);
            //返回
src/main/java/org/springblade/modules/system/controller/UserController.java
@@ -73,12 +73,10 @@
import org.springblade.modules.system.entity.Dept;
import org.springblade.modules.system.entity.Role;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.excel.*;
import org.springblade.modules.system.node.TreeNode;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IRoleService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.MyAsyncService;
import org.springblade.modules.system.service.*;
import org.springblade.modules.system.vo.UserVO;
import org.springblade.modules.system.wrapper.UserWrapper;
import org.springblade.modules.training.entity.TrainingRegistration;
@@ -113,6 +111,7 @@
public class UserController {
    private final IUserService userService;
    private final IUserDetailService userDetailService;
    private final IDeptService iDeptService;
    private final IRoleService roleService;
    private final IExperienceService experienceService;
@@ -270,50 +269,64 @@
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入User")
    public R update(@Valid @RequestBody User user) throws Exception {
    @Transactional(rollbackFor = Exception.class)
    public R update(@Valid @RequestBody Map<String, Object> userMap) throws Exception {
        //获取user
        User user = JSON.parseObject(JSON.toJSONString(userMap.get("user")), User.class);
        // 用户详情
        UserDetailEntity userDetailEntity = JSON.parseObject(JSON.toJSONString(userMap.get("userDetail")), UserDetailEntity.class);
        //分配保安角色
        CacheUtil.clear(USER_CACHE);
        User user1 = userService.getById(user.getId());
        String url = "";
        if (null != user.getFingerprint() && !user.getFingerprint().equals("")) {
            if (user.getFingerprint().length() > 100) {
                //指纹图片上传并返回url
                String s = uploadBase64String(user);
                String[] split = s.split(",");
                user.setFingerprint(split[0]);
                //内网指纹图片url
                url = split[1];
            }
        }
        //判断是否持证
        boolean states = false;
        if (user.getHold().equals("1") && null!=user.getSecuritynumber() && !user.getSecuritynumber().equals("")){
            //持证,校验保安证编号是否合法
            SecurityPaper securityPaper = new SecurityPaper();
            securityPaper.setIdCardNo(user.getCardid());
            List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
            if (securityPaperList.size()>0){
                //遍历
                for (SecurityPaper paper : securityPaperList) {
                    if (paper.getNumber().equals(user.getSecuritynumber())){
                        states = true;
                    }
                }
                if (!states){
                    user.setHold("2");
//                    throw new ServiceException("保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
                }
            }else {
//                throw new ServiceException("保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
                states = false;
                user.setHold("2");
            }
        }
        if (user.getHold().equals("2")){
            states = true;
        }
        // 指纹设置
        fingerprintSet(user);
        // 校验是否持证
        boolean states = updateByIsSecurity(user);
        //如果是离职
        if (leaveHandle(user)) return R.success("修改成功");
        int state = 0;
        //如果是异常标记
        if (null != user.getExaminationType() && !user.getExaminationType().equals("")) {
            if (user.getExaminationType().equals("1")) {
                //吊销保安证
                user.setHold("3");
                state = 1;
            }
        }
        user.setPassword(user1.getPassword());
        user.setUpdateTime(new Date());
        //如果身份证号修改
        if (!user.getCardid().equals(user1.getCardid())) {
            //账号,密码也修改
            user.setAccount(user.getCardid());
            //获取默认密码配置
            user.setPassword(user.getCardid().substring(user.getCardid().length() - 6));
            //加密
            if (Func.isNotEmpty(user.getPassword())) {
                user.setPassword(DigestUtil.encrypt(user.getPassword()));
            }
            state = 2;
        }
        //修改
        boolean status = userService.updateById(user);
        if (status){
            //同时更新用户详情信息
            userDetailService.updateById(userDetailEntity);
        }
        if (!states) {
            return R.data(201,null,"保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
        }
        return R.data(200,null,"修改成功!");
    }
    /**
     * 离职处理
     * @param user
     * @return
     */
    public boolean leaveHandle(@RequestBody @Valid User user) {
        if (null != user.getStatus()) {
            if (user.getStatus().equals(2)) {
                //修改派遣状态
@@ -403,60 +416,46 @@
                            + " " + "where id = " + "'" + user.getId() + "'";
                    myAsyncService.dataSync(s1);
                }
                return R.success("修改成功");
                return true;
            }
        }
        return false;
    }
        int state = 0;
        //如果是异常标记
        if (null != user.getExaminationType() && !user.getExaminationType().equals("")) {
            if (user.getExaminationType().equals("1")) {
                //吊销保安证
                user.setHold("3");
                state = 1;
    /**
     *     校验是否持证-更新
     * @param user
     * @return
     */
    public boolean updateByIsSecurity(@RequestBody @Valid User user) {
        //判断是否持证
        boolean states = false;
        if (user.getHold().equals("1") && null!=user.getSecuritynumber() && !user.getSecuritynumber().equals("")){
            //持证,校验保安证编号是否合法
            SecurityPaper securityPaper = new SecurityPaper();
            securityPaper.setIdCardNo(user.getCardid());
            List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
            if (securityPaperList.size()>0){
                //遍历
                for (SecurityPaper paper : securityPaperList) {
                    if (paper.getNumber().equals(user.getSecuritynumber())){
                        states = true;
                    }
                }
                if (!states){
                    user.setHold("2");
//                    throw new ServiceException("保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
                }
            }else {
//                throw new ServiceException("保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
                states = false;
                user.setHold("2");
            }
        }
        user.setPassword(user1.getPassword());
        user.setUpdateTime(new Date());
        //如果身份证号修改
        if (!user.getCardid().equals(user1.getCardid())) {
            //账号,密码也修改
            user.setAccount(user.getCardid());
            //获取默认密码配置
            user.setPassword(user.getCardid().substring(user.getCardid().length() - 6));
            //加密
            if (Func.isNotEmpty(user.getPassword())) {
                user.setPassword(DigestUtil.encrypt(user.getPassword()));
            }
            state = 2;
        if (user.getHold().equals("2")){
            states = true;
        }
        //修改
        boolean status = userService.updateById(user);
        if (status) {
            if (state == 2) {
                UserDTO userDTO = new UserDTO();
                userDTO.setAccount(user.getAccount());
                userDTO.setCardid(user.getCardid());
                userDTO.setOldCardid(user1.getCardid());
                userDTO.setPassword(user.getPassword());
                userDTO.setRealName(user.getRealName());
                userDTO.setPhone(user.getPhone());
                userDTO.setSex(user.getSex());
                userDTO.setAvatar(user.getAvatar());
                //推送qfqk
//                myAsyncService.updateUserByAccount(userDTO);
            } else {
//                myAsyncService.updateUserByQfqk(user);
            }
        }
        if (!states) {
            return R.data(201,null,"保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
        }
        return R.data(200,null,"修改成功!");
        return states;
    }
@@ -656,25 +655,15 @@
    @PostMapping("/remove")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "删除", notes = "传入id集合")
    //@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
    public R remove(@RequestParam String ids) {
        CacheUtil.clear(USER_CACHE);
//        List<String> list = Arrays.asList(ids.split(","));
//        list.forEach(id -> {
//            User user = userService.getById(id);
//            User user1 = new User();
//            user1.setId(user.getId());
//            user1.setCardid(user.getCardid());
//            user1.setIsDeleted(1);
//            //qfqk 同步
////            myAsyncService.deleteUserByQfqk(user1);
//            //内网同步
//            String s1 = "update blade_user set is_deleted = 1"
//                + ",update_time = " + "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "'"
//                + " " + "where id = " + "'" + id + "'";
//            //FtpUtil.sqlFileUpload(s1);
//            myAsyncService.dataSync(s1);
//        });
        List<String> list = Arrays.asList(ids.split(","));
        // 遍历删除用户详情信息
        list.forEach(id -> {
            QueryWrapper<UserDetailEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id",id);
            userDetailService.remove(wrapper);
        });
        return R.status(userService.removeUser(ids));
    }
@@ -1068,6 +1057,8 @@
    public R securitySave(@Valid @RequestBody Map<String, Object> userMap) throws Exception {
        //获取user
        User user = JSON.parseObject(JSON.toJSONString(userMap.get("user")), User.class);
        // 用户详情
        UserDetailEntity userDetailEntity = JSON.parseObject(JSON.toJSONString(userMap.get("userDetail")), UserDetailEntity.class);
        //分配保安角色
        Role role = new Role();
        role.setRoleAlias("保安");
@@ -1075,14 +1066,124 @@
        user.setRoleId(oneRole.getId().toString());
        user.setDispatch("1");
        user.setExaminationType("0");
        user.setCreateTime(new Date());
        user.setTenantId("000000");
        user.setAccount(user.getCardid());
        // 用户校验
        userCheck(user);
        // 保安员证校验
        boolean state = securityPaperCheck(user);
        // 指纹设置
        fingerprintSet(user);
        //密码加密
        if (Func.isNotEmpty(user.getCardid())) {
//            user.setPassword(DigestUtil.encrypt(user.getPassword()));
            //取身份证号码后6位作为密码
            user.setPassword(DigestUtil.encrypt(user.getCardid().substring(user.getCardid().length() - 6)));
        }
        //用户新增
        boolean status = userService.save(user);
        // 用户详情信息新增
        if (status){
            userDetailEntity.setUserId(user.getId());
            // 新增
            userDetailService.save(userDetailEntity);
        }
        //从业记录新增
        experienceSave(user);
        //判断是否持证是否为空
        if (!state) {
            return R.data(201, null, "保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
        }
        return R.data(200,null,"新增成功!");
    }
    /**
     * 指纹设置
     * @param user
     * @throws Exception
     */
    private void fingerprintSet(User user) throws Exception {
        String url = "";
        if (null != user.getFingerprint() && !user.getFingerprint().equals("")) {
            if (user.getFingerprint().length() > 100) {
                String s = uploadBase64String(user);
                String[] split = s.split(",");
                user.setFingerprint(split[0]);
                url = split[1];
            }
        }
    }
    /**
     * 保安员证校验
     * @param user
     * @return
     */
    private boolean securityPaperCheck(User user) {
        boolean state = false;
        if (user.getHold().equals("1")){
            //持证,校验保安证编号是否合法
            SecurityPaper securityPaper = new SecurityPaper();
            securityPaper.setIdCardNo(user.getCardid());
            List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
            if (securityPaperList.size()>0){
                //遍历
                for (SecurityPaper paper : securityPaperList) {
                    if (paper.getNumber().equals(user.getSecuritynumber())){
                        state = true;
                    }
                }
                if (!state){
                    user.setHold("2");
                    user.setSecuritynumber(null);
                }
            }else {
                user.setHold("2");
                user.setSecuritynumber(null);
            }
        }else {
            state = true;
        }
        return state;
    }
    /**
     * 从业记录新增
     * @param user
     */
    public void experienceSave(User user) {
        //从业记录新增
        Experience experience = new Experience();
        String rtime;
        String paperTime;
        if (user.getRtime() == null) {
            rtime = null;
        } else {
            rtime = new SimpleDateFormat("yyyy-MM-dd").format(user.getRtime());
            experience.setEntrytime(user.getRtime());
        }
        Dept dept = iDeptService.getById(user.getDeptId());
        experience.setCardid(user.getCardid());
        experience.setSecurityid(user.getId().toString());
        experience.setCompanyname(dept.getDeptName());
        experience.setName(user.getRealName());
        experience.setPost("保安员");
        experienceService.save(experience);
    }
    /**
     * 用户校验
     * @param user
     */
    public void userCheck(User user) {
        User user1 = new User();
        user1.setIsDeleted(0);
        user1.setStatus(1);
        user1.setAccount(user.getCardid());
        List<User> list = userService.list(Condition.getQueryWrapper(user1));
        // 判断校验
        if (list.size() > 0 && Func.isEmpty(user.getId())) {
            if (null != user.getCell() && !user.getCell().equals("")) {
                if (user.getCell().equals("2")) {
@@ -1113,91 +1214,6 @@
                throw new ServiceException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount()));
            }
        }
        //判断是否持证
        boolean state = false;
        if (user.getHold().equals("1")){
            //持证,校验保安证编号是否合法
            SecurityPaper securityPaper = new SecurityPaper();
            securityPaper.setIdCardNo(user.getCardid());
            List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
            if (securityPaperList.size()>0){
                //遍历
                for (SecurityPaper paper : securityPaperList) {
                    if (paper.getNumber().equals(user.getSecuritynumber())){
                        state = true;
                    }
                }
                if (!state){
                    user.setHold("2");
                    user.setSecuritynumber(null);
                }
            }else {
                user.setHold("2");
                user.setSecuritynumber(null);
            }
        }else {
            state = true;
        }
        String url = "";
        if (null != user.getFingerprint() && !user.getFingerprint().equals("")) {
            if (user.getFingerprint().length() > 100) {
                String s = uploadBase64String(user);
                String[] split = s.split(",");
                user.setFingerprint(split[0]);
                url = split[1];
            }
        }
        //密码加密
        if (Func.isNotEmpty(user.getCardid())) {
//            user.setPassword(DigestUtil.encrypt(user.getPassword()));
            //取身份证号码后6位作为密码
            user.setPassword(DigestUtil.encrypt(user.getCardid().substring(user.getCardid().length() - 6)));
        }
        user.setCreateTime(new Date());
        user.setTenantId("000000");
        //用户新增
        boolean status = userService.save(user);
        //从业记录新增
        Experience experience = new Experience();
        String rtime;
        String paperTime;
        if (user.getRtime() == null) {
            rtime = null;
        } else {
            rtime = new SimpleDateFormat("yyyy-MM-dd").format(user.getRtime());
            experience.setEntrytime(user.getRtime());
        }
        Dept dept = iDeptService.getById(user.getDeptId());
        experience.setCardid(user.getCardid());
        experience.setSecurityid(user.getId().toString());
        experience.setCompanyname(dept.getDeptName());
        experience.setName(user.getRealName());
        experience.setPost("保安员");
        experienceService.save(experience);
        //发证日期处理
//        if (user.getPaperTime() == null) {
//            paperTime = "";
//        } else {
//            paperTime = new SimpleDateFormat("yyyy-MM-dd").format(user.getPaperTime());
//        }
        //头像
        if (null != user.getAvatar() && !user.getAvatar().equals("")) {
            user.setAvatar(FtpConfig.ip + user.getAvatar().substring(26));
        }
        //判断是否持证是否为空
        if (!state) {
            return R.data(201, null, "保安证编号不匹配,请核实!也可通过提供保安证件信息提交核实申请!");
        }
        return R.data(200,null,"新增成功!");
    }
    /**
@@ -1314,14 +1330,20 @@
     */
    @GetMapping("/details")
    public R details(User user) {
        User user1 = userService.getById(user.getId());
        if (null != user1.getFingerprint() && !user1.getFingerprint().equals("")) {
            //url 转base64
            String base64Url = ImageUtils.imageUrlToBase64(user1.getFingerprint());
            System.out.println("base64Url = " + base64Url);
            user1.setFingerprint(base64Url);
        UserVO userInfo = userService.getUserDetailById(user.getId());
        // 查询对应的详情信息
        if (null!=userInfo){
            QueryWrapper<UserDetailEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id",userInfo.getId()).eq("is_deleted",0);
            UserDetailEntity one = userDetailService.getOne(wrapper);
            userInfo.setUserDetail(one);
        }
        return R.data(user1);
        if (null != userInfo.getFingerprint() && !userInfo.getFingerprint().equals("")) {
            //url 转base64
            String base64Url = ImageUtils.imageUrlToBase64(userInfo.getFingerprint());
            userInfo.setFingerprint(base64Url);
        }
        return R.data(userInfo);
    }
@@ -1399,4 +1421,14 @@
    public R getNotUpdatePwdInfo() {
        return R.data(userService.getNotUpdatePwdInfo());
    }
    /**
     * 数据处理
     * @return
     */
    @GetMapping("/dataHandler")
    public R dataHandler() {
        return R.data(userService.dataHandler());
    }
}
src/main/java/org/springblade/modules/system/controller/UserDetailController.java
New file
@@ -0,0 +1,126 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import javax.validation.Valid;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.vo.UserDetailVO;
import org.springblade.modules.system.wrapper.UserDetailWrapper;
import org.springblade.modules.system.service.IUserDetailService;
import org.springblade.core.boot.ctrl.BladeController;
/**
 * 用户详情表 控制器
 *
 * @author BladeX
 * @since 2023-11-30
 */
@RestController
@AllArgsConstructor
@RequestMapping("blade-userDetail/userDetail")
@Api(value = "用户详情表", tags = "用户详情表接口")
public class UserDetailController{
    private final IUserDetailService userDetailService;
    /**
     * 用户详情表 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入userDetail")
    public R<UserDetailVO> detail(UserDetailEntity userDetail) {
        UserDetailEntity detail = userDetailService.getOne(Condition.getQueryWrapper(userDetail));
        return R.data(UserDetailWrapper.build().entityVO(detail));
    }
    /**
     * 用户详情表 分页
     */
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入userDetail")
    public R<IPage<UserDetailVO>> list(UserDetailEntity userDetail, Query query) {
        IPage<UserDetailEntity> pages = userDetailService.page(Condition.getPage(query), Condition.getQueryWrapper(userDetail));
        return R.data(UserDetailWrapper.build().pageVO(pages));
    }
    /**
     * 用户详情表 自定义分页
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入userDetail")
    public R<IPage<UserDetailVO>> page(UserDetailVO userDetail, Query query) {
        IPage<UserDetailVO> pages = userDetailService.selectUserDetailPage(Condition.getPage(query), userDetail);
        return R.data(pages);
    }
    /**
     * 用户详情表 新增
     */
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增", notes = "传入userDetail")
    public R save(@Valid @RequestBody UserDetailEntity userDetail) {
        return R.status(userDetailService.save(userDetail));
    }
    /**
     * 用户详情表 修改
     */
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入userDetail")
    public R update(@Valid @RequestBody UserDetailEntity userDetail) {
        return R.status(userDetailService.updateById(userDetail));
    }
    /**
     * 用户详情表 新增或修改
     */
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改", notes = "传入userDetail")
    public R submit(@Valid @RequestBody UserDetailEntity userDetail) {
        return R.status(userDetailService.saveOrUpdate(userDetail));
    }
    /**
     * 用户详情表 删除
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "逻辑删除", notes = "传入ids")
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        return R.status(userDetailService.removeByIds(Func.toLongList(ids)));
    }
}
src/main/java/org/springblade/modules/system/dto/UserDetailDTO.java
New file
@@ -0,0 +1,34 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.dto;
import org.springblade.modules.system.entity.UserDetailEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 用户详情表 数据传输对象实体类
 *
 * @author BladeX
 * @since 2023-11-30
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class UserDetailDTO extends UserDetailEntity {
    private static final long serialVersionUID = 1L;
}
src/main/java/org/springblade/modules/system/entity/UserDetailEntity.java
New file
@@ -0,0 +1,145 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springframework.format.annotation.DateTimeFormat;
/**
 * 用户详情表 实体类
 *
 * @author BladeX
 * @since 2023-11-30
 */
@Data
@TableName("blade_user_detail")
@ApiModel(value = "UserDetail对象", description = "用户详情表")
public class UserDetailEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @JsonSerialize(using = ToStringSerializer.class)
    @ApiModelProperty("主键id")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
    /**
     * 用户id
     */
    @ApiModelProperty(value = "用户id")
    private Long userId;
    /**
     * 婚姻状态
     */
    @ApiModelProperty(value = "婚姻状态")
    private Integer marriageStatus;
    /**
     * 报考等级
     */
    @ApiModelProperty(value = "报考等级")
    private Integer signLevel;
    /**
     * 户籍地址
     */
    @ApiModelProperty(value = "户籍地址")
    private String permanentResidenceAddress;
    /**
     * 居住地址
     */
    @ApiModelProperty(value = "居住地址")
    private String dwellAddress;
    /**
     * 家庭主要成员及联系方式
     */
    @ApiModelProperty(value = "家庭主要成员及联系方式")
    private String memberOfFamily;
    /**
     * 工作经历
     */
    @ApiModelProperty(value = "工作经历")
    private String workExperience;
    /**
     * 教育经历
     */
    @ApiModelProperty(value = "教育经历")
    private String educationExperience;
    /**
     * 健康状况图片(健康证)
     */
    @ApiModelProperty(value = "健康状况图片(健康证)")
    private String healthCertificateUrl;
    /**
     * 无犯罪记录图片
     */
    @ApiModelProperty(value = "无犯罪记录图片")
    private String noCriminalRecordProveUrl;
    /**
     * 创建人
     */
    @JsonSerialize(using = ToStringSerializer.class)
    @ApiModelProperty("创建人")
    @TableField(fill = FieldFill.INSERT)
    private String createUser;
    /**
     * 创建时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    @ApiModelProperty("创建时间")
    private Date createTime;
    /**
     * 更新人
     */
    @JsonSerialize(using = ToStringSerializer.class)
    @ApiModelProperty("更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String updateUser;
    /**
     * 更新时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @ApiModelProperty("更新时间")
    private Date updateTime;
    /**
     * 是否删除
     */
    @TableLogic
    @ApiModelProperty("是否已删除 0:否  1:是")
    private Integer isDeleted;
}
src/main/java/org/springblade/modules/system/excel/SecurityExcel.java
@@ -4,7 +4,12 @@
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springblade.common.excel.ExcelDictConverter;
import org.springblade.common.excel.ExcelDictItem;
import org.springblade.common.excel.ExcelDictItemLabel;
import java.io.Serializable;
/**
@@ -31,8 +36,10 @@
    @ExcelProperty("联系电话*")
    private String phone;
    @ExcelProperty("性别*(男/女)")
    @ExcelProperty(value = "性别*(男/女)",converter = ExcelDictConverter.class)
    @ColumnWidth(10)
    @ExcelDictItemLabel(type = "sex")
    @ExcelDictItem(type = "sex")
    private String sex;
    @ExcelProperty("身份证号*")
@@ -50,8 +57,10 @@
    @ColumnWidth(20)
    private String unitName;
    @ExcelProperty("最高学历*(初中及以下/高中/中技/中专/大专/本科/博士/硕士)")
    @ExcelProperty(value = "最高学历*(初中及以下/高中/中技/中专/大专/本科/博士/硕士)",converter = ExcelDictConverter.class)
    @ColumnWidth(20)
    @ExcelDictItemLabel(type = "educationType")
    @ExcelDictItem(type = "educationType")
    private String education;
    @ExcelProperty("政治面貌*")
@@ -60,6 +69,45 @@
    @ExcelProperty("联系地址*")
    private String address;
    /**
     * 婚姻状态
     */
    @ExcelProperty(value = "婚姻状态*(未婚/已婚/离异/丧偶)",converter = ExcelDictConverter.class)
    @ExcelDictItemLabel(type = "marriageStatusType")
    @ExcelDictItem(type = "marriageStatusType")
    private String marriageStatus;
    /**
     * 报考等级
     */
    @ExcelProperty(value = "报考等级(初级/中级/高级/特级)",converter = ExcelDictConverter.class)
    @ExcelDictItemLabel(type = "signLevelType")
    @ExcelDictItem(type = "signLevelType")
    private String signLevel;
    /**
     * 户籍地址
     */
    @ExcelProperty(value = "户籍地址")
    private String permanentResidenceAddress;
    /**
     * 居住地址
     */
    @ExcelProperty(value = "居住地址")
    private String dwellAddress;
    /**
     * 家庭主要成员及联系方式
     */
    @ExcelProperty(value = "家庭主要成员及联系方式")
    private String memberOfFamily;
    /**
     * 工作经历
     */
    @ExcelProperty(value = "工作经历")
    private String workExperience;
    /**
     * 教育经历
     */
    @ExcelProperty(value = "教育经历")
    private String educationExperience;
}
src/main/java/org/springblade/modules/system/mapper/UserDetailMapper.java
New file
@@ -0,0 +1,43 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.mapper;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.vo.UserDetailVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
/**
 * 用户详情表 Mapper 接口
 *
 * @author BladeX
 * @since 2023-11-30
 */
public interface UserDetailMapper extends BaseMapper<UserDetailEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param userDetail
     * @return
     */
    List<UserDetailVO> selectUserDetailPage(IPage page, UserDetailVO userDetail);
}
src/main/java/org/springblade/modules/system/mapper/UserDetailMapper.xml
New file
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.springblade.modules.system.mapper.UserDetailMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="userDetailResultMap" type="org.springblade.modules.system.entity.UserDetailEntity">
        <result column="id" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="marriage_status" property="marriageStatus"/>
        <result column="sign_level" property="signLevel"/>
        <result column="permanent_residence_address" property="permanentResidenceAddress"/>
        <result column="dwell_address" property="dwellAddress"/>
        <result column="member_of_family" property="memberOfFamily"/>
        <result column="work_experience" property="workExperience"/>
        <result column="education_experience" property="educationExperience"/>
        <result column="health_certificate_url" property="healthCertificateUrl"/>
        <result column="no_criminal_record_prove_url" property="noCriminalRecordProveUrl"/>
        <result column="create_user" property="createUser"/>
        <result column="create_dept" property="createDept"/>
        <result column="create_time" property="createTime"/>
        <result column="update_user" property="updateUser"/>
        <result column="update_time" property="updateTime"/>
        <result column="is_deleted" property="isDeleted"/>
    </resultMap>
    <select id="selectUserDetailPage" resultMap="userDetailResultMap">
        select * from blade_user_detail where is_deleted = 0
    </select>
</mapper>
src/main/java/org/springblade/modules/system/mapper/UserMapper.java
@@ -304,4 +304,17 @@
     * @return
     */
    User getUserIsApply(@Param("id") Long id);
    /**
     * 自定义查询详情信息
     * @param id
     * @return
     */
    UserVO getUserDetailById(@Param("id") Long id);
    /**
     * 查询未关联的保安员
     * @return
     */
    List<User> getNotGlList();
}
src/main/java/org/springblade/modules/system/mapper/UserMapper.xml
@@ -1191,5 +1191,21 @@
        and br.role_alias = '保安'
    </select>
    <!--自定义查询详情信息-->
    <select id="getUserDetailById" resultType="org.springblade.modules.system.vo.UserVO">
        select bu.* from blade_user bu
        where bu.is_deleted = 0
        and bu.id = #{id}
    </select>
    <!--查询未关联的保安员-->
    <select id="getNotGlList" resultType="org.springblade.modules.system.entity.User">
        select bu.* from blade_user bu
        left join blade_user_detail bud on bu.id = bud.user_id and bud.is_deleted = 0
        where bu.is_deleted = 0
        and bu.role_id = '1412226235153731586'
        and bud.id is null
    </select>
</mapper>
src/main/java/org/springblade/modules/system/service/IUserDetailService.java
New file
@@ -0,0 +1,26 @@
package org.springblade.modules.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.vo.UserDetailVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
/**
 * 用户详情表 服务类
 *
 * @author BladeX
 * @since 2023-11-30
 */
public interface IUserDetailService extends IService<UserDetailEntity> {
    /**
     * 自定义分页
     *
     * @param page
     * @param userDetail
     * @return
     */
    IPage<UserDetailVO> selectUserDetailPage(IPage<UserDetailVO> page, UserDetailVO userDetail);
}
src/main/java/org/springblade/modules/system/service/IUserService.java
@@ -418,4 +418,17 @@
     * @return
     */
    boolean getUserIsApply(Long id);
    /**
     * 自定义查询详情信息
     * @param id
     * @return
     */
    UserVO getUserDetailById(Long id);
    /**
     * 数据处理
     * @return
     */
    Object dataHandler();
}
src/main/java/org/springblade/modules/system/service/impl/UserDetailServiceImpl.java
New file
@@ -0,0 +1,25 @@
package org.springblade.modules.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.vo.UserDetailVO;
import org.springblade.modules.system.mapper.UserDetailMapper;
import org.springblade.modules.system.service.IUserDetailService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
/**
 * 用户详情表 服务实现类
 *
 * @author BladeX
 * @since 2023-11-30
 */
@Service
public class UserDetailServiceImpl extends ServiceImpl<UserDetailMapper, UserDetailEntity> implements IUserDetailService {
    @Override
    public IPage<UserDetailVO> selectUserDetailPage(IPage<UserDetailVO> page, UserDetailVO userDetail) {
        return page.setRecords(baseMapper.selectUserDetailPage(page, userDetail));
    }
}
src/main/java/org/springblade/modules/system/service/impl/UserServiceImpl.java
@@ -18,6 +18,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.zxing.WriterException;
@@ -98,6 +99,7 @@
    private final IExperienceService experienceService;
    private final MyAsyncService myAsyncService;
    private final SecurityPaperService securityPaperService;
    private final IUserDetailService userDetailService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -877,8 +879,8 @@
     * @param isCovered
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importSecurity(List<SecurityExcel> data, Boolean isCovered, String deptId) {
        long time = System.currentTimeMillis();
        //将不能导入的保安员账号存起来
        List<String> errorList = new ArrayList<>();
        //年龄不符的保安员信息存入集合
@@ -938,42 +940,9 @@
            }
            //性别
            if (null != userExcel.getSex()) {
                if (userExcel.getSex().equals("男")) {
                    user.setSex(1);
                }
                if (userExcel.getSex().equals("女")) {
                    user.setSex(2);
                }
            }
            user.setSex(Integer.parseInt(userExcel.getSex()));
            // 学历
            if (null != userExcel.getEducation()) {
                if (userExcel.getEducation().equals("初中及以下")
                    || userExcel.getEducation().equals("初中")
                ) {
                    user.setEducation("1");
                }
                if (userExcel.getEducation().equals("高中/中技/中专")
                    || userExcel.getEducation().equals("高中")
                    || userExcel.getEducation().equals("中技")
                    || userExcel.getEducation().equals("中专")
                ) {
                    user.setEducation("2");
                }
                if (userExcel.getEducation().equals("大专")) {
                    user.setEducation("3");
                }
                if (userExcel.getEducation().equals("本科")) {
                    user.setEducation("4");
                }
                if (userExcel.getEducation().equals("博士")) {
                    user.setEducation("5");
                }
                if (userExcel.getEducation().equals("硕士")) {
                    user.setEducation("6");
                }
            }
            user.setEducation(userExcel.getEducation());
            //判断当前用户是否已在本单位,如果是的更新数据
            User user1 = new User();
@@ -989,38 +958,6 @@
                user.setStatus(1);
                user.setIsDeleted(0);
                user.setHold("2");
                //判断是否持证
//                if (null != userExcel.getSecuritynumber() && userExcel.getSecuritynumber() != "") {
//                    user.setHold("1");
//                    //校验保安员证编号是否合规
//                    SecurityPaper securityPaper = new SecurityPaper();
//                    securityPaper.setIdCardNo(userExcel.getCardid());
//                    List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
//                    if (securityPaperList.size()>0){
//                        boolean state = false;
//                        //遍历
//                        for (SecurityPaper paper : securityPaperList) {
//                            if (paper.getNumber().equals(user.getSecuritynumber())){
//                                state = true;
//                            }
//                        }
//                        if (!state){
//                            user.setHold("2");
//                            user.setSecuritynumber(null);
//                            securityInvalidList.add(userExcel.getCardid());
//                            securityInvalidStatus.set(false);
//                        }
//                    }else {
//                        user.setHold("2");
//                        user.setSecuritynumber(null);
//                        securityInvalidList.add(userExcel.getCardid());
//                        securityInvalidStatus.set(false);
//                    }
//                }else {
//                    user.setHold("2");
//                }
                //判断年龄,超过60岁的不入
//                if (AgeUtil.idCardToAge(user.getCardid())<60) {
                //分配保安角色
                Role role = new Role();
                role.setRoleAlias("保安");
@@ -1043,20 +980,33 @@
                user.setDispatch("1");
                user.setExaminationType("0");
                //新增
//                this.save(user);
                boolean save = this.save(user);
                //并更新详情数据
                if(save){
                    UserDetailEntity detailEntity = new UserDetailEntity();
                    detailEntity.setUserId(user.getId());
                    detailEntity.setDwellAddress(userExcel.getDwellAddress());
                    detailEntity.setEducationExperience(userExcel.getEducationExperience());
                    detailEntity.setMemberOfFamily(userExcel.getMemberOfFamily());
                    detailEntity.setWorkExperience(userExcel.getWorkExperience());
                    detailEntity.setPermanentResidenceAddress(userExcel.getPermanentResidenceAddress());
                    detailEntity.setMarriageStatus(Integer.parseInt(userExcel.getMarriageStatus()));
                    detailEntity.setSignLevel(Integer.parseInt(userExcel.getSignLevel()));
                    userDetailService.save(detailEntity);
                }
                //加入集合
                userList.add(user);
//                userList.add(user);
                //从业记录新增
                Experience experience = new Experience();
                experience.setCardid(user.getCardid());
//                experience.setSecurityid(user.getId().toString());
                experience.setCompanyname(userExcel.getDeptId());
                experience.setName(user.getRealName());
                experience.setPost("保安员");
                experience.setEntrytime(new Date());
//                experienceService.save(experience);
                // 新增
                experienceService.save(experience);
                //加入集合
                experienceList.add(experience);
//                experienceList.add(experience);
            }else {
                //匹配组织机构是否一致,如果不一致
@@ -1069,38 +1019,6 @@
                    continue;
                }else {
                    //如果是一致,则更新用户数据
                    //判断是否持证
//                    if (null != userExcel.getSecuritynumber() && userExcel.getSecuritynumber() != "") {
//                        user2.setHold("1");
//                        user2.setSecuritynumber(user.getSecuritynumber());
//                        //校验保安员证编号是否合规
//                        SecurityPaper securityPaper = new SecurityPaper();
//                        securityPaper.setIdCardNo(userExcel.getCardid());
//                        List<SecurityPaper> securityPaperList = securityPaperService.list(Condition.getQueryWrapper(securityPaper));
//                        if (securityPaperList.size()>0){
//                            boolean state = false;
//                            //遍历
//                            for (SecurityPaper paper : securityPaperList) {
//                                if (paper.getNumber().equals(user.getSecuritynumber())){
//                                    state = true;
//                                }
//                            }
//                            if (!state){
//                                user2.setHold("2");
//                                user2.setSecuritynumber(null);
//                                securityInvalidList.add(userExcel.getCardid());
//                                securityInvalidStatus.set(false);
//                            }
//                        }else {
//                            user2.setHold("2");
//                            user2.setSecuritynumber(null);
//                            securityInvalidList.add(userExcel.getCardid());
//                            securityInvalidStatus.set(false);
//                        }
//                    }else {
//                        user2.setHold("2");
//                    }
//                    user2.setHold("2");
                    if (null!=userExcel.getRegistered()){
                        user2.setRegistered(userExcel.getRegistered());
                    }else {
@@ -1137,27 +1055,54 @@
                    user2.setUpdateTime(new Date());
                    //更新用户数据
                    this.updateById(user2);
                    boolean update = this.updateById(user2);
                    //并更新详情数据
                    if(update){
                        // 通过用户id 查询,如果存在则更新,不存在则更新
                        QueryWrapper<UserDetailEntity> wrapper = new QueryWrapper<>();
                        wrapper.eq("is_deleted",0).eq("user_id",user2.getId());
                        UserDetailEntity one = userDetailService.getOne(wrapper);
                        if (null!=one){
                            one.setDwellAddress(userExcel.getDwellAddress());
                            one.setEducationExperience(userExcel.getEducationExperience());
                            one.setMemberOfFamily(userExcel.getMemberOfFamily());
                            one.setWorkExperience(userExcel.getWorkExperience());
                            one.setPermanentResidenceAddress(userExcel.getPermanentResidenceAddress());
                            one.setMarriageStatus(Integer.parseInt(userExcel.getMarriageStatus()));
                            one.setSignLevel(Integer.parseInt(userExcel.getSignLevel()));
                            userDetailService.updateById(one);
                        }else {
                            UserDetailEntity detailEntity = new UserDetailEntity();
                            detailEntity.setUserId(user2.getId());
                            detailEntity.setDwellAddress(userExcel.getDwellAddress());
                            detailEntity.setEducationExperience(userExcel.getEducationExperience());
                            detailEntity.setMemberOfFamily(userExcel.getMemberOfFamily());
                            detailEntity.setWorkExperience(userExcel.getWorkExperience());
                            detailEntity.setPermanentResidenceAddress(userExcel.getPermanentResidenceAddress());
                            detailEntity.setMarriageStatus(Integer.parseInt(userExcel.getMarriageStatus()));
                            detailEntity.setSignLevel(Integer.parseInt(userExcel.getSignLevel()));
                            userDetailService.save(detailEntity);
                        }
                    }
                }
            }
        }
        //批量插入
        //用户批量插入
        if (userList.size()>0) {
            baseMapper.batchUserList(userList);
            //装换成map
            Map<String, User> userMap = userList.stream().collect(Collectors.toMap(user -> user.getCardid(), user -> user));
            //匹配
            experienceList = experienceList.stream().map(experience -> {
                if (experience.getCardid().equals(userMap.get(experience.getCardid()).getCardid())) {
                    experience.setSecurityid(userMap.get(experience.getCardid()).getId().toString());
                }
                return experience;
            }).collect(Collectors.toList());
            //批量插入从业记录
            baseMapper.batchExperienceList(experienceList);
        }
//        System.out.println("导入时间: = " + (System.currentTimeMillis()-time));
//        if (userList.size()>0) {
//            baseMapper.batchUserList(userList);
//            //装换成map
//            Map<String, User> userMap = userList.stream().collect(Collectors.toMap(user -> user.getCardid(), user -> user));
//            //匹配
//            experienceList = experienceList.stream().map(experience -> {
//                if (experience.getCardid().equals(userMap.get(experience.getCardid()).getCardid())) {
//                    experience.setSecurityid(userMap.get(experience.getCardid()).getId().toString());
//                }
//                return experience;
//            }).collect(Collectors.toList());
//            //批量插入从业记录
//            baseMapper.batchExperienceList(experienceList);
//        }
        //如果所有数据导入有一个异常
        StringBuilder errorBuilder = new StringBuilder();
@@ -2061,4 +2006,31 @@
        }
        return false;
    }
    /**
     * 自定义查询详情信息
     * @param id
     * @return
     */
    @Override
    public UserVO getUserDetailById(Long id) {
        return baseMapper.getUserDetailById(id);
    }
    /**
     * 数据处理
     * @return
     */
    @Override
    public Object dataHandler() {
        // 查询未关联的保安员
        List<User> list = baseMapper.getNotGlList();
        // 批量插入
        for (User user : list) {
            UserDetailEntity detailEntity = new UserDetailEntity();
            detailEntity.setUserId(user.getId());
            userDetailService.save(detailEntity);
        }
        return null;
    }
}
src/main/java/org/springblade/modules/system/vo/UserDetailVO.java
New file
@@ -0,0 +1,35 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.vo;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.core.tool.node.INode;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 用户详情表 视图实体类
 *
 * @author BladeX
 * @since 2023-11-30
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class UserDetailVO extends UserDetailEntity {
    private static final long serialVersionUID = 1L;
}
src/main/java/org/springblade/modules/system/vo/UserVO.java
@@ -23,6 +23,7 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserDetailEntity;
/**
 * 视图实体类
@@ -174,4 +175,9 @@
     * 年龄段类型 1:18-30周岁  2:30-45周岁  3:45-60周岁  4:全部
     */
    private Integer ageType;
    /**
     * 用户详情
     */
    private UserDetailEntity userDetail = new UserDetailEntity();
}
src/main/java/org/springblade/modules/system/wrapper/UserDetailWrapper.java
New file
@@ -0,0 +1,50 @@
/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.system.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.modules.system.entity.UserDetailEntity;
import org.springblade.modules.system.vo.UserDetailVO;
import java.util.Objects;
/**
 * 用户详情表 包装类,返回视图层所需的字段
 *
 * @author BladeX
 * @since 2023-11-30
 */
public class UserDetailWrapper extends BaseEntityWrapper<UserDetailEntity, UserDetailVO>  {
    public static UserDetailWrapper build() {
        return new UserDetailWrapper();
     }
    @Override
    public UserDetailVO entityVO(UserDetailEntity userDetail) {
        UserDetailVO userDetailVO = Objects.requireNonNull(BeanUtil.copy(userDetail, UserDetailVO.class));
        //User createUser = UserCache.getUser(userDetail.getCreateUser());
        //User updateUser = UserCache.getUser(userDetail.getUpdateUser());
        //userDetailVO.setCreateUserName(createUser.getName());
        //userDetailVO.setUpdateUserName(updateUser.getName());
        return userDetailVO;
    }
}
src/main/resources/application-dev.yml
@@ -44,11 +44,11 @@
#图片批量上传zip
upload:
  localtion: ${UPLOAD_DIR:/home/zhbaw/temp}
  localtion: E:\tmp
  maxFileSize: 10240KB
  maxRequestSize: 102400KB
  url: http://60.220.177.113:9000
  apiUrl: http://127.0.0.1:9000
  apiUrl: http://60.220.177.113:9000
  access: minioadmin
  secret: minioadmin
  bucket: zhba