From df42fa7e97c4a93caa17b2aed5aecdc768d8bbd7 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Tue, 15 Apr 2025 21:57:46 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/drone/drone-web-manage

---
 src/views/tickets/ticket.vue |  460 ++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 256 insertions(+), 204 deletions(-)

diff --git a/src/views/tickets/ticket.vue b/src/views/tickets/ticket.vue
index e63ce87..673180f 100644
--- a/src/views/tickets/ticket.vue
+++ b/src/views/tickets/ticket.vue
@@ -32,18 +32,10 @@
             @size-change="sizeChange" @current-change="handleCurrentChange" :table-loading="loading"
             @selection-change="handleSelectionChange">
             <template #menu-left>
-              <el-button
-                v-if="activeTab === 'all' || activeTab === 'myTickets'"
-                type="primary"
-                icon="el-icon-plus"
-                @click="handleAdd"
-              >新建工单</el-button>
-              <el-button
-    v-if="activeTab === 'pending'"
-    type="success"
-    icon="el-icon-check"
-    @click="openReviewDialog"
-  >批量审核</el-button>
+              <el-button v-if="activeTab === 'all' || activeTab === 'myTickets'" type="primary" icon="el-icon-plus"
+                @click="handleAdd">新建工单</el-button>
+              <el-button v-if="activeTab === 'pending'" type="success" icon="el-icon-check"
+                @click="openReviewDialog">批量审核</el-button>
               <el-button type="success" plain icon="el-icon-download" @click="exportData">导出</el-button>
             </template>
             <template #menu="{ row }">
@@ -89,14 +81,16 @@
           <el-row :gutter="16">
             <el-col :span="12">
               <el-form-item label="所属部门" prop="department">
-                <el-select v-model="form.department" placeholder="请选择所属部门" @change="handleDepartmentChange" class="full-width">
+                <el-select v-model="form.department" placeholder="请选择所属部门" @change="handleDepartmentChange"
+                  class="full-width">
                   <el-option v-for="dept in departments" :key="dept.value" :label="dept.label" :value="dept.value" />
                 </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="12">
               <el-form-item label="处理人员" prop="handler">
-                <el-select v-model="form.handler" placeholder="请先选择所属部门" :disabled="!form.department" class="full-width">
+                <el-select v-model="form.handler" placeholder="请先选择所属部门" :disabled="!form.department"
+                  class="full-width">
                   <el-option v-for="user in availableHandlers" :key="user.id" :label="user.name" :value="user.id" />
                 </el-select>
               </el-form-item>
@@ -114,7 +108,8 @@
             <el-col :span="12">
               <el-form-item label="选择位置" prop="location" required>
                 <div class="location-wrapper">
-                  <avue-input-map v-model="form.location" :params="mapParams" @change="handleLocationChange" type="button">
+                  <avue-input-map v-model="form.location" :params="mapParams" @change="handleLocationChange"
+                    type="button">
                     <el-button type="primary" plain class="map-button">
                       <i class="el-icon-map-location"></i> 地图选点
                     </el-button>
@@ -133,18 +128,9 @@
             </el-col>
             <el-col :span="12">
               <el-form-item label="附件图片" prop="photos" required class="upload-wrapper">
-                <el-upload ref="upload" 
-                  :action="'#'" 
-                  :auto-upload="false" 
-                  list-type="picture-card"
-                  :on-change="handleFileChange" 
-                  :on-remove="handleUploadRemove" 
-                  :before-upload="beforeUpload"
-                  :file-list="form.photos" 
-                  :limit="1" 
-                  accept="image/*"
-                  class="uploader"
-                >
+                <el-upload ref="upload" :action="'#'" :auto-upload="false" list-type="picture-card"
+                  :on-change="handleFileChange" :on-remove="handleUploadRemove" :before-upload="beforeUpload"
+                  :file-list="form.photos" :limit="1" accept="image/*" class="uploader">
                   <i class="el-icon-plus"></i>
                 </el-upload>
                 <div class="upload-tip">支持jpg/png格式图片,单张不超过5MB</div>
