Преглед изворни кода

升级工作流引擎,任务可以添加附件、删除附件、下载附件。

YangZhiJie пре 2 година
родитељ
комит
6a2b656457

+ 0 - 31
src/api/workflow/WorkflowResource.js

@@ -38,37 +38,6 @@ export default {
     });
   },
 
-  /**
-	 * 工具类自动生成的方法
-	 * 工具作者: 杨志杰
-	 * 添加评论 
-	 */
-  addComment: function(chooseTask){
-    var requestUrl = 'api/WorkflowResource/AddComment';
-
-
-    return new Promise((resolve, reject) => {
-      $.ajax({
-        url: Common.getApiUrl2(requestUrl),
-        type: 'post',
-        contentType: 'application/json',
-				
-				
-        data: JSON.stringify(chooseTask),
-				
-        beforeSend: function(request) {
-          Common.addTokenToRequest(request);
-        },
-        success: function(data) {
-          resolve(data);
-        },
-        error: function(XMLHttpRequest, textStatus, errorThrown) {
-          reject(XMLHttpRequest);
-        },
-      });
-    });
-  },
-
   /**
 	 * 工具类自动生成的方法
 	 * 工具作者: 杨志杰

+ 22 - 0
src/common/Common.js

@@ -309,5 +309,27 @@ export default {
       return this.getHostPageBaseURL() + '/' + url;
     }
   },
+
+  /**
+   * 函数防抖
+   * 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
+   * @param {*} fn 
+   * @param {*} delay 
+   * @returns 
+   */
+  debounce: function (fn, delay) {
+    var timer; // 维护一个 timer
+    return function () {
+      var _this = this; // 取debounce执行作用域的this
+      var args = arguments;
+      if (timer) {
+        clearTimeout(timer);
+      }
+      timer = setTimeout(function () {
+        fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
+      }, delay);
+    };
+  },
+
 };
 

+ 1 - 1
src/widget/Cropper.vue

@@ -50,7 +50,7 @@
     <div style="height: 5px" />
     <div :id="'modal-contain' + uuid">
       <div :id="'preview-image-div' + uuid">
-        <img :id="'crop-image' + uuid" />
+        <img :id="'crop-image' + uuid" width="100%" />
       </div>
     </div>
   </div>

+ 37 - 307
src/workflow/ApproveComment.vue

@@ -8,7 +8,7 @@
         {{ $t("lang.approveComment.approveStatus") }}
         <span class="label label-primary m-label">
           {{
-            processInstanceDescription.isActive
+            !processInstanceDescription.suspended
               ? $t("lang.approveComment.running")
               : $t("lang.approveComment.finished")
           }}
@@ -17,58 +17,22 @@
         <span class="label label-info m-label">
           {{ $t("lang.approveComment.needApprove") }}:
           {{
-            processInstanceDescription.activeTaskDescriptions == undefined
+            processInstanceDescription.taskDescriptions == undefined
               ? "0"
-              : processInstanceDescription.activeTaskDescriptions.length
+              : processInstanceDescription.taskDescriptions.length
           }}
         </span>
 
         <span class="label label-success m-label">
           {{ $t("lang.approveComment.approved") }}:
           {{
-            processInstanceDescription.taskComments == undefined
+            processInstanceDescription.historicTaskInstanceDescriptions == undefined
               ? "0"
-              : processInstanceDescription.taskComments.length
+              : processInstanceDescription.historicTaskInstanceDescriptions.length
           }}
         </span>
-
-        <span class="label label-warning m-label">
-          {{ $t("lang.approveComment.abandon") }}:
-          {{
-            processInstanceDescription.abandonCount == undefined
-              ? "0"
-              : processInstanceDescription.abandonCount
-          }}
-        </span>
-        
-        <span v-if="windowNo == '20220707_162600'" class="label label-primary m-label" @click="viewApprovalProcess()">
-          {{ $t("lang.approveComment.viewApprovalProcess") }}
-        </span>
-        <span v-if="windowNo == '20220703_174047'" class="label label-primary m-label" @click="viewApprovalProcess()">
-          {{ $t("lang.approveComment.viewApprovalProcess") }}
-        </span>
       </div>
       <div class="panel-body">
-        <div class="progress">
-          <div
-            class="progress-bar progress-bar-success progress-bar-striped"
-            role="progressbar"
-            aria-valuenow="40"
-            aria-valuemin="0"
-            aria-valuemax="100"
-            :style="{
-              width: processInstanceDescription.isActive ? '50%' : '100%',
-            }"
-          >
-            <span class="sr-only">{{
-              processInstanceDescription.isActive
-                ? $t("lang.approveComment.running")
-                : $t("lang.approveComment.finished")
-            }}</span>
-            <!-- <span>查看审批流程</span> -->
-          </div>
-        </div>
-
         <div v-if="showChoiceButton && isActiveTask" class="form">
           <PreviousNodeSelectUser
             ref="previousNodeSelectUser"
@@ -145,48 +109,7 @@
             <textarea v-model="comment" class="form-control" rows="3" />
           </div>
 
