zhangwencui
2026-03-06 41acc01d0056630ac11083cf31397f2462acaf4e
src/pages/equipmentManagement/inspection/detail.vue
@@ -1,20 +1,25 @@
<template>
  <view class="inspection-detail">
    <!-- 使用通用页面头部组件 -->
    <PageHeader title="设备巡检详情" @back="goBack" />
    <PageHeader title="巡检管理详情"
                @back="goBack" />
    <!-- 设备信息卡片 -->
    <view class="device-card">
      <view class="device-header">
        <view class="device-icon">
          <up-icon name="settings" size="24" color="#1890ff"></up-icon>
          <up-icon name="settings"
                   size="24"
                   color="#1890ff"></up-icon>
        </view>
        <view class="device-info">
          <text class="device-name">{{ deviceInfo.deviceName }}</text>
          <text class="device-code">{{ deviceInfo.deviceCode }}</text>
        </view>
        <view class="qr-scan" @click="scanDeviceQR">
          <up-icon name="scan" size="20" color="#1890ff"></up-icon>
        <view class="qr-scan"
              @click="scanDeviceQR">
          <up-icon name="scan"
                   size="20"
                   color="#1890ff"></up-icon>
          <text class="scan-text">扫码</text>
        </view>
      </view>
@@ -33,134 +38,131 @@
        </view>
      </view>
    </view>
    <!-- 巡检项目清单 -->
    <view class="inspection-items">
      <view class="section-title">
        <up-icon name="list" size="18" color="#333"></up-icon>
        <up-icon name="list"
                 size="18"
                 color="#333"></up-icon>
        <text class="title-text">巡检项目清单</text>
        <text class="progress-text">({{ completedItems }}/{{ totalItems }})</text>
      </view>
      <view class="items-list">
        <view
          v-for="(item, index) in inspectionItems"
        <view v-for="(item, index) in inspectionItems"
          :key="index"
          class="inspection-item"
          :class="{ 'completed': item.completed, 'abnormal': item.isAbnormal }"
        >
          <view class="item-header" @click="toggleItem(index)">
              :class="{ 'completed': item.completed, 'abnormal': item.isAbnormal }">
          <view class="item-header"
                @click="toggleItem(index)">
            <view class="item-left">
              <view class="checkbox" :class="{ 'checked': item.completed }">
                <up-icon v-if="item.completed" name="checkmark" size="14" color="#ffffff"></up-icon>
              <view class="checkbox"
                    :class="{ 'checked': item.completed }">
                <up-icon v-if="item.completed"
                         name="checkmark"
                         size="14"
                         color="#ffffff"></up-icon>
              </view>
              <text class="item-name">{{ item.name }}</text>
            </view>
            <view class="item-status">
              <u-tag v-if="item.isAbnormal" type="error" size="mini">异常</u-tag>
              <u-tag v-else-if="item.completed" type="success" size="mini">正常</u-tag>
              <u-tag v-else type="info" size="mini">待检</u-tag>
              <u-tag v-if="item.isAbnormal"
                     type="error"
                     size="mini">异常</u-tag>
              <u-tag v-else-if="item.completed"
                     type="success"
                     size="mini">正常</u-tag>
              <u-tag v-else
                     type="info"
                     size="mini">待检</u-tag>
            </view>
          </view>
          <!-- 展开的详情内容 -->
          <view v-if="item.expanded" class="item-content">
          <view v-if="item.expanded"
                class="item-content">
            <view class="item-description">
              <text class="desc-text">{{ item.description }}</text>
            </view>
            <!-- 巡检结果选择 -->
            <view class="result-section">
              <text class="section-label">巡检结果:</text>
              <view class="result-options">
                <u-radio-group v-model="item.result" @change="onResultChange(index, $event)">
                  <u-radio
                    v-for="option in resultOptions"
                <u-radio-group v-model="item.result"
                               @change="onResultChange(index, $event)">
                  <u-radio v-for="option in resultOptions"
                    :key="option.value"
                    :label="option.value"
                    :name="option.label"
                    size="small"
                  >
                           size="small">
                    {{ option.label }}
                  </u-radio>
                </u-radio-group>
              </view>
            </view>
            <!-- 异常情况描述 -->
            <view v-if="item.result === 'abnormal'" class="abnormal-section">
            <view v-if="item.result === 'abnormal'"
                  class="abnormal-section">
              <text class="section-label">异常描述:</text>
              <up-textarea
                v-model="item.abnormalDesc"
              <up-textarea v-model="item.abnormalDesc"
                placeholder="请详细描述异常情况"
                :maxlength="200"
                count
                height="80"
              ></up-textarea>
                           height="80"></up-textarea>
            </view>
            <!-- 图片上传 -->
            <view class="upload-section">
              <text class="section-label">现场照片:</text>
              <up-upload
                :fileList="item.images"
              <up-upload :fileList="item.images"
                @afterRead="(event) => afterRead(event, index, 'images')"
                @delete="(event) => deleteFile(event, index, 'images')"
                name="images"
                multiple
                :maxCount="5"
                :previewImage="true"
              >
                         :previewImage="true">
                <view class="upload-btn">
                  <up-icon name="camera" size="20" color="#999"></up-icon>
                  <up-icon name="camera"
                           size="20"
                           color="#999"></up-icon>
                  <text class="upload-text">添加照片</text>
                </view>
              </up-upload>
            </view>
            <!-- 视频上传 -->
            <view class="upload-section">
              <text class="section-label">现场视频:</text>
              <up-upload
                :fileList="item.videos"
              <up-upload :fileList="item.videos"
                @afterRead="(event) => afterRead(event, index, 'videos')"
                @delete="(event) => deleteFile(event, index, 'videos')"
                name="videos"
                :maxCount="2"
                accept="video"
              >
                         accept="video">
                <view class="upload-btn">
                  <up-icon name="play-circle" size="20" color="#999"></up-icon>
                  <up-icon name="play-circle"
                           size="20"
                           color="#999"></up-icon>
                  <text class="upload-text">添加视频</text>
                </view>
              </up-upload>
            </view>
            <!-- 备注 -->
            <view class="remark-section">
              <text class="section-label">备注:</text>
              <up-textarea
                v-model="item.remark"
              <up-textarea v-model="item.remark"
                placeholder="请输入备注信息(可选)"
                :maxlength="100"
                count
                height="60"
              ></up-textarea>
                           height="60"></up-textarea>
            </view>
          </view>
        </view>
      </view>
    </view>
    <!-- 底部操作按钮 -->
    <view class="bottom-actions">
      <u-button
        type="primary"
      <u-button type="primary"
        size="large"
        :disabled="!canSubmit"
        @click="submitInspection"
        :loading="submitting"
      >
                :loading="submitting">
        {{ allCompleted ? '提交巡检记录' : `继续巡检 (${completedItems}/${totalItems})` }}
      </u-button>
    </view>