@@ -169,18 +155,11 @@
         <div class="custom-steps-container">
           <!-- 标题行 -->
           <div class="steps-titles">
-            <div 
-              class="step-title" 
-              :class="{ active: true }"
-            >
+            <div class="step-title" :class="{ active: true }">
               发起任务
             </div>
-            <div
-              v-for="(status, index) in dynamicFixedStatuses"
-              :key="index"
-              :class="{ active: Number(currentDetail.status) >= Number(status) }"
-              class="step-title"
-            >
+            <div v-for="(status, index) in dynamicFixedStatuses" :key="index"
+              :class="{ active: Number(currentDetail.status) >= Number(status) }" class="step-title">
               {{ mapStatus(status) }}
             </div>
           </div>
@@ -203,7 +182,7 @@
                   {{ getStepHandler(status) }}
                 </span>
                 <div class="step-description" v-if="getStepTime(status)">
-                 <span style="         position: absolute;
+                  <span style="         position: absolute;
           right: 80%;  
           top: 50%;
           transform: translateY(-50%);
@@ -212,7 +191,7 @@
           color: #666;
           font-size: 12px;">耗时:{{ getStepTime(status) }}</span>
                 </div>
-                <div class="step-description" >
+                <div class="step-description">
                   {{ getStepCreateTime(status) }}
                 </div>
               </template>
@@ -407,62 +386,49 @@
     </el-dialog>
 
     <!-- 添加在其他 dialog 组件之后 -->
-<el-dialog v-model="reviewDialogVisible" title="批量审核" width="70%" append-to-body custom-class="review-dialog">
-  <div class="review-container">
-    <!-- 图片浏览区域 -->
-    <div class="review-image-wrapper">
-      <!-- 左箭头 -->
-      <div v-show="selections.length > 1" class="arrow-button left" @click="handlePrevImage">
-        <el-icon><ArrowLeft /></el-icon>
+    <el-dialog v-model="reviewDialogVisible" title="批量审核" width="70%" append-to-body custom-class="review-dialog">
+      <div class="review-container">
+        <div class="review-image-wrapper">
+          <!-- 修改左右箭头的显示条件 -->
+          <div v-if="selections.length > 1 && currentReviewImage" class="arrow-button left" @click="handlePrevImage">
+            <i class="el-icon-arrow-left"></i>
+          </div>
+
+          <div class="review-image-container">
+            <el-image v-if="currentReviewImage" :src="currentReviewImage" fit="cover" :preview-src-list="getImageList()"
+              :initial-index="currentImageIndex - 1" class="preview-image">
+              <template #error>
+                <div class="image-error">
+                  <i class="el-icon-picture-outline"></i>
+                  <span>图片加载失败</span>
+                </div>
+              </template>
+            </el-image>
+            <div v-else class="no-image">暂无图片</div>
+          </div>
+
+          <!-- 修改右箭头的显示条件 -->
+          <div v-if="selections.length > 1 && currentReviewImage" class="arrow-button right" @click="handleNextImage">
+            <i class="el-icon-arrow-right"></i>
+          </div>
+        </div>
+
+        <!-- 修改分页器的显示条件 -->
+        <div class="review-pagination" v-if="selections.length > 1 && currentReviewImage">
+          <el-pagination small layout="prev, pager, next" hide-on-single-page :total="selections.length"
+            :current-page="currentImageIndex" :page-size="1" @current-change="handleImagePageChange">
+          </el-pagination>
+        </div>
       </div>
 