-          <div class="form-group" :class="{ 'image-height': hasImage() }">
-            <label class="control-label">{{ $t("lang.approveComment.picture") }}</label>
-            <div class="input-group">
-              <ImageListWidget ref="imageListWidget" :class-name="className" />
-            </div>
-          </div>
-
-          <div class="form-group">
-            <div id="uploadAttachmentForm">
-              <label class="control-label" for="uploadAttachmentForm">{{
-                $t("lang.approveComment.attachment")
-              }}</label>
-              <div class="input-group">
-                <div
-                  v-for="(item, index) in attachments"
-                  :key="item.id"
-                  class="file-box"
-                >
-                  <FileImage
-                    :file-property="generateFileProperty(item)"
-                    :show-image="true"
-                  />
-                  <span
-                    class="glyphicon glyphicon-trash file-remove"
-                    @click="removeFile(index)"
-                  />
-                </div>
-                <div>
-                  <label for="exampleInputFile" class="label-btn">
-                    {{ $t("lang.approveComment.chooseFile") }}
-                  </label>
-                  <input
-                    id="exampleInputFile"
-                    autocomplete="off"
-                    type="file"
-                    class="inputfile"
-                    @change="uploadFile"
-                  />
-                </div>
-              </div>
-            </div>
-          </div>
+          <ApproveTaskAttachmentEdit :task-id="taskInfoId" />
         </div>
 
         
@@ -215,14 +138,14 @@
                 }}</small>
               </h4>
               <h5 class="m-h5">{{ processInstanceDescription.startTime }}</h5>
-              <p>{{ $t("lang.approveComment.submitApprove") }}</p>
+              <p class="comment-text">{{ $t("lang.approveComment.submitApprove") }}</p>
             </div>
           </li>
 
-          <template v-if="processInstanceDescription.taskComments != undefined">
+          <template v-if="processInstanceDescription.historicTaskInstanceDescriptions != undefined">
             <li
-              v-for="taskComment in processInstanceDescription.taskComments"
-              :key="taskComment.id"
+              v-for="historicTaskInstanceDescription in processInstanceDescription.historicTaskInstanceDescriptions"
+              :key="historicTaskInstanceDescription.id"
               class="media"
             >
               <div class="media-left">
@@ -231,7 +154,7 @@
                     :auth-src="
                       Common.getThumbnailImageSrc(
                         'com.leanwo.prodog.base.model.User',
-                        taskComment.userImageUrl
+                        historicTaskInstanceDescription.assigneeImageUrl
                       )
                     "
                     class="media-object thumbnail m-image"
@@ -240,52 +163,32 @@
               </div>
               <div class="media-body">
                 <h4 class="media-heading">
-                  {{ taskComment.userName }}
+                  {{ historicTaskInstanceDescription.assigneeName }}
                   <small class="badge alert-success">{{
-                    taskComment.taskName
+                    historicTaskInstanceDescription.name
                   }}</small>
                 </h4>
 
-                <div v-if="taskComment.comments != undefined">
+                <div v-if="historicTaskInstanceDescription.comments != undefined">
                   <div
-                    v-for="commentItem in taskComment.comments"
+                    v-for="commentItem in historicTaskInstanceDescription.comments"
                     :key="commentItem.id"
                   >
-                    <h5 class="m-h5">{{ commentItem.commentDate }}</h5>
-                    <p>{{ commentItem.comment }}</p>
+                    <h5 class="m-h5">{{ commentItem.time }}</h5>
+                    <p class="comment-text">{{ commentItem.message }}</p>
                   </div>
                 </div>
 
-                <div v-if="taskComment.imageNames != undefined">
-                  <AuthImage
-                    v-for="(imageName, index) in taskComment.imageNames"
-                    :key="index"
-                    :auth-src="getCommentImageSrc(imageName)"
-                    class="thumbnail m-image1"
-                    @click="openImageAttachment(imageName)"
-                  />
-                </div>
-
-                <div v-if="taskComment.attachmentNames != undefined">
-                  <a
-                    v-for="(
-                      attachmentName, index
-                    ) in taskComment.attachmentNames"
-                    :key="index"
-                    :href="getAttachmentsUrl(attachmentName)"
-                    target="view_window"
-                    class="btn btn-primary btn-sm btn-block"
-                  >{{ attachmentName }}</a>
-                </div>
+                <ApproveTaskAttachmentView :enable-delete="false" :attachments="historicTaskInstanceDescription.attachments" />
               </div>
             </li>
           </template>
 
-          <template v-for="activeTask in processInstanceDescription.activeTaskDescriptions" :key="activeTask.id">
+          <template v-for="activeTask in processInstanceDescription.taskDescriptions" :key="activeTask.id">
             <li
             
               v-if="
-                processInstanceDescription.activeTaskDescriptions != undefined
+                processInstanceDescription.taskDescriptions != undefined
               "
             
               class="media"
@@ -305,11 +208,13 @@
               </div>
               <div class="media-body">
                 <h4 class="media-heading">