@@ -168,166 +170,171 @@
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import { submitInspectionRecord } from '@/api/equipmentManagement/inspection'
import dayjs from 'dayjs'
  import { ref, computed, onMounted } from "vue";
  import { onShow } from "@dcloudio/uni-app";
  import PageHeader from "@/components/PageHeader.vue";
  import { submitInspectionRecord } from "@/api/equipmentManagement/inspection";
  import dayjs from "dayjs";
// 设备信息
const deviceInfo = ref({})
  const deviceInfo = ref({});
// 巡检项目列表
const inspectionItems = ref([])
  const inspectionItems = ref([]);
// 提交状态
const submitting = ref(false)
  const submitting = ref(false);
// 巡检结果选项
const resultOptions = [
  { label: '正常', value: 'normal' },
  { label: '异常', value: 'abnormal' }
]
    { label: "正常", value: "normal" },
    { label: "异常", value: "abnormal" },
  ];
// 显示提示信息
const showToast = (message) => {
  const showToast = message => {
  uni.showToast({
    title: message,
    icon: 'none'
  })
}
      icon: "none",
    });
  };
// 计算属性
const totalItems = computed(() => inspectionItems.value.length)
const completedItems = computed(() => inspectionItems.value.filter(item => item.completed).length)
const allCompleted = computed(() => completedItems.value === totalItems.value && totalItems.value > 0)
const canSubmit = computed(() => completedItems.value > 0)
  const totalItems = computed(() => inspectionItems.value.length);
  const completedItems = computed(
    () => inspectionItems.value.filter(item => item.completed).length
  );
  const allCompleted = computed(
    () => completedItems.value === totalItems.value && totalItems.value > 0
  );
  const canSubmit = computed(() => completedItems.value > 0);
// 返回上一页
const goBack = () => {
  if (completedItems.value > 0) {
    uni.showModal({
      title: '提示',
      content: '当前有未保存的巡检记录,确定要离开吗?',
      success: (res) => {
        title: "提示",
        content: "当前有未保存的巡检记录,确定要离开吗?",
        success: res => {
        if (res.confirm) {
          uni.navigateBack()
            uni.navigateBack();
        }
      }
    })
        },
      });
  } else {
    uni.navigateBack()
      uni.navigateBack();
  }
}
  };
