Browse Source

导入查重合并功能,提交一个版本(有bug)

wanyuan 10 months ago
parent
commit
435ab084f7

+ 7 - 0
tc-service/tap-task/src/main/java/com/minto/app/task/dao/ITaskSummaryDao.java

@@ -621,4 +621,11 @@ public interface ITaskSummaryDao extends BaseDao {
     PageInfo<TaskPanelOutput> findAllManagerTask4WebPanel(PageInfo pageInfo, Map<String, Object> params);
 
     int countAllManagerTask4WebPanel(Map<String, Object> params);
+
+    /**
+     * 查找所有任务,不包含被逻辑删除的
+     *
+     * @return
+     */
+    List<Map<String, Object>> findAllTaskSummaryExcludeDeleted();
 }

+ 6 - 0
tc-service/tap-task/src/main/java/com/minto/app/task/dao/TaskSummaryDaoImpl.java

@@ -2299,4 +2299,10 @@ public class TaskSummaryDaoImpl extends BaseDaoImpl implements ITaskSummaryDao {
         }
         return 0;
     }
+
+    @Override
+    public List<Map<String, Object>> findAllTaskSummaryExcludeDeleted(){
+        String sql = "SELECT T.id AS id, T.title AS title FROM task_summary T WHERE tstate != 7;";
+        return DBAgent.findByNativeSql(sql);
+    }
 }

+ 217 - 0
tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskByTypeManagerImpl.java

@@ -86,6 +86,7 @@ import com.minto.core.common.AppContext;
 import com.minto.core.constants.BaseConstants;
 import com.minto.core.ds.DBAgent;
 import com.minto.core.event.SystemFrameWorkEvent;
+import com.minto.core.po.BasePO;
 import com.minto.core.util.*;
 import com.minto.core.util.concurrent.Worker;
 import com.minto.tap.collaboration.api.CollaborationApi;
@@ -98,6 +99,7 @@ import com.minto.tip.common.exceptions.BusinessException;
 import com.minto.tip.common.util.annotation.Transactional;
 import com.minto.tip.event.EventDispatcher;
 import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.criterion.Criterion;
@@ -114,12 +116,16 @@ import org.springframework.util.CollectionUtils;
 import java.lang.reflect.Field;
 import java.sql.SQLException;
 import java.text.MessageFormat;
+import java.text.NumberFormat;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.servlet.http.HttpServletRequest;
 
 import static com.minto.app.organization.OrgConstants.DEFAULT_ACCOUNT_ID;
 
