ludc
2024-07-04 328b0158c3d97f87efc7da22a1e3f5a7c258b127
Merge remote-tracking branch 'origin/master'
已修改23个文件
已删除1个文件
已添加4个文件
1749 ■■■■ 文件已修改
Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/revision/service/RevisionModelUtil.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/controller/VciFileUploadController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/controller/WebUIDataController.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/UIDataServiceI.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIDataServiceImpl.java 126 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/VciFileUploadServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/WebBoServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/README-AVUE.md 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/App.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/api/base/file/index.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/api/base/startWork/index.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/api/system/user/api.js 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/Upload-files.vue 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/transfer.vue 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/upload-file.vue 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/StartWorkflowAction.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/downLoadFile.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/downloadFileAction.js 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/startWorkFlow.vue 264 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/uploadFile.vue 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/base/uploadFileAction.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/components/actions/handlers.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/main.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/util/basic-option.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/views/system/user/index.vue 435 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/src/views/system/user/option.js 78 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-ui/vue.config.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/revision/service/RevisionModelUtil.java
@@ -395,16 +395,15 @@
     */
    public boolean checkDataSecret(BaseModel baseModel) throws VciBaseException{
        VciBaseUtil.alertNotNull(baseModel,"要校验密级的数据对象");
        //todo ç™»å½•还未启用,所以密级无法获取需要修改
//        if(isCheckSecret(baseModel) && VciBaseUtil.getCurrentUserSecret()>0) {
//            if (baseModel.getSecretGrade() == null ) {
//                baseModel.setSecretGrade(DataSecretEnum.NONE.getValue());
//            }
//            Integer userSecret = VciBaseUtil.getCurrentUserSecret();
//            if (!checkUserSecret(baseModel.getSecretGrade())) {
//                throw new VciBaseException("当前用户的密级低于数据的密级,用户密级为" + UserSecretEnum.getSecretText(userSecret) + ",数据密级为" + DataSecretEnum.getSecretText(baseModel.getSecretGrade()));
//            }
//        }
        if(isCheckSecret(baseModel) && VciBaseUtil.getCurrentUserSecret()>0) {
            if (baseModel.getSecretGrade() == null ) {
                baseModel.setSecretGrade(DataSecretEnum.NONE.getValue());
            }
            Integer userSecret = VciBaseUtil.getCurrentUserSecret();
            if (!checkUserSecret(baseModel.getSecretGrade())) {
                throw new VciBaseException("当前用户的密级低于数据的密级,用户密级为" + UserSecretEnum.getSecretText(userSecret) + ",数据密级为" + DataSecretEnum.getSecretText(baseModel.getSecretGrade()));
            }
        }
        return true;
    }
Source/plt-web/plt-web-parent/plt-web-base/src/main/java/com/vci/starter/web/interceptor/VciSecurityInterceptor.java
@@ -99,6 +99,11 @@
            //虽然不校验权限,但是如果token不为空,需要更新当前用户
            SessionInfo sessionInfo = getSessionInfo(userToken);
            if(sessionInfo != null){
                //初始化平台的token
                vciSessionForLoginI.initInvocationInfo(sessionInfo);
            }
            return true;
        }
        //获取配置文件中,不校验权限的路径
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/controller/VciFileUploadController.java
@@ -48,7 +48,6 @@
     * @return æ–‡ä»¶ä¿¡æ¯æ˜¾ç¤ºå¯¹è±¡
     */
    @PostMapping("/uploadFile")
    @VciUnCheckRight
    public BaseResult<VciFileObjectVO> uploadFile(MultipartFile file, VciFileObjectDTO fileObjectDTO){
        try {
            if (file != null ) {
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/controller/WebUIDataController.java
@@ -1,5 +1,7 @@
package com.vci.web.controller;
import com.vci.corba.common.PLException;
import com.vci.corba.omd.data.BusinessObject;
import com.vci.starter.web.annotation.controller.VciUnCheckRight;
import com.vci.starter.web.annotation.log.VciBusinessLog;
import com.vci.starter.web.pagemodel.*;
@@ -13,6 +15,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -115,14 +119,33 @@
    }
    /**
     * æ•°æ®å‡ç‰ˆï¼Œå‰ç«¯ä½¿ç”¨JSON提交
     * æ•°æ®å‡ç‰ˆæœ¬/次,前端使用JSON提交
     * @param formDataDTO è¡¨å•数据
     * @return æ‰§è¡Œçš„结果
     */
    @PutMapping("/upRevision")
    @VciBusinessLog(operateName = "数据升版",description = "${param.btmname}里的${param.copyFromVersion}")
    public BaseResult<Map<String,Object>> upRevision(@RequestBody FormDataDTO formDataDTO){
    public BaseResult<Map<String, Object>> upRevision(@RequestBody FormDataDTO formDataDTO) throws PLException {
        return uiDataService.upRevision(formDataDTO);
    }
    /**
     * æ•°æ®å‡ç‰ˆæœ¬/次,前端使用JSON提交
     * @param btmname ä¸šåŠ¡ç±»åž‹çš„ä¿¡æ¯
     * @param oid ä¸šåŠ¡æ•°æ®çš„ä¸»é”®
     * @param type 1:版次对象;2:版本对象;3:主对象
     * @return æ‰§è¡Œçš„结果
     */
    @DeleteMapping("/deleteBusinessObject")
    public BaseResult deleteBusinessObject(String btmname , String oid, int type) {
        try {
            return uiDataService.deleteBusinessObject(btmname, oid, type);
        }catch (PLException e){
            BaseResult<Object> objectBaseResult = new BaseResult<>();
            objectBaseResult.setCode(Integer.parseInt(e.code));
            objectBaseResult.setMsg(Arrays.toString(e.messages));
            return objectBaseResult;
        }
    }
    /**
@@ -187,4 +210,40 @@
        re.setData(dataMapList);
        return re;
    }
    /**
     * å˜æ›´æ‰€æœ‰è€…
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @return æ‰§è¡Œçš„结果
     */
    @PutMapping("/changeBusinessObjectOwner")
    public BaseResult changeBusinessObjectOwner(String btmname , String oid) {
        try {
            return uiDataService.changeBusinessObjectOwner(btmname, oid);
        } catch (PLException e) {
            BaseResult<Object> objectBaseResult = new BaseResult<>();
            objectBaseResult.setCode(Integer.parseInt(e.code));
            objectBaseResult.setMsg(Arrays.toString(e.messages));
            return objectBaseResult;
        }
    }
    /**
     * çŠ¶æ€è·ƒè¿
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @param releaseStatus å‘布状态
     * @return æ‰§è¡Œçš„结果
     */
    @PutMapping("/transferBusinessObject")
    public BaseResult transferBusinessObject(String btmname , String oid, String toStatus, String releaseStatus) {
        try {
            return uiDataService.transferBusinessObject(btmname, oid, toStatus, releaseStatus);
        } catch (PLException e) {
            BaseResult<Object> objectBaseResult = new BaseResult<>();
            objectBaseResult.setCode(Integer.parseInt(e.code));
            objectBaseResult.setMsg(Arrays.toString(e.messages));
            return objectBaseResult;
        }
    }
}
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/UIDataServiceI.java
@@ -1,5 +1,6 @@
package com.vci.web.service;
import com.vci.corba.common.PLException;
import com.vci.corba.omd.data.BusinessObject;
import com.vci.corba.omd.data.LinkObject;
import com.vci.corba.omd.data.RevisionDataInfo;
@@ -175,7 +176,7 @@
     * @return æ‰§è¡Œç»“果和显示后的值
     * @throws VciBaseException ä¿å­˜å‡ºé”™çš„æ—¶å€™ä¼šæŠ›å‡ºå¼‚常
     */
    BaseResult<Map<String, Object>> upRevision(FormDataDTO formDataDTO) throws VciBaseException;
    BaseResult<Map<String, Object>> upRevision(FormDataDTO formDataDTO) throws VciBaseException, PLException;
    /**
     * æ‰¹é‡ä¿®æ”¹ï¼Œæ³¨æ„è¡¨å•定义的字段才会被修改,ts这种默认字段除外
@@ -248,4 +249,28 @@
     * @return ä¸šåŠ¡æ•°æ®çš„å±žæ€§ä¿¡æ¯
     */
    List<Map<String,String>>  getDataAttr(String btmName, String oid);
    /**
     * æ•°æ®å‡ç‰ˆæœ¬/次,前端使用JSON提交
     * @param btmname ä¸šåŠ¡ç±»åž‹çš„ä¿¡æ¯
     * @param oid ä¸šåŠ¡æ•°æ®çš„ä¸»é”®
     * @param type 1:版次对象;2:版本对象;3:主对象
     * @return æ‰§è¡Œçš„结果
     */
    BaseResult deleteBusinessObject(String btmname, String oid, int type) throws PLException;
    /**
     * å˜æ›´æ‰€æœ‰è€…
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @return æ‰§è¡Œçš„结果
     */
    BaseResult changeBusinessObjectOwner(String btmname, String oid) throws PLException;
    /**
     * çŠ¶æ€è·ƒè¿
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @param releaseStatus å‘布状态
     * @return æ‰§è¡Œçš„结果
     */
    BaseResult transferBusinessObject(String btmname, String oid, String toStatus, String releaseStatus) throws PLException;
}
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIDataServiceImpl.java
@@ -2,10 +2,8 @@
import com.vci.client.common.providers.ClientServiceProvider;
import com.vci.corba.common.PLException;
import com.vci.corba.omd.data.BusinessObject;
import com.vci.corba.omd.data.LinkObject;
import com.vci.corba.omd.data.RevisionDataInfo;
import com.vci.corba.omd.data.VersionDataInfo;
import com.vci.corba.framework.data.UserInfo;
import com.vci.corba.omd.data.*;
import com.vci.corba.omd.lcm.LifeCycle;
import com.vci.file.pagemodel.VciFileObjectVO;
import com.vci.frameworkcore.lcstatuspck.FrameworkDataLCStatus;
@@ -37,6 +35,7 @@
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Method;
@@ -1243,7 +1242,7 @@
            if(baseModel.getRevisionValue() == null){
                baseModel.setRevisionValue("");
            }
            return  changeRevisionValueInfoToObject(platformClientUtil.getBOFactoryService().getNextRevisionValueObject(WebUtil.getTableName(btmTypeVO.getId()),baseModel.getNameOid(),btmTypeVO.getRevisionRuleId(),btmTypeVO.isInputRevisionFlag(),baseModel.getRevisionValue()));
            return  changeRevisionValueInfoToObject(platformClientUtil.getBOFactoryService().getNextRevisionValueObject(btmTypeVO.getId(),baseModel.getNameOid(),btmTypeVO.getRevisionRuleId(),btmTypeVO.isInputRevisionFlag(),baseModel.getRevisionValue()));
        } catch (PLException vciError) {
            throw WebUtil.getVciBaseException(vciError);
        }