// 扫描设备二维码
const scanDeviceQR = () => {
  uni.scanCode({
    success: (res) => {
      console.log('扫码结果:', res)
      success: res => {
        console.log("扫码结果:", res);
      if (res.result.includes(deviceInfo.value.deviceCode)) {
        showToast('设备确认成功')
          showToast("设备确认成功");
        // 记录扫码时间
        deviceInfo.value.scanTime = new Date().toISOString()
          deviceInfo.value.scanTime = new Date().toISOString();
      } else {
        showToast('设备二维码不匹配')
          showToast("设备二维码不匹配");
      }
    },
    fail: (err) => {
      console.log('扫码失败:', err)
      showToast('扫码失败')
    }
  })
}
      fail: err => {
        console.log("扫码失败:", err);
        showToast("扫码失败");
      },
    });
  };
// 切换巡检项目
const toggleItem = (index) => {
  inspectionItems.value[index].expanded = !inspectionItems.value[index].expanded
}
  const toggleItem = index => {
    inspectionItems.value[index].expanded =
      !inspectionItems.value[index].expanded;
  };
// 巡检结果改变
const onResultChange = (index, value) => {
  const item = inspectionItems.value[index]
  item.result = value
  item.completed = true
  item.isAbnormal = value === 'abnormal'
    const item = inspectionItems.value[index];
    item.result = value;
    item.completed = true;
    item.isAbnormal = value === "abnormal";
  
  // 如果选择正常,清空异常描述
  if (value === 'normal') {
    item.abnormalDesc = ''
    if (value === "normal") {
      item.abnormalDesc = "";
  }
}
  };
// 文件上传后处理
const afterRead = async (event, index, type) => {
  const { file } = event
  const item = inspectionItems.value[index]
    const { file } = event;
    const item = inspectionItems.value[index];
  
  // 模拟上传过程
  uni.showLoading({ title: '上传中...' })
    uni.showLoading({ title: "上传中..." });
  
  try {
    // 这里应该调用实际的上传API
    await new Promise(resolve => setTimeout(resolve, 1000))
      await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 添加到对应的文件列表
    if (type === 'images') {
      item.images = item.images || []
      if (type === "images") {
        item.images = item.images || [];
      item.images.push({
        url: file.url,
        name: file.name,
        size: file.size
      })
    } else if (type === 'videos') {
      item.videos = item.videos || []
          size: file.size,
        });
      } else if (type === "videos") {
        item.videos = item.videos || [];
      item.videos.push({
        url: file.url,
        name: file.name,
        size: file.size
      })
          size: file.size,
        });
    }
    
    uni.hideLoading()
    showToast('上传成功')
      uni.hideLoading();
      showToast("上传成功");
  } catch (error) {
    uni.hideLoading()
    showToast('上传失败')
      uni.hideLoading();
      showToast("上传失败");
  }
}
  };
// 删除文件
const deleteFile = (event, index, type) => {
  const item = inspectionItems.value[index]
  if (type === 'images') {
    item.images.splice(event.index, 1)
  } else if (type === 'videos') {
    item.videos.splice(event.index, 1)
    const item = inspectionItems.value[index];
    if (type === "images") {
      item.images.splice(event.index, 1);
    } else if (type === "videos") {
      item.videos.splice(event.index, 1);
  }
}
  };