@@ -14832,4 +14838,215 @@ public class TaskByTypeManagerImpl implements ITaskByTypeManager{
     public List<TaskReportBean> findReportByTaskIdAndPhaseIdAndPhaseConfigId(Map<String, Object> params) {
         return taskReportDao.findReportByTaskIdAndPhaseIdAndPhaseConfigId(params);
     }
+
+    @Override
+    public List<Map<String, Object>> checkRepeatTaskByName(List<Long> taskIds, Long taskType){
+        List<Map<String, Object>> res = new ArrayList<>();
+        List<Map<String, Object>> tasks = taskSummaryDao.findAllTaskSummaryExcludeDeleted();
+        Map<Boolean, List<Map<String, Object>>> map =
+                tasks.stream().collect(Collectors.groupingBy(e -> taskIds.contains(e.get("id"))));
+        List<Map<String, Object>> sourceTasks = map.get(Boolean.TRUE);
+        List<Map<String, Object>> targetTasks =
+                map.get(Boolean.FALSE).stream().filter(e -> e.get("title") != null).collect(
+                        Collectors.toList());
+        if(CollectionUtils.isEmpty(sourceTasks) || CollectionUtils.isEmpty(tasks)){
+            return res;
+        }
+        //通过相似度算法匹配相似的督办任务
+        //FIXME 可能性能较差
+        Map<Long, List<Long>> idmap = new HashMap<>();
+        sourceTasks.forEach(a -> {
+            Long id = (Long)a.get("id");
+            String s = a.get("title").toString();
+            int l = s.length();
+            targetTasks.forEach(b -> {
+                String t = b.get("title").toString();
+                double d = levenshteinDistance(s, t);
+                //d = jaccardSimilarity(s,t);
+                if((l <= 10 && d > 70) || (10 < l && l <= 20 && d > 75) || (20 < l && d > 80)){
+                    //认为相似
+                    List<Long> longs = idmap.get(id);
+                    if(longs == null){
+                        longs = new ArrayList<>();
+                        idmap.put(id, longs);
+                    }
+                    longs.add((Long)b.get("id"));
+                }
+            });
+
+        });
+        //构建返回数据
+        if(!idmap.isEmpty()){
+            idmap.forEach((k, v) -> {
+                Map<String, Object> smap = new HashMap<>();
+                smap.put("id", k);
+                List<Map<String, Object>> taskDatas = new ArrayList<>();
+                List<Long> tIds = Lists.newArrayList();
+                tIds.add(k);
+                tIds.addAll(v);
+                tIds.forEach(e -> {
+                    TaskSummaryBean summary = taskSummaryDao.findTaskSummaryById(e);
+                    Map<String, Object> data = buildImportReportData(summary, taskType);
+                    taskDatas.add(data);
+                });
+                smap.put("tasks", taskDatas);
+                res.add(smap);
+            });
+
+        }
+        return res;
+    }
+
+    private Map<String, Object> buildImportReportData(TaskSummaryBean summary, Long taskType){
+        Map<String, Object> data = new HashMap<>();
+        data.put("id", summary.getId());
+        List<TaskTypeRelationBean> relations = findTaskTypeRelByTaskId(summary.getId());
+        Set<Long> collect = relations.stream().map(TaskTypeRelationBean::getTypeId).collect(Collectors.toSet());
+        if(StringUtils.isNumeric(summary.getTaskTypeId())){
+            collect.add(Long.valueOf(summary.getTaskTypeId()));
+        }
+        String typeNames = findTaskTypeByIds(new ArrayList<>(collect))
+                        .stream().map(TaskTypeBean::getName).collect(Collectors.joining(","));
+        data.put("type", typeNames);
+        List<Map<String, Object>> extendDatas = taskListManager.findTemplateData4Task(summary.getId(), taskType, "task");
+        extendDatas.forEach(d -> {
+            Object value = d.get("value");
+            String name = d.get("name").toString();
+            data.put(name, value);
+            if("select".equals(d.get("showType"))){
+                if(value instanceof Map){
+                    Object names = ((Map<?, ?>)value).get("names");
+                    if(names instanceof List){
+                        data.put(name, StringUtils.join(names,","));
+                    }
+                }
+            }else if("personOrOrgs".equals(d.get("showType"))){
+                if(value instanceof Map){
+                    data.put(name, ((Map<?, ?>)value).get("names"));
+                }
+            }
+        });
+        return data;
+    }
+
+
+    /**
+     * 使用编辑距离来计算相似度
+     * @param s
+     * @param t
+     * @return
+     */
+    private double levenshteinDistance(String s, String t){
+        int n = s.length();
+        int m = t.length();
+        if(n == 0)
+            return m;
+        if(m == 0)
+            return n;
+
+        int[][] dp = new int[n + 1][m + 1];
+        for(int i = 0; i <= n; i++){
+            dp[i][0] = i;
+        }
+        for(int j = 0; j <= m; j++){
+            dp[0][j] = j;
+        }
+
+        for(int i = 1; i <= n; i++){
+            for(int j = 1; j <= m; j++){
+                if(s.charAt(i - 1) == t.charAt(j - 1)){
+                    dp[i][j] = dp[i - 1][j - 1];
+                } else{
+                    dp[i][j] = 1 + Math.min(
+                            Math.min(dp[i - 1][j], dp[i][j - 1]),
+                            dp[i - 1][j - 1]);
+                }
+            }
+        }
+        int levenshteinDistance = dp[n][m];
+        int length = Math.max(s.length(), t.length());
+
+        NumberFormat numberFormat = NumberFormat.getInstance();
+        // 设置精确到小数点后2位
+        numberFormat.setMaximumFractionDigits(2);
+        return Double.parseDouble(numberFormat.format(((float)1 - (float)levenshteinDistance / (float)length) * 100));
+    }
+
+    @Override
+    public Map<String, Object> updateTask4Merge(HttpServletRequest request){
+        Map<String, Object> res = new HashMap<>();
+        Long taskType = ReqUtil.getLong(request,"taskType");
+        Long[] idArray = ReqUtil.getLongArray(request, "ids[]");
+        List<TaskSummaryBean> tasks = taskSummaryDao.findTaskSummariesById(idArray);
+        Map<Long, TaskSummaryBean> taskMap = tasks.stream().collect(Collectors.toMap(BasePO::getId, e -> e));
+        Long titleTaskId = ReqUtil.getLong(request, "titleId");
+        TaskSummaryBean task = taskMap.get(titleTaskId);
+
+        Long typeTaskId = ReqUtil.getLong(request, "typeId");
+        if(!titleTaskId.equals(typeTaskId)){
+            //更新任务类型
+            TaskSummaryBean sourceTask = taskMap.get(typeTaskId);
+            if(!StringUtils.equals(task.getTaskTypeId(), sourceTask.getTaskTypeId())){
+                task.setTaskTypeId(sourceTask.getTaskTypeId());
+                taskSummaryDao.updateTaskSummaryBean(task);
+            }
+            deleteTaskTypeRel(new Long[]{titleTaskId});
+            List<TaskTypeRelationBean> soureTaskTypes = findTaskTypeRelByTaskId(typeTaskId);
+            Set<Long> sourceTaskTypeIds =soureTaskTypes.stream().map(TaskTypeRelationBean::getTypeId).collect(Collectors.toSet());
+            if(!CollectionUtils.isEmpty(sourceTaskTypeIds)){
+                List<Object> collect = sourceTaskTypeIds.stream().map(e -> {
+                    TaskTypeRelationBean bean = new TaskTypeRelationBean();
+                    bean.setId(UUIDUtil.UUIDLong());
+                    bean.setTaskId(titleTaskId);
+                    bean.setTypeId(e);
+                    return bean;
+                }).collect(Collectors.toList());
+                taskManager.saveOrUpdateAll(collect);
+            }
+        }
+        Long contentTaskId = ReqUtil.getLong(request, "contentId");
+        if(!titleTaskId.equals(contentTaskId)){
+            //更新工作任务(content)
+            CommonContentBean sourceBean = contentManager.findCommonContentBeanById(contentTaskId);
+            CommonContentBean bean = contentManager.findCommonContentBeanById(titleTaskId);
+            bean.setContent(sourceBean == null ? "" : sourceBean.getContent());
+            contentManager.updateCommonContentBean(bean);
+        }
+
+        Map<String, Object> extendMap = new HashMap<>();
+        Long directoryTaskId = ReqUtil.getLong(request, "directoryId");
+        if(!titleTaskId.equals(directoryTaskId)){
+            //更新任务分档(field_1000)
+            List<Map<String, Object>> extendDatas = taskListManager.findTemplateData4Task(directoryTaskId, taskType, "task");
+            Map<String, Object> extendData =
+                    extendDatas.stream().filter(e->"field_1000".equals(e.get("name"))).findFirst().orElse(new HashMap<>());
+            if(extendData != null && extendData.get("value") instanceof Map){
+                Object names = ((Map)extendData.get("value")).get("ids");
+                if(names instanceof List){
+                    extendMap.put("field_1000", ((List)names).stream().map(String::valueOf).collect(Collectors.joining(",")));
+                }
+            }
+        }
+        Long fromTaskId = ReqUtil.getLong(request, "fromId");
+        if(!titleTaskId.equals(fromTaskId)){
+            List<Map<String, Object>> extendDatas = taskListManager.findTemplateData4Task(directoryTaskId, taskType,
+                    "task");
+            Map<String, Object> extendData =
+                    extendDatas.stream().filter(e -> "field_51".equals(e.get("name"))).findFirst()
+                               .orElse(new HashMap<>());
+            extendMap.put("field_51", extendData.get("realValue"));
+        }
+        if(MapUtils.isNotEmpty(extendMap)){
+            saveExtendDataByTemplate(task, extendMap,false);
+        }
+
+        List<Long> ids = Stream.of(idArray).collect(Collectors.toList());
+        ids.remove(titleTaskId);
+        taskManager.deleteTaskById(ids.toArray(new Long[0]), true);
+        task = taskSummaryDao.findTaskSummaryById(titleTaskId);
+        Map<String, Object> data = buildImportReportData(task, taskType);
+        res.put("ids", ids);
+        res.put("task", data);
+        return res;
+    }
 }

