| src/api/device/statusChangeRecord.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/equipmentManagement/deviceInfo.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/config.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/equipmentManagement/deviceInfo/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/works.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/static/images/icon/saomashebei.svg | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/device/statusChangeRecord.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ import request from '@/utils/request' export function listStatusChangeRecord(query) { return request({ url: '/device/statusChangeRecord/list', method: 'get', params: query }) } src/api/equipmentManagement/deviceInfo.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ import request from "@/utils/request"; // è·å设å¤åºæ¬ä¿¡æ¯ export function getDeviceInfo(id) { return request({ url: `/device/ledger/${id}`, method: "get", }); } src/config.js
@@ -1,6 +1,6 @@ // åºç¨å ¨å±é ç½® const config = { baseUrl: "http://1.15.17.182:9048", baseUrl: "http://192.168.0.31:25615", fileUrl: "http://1.15.17.182:9049", // åºç¨ä¿¡æ¯ appInfo: { src/pages.json
@@ -661,6 +661,13 @@ } }, { "path": "pages/equipmentManagement/deviceInfo/index", "style": { "navigationBarTitleText": "设å¤ä¿¡æ¯", "navigationStyle": "custom" } }, { "path": "pages/equipmentManagement/runManagement/index", "style": { "navigationBarTitleText": "è¿è¡ç®¡ç", src/pages/equipmentManagement/deviceInfo/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,275 @@ <template> <view class="device-info-container"> <PageHeader title="设å¤ä¿¡æ¯" @back="goBack" /> <!-- åºæ¬ä¿¡æ¯ --> <view class="info-card"> <view class="card-header"> <text class="card-title">åºæ¬ä¿¡æ¯</text> <text class="device-status">æ£å¸¸</text> </view> <view class="card-content"> <view class="info-row"> <text class="label">设å¤åç§°ï¼</text> <text class="value">{{ deviceInfo.deviceName || '--' }}</text> </view> <view class="info-row"> <text class="label">è§æ ¼åå·ï¼</text> <text class="value">{{ deviceInfo.deviceModel || '--' }}</text> </view> <view class="info-row"> <text class="label">ç产åå®¶ï¼</text> <text class="value">{{ deviceInfo.supplierName || '--' }}</text> </view> <view class="info-row"> <text class="label">åä½ï¼</text> <text class="value">{{ deviceInfo.unit || '--' }}</text> </view> </view> </view> <!-- åæ´è®°å½ --> <view class="info-card"> <view class="card-header"> <text class="card-title">åæ´è®°å½</text> </view> <view class="card-content"> <view v-if="!recordsLoading && changeRecords.length === 0" class="empty-tip">ææ åæ´è®°å½</view> <view v-else class="change-record" v-for="(item, index) in changeRecords" :key="index"> <view class="record-header"> <text class="record-time">{{ item.createTime }}</text> <text class="record-status" :class="approvalClass(item.approvalStatus)">{{ approvalText(item.approvalStatus) }}</text> </view> <view class="record-line"> <text class="record-status-change">{{ statusText(item.originalStatus) }} â {{ statusText(item.targetStatus) }}</text> <text class="record-user">ç³è¯·äººï¼{{ item.createUserName || '--' }}</text> </view> <view class="record-reason">åæ´åå ï¼{{ item.reason || '--' }}</view> <view v-if="item.approvalStatus === 'REJECTED' && item.rejectReason" class="record-reject">驳ååå ï¼{{ item.rejectReason }}</view> </view> </view> </view> </view> </template> <script setup> import { ref, reactive } from 'vue' import { onLoad } from '@dcloudio/uni-app' import PageHeader from '@/components/PageHeader.vue' import { getDeviceInfo } from '@/api/equipmentManagement/deviceInfo' import { listStatusChangeRecord } from '@/api/device/statusChangeRecord' const deviceInfo = reactive({ deviceName: '', deviceModel: '', supplierName: '', unit: '', }) const changeRecords = ref([]) const recordsLoading = ref(false) const statusText = (s) => (s == 1 ? 'å¯ç¨' : 'åç¨') const approvalText = (s) => { const map = { PENDING: '审æ¹ä¸', APPROVED: 'å·²éè¿', REJECTED: '已驳å' } return map[s] || s || '--' } const approvalClass = (s) => { const map = { PENDING: 'status-pending', APPROVED: 'status-approved', REJECTED: 'status-rejected' } return map[s] || '' } const fetchDeviceInfo = async (deviceId) => { try { const res = await getDeviceInfo(deviceId) console.log('设å¤ä¿¡æ¯ååº:', res) if (res.code === 200 && res.data) { Object.assign(deviceInfo, res.data) } } catch (error) { console.error('è·å设å¤ä¿¡æ¯å¤±è´¥:', error) } } const fetchChangeRecords = async (deviceId) => { recordsLoading.value = true try { const res = await listStatusChangeRecord({ deviceId, pageNum: 1, pageSize: 20 }) console.log('åæ´è®°å½ååº:', res) if (res.code === 200) { changeRecords.value = res.data?.records || res.data || [] } } catch (error) { console.error('è·ååæ´è®°å½å¤±è´¥:', error) } finally { recordsLoading.value = false } } const goBack = () => { uni.navigateBack() } onLoad((options) => { const deviceId = options?.deviceId || '' if (!deviceId) { uni.showToast({ title: '缺å°è®¾å¤ID', icon: 'none' }) return } fetchDeviceInfo(deviceId) fetchChangeRecords(deviceId) }) </script> <style scoped lang="scss"> .device-info-container { min-height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 16px 20px 20px; box-sizing: border-box; } .info-card { background: rgba(255, 255, 255, 0.95); border-radius: 16px; margin-bottom: 16px; overflow: hidden; } .card-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #ffffff; padding: 14px 20px; font-weight: 500; display: flex; justify-content: space-between; align-items: center; } .card-title { font-size: 15px; color: #ffffff; } .device-status { padding: 4px 14px; border-radius: 20px; font-size: 12px; color: #ffffff; background: #52c41a; } .card-content { padding: 16px 20px; } .info-row { display: flex; align-items: flex-start; margin-bottom: 12px; &:last-child { margin-bottom: 0; } } .label { width: 88px; flex-shrink: 0; color: #666666; font-size: 14px; } .value { flex: 1; color: #2c3e50; font-weight: 500; font-size: 14px; word-break: break-all; } .status-normal { color: #52c41a; } .empty-tip { color: #999999; text-align: center; padding: 20px 0; } .change-record { padding: 14px 0; border-bottom: 1px solid #f0f0f0; &:last-child { border-bottom: none; } } .record-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .record-time { color: #666666; font-size: 13px; } .record-status { font-size: 12px; padding: 2px 10px; border-radius: 12px; background: #f5f5f5; color: #666666; } .status-pending { background: #fff7e6; color: #fa8c16; } .status-approved { background: #f6ffed; color: #52c41a; } .status-rejected { background: #fff1f0; color: #f5222d; } .record-line { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; } .record-status-change { color: #2c3e50; font-weight: 500; font-size: 14px; } .record-user { color: #999999; font-size: 13px; } .record-reason { color: #666666; font-size: 13px; } .record-reject { color: #f5222d; font-size: 13px; margin-top: 4px; } </style> src/pages/index.vue
@@ -231,6 +231,11 @@ action: "scan", }, { label: "æ«ç æ¥è®¾å¤", icon: "/static/images/icon/saomashebei.svg", action: "scanDevice", }, { label: "设å¤å·¡æ£", icon: "/static/images/icon/xunjianshangchuan.svg", route: "/pages/inspectionUpload/index", @@ -265,6 +270,41 @@ overviewExpanded.value = !overviewExpanded.value; } function getDeviceIdFromScan(scanResult) { if (!scanResult) return null; const match = scanResult.match(/deviceId=(\d+)/); if (match && match[1]) return match[1]; if (/^\d+$/.test(scanResult.trim())) return scanResult.trim(); try { const obj = JSON.parse(scanResult); if (obj.deviceId) return String(obj.deviceId); } catch (e) { // 忽ç¥é JSON å 容 } return null; } function scanDevice() { uni.scanCode({ scanType: ["qrCode", "barCode"], success: (res) => { console.log("æ«ç ç»æ:", res.result); const deviceId = getDeviceIdFromScan(res.result); if (!deviceId) { uni.showToast({ title: "æªè¯å«å°è®¾å¤ID", icon: "none" }); return; } uni.navigateTo({ url: `/pages/equipmentManagement/deviceInfo/index?deviceId=${deviceId}`, }); }, fail: (err) => { console.error("æ«ç 失败:", err); uni.showToast({ title: "æ«ç 失败ï¼è¯·éè¯", icon: "none" }); }, }); } function handleQuickTool(item) { if (item?.action === "scan") { // ç产æ¥å·¥ - è°ç¨æ«ç @@ -286,6 +326,10 @@ console.error("æ«ç 失败:", err); } }); return; } if (item?.action === "scanDevice") { scanDevice(); return; } if (!item?.route) return; @@ -322,7 +366,7 @@ allowedMenuTitles.value = titles; quickTools.value = quickToolSource.filter((item) => titles.has(item.label) item.action === "scanDevice" || titles.has(item.label) ); } src/pages/works.vue
@@ -656,6 +656,10 @@ // label: '设å¤å°è´¦', // }, { icon: "/static/images/icon/saomashebei.svg", label: "æ«ç æ¥è®¾å¤", }, { icon: "/static/images/icon/yunxingguanli.svg", label: "è¿è¡ç®¡ç", }, @@ -672,6 +676,42 @@ label: "设å¤å·¡æ£", }, ]); // æ«ç æ¥è®¾å¤ï¼è§£æ deviceId å跳转å°è®¾å¤ä¿¡æ¯é¡µ const getDeviceIdFromScan = scanResult => { if (!scanResult) return null; const match = scanResult.match(/deviceId=(\d+)/); if (match && match[1]) return match[1]; if (/^\d+$/.test(scanResult.trim())) return scanResult.trim(); try { const obj = JSON.parse(scanResult); if (obj.deviceId) return String(obj.deviceId); } catch (e) { // 忽ç¥é JSON å 容 } return null; }; const startScanDevice = () => { uni.scanCode({ scanType: ["qrCode", "barCode"], success: res => { console.log("æ«ç ç»æ:", res.result); const deviceId = getDeviceIdFromScan(res.result); if (!deviceId) { uni.showToast({ title: "æªè¯å«å°è®¾å¤ID", icon: "none" }); return; } uni.navigateTo({ url: `/pages/equipmentManagement/deviceInfo/index?deviceId=${deviceId}`, }); }, fail: err => { console.error("æ«ç 失败:", err); uni.showToast({ title: "æ«ç 失败ï¼è¯·éè¯", icon: "none" }); }, }); }; // å¤ç常ç¨åè½ç¹å» const handleCommonItemClick = item => { @@ -938,6 +978,9 @@ uni.navigateTo({ url: "/pages/equipmentManagement/ledger/index", }); break; case "æ«ç æ¥è®¾å¤": startScanDevice(); break; case "è¿è¡ç®¡ç": uni.navigateTo({ @@ -1258,7 +1301,7 @@ // æ¶éææææéçèåæ é¢ï¼æ ¹æ® meta.titleï¼ const allowedMenuTitles = new Set(); const alwaysShowTitles = new Set(["éè´éè´§å", "ä¾åºå管ç"]); const alwaysShowTitles = new Set(["éè´éè´§å", "ä¾åºå管ç", "æ«ç æ¥è®¾å¤"]); const collectMenuTitles = routes => { if (!Array.isArray(routes)) return; routes.forEach(route => { @@ -1284,6 +1327,7 @@ // éç¨è¿æ»¤å½æ° const filterArray = (targetArray, specialMapping) => { const filtered = targetArray.filter(item => { if (alwaysShowTitles.has(item.label)) return true; let matched = allowedMenuTitles.has(item.label); if (specialMapping && !matched && specialMapping[item.label]) { matched = allowedMenuTitles.has(specialMapping[item.label]); src/static/images/icon/saomashebei.svg
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ <svg xmlns="http://www.w3.org/2000/svg" fill="none" version="1.1" width="28" height="28" viewBox="0 0 28 28"> <rect x="1" y="1" width="26" height="26" rx="6" fill="#9C27B0"/> <rect x="7" y="7" width="5" height="5" rx="1" fill="#FFFFFF"/> <rect x="16" y="7" width="5" height="5" rx="1" fill="#FFFFFF"/> <rect x="7" y="16" width="5" height="5" rx="1" fill="#FFFFFF"/> <rect x="16" y="16" width="2.5" height="2.5" rx="0.5" fill="#FFFFFF"/> <rect x="19.5" y="16" width="2.5" height="2.5" rx="0.5" fill="#FFFFFF"/> <rect x="16" y="19.5" width="2.5" height="2.5" rx="0.5" fill="#FFFFFF"/> </svg>