2025/4/23团队进度开发报告

工程师工作页任务管理,安全须知与图片水印保存:


RepairOrder:

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("repair_orders")
public class RepairOrder {
    
    @TableId(type = IdType.AUTO)
    private Integer orderId;        // 工单编号
    
    private Integer faultId;        // 故障编号
    
    private String engineerId;      // 工程师工号
    
    private String repairDesc;      // 维修描述
    
    private String status;          // 工单状态:待处理、处理中、已完成、待审批、已关闭
    
    private String safetyNotice;    // 安全须知
    
    private String photos;          // 维修照片

    public Integer getOrderId() {
        return orderId;
    }

    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }

    public Integer getFaultId() {
        return faultId;
    }

    public void setFaultId(Integer faultId) {
        this.faultId = faultId;
    }

    public String getEngineerId() {
        return engineerId;
    }

    public void setEngineerId(String engineerId) {
        this.engineerId = engineerId;
    }

    public String getRepairDesc() {
        return repairDesc;
    }

    public void setRepairDesc(String repairDesc) {
        this.repairDesc = repairDesc;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getSafetyNotice() {
        return safetyNotice;
    }

    public void setSafetyNotice(String safetyNotice) {
        this.safetyNotice = safetyNotice;
    }

    public String getPhotos() {
        return photos;
    }

    public void setPhotos(String photos) {
        this.photos = photos;
    }
}

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());
        }
    }
}

RepairOrderMapper:

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());
        }
    }
}

RepairOrderServiceImpl:

package com.example.demo.service.impl;

import com.example.demo.entity.RepairOrder;
import com.example.demo.mapper.RepairOrderMapper;
import com.example.demo.service.RepairOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class RepairOrderServiceImpl implements RepairOrderService {
    
    @Autowired
    private RepairOrderMapper repairOrderMapper;

    @Override
    public RepairOrder createRepairOrder(RepairOrder repairOrder) {
        repairOrderMapper.insert(repairOrder);
        return repairOrder;
    }

    @Override
    public boolean updateOrderStatus(Integer orderId, String status) {
        RepairOrder order = repairOrderMapper.selectById(orderId);
        if (order == null) {
            System.out.println("未找到ID为"+orderId+"的维修工单");
            return false;
        }
        
        // 将前端传入的"completed"转换为"待审批"
        if ("completed".equals(status)) {
            status = "待审批";
        }
        
        // 验证状态是否合法
        List<String> validStatus = Arrays.asList("待处理", "处理中", "已完成", "待审批", "已关闭");
        if (!validStatus.contains(status)) {
            System.out.println("无效的状态值: "+status);
            throw new IllegalArgumentException("无效的状态值");
        }
        
        order.setStatus(status);
        boolean success = repairOrderMapper.updateById(order) > 0;
        
        if (success) {
            System.out.println("工单状态更新成功,更新后工单信息:");
            System.out.println(order);
        } else {
            System.out.println("工单状态更新失败,工单ID: "+orderId);
        }
        
        return success;
    }

    @Override
    public List<RepairOrder> getOrdersByEngineerId(String engineerId) {
        QueryWrapper<RepairOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("engineer_id", engineerId);
        return repairOrderMapper.selectList(queryWrapper);
    }

    @Override
    public RepairOrder getOrderById(Integer orderId) {
        return repairOrderMapper.selectById(orderId);
    }

    @Override
    public Page<RepairOrder> getOrdersByPage(Integer pageNum, Integer pageSize) {
        Page<RepairOrder> page = new Page<>(pageNum, pageSize);
        return repairOrderMapper.selectPage(page, null);
    }

    @Override
    public List<RepairOrder> getOrdersByStatus(String status) {
        QueryWrapper<RepairOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", status);
        return repairOrderMapper.selectList(queryWrapper);
    }

    @Override
    public boolean deleteOrder(Integer orderId) {
        return repairOrderMapper.deleteById(orderId) > 0;
    }

    @Override
    public boolean updateOrder(RepairOrder repairOrder) {
        return repairOrderMapper.updateById(repairOrder) > 0;
    }

    @Override
    public List<RepairOrder> getAllOrders() {
        return repairOrderMapper.selectList(null);
    }
}

RepairOrderService:

package com.example.demo.service.impl;

