无人机管理后台前端(已迁走)
rain
2025-04-15 fe11a72dccadc8aae644406b7d1e6b5465721fc1
批量审核
1 files modified
362 ■■■■■ changed files
src/views/tickets/ticket.vue 362 ●●●●● patch | view | raw | blame | history
src/views/tickets/ticket.vue
@@ -38,6 +38,12 @@
                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 }">
@@ -399,6 +405,64 @@
        <el-button type="primary" @click="submitDispatch">确认派发</el-button>
      </template>
    </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>
      </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>
  </basic-container>
</template>
@@ -555,6 +619,9 @@
      userNameToIdMap: {}, // 新增用户名到ID的映射
      workType: 0, // 新增:当前工单work_type
      selections: [], // 添加选中行数据数组
      reviewDialogVisible: false, // 新增:审核对话框可见性
      currentReviewImage: '', // 新增:当前审核图片
      currentImageIndex: 1, // 新增:当前图片索引
    };
  },
  created() {
@@ -709,7 +776,43 @@
        this.$message.error('地图加载失败,请检查网络或API Key配置');
      }
    },
    async handleBatchApprove() {
    try {
      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 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('批量审核失败');
      }
    } catch (error) {
      if (error === 'cancel') return;
      this.$message.error(error.message || '批量审核失败,请稍后重试');
    }
  },
    async fetchDropdownData() {
      try {
        const response = await getTicketInfo();
@@ -1604,6 +1707,143 @@
    clearSelection() {
      this.$refs.avueCrud.clearSelection();
    },
    // 打开审核对话框
    openReviewDialog() {
      if (this.selections.length === 0) {
        this.$message.warning('请先选择要审核的工单');
        return;
      }
      this.currentImageIndex = 1;
      this.updateCurrentReviewImage();
      this.reviewDialogVisible = true;
    },
    // 更新当前审核图片
    updateCurrentReviewImage() {
      if (this.selections.length > 0 && this.currentImageIndex > 0) {
        const currentItem = this.selections[this.currentImageIndex - 1];
        this.currentReviewImage = currentItem.photo_url || '';
      } else {
        this.currentReviewImage = '';
      }
    },
    // 处理图片分页变化
    handleImagePageChange(page) {
      this.currentImageIndex = page;
      this.updateCurrentReviewImage();
    },
    // 批量审核通过
    async handleBatchApprove() {
      try {
        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 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;
        } else {
          throw new Error('批量审核失败');
        }
      } catch (error) {
        if (error === 'cancel') return;
        this.$message.error(error.message || '批量审核失败,请稍后重试');
      }
    },
    // 批量审核不通过
    async handleBatchReject() {
      try {
        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 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;
        } else {
          throw new Error('批量审核失败');
        }
      } catch (error) {
        if (error === 'cancel') return;
        this.$message.error(error.message || '批量审核失败,请稍后重试');
      }
    },
    // 获取所有图片列表用于预览
    getImageList() {
      return this.selections
        .map(item => item.photo_url)
        .filter(url => url); // 过滤掉空值
    },
    // 处理图片点击
    handleImageClick() {
      // 图片点击事件由 el-image 的预览功能处理
    },
    // 处理上一张图片
    handlePrevImage() {
      if (this.currentImageIndex > 1) {
        this.currentImageIndex--;
        this.updateCurrentReviewImage();
      }
    },
    // 处理下一张图片
    handleNextImage() {
      if (this.currentImageIndex < this.selections.length) {
        this.currentImageIndex++;
        this.updateCurrentReviewImage();
      }
    },
  },
};
</script>
@@ -2095,4 +2335,124 @@
    }
  }
}
</style>
// 添加新的样式
.review-dialog {
  :deep(.el-dialog__body) {
    padding: 0;
    background-color: #f5f7fa;
  }
}
.review-container {
  position: relative;
  .review-image-wrapper {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 600px;
    background-color: #f5f7fa;
  }
  .review-image-container {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    :deep(.el-image) {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      .el-image__inner {
        max-height: 100%;
        max-width: 100%;
        object-fit: contain;
      }
    }
  }
  .arrow-button {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    background: rgba(0, 0, 0, 0.3);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s;
    z-index: 100;
    &:hover {
      background: rgba(0, 0, 0, 0.6);
    }
    i {
      color: #fff;
      font-size: 24px;
    }
    &.left {
      left: 20px;
    }
    &.right {
      right: 20px;
    }
  }
  .preview-image {
    max-width: 100%;
    max-height: 100%;
  }
  .review-pagination {
    padding: 16px 0;
    display: flex;
    justify-content: center;
    background-color: #fff;
    :deep(.el-pagination) {
      .btn-prev,
      .btn-next {
        display: none;
      }
      .el-pager {
        .number {
          margin: 0 4px;
        }
      }
    }
  }
  .image-error {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #909399;
    i {
      font-size: 48px;
      margin-bottom: 16px;
    }
    span {
      font-size: 16px;
    }
  }
}
</style>
```