-      <!-- 图片显示区域 -->
-      <div class="review-image-container">
-        <el-image 
-          :src="currentReviewImage"
-          fit="cover"
-          :preview-src-list="getImageList()"
-          :initial-index="currentImageIndex - 1"
-          class="preview-image"
-        >
-          <template #error>
-            <div class="image-error">
-              <i class="el-icon-picture-outline"></i>
-              <span>图片加载失败</span>
-            </div>
-          </template>
-        </el-image>
-      </div>
-
-      <!-- 右箭头 -->
-      <div v-show="selections.length > 1" class="arrow-button right" @click="handleNextImage">
-        <el-icon><ArrowRight /></el-icon>
-      </div>
-    </div>
-    
-    <!-- 分页指示器 -->
-    <div class="review-pagination" v-if="selections.length > 1">
-      <el-pagination
-        small
-        layout="prev, pager, next"
-        hide-on-single-page
-        :total="selections.length"
-        :current-page.sync="currentImageIndex"
-        :page-size="1"
-        @current-change="handleImagePageChange"
-      >
-      </el-pagination>
-    </div>
-  </div>
-  
-  <template #footer>
-    <div class="dialog-footer">
-      <el-button type="primary" @click="handleBatchApprove">通过</el-button>
-      <el-button type="danger" @click="handleBatchReject">不通过</el-button>
-      <el-button @click="reviewDialogVisible = false">取消</el-button>
-    </div>
-  </template>
-</el-dialog>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleBatchApprove">通过</el-button>
+          <el-button type="danger" @click="handleBatchReject">不通过</el-button>
+          <el-button @click="cancleBatchReject">取消</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </basic-container>
 </template>
 
@@ -573,7 +539,7 @@
         handler: [{ required: true, message: '请选择处理人员', trigger: 'change' }],
         content: [{ required: true, message: '请输入工单内容', trigger: 'blur' }],
         algorithm: [{ required: true, message: '请选择关联算法', trigger: 'change' }],