import com.example.demo.entity.RepairOrder;
import com.example.demo.mapper.RepairOrderMapper;
import com.example.demo.service.RepairOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class RepairOrderServiceImpl implements RepairOrderService {
    
    @Autowired
    private RepairOrderMapper repairOrderMapper;

    @Override
    public RepairOrder createRepairOrder(RepairOrder repairOrder) {
        repairOrderMapper.insert(repairOrder);
        return repairOrder;
    }

    @Override
    public boolean updateOrderStatus(Integer orderId, String status) {
        RepairOrder order = repairOrderMapper.selectById(orderId);
        if (order == null) {
            System.out.println("未找到ID为"+orderId+"的维修工单");
            return false;
        }
        
        // 将前端传入的"completed"转换为"待审批"
        if ("completed".equals(status)) {
            status = "待审批";
        }
        
        // 验证状态是否合法
        List<String> validStatus = Arrays.asList("待处理", "处理中", "已完成", "待审批", "已关闭");
        if (!validStatus.contains(status)) {
            System.out.println("无效的状态值: "+status);
            throw new IllegalArgumentException("无效的状态值");
        }
        
        order.setStatus(status);
        boolean success = repairOrderMapper.updateById(order) > 0;
        
        if (success) {
            System.out.println("工单状态更新成功,更新后工单信息:");
            System.out.println(order);
        } else {
            System.out.println("工单状态更新失败,工单ID: "+orderId);
        }
        
        return success;
    }

    @Override
    public List<RepairOrder> getOrdersByEngineerId(String engineerId) {
        QueryWrapper<RepairOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("engineer_id", engineerId);
        return repairOrderMapper.selectList(queryWrapper);
    }

    @Override
    public RepairOrder getOrderById(Integer orderId) {
        return repairOrderMapper.selectById(orderId);
    }

    @Override
    public Page<RepairOrder> getOrdersByPage(Integer pageNum, Integer pageSize) {
        Page<RepairOrder> page = new Page<>(pageNum, pageSize);
        return repairOrderMapper.selectPage(page, null);
    }

    @Override
    public List<RepairOrder> getOrdersByStatus(String status) {
        QueryWrapper<RepairOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", status);
        return repairOrderMapper.selectList(queryWrapper);
    }

    @Override
    public boolean deleteOrder(Integer orderId) {
        return repairOrderMapper.deleteById(orderId) > 0;
    }

    @Override
    public boolean updateOrder(RepairOrder repairOrder) {
        return repairOrderMapper.updateById(repairOrder) > 0;
    }

    @Override
    public List<RepairOrder> getAllOrders() {
        return repairOrderMapper.selectList(null);
    }
}

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  // 直接传递参数对象
  })
}

Work.vue:

<template>
  <div class="work-container">
    <el-card class="work-card">
      <template #header>
        <div class="card-header">
          <span>我的工单</span>
          <el-button type="primary" @click="refreshOrders">刷新</el-button>
        </div>
      </template>

      <el-table :data="repairOrders" style="width: 100%" v-loading="loading">
        <el-table-column prop="orderId" label="工单号" width="120" />
        <el-table-column prop="deviceId" label="设备ID" width="120" />
        <el-table-column prop="faultDesc" label="描述" />
        <el-table-column prop="status" label="状态" width="100">
          <template #default="scope">
            <el-tag :type="getStatusType(scope.row.status)">
              {{ getStatusText(scope.row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200">
          <template #default="scope">
            <el-button 
              size="small" 
              type="primary"
              @click="handleViewDetail(scope.row)"
            >
              查看详情
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 状态更新对话框 -->
    <el-dialog v-model="dialogVisible" title="更新工单状态" width="30%">
      <el-form :model="updateForm">
        <el-form-item label="工单状态">
          <el-select v-model="updateForm.status" placeholder="请选择状态">
            <el-option label="处理中" value="processing" />
            <el-option label="已完成" value="completed" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmUpdateStatus">确认</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'  // 添加这行
import { ElMessage } from 'element-plus'
import { getRepairOrderList, updateRepairOrderStatus } from '@/api/repairOrder'
import { getFault } from '@/api/deviceFault'  // 添加故障查询 API

const loading = ref(false)
const repairOrders = ref([])
const dialogVisible = ref(false)
const updateForm = ref({
  orderId: null,
  status: ''
})

// 获取当前登录用户信息
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')

// 获取工单列表
const fetchOrders = async () => {
  loading.value = true
  try {
    const response = await getRepairOrderList({ engineerId: userInfo.id })  // 修改这里
    if (response && response.data) {
      const orders = response.data || []
      
      const ordersWithFaults = await Promise.all(orders.map(async (order) => {
        try {
          const faultResponse = await getFault(order.faultId)
          if (faultResponse && faultResponse.data) {
            return {
              ...order,
              deviceId: faultResponse.data.deviceId,
              faultDesc: faultResponse.data.faultDesc  // 修改这里,使用正确的字段名
            }
          }
          return order
        } catch (error) {
          console.error('获取故障信息失败:', error)
          return order
        }
      }))
      
      repairOrders.value = ordersWithFaults
    } else {
      repairOrders.value = []
    }
    
    if (repairOrders.value.length === 0) {
      ElMessage.info('暂无维修工单')
    }
  } catch (error) {
    console.error('获取工单列表失败:', error)
    ElMessage.error('获取工单列表失败')
    repairOrders.value = []
  } finally {
    loading.value = false
  }
}

// 刷新工单列表
const refreshOrders = () => {
  fetchOrders()
}

// 处理状态更新
const handleUpdateStatus = (row) => {
  updateForm.value.orderId = row.orderId
  updateForm.value.status = row.status
  dialogVisible.value = true
}

// 确认更新状态
const confirmUpdateStatus = async () => {
  try {
    await updateRepairOrderStatus(updateForm.value)
    ElMessage.success('状态更新成功')
    dialogVisible.value = false
    fetchOrders() // 刷新列表
  } catch (error) {
    ElMessage.error('状态更新失败')
  }
}

// 获取状态标签类型
const getStatusType = (status) => {
  const statusMap = {
    'pending': 'warning',
    'processing': 'primary',
    'completed': 'success'
  }
  return statusMap[status] || 'info'
}

// 获取状态显示文本
const getStatusText = (status) => {
  const statusMap = {
    'pending': '待处理',
    'processing': '处理中',
    'completed': '已完成'
  }
  return statusMap[status] || status
}

const router = useRouter()  // 添加这行

onMounted(() => {
  fetchOrders()
})

// 添加查看详情方法
const handleViewDetail = (row) => {
  router.push(`/work-detail/${row.orderId}`)
}
</script>

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

.work-card {
  margin-bottom: 20px;
}

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

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
</style>

WorkDetail.vue:

<template>
  <div class="work-detail-container">
    <!-- 添加音频元素 -->
    <audio id="notice-audio" style="display: none;">
      <source src="@/assets/repair_notice.mp3" type="audio/mpeg">
    </audio>
    
    <!-- 现有的模板内容 -->
    <el-card class="work-card">
      <template #header>
        <div class="card-header">
          <span>工单详情</span>
          <el-button @click="$router.back()">返回</el-button>
        </div>
      </template>

      <el-descriptions :column="1" border>
        <el-descriptions-item label="工单号">{{ orderDetail.orderId }}</el-descriptions-item>
        <el-descriptions-item label="设备ID">{{ orderDetail.deviceId }}</el-descriptions-item>
        <el-descriptions-item label="故障描述">{{ orderDetail.faultDesc }}</el-descriptions-item>
        <el-descriptions-item label="状态">
          <el-tag :type="getStatusType(orderDetail.status)">
            {{ getStatusText(orderDetail.status) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="安全须知">
          <pre class="safety-notice">{{ orderDetail.safetyNotice }}</pre>
        </el-descriptions-item>
        <el-descriptions-item label="维修描述">
          <el-input
            v-model="orderDetail.repairDesc"
            type="textarea"
            :rows="3"
            placeholder="请输入维修描述"
          />
        </el-descriptions-item>
        <el-descriptions-item label="维修照片">
          <div class="upload-section">
            <input
              type="file"
              ref="fileInput"
              style="display: none"
              accept="image/*"
              @change="handleFileChange"
            />
            <!-- 修改上传区域结构 -->
            <div 
              class="upload-area" 
              @click="triggerFileInput"
              @dragover.prevent
              @drop.prevent="handleDrop"
            >
              <!-- 当没有图片时显示上传提示 -->
              <template v-if="fileList.length === 0">
                <el-icon class="upload-icon"><Upload /></el-icon>
                <div class="upload-text">
                  <span>点击选择或拖拽图片到此处</span>
                  <p>支持 jpg、png 格式图片</p>
                </div>
              </template>
              
              <!-- 图片预览列表 -->
              <div v-else class="image-preview-container">
                <div v-for="(img, index) in fileList" :key="index" class="image-preview-item">
                  <el-image :src="img.url" fit="cover" />
                  <div class="image-actions">
                    <el-button type="danger" icon="Delete" circle @click.stop="removeImage(index)" />
                  </div>
                </div>
              </div>
            </div>
          </div>
        </el-descriptions-item>
      </el-descriptions>

      <div class="action-buttons">
        <el-button 
          type="primary" 
          @click="handleSave" 
          style="margin-right: 10px"
          :disabled="orderDetail.status === '已完成' || !canOperate"
        >{{ !canOperate ? '请等待3秒' : '保存' }}</el-button>
        <el-button 
          type="success" 
          @click="handleComplete" 
          :disabled="orderDetail.status === '已完成' || !canOperate"
        >{{ !canOperate ? '请等待3秒' : '完成工单' }}</el-button>
      </div>
    </el-card>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getRepairOrderList, updateRepairOrderStatus, updateRepairOrder } from '@/api/repairOrder'
import { getFault, updateFaultStatus } from '@/api/deviceFault'  // 添加 updateFaultStatus

// 在 script setup 顶部其他变量声明后添加
const route = useRoute()
const router = useRouter()
const orderDetail = ref({})
const fileList = ref([])
const canOperate = ref(false)  // 添加这行

const getStatusType = (status) => {
  const statusMap = {
    'pending': 'warning',
    'processing': 'primary',
    'completed': 'success'
  }
  return statusMap[status] || 'info'
}

const getStatusText = (status) => {
  const statusMap = {
    'pending': '待处理',
    'processing': '处理中',
    'completed': '已完成'
  }
  return statusMap[status] || status
}

const fetchOrderDetail = async () => {
  try {
    const orderId = route.params.id
    const response = await getRepairOrderList({ engineerId: JSON.parse(localStorage.getItem('userInfo') || '{}').userId })
    const order = response.data.find(o => o.orderId === parseInt(orderId))
    
    if (order) {
      const faultResponse = await getFault(order.faultId)
      orderDetail.value = {
        ...order,
        deviceId: faultResponse.data.deviceId,
        faultDesc: faultResponse.data.faultDesc
      }
      
      // 处理已有的照片数据
      if (orderDetail.value.photos) {
        try {
          // 清空现有图片列表
          fileList.value = []
          
          // 将逗号分隔的字符串转换为数组,并过滤掉空字符串
          const photoArray = orderDetail.value.photos.split(',').filter(item => item.trim() !== '')
          
          // 处理每张照片
          fileList.value = photoArray.map((base64String, index) => {
            // 检查并处理 Base64 字符串
            let imgSrc = base64String
            if (base64String && !base64String.startsWith('data:image')) {
              imgSrc = 'data:image/png;base64,' + base64String
            }

            return {
              url: imgSrc,
              name: `photo_${index}`  // 使用索引而不是时间戳
            }
          }).filter(item => {
            // 验证 Base64 数据的有效性
            return item.url && item.url.length > 22  // 最小有效base64长度检查
          })
        } catch (error) {
          console.error('处理照片数据失败:', error)
          ElMessage.warning('部分照片加载失败')
          fileList.value = []  // 出错时清空列表
        }
      } else {
        fileList.value = []  // 没有照片时确保列表为空
      }
    }
  } catch (error) {
    ElMessage.error('获取工单详情失败')
  }
}

const handleComplete = async () => {
  try {
    // 更新工单状态
    await updateRepairOrderStatus({
      orderId: orderDetail.value.orderId,
      status: 'completed'
    })
    
    // 更新故障状态为待审批
    await updateFaultStatus({
      faultId: orderDetail.value.faultId,
      status: '待审批'
    })

    ElMessage.success('工单已完成')
    orderDetail.value.status = 'completed'
  } catch (error) {
    ElMessage.error('更新状态失败')
  }
}

const handleUploadSuccess = (response, file) => {
  ElMessage.success('上传成功')
  if (!orderDetail.value.photos) {
    orderDetail.value.photos = []
  }
  orderDetail.value.photos.push(response.url)
}

const handleUploadError = () => {
  ElMessage.error('上传失败')
}

const fileInput = ref(null)
const watermarkText = ref('')
const watermarkPosition = ref('bottomRight')
const watermarkColor = ref('#000000')

// 触发文件选择
const triggerFileInput = () => {
  fileInput.value.click()
}

// 添加拖拽处理函数
const handleDrop = (e) => {
  const file = e.dataTransfer.files[0]
  if (file && file.type.startsWith('image/')) {
    processImage(file)
  } else {
    ElMessage.warning('请上传图片文件')
  }
}

// 处理文件选择
const handleFileChange = (e) => {
  const file = e.target.files[0]
  if (file) {
    processImage(file)
  }
}

// 图片处理函数
const processImage = (file) => {
  const reader = new FileReader()
  reader.onload = (e) => {
    const img = new Image()
    img.onload = () => {
      const canvas = document.createElement('canvas')
      canvas.width = img.width
      canvas.height = img.height
      const ctx = canvas.getContext('2d')

      // 绘制原图
      ctx.drawImage(img, 0, 0)

      // 添加水印(固定为当前时间和右下角位置)
      const text = new Date().toLocaleString('zh-CN')
      ctx.font = '24px Arial'
      ctx.fillStyle = watermarkColor.value
      ctx.globalAlpha = 0.5

      // 计算水印位置(固定右下角)
      const textWidth = ctx.measureText(text).width
      const x = canvas.width - textWidth - 20
      const y = canvas.height - 20

      // 绘制水印
      ctx.fillText(text, x, y)

      // 转换为 base64 并添加到列表
      const watermarkedImage = canvas.toDataURL(file.type)
      fileList.value.push({
        url: watermarkedImage,
        name: file.name
      })
    }
    img.src = e.target.result
  }
  reader.readAsDataURL(file)
}

// 移除图片
const removeImage = (index) => {
  fileList.value.splice(index, 1)
}

// 修改保存方法
const handleSave = async () => {
  try {
    // 将图片转换为Base64字符串数组,过滤掉可能的无效数据
    const imageUrls = fileList.value
      .filter(file => file.url && file.url.length > 22)  // 过滤无效图片
      .map(file => file.url)
    
    // 构建更新的工单数据
    const updateData = {
      orderId: orderDetail.value.orderId,
      faultId: orderDetail.value.faultId,
      engineerId: orderDetail.value.engineerId,
      repairDesc: orderDetail.value.repairDesc,
      status: orderDetail.value.status,
      safetyNotice: orderDetail.value.safetyNotice,
      photos: imageUrls.join(',') // 将图片数组转换为逗号分隔的字符串
    }

    // 调用更新接口
    const response = await updateRepairOrder(updateData)
    if (response.code === 200) {
      ElMessage.success('保存成功')
    } else {
      throw new Error(response.msg)
    }
  } catch (error) {
    ElMessage.error('保存失败:' + error.message)
  }
}

// 添加音频播放逻辑
const playNoticeAudio = () => {
  const audio = document.getElementById('notice-audio')
  
  function tryPlay() {
    document.removeEventListener('click', tryPlay)
    audio.play().then(() => {
      console.log('提示音播放成功')
    }).catch(err => {
      console.error('提示音播放失败:', err)
    })
  }

  // 页面第一次点击触发播放
  document.addEventListener('click', tryPlay)
}

onMounted(() => {
  // 在组件挂载后初始化音频播放
  playNoticeAudio()
  fetchOrderDetail()
  
  // 添加3秒计时器
  setTimeout(() => {
    canOperate.value = true
  }, 3000)
})
</script>

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

.work-detail-card {
  margin-bottom: 20px;
}

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

.action-buttons {
  margin-top: 20px;
  text-align: center;
}

.upload-demo {
  margin: 10px 0;
}

.el-descriptions-item {
  margin-bottom: 20px;
  width: 100%;  /* 确保描述项占满宽度 */
}

.upload-section {
  padding: 10px;  /* 减小内边距 */
  width: 100%;    /* 确保上传区域占满宽度 */
  box-sizing: border-box;  /* 包含内边距在宽度内 */
}

.upload-area {
  width: 100%;
  min-height: 180px;
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transition: border-color 0.3s;
  padding: 10px;  /* 减小内边距 */
  box-sizing: border-box;  /* 包含内边距在宽度内 */
}

.image-preview-container {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));  /* 减小图片大小 */
  gap: 10px;  /* 减小间距 */
  padding: 5px;  /* 减小内边距 */
}

/* 确保描述列表的标签列宽度固定 */
:deep(.el-descriptions__label) {
  min-width: 120px;  /* 设置固定的标签宽度 */
  width: 120px;
  white-space: nowrap;
}

.watermark-settings {
  margin: 20px 0;
  display: flex;
  align-items: center;
}

.image-list {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin-top: 20px;
}

.image-item {
  position: relative;
  width: 200px;
  height: 200px;
}

.image-item .el-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.image-item .el-button {
  position: absolute;
  top: 10px;
  right: 10px;
}

.safety-notice {
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: inherit;
  margin: 0;
  padding: 0;
  line-height: 1.5;
}

.upload-area {
  width: 100%;
  min-height: 180px;
  border: 2px dashed #d9d9d9;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transition: border-color 0.3s;
  padding: 20px;
}

.image-preview-container {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 16px;
  padding: 10px;
}

.image-preview-item {
  position: relative;
  aspect-ratio: 1;
  border-radius: 4px;
  overflow: hidden;
}

.image-preview-item .el-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.image-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  display: none;
}

.image-preview-item:hover .image-actions {
  display: block;
}

</style>
posted @ 2025-04-23 23:36  三拍  阅读(41)  评论(0)    收藏  举报