@@ -1429,7 +1428,7 @@
     * @throws VciBaseException ä¿å­˜å‡ºé”™çš„æ—¶å€™ä¼šæŠ›å‡ºå¼‚常
     */
    @Override
    public BaseResult<Map<String, Object>> upRevision(FormDataDTO formDataDTO) throws VciBaseException {
    public BaseResult<Map<String, Object>> upRevision(FormDataDTO formDataDTO) throws VciBaseException, PLException {
        //首先判断对象是否为空
        VciBaseUtil.alertNotNull(formDataDTO,"修改的数据对象",formDataDTO.getBtmname(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号",formDataDTO.getCopyFromVersion(),"老版本的主键");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmname(), formDataDTO.getFormDefineId());
@@ -1440,28 +1439,40 @@
            //说明前置事件没有执行成功
            return beforeResult;
        }
        //封装数据
        BaseResult<BusinessObject> resultCbo = wrapperCbo(formDataDTO,formDefineVO,false,formDataDTO.isUpVersion()?false:true,formDataDTO.isUpVersion());
        if(!resultCbo.isSuccess()){
            return BaseResult.fail(resultCbo.getMsg(),resultCbo.getMsgObjs());
        List<BusinessObject> businessObjects = null;
        Date ts = formDataDTO.getTs();
        Map<String,String> conditionMap = WebUtil.getOidQuery(formDataDTO.getCopyFromVersion());
        conditionMap.put("ts", VciDateUtil.date2Str(ts,VciDateUtil.DateTimeMillFormat));
        conditionMap.put("oid",formDataDTO.getCopyFromVersion());
        businessObjects = boService.queryCBO(formDataDTO.getBtmname(), conditionMap);
        if(businessObjects.size() ==0){
            throw new VciBaseException("数据不是最新的,建议您刷新后重新操作");
        }
        //扩展属性的值
        Map<String, String> data = formDataDTO.getData();
        Map<String,String> dataLow = new HashMap<>();
        data.forEach((key,value)->{
            dataLow.put(key.toLowerCase(),value);
        });
        Map<String,String> baseDataMap = formDataDTO2MapLow(formDataDTO);
        Map<String,String> allDataMapLow = new HashMap<>();
        allDataMapLow.putAll(dataLow);
        allDataMapLow.putAll(baseDataMap);
        //判断唯一项
        BaseResult baseResult = checkUnique(formDefineVO, null, allDataMapLow, true);
        if(!baseResult.isSuccess()){
            return baseResult;
        }
        BusinessObject businessObject = platformClientUtil.getBOFService()
                .revisionBusinessObject(businessObjects.get(0), null, !formDataDTO.isUpVersion(),true, false, false);
        //执行保存
        BaseResult<Map<String,Object>> result = BaseResult.success();
        try {
            BusinessObject bo = platformClientUtil.getBOFService().createBusinessObject(resultCbo.getObj(),formDataDTO.isUpVersion()?false:true,formDataDTO.isUpVersion());
            BusinessObject afterCbo = new BusinessObject();
            afterCbo = bo;
            result.setObj(boService.cbo2Map(afterCbo));
        } catch (PLException vciError) {
            throw WebUtil.getVciBaseException(vciError);
        }
        if(!CollectionUtils.isEmpty(formDataDTO.getReleaseFileOids())){
            fileObjectService.releasedFile(resultCbo.getObj().btName,resultCbo.getObj().oid,formDataDTO.getReleaseFileOids());
        }
        BaseResult<Map<String, Object>> result = BaseResult.success();
        result.setObj(boService.cbo2Map(businessObject));
        //后置事件
        String afterEvent = formDataDTO.getPostEvent();
        try {
            callPostEvent(Arrays.stream(new BusinessObject[]{resultCbo.getObj()}).collect(Collectors.toList()), null,afterEvent, VciChangeDocumentTypeEnum.EDIT);
            callPostEvent(Arrays.stream(new BusinessObject[]{businessObject}).collect(Collectors.toList()), null,afterEvent, VciChangeDocumentTypeEnum.EDIT);
        }catch (Throwable e){
            throw new VciBaseException(LangBaseUtil.getErrorMsg(e),new String[]{},e);
        }
@@ -2454,4 +2465,73 @@
        }
        return dataMap;
    }
    /**
     * æ•°æ®å‡ç‰ˆæœ¬/次,前端使用JSON提交
     * @param btmname ä¸šåŠ¡ç±»åž‹çš„ä¿¡æ¯
     * @param oid ä¸šåŠ¡æ•°æ®çš„ä¸»é”®
     * @param type 1:版次对象;2:版本对象;3:主对象
     * @return æ‰§è¡Œçš„结果
     */
    @Override
    public BaseResult deleteBusinessObject(String btmname, String oid, int type) throws PLException {
        List<BusinessObject> cbos = boService.queryCBO(btmname,WebUtil.getOidQuery(oid));
        BaseResult<Object> objectBaseResult = new BaseResult<>();
        if(cbos.size() == 0){
            objectBaseResult.setSuccess(false);
            throw new PLException("500", new String[]{"没有获取到数据的主键"});
        }
        for (BusinessObject cbo : cbos) {
            if(StringUtils.isBlank(cbo.revisionid)){
                String revisionoid = Arrays.stream(cbo.hisAttrValList).filter(e -> e.attrName.equals("REVISIONOID")).findFirst().map(e -> e.attrVal).orElse("");
                cbo.revisionid = revisionoid;
            }
            boolean b = platformClientUtil.getBOFService().deleteBusinessObject(cbo,type);
            if(!b){
                throw new PLException("500", new String[]{"数据删除失败!!"});
            }
        }
        return BaseResult.success();
    }
    /**
     * å˜æ›´æ‰€æœ‰è€…
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @return æ‰§è¡Œçš„结果
     */
    @Override
    public BaseResult changeBusinessObjectOwner(String btmname, String oid) throws PLException {
        List<BusinessObject> cbos = boService.queryCBO(btmname,WebUtil.getOidQuery(oid));
        BaseResult<Object> objectBaseResult = new BaseResult<>();
        if(cbos.size() == 0){
            objectBaseResult.setSuccess(false);
            throw new PLException("500", new String[]{"没有获取到数据的主键"});
        }
        UserInfo userInfo = platformClientUtil.getFrameworkService().getUserObjectByUserName(WebUtil.getCurrentUserId());
        for (BusinessObject cbo : cbos) {
            platformClientUtil.getBOFService().changeBusinessObjectOwner(cbo,userInfo);
        }
        return BaseResult.success();
    }
    /**
     * å˜æ›´æ‰€æœ‰è€…
     * @param btmname ä¸šåŠ¡ç±»åž‹
     * @param oid ä¸»é”®
     * @param releaseStatus å‘布状态
     * @return æ‰§è¡Œçš„结果
     */
    @Override
    @Transactional
    public BaseResult transferBusinessObject(String btmname, String oid, String toStatus,String releaseStatus) throws PLException {
        List<BusinessObject> cbos = boService.queryCBO(btmname,WebUtil.getOidQuery(oid));
        BaseResult<Object> objectBaseResult = new BaseResult<>();
        if(cbos.size() == 0){
            objectBaseResult.setSuccess(false);
            throw new PLException("500", new String[]{"没有获取到数据的主键"});
        }
        for (BusinessObject cbo : cbos) {
            platformClientUtil.getBOFService().transferBusinessObjectAndRelease(cbo, toStatus, releaseStatus);
        }
        return BaseResult.success();
    }
}
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/VciFileUploadServiceImpl.java
@@ -205,9 +205,6 @@
        if(vciFileObjectDO.getSecretGrade() == null) {
            vciFileObjectDO.setSecretGrade(DataSecretEnum.NONE.getValue());
        }
        //todo ç™»å½•还未弄好需要修改
        vciFileObjectDO.setCreator("1");
        vciFileObjectDO.setLastModifier("1");
        revisionModelUtil.wrapperForAdd(vciFileObjectDO);
        //随机路径
        String randomPath = VciBaseUtil.getPk();
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/WebBoServiceImpl.java
@@ -154,9 +154,7 @@
        if(btmName!=null){
            btmName = btmName.trim().toLowerCase();
        }
        //todo ç”±äºŽç™»å½•问题后续需要修改
//        String userid = WebUtil.getCurrentUserId();
        String userid = "1";
        String userid = WebUtil.getCurrentUserId();
        if(!hasCreatedCbos.containsKey(btmName)){
            if(StringUtils.isEmpty(userid)){
                throw new VciBaseException(msgCodePrefix +"noHasUserid");
Source/plt-web/plt-web-ui/README-AVUE.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
## AVUE-CRUD è¡¨æ ¼é…ç½®
```javascript
<avue-crud     :option="option"                 //表格配置属性
               :table-loading="loading"         //表格等待框的控制,加载的时候转圈圈,设置true/false
               :search.sync="search"            //搜索的变量(需要sync修饰符)
               :visible.sync="changeInfo"       //是否显示,设置true/false
               :data="data"                     //表格显示的数据
               :page.sync="page"                //表格分页配置选项(需要sync修饰符)
               :permission="permissionList"     //权限控制
               :before-open="beforeOpen"        //打开前的回调function(file,column)
               v-model="form"                   //数据模型 ç”¨æ¥å­˜å–页面值的
               ref="crud"                       //在普通的 DOM å…ƒç´ ä¸Šä½¿ç”¨ï¼Œå¼•用指向的就是 DOM å…ƒç´ ï¼›
               @cell-click="pageto"             //表格点击运行方法 onclick方法定义
               @row-update="rowUpdate"          //修改数据后点击确定触发该事件
               @row-save="rowSave"              //新增数据后点击确定触发该事件
               @row-del="rowDel"                //行数据删除时触发该事件
               @row-click="handleRowClick"      //单击行运行的方法
               @search-change="searchChange"    //搜索栏变化事件
               @search-reset="searchReset"      //清空搜索栏变化事件
               @selection-change="selectionChange"//选择框变化变化事件
               @current-change="currentChange"  //点击页码会调用current-change方法回调当前页数,返回当前第几页
               @size-change="sizeChange"       //点击每页多少条会调size-change方法回调
               @refresh-change="refreshChange" //点击刷新按钮触发该事件
               @on-load="onLoad">              //打开表格页面的方法,一般用来初始化,返回页面数据
          </avue-crud>
option: {
          height:'auto',                 //表格高度
          emptyText: "暂无数据哦~",       //数据为空的提示
          calcHeight: 30,                //表格高度差(主要用于减去其他部分让表格高度自适应)
          tip: false,                    //提示信息
          searchShow: true,              //首次加载是否显示搜索
          searchMenuSpan: 4,             //搜索按钮长度
          searchSpan:6,                  //搜索框长度  æœ€å¤§é•¿åº¦24
          border: true,                  //表格边框是否显示
          index: true,                   //是否显示序号
          viewBtn: true,                 //是否显示查看按钮
          selection: true,               //搜索框显示
          addBtn:false,                  //是否显示添加按钮
          editBtn:false,                 //是否显示编辑按钮
          delBtn:false,                  //是否显示删除按钮
          excelBtn:false,                //表格导出按钮是否显示
          labelWidth:120,                //表单前面的标题长度
          refreshBtn: false,             //表格上面小的 åˆ·æ–°æŒ‰é’®
          columnBtn: false,              //表格上面小的 åˆ—表按钮
          searchBtn: false,              //表格上面小的 æœç´¢æŒ‰é’®
          menu: true,                    //是否显示操作栏
          defaultExpandAll:true,         //树默认展开
          column:[
             {
              label: "",                 //表单属性名称
              prop: "",                  //属性对应实体类字段
              type: "",                  //输入框类型
              addDisplay: false,         //新增时是否显示
              editDisplay: false,        //编辑时是否显示
              viewDisplay: true,         //详情时是否显示
              hide: true,                //表单查询时是否显示
              display: true,             //在查看,新增,编辑页面是否显示
              labelWidth:'100',             //标题名称宽度
              span: 24,                  //24一条数据占一行,8一行3条数据
              gutter:20,                 //项间距
              addDisabled: true,         //添加的时候不能修改
              editDisabled: true,        //编辑的时候不能修改
              sortable:true,             //排序方式切换,倒序、正序切换
              maxlength: 30,             //字数限制
              showWordLimit:true,        //显示字数限制
              defaultExpandAll:true,     //树默认展开
              search:true,              //查询是否显示
              searchFilterable:true,     //select选择框匹配
              showColumn:false,          //列显隐中是否有
              addDisplay: false,         // æ·»åŠ å¼¹çª—ä¸æ˜¾ç¤º
              editDisplay: false,        // ç¼–辑弹窗不显示
              viewDisplay: false         // æŸ¥çœ‹å¼¹çª—不显示
              disabled:true,             //表单item禁用
              row:'false/true',          //是否单独成行
              rules:Obj,                 //验证规则
              dicData:[],                //字典
              dicUrl:'',                 //远程字典地址
              dicMethod:'get/post'         //字典请求方式
              dicQuery:obj,              //字典请求方式
              props:{
                lable:'字典的名称属性值',
                value:'字典的值属性值',
                children:'字典的子属性值'
              },
            }
```
Source/plt-web/plt-web-ui/src/App.vue
@@ -40,6 +40,7 @@
}
.avue-dialog .el-dialog__body{
  padding: 20px;
  margin-bottom: 20px !important;
}
.avue--detail .el-col{
  margin-bottom: 0;
@@ -92,4 +93,7 @@
.tree-buttons .el-button{
  margin: 0 5px 5px 0;
}
.el-dialog__footer{
  border-top: 1px solid #e9e7e7;
}
</style>
Source/plt-web/plt-web-ui/src/api/base/file/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
import request from '@/router/axios';
// ä¸‹è½½æ–‡ä»¶
export const download = (data) => {
  return request({
    url: '/api/vciFileDownloadController/downloadByFileOidPost',
    method: 'post',
    headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
    responseType: 'blob',
    data: data
  })
}
Source/plt-web/plt-web-ui/src/api/base/startWork/index.js
@@ -18,3 +18,25 @@
    params: params,
  });
}
//启动流程
export const startProcess = (params) => {
  let formData = new FormData()
  for (let key in params) {
    // å¦‚果是 nodeUsers å¯¹è±¡ï¼Œåˆ™ç‰¹æ®Šå¤„理
    if (key === 'nodeUsers' && typeof params[key] === 'object' && params[key] !== null) {
      for (let innerKey in params[key]) {
        formData.append(`${key}[${innerKey}]`, params[key][innerKey]);
      }
    } else {
      // éžnodeUsers属性,直接添加到 formData ä¸­
      formData.append(key.replaceAll('"', ''), params[key]);
    }
  }
  return request({
    url: '/api/processDefineController/startProcess',
    method: 'post',
    data:formData
  });
}
Source/plt-web/plt-web-ui/src/api/system/user/api.js
@@ -25,7 +25,7 @@
// è§’色全查询
export function gridRoles(page,limit) {
  return request({
    url: "/api/roleQueryController/gridRoles",
    url: "/api/roleQueryController/refDataGrid",
    method: "get",
    params:{
      page,limit
@@ -54,19 +54,19 @@
}
// æ–°å¢žæˆå‘˜
export function addUser(data) {
export function addUser(row) {
  return request({
    url: "/api/roleQueryController/addUser",
    url: "/api/userQueryController/addUser",
    method: "post",
    data:data
    data:row
  });
}
// ä¿®æ”¹æˆå‘˜
export function updateUser(data) {
  return request({
    url: "/api/roleQueryController/updateUser",
    method: "post",
    url: "/api/userQueryController/updateUser",
    method: "put",
    data:data
  });
}
@@ -74,8 +74,60 @@
// åˆ é™¤æˆå‘˜
export function deleteUser(params) {
  return request({
    url: "/api/roleQueryController/deleteUser",
    url: "/api/userQueryController/deleteUser",
    method: "delete",
    params
  });
}
//获取密码策略
export function selectPwdStrategyMap(params) {
  return request({
    url: "/api/passwordStrategyQueryController/selectPwdStrategyMap",
    method: "get",
    params
  });
}
//保存密码策略
export function saveUserPasswordStrateg(params) {
  let formData = new FormData()
  for (let key in params){
    formData.append(key,params[key])
  }
  return request({
    url: "/api/passwordStrategyQueryController/saveUserPasswordStrateg",
    method: "post",
    data:formData
  });
}
// ä¸‹è½½æ¨¡æ¿æŽ¥å£
export const download = (params) => {
  return request({
    url: '/api/userQueryController/downloadImportTemplate',
    method: 'get',
    headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
    responseType: 'blob',
    params
  })
}
//获取密码策略
export function departmentQueryController(params) {
  return request({
    url: "/api/departmentQueryController/refTree",
    method: "get",
    params
  });
}
//获取密码策略
export function saveUsersDepts(params) {
  return request({
    url: "/api/departmentQueryController/saveUsersDepts",
    method: "post",
    params
  });
}
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/Upload-files.vue
ÎļþÒÑɾ³ý
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/transfer.vue
@@ -1,59 +1,59 @@
<template>
    <el-dialog
      v-dialogDrag
      :close-on-click-modal="false"
      :destroy-on-close="true"
      :title="title"
      :visible.sync="visible"
      append-to-body="true"
      class="avue-dialog"
      style="text-align: center"
      width="40%"
      @close="dialogClose">
      <el-transfer
        v-model="rightRoleData"
        v-loading="loading"
        :data="data"
        :filter-method="filterMethod"
        :render-content="renderFunc"
        :titles="['现有角色', '拥有角色']"
        filter-placeholder="角色名称搜索"
        filterable
        style="text-align: left; display: inline-block;">
      </el-transfer>
      <span slot="footer" class="dialog-footer">
    <el-button @click="visible = false">取 æ¶ˆ</el-button>
    <el-button type="primary" @click="sendHandler">ç¡® å®š</el-button>
  </span>
    </el-dialog>
  <el-dialog
    v-dialogDrag
    :close-on-click-modal="false"
    :destroy-on-close="true"
    :title="title"
    :visible.sync="visible"
    append-to-body="true"
    class="avue-dialog"
    style="text-align: center"
    width="50%"
    @close="dialogClose">
    <el-transfer
      v-model="rightRoleData"
      v-loading="loading"
      :data="data"
      :filter-method="filterMethod"
      :render-content="renderFunc"
      :titles="transferTitle"
      filter-placeholder="关键词搜索"
      filterable
      style="text-align: left; display: inline-block;">
    </el-transfer>
    <div slot="footer" class="dialog-footer">
      <div class="valueInfo" v-if="bottomValue">已设置的值为:[{{bottomValue}}]</div>
      <el-button @click="visible = false" size="small">取 æ¶ˆ</el-button>
      <el-button type="primary" @click="sendHandler" size="small">ç¡® å®š</el-button>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: "transfer",
  props: ['title', 'leftRoleData', 'rightRoleData'],
  props: ['title', 'leftRoleData', 'rightRoleData', 'transferTitle' , 'bottomValue'],
  data() {
    return {
      visible: false, // é€šè¿‡ this.$refs.transfer.visible = true; å¼€å¯å­ç»„件对话框
      data: [],
      value: [],
      loading: false,
      filterMethod(query, item) {
        return item.label.indexOf(query) > -1;
      },
      renderFunc(h, option) {
        return <span><i class="el-icon-s-custom"></i> { option.label }</span>;
        return <span><i class="el-icon-s-custom"></i> {option.label}</span>;
      }
    }
  },
  watch: {
    //渲染穿梭框
    leftRoleData: {
      handler(newval, oldval) {
      handler(newval) {
        if (newval) {
          // æ¸…空data数组
          this.data = [];
          newval.forEach((city, index) => {
          newval.forEach((city) => {
            this.data.push({
              label: city.name,
              key: city.oid,
@@ -82,11 +82,20 @@
</script>
<style lang="scss" scoped>
/deep/ .el-transfer-panel{ /* å·¦å³ä¸¤ä¸ªç©¿æ¢­æ¡†çš„高度和宽度 */
  height: 450px;
/deep/ .el-transfer-panel {
  height: 450px; /* å·¦å³ä¸¤ä¸ªç©¿æ¢­æ¡†çš„高度和宽度 */
  width: 300px;
}
/deep/ .el-transfer-panel__list.is-filterable {
  height: 323px; /* ç©¿æ¢­æ¡†åˆ—表高度 */
}
.valueInfo{
  float: left;
  border: 1px solid #E9E7E7;
  display: inline-block;
  vertical-align: middle;
  padding: 6px 12px;
  line-height: 1;
}
</style>
Source/plt-web/plt-web-ui/src/components/PLT-basic-component/upload-file.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
<template>
  <el-dialog
    v-dialogDrag
    :close-on-click-modal="false"
    :destroy-on-close="true"
    :title="title"
    :visible.sync="visible"
    width="40%"
    append-to-body
    class="avue-dialog"
    style="margin-top: -20vh !important;"
  >
    <Divider left="30px" text="导入提示"></Divider>
    <ul>
      <li>
        è¯·ç‚¹å‡»æµè§ˆæ–‡ä»¶è¿›è¡Œä¸Šä¼ 
      </li>
    </ul>
    <Divider left="30px" text="选择文件后会自动上传"></Divider>
    <el-upload
      :action="fileUrl"
      :before-upload="beforeUpload"
      :data="fileData"
      :headers="uploadHeaders"
      :on-change="uploadChange"
      :on-error="onError"
      :on-success="onSuccess"
      :show-file-list="false"
      class="upload-demo">
      <el-button size="small" style="margin: 15px 35px" type="primary">浏览文件</el-button>
    </el-upload>
    <template #footer>
      <el-button size="small" @click="visible = false">关闭</el-button>
    </template>
  </el-dialog>
</template>
<script>
import {getToken} from "@/util/auth";
import func from "@/util/func";
import {validatenull} from "@/util/validate";
export default {
  name: "upload-file",
  props: {
    fileType: {
      type: Array,
      default: () => []
    },
    title: {
      type: String,
      default: '上传文件'
    },
    fileUrl: {
      type: String,
      default: ''
    },
    fileData: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      flga: true,
      pageLoading: null,
      downloadLoading: false,
      visible: false,
    }
  },
  created() {
  },
  watch: {
    visible: {
      handler(newval, oldval) {
        // console.log('newval',newval)
      }
    }
  },
  computed: {
    uploadHeaders() {
      return {
        "Authorizationtoken": getToken(),
      };
    },
  },
  methods: {
    //文件上传前
    async beforeUpload(file) {
      // èŽ·å–æ–‡ä»¶æ‰©å±•å
      const fileExtension = file.name.split(".").pop().toLowerCase(); // è½¬æ¢ä¸ºå°å†™ä»¥é¿å…å¤§å°å†™ä¸åŒ¹é…çš„问题
      if (this.fileType) {
        if (!this.fileType.includes(fileExtension)) {
          // ä¸Šä¼ æ ¼å¼ä¸ç¬¦åˆè¦æ±‚,提示错误信息并取消上传
          this.$message.error(`只允许上传${this.fileType.toString()}格式的文件`);
          return Promise.reject(false);
        }
      }
      this.pageLoading = this.$loading({
        lock: true,
        text: "文件上传中",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });
      return true;
    },
    // æ–‡ä»¶ä¸Šä¼ æˆåŠŸ
    onSuccess(resbonse) {
      console.log(resbonse);
      if (resbonse.code === 200) {
        this.$message.success("导入成功!");
        this.visible = false;
      } else {
        this.$message.error(resbonse.msg);
      }
    },
    //文件上传失败
    onError(res) {
      this.pageLoading.close();
      this.$message.error(res);
    },
    //文件状态改变
    uploadChange(file) {
      console.log( this.pageLoading);
      if (file.status === "success" || file.status === "error") {
        this.pageLoading.close();
      }
    }
  }
}
</script>
<style lang="scss" scoped>
ul {
  color: rgb(188, 188, 188);
  margin: 20px 0 20px 0;
  padding: 0 0 0 30px;
  list-style: none;
  li {
    margin-bottom: 5px;
    font-size: 13px;
  }
}
</style>
Source/plt-web/plt-web-ui/src/components/actions/base/StartWorkflowAction.js
@@ -8,7 +8,6 @@
export const doAction = (options,callback) => {
  //modelName æµç¨‹åç§° é»˜è®¤ä¸º å½“前用户+'启动流程'+当前分类
  //multi æ˜¯å¦å¼€å¯å¤šé€‰
  //checknotprocess æ˜¯å¦å…è®¸å‘起流程
Source/plt-web/plt-web-ui/src/components/actions/base/downLoadFile.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
  name: "downLoadFile"
}
</script>
<style scoped>
</style>
Source/plt-web/plt-web-ui/src/components/actions/base/downloadFileAction.js
@@ -5,8 +5,10 @@
import {validatenull} from "@/util/validate";
import Vue from "vue";
import func from "@/util/func";
import {download} from "@/api/base/file";
export const doAction = (options,callback) => {
  console.log(options)
  options.sourceData = options.sourceData || {};
  options.dataStore = options.dataStore || [];
  if (!options.dataStore || options.dataStore.length < 1) {
@@ -33,10 +35,22 @@
 */
export const showStartWindow = (options,callback)=> {
  const paramVOS = options.paramVOS;
  if (!paramVOS['form'] && !paramVOS['context']) {
    Vue.prototype.$message.error("按钮配置不正确");
    return false;
  }
  const oids = options.dataStore.map(item => item.oid).join(',');
  let data = new FormData();
  data.append('fileOid',oids);
  download(data).then(res => {
    console.log(res);
    if (res) {
      func.downloadFileByBlobHandler(res);
      Vue.prototype.$message.success("下载成功");
    }
  }).catch(err => {
    console.log(err);
  });
  // if (!paramVOS['form'] && !paramVOS['context']) {
  //   Vue.prototype.$message.error("按钮配置不正确");
  //   return false;
  // }
  // func.downloadFileByBlobHandler();
}
Source/plt-web/plt-web-ui/src/components/actions/base/startWorkFlow.vue
@@ -6,14 +6,18 @@
             :width="width"
             append-to-body="true"
             class="avue-dialog"
             style="margin-top: -10% !important;"
             title="启动流程"
             top="0"
             @close="dialogClose">
    <el-form :model="saveParam" :rules="rules" class="demo-form-inline" label-position="left" label-width="auto">
    <el-divider content-position="left">流程信息</el-divider>
    <el-form ref="nodeForm" :model="saveParam" :rules="rules" class="demo-form-inline" label-position="left"
             label-width="auto">
      <el-form-item label="流程模板">
        <el-input v-model="saveParam.modelName" disabled placeholder="流程模板"></el-input>
        <el-select v-model="saveParam.processTemplate" filterable style="width: 100%;" @change="proTemSelect($event)">
          <el-option v-for="(item, key) in processTemplateList" :key="key" :label="item.value"
                     :value="item.value"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="流程名称" prop="processName">
        <el-input v-model="saveParam.processName" placeholder="流程名称">
@@ -25,30 +29,33 @@
      </el-form-item>
    </el-form>
    <el-divider></el-divider>
    <!--    <div class="btns-icon">-->
    <!--      <el-button circle icon="el-icon-star-off" @click="handleCollect"></el-button>-->
    <!--    </div>-->
    <el-form :model="collectParam" class="demo-form-inline" label-position="left" label-width="auto">
      <el-form-item v-for="(item, index) in initFrom" :key="index" :label="`节点${index + 1}`">
        <el-select style="width: 100%;" filterable v-model="collectParam.flowTaskUsers[index]['userId']"
                   :placeholder="item.value" @change="handleSelect($event, index)">
          <el-option :label="key.name" :value="key.name" v-for="(key, keyi) in item.processNodes"
                     :key="keyi"></el-option>
        </el-select>
    <el-divider content-position="left">流程节点</el-divider>
    <el-form :key="formKey" v-loading="nodeLoading" :model="collectParam" :rules="nodeRules" class="demo-form-inline"
             label-position="left"
             label-width="auto">
      <el-form-item v-for="(item, index) in initFrom" :key="index" :label="item.name" prop="node">
        <div @click="nodeChange(item)">
          <el-input v-model="collectParam[item.name+'name']" readonly="true" suffix-icon="el-icon-zoom-in"></el-input>
        </div>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="handleCancel">取 æ¶ˆ</el-button>
      <el-button type="primary" @click="handleConfirm">ç¡® å®š</el-button>
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="handleCancel">取 æ¶ˆ</el-button>
      <el-button size="small" type="primary" @click="handleConfirm">ç¡® å®š</el-button>
    </div>
    <transfer ref="transfer" :left-role-data="leftRoleData" :right-role-data="rightRoleData"
              :title="`为【${this.nodeName}】选取值`" :transferTitle="transferTitle" :bottomValue="bottomValue"
              @transferSend="roleSendHandler"></transfer>
  </el-dialog>
</template>
<script>
import {validatenull} from "@/util/validate";
import {getTemplateByType, getAllProcessNode} from "@/api/base/startWork/index"
import {getTemplateByType, getAllProcessNode, startProcess} from "@/api/base/startWork/index"
export default {
  name: "startWorkFlow",
@@ -71,34 +78,67 @@
  data() {
    return {
      visible: false,
      saveParam: {}, // å¯¹è±¡åŒ…含 {modelName流程模板(由接口返回当前流程模板) , processName流程名称(为当前用户+'启动流程'+当前分类) , processDesc流程描述 }
      saveParam: {
        processName: ''
      }, // å¯¹è±¡åŒ…含 {processTemplate流程模板(由接口返回当前流程模板) , processName流程名称(为当前用户+'启动流程'+当前分类) , processDesc流程描述 }
      processTemplateList: [], // æµç¨‹æ¨¡æ¿ä¸‹æ‹‰æ•°ç»„
      initFrom: [],  // å½“前流程节点循环数组
      collectParam: {}, // æµç¨‹èŠ‚ç‚¹ä¸‹æ‹‰æ¡†åŒå‘ç»‘å®šå±žæ€§
      typeName: [], // æµç¨‹èŠ‚ç‚¹option循环选项
      nodeLoading: false,
      rules: {
        processName: [
          {required: true, message: '流程名称不能为空', trigger: 'blur'},
          {min: 3, max: 50, message: '长度在 3 åˆ° 50 ä¸ªå­—符', trigger: 'blur'}
        ]
      }
      },
      nodeRules: {
        node: [
          {required: true, message: '选择内容不能为空', trigger: 'change'},
        ]
      },
      bottomValue:'',
      leftRoleData: [],
      rightRoleData: [],
      transferTitle: [],
      nodeName: '', // å½“前节点名称
      userVo: [
        {
          "children": [],
          "id": "zkjs",
          "leaf": true,
          "name": "总会计师",
          "oid": "1241AC3B-26AF-9B86-7870-53DA8D78A742",
          "secret": -1,
          "secretText": "",
          "type": "user"
        },
        {
          "children": [],
          "id": "1",
          "leaf": true,
          "name": "测试",
          "oid": "921D71F8-C2BB-3BCE-B744-AD0C3812F41A",
          "secret": -1,
          "secretText": "",
          "type": "user"
        },
        {
          "children": [],
          "id": "5",
          "leaf": true,
          "name": "总会计师",
          "oid": "34ddb5a8-ab95-4070-b72f-abaaa48cf8b1",
          "secret": -1,
          "secretText": "",
          "type": "user"
        }
      ],
      formKey: 0,
    }
  },
  watch: {
    users: {
      handler(val) {
        this.collectParam.flowTaskUsers = val
      },
      deep: true,
      immediate: true
    },
    parameter: {
      handler(newval, oldval) {
        this.saveParam = Object.assign({processName: '', processDesc: '',}, newval);
      },
      deep: true,
      immediate: true
    }
  },
  watch: {},
  computed: {
    fullscreen() {
      if (this.paramVOS.width || this.paramVOS.height) {
@@ -121,7 +161,7 @@
    },
  },
  created() {
    this.modelNameChange();
    // this.modelNameChange();
    this.getWorkByType();
  },
  mounted() {
@@ -131,30 +171,43 @@
    getWorkByType() {
      let params = {
        type: '文档审签流程',
        filterTemplate: ""
        filterTemplate: "文档审签流程"
      }
      getTemplateByType(params).then(res => {
        const data = res.data.data;
        data.forEach(item => {
          this.getProcessNode(item);
        })
        this.initFrom = data;
      }).catch(error => {
        console.log(error);
        const userInfo = JSON.parse(localStorage.getItem('saber-userInfo'));
        this.processTemplateList = data;
        this.saveParam.processTemplate = data[0].value;
        this.saveParam.processName = this.paramVOS.processName || userInfo.content.userName + '-' + data[0].value; // å¯¹æµç¨‹æ¨¡æ¿ æµç¨‹åç§°èµ‹é»˜è®¤å€¼
        this.getProcessNode(data[0].attributes.oid); // é¦–次进入调用第一个模板的所有节点
      }).catch(err => {
        this.$message.error(err);
      })
    },
    // è¯·æ±‚流程节点
    getProcessNode(item) {
    getProcessNode(oid) {
      let params = {
        processOid: item.attributes.oid,
        processOid: oid,
        maxSecret: -1
      }
      getAllProcessNode(params).then(res => {
        const nodes = res.data.data;
        item.processNodes = nodes;
      }).catch(error => {
        console.log(error);
        this.initFrom = nodes;
        nodes.forEach(item => {
          // let name = item.processUserVO[0].children.map(name => name.name).join(',');
          // let ids = item.processUserVO[0].children.map(id => id.id).join(',');
          let name = this.userVo.map(name => name.name).join(',');
          let ids = this.userVo.map(id => id.id).join(',');
          this.bottomValue = name;
          this.collectParam[item.name + 'name'] = name;
          this.collectParam[item.name] = ids;
        })
        this.nodeLoading = false;
      }).catch(err => {
        this.$message.error(err);
      })
    },
@@ -163,38 +216,109 @@
      this.visible = false;
    },
    handleSelect() {
    },
    handleCollect() {
    },
    handleCancel() {
      this.dialogClose();
    },
    handleConfirm() {
      console.log(this.initFrom);
      const oids = this.dataStore.map(item => item.oid).join(',');
      let params = {
        deployid:this.processTemplateList[0].attributes.deploymentId,
        title:this.saveParam.processName,
        description:this.saveParam.processDesc,
        btmType:this.processTemplateList[0].attributes.taskType,
        uiType:this.processTemplateList[0].attributes.taskType,
        oids:oids, // å½“前数据oid,多个用,分隔
        detailInfoUrl:this.paramVOS.detailInfoUrl || '', // ç”¨æˆ·é…ç½®å±žæ€§
        resetStatus:'Editing',
        nodeUsers:{
          ...this.collectParam
        }
      }
      startProcess(params).then(res => {
        if(res.data.obj.status === 200){
          this.dialogClose();
          this.$message.success('启动流程成功');
        }else {
          this.$message.error(res.data.obj.error);
        }
      }).catch(err => {
        this.$message.error(err);
      })
    },
    //  æµç¨‹åç§°åˆå§‹åŒ–绑定
    modelNameChange() {
      var userInfo = JSON.parse(localStorage.getItem('saber-userInfo'));
    // åˆ‡æ¢æµç¨‹æ¨¡æ¿
    proTemSelect(event) {
      this.nodeLoading = true;
      this.getProcessNode(event);
      this.$refs.nodeForm.clearValidate();
    },
      if (this.paramVOS && this.paramVOS.modelName) {
        this.saveParam.modelName = this.paramVOS.modelName;
      } else if (userInfo.content && userInfo.content.userName) {
        this.saveParam.modelName = userInfo.content.userName + '启动流程';
      } else {
        this.saveParam.modelName = '';
      }
    }
    // èŠ‚ç‚¹ç‚¹å‡»äº‹ä»¶
    nodeChange(item) {
      this.nodeName = item.name;
      this.transferTitle = [`[${item.name}]未选用户`, `[${item.name}]已选用户`]
      this.leftRoleData = [
        {
          "children": [],
          "id": "zkjs",
          "leaf": true,
          "name": "总会计师",
          "oid": "1241AC3B-26AF-9B86-7870-53DA8D78A742",
          "secret": -1,
          "secretText": "",
          "type": "user"
        },
        {
          "children": [],
          "id": "1",
          "leaf": true,
          "name": "测试",
          "oid": "921D71F8-C2BB-3BCE-B744-AD0C3812F41A",
          "secret": -1,
          "secretText": "",
          "type": "user"
        },
        {
          "children": [],
          "id": "5",
          "leaf": true,
          "name": "总会计师",
          "oid": "34ddb5a8-ab95-4070-b72f-abaaa48cf8b1",
          "secret": -1,
          "secretText": "",
          "type": "user"
        }
      ];
      this.rightRoleData = this.userVo.map(item => item.oid);
      this.$refs.transfer.visible = true;
    },
    // ç©¿æ¢­æ¡†å›žå¡«
    roleSendHandler(data) {
      let filterData;
      filterData = this.userVo.filter(item => {
        return data.includes(item.oid);
      });
      const filterName = filterData.map(item => item.name).join(',');
      this.$set(this.collectParam, this.nodeName + 'name', filterName);
      this.formKey += 1; // åˆ·æ–°è¡¨å• å› ä¸ºåŒå‘绑定的this.collectParam[this.nodeName + 'name']是动态值 vue无法检测到值的更新
    },
  }
}
</script>
<style lang="scss" scoped>
.el-form-item {
  margin-bottom: 25px;
}
.el-divider--horizontal {
  margin-bottom: 20px !important;
}
.el-divider__text.is-left {
  color: #8b8989 !important;
}
</style>
Source/plt-web/plt-web-ui/src/components/actions/base/uploadFile.vue
@@ -1,45 +1,35 @@
<template>
  <el-dialog
    v-dialogDrag
    :width="width"
    :visible.sync="visible"
    :destroy-on-close="true"
    :close-on-click-modal="false"
    :destroy-on-close="true"
    :visible.sync="visible"
    :width="width"
    append-to-body
    title="上传文件"
    class="avue-dialog"
    title="上传文件"
    style="margin-top: -20vh !important;"
  >
    <Divider left="30px" text="导入提示"></Divider>
    <ul>
      <li>
        1.红色字体表示必输项
      </li>
      <li>
        2.每次仅能最多导入10000条数据
        è¯·ç‚¹å‡»æµè§ˆæ–‡ä»¶è¿›è¡Œä¸Šä¼ 
      </li>
    </ul>
    <Divider left="30px" text="excel文件,选择文件后会自动上传"></Divider>
    <Divider left="30px" text="选择文件后会自动上传"></Divider>
    <el-upload
      :before-upload="beforeUpload"
      :data="fileData"
      :headers="uploadHeaders"
      :on-change="uploadChange"
      :on-error="onError"
      :on-success="onSuccess"
      :show-file-list="false"
      accept=".xlsx, .xls"
      action="/api/ubcs-code/codeClassify/importClassify"
      action="/api/vciFileUploadController/uploadFile"
      class="upload-demo">
      <el-button size="small" style="margin: 15px 35px" type="primary">浏览文件</el-button>
    </el-upload>
    <template #footer>
      <el-button
        :loading="downloadLoading"
        size="small"
        type="primary"
        @click="downloadTemplateFun"
      >下载导入模板
      </el-button
      >
      <el-button size="small" @click="visible = false">关闭</el-button>
    </template>
  </el-dialog>
@@ -74,8 +64,11 @@
      flga: true,
      pageLoading: null,
      downloadLoading: false,
      visible:false,
      visible: false,
    }
  },
  created() {
    console.log(this.sourceData);
  },
  watch: {
    visible: {
@@ -87,8 +80,17 @@
  computed: {
    uploadHeaders() {
      return {
        "Blade-Auth": "bearer " + getToken(),
        "Authorizationtoken": getToken(),
      };
    },
    fileData() {
      return {
        ownbizOid: this.sourceData.oid,
        ownBtmName: this.sourceData.btmname,
        secretGrade: -1,
        fileDocClassify: '',
        updateFileFlag: true,
      }
    },
    width() {
      if (!validatenull(this.paramVOS.width)) {
@@ -98,14 +100,14 @@
          return this.paramVOS.width + "px";
        }
      } else {
        return "60%";
        return "40%";
      }
    },
    fullscreen(){
    fullscreen() {
      console.log(this.paramVOS)
      if(this.paramVOS.width || this.paramVOS.height){
      if (this.paramVOS.width || this.paramVOS.height) {
        return false;
      }else if(this.paramVOS.form){
      } else if (this.paramVOS.form) {
        return false;
      }
      return true;
@@ -114,49 +116,39 @@
  methods: {
    //文件上传前
    async beforeUpload(file) {
      const fileType = file.name.split(".").pop();
      if (fileType !== "xlsx" && fileType !== "xls") {
        // ä¸Šä¼ æ ¼å¼ä¸ç¬¦åˆè¦æ±‚,提示错误信息并取消上传
        this.$message.error("只允许上传xlsx、xls格式的文件");
        return Promise.reject(false);
      // èŽ·å–æ–‡ä»¶æ‰©å±•å
      const fileExtension = file.name.split(".").pop().toLowerCase(); // è½¬æ¢ä¸ºå°å†™ä»¥é¿å…å¤§å°å†™ä¸åŒ¹é…çš„问题
      if(this.paramVOS.fileType){
        if (!this.paramVOS.fileType.includes(fileExtension)) {
          // ä¸Šä¼ æ ¼å¼ä¸ç¬¦åˆè¦æ±‚,提示错误信息并取消上传
          this.$message.error(`只允许上传${this.paramVOS.fileType.toString()}格式的文件`);
          return Promise.reject(false);
        }
      }
      this.pageLoading = this.$loading({
        lock: true,
        text: "文件上传中",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });
      return true;
    },
    // æ–‡ä»¶ä¸Šä¼ æˆåŠŸ
    onSuccess(resbonse) {
      if (Object.keys(resbonse.data).length === 0) {
      if (resbonse.code === 200) {
        this.$message.success("上传成功!");
        this.dialogVisible = false;
        return;
      }else {
        this.$message.error(resbonse.msg);
      }
      if (resbonse.data.fileOid) {
        const fileName = resbonse.data.filePath.split("/").pop();
        this.$message.error("请下载错误信息文件进行查看!");
        downloadErrorFile({uuid: resbonse.data.fileOid}).then((res) => {
          func.downloadFileByBlobHandler(res);
        });
      }
    },
    //点击下载模板
    downloadTemplateFun() {
      this.downloadLoading = true;
      downloadBatchImportApplyTemplate({codeClassifyOid: this.codeClassifyOid}).then(res => {
        this.$utilFunc.downloadFileByBlob(res.data, "模板文件.xls");
        this.downloadLoading = false;
      }).catch((res) => {
        this.$message.warning(res)
        this.downloadLoading = false;
      })
    },
    //文件上传失败
    onError(res) {
      this.pageLoading.close();
      this.$message.error(res);
    },
    //文件状态改变
    uploadChange(file) {
Source/plt-web/plt-web-ui/src/components/actions/base/uploadFileAction.js
@@ -5,12 +5,16 @@
import {validatenull} from "@/util/validate";
import Vue from "vue";
import uploadFileDialog from "@/components/actions/base/uploadFile"
import func from "@/util/func";
export const doAction = (options,callback) => {
  options.sourceData = options.sourceData || {};
  options.dataStore = options.dataStore || [];
  if (func.isEmptyObject(options.sourceData)) {
    Vue.prototype.$message.error("请选择要上传的分类!");
    return false;
  }
  callPreEvent(options, doBefore, function (options) {
    showStartWindow(options, function () {
      callPostEvent(options, doAfter, callback,type);
Source/plt-web/plt-web-ui/src/components/actions/handlers.js
@@ -35,7 +35,7 @@
    uploadfile: () => {import("@/components/actions/base/uploadFileAction").then(module => {
      module.doAction(options,callback);
    })},
    //上传文件
    //下载文件
    downloadfile: () => {import("@/components/actions/base/downloadFileAction").then(module => {
      module.doAction(options,callback);
    })},
Source/plt-web/plt-web-ui/src/main.js
@@ -39,7 +39,7 @@
// å¯Œæ–‡æœ¬ç»„ä»¶
import richText from '@/components/PLT-basic-component/richText'
// ä¸Šä¼ æ–‡ä»¶ç»„ä»¶
import UploadFiles from  '@/components/PLT-basic-component/Upload-files'
import uploadFile from '@/components/PLT-basic-component/upload-file'
// è¡¨å•上传文件组件
import formUpload from "@/components/PLT-basic-component/formUpload";
// ç©¿æ¢­æ¡†ç»„ä»¶
@@ -56,7 +56,7 @@
Vue.component('dynamicTableForm', dynamicTableForm);
Vue.component('dynamicForm', dynamicForm);
Vue.component('richText', richText);
Vue.component('UploadFiles', UploadFiles);
Vue.component('uploadFile', uploadFile);
Vue.component('formUpload', formUpload);
Vue.component('Divider', Divider);
Vue.component('transfer', transfer);
Source/plt-web/plt-web-ui/src/util/basic-option.js
@@ -7,8 +7,11 @@
  searchIcon:true,
  selection:true,
  stripe:true,
  headerAlign: 'center',
  align: 'center',
  // selection æ˜¯å¦æœ‰é€‰æ‹©æ¡†
  // indexFixed:true/left/right, å›ºå®šåˆ—
  // menu:false, æ˜¯å¦æœ‰æ“ä½œæ 
  // menuTitle:xxx, æ“ä½œæ æ ‡é¢˜
  // stripe æ¡çº¹
}
Source/plt-web/plt-web-ui/src/views/system/user/index.vue
@@ -2,6 +2,7 @@
  <basic-container>
    <avue-crud
      ref="userCrud"
      :before-open="beforeOpen"
      :data="tableData"
      :option="option"
      :page.sync="page"
@@ -14,7 +15,29 @@
      @current-change="currentChange"
      @selection-change="selectChange"
      @row-click="rowClickHandler"
      @row-save="rowSaveHandler"
      @row-update="rowUpdateHandler"
    >
      <!-- éƒ¨é—¨å¤´éƒ¨æœç´¢æ’æ§½  -->
      <template slot-scope="{disabled,size}" slot="pkDepartmentNameSearch">
        <div style="display: flex;gap: 5px">
          <el-select v-model="departSearchValue" clearable placeholder="请选择部门">
            <el-option :label="departSearchObj.name" :value="departSearchObj.oid"></el-option>
          </el-select>
          <el-button size="small" type="success" @click="dialogDepartSearchHandler">选择部门</el-button>
        </div>
      </template>
      <!-- å¯¹è¯æ¡†éƒ¨é—¨æ’æ§½     -->
      <template slot="pkDepartmentNameForm" slot-scope="scope">
        <div style="display: flex;gap: 5px">
          <el-select v-model="departValue" clearable placeholder="请选择部门">
            <el-option :label="departObj.name" :value="departObj.oid"></el-option>
          </el-select>
          <el-button size="small" type="success" @click="dialogDepartHandler">选择部门</el-button>
        </div>
      </template>
      <template slot="status" slot-scope="{row}">
        <el-tag v-if="row.status === 0" type="success">启用</el-tag>
        <el-tag v-if="row.status === 1" type="danger">停用</el-tag>
@@ -26,40 +49,157 @@
      </template>
      <template #menu="{row,index,size}">
        <el-button size="small" type="text" @click="stopUserHandler(row)">
        <el-button icon="el-icon-edit" size="small" type="text" @click.stop="rowEditHandler(row,index)">编辑</el-button>
        <el-button icon="el-icon-delete" size="small" type="text" @click.stop="rowDeleteHandler(row)">删除</el-button>
        <el-button size="small" type="text" @click.stop="stopUserHandler(row)">
          <span v-if="row.status === 0" style="color: #fa3434"><i class="el-icon-video-pause"></i> åœç”¨</span>
          <span v-if="row.status === 1" style="color: #55b61d"><i class="el-icon-video-pause"></i> å¯ç”¨</span>
        </el-button>
      </template>
      <template slot="menuLeft" slot-scope="scope">
        <el-button icon="el-icon-delete" plain size="small" type="danger">删除</el-button>
        <el-button icon="el-icon-delete" plain size="small" type="danger" @click="allDelHandler">删除</el-button>
        <el-button icon="el-icon-user" plain size="small" type="primary" @click="roleHandler">分配角色</el-button>
        <el-button icon="el-icon-school" plain size="small" type="primary">分配部门</el-button>
        <el-button icon="el-icon-key" plain size="small" type="success">设置密码策略</el-button>
        <el-button icon="el-icon-upload2" plain size="small" type="primary">导入人员</el-button>
        <el-button icon="el-icon-download" plain size="small" type="primary">下载导入模板</el-button>
        <el-button icon="el-icon-school" plain size="small" type="primary" @click="departmentHandler">分配部门</el-button>
        <el-button icon="el-icon-key" plain size="small" type="success" @click="setPwsHandler">设置密码策略</el-button>
        <el-button icon="el-icon-upload2" plain size="small" type="primary" @click="uploadRole">导入人员</el-button>
        <el-button icon="el-icon-download" plain size="small" type="primary" @click="downloadHandler">下载导入模板</el-button>
      </template>
    </avue-crud>
    <transfer ref="transfer" :left-role-data="leftRoleData" :right-role-data="rightRoleData" title="分配角色"
              @transferSend="roleSendHandler"></transfer>
    <!-- åˆ†é…è§’色穿梭框   -->
    <transfer ref="transfer" :left-role-data="leftRoleData" :right-role-data="rightRoleData"
              :transferTitle="transferTitle" title="分配角色"
              @transferSend="roleSendHandler">
    </transfer>
    <!-- è®¾ç½®å¯†ç ç­–略对话框   -->
    <el-dialog
      v-dialogDrag
      v-loading="pwdLoading"
      :destroy-on-close="true"
      :visible.sync="pwdVisible"
      append-to-body="true"
      class="avue-dialog"
      style="margin-top: -15vh !important;"
      title="设置密码策略"
      width="30%"
    >
      <div class="password-strategy-container">
        <div><i class="el-icon-setting"/>设置密码策略:</div>
        <el-select v-model="pwdValue" placeholder="请选择密码策略">
          <el-option v-for="(item,index) in pwdList" :key="index" :label="item.name" :value="item.id"></el-option>
        </el-select>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="pwdVisible = false">取 æ¶ˆ</el-button>
        <el-button size="small" type="primary" @click="savePwdHandler">ç¡® å®š</el-button>
      </div>
    </el-dialog>
    <!-- å¯¼å…¥äººå‘˜   -->
    <upload-file ref="upload" :fileType="upFileType" :fileUrl="fileUrl" title="导入人员"></upload-file>
    <!-- åˆ†é…éƒ¨é—¨å¯¹è¯æ¡†    -->
    <el-dialog
      v-dialogDrag
      v-loading="departLoading"
      :destroy-on-close="true"
      :visible.sync="departVisible"
      append-to-body="true"
      class="avue-dialog"
      title="分配部门"
      width="50%"
    >
      <avue-crud
        ref="departCrud"
        :data="departData"
        :option="departOption"
        @current-row-change="handleCurrentRowChange"
      >
      </avue-crud>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="departVisible = false">取 æ¶ˆ</el-button>
        <el-button size="small" type="primary" @click="saveDepartHandler">ç¡® å®š</el-button>
      </div>
    </el-dialog>
  </basic-container>
</template>
<script>
import basicOption from '@/util/basic-option'
import {getDataUsers, stopUser, gridRoles, listRoleByUserOid, saveRights, addUser, updateUser, deleteUser} from '@/api/system/user/api'
import {
  getDataUsers,
  stopUser,
  gridRoles,
  listRoleByUserOid,
  saveRights,
  addUser,
  updateUser,
  deleteUser,
  selectPwdStrategyMap,
  saveUserPasswordStrateg,
  download,
  departmentQueryController,
  saveUsersDepts
} from '@/api/system/user/api'
import {column} from "./option"
import func from '@/util/func'
export default {
  name: "userManage",
  data() {
  data: function () {
    return {
      departSearchObj:{},
      departSearchValue:'',
      loadKey: 0,
      departStatus: '', // åŒºåˆ†ä¸åŒæ–¹å¼æ‰“开部门对话框
      departValue: '', // éƒ¨é—¨å¯¹è¯æ¡†ä¸‹æ‹‰æ¡†ç»‘定值
      departObj: {},  // éƒ¨é—¨å¯¹è¯æ¡†ä¸‹æ‹‰æ¡†é€‰é¡¹ç»‘定值
      departCurrenRow: {},
      departOption: {
        ...basicOption,
        rowKey: 'oid',
        rowParentKey: 'parentId',
        selection: false,
        highlightCurrentRow: true,
        stripe: false,
        menu: false,
        refreshBtn: false,
        gridBtn: false,
        column: [
          {
            label: '名称',
            prop: 'name',
          },
          {
            label: '编号',
            prop: 'id',
          },
          {
            label: '描述',
            prop: 'description',
          },
        ]
      },
      departData: [],
      departLoading: false,
      departVisible: false,
      upFileType: ['xls', 'xlsx'],
      fileUrl: 'api/userQueryController/importUser',
      pwdVisible: false,
      pwdLoading: false,
      pwdValue: '',
      pwdList: [],
      tableLoading: false,
      tableData: [],
      option: {
        ...basicOption,
        editBtn: false,
        delBtn: false,
        dialogWidth: '50%',
        calcHeight: -60,
        column: column
      },
@@ -71,13 +211,22 @@
      },
      searchParams: {},
      selectList: [],
      leftRoleData: [],  // åˆ†é…è§’色穿梭框左侧默认数据
      rightRoleData: [], // åˆ†é…è§’色穿梭框右侧默认数据
      leftRoleData: [],  // åˆ†é…è§’色穿梭框左侧初始数据
      rightRoleData: [], // åˆ†é…è§’色穿梭框右侧初始数据
      transferTitle: ['现有角色', '拥有角色']
    }
  },
  created() {
  },
  methods: {
    // æ–°å¢žæˆ–修改对话框打开前
    beforeOpen(done, type) {
      if(type == 'add'){
        this.departObj = {};
        this.departValue = "";
      }
      done();
    },
    // è¡¨æ ¼è¯·æ±‚
    getTableList() {
      this.tableLoading = true;
@@ -98,6 +247,11 @@
    // æœç´¢æŸ¥è¯¢
    handleSearch(params, done) {
      this.searchParams = {};
      if(this.departSearchObj && this.departSearchValue){
        this.searchParams['conditionMap["pkDepartment"]'] = this.departSearchValue;
      }
      if (!func.isEmptyObject(params)) {
        for (let key in params) {
          if (params.hasOwnProperty(key)) {
@@ -106,15 +260,20 @@
            this.searchParams[`conditionMap["${newKey}"]`] = params[key];
          }
        }
      } else {
      }
      if (func.isEmptyObject(params) && !this.departSearchValue) {
        this.searchParams = {};
      }
      this.getTableList();
      done();
    },
    // é‡ç½®æœç´¢æ¡ä»¶
    handleReset() {
      this.departSearchObj = {};
      this.departSearchValue = "";
      this.searchParams = {};
      this.getTableList();
    },
@@ -182,7 +341,7 @@
    // ç©¿æ¢­æ¡†ç»„件回填
    roleSendHandler(row) {
      let params = {
        userOid: this.selectList[0].oid,
        userOids: this.selectList[0].oid,
        roleIds: row.join(',')
      }
      saveRights(params).then(res => {
@@ -191,12 +350,256 @@
      }).catch(err => {
        this.$message.error(err)
      })
    }
    },
    // è®¾ç½®å¯†ç ç­–ç•¥
    setPwsHandler() {
      if (this.selectList.length <= 0) {
        this.$message.warning('清先选择人员再进行操作!')
        return;
      }
      this.pwdLoading = false;
      selectPwdStrategyMap().then(res => {
        if (res.data.code === 200) {
          this.pwdList = res.data.data;
          this.pwdValue = res.data.data[0].id;
          console.log(res.data)
          this.pwdVisible = true;
          this.pwdLoading = false;
        } else {
          this.$message.error(res.data.msg);
        }
      })
    },
    // ä¿å­˜å¯†ç ç­–ç•¥
    savePwdHandler() {
      let params = {
        userIds: this.selectList.map(item => item.oid).join(','),
        passwordStrategId: this.pwdValue
      }
      saveUserPasswordStrateg(params).then(res => {
        this.pwdVisible = false;
        this.$message.success(res.data.obj)
      }).catch(err => {
        this.$message.error(err)
      })
    },
    // æ–°å¢ž
    rowSaveHandler(row, done) {
      if (row.password != row.confirmPassword) {
        this.$message.error('请检查两次密码是否输入一致!')
        return this.$refs.userCrud.$refs.dialogForm.$refs.tableForm.allDisabled = false;
      }
      row.pkDepartment = this.departValue; // å°†å½“前行的部门参数pkDepartment èµ‹å€¼ä¸ºä¸‹æ‹‰æ¡†ç»‘定的值
      addUser(row).then(res => {
        if (res.data.code === 200) {
          this.$message.success(res.data.obj);
          this.getTableList();
        }
      }).catch(err => {
        console.log(err);
      })
      done()
    },
    // æ“ä½œæ ç¼–辑
    rowEditHandler(row, index) {
      let obj = { name: row.pkDepartmentName, oid: row.pkDepartment, rowOid: row.oid };
      this.departValue = row.pkDepartment;
      this.departObj = obj;
      if (this.departObj.rowOid) {
        this.$refs.userCrud.rowEdit(row, index);
      }
    },
    // ç¼–辑
    rowUpdateHandler(row, index, done) {
      if (row.password != row.confirmPassword) {
        this.$message.error('请检查两次密码是否输入一致!')
        return this.$refs.userCrud.$refs.dialogForm.$refs.tableForm.allDisabled = false;
      }
      row.pkDepartment = this.departValue; // å°†å½“前行的部门参数pkDepartment èµ‹å€¼ä¸ºä¸‹æ‹‰æ¡†ç»‘定的值
      updateUser(row).then(res => {
        if (res.data.code === 200) {
          this.$message.success(res.data.obj);
          this.getTableList();
        }
      }).catch(err => {
        console.log(err);
      });
      done()
    },
    // åˆ é™¤
    rowDeleteHandler(row) {
      let params = {
        ids: row.oid
      }
      deleteUser(params).then(res => {
        if (res.data.code === 200) {
          this.$message.success(res.data.obj);
          this.getTableList();
        }
      }).catch(err => {
        console.log(err);
      })
    },
    // å¤šé€‰åˆ é™¤
    allDelHandler() {
      let params = {
        ids: this.selectList.map(item => item.oid).join(',')
      }
      if (this.selectList.length <= 0) {
        this.$message.warning('请至少选择一条数据进行删除!')
        return;
      }
      this.$confirm('您确定要删除所选择的成员吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteUser(params).then(res => {
          if (res.data.code === 200) {
            this.$message.success(res.data.obj);
            this.getTableList();
          }
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // ä¸‹è½½å¯¼å…¥æ¨¡æ¿
    downloadHandler() {
      download().then(res => {
        console.log(res);
        func.downloadFileByBlobHandler(res);
        this.$message.success('下载成功')
      }).catch(err => {
        this.$message.error(err);
      })
    },
    // å¯¼å…¥äººå‘˜
    uploadRole() {
      this.$refs.upload.visible = true;
    },
    // åˆ†é…éƒ¨é—¨
    departmentHandler() {
      if (this.selectList.length <= 0) {
        this.$message.warning('清先选择人员再进行操作!')
        return;
      }
      this.departStatus = 'default'; // åŒºåˆ†ä¸åŒæ–¹å¼æ‰“开部门对话框
      this.departmentQueryOnLoad();
    },
    // åˆ†é…éƒ¨é—¨è¡¨æ ¼åˆå§‹åŒ–请求
    departmentQueryOnLoad() {
      departmentQueryController({queryAllLevel: true}).then(res => {
        const data = res.data.treeData;
        this.departData = this.departDtaFormAtter(data);
        this.departVisible = true;
      }).catch(err => {
        this.$message.error(err);
      })
    },
    // åˆ†é…éƒ¨é—¨æ•°æ®è½¬æ¢
    departDtaFormAtter(items) {
      return items.map(item => {
        // è½¬æ¢å½“前节点的属性
        const formList = {
          oid: item.oid,
          id: item.attributes.id,
          name: item.attributes.name,
          description: item.attributes.description,
          parentId: item.parentId,
          parentName: item.parentName,
          parentBtmName: item.parentBtmName,
          // å¦‚æžœchildren存在且不为空,则递归转换children
          children: item.children && item.children.length > 0 ? this.departDtaFormAtter(item.children) : undefined
        };
        return formList;
      });
    },
    // åˆ†é…éƒ¨é—¨ è¡Œå•选
    handleCurrentRowChange(row) {
      this.departCurrenRow = row;
    },
    // åˆ†é…éƒ¨é—¨ ä¿å­˜
    saveDepartHandler() {
      if (func.isEmptyObject(this.departCurrenRow)) {
        this.$message.warning('请选择部门节点!')
        return;
      }
      if (this.departStatus == 'default') {
        let params = {
          userOIds: this.selectList.map(item => item.oid).join(','),
          deptId: this.departCurrenRow.oid,
        };
        saveUsersDepts(params).then(res => {
          if (res.data.code === 200) {
            this.departVisible = false;
            this.getTableList();
            this.$message.success('分配成功!')
          }
        }).catch(err => {
          console.log(err);
        })
        return;
      }
      if (this.departStatus == 'handle') {
        this.departObj = this.departCurrenRow;
        this.departValue = this.departCurrenRow.oid;
        this.departVisible = false;
        return;;
      }
      if(this.departStatus == 'search'){
        this.departSearchObj =  this.departCurrenRow;
        this.departSearchValue =  this.departCurrenRow.oid;
        this.departVisible = false;
        return;
      }
    },
    // å¯¹è¯æ¡†åˆ†é…éƒ¨é—¨æŒ‰é’®
    dialogDepartHandler() {
      this.departmentQueryOnLoad();
      this.departStatus = 'handle'; // åŒºåˆ†ä¸åŒæ–¹å¼æ‰“开部门对话框
    },
    // æœç´¢å¯¹è¯æ¡†åˆ†é…éƒ¨é—¨æŒ‰é’®
    dialogDepartSearchHandler(){
      this.departmentQueryOnLoad();
      this.departStatus = 'search'; // åŒºåˆ†ä¸åŒæ–¹å¼æ‰“开部门对话框
    },
  }
}
</script>
<style scoped>
<style lang="scss" scoped>
.password-strategy-container {
  padding-left: 20px;
  display: flex;
  //justify-content: center;
  align-items: center;
  gap: 10px;
}
</style>
Source/plt-web/plt-web-ui/src/views/system/user/option.js
@@ -1,21 +1,64 @@
export const column = [
export let column = [
  {
    label: '账号',
    prop: 'id',
    search:true,
    sortable:true,
    rules: [
      {
        required: true,
        message: '请输入姓名',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '姓名',
    prop: 'name',
    align:'center',
    search:true,
    sortable:true
  }, {
    label: '账号',
    prop: 'id',
    align:'center',
    search:true,
    sortable:true
    sortable:true,
    rules: [
      {
        required: true,
        message: '请输入姓名',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '密码',
    prop: 'password',
    hide:true,
    type:'password',
    change: (val)=>{
      const confirmPasswordColumn = column.find(item => item.prop === 'confirmPassword');
      confirmPasswordColumn.disabled = val.value === "";
    },
    rules: [
      {
        required: true,
        message: '请输入密码',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '确认密码',
    prop: 'confirmPassword',
    hide:true,
    type:'password',
    disabled:true,
    rules: [
      {
        required: true,
        message: '请再次确认密码',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '状态',
    prop: 'status',
    align: 'center',
    display:false,
    sortable:true,
    slot: true,
@@ -29,7 +72,6 @@
  {
    label: '锁定状态',
    prop: 'lockFlag',
    align:'center',
    sortable:true,
    display:false,
  },
@@ -40,19 +82,18 @@
    search:true,
    sortable:true,
    searchslot:true,
    formslot:true,
  },
  {
    label: '专业',
    prop: 'specialties',
    align:'center',
    sortable:true,
  },
  {
    label: '角色',
    prop: 'pkPersonName',
    align:'center',
    type:'select',
    dicUrl: 'api/roleQueryController/gridRoles',
    dicUrl: 'api/roleQueryController/refDataGrid',
    props: {
      label: 'name',
      value: 'oid'
@@ -65,28 +106,27 @@
  {
    label: '电子邮件',
    prop: 'email',
    align:'center',
    sortable:true,
    overHidden: true,
    row:true
  },
  {
    label: '描述',
    type:'textarea',
    prop: 'description',
    align:'center',
    sortable:true,
    overHidden: true,
  },
  {
    label: '部门领导',
    prop: 'isDeptLeader',
    align:'center',
    sortable:true,
    display:false,
  },
  {
    label: '所属密级',
    prop: 'secretGradeText',
    align:'center',
    sortable:true,
    display:false,
  }
  },
];
Source/plt-web/plt-web-ui/vue.config.js
@@ -26,7 +26,9 @@
    proxy: {
      '/api': {
        //本地服务接口地址
        target: 'http://localhost:12000/web',
        // target: 'http://localhost:12000/web',
        target: 'http://192.168.0.105:12005/web', // yxc
        // target: 'http://192.168.0.103:12005/web', // ldc
        // target: 'http://dev.vci-tech.com:37000',
        //远程演示服务地址,可用于直接启动项目
        //target: 'https://saber.bladex.vip/api/',