zhangwencui
8 天以前 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"
          :key="index"
          class="inspection-item"
          :class="{ 'completed': item.completed, 'abnormal': item.isAbnormal }"
        >
          <view class="item-header" @click="toggleItem(index)">
        <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)">
            <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"
                    :key="option.value"
                    :label="option.value"
                    :name="option.label"
                    size="small"
                  >
                <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">
                    {{ 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"
                placeholder="请详细描述异常情况"
                :maxlength="200"
                count
                height="80"
              ></up-textarea>
              <up-textarea v-model="item.abnormalDesc"
                           placeholder="请详细描述异常情况"
                           :maxlength="200"
                           count
                           height="80"></up-textarea>
            </view>
            <!-- 图片上传 -->
            <view class="upload-section">
              <text class="section-label">现场照片:</text>
              <up-upload
                :fileList="item.images"
                @afterRead="(event) => afterRead(event, index, 'images')"
                @delete="(event) => deleteFile(event, index, 'images')"
                name="images"
                multiple
                :maxCount="5"
                :previewImage="true"
              >
              <up-upload :fileList="item.images"
                         @afterRead="(event) => afterRead(event, index, 'images')"
                         @delete="(event) => deleteFile(event, index, 'images')"
                         name="images"
                         multiple
                         :maxCount="5"
                         :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"
                @afterRead="(event) => afterRead(event, index, 'videos')"
                @delete="(event) => deleteFile(event, index, 'videos')"
                name="videos"
                :maxCount="2"
                accept="video"
              >
              <up-upload :fileList="item.videos"
                         @afterRead="(event) => afterRead(event, index, 'videos')"
                         @delete="(event) => deleteFile(event, index, 'videos')"
                         name="videos"
                         :maxCount="2"
                         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"
                placeholder="请输入备注信息(可选)"
                :maxlength="100"
                count
                height="60"
              ></up-textarea>
              <up-textarea v-model="item.remark"
                           placeholder="请输入备注信息(可选)"
                           :maxlength="100"
                           count
                           height="60"></up-textarea>
            </view>
          </view>
        </view>
      </view>
    </view>
    <!-- 底部操作按钮 -->
    <view class="bottom-actions">
      <u-button
        type="primary"
        size="large"
        :disabled="!canSubmit"
        @click="submitInspection"
        :loading="submitting"
      >
      <u-button type="primary"
                size="large"
                :disabled="!canSubmit"
                @click="submitInspection"
                :loading="submitting">
        {{ allCompleted ? '提交巡检记录' : `继续巡检 (${completedItems}/${totalItems})` }}
      </u-button>
    </view>
@@ -168,638 +170,646 @@
</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' }
]
  // 巡检结果选项
  const resultOptions = [
    { label: "正常", value: "normal" },
    { label: "异常", value: "abnormal" },
  ];
// 显示提示信息
const showToast = (message) => {
  uni.showToast({
    title: message,
    icon: 'none'
  })
}
  // 显示提示信息
  const showToast = message => {
    uni.showToast({
      title: message,
      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) => {
        if (res.confirm) {
          uni.navigateBack()
  // 返回上一页
  const goBack = () => {
    if (completedItems.value > 0) {
      uni.showModal({
        title: "提示",
        content: "当前有未保存的巡检记录,确定要离开吗?",
        success: res => {
          if (res.confirm) {
            uni.navigateBack();
          }
        },
      });
    } else {
      uni.navigateBack();
    }
  };
  // 扫描设备二维码
  const scanDeviceQR = () => {
    uni.scanCode({
      success: res => {
        console.log("扫码结果:", res);
        if (res.result.includes(deviceInfo.value.deviceCode)) {
          showToast("设备确认成功");
          // 记录扫码时间
          deviceInfo.value.scanTime = new Date().toISOString();
        } else {
          showToast("设备二维码不匹配");
        }
      },
      fail: err => {
        console.log("扫码失败:", err);
        showToast("扫码失败");
      },
    });
  };
  // 切换巡检项目
  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";
    // 如果选择正常,清空异常描述
    if (value === "normal") {
      item.abnormalDesc = "";
    }
  };
  // 文件上传后处理
  const afterRead = async (event, index, type) => {
    const { file } = event;
    const item = inspectionItems.value[index];
    // 模拟上传过程
    uni.showLoading({ title: "上传中..." });
    try {
      // 这里应该调用实际的上传API
      await new Promise(resolve => setTimeout(resolve, 1000));
      // 添加到对应的文件列表
      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 || [];
        item.videos.push({
          url: file.url,
          name: file.name,
          size: file.size,
        });
      }
    })
  } else {
    uni.navigateBack()
  }
}
// 扫描设备二维码
const scanDeviceQR = () => {
  uni.scanCode({
    success: (res) => {
      console.log('扫码结果:', res)
      if (res.result.includes(deviceInfo.value.deviceCode)) {
        showToast('设备确认成功')
        // 记录扫码时间
        deviceInfo.value.scanTime = new Date().toISOString()
      } else {
        showToast('设备二维码不匹配')
      uni.hideLoading();
      showToast("上传成功");
    } catch (error) {
      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 submitInspection = async () => {
    if (!canSubmit.value) {
      showToast("请至少完成一项巡检");
      return;
    }
    // 检查异常项目是否填写了描述
    const abnormalItems = inspectionItems.value.filter(item => item.isAbnormal);
    for (const item of abnormalItems) {
      if (!item.abnormalDesc || item.abnormalDesc.trim() === "") {
        showToast(`请填写"${item.name}"的异常描述`);
        return;
      }
    },
    fail: (err) => {
      console.log('扫码失败:', err)
      showToast('扫码失败')
    }
  })
}
// 切换巡检项目
const toggleItem = (index) => {
  inspectionItems.value[index].expanded = !inspectionItems.value[index].expanded
}
    submitting.value = true;
// 巡检结果改变
const onResultChange = (index, value) => {
  const item = inspectionItems.value[index]
  item.result = value
  item.completed = true
  item.isAbnormal = value === 'abnormal'
  // 如果选择正常,清空异常描述
  if (value === 'normal') {
    item.abnormalDesc = ''
  }
}
    try {
      const recordData = {
        deviceId: deviceInfo.value.id,
        deviceCode: deviceInfo.value.deviceCode,
        inspectionDate: dayjs().format("YYYY-MM-DD"),
        inspector: deviceInfo.value.inspector,
        scanTime: deviceInfo.value.scanTime,
        items: inspectionItems.value.map(item => ({
          name: item.name,
          result: item.result,
          completed: item.completed,
          isAbnormal: item.isAbnormal,
          abnormalDesc: item.abnormalDesc,
          images: item.images || [],
          videos: item.videos || [],
          remark: item.remark,
        })),
        completedAt: new Date().toISOString(),
      };
// 文件上传后处理
const afterRead = async (event, index, type) => {
  const { file } = event
  const item = inspectionItems.value[index]
  // 模拟上传过程
  uni.showLoading({ title: '上传中...' })
  try {
    // 这里应该调用实际的上传API
    await new Promise(resolve => setTimeout(resolve, 1000))
    // 添加到对应的文件列表
    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 || []
      item.videos.push({
        url: file.url,
        name: file.name,
        size: file.size
      })
      // 模拟API调用
      await new Promise(resolve => setTimeout(resolve, 2000));
      // 实际API调用
      // await submitInspectionRecord(recordData)
      showToast("巡检记录提交成功");
      // 返回列表页面
      setTimeout(() => {
        uni.navigateBack();
      }, 1500);
    } catch (error) {
      showToast("提交失败,请重试");
    } finally {
      submitting.value = false;
    }
    uni.hideLoading()
    showToast('上传成功')
  } catch (error) {
    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 submitInspection = async () => {
  if (!canSubmit.value) {
    showToast('请至少完成一项巡检')
    return
  }
  // 检查异常项目是否填写了描述
  const abnormalItems = inspectionItems.value.filter(item => item.isAbnormal)
  for (const item of abnormalItems) {
    if (!item.abnormalDesc || item.abnormalDesc.trim() === '') {
      showToast(`请填写"${item.name}"的异常描述`)
      return
  // 初始化数据
  const initData = () => {
    // 从存储中获取当前巡检信息
    const currentInspection = uni.getStorageSync("currentInspection");
    if (currentInspection) {
      deviceInfo.value = currentInspection;
    }
  }
  submitting.value = true
  try {
    const recordData = {
      deviceId: deviceInfo.value.id,
      deviceCode: deviceInfo.value.deviceCode,
      inspectionDate: dayjs().format('YYYY-MM-DD'),
      inspector: deviceInfo.value.inspector,
      scanTime: deviceInfo.value.scanTime,
      items: inspectionItems.value.map(item => ({
        name: item.name,
        result: item.result,
        completed: item.completed,
        isAbnormal: item.isAbnormal,
        abnormalDesc: item.abnormalDesc,
        images: item.images || [],
        videos: item.videos || [],
        remark: item.remark
      })),
      completedAt: new Date().toISOString()
    }
    // 模拟API调用
    await new Promise(resolve => setTimeout(resolve, 2000))
    // 实际API调用
    // await submitInspectionRecord(recordData)
    showToast('巡检记录提交成功')
    // 返回列表页面
    setTimeout(() => {
      uni.navigateBack()
    }, 1500)
  } catch (error) {
    showToast('提交失败,请重试')
  } finally {
    submitting.value = false
  }
}
// 初始化数据
const initData = () => {
  // 从存储中获取当前巡检信息
  const currentInspection = uni.getStorageSync('currentInspection')
  if (currentInspection) {
    deviceInfo.value = currentInspection
  }
  // 模拟巡检项目数据
  inspectionItems.value = [
    {
      name: '设备外观检查',
      description: '检查设备外观是否有损坏、锈蚀、变形等异常情况',
      completed: false,
      expanded: false,
      result: '',
      isAbnormal: false,
      abnormalDesc: '',
      images: [],
      videos: [],
      remark: ''
    },
    {
      name: '运行状态检查',
      description: '检查设备运行是否正常,有无异常声音、振动等',
      completed: false,
      expanded: false,
      result: '',
      isAbnormal: false,
      abnormalDesc: '',
      images: [],
      videos: [],
      remark: ''
    },
    {
      name: '安全装置检查',
      description: '检查各类安全装置是否完好,安全标识是否清晰',
      completed: false,
      expanded: false,
      result: '',
      isAbnormal: false,
      abnormalDesc: '',
      images: [],
      videos: [],
      remark: ''
    },
    {
      name: '环境条件检查',
      description: '检查设备周围环境是否符合要求,通风、照明等是否正常',
      completed: false,
      expanded: false,
      result: '',
      isAbnormal: false,
      abnormalDesc: '',
      images: [],
      videos: [],
      remark: ''
    },
    {
      name: '仪表读数记录',
      description: '记录相关仪表的读数,检查是否在正常范围内',
      completed: false,
      expanded: false,
      result: '',
      isAbnormal: false,
      abnormalDesc: '',
      images: [],
      videos: [],
      remark: ''
    }
  ]
}
    // 模拟巡检项目数据
    inspectionItems.value = [
      {
        name: "设备外观检查",
        description: "检查设备外观是否有损坏、锈蚀、变形等异常情况",
        completed: false,
        expanded: false,
        result: "",
        isAbnormal: false,
        abnormalDesc: "",
        images: [],
        videos: [],
        remark: "",
      },
      {
        name: "运行状态检查",
        description: "检查设备运行是否正常,有无异常声音、振动等",
        completed: false,
        expanded: false,
        result: "",
        isAbnormal: false,
        abnormalDesc: "",
        images: [],
        videos: [],
        remark: "",
      },
      {
        name: "安全装置检查",
        description: "检查各类安全装置是否完好,安全标识是否清晰",
        completed: false,
        expanded: false,
        result: "",
        isAbnormal: false,
        abnormalDesc: "",
        images: [],
        videos: [],
        remark: "",
      },
      {
        name: "环境条件检查",
        description: "检查设备周围环境是否符合要求,通风、照明等是否正常",
        completed: false,
        expanded: false,
        result: "",
        isAbnormal: false,
        abnormalDesc: "",
        images: [],
        videos: [],
        remark: "",
      },
      {
        name: "仪表读数记录",
        description: "记录相关仪表的读数,检查是否在正常范围内",
        completed: false,
        expanded: false,
        result: "",
        isAbnormal: false,
        abnormalDesc: "",
        images: [],
        videos: [],
        remark: "",
      },
    ];
  };
onMounted(() => {
  initData()
})
  onMounted(() => {
    initData();
  });
onShow(() => {
  // 页面显示时刷新数据
})
  onShow(() => {
    // 页面显示时刷新数据
  });
</script>
<style scoped lang="scss">
.inspection-detail {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  min-height: 100vh;
  padding-bottom: 80px;
  position: relative;
  &::before {
    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%);
    z-index: 0;
  .inspection-detail {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    padding-bottom: 80px;
    position: relative;
    &::before {
      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%
      );
      z-index: 0;
    }
  }
}
.device-card {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(15px);
  margin: 10px 20px;
  border-radius: 20px;
  padding: 24px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  position: relative;
  z-index: 1;
  transition: all 0.3s ease;
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
  }
}
  .device-card {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(15px);
    margin: 10px 20px;
    border-radius: 20px;
    padding: 24px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    position: relative;
    z-index: 1;
    transition: all 0.3s ease;
.device-header {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 20px;
}
.device-icon {
  width: 56px;
  height: 56px;
  background: linear-gradient(135deg, #667eea, #764ba2);
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
  transition: all 0.3s ease;
  &:hover {
    transform: scale(1.05);
  }
}
.device-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.device-name {
  font-size: 20px;
  font-weight: 600;
  color: #1a1a1a;
  line-height: 1.3;
}
.device-code {
  font-size: 13px;
  color: #8c8c8c;
  font-weight: 500;
  padding: 4px 12px;
  background: rgba(140, 140, 140, 0.1);
  border-radius: 12px;
  display: inline-block;
  width: fit-content;
}
.qr-scan {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 12px 16px;
  background: linear-gradient(135deg, #52c41a, #389e0d);
  border-radius: 12px;
  box-shadow: 0 4px 15px rgba(82, 196, 26, 0.3);
  transition: all 0.3s ease;
  &:hover {
    transform: scale(1.05);
    box-shadow: 0 6px 20px rgba(82, 196, 26, 0.4);
  }
  &:active {
    transform: scale(0.98);
  }
}
.scan-text {
  font-size: 13px;
  color: #ffffff;
  font-weight: 600;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.device-details {
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: rgba(248, 250, 252, 0.8);
  border-radius: 16px;
  padding: 16px;
  backdrop-filter: blur(10px);
}
.detail-item {
  display: flex;
  align-items: center;
  font-size: 14px;
  padding: 8px 0;
  transition: all 0.2s ease;
  &:hover {
    background: rgba(255, 255, 255, 0.5);
    margin: 0 -8px;
    padding-left: 8px;
    padding-right: 8px;
    border-radius: 8px;
  }
}
.label {
  color: #595959;
  min-width: 80px;
  font-weight: 500;
}
.value {
  color: #262626;
  flex: 1;
  font-weight: 500;
}
.inspection-items {
  margin: 10px 20px;
  position: relative;
  z-index: 1;
}
.section-title {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(15px);
  border-radius: 16px;
  padding: 20px;
  margin-bottom: 16px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.title-text {
  font-size: 18px;
  font-weight: 600;
  color: #1a1a1a;
  flex: 1;
}
.progress-text {
  font-size: 15px;
  font-weight: 600;
  background: linear-gradient(135deg, #667eea, #764ba2);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.items-list {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(15px);
  border-radius: 20px;
  overflow: hidden;
  margin-top: 0;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.inspection-item {
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  transition: all 0.3s ease;
  &:last-child {
    border-bottom: none;
  }
  &.completed {
    background: rgba(82, 196, 26, 0.05);
    border-left: 4px solid #52c41a;
  }
  &.abnormal {
    background: rgba(255, 77, 79, 0.05);
    border-left: 4px solid #ff4d4f;
  }
  &:hover {
    background: rgba(102, 126, 234, 0.05);
  }
}
.item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px;
  cursor: pointer;
}
.item-left {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}
.checkbox {
  width: 20px;
  height: 20px;
  border: 2px solid #d9d9d9;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  &.checked {
    background: #52c41a;
    border-color: #52c41a;
  }
}
.item-name {
  font-size: 15px;
  color: #333;
  font-weight: 500;
}
.item-status {
  flex-shrink: 0;
}
.item-content {
  padding: 0 15px 20px;
  border-top: 1px solid #f5f5f5;
}
.item-description {
  padding: 15px 0;
}
.desc-text {
  font-size: 14px;
  color: #666;
  line-height: 1.5;
}
.result-section,
.abnormal-section,
.upload-section,
.remark-section {
  margin-top: 15px;
}
.section-label {
  display: block;
  font-size: 14px;
  color: #333;
  margin-bottom: 8px;
  font-weight: 500;
}
.result-options {
  display: flex;
  gap: 20px;
}
.upload-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 88px;
  border: 2px dashed rgba(102, 126, 234, 0.3);
  border-radius: 16px;
  background: rgba(102, 126, 234, 0.05);
  gap: 8px;
  transition: all 0.3s ease;
  &:hover {
    border-color: rgba(102, 126, 234, 0.5);
    background: rgba(102, 126, 234, 0.1);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
  }
  &:active {
    transform: translateY(0);
  }
}
.upload-text {
  font-size: 13px;
  color: #667eea;
  font-weight: 500;
}
.bottom-actions {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  padding: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.1);
  z-index: 10;
  button {
    height: 48px;
    border-radius: 16px;
    font-weight: 600;
    font-size: 16px;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    &:hover {
      transform: translateY(-2px);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
      box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
    }
  }
  .device-header {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 20px;
  }
  .device-icon {
    width: 56px;
    height: 56px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
    transition: all 0.3s ease;
    &:hover {
      transform: scale(1.05);
    }
  }
  .device-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .device-name {
    font-size: 20px;
    font-weight: 600;
    color: #1a1a1a;
    line-height: 1.3;
  }
  .device-code {
    font-size: 13px;
    color: #8c8c8c;
    font-weight: 500;
    padding: 4px 12px;
    background: rgba(140, 140, 140, 0.1);
    border-radius: 12px;
    display: inline-block;
    width: fit-content;
  }
  .qr-scan {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 16px;
    background: linear-gradient(135deg, #52c41a, #389e0d);
    border-radius: 12px;
    box-shadow: 0 4px 15px rgba(82, 196, 26, 0.3);
    transition: all 0.3s ease;
    &:hover {
      transform: scale(1.05);
      box-shadow: 0 6px 20px rgba(82, 196, 26, 0.4);
    }
    &:active {
      transform: scale(0.98);
    }
  }
  .scan-text {
    font-size: 13px;
    color: #ffffff;
    font-weight: 600;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  }
  .device-details {
    display: flex;
    flex-direction: column;
    gap: 12px;
    background: rgba(248, 250, 252, 0.8);
    border-radius: 16px;
    padding: 16px;
    backdrop-filter: blur(10px);
  }
  .detail-item {
    display: flex;
    align-items: center;
    font-size: 14px;
    padding: 8px 0;
    transition: all 0.2s ease;
    &:hover {
      background: rgba(255, 255, 255, 0.5);
      margin: 0 -8px;
      padding-left: 8px;
      padding-right: 8px;
      border-radius: 8px;
    }
  }
  .label {
    color: #595959;
    min-width: 80px;
    font-weight: 500;
  }
  .value {
    color: #262626;
    flex: 1;
    font-weight: 500;
  }
  .inspection-items {
    margin: 10px 20px;
    position: relative;
    z-index: 1;
  }
  .section-title {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 20px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(15px);
    border-radius: 16px;
    padding: 20px;
    margin-bottom: 16px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  }
  .title-text {
    font-size: 18px;
    font-weight: 600;
    color: #1a1a1a;
    flex: 1;
  }
  .progress-text {
    font-size: 15px;
    font-weight: 600;
    background: linear-gradient(135deg, #667eea, #764ba2);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }
  .items-list {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(15px);
    border-radius: 20px;
    overflow: hidden;
    margin-top: 0;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
  }
  .inspection-item {
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    transition: all 0.3s ease;
    &:last-child {
      border-bottom: none;
    }
    &.completed {
      background: rgba(82, 196, 26, 0.05);
      border-left: 4px solid #52c41a;
    }
    &.abnormal {
      background: rgba(255, 77, 79, 0.05);
      border-left: 4px solid #ff4d4f;
    }
    &:hover {
      background: rgba(102, 126, 234, 0.05);
    }
  }
  .item-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 15px;
    cursor: pointer;
  }
  .item-left {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1;
  }
  .checkbox {
    width: 20px;
    height: 20px;
    border: 2px solid #d9d9d9;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s;
    &.checked {
      background: #52c41a;
      border-color: #52c41a;
    }
  }
  .item-name {
    font-size: 15px;
    color: #333;
    font-weight: 500;
  }
  .item-status {
    flex-shrink: 0;
  }
  .item-content {
    padding: 0 15px 20px;
    border-top: 1px solid #f5f5f5;
  }
  .item-description {
    padding: 15px 0;
  }
  .desc-text {
    font-size: 14px;
    color: #666;
    line-height: 1.5;
  }
  .result-section,
  .abnormal-section,
  .upload-section,
  .remark-section {
    margin-top: 15px;
  }
  .section-label {
    display: block;
    font-size: 14px;
    color: #333;
    margin-bottom: 8px;
    font-weight: 500;
  }
  .result-options {
    display: flex;
    gap: 20px;
  }
  .upload-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 88px;
    height: 88px;
    border: 2px dashed rgba(102, 126, 234, 0.3);
    border-radius: 16px;
    background: rgba(102, 126, 234, 0.05);
    gap: 8px;
    transition: all 0.3s ease;
    &:hover {
      border-color: rgba(102, 126, 234, 0.5);
      background: rgba(102, 126, 234, 0.1);
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
    }
    &:active {
      transform: translateY(0);
    }
  }
}
  .upload-text {
    font-size: 13px;
    color: #667eea;
    font-weight: 500;
  }
  .bottom-actions {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(20px);
    padding: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.2);
    box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.1);
    z-index: 10;
    button {
      height: 48px;
      border-radius: 16px;
      font-weight: 600;
      font-size: 16px;
      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
      &:hover {
        transform: translateY(-2px);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
      }
      &:active {
        transform: translateY(0);
      }
    }
  }
</style>