-                  {{ activeTask.assignee }}
+                  {{ activeTask.assigneeName }}
                   <small class="badge alert-info">{{ activeTask.name }}</small>
                 </h4>
                 <h5 class="m-h5">{{ activeTask.startTime }}</h5>
-                <p>{{ $t("lang.approveComment.processing") }}</p>
+                <p class="comment-text">{{ $t("lang.approveComment.processing") }}</p>
+
+                <ApproveTaskAttachmentView :enable-delete="activeTask.id == taskInfoId" :attachments="activeTask.attachments" />
               </div>
             </li>
           </template>
@@ -464,27 +369,27 @@ import UserStorageResource from '../api/base/UserStorageResource.js';
 import UserResource from '../api/base/UserResource.js';
 import WorkflowResource from '../api/workflow/WorkflowResource.js';
 
-import ImageListWidget from './ImageListWidget.vue';
 import PreviousNodeSelectUser from './PreviousNodeSelectUser.vue';
 
 
-import FileImage from '../widget/FileImage.vue';
-
 import AuthImage from '../widget/AuthImage.vue';
 import ApproveForm from './ApproveForm.vue';
 
 import vSelect from 'vue-select';
 import 'vue-select/dist/vue-select.css';
 import { Notify, Uuid } from 'pc-component-v3';
