From 752b14d2caa47ccceac328f79389fbf5e2e62ce4 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 24 九月 2025 15:18:39 +0800
Subject: [PATCH] 分析追溯

---
 src/pages/index.vue                                     |   18 
 src/pages.json                                          |    7 
 src/pages/inspectionUpload/index.vue                    |  793 ++++++++--------
 src/static/images/icon/xunjianshangchuan@2x.png         |    0 
 src/static/images/icon/zuoyezhidao@2x.png               |    0 
 src/components/imageUpload/index.vue                    |  819 +++++++++++++++++
 src/components/imageUpload/viewQrCodeFiles.vue          |  297 ++++++
 src/pages/inspectionUpload/components/qrCodeFormDia.vue |  236 +---
 src/static/images/icon/zhinengpaidan@2x.png             |    0 
 src/pages/equipmentManagement/faultAnalysis/index.vue   |  353 +++++++
 src/pages/equipmentManagement/repair/add.vue            |    2 
 src/config.js                                           |    1 
 src/static/images/icon/guzhangfenxi@2x.png              |    0 
 src/static/images/icon/jieguoyanzheng@2x.png            |    0 
 src/components/imageUpload/viewQrCodeFilesSimple.vue    |  288 ++++++
 15 files changed, 2,251 insertions(+), 563 deletions(-)

