From d85836bf6b1574122830f6db8770e98184edd51c Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 20 九月 2025 09:49:01 +0800
Subject: [PATCH] 巡检上传页面
---
src/pages/equipmentManagement/inspection/index.vue | 2
src/pages/index.vue | 6
src/pages/inspectionUpload/components/formDia.vue | 256 +++++++++
src/pages.json | 7
src/api/inspectionUpload/index.js | 43 +
src/api/inspectionManagement/index.js | 61 ++
src/api/equipmentManagement/inspection.js | 433 ++++++++++----
src/pages/inspectionUpload/index.vue | 597 +++++++++++++++++++++
src/pages/inspectionUpload/components/qrCodeFormDia.vue | 254 +++++++++
9 files changed, 1,517 insertions(+), 142 deletions(-)
diff --git a/src/api/equipmentManagement/inspection.js b/src/api/equipmentManagement/inspection.js
index 5545b4e..c3113a8 100644
--- a/src/api/equipmentManagement/inspection.js
+++ b/src/api/equipmentManagement/inspection.js
@@ -1,220 +1,377 @@
-import request from "@/utils/request";
+import request from '@/utils/request'
+
+// ==================== 宸℃浠诲姟绠$悊 ====================
/**
- * @desc 鑾峰彇宸℃娓呭崟鍒楄〃
- * @param {Object} params - 鏌ヨ鍙傛暟
- * @param {string} params.date - 宸℃鏃ユ湡
- * @param {string} params.inspector - 宸℃鍛�
- * @param {number} params.status - 宸℃鐘舵�� 0:寰呭贰妫� 1:宸℃涓� 2:宸插畬鎴�
+ * @desc 鏌ヨ宸℃浠诲姟鍒楄〃
+ * @param {Object} query - 鏌ヨ鍙傛暟
+ * @param {string} query.date - 宸℃鏃ユ湡
+ * @param {string} query.status - 浠诲姟鐘舵��
+ * @param {string} query.inspector - 宸℃鍛�
* @returns {Promise}
*/
-export const getInspectionList = (params) => {
+export function getInspectionTaskList(query) {
return request({
- url: "/device/inspection/list",
- method: "get",
- params,
- });
-};
+ url: '/equipment/inspection/task/list',
+ method: 'get',
+ params: query
+ })
+}
/**
- * @desc 鑾峰彇宸℃璇︽儏
- * @param {string|number} id - 宸℃ID
+ * @desc 鏌ヨ宸℃浠诲姟璇︾粏
+ * @param {string|number} id - 浠诲姟ID
* @returns {Promise}
*/
-export const getInspectionDetail = (id) => {
+export function getInspectionTask(id) {
return request({
- url: `/device/inspection/${id}`,
- method: "get",
- });
-};
+ url: '/equipment/inspection/task/' + id,
+ method: 'get'
+ })
+}
/**
- * @desc 寮�濮嬪贰妫�
- * @param {Object} data - 宸℃鏁版嵁
- * @param {string|number} data.inspectionId - 宸℃ID
- * @param {string} data.startTime - 寮�濮嬫椂闂�
+ * @desc 鍒涘缓宸℃浠诲姟
+ * @param {Object} data - 浠诲姟鏁版嵁
* @returns {Promise}
*/
-export const startInspection = (data) => {
+export function createInspectionTask(data) {
return request({
- url: "/device/inspection/start",
- method: "post",
- data,
- });
-};
+ url: '/equipment/inspection/task',
+ method: 'post',
+ data: data
+ })
+}
+
+/**
+ * @desc 鏇存柊宸℃浠诲姟
+ * @param {Object} data - 浠诲姟鏁版嵁
+ * @returns {Promise}
+ */
+export function updateInspectionTask(data) {
+ return request({
+ url: '/equipment/inspection/task',
+ method: 'put',
+ data: data
+ })
+}
+
+/**
+ * @desc 鍒犻櫎宸℃浠诲姟
+ * @param {string|number} id - 浠诲姟ID
+ * @returns {Promise}
+ */
+export function deleteInspectionTask(id) {
+ return request({
+ url: '/equipment/inspection/task/' + id,
+ method: 'delete'
+ })
+}
+
+/**
+ * @desc 寮�濮嬪贰妫�浠诲姟
+ * @param {string|number} taskId - 浠诲姟ID
+ * @returns {Promise}
+ */
+export function startInspectionTask(taskId) {
+ return request({
+ url: '/equipment/inspection/task/' + taskId + '/start',
+ method: 'post'
+ })
+}
+
+/**
+ * @desc 瀹屾垚宸℃浠诲姟
+ * @param {string|number} taskId - 浠诲姟ID
+ * @param {Object} data - 瀹屾垚鏁版嵁
+ * @returns {Promise}
+ */
+export function completeInspectionTask(taskId, data) {
+ return request({
+ url: '/equipment/inspection/task/' + taskId + '/complete',
+ method: 'post',
+ data: data
+ })
+}
+
+// ==================== 宸℃璁板綍绠$悊 ====================
/**
* @desc 鎻愪氦宸℃璁板綍
* @param {Object} data - 宸℃璁板綍鏁版嵁
- * @param {string|number} data.deviceId - 璁惧ID
- * @param {string} data.deviceCode - 璁惧缂栫爜
- * @param {string} data.inspectionDate - 宸℃鏃ユ湡
- * @param {string} data.inspector - 宸℃鍛�
- * @param {string} data.scanTime - 鎵爜鏃堕棿
- * @param {Array} data.items - 宸℃椤圭洰鍒楄〃
- * @param {string} data.completedAt - 瀹屾垚鏃堕棿
* @returns {Promise}
*/
-export const submitInspectionRecord = (data) => {
+export function submitInspectionRecord(data) {
return request({
- url: "/device/inspection/submit",
- method: "post",
- data,
- });
-};
+ url: '/equipment/inspection/record/submit',
+ method: 'post',
+ data: data
+ })
+}
/**
- * @desc 鏇存柊宸℃椤圭洰
- * @param {Object} data - 宸℃椤圭洰鏁版嵁
- * @param {string|number} data.inspectionId - 宸℃ID
- * @param {string|number} data.itemId - 椤圭洰ID
- * @param {string} data.result - 宸℃缁撴灉 normal:姝e父 abnormal:寮傚父
- * @param {string} data.abnormalDesc - 寮傚父鎻忚堪
- * @param {Array} data.images - 鍥剧墖鍒楄〃
- * @param {Array} data.videos - 瑙嗛鍒楄〃
- * @param {string} data.remark - 澶囨敞
+ * @desc 鏌ヨ宸℃璁板綍鍒楄〃
+ * @param {Object} query - 鏌ヨ鍙傛暟
* @returns {Promise}
*/
-export const updateInspectionItem = (data) => {
+export function getInspectionRecordList(query) {
return request({
- url: "/device/inspection/item/update",
- method: "put",
- data,
- });
-};
+ url: '/equipment/inspection/record/list',
+ method: 'get',
+ params: query
+ })
+}
/**
- * @desc 鎵爜鎵撳崱
- * @param {Object} data - 鎵撳崱鏁版嵁
- * @param {string|number} data.inspectionId - 宸℃ID
- * @param {string} data.deviceCode - 璁惧缂栫爜
- * @param {string} data.qrCode - 浜岀淮鐮佸唴瀹�
- * @param {string} data.checkInTime - 鎵撳崱鏃堕棿
- * @param {string} data.location - 鎵撳崱浣嶇疆
+ * @desc 鏌ヨ宸℃璁板綍璇︽儏
+ * @param {string|number} id - 璁板綍ID
* @returns {Promise}
*/
-export const checkInByQRCode = (data) => {
+export function getInspectionRecord(id) {
return request({
- url: "/device/inspection/checkin",
- method: "post",
- data,
- });
-};
+ url: '/equipment/inspection/record/' + id,
+ method: 'get'
+ })
+}
+
+// ==================== 鏂囦欢涓婁紶 ====================
/**
- * @desc 涓婁紶宸℃鏂囦欢锛堝浘鐗�/瑙嗛锛�
+ * @desc 涓婁紶宸℃鍥剧墖
+ * @param {File} file - 鍥剧墖鏂囦欢
+ * @returns {Promise}
+ */
+export function uploadInspectionImage(file) {
+ return request({
+ url: '/equipment/inspection/upload/image',
+ method: 'post',
+ data: file,
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ })
+}
+
+/**
+ * @desc 涓婁紶宸℃瑙嗛
+ * @param {File} file - 瑙嗛鏂囦欢
+ * @returns {Promise}
+ */
+export function uploadInspectionVideo(file) {
+ return request({
+ url: '/equipment/inspection/upload/video',
+ method: 'post',
+ data: file,
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ })
+}
+
+/**
+ * @desc 鎵归噺涓婁紶鏂囦欢
* @param {FormData} formData - 鏂囦欢鏁版嵁
* @returns {Promise}
*/
-export const uploadInspectionFile = (formData) => {
+export function batchUploadFiles(formData) {
return request({
- url: "/device/inspection/upload",
- method: "post",
+ url: '/equipment/inspection/upload/batch',
+ method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
- });
-};
+ })
+}
+
+// ==================== 寮傚父鎶ュ绠$悊 ====================
+
+/**
+ * @desc 鎶ュ寮傚父鎯呭喌
+ * @param {Object} data - 寮傚父鎶ュ鏁版嵁
+ * @returns {Promise}
+ */
+export function reportAbnormalSituation(data) {
+ return request({
+ url: '/equipment/inspection/abnormal/report',
+ method: 'post',
+ data: data
+ })
+}
+
+/**
+ * @desc 鏌ヨ寮傚父鎶ュ鍒楄〃
+ * @param {Object} query - 鏌ヨ鍙傛暟
+ * @returns {Promise}
+ */
+export function getAbnormalReportList(query) {
+ return request({
+ url: '/equipment/inspection/abnormal/list',
+ method: 'get',
+ params: query
+ })
+}
+
+/**
+ * @desc 鏌ヨ寮傚父鎶ュ璇︽儏
+ * @param {string|number} id - 鎶ュID
+ * @returns {Promise}
+ */
+export function getAbnormalReport(id) {
+ return request({
+ url: '/equipment/inspection/abnormal/' + id,
+ method: 'get'
+ })
+}
+
+/**
+ * @desc 澶勭悊寮傚父鎶ュ
+ * @param {string|number} id - 鎶ュID
+ * @param {Object} data - 澶勭悊鏁版嵁
+ * @returns {Promise}
+ */
+export function handleAbnormalReport(id, data) {
+ return request({
+ url: '/equipment/inspection/abnormal/' + id + '/handle',
+ method: 'post',
+ data: data
+ })
+}
+
+/**
+ * @desc 杞淳寮傚父鎶ュ
+ * @param {string|number} id - 鎶ュID
+ * @param {Object} data - 杞淳鏁版嵁
+ * @returns {Promise}
+ */
+export function transferAbnormalReport(id, data) {
+ return request({
+ url: '/equipment/inspection/abnormal/' + id + '/transfer',
+ method: 'post',
+ data: data
+ })
+}
+
+/**
+ * @desc 鍏抽棴寮傚父鎶ュ
+ * @param {string|number} id - 鎶ュID
+ * @param {Object} data - 鍏抽棴鏁版嵁
+ * @returns {Promise}
+ */
+export function closeAbnormalReport(id, data) {
+ return request({
+ url: '/equipment/inspection/abnormal/' + id + '/close',
+ method: 'post',
+ data: data
+ })
+}
+
+// ==================== 缁熻鍒嗘瀽 ====================
/**
* @desc 鑾峰彇宸℃缁熻鏁版嵁
* @param {Object} params - 鏌ヨ鍙傛暟
- * @param {string} params.startDate - 寮�濮嬫棩鏈�
- * @param {string} params.endDate - 缁撴潫鏃ユ湡
- * @param {string} params.inspector - 宸℃鍛�
* @returns {Promise}
*/
-export const getInspectionStats = (params) => {
+export function getInspectionStats(params) {
return request({
- url: "/device/inspection/stats",
- method: "get",
- params,
- });
-};
+ url: '/equipment/inspection/stats',
+ method: 'get',
+ params: params
+ })
+}
/**
- * @desc 鑾峰彇宸℃鍘嗗彶璁板綍
+ * @desc 鑾峰彇寮傚父缁熻鏁版嵁
* @param {Object} params - 鏌ヨ鍙傛暟
- * @param {string|number} params.deviceId - 璁惧ID
- * @param {number} params.current - 褰撳墠椤�
- * @param {number} params.size - 椤甸潰澶у皬
* @returns {Promise}
*/
-export const getInspectionHistory = (params) => {
+export function getAbnormalStats(params) {
return request({
- url: "/device/inspection/history",
- method: "get",
- params,
- });
-};
+ url: '/equipment/inspection/abnormal/stats',
+ method: 'get',
+ params: params
+ })
+}
/**
- * @desc 瀵煎嚭宸℃璁板綍
+ * @desc 瀵煎嚭宸℃鎶ュ憡
* @param {Object} params - 瀵煎嚭鍙傛暟
- * @param {string} params.startDate - 寮�濮嬫棩鏈�
- * @param {string} params.endDate - 缁撴潫鏃ユ湡
- * @param {string} params.inspector - 宸℃鍛�
- * @param {Array} params.deviceIds - 璁惧ID鍒楄〃
* @returns {Promise}
*/
-export const exportInspectionRecords = (params) => {
+export function exportInspectionReport(params) {
return request({
- url: "/device/inspection/export",
- method: "get",
- params,
+ url: '/equipment/inspection/export/report',
+ method: 'get',
+ params: params,
responseType: 'blob'
- });
-};
+ })
+}
/**
- * @desc 鍒犻櫎宸℃璁板綍
- * @param {string|number} id - 宸℃璁板綍ID
+ * @desc 瀵煎嚭寮傚父鎶ュ璁板綍
+ * @param {Object} params - 瀵煎嚭鍙傛暟
* @returns {Promise}
*/
-export const deleteInspectionRecord = (id) => {
+export function exportAbnormalRecords(params) {
return request({
- url: `/device/inspection/${id}`,
- method: "delete",
- });
-};
+ url: '/equipment/inspection/abnormal/export',
+ method: 'get',
+ params: params,
+ responseType: 'blob'
+ })
+}
-/**
- * @desc 鎵归噺鍒犻櫎宸℃璁板綍
- * @param {Array} ids - 宸℃璁板綍ID鍒楄〃
- * @returns {Promise}
- */
-export const batchDeleteInspectionRecords = (ids) => {
- return request({
- url: "/device/inspection/batch/delete",
- method: "delete",
- data: { ids },
- });
-};
+// ==================== 璁惧浜岀淮鐮� ====================
/**
* @desc 鑾峰彇璁惧浜岀淮鐮�
* @param {string|number} deviceId - 璁惧ID
* @returns {Promise}
*/
-export const getDeviceQRCode = (deviceId) => {
+export function getDeviceQRCode(deviceId) {
return request({
- url: `/device/qrcode/${deviceId}`,
- method: "get",
- });
-};
+ url: `/equipment/device/${deviceId}/qrcode`,
+ method: 'get'
+ })
+}
/**
* @desc 楠岃瘉璁惧浜岀淮鐮�
* @param {Object} data - 楠岃瘉鏁版嵁
- * @param {string} data.qrCode - 浜岀淮鐮佸唴瀹�
- * @param {string|number} data.deviceId - 璁惧ID
* @returns {Promise}
*/
-export const verifyDeviceQRCode = (data) => {
+export function verifyDeviceQRCode(data) {
return request({
- url: "/device/qrcode/verify",
- method: "post",
- data,
- });
-};
\ No newline at end of file
+ url: '/equipment/device/qrcode/verify',
+ method: 'post',
+ data: data
+ })
+}
+
+// ==================== 妯℃澘绠$悊 ====================
+
+/**
+ * @desc 鑾峰彇宸℃妯℃澘鍒楄〃
+ * @param {Object} query - 鏌ヨ鍙傛暟
+ * @returns {Promise}
+ */
+export function getInspectionTemplateList(query) {
+ return request({
+ url: '/equipment/inspection/template/list',
+ method: 'get',
+ params: query
+ })
+}
+
+/**
+ * @desc 鑾峰彇宸℃妯℃澘璇︽儏
+ * @param {string|number} id - 妯℃澘ID
+ * @returns {Promise}
+ */
+export function getInspectionTemplate(id) {
+ return request({
+ url: '/equipment/inspection/template/' + id,
+ method: 'get'
+ })
+}
\ No newline at end of file
diff --git a/src/api/inspectionManagement/index.js b/src/api/inspectionManagement/index.js
new file mode 100644
index 0000000..d0c444a
--- /dev/null
+++ b/src/api/inspectionManagement/index.js
@@ -0,0 +1,61 @@
+// 宸℃绠$悊
+import request from '@/utils/request'
+
+// 宸℃浠诲姟琛ㄨ〃鏌ヨ
+export function inspectionTaskList(query) {
+ return request({
+ url: '/inspectionTask/list',
+ method: 'get',
+ params: query
+ })
+}
+// 宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
+export function addOrEditInspectionTask(query) {
+ return request({
+ url: '/inspectionTask/addOrEditInspectionTask',
+ method: 'post',
+ data: query
+ })
+}
+// 宸℃浠诲姟琛ㄥ垹闄�
+export function delInspectionTask(query) {
+ return request({
+ url: '/inspectionTask/delInspectionTask',
+ method: 'delete',
+ data: query
+ })
+}
+// 瀹氭椂宸℃浠诲姟琛ㄥ垹闄�
+export function delTimingTask(query) {
+ return request({
+ url: '/timingTask/delTimingTask',
+ method: 'delete',
+ data: query
+ })
+}
+
+// /inspectionTask/addOrEditInspectionTask
+// 宸℃涓婁紶
+export function uploadInspectionTask(query) {
+ return request({
+ url: '/inspectionTask/addOrEditInspectionTask',
+ method: 'post',
+ data: query
+ })
+}
+// 瀹氭椂宸℃浠诲姟琛ㄦ煡璇�
+export function timingTaskList(query) {
+ return request({
+ url: '/timingTask/list',
+ method: 'get',
+ params: query
+ })
+}
+// 瀹氭椂宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
+export function addOrEditTimingTask(query) {
+ return request({
+ url: '/timingTask/addOrEditTimingTask',
+ method: 'post',
+ data: query
+ })
+}
\ No newline at end of file
diff --git a/src/api/inspectionUpload/index.js b/src/api/inspectionUpload/index.js
new file mode 100644
index 0000000..0d954e2
--- /dev/null
+++ b/src/api/inspectionUpload/index.js
@@ -0,0 +1,43 @@
+// 宸℃涓婁紶
+import request from '@/utils/request'
+
+// 浜岀淮鐮佺鐞嗚〃鏌ヨ
+export function qrCodeList(query) {
+ return request({
+ url: '/qrCode/list',
+ method: 'get',
+ params: query
+ })
+}
+// 浜岀淮鐮佹壂鐮佽褰曡〃鏌ヨ
+export function qrCodeScanRecordList(query) {
+ return request({
+ url: '/qrCodeScanRecord/list',
+ method: 'get',
+ params: query
+ })
+}
+// 浜岀淮鐮佺鐞嗚〃鏂板淇敼
+export function addOrEditQrCode(query) {
+ return request({
+ url: '/qrCode/addOrEditQrCode',
+ method: 'post',
+ data: query
+ })
+}
+// 浜岀淮鐮佹壂鐮佽褰曡〃鏂板淇敼
+export function addOrEditQrCodeRecord(query) {
+ return request({
+ url: '/qrCodeScanRecord/addOrEditQrCodeRecord',
+ method: 'post',
+ data: query
+ })
+}
+// 浜岀淮鐮佹壂鐮佽褰曡〃鏂板淇敼
+export function delQrCode(query) {
+ return request({
+ url: '/qrCode/delQrCode',
+ method: 'delete',
+ data: query
+ })
+}
\ No newline at end of file
diff --git a/src/pages.json b/src/pages.json
index 8fd1a91..3937f03 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -385,6 +385,13 @@
"navigationBarTitleText": "缁撴灉楠岃瘉",
"navigationStyle": "custom"
}
+ },
+ {
+ "path": "pages/inspectionUpload/index",
+ "style": {
+ "navigationBarTitleText": "宸℃涓婁紶",
+ "navigationStyle": "custom"
+ }
}
],
"subPackages": [
diff --git a/src/pages/equipmentManagement/inspection/index.vue b/src/pages/equipmentManagement/inspection/index.vue
index d647dea..bb949fa 100644
--- a/src/pages/equipmentManagement/inspection/index.vue
+++ b/src/pages/equipmentManagement/inspection/index.vue
@@ -96,7 +96,7 @@
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
-import { getInspectionList } from '@/api/equipmentManagement/inspection'
+// import { getInspectionList } from '@/api/inspectionUpload/index'
import dayjs from 'dayjs'
// 閫変腑鐨勬棩鏈�
diff --git a/src/pages/index.vue b/src/pages/index.vue
index ceb1000..2062b64 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -269,7 +269,7 @@
},
{
icon: '/static/images/icon/shebeixunjian@2x.png',
- label: '璁惧宸℃',
+ label: '宸℃涓婁紶',
},
{
icon: 'flash',
@@ -377,9 +377,9 @@
url: '/pages/equipmentManagement/upkeep/index'
});
break;
- case '璁惧宸℃':
+ case '宸℃涓婁紶':
uni.navigateTo({
- url: '/pages/equipmentManagement/inspection/index'
+ url: '/pages/inspectionUpload/index'
});
break;
case '鏅鸿兘娲惧崟':
diff --git a/src/pages/inspectionUpload/components/formDia.vue b/src/pages/inspectionUpload/components/formDia.vue
new file mode 100644
index 0000000..41837cb
--- /dev/null
+++ b/src/pages/inspectionUpload/components/formDia.vue
@@ -0,0 +1,256 @@
+<template>
+ <u-popup
+ v-model="dialogVisitable"
+ mode="center"
+ :round="10"
+ :closeable="true"
+ @close="cancel"
+ >
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">涓婁紶</text>
+ </view>
+
+ <view class="upload-container">
+ <view class="form-container">
+ <view class="title">鐢熶骇鍓�</view>
+ <u-upload
+ :fileList="beforeModelValue"
+ @afterRead="afterRead"
+ @delete="deleteFile"
+ name="before"
+ multiple
+ :maxCount="10"
+ :maxSize="1024 * 1024"
+ accept="video/*"
+ :previewFullImage="true"
+ ></u-upload>
+ </view>
+
+ <view class="form-container">
+ <view class="title">鐢熶骇鍚�</view>
+ <u-upload
+ :fileList="afterModelValue"
+ @afterRead="afterRead"
+ @delete="deleteFile"
+ name="after"
+ multiple
+ :maxCount="10"
+ :maxSize="1024 * 1024"
+ accept="video/*"
+ :previewFullImage="true"
+ ></u-upload>
+ </view>
+
+ <view class="form-container">
+ <view class="title">鐢熶骇闂</view>
+ <u-upload
+ :fileList="issueModelValue"
+ @afterRead="afterRead"
+ @delete="deleteFile"
+ name="issue"
+ multiple
+ :maxCount="10"
+ :maxSize="1024 * 1024"
+ accept="video/*"
+ :previewFullImage="true"
+ ></u-upload>
+ </view>
+ </view>
+
+ <view class="popup-footer">
+ <u-button @click="cancel" :customStyle="{ marginRight: '10px' }">鍙栨秷</u-button>
+ <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+ </view>
+ </view>
+ </u-popup>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { submitInspectionRecord } from '@/api/equipmentManagement/inspection.js'
+
+const emit = defineEmits(['closeDia'])
+
+const dialogVisitable = ref(false)
+const beforeModelValue = ref([])
+const afterModelValue = ref([])
+const issueModelValue = ref([])
+const infoData = ref(null)
+
+// 鏂囦欢涓婁紶澶勭悊
+const afterRead = (event) => {
+ const { name, file } = event
+
+ // 涓婁紶鏂囦欢鍒版湇鍔″櫒
+ uni.uploadFile({
+ url: '/api/upload', // 鏇挎崲涓哄疄闄呯殑涓婁紶鎺ュ彛
+ filePath: file.url,
+ name: 'file',
+ success: (res) => {
+ const data = JSON.parse(res.data)
+ if (data.code === 200) {
+ const fileItem = {
+ url: data.data.url,
+ name: file.name,
+ status: 'success'
+ }
+
+ // 鏍规嵁name娣诲姞鍒板搴旂殑鏁扮粍
+ if (name === 'before') {
+ beforeModelValue.value.push(fileItem)
+ } else if (name === 'after') {
+ afterModelValue.value.push(fileItem)
+ } else if (name === 'issue') {
+ issueModelValue.value.push(fileItem)
+ }
+
+ uni.showToast({
+ title: '涓婁紶鎴愬姛',
+ icon: 'success'
+ })
+ } else {
+ uni.showToast({
+ title: '涓婁紶澶辫触',
+ icon: 'error'
+ })
+ }
+ },
+ fail: () => {
+ uni.showToast({
+ title: '涓婁紶澶辫触',
+ icon: 'error'
+ })
+ }
+ })
+}
+
+// 鍒犻櫎鏂囦欢
+const deleteFile = (event) => {
+ const { name, index } = event
+
+ if (name === 'before') {
+ beforeModelValue.value.splice(index, 1)
+ } else if (name === 'after') {
+ afterModelValue.value.splice(index, 1)
+ } else if (name === 'issue') {
+ issueModelValue.value.splice(index, 1)
+ }
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = async () => {
+ try {
+ let arr = []
+ if (beforeModelValue.value.length > 0) {
+ arr.push(...beforeModelValue.value.map(item => ({ ...item, statusType: 0 })))
+ }
+ if (afterModelValue.value.length > 0) {
+ arr.push(...afterModelValue.value.map(item => ({ ...item, statusType: 1 })))
+ }
+ if (issueModelValue.value.length > 0) {
+ arr.push(...issueModelValue.value.map(item => ({ ...item, statusType: 2 })))
+ }
+
+ // 鎻愪氦鏁版嵁
+ infoData.value.storageBlobDTO = arr
+ await submitInspectionRecord({ ...infoData.value })
+
+ uni.showToast({
+ title: '鎻愪氦鎴愬姛',
+ icon: 'success'
+ })
+
+ cancel()
+ } catch (error) {
+ console.error('鎻愪氦澶辫触:', error)
+ uni.showToast({
+ title: '鎻愪氦澶辫触',
+ icon: 'error'
+ })
+ }
+}
+
+// 鎵撳紑寮规
+const openDialog = async (row) => {
+ infoData.value = row
+ dialogVisitable.value = true
+
+ // 娓呯┖涔嬪墠鐨勬暟鎹�
+ beforeModelValue.value = []
+ afterModelValue.value = []
+ issueModelValue.value = []
+}
+
+// 鍏抽棴寮规
+const cancel = () => {
+ dialogVisitable.value = false
+ emit('closeDia')
+}
+
+defineExpose({ openDialog })
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+ width: 90vw;
+ max-width: 400px;
+ background-color: #fff;
+ border-radius: 10px;
+ overflow: hidden;
+}
+
+.popup-header {
+ padding: 20px 20px 10px;
+ text-align: center;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+}
+
+.upload-container {
+ padding: 20px;
+ max-height: 60vh;
+ overflow-y: auto;
+}
+
+.form-container {
+ margin-bottom: 20px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.title {
+ font-size: 14px;
+ color: #1890ff;
+ line-height: 20px;
+ font-weight: 600;
+ padding-left: 10px;
+ position: relative;
+ margin: 6px 0 10px;
+
+ &::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 3px;
+ width: 4px;
+ height: 14px;
+ background-color: #1890ff;
+ }
+}
+
+.popup-footer {
+ display: flex;
+ justify-content: center;
+ padding: 15px 20px;
+ border-top: 1px solid #f0f0f0;
+ background-color: #fafafa;
+}
+</style>
diff --git a/src/pages/inspectionUpload/components/qrCodeFormDia.vue b/src/pages/inspectionUpload/components/qrCodeFormDia.vue
new file mode 100644
index 0000000..07a94cd
--- /dev/null
+++ b/src/pages/inspectionUpload/components/qrCodeFormDia.vue
@@ -0,0 +1,254 @@
+<template>
+ <u-popup
+ v-model="dialogVisitable"
+ mode="center"
+ :round="10"
+ :closeable="true"
+ @close="cancel"
+ >
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">宸℃</text>
+ </view>
+
+ <view class="form-container">
+ <u-form :model="form" ref="formRef" :rules="rules">
+ <u-form-item label="璁惧鍚嶇О" prop="deviceName" labelWidth="80">
+ <u-input
+ v-model="form.deviceName"
+ placeholder="璇疯緭鍏ヨ澶囧悕绉�"
+ :maxlength="30"
+ :disabled="true"
+ />
+ </u-form-item>
+
+ <u-form-item label="鍦扮偣" prop="location" labelWidth="80">
+ <u-input
+ v-model="form.location"
+ placeholder="璇疯緭鍏ュ湴鐐�"
+ :maxlength="30"
+ :disabled="true"
+ />
+ </u-form-item>
+
+ <u-form-item label="闄勪欢" prop="storageBlobDTO" labelWidth="80">
+ <u-upload
+ :fileList="form.storageBlobDTO"
+ @afterRead="afterRead"
+ @delete="deleteFile"
+ name="files"
+ multiple
+ :maxCount="10"
+ :maxSize="1024 * 1024"
+ accept="video/*"
+ :previewFullImage="true"
+ ></u-upload>
+ </u-form-item>
+
+ <u-form-item label="宸℃浜�" prop="scannerName" labelWidth="80">
+ <u-input
+ v-model="form.scannerName"
+ :disabled="true"
+ placeholder="璇疯緭鍏�"
+ />
+ </u-form-item>
+
+ <u-form-item label="宸℃鏃堕棿" prop="scanTime" labelWidth="80">
+ <u-input
+ v-model="form.scanTime"
+ :disabled="true"
+ placeholder="璇疯緭鍏�"
+ />
+ </u-form-item>
+ </u-form>
+ </view>
+
+ <view class="popup-footer">
+ <u-button @click="cancel" :customStyle="{ marginRight: '10px' }">鍙栨秷</u-button>
+ <u-button type="primary" @click="submitForm">淇濆瓨</u-button>
+ </view>
+ </view>
+ </u-popup>
+</template>
+
+<script setup>
+import { reactive, ref, onMounted } from 'vue'
+import { addOrEditQrCodeRecord } from '@/api/inspectionUpload/index.js'
+import useUserStore from '@/store/modules/user.ts'
+
+const emit = defineEmits(['closeDia'])
+
+const dialogVisitable = ref(false)
+const formRef = ref(null)
+const userStore = useUserStore()
+const userInfo = ref({})
+
+// 鑾峰彇褰撳墠鏃堕棿
+function getCurrentDateTime() {
+ const now = new Date()
+ const year = now.getFullYear()
+ const month = String(now.getMonth() + 1).padStart(2, '0')
+ const day = String(now.getDate()).padStart(2, '0')
+ const hours = String(now.getHours()).padStart(2, '0')
+ const minutes = String(now.getMinutes()).padStart(2, '0')
+ const seconds = String(now.getSeconds()).padStart(2, '0')
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+}
+
+// 琛ㄥ崟鏁版嵁
+const form = reactive({
+ deviceName: '',
+ location: '',
+ scannerName: '',
+ scannerId: '',
+ scanTime: '',
+ storageBlobDTO: [],
+ qrCode: {
+ id: ''
+ }
+})
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = reactive({
+ deviceName: [{ required: true, message: '璇疯緭鍏ヨ澶囧悕绉�', trigger: 'blur' }],
+ location: [{ required: true, message: '璇疯緭鍏ュ湴鐐�', trigger: 'blur' }]
+})
+
+// 鑾峰彇鐢ㄦ埛淇℃伅
+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()
+ } catch (error) {
+ console.error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触:', error)
+ }
+})
+
+// 鏂囦欢涓婁紶澶勭悊
+const afterRead = (event) => {
+ const { file } = event
+
+ // 涓婁紶鏂囦欢鍒版湇鍔″櫒
+ uni.uploadFile({
+ url: '/api/upload', // 鏇挎崲涓哄疄闄呯殑涓婁紶鎺ュ彛
+ filePath: file.url,
+ name: 'file',
+ success: (res) => {
+ const data = JSON.parse(res.data)
+ if (data.code === 200) {
+ const fileItem = {
+ url: data.data.url,
+ name: file.name,
+ status: 'success'
+ }
+
+ form.storageBlobDTO.push(fileItem)
+
+ uni.showToast({
+ title: '涓婁紶鎴愬姛',
+ icon: 'success'
+ })
+ } else {
+ uni.showToast({
+ title: '涓婁紶澶辫触',
+ icon: 'error'
+ })
+ }
+ },
+ fail: () => {
+ uni.showToast({
+ title: '涓婁紶澶辫触',
+ icon: 'error'
+ })
+ }
+ })
+}
+
+// 鍒犻櫎鏂囦欢
+const deleteFile = (event) => {
+ const { index } = event
+ form.storageBlobDTO.splice(index, 1)
+}
+
+// 鎵撳紑寮规
+const openDialog = async (row) => {
+ dialogVisitable.value = true
+ form.deviceName = row.deviceName || ''
+ form.location = row.location || ''
+ form.qrCodeId = row.qrCodeId || row.id || ''
+ form.storageBlobDTO = []
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = async () => {
+ try {
+ // 琛ㄥ崟楠岃瘉
+ const valid = await formRef.value.validate()
+ if (!valid) return
+
+ form.qrCode.id = form.qrCodeId
+
+ await addOrEditQrCodeRecord({ ...form })
+
+ uni.showToast({
+ title: '鎻愪氦鎴愬姛',
+ icon: 'success'
+ })
+
+ cancel()
+ } catch (error) {
+ console.error('鎻愪氦澶辫触:', error)
+ uni.showToast({
+ title: '鎻愪氦澶辫触',
+ icon: 'error'
+ })
+ }
+}
+
+// 鍏抽棴寮规
+const cancel = () => {
+ dialogVisitable.value = false
+ emit('closeDia')
+}
+
+defineExpose({ openDialog })
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+ width: 90vw;
+ max-width: 400px;
+ background-color: #fff;
+ border-radius: 10px;
+ overflow: hidden;
+}
+
+.popup-header {
+ padding: 20px 20px 10px;
+ text-align: center;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.popup-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+}
+
+.form-container {
+ padding: 20px;
+ max-height: 60vh;
+ overflow-y: auto;
+}
+
+.popup-footer {
+ display: flex;
+ justify-content: center;
+ padding: 15px 20px;
+ border-top: 1px solid #f0f0f0;
+ background-color: #fafafa;
+}
+</style>
diff --git a/src/pages/inspectionUpload/index.vue b/src/pages/inspectionUpload/index.vue
new file mode 100644
index 0000000..5c57b4e
--- /dev/null
+++ b/src/pages/inspectionUpload/index.vue
@@ -0,0 +1,597 @@
+<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>
+
+ <!-- 鏁版嵁鍒楄〃 -->
+ <view class="table-section">
+ <!-- 鐢熶骇宸℃鍒楄〃 -->
+ <view v-if="activeTab === 'task'" class="task-list">
+ <view
+ v-for="(item, index) in tableData"
+ :key="index"
+ class="task-item"
+ @click="handleAdd(item)"
+ >
+ <view class="task-header">
+ <view class="task-info">
+ <text class="task-name">{{ item.taskName }}</text>
+ <text class="task-location">{{ item.inspectionLocation }}</text>
+ </view>
+ <view class="task-actions">
+ <u-button
+ type="primary"
+ size="small"
+ @click.stop="handleAdd(item)"
+ :customStyle="{
+ borderRadius: '15px',
+ height: '30px',
+ fontSize: '12px'
+ }"
+ >
+ 涓婁紶
+ </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"
+ size="small"
+ @click.stop="viewFile(item)"
+ :customStyle="{
+ borderRadius: '15px',
+ height: '30px',
+ fontSize: '12px'
+ }"
+ >
+ 鏌ョ湅闄勪欢
+ </u-button>
+ </view>
+ </view>
+ <view class="qr-details">
+ <view class="detail-item">
+ <text class="detail-label">宸℃浜猴細</text>
+ <text class="detail-value">{{ item.scanner }}</text>
+ </view>
+ <view class="detail-item">
+ <text class="detail-label">宸℃鏃堕棿锛�</text>
+ <text class="detail-value">{{ item.scanTime }}</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>
+ </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>
+
+ <!-- 寮圭獥缁勪欢 -->
+ <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 { 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 {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 tableData = ref([])
+const tableLoading = ref(false)
+const total = ref(0)
+const pageNum = ref(1)
+const pageSize = ref(10)
+
+// 鎵爜鐩稿叧鐘舵��
+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' } })
+ })
+})
+
+onShow(() => {
+ // 椤甸潰鏄剧ず鏃跺埛鏂版暟鎹�
+ 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()
+}
+
+// 鏍囩椤电偣鍑伙紙鍏煎鏃ф柟娉曪級
+const handleTabClick = (tab) => {
+ tabName.value = tab.props.name
+ activeTab.value = tab.props.name
+ tableData.value = []
+ getList()
+}
+
+// 鏌ヨ鏁版嵁
+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;
+ })
+ }
+}
+
+// 鍒嗛〉鍙樺寲
+const handlePageChange = (page) => {
+ pageNum.value = page
+ getList()
+}
+
+// 涓婁紶
+const handleAdd = (row) => {
+ nextTick(() => {
+ formDia.value?.openDialog(row)
+ })
+}
+
+// 鏌ョ湅闄勪欢
+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 () => {
+ try {
+ // 浣跨敤uniapp鐨勬壂鐮丄PI
+ uni.scanCode({
+ success: (res) => {
+ handleScanSuccess(res)
+ },
+ fail: (err) => {
+ console.error('鎵爜澶辫触:', err)
+ uni.showToast({
+ title: '鎵爜澶辫触',
+ icon: 'error'
+ })
+ }
+ })
+ } catch (e) {
+ console.error('鍚姩鎵爜澶辫触:', e)
+ uni.showToast({
+ title: '鍚姩鎵爜澶辫触',
+ icon: 'error'
+ })
+ }
+}
+
+const stopScan = async () => {
+ isScanning.value = false
+}
+
+// 鎵爜鎴愬姛澶勭悊
+const handleScanSuccess = async (result) => {
+ try {
+ uni.showToast({
+ title: '璇嗗埆鎴愬姛',
+ icon: 'success'
+ })
+
+ // 瑙f瀽浜岀淮鐮佹暟鎹�
+ let qrData
+ try {
+ qrData = JSON.parse(result.result)
+ } catch (e) {
+ qrData = { deviceName: result.result, location: '' }
+ }
+
+ callBackendAPI(qrData)
+ } catch (error) {
+ uni.showToast({
+ title: error.message || '鏁版嵁瑙f瀽澶辫触',
+ icon: 'error'
+ })
+ }
+}
+
+const callBackendAPI = (result) => {
+ nextTick(() => {
+ qrCodeFormDia.value?.openDialog(result)
+ })
+}
+
+// 鎵爜澶勭悊
+const handleScanCode = (result) => {
+ console.log('鎵爜缁撴灉:', result)
+ handleScanSuccess(result)
+}
+
+// 鎽勫儚澶撮敊璇鐞�
+const handleCameraError = (error) => {
+ console.error('鎽勫儚澶撮敊璇�:', error)
+ cameraError.value = '鎽勫儚澶磋闂け璐ワ紝璇锋鏌ユ潈闄愯缃�'
+}
+</script>
+
+<style scoped lang="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;
+ position: relative;
+ background-color: #fff;
+ width: 100%;
+}
+
+.tab-item {
+ flex: 1;
+ text-align: center;
+ padding: 20px 0;
+ font-size: 16px;
+ font-weight: 500;
+ color: #606266;
+ transition: all 0.3s ease;
+ cursor: pointer;
+ position: relative;
+ z-index: 2;
+}
+
+.tab-item.tab-active {
+ color: #1890ff;
+ font-weight: 600;
+}
+
+.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 {
+ display: flex;
+ justify-content: center;
+}
+
+.qr-scan-container {
+ position: relative;
+ width: 100%;
+ max-width: 500px;
+ margin: 0 auto;
+ background: #000;
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.qr-camera {
+ width: 100%;
+ height: 300px;
+}
+
+.scan-overlay {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 70%;
+ height: 70%;
+ 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;
+ left: 50%;
+ transform: translateX(-50%);
+ color: #fff;
+ font-size: 14px;
+ text-align: center;
+}
+
+@keyframes pulse {
+ 0% { opacity: 0.8; }
+ 50% { opacity: 0.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
--
Gitblit v1.9.3