+ 12 - 0
tc-service/tap-task/src/main/java/com/minto/app/task/manager/TaskListManagerImpl.java

@@ -1457,6 +1457,18 @@ public class TaskListManagerImpl implements ITaskListManager {
 		//事项类型
 		String currentTaskTypeId = ParameterUtil.getString(keyParam, "currentTaskTypeId");
 		data.put("category",getKeyDes(currentTaskTypeId,typeInfo));
+		TaskTypeBean currentTaskType = ParameterUtil.get(keyParam, "currentTaskType",TaskTypeBean.class);
+		if(currentTaskType.getId().equals(currentTaskType.getParentId())){
+			//一极两大三区
+			List<TaskTypeRelationBean> taskTypeRelations = AppContext.getBean(ITaskTypeRelationDao.class).getTaskTypeRelations(summary.getId());
+			if(CollectionUtil.isNotEmpty(taskTypeRelations)){
+				String categoryStr = taskTypeRelations.stream().filter(e -> !e.getTypeId().equals(currentTaskType.getId()))
+					.map(e -> getKeyDes(e.getTypeId().toString(), typeInfo)).collect(Collectors.joining("\n"));
+				if(StringUtils.isNotEmpty(categoryStr)){
+					data.put("category", data.get("category") + "\n" + categoryStr);
+				}
+			}
+		}
 		data.put("from",getKeyDes(summary.getFromId(),fromInfo));//事项来源
 		data.put("startDate",summary.getStartDate());//开始时间
 		List<Map<String,Object>> participantNameList=(List<Map<String,Object>>)minfo.get(""+TaskMemberRelTypeEnum.Participant.getKey()).get("names");

+ 25 - 4
tip-front/src/main/java/com/minto/app/task/controller/TaskByTypeController.java

@@ -137,6 +137,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.ui.ModelMap;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -5583,6 +5584,11 @@ public class TaskByTypeController extends BaseController{
 
             List<Long> taskIds = taskByTypeManager.importTask(taskType, dataList, isTemplate);
             dataMap.put("taskIds", taskIds);
+            //检查重复
+            List<Map<String,Object>> repeatTasks = taskByTypeManager.checkRepeatTaskByName(taskIds, taskType);
+            if(!CollectionUtils.isEmpty(repeatTasks)){
+                dataMap.put("repeatTasks", repeatTasks);
+            }
             /*****************立即刷新没有承办部门的数据 by zhangyu 2015-5-15***************/
 //            if(CollectionUtil.isNotEmpty(dataList)){
 //                taskManager.updateNotDeptInfos();
@@ -5590,13 +5596,13 @@ public class TaskByTypeController extends BaseController{
             dataMap.put("state", "success");
             dataMap.put("message", "导入成功!");
             //异步汇报历史数据,延迟20m执行
-            TimerHolder.newTimerAtDelay(()->{
+            TimerHolder.newTimerAtDelay(() -> {
                 try{
                     AppContext.getBean(ITaskDynamicMonManager.class).defaultDoStart();
-                }catch (Exception e){
-                    log.error(">汇报历史数据线程异步执行失败."+e.getMessage());
+                } catch(Exception e){
+                    log.error(">汇报历史数据线程异步执行失败." + e.getMessage());
                 }
-            },"task-async-save-history-report", 20, TimeUnit.SECONDS);
+            }, "task-async-save-history-report", 20, TimeUnit.SECONDS);
         } catch (Exception e) {
             dataMap.put("state", "error");
             // dataMap.put("message", "格式错误,请检查模版!");
@@ -5607,6 +5613,21 @@ public class TaskByTypeController extends BaseController{
         }
         return null;
     }
+
+    @RequestMapping(value = "/mergeTask", method = RequestMethod.POST)
+    public void mergeTask(HttpServletRequest request, HttpServletResponse response) throws Exception{
+        Map<String, Object> dataMap = new HashMap<>();
+        try{
+            Map<String, Object> map = taskByTypeManager.updateTask4Merge(request);
+            dataMap.put("state", "success");
+            dataMap.putAll(map);
+        } catch(Exception e){
+            dataMap.put("state", "error");
+            log.error(e.getMessage(), e);
+        } finally{
+            RespUtil.rendJson(response, dataMap);
+        }
+    }
     class CountDownCreateTaskSummaryList implements CountDownLatchInterface{
 
         Long cid;

+ 200 - 0
tip-front/src/main/webapp/tc_suite/minto/task/js/newListShow.js

@@ -983,6 +983,7 @@ var TaskSummaryListBusinessEnum = {
             },
             // 导入数据
             importExcel:function(callback){
+
                 TC.ui.rel.show({
                     title:$.i18n("task.import.data"),// '导入数据',
                     model: 1,
@@ -1000,6 +1001,7 @@ var TaskSummaryListBusinessEnum = {
                             $.startProc();
                             $.post(TC.config.baseUrl+"/taskByType/importData/",{from:'space',fileId:fileId.join(","),taskType:TC.task.table.getTaskType()},function(result){
                                 $.endProc();
+                                debugger;
                                 if(result.state == "success"){
                                     $.ok(result.message,function(){
                                         if ($.isFunction(callback)){
@@ -1026,6 +1028,7 @@ var TaskSummaryListBusinessEnum = {
                                                 TC.task.table.reloadData();
                                             }
                                         }
+                                        TC.task.table.showRepeatData(result.repeatTasks);
                                     });
                                 }else{
                                     $.error(result.message);
@@ -2261,6 +2264,7 @@ var TaskSummaryListBusinessEnum = {
                     $.alert("请选中要分配任务类型的事项!");//"请选中要分配任务类型的事项!"
                     return ;
                 }
+                debugger;
                 $.dialog({
                     title :"任务类型分配",//任务类型分配,
                     max: false,
@@ -4753,7 +4757,203 @@ var TaskSummaryListBusinessEnum = {
                 }
             })
         };
+        this.repeatVm = null;
+        this.showRepeatData = function (result){
+            if(result && window.Vue){
+                //需要展开的重复项
+//                var name = result[0].id;
+                var $that = this;
+//                debugger;
+                if(!this.repeatVm){
+                    this.repeatVm = new Vue({
+                        el:'#importRepeatDiv',
+                        data(){
+                            return{
+                                collapseVisible: false,//是否显示重复详情
+                                dialogVisible: false,//是否显示合并弹窗
+                                activeNames: ['1'],//需要展开的重复项
+                                repeatData: result, //重复数据
+                                multipleSelection: [],//选择任务项的集合
+                                titles: [],//以下都是合并弹窗内数据
+                                contents: [],
+                                types: [],
+                                directorys: [],
+                                froms: [],
+                                form: {
+                                    titleId: '',
+                                    contentId: '',
+                                    typeId: '',
+                                    directoryId: '',
+                                    fromId:''
+                                }
+                            }
+                        },
+                        methods: {
+                            handleChange(val) {
+                                console.log(val);
+                            },
+                            handleSelectionChange(val) {
+                                this.multipleSelection = val;
+                            },
+                            handleDelete(index, id, row) {
+                                console.log('点击删除按钮得到这条数据的id:'+id, row.id)
+                                this.removeDataTasks(row.id, id);
+                            },
+                            openDialogButton() {
+                                console.log('选择合并的数据:', this.multipleSelection);
+                                if(this.multipleSelection.length < 2 ){
+                                    $.alert("单条督办任务不能合并!");
+                                    return;
+                                }
+
+                                this.dialogVisible = true
+                                this.titles = this.multipleSelection.map(function (item) {
+                                    return {value:item.id, label:item.title}
+                                })
+                                this.contents = this.multipleSelection.map(function (item) {
+                                    return {value:item.id, label:item.content}
+                                })
+                                this.types = this.multipleSelection.map(function (item) {
+                                    return {value:item.id, label:item.type}
+                                })
+                                this.directorys = this.multipleSelection.map(function (item) {
+                                    return {value:item.id, label:item.field_1000}
+                                })
+                                this.froms = this.multipleSelection.map(function (item) {
+                                    return {value:item.id, label:item.field_51}
+                                })
+
+                                $.dialog({
+                                    title :"合并",//任务类型分配,
+                                    max: false,
+                                    min: false,
+                                    width:"800px",
+                                    height:"400px",
+                                    content : "url:"+TC.config.baseUrl+"/tc_suite/taskmt/byType/mergeTask.jsp",
+                                    data:{
+                                    "taskType":TC.task.table.getTaskType(),
+                                    "titles":this.titles,
+                                    "contents":this.contents,
+                                    "types":this.types,
+                                    "directorys":this.directorys,
+                                    "froms":this.froms,
+                                    form: {
+                                        titleId: this.titles[0].value,
+                                        contentId: this.contents[0].value,
+                                        typeId: this.types[0].value,
+                                        directoryId: this.directorys[0].value,
+                                        fromId: this.froms[0].value
+                                                                                                                }
+                                    },
+                                    lock : true,
+                                    button : [{
+                                        "name":"提交",// "发送",
+                                        callback:function(){
+                                        var _this = this;
+                                            this.iframe.contentWindow.mergeRequest(function(result){
+                                                if (result.state=="success") {
+                                                    $.ok("合并成功!");
+                                                    _this.close();
+                                                    var repeatData = vm.repeatData;
+                                                    for( var i=0;i<repeatData.length;i++){
+                                                            var item = repeatData[i];
+                                                            const index = item.tasks.findIndex(chdItem => chdItem.id === result.task.id);
+                                                            if (index != -1) {
+                //                                                            item.tasks[index] = result.task;
+                                                                vm.$set(item.tasks,index,result.task);
+                                                                vm.$set(repeatData,i,item);
+                                                                continue;
+                                                            }
+                                                    }
+                                                    for(var i =0 ; i < result.ids.length; i++){
+                                                        debugger;
+                                                        vm.removeDataTasks(result.ids[i]);
+                                                    }
+
+                                                    vm.clearDialogData();
+                                                    TC.task.table.changeTab({
+                                                        listType: TaskSummaryListBusinessEnum.Supervise,
+                                                        listStatus: TaskSummaryListBusinessEnum.Register,
+                                                    });
+                                                    TC.task.table.reloadData();
+                                                } else {
+                                                    $.alert("合并失败!");
+                                                }
+                                            });
+                                            return false;
+                                        },
+                                        focus:true
+                                    }],
+                                    cancel:function(){
+
+                                    }
+                                });
+                            },
+                            removeDataTasks(taskId, id){
+                                debugger;
+                                this.repeatData.forEach(item => {
+                                    if(!id || item.id == id){
+                                        const removeIndex = item.tasks.findIndex(chdItem => chdItem.id === taskId);
+                                        if (removeIndex !== -1) {
+                                            item.tasks.splice(removeIndex, 1)
+                                        }
+                                    }
+                                });
+                                this.repeatData =  this.repeatData.filter(function(item) {
+                                    return item.tasks.length != 0;
+                                });
+                            },
+                            clearDialogData() {
+                                this.titles = [];
+                                this.contents = [];
+                                this.types = [];
+                                this.directorys = [];
+                                this.froms = [];
+                                this.form = {
+                                    titleId: '',
+                                    contentId: '',
+                                    typeId: '',
+                                    directoryId: '',
+                                    fromId:''
+                                };
+                            },
+                            mergeRequest() {
+                                if(this.titles.length<2){
+                                    $.alert("至少需要选中2条督办任务才能合并!");
+                                    return;
+                                }
+                            },
+                            closeMergeDialog(){
+                                this.dialogVisible = false;
+                                this.clearDialogData();
+                            }
+                        }
+                    })
+                }else{
+                    this.repeatVm.$data = {
+                        collapseVisible: false,//是否显示重复详情
+                        dialogVisible: false,//是否显示合并弹窗
+                        activeNames: ['1'],//需要展开的重复项
+                        repeatData: result, //重复数据
+                        multipleSelection: [],//选择任务项的集合
+                        titles: [],//以下都是合并弹窗内数据
+                        contents: [],
+                        types: [],
+                        directorys: [],
+                        froms: [],
+                        form: {
+                            titleId: '',
+                            contentId: '',
+                            typeId: '',
+                            directoryId: '',
+                            fromId:''
+                        }
+                    };
+
+                }
 
+            }
+        }
     });
 
     win.TC = _TC;

+ 64 - 0
tip-front/src/main/webapp/tc_suite/minto/task/list.jsp

@@ -26,6 +26,8 @@
     <link rel="stylesheet" href="${path}/common/zTree/css/zTreeStyle/zTreeStyle.css${resSuffix}">
     <link rel="stylesheet" href="${path}/tc_ttp/bootstrap/css/font-awesome.css">
     <link rel="stylesheet" href="${path}/tc_ttp/element-ui/minto/element-ui.css${resSuffix}">
+    <link rel="stylesheet" type="text/css" href="${path}/tc_ttp/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" type="text/css" href="${path}/common/element-ui/theme-chalk/index.css">
     <style>
         html, body {
             height: 100%;
@@ -51,6 +53,7 @@
 
         #addTaskPro {
             box-shadow: 0 7px 10px 0px rgba(0, 74, 143, 0.18);
+            margin-bottom:0;
         }
 
         * {
@@ -757,6 +760,36 @@
         .mt-btn-help-2{
             width: 38px;
         }
+        [v-cloak]{
+            display:none;
+        }
+        .repeat {
+            background: #fff;
+            border-radius: 10px;
+            padding: 0 10px;
+            position: absolute;
+            width: 600px;
+            z-index: 10;
+            border: 1px solid #ddd;
+            max-height:600px;
+            overflow:auto;
+        }
+        .el-icon-delete{
+            cursor: pointer;
+            padding:0 10px;''
+        }
+        .mixinButton {
+            margin-top: 25px;
+        }
+        .el-table{
+            max-height:200px;
+            overflow:auto;
+         }
+       .el-collapse-item__content{
+         display: flex;
+         flex-direction: column;
+         align-items: center;
+       }
 
     </style>
 </head>
@@ -1610,6 +1643,34 @@
                         </div>
                     </div>
                     <div class="leftBottom">
+                        <div id="importRepeatDiv" v-cloak>
+                            <div class="repeat-box" v-if="repeatData.length>0">
+                <!-- 模拟下拉框 -->
+                <div class="select-box" >
+                    <el-button  @click="collapseVisible = !collapseVisible">重复数据<span>{{repeatData.length}}</span>条
+                        <i class="el-icon-caret-bottom"></i>
+                    </el-button>
+                </div>
+                <!-- 手风琴 -->
+                <div class="repeat" v-if="collapseVisible">
+                    <el-collapse v-model="activeNames" @change="handleChange">
+                        <el-collapse-item :title="item.tasks.length + '项'" :name="index+1" v-for="item,index in
+                        repeatData" :key="item.id" v-if="item.tasks.length>0">
+                            <el-table :data="item.tasks" style="width: 100%" :show-header="false" @selection-change="handleSelectionChange">
+                                <el-table-column type="selection"></el-table-column>
+                                <el-table-column prop="title" width="400"> </el-table-column>
+                                <el-table-column align="right">
+                                    <template slot-scope="scope">
+                                        <i class="el-icon-delete" @click="handleDelete(scope.$index, item.id, scope.row)"></i>
+                                    </template>
+                                </el-table-column>
+                            </el-table>
+                            <el-button @click="openDialogButton" type="primary" class="mixinButton">合并</el-button>
+                        </el-collapse-item>
+                    </el-collapse>
+                </div>
+            </div>
+                        </div>
                         <div id="frameDiv" class="tabDiv">
                             <iframe class="111" id="mainFrame" name="mainFrame" width="95%" height="100%"
                                     frameborder="0" scrolling="no"
@@ -1817,6 +1878,8 @@
         src="${path}/common/mCustomScrollbar/js/jquery.mCustomScrollbar.concat.min.js${resSuffix}"></script>
 <%--<script type="text/javascript" src="${path}/tc_suite/meeting/js/layer.js${resSuffix}"></script>--%>
 <script type="text/javascript" src="${path}/tc_suite/minto/task/js/listAction.js${resSuffix}"></script>
+<script type="text/javascript" src="${path}/common/vue/vue.min.js"></script>
+<script type="text/javascript" src="${path}/common/element-ui/index.js"></script>
 
 <script>
     var localStorage = window.localStorage;
@@ -3825,4 +3888,5 @@
     }
 
 </script>
+
 </html>

+ 196 - 0
tip-front/src/main/webapp/tc_suite/taskmt/byType/mergeTask.jsp

@@ -0,0 +1,196 @@
+<%--
+  ~ Copyright (c) 2014, 2023, Chengdu Minto Technology Co.,LTD. All rights reserved.
+  ~ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  --%>
+<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="tc" uri="http://www.mingto.net/tip" %>
+<%@ page isELIgnored="false" %>
+<!DOCTYPE html>
+
+<html  lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>事项类型分配</title>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="renderer" content="webkit|ie-stand|ie-comp">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta http-equiv="X-UA-Compatible" content="IE=11;IE=10;IE=9; IE=8; IE=7; IE=EDGE,chrome=1" />
+    <style type="text/css">
+            .mt-form-item {
+                align-items: center;
+            }
+        </style>
+    <link rel="stylesheet" href="${path}/common/css/minto.icon.css${resSuffix}" type="text/css"/>
+    <link rel="stylesheet" href="${path}/common/css/minto.comp.css${resSuffix}" type="text/css"/>
+    <link href="${path}/common/css/minto.layout.css${resSuffix}" rel="Stylesheet" type="text/css"/>
+    <link rel="stylesheet" href="${path}/common/mCustomScrollbar/css/jquery.mCustomScrollbar.css">
+    <link rel="stylesheet" href="${path}/tc_suite/minto/task/css/list.css${resSuffix}">
+    <link rel="shortcut icon" href="${path}/favicon.ico${resSuffix}" type="image/x-icon"/>
+    <link rel="stylesheet" href="${path}/common/zTree/css/zTreeStyle/zTreeStyle.css${resSuffix}">
+    <link rel="stylesheet" href="${path}/tc_ttp/bootstrap/css/font-awesome.css">
+    <link rel="stylesheet" href="${path}/tc_ttp/element-ui/minto/element-ui.css${resSuffix}">
+    <link rel="stylesheet" type="text/css" href="${path}/tc_ttp/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" type="text/css" href="${path}/common/element-ui/theme-chalk/index.css">
+    <style  type="text/css">
+        a, a:hover, a:focus{
+            color: #0c94ff;
+        }
+        .mt-content{
+            display: flex;
+            height: 100vh;
+            font-size: 16px;
+            padding: 20px;
+        }
+        .taskList{
+            width: 70%;
+        }
+        .origin-tree{
+            width: 30%;
+        }
+        .list-item{
+            display: flex;
+        }
+        #taskType{
+            width: 618px;
+            height: 120px;
+            resize: none;
+            padding: 10px;
+        }
+        .close-icon {
+            display: none;
+            cursor: pointer;
+            color: red;
+            font-size: 20px;
+            margin-left: 5px;
+        }
+        .flex-ac{
+            display: flex;
+            align-items: center;
+        }
+        .list-name{
+            line-height: 22px;
+            margin-bottom: 10px;
+            width: fit-content;
+        }
+        .list-name:hover{
+            background-color: #f0f0f0;
+        }
+        .list-name:hover .close-icon{
+            display: block;
+        }
+        .text-ellipsis-1 {
+            overflow: hidden;
+            display: -webkit-box;
+            /*white-space: break-spaces;*/
+            word-break: break-all;
+            -webkit-box-orient: vertical;
+            -webkit-line-clamp: 1;
+        }
+        textarea[disabled] {
+            background: #fff !important;
+            cursor: not-allowed;
+        }
+        label{
+            font-weight: normal;
+            user-select: none;
+        }
+        .red-point{
+            color: red;
+            margin-right: 5px;
+        }
+
+
+
+      .vm-el-select .el-form-item__content .el-select{
+           display:flex;
+           flex:1;
+      }
+
+    </style>
+
+
+</head>
+<body>
+<div id="vm" class="vm-el-select">
+
+                <!-- 对话框 -->
+                    <el-form :model="form">
+                        <el-form-item label="任务名称:" label-width="400">
+                            <el-select v-model="form.titleId" placeholder="">
+                                <el-option v-for="(item, index) in titles" :key="index" :label="item.label" :value="item.value" ></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="工作任务:" label-width="400">
+                            <el-select v-model="form.contentId" placeholder="">
+                                <el-option v-for="(item, index) in contents" :key="index" :label="item.label" :value="item.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="事项类型:" label-width="400">
+                            <el-select v-model="form.typeId" placeholder="">
+                                <el-option v-for="(item, index) in types":key="index" :label="item.label" :value="item.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="任务分档:" label-width="400">
+                            <el-select v-model="form.directoryId" placeholder="">
+                                <el-option v-for="(item, index) in directorys" :key="index" :label="item.label" :value="item.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="事项来源:" label-width="400">
+                            <el-select v-model="form.fromId" placeholder="">
+                                <el-option v-for="(item, index) in froms" :key="index" :label="item.label" :value="item.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-form>
+</div>
+<script type="text/javascript" src="${path}/tc_ttp/jquery/jquery-1.12.4.min.js${resSuffix}"></script>
+<script type="text/javascript" src="${path}/tc_ttp/common/tc.js"></script>
+<script type="text/javascript" src="${path}/common/vue/vue.min.js"></script>
+<script type="text/javascript" src="${path}/common/element-ui/index.js"></script>
+
+<script>
+ var vm = new Vue({
+    el:'#vm',
+    data(){
+        return {
+            ...window.frameElement.api.data
+        };
+    },
+
+ })
+function mergeRequest(callback){
+    console.log('合并表单的数据:',this.form);
+                var ids = [];
+                var _this = this.vm;
+                _this.titles.forEach(item => {
+                    ids.push(item.value);
+                });
+                $.ajax({
+                    url: TC.config.baseUrl + "/taskByType/mergeTask",
+                    type: "post",
+                    dataType: "json",
+                    data: {
+                        taskType: _this.taskType,
+                        ids: ids,
+                        titleId: _this.form.titleId,
+                        typeId: _this.form.typeId,
+                        contentId: _this.form.contentId,
+                        directoryId: _this.form.directoryId,
+                        fromId: _this.form.fromId,
+                    },
+                    success: function (result) {
+                        if ($.isFunction(callback)) {
+                            callback(result);
+                        }
+                    },
+                    error:function(){
+                        $.alert("合并失败!");
+                    }
+                });
+}
+</script>
+</body>
+
+</html>