// 提交巡检记录
const submitInspection = async () => {
  if (!canSubmit.value) {
    showToast('请至少完成一项巡检')
    return
      showToast("请至少完成一项巡检");
      return;
  }
  
  // 检查异常项目是否填写了描述
  const abnormalItems = inspectionItems.value.filter(item => item.isAbnormal)
    const abnormalItems = inspectionItems.value.filter(item => item.isAbnormal);
  for (const item of abnormalItems) {
    if (!item.abnormalDesc || item.abnormalDesc.trim() === '') {
      showToast(`请填写"${item.name}"的异常描述`)
      return
      if (!item.abnormalDesc || item.abnormalDesc.trim() === "") {
        showToast(`请填写"${item.name}"的异常描述`);
        return;
    }
  }
  
  submitting.value = true
    submitting.value = true;
  
  try {
    const recordData = {
      deviceId: deviceInfo.value.id,
      deviceCode: deviceInfo.value.deviceCode,
      inspectionDate: dayjs().format('YYYY-MM-DD'),
        inspectionDate: dayjs().format("YYYY-MM-DD"),
      inspector: deviceInfo.value.inspector,
      scanTime: deviceInfo.value.scanTime,
      items: inspectionItems.value.map(item => ({
@@ -338,111 +345,110 @@
        abnormalDesc: item.abnormalDesc,
        images: item.images || [],
        videos: item.videos || [],
        remark: item.remark
          remark: item.remark,
      })),
      completedAt: new Date().toISOString()
    }
        completedAt: new Date().toISOString(),
      };
    
    // 模拟API调用
    await new Promise(resolve => setTimeout(resolve, 2000))
      await new Promise(resolve => setTimeout(resolve, 2000));
    
    // 实际API调用
    // await submitInspectionRecord(recordData)
    
    showToast('巡检记录提交成功')
      showToast("巡检记录提交成功");
    
    // 返回列表页面
    setTimeout(() => {
      uni.navigateBack()
    }, 1500)
        uni.navigateBack();
      }, 1500);
  } catch (error) {
    showToast('提交失败,请重试')
      showToast("提交失败,请重试");
  } finally {
    submitting.value = false
      submitting.value = false;
  }
}
  };
// 初始化数据
const initData = () => {
  // 从存储中获取当前巡检信息
  const currentInspection = uni.getStorageSync('currentInspection')
    const currentInspection = uni.getStorageSync("currentInspection");
  if (currentInspection) {
    deviceInfo.value = currentInspection
      deviceInfo.value = currentInspection;
  }
  
  // 模拟巡检项目数据
  inspectionItems.value = [
    {
      name: '设备外观检查',
      description: '检查设备外观是否有损坏、锈蚀、变形等异常情况',
        name: "设备外观检查",
        description: "检查设备外观是否有损坏、锈蚀、变形等异常情况",
      completed: false,
      expanded: false,
      result: '',
        result: "",
      isAbnormal: false,
      abnormalDesc: '',
        abnormalDesc: "",
      images: [],
      videos: [],
      remark: ''
        remark: "",
    },
    {
      name: '运行状态检查',
      description: '检查设备运行是否正常,有无异常声音、振动等',
        name: "运行状态检查",
        description: "检查设备运行是否正常,有无异常声音、振动等",
      completed: false,
      expanded: false,
      result: '',
        result: "",
      isAbnormal: false,
      abnormalDesc: '',
        abnormalDesc: "",
      images: [],
      videos: [],
      remark: ''
        remark: "",
    },
    {
      name: '安全装置检查',
      description: '检查各类安全装置是否完好,安全标识是否清晰',
        name: "安全装置检查",
        description: "检查各类安全装置是否完好,安全标识是否清晰",
      completed: false,
      expanded: false,
      result: '',
        result: "",
      isAbnormal: false,
      abnormalDesc: '',
        abnormalDesc: "",
      images: [],
      videos: [],
      remark: ''
        remark: "",
    },
    {
      name: '环境条件检查',
      description: '检查设备周围环境是否符合要求,通风、照明等是否正常',
        name: "环境条件检查",
        description: "检查设备周围环境是否符合要求,通风、照明等是否正常",
      completed: false,
      expanded: false,
      result: '',
        result: "",
      isAbnormal: false,
      abnormalDesc: '',
        abnormalDesc: "",
      images: [],
      videos: [],
      remark: ''
        remark: "",
    },
    {
      name: '仪表读数记录',
      description: '记录相关仪表的读数,检查是否在正常范围内',
        name: "仪表读数记录",
        description: "记录相关仪表的读数,检查是否在正常范围内",
      completed: false,
      expanded: false,
      result: '',
        result: "",
      isAbnormal: false,
      abnormalDesc: '',
        abnormalDesc: "",
      images: [],
      videos: [],
      remark: ''
    }
  ]
}
        remark: "",
      },
    ];
  };
onMounted(() => {
  initData()
})
    initData();
  });
onShow(() => {
  // 页面显示时刷新数据
})
  });
</script>
<style scoped lang="scss">
@@ -453,13 +459,17 @@
  position: relative;
  
  &::before {
    content: '';
      content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 200px;
    background: linear-gradient(135deg, rgba(102, 126, 234, 0.8) 0%, rgba(118, 75, 162, 0.8) 100%);
      background: linear-gradient(
        135deg,
        rgba(102, 126, 234, 0.8) 0%,
        rgba(118, 75, 162, 0.8) 100%
      );
    z-index: 0;
  }
}