2025/4/28日团队开发进度报告

管理员审批功能:

RepairOrderController:

package com.example.demo.controller;

import com.example.demo.common.Result;
import com.example.demo.entity.RepairOrder;
import com.example.demo.service.RepairOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/repair-order")
public class RepairOrderController {
    
    @Autowired
    private RepairOrderService repairOrderService;

    @PostMapping("/create")
    public Result createRepairOrder(@RequestBody RepairOrder repairOrder) {
        try {
            RepairOrder createdOrder = repairOrderService.createRepairOrder(repairOrder);
            return Result.success(createdOrder);
        } catch (Exception e) {
            return Result.fail("创建维修工单失败:" + e.getMessage());
        }
    }

    @GetMapping("/engineer/{engineerId}")
    public Result getOrdersByEngineerId(@PathVariable String engineerId) {
        try {
            List<RepairOrder> orders = repairOrderService.getOrdersByEngineerId(engineerId);
            return Result.success(orders);
        } catch (Exception e) {
            return Result.fail("获取工程师维修工单失败:" + e.getMessage());
        }
    }

    @GetMapping("/list")
    public Result getRepairOrderList(@RequestParam(required = false) String engineerId) {
        try {
            List<RepairOrder> orders;
            if (engineerId != null && !engineerId.isEmpty()) {
                orders = repairOrderService.getOrdersByEngineerId(engineerId);
            } else {
                orders = repairOrderService.getAllOrders();
            }
            return Result.success(orders);
        } catch (Exception e) {
            return Result.fail("获取维修工单列表失败:" + e.getMessage());
        }
    }

    @PutMapping("/update")
    public Result updateRepairOrder(@RequestBody RepairOrder repairOrder) {
        try {
            boolean updated = repairOrderService.updateOrder(repairOrder);
            if (updated) {
                return Result.success(repairOrder);
            } else {
                return Result.fail("未找到对应的维修工单");
            }
        } catch (Exception e) {
            return Result.fail("更新维修工单失败:" + e.getMessage());
        }
    }

    @PutMapping("/status")
    public Result updateRepairOrderStatus(@RequestBody Map<String, Object> params) {
        try {
            Integer orderId = (Integer) params.get("orderId");
            String status = (String) params.get("status");
            
            if (orderId == null || status == null) {
                return Result.fail("参数不能为空");
            }
    
            boolean updated = repairOrderService.updateOrderStatus(orderId, status);
            if (updated) {
                return Result.success("状态更新成功");
            } else {
                return Result.fail("未找到对应的维修工单");
            }
        } catch (Exception e) {
            return Result.fail("更新工单状态失败:" + e.getMessage());
        }
    }
}

repairOrder.js:

import request from '@/utils/request'

// 创建维修工单
export function createRepairOrder(data) {
  return request({
    url: '/repair-order/create',
    method: 'post',  // 确保使用 POST 方法
    data
  })
}

export function updateRepairOrderStatus(data) {
  return request({
    url: '/repair-order/status',
    method: 'put',
    data
  })
}

// 更新维修工单
export function updateRepairOrder(data) {
  return request({
    url: '/repair-order/update',
    method: 'put',
    data
  })
}

export function getRepairOrderList(params) {
  return request({
    url: '/repair-order/list',
    method: 'get',
    params  // 直接传递参数对象
  })
}

Approve.vue:

<template>
  <div class="approve-container">
    <el-card class="approve-card">
      <template #header>
        <div class="card-header">
          <span>维修工单审批</span>
        </div>
      </template>

      <el-table :data="repairOrders" border style="width: 100%" height="450">
        <el-table-column prop="orderId" label="工单编号" width="100" />
        <el-table-column prop="faultId" label="故障编号" width="100" />
        <el-table-column prop="engineerId" label="工程师工号" width="120" />
        <el-table-column prop="repairDesc" label="维修描述" min-width="200" show-overflow-tooltip />
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag :type="getStatusType(scope.row.status)">{{ scope.row.status }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200" fixed="right">
          <template #default="scope">
            <el-button 
              v-if="scope.row.status === '待审批'"
              type="success" 
              size="small" 
              @click="handleApprove(scope.row)"
            >
              通过
            </el-button>
            <el-button 
              v-if="scope.row.status === '待审批'"
              type="danger" 
              size="small" 
              @click="handleReject(scope.row)"
            >
              驳回
            </el-button>
            <el-button 
              type="primary" 
              size="small" 
              @click="handleDetail(scope.row)"
            >
              详情
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 详情对话框 -->
    <el-dialog
      v-model="dialogVisible"
      title="工单详情"
      width="600px"
    >
      <div class="detail-content">
        <div class="detail-item">
          <span class="label">工单编号:</span>
          <span>{{ currentOrder.orderId }}</span>
        </div>
        <div class="detail-item">
          <span class="label">故障编号:</span>
          <span>{{ currentOrder.faultId }}</span>
        </div>
        <div class="detail-item">
          <span class="label">工程师工号:</span>
          <span>{{ currentOrder.engineerId }}</span>
        </div>
        <div class="detail-item">
          <span class="label">维修描述:</span>
          <p>{{ currentOrder.repairDesc }}</p>
        </div>
        <div class="detail-item">
          <span class="label">安全须知:</span>
          <p>{{ currentOrder.safetyNotice }}</p>
        </div>
        <div class="detail-item">
          <span class="label">维修照片:</span>
          <div class="photos" v-if="currentOrder.photos">
            <el-image 
              v-for="(photo, index) in processPhotos(currentOrder.photos)"
              :key="index"
              :src="photo"
              :preview-src-list="processPhotos(currentOrder.photos)"
              fit="cover"
              class="photo-item"
              @error="handleImageError"
            />
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getRepairOrderList } from '@/api/repairOrder'
import { updateRepairOrderStatus } from '@/api/repairOrder'
import { updateFaultStatus, getFault } from '@/api/deviceFault'
import { updateDeviceStatus } from '@/api/device'  // 添加这行