+import ApproveTaskAttachmentEdit from './ApproveTaskAttachmentEdit.vue';
+import ApproveTaskAttachmentView from './ApproveTaskAttachmentView.vue';
+
 export default {
 
   components: {
-    ImageListWidget,
-    FileImage,
     AuthImage,
     vSelect,
     PreviousNodeSelectUser,
     ApproveForm,
+    ApproveTaskAttachmentEdit,
+    ApproveTaskAttachmentView,
   },
 
   props: {
@@ -543,7 +448,6 @@ export default {
     this.Common = Common;
     return {
       processInstanceDescription: {},
-      attachments: [],
       comment: '',
       className: 'WorkFlow',
       infoWindowNo: '050408',
@@ -671,82 +575,6 @@ export default {
       });
     },
 
-    /**
-     * 查看审批流程
-     * @author XiongLiuJie 20221952
-     */
-    viewApprovalProcess: function(){
-      let _self = this;
-      if(_self.windowNo == '20220707_162600'){
-        let isAutoFlow = _self.modelData.data.isAutoFlow.displayValue[0];
-        if(isAutoFlow == 'false'){
-          let totalAmountUSD = _self.modelData.data.totalAmountUSD.displayValue[0];
-          if(totalAmountUSD < 5000){
-            let url = '/static/x-spreadsheet/index.html?processReportNo=20221110_200758&recordId=' + _self.recordId;
-            window.open(url);
-            // window.layer.open({
-            //   title: '查看ADA审批人报告',
-            //   type: 2,
-            //   area: ['1280px', '720px'],
-            //   fixed: false, //不固定
-            //   maxmin: true,
-            //   content: url,
-            // });
-          }
-          if(totalAmountUSD > 5000){
-            let url = '/static/x-spreadsheet/index.html?processReportNo=20221117_022208&recordId=' + _self.recordId;
-            window.open(url);
-            // window.layer.open({
-            //   title: '查看ADA审批人报告',
-            //   type: 2,
-            //   area: ['1280px', '720px'],
-            //   fixed: false, //不固定
-            //   maxmin: true,
-            //   content: url,
-            // });
-          }
-          
-        }else{
-          let url = '/static/x-spreadsheet/index.html?processReportNo=20221117_013808&recordId=' + _self.recordId;
-          window.open(url);
-          // window.layer.open({
-          //   title: '查看Auto_ADA审批人报告',
-          //   type: 2,
-          //   area: ['1280px', '720px'],
-          //   fixed: false, //不固定
-          //   maxmin: true,
-          //   content: url,
-          // });
-        }
-      }
-      if(_self.windowNo == '20220703_174047'){
-        let totalAmountUSD = _self.modelData.data.totalAmountUSD.displayValue[0];
-        if(totalAmountUSD < 5000){
-          let url = '/static/x-spreadsheet/index.html?processReportNo=20221110_204424&recordId=' + _self.recordId;
-          window.open(url);
-          // window.layer.open({
-          //   title: '查看ATA审批人报告',
-          //   type: 2,
-          //   area: ['1280px', '720px'],
-          //   fixed: false, //不固定
-          //   maxmin: true,
-          //   content: url,
-          // });
-        }
-        if(totalAmountUSD > 5000){
-          let url = '/static/x-spreadsheet/index.html?processReportNo=20221117_025516&recordId=' + _self.recordId;
-          window.open(url);
-          // window.layer.open({
-          //   title: '查看ATA审批人报告',
-          //   type: 2,
-          //   area: ['1280px', '720px'],
-          //   fixed: false, //不固定
-          //   maxmin: true,
-          //   content: url,
-          // });
-        }
-      }
-    },
 
     /**
      * 转批
@@ -801,12 +629,6 @@ export default {
       var _self = this;
     },
 
-    /**
-     * 删除文件
-     */
-    removeFile: function (index) {
-      this.attachments.splice(index, 1);
-    },
 
     /**
      * 生成文件属性
@@ -861,52 +683,6 @@ export default {
       });
     },
 
-    /**
-     * 上传文件
-     */
-    uploadFile: function (event) {
-      var _self = this;
-
-      let fileList = event.target.files;
-      var selectedFile = null;
-      if (fileList.length > 0) {
-        selectedFile = fileList[0];
-      }
-      if (selectedFile == null) {
-        return;
-      }
-      var formData = new FormData();
-      formData.append('file', selectedFile);
-      formData.append('className', _self.className);
-      _self.loading=true;
-
-      $.ajax({
-        url: Common.getApiURL('file/multipleAttachmentUpload'),
-        type: 'post',
-        beforeSend: function (request) {
-          Common.addTokenToRequest(request);
-        },
-        data: formData,
-        contentType: false,
-        processData: false,
-        success: function (data) {
-          _self.loading=false;
-          if (data.success) {
-            var fileNames = data.fileNames;
-            if (fileNames != undefined && fileNames.length > 0) {
-              fileNames.forEach(function (item) {
-                //   _self.attachments = [item.nameAfterSave];
-                _self.attachments.push(item.nameAfterSave);
-              });
-            }
-          }
-        },
-        error: function (XMLHttpRequest, textStatus, errorThrown) {
-          _self.loading=false;
-          Common.processException(XMLHttpRequest, textStatus, errorThrown);
-        },
-      });
-    },
 
     /**
      * 拒绝
@@ -953,25 +729,23 @@ export default {
         return;
       }
 
-      var chooseTask = {
+      var addCommentRequest = {
         taskId: _self.taskInfoId,
         comment: _self.comment,
-        imageNames: _self.$refs.imageListWidget.getImages(),
-        attachmentNames: _self.attachments,
       };
 
       _self.loading=true;
 
       $.ajax({
-        url: Common.getApiURL('WorkflowResource/AddComment'),
+        url: Common.getApiURL('WorkflowResource/addComment'),
         type: 'post',
         beforeSend: function (request) {
           Common.addTokenToRequest(request);
         },
         contentType: 'application/json',
-        data: JSON.stringify(chooseTask),
+        data: JSON.stringify(addCommentRequest),
         success: function (data) {
-          _self.loading=false;
+          _self.loading = false;
           _self.comment = '';
           _self.refresh();
         },
@@ -1000,12 +774,6 @@ export default {
       chooseTask.modelData = modelData;
       chooseTask.className = _self.workflowClassName;
 
-      //var images = _self.$refs.imageListWidget.getImages();
-      //console.log(images);
-      //chooseTask.imageNames = images;
-      //chooseTask.attachmentNames = _self.attachments;
-
-      // 添加工作流表单数据
 
       if (command === 'APPROVE') {
         try {
@@ -1051,16 +819,6 @@ export default {
       });
     },
 
-    hasImage: function () {
-      var _self = this;
-      if (_self.$refs.imageListWidget) {
-        var images = _self.$refs.imageListWidget.getImages();
-        if (images != undefined && images.length > 0) {
-          return true;
-        }
-      }
-      return false;
-    },
 
     /**
      * 获取评论的图片
@@ -1089,15 +847,6 @@ export default {
       window.open(fullPath);
     },
 
-    /**
-     * 获取附件的URL
-     * @param  {[type]} url [description]
-     * @return {[type]}     [description]
-     */
-    getAttachmentsUrl: function (url) {
-      console.log(url);
-      return Common.getAttachmentsSrc(this.className, url);
-    },
 
     /**
      * 打开自定义窗口
@@ -1206,6 +955,7 @@ export default {
 .m-image {
   width: 64px;
   height: 64px;
+  margin-bottom: 0px;
 }
 
 .m-image1 {
@@ -1215,29 +965,6 @@ export default {
   cursor: pointer;
   margin-right: 5px;
 }
-.inputfile {
-  width: 0.1px;
-  height: 0.1px;
-  opacity: 0;
-  overflow: hidden;
-  position: absolute;
-  z-index: -1;
-}
-.label-btn {
-  color: white;
-  background-color: #006699;
-  display: inline-block;
-  padding: 5px 15px;
-  border-radius: 5px;
-}
-.label-btn:hover {
-  color: white;
-  background-color: #003399;
-  display: inline-block;
-  padding: 5px 15px;
-  border-radius: 5px;
-  cursor: pointer;
-}
 .file-box {
   width: 150px;
   position: relative;
@@ -1328,4 +1055,7 @@ button.forSaleOrder {
   animation: go 3s infinite;
   text-shadow: 1px 1px 1px black;
 }
+.comment-text{
+  margin-bottom: 0px;
+}
 </style>

+ 144 - 0
src/workflow/ApproveTaskAttachmentEdit.vue

@@ -0,0 +1,144 @@
+<template>
+  <div class="form-group">
+    <div id="uploadAttachmentForm">
+      <label class="control-label" for="uploadAttachmentForm">{{
+        $t("lang.approveComment.attachment")
+      }}</label>
+      <div class="input-group">
+        <div>
+          <a-upload
+            name="file"
+            :file-list="fileList"
+            :before-upload="beforeUpload"
+            :show-upload-list="{ showDownloadIcon: false, showRemoveIcon: false }"
+            @change="handleChange"
+          >
+            <a-button>
+              <upload-outlined />
+              {{ $t("lang.approveComment.chooseFile") }}
+            </a-button>
+          </a-upload>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import Common from '../common/Common.js';
+import FileImage from '../widget/FileImage.vue';
+import { message } from 'ant-design-vue';
+import { UploadOutlined } from '@ant-design/icons-vue';
+
+
+export default {
+    
+  components: {
+    FileImage,
+    UploadOutlined,
+  },
+
+  props: {
+    taskId: {
+      type: String,
+      default: null,
+    },
+  },
+  data: function () {
+    return {
+      fileList: [],
+      headers: {
+        token: localStorage.getItem('#token'),
+      },
+    };
+  },
+
+  methods: {
+    beforeUpload: function(file){
+      console.log(file);
+      const _self = this;
+      file.status = 'uploading';
+      this.fileList = [...this.fileList, file];
+      this.$nextTick(function(){
+        _self.uploadFile(file, file.uid);
+      });
+      return false;
+    },
+
+
+    
+    /**
+     * 设置上传文件的状态
+     */
+    setFileStatus : function(uid, status){
+      const _self = this;
+      for(var i = 0; i < _self.fileList.length; i++){
+        if(_self.fileList[i].uid === uid){
+          _self.fileList[i].status = status;
+          console.debug(JSON.stringify(_self.fileList[i]));
+          break;
+        }
+      }
+      this.fileList = [...this.fileList];
+    },
+    
+
+    handleChange: function(info) {
+      if (info.file.status !== 'uploading') {
+        console.log(info.file, info.fileList);
+      }
+      if (info.file.status === 'done') {
+        message.success(`${info.file.name} file uploaded successfully`);
+      } else if (info.file.status === 'error') {
+        message.error(`${info.file.name} file upload failed.`);
+      }
+    },
+
+
+    /**
+     * 上传文件
+     * @param file 文件
+     * @param uid 文件唯一标识
+     */
+    uploadFile: function (file, uid) {
+      var _self = this;
+      const formData = new FormData();
+      formData.append('file', file);
+      formData.append('uid', uid);
+      formData.append('taskId', _self.taskId);
+      formData.append('attachmentType', 'FileAttachment');
+
+      $.ajax({
+        url: Common.getApiURL('WorkflowResource/addAttachment'),
+        type: 'post',
+        beforeSend: function (request) {
+          Common.addTokenToRequest(request);
+        },
+        data: formData,
+        contentType: false,
+        processData: false,
+        success: function (data) {
+          if (data.errorCode == 0) {
+            const fileUploadResponses = data.datas;
+            if (fileUploadResponses != undefined && fileUploadResponses.length > 0) {
+              fileUploadResponses.forEach(function (fileUploadResponse) {
+                if(fileUploadResponse.errorCode == 0){
+                  _self.setFileStatus(fileUploadResponse.uid, 'done');
+                }else{
+                  _self.setFileStatus(fileUploadResponse.uid, 'error');
+                }
+              });
+            }
+          } else {
+            message.error(data.errorMessage);
+          }
+        },
+        error: function (XMLHttpRequest, textStatus, errorThrown) {
+          Common.processException(XMLHttpRequest, textStatus, errorThrown);
+        },
+      });
+    },
+  },
+};
+</script>