diff --git a/src/components/imageUpload/index.vue b/src/components/imageUpload/index.vue
new file mode 100644
index 0000000..51e4331
--- /dev/null
+++ b/src/components/imageUpload/index.vue
@@ -0,0 +1,819 @@
+<template>
+  <view class="camera-upload">
+    <!-- 鎷嶇収/鎷嶈棰戞寜閽� -->
+    <view v-if="!disabled" class="camera-buttons">
+      <view class="button-row">
+        <u-button 
+          type="primary" 
+          @click="takePhoto"
+          :loading="uploading"
+          :disabled="fileList.length >= limit"
+          :customStyle="{ marginRight: '10px', flex: 1 }"
+        >
+          <u-icon name="camera" size="18" color="#fff" style="margin-right: 5px;"></u-icon>
+          {{ uploading ? '涓婁紶涓�...' : '鎷嶇収' }}
+        </u-button>
+        <u-button 
+          type="success" 
+          @click="takeVideo"
+          :loading="uploading"
+          :disabled="fileList.length >= limit"
+          :customStyle="{ flex: 1 }"
+        >
+          <u-icon name="video" size="18" color="#fff" style="margin-right: 5px;"></u-icon>
+          {{ uploading ? '涓婁紶涓�...' : '鎷嶈棰�' }}
+        </u-button>
+      </view>
+    </view>
+    
+    <!-- 鎻愮ず淇℃伅 -->
+    <view v-if="showTip && !disabled" class="upload-tip">
+      璇蜂娇鐢ㄧ浉鏈�
+      <text v-if="fileSize" class="tip-text">
+        鎷嶆憚澶у皬涓嶈秴杩� <text class="tip-highlight">{{ fileSize }}MB</text>
+      </text>
+      鐨�
+      <text class="tip-highlight">鐓х墖鎴栬棰�</text>
+    </view>
+    
+    <!-- 濯掍綋鏂囦欢鍒楄〃 -->
+    <view class="media-list">
+      <view
+        v-for="(file, index) in fileList"
+        :key="file.uid || index"
+        class="media-item"
+      >
+        <!-- 棰勮鍖哄煙 -->
+        <view class="media-preview" @click="previewMedia(file, index)">
+          <image 
+            v-if="file.type === 'image'"
+            :src="file.url || file.tempFilePath" 
+            class="preview-image"
+            mode="aspectFill"
+          ></image>
+          <video 
+            v-else-if="file.type === 'video'"
+            :src="file.url || file.tempFilePath"
+            class="preview-video"
+            :controls="false"
+          ></video>
+          <view class="media-type-icon">
+            <u-icon 
+              :name="file.type === 'image' ? 'photo' : 'video'" 
+              size="12" 
+              color="#fff"
+            ></u-icon>
+          </view>
+        </view>
+        
+        <!-- 鎿嶄綔鎸夐挳 -->
+        <view class="media-actions" v-if="!disabled">
+          <u-button 
+            type="error" 
+            size="mini" 
+            @click="handleDelete(index)"
+            :customStyle="{ 
+              minWidth: '40px', 
+              height: '24px', 
+              fontSize: '10px',
+              padding: '0 8px'
+            }"
+          >
+            鍒犻櫎
+          </u-button>
+        </view>
+      </view>
+    </view>
+    
+    <!-- 涓婁紶杩涘害 -->
+    <view v-if="uploading" class="upload-progress">
+      <u-line-progress 
+        :percentage="uploadProgress" 
+        :showText="true"
+        activeColor="#409eff"
+      ></u-line-progress>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
+import { getToken } from "@/utils/auth";
+
+// Props 瀹氫箟
+const props = defineProps({
+  modelValue: [String, Object, Array],
+  action: { type: String, default: "/common/minioUploads" },
+  data: { type: Object },
+  limit: { type: Number, default: 5 },
+  fileSize: { type: Number, default: 10 }, // 榛樿10MB锛岄�傚悎瑙嗛
+  fileType: { 
+    type: Array, 
+    default: () => ["jpg", "jpeg", "png", "mp4", "mov"] 
+  },
+  isShowTip: { type: Boolean, default: true },
+  disabled: { type: Boolean, default: false },
+  drag: { type: Boolean, default: false }, // 鎷嶇収涓嶉渶瑕佹嫋鎷�
+  statusType: { type: Number, default: "" }, // 鐢ㄤ簬鍖哄垎涓嶅悓鐘舵�佺殑涓婁紶
+  maxVideoDuration: { type: Number, default: 30 }, // 鏈�澶ц棰戞椂闀匡紙绉掞級
+});
+
+// 浜嬩欢瀹氫箟
+const emit = defineEmits(['update:modelValue']);
+
+// 鍝嶅簲寮忔暟鎹�
+const number = ref(0);
+const uploadList = ref([]);
+const fileList = ref([]);
+const uploading = ref(false);
+const uploadProgress = ref(0);
+
+// 璁$畻灞炴��
+const uploadFileUrl = computed(() => {
+  // 鑾峰彇鍩虹API鍦板潃锛岄�傞厤uniapp鐜
+  let baseUrl = '';
+  
+  // 灏濊瘯澶氱鏂瑰紡鑾峰彇baseUrl
+  if (process.env.VUE_APP_BASE_API) {
+    baseUrl = process.env.VUE_APP_BASE_API;
+  } else if (process.env.NODE_ENV === 'development') {
+    baseUrl = 'http://192.168.1.147:9036';
+  } else {
+    baseUrl = 'http://192.168.1.147:9036';
+  }
+  
+  const fullUrl = baseUrl + props.action;
+  return fullUrl;
+});
+const headers = computed(() => {
+  const token = getToken();
+  return token ? { Authorization: "Bearer " + token } : {};
+});
+const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize));
+// 鍒濆鍖栧拰缂栬緫鍒濆鍖栨柟娉�
+const init = () => {
+  fileList.value = [];
+  uploadList.value = [];
+  number.value = 0;
+};
+
+const editInit = (val) => {
+  fileList.value = [];
+  val.storageBlobDTO.forEach((element) => {
+    // 纭繚鏂囦欢鏁版嵁鍖呭惈鎵�鏈夊繀瑕佸瓧娈碉紝鍖呮嫭id
+    const fileData = {
+      ...element,
+      id: element.id, // 淇濈暀鏈嶅姟鍣ㄨ繑鍥炵殑id
+      url: element.url || element.downloadUrl,
+      bucketFilename: element.bucketFilename || element.name,
+      downloadUrl: element.downloadUrl || element.url,
+      type: element.type || (element.url && element.url.includes('video') ? 'video' : 'image'),
+      name: element.name || element.bucketFilename || `鏂囦欢_${Date.now()}`,
+      size: element.size || 0,
+      createTime: element.createTime || new Date().getTime(),
+      uid: element.uid || new Date().getTime() + Math.random()
+    };
+    fileList.value.push(fileData);
+    uploadedSuccessfully();
+  });
+};
+
+// 娴嬭瘯鏈嶅姟鍣ㄨ繛鎺�
+const testServerConnection = () => {
+  return new Promise((resolve) => {
+    uni.request({
+      url: uploadFileUrl.value.replace('/common/minioUploads', '/common/test'),
+      method: 'GET',
+      timeout: 5000,
+      success: (res) => {
+        resolve(true);
+      },
+      fail: (err) => {
+        resolve(false);
+      }
+    });
+  });
+};
+
+// 缁勪欢閿�姣佹椂鐨勬竻鐞�
+onUnmounted(() => {
+  // 娓呯悊涓婁紶鐘舵��
+  if (uploading.value) {
+    uploading.value = false
+  }
+  
+  // 闅愯棌鍙兘鏄剧ず鐨勫姞杞芥彁绀�
+  uni.hideLoading()
+  uni.hideToast()
+})
+
+// 鏆撮湶鏂规硶
+defineExpose({ init, editInit, testServerConnection });
+
+// 鐩戝惉 modelValue 鍙樺寲
+watch(
+  () => props.modelValue,
+  (val) => {
+    if (val) {
+      let temp = 1;
+      let list = [];
+      
+      if (Array.isArray(val)) {
+        list = val;
+      } else if (typeof val === "string") {
+        list = val.split(",").map(url => ({ url: url.trim() }));
+      }
+      
+      fileList.value = list.map((item) => {
+        if (typeof item === "string") {
+          item = { name: item, url: item };
+        }
+        // 纭繚姣忎釜鏂囦欢閮芥湁蹇呰鐨勫睘鎬э紝鍖呮嫭id
+        return {
+          ...item,
+          id: item.id, // 淇濈暀id瀛楁
+          uid: item.uid || new Date().getTime() + temp++,
+          type: item.type || (item.url && item.url.includes('video') ? 'video' : 'image'),
+          name: item.name || item.bucketFilename || `鏂囦欢_${Date.now()}`,
+          size: item.size || 0,
+          createTime: item.createTime || new Date().getTime()
+        };
+      });
+    } else {
+      fileList.value = [];
+    }
+  },
+  { deep: true, immediate: true }
+);
+
+// 鎷嶇収
+const takePhoto = () => {
+  if (fileList.value.length >= props.limit) {
+    uni.showToast({
+      title: `鏈�澶氬彧鑳芥媿鎽�${props.limit}涓枃浠禶,
+      icon: 'none'
+    });
+    return;
+  }
+  
+  uni.chooseImage({
+    count: 1,
+    sizeType: ['compressed', 'original'],
+    sourceType: ['camera'],
+    success: (res) => {
+      try {
+        if (!res.tempFilePaths || res.tempFilePaths.length === 0) {
+          throw new Error('鏈幏鍙栧埌鍥剧墖鏂囦欢');
+        }
+        
+        const tempFilePath = res.tempFilePaths[0];
+        const tempFile = res.tempFiles && res.tempFiles[0] ? res.tempFiles[0] : {};
+        
+        const file = {
+          tempFilePath: tempFilePath,
+          type: 'image',
+          name: `photo_${Date.now()}.jpg`,
+          size: tempFile.size || 0,
+          createTime: new Date().getTime(),
+          uid: Date.now() + Math.random()
+        };
+        
+        handleBeforeUpload(file);
+      } catch (error) {
+        console.error('澶勭悊鎷嶇収缁撴灉澶辫触:', error);
+        uni.showToast({
+          title: '澶勭悊鍥剧墖澶辫触',
+          icon: 'error'
+        });
+      }
+    },
+    fail: (err) => {
+      console.error('鎷嶇収澶辫触:', err);
+      uni.showToast({
+        title: '鎷嶇収澶辫触: ' + (err.errMsg || '鏈煡閿欒'),
+        icon: 'error'
+      });
+    }
+  });
+};
+
+// 鎷嶈棰�
+const takeVideo = () => {
+  if (fileList.value.length >= props.limit) {
+    uni.showToast({
+      title: `鏈�澶氬彧鑳芥媿鎽�${props.limit}涓枃浠禶,
+      icon: 'none'
+    });
+    return;
+  }
+  
+  uni.chooseVideo({
+    sourceType: ['camera'],
+    maxDuration: props.maxVideoDuration,
+    camera: 'back',
+    success: (res) => {
+      try {
+        if (!res.tempFilePath) {
+          throw new Error('鏈幏鍙栧埌瑙嗛鏂囦欢');
+        }
+        
+        const file = {
+          tempFilePath: res.tempFilePath,
+          type: 'video',
+          name: `video_${Date.now()}.mp4`,
+          size: res.size || 0,
+          duration: res.duration || 0,
+          createTime: new Date().getTime(),
+          uid: Date.now() + Math.random()
+        };
+        
+        handleBeforeUpload(file);
+      } catch (error) {
+        console.error('澶勭悊鎷嶈棰戠粨鏋滃け璐�:', error);
+        uni.showToast({
+          title: '澶勭悊瑙嗛澶辫触',
+          icon: 'error'
+        });
+      }
+    },
+    fail: (err) => {
+      console.error('鎷嶈棰戝け璐�:', err);
+      uni.showToast({
+        title: '鎷嶈棰戝け璐�: ' + (err.errMsg || '鏈煡閿欒'),
+        icon: 'error'
+      });
+    }
+  });
+};
+
+// 鏂囦欢涓婁紶澶勭悊
+const uploadFile = (file) => {
+  uploading.value = true;
+  uploadProgress.value = 0;
+  number.value++; // 澧炲姞涓婁紶璁℃暟
+  
+  // 纭繚鏂囦欢璺緞姝g‘
+  const filePath = file.tempFilePath || file.path;
+  if (!filePath) {
+    handleUploadError('鏂囦欢璺緞涓嶅瓨鍦�');
+    return;
+  }
+  
+  // 纭繚token瀛樺湪
+  const token = getToken();
+  if (!token) {
+    handleUploadError('鐢ㄦ埛鏈櫥褰�');
+    return;
+  }
+  
+  // 鍑嗗涓婁紶鍙傛暟
+  const uploadParams = {
+    url: uploadFileUrl.value,
+    filePath: filePath,
+    name: 'files',
+    formData: {
+      type: props.statusType || 0,
+      ...(props.data || {})
+    },
+    header: {
+      'Authorization': `Bearer ${token}`
+    }
+  };
+  
+  const uploadTask = uni.uploadFile({
+    ...uploadParams,
+    success: (res) => {
+      try {
+        if (res.statusCode === 200) {
+          const response = JSON.parse(res.data);
+          if (response.code === 200) {
+            handleUploadSuccess(response, file);
+            uni.showToast({
+              title: '涓婁紶鎴愬姛',
+              icon: 'success'
+            });
+            emit("update:modelValue", fileList.value);
+          } else {
+            handleUploadError(response.msg || '鏈嶅姟鍣ㄨ繑鍥為敊璇�');
+          }
+        } else {
+          handleUploadError(`鏈嶅姟鍣ㄩ敊璇紝鐘舵�佺爜: ${res.statusCode}`);
+        }
+      } catch (e) {
+        console.error('瑙f瀽鍝嶅簲澶辫触:', e);
+        console.error('鍘熷鍝嶅簲鏁版嵁:', res.data);
+        handleUploadError('鍝嶅簲鏁版嵁瑙f瀽澶辫触: ' + e.message);
+      }
+    },
+    fail: (err) => {
+      console.error('涓婁紶澶辫触:', err.errMsg || err);
+      number.value--; // 涓婁紶澶辫触鏃跺噺灏戣鏁�
+      
+      let errorMessage = '涓婁紶澶辫触';
+      if (err.errMsg) {
+        if (err.errMsg.includes('statusCode: null')) {
+          errorMessage = '缃戠粶杩炴帴澶辫触锛岃妫�鏌ョ綉缁滆缃�';
+        } else if (err.errMsg.includes('timeout')) {
+          errorMessage = '涓婁紶瓒呮椂锛岃閲嶈瘯';
+        } else if (err.errMsg.includes('fail')) {
+          errorMessage = '涓婁紶澶辫触锛岃妫�鏌ョ綉缁滆繛鎺�';
+        } else {
+          errorMessage = err.errMsg;
+        }
+      }
+      
+      handleUploadError(errorMessage);
+    },
+    complete: () => {
+      uploading.value = false;
+      uploadProgress.value = 0;
+    }
+  });
+  
+  // 鐩戝惉涓婁紶杩涘害
+  if (uploadTask && uploadTask.onProgressUpdate) {
+    uploadTask.onProgressUpdate((res) => {
+      uploadProgress.value = res.progress;
+    });
+  }
+};
+// 鑾峰彇濯掍綋鏂囦欢鍚�
+const getMediaName = (file) => {
+  if (file.bucketFilename) {
+    return file.bucketFilename.length > 15 
+      ? file.bucketFilename.substring(0, 15) + '...'
+      : file.bucketFilename;
+  }
+  if (file.name) {
+    return file.name.length > 15 
+      ? file.name.substring(0, 15) + '...'
+      : file.name;
+  }
+  return file.type === 'image' ? '鐓х墖' : '瑙嗛';
+};
+
+// 鏍煎紡鍖栨枃浠跺ぇ灏�
+const formatFileSize = (size) => {
+  if (!size) return '';
+  if (size < 1024) return size + 'B';
+  if (size < 1024 * 1024) return (size / 1024).toFixed(1) + 'KB';
+  return (size / (1024 * 1024)).toFixed(1) + 'MB';
+};
+
+// 鏍煎紡鍖栨椂闂�
+const formatTime = (timestamp) => {
+  if (!timestamp) return '';
+  const date = new Date(timestamp);
+  const now = new Date();
+  const diff = now - date;
+  
+  if (diff < 60000) return '鍒氬垰';
+  if (diff < 3600000) return Math.floor(diff / 60000) + '鍒嗛挓鍓�';
+  if (diff < 86400000) return Math.floor(diff / 3600000) + '灏忔椂鍓�';
+  
+  return date.toLocaleDateString();
+};
+
+// 棰勮濯掍綋鏂囦欢
+const previewMedia = (file, index) => {
+  if (file.type === 'image') {
+    // 棰勮鍥剧墖
+    const urls = fileList.value
+      .filter(item => item.type === 'image')
+      .map(item => item.url || item.tempFilePath);
+    
+    uni.previewImage({
+      urls: urls,
+      current: file.url || file.tempFilePath
+    });
+  } else if (file.type === 'video') {
+    // 棰勮瑙嗛
+    uni.previewVideo({
+      sources: [{
+        src: file.url || file.tempFilePath,
+        type: 'mp4'
+      }],
+      current: 0
+    });
+  }
+};
+
+// 涓嬭浇鏂囦欢
+const handleDownload = (index) => {
+  const file = fileList.value[index];
+  const url = file.url || file.downloadUrl;
+  
+  if (!url) {
+    uni.showToast({
+      title: '鏂囦欢閾炬帴涓嶅瓨鍦紝鏃犳硶涓嬭浇',
+      icon: 'none'
+    });
+    return;
+  }
+  
+  // 浣跨敤uniapp鐨勪笅杞紸PI
+  uni.downloadFile({
+    url: url,
+    success: (res) => {
+      if (res.statusCode === 200) {
+        // 淇濆瓨鍒扮浉鍐屾垨鏂囦欢绯荤粺
+        uni.saveFile({
+          tempFilePath: res.tempFilePath,
+          success: (saveRes) => {
+            uni.showToast({
+              title: '涓嬭浇鎴愬姛',
+              icon: 'success'
+            });
+          },
+          fail: (err) => {
+            console.error('淇濆瓨鏂囦欢澶辫触:', err);
+            uni.showToast({
+              title: '淇濆瓨鏂囦欢澶辫触',
+              icon: 'error'
+            });
+          }
+        });
+      }
+    },
+    fail: (err) => {
+      console.error('涓嬭浇澶辫触:', err);
+      uni.showToast({
+        title: '涓嬭浇澶辫触',
+        icon: 'error'
+      });
+    }
+  });
+};
+
+// 妫�鏌ョ綉缁滆繛鎺�
+const checkNetworkConnection = () => {
+  return new Promise((resolve) => {
+    uni.getNetworkType({
+      success: (res) => {
+        if (res.networkType === 'none') {
+          resolve(false);
+        } else {
+          resolve(true);
+        }
+      },
+      fail: () => {
+        resolve(false);
+      }
+    });
+  });
+};
+
+// 涓婁紶鍓嶆牎楠�
+const handleBeforeUpload = async (file) => {
+  // 妫�鏌ョ綉缁滆繛鎺�
+  const hasNetwork = await checkNetworkConnection();
+  if (!hasNetwork) {
+    uni.showToast({
+      title: '缃戠粶杩炴帴涓嶅彲鐢紝璇锋鏌ョ綉缁滆缃�',
+      icon: 'none'
+    });
+    return false;
+  }
+
+  // 鏍¢獙鏂囦欢澶у皬
+  if (props.fileSize && file.size) {
+    const isLt = file.size / 1024 / 1024 < props.fileSize;
+    if (!isLt) {
+      uni.showToast({
+        title: `鏂囦欢澶у皬涓嶈兘瓒呰繃 ${props.fileSize} MB!`,
+        icon: 'none'
+      });
+      return false;
+    }
+  }
+
+  // 鏍¢獙瑙嗛鏃堕暱
+  if (file.type === 'video' && file.duration && file.duration > props.maxVideoDuration) {
+    uni.showToast({
+      title: `瑙嗛鏃堕暱涓嶈兘瓒呰繃 ${props.maxVideoDuration} 绉�!`,
+      icon: 'none'
+    });
+    return false;
+  }
+
+  // 鏍¢獙鏂囦欢绫诲瀷
+  if (props.fileType && Array.isArray(props.fileType) && props.fileType.length > 0) {
+    const fileName = file.name || '';
+    const fileExtension = fileName ? fileName.split('.').pop().toLowerCase() : '';
+    
+    // 鏍规嵁鏂囦欢绫诲瀷纭畾鏈熸湜鐨勬墿灞曞悕
+    let expectedTypes = [];
+    if (file.type === 'image') {
+      expectedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+    } else if (file.type === 'video') {
+      expectedTypes = ['mp4', 'mov', 'avi', 'wmv'];
+    }
+    
+    // 妫�鏌ユ枃浠舵墿灞曞悕鏄惁鍦ㄥ厑璁哥殑绫诲瀷涓�
+    if (fileExtension && expectedTypes.length > 0) {
+      const isAllowed = expectedTypes.some(type => 
+        props.fileType.includes(type) && type === fileExtension
+      );
+      
+      if (!isAllowed) {
+        uni.showToast({
+          title: `鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇锋媿鎽� ${expectedTypes.join('/')} 鏍煎紡鐨勬枃浠禶,
+          icon: 'none'
+        });
+        return false;
+      }
+    }
+  }
+
+  // 鏍¢獙閫氳繃锛屽紑濮嬩笂浼�
+  uploadFile(file);
+  return true;
+};
+
+// 涓婁紶澶辫触澶勭悊
+const handleUploadError = (message = '涓婁紶鏂囦欢澶辫触', showRetry = true) => {
+  if (showRetry) {
+    uni.showModal({
+      title: '涓婁紶澶辫触',
+      content: message + '锛屾槸鍚﹂噸璇曪紵',
+      success: (res) => {
+        if (res.confirm) {
+          // 鐢ㄦ埛閫夋嫨閲嶈瘯锛岃繖閲屽彲浠ラ噸鏂拌Е鍙戜笂浼�
+        }
+      }
+    });
+  } else {
+    uni.showToast({
+      title: message,
+      icon: 'error'
+    });
+  }
+};
+
+// 涓婁紶鎴愬姛鍥炶皟
+const handleUploadSuccess = (res, file) => {
+  if (res.code === 200 && res.data && Array.isArray(res.data) && res.data.length > 0) {
+    const uploadedFile = res.data[0];
+    // 纭繚涓婁紶鐨勬枃浠舵暟鎹畬鏁达紝鍖呭惈id
+    const fileData = {
+      ...file,
+      id: uploadedFile.id, // 娣诲姞鏈嶅姟鍣ㄨ繑鍥炵殑id
+      url: uploadedFile.url || uploadedFile.downloadUrl,
+      bucketFilename: uploadedFile.bucketFilename || file.name,
+      downloadUrl: uploadedFile.downloadUrl || uploadedFile.url,
+      size: uploadedFile.size || file.size,
+      createTime: uploadedFile.createTime || new Date().getTime()
+    };
+    
+    uploadList.value.push(fileData);
+    uploadedSuccessfully();
+  } else {
+    number.value--; // 涓婁紶澶辫触鏃跺噺灏戣鏁�
+    handleUploadError(res.msg || '涓婁紶澶辫触');
+  }
+};
+
+// 鍒犻櫎鏂囦欢
+const handleDelete = (index) => {
+  uni.showModal({
+    title: '纭鍒犻櫎',
+    content: '纭畾瑕佸垹闄よ繖涓枃浠跺悧锛�',
+    success: (res) => {
+      if (res.confirm) {
+        fileList.value.splice(index, 1);
+        emit("update:modelValue", listToString(fileList.value));
+        uni.showToast({
+          title: '鍒犻櫎鎴愬姛',
+          icon: 'success'
+        });
+      }
+    }
+  });
+};
+
+// 涓婁紶缁撴潫澶勭悊
+const uploadedSuccessfully = () => {
+  if (number.value > 0 && uploadList.value.length === number.value) {
+    // 鍚堝苟宸插瓨鍦ㄧ殑鏂囦欢鍜屽垰涓婁紶鐨勬枃浠�
+    const existingFiles = fileList.value.filter((f) => f.url !== undefined);
+    fileList.value = [...existingFiles, ...uploadList.value];
+    
+    // 閲嶇疆鐘舵��
+    uploadList.value = [];
+    number.value = 0;
+    
+    // 瑙﹀彂鏇存柊浜嬩欢锛屼紶閫掑畬鏁寸殑鏂囦欢鍒楄〃
+    emit("update:modelValue", fileList.value);
+  }
+};
+
+const listToString = (list, separator = ",") => {
+  const strs = list
+    .filter(item => item.url)
+    .map(item => item.url)
+    .join(separator);
+  return strs;
+};
+</script>
+<style scoped lang="scss">
+.camera-upload {
+  width: 100%;
+}
+
+.camera-buttons {
+  margin-bottom: 15px;
+  
+  .button-row {
+    display: flex;
+    gap: 10px;
+  }
+}
+
+.upload-tip {
+  font-size: 12px;
+  color: #909399;
+  margin-bottom: 15px;
+  text-align: center;
+  line-height: 1.5;
+  
+  .tip-text {
+    margin: 0 2px;
+  }
+  
+  .tip-highlight {
+    color: #f56c6c;
+    font-weight: bold;
+  }
+}
+
+.media-list {
+  margin-top: 10px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.media-item {
+  position: relative;
+  width: 80px;
+  height: 80px;
+  border-radius: 8px;
+  overflow: hidden;
+  background-color: #f5f5f5;
+  border: 2px solid #e9ecef;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    border-color: #409eff;
+    transform: scale(1.02);
+  }
+}
+
+.media-preview {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  cursor: pointer;
+  
+  .preview-image, .preview-video {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+  }
+  
+  .media-type-icon {
+    position: absolute;
+    top: 4px;
+    right: 4px;
+    width: 20px;
+    height: 20px;
+    background-color: rgba(0, 0, 0, 0.6);
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+}
+
+.media-actions {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
+  padding: 4px;
+  display: flex;
+  justify-content: center;
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  
+  .media-item:hover & {
+    opacity: 1;
+  }
+}
+
+.upload-progress {
+  margin-top: 15px;
+  padding: 0 10px;
+}
+</style>
diff --git a/src/components/imageUpload/viewQrCodeFiles.vue b/src/components/imageUpload/viewQrCodeFiles.vue
new file mode 100644
index 0000000..32f5684
--- /dev/null
+++ b/src/components/imageUpload/viewQrCodeFiles.vue
@@ -0,0 +1,297 @@
+<template>
+  <view>
+    <!-- 寮圭獥 -->
+    <u-popup 
+      v-model="dialogVisitable" 
+      mode="center" 
+      width="90%" 
+      height="80%"
+      border-radius="20"
+      @close="cancel"
+    >
+      <view class="popup-content">
+        <view class="popup-header">
+          <text class="popup-title">鏌ョ湅闄勪欢</text>
+          <u-icon 
+            name="close" 
+            size="24" 
+            color="#999" 
+            @click="cancel"
+          ></u-icon>
+        </view>
+        
+        <view class="upload-container">
+          <view class="form-container">
+            <view class="title">宸℃闄勪欢</view>
+            
+            <!-- 鍥剧墖鍒楄〃 -->
+            <view v-if="beforeProductionImgs.length > 0" class="media-section">
+              <view class="section-title">鍥剧墖</view>
+              <view class="image-grid">
+                <view 
+                  v-for="(item, index) in beforeProductionImgs" 
+                  :key="index"
+                  class="image-item"
+                  @click="previewImage(item, index)"
+                >
+                  <image 
+                    :src="item" 
+                    mode="aspectFill"
+                    class="image-preview"
+                  />
+                </view>
+              </view>
+            </view>
+            
+            <!-- 瑙嗛鍒楄〃 -->
+            <view v-if="beforeProductionVideos.length > 0" class="media-section">
+              <view class="section-title">瑙嗛</view>
+              <view class="video-grid">
+                <view
+                  v-for="(videoUrl, index) in beforeProductionVideos"
+                  :key="index"
+                  class="video-item"
+                  @click="previewVideo(videoUrl)"
+                >
+                  <view class="video-preview">
+                    <u-icon name="play-circle-fill" size="40" color="#fff"></u-icon>
+                  </view>
+                  <view class="video-tip">鐐瑰嚮鎾斁</view>
+                </view>
+              </view>
+            </view>
+            
+            <!-- 绌虹姸鎬� -->
+            <view v-if="beforeProductionImgs.length === 0 && beforeProductionVideos.length === 0" class="empty-state">
+              <u-empty 
+                mode="data" 
+                text="鏆傛棤闄勪欢"
+                :iconSize="60"
+              ></u-empty>
+            </view>
+          </view>
+        </view>
+      </view>
+    </u-popup>
+  </view>
+</template>
+
+<script setup>
+import { ref, onUnmounted } from 'vue'
+
+// 鎺у埗寮圭獥鏄剧ず
+const dialogVisitable = ref(false)
+// 鍥剧墖鏁扮粍
+const beforeProductionImgs = ref([])
+// 瑙嗛鏁扮粍
+const beforeProductionVideos = ref([])
+
+// 鎵撳紑寮圭獥骞跺姞杞芥暟鎹�
+const openDialog = async (row) => {
+  console.log('鎵撳紑闄勪欢鏌ョ湅寮圭獥锛屾暟鎹�:', row)
+  
+  // 澶勭悊鏁版嵁锛屽垎绂诲浘鐗囧拰瑙嗛
+  const { images: beforeImgs, videos: beforeVids } = processItems(row.storageBlobDTO || [])
+  
+  beforeProductionImgs.value = beforeImgs
+  beforeProductionVideos.value = beforeVids
+  dialogVisitable.value = true
+}
+
+// 棰勮鍥剧墖
+const previewImage = (url, index) => {
+  uni.previewImage({
+    urls: beforeProductionImgs.value,
+    current: index,
+    fail: (err) => {
+      console.error('鍥剧墖棰勮澶辫触:', err)
+      uni.showToast({
+        title: '鍥剧墖棰勮澶辫触',
+        icon: 'error'
+      })
+    }
+  })
+}
+
+// 棰勮瑙嗛
+const previewVideo = (url) => {
+  uni.previewVideo({
+    sources: [{
+      src: url
+    }],
+    fail: (err) => {
+      console.error('瑙嗛棰勮澶辫触:', err)
+      uni.showToast({
+        title: '瑙嗛棰勮澶辫触',
+        icon: 'error'
+      })
+    }
+  })
+}
+
+// 琛ㄥ崟鍏抽棴鏂规硶
+const cancel = () => {
+  dialogVisitable.value = false
+  // 閲嶇疆鏁版嵁
+  beforeProductionImgs.value = []
+  beforeProductionVideos.value = []
+}
+
+// 澶勭悊姣忎竴绫绘暟鎹細鍒嗙鍥剧墖鍜岃棰�
+function processItems(items) {
+  if (!items || !Array.isArray(items)) {
+    return { images: [], videos: [] }
+  }
+  
+  const images = []
+  const videos = []
+  
+  items.forEach(item => {
+    if (item.contentType?.startsWith('image/')) {
+      images.push(item.url)
+    } else if (item.contentType?.startsWith('video/')) {
+      videos.push(item.url)
+    }
+  })
+  
+  return { images, videos }
+}
+
+// 缁勪欢閿�姣佹椂鐨勬竻鐞�
+onUnmounted(() => {
+  // 鍏抽棴寮圭獥
+  dialogVisitable.value = false
+  // 娓呯悊鏁版嵁
+  beforeProductionImgs.value = []
+  beforeProductionVideos.value = []
+})
+
+// 鏆撮湶鏂规硶缁欑埗缁勪欢
+defineExpose({ openDialog })
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.popup-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+.upload-container {
+  flex: 1;
+  padding: 20px;
+  overflow-y: auto;
+}
+
+.form-container {
+  width: 100%;
+}
+
+.title {
+  font-size: 16px;
+  color: #1890ff;
+  line-height: 24px;
+  font-weight: 600;
+  padding-left: 12px;
+  position: relative;
+  margin: 0 0 20px 0;
+  
+  &::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 4px;
+    width: 4px;
+    height: 16px;
+    background-color: #1890ff;
+    border-radius: 2px;
+  }
+}
+
+.media-section {
+  margin-bottom: 30px;
+}
+
+.section-title {
+  font-size: 14px;
+  color: #666;
+  margin-bottom: 15px;
+  font-weight: 500;
+}
+
+.image-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.image-item {
+  width: 100px;
+  height: 100px;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.image-preview {
+  width: 100%;
+  height: 100%;
+}
+
+.video-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 15px;
+}
+
+.video-item {
+  width: 160px;
+  height: 90px;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.video-preview {
+  width: 100%;
+  height: 100%;
+  background-color: #333;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+}
+
+.video-tip {
+  position: absolute;
+  bottom: 5px;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 12px;
+  color: #fff;
+  background-color: rgba(0, 0, 0, 0.6);
+  padding: 2px 8px;
+  border-radius: 4px;
+}
+
+.empty-state {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+}
+</style>
diff --git a/src/components/imageUpload/viewQrCodeFilesSimple.vue b/src/components/imageUpload/viewQrCodeFilesSimple.vue
new file mode 100644
index 0000000..574a713
--- /dev/null
+++ b/src/components/imageUpload/viewQrCodeFilesSimple.vue
@@ -0,0 +1,288 @@
+<template>
+  <view>
+    <!-- 寮圭獥 -->
+    <u-popup 
+      v-model="dialogVisitable" 
+      mode="center" 
+      width="90%" 
+      height="80%"
+      border-radius="20"
+      @close="cancel"
+    >
+      <view class="popup-content">
+        <view class="popup-header">
+          <text class="popup-title">鏌ョ湅闄勪欢</text>
+          <u-icon 
+            name="close" 
+            size="24" 
+            color="#999" 
+            @click="cancel"
+          ></u-icon>
+        </view>
+        
+        <view class="upload-container">
+          <view class="form-container">
+            <view class="title">宸℃闄勪欢</view>
+            
+            <!-- 鍥剧墖鍒楄〃 -->
+            <view v-if="beforeProductionImgs.length > 0" class="media-section">
+              <view class="section-title">鍥剧墖</view>
+              <view class="image-grid">
+                <view 
+                  v-for="(item, index) in beforeProductionImgs" 
+                  :key="index"
+                  class="image-item"
+                  @click="previewImage(item, index)"
+                >
+                  <image 
+                    :src="item" 
+                    mode="aspectFill"
+                    class="image-preview"
+                  />
+                </view>
+              </view>
+            </view>
+            
+            <!-- 瑙嗛鍒楄〃 -->
+            <view v-if="beforeProductionVideos.length > 0" class="media-section">
+              <view class="section-title">瑙嗛</view>
+              <view class="video-grid">
+                <view
+                  v-for="(videoUrl, index) in beforeProductionVideos"
+                  :key="index"
+                  class="video-item"
+                  @click="previewVideo(videoUrl)"
+                >
+                  <view class="video-preview">
+                    <u-icon name="play-circle-fill" size="40" color="#fff"></u-icon>
+                  </view>
+                  <view class="video-tip">鐐瑰嚮鎾斁</view>
+                </view>
+              </view>
+            </view>
+            
+            <!-- 绌虹姸鎬� -->
+            <view v-if="beforeProductionImgs.length === 0 && beforeProductionVideos.length === 0" class="empty-state">
+              <u-empty 
+                mode="data" 
+                text="鏆傛棤闄勪欢"
+                :iconSize="60"
+              ></u-empty>
+            </view>
+          </view>
+        </view>
+      </view>
+    </u-popup>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// 鎺у埗寮圭獥鏄剧ず
+const dialogVisitable = ref(false)
+// 鍥剧墖鏁扮粍
+const beforeProductionImgs = ref([])
+// 瑙嗛鏁扮粍
+const beforeProductionVideos = ref([])
+
+// 鎵撳紑寮圭獥骞跺姞杞芥暟鎹�
+const openDialog = async (row) => {
+  console.log('鎵撳紑闄勪欢鏌ョ湅寮圭獥锛屾暟鎹�:', row)
+  
+  // 澶勭悊鏁版嵁锛屽垎绂诲浘鐗囧拰瑙嗛
+  const { images: beforeImgs, videos: beforeVids } = processItems(row.storageBlobDTO || [])
+  
+  beforeProductionImgs.value = beforeImgs
+  beforeProductionVideos.value = beforeVids
+  dialogVisitable.value = true
+}
+
+// 棰勮鍥剧墖
+const previewImage = (url, index) => {
+  uni.previewImage({
+    urls: beforeProductionImgs.value,
+    current: index,
+    fail: (err) => {
+      console.error('鍥剧墖棰勮澶辫触:', err)
+      uni.showToast({
+        title: '鍥剧墖棰勮澶辫触',
+        icon: 'error'
+      })
+    }
+  })
+}
+
+// 棰勮瑙嗛
+const previewVideo = (url) => {
+  uni.previewVideo({
+    sources: [{
+      src: url
+    }],
+    fail: (err) => {
+      console.error('瑙嗛棰勮澶辫触:', err)
+      uni.showToast({
+        title: '瑙嗛棰勮澶辫触',
+        icon: 'error'
+      })
+    }
+  })
+}
+
+// 琛ㄥ崟鍏抽棴鏂规硶
+const cancel = () => {
+  dialogVisitable.value = false
+  // 閲嶇疆鏁版嵁
+  beforeProductionImgs.value = []
+  beforeProductionVideos.value = []
+}
+
+// 澶勭悊姣忎竴绫绘暟鎹細鍒嗙鍥剧墖鍜岃棰�
+function processItems(items) {
+  if (!items || !Array.isArray(items)) {
+    return { images: [], videos: [] }
+  }
+  
+  const images = []
+  const videos = []
+  
+  items.forEach(item => {
+    if (item.contentType?.startsWith('image/')) {
+      images.push(item.url)
+    } else if (item.contentType?.startsWith('video/')) {
+      videos.push(item.url)
+    }
+  })
+  
+  return { images, videos }
+}
+
+// 鏆撮湶鏂规硶缁欑埗缁勪欢
+defineExpose({ openDialog })
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.popup-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+.upload-container {
+  flex: 1;
+  padding: 20px;
+  overflow-y: auto;
+}
+
+.form-container {
+  width: 100%;
+}
+
+.title {
+  font-size: 16px;
+  color: #1890ff;
+  line-height: 24px;
+  font-weight: 600;
+  padding-left: 12px;
+  position: relative;
+  margin: 0 0 20px 0;
+  
+  &::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 4px;
+    width: 4px;
+    height: 16px;
+    background-color: #1890ff;
+    border-radius: 2px;
+  }
+}
+
+.media-section {
+  margin-bottom: 30px;
+}
+
+.section-title {
+  font-size: 14px;
+  color: #666;
+  margin-bottom: 15px;
+  font-weight: 500;
+}
+
+.image-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.image-item {
+  width: 100px;
+  height: 100px;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.image-preview {
+  width: 100%;
+  height: 100%;
+}
+
+.video-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 15px;
+}
+
+.video-item {
+  width: 160px;
+  height: 90px;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.video-preview {
+  width: 100%;
+  height: 100%;
+  background-color: #333;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+}
+
+.video-tip {
+  position: absolute;
+  bottom: 5px;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 12px;
+  color: #fff;
+  background-color: rgba(0, 0, 0, 0.6);
+  padding: 2px 8px;
+  border-radius: 4px;
+}
+
+.empty-state {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+}
+</style>
diff --git a/src/config.js b/src/config.js
index d41d2bb..b7c35cd 100644
--- a/src/config.js
+++ b/src/config.js
@@ -3,6 +3,7 @@
   //  baseUrl: 'https://vue.ruoyi.vip/prod-api',
   // baseUrl: 'http://localhost/prod-api',
   baseUrl: 'http://114.132.189.42:9036',
+  // baseUrl: 'http://192.168.1.147:9036',
    //cloud鍚庡彴缃戝叧鍦板潃
   //  baseUrl: 'http://192.168.10.3:8080',
    // 搴旂敤淇℃伅
diff --git a/src/pages.json b/src/pages.json
index 3937f03..a2b3ca6 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -392,6 +392,13 @@
         "navigationBarTitleText": "宸℃涓婁紶",
         "navigationStyle": "custom"
       }
+    },
+    {
+      "path": "pages/equipmentManagement/faultAnalysis/index",
+      "style": {
+        "navigationBarTitleText": "鏁呴殰鍒嗘瀽杩芥函",
+        "navigationStyle": "custom"
+      }
     }
   ],
   "subPackages": [
diff --git a/src/pages/equipmentManagement/faultAnalysis/index.vue b/src/pages/equipmentManagement/faultAnalysis/index.vue
new file mode 100644
index 0000000..5bf8c6e
--- /dev/null
+++ b/src/pages/equipmentManagement/faultAnalysis/index.vue
@@ -0,0 +1,353 @@
+<template>
+  <view class="fault-analysis-page">
+    <!-- 椤甸潰澶撮儴 -->
+    <PageHeader title="鏁呴殰鍒嗘瀽杩芥函" @back="goBack" />
+    
+    <!-- 缁熻姒傝 -->
+    <view class="overview-section">
+      <view class="section-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">缁熻姒傝</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        
+        <view class="overview-content">
+          <view class="overview-item">
+            <view class="overview-number">{{ overviewData.totalFaults }}</view>
+            <view class="overview-label">鏁呴殰鎬绘暟</view>
+          </view>
+          <view class="overview-item">
+            <view class="overview-number">{{ overviewData.totalDowntime }}</view>
+            <view class="overview-label">鎬诲仠鏈烘椂闀�(h)</view>
+          </view>
+          <view class="overview-item">
+            <view class="overview-number">{{ overviewData.avgRepairTime }}</view>
+            <view class="overview-label">骞冲潎淇鏃堕棿(h)</view>
+          </view>
+          <view class="overview-item">
+            <view class="overview-number">{{ overviewData.faultRate }}%</view>
+            <view class="overview-label">鏁呴殰鐜�</view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鏁呴殰绫诲瀷缁熻 -->
+    <view class="stat-section">
+      <view class="section-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">鏁呴殰绫诲瀷缁熻</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        
+        <view class="item-details">
+          <view class="detail-row" v-for="(item, index) in faultTypeStats" :key="index">
+            <text class="detail-label">{{ item.name }}</text>
+            <text class="detail-value">{{ item.value }}娆�</text>
+            <text class="detail-value highlight">{{ item.percent }}%</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 鏍瑰洜鍒嗘瀽缁熻 -->
+    <view class="stat-section">
+      <view class="section-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="search" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">鏍瑰洜鍒嗘瀽缁熻</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        
+        <view class="item-details">
+          <view class="detail-row" v-for="(item, index) in rootCauseStats" :key="index">
+            <text class="detail-label">{{ item.name }}</text>
+            <text class="detail-value">{{ item.value }}娆�</text>
+            <text class="detail-value highlight">{{ item.percent }}%</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 璇︾粏鏁版嵁鍒楄〃 -->
+    <view class="table-section">
+      <view class="section-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="list" size="16" color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">璇︾粏鏁版嵁</text>
+          </view>
+        </view>
+        <up-divider></up-divider>
+        
+        <view class="fault-list">
+          <view v-for="(item, index) in tableData" :key="index" class="fault-item">
+            <view class="item-details">
+              <view class="detail-row">
+                <text class="detail-label">璁惧鍚嶇О</text>
+                <text class="detail-value">{{ item.equipmentName }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鏁呴殰绫诲瀷</text>
+                <view class="detail-value">
+                  <u-tag :type="getFaultTypeTagType(item.faultType)" size="small">
+                    {{ item.faultType }}
+                  </u-tag>
+                </view>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鏍瑰洜</text>
+                <text class="detail-value">{{ item.rootCause }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鍋滄満鏃堕暱</text>
+                <text class="detail-value highlight">{{ item.downtime }}h</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鐝粍</text>
+                <text class="detail-value">{{ item.team }}</text>
+              </view>
+              <view class="detail-row">
+                <text class="detail-label">鍙戠敓鏃堕棿</text>
+                <text class="detail-value">{{ item.occurTime }}</text>
+              </view>
+            </view>
+            <up-divider v-if="index < tableData.length - 1"></up-divider>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import PageHeader from '@/components/PageHeader.vue'
+
+// 缁熻姒傝鏁版嵁
+const overviewData = ref({
+  totalFaults: 156,
+  totalDowntime: 1248.5,
+  avgRepairTime: 8.0,
+  faultRate: 3.2
+})
+
+// 鏁呴殰绫诲瀷缁熻
+const faultTypeStats = ref([
+  { name: '鏈烘鏁呴殰', value: 45, percent: 28.8 },
+  { name: '鐢垫皵鏁呴殰', value: 32, percent: 20.5 },
+  { name: '娑插帇鏁呴殰', value: 28, percent: 17.9 },
+  { name: '姘斿姩鏁呴殰', value: 25, percent: 16.0 },
+  { name: '鍏朵粬鏁呴殰', value: 26, percent: 16.7 }
+])
+
+// 鏍瑰洜鍒嗘瀽缁熻
+const rootCauseStats = ref([
+  { name: '鎿嶄綔涓嶅綋', value: 35, percent: 22.4 },
+  { name: '璁惧鑰佸寲', value: 28, percent: 17.9 },
+  { name: '缁存姢涓嶈冻', value: 22, percent: 14.1 },
+  { name: '鐜鍥犵礌', value: 18, percent: 11.5 },
+  { name: '璁捐缂洪櫡', value: 15, percent: 9.6 },
+  { name: '鍏朵粬鍘熷洜', value: 38, percent: 24.4 }
+])
+
+// 琛ㄦ牸鏁版嵁
+const tableData = ref([
+  {
+    equipmentName: '鐢熶骇绾緼-01',
+    faultType: '鏈烘鏁呴殰',
+    rootCause: '杞存壙纾ㄦ崯',
+    downtime: 12.5,
+    team: '鐢熶骇涓�鐝�',
+    occurTime: '2024-01-15 14:30'
+  },
+  {
+    equipmentName: '妫�娴嬭澶嘊-02',
+    faultType: '鐢垫皵鏁呴殰',
+    rootCause: '鐢佃矾鐭矾',
+    downtime: 8.0,
+    team: '鐢熶骇浜岀彮',
+    occurTime: '2024-01-16 09:15'
+  },
+  {
+    equipmentName: '杈呭姪璁惧C-03',
+    faultType: '娑插帇鏁呴殰',
+    rootCause: '娌圭娉勬紡',
+    downtime: 6.5,
+    team: '缁翠慨鐝�',
+    occurTime: '2024-01-17 16:45'
+  },
+  {
+    equipmentName: '鐢熶骇绾緼-02',
+    faultType: '姘斿姩鏁呴殰',
+    rootCause: '姘斿帇涓嶈冻',
+    downtime: 4.0,
+    team: '鐢熶骇涓�鐝�',
+    occurTime: '2024-01-18 11:20'
+  },
+  {
+    equipmentName: '妫�娴嬭澶嘊-01',
+    faultType: '鏈烘鏁呴殰',
+    rootCause: '浼犲姩甯︽柇瑁�',
+    downtime: 15.0,
+    team: '鐢熶骇浜岀彮',
+    occurTime: '2024-01-19 08:30'
+  }
+])
+
+// 鏂规硶
+const goBack = () => {
+  uni.navigateBack()
+}
+
+const getFaultTypeTagType = (faultType) => {
+  const typeMap = {
+    '鏈烘鏁呴殰': 'error',
+    '鐢垫皵鏁呴殰': 'warning',
+    '娑插帇鏁呴殰': 'info',
+    '姘斿姩鏁呴殰': 'success',
+    '鍏朵粬鏁呴殰': 'primary'
+  }
+  return typeMap[faultType] || 'primary'
+}
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  console.log('鏁呴殰鍒嗘瀽椤甸潰宸插姞杞�')
+})
+</script>
+
+<style scoped>
+.fault-analysis-page {
+  background-color: #f5f5f5;
+  min-height: 100vh;
+}
+
+.overview-section,
+.stat-section,
+.table-section {
+  margin: 15px;
+}
+
+.section-item {
+  background: #ffffff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+}
+
+.item-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 15px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
+
+.item-left {
+  display: flex;
+  align-items: center;
+}
+
+.document-icon {
+  width: 28px;
+  height: 28px;
+  background: rgba(255, 255, 255, 0.2);
+  border-radius: 6px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 10px;
+}
+
+.item-id {
+  color: #ffffff;
+  font-size: 16px;
+  font-weight: 600;
+}
+
+.overview-content {
+  display: flex;
+  justify-content: space-around;
+  padding: 20px 15px;
+}
+
+.overview-item {
+  text-align: center;
+  flex: 1;
+}
+
+.overview-number {
+  font-size: 24px;
+  font-weight: bold;
+  color: #007aff;
+  margin-bottom: 5px;
+}
+
+.overview-label {
+  font-size: 12px;
+  color: #666;
+}
+
+.item-details {
+  padding: 15px;
+}
+
+.detail-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-row:last-child {
+  border-bottom: none;
+}
+
+.detail-label {
+  font-size: 14px;
+  color: #666;
+  min-width: 80px;
+}
+
+.detail-value {
+  font-size: 14px;
+  color: #333;
+  font-weight: 500;
+  text-align: right;
+}
+
+.detail-value.highlight {
+  color: #007aff;
+  font-weight: bold;
+}
+
+.fault-list {
+  padding: 15px;
+}
+
+.fault-item {
+  margin-bottom: 15px;
+}
+
+.fault-item:last-child {
+  margin-bottom: 0;
+}
+</style>
diff --git a/src/pages/equipmentManagement/repair/add.vue b/src/pages/equipmentManagement/repair/add.vue
index 8717814..0940052 100644
--- a/src/pages/equipmentManagement/repair/add.vue
+++ b/src/pages/equipmentManagement/repair/add.vue
@@ -356,7 +356,7 @@
 		// 缂栬緫妯″紡锛岃幏鍙栬鎯�
 		loadForm(id);
 		// 鍙�夛細鑾峰彇鍚庢竻闄ゅ瓨鍌ㄧ殑id锛岄伩鍏嶅奖鍝嶅悗缁搷浣�
-		// uni.removeStorageSync('repairId');
+		uni.removeStorageSync('repairId');
 	} else {
 		// 鏂板妯″紡
 		loadForm();
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 2062b64..1749b98 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -268,21 +268,26 @@
 		label: '璁惧淇濆吇',
 	},
 	{
-		icon: '/static/images/icon/shebeixunjian@2x.png',
+		icon: '/static/images/icon/xunjianshangchuan@2x.png',
 		label: '宸℃涓婁紶',
 	},
 	{
-		icon: 'flash',
+		icon: '/static/images/icon/guzhangfenxi@2x.png',
+		label: '鍒嗘瀽杩芥函',
+		bgColor: '#ff9800'
+	},
+	{
+		icon: '/static/images/icon/zhinengpaidan@2x.png',
 		label: '鏅鸿兘娲惧崟',
 		bgColor: '#ff6b35'
 	},
 	{
-		icon: 'file-text',
+		icon: '/static/images/icon/zuoyezhidao@2x.png',
 		label: '浣滀笟鎸囧',
 		bgColor: '#4caf50'
 	},
 	{
-		icon: 'checkmark-circle',
+		icon: '/static/images/icon/jieguoyanzheng@2x.png',
 		label: '缁撴灉楠岃瘉',
 		bgColor: '#9c27b0'
 	}
@@ -382,6 +387,11 @@
 				url: '/pages/inspectionUpload/index'
 			});
 			break;
+		case '鍒嗘瀽杩芥函':
+			uni.navigateTo({
+				url: '/pages/equipmentManagement/faultAnalysis/index'
+			});
+			break;
 		case '鏅鸿兘娲惧崟':
 			uni.navigateTo({
 				url: '/pages/equipmentManagement/smartDispatch/index'
diff --git a/src/pages/inspectionUpload/components/qrCodeFormDia.vue b/src/pages/inspectionUpload/components/qrCodeFormDia.vue
index 3dc83ef..bcf30ef 100644
--- a/src/pages/inspectionUpload/components/qrCodeFormDia.vue
+++ b/src/pages/inspectionUpload/components/qrCodeFormDia.vue
@@ -42,36 +42,15 @@
           
           <u-form-item label="闄勪欢" prop="storageBlobDTO" labelWidth="80">
             <view class="upload-container">
-              <u-upload
-                :fileList="form.storageBlobDTO"
-                @afterRead="afterRead"
-                @delete="deleteFile"
-                name="files"
-                multiple
-                :maxCount="10"
-                :maxSize="50 * 1024 * 1024"
-                accept="image/*,video/*"
-                :previewFullImage="true"
-                :camera="true"
-                :gallery="true"
-              ></u-upload>
-              <view class="upload-actions">
-                <u-button 
-                  type="primary" 
-                  size="small"
-                  @click="chooseImage"
-                  :customStyle="{ marginRight: '10px' }"
-                >
-                  鎷嶇収
-                </u-button>
-                <u-button 
-                  type="success" 
-                  size="small"
-                  @click="chooseVideo"
-                >
-                  褰曞儚
-                </u-button>
-              </view>
+              <ImageUpload
+                v-model="form.storageBlobDTO"
+                :limit="10"
+                :fileSize="50"
+                :fileType="['jpg', 'jpeg', 'png', 'mp4', 'mov']"
+                :maxVideoDuration="60"
+                :statusType="0"
+                @update:modelValue="handleStorageBlobUpdate"
+              />
             </view>
           </u-form-item>
           
@@ -102,9 +81,10 @@
 </template>
 
 <script setup>
-import { reactive, ref, onMounted, nextTick } from 'vue'
+import { reactive, ref, onMounted, onUnmounted, nextTick } from 'vue'
 import { addOrEditQrCodeRecord } from '@/api/inspectionUpload/index.js'
 import useUserStore from '@/store/modules/user.ts'
+import ImageUpload from '@/components/imageUpload/index.vue'
 
 const emit = defineEmits(['closeDia'])
 
@@ -113,6 +93,9 @@
 const userStore = useUserStore()
 const userInfo = ref({})
 const locationLoading = ref(false)
+
+// 璇锋眰鍙栨秷鏍囧織
+let isRequestCancelled = false
 
 // 鑾峰彇褰撳墠鏃堕棿
 function getCurrentDateTime() {
@@ -149,125 +132,50 @@
 onMounted(async () => {
   try {
     const res = await userStore.getInfo()
-    userInfo.value = res.user
-    form.scannerName = userInfo.value.nickName
-    form.scannerId = userInfo.value.userId
-    form.scanTime = getCurrentDateTime()
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+    if (!isRequestCancelled && userInfo.value !== undefined) {
+      userInfo.value = res.user
+      form.scannerName = userInfo.value.nickName
+      form.scannerId = userInfo.value.userId
+      form.scanTime = getCurrentDateTime()
+    }
   } catch (error) {
     console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
   }
 })
 
-// 鏂囦欢涓婁紶澶勭悊
-const afterRead = (event) => {
-  const { file } = event
-  console.log('鏂囦欢閫夋嫨:', file)
-  
-  // 鐩存帴娣诲姞鍒版枃浠跺垪琛紝涓嶄笂浼犲埌鏈嶅姟鍣�
-  const fileItem = {
-    url: file.url,
-    name: file.name || `鏂囦欢_${Date.now()}`,
-    status: 'success',
-    size: file.size || 0,
-    type: file.type || 'image/jpeg'
-  }
-  
-  form.storageBlobDTO.push(fileItem)
-  
-  uni.showToast({
-    title: '鏂囦欢娣诲姞鎴愬姛',
-    icon: 'success'
-  })
-}
-
-// 鎷嶇収
-const chooseImage = () => {
-  uni.chooseImage({
-    count: 1,
-    sizeType: ['original', 'compressed'],
-    sourceType: ['camera'],
-    success: (res) => {
-      console.log('鎷嶇収鎴愬姛:', res)
-      const tempFilePath = res.tempFilePaths[0]
-      
-      const fileItem = {
-        url: tempFilePath,
-        name: `鐓х墖_${Date.now()}.jpg`,
-        status: 'success',
-        type: 'image/jpeg'
-      }
-      
-      form.storageBlobDTO.push(fileItem)
-      
-      uni.showToast({
-        title: '鎷嶇収鎴愬姛',
-        icon: 'success'
-      })
-    },
-    fail: (err) => {
-      console.error('鎷嶇収澶辫触:', err)
-      uni.showToast({
-        title: '鎷嶇収澶辫触',
-        icon: 'error'
-      })
-    }
-  })
-}
-
-// 褰曞儚
-const chooseVideo = () => {
-  uni.chooseVideo({
-    sourceType: ['camera'],
-    maxDuration: 60, // 鏈�澶�60绉�
-    camera: 'back',
-    success: (res) => {
-      console.log('褰曞儚鎴愬姛:', res)
-      const tempFilePath = res.tempFilePath
-      
-      const fileItem = {
-        url: tempFilePath,
-        name: `瑙嗛_${Date.now()}.mp4`,
-        status: 'success',
-        type: 'video/mp4',
-        duration: res.duration,
-        size: res.size
-      }
-      
-      form.storageBlobDTO.push(fileItem)
-      
-      uni.showToast({
-        title: '褰曞儚鎴愬姛',
-        icon: 'success'
-      })
-    },
-    fail: (err) => {
-      console.error('褰曞儚澶辫触:', err)
-      uni.showToast({
-        title: '褰曞儚澶辫触',
-        icon: 'error'
-      })
-    }
-  })
-}
-
-// 鍒犻櫎鏂囦欢
-const deleteFile = (event) => {
-  const { index } = event
-  form.storageBlobDTO.splice(index, 1)
+// 澶勭悊storageBlobDTO鏁版嵁鏇存柊
+const handleStorageBlobUpdate = (value) => {
+  form.storageBlobDTO = value || []
 }
 
 // 鑾峰彇褰撳墠浣嶇疆
 const getCurrentLocation = () => {
+  // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+  if (isRequestCancelled) return
+  
   locationLoading.value = true
   uni.showLoading({ title: '鑾峰彇浣嶇疆涓�...' })
   
   uni.getLocation({
     type: 'gcj02',
     success: (res) => {
+      // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+      if (isRequestCancelled) {
+        uni.hideLoading()
+        return
+      }
+      
       // 浣跨敤閫嗗湴鐞嗙紪鐮佽幏鍙栧湴鍧�淇℃伅
       uni.request({
         url: `https://restapi.amap.com/v3/geocode/regeo?key=c120a5dc69a9f61839f7763e6057005f&location=${res.longitude},${res.latitude}&radius=1000&extensions=all`,
         success: (geoRes) => {
+          // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+          if (isRequestCancelled) {
+            uni.hideLoading()
+            return
+          }
+          
           uni.hideLoading()
           locationLoading.value = false
           
@@ -303,6 +211,12 @@
           }
         },
         fail: (err) => {
+          // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+          if (isRequestCancelled) {
+            uni.hideLoading()
+            return
+          }
+          
           uni.hideLoading()
           locationLoading.value = false
           console.error('閫嗗湴鐞嗙紪鐮佸け璐�:', err)
@@ -318,6 +232,12 @@
       })
     },
     fail: (err) => {
+      // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+      if (isRequestCancelled) {
+        uni.hideLoading()
+        return
+      }
+      
       uni.hideLoading()
       locationLoading.value = false
       uni.showToast({
@@ -335,15 +255,11 @@
 // 鎵撳紑寮规
 const openDialog = async (row) => {
   console.log('寮规鎺ユ敹鍒扮殑鏁版嵁:', row)
-  console.log('寮规鎵撳紑鍓嶇姸鎬�:', dialogVisitable.value)
-  
   dialogVisitable.value = true
   form.deviceName = row.deviceName || ''
   form.location = row.location || ''
-  form.qrCodeId = row.qrCodeId || row.id || ''
+  form.qrCodeId = row.qrCodeId
   form.storageBlobDTO = []
-  
-  console.log('寮规鎵撳紑鍚庣姸鎬�:', dialogVisitable.value)
   console.log('寮规琛ㄥ崟鏁版嵁:', form)
   
   // 寮哄埗鏇存柊瑙嗗浘
@@ -354,6 +270,9 @@
 // 鎻愪氦琛ㄥ崟
 const submitForm = async () => {
   try {
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+    if (isRequestCancelled) return
+    
     console.log('寮�濮嬫彁浜よ〃鍗曪紝褰撳墠琛ㄥ崟鏁版嵁:', form)
     
     // 琛ㄥ崟楠岃瘉
@@ -389,15 +308,27 @@
       scannerName: form.scannerName,
       scannerId: form.scannerId,
       scanTime: form.scanTime,
-      storageBlobDTO: form.storageBlobDTO,
+      storageBlobDTO: form.storageBlobDTO.map(file => ({
+        id: file.id, // 娣诲姞id瀛楁
+        url: file.url,
+        bucketFilename: file.bucketFilename || file.name,
+        downloadUrl: file.downloadUrl || file.url,
+        type: 0,
+        size: file.size,
+        createTime: file.createTime || new Date().getTime()
+      })),
       qrCode: {
-        id: form.qrCodeId || form.qrCode.id
+        id: form.qrCodeId
       }
     }
     
     console.log('鍑嗗鎻愪氦鐨勬暟鎹�:', submitData)
     
     const response = await addOrEditQrCodeRecord(submitData)
+    
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+    if (isRequestCancelled) return
+    
     console.log('鎻愪氦鍝嶅簲:', response)
     
     uni.showToast({
@@ -407,6 +338,9 @@
     
     cancel()
   } catch (error) {
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+    if (isRequestCancelled) return
+    
     console.error('鎻愪氦澶辫触:', error)
     
     // 鏄剧ず鏇磋缁嗙殑閿欒淇℃伅
@@ -430,6 +364,25 @@
   dialogVisitable.value = false
   emit('closeDia')
 }
+
+// 缁勪欢閿�姣佹椂鐨勬竻鐞�
+onUnmounted(() => {
+  // 璁剧疆鍙栨秷鏍囧織锛岄樆姝㈠悗缁殑寮傛鎿嶄綔
+  isRequestCancelled = true
+  
+  // 娓呯悊鐘舵��
+  if (locationLoading.value) {
+    locationLoading.value = false
+  }
+  
+  // 鍏抽棴寮圭獥
+  if (dialogVisitable.value) {
+    dialogVisitable.value = false
+  }
+  
+  // 闅愯棌鍙兘鏄剧ず鐨勫姞杞芥彁绀�
+  uni.hideLoading()
+})
 
 defineExpose({ openDialog })
 </script>
@@ -491,12 +444,5 @@
 
 .upload-container {
   width: 100%;
-}
-
-.upload-actions {
-  display: flex;
-  justify-content: flex-start;
-  margin-top: 10px;
-  gap: 10px;
 }
 </style>
diff --git a/src/pages/inspectionUpload/index.vue b/src/pages/inspectionUpload/index.vue
index aed4e6e..3b9e0d7 100644
--- a/src/pages/inspectionUpload/index.vue
+++ b/src/pages/inspectionUpload/index.vue
@@ -1,74 +1,14 @@
 <template>
   <view class="inspection-upload-page">
     <!-- 椤甸潰澶撮儴 -->
-    <PageHeader title="宸℃涓婁紶" />
-    
-    <!-- 鏍囩椤� -->
-    <view class="tabs-container">
-      <view class="custom-tabs">
-        <view 
-          v-for="(tab, index) in tabs" 
-          :key="index"
-          class="tab-item"
-          :class="{ 'tab-active': currentTabIndex === index }"
-          @click="handleTabChange(index)"
-        >
-          {{ tab.name }}
-        </view>
-        <view class="tab-line" :style="{ left: currentTabIndex * 50 + '%' }"></view>
-      </view>
-    </view>
-    
-    <!-- 鎵爜妯″潡 -->
-    <view v-if="activeTab === 'qrCode'" class="scan-section">
-      <view class="scan-controls">
-        <u-button 
-          :type="isScanning ? 'error' : 'primary'"
-          :loading="scanLoading"
-          @click="toggleScan"
-        >
-          {{ scanButtonText }}
-        </u-button>
-      </view>
-      
-      <!-- 鎵爜鍖哄煙 -->
-      <view v-show="isScanning" class="qr-scan-container">
-        <camera 
-          class="qr-camera"
-          device-position="back"
-          flash="off"
-          @scancode="handleScanCode"
-          @error="handleCameraError"
-        ></camera>
-        <view class="scan-overlay">
-          <view class="scan-frame"></view>
-          <view class="scan-tip">璇峰皢浜岀淮鐮佹斁鍏ユ鍐�</view>
-        </view>
-      </view>
-      
-      <!-- 鐘舵�佹彁绀� -->
-      <view class="status-info">
-        <u-alert 
-          v-if="cameraError"
-          :title="cameraError"
-          type="error"
-          :showIcon="true"
-          :closable="true"
-          @close="cameraError = ''"
-        ></u-alert>
-        <view v-if="isScanning" class="scanning-text">
-          <u-loading-icon mode="circle" color="#1890ff" size="20"></u-loading-icon>
-          <text class="scanning-label">姝e湪鎵弿浜岀淮鐮�...</text>
-        </view>
-      </view>
-    </view>
+    <PageHeader title="宸℃涓婁紶"  @back="goBack"/>
     
     <!-- 鏁版嵁鍒楄〃 -->
     <view class="table-section">
       <!-- 鐢熶骇宸℃鍒楄〃 -->
-      <view v-if="activeTab === 'task'" class="task-list">
+      <view class="task-list">
         <view 
-          v-for="(item, index) in tableData" 
+          v-for="(item, index) in taskTableData" 
           :key="index"
           class="task-item"
           @click="handleAdd(item)"
@@ -91,147 +31,127 @@
               >
                 涓婁紶
               </u-button>
-            </view>
-          </view>
-          <view class="task-details">
-            <view class="detail-item">
-              <text class="detail-label">澶囨敞锛�</text>
-              <text class="detail-value">{{ item.remarks || '鏃�' }}</text>
-            </view>
-            <view class="detail-item">
-              <text class="detail-label">鎵ц浜猴細</text>
-              <text class="detail-value">{{ item.inspector }}</text>
-            </view>
-          </view>
-        </view>
-      </view>
-      
-      <!-- 鐜板満宸℃鍒楄〃 -->
-      <view v-if="activeTab === 'qrCode'" class="qr-list">
-        <view 
-          v-for="(item, index) in tableData" 
-          :key="index"
-          class="qr-item"
-          @click="viewFile(item)"
-        >
-          <view class="qr-header">
-            <view class="qr-info">
-              <text class="device-name">{{ item.qrCode?.deviceName }}</text>
-              <text class="device-location">{{ item.qrCode?.location }}</text>
-            </view>
-            <view class="qr-actions">
               <u-button 
-                type="primary" 
+                type="info" 
                 size="small"
-                @click.stop="viewFile(item)"
+                @click.stop="startScanForTask(item)"
                 :customStyle="{
                   borderRadius: '15px',
                   height: '30px',
                   fontSize: '12px'
                 }"
               >
-                鏌ョ湅闄勪欢
+                鎵爜
               </u-button>
             </view>
           </view>
-          <view class="qr-details">
+          <view class="task-details">
             <view class="detail-item">
-              <text class="detail-label">宸℃浜猴細</text>
-              <text class="detail-value">{{ item.scanner }}</text>
+              <text class="detail-label">澶囨敞</text>
+              <text class="detail-value">{{ item.remarks || '鏃�' }}</text>
             </view>
             <view class="detail-item">
-              <text class="detail-label">宸℃鏃堕棿锛�</text>
-              <text class="detail-value">{{ item.scanTime }}</text>
+              <text class="detail-label">鎵ц浜�</text>
+              <text class="detail-value">{{ item.inspector }}</text>
             </view>
           </view>
         </view>
       </view>
       
       <!-- 绌虹姸鎬� -->
-      <view v-if="tableData.length === 0 && !tableLoading" class="empty-state">
-        <u-empty 
-          mode="data" 
-          text="鏆傛棤鏁版嵁"
-          :iconSize="80"
-        ></u-empty>
-      </view>
-      
-      <!-- 鍔犺浇鐘舵�� -->
-      <view v-if="tableLoading" class="loading-state">
-        <u-loading-icon mode="circle" color="#1890ff" size="40"></u-loading-icon>
-        <text class="loading-text">鍔犺浇涓�...</text>
+      <view v-if="taskTableData.length === 0" class="no-data">
+        <text>鏆傛棤鏁版嵁</text>
       </view>
     </view>
     
-    <!-- 鍒嗛〉 -->
-    <view v-if="total > 0" class="pagination-container">
-      <u-pagination 
-        :total="total"
-        :current="pageNum"
-        :pageSize="pageSize"
-        @change="handlePageChange"
-        :showTotal="true"
-        :showSizer="false"
-        :showJumper="false"
-      ></u-pagination>
+    <!-- 鎵爜鍖哄煙 - 鍏ㄥ眬寮圭獥 -->
+    <view v-if="isScanning" class="qr-scan-overlay">
+      <view class="qr-scan-container">
+        <view class="scan-header">
+          <text class="scan-title">鎵弿浜岀淮鐮�</text>
+          <u-button 
+            type="error" 
+            size="small"
+            @click.stop="stopScan"
+            :customStyle="{
+              borderRadius: '15px',
+              height: '30px',
+              fontSize: '12px'
+            }"
+          >
+            鍏抽棴
+          </u-button>
+        </view>
+        <camera 
+          class="qr-camera"
+          device-position="back"
+          flash="off"
+          @scancode="handleScanCode"
+          @error="handleCameraError"
+        ></camera>
+        <view class="scan-frame-wrapper">
+          <view class="scan-frame"></view>
+          <view class="scan-tip">璇峰皢浜岀淮鐮佹斁鍏ユ鍐�</view>
+        </view>
+        <u-alert 
+          v-if="cameraError"
+          :title="cameraError"
+          type="error"
+          :showIcon="true"
+          :closable="true"
+          @close="cameraError = ''"
+          :customStyle="{
+            margin: '10px 0'
+          }"
+        ></u-alert>
+      </view>
     </view>
     
     <!-- 寮圭獥缁勪欢 -->
     <form-dia ref="formDia" @closeDia="handleQuery"></form-dia>
-    <qr-code-form-dia ref="qrCodeFormDia" @closeDia="handleQuery"></qr-code-form-dia>
   </view>
 </template>
 
 <script setup>
-import { onMounted, ref, reactive, computed, nextTick } from 'vue'
+import { onMounted, onUnmounted, ref, nextTick } from 'vue'
 import { onShow } from '@dcloudio/uni-app'
 import PageHeader from '@/components/PageHeader.vue'
 import FormDia from './components/formDia.vue'
-import QrCodeFormDia from './components/qrCodeFormDia.vue'
-import { qrCodeScanRecordList } from '@/api/inspectionUpload/index.js'
-import { getInspectionTaskList } from '@/api/equipmentManagement/inspection.js'
+import { getLedgerById } from '@/api/equipmentManagement/ledger.js'
 import {inspectionTaskList} from "@/api/inspectionManagement";
-// import ViewQrCodeFiles from '@/pages/inspectionManagement/components/viewQrCodeFiles.vue'
 
 // 缁勪欢寮曠敤
 const formDia = ref()
-const qrCodeFormDia = ref()
 
-// 褰撳墠鏍囩
-const activeTab = ref('task')
-
-const tabName = ref('task')
-const currentTabIndex = ref(0)
-
-// 鏍囩椤垫暟鎹�
-const tabs = reactive([
-  { name: '鐢熶骇宸℃' },
-  { name: '鐜板満宸℃' }
-])
+// 鍔犺浇鎻愮ず鏂规硶
+const showLoadingToast = (message) => {
+  uni.showLoading({
+    title: message,
+    mask: true
+  })
+}
+const closeToast = () => {
+  uni.hideLoading()
+}
 
 // 琛ㄦ牸鏁版嵁
-const tableData = ref([])
-const tableLoading = ref(false)
-const total = ref(0)
-const pageNum = ref(1)
-const pageSize = ref(10)
+const taskTableData = ref([]) // 鐢熶骇宸℃鏁版嵁
+
+// 褰撳墠鎵弿鐨勪换鍔�
+const currentScanningTask = ref(null)
+
+// 璇锋眰鍙栨秷鏍囧織锛岀敤浜庡彇娑堟鍦ㄨ繘琛岀殑璇锋眰
+let isRequestCancelled = false
 
 // 鎵爜鐩稿叧鐘舵��
 const isScanning = ref(false)
-const scanLoading = ref(false)
 const cameraError = ref('')
-
-// 璁$畻灞炴��
-const scanButtonText = computed(() => {
-  if (scanLoading.value) return '姝e湪鍒濆鍖�...'
-  return isScanning.value ? '鍋滄鎵爜' : '寮�濮嬫壂鐮�'
-})
 
 // 鐢熷懡鍛ㄦ湡
 onMounted(() => {
   // 寤惰繜鍒濆鍖栵紝纭繚DOM宸叉覆鏌�
   nextTick(() => {
-    handleTabClick({ props: { name: 'task' } })
+    getList()
   })
 })
 
@@ -240,84 +160,112 @@
   getList()
 })
 
-// 鏍囩椤靛垏鎹�
-const handleTabChange = (index) => {
-  currentTabIndex.value = index
-  const tabNames = ['task', 'qrCode']
-  activeTab.value = tabNames[index]
-  tabName.value = tabNames[index]
-  tableData.value = []
-  pageNum.value = 1
-  getList()
-}
+// 缁勪欢閿�姣佹椂鐨勬竻鐞�
+onUnmounted(() => {
+  // 璁剧疆鍙栨秷鏍囧織锛岄樆姝㈠悗缁殑寮傛鎿嶄綔
+  isRequestCancelled = true
+  
+  // 鍋滄鎵爜
+  if (isScanning.value) {
+    isScanning.value = false
+  }
+})
 
-// 鏍囩椤电偣鍑伙紙鍏煎鏃ф柟娉曪級
-const handleTabClick = (tab) => {
-  tabName.value = tab.props.name
-  activeTab.value = tab.props.name
-  tableData.value = []
-  getList()
+// 杩斿洖涓婁竴椤�
+const goBack = () => {
+  uni.navigateBack()
 }
 
 // 鏌ヨ鏁版嵁
 const handleQuery = () => {
-  pageNum.value = 1
-  pageSize.value = 10
   getList()
 }
 
 // 鑾峰彇鍒楄〃鏁版嵁
 const getList = () => {
-  tableLoading.value = true
-  if (tabName.value === "task") {
-    inspectionTaskList({size: pageSize.value, current: pageNum.value}).then(res => {
-      tableLoading.value = false;
-      tableData.value = res.data.records;
-      total.value = res.data.total;
-    })
-  } else {
-    qrCodeScanRecordList({size: pageSize.value, current: pageNum.value}).then(res => {
-      tableLoading.value = false;
-      tableData.value = res.data.records;
-      total.value = res.data.total;
-    })
-  }
+  // 鏄剧ず鍔犺浇鎻愮ず
+  showLoadingToast('鍔犺浇涓�...')
+  
+  // 璁剧疆鍙栨秷鏍囧織
+  isRequestCancelled = false
+  
+  inspectionTaskList({}).then(res => {
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪涓旇姹傛湭琚彇娑�
+    if (!isRequestCancelled) {
+      console.log('鐢熶骇宸℃API杩斿洖鏁版嵁:', res);
+      
+      // 澶勭悊涓嶅悓鐨勬暟鎹粨鏋�
+      let records = [];
+      if (res && res.data) {
+        // 灏濊瘯澶氱鍙兘鐨勬暟鎹粨鏋�
+        if (Array.isArray(res.data.records)) {
+          records = res.data.records;
+        } else if (Array.isArray(res.data.rows)) {
+          records = res.data.rows;
+        } else if (Array.isArray(res.data)) {
+          records = res.data;
+        } else if (Array.isArray(res.data.list)) {
+          records = res.data.list;
+        }
+      }
+      
+      if (records.length > 0) {
+        taskTableData.value = records;
+        console.log('鐢熶骇宸℃鏁版嵁璁剧疆鎴愬姛锛岃褰曟暟:', records.length);
+      } else {
+        console.warn('鐢熶骇宸℃鏁版嵁涓虹┖鎴栨牸寮忎笉姝g‘:', res);
+        taskTableData.value = [];
+        uni.showToast({
+          title: '鏆傛棤宸℃浠诲姟鏁版嵁',
+          icon: 'none'
+        });
+      }
+    }
+    // 鍏抽棴鍔犺浇鎻愮ず
+    closeToast()
+  }).catch(err => {
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪涓旇姹傛湭琚彇娑�
+    if (!isRequestCancelled) {
+      console.error('鑾峰彇鐢熶骇宸℃鏁版嵁澶辫触:', err);
+      taskTableData.value = [];
+      // 娣诲姞閿欒鎻愮ず
+      uni.showToast({
+        title: '鑾峰彇鏁版嵁澶辫触',
+        icon: 'error'
+      })
+    }
+    // 鍏抽棴鍔犺浇鎻愮ず
+    closeToast()
+  })
 }
 
-// 鍒嗛〉鍙樺寲
-const handlePageChange = (page) => {
-  pageNum.value = page
-  getList()
-}
 
 // 涓婁紶
 const handleAdd = (row) => {
   nextTick(() => {
-    formDia.value?.openDialog(row)
+    // 妫�鏌ョ粍浠舵槸鍚﹁繕瀛樺湪
+    if (formDia.value && formDia.value.openDialog) {
+      formDia.value.openDialog(row)
+    } else {
+      console.error('涓婁紶缁勪欢寮曠敤涓嶅瓨鍦�')
+      uni.showToast({
+        title: '缁勪欢鏈噯澶囧ソ',
+        icon: 'error'
+      })
+    }
   })
 }
 
-// 鏌ョ湅闄勪欢
-const viewFile = (row) => {
-  console.log('鏌ョ湅闄勪欢:', row)
-  uni.showToast({
-    title: '鏌ョ湅闄勪欢鍔熻兘寮�鍙戜腑',
-    icon: 'none'
-  })
-}
-
-// 鎵爜鐩稿叧鏂规硶
-const toggleScan = async () => {
-  if (isScanning.value) {
-    await stopScan()
-  } else {
-    await startScan()
-  }
-}
-
-const startScan = async () => {
+// 涓烘寚瀹氫换鍔″紑濮嬫壂鐮�
+const startScanForTask = async (task) => {
   try {
-    scanLoading.value = true
+    // 璁板綍褰撳墠鎵弿鐨勪换鍔�
+    currentScanningTask.value = task
+    console.log('涓轰换鍔″紑濮嬫壂鐮�:', task.taskName)
+    
+    // 鏄剧ず鎵弿鐣岄潰
+    isScanning.value = true
+    
     // 浣跨敤uniapp鐨勬壂鐮丄PI
     uni.scanCode({
       success: (res) => {
@@ -330,29 +278,37 @@
           title: '鎵爜澶辫触',
           icon: 'error'
         })
+        // 鍏抽棴鎵弿鐣岄潰
+        isScanning.value = false
       },
       complete: () => {
-        scanLoading.value = false
+        // 鎵爜瀹屾垚鍚庡叧闂壂鎻忕晫闈�
+        setTimeout(() => {
+          isScanning.value = false
+        }, 1000)
       }
     })
   } catch (e) {
     console.error('鍚姩鎵爜澶辫触:', e)
-    scanLoading.value = false
     uni.showToast({
       title: '鍚姩鎵爜澶辫触',
       icon: 'error'
     })
+    isScanning.value = false
   }
 }
 
-const stopScan = async () => {
+// 鍋滄鎵爜
+const stopScan = () => {
   isScanning.value = false
+  currentScanningTask.value = null
 }
 
 // 鎵爜鎴愬姛澶勭悊
 const handleScanSuccess = async (result) => {
   try {
     console.log('澶勭悊鎵爜缁撴灉:', result)
+    console.log('褰撳墠鍏宠仈浠诲姟:', currentScanningTask.value?.taskName)
     
     uni.showToast({
       title: '璇嗗埆鎴愬姛',
@@ -361,17 +317,51 @@
     
     // 瑙f瀽浜岀淮鐮佹暟鎹�
     let qrData
+    let deviceId = ''
+    
     try {
       qrData = JSON.parse(result.result)
       console.log('瑙f瀽鐨勪簩缁寸爜鏁版嵁:', qrData)
+      deviceId = qrData.deviceId || qrData.qrCodeId
     } catch (e) {
-      // 濡傛灉涓嶆槸JSON鏍煎紡锛岀洿鎺ヤ娇鐢ㄦ壂鐮佺粨鏋滀綔涓鸿澶囧悕绉�
-      qrData = { 
-        deviceName: result.result, 
-        location: '',
-        qrCodeId: result.result // 娣诲姞浜岀淮鐮両D
+      // 濡傛灉涓嶆槸JSON鏍煎紡锛屽皾璇曚粠URL涓彁鍙杁eviceId
+      const url = result.result
+      
+      if (url.includes('deviceId=')) {
+        // 浠嶶RL涓彁鍙杁eviceId
+        const match = url.match(/deviceId=(\d+)/)
+        if (match && match[1]) {
+          deviceId = match[1]
+        }
       }
-      console.log('浣跨敤榛樿鏁版嵁鏍煎紡:', qrData)
+      
+      qrData = { 
+        deviceName: deviceId ? `璁惧${deviceId}` : result.result, 
+        location: '',
+        qrCodeId: deviceId // 浣跨敤鎻愬彇鐨刣eviceId鎴栧師濮嬬粨鏋�
+      }
+    }
+    
+    // 濡傛灉鏈夎澶嘔D锛屽皾璇曚粠API鑾峰彇鐪熷疄鐨勮澶囧悕绉�
+    if (deviceId) {
+      try {
+        console.log('姝e湪鏌ヨ璁惧淇℃伅锛岃澶嘔D:', deviceId)
+        const response = await getLedgerById(deviceId)
+        console.log('璁惧淇℃伅鏌ヨ缁撴灉:', response)
+        
+        if (response.code === 200 && response.data) {
+          qrData.deviceName = response.data.deviceName || `璁惧${deviceId}`
+          qrData.location = response.data.storageLocation || ''
+          console.log('鑾峰彇鍒拌澶囧悕绉�:', qrData.deviceName)
+        } else {
+          console.warn('璁惧淇℃伅鏌ヨ澶辫触锛屼娇鐢ㄩ粯璁ゅ悕绉�')
+          qrData.deviceName = qrData.deviceName || `璁惧${deviceId}`
+        }
+      } catch (apiError) {
+        console.error('鏌ヨ璁惧淇℃伅澶辫触:', apiError)
+        // API璋冪敤澶辫触鏃朵娇鐢ㄩ粯璁ゅ悕绉�
+        qrData.deviceName = qrData.deviceName || `璁惧${deviceId}`
+      }
     }
     
     // 纭繚鏁版嵁瀹屾暣鎬�
@@ -379,51 +369,40 @@
       qrData.deviceName = result.result
     }
     if (!qrData.qrCodeId) {
-      qrData.qrCodeId = result.result
+      qrData.qrCodeId = deviceId || result.result
     }
     
-    callBackendAPI(qrData)
+    // 灏嗘壂鐮佹暟鎹笌浠诲姟鍏宠仈
+    if (currentScanningTask.value) {
+      // 鍏宠仈浠诲姟淇℃伅
+      const taskData = {
+        ...currentScanningTask.value,
+        qrCodeData: qrData
+      }
+      
+      // 鎵撳紑涓婁紶寮圭獥锛屼紶閫掑叧鑱斿悗鐨勪换鍔℃暟鎹�
+      nextTick(() => {
+        if (formDia.value && formDia.value.openDialog) {
+          formDia.value.openDialog(taskData)
+        } else {
+          console.error('涓婁紶缁勪欢寮曠敤涓嶅瓨鍦�')
+          uni.showToast({
+            title: '缁勪欢鏈噯澶囧ソ',
+            icon: 'error'
+          })
+        }
+      })
+    }
   } catch (error) {
     console.error('澶勭悊鎵爜缁撴灉澶辫触:', error)
     uni.showToast({
       title: error.message || '鏁版嵁瑙f瀽澶辫触',
       icon: 'error'
     })
+  } finally {
+    // 鍏抽棴鎵弿鐣岄潰
+    isScanning.value = false
   }
-}
-
-const callBackendAPI = (result) => {
-  console.log('鍑嗗鎵撳紑寮规锛屾暟鎹�:', result)
-  console.log('寮规缁勪欢寮曠敤:', qrCodeFormDia.value)
-  
-  // 纭繚缁勪欢寮曠敤瀛樺湪
-  if (qrCodeFormDia.value) {
-    console.log('鐩存帴璋冪敤寮规openDialog鏂规硶')
-    qrCodeFormDia.value.openDialog(result)
-  } else {
-    // 濡傛灉缁勪欢寮曠敤涓嶅瓨鍦紝绛夊緟涓嬩竴涓猼ick
-    console.log('缁勪欢寮曠敤涓嶅瓨鍦紝绛夊緟nextTick')
-    nextTick(() => {
-      console.log('nextTick鍚庡脊妗嗙粍浠跺紩鐢�:', qrCodeFormDia.value)
-      if (qrCodeFormDia.value) {
-        console.log('nextTick鍚庤皟鐢ㄥ脊妗唎penDialog鏂规硶')
-        qrCodeFormDia.value.openDialog(result)
-      } else {
-        console.error('寮规缁勪欢寮曠敤涓嶅瓨鍦�')
-        uni.showToast({
-          title: '寮规缁勪欢鏈噯澶囧ソ',
-          icon: 'error'
-        })
-      }
-    })
-  }
-}
-
-
-// 鎵爜澶勭悊
-const handleScanCode = (result) => {
-  console.log('鎵爜缁撴灉:', result)
-  handleScanSuccess(result)
 }
 
 // 鎽勫儚澶撮敊璇鐞�
@@ -434,104 +413,192 @@
 </script>
 
 <style scoped lang="scss">
+// 瀵煎叆閿�鍞ā鍧楀叕鍏辨牱寮�
+@import '@/styles/sales-common.scss';
+
+// 椤甸潰瀹瑰櫒鏍峰紡
 .inspection-upload-page {
   min-height: 100vh;
-  background-color: #f5f5f5;
-}
-
-.tabs-container {
-  background-color: #fff;
-  margin: 0;
-  border-bottom: 1px solid #e8e8e8;
-}
-
-.custom-tabs {
-  display: flex;
+  background: #f8f9fa;
   position: relative;
-  background-color: #fff;
-  width: 100%;
 }
 
-.tab-item {
+// 鍒楄〃瀹瑰櫒鏍峰紡
+.table-section {
+  padding: 20px;
+}
+
+// 浠诲姟鍒楄〃鏍峰紡 - 浣跨敤閿�鍞彴璐︾殑鏍峰紡瑙勮寖
+.task-list {
+  .task-item {
+    background: #ffffff;
+    border-radius: 12px;
+    margin-bottom: 16px;
+    overflow: hidden;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+    padding: 0 16px;
+    
+    &:active {
+      transform: scale(0.98);
+      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+    }
+  }
+}
+
+// 椤圭洰澶撮儴鏍峰紡
+.task-header {
+  padding: 16px 0;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 0;
+}
+
+.task-info {
   flex: 1;
-  text-align: center;
-  padding: 20px 0;
-  font-size: 16px;
+}
+
+.task-name {
+  font-size: 14px;
+  color: #333;
   font-weight: 500;
-  color: #606266;
-  transition: all 0.3s ease;
-  cursor: pointer;
-  position: relative;
-  z-index: 2;
+  margin-bottom: 0;
+  line-height: 1.4;
 }
 
-.tab-item.tab-active {
-  color: #1890ff;
-  font-weight: 600;
+.task-location {
+  font-size: 12px;
+  color: #666;
+  margin-top: 4px;
 }
 
-.tab-line {
-  position: absolute;
-  bottom: 0;
-  width: 50%;
-  height: 3px;
-  background-color: #1890ff;
-  transition: left 0.3s ease;
-}
-
-.scan-section {
-  background-color: #fff;
-	padding: 10px;
-}
-
-.scan-controls {
+// 浠诲姟鎿嶄綔鎸夐挳鏍峰紡
+.task-actions {
   display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-left: 0;
+}
+
+// 浠诲姟璇︽儏鏍峰紡 - 浣跨敤閿�鍞彴璐︾殑璇︽儏琛屾牱寮�
+.task-details {
+  padding: 16px 0;
+  
+  .detail-item {
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    margin-bottom: 8px;
+    
+    &:last-child {
+      margin-bottom: 0;
+    }
+    
+    .detail-label {
+      font-size: 12px;
+      color: #777777;
+      min-width: 60px;
+      flex-shrink: 0;
+    }
+    
+    .detail-value {
+      font-size: 12px;
+      color: #000000;
+      text-align: right;
+      flex: 1;
+      margin-left: 16px;
+      line-height: 1.4;
+    }
+  }
+}
+
+// 鏃犳暟鎹彁绀烘牱寮� - 浣跨敤閿�鍞彴璐︾殑鏍峰紡
+.no-data {
+  padding: 40px 0;
+  text-align: center;
+  color: #999;
+  background: none;
+  margin: 0;
+}
+
+.no-data text {
+  font-size: 14px;
+  color: #999;
+}
+
+/* 鎵爜寮圭獥鏍峰紡 */
+.qr-scan-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.8);
+  z-index: 9999;
+  display: flex;
+  flex-direction: column;
   justify-content: center;
+  align-items: center;
+  padding: 20px;
 }
 
 .qr-scan-container {
-  position: relative;
   width: 100%;
-  max-width: 500px;
-  margin: 0 auto;
-  background: #000;
-  border-radius: 8px;
+  max-width: 400px;
+  background-color: #000;
+  border-radius: 12px;
   overflow: hidden;
+}
+
+.scan-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px;
+  background-color: rgba(0, 0, 0, 0.7);
+}
+
+.scan-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #fff;
 }
 
 .qr-camera {
   width: 100%;
+  height: 400px;
+}
+
+.scan-frame-wrapper {
+  position: relative;
+  width: 100%;
   height: 300px;
 }
 
-.scan-overlay {
+.scan-frame {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
-  width: 70%;
-  height: 70%;
+  width: 80%;
+  height: 80%;
   border: 3px solid #1890ff;
   border-radius: 8px;
   box-shadow: 0 0 20px rgba(24, 144, 255, 0.3);
   animation: pulse 2s infinite;
 }
 
-.scan-frame {
-  width: 100%;
-  height: 100%;
-  border: 2px solid #fff;
-  border-radius: 4px;
-}
-
 .scan-tip {
   position: absolute;
-  bottom: -30px;
+  bottom: 10px;
   left: 50%;
   transform: translateX(-50%);
   color: #fff;
   font-size: 14px;
   text-align: center;
+  background-color: rgba(0, 0, 0, 0.6);
+  padding: 5px 15px;
+  border-radius: 20px;
 }
 
 @keyframes pulse {
@@ -540,104 +607,4 @@
   100% { opacity: 0.8; }
 }
 
-.status-info {
-  margin-top: 16px;
-  text-align: center;
-}
-
-.scanning-text {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  color: #1890ff;
-  margin-top: 8px;
-}
-
-.scanning-label {
-  margin-left: 8px;
-  font-size: 14px;
-}
-
-.table-section {
-  padding: 0 15px;
-}
-
-.task-list, .qr-list {
-  .task-item, .qr-item {
-    background-color: #fff;
-    border-radius: 8px;
-    margin-bottom: 10px;
-    padding: 15px;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-  }
-}
-
-.task-header, .qr-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-start;
-  margin-bottom: 10px;
-}
-
-.task-info, .qr-info {
-  flex: 1;
-}
-
-.task-name, .device-name {
-  font-size: 16px;
-  font-weight: 600;
-  color: #333;
-  margin-bottom: 4px;
-}
-
-.task-location, .device-location {
-  font-size: 14px;
-  color: #666;
-}
-
-.task-actions, .qr-actions {
-  margin-left: 10px;
-}
-
-.task-details, .qr-details {
-  .detail-item {
-    display: flex;
-    margin-bottom: 6px;
-    
-    .detail-label {
-      font-size: 14px;
-      color: #666;
-      min-width: 60px;
-    }
-    
-    .detail-value {
-      font-size: 14px;
-      color: #333;
-      flex: 1;
-    }
-  }
-}
-
-.empty-state, .loading-state {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  padding: 40px 20px;
-  background-color: #fff;
-  border-radius: 8px;
-  margin: 10px 15px;
-}
-
-.loading-text {
-  margin-top: 10px;
-  font-size: 14px;
-  color: #666;
-}
-
-.pagination-container {
-  padding: 20px 15px;
-  background-color: #fff;
-  margin-top: 10px;
-}
 </style>
\ No newline at end of file
diff --git a/src/static/images/icon/guzhangfenxi@2x.png b/src/static/images/icon/guzhangfenxi@2x.png
new file mode 100644
index 0000000..7a0efd5
--- /dev/null
+++ b/src/static/images/icon/guzhangfenxi@2x.png
Binary files differ
diff --git a/src/static/images/icon/jieguoyanzheng@2x.png b/src/static/images/icon/jieguoyanzheng@2x.png
new file mode 100644
index 0000000..e8e72fc
--- /dev/null
+++ b/src/static/images/icon/jieguoyanzheng@2x.png
Binary files differ
diff --git a/src/static/images/icon/xunjianshangchuan@2x.png b/src/static/images/icon/xunjianshangchuan@2x.png
new file mode 100644
index 0000000..84be030
--- /dev/null
+++ b/src/static/images/icon/xunjianshangchuan@2x.png
Binary files differ
diff --git a/src/static/images/icon/zhinengpaidan@2x.png b/src/static/images/icon/zhinengpaidan@2x.png
new file mode 100644
index 0000000..8317c98
--- /dev/null
+++ b/src/static/images/icon/zhinengpaidan@2x.png
Binary files differ
diff --git a/src/static/images/icon/zuoyezhidao@2x.png b/src/static/images/icon/zuoyezhidao@2x.png
new file mode 100644
index 0000000..8180fa3
--- /dev/null
+++ b/src/static/images/icon/zuoyezhidao@2x.png
Binary files differ

--
Gitblit v1.9.3