const repairOrders = ref([])
const dialogVisible = ref(false)
const currentOrder = ref({})

// 获取工单列表
const fetchRepairOrders = async () => {
  try {
    const res = await getRepairOrderList()
    if (res.code === 200) {
      // 只保留状态为"待审批"的工单
      repairOrders.value = res.data.filter(order => order.status === '待审批')
    } else {
      ElMessage.error(res.msg || '获取工单列表失败')
    }
  } catch (error) {
    console.error('获取工单列表失败:', error)
    ElMessage.error('获取工单列表失败')
  }
}

// 获取状态标签类型
const getStatusType = (status) => {
  const statusMap = {
    '待处理': 'info',
    '处理中': 'warning',
    '已完成': 'success',
    '待审批': 'warning',
    '已关闭': ''
  }
  return statusMap[status] || ''
}

// 处理审批通过
const handleApprove = async (order) => {
  try {
    // 更新工单状态
    const res = await updateRepairOrderStatus({
      orderId: order.orderId,
      status: '已完成'
    })
    
    if (res.code === 200) {
      // 更新故障状态
      await updateFaultStatus({
        faultId: order.faultId,
        status: '已解决'
      })

      // 获取故障信息以获取设备ID
      const faultRes = await getFault(order.faultId)
      if (faultRes.code === 200) {
        // 更新设备状态为正常
        await updateDeviceStatus({
          deviceId: faultRes.data.deviceId,
          status: '正常'
        })
      }
      
      ElMessage.success('审批通过')
      fetchRepairOrders()
    } else {
      ElMessage.error(res.msg || '操作失败')
    }
  } catch (error) {
    console.error('审批失败:', error)
    ElMessage.error('审批失败')
  }
}

// 处理审批驳回
const handleReject = async (order) => {
  ElMessageBox.prompt('请输入驳回原因', '驳回工单', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPattern: /\S+/,
    inputErrorMessage: '驳回原因不能为空'
  }).then(async ({ value }) => {
    try {
      const res = await updateRepairOrderStatus({
        orderId: order.orderId,
        status: '处理中',
        rejectReason: value
      })
      if (res.code === 200) {
        ElMessage.success('已驳回')
        fetchRepairOrders()
      } else {
        ElMessage.error(res.msg || '操作失败')
      }
    } catch (error) {
      console.error('驳回失败:', error)
      ElMessage.error('驳回失败')
    }
  }).catch(() => {})
}

// 查看详情
const handleDetail = (order) => {
  currentOrder.value = order
  dialogVisible.value = true
}

onMounted(() => {
  fetchRepairOrders()
})

// 处理照片显示
const processPhotos = (photos) => {
  if (!photos) return []
  
  return photos.split(',').map(photo => {
    try {
      // 检查是否为有效的 Base64 字符串
      if (photo.length % 4 !== 0) {
        console.warn('Invalid Base64 length')
        return ''
      }

      // 如果已经是 data:image 格式,直接返回
      if (photo.startsWith('data:image')) {
        return photo
      }

      // 尝试检测图片类型(简单判断,可根据实际需求扩展)
      let imageType = 'png'
      if (photo.startsWith('/9j/')) {
        imageType = 'jpeg'
      } else if (photo.startsWith('R0lGOD')) {
        imageType = 'gif'
      }

      // 添加适当的 MIME 类型前缀
      return `data:image/${imageType};base64,${photo}`
    } catch (error) {
      console.error('处理图片数据失败:', error)
      return ''
    }
  }).filter(url => url) // 过滤掉无效的图片URL
}
</script>

<style scoped>
.approve-container {
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.detail-content {
  padding: 20px;
}

.detail-item {
  margin-bottom: 15px;
}

.detail-item .label {
  font-weight: bold;
  margin-right: 10px;
}

.detail-item p {
  margin: 10px 0;
  white-space: pre-wrap;
}

.photos {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}

.photo-item {
  width: 100px;
  height: 100px;
  border-radius: 4px;
  cursor: pointer;
  object-fit: cover;
}


.photo-error {
  border: 1px solid #f56c6c;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #f56c6c;
  font-size: 12px;
}
</style>
posted @ 2025-04-28 20:00  三拍  阅读(23)  评论(0)    收藏  举报