+ 113 - 0
src/workflow/ApproveTaskAttachmentView.vue

@@ -0,0 +1,113 @@
+<template>
+  <a-tag
+    v-for="attachment in attachments"
+    :key="attachment.id"
+    :closable="enableDelete"
+  >
+    <template #icon>
+      <paper-clip-outlined />
+    </template>
+
+    <template #closeIcon>
+      <a-popconfirm
+        title="您确定要删除此附件吗?"
+        ok-text="确定"
+        cancel-text="取消"
+        @confirm="deleteAttachment(attachment)"
+      >
+        <close-outlined />
+      </a-popconfirm>
+    </template>
+
+    <a-popover title="附件信息" trigger="click">
+      <template #content>
+        <p class="attachment-prop">附件名称: {{ attachment.name }}</p>
+        <p class="attachment-prop">上传人: {{ attachment.createUserName }}</p>
+        <p class="attachment-prop">上传时间: {{ attachment.time }}</p>
+        <p class="attachment-prop">
+          <a href="javascript: void(0)" @click="downloadAttachment(attachment)">
+            下载
+          </a>
+        </p>
+      </template>
+      <span style="cursor: pointer">
+        {{ attachment.name }}
+      </span>
+    </a-popover>
+  </a-tag>
+</template>
+
+<script>
+import Common from '../common/Common.js';
+import { message } from 'ant-design-vue';
+import { PaperClipOutlined, CloseOutlined } from '@ant-design/icons-vue';
+export default {
+  components: {
+    PaperClipOutlined,
+    CloseOutlined,
+  },
+  props: {
+    /**
+     * 是否启用删除附件
+     */
+    enableDelete: {
+      type: Boolean,
+      default: false,
+    },
+    /**
+     * 附件列表
+     */
+    attachments: {
+      type: Array,
+      default: function () {
+        return [];
+      },
+    },
+  },
+
+  methods: {
+    deleteAttachment: function (attachment) {
+      var _self = this;
+    },
+
+    /**
+     * 下载附件
+     */
+    downloadAttachment: function (attachment) {
+      const url = Common.getApiURL(
+        'WorkflowResource/downloadAttachment?url=' +
+          encodeURIComponent(attachment.url),
+      );
+      const xhr = new XMLHttpRequest();
+      xhr.open('get', url, true);
+      const token = localStorage.getItem('#token');
+      xhr.setRequestHeader('token', token);
+      xhr.setRequestHeader('Content-type', 'application/json');
+      xhr.responseType = 'blob';
+      xhr.onreadystatechange = function () {
+        if (xhr.readyState === 4 && xhr.status === 200) {
+          let res = xhr.response;
+          let blob = new Blob([res]);
+          const blobUrl = URL.createObjectURL(blob);
+          const link = document.createElement('a');
+          link.download = attachment.name;
+          link.style.display = 'none';
+          link.href = blobUrl;
+          document.body.appendChild(link);
+          link.click();
+          URL.revokeObjectURL(blobUrl);
+          document.body.removeChild(link);
+          message.success('下载成功');
+        }
+      };
+      xhr.send();
+    },
+  },
+};
+</script>
+
+<style scoped>
+.attachment-prop{
+    margin-bottom: 0px;
+}
+</style>