-        location: [{ 
+        location: [{
           validator: (rule, value, callback) => {
             if (!value || value.length < 2) {
               callback(new Error('请选择位置信息'));
@@ -583,7 +549,7 @@
           },
           trigger: 'change'
         }],
-        photos: [{ 
+        photos: [{
           validator: (rule, value, callback) => {
             if (!this.form.photos || this.form.photos.length === 0) {
               callback(new Error('请上传工单图片'));
@@ -777,42 +743,64 @@
       }
     },
     async handleBatchApprove() {
-    try {
-      await this.$confirm('确认批量审核通过选中的工单?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      });
+      try {
+        if (this.selections.length === 0) {
+          this.$message.warning('没有选中的工单');
+          return;
+        }
 
-      const promises = this.selections.map(async (item) => {
+        const currentItem = this.selections[this.currentImageIndex - 1];
+        if (!currentItem) {
+          this.$message.warning('当前工单数据无效');
+          return;
+        }
+
+        await this.$confirm('确认审核通过当前工单?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        });
+
         const data = {
-          id: item.id,
-          status: item.status,
-          isPass: 0, // 0 表示通过
-          eventNum: item.orderNumber,
-          eventName: item.orderName,
-          eventType: item.type,
+          id: currentItem.id,
+          status: currentItem.status,
+          isPass: 0,
+          eventNum: currentItem.orderNumber,
+          eventName: currentItem.orderName,
+          eventType: currentItem.type,
         };
-        return flowEvent(data);
-      });
 
-      const results = await Promise.all(promises);
-      const successCount = results.filter(res => res.data.code === 0).length;
-      
-      if (successCount > 0) {
-        this.$message.success(`成功审核通过 ${successCount} 个工单`);
-        // 清空选择
-        this.clearSelection();
-        // 刷新数据
-        this.fetchTableData();
-      } else {
-        throw new Error('批量审核失败');
+        const response = await flowEvent(data);
+        if (response.data.code === 0) {
+          this.$message.success('工单审核通过');
+
+          // 创建新的数组而不是修改原数组
+          const newSelections = [...this.selections];
+          newSelections.splice(this.currentImageIndex - 1, 1);
+          this.selections = newSelections;
+
+          // 修正索引并更新图片
+          if (this.selections.length > 0) {
+            if (this.currentImageIndex > this.selections.length) {
+              this.currentImageIndex = this.selections.length;
+            }
+            this.updateCurrentReviewImage();
+          } else {
+            this.reviewDialogVisible = false;
+            this.currentImageIndex = 1;
+            this.currentReviewImage = '';
+          }
+
+          // 刷新表格数据
+          this.fetchTableData();
+        } else {
+          throw new Error(response.data.msg || '审核失败');
+        }
+      } catch (error) {
+        if (error === 'cancel') return;
+        this.$message.error(error.message || '审核失败,请稍后重试');
       }
-    } catch (error) {
-      if (error === 'cancel') return;
-      this.$message.error(error.message || '批量审核失败,请稍后重试');
-    }
-  },
+    },
     async fetchDropdownData() {
       try {
         const response = await getTicketInfo();
@@ -939,7 +927,7 @@
       try {
         // 提交时需要完整验证
         await this.$refs.form.validate();
-        
+
         // 验证位置信息
         if (!this.form.location || this.form.location.length < 2) {
           this.$message.warning('请在地图上选择位置');
@@ -1238,10 +1226,10 @@
     },
 
     getStepTime(status) {
-  const step = this.stepInfos.find(step => step.status === status);
-  // 如果 step 不存在或 step.time 为 0,返回 false
-  return step && step.time && step.time !== '0' ? step.time : false;
-},
+      const step = this.stepInfos.find(step => step.status === status);
+      // 如果 step 不存在或 step.time 为 0,返回 false
+      return step && step.time && step.time !== '0' ? step.time : false;
+    },
     getStepCreateTime(status) {
       const step = this.stepInfos.find(step => step.status === status);
       return step ? step.create_time : null;
@@ -1282,7 +1270,7 @@
       // 修改导出方法,添加选中数据的处理
       try {
         this.loading = true;
-        
+
         // 如果有选中的数据,则只导出选中的数据
         let exportData = [];
         if (this.selections.length > 0) {
@@ -1421,7 +1409,7 @@
           id: this.currentDetail.id,
           status: this.currentDetail.status,
           isPass: 0, // 0 表示通过
-          eventNum: this.currentDetail.orderNumber, 
+          eventNum: this.currentDetail.orderNumber,
           eventName: this.currentDetail.orderName, // 工单名称
           eventType: this.currentDetail.type, // 工单类型
           departmentId: this.dispatchForm.department, // 派发部门 ID
@@ -1597,17 +1585,17 @@
     // 添加编辑方法
     handleEdit(row) {
       console.log('编辑原始数据:', row);
-      
+
       // 尝试从row.dept_id或通过部门名称查找对应的部门ID
       let deptId = row.dept_id;  // 优先使用原始数据中的dept_id
-      
+
       // 如果没有dept_id,则通过部门名称查找
       if (!deptId) {
         // 输出所有可用的部门数据用于调试
         console.log('可用部门列表:', this.departments);
         console.log('当前部门名称:', row.department);
-        
-        const deptInfo = this.departments.find(dept => 
+
+        const deptInfo = this.departments.find(dept =>
           dept.label && dept.label.trim() === row.department.trim()
         );
         deptId = deptInfo?.value;
@@ -1615,10 +1603,10 @@
 
       // 获取工单类型值 - 从types中找到匹配的值
       const typeValue = this.types.find(t => t.label === row.type)?.value || row.event_dict_key;
-      
+
       // 获取处理人ID - 使用userNameToIdMap映射
       const handlerId = this.userNameToIdMap[row.handler] || row.handler;
-      
+
       console.log('数据映射:', {
         部门名称: row.department,
         找到的部门ID: deptId,
@@ -1721,8 +1709,22 @@
 
     // 更新当前审核图片
     updateCurrentReviewImage() {
-      if (this.selections.length > 0 && this.currentImageIndex > 0) {
-        const currentItem = this.selections[this.currentImageIndex - 1];
+      // 修正索引范围
+      if (!this.selections || this.selections.length === 0) {
+        this.currentReviewImage = '';
+        this.currentImageIndex = 1;
+        return;
+      }
+      // 如果当前索引超出范围,自动回退到最后一张
+      if (this.currentImageIndex > this.selections.length) {
+        this.currentImageIndex = this.selections.length;
+      }
+      if (this.currentImageIndex < 1) {
+        this.currentImageIndex = 1;
+      }
+      const index = this.currentImageIndex - 1;
+      if (index >= 0 && index < this.selections.length) {
+        const currentItem = this.selections[index];
         this.currentReviewImage = currentItem.photo_url || '';
       } else {
         this.currentReviewImage = '';
@@ -1731,89 +1733,138 @@
 
     // 处理图片分页变化
     handleImagePageChange(page) {
-      this.currentImageIndex = page;
-      this.updateCurrentReviewImage();
+      if (page > 0 && page <= this.selections.length) {
+        this.currentImageIndex = page;
+        this.updateCurrentReviewImage();
+      }
     },
 
     // 批量审核通过
     async handleBatchApprove() {
       try {
-        await this.$confirm('确认批量审核通过选中的工单?', '提示', {
+        if (this.selections.length === 0) {
+          this.$message.warning('没有选中的工单');
+          return;
+        }
+
+        const currentItem = this.selections[this.currentImageIndex - 1];
+        if (!currentItem) {
+          this.$message.warning('当前工单数据无效');
+          return;
+        }
+
+        await this.$confirm('确认审核通过当前工单?', '提示', {
           confirmButtonText: '确定',
           cancelButtonText: '取消',
           type: 'warning'
         });
 
-        const promises = this.selections.map(async (item) => {
-          const data = {
-            id: item.id,
-            status: item.status,
-            isPass: 0, // 0 表示通过
-            eventNum: item.orderNumber,
-            eventName: item.orderName,
-            eventType: item.type,
-          };
-          return flowEvent(data);
-        });
+        const data = {
+          id: currentItem.id,
+          status: currentItem.status,
+          isPass: 0,
+          eventNum: currentItem.orderNumber,
+          eventName: currentItem.orderName,
+          eventType: currentItem.type,
+        };
+        console.log('删除前:', this.selections)
+        const response = await flowEvent(data);
+        if (response.data.code === 0) {
+          this.$message.success('工单审核通过');
 
-        const results = await Promise.all(promises);
-        const successCount = results.filter(res => res.data.code === 0).length;
-        
-        if (successCount > 0) {
-          this.$message.success(`成功审核通过 ${successCount} 个工单`);
-          // 清空选择
-          this.clearSelection();
-          // 刷新数据
-          this.fetchTableData();
-          // 关闭审核对话框
-          this.reviewDialogVisible = false;
+          // 创建新的数组而不是修改原数组
+          const newSelections = [...this.selections];
+          newSelections.splice(this.currentImageIndex - 1, 1);
+
+          // 修正索引并更新图片
+          if (newSelections.length > 0) {
+            if (this.currentImageIndex > this.selections.length) {
+              this.currentImageIndex = this.selections.length;
+            }
+            this.updateCurrentReviewImage();
+          } else {
+            this.reviewDialogVisible = false;
+            this.currentImageIndex = 1;
+            this.currentReviewImage = '';
+            this.fetchTableData();
+          }
+
+          // 刷新表格数据
+          // this.fetchTableData();
+          this.selections = newSelections;
+
         } else {
-          throw new Error('批量审核失败');
+          throw new Error(response.data.msg || '审核失败');
         }
       } catch (error) {
         if (error === 'cancel') return;
-        this.$message.error(error.message || '批量审核失败,请稍后重试');
+        this.$message.error(error.message || '审核失败,请稍后重试');
       }
     },
 
+    cancleBatchReject(){
+      reviewDialogVisible = false;
+      this.fetchTableData();
+    },
     // 批量审核不通过
     async handleBatchReject() {
       try {
-        await this.$confirm('确认批量审核不通过选中的工单?', '提示', {
+        if (this.selections.length === 0) {
+          this.$message.warning('没有选中的工单');
+          return;
+        }
+
+        const currentItem = this.selections[this.currentImageIndex - 1];
+        if (!currentItem) {
+          this.$message.warning('当前工单数据无效');
+          return;
+        }
+
+        await this.$confirm('确认驳回当前工单?', '提示', {
           confirmButtonText: '确定',
           cancelButtonText: '取消',
           type: 'warning'
         });
 
-        const promises = this.selections.map(async (item) => {
-          const data = {
-            id: item.id,
-            status: item.status,
-            isPass: 1, // 1 表示不通过
-            eventNum: item.orderNumber,
-            eventName: item.orderName,
-            eventType: item.type,
-          };
-          return flowEvent(data);
-        });
+        const data = {
+          id: currentItem.id,
+          status: currentItem.status,
+          isPass: 1,
+          eventNum: currentItem.orderNumber,
+          eventName: currentItem.orderName,
+          eventType: currentItem.type,
+        };
 
-        const results = await Promise.all(promises);
-        const successCount = results.filter(res => res.data.code === 0).length;
-        
-        if (successCount > 0) {
-          this.$message.success(`成功审核不通过 ${successCount} 个工单`);
-          // 清空选择
-          this.clearSelection();
-          // 刷新数据
-          this.fetchTableData();
-          // 关闭审核对话框
-          this.reviewDialogVisible = false;
+        const response = await flowEvent(data);
+        if (response.data.code === 0) {
+          this.$message.success('工单已驊回');
+
+          // 创建新的数组而不是修改原数组
+          const newSelections = [...this.selections];
+          newSelections.splice(this.currentImageIndex - 1, 1);
+          this.selections = newSelections;
+
+          // 修正索引并更新图片
+          if (this.selections.length > 0) {
+            if (this.currentImageIndex > this.selections.length) {
+              this.currentImageIndex = this.selections.length;
+            }
+            this.updateCurrentReviewImage();
+          } else {
+            this.reviewDialogVisible = false;
+            this.currentImageIndex = 1;
+            this.currentReviewImage = '';
+            this.fetchTableData();
+          }
+
+          // 刷新表格数据
+          // this.fetchTableData();
         } else {
-          throw new Error('批量审核失败');
+          throw new Error(response.data.msg || '驳回失败');
         }
       } catch (error) {
         if (error === 'cancel') return;
-        this.$message.error(error.message || '批量审核失败,请稍后重试');
+        this.$message.error(error.message || '驳回失败,请稍后重试');
       }
     },
 
@@ -1947,13 +1998,14 @@
   .location-wrapper {
     width: 100%; // 修改为100%以适应父容器
     height: auto; // 修改为auto以自适应内容
+
     .map-button {
       width: 100%; // 让按钮填满容器宽度
       height: 36px; // 与其他输入框保持一致的高度
       display: flex;
       align-items: center;
       justify-content: center;
-      
+
       i {
         margin-right: 4px;
       }
@@ -2030,13 +2082,13 @@
   padding-top: 16px;
   border-top: 1px solid #ebeef5;
 
-  .el-button + .el-button {
+  .el-button+.el-button {
     margin-left: 12px;
   }
 
   .el-button {
     padding: 9px 20px;
-    
+
     &:last-child {
       margin-left: 12px;
     }
@@ -2253,7 +2305,7 @@
   line-height: 1.5;
   display: block;
   text-align: left;
-  
+
   &:first-child {
     font-weight: bold;
     margin-bottom: 4px;
@@ -2310,7 +2362,7 @@
   line-height: 1.5;
   display: block;
   text-align: center;
-  
+
   &:first-child {
     font-weight: bold;
     margin-bottom: 4px;
@@ -2346,7 +2398,7 @@
 
 .review-container {
   position: relative;
-  
+
   .review-image-wrapper {
     position: relative;
     display: flex;
@@ -2362,7 +2414,7 @@
     display: flex;
     align-items: center;
     justify-content: center;
-    
+
     :deep(.el-image) {
       width: 100%;
       height: 100%;
@@ -2423,6 +2475,7 @@
     background-color: #fff;
 
     :deep(.el-pagination) {
+
       .btn-prev,
       .btn-next {
         display: none;
@@ -2443,16 +2496,15 @@
     align-items: center;
     justify-content: center;
     color: #909399;
-    
+
     i {
       font-size: 48px;
       margin-bottom: 16px;
     }
-    
+
     span {
       font-size: 16px;
     }
   }
 }
-</style>
-```
\ No newline at end of file
+</style>
\ No newline at end of file

--
Gitblit v1.9.3