From af4f45eaa2703ecf991bd10f07f6df179f2677d9 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 19 十一月 2025 10:04:45 +0800
Subject: [PATCH] Merge branch 'refs/heads/yyb'
---
src/pages.json | 22
src/pages/production/twist/receive/monofil.vue | 96
src/api/routingInspection/routingInspection.ts | 63
src/pages/production/detail/wireDetail.vue | 3
src/pages/production/twist/report/form.vue | 184 +
src/pages/production/twist/components/MonofilCard.vue | 152 +
src/pages/production/twist/report/draw.vue | 2
src/pages/production/wire/attachment/index.vue | 232 ++
src/pages/production/twist/report/index.vue | 205 ++
src/pages/production/components/ProductionCard.vue | 2
src/pages/production/twist/attachment/index.vue | 221 ++
src/pages/routingInspection/detail/indexJX.vue | 867 +++++++++++
src/manifest.json | 2
src/pages/production/list/index.vue | 17
src/pages/routingInspection/product_card/index.vue | 202 ++
src/utils/request.ts | 3
src/pages/production/twist/components/TwistReportCard.vue | 37
src/composables/useScanCode.ts | 249 +++
src/pages/index/index.vue | 35
src/pages/production/twist/receive/index.vue | 8
src/pages/routingInspection/upload.vue | 587 +++++++
src/pages/production/components/Statistics.vue | 4
src/api/product/twist.ts | 18
src/pages/routingInspection/index.vue | 164 ++
src/pages/production/twist/receive/steelCore/edit.vue | 5
src/pages/routingInspection/list/index.vue | 130 +
src/pages/production/detail/twistDetail.vue | 3
src/App.vue | 59
src/pages/production/index.vue | 40
src/pages/production/twist/receive/steelCore/index.vue | 82 +
src/components/product_card/index.vue | 13
src/pages/production/twist/receive/steelCore/form.vue | 80 +
src/static/icons/routingInspection.png | 0
src/utils/cache.ts | 17
src/pages/routingInspection/detail/indexLS.vue | 788 ++++++++++
35 files changed, 4,328 insertions(+), 264 deletions(-)
diff --git a/src/App.vue b/src/App.vue
index 220abd9..e1a44ed 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,22 +1,81 @@
<script setup lang="ts">
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
import { useThemeStore } from "@/store";
+import { ref } from "vue";
// 涓婚鍒濆鍖�
const themeStore = useThemeStore();
+
+// 鍏ㄥ眬鎵爜骞挎挱鎺ユ敹鍣�
+let main: any = null;
+let receiver: any = null;
+let filter: any = null;
+
+// 鍒濆鍖栨壂鐮佸箍鎾帴鏀�
+const initGlobalScan = () => {
+ // #ifdef APP-PLUS
+ try {
+ main = plus.android.runtimeMainActivity();
+ const IntentFilter = plus.android.importClass("android.content.IntentFilter");
+ filter = new IntentFilter();
+ filter.addAction("com.dwexample.ACTION");
+
+ receiver = plus.android.implements("io.dcloud.feature.internal.reflect.BroadcastReceiver", {
+ onReceive: (context: any, intent: any) => {
+ console.log("馃攳 [鍏ㄥ眬Scan] onReceive 瑙﹀彂:", context, intent);
+ plus.android.importClass(intent);
+ const scanResult = intent.getStringExtra("com.motorolasolutions.emdk.datawedge.data_string");
+ console.log("馃攳 [鍏ㄥ眬Scan] 鎵弿缁撴灉:", scanResult);
+
+ // 鍙戦�佸埌鎵�鏈夊彲鑳界殑浜嬩欢
+ const eventNames = ["scan", "scanIndex", "scanJX", "scanLS"];
+ eventNames.forEach((eventName) => {
+ uni.$emit(eventName, { code: scanResult });
+ console.log(`馃攳 [鍏ㄥ眬Scan] 宸插彂閫� ${eventName} 浜嬩欢`);
+ });
+ },
+ });
+
+ // 娉ㄥ唽骞挎挱鎺ユ敹鍣�
+ main.registerReceiver(receiver, filter);
+ console.log("馃攳 [鍏ㄥ眬Scan] 鍏ㄥ眬鎵爜骞挎挱鎺ユ敹鍣ㄥ凡鍚姩");
+ } catch (error) {
+ console.error("馃攳 [鍏ㄥ眬Scan] 鍒濆鍖栧け璐�:", error);
+ }
+ // #endif
+};
+
+// 鍋滄鎵爜骞挎挱鎺ユ敹
+const stopGlobalScan = () => {
+ // #ifdef APP-PLUS
+ try {
+ if (main && receiver) {
+ main.unregisterReceiver(receiver);
+ console.log("馃攳 [鍏ㄥ眬Scan] 鍏ㄥ眬鎵爜骞挎挱鎺ユ敹鍣ㄥ凡鍋滄");
+ }
+ } catch (error) {
+ console.error("馃攳 [鍏ㄥ眬Scan] 鍋滄澶辫触:", error);
+ }
+ // #endif
+};
onLaunch(() => {
console.log("App Launch");
// 鍒濆鍖栦富棰�
themeStore.initTheme();
+ // 鍒濆鍖栧叏灞�鎵爜骞挎挱鎺ユ敹鍣�
+ initGlobalScan();
});
onShow(() => {
console.log("App Show");
+ // 搴旂敤鏄剧ず鏃堕噸鏂板惎鍔ㄥ箍鎾帴鏀跺櫒
+ initGlobalScan();
});
onHide(() => {
console.log("App Hide");
+ // 搴旂敤闅愯棌鏃朵笉鍋滄骞挎挱锛堜繚鎸佸悗鍙版帴鏀讹級
});
</script>
diff --git a/src/api/product/twist.ts b/src/api/product/twist.ts
index 3360277..086f1d3 100644
--- a/src/api/product/twist.ts
+++ b/src/api/product/twist.ts
@@ -79,6 +79,24 @@
data: data,
});
},
+
+ // 鍒犻櫎鍗曚笣棰嗙敤
+ deleteStrandedWireDish(id: number) {
+ return request<BaseResult<any>>({
+ url: `/strandedWire/deleteStrandedWireDish/${id}`,
+ method: "DELETE",
+ });
+ },
+
+ // 鍒犻櫎缁炵嚎鎶ュ伐
+ deleteWireOutput(params: { id: number }) {
+ // 灏嗗弬鏁版嫾鎺ュ埌 URL 浣滀负 query 鍙傛暟
+ const queryString = `?id=${params.id}`;
+ return request<BaseResult<any>>({
+ url: `/strandedWire/deleteWireOutput${queryString}`,
+ method: "DELETE",
+ });
+ },
};
export default TwistApi;
diff --git a/src/api/routingInspection/routingInspection.ts b/src/api/routingInspection/routingInspection.ts
new file mode 100644
index 0000000..1e2488a
--- /dev/null
+++ b/src/api/routingInspection/routingInspection.ts
@@ -0,0 +1,63 @@
+import request from "@/utils/request";
+import { BaseResult } from "@/models/base";
+
+const RoutingInspectionApi = {
+ // 鏌ヨ宸℃璁板綍
+ getDeviceInspectListByPatrol(params: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/getDeviceInspectListByPatrol",
+ method: "GET",
+ data: params,
+ });
+ },
+ // 鑾峰彇宸℃鏁版嵁
+ getInspectListByPatrol(data: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/getInspectListByPatrol",
+ method: "POST",
+ data: data,
+ });
+ },
+ // 鑾峰彇鎷変笣鍗曚釜缁撴瀯璁板綍 0
+ getDrawInspectInfoById(params: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/getDrawInspectInfoById/" + params.id,
+ method: "GET",
+ // data: params,
+ });
+ },
+ // 鑾峰彇缁炵嚎鍗曚釜缁撴瀯璁板綍 1
+ getStrandedInspectionStructureInfoById(params: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/getStrandedInspectionStructureInfoById/" + params.id,
+ method: "GET",
+ // data: params,
+ });
+ },
+ // 鎷変笣宸℃淇濆瓨
+ drawPatrolCheckInspection(data: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/drawPatrolCheckInspection?deviceUid=" + data.deviceUid,
+ method: "POST",
+ data: data,
+ });
+ },
+ // 缁炵嚎宸℃淇濆瓨
+ strandedPatrolCheckInspection(data: any) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/strandedPatrolCheckInspection?deviceUid=" + data.deviceUid,
+ method: "POST",
+ data: data,
+ });
+ },
+
+ // 楠岃瘉浜岀淮鐮�
+ assertScanQR(params: { deviceUid: string }) {
+ return request<BaseResult<any>>({
+ url: "/wireInspection/assertScanQR?deviceUid=" + params.deviceUid,
+ method: "GET",
+ });
+ },
+};
+
+export default RoutingInspectionApi;
diff --git a/src/components/product_card/index.vue b/src/components/product_card/index.vue
index 9fb6b8c..24ff6e9 100644
--- a/src/components/product_card/index.vue
+++ b/src/components/product_card/index.vue
@@ -8,6 +8,19 @@
</wd-tag>
</view>
</template>
+ <wd-row class="my-2" v-if="data[map.systemNo]">
+ <wd-col :span="24">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 璐ㄩ噺杩芥函鍙�:
+ <text class="text-[#252525]">{{ data[map.systemNo] }}</text>
+ </text>
+ </view>
+ </wd-col>
+ </wd-row>
<wd-row class="my-2">
<wd-col :span="12">
<view class="flex">
diff --git a/src/composables/useScanCode.ts b/src/composables/useScanCode.ts
new file mode 100644
index 0000000..2c77588
--- /dev/null
+++ b/src/composables/useScanCode.ts
@@ -0,0 +1,249 @@
+import { ref, computed, onUnmounted } from "vue";
+import { onShow, onHide } from "@dcloudio/uni-app";
+import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
+
+/**
+ * 鎵爜鏁版嵁鎺ュ彛
+ */
+interface ScanCodeData {
+ uid?: string;
+ deviceModel?: string;
+ [key: string]: any;
+}
+
+// 鍏ㄥ眬鐩戝惉鍣ㄧ姸鎬佹槧灏勶紙纭繚姣忎釜浜嬩欢鍚嶅彧鏈変竴涓洃鍚櫒锛�
+const globalListeners = new Map<string, boolean>();
+
+// 娣诲姞涓�涓叏灞�鐨勬崟鑾锋墍鏈夋壂鐮佷簨浠剁殑鐩戝惉鍣紙鐢ㄤ簬璋冭瘯锛�
+let debugListenerInitialized = false;
+
+const initDebugListener = () => {
+ if (debugListenerInitialized) return;
+
+ // 鐩戝惉鎵�鏈夊彲鑳界殑鎵爜浜嬩欢
+ const eventNames = ["scan", "scanIndex", "scanJX", "scanLS"];
+ eventNames.forEach((eventName) => {
+ uni.$on(eventName, (data: any) => {
+ console.log(`馃攳 [鍏ㄥ眬璋冭瘯] 鎹曡幏鍒� ${eventName} 浜嬩欢:`, data);
+ });
+ });
+
+ debugListenerInitialized = true;
+ console.log("馃攳 [鍏ㄥ眬璋冭瘯] 璋冭瘯鐩戝惉鍣ㄥ凡鍒濆鍖�");
+};
+
+/**
+ * 鎵爜绠$悊 Composable
+ * 缁熶竴绠$悊鎵爜浜嬩欢鐩戝惉銆佺紦瀛樺瓨鍌ㄥ拰鏁版嵁璇诲彇
+ * 鍏ㄥ眬鐩戝惉鍣紝涓嶉殢椤甸潰鍒囨崲鑰屽叧闂�
+ * @param eventName 鐩戝惉鐨勪簨浠跺悕绉帮紝榛樿涓� "scan"
+ */
+export function useScanCode(eventName: string = "scan") {
+ // 褰撳墠鎵爜鐨勮澶� UID
+ const deviceUid = ref<string>("");
+ // 褰撳墠鎵爜鐨勬満鍙板瀷鍙�
+ const deviceModel = ref<string>("");
+ // 瀹屾暣鐨勬壂鐮佹暟鎹�
+ const scanData = ref<ScanCodeData>({});
+ // 淇濆瓨浜嬩欢鍚嶇О
+ const currentEventName = eventName;
+
+ /**
+ * 浠庢湰鍦扮紦瀛樺姞杞芥壂鐮佹暟鎹�
+ */
+ const loadFromCache = () => {
+ try {
+ const cachedData = uni.getStorageSync("scanCodeData");
+ if (cachedData) {
+ scanData.value = cachedData;
+ deviceUid.value = cachedData.uid || "";
+ deviceModel.value = cachedData.deviceModel || "";
+ console.log("[useScanCode] 浠庣紦瀛樺姞杞芥壂鐮佹暟鎹�:", cachedData);
+ return cachedData;
+ }
+ } catch (error) {
+ console.error("[useScanCode] 璇诲彇缂撳瓨澶辫触:", error);
+ }
+ return null;
+ };
+
+ /**
+ * 淇濆瓨鎵爜鏁版嵁鍒扮紦瀛�
+ */
+ const saveToCache = (data: ScanCodeData) => {
+ try {
+ uni.setStorageSync("scanCodeData", data);
+ console.log("[useScanCode] 宸蹭繚瀛樺埌缂撳瓨:", data);
+ return true;
+ } catch (error) {
+ console.error("[useScanCode] 淇濆瓨缂撳瓨澶辫触:", error);
+ return false;
+ }
+ };
+
+ /**
+ * 娓呯┖鎵爜鏁版嵁鍜岀紦瀛�
+ */
+ const clearScanData = () => {
+ try {
+ uni.removeStorageSync("scanCodeData");
+ deviceUid.value = "";
+ deviceModel.value = "";
+ scanData.value = {};
+ console.log("[useScanCode] 宸叉竻绌烘壂鐮佹暟鎹�");
+ } catch (error) {
+ console.error("[useScanCode] 娓呯┖缂撳瓨澶辫触:", error);
+ }
+ };
+
+ /**
+ * 楠岃瘉浜岀淮鐮侊紙浠呰皟鐢ㄦ帴鍙o紝涓嶅鐞嗚繑鍥炵粨鏋滐級
+ */
+ const validateQRCode = async (uid: string): Promise<void> => {
+ try {
+ console.log("[useScanCode] 璋冪敤楠岃瘉浜岀淮鐮佹帴鍙�, deviceUid:", uid);
+ await RoutingInspectionApi.assertScanQR({ deviceUid: uid });
+ console.log("[useScanCode] 楠岃瘉鎺ュ彛璋冪敤瀹屾垚");
+ } catch (error: any) {
+ console.error("[useScanCode] 楠岃瘉鎺ュ彛璋冪敤寮傚父:", error);
+ // 鍗充娇寮傚父涔熶笉褰卞搷鍚庣画娴佺▼
+ }
+ };
+
+ /**
+ * 澶勭悊鎵爜浜嬩欢
+ */
+ const handleScanEvent = async (params: any) => {
+ console.log(`========== [useScanCode][${currentEventName}] 鏀跺埌鎵爜浜嬩欢 ==========`);
+ console.log(`[useScanCode][${currentEventName}] 鎺ユ敹鍙傛暟:`, params);
+ console.log(`[useScanCode][${currentEventName}] 瑙﹀彂鏃堕棿:`, new Date().toLocaleTimeString());
+
+ try {
+ if (!params?.code) {
+ console.warn("[useScanCode] 鎵爜鍐呭涓虹┖");
+ return;
+ }
+
+ let codeObj: ScanCodeData = {};
+ try {
+ codeObj = JSON.parse(params.code);
+ console.log("[useScanCode] 瑙f瀽鍚庣殑瀵硅薄:", codeObj);
+ } catch (err) {
+ console.error("[useScanCode] JSON 瑙f瀽澶辫触:", err);
+ console.log("[useScanCode] 鍘熷瀛楃涓�:", params.code);
+ // 濡傛灉涓嶆槸 JSON锛屽皾璇曚綔涓烘櫘閫氬瓧绗︿覆澶勭悊
+ codeObj = { code: params.code };
+ }
+
+ // 妫�鏌ユ槸鍚︽湁蹇呰鐨勫瓧娈碉紙uid 鎴� deviceModel锛�
+ if (!codeObj.uid && !codeObj.deviceModel) {
+ console.warn("[useScanCode] 鎵爜鏁版嵁缂哄皯 uid 鍜� deviceModel锛屼笉淇濆瓨缂撳瓨");
+ uni.showToast({
+ title: "鎵爜鏁版嵁鏃犳晥",
+ icon: "none",
+ });
+ return;
+ }
+
+ // 鏇存柊鏈湴鐘舵��
+ scanData.value = codeObj;
+ deviceUid.value = codeObj.uid || "";
+ deviceModel.value = codeObj.deviceModel || "";
+
+ // 淇濆瓨鍒扮紦瀛�
+ saveToCache(codeObj);
+
+ // 濡傛灉鏈� uid锛岃皟鐢ㄩ獙璇佹帴鍙o紙涓嶇瓑寰呯粨鏋滐級
+ if (codeObj.uid) {
+ validateQRCode(codeObj.uid);
+ }
+
+ // 鏄剧ず鎴愬姛鎻愮ず
+ uni.showToast({
+ title: "鎵爜鎴愬姛",
+ icon: "success",
+ });
+
+ console.log("[useScanCode] 鎵爜鏁版嵁宸叉洿鏂�:", {
+ uid: deviceUid.value,
+ deviceModel: deviceModel.value,
+ });
+ } catch (error) {
+ console.error("[useScanCode] 澶勭悊鎵爜鏁版嵁寮傚父:", error);
+ }
+ };
+
+ /**
+ * 鍚敤鎵爜鐩戝惉锛堝叏灞�锛屾瘡娆¢兘閲嶆柊娉ㄥ唽浠ョ‘淇濇湁鏁堬級
+ */
+ const enableListener = () => {
+ // 鍏堢Щ闄ゅ彲鑳藉瓨鍦ㄧ殑鏃х洃鍚櫒
+ uni.$off(currentEventName, handleScanEvent);
+ // 娣诲姞鏂扮殑鐩戝惉鍣�
+ uni.$on(currentEventName, handleScanEvent);
+ // 鏍囪涓哄叏灞�宸插惎鐢�
+ globalListeners.set(currentEventName, true);
+ console.log(
+ `[useScanCode][${currentEventName}] 鉁� 鍏ㄥ眬鐩戝惉鍣ㄥ凡鍚敤/鍒锋柊锛堜笉浼氶殢椤甸潰鍒囨崲鍏抽棴锛塦
+ );
+ };
+
+ /**
+ * 绂佺敤鎵爜鐩戝惉锛堜粎鐢ㄤ簬搴旂敤閫�鍑烘椂娓呯悊锛屾甯搁〉闈㈠垏鎹笉璋冪敤锛�
+ */
+ const disableListener = () => {
+ if (!globalListeners.get(currentEventName)) {
+ console.log(`[useScanCode][${currentEventName}] 鐩戝惉鍣ㄦ湭鍚敤锛岃烦杩嘸);
+ return;
+ }
+
+ uni.$off(currentEventName, handleScanEvent);
+ globalListeners.delete(currentEventName);
+ console.log(`[useScanCode][${currentEventName}] 鉂� 鍏ㄥ眬鐩戝惉鍣ㄥ凡绂佺敤`);
+ };
+
+ /**
+ * 璁剧疆椤甸潰鐢熷懡鍛ㄦ湡閽╁瓙锛堝叏灞�鐩戝惉鍣ㄦā寮忥級
+ * 鐩戝惉鍣ㄥ叏灞�鍚敤涓�娆★紝涓嶉殢椤甸潰鍒囨崲鍏抽棴
+ * @param options 閰嶇疆閫夐」
+ */
+ const setupLifecycle = (
+ options: {
+ loadCacheOnShow?: boolean; // 鏄惁鍦� onShow 鏃跺姞杞界紦瀛�
+ } = {}
+ ) => {
+ const { loadCacheOnShow = true } = options;
+
+ // 鍙湪 onShow 鏃跺姞杞界紦瀛橈紝涓嶇鐢ㄧ洃鍚櫒
+ if (loadCacheOnShow) {
+ onShow(() => {
+ console.log(`[useScanCode][${currentEventName}] onShow 瑙﹀彂`);
+ loadFromCache();
+ });
+ }
+
+ // 娉ㄦ剰锛氫笉鍐嶅湪 onHide 鍜� onUnmounted 涓鐢ㄧ洃鍚櫒
+ // 鐩戝惉鍣ㄤ繚鎸佸叏灞�婵�娲荤姸鎬�
+ };
+
+ // 椤甸潰鍔犺浇鏃惰嚜鍔ㄤ粠缂撳瓨璇诲彇
+ loadFromCache();
+
+ return {
+ // 鐘舵��
+ deviceUid,
+ deviceModel,
+ scanData,
+ // 璁$畻灞炴��
+ hasScanned: computed(() => !!deviceUid.value),
+ displayText: computed(() => deviceModel.value || "鏈壂鐮�"),
+ // 鏂规硶
+ loadFromCache,
+ saveToCache,
+ clearScanData,
+ validateQRCode,
+ enableListener,
+ disableListener,
+ setupLifecycle,
+ };
+}
diff --git a/src/manifest.json b/src/manifest.json
index 280f32b..1054727 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -2,7 +2,7 @@
"name" : "绾跨紗涓婃姤",
"appid" : "__UNI__F64E0A4",
"description" : "",
- "versionName" : "1.0.12",
+ "versionName" : "1.0.15",
"versionCode" : "100",
"transformPx" : false,
/* 5+App鐗规湁鐩稿叧 */
diff --git a/src/pages.json b/src/pages.json
index 55210a1..6841877 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -6,7 +6,6 @@
"^cu-(.*)": "@/components/cu-$1/index.vue"
}
},
-
"pages": [
{
"path": "pages/index/index",
@@ -98,7 +97,6 @@
"navigationBarTitleText": "涓汉璧勬枡"
}
},
-
{
"path": "pages/work/user/index",
"style": {
@@ -284,6 +282,24 @@
"style": {
"navigationBarTitleText": "鏃舵晥鎶ュ伐"
}
+ },
+ {
+ "path": "pages/routingInspection/index",
+ "style": {
+ "navigationBarTitleText": "宸℃"
+ }
+ },
+ {
+ "path": "pages/routingInspection/detail/indexJX",
+ "style": {
+ "navigationBarTitleText": "缁炵嚎宸℃璇︽儏"
+ }
+ },
+ {
+ "path": "pages/routingInspection/detail/indexLS",
+ "style": {
+ "navigationBarTitleText": "鎷変笣宸℃璇︽儏"
+ }
}
],
"globalStyle": {
@@ -317,4 +333,4 @@
}
]
}
-}
+}
\ No newline at end of file
diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue
index 2df7101..46174fc 100644
--- a/src/pages/index/index.vue
+++ b/src/pages/index/index.vue
@@ -18,8 +18,8 @@
</wd-notice-bar>
<!-- 蹇嵎瀵艰埅 -->
<wd-grid clickable :column="1" class="mt-2">
- <view v-for="(item, index) in navList">
- <wd-grid-item v-if="item.show" :key="index" use-slot link-type="navigateTo" :url="item.url">
+ <view v-for="(item, index) in navList" :key="index">
+ <wd-grid-item v-if="item.show" use-slot link-type="navigateTo" :url="item.url">
<view class="p-2">
<image class="w-72rpx h-72rpx rounded-8rpx" :src="item.icon" />
</view>
@@ -87,11 +87,12 @@
</template>
<script setup lang="ts">
-import { reactive } from "vue";
+import { reactive, computed } from "vue";
import { dayjs, useMessage, useToast } from "wot-design-uni";
import LogAPI, { VisitStatsVO } from "@/api/system/log";
import WorkerCallingCard from "@/components/worker-calling-card/index.vue";
import HomeApi from "@/api/home";
+import { useUserStore } from "@/store/modules/user";
const visitStatsData = ref<VisitStatsVO>({
todayUvCount: 0,
@@ -104,6 +105,22 @@
const message = useMessage();
const toast = useToast();
+
+// 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+const userStore = useUserStore();
+const userInfo: any = computed(() => userStore.userInfo);
+
+// 鍒ゆ柇鏄惁涓哄贰妫�鍛樿鑹�
+const isInspector = computed(() => {
+ if (!userInfo.value || !userInfo.value.roles || !Array.isArray(userInfo.value.roles)) {
+ return false;
+ }
+ console.log(
+ "userInfo.value.roles",
+ userInfo.value.roles.some((role: any) => role.roleKey === "qualitative-inspector")
+ );
+ return userInfo.value.roles.some((role: any) => role.roleKey === "qualitative-inspector");
+});
const fileProgress = reactive({
show: false,
@@ -177,6 +194,12 @@
url: "/pages/timely/index",
show: false,
},
+ {
+ icon: "/static/icons/routingInspection.png",
+ title: "宸℃",
+ url: "/pages/routingInspection/index",
+ show: false,
+ },
]);
// 鍔犺浇璁块棶缁熻鏁版嵁
@@ -225,11 +248,17 @@
const init = async () => {
checkVersion();
const { data } = await HomeApi.getIndex();
+
+ // 鍒ゆ柇鏄惁涓哄贰妫�鍛樿鑹�
if (data.deviceGroupName == "鏃舵晥缁�") {
navList[1].show = true;
} else {
navList[0].show = true;
}
+ if (isInspector.value) {
+ // 濡傛灉鏄贰妫�鍛橈紝鏄剧ず宸℃鑿滃崟
+ navList[2].show = true;
+ }
};
/**
diff --git a/src/pages/production/components/ProductionCard.vue b/src/pages/production/components/ProductionCard.vue
index f5a9a84..108eae9 100644
--- a/src/pages/production/components/ProductionCard.vue
+++ b/src/pages/production/components/ProductionCard.vue
@@ -1,6 +1,6 @@
<template>
<wd-row>
- <wd-col v-for="(item, index) in data" :key="index" :span="item.span ?? 12" class="my-1">
+ <wd-col v-for="(item, index) in data" :key="index" :span="24" class="my-1">
<view class="flex w-full h-[20px]">
<view class="text-[#646874] pl-1 mr-3">{{ item.label }}</view>
<view class="font-medium pr-1" :style="{ color: item.color ?? color }">
diff --git a/src/pages/production/components/Statistics.vue b/src/pages/production/components/Statistics.vue
index 094e0e2..b35822d 100644
--- a/src/pages/production/components/Statistics.vue
+++ b/src/pages/production/components/Statistics.vue
@@ -1,6 +1,6 @@
<template>
<view class="statistics_box">
- <wd-row>
+ <!-- <wd-row>
<wd-col :span="12">
<view class="h_48 px-4 flex items-center">
<view class="icon_box">
@@ -19,7 +19,7 @@
<text class="text-lg text-[#339599] ml-2 font-semibold">87%</text>
</view>
</wd-col>
- </wd-row>
+ </wd-row> -->
</view>
</template>
<style scoped lang="scss">
diff --git a/src/pages/production/detail/twistDetail.vue b/src/pages/production/detail/twistDetail.vue
index 6ccb078..fede20a 100644
--- a/src/pages/production/detail/twistDetail.vue
+++ b/src/pages/production/detail/twistDetail.vue
@@ -5,6 +5,7 @@
:map="{
deviceModel: 'deviceModel',
model: 'model',
+ systemNo: 'systemNo',
totalAmount: 'totalAmount',
amount: 'amount',
unAmount: 'unAmount',
@@ -50,6 +51,7 @@
const cardData = reactive({
deviceModel: undefined,
model: undefined,
+ systemNo: undefined,
totalAmount: undefined,
amount: undefined,
unAmount: undefined,
@@ -61,6 +63,7 @@
});
cardData.deviceModel = data.deviceModel;
cardData.model = data.model;
+ cardData.systemNo = data.systemNo;
cardData.totalAmount = data.totalLength;
cardData.amount = data.length;
cardData.unAmount = data.unLength;
diff --git a/src/pages/production/detail/wireDetail.vue b/src/pages/production/detail/wireDetail.vue
index 305e6e0..29f6caf 100644
--- a/src/pages/production/detail/wireDetail.vue
+++ b/src/pages/production/detail/wireDetail.vue
@@ -5,6 +5,7 @@
:map="{
deviceModel: 'deviceModel',
model: 'model',
+ systemNo: 'systemNo',
totalAmount: 'totalAmount',
amount: 'amount',
unAmount: 'unAmount',
@@ -50,6 +51,7 @@
const cardData = reactive({
deviceModel: undefined,
model: undefined,
+ systemNo: undefined,
totalAmount: undefined,
amount: undefined,
unAmount: undefined,
@@ -62,6 +64,7 @@
});
cardData.deviceModel = data.deviceModel;
cardData.model = data.model;
+ cardData.systemNo = data.systemNo;
cardData.totalAmount = data.totalAmount;
cardData.amount = data.amount;
cardData.unAmount = data.unAmount;
diff --git a/src/pages/production/index.vue b/src/pages/production/index.vue
index 017062f..1fbe803 100644
--- a/src/pages/production/index.vue
+++ b/src/pages/production/index.vue
@@ -2,7 +2,14 @@
<view>
<wd-row>
<wd-col :span="21">
- <wd-search placeholder-left hide-cancel></wd-search>
+ <wd-search
+ v-model="searchKeyword"
+ placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
+ placeholder-left
+ hide-cancel
+ @search="handleSearch"
+ @clear="handleClear"
+ ></wd-search>
</wd-col>
<wd-col :span="3">
<view class="scan_box" @click="openScan">
@@ -14,16 +21,30 @@
<wd-tab :title="`寰呯敓浜�(${total.wait})`" class="tab_bg">
<ProductList
ref="waitRef"
+ :key="`wait-${searchKey}`"
:api="ManageApi.getProductList"
state="寰呭畬鎴�"
+ :model="searchKeyword"
@ok="changeWait"
+ />
+ </wd-tab>
+ <wd-tab :title="`閮ㄥ垎瀹屾垚(${total.partial})`" class="tab_bg">
+ <ProductList
+ ref="partialRef"
+ :key="`partial-${searchKey}`"
+ :api="ManageApi.getProductList"
+ state="閮ㄥ垎瀹屾垚"
+ :model="searchKeyword"
+ @ok="changePartial"
/>
</wd-tab>
<wd-tab :title="`宸茬敓浜�(${total.already})`" class="tab_bg">
<ProductList
ref="alreadyRef"
+ :key="`already-${searchKey}`"
:api="ManageApi.getProductList"
state="宸插畬鎴�"
+ :model="searchKeyword"
@ok="changeAlready"
/>
</wd-tab>
@@ -48,10 +69,14 @@
const toast = useToast();
const waitRef = ref();
+const partialRef = ref();
const alreadyRef = ref();
const tab = ref<number>(0);
+const searchKeyword = ref("");
+const searchKey = ref(0);
const total = reactive({
wait: 0,
+ partial: 0,
already: 0,
});
@@ -59,10 +84,23 @@
total.wait = num;
};
+const changePartial = (num: number) => {
+ total.partial = num;
+};
+
const changeAlready = (num: number) => {
total.already = num;
};
+const handleSearch = () => {
+ searchKey.value++;
+};
+
+const handleClear = () => {
+ searchKeyword.value = "";
+ handleSearch();
+};
+
const openScan = () => {
scanRef.value.triggerScan();
};
diff --git a/src/pages/production/list/index.vue b/src/pages/production/list/index.vue
index 92862f8..79b8d0e 100644
--- a/src/pages/production/list/index.vue
+++ b/src/pages/production/list/index.vue
@@ -36,6 +36,7 @@
const map = reactive({
deviceModel: "deviceModel",
model: "model",
+ systemNo: "systemNo",
totalAmount: "totalAmount",
amount: "amount",
unAmount: "unAmount",
@@ -50,13 +51,17 @@
type: String,
default: "",
},
+ model: {
+ type: String,
+ default: "",
+ },
});
const emits = defineEmits(["ok"]);
const list = ref<any[]>([]);
const toDetail = (id: number, type: string) => {
- toast.show("鐐瑰嚮鍗$墖");
+ // toast.show("鐐瑰嚮鍗$墖");
if (type == "鎷変笣") {
uni.navigateTo({
url: `/pages/production/detail/wireDetail?id=${id}`,
@@ -69,22 +74,28 @@
};
const getList = async (pageNo: number, pageSize: number) => {
- const { code, data } = await props.api({
+ const params: any = {
userName: userInfo.value.userName,
state: props.state,
current: pageNo,
size: pageSize,
- });
+ };
+ if (props.model) {
+ params.model = props.model;
+ }
+ const { code, data } = await props.api(params);
if (code == 200) {
if (data.type == "缁炵嚎") {
map.deviceModel = "deviceModel";
map.model = "model";
+ map.systemNo = "systemNo";
map.totalAmount = "totalLength";
map.amount = "length";
map.unAmount = "unLength";
} else if (data.type == "鎷変笣") {
map.deviceModel = "deviceModel";
map.model = "model";
+ map.systemNo = "systemNo";
map.totalAmount = "totalAmount";
map.amount = "amount";
map.unAmount = "unAmount";
diff --git a/src/pages/production/twist/attachment/index.vue b/src/pages/production/twist/attachment/index.vue
index c654299..0d17e10 100644
--- a/src/pages/production/twist/attachment/index.vue
+++ b/src/pages/production/twist/attachment/index.vue
@@ -17,26 +17,54 @@
<view class="attachment-list">
<wd-status-tip v-if="attachmentList.length === 0" image="content" tip="鏆傛棤闄勪欢" />
- <wd-card
- v-for="item in attachmentList"
- :key="item.id"
- type="rectangle"
- custom-class="attachment-card"
- :border="false"
- >
- <view class="attachment-item" @click="previewAttachment(item)">
- <view class="attachment-info">
- <view class="attachment-name">{{ item.bucketFileName || item.name }}</view>
- <view class="attachment-meta">
- <text class="file-type">{{ getFileType(item.bucketFileName) }}</text>
- <text class="upload-time">{{ formatTime(item.createTime) }}</text>
+ <view v-for="item in attachmentList" :key="item.id" class="attachment-card">
+ <view class="media-wrapper" @click="previewAttachment(item)">
+ <!-- 鍥剧墖棰勮 -->
+ <template v-if="isImageType(item.url)">
+ <image
+ v-if="!item.loadError"
+ :src="getFullUrl(item.url)"
+ mode="aspectFill"
+ class="media-preview"
+ @error="onImageError(item)"
+ @load="onImageLoad(item)"
+ />
+ <!-- 鍥剧墖鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="picture" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
</view>
+ </template>
+
+ <!-- 瑙嗛棰勮 -->
+ <template v-else-if="isVideoType(item.url)">
+ <video
+ v-if="!item.loadError"
+ :src="getFullUrl(item.url)"
+ class="media-preview"
+ :controls="false"
+ :show-center-play-btn="false"
+ @error="onVideoError(item)"
+ />
+ <!-- 瑙嗛鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="video" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
+ </view>
+ </template>
+
+ <!-- 鍏朵粬鏂囦欢绫诲瀷鏄剧ず鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="file-outline" size="48px" color="#999" />
+ <text class="file-name">鏂囦欢</text>
</view>
- <view class="attachment-actions" @click.stop>
- <wd-icon name="delete" color="#ff4757" @click="deleteAttachment(item.id)" />
+
+ <!-- 鍒犻櫎鎸夐挳 -->
+ <view class="delete-btn" @click.stop="deleteAttachment(item.id)">
+ <wd-icon name="delete" color="#fff" size="20px" />
</view>
</view>
- </wd-card>
+ </view>
</view>
<wd-toast />
@@ -48,6 +76,12 @@
import { useToast } from "wot-design-uni";
import AttachmentAPI from "@/api/product/attachment";
+// H5 浣跨敤 VITE_APP_BASE_API 浣滀负浠g悊璺緞锛屽叾浠栧钩鍙颁娇鐢� VITE_APP_API_URL 浣滀负璇锋眰璺緞
+let baseUrl = import.meta.env.VITE_APP_API_URL;
+// #ifdef H5
+baseUrl = import.meta.env.VITE_APP_BASE_API;
+// #endif
+
const toast = useToast();
// 椤甸潰鍙傛暟
@@ -56,6 +90,57 @@
const attachmentList = ref<any[]>([]);
const detailData = ref<any>({});
+
+// 鑾峰彇瀹屾暣鐨勫浘鐗�/瑙嗛 URL
+const getFullUrl = (url: string) => {
+ if (!url) return "";
+ // 濡傛灉宸茬粡鏄畬鏁寸殑 URL锛坔ttp 鎴� https 寮�澶达級锛岀洿鎺ヨ繑鍥�
+ if (url.startsWith("http://") || url.startsWith("https://")) {
+ return url;
+ }
+ // 濡傛灉鏄浉瀵硅矾寰勶紝鎷兼帴鍩虹 URL
+ return `${baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
+};
+
+// 浠� URL 鎴栨枃浠跺悕涓彁鍙栨墿灞曞悕
+const getExtension = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "";
+ // 绉婚櫎鏌ヨ鍙傛暟鍜屽搱甯�
+ const cleanUrl = urlOrFileName.split("?")[0].split("#")[0];
+ // 鑾峰彇鏈�鍚庝竴涓偣鍚庨潰鐨勫唴瀹�
+ const extension = cleanUrl.split(".").pop()?.toLowerCase();
+ return extension || "";
+};
+
+// 鍒ゆ柇鏄惁涓哄浘鐗囩被鍨�
+const isImageType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(extension);
+};
+
+// 鍒ゆ柇鏄惁涓鸿棰戠被鍨�
+const isVideoType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["mp4", "mov", "avi", "wmv", "flv", "mkv", "webm"].includes(extension);
+};
+
+// 鍥剧墖鍔犺浇鎴愬姛
+const onImageLoad = (item: any) => {
+ item.loadError = false;
+};
+
+// 鍥剧墖鍔犺浇澶辫触
+const onImageError = (item: any) => {
+ console.error("鍥剧墖鍔犺浇澶辫触:", item.url);
+ item.loadError = true;
+};
+
+// 瑙嗛鍔犺浇澶辫触
+const onVideoError = (item: any) => {
+ console.error("瑙嗛鍔犺浇澶辫触:", item.url);
+ item.loadError = true;
+};
+
// 鑾峰彇闄勪欢鍒楄〃
const getAttachmentList = async (data: any) => {
try {
@@ -252,24 +337,24 @@
// 棰勮闄勪欢
const previewAttachment = (item: any) => {
// 鏍规嵁鏂囦欢绫诲瀷杩涜棰勮
- const fileName = item.bucketFileName || item.name;
- const fileType = getFileType(fileName);
+ const fileType = getFileType(item.url);
+ const fullUrl = getFullUrl(item.url);
if (fileType.startsWith("image")) {
// 鍥剧墖棰勮
uni.previewImage({
- urls: [item.url],
- current: item.url,
+ urls: [fullUrl],
+ current: fullUrl,
});
} else {
// 鍏朵粬鏂囦欢绫诲瀷锛屽彲浠ヤ笅杞芥垨鎵撳紑
uni.downloadFile({
- url: item.url,
+ url: fullUrl,
success: (res) => {
uni.openDocument({
filePath: res.tempFilePath,
success: () => {
- console.log("鎵撳紑鏂囨。鎴愬姛");
+ // 鎵撳紑鏂囨。鎴愬姛
},
fail: (error) => {
console.error("鎵撳紑鏂囨。澶辫触:", error);
@@ -286,9 +371,9 @@
};
// 鑾峰彇鏂囦欢绫诲瀷
-const getFileType = (fileName: string) => {
- if (!fileName) return "unknown";
- const extension = fileName.split(".").pop()?.toLowerCase();
+const getFileType = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "unknown";
+ const extension = getExtension(urlOrFileName);
switch (extension) {
case "jpg":
case "jpeg":
@@ -297,6 +382,14 @@
case "bmp":
case "webp":
return "image";
+ case "mp4":
+ case "mov":
+ case "avi":
+ case "wmv":
+ case "flv":
+ case "mkv":
+ case "webm":
+ return "video";
case "pdf":
return "pdf";
case "doc":
@@ -357,43 +450,69 @@
}
.attachment-list {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 8px;
+
.attachment-card {
- margin-bottom: 12px;
- border-radius: 4px;
+ width: 100%;
+ aspect-ratio: 1;
}
}
-.attachment-item {
- display: flex;
- align-items: center;
- padding: 12px;
+.media-wrapper {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f5f5f5;
- .attachment-info {
- flex: 1;
+ .media-preview {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
- .attachment-name {
- font-size: 16px;
- font-weight: 500;
- color: #333;
- margin-bottom: 4px;
- word-break: break-all;
- }
+ .file-icon-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ padding: 8px;
+ text-align: center;
- .attachment-meta {
- display: flex;
- gap: 12px;
+ .file-name {
+ margin-top: 8px;
font-size: 12px;
- color: #999;
+ color: #666;
+ word-break: break-all;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+
+ &.error-text {
+ color: #ff4757;
+ }
}
}
- .attachment-actions {
- margin-left: 12px;
-
- :deep(.wd-icon) {
- font-size: 20px;
- cursor: pointer;
- }
+ .delete-btn {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
}
}
</style>
diff --git a/src/pages/production/twist/components/MonofilCard.vue b/src/pages/production/twist/components/MonofilCard.vue
index 68268d5..972c910 100644
--- a/src/pages/production/twist/components/MonofilCard.vue
+++ b/src/pages/production/twist/components/MonofilCard.vue
@@ -1,21 +1,153 @@
<template>
- <wd-card>
- <wd-cell-group :border="true">
- <wd-cell title="鍗曚笣缂栧彿" :value="data.monofilamentNumber" />
- <wd-cell title="鐞嗚闀垮害" :value="data.amount + ' (m)'" />
- <wd-cell title="鐢熶骇闀垮害" :value="data.actuallyLength + ' (m)'" />
- <wd-cell title="閲嶉噺" :value="data.actuallyWeight + ' (kg)'" />
- </wd-cell-group>
- </wd-card>
+ <view class="swipe-container">
+ <view
+ class="swipe-content"
+ :style="{ transform: `translateX(${translateX}px)` }"
+ @touchstart="handleTouchStart"
+ @touchmove="handleTouchMove"
+ @touchend="handleTouchEnd"
+ >
+ <wd-card>
+ <wd-cell-group :border="true">
+ <wd-cell title="鍗曚笣缂栧彿" :value="data.monofilamentNumber" />
+ <wd-cell title="鐞嗚闀垮害" :value="data.amount + ' (m)'" />
+ <wd-cell title="鐢熶骇闀垮害" :value="data.actuallyLength + ' (m)'" />
+ <wd-cell title="閲嶉噺" :value="data.actuallyWeight + ' (kg)'" />
+ </wd-cell-group>
+ </wd-card>
+ </view>
+ <view class="swipe-delete" @click="handleDelete">
+ <text class="delete-text">鍒犻櫎</text>
+ </view>
+ </view>
</template>
<script setup lang="ts">
-defineProps({
+import { ref } from "vue";
+
+const props = defineProps({
data: {
type: Object,
default: () => {},
},
});
+
+const emit = defineEmits(["delete", "swipe-open"]);
+
+const translateX = ref(0);
+const startX = ref(0);
+const startY = ref(0);
+const currentX = ref(0);
+const isSwipeOpen = ref(false);
+const deleteWidth = 80; // 鍒犻櫎鎸夐挳瀹藉害
+const isHorizontalSwipe = ref(false);
+
+const handleTouchStart = (e: any) => {
+ startX.value = e.touches[0].clientX;
+ startY.value = e.touches[0].clientY;
+ currentX.value = translateX.value;
+ isHorizontalSwipe.value = false;
+};
+
+const handleTouchMove = (e: any) => {
+ const moveX = e.touches[0].clientX - startX.value;
+ const moveY = e.touches[0].clientY - startY.value;
+
+ // 鍒ゆ柇鏄惁涓烘按骞虫粦鍔紙姘村钩绉诲姩璺濈澶т簬鍨傜洿绉诲姩璺濈锛�
+ if (!isHorizontalSwipe.value && Math.abs(moveX) > Math.abs(moveY) && Math.abs(moveX) > 10) {
+ isHorizontalSwipe.value = true;
+ }
+
+ // 鍙湁姘村钩婊戝姩鏃舵墠澶勭悊鍒犻櫎婊戝姩
+ if (isHorizontalSwipe.value) {
+ e.stopPropagation();
+ const newTranslateX = currentX.value + moveX;
+
+ // 闄愬埗婊戝姩鑼冨洿锛氬彧鑳藉悜宸︽粦鍔紝鏈�澶ф粦鍔ㄨ窛绂讳负鍒犻櫎鎸夐挳瀹藉害
+ if (newTranslateX <= 0 && newTranslateX >= -deleteWidth) {
+ translateX.value = newTranslateX;
+ } else if (newTranslateX < -deleteWidth) {
+ translateX.value = -deleteWidth;
+ } else if (newTranslateX > 0) {
+ translateX.value = 0;
+ }
+ }
+};
+
+const handleTouchEnd = (e: any) => {
+ // 鍙湁姘村钩婊戝姩鏃舵墠澶勭悊缁撴潫閫昏緫
+ if (isHorizontalSwipe.value) {
+ e.stopPropagation();
+ // 鍒ゆ柇鏄惁搴旇鎵撳紑鎴栧叧闂垹闄ゆ寜閽�
+ if (translateX.value < -deleteWidth / 2) {
+ // 婊戝姩瓒呰繃涓�鍗婏紝鎵撳紑鍒犻櫎鎸夐挳
+ translateX.value = -deleteWidth;
+ isSwipeOpen.value = true;
+ emit("swipe-open", props.data);
+ } else {
+ // 婊戝姩涓嶈冻涓�鍗婏紝鍏抽棴鍒犻櫎鎸夐挳
+ translateX.value = 0;
+ isSwipeOpen.value = false;
+ }
+ }
+ isHorizontalSwipe.value = false;
+};
+
+const handleDelete = () => {
+ // 鍏堝叧闂粦鍔�
+ translateX.value = 0;
+ isSwipeOpen.value = false;
+ emit("delete", props.data);
+};
+
+// 鍏抽棴婊戝姩鐨勬柟娉曪紝渚涘閮ㄨ皟鐢�
+const closeSwipe = () => {
+ if (isSwipeOpen.value) {
+ translateX.value = 0;
+ isSwipeOpen.value = false;
+ }
+};
+
+// 鏆撮湶鏂规硶渚涚埗缁勪欢璋冪敤
+defineExpose({
+ closeSwipe,
+ isSwipeOpen,
+});
</script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.swipe-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 8px;
+}
+
+.swipe-content {
+ position: relative;
+ transition: transform 0.3s ease;
+ z-index: 2;
+ background: #fff;
+ touch-action: pan-y;
+}
+
+.swipe-delete {
+ position: absolute;
+ right: 0;
+ top: 12px;
+ bottom: 12px;
+ width: 80px;
+ background: #ff4444;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1;
+ border-radius: 4px;
+ box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.05);
+
+ .delete-text {
+ color: #fff;
+ font-size: 14px;
+ font-weight: 500;
+ }
+}
+</style>
diff --git a/src/pages/production/twist/components/TwistReportCard.vue b/src/pages/production/twist/components/TwistReportCard.vue
new file mode 100644
index 0000000..ee3f754
--- /dev/null
+++ b/src/pages/production/twist/components/TwistReportCard.vue
@@ -0,0 +1,37 @@
+<template>
+ <wd-row>
+ <wd-col v-for="(item, index) in data" :key="index" :span="item.span || 24" class="my-1">
+ <view class="flex w-full h-[20px]">
+ <view class="text-[#646874] pl-1 mr-3">{{ item.label }}</view>
+ <view class="font-medium pr-1" :style="{ color: item.color ?? color }">
+ {{ value[item.prop] }} {{ value[item.unitProp] }} {{ item.unit }}
+ </view>
+ </view>
+ </wd-col>
+ </wd-row>
+</template>
+
+<script lang="ts" setup>
+defineProps({
+ data: {
+ type: Array as any,
+ default: () => {
+ return [];
+ },
+ },
+ value: {
+ type: Object,
+ default: () => {
+ return {};
+ },
+ },
+ color: {
+ type: String,
+ default: "#333333",
+ },
+ unit: {
+ type: String,
+ default: "",
+ },
+});
+</script>
diff --git a/src/pages/production/twist/receive/index.vue b/src/pages/production/twist/receive/index.vue
index 277e46e..d4cede7 100644
--- a/src/pages/production/twist/receive/index.vue
+++ b/src/pages/production/twist/receive/index.vue
@@ -1,16 +1,16 @@
<template>
<wd-tabs v-model="tab" auto-line-width>
<wd-tab title="鍗曚笣棰嗙敤" name="鍗曚笣棰嗙敤">
- <Monofil />
+ <Monofil v-if="tab === '鍗曚笣棰嗙敤'" />
</wd-tab>
<wd-tab title="鐩樺叿棰嗙敤" name="鐩樺叿棰嗙敤">
<view class="content">
- <Plate />
+ <Plate v-if="tab === '鐩樺叿棰嗙敤'" />
</view>
</wd-tab>
- <wd-tab title="閽㈣姱棰嗙敤" name="閽㈣姱棰嗙敤">
+ <wd-tab title="鑺嚎棰嗙敤" name="鑺嚎棰嗙敤">
<view class="content">
- <SteelCore />
+ <SteelCore v-if="tab === '鑺嚎棰嗙敤'" />
</view>
</wd-tab>
</wd-tabs>
diff --git a/src/pages/production/twist/receive/monofil.vue b/src/pages/production/twist/receive/monofil.vue
index 49b261e..b4998fc 100644
--- a/src/pages/production/twist/receive/monofil.vue
+++ b/src/pages/production/twist/receive/monofil.vue
@@ -25,7 +25,12 @@
<block v-for="item in nodeList" :key="item">
<wd-tab :title="item.twistedLayer" :name="item.twistedLayer">
<scroll-view class="content" scroll-y>
- <MonofilCard v-for="(m, i) in item.strandedWireDish" :key="i" :data="m" />
+ <MonofilCard
+ v-for="(m, i) in item.strandedWireDish"
+ :key="i"
+ :data="m"
+ @delete="handleDeleteCard(item, m)"
+ />
</scroll-view>
</wd-tab>
</block>
@@ -79,7 +84,7 @@
import MonofilCard from "../components/MonofilCard.vue";
import StatisticsModal from "../components/StatisticsModal.vue";
import { useToast } from "wot-design-uni";
-import { onLoad, onUnload } from "@dcloudio/uni-app";
+import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app";
import Scan from "@/components/scan/index.vue";
import ManageApi from "@/api/product/manage";
import TwistApi from "@/api/product/twist";
@@ -95,20 +100,21 @@
const showStatisticsModal = ref(false);
const showManualInput = ref(false);
const manualOutPutId = ref("");
+const isPageVisible = ref(false); // 鏍囪椤甸潰鏄惁鍙
// 鐩戝惉鏍囩鍒囨崲
watch(tab, () => {
if (tab.value) {
- console.log("tab.value:===========1", tab.value);
getList();
}
});
const getScanCode = async (code: any) => {
- console.log("鑷畾涔夋壂鎻忕殑缁撴灉鍥炶皟鍑芥暟:", code);
- // let parseData = code.trim();
- console.log("code:===========", JSON.parse(code.code));
- console.log("id:=============", JSON.parse(code.code).id);
+ // 妫�鏌ラ〉闈㈡槸鍚﹀彲瑙侊紝濡傛灉涓嶅彲瑙佸垯涓嶅鐞嗘壂鐮佹暟鎹�
+ if (!isPageVisible.value) {
+ return;
+ }
+
try {
// 妫�鏌ユ槸鍚﹀凡閫夋嫨鏍囩
if (!tab.value) {
@@ -117,24 +123,25 @@
}
// 鎵惧埌褰撳墠閫変腑鐨勫眰
- console.log("tab.value:===========2", tab.value);
const currentLayer = nodeList.value.find((node) => node.twistedLayer === tab.value);
if (!currentLayer) {
toast.error("鏈壘鍒板綋鍓嶉�変腑鐨勫眰");
return;
}
- console.log("tab.value:===========3", currentLayer);
- // 鍦ㄥ彂璧疯姹傚墠锛屽厛鏍¢獙璇ュ崟涓濇槸鍚﹀凡鍦ㄥ綋鍓嶆垨鍏朵粬灞傜骇琚鐢�
- const scannedOutputId = JSON.parse(code.code).id;
- const alreadyUsed = nodeList.value.some((node) =>
- (node.strandedWireDish || []).some((item: any) => item.outputId === scannedOutputId)
- );
- if (alreadyUsed) {
- toast.error("璇ュ崟涓濆凡棰嗙敤锛岃鍕块噸澶嶆壂鐮�");
- return;
+
+ // 瑙f瀽鎵爜鏁版嵁
+ const scanData = JSON.parse(code.code);
+
+ // 鍒ゆ柇灞傜骇鏄惁鍖归厤
+ if (scanData.layer && scanData.layer !== currentLayer.twistedLayer) {
+ toast.error(
+ `棰嗙敤灞傜骇涓嶅锛屽綋鍓嶅眰鏄細${currentLayer.twistedLayer}锛岄鐢ㄥ崟涓濆眰鏄細${scanData.layer}`
+ );
+ // return;
}
+
const { data } = await TwistApi.getScarn({
- outPutId: scannedOutputId,
+ outPutId: scanData.id,
twistId: currentLayer.twistId,
});
@@ -268,7 +275,6 @@
// 璁剧疆榛樿绗竴灞�
if (nodeList.value && nodeList.value.length > 0 && !tab.value) {
tab.value = nodeList.value[0].twistedLayer;
- console.log("璁剧疆榛樿绗竴灞�:", tab.value);
// 璁剧疆榛樿鏍囩鍚庯紝鍔犺浇绗竴灞傜殑鏁版嵁
getList();
}
@@ -344,6 +350,44 @@
}
};
+// 鍒犻櫎鍗$墖
+const handleDeleteCard = async (layer: any, cardData: any) => {
+ // 鏄剧ず纭鎻愮ず
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "纭畾瑕佸垹闄よ鍗曚笣鍚楋紵",
+ success: async (res) => {
+ if (res.confirm) {
+ try {
+ // 濡傛灉鏈塱d锛岃皟鐢ㄦ帴鍙e垹闄�
+ if (cardData.id !== undefined && cardData.id !== null) {
+ const { code, msg } = await TwistApi.deleteStrandedWireDish(cardData.id);
+ if (code !== 200) {
+ toast.error(msg || "鍒犻櫎澶辫触");
+ return;
+ }
+ }
+
+ // 鍓嶇鐩存帴鍒犻櫎锛堟棤璁烘槸鍚︽湁id锛岄兘浠庡墠绔垹闄わ級
+ if (layer.strandedWireDish && Array.isArray(layer.strandedWireDish)) {
+ const index = layer.strandedWireDish.findIndex(
+ (item: any) => item.monofilamentNumber === cardData.monofilamentNumber
+ );
+ if (index !== -1) {
+ layer.strandedWireDish.splice(index, 1);
+ toast.success("鍒犻櫎鎴愬姛");
+ // 鍒锋柊褰撳墠灞傜殑鏁版嵁鏄剧ず
+ getList();
+ }
+ }
+ } catch (error: any) {
+ toast.error(error.msg || "鍒犻櫎澶辫触");
+ }
+ }
+ },
+ });
+};
+
onLoad(async (options: any) => {
// 寮�鍚箍鎾洃鍚簨浠�
uni.$on("scanMono", getScanCode);
@@ -353,9 +397,21 @@
getRootNumber(options.id);
// getRootNumber(118);
});
+
+onShow(() => {
+ // 椤甸潰鏄剧ず鏃舵爣璁颁负鍙
+ isPageVisible.value = true;
+});
+
+onHide(() => {
+ // 椤甸潰闅愯棌鏃舵爣璁颁负涓嶅彲瑙�
+ isPageVisible.value = false;
+});
+
onUnload(() => {
- // 寮�鍚箍鎾洃鍚簨浠�
+ // 鍙栨秷骞挎挱鐩戝惉浜嬩欢
uni.$off("scanMono", getScanCode);
+ isPageVisible.value = false;
});
</script>
diff --git a/src/pages/production/twist/receive/steelCore/edit.vue b/src/pages/production/twist/receive/steelCore/edit.vue
index fb7ae58..cbca0fe 100644
--- a/src/pages/production/twist/receive/steelCore/edit.vue
+++ b/src/pages/production/twist/receive/steelCore/edit.vue
@@ -1,6 +1,6 @@
<template>
<view>
- <CardTitle title="缁炵嚎閽㈣姱棰嗙敤" :hideAction="false" />
+ <CardTitle title="缁炵嚎鑺嚎棰嗙敤" :hideAction="false" />
<SteelCoreForm ref="formRef" class="mx-4" />
<view class="footer">
<wd-button
@@ -37,13 +37,10 @@
// 鎺ユ敹鍒楄〃椤典紶閫掔殑鏁版嵁
const receiveEditData = (data: any) => {
- console.log("receiveEditData 鎺ユ敹鍒扮殑鏁版嵁:", data);
if (data && formRef.value) {
// 纭繚 list 鍜� editId 閮藉瓨鍦�
if (data.list && data.editId) {
formRef.value.setFormData(data.list, data.editId);
- } else {
- console.error("鏁版嵁鏍煎紡閿欒:", data);
}
}
};
diff --git a/src/pages/production/twist/receive/steelCore/form.vue b/src/pages/production/twist/receive/steelCore/form.vue
index 616e48f..4561801 100644
--- a/src/pages/production/twist/receive/steelCore/form.vue
+++ b/src/pages/production/twist/receive/steelCore/form.vue
@@ -1,6 +1,16 @@
<template>
<wd-form ref="form" :model="model" class="relative form_box">
<wd-cell-group :border="true">
+ <wd-picker
+ v-model="diskMaterialValue"
+ :columns="diskMaterialOptions"
+ label="鑺嚎绫诲瀷"
+ label-width="100px"
+ prop="diskMaterial"
+ placeholder="璇烽�夋嫨鑺嚎绫诲瀷"
+ clearable
+ @confirm="handleDiskMaterialChange"
+ />
<wd-input
v-model="model.model"
label="瑙勬牸鍨嬪彿"
@@ -48,6 +58,7 @@
<script lang="ts" setup>
import useFormData from "@/hooks/useFormData";
import TwistApi from "@/api/product/twist";
+import ManageApi from "@/api/product/manage";
import { useToast } from "wot-design-uni";
const props = defineProps({
@@ -59,6 +70,10 @@
type: Object,
default: null,
},
+ wireId: {
+ type: [String, Number],
+ default: undefined,
+ },
});
const emits = defineEmits(["refresh"]);
@@ -67,6 +82,7 @@
const allListData = ref<any[]>([]); // 瀛樺偍瀹屾暣鍒楄〃鏁版嵁
const toast = useToast();
const { form: model } = useFormData({
+ diskMaterial: undefined, // 鑺嚎绫诲瀷
model: undefined, // 瑙勬牸鍨嬪彿
monofilamentNumber: undefined, // 鏍峰搧缂栧彿
amount: undefined, // 鏁伴噺
@@ -75,11 +91,45 @@
type: "閽㈣姱",
});
+// 鑺嚎绫诲瀷瀛楀吀鏁版嵁
+const diskMaterialOptions = ref<Array<{ label: string; value: string }>>([]);
+const diskMaterialValue = ref("");
+
+// 鍔犺浇鑺嚎绫诲瀷瀛楀吀鏁版嵁
+const loadDiskMaterialDict = async () => {
+ try {
+ const res = await ManageApi.dictAPI("core_wire_type");
+ if (res.data && Array.isArray(res.data)) {
+ diskMaterialOptions.value = res.data.map((item: any) => ({
+ label: item.dictLabel || "",
+ value: item.dictValue || "",
+ }));
+ }
+ } catch (error) {
+ // 鍔犺浇瀛楀吀澶辫触锛岄潤榛樺鐞�
+ }
+};
+
+// 澶勭悊鑺嚎绫诲瀷閫夋嫨
+const handleDiskMaterialChange = (val: any) => {
+ model.diskMaterial = val.value;
+};
+
+// 鐩戝惉 model.diskMaterial 鍙樺寲锛屽悓姝ラ�夋嫨鍣ㄦ樉绀�
+watch(
+ () => model.diskMaterial,
+ (newValue) => {
+ diskMaterialValue.value = newValue || "";
+ },
+ { immediate: true }
+);
+
// 鏂板鎻愪氦
const submit = async () => {
+ const currentWireId = props.wireId || paramsId.value;
const { code } = await TwistApi.addStrandedWireDish([
{
- wireId: paramsId.value,
+ wireId: currentWireId,
...model,
},
]);
@@ -107,6 +157,7 @@
// 淇濈暀鍘熸湁鏁版嵁锛岀劧鍚庢洿鏂颁慨鏀圭殑瀛楁
const updatedItem = {
...item, // 鍏堜繚鐣欏師鏈夌殑鎵�鏈夋暟鎹�
+ diskMaterial: model.diskMaterial,
model: model.model,
monofilamentNumber: model.monofilamentNumber,
amount: model.amount,
@@ -133,7 +184,6 @@
const setFormData = (list: any[], currentEditId: number) => {
// 瀹夊叏妫�鏌ワ細纭繚list鏄暟缁�
if (!Array.isArray(list)) {
- console.error("setFormData: list 鍙傛暟涓嶆槸鏁扮粍", list);
return;
}
@@ -144,12 +194,15 @@
// 鎵惧埌褰撳墠缂栬緫椤瑰苟鍥炴樉鍒拌〃鍗�
const currentItem = list.find((item) => item.id === currentEditId);
if (currentItem) {
+ model.diskMaterial = currentItem.diskMaterial;
model.model = currentItem.model;
model.monofilamentNumber = currentItem.monofilamentNumber;
model.amount = currentItem.amount;
model.weight = currentItem.weight;
model.supplier = currentItem.supplier;
model.type = currentItem.type || "閽㈣姱";
+ // 璁剧疆鑺嚎绫诲瀷鐨勫洖鏄惧��
+ diskMaterialValue.value = currentItem.diskMaterial || "";
}
};
@@ -158,12 +211,14 @@
() => props.editData,
(newData) => {
if (newData && props.mode === "edit") {
+ model.diskMaterial = newData.diskMaterial || "";
model.model = newData.model || "";
model.monofilamentNumber = newData.monofilamentNumber || "";
model.amount = newData.amount || "";
model.weight = newData.weight || "";
model.supplier = newData.supplier || "";
model.type = newData.type || "閽㈣姱";
+ diskMaterialValue.value = newData.diskMaterial || "";
}
},
{ immediate: true, deep: true }
@@ -171,16 +226,36 @@
// 閲嶇疆琛ㄥ崟鏁版嵁
const resetFormData = () => {
+ model.diskMaterial = undefined;
model.model = undefined;
model.monofilamentNumber = undefined;
model.amount = undefined;
model.weight = undefined;
model.supplier = undefined;
model.type = "閽㈣姱";
+ diskMaterialValue.value = "";
+};
+
+// 濉厖琛ㄥ崟鏁版嵁锛堢敤浜庢壂鐮佸悗鍥炴樉锛�
+const fillFormData = (data: any) => {
+ if (data) {
+ model.diskMaterial = data.diskMaterial || "";
+ model.model = data.model || "";
+ model.monofilamentNumber = data.monofilamentNumber || "";
+ model.amount = data.oneLength || data.amount || "";
+ model.weight = data.weight || "";
+ model.supplier = data.supplier || "";
+ model.type = data.type || "閽㈣姱";
+ diskMaterialValue.value = data.diskMaterial || "";
+ }
};
onLoad((options: any) => {
paramsId.value = options.id;
+});
+
+onMounted(async () => {
+ await loadDiskMaterialDict();
});
defineExpose({
@@ -188,6 +263,7 @@
submitEdit,
setFormData,
resetFormData,
+ fillFormData,
});
</script>
diff --git a/src/pages/production/twist/receive/steelCore/index.vue b/src/pages/production/twist/receive/steelCore/index.vue
index 85da5f2..1e6b91c 100644
--- a/src/pages/production/twist/receive/steelCore/index.vue
+++ b/src/pages/production/twist/receive/steelCore/index.vue
@@ -8,7 +8,12 @@
@query="getList"
>
<template #top>
- <CardTitle title="閽㈣姱棰嗙敤" :hideAction="true" :full="false" @action="addReport" />
+ <CardTitle title="鑺嚎棰嗙敤" :hideAction="false" :full="false">
+ <template #action>
+ <wd-button type="icon" icon="scan" color="#0D867F" @click="openScan"></wd-button>
+ <wd-button type="icon" icon="add-circle" color="#0D867F" @click="addReport"></wd-button>
+ </template>
+ </CardTitle>
</template>
<wd-card v-for="(item, index) in cardList" :key="index" type="rectangle" custom-class="round">
<template #title>
@@ -28,7 +33,7 @@
<wd-button type="text" @click="cancelAdd">鍙栨秷</wd-button>
<wd-button type="text" @click="submitAdd">纭畾</wd-button>
</view>
- <SteelCore ref="addFormRef" mode="add" @refresh="reloadList" />
+ <SteelCore ref="addFormRef" mode="add" :wireId="paramsId" @refresh="reloadList" />
</wd-popup>
<wd-popup v-model="editDialog.visible" position="bottom" custom-class="yl-popup">
<view class="action px-3">
@@ -38,10 +43,12 @@
<SteelCore
ref="editFormRef"
mode="edit"
+ :wireId="paramsId"
:editData="editDialog.currentItem"
@refresh="reloadList"
/>
</wd-popup>
+ <Scan ref="scanRef" emitName="scanSteelCore" />
<wd-toast />
</view>
</template>
@@ -51,15 +58,19 @@
import ProductionCard from "../../../components/ProductionCard.vue";
import { useToast } from "wot-design-uni";
import SteelCore from "./form.vue";
-import { onLoad } from "@dcloudio/uni-app";
+import { onLoad, onUnload, onShow, onHide } from "@dcloudio/uni-app";
import ManageApi from "@/api/product/manage";
+import TwistApi from "@/api/product/twist";
import zPaging from "@/components/z-paging/z-paging.vue";
+import Scan from "@/components/scan/index.vue";
const paramsId = ref();
const pagingRef = ref();
const addFormRef = ref();
const editFormRef = ref();
+const scanRef = ref();
const toast = useToast();
+const isPageVisible = ref(false); // 鏍囪椤甸潰鏄惁鍙
const addDialog = reactive({
visible: false,
});
@@ -147,8 +158,69 @@
pagingRef.value.refresh();
};
+// 鎵爜鐩稿叧鏂规硶
+const openScan = () => {
+ scanRef.value.triggerScan();
+};
+
+const getScanCode = async (code: any) => {
+ // 妫�鏌ラ〉闈㈡槸鍚﹀彲瑙侊紝濡傛灉涓嶅彲瑙佸垯涓嶅鐞嗘壂鐮佹暟鎹�
+ if (!isPageVisible.value) {
+ return;
+ }
+
+ try {
+ const parseData = JSON.parse(code.code);
+
+ // 妫�鏌ュ繀闇�瀛楁锛歮odel銆乻upplier銆乨iskMaterial
+ const requiredFields = ["model", "supplier", "diskMaterial"];
+ const missingFields = requiredFields.filter((field) => !parseData[field]);
+
+ if (missingFields.length > 0) {
+ toast.error(`浜岀淮鐮侀敊璇紝璇锋洿鎹簩缁寸爜锛乣);
+ return;
+ }
+
+ // 鎵撳紑鏂板寮规骞跺~鍏呮壂鐮佽幏鍙栫殑淇℃伅
+ addDialog.visible = true;
+
+ // 绛夊緟寮规鎵撳紑鍚庡~鍏呰〃鍗曟暟鎹�
+ // 浣跨敤鍙岄噸绛夊緟锛歯extTick + setTimeout 纭繚缁勪欢宸插畬鍏ㄦ寕杞�
+ nextTick(() => {
+ setTimeout(() => {
+ if (addFormRef.value) {
+ addFormRef.value.fillFormData(parseData);
+ toast.success("鎵爜鎴愬姛锛岃纭淇℃伅");
+ } else {
+ toast.error("琛ㄥ崟鍔犺浇澶辫触锛岃閲嶈瘯");
+ }
+ }, 200); // 寤惰繜200ms纭繚寮规鍜岀粍浠跺凡瀹屽叏娓叉煋
+ });
+ } catch (error) {
+ toast.error("浜岀淮鐮佸紓甯革紝璇锋洿鎹簩缁寸爜锛�");
+ }
+};
+
onLoad((options: any) => {
+ // 寮�鍚箍鎾洃鍚簨浠�
+ uni.$on("scanSteelCore", getScanCode);
paramsId.value = options.id;
+});
+
+onShow(() => {
+ // 椤甸潰鏄剧ず鏃舵爣璁颁负鍙
+ isPageVisible.value = true;
+});
+
+onHide(() => {
+ // 椤甸潰闅愯棌鏃舵爣璁颁负涓嶅彲瑙�
+ isPageVisible.value = false;
+});
+
+onUnload(() => {
+ // 鍙栨秷骞挎挱鐩戝惉浜嬩欢
+ uni.$off("scanSteelCore", getScanCode);
+ isPageVisible.value = false;
});
</script>
@@ -169,4 +241,8 @@
display: flex;
justify-content: space-between;
}
+
+:deep(.wd-button__content) {
+ color: #0d867f;
+}
</style>
diff --git a/src/pages/production/twist/report/draw.vue b/src/pages/production/twist/report/draw.vue
index 56eb4bc..b8e2a1e 100644
--- a/src/pages/production/twist/report/draw.vue
+++ b/src/pages/production/twist/report/draw.vue
@@ -62,7 +62,7 @@
</template>
</view>
</wd-tab>
- <wd-tab title="閽㈣姱棰嗙敤鑷" name="steel">
+ <wd-tab title="鑺嚎棰嗙敤鑷" name="steel">
<view class="form-section">
<wd-form :model="localSteelData">
<wd-form-item label="瑙勬牸鍨嬪彿" prop="model" required>
diff --git a/src/pages/production/twist/report/form.vue b/src/pages/production/twist/report/form.vue
index 2e62f0c..cb804bb 100644
--- a/src/pages/production/twist/report/form.vue
+++ b/src/pages/production/twist/report/form.vue
@@ -2,103 +2,139 @@
<wd-form ref="form" :model="model" class="relative form_box">
<wd-cell-group :border="true">
<wd-input
- v-model="model.contractNo"
- label="棰嗙敤鏉嗗彿"
- label-width="100px"
- prop="contractNo"
- clearable
- placeholder="璇疯緭鍏ラ鐢ㄦ潌鍙�"
- />
- <wd-input
- v-model="model.status"
- label="鏉嗛噸(kg)"
- label-width="100px"
- prop="status"
- clearable
- placeholder="璇疯緭鍏ユ潌閲�"
- />
- <wd-input
- v-model="model.clientName"
- label="鍗曚笣鐩樺彿"
- label-width="100px"
- prop="clientName"
- clearable
- placeholder="璇疯緭鍏ュ崟涓濈洏鍙�"
- />
- <wd-input
- v-model="model.workbench"
- label="瀹為檯閲嶉噺(kg)"
- label-width="100px"
- prop="workbench"
- clearable
- placeholder="璇疯緭鍏ュ疄闄呴噸閲�"
- />
- <wd-input
- v-model="model.quality"
- label="鐩橀暱(m)"
- label-width="100px"
- prop="quality"
- clearable
- placeholder="璇疯緭鍏ョ洏闀�"
- />
- <wd-input
- v-model="model.specification"
- label="鐞嗚閲嶉噺(kg)"
- label-width="100px"
- prop="specification"
- clearable
- placeholder="璇疯緭鍏ョ悊璁洪噸閲�"
- />
- <wd-input
- v-model="model.disc"
- label="瑙勬牸鍨嬪彿"
- label-width="100px"
- prop="disc"
- clearable
- placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
- />
- <wd-input
v-model="model.actuallyLength"
- label="瀹為檯鐩橀暱(m)"
+ label="鐢熶骇闀垮害(m)"
label-width="100px"
prop="actuallyLength"
clearable
- placeholder="璇疯緭鍏ュ疄闄呯洏闀�"
- />
+ placeholder="璇疯緭鍏ョ敓浜ч暱搴�"
+ type="digit"
+ >
+ <template #label>
+ <span style="color: #f56c6c">鐢熶骇闀垮害(m)</span>
+ </template>
+ </wd-input>
+ <wd-input
+ v-model="model.tare"
+ label="鐩樺叿鐨噸(kg)"
+ label-width="100px"
+ prop="tare"
+ :disabled="!isFirstReport"
+ :clearable="isFirstReport"
+ :placeholder="isFirstReport ? '璇疯緭鍏ョ洏鍏风毊閲�' : '鐩樺叿鐨噸鑷姩甯﹀嚭'"
+ type="digit"
+ >
+ <template #label>
+ <span style="color: #f56c6c">鐩樺叿鐨噸(kg)</span>
+ </template>
+ </wd-input>
</wd-cell-group>
</wd-form>
</template>
<script lang="ts" setup>
+import { computed, watch } from "vue";
import useFormData from "@/hooks/useFormData";
-import { useToast } from "wot-design-uni";
+import { useToast, dayjs } from "wot-design-uni";
import TwistApi from "@/api/product/twist";
+
+// 瀹氫箟 props
+const props = defineProps<{
+ firstTareValue?: number;
+ teamId?: string | number | null;
+ isFirstReport?: boolean; // 鏄惁鏄涓�鏉℃姤宸�
+}>();
+
+// 璁$畻鏄惁鏄涓�鏉℃姤宸�
+const isFirstReport = computed(() => props.isFirstReport ?? true);
const paramsId = ref();
const toast = useToast();
-const { form: model } = useFormData({
- poleNumber: undefined, // 棰嗙敤鏉嗗彿
- poleWeight: undefined, // 鏉嗛噸(kg)
- monofilamentNumber: undefined, // 鍗曚笣鐩樺彿
- actuallyWeight: undefined, // 瀹為檯閲嶉噺(kg)
- oneLength: undefined, // 鐩橀暱(m)
- theoryWeight: undefined, // 鐞嗚閲嶉噺(kg)
- model: undefined, // 瑙勬牸鍨嬪彿
- actuallyLength: undefined, // 瀹為檯鐩橀暱(m)
+const { form: model, resetForm } = useFormData({
+ actuallyLength: undefined, // 鐢熶骇闀垮害(m)
+ tare: undefined, // 鐩樺叿鐨噸(kg)
});
+// 涓昏〃鏁版嵁锛堜粠鐖剁粍浠朵紶鍏ワ級
+const mainTableData = ref<any>({});
+
+// 璁剧疆涓昏〃鏁版嵁
+const setMainTableData = (data: any) => {
+ mainTableData.value = data;
+};
+
+// 鐩戝惉 firstTareValue 鍙樺寲锛屽鏋滀笉鏄涓�鏉★紝鑷姩濉厖
+watch(
+ () => props.firstTareValue,
+ (newVal) => {
+ if (!isFirstReport.value && newVal !== undefined) {
+ model.tare = newVal;
+ }
+ },
+ { immediate: true }
+);
+
const submit = async () => {
- const { code } = await TwistApi.addTwistOutput({
+ // 鑾峰彇绗竴鏉℃暟鎹殑鐨噸鍊硷紝鐢ㄤ簬鍚庣画鏂板鐨勬姤宸�
+ const firstTareValue = props.firstTareValue;
+
+ // 濡傛灉涓昏〃鏁版嵁鏈幏鍙栵紝灏濊瘯閲嶆柊鑾峰彇
+ if (!mainTableData.value.model) {
+ try {
+ const { data } = await TwistApi.getTwistDetailById({
+ id: paramsId.value,
+ });
+ mainTableData.value = {
+ model: data.model,
+ totalLength: data.totalLength,
+ systemNo: data.systemNo,
+ };
+ } catch (error) {
+ console.error("鑾峰彇涓昏〃鏁版嵁澶辫触:", error);
+ toast.error("鑾峰彇瑙勬牸鍨嬪彿鏁版嵁澶辫触锛岃閲嶈瘯");
+ return false;
+ }
+ }
+
+ // 鍐嶆妫�鏌ヤ富琛ㄦ暟鎹�
+ if (!mainTableData.value.model) {
+ toast.error("瑙勬牸鍨嬪彿鏁版嵁鏈幏鍙栵紝璇烽噸璇�");
+ return false;
+ }
+
+ const submitData = {
+ teamId: props.teamId || null,
wireId: paramsId.value,
- ...model,
- });
+ type: "缁炵嚎",
+ actuallyLength: model.actuallyLength,
+ tare: model.tare || firstTareValue,
+ // 浠庝富琛ㄨ幏鍙栫殑瀛楁
+ model: mainTableData.value.model, // 瑙勬牸鍨嬪彿
+ oneLength: mainTableData.value.totalLength,
+ systemNo: mainTableData.value.systemNo,
+ monofilamentNumber: undefined, // 鎵规鍙凤紙鍚庣鑷姩鐢熸垚锛�
+ // 鐢熶骇鏃ユ湡鑷姩璁剧疆涓哄綋鍓嶆椂闂�
+ productTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ };
+
+ // 璋冭瘯鏃ュ織
+ console.log("鎻愪氦鏁版嵁:", submitData);
+ console.log("涓昏〃鏁版嵁:", mainTableData.value);
+
+ const { code } = await TwistApi.addTwistOutput(submitData);
if (code == 200) {
toast.success("鎻愪氦鎴愬姛");
+ resetForm();
return true;
} else {
toast.error("鎻愪氦澶辫触");
return false;
}
+};
+
+// 鑾峰彇琛ㄥ崟鏁版嵁
+const getFormData = () => {
+ return { ...model };
};
onLoad((options: any) => {
@@ -107,12 +143,12 @@
defineExpose({
submit,
+ getFormData,
+ setMainTableData,
});
</script>
<style lang="scss" scoped>
-.form_box {
-}
.submit_btn {
position: absolute;
bottom: 0;
diff --git a/src/pages/production/twist/report/index.vue b/src/pages/production/twist/report/index.vue
index f100b78..b9244b1 100644
--- a/src/pages/production/twist/report/index.vue
+++ b/src/pages/production/twist/report/index.vue
@@ -12,15 +12,23 @@
<text class="text-[#0D867F] ml-2 font-medium">鐢熶骇浜�</text>
<text class="text-[#333333] ml-2">{{ item.productUser }}</text>
</view>
- <view class="text-[#A8A8A8]" @click="toEdit">缂栬緫</view>
+ <!-- <view class="text-[#A8A8A8]" @click="toEdit">缂栬緫</view> -->
</view>
</template>
- <ProductionCard :data="cardAttr" :value="item" />
+ <TwistReportCard :data="cardAttr" :value="item" />
<template #footer>
<wd-button size="small" plain style="margin-right: 10px" @click="toAttachment(item)">
闄勪欢
</wd-button>
- <wd-button size="small" plain @click="handleSelfCheck(item.id)">鑷</wd-button>
+ <wd-button
+ size="small"
+ plain
+ style="margin-right: 10px"
+ @click="handleSelfCheck(item.id)"
+ >
+ 鑷
+ </wd-button>
+ <wd-button size="small" plain type="error" @click="handleDelete(item)">鍒犻櫎</wd-button>
</template>
</wd-card>
</z-paging>
@@ -30,7 +38,12 @@
<wd-button type="text" @click="cancel">鍙栨秷</wd-button>
<wd-button type="text" @click="submit">纭畾</wd-button>
</view>
- <TwistForm ref="twistFormRef" />
+ <TwistForm
+ ref="twistFormRef"
+ :first-tare-value="twistReportList.length > 0 ? twistReportList[0].tare : undefined"
+ :team-id="teamId"
+ :is-first-report="twistReportList.length === 0"
+ />
</wd-popup>
<wd-popup v-model="drawFormRef.visible" position="bottom" custom-class="yl-popup">
<Draw
@@ -47,13 +60,15 @@
<script setup lang="ts">
import CardTitle from "@/components/card-title/index.vue";
import TwistForm from "./form.vue";
-import { useToast } from "wot-design-uni";
-import ProductionCard from "../../components/ProductionCard.vue";
+import { useToast, dayjs } from "wot-design-uni";
+import TwistReportCard from "../components/TwistReportCard.vue";
import { onLoad } from "@dcloudio/uni-app";
-import { ref, reactive } from "vue";
+import { ref, reactive, nextTick } from "vue";
import ManageApi from "@/api/product/manage";
import TwistApi from "@/api/product/twist";
import Draw from "./draw.vue";
+import HomeApi from "@/api/home";
+import { setTeamId, getTeamId } from "@/utils/cache";
const drawFormRef = reactive({
visible: false,
@@ -95,36 +110,65 @@
const cardAttr = ref<any[]>([
{
- label: "棰嗙敤鏉嗗彿",
- prop: "poleNumber",
- },
- {
- label: "鏉嗛噸(kg)",
- prop: "poleWeight",
- },
- {
- label: "鍗曚笣鐩樺彿",
+ label: "鎵规鍙�",
prop: "monofilamentNumber",
+ span: 24,
},
{
- label: "瀹為檯閲嶉噺(kg)",
- prop: "actuallyWeight",
+ label: "璐ㄩ噺杩芥函鍙�",
+ prop: "systemNo",
+ span: 24,
},
{
label: "鐩橀暱(m)",
prop: "oneLength",
},
{
- label: "鐞嗚閲嶉噺(kg)",
- prop: "theoryWeight",
- },
- {
label: "瑙勬牸鍨嬪彿",
prop: "model",
+ },
+ {
+ label: "鐢熶骇闀垮害(m)",
+ prop: "actuallyLength",
+ },
+ {
+ label: "鐩樺叿鐨噸(kg)",
+ prop: "tare",
+ },
+ {
+ label: "鐢熶骇鏃ユ湡",
+ prop: "productTime",
+ span: 24,
+ },
+ {
+ label: "鍔犲伐鏃堕棿(h)",
+ prop: "processHour",
},
]);
const twistReportList = ref<any[]>([]);
+const teamId = ref<string | number | null>(null);
+
+// 鑾峰彇骞剁紦瀛樼彮缁処D
+const initTeamId = async () => {
+ // 鍏堝皾璇曚粠缂撳瓨鑾峰彇
+ const cachedTeamId = getTeamId();
+ if (cachedTeamId) {
+ teamId.value = cachedTeamId;
+ return;
+ }
+
+ // 濡傛灉缂撳瓨涓病鏈夛紝鍒欒皟鐢ㄦ帴鍙h幏鍙�
+ try {
+ const { data } = await HomeApi.getIndex();
+ if (data && data.team) {
+ teamId.value = data.team;
+ setTeamId(data.team);
+ }
+ } catch (error) {
+ console.error("鑾峰彇鐝粍ID澶辫触:", error);
+ }
+};
const toEdit = () => {
uni.navigateTo({
@@ -132,23 +176,83 @@
});
};
+// 涓昏〃鏁版嵁
+const mainTableData = ref<any>({});
+
+// 鑾峰彇涓昏〃鏁版嵁
+const getMainTableData = async () => {
+ try {
+ const { data } = await TwistApi.getTwistDetailById({
+ id: paramsId.value,
+ });
+ mainTableData.value = {
+ model: data.model,
+ totalLength: data.totalLength,
+ systemNo: data.systemNo,
+ };
+ // 璁剧疆涓昏〃鏁版嵁鍒拌〃鍗曠粍浠�
+ if (twistFormRef.value) {
+ twistFormRef.value.setMainTableData(mainTableData.value);
+ }
+ } catch (error) {
+ console.error("鑾峰彇涓昏〃鏁版嵁澶辫触:", error);
+ }
+};
+
const addReport = async () => {
- dialog.visible = true;
- // 鎵撳紑鏂板寮圭獥鏃惰嚜鍔ㄦ墽琛�
- // await showDrawPopup();
+ // 妫�鏌ユ槸鍚︽墍鏈夋暟鎹兘宸蹭繚瀛橈紙閮芥湁id锛�
+ if (twistReportList.value.length > 0 && twistReportList.value.every((item) => item.id)) {
+ // 纭繚涓昏〃鏁版嵁宸茶幏鍙�
+ if (!mainTableData.value.model) {
+ await getMainTableData();
+ }
+ dialog.visible = true;
+ // 绛夊緟寮圭獥鎵撳紑鍚庤缃暟鎹�
+ await nextTick();
+ if (twistFormRef.value) {
+ twistFormRef.value.setMainTableData(mainTableData.value);
+ }
+ } else if (twistReportList.value.length === 0) {
+ // 纭繚涓昏〃鏁版嵁宸茶幏鍙�
+ if (!mainTableData.value.model) {
+ await getMainTableData();
+ }
+ dialog.visible = true;
+ // 绛夊緟寮圭獥鎵撳紑鍚庤缃暟鎹�
+ await nextTick();
+ if (twistFormRef.value) {
+ twistFormRef.value.setMainTableData(mainTableData.value);
+ }
+ } else {
+ toast.warning("璇峰厛淇濆瓨鏈潯鏁版嵁锛屽啀鏂板");
+ }
};
const submit = async () => {
+ // 楠岃瘉蹇呭~瀛楁 - 鏍规嵁鍙傝�冧唬鐮侊紝闇�瑕佹鏌ョ敓浜ч暱搴﹀拰鐩樺叿鐨噸
+ const formData = twistFormRef.value?.getFormData?.() || {};
+ const firstTareValue =
+ twistReportList.value.length > 0 ? twistReportList.value[0].tare : undefined;
+
+ if (!formData.actuallyLength) {
+ toast.warning("璇疯緭鍏ョ敓浜ч暱搴﹀悗鍐嶆彁浜�");
+ return;
+ }
+
+ if (!formData.tare && !firstTareValue) {
+ toast.warning("璇疯緭鍏ョ洏鍏风毊閲嶅悗鍐嶆彁浜�");
+ return;
+ }
+
const isSuccess = await twistFormRef.value.submit();
- dialog.visible = !isSuccess; // 濡傛灉鎻愪氦鎴愬姛锛屽叧闂脊绐�
if (isSuccess) {
- // 鎻愪氦鎴愬姛鍚庢墽琛�
- // showDrawPopup();
+ dialog.visible = false;
+ // 鎻愪氦鎴愬姛鍚庡埛鏂板垪琛�
+ pagingRef.value?.reload();
}
};
const cancel = () => {
- toast.show("鍙栨秷");
dialog.visible = false;
};
@@ -197,6 +301,35 @@
});
};
+// 鍒犻櫎鎶ュ伐璁板綍
+const handleDelete = (item: any) => {
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "纭畾鍒犻櫎鍚楋紵",
+ success: async (res) => {
+ if (res.confirm) {
+ try {
+ if (item.id) {
+ const { code } = await TwistApi.deleteWireOutput({ id: item.id });
+ if (code == 200) {
+ toast.success("鍒犻櫎鎴愬姛");
+ // 鍒锋柊鍒楄〃
+ pagingRef.value?.reload();
+ } else {
+ toast.error("鍒犻櫎澶辫触");
+ }
+ } else {
+ toast.warning("璇ヨ褰曞皻鏈繚瀛橈紝鏃犳硶鍒犻櫎");
+ }
+ } catch (error) {
+ console.error("鍒犻櫎澶辫触:", error);
+ toast.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ }
+ }
+ },
+ });
+};
+
// 淇濈暀鍘熸湁鐨刢onfirm鍑芥暟锛岀敤浜庡叾浠栧湴鏂硅皟鐢�
// const confirm = async () => {
// await showDrawPopup();
@@ -208,11 +341,23 @@
wireId: paramsId.value,
type: "缁炵嚎",
});
+ // 鏍煎紡鍖栫敓浜ф棩鏈�
+ if (Array.isArray(data)) {
+ data.forEach((item: any) => {
+ if (item.productTime) {
+ item.productTime = dayjs(item.productTime).format("YYYY-MM-DD HH:mm:ss");
+ }
+ });
+ }
pagingRef.value.complete(data);
};
-onLoad((options: any) => {
+onLoad(async (options: any) => {
paramsId.value = options.id;
+ // 鑾峰彇骞剁紦瀛樼彮缁処D
+ await initTeamId();
+ // 鑾峰彇涓昏〃鏁版嵁
+ await getMainTableData();
showDrawPopup();
});
</script>
diff --git a/src/pages/production/wire/attachment/index.vue b/src/pages/production/wire/attachment/index.vue
index c654299..d6394e8 100644
--- a/src/pages/production/wire/attachment/index.vue
+++ b/src/pages/production/wire/attachment/index.vue
@@ -17,26 +17,54 @@
<view class="attachment-list">
<wd-status-tip v-if="attachmentList.length === 0" image="content" tip="鏆傛棤闄勪欢" />
- <wd-card
- v-for="item in attachmentList"
- :key="item.id"
- type="rectangle"
- custom-class="attachment-card"
- :border="false"
- >
- <view class="attachment-item" @click="previewAttachment(item)">
- <view class="attachment-info">
- <view class="attachment-name">{{ item.bucketFileName || item.name }}</view>
- <view class="attachment-meta">
- <text class="file-type">{{ getFileType(item.bucketFileName) }}</text>
- <text class="upload-time">{{ formatTime(item.createTime) }}</text>
+ <view v-for="item in attachmentList" :key="item.id" class="attachment-card">
+ <view class="media-wrapper" @click="previewAttachment(item)">
+ <!-- 鍥剧墖棰勮 -->
+ <template v-if="isImageType(item.url)">
+ <image
+ v-if="!item.loadError"
+ :src="getFullUrl(item.url)"
+ mode="aspectFill"
+ class="media-preview"
+ @error="onImageError(item)"
+ @load="onImageLoad(item)"
+ />
+ <!-- 鍥剧墖鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="picture" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
</view>
+ </template>
+
+ <!-- 瑙嗛棰勮 -->
+ <template v-else-if="isVideoType(item.url)">
+ <video
+ v-if="!item.loadError"
+ :src="getFullUrl(item.url)"
+ class="media-preview"
+ :controls="false"
+ :show-center-play-btn="false"
+ @error="onVideoError(item)"
+ />
+ <!-- 瑙嗛鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="video" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
+ </view>
+ </template>
+
+ <!-- 鍏朵粬鏂囦欢绫诲瀷鏄剧ず鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="file-outline" size="48px" color="#999" />
+ <text class="file-name">鏂囦欢</text>
</view>
- <view class="attachment-actions" @click.stop>
- <wd-icon name="delete" color="#ff4757" @click="deleteAttachment(item.id)" />
+
+ <!-- 鍒犻櫎鎸夐挳 -->
+ <view class="delete-btn" @click.stop="deleteAttachment(item.id)">
+ <wd-icon name="delete" color="#fff" size="20px" />
</view>
</view>
- </wd-card>
+ </view>
</view>
<wd-toast />
@@ -48,6 +76,12 @@
import { useToast } from "wot-design-uni";
import AttachmentAPI from "@/api/product/attachment";
+// H5 浣跨敤 VITE_APP_BASE_API 浣滀负浠g悊璺緞锛屽叾浠栧钩鍙颁娇鐢� VITE_APP_API_URL 浣滀负璇锋眰璺緞
+let baseUrl = import.meta.env.VITE_APP_API_URL;
+// #ifdef H5
+baseUrl = import.meta.env.VITE_APP_BASE_API;
+// #endif
+
const toast = useToast();
// 椤甸潰鍙傛暟
@@ -56,6 +90,57 @@
const attachmentList = ref<any[]>([]);
const detailData = ref<any>({});
+
+// 鑾峰彇瀹屾暣鐨勫浘鐗�/瑙嗛 URL
+const getFullUrl = (url: string) => {
+ if (!url) return "";
+ // 濡傛灉宸茬粡鏄畬鏁寸殑 URL锛坔ttp 鎴� https 寮�澶达級锛岀洿鎺ヨ繑鍥�
+ if (url.startsWith("http://") || url.startsWith("https://")) {
+ return url;
+ }
+ // 濡傛灉鏄浉瀵硅矾寰勶紝鎷兼帴鍩虹 URL
+ return `${baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
+};
+
+// 浠� URL 鎴栨枃浠跺悕涓彁鍙栨墿灞曞悕
+const getExtension = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "";
+ // 绉婚櫎鏌ヨ鍙傛暟鍜屽搱甯�
+ const cleanUrl = urlOrFileName.split("?")[0].split("#")[0];
+ // 鑾峰彇鏈�鍚庝竴涓偣鍚庨潰鐨勫唴瀹�
+ const extension = cleanUrl.split(".").pop()?.toLowerCase();
+ return extension || "";
+};
+
+// 鍒ゆ柇鏄惁涓哄浘鐗囩被鍨�
+const isImageType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(extension);
+};
+
+// 鍒ゆ柇鏄惁涓鸿棰戠被鍨�
+const isVideoType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["mp4", "mov", "avi", "wmv", "flv", "mkv", "webm"].includes(extension);
+};
+
+// 鍥剧墖鍔犺浇鎴愬姛
+const onImageLoad = (item: any) => {
+ item.loadError = false;
+};
+
+// 鍥剧墖鍔犺浇澶辫触
+const onImageError = (item: any) => {
+ console.error("鍥剧墖鍔犺浇澶辫触:", item.url);
+ item.loadError = true;
+};
+
+// 瑙嗛鍔犺浇澶辫触
+const onVideoError = (item: any) => {
+ console.error("瑙嗛鍔犺浇澶辫触:", item.url);
+ item.loadError = true;
+};
+
// 鑾峰彇闄勪欢鍒楄〃
const getAttachmentList = async (data: any) => {
try {
@@ -252,24 +337,24 @@
// 棰勮闄勪欢
const previewAttachment = (item: any) => {
// 鏍规嵁鏂囦欢绫诲瀷杩涜棰勮
- const fileName = item.bucketFileName || item.name;
- const fileType = getFileType(fileName);
+ const fileType = getFileType(item.url);
+ const fullUrl = getFullUrl(item.url);
if (fileType.startsWith("image")) {
// 鍥剧墖棰勮
uni.previewImage({
- urls: [item.url],
- current: item.url,
+ urls: [fullUrl],
+ current: fullUrl,
});
} else {
// 鍏朵粬鏂囦欢绫诲瀷锛屽彲浠ヤ笅杞芥垨鎵撳紑
uni.downloadFile({
- url: item.url,
+ url: fullUrl,
success: (res) => {
uni.openDocument({
filePath: res.tempFilePath,
success: () => {
- console.log("鎵撳紑鏂囨。鎴愬姛");
+ // 鎵撳紑鏂囨。鎴愬姛
},
fail: (error) => {
console.error("鎵撳紑鏂囨。澶辫触:", error);
@@ -286,9 +371,9 @@
};
// 鑾峰彇鏂囦欢绫诲瀷
-const getFileType = (fileName: string) => {
- if (!fileName) return "unknown";
- const extension = fileName.split(".").pop()?.toLowerCase();
+const getFileType = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "unknown";
+ const extension = getExtension(urlOrFileName);
switch (extension) {
case "jpg":
case "jpeg":
@@ -297,6 +382,14 @@
case "bmp":
case "webp":
return "image";
+ case "mp4":
+ case "mov":
+ case "avi":
+ case "wmv":
+ case "flv":
+ case "mkv":
+ case "webm":
+ return "video";
case "pdf":
return "pdf";
case "doc":
@@ -357,43 +450,80 @@
}
.attachment-list {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 8px;
+
.attachment-card {
- margin-bottom: 12px;
- border-radius: 4px;
+ width: 100%;
+ aspect-ratio: 1;
}
}
-.attachment-item {
- display: flex;
- align-items: center;
- padding: 12px;
+.media-wrapper {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f5f5f5;
- .attachment-info {
- flex: 1;
+ .media-preview {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
- .attachment-name {
- font-size: 16px;
- font-weight: 500;
- color: #333;
- margin-bottom: 4px;
- word-break: break-all;
- }
+ .file-icon-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ padding: 8px;
+ text-align: center;
- .attachment-meta {
- display: flex;
- gap: 12px;
+ .file-name {
+ margin-top: 8px;
font-size: 12px;
- color: #999;
+ color: #666;
+ word-break: break-all;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+
+ &.error-text {
+ color: #ff4757;
+ }
}
}
- .attachment-actions {
- margin-left: 12px;
-
- :deep(.wd-icon) {
- font-size: 20px;
- cursor: pointer;
- }
+ .delete-btn {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
}
}
</style>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/routingInspection/detail/indexJX.vue b/src/pages/routingInspection/detail/indexJX.vue
new file mode 100644
index 0000000..f655cb6
--- /dev/null
+++ b/src/pages/routingInspection/detail/indexJX.vue
@@ -0,0 +1,867 @@
+<template>
+ <view class="fixed-header">
+ <view class="header-container">
+ <wd-button
+ icon="file-add"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="editList"
+ v-if="!isEdit"
+ >
+ 缂栬緫
+ </wd-button>
+ <wd-button
+ icon="close"
+ type="info"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="close"
+ v-if="isEdit"
+ >
+ 鍙栨秷
+ </wd-button>
+ <wd-button
+ icon="check"
+ type="success"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="saveList"
+ v-if="isEdit"
+ >
+ 淇濆瓨
+ </wd-button>
+ <view class="placeholder"></view>
+ <view class="scan-info">
+ <text class="scan-device-text">褰撳墠鎵爜鏈哄彴: {{ scannedDeviceModel || "鏈壂鐮�" }}</text>
+ </view>
+ <view class="scan-wrapper" @click="openScan">
+ <wd-icon name="scan" size="24px" color="#0D867F"></wd-icon>
+ </view>
+ </view>
+ </view>
+ <view class="list">
+ <!-- 鍩烘湰淇℃伅妯″潡 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "鍩烘湰淇℃伅" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="鏃ユ湡" prop="recordDate">
+ {{ formatDate(recordData.fixedInfo?.recordDate) }}
+ </wd-form-item>
+ <wd-form-item label="鐝" prop="workShift">
+ {{ formatValue(recordData.fixedInfo?.workShift) }}
+ </wd-form-item>
+ <wd-form-item label="鍨嬪彿瑙勬牸" prop="model">
+ {{ formatValue(recordData.fixedInfo?.model) }}
+ </wd-form-item>
+ <wd-form-item label="鎴愬搧绾跨洏鍙�" prop="systemNo">
+ {{ formatValue(recordData.fixedInfo?.systemNo) }}
+ </wd-form-item>
+ <wd-form-item label="璁板綍浜�" prop="createUserName">
+ {{ formatValue(recordData.fixedInfo?.createUserName) }}
+ </wd-form-item>
+ <wd-form-item label="鏈哄彴" prop="deviceModel">
+ {{ formatValue(recordData.fixedInfo?.deviceModel) }}
+ </wd-form-item>
+ <wd-form-item label="浜у搧绫诲埆" prop="productType">
+ {{ formatValue(recordData.fixedInfo?.productType) }}
+ </wd-form-item>
+ <wd-form-item label="鐢熶骇闀垮害" prop="actuallyLength">
+ {{ formatValue(recordData.fixedInfo?.actuallyLength, "m") }}
+ </wd-form-item>
+ <wd-form-item label="寮犲姏璁剧疆" prop="tensionSetting">
+ {{ formatValue(recordData.fixedInfo?.tensionSetting, "N/m") }}
+ </wd-form-item>
+ <!-- 缁炲埗澶栧緞锛堝彲缂栬緫锛� -->
+ <wd-form-item label="缁炲悎澶栧緞" prop="twistedOuterDiameter" required>
+ <template v-if="isEdit">
+ <wd-input
+ v-model="formData.twistedOuterDiameter"
+ placeholder="璇疯緭鍏ョ粸鍚堝寰勶紙mm锛�"
+ type="number"
+ />
+ </template>
+ <template v-else>
+ {{ formatValue(formData.twistedOuterDiameter, "mm") }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 宸ヨ壓璁板綍璇︽儏妯″潡 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "宸ヨ壓璁板綍璇︽儏" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="璁板綍浣嶇疆" prop="recordPosition">
+ {{ recordData.structureInfo?.recordPosition || "-" }}
+ </wd-form-item>
+ <wd-form-item label="璁板綍浜�" prop="createUserName">
+ {{ recordData.structureInfo?.createUserName || "-" }}
+ </wd-form-item>
+ <wd-form-item label="鐘舵��" prop="status">
+ <wd-tag custom-class="space" :type="getStatusType(recordData.structureInfo?.status)">
+ {{ getStatusText(recordData.structureInfo?.status) }}
+ </wd-tag>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 缁撴瀯妫�鏌ユā鍧� -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "缁撴瀯妫�鏌�" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="鎴愬搧缁撴瀯" prop="structureFormula" required>
+ <template v-if="isEdit">
+ <wd-input v-model="formData.structureFormula" placeholder="璇疯緭鍏ユ垚鍝佺粨鏋�" />
+ </template>
+ <template v-else>
+ {{ formData.structureFormula || "-" }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 缁撴瀯鏍囧噯鍊煎拰瀹炴祴锛堝彲缂栬緫锛� -->
+ <wd-row v-if="formData.structureItems.length">
+ <view style="margin: 10rpx">
+ <text class="title">{{ "缁撴瀯鏍囧噯鍊煎拰瀹炴祴" }}</text>
+ </view>
+ <wd-col
+ :span="24"
+ v-for="(item, index) in formData.structureItems"
+ :key="index"
+ style="padding-bottom: 10px"
+ >
+ <wd-form-item
+ prop="structureItemsGroup"
+ :label="formatValue(item.structureName)"
+ label-width="400rpx"
+ style="color: red"
+ required
+ ></wd-form-item>
+ <wd-form-item label="鏍囧噯鍊�" prop="structureValue" required>
+ {{ formatValue(item.structureValue) }}
+ </wd-form-item>
+ <wd-form-item label="瀹炴祴鏍规暟" prop="actualValue1" required>
+ <template v-if="isEdit">
+ <wd-input v-model="item.actualValue1" placeholder="璇疯緭鍏ュ疄娴嬫牴鏁�" type="number" />
+ </template>
+ <template v-else>
+ {{ formatValue(item.actualValue1, "鏍�") }}
+ </template>
+ </wd-form-item>
+ <wd-form-item label="瀹炴祴鐩村緞" prop="actualValue2" required>
+ <template v-if="isEdit">
+ <wd-input
+ v-model="item.actualValue2"
+ placeholder="璇疯緭鍏ュ疄娴嬬洿寰勶紙mm锛�"
+ type="number"
+ />
+ </template>
+ <template v-else>
+ {{ formatValue(item.actualValue2, "mm") }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 缁炵嚎宸ヨ壓璐ㄩ噺鎺у埗锛堝彲缂栬緫锛� -->
+ <wd-row v-if="formData.inspectTwist.length">
+ <view style="margin: 10rpx">
+ <text class="title">{{ "缁炵嚎宸ヨ壓璐ㄩ噺鎺у埗" }}</text>
+ </view>
+ <wd-col
+ :span="24"
+ v-for="(item, index) in formData.inspectTwist"
+ :key="index"
+ style="padding-bottom: 10px"
+ >
+ <wd-form-item
+ :label="formatValue(item.twistName)"
+ label-width="400rpx"
+ style="color: red"
+ prop="inspectTwistGroup"
+ required
+ ></wd-form-item>
+ <wd-form-item label="缁炲悜" prop="direction" required>
+ <template v-if="isEdit">
+ <wd-select-picker
+ label=""
+ v-model="item.direction"
+ :columns="twistDirectionOptions"
+ type="radio"
+ placeholder="璇烽�夋嫨缁炲悜"
+ :clearable="false"
+ ></wd-select-picker>
+ </template>
+ <template v-else>
+ {{ formatValue(item.direction) }}
+ </template>
+ </wd-form-item>
+ <wd-form-item label="鑺傝窛" prop="pitch" required>
+ <template v-if="isEdit">
+ <wd-input
+ v-model="item.pitch"
+ placeholder="璇疯緭鍏ヨ妭璺濓紙mm锛�"
+ type="number"
+ @input="updatePitchRatio(item)"
+ />
+ </template>
+ <template v-else>
+ {{ formatValue(item.pitch, "mm") }}
+ </template>
+ </wd-form-item>
+ <wd-form-item label="鑺傚緞姣�" prop="pitchRatio" required>
+ {{ formatValue(item.pitchRatio) }}
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 澶栬鍜岀粨璁猴紙鍙紪杈戯級 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "澶栬鍜岀粨璁�" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="浜у搧澶栬" prop="productAppearance" required>
+ <template v-if="isEdit">
+ <view style="display: flex; flex-wrap: wrap; gap: 10px">
+ <wd-checkbox
+ v-for="(opt, idx) in appearanceOptions"
+ :key="idx"
+ :value="opt.value"
+ :modelValue="formData.productAppearance.includes(opt.value)"
+ @click="handleAppearanceClick(opt.value)"
+ style="width: 100px"
+ >
+ {{ opt.label }}
+ </wd-checkbox>
+ </view>
+ </template>
+ <template v-else>
+ {{ formatProductAppearance(formData.productAppearance) }}
+ </template>
+ </wd-form-item>
+ <wd-form-item label="缁撹" prop="conclusion" required>
+ <template v-if="isEdit">
+ <wd-radio-group v-model="formData.conclusion" inline class="conclusion-radio-group">
+ <wd-radio
+ v-for="(opt, idx) in conclusionOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(formData.conclusion) }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 宸℃缁撴灉妯″潡 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "宸℃缁撴灉" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="鏍峰搧鏄惁榻愬叏" prop="isFully" required>
+ <template v-if="isEdit">
+ <wd-radio-group v-model="formData.isFully" inline class="conclusion-radio-group">
+ <wd-radio
+ v-for="(opt, idx) in sampleCompleteOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(formData.isFully) }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 闄勪欢妯″潡锛堝惈涓婁紶鍔熻兘锛� -->
+ <wd-row class="attachment-section">
+ <view style="margin: 10rpx">
+ <text class="title">{{ "闄勪欢" }}</text>
+ </view>
+ <wd-col :span="24">
+ <AttachmentUpload
+ :detailData="detailData"
+ :isEdit="isEdit"
+ :deviceType="paramsType"
+ ref="attachmentRef"
+ v-if="detailDataLoaded"
+ />
+ </wd-col>
+ </wd-row>
+
+ <wd-popup v-model="show" custom-style="border-radius:32rpx;" @close="handleClose">
+ <div class="image-preview">
+ <img :src="previewImageUrl" alt="棰勮鍥剧墖" style="width: 100%; height: auto" />
+ </div>
+ </wd-popup>
+ <wd-toast />
+ </view>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed, onUnmounted } from "vue";
+import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
+import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
+import { useToast } from "wot-design-uni";
+import AttachmentUpload from "../upload.vue";
+import { useUserStore } from "@/store/modules/user";
+import { useScanCode } from "@/composables/useScanCode";
+
+const paramsType = ref("");
+const paramsId = ref("");
+const recordData = ref<any>({ structureInfo: { files: [], structureRecordResult: {} } });
+const show = ref(false);
+const previewImageUrl = ref("");
+const isEdit = ref(false);
+const tempFiles = ref<any[]>([]); // 涓存椂瀛樺偍鏂颁笂浼犵殑闄勪欢
+const toast = useToast();
+const attachmentRef = ref<any>(null);
+const detailData = reactive<any>({});
+const detailDataLoaded = ref(false);
+
+// 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+const userStore = useUserStore();
+const userInfo: any = computed(() => userStore.userInfo);
+
+// 浣跨敤鎵爜绠$悊 composable锛堝叏灞�鐩戝惉鍣紝涓嶉殢椤甸潰鍒囨崲鍏抽棴锛�
+const {
+ deviceUid,
+ deviceModel: scannedDeviceModel,
+ loadFromCache,
+ enableListener,
+} = useScanCode("scanJX");
+
+const formData = reactive({
+ twistedOuterDiameter: "", // 缁炲埗澶栧緞
+ structureFormula: "", // 鎴愬搧缁撴瀯
+ structureItems: [], // 缁撴瀯鏍囧噯鍊煎拰瀹炴祴
+ inspectTwist: [], // 缁炵嚎宸ヨ壓璐ㄩ噺鎺у埗
+ productAppearance: [] as string[], // 浜у搧澶栬锛堟敼涓烘暟缁勫瓨鍌ㄩ�変腑鍊硷級
+ conclusion: "", // 缁撹锛堟敼涓烘暟缁勫瓨鍌ㄩ�変腑鍊硷級
+ isFully: "", // 鏍峰搧鏄惁榻愬叏
+});
+
+const twistDirectionOptions = [
+ { label: "宸﹀悜", value: "宸﹀悜" },
+ { label: "鍙冲悜", value: "鍙冲悜" },
+];
+
+const appearanceOptions = [
+ { label: "鏃犲瑙傞棶棰�", value: "鏃犲瑙傞棶棰�" },
+ { label: "琛ㄩ潰鍒掍激", value: "琛ㄩ潰鍒掍激" },
+ { label: "鐩村緞涓嶅潎", value: "鐩村緞涓嶅潎" },
+ { label: "鍏朵粬缂洪櫡", value: "鍏朵粬缂洪櫡" },
+];
+
+const conclusionOptions = [
+ { label: "鍚堟牸", value: "鍚堟牸" },
+ { label: "涓嶅悎鏍�", value: "涓嶅悎鏍�" },
+];
+const sampleCompleteOptions = [
+ { label: "鏄�", value: "鏄�" },
+ { label: "鍚�", value: "鍚�" },
+];
+
+const initFormData = () => {
+ const structureResult = recordData.value.structureInfo?.structureRecordResult || {};
+ const inspectionResult = recordData.value.inspectionResult || {};
+
+ formData.twistedOuterDiameter =
+ recordData.value.structureInfo.structureRecordResult.twistedOuterDiameter || "";
+ formData.structureFormula = structureResult.inspectStructure?.structureFormula || "";
+ formData.isFully = inspectionResult.isFully || "";
+ formData.conclusion = structureResult.conclusion || "";
+
+ // 鍒濆鍖栦骇鍝佸瑙�
+ const appearance = Array.isArray(structureResult.productAppearance)
+ ? structureResult.productAppearance
+ : structureResult.productAppearance
+ ? [structureResult.productAppearance]
+ : [];
+ formData.productAppearance = appearance;
+
+ formData.structureItems = JSON.parse(
+ JSON.stringify(structureResult.inspectStructure?.structureItems || [])
+ );
+ formData.inspectTwist = JSON.parse(JSON.stringify(structureResult.inspectTwist || []));
+
+ formData.inspectTwist.forEach((item: any) => {
+ if (!item.direction) item.direction = "";
+ });
+};
+
+const getDetailData = async (id: string, deviceType: string) => {
+ try {
+ const response = await RoutingInspectionApi.getStrandedInspectionStructureInfoById({ id });
+ recordData.value = response.data;
+ detailData.value = response.data.structureInfo;
+
+ // 濡傛灉璁板綍浜轰负绌猴紝榛樿璁剧疆涓哄綋鍓嶇櫥褰曠敤鎴�
+ if (recordData.value.structureInfo && !recordData.value.structureInfo.createUserName) {
+ recordData.value.structureInfo.createUserName =
+ userInfo.value?.nickName || userInfo.value?.userName || "";
+ }
+
+ console.log("detailData.value", detailData.value);
+ tempFiles.value = []; // 娓呯┖涓存椂鏂囦欢
+ initFormData(); // 鏁版嵁杩斿洖鍚庡垵濮嬪寲琛ㄥ崟
+ detailDataLoaded.value = true; // 鏁版嵁鍔犺浇瀹屾垚鍚庯紝娓叉煋瀛愮粍浠�
+ console.log("鐖剁粍浠�-鏁版嵁灏辩华鍚庢墦鍗�");
+ } catch (error) {
+ console.error("鑾峰彇璇︽儏澶辫触:", error);
+ uni.showToast({ title: "鍔犺浇澶辫触", icon: "error" });
+ }
+};
+
+// 椤甸潰鍔犺浇
+onLoad((options: any) => {
+ try {
+ paramsId.value = options.id;
+ paramsType.value = options.deviceType;
+ getDetailData(options.id, options.deviceType);
+ } catch (error) {
+ console.error("鑾峰彇璇︽儏澶辫触:", error);
+ uni.showToast({ title: "鍔犺浇澶辫触", icon: "error" });
+ }
+});
+
+// 缂栬緫妯″紡鍒囨崲
+const editList = () => {
+ isEdit.value = true;
+};
+
+// 鍙栨秷缂栬緫锛堥噸缃〃鍗曪級
+const close = () => {
+ isEdit.value = false;
+ tempFiles.value = [];
+ initFormData();
+};
+
+// 淇濆瓨缂栬緫锛堝惈蹇呭~椤规牎楠岋級
+const saveList = async () => {
+ // 1. 鍩虹瀛楁鏍¢獙
+ if (!formData.structureFormula) return uni.showToast({ title: "鎴愬搧缁撴瀯涓哄繀濉」", icon: "none" });
+ if (!formData.twistedOuterDiameter)
+ return uni.showToast({ title: "缁炲埗澶栧緞涓哄繀濉」", icon: "none" });
+ if (!formData.productAppearance.length)
+ return uni.showToast({ title: "浜у搧澶栬涓哄繀濉」", icon: "none" });
+ if (!formData.conclusion) return uni.showToast({ title: "缁撹涓哄繀濉」", icon: "none" });
+ if (!formData.isFully) return uni.showToast({ title: "鏍峰搧鏄惁榻愬叏涓哄繀濉」", icon: "none" });
+ // 2. 缁撴瀯椤瑰惊鐜牎楠�
+ for (const item of formData.structureItems) {
+ if (!item.structureValue)
+ return uni.showToast({ title: `${item.structureName}鏍囧噯鍊间负蹇呭~椤筦, icon: "none" });
+ if (!item.actualValue1)
+ return uni.showToast({ title: `${item.structureName}瀹炴祴鏍规暟涓哄繀濉」`, icon: "none" });
+ if (!item.actualValue2)
+ return uni.showToast({ title: `${item.structureName}瀹炴祴鐩村緞涓哄繀濉」`, icon: "none" });
+ }
+
+ // 3. 缁炵嚎宸ヨ壓椤瑰惊鐜牎楠�
+ for (const item of formData.inspectTwist) {
+ if (!item.direction)
+ return uni.showToast({ title: `${item.twistName}缁炲悜涓哄繀濉」`, icon: "none" });
+ if (!item.pitch) return uni.showToast({ title: `${item.twistName}鑺傝窛涓哄繀濉」`, icon: "none" });
+ if (!item.pitchRatio)
+ return uni.showToast({ title: `${item.twistName}鑺傚緞姣斾负蹇呭~椤筦, icon: "none" });
+ }
+ // 楠岃瘉鎵爜鏁版嵁锛堜粠缂撳瓨鎴栨柊鎵爜鑾峰彇锛�
+ console.log("淇濆瓨鍓嶆鏌� deviceUid:", deviceUid.value);
+ if (!deviceUid.value) {
+ return uni.showToast({
+ title: "璇峰厛鎵弿璁惧浜岀淮鐮�",
+ icon: "none",
+ duration: 2000,
+ });
+ }
+ const { newFiles } = attachmentRef.value.getSubmitFiles();
+ console.log("newFiles", newFiles);
+ const allFileIds = [...newFiles];
+ try {
+ const res = await RoutingInspectionApi.strandedPatrolCheckInspection({
+ deviceUid: deviceUid.value,
+ id: paramsId.value,
+ inspectionResult: {
+ twistedOuterDiameter: formData.twistedOuterDiameter,
+ structureFormula: formData.structureFormula,
+ structureItems: formData.structureItems,
+ inspectTwist: formData.inspectTwist,
+ productAppearance: formData.productAppearance,
+ conclusion: formData.conclusion,
+ isFully: formData.isFully,
+ },
+ result: {
+ isFully: formData.isFully,
+ },
+ processInspectionAttachmentList: allFileIds,
+ });
+
+ if (res.code === 200) {
+ // 璁剧疆鍒锋柊鏍囪锛屽憡璇夊垪琛ㄩ〉闇�瑕佸埛鏂�
+ uni.setStorageSync("needRefreshInspectionList", true);
+
+ uni.showToast({
+ title: "淇濆瓨鎴愬姛",
+ icon: "success",
+ duration: 1500,
+ });
+ // 寤惰繜杩斿洖鍒楄〃椤碉紝璁╃敤鎴风湅鍒版垚鍔熸彁绀�
+ setTimeout(() => {
+ uni.navigateBack({
+ delta: 1,
+ });
+ }, 1500);
+ } else {
+ uni.showModal({ title: res.msg || "淇濆瓨澶辫触", icon: "error" });
+ }
+ } catch (e) {
+ console.error("淇濆瓨澶辫触:", e);
+ uni.showModal({ title: e.message || "淇濆瓨澶辫触", icon: "error" });
+ }
+};
+
+const handleClose = () => {
+ show.value = false;
+};
+
+// 鐘舵�佺被鍨嬫槧灏�
+const getStatusType = (status: number) => {
+ switch (status) {
+ case 0:
+ return "warning"; // 寰呭贰妫�
+ case 1:
+ return "danger"; // 宸查┏鍥�
+ case 2:
+ return "primary"; // 寰呭鏍�
+ case 3:
+ return "success"; // 閫氳繃
+ default:
+ return "default";
+ }
+};
+
+// 鐘舵�佹枃鏈槧灏�
+const getStatusText = (status: number) => {
+ switch (status) {
+ case 0:
+ return "寰呭贰妫�";
+ case 1:
+ return "宸查┏鍥�";
+ case 2:
+ return "寰呭鏍�";
+ case 3:
+ return "閫氳繃";
+ default:
+ return "鏈煡";
+ }
+};
+
+// 鏍煎紡鍖栦骇鍝佸瑙傛樉绀�
+const formatProductAppearance = (productAppearance: string[]) => {
+ if (!productAppearance || productAppearance.length === 0) return "-";
+ return productAppearance.join("銆�");
+};
+
+// 鏍煎紡鍖栨暟鍊兼樉绀�
+const formatValue = (value: any, unit?: string) => {
+ if (value === null || value === undefined || value === "") return "-";
+ return unit ? `${value}${unit}` : value;
+};
+
+// 鏍煎紡鍖栨棩鏈熸樉绀�
+const formatDate = (date: string) => {
+ if (!date) return "-";
+ return new Date(date).toLocaleDateString("zh-CN", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ });
+};
+
+// 璁$畻鑺傚緞姣�
+const calculatePitchRatio = (pitch: string, dia: string) => {
+ // 濡傛灉pitch鎴杁ia涓虹┖锛屽垯杩斿洖"-"
+ if (!pitch || !dia) return "-";
+
+ // 灏唒itch鍜宒ia杞崲涓烘诞鐐规暟
+ const pitchNum = parseFloat(pitch);
+ const diaNum = parseFloat(dia);
+
+ // 濡傛灉pitchNum鎴杁iaNum鏄疦aN锛屾垨鑰卍iaNum涓�0锛屽垯杩斿洖"-"
+ if (isNaN(pitchNum) || isNaN(diaNum) || diaNum === 0) return "-";
+
+ // 璁$畻pitchNum鍜宒iaNum鐨勬瘮鍊硷紝骞朵繚鐣欎袱浣嶅皬鏁�
+ return (pitchNum / diaNum).toFixed(2);
+};
+
+// 鏇存柊鑺傚緞姣旓紙褰撹妭璺濆彉鍖栨椂鑷姩璁$畻锛�
+const updatePitchRatio = (item: any) => {
+ // 浣跨敤缁炲悎澶栧緞浣滀负鐩村緞鏉ヨ绠楄妭寰勬瘮
+ const dia = item.dia;
+ item.pitchRatio = calculatePitchRatio(item.pitch, dia);
+};
+
+// 澶勭悊浜у搧澶栬閫夋嫨鐨勪簰鏂ラ�昏緫
+const handleAppearanceClick = (value: string) => {
+ const currentValues = [...formData.productAppearance];
+ const isCurrentlyChecked = currentValues.includes(value);
+
+ let newSelection: string[] = [];
+
+ if (value === "鏃犲瑙傞棶棰�") {
+ if (isCurrentlyChecked) {
+ // 鍙栨秷閫変腑"鏃犲瑙傞棶棰�"
+ newSelection = [];
+ } else {
+ // 閫変腑"鏃犲瑙傞棶棰�"锛屾竻绌哄叾浠栭�夐」
+ newSelection = ["鏃犲瑙傞棶棰�"];
+ }
+ } else {
+ // 鐐瑰嚮鍏朵粬閫夐」
+ if (isCurrentlyChecked) {
+ // 鍙栨秷閫変腑璇ラ�夐」
+ newSelection = currentValues.filter((v) => v !== value);
+ } else {
+ // 閫変腑璇ラ�夐」锛岀Щ闄�"鏃犲瑙傞棶棰�"
+ const filteredValues = currentValues.filter((v) => v !== "鏃犲瑙傞棶棰�");
+ newSelection = [...filteredValues, value];
+ }
+ }
+
+ formData.productAppearance = newSelection;
+};
+
+const openScan = () => {
+ console.log("indexJX - 鐐瑰嚮鎵爜鎸夐挳锛堝叏灞�鎵爜妯″紡锛屾棤闇�鎵嬪姩瑙﹀彂锛�");
+ // 鍏ㄥ眬鎵爜妯″紡涓嬶紝纭欢鎵爜浼氳嚜鍔ㄨЕ鍙戯紝鏃犻渶鎵嬪姩璋冪敤
+ uni.showToast({
+ title: "璇蜂娇鐢ㄦ壂鐮佹灙鎵弿",
+ icon: "none",
+ });
+};
+
+// 椤甸潰鏄剧ず鏃剁殑澶勭悊
+onShow(() => {
+ console.log("========== indexJX - onShow 瑙﹀彂 ==========");
+ // 閲嶆柊鍚敤鐩戝惉鍣紙纭繚鐩戝惉鍣ㄦ湁鏁堬級
+ enableListener();
+ // 鍔犺浇缂撳瓨锛堟洿鏂癠I鏄剧ず锛�
+ const cachedData = loadFromCache();
+
+ // 濡傛灉娌℃湁缂撳瓨鏁版嵁锛屾彁绀虹敤鎴烽渶瑕佹壂鐮�
+ if (!cachedData || !cachedData.uid) {
+ console.log("鈿狅笍 鏈娴嬪埌鎵爜缂撳瓨锛岀敤鎴烽渶瑕佹壂鎻忚澶囦簩缁寸爜");
+ // 鍦ㄧ紪杈戞ā寮忎笅鎵嶆彁绀�
+ if (isEdit.value) {
+ setTimeout(() => {
+ uni.showToast({
+ title: "璇锋壂鎻忚澶囦簩缁寸爜鍚庡啀淇濆瓨",
+ icon: "none",
+ duration: 2000,
+ });
+ }, 500);
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.fixed-header {
+ position: fixed;
+ top: 44;
+ left: 0;
+ right: 0;
+ background: #f3f9f8;
+ z-index: 999;
+ padding: 12px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ min-height: 60px;
+ box-sizing: border-box;
+ overflow: visible;
+}
+
+.header-container {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ gap: 10px;
+}
+
+.placeholder {
+ flex: 1;
+}
+
+.scan-info {
+ display: flex;
+ align-items: center;
+ margin-right: 10px;
+
+ .scan-device-text {
+ font-size: 14px;
+ color: #0d867f;
+ font-weight: 500;
+ }
+}
+
+.scan-wrapper {
+ width: 38px;
+ height: 38px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px;
+ flex-shrink: 0;
+}
+
+.list {
+ padding: 12px;
+ padding-top: 84px;
+ background: #f3f9f8;
+ min-height: 100vh;
+ box-sizing: border-box;
+ overflow-y: auto;
+}
+
+.title {
+ position: relative;
+ margin-left: 10px;
+ font-size: 16px;
+ font-weight: 500;
+ color: #0d867f;
+}
+
+.title::after {
+ position: absolute;
+ content: "";
+ top: 4px;
+ left: -10px;
+ width: 4px;
+ height: 16px;
+ background: #0d867f;
+ border-radius: 2px;
+}
+
+// 浜у搧澶栬鍜岀粨璁洪�夋嫨鍣ㄦ牱寮忥紙涓�琛屼袱涓級
+.checkbox-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+ padding: 8rpx 0;
+}
+
+.checkbox-item {
+ width: calc(50% - 8rpx);
+ margin-bottom: 8rpx;
+}
+
+// 闄勪欢鐩稿叧鏍峰紡
+.attachment-section {
+ width: 100%;
+}
+
+.attachment-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ padding: 10px 0;
+}
+
+.attachment-item {
+ width: calc(25% - 10px);
+ box-sizing: border-box;
+ position: relative;
+}
+
+.upload-btn {
+ width: 80px;
+ height: 80px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px dashed #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+}
+
+.upload-icon {
+ font-size: 32px;
+ color: #0d867f;
+}
+
+// 闄勪欢鍒犻櫎鍥炬爣
+.delete-icon {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ width: 24px;
+ height: 24px;
+ background-color: rgba(255, 0, 0, 0.8);
+ color: white;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
+}
+
+@media (max-width: 768px) {
+ .attachment-item {
+ width: calc(25% - 10px);
+ }
+}
+
+// 缂栬緫妯″紡涓嬭〃鍗曠粍浠舵牱寮忎紭鍖�
+:deep(.wd-form-item) {
+ margin-bottom: 8rpx;
+}
+
+:deep(.wd-input, .wd-select, .wd-radio-group, .wd-checkbox-group) {
+ width: 100%;
+ box-sizing: border-box;
+}
+
+:deep(.wd-form-item__label) {
+ &::after {
+ content: "*";
+ color: red;
+ margin-left: 4rpx;
+ }
+}
+
+// 淇閫夋嫨鍣ㄦ牱寮�
+:deep(.wd-select) {
+ width: 100%;
+}
+
+:deep(.wd-checkbox) {
+ margin-right: 0;
+}
+.conclusion-radio-group {
+ display: flex;
+ align-items: flex-start; // 鍨傜洿鏂瑰悜椤堕儴瀵归綈锛堜笂绉诲叧閿級
+ gap: 20rpx; // 閫夐」涔嬮棿鐨勯棿璺�
+}
+</style>
diff --git a/src/pages/routingInspection/detail/indexLS.vue b/src/pages/routingInspection/detail/indexLS.vue
new file mode 100644
index 0000000..d2d46a6
--- /dev/null
+++ b/src/pages/routingInspection/detail/indexLS.vue
@@ -0,0 +1,788 @@
+<template>
+ <view class="fixed-header">
+ <view class="header-container">
+ <wd-button
+ icon="file-add"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="editList"
+ v-if="!isEdit"
+ >
+ 缂栬緫
+ </wd-button>
+ <wd-button
+ icon="close"
+ type="info"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="close"
+ v-if="isEdit"
+ >
+ 鍙栨秷
+ </wd-button>
+ <wd-button
+ icon="check"
+ type="success"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="saveList"
+ v-if="isEdit"
+ >
+ 淇濆瓨
+ </wd-button>
+ <view class="placeholder"></view>
+ <view class="scan-info">
+ <text class="scan-device-text">褰撳墠鎵爜鏈哄彴: {{ scannedDeviceModel || "鏈壂鐮�" }}</text>
+ </view>
+ <view class="scan-wrapper" @click="openScan">
+ <wd-icon name="scan" size="24px" color="#0D867F"></wd-icon>
+ </view>
+ </view>
+ </view>
+ <view class="list">
+ <!-- 鍩烘湰淇℃伅妯″潡 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "鍩烘湰淇℃伅" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="鏃ユ湡" prop="recordDate">
+ {{ formatDate(detailData.fixedInfo?.recordDate) }}
+ </wd-form-item>
+ <wd-form-item label="鏈哄彴" prop="deviceModel">
+ {{ formatValue(detailData.fixedInfo?.deviceModel) }}
+ </wd-form-item>
+ <wd-form-item label="鐝" prop="workShift">
+ {{ formatValue(detailData.fixedInfo?.workShift) }}
+ </wd-form-item>
+ <wd-form-item label="鐝粍" prop="teamName">
+ {{ formatValue(detailData.fixedInfo?.teamName) }}
+ </wd-form-item>
+ <wd-form-item label="鍗曚笣瑙勬牸" prop="model">
+ {{ formatValue(detailData.fixedInfo?.model) }}
+ </wd-form-item>
+ <wd-form-item label="鐢熶骇杞存暟" prop="outputNumber">
+ {{ formatValue(detailData.fixedInfo?.outputNumber, "杞�") }}
+ </wd-form-item>
+ <wd-form-item label="鍨嬪彿" prop="poleModel">
+ {{ formatValue(detailData.fixedInfo?.poleModel) }}
+ </wd-form-item>
+ <wd-form-item label="鎵规" prop="poleNumber">
+ {{ formatValue(detailData.fixedInfo?.poleNumber) }}
+ </wd-form-item>
+ <wd-form-item label="璁板綍浜�" prop="createUserName">
+ {{ formatValue(detailData.fixedInfo?.createUserName) }}
+ </wd-form-item>
+ <wd-form-item label="棣栨鐩樺彿" prop="firstNo">
+ {{ formatValue(detailData.fixedInfo?.firstNo) }}
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 宸ヨ壓璁板綍璇︽儏妯″潡 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "宸ヨ壓璁板綍璇︽儏" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="宸℃鍛�" prop="processInspectionUserName">
+ {{ detailData.processInspectionUserName || "-" }}
+ </wd-form-item>
+ <wd-form-item label="鐘舵��" prop="status">
+ <wd-tag custom-class="space" :type="getStatusType(detailData.status)">
+ {{ getStatusText(detailData.status) }}
+ </wd-tag>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 妫�楠岀粨鏋� -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "妫�楠岀粨鏋�" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item label="鍗曚笣鐩村緞" prop="dia">
+ {{ formatValue(detailData.inspectionResult?.dia, "mm") || "-" }}
+ </wd-form-item>
+
+ <wd-form-item label="鏈�澶х洿寰�" prop="maxDia" required>
+ <template v-if="isEdit">
+ <wd-input v-model="formData.maxDia" placeholder="璇疯緭鍏ユ渶澶х洿寰�(mm)" type="number" />
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.maxDia, "mm") || "-" }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="鏈�灏忕洿寰�" prop="minDia" required>
+ <template v-if="isEdit">
+ <wd-input v-model="formData.minDia" placeholder="璇疯緭鍏ユ渶灏忕洿寰�(mm)" type="number" />
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.minDia, "mm") || "-" }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="澶栬" prop="appearance" required>
+ <template v-if="isEdit">
+ <view style="display: flex; flex-wrap: wrap; gap: 10px">
+ <wd-checkbox
+ v-for="(opt, idx) in appearanceOptions"
+ :key="idx"
+ :value="opt.value"
+ :modelValue="formData.appearance?.includes(opt.value) || false"
+ @click="handleAppearanceClick(opt.value)"
+ style="width: 100px"
+ >
+ {{ opt.label }}
+ </wd-checkbox>
+ </view>
+ </template>
+ <template v-else>
+ {{ formatProductAppearance(formData.appearance) }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="鍗风粫绱у瘑" prop="windingTightness" required>
+ <template v-if="isEdit">
+ <wd-radio-group
+ v-model="formData.windingTightness"
+ inline
+ class="conclusion-radio-group"
+ >
+ <wd-radio
+ v-for="(opt, idx) in sampleCompleteOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.windingTightness) }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="鎺掑垪鏁撮綈" prop="arrangementNeatness" required>
+ <template v-if="isEdit">
+ <wd-radio-group
+ v-model="formData.arrangementNeatness"
+ inline
+ class="conclusion-radio-group"
+ >
+ <wd-radio
+ v-for="(opt, idx) in sampleCompleteOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.arrangementNeatness) }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item
+ label="澶栧眰閾濈嚎绂讳晶鏉胯竟缂樿窛绂�"
+ prop="aluminumWireDistance"
+ label-width="360rpx"
+ required
+ >
+ <template v-if="isEdit">
+ <wd-input
+ v-model="formData.aluminumWireDistance"
+ placeholder="璇疯緭鍏ヨ窛绂�(mm)"
+ type="number"
+ />
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.aluminumWireDistance, "mm") || "-" }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="鎴愬搧妯″悗鎺ュご鎯呭喌" prop="jointCondition" label-width="280rpx" required>
+ <template v-if="isEdit">
+ <wd-radio-group v-model="formData.jointCondition" inline class="conclusion-radio-group">
+ <wd-radio
+ v-for="(opt, idx) in jointConditionOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.jointCondition) || "-" }}
+ </template>
+ </wd-form-item>
+
+ <wd-form-item label="缁撹" prop="conclusion" required>
+ <template v-if="isEdit">
+ <wd-radio-group v-model="formData.conclusion" inline class="conclusion-radio-group">
+ <wd-radio
+ v-for="(opt, idx) in conclusionOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ {{ formatValue(detailData.inspectionResult?.conclusion) || "-" }}
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 宸℃缁撴灉 -->
+ <wd-row>
+ <view style="margin: 10rpx">
+ <text class="title">{{ "宸℃缁撴灉" }}</text>
+ </view>
+ <wd-col :span="24">
+ <wd-form-item
+ label="閾濇潌鍓嶃�佷腑銆佸熬鏍峰搧鏄惁榻愬叏"
+ prop="isFully"
+ required
+ label-width="420rpx"
+ >
+ <template v-if="isEdit">
+ <wd-radio-group v-model="formData.isFully" inline class="conclusion-radio-group">
+ <wd-radio
+ v-for="(opt, idx) in sampleCompleteOptions"
+ :key="idx"
+ :value="opt.value"
+ shape="dot"
+ >
+ {{ opt.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </template>
+ <template v-else>
+ <wd-tag
+ custom-class="space"
+ :type="detailData.processInspectionResult?.isFully ? 'success' : 'danger'"
+ >
+ {{ detailData.processInspectionResult?.isFully ? "鏄�" : "鍚�" }}
+ </wd-tag>
+ </template>
+ </wd-form-item>
+ </wd-col>
+ </wd-row>
+
+ <!-- 闄勪欢妯″潡 -->
+ <wd-row class="attachment-section">
+ <view style="margin: 10rpx">
+ <text class="title">{{ "闄勪欢" }}</text>
+ </view>
+ <wd-col :span="24">
+ <AttachmentUpload
+ :detailData="detailData"
+ :isEdit="isEdit"
+ :deviceType="paramsType"
+ ref="attachmentRef"
+ />
+ </wd-col>
+ </wd-row>
+ <wd-popup v-model="show" custom-style="border-radius:32rpx;" @close="handleClose">
+ <div class="image-preview">
+ <img :src="previewImageUrl" alt="棰勮鍥剧墖" style="width: 100%; height: auto" />
+ </div>
+ </wd-popup>
+ <wd-toast />
+ </view>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed, onUnmounted } from "vue";
+import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
+import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
+import { useToast } from "wot-design-uni";
+import AttachmentUpload from "../upload.vue";
+import { useUserStore } from "@/store/modules/user";
+import { useScanCode } from "@/composables/useScanCode";
+
+// 鏍稿績鐘舵��
+const paramsId = ref("");
+const paramsType = ref("");
+const detailData = ref<any>({});
+const show = ref(false);
+const previewImageUrl = ref("");
+const isEdit = ref(false);
+const tempFiles = ref<any[]>([]);
+const toast = useToast();
+const attachmentRef = ref<any>(null);
+
+// 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+const userStore = useUserStore();
+const userInfo: any = computed(() => userStore.userInfo);
+
+// 浣跨敤鎵爜绠$悊 composable锛堝叏灞�鐩戝惉鍣紝涓嶉殢椤甸潰鍒囨崲鍏抽棴锛�
+const {
+ deviceUid,
+ deviceModel: scannedDeviceModel,
+ loadFromCache,
+ enableListener,
+} = useScanCode("scanLS");
+
+// 琛ㄥ崟鏁版嵁
+const formData = reactive({
+ dia: "",
+ maxDia: "",
+ minDia: "",
+ appearance: [] as string[],
+ windingTightness: "",
+ arrangementNeatness: "",
+ aluminumWireDistance: "",
+ jointCondition: "",
+ conclusion: "",
+ isFully: "",
+});
+
+// 澶栬閫夐」
+const appearanceOptions = [
+ { label: "鏃犲瑙傞棶棰�", value: "鏃犲瑙傞棶棰�" },
+ { label: "琛ㄩ潰鍒掍激", value: "琛ㄩ潰鍒掍激" },
+ { label: "鐩村緞涓嶅潎", value: "鐩村緞涓嶅潎" },
+ { label: "鍏朵粬缂洪櫡", value: "鍏朵粬缂洪櫡" },
+];
+const sampleCompleteOptions = [
+ { label: "鏄�", value: "鏄�" },
+ { label: "鍚�", value: "鍚�" },
+];
+const jointConditionOptions = [
+ { label: "鏈�", value: "鏈�" },
+ { label: "鏃�", value: "鏃�" },
+];
+const conclusionOptions = [
+ { label: "鍚堟牸", value: "鍚堟牸" },
+ { label: "涓嶅悎鏍�", value: "涓嶅悎鏍�" },
+];
+// 鐘舵�佹槧灏�
+const getStatusType = (status: number) => {
+ switch (status) {
+ case 0:
+ return "warning";
+ case 1:
+ return "danger";
+ case 2:
+ return "primary";
+ case 3:
+ return "success";
+ default:
+ return "default";
+ }
+};
+
+const getStatusText = (status: number) => {
+ switch (status) {
+ case 0:
+ return "寰呭贰妫�";
+ case 1:
+ return "宸查┏鍥�";
+ case 2:
+ return "寰呭鏍�";
+ case 3:
+ return "閫氳繃";
+ default:
+ return "鏈煡";
+ }
+};
+
+// 鏍煎紡鍖栧伐鍏�
+const formatProductAppearance = (productAppearance: string[]) => {
+ if (!productAppearance || !Array.isArray(productAppearance) || !productAppearance.length) {
+ return "-";
+ }
+ return productAppearance.join("銆�");
+};
+
+// 澶勭悊澶栬閫夋嫨鐨勪簰鏂ラ�昏緫
+const handleAppearanceClick = (value: string) => {
+ // 纭繚 appearance 鏄暟缁�
+ if (!Array.isArray(formData.appearance)) {
+ formData.appearance = [];
+ }
+
+ const currentValues = [...formData.appearance];
+ const isCurrentlyChecked = currentValues.includes(value);
+
+ let newSelection: string[] = [];
+
+ if (value === "鏃犲瑙傞棶棰�") {
+ if (isCurrentlyChecked) {
+ // 鍙栨秷閫変腑"鏃犲瑙傞棶棰�"
+ newSelection = [];
+ } else {
+ // 閫変腑"鏃犲瑙傞棶棰�"锛屾竻绌哄叾浠栭�夐」
+ newSelection = ["鏃犲瑙傞棶棰�"];
+ }
+ } else {
+ // 鐐瑰嚮鍏朵粬閫夐」
+ if (isCurrentlyChecked) {
+ // 鍙栨秷閫変腑璇ラ�夐」
+ newSelection = currentValues.filter((v) => v !== value);
+ } else {
+ // 閫変腑璇ラ�夐」锛岀Щ闄�"鏃犲瑙傞棶棰�"
+ const filteredValues = currentValues.filter((v) => v !== "鏃犲瑙傞棶棰�");
+ newSelection = [...filteredValues, value];
+ }
+ }
+
+ formData.appearance = newSelection;
+};
+
+const formatValue = (value: any, unit?: string) => {
+ if (value === null || value === undefined || value === "") return "-";
+ return unit ? `${value}${unit}` : value;
+};
+
+const formatDate = (date: string) => {
+ if (!date) return "-";
+ return new Date(date).toLocaleDateString("zh-CN", {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ });
+};
+
+// 鍒濆鍖栬〃鍗�
+const initFormData = () => {
+ const inspectionResult = detailData.value.inspectionResult || {};
+ const processInspectionResult = detailData.value.processInspectionResult || {};
+ formData.dia = inspectionResult.dia || "";
+ formData.maxDia = inspectionResult.maxDia || "";
+ formData.minDia = inspectionResult.minDia || "";
+ // 纭繚 appearance 鏄暟缁�
+ formData.appearance = Array.isArray(inspectionResult.appearance)
+ ? inspectionResult.appearance
+ : inspectionResult.appearance
+ ? [inspectionResult.appearance]
+ : [];
+ formData.windingTightness = inspectionResult.windingTightness || "";
+ formData.arrangementNeatness = inspectionResult.arrangementNeatness || "";
+ formData.aluminumWireDistance = inspectionResult.aluminumWireDistance || "";
+ formData.jointCondition = inspectionResult.jointCondition || "";
+ formData.conclusion = inspectionResult.conclusion || "";
+ formData.isFully = processInspectionResult.isFully ? "鏄�" : "鍚�";
+};
+
+// 鑾峰彇璇︽儏
+const getDetailData = async (id: string, deviceType: string) => {
+ try {
+ const response = await RoutingInspectionApi.getDrawInspectInfoById({ id });
+ detailData.value = response.data;
+
+ // 濡傛灉宸℃鍛樹负绌猴紝榛樿璁剧疆涓哄綋鍓嶇櫥褰曠敤鎴�
+ if (!detailData.value.processInspectionUserName) {
+ detailData.value.processInspectionUserName =
+ userInfo.value?.nickName || userInfo.value?.userName || "";
+ }
+
+ tempFiles.value = [];
+ initFormData();
+ } catch (error) {
+ console.error("鑾峰彇璇︽儏澶辫触:", error);
+ }
+};
+
+// 椤甸潰鍔犺浇
+onLoad((options: any) => {
+ paramsId.value = options.id;
+ paramsType.value = options.deviceType;
+ getDetailData(options.id, options.deviceType);
+});
+
+// 缂栬緫鍒囨崲
+const editList = () => {
+ isEdit.value = true;
+};
+
+// 鍙栨秷缂栬緫
+const close = () => {
+ isEdit.value = false;
+ tempFiles.value = [];
+ initFormData();
+};
+
+// 淇濆瓨缂栬緫
+const saveList = async () => {
+ // 鏍¢獙
+ if (!formData.maxDia) return uni.showToast({ title: "鏈�澶х洿寰勪负蹇呭~椤�", icon: "none" });
+ if (!formData.minDia) return uni.showToast({ title: "鏈�灏忕洿寰勪负蹇呭~椤�", icon: "none" });
+ if (!formData.appearance.length) return uni.showToast({ title: "澶栬涓哄繀濉」", icon: "none" });
+ if (!formData.windingTightness) return uni.showToast({ title: "鍗风粫绱у瘑涓哄繀濉」", icon: "none" });
+ if (!formData.arrangementNeatness)
+ return uni.showToast({ title: "鎺掑垪鏁撮綈涓哄繀濉」", icon: "none" });
+ if (!formData.aluminumWireDistance)
+ return uni.showToast({ title: "澶栧眰閾濈嚎绂讳晶鏉胯竟缂樿窛绂讳负蹇呭~椤�", icon: "none" });
+ if (!formData.jointCondition)
+ return uni.showToast({ title: "鎴愬搧妯″悗鎺ュご鎯呭喌涓哄繀濉」", icon: "none" });
+ if (!formData.conclusion) return uni.showToast({ title: "缁撹涓哄繀濉」", icon: "none" });
+ if (!formData.isFully) return uni.showToast({ title: "閾濇潌鏍峰搧鏄惁榻愬叏涓哄繀濉」", icon: "none" });
+
+ // 楠岃瘉鎵爜鏁版嵁锛堜粠缂撳瓨鎴栨柊鎵爜鑾峰彇锛�
+ console.log("淇濆瓨鍓嶆鏌� deviceUid:", deviceUid.value);
+ if (!deviceUid.value) {
+ return uni.showToast({
+ title: "璇峰厛鎵弿璁惧浜岀淮鐮�",
+ icon: "none",
+ duration: 2000,
+ });
+ }
+ const { newFiles } = attachmentRef.value.getSubmitFiles();
+ console.log("newFiles", newFiles);
+ const allFileIds = [...newFiles];
+ // 鎻愪氦
+ try {
+ const res = await RoutingInspectionApi.drawPatrolCheckInspection({
+ deviceUid: deviceUid.value,
+ id: paramsId.value,
+ inspectionResult: {
+ dia: formData.dia,
+ maxDia: formData.maxDia,
+ minDia: formData.minDia,
+ appearance: formData.appearance,
+ windingTightness: formData.windingTightness,
+ arrangementNeatness: formData.arrangementNeatness,
+ aluminumWireDistance: formData.aluminumWireDistance,
+ jointCondition: formData.jointCondition,
+ conclusion: formData.conclusion,
+ },
+ result: { isFully: formData.isFully },
+ processInspectionAttachmentList: allFileIds,
+ });
+ if (res.code === 200) {
+ // 璁剧疆鍒锋柊鏍囪锛屽憡璇夊垪琛ㄩ〉闇�瑕佸埛鏂�
+ uni.setStorageSync("needRefreshInspectionList", true);
+
+ uni.showToast({
+ title: "淇濆瓨鎴愬姛",
+ icon: "success",
+ duration: 1500,
+ });
+ // 寤惰繜杩斿洖鍒楄〃椤碉紝璁╃敤鎴风湅鍒版垚鍔熸彁绀�
+ setTimeout(() => {
+ uni.navigateBack({
+ delta: 1,
+ });
+ }, 1500);
+ } else {
+ uni.showModal({ title: res.msg || "淇濆瓨澶辫触", icon: "error" });
+ }
+ } catch (e) {
+ console.error("淇濆瓨澶辫触:", e);
+ uni.showModal({ title: e.message || "淇濆瓨澶辫触", icon: "error" });
+ }
+};
+
+const handleClose = () => {
+ show.value = false;
+};
+
+const openScan = () => {
+ console.log("indexLS - 鐐瑰嚮鎵爜鎸夐挳锛堝叏灞�鎵爜妯″紡锛屾棤闇�鎵嬪姩瑙﹀彂锛�");
+ // 鍏ㄥ眬鎵爜妯″紡涓嬶紝纭欢鎵爜浼氳嚜鍔ㄨЕ鍙戯紝鏃犻渶鎵嬪姩璋冪敤
+ uni.showToast({
+ title: "璇蜂娇鐢ㄦ壂鐮佹灙鎵弿",
+ icon: "none",
+ });
+};
+
+// 椤甸潰鏄剧ず鏃剁殑澶勭悊
+onShow(() => {
+ console.log("========== indexLS - onShow 瑙﹀彂 ==========");
+ // 閲嶆柊鍚敤鐩戝惉鍣紙纭繚鐩戝惉鍣ㄦ湁鏁堬級
+ enableListener();
+ // 鍔犺浇缂撳瓨锛堟洿鏂癠I鏄剧ず锛�
+ const cachedData = loadFromCache();
+
+ // 濡傛灉娌℃湁缂撳瓨鏁版嵁锛屾彁绀虹敤鎴烽渶瑕佹壂鐮�
+ if (!cachedData || !cachedData.uid) {
+ console.log("鈿狅笍 鏈娴嬪埌鎵爜缂撳瓨锛岀敤鎴烽渶瑕佹壂鎻忚澶囦簩缁寸爜");
+ // 鍦ㄧ紪杈戞ā寮忎笅鎵嶆彁绀�
+ if (isEdit.value) {
+ setTimeout(() => {
+ uni.showToast({
+ title: "璇锋壂鎻忚澶囦簩缁寸爜鍚庡啀淇濆瓨",
+ icon: "none",
+ duration: 2000,
+ });
+ }, 500);
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.fixed-header {
+ position: fixed;
+ top: 44;
+ left: 0;
+ right: 0;
+ background: #f3f9f8;
+ z-index: 999;
+ padding: 12px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ min-height: 60px;
+ box-sizing: border-box;
+ overflow: visible;
+}
+
+.header-container {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ gap: 10px;
+}
+
+.placeholder {
+ flex: 1;
+}
+
+.scan-info {
+ display: flex;
+ align-items: center;
+ margin-right: 10px;
+
+ .scan-device-text {
+ font-size: 14px;
+ color: #0d867f;
+ font-weight: 500;
+ }
+}
+
+.scan-wrapper {
+ width: 38px;
+ height: 38px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px;
+ flex-shrink: 0;
+}
+
+.list {
+ padding: 12px;
+ padding-top: 84px;
+ background: #f3f9f8;
+ min-height: 100vh;
+ box-sizing: border-box;
+ overflow-y: auto;
+}
+
+.title {
+ position: relative;
+ margin-left: 10px;
+ font-size: 16px;
+ font-weight: 500;
+ color: #0d867f;
+}
+
+.title::after {
+ position: absolute;
+ content: "";
+ top: 4px;
+ left: -10px;
+ width: 4px;
+ height: 16px;
+ background: #0d867f;
+ border-radius: 2px;
+}
+
+.attachment-section {
+ width: 100%;
+}
+
+.attachment-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ padding: 10px 0;
+}
+
+.attachment-item {
+ width: calc(25% - 10px);
+ box-sizing: border-box;
+ position: relative;
+}
+
+.upload-btn {
+ width: 80px;
+ height: 80px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px dashed #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+}
+
+.upload-icon {
+ font-size: 32px;
+ color: #0d867f;
+}
+
+.delete-icon {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ width: 24px;
+ height: 24px;
+ background-color: rgba(255, 0, 0, 0.8);
+ color: white;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
+}
+
+@media (max-width: 768px) {
+ .attachment-item {
+ width: calc(25% - 10px);
+ margin: 10;
+ }
+}
+
+:deep(.wd-form-item) {
+ margin-bottom: 8rpx;
+}
+
+:deep(.wd-input, .wd-select, .wd-radio-group, .wd-checkbox-group) {
+ width: 100%;
+ box-sizing: border-box;
+}
+
+:deep(.wd-form-item__label)::after {
+ content: "*";
+ color: red;
+ margin-left: 4rpx;
+}
+
+:deep(.wd-select) {
+ width: 100%;
+}
+
+:deep(.wd-checkbox) {
+ margin-right: 0;
+}
+.conclusion-radio-group {
+ display: flex;
+ align-items: flex-start; // 鍨傜洿鏂瑰悜椤堕儴瀵归綈锛堜笂绉诲叧閿級
+ gap: 20rpx; // 閫夐」涔嬮棿鐨勯棿璺�
+}
+</style>
diff --git a/src/pages/routingInspection/index.vue b/src/pages/routingInspection/index.vue
new file mode 100644
index 0000000..ddad4be
--- /dev/null
+++ b/src/pages/routingInspection/index.vue
@@ -0,0 +1,164 @@
+<template>
+ <view>
+ <wd-row>
+ <wd-col :span="21">
+ <wd-search
+ v-model="searchKeyword"
+ placeholder="璇疯緭鍏ョ彮缁勫悕绉�"
+ placeholder-left
+ hide-cancel
+ @search="handleSearch"
+ @clear="handleClear"
+ ></wd-search>
+ </wd-col>
+ <wd-col :span="3">
+ <view class="scan_box" @click="openScan">
+ <wd-icon name="scan" size="24px" color="#0D867F"></wd-icon>
+ </view>
+ </wd-col>
+ </wd-row>
+ <wd-tabs v-model="tab" auto-line-width slidable="always" :map-num="patrolList.length">
+ <wd-tab
+ v-for="(item, index) in patrolList"
+ :key="index"
+ :title="`${item.deviceModel}锛堝緟妫�鏌�${item.pendingNum}鏉★級`"
+ class="tab_bg"
+ >
+ <ProductList
+ :key="searchKey"
+ :api="RoutingInspectionApi.getInspectListByPatrol"
+ :ProList="{ ...item, teamName: searchKeyword }"
+ />
+ </wd-tab>
+ </wd-tabs>
+ <wd-toast />
+ </view>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, computed, onMounted, onUnmounted } from "vue";
+import { onShow, onHide } from "@dcloudio/uni-app";
+import ProductList from "./list/index.vue";
+import { useUserStore } from "@/store/modules/user";
+import reportApi from "@/api/work/report";
+import { useToast } from "wot-design-uni";
+import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
+import { useScanCode } from "@/composables/useScanCode";
+
+const userStore = useUserStore();
+const userInfo: any = computed(() => userStore.userInfo);
+const toast = useToast();
+const tab = ref<number>(0);
+const patrolList = ref<any[]>([]); // 宸℃璁惧鍒楄〃鏁版嵁
+const searchKeyword = ref<string>(""); // 鎼滅储鍏抽敭璇嶏紙鐝粍鍚嶇О锛�
+const searchKey = ref<number>(0); // 鐢ㄤ簬寮哄埗鍒锋柊鍒楄〃
+
+// 浣跨敤鎵爜绠$悊 composable锛堝叏灞�鐩戝惉鍣紝涓嶉殢椤甸潰鍒囨崲鍏抽棴锛�
+const { deviceUid, deviceModel, hasScanned, displayText, loadFromCache, enableListener } =
+ useScanCode("scanIndex");
+
+const handlePatrolData = (index: number, count: number) => {
+ // 鍙互鍦ㄨ繖閲屾洿鏂扮壒瀹氬贰妫�璁惧鐨勫緟妫�鏌ユ暟閲�
+ // 渚嬪锛歱atrolList.value[index].pendingNum = count;
+};
+
+// 澶勭悊鎼滅储
+const handleSearch = (value: string) => {
+ console.log("鎼滅储鐝粍:", value);
+ searchKey.value++; // 鏇存柊 key 寮哄埗鍒锋柊鍒楄〃
+};
+
+// 澶勭悊娓呯┖鎼滅储
+const handleClear = () => {
+ console.log("娓呯┖鎼滅储");
+ searchKeyword.value = "";
+ searchKey.value++; // 鏇存柊 key 寮哄埗鍒锋柊鍒楄〃
+};
+
+const openScan = () => {
+ console.log("index.vue - 鐐瑰嚮鎵爜鎸夐挳锛堝叏灞�鎵爜妯″紡锛屾棤闇�鎵嬪姩瑙﹀彂锛�");
+ // 鍏ㄥ眬鎵爜妯″紡涓嬶紝纭欢鎵爜浼氳嚜鍔ㄨЕ鍙戯紝鏃犻渶鎵嬪姩璋冪敤
+ uni.showToast({
+ title: "璇蜂娇鐢ㄦ壂鐮佹灙鎵弿",
+ icon: "none",
+ });
+};
+
+// 鑾峰彇宸℃璁惧鍒楄〃
+const loadPatrolList = async () => {
+ try {
+ const { data } = await RoutingInspectionApi.getDeviceInspectListByPatrol({});
+ if (data) {
+ patrolList.value = data;
+ }
+ } catch (error) {
+ toast.error("鑾峰彇宸℃璁惧鍒楄〃澶辫触");
+ }
+};
+
+onMounted(() => {
+ // 椤甸潰鍔犺浇鏃惰幏鍙栧贰妫�璁惧鍒楄〃
+ loadPatrolList();
+ // 鍚敤鍏ㄥ眬鐩戝惉鍣�
+ enableListener();
+ console.log("index.vue - onMounted");
+});
+
+onShow(() => {
+ console.log("========== index.vue - onShow 瑙﹀彂 ==========");
+ // 椤甸潰鏄剧ず鏃堕噸鏂板惎鐢ㄧ洃鍚櫒锛堢‘淇濈洃鍚櫒鏈夋晥锛�
+ enableListener();
+ // 鍔犺浇缂撳瓨锛堟洿鏂癠I鏄剧ず锛�
+ loadFromCache();
+
+ // 妫�鏌ユ槸鍚﹂渶瑕佸埛鏂板垪琛紙鍙湁鎻愪氦鎴愬姛鍚庢墠鍒锋柊锛�
+ const needRefresh = uni.getStorageSync("needRefreshInspectionList");
+ if (needRefresh) {
+ console.log("妫�娴嬪埌闇�瑕佸埛鏂板垪琛紝寮�濮嬪埛鏂�...");
+ // 閲嶆柊鍔犺浇宸℃璁惧鍒楄〃锛堝埛鏂板緟妫�鏌ユ暟閲忥級
+ loadPatrolList();
+ // 寮哄埗鍒锋柊 ProductList 缁勪欢
+ searchKey.value++;
+ // 娓呴櫎鍒锋柊鏍囪
+ uni.removeStorageSync("needRefreshInspectionList");
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+::v-deep .wd-search__block {
+ border-radius: unset;
+}
+.scan_box {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 38px;
+ height: 38px;
+ padding: 6px;
+ background: #fff;
+}
+::v-deep .wd-tabs__line {
+ background: #0d867f;
+}
+::v-deep .wd-tabs__nav {
+ border-bottom: 1px #dddddd solid;
+}
+.tab_bg {
+ background: #f3f9f8;
+}
+
+.icon_box {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 20px;
+ height: 20px;
+ background: #e7f4ec99;
+ border-radius: 50%;
+}
+
+.statistics_box {
+ margin: 15px;
+}
+</style>
diff --git a/src/pages/routingInspection/list/index.vue b/src/pages/routingInspection/list/index.vue
new file mode 100644
index 0000000..43d1041
--- /dev/null
+++ b/src/pages/routingInspection/list/index.vue
@@ -0,0 +1,130 @@
+<template>
+ <view class="card_box">
+ <z-paging
+ ref="pagingRef"
+ v-model="list"
+ :fixed="false"
+ :auto-show-back-to-top="true"
+ @query="getList"
+ >
+ <ProductCard
+ v-for="(item, index) in list"
+ :key="index"
+ :data="item"
+ :map="map"
+ @click="toDetail(item.id, item.deviceType)"
+ />
+ </z-paging>
+ <wd-toast />
+ </view>
+</template>
+
+<script setup lang="ts">
+import ProductCard from "../product_card/index.vue";
+import { useUserStore } from "@/store/modules/user";
+import zPaging from "@/components/z-paging/z-paging.vue";
+import { useToast } from "wot-design-uni";
+
+const toast = useToast();
+const userStore = useUserStore();
+const userInfo: any = computed(() => userStore.userInfo);
+const pagingRef = ref();
+const map = reactive({
+ deviceModel: "deviceModel",
+ model: "model",
+ firstNo: "firstNo",
+ recordDate: "recordDate",
+ workShift: "workShift",
+ teamName: "teamName",
+ poleModel: "poleModel",
+ poleNumber: "poleNumber",
+ outputNumber: "outputNumber",
+ inspectPerson: "inspectPerson",
+ status: "status",
+ productType: "productType",
+ recordPosition: "recordPosition",
+ rejectList: [
+ {
+ rejectPerson: "rejectPerson",
+ rejectTime: "rejectTime",
+ rejectReason: {
+ reason: "reason",
+ },
+ },
+ ], // 鏀逛负瀵硅薄锛屽寘鍚墍闇�鐨勫祵濂楀睘鎬�
+});
+const props = defineProps({
+ api: {
+ type: Function,
+ default: () => {},
+ },
+ ProList: {
+ type: Object,
+ default: () => {},
+ },
+});
+
+const list = ref<any[]>([]);
+
+const toDetail = (id: number, deviceType: number) => {
+ console.log("鐐瑰嚮鍗$墖", id, deviceType);
+ if (deviceType == 1) {
+ // 缁炵嚎
+ uni.navigateTo({
+ url: `/pages/routingInspection/detail/indexJX?id=${id}&deviceType=${deviceType}`,
+ });
+ } else if (deviceType == 0) {
+ // 鎷変笣
+ uni.navigateTo({
+ url: `/pages/routingInspection/detail/indexLS?id=${id}&deviceType=${deviceType}`,
+ });
+ }
+};
+
+const getList = async (pageNo = 1, pageSize = 10) => {
+ const { code, data } = await props.api({
+ deviceModel: props.ProList.deviceModel,
+ status: "0",
+ deviceType: props.ProList.deviceType,
+ teamName: props.ProList.teamName || "", // 鐝粍鍚嶇О鎼滅储
+ current: pageNo,
+ size: pageSize,
+ });
+ if (code == 200) {
+ map.deviceModel = "deviceModel";
+ map.model = "model";
+ map.firstNo = "firstNo";
+ map.recordDate = "recordDate";
+ map.workShift = "workShift";
+ map.teamName = "teamName";
+ map.poleModel = "poleModel";
+ map.poleNumber = "poleNumber";
+ map.outputNumber = "outputNumber";
+ map.inspectPerson = "inspectPerson";
+ map.productType = "productType";
+ map.recordPosition = "recordPosition";
+ map.rejectList = [
+ {
+ rejectPerson: "rejectPerson",
+ rejectTime: "rejectTime",
+ rejectReason: {
+ reason: "reason",
+ },
+ },
+ ];
+ map.status = "status";
+ if (data.total == 0) {
+ pagingRef.value.complete(true);
+ } else {
+ console.log("data.records", data.records);
+ pagingRef.value.complete(data.records);
+ }
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+.card_box {
+ height: calc(100vh - 120px);
+}
+</style>
diff --git a/src/pages/routingInspection/product_card/index.vue b/src/pages/routingInspection/product_card/index.vue
new file mode 100644
index 0000000..dd95bd5
--- /dev/null
+++ b/src/pages/routingInspection/product_card/index.vue
@@ -0,0 +1,202 @@
+<template>
+ <wd-card class="card_bg" @click="handleCardClick">
+ <template #title>
+ <view class="flex justify-between w-full">
+ <text class="font-medium text-[#252525]">璁板綍浣嶇疆: {{ data[map.recordPosition] }}</text>
+ <wd-tag color="#0D867F" bg-color="#E7F4EC">
+ <text class="text-xs">{{ data[map.model] }}</text>
+ </wd-tag>
+ </view>
+ </template>
+ <wd-row class="my-2">
+ <wd-col :span="24">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 鐝:
+ <text class="text-[#252525]">{{ data[map.workShift] }}</text>
+ </text>
+ </view>
+ </wd-col>
+ </wd-row>
+ <wd-row class="my-2">
+ <wd-col :span="24">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 鐝粍:
+ <text class="text-[#252525]">
+ {{ data[map.teamName]?.slice(-2) || data[map.teamName] }}
+ </text>
+ </text>
+ </view>
+ </wd-col>
+ </wd-row>
+ <wd-row class="my-2" v-if="data[map.productType]">
+ <wd-col :span="24">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 浜у搧绫诲埆:
+ <text class="text-[#252525]">{{ data[map.productType] }}</text>
+ </text>
+ </view>
+ </wd-col>
+ </wd-row>
+ <wd-row class="my-2">
+ <wd-col :span="12">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 鑷浜�:
+ <text class="text-[#252525]">{{ data[map.inspectPerson] }}</text>
+ </text>
+ </view>
+ </wd-col>
+ <wd-col :span="12">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 鐘舵��:
+ <text class="text-[#252525]">{{ data[map.status] == 1 ? "琚┏鍥�" : "宸℃" }}</text>
+ </text>
+ </view>
+ </wd-col>
+ </wd-row>
+ <wd-row class="my-2">
+ <wd-col :span="16">
+ <view class="flex">
+ <view class="icon_box">
+ <wd-icon name="folder" color="#0D867F"></wd-icon>
+ </view>
+ <text class="text-[#646874] mx-2">
+ 璁板綍鏃堕棿:
+ <text class="text-[#252525]">{{ data[map.recordDate] }}</text>
+ </text>
+ </view>
+ </wd-col>
+ <wd-col :span="8">
+ <view class="flex" @click.stop>
+ <wd-button
+ v-if="data[map.status] == 1"
+ size="small"
+ type="primary"
+ @click="showRejectPopup = true"
+ style="margin-left: auto"
+ >
+ 鏌ョ湅椹冲洖淇℃伅
+ </wd-button>
+ </view>
+ </wd-col>
+ </wd-row>
+ </wd-card>
+ <wd-popup
+ v-model="showRejectPopup"
+ title="椹冲洖淇℃伅"
+ custom-style="border-radius:32rpx;height: 800rpx;width: 600rpx;"
+ >
+ <wd-card
+ v-for="(item, index) in data.rejectList"
+ :key="index"
+ :class="index % 2 === 0 ? 'reject-card-bg-1' : 'reject-card-bg-2'"
+ style="margin-bottom: 8px; padding: 10px; border-radius: 8px"
+ >
+ <view class="content">
+ <view>
+ <view
+ style="
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: rgba(0, 0, 0, 0.85);
+ font-size: 14px;
+ margin-bottom: 8px;
+ "
+ >
+ <view>{{ item.rejectPerson }}</view>
+ <view>{{ item.rejectTime }}</view>
+ </view>
+ <view
+ style="
+ color: rgba(0, 0, 0, 0.85);
+ font-size: 14px;
+ word-break: break-word;
+ overflow-wrap: break-word;
+ max-width: 100%;
+ padding: 5px 0;
+ "
+ >
+ {{ item.rejectReason.reason }}
+ </view>
+ </view>
+ </view>
+ </wd-card>
+ </wd-popup>
+</template>
+
+<script setup lang="ts">
+import { ref } from "vue";
+const emit = defineEmits(["click"]);
+defineProps({
+ data: {
+ type: Object,
+ default: () => {},
+ },
+ map: {
+ type: Object,
+ default: () => {},
+ },
+});
+const showRejectPopup = ref<boolean>(false);
+const handleCardClick = () => {
+ emit("click");
+};
+</script>
+
+<style lang="scss" scoped>
+.card_bg {
+ box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.05);
+ padding-bottom: 10px;
+}
+
+// 娣诲姞锛氫袱绉嶄笉鍚岀殑鑳屾櫙鑹叉牱寮�
+.reject-card-bg-1 {
+ background-color: #f5f7fa;
+}
+
+.reject-card-bg-2 {
+ background-color: #eef2f7;
+}
+
+.page-class {
+ :deep() {
+ .custom-shadow {
+ box-shadow:
+ 0 3px 1px -2px rgb(0 0 0 / 20%),
+ 0 2px 2px 0 rgb(0 0 0 / 14%),
+ 0 1px 5px 0 rgb(0 0 0 / 12%);
+ }
+ }
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+// 淇敼锛氳皟鏁村唴瀹瑰尯鍩熺殑鏍峰紡
+.content {
+ padding: 5px;
+}
+</style>
diff --git a/src/pages/routingInspection/upload.vue b/src/pages/routingInspection/upload.vue
new file mode 100644
index 0000000..1a50117
--- /dev/null
+++ b/src/pages/routingInspection/upload.vue
@@ -0,0 +1,587 @@
+<template>
+ <view class="attachment-container">
+ <!-- 澶撮儴鎿嶄綔鍖� -->
+ <view class="header-actions">
+ <wd-button
+ icon="file-add"
+ :round="false"
+ size="small"
+ custom-class="add_btn"
+ @click="addAttachment"
+ v-if="isEdit"
+ >
+ 鏂板
+ </wd-button>
+ </view>
+
+ <!-- 闄勪欢鍒楄〃 -->
+ <view class="attachment-list">
+ <wd-status-tip
+ v-if="attachmentList.length === 0"
+ image="content"
+ tip="鏆傛棤闄勪欢"
+ custom-class="status-tip-full"
+ />
+
+ <view v-for="(item, index) in attachmentList" :key="item.id || index" class="attachment-card">
+ <view class="media-wrapper" @click="previewAttachment(item)">
+ <!-- 鍥剧墖棰勮 -->
+ <template v-if="isImageType(item.url)">
+ <image
+ :src="getFullUrl(item.url)"
+ mode="aspectFill"
+ class="media-preview"
+ style="width: 100%; height: 100%"
+ @error="onImageError(item, index)"
+ @load="onImageLoad(item, index)"
+ :show-menu-by-longpress="true"
+ />
+ <!-- 鍔犺浇涓伄缃� -->
+ <view v-if="item.loading" class="loading-mask">
+ <text class="loading-text">鍔犺浇涓�...</text>
+ </view>
+ <!-- 鍥剧墖鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-if="item.loadError" class="file-icon-wrapper error-overlay">
+ <wd-icon name="picture" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
+ </view>
+ </template>
+
+ <!-- 瑙嗛棰勮 -->
+ <template v-else-if="isVideoType(item.url)">
+ <video
+ :src="getFullUrl(item.url)"
+ class="media-preview"
+ :controls="false"
+ :show-center-play-btn="true"
+ @error="onVideoError(item, index)"
+ object-fit="cover"
+ />
+ <!-- 瑙嗛鍔犺浇澶辫触鏄剧ず榛樿鍥炬爣 -->
+ <view v-if="item.loadError" class="file-icon-wrapper error-overlay">
+ <wd-icon name="video" size="48px" color="#ccc" />
+ <text class="file-name error-text">鍔犺浇澶辫触</text>
+ </view>
+ </template>
+
+ <!-- 鍏朵粬鏂囦欢绫诲瀷鏄剧ず鍥炬爣 -->
+ <view v-else class="file-icon-wrapper">
+ <wd-icon name="file-outline" size="48px" color="#999" />
+ <text class="file-name">鏂囦欢</text>
+ </view>
+
+ <!-- 鍒犻櫎鎸夐挳 -->
+ <view class="delete-btn" @click.stop="deleteAttachment(item.id)" v-if="isEdit">
+ <wd-icon name="delete" color="#fff" size="20px" />
+ </view>
+ </view>
+ </view>
+ </view>
+
+ <wd-toast />
+ </view>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, watch } from "vue";
+import { useToast } from "wot-design-uni";
+import AttachmentAPI from "@/api/product/attachment";
+
+// H5 浣跨敤 VITE_APP_BASE_API 浣滀负浠g悊璺緞锛屽叾浠栧钩鍙颁娇鐢� VITE_APP_API_URL 浣滀负璇锋眰璺緞
+let baseUrlValue = import.meta.env.VITE_APP_API_URL || "";
+// #ifdef H5
+baseUrlValue = import.meta.env.VITE_APP_BASE_API || "";
+// #endif
+
+const baseUrl = ref(baseUrlValue); // 浣跨敤ref浣垮叾鍦ㄦā鏉夸腑鍙闂�
+
+// 澶栭儴鍙傛暟
+const props = defineProps({
+ detailData: { type: Object, default: () => ({}) },
+ isEdit: { type: Boolean, default: false },
+ deviceType: { type: String, default: "" },
+});
+
+const toast = useToast();
+
+// 鑾峰彇鍒濆鏁版嵁
+const getInitialData = () => {
+ // 澶勭悊涓嶅悓鐨勬暟鎹粨鏋�
+ let data = props.detailData;
+
+ // 濡傛灉鏄� ref 瀵硅薄锛岃幏鍙栧叾 value
+ if (data && typeof data === "object" && "value" in data) {
+ data = data.value;
+ }
+
+ // 濡傛灉鏄暟缁勶紝鐩存帴杩斿洖
+ if (Array.isArray(data)) {
+ return data.map((item) => ({
+ ...item,
+ loading: false,
+ loadError: false,
+ }));
+ }
+
+ // 濡傛灉鏈� files 灞炴��
+ if (data && data.files) {
+ const files = Array.isArray(data.files) ? data.files : [];
+ return files.map((item) => ({
+ ...item,
+ loading: false,
+ loadError: false,
+ }));
+ }
+
+ return [];
+};
+
+const attachmentList = ref<any[]>(getInitialData());
+const attachmentIds = ref<string[]>(attachmentList.value.map((item: any) => item.id) || []);
+
+// 鐩戝惉 props.detailData 鍙樺寲
+watch(
+ () => props.detailData,
+ (newVal) => {
+ const newData = getInitialData();
+ if (newData.length > 0) {
+ attachmentList.value = newData.map((item) => ({
+ ...item,
+ loading: false,
+ loadError: false,
+ }));
+ attachmentIds.value = newData.map((item: any) => item.id);
+ }
+ },
+ { deep: true, immediate: false }
+);
+
+// 鑾峰彇瀹屾暣鐨勫浘鐗�/瑙嗛 URL
+const getFullUrl = (url: string) => {
+ if (!url) return "";
+
+ // 濡傛灉宸茬粡鏄畬鏁寸殑 URL锛坔ttp 鎴� https 寮�澶达級锛岀洿鎺ヨ繑鍥�
+ if (url.startsWith("http://") || url.startsWith("https://")) {
+ return url;
+ }
+
+ // 妫�鏌� baseUrl 鏄惁鏈夋晥
+ if (!baseUrl.value) {
+ console.error("鉂� baseUrl鏈厤缃紝url:", url);
+ return url;
+ }
+
+ // 濡傛灉鏄浉瀵硅矾寰勶紝鎷兼帴鍩虹 URL
+ const separator = url.startsWith("/") || baseUrl.value.endsWith("/") ? "" : "/";
+ return `${baseUrl.value}${separator}${url}`;
+};
+
+// 鍥剧墖鍔犺浇鎴愬姛
+const onImageLoad = (item: any, index: number) => {
+ item.loading = false;
+ item.loadError = false;
+ attachmentList.value = [...attachmentList.value];
+};
+
+// 鍥剧墖鍔犺浇澶辫触
+const onImageError = (item: any, index: number) => {
+ console.error(`鍥剧墖鍔犺浇澶辫触 [${index}]:`, item.url);
+ item.loading = false;
+ item.loadError = true;
+ attachmentList.value = [...attachmentList.value];
+};
+
+// 瑙嗛鍔犺浇澶辫触
+const onVideoError = (item: any, index: number) => {
+ console.error(`瑙嗛鍔犺浇澶辫触 [${index}]:`, item.url);
+ item.loading = false;
+ item.loadError = true;
+ attachmentList.value = [...attachmentList.value];
+};
+
+// 鏂板闄勪欢
+const addAttachment = () => {
+ // 鏄剧ず閫夋嫨鏂囦欢绫诲瀷鐨勫脊绐�
+ uni.showActionSheet({
+ itemList: ["閫夋嫨鍥剧墖", /* "閫夋嫨瑙嗛", */ "鎷嶇収" /* , "褰曞儚" */],
+ success: (res) => {
+ switch (res.tapIndex) {
+ case 0: // 閫夋嫨鍥剧墖
+ chooseImages();
+ break;
+ // case 1: // 閫夋嫨瑙嗛
+ // chooseVideos();
+ // break;
+ case 1: // 鎷嶇収
+ takePhoto();
+ break;
+ // case 3: // 褰曞儚
+ // recordVideo();
+ // break;
+ }
+ },
+ fail: (error) => {
+ console.error("閫夋嫨鏂囦欢绫诲瀷澶辫触:", error);
+ toast.show("閫夋嫨鏂囦欢绫诲瀷澶辫触");
+ },
+ });
+};
+
+// 閫夋嫨鍥剧墖
+const chooseImages = () => {
+ uni.chooseImage({
+ count: 9,
+ sizeType: ["original", "compressed"],
+ sourceType: ["album"],
+ success: async (res) => {
+ const filePaths = Array.isArray(res.tempFilePaths) ? res.tempFilePaths : [res.tempFilePaths];
+ await handleFileUpload(filePaths);
+ },
+ fail: (error) => {
+ console.error("閫夋嫨鍥剧墖澶辫触:", error);
+ toast.show("閫夋嫨鍥剧墖澶辫触");
+ },
+ });
+};
+
+// 閫夋嫨瑙嗛
+const chooseVideos = () => {
+ uni.chooseVideo({
+ sourceType: ["album"],
+ maxDuration: 60,
+ camera: "back",
+ success: async (res) => {
+ await handleFileUpload([res.tempFilePath]);
+ },
+ fail: (error) => {
+ console.error("閫夋嫨瑙嗛澶辫触:", error);
+ toast.show("閫夋嫨瑙嗛澶辫触");
+ },
+ });
+};
+
+// 鎷嶇収
+const takePhoto = () => {
+ uni.chooseImage({
+ count: 1,
+ sizeType: ["original", "compressed"],
+ sourceType: ["camera"],
+ success: async (res) => {
+ const filePaths = Array.isArray(res.tempFilePaths) ? res.tempFilePaths : [res.tempFilePaths];
+ await handleFileUpload(filePaths);
+ },
+ fail: (error) => {
+ console.error("鎷嶇収澶辫触:", error);
+ toast.show("鎷嶇収澶辫触");
+ },
+ });
+};
+
+// 褰曞儚
+const recordVideo = () => {
+ uni.chooseVideo({
+ sourceType: ["camera"],
+ maxDuration: 60,
+ camera: "back",
+ success: async (res) => {
+ await handleFileUpload([res.tempFilePath]);
+ },
+ fail: (error) => {
+ console.error("褰曞儚澶辫触:", error);
+ toast.show("褰曞儚澶辫触");
+ },
+ });
+};
+
+// 澶勭悊鏂囦欢涓婁紶
+const handleFileUpload = async (filePaths: string[]) => {
+ try {
+ toast.show("姝e湪涓婁紶...");
+
+ // 涓婁紶鏂囦欢
+ const uploadResults: any = await AttachmentAPI.uploadAttachmentFiles(filePaths);
+ const result = uploadResults.map((it: any) => {
+ return it.data;
+ });
+
+ // 鏇存柊闄勪欢鍒楄〃
+ const flattenedResult = result.flat();
+ attachmentList.value.push(...flattenedResult);
+
+ // 鎻愬彇闄勪欢ID
+ attachmentIds.value = attachmentList.value.map((item: any) => item.id);
+ toast.show("涓婁紶鎴愬姛");
+ } catch (error) {
+ console.error("涓婁紶澶辫触:", error);
+ toast.show("涓婁紶澶辫触");
+ }
+};
+
+// 鍒犻櫎闄勪欢
+const deleteAttachment = async (aid: number) => {
+ try {
+ uni.showModal({
+ title: "纭鍒犻櫎",
+ content: "纭畾瑕佸垹闄よ繖涓檮浠跺悧锛�",
+ success: async (res) => {
+ if (res.confirm) {
+ // 鍓嶇鎵嬪姩鍒犻櫎锛氱洿鎺ヤ粠鍒楄〃涓Щ闄よ繖鏉℃暟鎹�
+ attachmentList.value = attachmentList.value.filter((item) => item.id !== aid);
+
+ // 鑾峰彇鍓╀綑鐨勯檮浠禝D
+ attachmentIds.value = attachmentList.value.map((item) => item.id);
+ toast.show("鍒犻櫎鎴愬姛");
+ }
+ },
+ });
+ } catch (error) {
+ console.error("鍒犻櫎澶辫触:", error);
+ toast.show("鍒犻櫎澶辫触");
+ }
+};
+
+// 棰勮闄勪欢
+const previewAttachment = (item: any) => {
+ // 鏍规嵁鏂囦欢绫诲瀷杩涜棰勮
+ const fileType = getFileType(item.url);
+ const fullUrl = getFullUrl(item.url);
+
+ if (fileType.startsWith("image")) {
+ // 鍥剧墖棰勮
+ uni.previewImage({
+ urls: [fullUrl],
+ current: fullUrl,
+ });
+ } else {
+ // 鍏朵粬鏂囦欢绫诲瀷锛屽彲浠ヤ笅杞芥垨鎵撳紑
+ uni.downloadFile({
+ url: fullUrl,
+ success: (res) => {
+ uni.openDocument({
+ filePath: res.tempFilePath,
+ success: () => {
+ // 鎵撳紑鏂囨。鎴愬姛
+ },
+ fail: (error) => {
+ console.error("鎵撳紑鏂囨。澶辫触:", error);
+ toast.show("鏃犳硶棰勮姝ゆ枃浠剁被鍨�");
+ },
+ });
+ },
+ fail: (error) => {
+ console.error("涓嬭浇鏂囦欢澶辫触:", error);
+ toast.show("涓嬭浇鏂囦欢澶辫触");
+ },
+ });
+ }
+};
+
+// 浠� URL 鎴栨枃浠跺悕涓彁鍙栨墿灞曞悕
+const getExtension = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "";
+ // 绉婚櫎鏌ヨ鍙傛暟鍜屽搱甯�
+ const cleanUrl = urlOrFileName.split("?")[0].split("#")[0];
+ // 鑾峰彇鏈�鍚庝竴涓偣鍚庨潰鐨勫唴瀹�
+ const extension = cleanUrl.split(".").pop()?.toLowerCase();
+ return extension || "";
+};
+
+// 鍒ゆ柇鏄惁涓哄浘鐗囩被鍨�
+const isImageType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(extension);
+};
+
+// 鍒ゆ柇鏄惁涓鸿棰戠被鍨�
+const isVideoType = (urlOrFileName: string) => {
+ const extension = getExtension(urlOrFileName);
+ return ["mp4", "mov", "avi", "wmv", "flv", "mkv", "webm"].includes(extension);
+};
+
+// 鑾峰彇鏂囦欢绫诲瀷
+const getFileType = (urlOrFileName: string) => {
+ if (!urlOrFileName) return "unknown";
+ const extension = getExtension(urlOrFileName);
+ switch (extension) {
+ case "jpg":
+ case "jpeg":
+ case "png":
+ case "gif":
+ case "bmp":
+ case "webp":
+ return "image";
+ case "mp4":
+ case "mov":
+ case "avi":
+ case "wmv":
+ case "flv":
+ case "mkv":
+ case "webm":
+ return "video";
+ case "pdf":
+ return "pdf";
+ case "doc":
+ case "docx":
+ return "word";
+ case "xls":
+ case "xlsx":
+ return "excel";
+ case "ppt":
+ case "pptx":
+ return "powerpoint";
+ case "txt":
+ return "text";
+ case "zip":
+ case "rar":
+ return "archive";
+ default:
+ return "file";
+ }
+};
+
+// 鏍煎紡鍖栨枃浠跺ぇ灏�
+const formatFileSize = (size: number) => {
+ 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 = (time: string) => {
+ const date = new Date(time);
+ return date.toLocaleString();
+};
+// 瀵瑰鏆撮湶鏂规硶锛氳幏鍙栨墍鏈夐渶鎻愪氦鐨勬枃浠�
+const getSubmitFiles = () => ({
+ newFiles: attachmentIds.value || [],
+});
+defineExpose({ getSubmitFiles });
+</script>
+
+<style lang="scss" scoped>
+.attachment-container {
+ padding: 12px;
+ background: #f3f9f8;
+ min-height: 100vh;
+}
+
+.header-actions {
+ margin-bottom: 12px;
+
+ :deep(.add_btn) {
+ background: #0d867f;
+ color: white;
+ border: none;
+ }
+}
+
+.attachment-list {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 8px;
+
+ :deep(.status-tip-full) {
+ grid-column: 1 / -1;
+ width: 100%;
+ }
+
+ .attachment-card {
+ width: 100%;
+ position: relative;
+
+ // 浣跨敤 padding-top 瀹炵幇姝f柟褰紙鍏煎鎬ф洿濂斤級
+ &::before {
+ content: "";
+ display: block;
+ padding-top: 100%; // 楂樺害绛変簬瀹藉害
+ }
+ }
+}
+
+.media-wrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f5f5f5;
+
+ .media-preview {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+
+ .loading-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.3);
+ z-index: 5;
+
+ .loading-text {
+ font-size: 12px;
+ color: #fff;
+ }
+ }
+
+ .file-icon-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ padding: 8px;
+ text-align: center;
+
+ .file-name {
+ margin-top: 8px;
+ font-size: 12px;
+ color: #666;
+ word-break: break-all;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+
+ &.error-text {
+ color: #ff4757;
+ }
+ }
+
+ &.error-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(255, 255, 255, 0.9);
+ z-index: 5;
+ }
+ }
+
+ .delete-btn {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
+ }
+}
+</style>
diff --git a/src/static/icons/routingInspection.png b/src/static/icons/routingInspection.png
new file mode 100644
index 0000000..e8bb5a4
--- /dev/null
+++ b/src/static/icons/routingInspection.png
Binary files differ
diff --git a/src/utils/cache.ts b/src/utils/cache.ts
index 93b1a42..ed9ab16 100644
--- a/src/utils/cache.ts
+++ b/src/utils/cache.ts
@@ -1,6 +1,7 @@
const TOKEN_KEY = "app-token";
const USER_INFO_KEY = "user-info";
const DICT_KEY = "dict";
+const TEAM_ID_KEY = "team-id";
import { type DictData } from "@/api/system/dict";
// 璁剧疆 token
@@ -48,9 +49,25 @@
uni.removeStorageSync(DICT_KEY);
}
+// 璁剧疆鐝粍ID
+export function setTeamId(teamId: string | number) {
+ uni.setStorageSync(TEAM_ID_KEY, teamId);
+}
+
+// 鑾峰彇鐝粍ID
+export function getTeamId(): string | number | null {
+ return uni.getStorageSync(TEAM_ID_KEY) || null;
+}
+
+// 娓呴櫎鐝粍ID
+export function clearTeamId() {
+ uni.removeStorageSync(TEAM_ID_KEY);
+}
+
// 娓呴櫎鎵�鏈夌紦瀛樹俊鎭�
export function clearAll() {
clearToken();
clearUserInfo();
clearDictCache();
+ clearTeamId();
}
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 8fa1c60..804150b 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -36,10 +36,12 @@
uni.showToast({
title: resData.msg || "涓氬姟澶勭悊澶辫触",
icon: "none",
+ duration: 2000,
});
reject({
message: resData.msg || "涓氬姟澶勭悊澶辫触",
code: resData.code,
+ duration: 2000,
});
}
},
@@ -53,6 +55,7 @@
reject({
message: "缃戠粶璇锋眰澶辫触",
error,
+ duration: 2000,
});
},
});
--
Gitblit v1.9.3