+ 51 - 86
src/workflow/HistoryApproveComment.vue

@@ -1,20 +1,24 @@
 <!-- 历史评论信息 -->
 <template>
-  <div>
+  <div v-if="historyProcessInstanceDescriptions != undefined">
     <div
-      v-if="historyProcessInstanceDescriptions != undefined"
+      v-for="historyProcessInstanceDescription, index in historyProcessInstanceDescriptions"
+      :key="historyProcessInstanceDescription.id"
       class="panel panel-default"
     >
       <div class="panel-heading">
         {{ $t("lang.historyApproveComment.title") }}
+        <span v-if="historyProcessInstanceDescription.approvalHistory != null" class="label label-default m-label">
+          {{ historyProcessInstanceDescription.approvalHistory.documentStatusChangeReason }}
+        </span>
         <span class="label label-warning m-label">
-          {{ abandonCount == undefined ? "0" : abandonCount }}
+          {{ index + 1 }} / {{ abandonCount == undefined ? "0" : abandonCount }}
         </span>
       </div>
-      <div class="panel-body">
+      <div
+        class="panel-body"
+      >
         <ul
-          v-for="item in historyProcessInstanceDescriptions"
-          :key="item.id"
           class="media-list m-media-list"
         >
           <li class="media">
@@ -24,7 +28,7 @@
                   :auth-src="
                     Common.getThumbnailImageSrc(
                       'com.leanwo.prodog.base.model.User',
-                      item.startUserImage
+                      historyProcessInstanceDescription.startUserImageUrl
                     )
                   "
                   class="media-object thumbnail m-image"
@@ -33,21 +37,20 @@
             </div>
             <div class="media-body">
               <h4 class="media-heading">
-                {{ item.startUserName }}
+                {{ historyProcessInstanceDescription.startUserName }}
                 <small class="badge alert-error">
                   {{ $t("lang.approveComment.submitUser") }}
-                  ({{ item.documentStatusChangeReason }})
                 </small>
               </h4>
-              <h5 class="m-h5">{{ item.startTime }}</h5>
-              <p>{{ $t("lang.approveComment.submitApprove") }}</p>
+              <h5 class="m-h5">{{ historyProcessInstanceDescription.startTime }}-{{ historyProcessInstanceDescription.endTime }}</h5>
+              <p class="comment-text">{{ $t("lang.approveComment.submitApprove") }}</p>
             </div>
           </li>
 
-          <template v-if="item.taskComments != undefined">
+          <template v-if="historyProcessInstanceDescription.historicTaskInstanceDescriptions != undefined">
             <li
-              v-for="taskComment in item.taskComments"
-              :key="taskComment.id"
+              v-for="historicTaskInstanceDescription in historyProcessInstanceDescription.historicTaskInstanceDescriptions"
+              :key="historicTaskInstanceDescription.id"
               class="media"
             >
               <div class="media-left">
@@ -56,7 +59,7 @@
                     :auth-src="
                       Common.getThumbnailImageSrc(
                         'com.leanwo.prodog.base.model.User',
-                        taskComment.userImageUrl
+                        historicTaskInstanceDescription.assigneeImageUrl
                       )
                     "
                     class="media-object thumbnail m-image"
@@ -65,74 +68,24 @@
               </div>
               <div class="media-body">
                 <h4 class="media-heading">
