From 3f85e5410dda49e7e6a6292859649513f3644cb2 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 28 八月 2026 14:44:12 +0800
Subject: [PATCH] 天津豹鸣app 1.添加扫码查看设备变更记录功能
---
src/api/device/statusChangeRecord.js | 9 +
src/pages/index.vue | 46 ++++++
src/pages.json | 7 +
src/pages/works.vue | 46 ++++++
src/api/equipmentManagement/deviceInfo.js | 9 +
src/pages/equipmentManagement/deviceInfo/index.vue | 275 +++++++++++++++++++++++++++++++++++++++
src/config.js | 2
src/static/images/icon/saomashebei.svg | 9 +
8 files changed, 400 insertions(+), 3 deletions(-)
diff --git a/src/api/device/statusChangeRecord.js b/src/api/device/statusChangeRecord.js
new file mode 100644
index 0000000..a4a5367
--- /dev/null
+++ b/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
+ })
+}
diff --git a/src/api/equipmentManagement/deviceInfo.js b/src/api/equipmentManagement/deviceInfo.js
new file mode 100644
index 0000000..fa912b1
--- /dev/null
+++ b/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",
+ });
+}
diff --git a/src/config.js b/src/config.js
index 27244b3..2654b1c 100644
--- a/src/config.js
+++ b/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: {
diff --git a/src/pages.json b/src/pages.json
index 1aa49ad..e61cc28 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -661,6 +661,13 @@
}
},
{
+ "path": "pages/equipmentManagement/deviceInfo/index",
+ "style": {
+ "navigationBarTitleText": "璁惧淇℃伅",
+ "navigationStyle": "custom"
+ }
+ },
+ {
"path": "pages/equipmentManagement/runManagement/index",
"style": {
"navigationBarTitleText": "杩愯绠$悊",
diff --git a/src/pages/equipmentManagement/deviceInfo/index.vue b/src/pages/equipmentManagement/deviceInfo/index.vue
new file mode 100644
index 0000000..5972626
--- /dev/null
+++ b/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">姝e父</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>
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 2d253b2..47fd3fe 100644
--- a/src/pages/index.vue
+++ b/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)
);
}
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 9e89ddf..3b7ffa7 100644
--- a/src/pages/works.vue
+++ b/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: "璁惧宸℃",
},
]);
+
+ // 鎵爜鏌ヨ澶囷細瑙f瀽 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]);
diff --git a/src/static/images/icon/saomashebei.svg b/src/static/images/icon/saomashebei.svg
new file mode 100644
index 0000000..84852ea
--- /dev/null
+++ b/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>
--
Gitblit v1.9.3