-                  {{ taskComment.userName }}
-                  <small class="badge alert-error">{{ taskComment.taskName }}({{
-                    item.documentStatusChangeReason
+                  {{ historicTaskInstanceDescription.assigneeName }}
+                  <small class="badge alert-error">{{ historicTaskInstanceDescription.name }}({{
+                    getTaskCompleteType(historicTaskInstanceDescription.completeReason)
+                    
                   }})</small>
                 </h4>
 
-                <div v-if="taskComment.comments != undefined">
+                <div v-if="historicTaskInstanceDescription.comments != undefined">
                   <div
-                    v-for="commentItem in taskComment.comments"
+                    v-for="commentItem in historicTaskInstanceDescription.comments"
                     :key="commentItem.id"
                   >
-                    <h5 class="m-h5">{{ commentItem.commentDate }}</h5>
-                    <p>{{ commentItem.comment }}</p>
+                    <h5 class="m-h5">{{ commentItem.time }}</h5>
+                    <p class="comment-text">{{ commentItem.message }}</p>
                   </div>
                 </div>
 
-                <div v-if="taskComment.imageNames != undefined">
-                  <AuthImage
-                    v-for="(imageName, index) in taskComment.imageNames"
-                    :key="index"
-                    :auth-src="getCommentImageSrc(imageName)"
-                    class="thumbnail m-image1"
-                    @click="openImageAttachment(imageName)"
-                  />
-                </div>
-
-                <div v-if="taskComment.attachmentNames != undefined">
-                  <a
-                    v-for="(
-                      attachmentName, index
-                    ) in taskComment.attachmentNames"
-                    :key="index"
-                    :href="getAttachmentsUrl(attachmentName)"
-                    target="view_window"
-                    class="btn btn-primary btn-sm btn-block"
-                  >{{ attachmentName }}</a>
-                </div>
-              </div>
-            </li>
-          </template>
-
-          <template v-for="activeTask in item.taskDescriptions" :key="activeTask.id">
-            <li
-              v-if="item.taskDescriptions != undefined"
-              class="media"
-            >
-              <div class="media-left">
-                <a>
-                  <AuthImage
-                    :auth-src="
-                      Common.getThumbnailImageSrc(
-                        'com.leanwo.prodog.base.model.User',
-                        activeTask.assigneeImageUrl
-                      )
-                    "
-                    class="media-object thumbnail m-image"
-                  />
-                </a>
-              </div>
-              <div class="media-body">
-                <h4 class="media-heading">
-                  {{ activeTask.assignee }}
-                  <small class="badge alert-error">{{ activeTask.name }}({{
-                    item.documentStatusChangeReason
-                  }})</small>
-                </h4>
-                <h5 class="m-h5">{{ activeTask.startTime }}</h5>
-                <p>{{ $t("lang.approveComment.processing") }}</p>
+                <ApproveTaskAttachmentView :enable-delete="false" :attachments="historicTaskInstanceDescription.attachments" />
               </div>
             </li>
           </template>
@@ -147,10 +100,12 @@
 import Common from '../common/Common.js';
 import AuthImage from '../widget/AuthImage.vue';
 import { Notify } from 'pc-component-v3';
+import ApproveTaskAttachmentView from './ApproveTaskAttachmentView.vue';
 
 export default {
   components: {
     AuthImage,
+    ApproveTaskAttachmentView,
   },
 
   props: {
@@ -178,19 +133,21 @@ export default {
 
   watch: {
     recordId: function (currentValue, oldValue) {
-      this.refresh();
+      this.refreshDebounce();
     },
     processInstanceId: function (currentValue, oldValue) {
-      this.refresh();
+      this.refreshDebounce();
     },
   },
 
   mounted: function () {
     var _self = this;
-    this.refresh();
+    this.refreshDebounce = Common.debounce(() => _self.refresh(), 1000);
+    this.refreshDebounce();
   },
 
   methods: {
+
     /**
      * 刷新流程信息
      */
@@ -263,14 +220,17 @@ export default {
       window.open(fullPath);
     },
 
-    /**
-     * 获取附件的URL
-     * @param  {[type]} url [description]
-     * @return {[type]}     [description]
-     */
-    getAttachmentsUrl: function (url) {
-      console.log(url);
-      return Common.getAttachmentsSrc(this.className, url);
+
+    getTaskCompleteType: function(completeReason){
+      if(completeReason == 'APPROVE'){
+        return '审批通过';
+      }else if(completeReason == 'REJECT'){
+        return '审批不通过';
+      }else if(completeReason == 'WITHDRAW'){
+        return '撤销';
+      }else{
+        return '未处理';
+      }
     },
   },
 };
@@ -287,6 +247,7 @@ export default {
 .m-image {
   width: 64px;
   height: 64px;
+  margin-bottom: 0px;
 }
 
 .m-image1 {
@@ -298,6 +259,10 @@ export default {
 }
 
 .m-media-list{
-  border-bottom: 1px solid #c4c3c3;
+  margin-bottom: 0px;
+}
+
+.comment-text{
+  margin-bottom: 0px;
 }
 </style>

+ 0 - 220
src/workflow/ImageListWidget.vue

@@ -1,220 +0,0 @@
-<template>
-  <div>
-    <div v-for="item in images" :key="item" class="room_img">
-      <AuthImage :auth-src="getThumbnailImageSrc(item)" />
-
-      <span class="glyphicon glyphicon-trash" @click="removeImage(item)" />
-    </div>
-    <div>
-      <div>
-        <label for="workflowFile" class="label-btn"> {{ $t("lang.ImageListWidget.selectPicture") }} </label>
-        <input
-          id="workflowFile"
-          autocomplete="off"
-          type="file"
-          class="inputfile"
-          @change="onFileChange"
-        />
-      </div>
-    </div>
-    <Loading v-if="loading" />
-  </div>
-</template>
-
-<script>
-
-
-import AuthImage from '../widget/AuthImage.vue';
-
-import {notificationError} from '../common/notification.js';
-import Common from '../common/Common.js';
-
-export default {
-
-  components: {
-    AuthImage,
-  },
-  props: {
-    className: {
-      type: String,
-      default: null,
-    },
-  },
-
-  data: function () {
-    this.Common = Common;
-    return {
-      images: [],
-      loading: false,
-    };
-  },
-
-  methods: {
-    /**
-     * 删除图片
-     * @param  {String} item 图片Name
-     */
-    removeImage(item) {
-      var _self = this;
-      var index = _self.images.indexOf(item);
-      if (index > -1) {
-        _self.images.splice(index, 1);
-      }
-    },
-
-    /**
-     * 选择图片发生改变
-     * @param  {[type]} e [description]
-     * @return {[type]}   [description]
-     */
-    onFileChange(e) {
-      var files = e.target.files || e.dataTransfer.files;
-      if (!files.length) return;
-      this.uploadImage(files[0]);
-    },
-
-    /**
-     * 上传图片
-     * @param  {File} selectedFile 选择的文件
-     */
-    uploadImage: function (selectedFile) {
-      var _self = this;
-      if (selectedFile == undefined) {
-        return;
-      }
-
-      if (!/image\/\w+/.test(selectedFile.type)) {
-        alert('请确保文件为图像类型');
-        return;
-      }
-
-      var formData = new FormData();
-      formData.append('images', selectedFile);
-      formData.append('className', _self.className);
-
-      _self.loading=true;
-      $.ajax({
-        url: Common.getApiURL('file/imageUpload'),
-        type: 'post',
-        beforeSend: function (request) {
-          Common.addTokenToRequest(request);
-        },
-        data: formData,
-        contentType: false,
-        processData: false,
-        success: function (data) {
-          _self.loading=false;
-          console.log(data);
-          if (data.errorCode == 0) {
-            _self.addImgs(data.datas);
-          }else{
-            notificationError(data.errorMessage, '图片上传失败');
-          }
-        },
-        error: function (XMLHttpRequest, textStatus, errorThrown) {
-          _self.loading=false;
-          Common.processException(XMLHttpRequest, textStatus, errorThrown);
-        },
-      });
-    },
-
-    /**
-     * 添加图片
-     * @param {String} imageName 添加的图片名称
-     */
-    addImgs: function (imageNames) {
-      var _self = this;
-      if(imageNames != null){
-        imageNames.forEach(element => {
-          _self.images.push(element);
-        });
-      }
-    },
-
-    /**
-     * 获取图片地址
-     * @param  {String} item 图片名称
-     * @return {String}      图片URL地址
-     */
-    getImageSrc: function (item) {
-      var _self = this;
-      if (item != undefined && item != null) {
-        return Common.getImageSrc(_self.className, item);
-      } else {
-        return '';
-      }
-    },
-
-    /**
-     * 获取图片缩略图地址
-     * @param  {String} item 图片名称
-     * @return {String}      图片URL地址
-     */
-    getThumbnailImageSrc: function(item){
-      var _self = this;
-      if (item != undefined && item != null) {
-        return Common.getThumbnailImageSrc(_self.className, item);
-      } else {
-        return '';
-      }
-    },
-
-    /**
-     * 获取图片路径供外部调用
-     * @return {Array} 图片地址
-     */
-    getImages: function () {
-      return this.images;
-    },
-  },
-};
-</script>
-
-<style scoped>
-.inputfile {
-  width: 0.1px;
-  height: 0.1px;
-  opacity: 0;
-  overflow: hidden;
-  position: absolute;
-  z-index: -1;
-}
-
-.room_img {
-  width: 150px;
-  height: 100px;
-  float: left;
-  margin-right: 10px;
-}
-
-.room_img img {
-  width: 100%;
-  height: 100%;
-}
-
-.room_img span {
-  position: relative;
-  right: -125px;
-  top: -95px;
-  font-size: 20px;
-  color: #43a51e;
-  cursor: pointer;
-}
-
-.label-btn {
-  color: white;
-  background-color: #006699;
-  display: inline-block;
-  padding: 5px 15px;
-  border-radius: 5px;
-}
-
-.label-btn:hover {
-  color: white;
-  background-color: #003399;
-  display: inline-block;
-  padding: 5px 15px;
-  border-radius: 5px;
-  cursor: pointer;
-}
-</style>