From add06adc5d974ac685cb637c48f2455034c8a52f Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 06 二月 2026 13:34:19 +0800
Subject: [PATCH] Merge branch 'dev_new' of http://114.132.189.42:9002/r/product-inventory-APP-before into dev_new
---
src/pages/procurementManagement/procurementLedger/index.vue | 72 +
src/pages.json | 42
src/pages/procurementManagement/procurementLedger/detail.vue | 47
src/pages/safeProduction/safeQualifications/detail.vue | 2
src/pages/safeProduction/accidentReportingRecord/view.vue | 4
src/pages/managementMeetings/meetingBoard/index.vue | 8
src/pages/sales/receiptPaymentLedger/detail.vue | 4
src/manifest.json | 162 +-
src/pages/safeProduction/safetyTrainingAssessment/index.vue | 448 ++++++++
src/pages/sales/receiptPaymentHistory/index.vue | 4
src/pages/index.vue | 10
src/pages/sales/receiptPayment/index.vue | 1
src/pages/safeProduction/safetyTrainingAssessment/view.vue | 171 +++
src/pages/sales/invoicingRegistration/index.vue | 4
src/pages/sales/salesAccount/index.vue | 85 +
src/pages/safeProduction/safetyTrainingAssessment/record.vue | 546 +++++++++
src/pages/sales/invoiceLedger/index.vue | 6
src/pages/safeProduction/emergencyPlanReview/detail.vue | 29
src/pages/safeProduction/safetyTrainingAssessment/resultDetail.vue | 388 +++++++
src/pages/procurementManagement/paymentLedger/detail.vue | 6
src/pages/safeProduction/safetyTrainingAssessment/fileList.vue | 567 ++++++++++
src/api/safeProduction/safetyTrainingAssessment.js | 120 ++
src/pages/safeProduction/accidentReportingRecord/detail.vue | 7
src/pages/sales/invoicingRegistration/view.vue | 5
src/pages/safeProduction/safeQualifications/index.vue | 5
src/pages/cooperativeOffice/clientVisit/detail.vue | 25
src/pages/safeProduction/safetyTrainingAssessment/detail.vue | 430 +++++++
src/pages/procurementManagement/procurementInvoiceLedger/detail.vue | 76
28 files changed, 3,115 insertions(+), 159 deletions(-)
diff --git a/src/api/safeProduction/safetyTrainingAssessment.js b/src/api/safeProduction/safetyTrainingAssessment.js
new file mode 100644
index 0000000..4e493f0
--- /dev/null
+++ b/src/api/safeProduction/safetyTrainingAssessment.js
@@ -0,0 +1,120 @@
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ
+export function safeTrainingListPage(query) {
+ return request({
+ url: "/safeTraining/page",
+ method: "get",
+ params: query,
+ });
+}
+
+
+// 鏂板瀹夊叏鍩硅鑰冩牳
+export function safeTrainingAdd(query) {
+ return request({
+ url: '/safeTraining',
+ method: 'post',
+ data: query
+ })
+}
+
+// 淇敼瀹夊叏鍩硅鑰冩牳
+export function safeTrainingUpdate(query) {
+ return request({
+ url: '/safeTraining',
+ method: 'put',
+ data: query
+ })
+}
+
+// 鍒犻櫎瀹夊叏鍩硅鑰冩牳
+export function safeTrainingDel(ids) {
+ return request({
+ url: '/safeTraining/' + ids,
+ method: 'delete',
+ data: ids
+ })
+}
+
+// 瀵煎嚭
+export function safeTrainingExport(query) {
+ return request({
+ url: '/safeTraining/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob'
+ })
+}
+
+// 鏌ヨ闄勪欢鍒楄〃
+export function safeTrainingFileListPage(query) {
+ return request({
+ url: "/safeTrainingFile/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 娣诲姞闄勪欢
+export function safeTrainingFileAdd(query) {
+ return request({
+ url: '/safeTrainingFile/add',
+ method: 'post',
+ data: query
+ })
+}
+
+// 鍒犻櫎闄勪欢
+export function safeTrainingFileDel(ids) {
+ return request({
+ url: '/safeTrainingFile/del',
+ method: 'delete',
+ data: ids
+ })
+}
+
+// 绛惧埌
+export function safeTrainingSign(query) {
+ return request({
+ url: '/safeTraining/sign',
+ method: 'post',
+ data: query
+ })
+}
+
+// 鏌ヨ璇︽儏
+export function safeTrainingGet(query) {
+ return request({
+ url: '/safeTraining/getSafeTraining',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鎻愪氦
+export function safeTrainingSave(query) {
+ return request({
+ url: '/safeTraining/saveSafeTraining',
+ method: 'post',
+ data: query
+ })
+}
+
+export function safeTrainingDetailListPage(query) {
+ return request({
+ url: "/safeTrainingDetails/page",
+ method: "get",
+ params: query,
+ });
+}
+
+// 瀵煎嚭
+export function safeTrainingDetailExport(query) {
+ return request({
+ url: '/safeTrainingDetails/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob'
+ })
+}
\ No newline at end of file
diff --git a/src/manifest.json b/src/manifest.json
index 076346e..f1b9741 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -1,35 +1,35 @@
{
- "name" : "淇℃伅绠$悊",
- "appid" : "__UNI__099A590",
- "description" : "",
- "versionName" : "1.0.0",
- "versionCode" : "100",
- "transformPx" : false,
+ "name": "淇℃伅绠$悊",
+ "appid": "__UNI__099A590",
+ "description": "",
+ "versionName": "1.0.0",
+ "versionCode": "100",
+ "transformPx": false,
/* 5+App鐗规湁鐩稿叧 */
- "app-plus" : {
- "compatible" : {
- "usingComponents" : true,
- "ignoreVersion" : true
+ "app-plus": {
+ "compatible": {
+ "usingComponents": true,
+ "ignoreVersion": true
},
- "usingComponents" : true,
- "nvueStyleCompiler" : "uni-app",
- "compilerVersion" : 3,
- "splashscreen" : {
- "alwaysShowBeforeRender" : true,
- "waiting" : true,
- "autoclose" : true,
- "delay" : 0
+ "usingComponents": true,
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "splashscreen": {
+ "alwaysShowBeforeRender": true,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
},
/* 妯″潡閰嶇疆 */
- "modules" : {
- "Camera" : {},
- "Barcode" : {}
+ "modules": {
+ "Camera": {},
+ "Barcode": {}
},
/* 搴旂敤鍙戝竷淇℃伅 */
- "distribute" : {
+ "distribute": {
/* android鎵撳寘閰嶇疆 */
- "android" : {
- "permissions" : [
+ "android": {
+ "permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
@@ -44,80 +44,90 @@
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
- "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+ "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
+ "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+ "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+ "<uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\"/>",
+ "<uses-feature android:name=\"android.hardware.location\"/>",
+ "<uses-feature android:name=\"android.hardware.location.gps\"/>",
+ "<uses-feature android:name=\"android.hardware.location.network\"/>"
]
},
/* ios鎵撳寘閰嶇疆 */
- "ios" : {
- "dSYMs" : false
+ "ios": {
+ "dSYMs": false,
+ "plist": {
+ "NSLocationWhenInUseUsageDescription": "闇�瑕佽幏鍙栨偍鐨勪綅缃俊鎭潵璁板綍瀹㈡埛鎷滆鍦扮偣",
+ "NSLocationAlwaysAndWhenInUseUsageDescription": "闇�瑕佽幏鍙栨偍鐨勪綅缃俊鎭潵璁板綍瀹㈡埛鎷滆鍦扮偣"
+ }
},
/* SDK閰嶇疆 */
- "sdkConfigs" : {
- "push" : {
- "unipush" : {
- "icons" : {
- "small" : {
- "ldpi" : "D:/xindao/wenjian/img/logo/app.png"
+ "sdkConfigs": {
+ "push": {
+ "unipush": {
+ "icons": {
+ "small": {
+ "ldpi": "D:/xindao/wenjian/img/logo/app.png"
}
}
}
}
},
- "icons" : {
- "android" : {
- "hdpi" : "unpackage/res/icons/72x72.png",
- "xhdpi" : "unpackage/res/icons/96x96.png",
- "xxhdpi" : "unpackage/res/icons/144x144.png",
- "xxxhdpi" : "unpackage/res/icons/192x192.png"
+ "icons": {
+ "android": {
+ "hdpi": "unpackage/res/icons/72x72.png",
+ "xhdpi": "unpackage/res/icons/96x96.png",
+ "xxhdpi": "unpackage/res/icons/144x144.png",
+ "xxxhdpi": "unpackage/res/icons/192x192.png"
},
- "ios" : {
- "appstore" : "unpackage/res/icons/1024x1024.png",
- "ipad" : {
- "app" : "unpackage/res/icons/76x76.png",
- "app@2x" : "unpackage/res/icons/152x152.png",
- "notification" : "unpackage/res/icons/20x20.png",
- "notification@2x" : "unpackage/res/icons/40x40.png",
- "proapp@2x" : "unpackage/res/icons/167x167.png",
- "settings" : "unpackage/res/icons/29x29.png",
- "settings@2x" : "unpackage/res/icons/58x58.png",
- "spotlight" : "unpackage/res/icons/40x40.png",
- "spotlight@2x" : "unpackage/res/icons/80x80.png"
+ "ios": {
+ "appstore": "unpackage/res/icons/1024x1024.png",
+ "ipad": {
+ "app": "unpackage/res/icons/76x76.png",
+ "app@2x": "unpackage/res/icons/152x152.png",
+ "notification": "unpackage/res/icons/20x20.png",
+ "notification@2x": "unpackage/res/icons/40x40.png",
+ "proapp@2x": "unpackage/res/icons/167x167.png",
+ "settings": "unpackage/res/icons/29x29.png",
+ "settings@2x": "unpackage/res/icons/58x58.png",
+ "spotlight": "unpackage/res/icons/40x40.png",
+ "spotlight@2x": "unpackage/res/icons/80x80.png"
},
- "iphone" : {
- "app@2x" : "unpackage/res/icons/120x120.png",
- "app@3x" : "unpackage/res/icons/180x180.png",
- "notification@2x" : "unpackage/res/icons/40x40.png",
- "notification@3x" : "unpackage/res/icons/60x60.png",
- "settings@2x" : "unpackage/res/icons/58x58.png",
- "settings@3x" : "unpackage/res/icons/87x87.png",
- "spotlight@2x" : "unpackage/res/icons/80x80.png",
- "spotlight@3x" : "unpackage/res/icons/120x120.png"
+ "iphone": {
+ "app@2x": "unpackage/res/icons/120x120.png",
+ "app@3x": "unpackage/res/icons/180x180.png",
+ "notification@2x": "unpackage/res/icons/40x40.png",
+ "notification@3x": "unpackage/res/icons/60x60.png",
+ "settings@2x": "unpackage/res/icons/58x58.png",
+ "settings@3x": "unpackage/res/icons/87x87.png",
+ "spotlight@2x": "unpackage/res/icons/80x80.png",
+ "spotlight@3x": "unpackage/res/icons/120x120.png"
}
}
}
}
},
/* 蹇簲鐢ㄧ壒鏈夌浉鍏� */
- "quickapp" : {},
+ "quickapp": {},
/* 灏忕▼搴忕壒鏈夌浉鍏� */
- "mp-weixin" : {
- "appid" : "",
- "setting" : {
- "urlCheck" : false
+ "mp-weixin": {
+ "appid": "",
+ "setting": {
+ "urlCheck": false
},
- "usingComponents" : true
+ "usingComponents": true
},
- "mp-alipay" : {
- "usingComponents" : true
+ "mp-alipay": {
+ "usingComponents": true
},
- "mp-baidu" : {
- "usingComponents" : true
+ "mp-baidu": {
+ "usingComponents": true
},
- "mp-toutiao" : {
- "usingComponents" : true
+ "mp-toutiao": {
+ "usingComponents": true
},
- "uniStatistics" : {
- "enable" : false
+ "uniStatistics": {
+ "enable": false
},
- "vueVersion" : "3"
-}
+ "vueVersion": "3"
+}
\ No newline at end of file
diff --git a/src/pages.json b/src/pages.json
index 2e1cabe..805d0f1 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -814,6 +814,48 @@
"navigationBarTitleText": "搴旀�ラ妗堣鎯�",
"navigationStyle": "custom"
}
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/index",
+ "style": {
+ "navigationBarTitleText": "瀹夊叏鍩硅鑰冩牳",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/detail",
+ "style": {
+ "navigationBarTitleText": "鍩硅璇︽儏",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/view",
+ "style": {
+ "navigationBarTitleText": "鍩硅璇︽儏",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/fileList",
+ "style": {
+ "navigationBarTitleText": "鍩硅闄勪欢",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/resultDetail",
+ "style": {
+ "navigationBarTitleText": "缁撴灉鏄庣粏",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/safeProduction/safetyTrainingAssessment/record",
+ "style": {
+ "navigationBarTitleText": "鍩硅璁板綍",
+ "navigationStyle": "custom"
+ }
}
],
"subPackages": [
diff --git a/src/pages/cooperativeOffice/clientVisit/detail.vue b/src/pages/cooperativeOffice/clientVisit/detail.vue
index 9c3ce0d..3c54b8e 100644
--- a/src/pages/cooperativeOffice/clientVisit/detail.vue
+++ b/src/pages/cooperativeOffice/clientVisit/detail.vue
@@ -212,9 +212,32 @@
},
fail: err => {
uni.hideLoading();
- showToast("鑾峰彇浣嶇疆澶辫触锛岃妫�鏌ュ畾浣嶆潈闄�");
console.error("鑾峰彇浣嶇疆澶辫触:", err);
+ // 鏄剧ず閿欒鎻愮ず骞跺紩瀵肩敤鎴锋鏌ユ潈闄�
+ showToast("鑾峰彇浣嶇疆澶辫触锛岃妫�鏌ュ畾浣嶆潈闄�");
+
+ // 寮曞鐢ㄦ埛妫�鏌ユ潈闄愯缃�
+ uni.showModal({
+ title: "浣嶇疆鏉冮檺鎻愮ず",
+ content:
+ "鑾峰彇浣嶇疆澶辫触锛屽彲鑳芥槸鍥犱负浣嶇疆鏉冮檺鏈紑鍚紝璇峰湪璁惧璁剧疆涓鏌ュ苟寮�鍚綅缃潈闄愩��",
+ confirmText: "鐭ラ亾浜�",
+ cancelText: "鍙栨秷",
+ success: res => {
+ if (res.confirm) {
+ // 鍙互灏濊瘯鎵撳紑璁剧疆椤甸潰锛堝鏋滄敮鎸侊級
+ if (uni.openSetting) {
+ uni.openSetting({
+ success: settingRes => {
+ console.log("璁剧疆缁撴灉:", settingRes);
+ },
+ });
+ }
+ }
+ },
+ });
+
// 澶辫触鏃舵樉绀洪敊璇俊鎭�
form.value.visitAddress = "浣嶇疆鑾峰彇澶辫触";
},
diff --git a/src/pages/index.vue b/src/pages/index.vue
index aa08cb3..7f0408c 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -331,6 +331,10 @@
icon: "/static/images/icon/guzhangfenxi@2x.png",
label: "浜嬫晠涓婃姤",
},
+ {
+ icon: "/static/images/icon/guzhangfenxi@2x.png",
+ label: "瀹夊叏鍩硅",
+ },
]);
// 鍗忓悓鍔炲叕鍔熻兘鏁版嵁
const collaborationItems = reactive([
@@ -724,6 +728,12 @@
url: "/pages/safeProduction/accidentReportingRecord/index",
});
break;
+ case "瀹夊叏鍩硅":
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/index",
+ });
+ break;
+
default:
uni.showToast({
title: `鐐瑰嚮浜�${item.label}`,
diff --git a/src/pages/managementMeetings/meetingBoard/index.vue b/src/pages/managementMeetings/meetingBoard/index.vue
index 5b930b4..913ab9a 100644
--- a/src/pages/managementMeetings/meetingBoard/index.vue
+++ b/src/pages/managementMeetings/meetingBoard/index.vue
@@ -8,7 +8,7 @@
<view class="topbox">
<view class="boxItem">
<view class="boxItem-num">
- {{stats.total}}
+ {{stats.total ? stats.total : 0}}
</view>
<view class="boxItem-title">
鎬讳細璁暟
@@ -16,7 +16,7 @@
</view>
<view class="boxItem">
<view class="boxItem-num">
- {{stats.underWay}}
+ {{stats.underWay ? stats.underWay : 0}}
</view>
<view class="boxItem-title">
杩涜涓�
@@ -24,7 +24,7 @@
</view>
<view class="boxItem">
<view class="boxItem-num">
- {{stats.completed}}
+ {{stats.completed ? stats.completed : 0}}
</view>
<view class="boxItem-title">
宸插畬鎴�
@@ -32,7 +32,7 @@
</view>
<view class="boxItem">
<view class="boxItem-num">
- {{stats.toStart}}
+ {{stats.toStart ? stats.toStart : 0}}
</view>
<view class="boxItem-title">
鍗冲皢寮�濮�
diff --git a/src/pages/procurementManagement/paymentLedger/detail.vue b/src/pages/procurementManagement/paymentLedger/detail.vue
index 33b2856..26f5cf5 100644
--- a/src/pages/procurementManagement/paymentLedger/detail.vue
+++ b/src/pages/procurementManagement/paymentLedger/detail.vue
@@ -54,6 +54,10 @@
<text class="detail-label">搴斾粯閲戦(鍏�)</text>
<text class="detail-value danger">{{ formatAmount(item.payableAmount) }}</text>
</view>
+ <view class="detail-row">
+ <text class="detail-label">鍙戠敓鏃ユ湡</text>
+ <text class="detail-value">{{ item.paymentDate }}</text>
+ </view>
</view>
</view>
</view>
@@ -121,7 +125,7 @@
return;
}
showLoadingToast("鍔犺浇涓�...");
- paymentRecordList({supplierId: supplierId.value})
+ paymentRecordList({ supplierId: supplierId.value })
.then(res => {
tableData.value = res.data;
closeToast();
diff --git a/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue b/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue
index 179e7e1..3b0bea3 100644
--- a/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue
+++ b/src/pages/procurementManagement/procurementInvoiceLedger/detail.vue
@@ -102,7 +102,7 @@
const temFutureTickets = ref(0);
const originalTicketsNum = ref(0); // 淇濆瓨鍘熷鏉ョエ鏁�
- // 琛ㄥ崟鏍¢獙瑙勫垯
+ // 琛ㄥ崟鏍¢獙瑙勫垯 - 浣跨敤绠�鍗曠殑 required 瑙勫垯
const rules = {
ticketsNum: [{ required: true, message: "璇疯緭鍏ユ潵绁ㄦ暟", trigger: "blur" }],
ticketsAmount: [
@@ -265,44 +265,50 @@
// 琛ㄥ崟鎻愪氦
const onSubmit = async () => {
- if (!formRef.value) {
- console.log("琛ㄥ崟寮曠敤涓嶅瓨鍦�");
+ // 鍦ㄩ獙璇佸墠锛岀‘淇濆繀濉瓧娈垫湁鍊�
+ if (!form.value.ticketsNum || form.value.ticketsNum === "" || form.value.ticketsNum === null || form.value.ticketsNum === undefined) {
+ uni.showToast({
+ title: "璇疯緭鍏ユ潵绁ㄦ暟",
+ icon: "none",
+ });
return;
}
- try {
- // 鍏堣皟鐢� validate 鏂规硶
- const validateResult = formRef.value.validate();
-
- // 濡傛灉 validate 杩斿洖 undefined 鎴� null锛岀洿鎺ユ彁浜�
- if (validateResult === undefined || validateResult === null) {
- submitForm();
- return;
- }
-
- // 濡傛灉杩斿洖 Promise锛屼娇鐢� await 鍜� catch
- if (validateResult && typeof validateResult.then === 'function') {
- const valid = await validateResult.catch(() => false);
- if (valid) {
- // 琛ㄥ崟楠岃瘉閫氳繃锛屾彁浜よ〃鍗�
- submitForm();
- } else {
- // 琛ㄥ崟楠岃瘉澶辫触
- console.log("琛ㄥ崟楠岃瘉澶辫触");
- }
- } else {
- // 濡傛灉杩斿洖甯冨皵鍊硷紝鐩存帴鍒ゆ柇
- if (validateResult) {
- submitForm();
- } else {
- console.log("琛ㄥ崟楠岃瘉澶辫触");
- }
- }
- } catch (error) {
- // 濡傛灉 validate 鏂规硶涓嶅瓨鍦ㄦ垨鎶涘嚭閿欒锛岀洿鎺ユ彁浜�
- console.log("琛ㄥ崟楠岃瘉澶辫触", error);
- submitForm();
+ if (!form.value.ticketsAmount || form.value.ticketsAmount === "" || form.value.ticketsAmount === null || form.value.ticketsAmount === undefined) {
+ uni.showToast({
+ title: "璇疯緭鍏ユ湰娆℃潵绁ㄩ噾棰�",
+ icon: "none",
+ });
+ return;
}
+
+ // 纭繚瀛楁鏄暟瀛楃被鍨嬶紝骞惰浆鎹负瀛楃涓诧紙鍥犱负琛ㄥ崟鍙兘闇�瑕佸瓧绗︿覆绫诲瀷锛�
+ const ticketsNum = Number(form.value.ticketsNum);
+ const ticketsAmount = Number(form.value.ticketsAmount);
+
+ // 濡傛灉鏉ョエ鏁颁负0鎴栨潵绁ㄩ噾棰濅负0锛屾彁绀虹敤鎴�
+ if (isNaN(ticketsNum) || ticketsNum <= 0) {
+ uni.showToast({
+ title: "鏉ョエ鏁板繀椤诲ぇ浜�0",
+ icon: "none",
+ });
+ return;
+ }
+
+ if (isNaN(ticketsAmount) || ticketsAmount <= 0) {
+ uni.showToast({
+ title: "鏈鏉ョエ閲戦蹇呴』澶т簬0",
+ icon: "none",
+ });
+ return;
+ }
+
+ // 鏇存柊琛ㄥ崟鍊硷紝纭繚鏄湁鏁堢殑鏁板瓧瀛楃涓�
+ form.value.ticketsNum = ticketsNum.toString();
+ form.value.ticketsAmount = ticketsAmount.toString();
+
+ // 鎵嬪姩楠岃瘉閫氳繃鍚庯紝鐩存帴鎻愪氦锛岃烦杩囪〃鍗曢獙璇侊紙閬垮厤鐪熸満涓婄殑楠岃瘉闂锛�
+ submitForm();
};
const purchaseLedgerId = ref("");
const productModelId = ref({});
diff --git a/src/pages/procurementManagement/procurementLedger/detail.vue b/src/pages/procurementManagement/procurementLedger/detail.vue
index 41df1af..004713b 100644
--- a/src/pages/procurementManagement/procurementLedger/detail.vue
+++ b/src/pages/procurementManagement/procurementLedger/detail.vue
@@ -17,27 +17,30 @@
</up-form-item>
<up-form-item label="閿�鍞悎鍚屽彿"
prop="salesContractNo"
- required
- @click="showPicker = true">
+ required>
<up-input v-model="form.salesContractNo"
- readonly=""
- @click="showPicker = true"
+ readonly
+ :disabled="isReadOnly"
+ @click="!isReadOnly && (showPicker = true)"
placeholder="鐐瑰嚮閫夋嫨閿�鍞悎鍚屽彿" />
<template #right>
<up-icon name="arrow-right"
+ v-if="!isReadOnly"
@click="showPicker = true"></up-icon>
</template>
</up-form-item>
<up-form-item label="渚涘簲鍟嗗悕绉�"
prop="supplierName"
required
- @click="showCustomerPicker = true">
+ >
<up-input v-model="form.supplierName"
- readonly=""
- @click="showCustomerPicker = true"
+ readonly
+ :disabled="isReadOnly"
+ @click="!isReadOnly && (showCustomerPicker = true)"
placeholder="鐐瑰嚮閫夋嫨渚涘簲鍟�" />
<template #right>
<up-icon name="arrow-right"
+ v-if="!isReadOnly"
@click="showCustomerPicker = true"></up-icon>
</template>
</up-form-item>
@@ -45,11 +48,13 @@
prop="projectName"
required>
<up-input v-model="form.projectName"
+ :disabled="isReadOnly"
placeholder="璇疯緭鍏ラ」鐩悕绉�" />
</up-form-item>
<up-form-item label="浠樻鏂瑰紡"
prop="paymentMethod">
<up-input v-model="form.paymentMethod"
+ :disabled="isReadOnly"
placeholder="璇疯緭鍏ヤ粯娆炬柟寮�" />
</up-form-item>
<up-form-item label="绛捐鏃ユ湡"
@@ -57,9 +62,11 @@
prop="executionDate">
<up-input v-model="form.executionDate"
placeholder="璇烽�夋嫨"
- readonly="" />
+ readonly
+ :disabled="isReadOnly" />
<template #right>
<up-icon name="arrow-right"
+ v-if="!isReadOnly"
@click="showTimePicker = true"></up-icon>
</template>
</up-form-item>
@@ -99,10 +106,12 @@
<text class="approver-name">{{ step.nickName }}</text>
</view>
<view class="delete-approver-btn"
+ v-if="!isReadOnly"
@click="removeApprover(stepIndex)">脳</view>
</view>
<view v-else
class="add-approver-btn"
+ v-if="!isReadOnly"
@click="addApprover(stepIndex)">
<view class="add-circle">+</view>
<text class="add-label">閫夋嫨瀹℃壒浜�</text>
@@ -111,11 +120,11 @@
<view class="step-line"
v-if="stepIndex < approverNodes.length - 1"></view>
<view class="delete-step-btn"
- v-if="approverNodes.length > 1"
+ v-if="approverNodes.length > 1 && !isReadOnly"
@click="removeApprovalStep(stepIndex)">鍒犻櫎鑺傜偣</view>
</view>
</view>
- <view class="add-step-btn">
+ <view class="add-step-btn" v-if="!isReadOnly">
<u-button icon="plus"
plain
type="primary"
@@ -400,13 +409,17 @@
const operationType = ref("");
const editData = ref(null);
const formRef = ref(null);
- // 瀹℃壒閫氳繃锛坅pprovalStatus === 3锛夊悗锛岀姝㈢紪杈�/鍒犻櫎浜у搧
+ // 瀹℃壒閫氳繃锛坅pprovalStatus === 3锛夊悗锛屾暣鍗曠姝㈢紪杈戯紙鍚骇鍝併�佸熀鏈俊鎭�佸鎵规祦绋嬶級
const isApprovalPassed = computed(() => {
const status = editData.value?.approvalStatus ?? form.value?.approvalStatus;
return Number(status) === 3;
});
const canEditProducts = computed(() => {
return operationType.value !== "view" && !isApprovalPassed.value;
+ });
+ // 鏄惁鏁翠綋鍙锛氭煡鐪嬫ā寮� 鎴� 宸插鎵归�氳繃
+ const isReadOnly = computed(() => {
+ return operationType.value === "view" || isApprovalPassed.value;
});
const userStore = useUserStore();
@@ -891,6 +904,14 @@
};
const onSubmit = () => {
+ // 瀹℃壒閫氳繃鐨勫彴璐︾姝㈠啀娆′慨鏀�
+ if (isApprovalPassed.value) {
+ uni.showToast({
+ title: "宸插鎵归�氳繃鐨勫彴璐︿笉鍏佽淇敼",
+ icon: "none",
+ });
+ return;
+ }
const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
if (hasEmptyApprover) {
uni.showToast({
@@ -1096,6 +1117,7 @@
};
const addApprover = stepIndex => {
+ if (isReadOnly.value) return;
// 璺宠浆鍒拌仈绯讳汉閫夋嫨椤甸潰
uni.setStorageSync("stepIndex", stepIndex);
uni.navigateTo({
@@ -1104,18 +1126,21 @@
};
const addApprovalStep = () => {
+ if (isReadOnly.value) return;
// 娣诲姞鏂扮殑瀹℃壒姝ラ
approverNodes.value.push({ userId: null, nickName: null });
console.log(approverNodes.value, "approverNodes.value");
};
const removeApprover = stepIndex => {
+ if (isReadOnly.value) return;
// 绉婚櫎瀹℃壒浜�
approverNodes.value[stepIndex].userId = null;
approverNodes.value[stepIndex].nickName = null;
};
const removeApprovalStep = stepIndex => {
+ if (isReadOnly.value) return;
// 纭繚鑷冲皯淇濈暀涓�涓鎵规楠�
if (approverNodes.value.length > 1) {
approverNodes.value.splice(stepIndex, 1);
diff --git a/src/pages/procurementManagement/procurementLedger/index.vue b/src/pages/procurementManagement/procurementLedger/index.vue
index ebcf07a..5d44a09 100644
--- a/src/pages/procurementManagement/procurementLedger/index.vue
+++ b/src/pages/procurementManagement/procurementLedger/index.vue
@@ -76,6 +76,21 @@
<text class="detail-value">{{ item.entryDate }}</text>
</view>
</view>
+ <!-- 浠呴潪鈥滃鎵归�氳繃鈥濈殑鍙拌处灞曠ず鍒犻櫎鎸夐挳 -->
+ <view
+ class="detail-row"
+ v-if="item.approvalStatus !== 3"
+ style="justify-content: flex-end; margin-top: 8px;"
+ >
+ <up-button
+ type="error"
+ size="small"
+ plain
+ @click.stop="handleDelete(item)"
+ >
+ 鍒犻櫎
+ </up-button>
+ </view>
</view>
</view>
</view>
@@ -99,7 +114,7 @@
import { onShow } from "@dcloudio/uni-app";
import useUserStore from "@/store/modules/user";
import PageHeader from "@/components/PageHeader.vue";
- import { purchaseListPage } from "@/api/procurementManagement/procurementLedger";
+ import { purchaseListPage, delPurchase } from "@/api/procurementManagement/procurementLedger";
const userStore = useUserStore();
const approvalStatusText = {
1: "寰呭鏍�",
@@ -208,6 +223,61 @@
}
};
+ // 鍒犻櫎鍗曟潯閲囪喘鍙拌处
+ const handleDelete = row => {
+ if (!row || !row.id) {
+ uni.showToast({
+ title: "鏁版嵁鏈夎锛屾棤娉曞垹闄�",
+ icon: "none",
+ });
+ return;
+ }
+
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�",
+ confirmText: "纭",
+ cancelText: "鍙栨秷",
+ success: res => {
+ if (res.confirm) {
+ delPurchase([row.id])
+ .then(result => {
+ // 鎴愬姛锛歝ode === 200
+ if (result && result.code === 200) {
+ uni.showToast({
+ title: "鍒犻櫎鎴愬姛",
+ icon: "success",
+ });
+ getList();
+ return;
+ }
+ // 涓氬姟澶辫触锛氫紭鍏堝睍绀哄悗绔繑鍥炵殑 msg锛堝 CG2026... 涓嶅厑璁稿垹闄わ級
+ uni.showToast({
+ title: (result && result.msg) || "鍒犻櫎澶辫触",
+ icon: "none",
+ });
+ })
+ .catch(error => {
+ // 瀵逛簬 request 灏佽杩斿洖鐨� '500' 鎴栧叾浠� code锛岄敊璇彁绀哄凡缁忓湪 request 閲� toast 杩囦簡锛岃繖閲屼笉鍐嶉噸澶嶈鐩�
+ if (error === "500" || typeof error === "number") {
+ return;
+ }
+ // 鍙湁鍦ㄧ湡姝e紓甯告椂锛屾墠鍦ㄨ繖閲屽厹搴曟彁绀�
+ const msg =
+ (error && error.msg) ||
+ (error && error.response && error.response.data && error.response.data.msg) ||
+ (error && error.message) ||
+ "鍒犻櫎澶辫触";
+ uni.showToast({
+ title: msg,
+ icon: "none",
+ });
+ });
+ }
+ },
+ });
+ };
+
onShow(() => {
// 椤甸潰鏄剧ず鏃跺埛鏂板垪琛�
getList();
diff --git a/src/pages/safeProduction/accidentReportingRecord/detail.vue b/src/pages/safeProduction/accidentReportingRecord/detail.vue
index af7e89b..ec9662e 100644
--- a/src/pages/safeProduction/accidentReportingRecord/detail.vue
+++ b/src/pages/safeProduction/accidentReportingRecord/detail.vue
@@ -79,6 +79,12 @@
<view class="unit">鍏�</view>
</template>
</u-form-item>
+ <u-form-item label="浜哄憳鎹熷け鎯呭喌"
+ prop="personLoss"
+ border-bottom>
+ <u-input v-model="form.personLoss"
+ placeholder="璇疯緭鍏ヤ汉鍛樻崯澶辨儏鍐�" />
+ </u-form-item>
<u-form-item label="浜嬫晠鐩存帴鍘熷洜"
prop="accidentCause"
border-bottom>
@@ -185,6 +191,7 @@
accidentGrade: "",
happenTime: "",
happenLocation: "",
+ personLoss: "",
createUserName: "",
createTime: "",
assetLoss: "",
diff --git a/src/pages/safeProduction/accidentReportingRecord/view.vue b/src/pages/safeProduction/accidentReportingRecord/view.vue
index c696dc3..ec15918 100644
--- a/src/pages/safeProduction/accidentReportingRecord/view.vue
+++ b/src/pages/safeProduction/accidentReportingRecord/view.vue
@@ -54,6 +54,10 @@
<view class="info-value">{{ accidentInfo.assetLoss || '-' }}<span v-if="accidentInfo.assetLoss">鍏�</span></view>
</view>
<view class="info-row">
+ <view class="info-label">浜哄憳鎹熷け鎯呭喌锛�</view>
+ <view class="info-value">{{ accidentInfo.personLoss || '-' }}</view>
+ </view>
+ <view class="info-row">
<view class="info-label">涓婃姤鏃堕棿锛�</view>
<view class="info-value">{{ accidentInfo.createTime || '-' }}</view>
</view>
diff --git a/src/pages/safeProduction/emergencyPlanReview/detail.vue b/src/pages/safeProduction/emergencyPlanReview/detail.vue
index 6117254..c36316b 100644
--- a/src/pages/safeProduction/emergencyPlanReview/detail.vue
+++ b/src/pages/safeProduction/emergencyPlanReview/detail.vue
@@ -436,10 +436,33 @@
// 鎻愪氦琛ㄥ崟
const submitForm = async () => {
// 楠岃瘉琛ㄥ崟蹇呭~椤�
- if (!formRef.value) return;
+ if (!form.value.planCode) {
+ showToast("璇疯緭鍏ュ簲鎬ラ妗堢紪鐮�");
+ return;
+ }
- const valid = await formRef.value.validate();
- if (!valid) {
+ if (!form.value.planName) {
+ showToast("璇疯緭鍏ュ簲鎬ラ妗堝悕绉�");
+ return;
+ }
+
+ if (!form.value.publishTime) {
+ showToast("璇烽�夋嫨鍙戝竷鐢熸晥鏃堕棿");
+ return;
+ }
+
+ if (!form.value.planType) {
+ showToast("璇烽�夋嫨棰勬绫诲瀷");
+ return;
+ }
+
+ if (!form.value.coreResponsorUserId) {
+ showToast("璇烽�夋嫨鏍稿績璐d换浜�");
+ return;
+ }
+
+ if (!form.value.applyScope || form.value.applyScope.length === 0) {
+ showToast("璇烽�夋嫨閫傜敤鑼冨洿");
return;
}
diff --git a/src/pages/safeProduction/safeQualifications/detail.vue b/src/pages/safeProduction/safeQualifications/detail.vue
index 0d0648b..e821920 100644
--- a/src/pages/safeProduction/safeQualifications/detail.vue
+++ b/src/pages/safeProduction/safeQualifications/detail.vue
@@ -235,7 +235,7 @@
onLoad(() => {
// 缂栬緫瑙勭▼璧勮川鏃讹紝浠庢湰鍦板瓨鍌ㄨ幏鍙栨暟鎹�
const qualification = uni.getStorageSync("safeQualifications");
- if (qualification) {
+ if (qualification.id) {
form.value = qualification;
isEdit.value = true;
diff --git a/src/pages/safeProduction/safeQualifications/index.vue b/src/pages/safeProduction/safeQualifications/index.vue
index 0456efd..95b18bc 100644
--- a/src/pages/safeProduction/safeQualifications/index.vue
+++ b/src/pages/safeProduction/safeQualifications/index.vue
@@ -106,12 +106,7 @@
import { delCustomer } from "@/api/cooperativeOffice/clientVisit";
import {
qualificationsListPage,
- safeCertificationAdd,
- safeCertificationUpdate,
safeCertificationDel,
- fileListPage,
- safeCertificationFileAdd,
- safeCertificationFileDel,
} from "@/api/safeProduction/safeQualifications";
import useUserStore from "@/store/modules/user";
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/detail.vue b/src/pages/safeProduction/safetyTrainingAssessment/detail.vue
new file mode 100644
index 0000000..d55c892
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/detail.vue
@@ -0,0 +1,430 @@
+<template>
+ <view class="danger-investigation-detail">
+ <PageHeader :title="isEdit ? '缂栬緫鍩硅' : '鏂板鍩硅'"
+ @back="goBack" />
+ <u-form @submit="handleSubmit"
+ ref="formRef"
+ label-width="110">
+ <!-- 鍩硅淇℃伅 -->
+ <u-cell-group title="鍩硅淇℃伅">
+ <u-form-item label="璇剧▼缂栧彿"
+ prop="courseCode"
+ border-bottom>
+ <u-input v-model="form.courseCode"
+ placeholder="绯荤粺鑷姩鐢熸垚"
+ readonly />
+ </u-form-item>
+ <u-form-item label="鍩硅鏃ユ湡"
+ prop="trainingDate"
+ required
+ border-bottom>
+ <u-input v-model="form.trainingDate"
+ placeholder="璇烽�夋嫨鍩硅鏃ユ湡"
+ @click="showTrainingDatePicker"
+ readonly />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showTrainingDatePicker"></up-icon>
+ </template>
+ </u-form-item>
+ <u-form-item label="寮�濮嬫椂闂�"
+ prop="openingTime"
+ required
+ border-bottom>
+ <u-input v-model="form.openingTime"
+ placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
+ @click="showOpeningTimePicker"
+ readonly />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showOpeningTimePicker"></up-icon>
+ </template>
+ </u-form-item>
+ <u-form-item label="缁撴潫鏃堕棿"
+ prop="endTime"
+ required
+ border-bottom>
+ <u-input v-model="form.endTime"
+ placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
+ @click="showEndTimePicker"
+ readonly />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showEndTimePicker"></up-icon>
+ </template>
+ </u-form-item>
+ <u-form-item label="鍩硅鐩爣"
+ prop="trainingObjectives"
+ border-bottom>
+ <u-input v-model="form.trainingObjectives"
+ placeholder="璇疯緭鍏ュ煿璁洰鏍�" />
+ </u-form-item>
+ <u-form-item label="鍙傚姞瀵硅薄"
+ prop="participants"
+ border-bottom>
+ <u-input v-model="form.participants"
+ placeholder="璇疯緭鍏ュ弬鍔犲璞�" />
+ </u-form-item>
+ <u-form-item label="鍩硅鍐呭"
+ prop="trainingContent"
+ required
+ border-bottom>
+ <u-textarea v-model="form.trainingContent"
+ placeholder="璇疯緭鍏ュ煿璁唴瀹�"
+ :maxlength="200"
+ count
+ :autoHeight="true" />
+ </u-form-item>
+ <u-form-item label="鍩硅璁插笀"
+ prop="trainingLecturer"
+ required
+ border-bottom>
+ <u-input v-model="form.trainingLecturer"
+ placeholder="璇疯緭鍏ュ煿璁甯�" />
+ </u-form-item>
+ <u-form-item label="椤圭洰瀛﹀垎"
+ prop="projectCredits"
+ border-bottom>
+ <u-input v-model="form.projectCredits"
+ placeholder="璇疯緭鍏ラ」鐩鍒�"
+ type="number" />
+ </u-form-item>
+ <u-form-item label="鍩硅鏂瑰紡"
+ prop="trainingMode"
+ border-bottom>
+ <u-input v-model="trainingModeName"
+ placeholder="璇烽�夋嫨鍩硅鏂瑰紡"
+ @click="showTrainingModeSheet"
+ readonly />
+ <template #right>
+ <up-icon name="arrow-right"
+ @click="showTrainingModeSheet"></up-icon>
+ </template>
+ </u-form-item>
+ <u-form-item label="鍩硅鍦扮偣"
+ prop="placeTraining"
+ border-bottom>
+ <u-input v-model="form.placeTraining"
+ placeholder="璇疯緭鍏ュ煿璁湴鐐�" />
+ </u-form-item>
+ <u-form-item label="璇炬椂"
+ prop="classHour"
+ required
+ border-bottom>
+ <u-input v-model="form.classHour"
+ placeholder="璇疯緭鍏ヨ鏃�"
+ type="number" />
+ </u-form-item>
+ </u-cell-group>
+ <!-- 鎻愪氦鎸夐挳 -->
+ <view class="footer-btns">
+ <u-button class="cancel-btn"
+ @click="goBack">鍙栨秷</u-button>
+ <u-button class="sign-btn"
+ type="primary"
+ @click="handleSubmit"
+ :loading="loading">{{ isEdit ? '淇濆瓨淇敼' : '鎻愪氦' }}</u-button>
+ </view>
+ </u-form>
+ <!-- 鏃堕棿閫夋嫨鍣� -->
+ <up-datetime-picker :show="trainingDateVisible"
+ mode="date"
+ v-model="nowDate"
+ @confirm="handleTrainingDateConfirm"
+ @cancel="trainingDateVisible = false"
+ title="閫夋嫨鍩硅鏃ユ湡" />
+ <u-datetime-picker :show="openingTimeVisible"
+ mode="time"
+ @confirm="handleOpeningTimeConfirm"
+ @cancel="openingTimeVisible = false"
+ title="閫夋嫨寮�濮嬫椂闂�" />
+ <u-datetime-picker :show="endTimeVisible"
+ mode="time"
+ @confirm="handleEndTimeConfirm"
+ @cancel="endTimeVisible = false"
+ title="閫夋嫨缁撴潫鏃堕棿" />
+ <!-- 鍩硅鏂瑰紡閫夋嫨鍣� -->
+ <up-action-sheet :show="trainingModeSheetVisible"
+ :actions="trainingModeOptions"
+ @select="handleTrainingModeSelect"
+ @close="trainingModeSheetVisible = false"
+ title="閫夋嫨鍩硅鏂瑰紡" />
+ </view>
+</template>
+
+<script setup>
+ // 鏇挎崲 toast 鏂规硶
+ defineOptions({ name: "danger-investigation-detail" });
+ const showToast = message => {
+ uni.showToast({ title: message, icon: "none" });
+ };
+
+ import { ref, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import {
+ safeTrainingAdd,
+ safeTrainingUpdate,
+ } from "@/api/safeProduction/safetyTrainingAssessment";
+ import { onLoad } from "@dcloudio/uni-app";
+ import { useDict } from "@/utils/dict";
+ import dayjs from "dayjs";
+
+ // 鑾峰彇瀛楀吀鏁版嵁
+ const { safe_training_methods } = useDict("safe_training_methods");
+
+ // 琛ㄥ崟鏁版嵁
+ const form = ref({
+ courseCode: "", // 璇剧▼缂栧彿
+ trainingDate: "", // 鍩硅鏃ユ湡
+ openingTime: "", // 寮�濮嬫椂闂�
+ endTime: "", // 缁撴潫鏃堕棿
+ trainingObjectives: "", // 鍩硅鐩爣
+ participants: "", // 鍙傚姞瀵硅薄
+ trainingContent: "", // 鍩硅鍐呭
+ trainingLecturer: "", // 鍩硅璁插笀
+ projectCredits: "", // 椤圭洰瀛﹀垎
+ trainingMode: "", // 鍩硅鏂瑰紡
+ placeTraining: "", // 鍩硅鍦扮偣
+ classHour: "", // 璇炬椂
+ });
+
+ // 椤甸潰鐘舵��
+ const loading = ref(false);
+ const formRef = ref(null);
+ const isEdit = ref(false);
+
+ // 鍩硅鏂瑰紡閫夋嫨鍣�
+ const trainingModeSheetVisible = ref(false);
+ const trainingModeName = ref("");
+ const trainingModeOptions = ref([]);
+
+ // 鏃堕棿閫夋嫨鍣�
+ const trainingDateVisible = ref(false);
+ const openingTimeVisible = ref(false);
+ const endTimeVisible = ref(false);
+ const nowDate = ref(new Date());
+
+ const showTrainingDatePicker = () => {
+ trainingDateVisible.value = true;
+ };
+
+ const showOpeningTimePicker = () => {
+ openingTimeVisible.value = true;
+ };
+
+ const showEndTimePicker = () => {
+ endTimeVisible.value = true;
+ };
+
+ const handleTrainingDateConfirm = e => {
+ form.value.trainingDate = dayjs(e.value).format("YYYY-MM-DD");
+ nowDate.value = e.value;
+ trainingDateVisible.value = false;
+ };
+
+ const handleOpeningTimeConfirm = e => {
+ console.log(e);
+ form.value.openingTime = e.value;
+ openingTimeVisible.value = false;
+ };
+
+ const handleEndTimeConfirm = e => {
+ form.value.endTime = e.value;
+ endTimeVisible.value = false;
+ };
+
+ // 鏄剧ず鍩硅鏂瑰紡閫夋嫨鍣�
+ const showTrainingModeSheet = () => {
+ trainingModeSheetVisible.value = true;
+ };
+
+ // 澶勭悊鍩硅鏂瑰紡閫夋嫨
+ const handleTrainingModeSelect = item => {
+ form.value.trainingMode = item.value;
+ trainingModeName.value = item.name;
+ trainingModeSheetVisible.value = false;
+ };
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.removeStorageSync("safetyTraining");
+ uni.navigateBack();
+ };
+
+ // 鎻愪氦琛ㄥ崟
+ const handleSubmit = async () => {
+ if (!form.value.trainingDate) {
+ showToast("璇烽�夋嫨鍩硅鏃ユ湡");
+ return;
+ }
+
+ if (!form.value.openingTime) {
+ showToast("璇烽�夋嫨寮�濮嬫椂闂�");
+ return;
+ }
+
+ if (!form.value.endTime) {
+ showToast("璇烽�夋嫨缁撴潫鏃堕棿");
+ return;
+ }
+ if (!form.value.trainingContent) {
+ showToast("璇疯緭鍏ュ煿璁唴瀹�");
+ return;
+ }
+
+ if (!form.value.trainingLecturer) {
+ showToast("璇疯緭鍏ュ煿璁甯�");
+ return;
+ }
+
+ if (!form.value.classHour) {
+ showToast("璇疯緭鍏ヨ鏃�");
+ return;
+ }
+ if (
+ form.value.projectCredits &&
+ (isNaN(Number(form.value.projectCredits)) ||
+ Number(form.value.projectCredits) <= 0)
+ ) {
+ showToast("瀛﹀垎蹇呴』鏄ぇ浜�0鐨勬暟瀛�");
+ return;
+ }
+ form.value.openingTime = form.value.openingTime + ":00";
+ form.value.endTime = form.value.endTime + ":00";
+
+ if (
+ form.value.classHour &&
+ (isNaN(Number(form.value.classHour)) || Number(form.value.classHour) <= 0)
+ ) {
+ showToast("璇炬椂蹇呴』鏄ぇ浜�0鐨勬暟瀛�");
+ return;
+ }
+
+ try {
+ loading.value = true;
+
+ // 浣跨敤瀹夊叏娴呮嫹璐�
+ const source =
+ form.value && typeof form.value === "object" ? form.value : {};
+ const submitData = {};
+ Object.keys(source).forEach(k => {
+ submitData[k] = source[k];
+ });
+
+ if (isEdit.value) {
+ const { code } = await safeTrainingAdd(submitData);
+ if (code === 200) {
+ showToast("淇敼鎴愬姛");
+ setTimeout(() => {
+ goBack();
+ }, 500);
+ } else {
+ loading.value = false;
+ showToast("淇敼澶辫触锛岃閲嶈瘯");
+ }
+ } else {
+ const { code } = await safeTrainingAdd(submitData);
+ if (code === 200) {
+ showToast("鏂板鎴愬姛");
+ setTimeout(() => {
+ goBack();
+ }, 500);
+ } else {
+ loading.value = false;
+ showToast("鏂板澶辫触锛岃閲嶈瘯");
+ }
+ }
+ } catch (e) {
+ loading.value = false;
+ console.error("鎻愪氦澶辫触:", e);
+ showToast("鎻愪氦澶辫触锛岃閲嶈瘯");
+ }
+ };
+
+ onLoad(() => {
+ // 缂栬緫鍩硅鏃讹紝浠庢湰鍦板瓨鍌ㄨ幏鍙栨暟鎹�
+ const safetyTraining = uni.getStorageSync("safetyTraining");
+ if (safetyTraining.id) {
+ form.value = safetyTraining;
+ nowDate.value = dayjs(form.value.trainingDate).toDate();
+ form.value.openingTime = form.value.openingTime
+ ? form.value.openingTime.slice(0, 5)
+ : "";
+ form.value.endTime = form.value.endTime
+ ? form.value.endTime.slice(0, 5)
+ : "";
+ isEdit.value = true;
+ } else {
+ isEdit.value = false;
+ // 榛樿鍩硅鏃ユ湡涓轰粖澶�
+ form.value.trainingDate = dayjs().format("YYYY-MM-DD");
+ }
+ });
+
+ onMounted(() => {
+ // 鍒濆鍖栧煿璁柟寮忛�夐」
+ if (safe_training_methods && Array.isArray(safe_training_methods.value)) {
+ trainingModeOptions.value =
+ safe_training_methods.value.map(item => ({
+ value: item.value,
+ name: item.label,
+ })) || [];
+ } else {
+ trainingModeOptions.value = [];
+ }
+
+ // 璁剧疆宸查�夊�肩殑鏄剧ず鏂囨湰
+ if (form.value.trainingMode) {
+ const modeItem = trainingModeOptions.value.find(
+ item => String(item.value) === String(form.value.trainingMode)
+ );
+ trainingModeName.value = modeItem ? modeItem.name : "";
+ }
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "@/static/scss/form-common.scss";
+
+ .danger-investigation-detail {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 100px;
+ }
+
+ .footer-btns {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: #fff;
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ padding: 0.75rem 0;
+ box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
+ z-index: 1000;
+ }
+
+ .cancel-btn {
+ font-weight: 400;
+ font-size: 1rem;
+ color: #666;
+ background: #f5f5f5;
+ border: 1px solid #ddd;
+ width: 45%;
+ height: 2.5rem;
+ border-radius: 2.5rem;
+ }
+
+ .sign-btn {
+ font-weight: 500;
+ font-size: 1rem;
+ color: #fff;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border: none;
+ width: 45%;
+ height: 2.5rem;
+ border-radius: 2.5rem;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/fileList.vue b/src/pages/safeProduction/safetyTrainingAssessment/fileList.vue
new file mode 100644
index 0000000..9797f21
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/fileList.vue
@@ -0,0 +1,567 @@
+<template>
+ <view class="file-list-page">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="闄勪欢绠$悊"
+ @back="goBack" />
+ <!-- 闄勪欢鍒楄〃 -->
+ <view class="file-list-container">
+ <view v-if="fileList.length > 0"
+ class="file-list">
+ <view v-for="(file, index) in fileList"
+ :key="file.id || index"
+ class="file-item">
+ <!-- 鏂囦欢鍥炬爣 -->
+ <!-- <view class="file-icon"
+ :class="getFileIconClass(file.fileType)">
+ <up-icon :name="getFileIcon(file.fileType)"
+ size="24"
+ color="#ffffff" />
+ </view> -->
+ <!-- 鏂囦欢淇℃伅 -->
+ <view class="file-info">
+ <text class="file-name">{{ file.name }}</text>
+ <!-- <text class="file-meta">{{ formatFileSize(file.fileSize) }} 路 {{ file.uploadTime || file.createTime }}</text> -->
+ </view>
+ <!-- 鎿嶄綔鎸夐挳 -->
+ <view class="file-actions">
+ <!-- <u-button size="small"
+ type="primary"
+ plain
+ @click="previewFile(file)">棰勮</u-button> -->
+ <u-button size="small"
+ type="info"
+ plain
+ @click="downloadFile(file)">涓嬭浇骞堕瑙�</u-button>
+ <u-button size="small"
+ type="error"
+ plain
+ @click="confirmDelete(file, index)">鍒犻櫎</u-button>
+ </view>
+ </view>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <view v-else
+ class="empty-state">
+ <up-icon name="document"
+ size="64"
+ color="#c0c4cc" />
+ <text class="empty-text">鏆傛棤闄勪欢</text>
+ </view>
+ </view>
+ <!-- <a rel="nofollow"
+ id="downloadLink"
+ href="#"
+ style="display:none;">涓嬭浇鏂囨湰鏂囦欢</a> -->
+ <!-- 涓婁紶鎸夐挳 -->
+ <view class="upload-button"
+ @click="chooseFile">
+ <up-icon name="plus"
+ size="24"
+ color="#ffffff" />
+ <text class="upload-text">涓婁紶闄勪欢</text>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import config from "@/config";
+ import { getToken } from "@/utils/auth";
+ // import { saveAs } from "file-saver";
+ import {
+ listRuleFiles,
+ delRuleFile,
+ } from "@/api/managementMeetings/rulesRegulationsManagement";
+ import {
+ safeTrainingFileListPage,
+ safeTrainingFileAdd,
+ safeTrainingFileDel,
+ } from "@/api/safeProduction/safetyTrainingAssessment";
+ import { blobValidate } from "@/utils/ruoyi";
+
+ // 闄勪欢鍒楄〃
+ const fileList = ref([]);
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+ // const request = axios.create({
+ // baseURL: "URL.com",
+ // adapter: axiosAdapterUniapp,
+ // });
+ // 鑾峰彇鏂囦欢鍥炬爣
+ const getFileIcon = fileType => {
+ const iconMap = {
+ doc: "document",
+ docx: "document",
+ xls: "grid",
+ xlsx: "grid",
+ pdf: "document",
+ ppt: "copy",
+ pptx: "copy",
+ txt: "document",
+ jpg: "image",
+ jpeg: "image",
+ png: "image",
+ gif: "image",
+ zip: "folder",
+ rar: "folder",
+ };
+ return iconMap[fileType.toLowerCase()] || "document";
+ };
+
+ // 鑾峰彇鏂囦欢鍥炬爣鏍峰紡绫�
+ const getFileIconClass = fileType => {
+ const colorMap = {
+ doc: "blue",
+ docx: "blue",
+ xls: "green",
+ xlsx: "green",
+ pdf: "red",
+ ppt: "orange",
+ pptx: "orange",
+ txt: "gray",
+ jpg: "purple",
+ jpeg: "purple",
+ png: "purple",
+ gif: "purple",
+ zip: "yellow",
+ rar: "yellow",
+ };
+ return colorMap[fileType.toLowerCase()] || "gray";
+ };
+
+ // 鏍煎紡鍖栨枃浠跺ぇ灏�
+ const formatFileSize = bytes => {
+ if (bytes === 0) return "0 B";
+ const k = 1024;
+ const sizes = ["B", "KB", "MB", "GB"];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
+ };
+
+ // 閫夋嫨鏂囦欢
+ const chooseFile = () => {
+ uni.chooseImage({
+ count: 9,
+ sizeType: ["original", "compressed"],
+ sourceType: ["album", "camera"],
+ success: res => {
+ console.log(res, "閫夋嫨鍥剧墖鎴愬姛");
+ uploadFiles(res.tempFiles);
+ },
+ fail: err => {
+ console.error("閫夋嫨鍥剧墖澶辫触:", err);
+ showToast("閫夋嫨鏂囦欢澶辫触");
+ },
+ });
+ // uni.chooseFile({
+ // count: 9,
+ // extension: [
+ // ".doc",
+ // ".docx",
+ // ".xls",
+ // ".xlsx",
+ // ".pdf",
+ // ".ppt",
+ // ".pptx",
+ // ".txt",
+ // ".jpg",
+ // ".jpeg",
+ // ".png",
+ // ".gif",
+ // ".zip",
+ // ".rar",
+ // ],
+ // success: res => {
+ // console.log(res, "閫夋嫨鏂囦欢鎴愬姛");
+ // uploadFiles(res.tempFiles);
+ // },
+ // fail: err => {
+ // showToast("閫夋嫨鏂囦欢澶辫触");
+ // },
+ // });
+ };
+
+ // 涓婁紶鏂囦欢
+ const uploadFiles = tempFiles => {
+ console.log(tempFiles, "涓婁紶鏂囦欢1");
+ tempFiles.forEach((tempFile, index) => {
+ // 鏄剧ず涓婁紶涓彁绀�
+ uni.showLoading({
+ title: "涓婁紶涓�...",
+ mask: true,
+ });
+ console.log(tempFile, "涓婁紶鏂囦欢2");
+ // 1. 鐩存帴浣跨敤 uni.uploadFile 涓婁紶鏂囦欢
+ uni.uploadFile({
+ url: config.baseUrl + "/file/upload",
+ filePath: tempFile.path,
+ name: "file",
+ header: {
+ Authorization: "Bearer " + getToken(),
+ },
+ success: uploadRes => {
+ uni.hideLoading();
+ console.log(uploadRes, "涓婁紶鏂囦欢3");
+
+ try {
+ const res = JSON.parse(uploadRes.data);
+ console.log(res, "涓婁紶鏂囦欢4");
+ if (res.code === 200) {
+ // 2. 鎻愬彇鏂囦欢淇℃伅
+ const fileName = tempFile.name
+ ? tempFile.name
+ : tempFile.path.split("/").pop();
+ // const fileType = fileName.split(".").pop();
+ // 3. 鏋勯�犱繚瀛樻枃浠朵俊鎭殑鍙傛暟
+ const saveData = {
+ name: fileName,
+ safeTrainingId: rulesRegulationsManagementId.value,
+ url: res.data.tempPath || "",
+ };
+ console.log(saveData, "淇濆瓨鏂囦欢淇℃伅鍙傛暟");
+ // 4. 璋冪敤 addRuleFile 鎺ュ彛淇濆瓨鏂囦欢淇℃伅
+ safeTrainingFileAdd(saveData)
+ .then(addRes => {
+ if (addRes.code === 200) {
+ // 5. 娣诲姞鍒版枃浠跺垪琛�
+ const newFile = {
+ ...addRes.data,
+ uploadTime: new Date().toLocaleString(),
+ };
+ // fileList.value.push(newFile);
+ getFileList();
+ showToast("涓婁紶鎴愬姛");
+ } else {
+ showToast("淇濆瓨鏂囦欢淇℃伅澶辫触");
+ }
+ })
+ .catch(err => {
+ console.error("淇濆瓨鏂囦欢淇℃伅澶辫触:", err);
+ showToast("淇濆瓨鏂囦欢淇℃伅澶辫触");
+ });
+ } else {
+ showToast("鏂囦欢涓婁紶澶辫触");
+ }
+ } catch (e) {
+ console.error("瑙f瀽涓婁紶缁撴灉澶辫触:", e);
+ showToast("涓婁紶澶辫触");
+ }
+ },
+ fail: err => {
+ uni.hideLoading();
+ console.error("涓婁紶澶辫触:", err);
+ showToast("涓婁紶澶辫触");
+ },
+ });
+ });
+ };
+ // 涓嬭浇鏂囦欢
+ const downloadFile = file => {
+ var url =
+ config.baseUrl +
+ "/common/download?fileName=" +
+ encodeURIComponent(file.url) +
+ "&delete=true";
+ console.log(url, "url");
+
+ uni
+ .downloadFile({
+ url: url,
+ responseType: "blob",
+ header: { Authorization: "Bearer " + getToken() },
+ })
+ .then(res => {
+ console.log(res, "涓嬭浇鏂囦欢");
+ let osType = uni.getStorageSync("deviceInfo").osName;
+ let filePath = res.tempFilePath;
+ if (osType === "ios") {
+ uni.openDocument({
+ filePath: filePath,
+ showMenu: true,
+ success: res => {
+ resolve(res);
+ },
+ fail: err => {
+ console.log("uni.openDocument--fail");
+ reject(err);
+ },
+ });
+ } else {
+ uni.saveFile({
+ tempFilePath: filePath,
+ success: fileRes => {
+ uni.showToast({
+ icon: "none",
+ mask: true,
+ title:
+ "鏂囦欢宸蹭繚瀛橈細Android/data/uni.UNI720216F/apps/__UNI__720216F/" +
+ fileRes.savedFilePath, //淇濆瓨璺緞
+ duration: 3000,
+ });
+ setTimeout(() => {
+ //鎵撳紑鏂囨。鏌ョ湅
+ uni.openDocument({
+ filePath: fileRes.savedFilePath,
+ success: function (res) {
+ resolve(fileRes);
+ },
+ });
+ }, 3000);
+ },
+ fail: err => {
+ console.log("uni.save--fail");
+ reject(err);
+ },
+ });
+ }
+ // const isBlob = blobValidate(res.data);
+ // if (isBlob) {
+ // const blob = new Blob([res.data], { type: "text/plain" });
+ // const url = URL.createObjectURL(blob);
+ // const downloadLink = document.getElementById("downloadLink");
+ // downloadLink.href = url;
+ // downloadLink.download = file.name;
+ // downloadLink.click();
+ // showToast("涓嬭浇鎴愬姛");
+ // } else {
+ // showToast("涓嬭浇澶辫触");
+ // }
+ })
+ .catch(err => {
+ console.error("涓嬭浇澶辫触:", err);
+ showToast("涓嬭浇澶辫触");
+ });
+ };
+
+ // 纭鍒犻櫎
+ const confirmDelete = (file, index) => {
+ uni.showModal({
+ title: "鍒犻櫎纭",
+ content: `纭畾瑕佸垹闄ら檮浠� "${file.name}" 鍚楋紵`,
+ success: res => {
+ if (res.confirm) {
+ deleteFile(file.id, index);
+ }
+ },
+ });
+ };
+
+ // 鍒犻櫎鏂囦欢
+ const deleteFile = (fileId, index) => {
+ uni.showLoading({
+ title: "鍒犻櫎涓�...",
+ mask: true,
+ });
+
+ safeTrainingFileDel([fileId])
+ .then(res => {
+ uni.hideLoading();
+ if (res.code === 200) {
+ // fileList.value.splice(index, 1);
+ getFileList();
+ showToast("鍒犻櫎鎴愬姛");
+ } else {
+ showToast("鍒犻櫎澶辫触");
+ }
+ })
+ .catch(err => {
+ uni.hideLoading();
+ showToast("鍒犻櫎澶辫触");
+ });
+ };
+
+ // 鏄剧ず鎻愮ず
+ const showToast = message => {
+ uni.showToast({
+ title: message,
+ icon: "none",
+ });
+ };
+ const rulesRegulationsManagementId = ref("");
+ // 椤甸潰鍔犺浇鏃�
+ onMounted(() => {
+ rulesRegulationsManagementId.value = uni.getStorageSync(
+ "safetyTrainingFileId"
+ );
+ // 浠� API 鑾峰彇闄勪欢鍒楄〃
+ getFileList();
+ // 浠庢湰鍦板瓨鍌ㄨ幏鍙� rulesRegulationsManagementId
+ });
+
+ // 鑾峰彇闄勪欢鍒楄〃
+ const getFileList = () => {
+ uni.showLoading({
+ title: "鍔犺浇涓�...",
+ mask: true,
+ });
+
+ safeTrainingFileListPage({
+ safeTrainingId: rulesRegulationsManagementId.value,
+ current: -1,
+ size: -1,
+ })
+ .then(res => {
+ uni.hideLoading();
+ if (res.code === 200) {
+ fileList.value = res.data.records || [];
+ } else {
+ showToast("鑾峰彇闄勪欢鍒楄〃澶辫触");
+ }
+ })
+ .catch(err => {
+ uni.hideLoading();
+ showToast("鑾峰彇闄勪欢鍒楄〃澶辫触");
+ });
+ };
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+
+ .file-list-page {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 100rpx;
+ }
+
+ .file-list-container {
+ padding: 20rpx;
+ }
+
+ .file-list {
+ background: #ffffff;
+ border-radius: 8rpx;
+ overflow: hidden;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ }
+
+ .file-item {
+ display: flex;
+ align-items: center;
+ padding: 20rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .file-icon {
+ width: 56rpx;
+ height: 56rpx;
+ border-radius: 8rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right: 20rpx;
+
+ &.blue {
+ background: #409eff;
+ }
+
+ &.green {
+ background: #67c23a;
+ }
+
+ &.red {
+ background: #f56c6c;
+ }
+
+ &.orange {
+ background: #e6a23c;
+ }
+
+ &.gray {
+ background: #909399;
+ }
+
+ &.purple {
+ background: #909399;
+ }
+
+ &.yellow {
+ background: #e6a23c;
+ }
+ }
+
+ .file-info {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .file-name {
+ display: block;
+ font-size: 16px;
+ color: #303133;
+ margin-bottom: 8rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .file-meta {
+ display: block;
+ font-size: 12px;
+ color: #909399;
+ }
+
+ .file-actions {
+ display: flex;
+ gap: 12rpx;
+ }
+
+ .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 100rpx 0;
+ background: #ffffff;
+ border-radius: 8rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ }
+
+ .empty-text {
+ font-size: 14px;
+ color: #909399;
+ margin-top: 20rpx;
+ }
+
+ .upload-button {
+ position: fixed;
+ bottom: 40rpx;
+ right: 40rpx;
+ width: 130rpx;
+ height: 130rpx;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4);
+ z-index: 1000;
+ }
+
+ .upload-text {
+ font-size: 10px;
+ color: #ffffff;
+ margin-top: 4rpx;
+ }
+
+ .upload-progress {
+ padding: 40rpx 0;
+ }
+
+ .upload-progress-text {
+ display: block;
+ text-align: center;
+ margin-top: 20rpx;
+ font-size: 14px;
+ color: #606266;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/index.vue b/src/pages/safeProduction/safetyTrainingAssessment/index.vue
new file mode 100644
index 0000000..905f9e8
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/index.vue
@@ -0,0 +1,448 @@
+<template>
+ <view class="sales-accoun">
+ <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+ <PageHeader title="瀹夊叏鍩硅鑰冩牳"
+ @back="goBack" />
+ <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view @click="selectDate"
+ class="search-input">
+ <view class="search-text">{{ searchKeyword? searchKeyword : '璇烽�夋嫨鍩硅鏃ユ湡' }}</view>
+ </view>
+ <view class="filter-button"
+ @click="clearDate">
+ <u-icon name="close-circle"
+ size="24"
+ color="#999"></u-icon>
+ </view>
+ </view>
+ <!-- 鍩硅璁板綍鎸夐挳 -->
+ <view class="record-button">
+ <u-button type="info"
+ @click="viewTrainingRecord">鍩硅璁板綍</u-button>
+ </view>
+ </view>
+ <!-- 鏍囩椤� -->
+ <view class="tabs-section">
+ <up-tabs v-model="searchForm.state"
+ :list="tabList"
+ itemStyle="width: 33%;height: 80rpx;"
+ @change="tabhandleQuery">
+ </up-tabs>
+ </view>
+ <!-- 鍩硅璁板綍鍒楄〃 -->
+ <view class="ledger-list"
+ v-if="trainingList.length > 0">
+ <view v-for="(item, index) in trainingList"
+ :key="index">
+ <view class="ledger-item">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="document-icon">
+ <up-icon name="file-text"
+ size="16"
+ color="#ffffff"></up-icon>
+ </view>
+ <text class="item-id">璇剧▼缂栧彿锛歿{ item.courseCode }}</text>
+ </view>
+ </view>
+ <up-divider></up-divider>
+ <view class="item-details">
+ <view class="detail-row">
+ <text class="detail-label">璇剧▼缂栧彿</text>
+ <text class="detail-value">{{ item.courseCode || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅鏃ユ湡</text>
+ <text class="detail-value">{{ item.trainingDate || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">寮�濮嬫椂闂�</text>
+ <text class="detail-value">{{ item.openingTime || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">缁撴潫鏃堕棿</text>
+ <text class="detail-value">{{ item.endTime || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅鐩爣</text>
+ <text class="detail-value">{{ item.trainingObjectives || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍙傚姞瀵硅薄</text>
+ <text class="detail-value">{{ item.participants || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅鍐呭</text>
+ <text class="detail-value">{{ item.trainingContent || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅璁插笀</text>
+ <text class="detail-value">{{ item.trainingLecturer || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">椤圭洰瀛﹀垎</text>
+ <text class="detail-value">{{ item.projectCredits || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅鏂瑰紡</text>
+ <text class="detail-value">{{ getTrainingModeLabel(item.trainingMode) || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍩硅鍦扮偣</text>
+ <text class="detail-value">{{ item.placeTraining || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">璇炬椂</text>
+ <text class="detail-value">{{ item.classHour || '-' }}</text>
+ </view>
+ </view>
+ <!-- 鎸夐挳鍖哄煙 -->
+ <view class="action-buttons">
+ <u-button type="primary"
+ size="small"
+ class="action-btn"
+ :disabled="item.state !== 0"
+ @click="editVisit(item)">
+ 缂栬緫
+ </u-button>
+ <u-button type="info"
+ size="small"
+ class="action-btn"
+ @click="viewFileList(item)">
+ 闄勪欢
+ </u-button>
+ <u-button type="error"
+ size="small"
+ class="action-btn"
+ @click="deleteVisit(item)">
+ 鍒犻櫎
+ </u-button>
+ </view>
+ <view class="action-buttons">
+ <u-button type="warning"
+ size="small"
+ class="action-btn"
+ :disabled="item.state !== 1"
+ @click="signIn(item)">
+ 绛惧埌
+ </u-button>
+ <u-button type="success"
+ size="small"
+ class="action-btn"
+ :disabled="item.state === 0"
+ @click="viewResultDetail(item)">
+ 缁撴灉鏄庣粏
+ </u-button>
+ </view>
+ </view>
+ </view>
+ </view>
+ <view v-else
+ class="no-data">
+ <text>鏆傛棤鍩硅璁板綍</text>
+ </view>
+ <up-datetime-picker :show="trainingDateVisible"
+ mode="date"
+ @confirm="handleDateConfirm"
+ @cancel="handleDateCancel"
+ title="閫夋嫨鍩硅鏃ユ湡" />
+ <!-- 娴姩鏂板鎸夐挳 -->
+ <view class="fab-button"
+ @click="addVisit">
+ <up-icon name="plus"
+ size="24"
+ color="#ffffff"></up-icon>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted, reactive } from "vue";
+
+ import { onShow } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import {
+ safeTrainingListPage,
+ safeTrainingDel,
+ safeTrainingSign,
+ safeTrainingGet,
+ } from "@/api/safeProduction/safetyTrainingAssessment";
+ import useUserStore from "@/store/modules/user";
+ import { useDict } from "@/utils/dict";
+ import dayjs from "dayjs";
+ // 鏇挎崲 toast 鏂规硶
+ defineOptions({ name: "safety-training-index" });
+ const showToast = message => {
+ uni.showToast({
+ title: message,
+ icon: "none",
+ });
+ };
+
+ const userStore = useUserStore();
+
+ // 鑾峰彇瀛楀吀鏁版嵁
+ const { safe_training_methods } = useDict("safe_training_methods");
+
+ // 鎼滅储鍏抽敭璇�
+ const searchKeyword = ref("");
+ // 鏃ユ湡閫夋嫨鍣ㄧ姸鎬�
+ const trainingDateVisible = ref(false);
+
+ const tabList = reactive([
+ { name: "鏈紑濮�", value: 0 },
+ { name: "杩涜涓�", value: 1 },
+ { name: "宸茬粨鏉�", value: 2 },
+ ]);
+ // 鎼滅储琛ㄥ崟
+ const searchForm = ref({
+ state: 0, // 榛樿鏄剧ず宸茬粨鏉�
+ trainingDate: "",
+ });
+ const tabhandleQuery = val => {
+ searchForm.value.state = val.value;
+ getList();
+ };
+ const getTrainingModeLabel = mode => {
+ if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) {
+ return mode || "-";
+ }
+ const dictItem = safe_training_methods.value.find(
+ item => String(item.value) === String(mode)
+ );
+ return dictItem ? dictItem.label : mode || "-";
+ };
+
+ // 鍩硅璁板綍鏁版嵁
+ const trainingList = ref([]);
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+ const viewFileList = item => {
+ uni.setStorageSync("safetyTrainingFileId", item.id);
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/fileList",
+ });
+ };
+ const currentUserId = ref("");
+ // 绛惧埌鍔熻兘
+ const signIn = item => {
+ uni.showModal({
+ title: "鎻愮ず",
+ content: "纭绛惧埌鍚楋紵",
+ success: function (res) {
+ if (res.confirm) {
+ safeTrainingSign({
+ safeTrainingId: item.id,
+ userId: currentUserId.value,
+ })
+ .then(res => {
+ if (res.code === 200) {
+ uni.showToast({ title: "绛惧埌鎴愬姛", icon: "success" });
+ setTimeout(() => {}, 1000);
+ } else {
+ uni.showToast({ title: res.msg || "绛惧埌澶辫触", icon: "none" });
+ }
+ })
+ .catch(() => {
+ uni.showToast({ title: "绛惧埌澶辫触锛岃閲嶈瘯", icon: "none" });
+ });
+ }
+ },
+ });
+ };
+
+ // 鏌ョ湅缁撴灉鏄庣粏
+ const viewResultDetail = item => {
+ uni.setStorageSync("safetyTrainingResultId", item.id);
+ uni.setStorageSync("safetyTrainingResultNums", item.nums);
+
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/resultDetail",
+ });
+ };
+
+ // 鏌ョ湅鍩硅璁板綍
+ const viewTrainingRecord = () => {
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/record",
+ });
+ };
+ // 娓呴櫎鏃ユ湡閫夋嫨
+ const clearDate = () => {
+ searchKeyword.value = "";
+ searchForm.value.trainingDate = "";
+ getList();
+ };
+ // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+ const selectDate = () => {
+ trainingDateVisible.value = true;
+ };
+
+ // 澶勭悊鏃ユ湡閫夋嫨纭
+ const handleDateConfirm = e => {
+ searchKeyword.value = dayjs(e.value).format("YYYY-MM-DD");
+ searchForm.value.trainingDate = dayjs(e.value).format("YYYY-MM-DD");
+ trainingDateVisible.value = false;
+ getList();
+ };
+
+ // 澶勭悊鏃ユ湡閫夋嫨鍙栨秷
+ const handleDateCancel = () => {
+ trainingDateVisible.value = false;
+ };
+
+ // 鏌ヨ鍒楄〃
+ const getList = () => {
+ showLoadingToast("鍔犺浇涓�...");
+ const params = {
+ current: -1,
+ size: -1,
+ trainingDate: searchForm.value.trainingDate,
+ state: searchForm.value.state,
+ };
+ safeTrainingListPage(params)
+ .then(res => {
+ trainingList.value = res.records || res.data?.records || [];
+ closeToast();
+ })
+ .catch(() => {
+ closeToast();
+ showToast("鑾峰彇鏁版嵁澶辫触");
+ });
+ };
+
+ // 鏄剧ず鍔犺浇鎻愮ず
+ const showLoadingToast = message => {
+ uni.showLoading({
+ title: message,
+ mask: true,
+ });
+ };
+
+ // 鍏抽棴鎻愮ず
+ const closeToast = () => {
+ uni.hideLoading();
+ };
+
+ // 鏂板鍩硅
+ const addVisit = () => {
+ uni.setStorageSync("safetyTraining", {});
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/detail",
+ });
+ };
+ // 缂栬緫鍩硅
+ const editVisit = item => {
+ uni.setStorageSync("safetyTraining", item);
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/detail",
+ });
+ };
+ // 鍒犻櫎鍩硅
+ const deleteVisit = item => {
+ uni.showModal({
+ title: "鍒犻櫎纭",
+ content: `纭畾瑕佸垹闄よ鍩硅璁板綍鍚楋紵`,
+ success: res => {
+ if (res.confirm) {
+ deleteClientVisit(item.id);
+ }
+ },
+ });
+ };
+ // 鍒犻櫎鍩硅璁板綍
+ const deleteClientVisit = id => {
+ showLoadingToast("鍒犻櫎涓�...");
+ safeTrainingDel([id])
+ .then(() => {
+ closeToast();
+ showToast("鍒犻櫎鎴愬姛");
+ getList();
+ })
+ .catch(() => {
+ closeToast();
+ showToast("鍒犻櫎澶辫触");
+ });
+ };
+ // 鏌ョ湅璇︽儏
+ const viewDetail = item => {
+ uni.setStorageSync("safetyTraining", item);
+ uni.navigateTo({
+ url: "/pages/safeProduction/safetyTrainingAssessment/view",
+ });
+ };
+
+ onMounted(() => {
+ userStore.getInfo().then(res => {
+ currentUserId.value = res.user.userId;
+ });
+ // currentUserId
+ getList();
+ });
+
+ onShow(() => {
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+
+ // 椤甸潰鐗瑰畾鐨勬牱寮忚鐩�
+ .sales-accoun {
+ min-height: 100vh;
+ background: #f8f9fa;
+ position: relative;
+ padding-bottom: 80px;
+ }
+
+ // 鍩硅璁板綍鎸夐挳
+ .record-button {
+ margin-top: 10px;
+ text-align: center;
+ }
+
+ // 鐗瑰畾鐨勫浘鏍囨牱寮�
+ .document-icon {
+ background: #667eea; // 淇濇寔椤甸潰鐗规湁鐨勮儗鏅壊
+ }
+
+ // 鐗规湁鏍峰紡
+ .visit-status {
+ display: flex;
+ align-items: center;
+ }
+
+ .detail-value {
+ word-break: break-all; // 淇濈暀椤甸潰鐗规湁鐨勬枃鏈崲琛屾牱寮�
+ }
+
+ // 鐗瑰畾鐨勬诞鍔ㄦ寜閽牱寮�
+ .fab-button {
+ background: #667eea; // 淇濇寔椤甸潰鐗规湁鐨勮儗鏅壊
+ box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3); // 淇濇寔椤甸潰鐗规湁鐨勯槾褰辨晥鏋�
+ }
+ .action-buttons {
+ gap: 4px;
+ }
+ .action-buttons {
+ padding: 0 0 10rpx 0;
+ }
+
+ .tabs-section {
+ background: #fff;
+ margin-bottom: 1rem;
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.05);
+ }
+ .search-text {
+ // font-size: 24rpx;
+ color: #a6a6a6;
+ height: 70rpx;
+ line-height: 70rpx;
+ margin-left: 20rpx;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/record.vue b/src/pages/safeProduction/safetyTrainingAssessment/record.vue
new file mode 100644
index 0000000..825b7d6
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/record.vue
@@ -0,0 +1,546 @@
+<template>
+ <view class="training-record">
+ <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+ <PageHeader title="鍩硅璁板綍"
+ @back="goBack" />
+ <!-- 鎼滅储鍜岀瓫閫夊尯鍩� -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <up-input class="search-text"
+ placeholder="浜哄憳鍚嶇О鎼滅储"
+ v-model="searchForm.searchText"
+ @change="searchName"
+ clearable />
+ </view>
+ <view class="filter-button"
+ @click="searchName">
+ <u-icon name="search"
+ size="24"
+ color="#999"></u-icon>
+ </view>
+ </view>
+ </view>
+ <!-- 浜哄憳鍗$墖鍒楄〃 -->
+ <view class="user-card-list"
+ v-if="userList.length > 0">
+ <view v-for="(user, index) in userList"
+ :key="index"
+ class="user-card">
+ <!-- 鍗$墖澶撮儴 -->
+ <view class="card-header"
+ @click="toggleUserCard(index)">
+ <view class="header-left">
+ <text class="user-name">{{ user.nickName }}</text>
+ <text class="user-dept">鎵�灞烇細{{ user.deptNames || '-' }}</text>
+ <text class="user-dept">鑱旂郴鏂瑰紡锛歿{ user.phonenumber || '-' }}</text>
+ <!-- 鍩硅缁熻淇℃伅 -->
+ </view>
+ <u-icon :name="expandedUsers[index] ? 'arrow-up' : 'arrow-down'"
+ size="20"
+ color="#999"></u-icon>
+ </view>
+ <!-- 鍗$墖鍐呭锛堟姌鍙犻儴鍒嗭級 -->
+ <view class="card-content"
+ v-if="expandedUsers[index]">
+ <!-- 骞翠唤绛涢�� -->
+ <view class="year-filter-section">
+ <!-- <text class="filter-label">骞翠唤绛涢��</text> -->
+ <view class="year-options">
+ <u-tag v-for="year in yearOptions"
+ :key="year"
+ :text="year"
+ :type="userYearFilters[user.userId] === year.toString() ? 'primary' : 'info'"
+ @click="() => {
+ userYearFilters[user.userId] = year.toString();
+ filterUserCourses(user.userId);
+ }"
+ :class="{ active: userYearFilters[user.userId] === year.toString() }"
+ style="margin-right: 8px; margin-bottom: 8px;"></u-tag>
+ </view>
+ </view>
+ <!-- 鍩硅璇剧▼鍒楄〃 -->
+ <view class="course-list"
+ v-if="userCourses[user.userId] && userCourses[user.userId].length > 0">
+ <view class="user-stats"
+ v-if="userStats[user.userId]">
+ <text class="stat-item">鍩硅娆℃暟: {{ userStats[user.userId].total }}</text>
+ <text class="stat-item success">鍚堟牸: {{ userStats[user.userId].qualified }}</text>
+ <text class="stat-item danger">涓嶅悎鏍�: {{ userStats[user.userId].unqualified }}</text>
+ </view>
+ <view v-for="(course, courseIndex) in userCourses[user.userId]"
+ :key="courseIndex">
+ <view class="course-item"
+ v-if="userYearFilters[user.userId] === '鍏ㄩ儴' || course.trainingDate.includes(userYearFilters[user.userId])">
+ <view class="course-header">
+ <text class="course-date">{{ course.trainingDate || '-' }}</text>
+ <u-tag :type="course.examinationResults === '鍚堟牸' ? 'success' : 'error'">
+ {{ course.examinationResults || '-' }}
+ </u-tag>
+ </view>
+ <view class="course-info">
+ <text class="info-label">鍩硅鍐呭锛�</text>
+ <text class="info-value">{{ course.trainingContent || '-' }}</text>
+ </view>
+ <view class="course-info">
+ <text class="info-label">鍩硅璇炬椂锛�</text>
+ <text class="info-value">{{ course.classHour || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ <!-- 绛涢�夊悗鏃犳暟鎹� -->
+ <view v-if="userYearFilters[user.userId] === '鍏ㄩ儴' ? userCourses[user.userId].length === 0 : userCourses[user.userId].filter(c => c.trainingDate.includes(userYearFilters[user.userId])).length === 0"
+ class="empty-course">
+ <text class="empty-text">{{ userYearFilters[user.userId] === '鍏ㄩ儴' ? '鏆傛棤鍩硅璁板綍' : '璇ュ勾浠芥殏鏃犲煿璁褰�' }}</text>
+ </view>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <view v-else
+ class="empty-course">
+ <text class="empty-text">鏆傛棤鍩硅璁板綍</text>
+ </view>
+ </view>
+ <!-- 瀵煎嚭鎸夐挳 -->
+ <!-- <view class="course-export">
+ <u-button type="primary"
+ size="small"
+ @click="exportUserRecord(user.userId)">瀵煎嚭璁板綍</u-button>
+ </view> -->
+ </view>
+ </view>
+ <view v-else
+ class="empty-state">
+ <up-icon name="people"
+ size="64"
+ color="#c0c4cc"></up-icon>
+ <text class="empty-text">鏆傛棤浜哄憳鏁版嵁</text>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <!-- 骞翠唤閫夋嫨鍣� -->
+ <up-datetime-picker :show="yearPickerVisible"
+ mode="year"
+ @confirm="handleYearConfirm"
+ @cancel="yearPickerVisible = false"
+ title="閫夋嫨骞翠唤" />
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted, reactive } from "vue";
+ import { onShow } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import { safeTrainingDetailListPage } from "@/api/safeProduction/safetyTrainingAssessment";
+ import { userListNoPage } from "@/api/system/user.js";
+ import { getToken } from "@/utils/auth";
+ import config from "@/config";
+
+ // 椤甸潰鐘舵��
+ const userList = ref([]);
+ const userCourses = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫煿璁绋�
+ const userStats = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫煿璁粺璁′俊鎭�
+ const expandedUsers = ref([]); // 鎺у埗鐢ㄦ埛鍗$墖灞曞紑鐘舵��
+ const loading = ref(false);
+ const courseLoading = ref({}); // 鎺у埗姣忎釜鐢ㄦ埛鐨勮绋嬪姞杞界姸鎬�
+ const userYearFilters = ref({}); // 瀛樺偍姣忎釜鐢ㄦ埛鐨勫勾浠界瓫閫夋潯浠�
+ const yearOptions = ref([]); // 骞翠唤閫夐」锛堜粖骞村拰杩囧幓涓夊勾锛�
+
+ // 鎼滅储琛ㄥ崟
+ const searchForm = reactive({
+ searchText: "",
+ invoiceDate: "",
+ });
+
+ // 骞翠唤閫夋嫨鍣ㄧ姸鎬�
+ const yearPickerVisible = ref(false);
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ // 鐢熸垚骞翠唤閫夐」
+ const generateYearOptions = () => {
+ const currentYear = new Date().getFullYear();
+ const options = [];
+ // 娣诲姞"鍏ㄩ儴"閫夐」
+ options.push("鍏ㄩ儴");
+ for (let i = 0; i < 4; i++) {
+ options.push(currentYear - i);
+ }
+ yearOptions.value = options;
+ };
+
+ // 鎼滅储浜哄憳鍚嶇О
+ const searchName = () => {
+ getUserList();
+ };
+
+ // 鏄剧ず骞翠唤閫夋嫨鍣�
+ const showYearPicker = () => {
+ yearPickerVisible.value = true;
+ };
+
+ // 澶勭悊骞翠唤閫夋嫨纭
+ const handleYearConfirm = e => {
+ searchForm.invoiceDate = e.value;
+ yearPickerVisible.value = false;
+ };
+
+ // 鎸夊勾浠芥悳绱�
+ const searchDate = () => {
+ // 閬嶅巻鎵�鏈夊睍寮�鐨勭敤鎴峰崱鐗囷紝閲嶆柊鍔犺浇鍩硅璁板綍
+ userList.value.forEach((user, index) => {
+ if (expandedUsers.value[index]) {
+ getUserCourses(user.userId, index);
+ }
+ });
+ };
+
+ // 鑾峰彇浜哄憳鍒楄〃
+ const getUserList = () => {
+ loading.value = true;
+ userListNoPage()
+ .then(res => {
+ loading.value = false;
+ if (res.data && res.data.length > 0) {
+ let users = res.data;
+ // 濡傛灉鏈夋悳绱㈠叧閿瘝锛岃繘琛岀瓫閫�
+ if (searchForm.searchText) {
+ users = users.filter(user =>
+ user.nickName.includes(searchForm.searchText)
+ );
+ }
+ userList.value = users;
+ // 鍒濆鍖栨墍鏈夊崱鐗囦负鏀惰捣鐘舵��
+ expandedUsers.value = new Array(userList.value.length).fill(false);
+ } else {
+ userList.value = [];
+ expandedUsers.value = [];
+ }
+ })
+ .catch(() => {
+ loading.value = false;
+ uni.showToast({ title: "鑾峰彇浜哄憳鍒楄〃澶辫触", icon: "none" });
+ });
+ };
+
+ // 鍒囨崲鐢ㄦ埛鍗$墖灞曞紑鐘舵��
+ const toggleUserCard = index => {
+ const user = userList.value[index];
+ expandedUsers.value[index] = !expandedUsers.value[index];
+
+ // 濡傛灉灞曞紑鍗$墖锛屽姞杞藉煿璁褰�
+ if (expandedUsers.value[index]) {
+ // 鍒濆鍖栧勾浠界瓫閫夋潯浠朵负"鍏ㄩ儴"
+ userYearFilters.value[user.userId] = "鍏ㄩ儴";
+ getUserCourses(user.userId, index);
+ }
+ };
+
+ // 绛涢�夌敤鎴峰煿璁绋�
+ const filterUserCourses = userId => {
+ if (!userYearFilters.value[userId]) return;
+ console.log("userYearFilters", userYearFilters.value);
+ const year = userYearFilters.value[userId];
+ const allCourses = userCourses.value[userId] || [];
+
+ // 绛涢�夋寚瀹氬勾浠界殑鍩硅璁板綍
+ let filteredCourses = allCourses;
+ if (year !== "鍏ㄩ儴") {
+ filteredCourses = allCourses.filter(
+ course => course.trainingDate && course.trainingDate.includes(year)
+ );
+ }
+ console.log("filteredCourses", filteredCourses);
+
+ // 鏇存柊缁熻淇℃伅
+ const total = filteredCourses.length;
+ const qualified = filteredCourses.filter(
+ course => course.examinationResults === "鍚堟牸"
+ ).length;
+ const unqualified = filteredCourses.filter(
+ course => course.examinationResults === "涓嶅悎鏍�"
+ ).length;
+ userStats.value[userId] = {
+ total,
+ qualified,
+ unqualified,
+ };
+ };
+
+ // 鑾峰彇鐢ㄦ埛鍩硅璇剧▼
+ const getUserCourses = (userId, index) => {
+ courseLoading.value[userId] = true;
+
+ const params = {
+ userId,
+ // 濡傛灉鏈夊勾浠界瓫閫夛紝娣诲姞骞翠唤鍙傛暟
+ // 杩欓噷闇�瑕佹牴鎹悗绔帴鍙g殑瀹為檯鍙傛暟鍚嶈繘琛岃皟鏁�
+ };
+
+ safeTrainingDetailListPage(params)
+ .then(res => {
+ courseLoading.value[userId] = false;
+ if (res.data && res.data.records) {
+ let courses = res.data.records;
+ // 濡傛灉鏈夊勾浠界瓫閫夛紝杩涜绛涢��
+ if (searchForm.invoiceDate) {
+ const year = searchForm.invoiceDate.substring(0, 4);
+ courses = courses.filter(
+ course => course.trainingDate && course.trainingDate.includes(year)
+ );
+ }
+ userCourses.value[userId] = courses;
+
+ // 璁$畻鍩硅缁熻淇℃伅
+ const total = courses.length;
+ const qualified = courses.filter(
+ course => course.examinationResults === "鍚堟牸"
+ ).length;
+ const unqualified = courses.filter(
+ course => course.examinationResults === "涓嶅悎鏍�"
+ ).length;
+
+ userStats.value[userId] = {
+ total,
+ qualified,
+ unqualified,
+ };
+ } else {
+ userCourses.value[userId] = [];
+ userStats.value[userId] = {
+ total: 0,
+ qualified: 0,
+ unqualified: 0,
+ };
+ }
+ })
+ .catch(() => {
+ courseLoading.value[userId] = false;
+ uni.showToast({ title: "鑾峰彇鍩硅璁板綍澶辫触", icon: "none" });
+ });
+ };
+
+ // 椤甸潰鍔犺浇
+ onMounted(() => {
+ // 鐢熸垚骞翠唤閫夐」
+ generateYearOptions();
+ getUserList();
+ });
+
+ // 椤甸潰鏄剧ず鏃跺埛鏂�
+ onShow(() => {
+ // 鍙互鍦ㄨ繖閲屾坊鍔犲埛鏂伴�昏緫
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+ .training-record {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 20px;
+ }
+
+ // 骞翠唤閫夋嫨鍣�
+ .year-picker {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 15px;
+ background: #f8f9fa;
+ border-radius: 4px;
+ margin-right: 10px;
+ }
+
+ .picker-text {
+ font-size: 14px;
+ color: #333;
+ }
+
+ // 浜哄憳鍗$墖鍒楄〃
+ .user-card-list {
+ padding: 10px;
+ }
+
+ // 浜哄憳鍗$墖
+ .user-card {
+ background: #fff;
+ border-radius: 8px;
+ margin-bottom: 12px;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
+ overflow: hidden;
+ border: 1px solid #e8e8e8;
+ }
+
+ // 鍗$墖澶撮儴
+ .card-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px;
+ background: #f5f7fa;
+ border-bottom: 1px solid #e8e8e8;
+ cursor: pointer;
+ }
+
+ .header-left {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .user-name {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 20rpx;
+ }
+
+ .user-dept {
+ font-size: 14px;
+ color: #666;
+ margin-bottom: 8px;
+ }
+
+ // 鍩硅缁熻淇℃伅
+ .user-stats {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 8px;
+ }
+
+ .stat-item {
+ font-size: 12px;
+ color: #555;
+ padding: 5px 10px;
+ background: #f0f2f5;
+ border-radius: 4px;
+ border: 1px solid #e0e0e0;
+ font-weight: 500;
+ }
+
+ .stat-item.success {
+ background: #e6f7ff;
+ color: #1890ff;
+ border-color: #91d5ff;
+ }
+
+ .stat-item.danger {
+ background: #fff1f0;
+ color: #ff4d4f;
+ border-color: #ffccc7;
+ }
+
+ // 骞翠唤绛涢�夊尯鍩�
+ .year-filter-section {
+ margin-bottom: 16px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #e8e8e8;
+ }
+
+ .filter-label {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+ margin-bottom: 8px;
+ display: block;
+ }
+
+ .year-options {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ // 鍗$墖鍐呭
+ .card-content {
+ padding: 16px;
+ }
+
+ // 鍩硅璇剧▼鍒楄〃
+ .course-list {
+ margin-bottom: 16px;
+ }
+
+ // 璇剧▼椤�
+ .course-item {
+ background: #fafafa;
+ border-radius: 6px;
+ padding: 14px;
+ margin-bottom: 12px;
+ border: 1px solid #e8e8e8;
+ }
+
+ // 璇剧▼澶撮儴
+ .course-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .course-date {
+ font-size: 14px;
+ font-weight: 600;
+ color: #333;
+ }
+
+ // 璇剧▼淇℃伅
+ .course-info {
+ display: flex;
+ margin-bottom: 8px;
+ align-items: flex-start;
+ }
+
+ .info-label {
+ font-size: 14px;
+ color: #666;
+ width: 80px;
+ flex-shrink: 0;
+ }
+
+ .info-value {
+ font-size: 14px;
+ color: #333;
+ flex: 1;
+ line-height: 1.4;
+ }
+
+ // 璇剧▼瀵煎嚭鎸夐挳
+ .course-export {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ // 绌虹姸鎬�
+ .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 60px 0;
+ }
+
+ .empty-course {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 30px 0;
+ color: #999;
+ font-size: 14px;
+ }
+
+ .empty-text {
+ font-size: 14px;
+ color: #999;
+ margin-top: 16px;
+ }
+ :deep(.u-tag--info) {
+ background-color: #c1c3c8;
+ border-width: 1px;
+ border-color: #c1c3c8;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/resultDetail.vue b/src/pages/safeProduction/safetyTrainingAssessment/resultDetail.vue
new file mode 100644
index 0000000..9fd10a1
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/resultDetail.vue
@@ -0,0 +1,388 @@
+<template>
+ <view class="result-detail">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="缁撴灉鏄庣粏"
+ @back="goBack" />
+ <!-- 鍐呭鍖哄煙 -->
+ <view class="content">
+ <!-- 璇剧▼璇︽儏 -->
+ <view class="section">
+ <view class="section-title">璇剧▼璇︽儏</view>
+ <view class="info-list">
+ <view class="info-item">
+ <text class="info-label">璇剧▼缂栧彿</text>
+ <text class="info-value">{{ currentTraining.courseCode || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鍐呭</text>
+ <text class="info-value">{{ currentTraining.trainingContent || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鐘舵��</text>
+ <text class="info-value">
+ <u-tag :type="currentTraining.state === 0 ? 'success' : (currentTraining.state === 1 ? 'warning' : 'info')">
+ {{ currentTraining.state === 0 ? '鏈紑濮�' : (currentTraining.state === 1 ? '杩涜涓�' : '宸茬粨鏉�') }}
+ </u-tag>
+ </text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅璁插笀</text>
+ <text class="info-value">{{ currentTraining.trainingLecturer || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅寮�濮嬫椂闂�</text>
+ <text class="info-value">{{ currentTraining.trainingDate + ' ' + currentTraining.openingTime || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅缁撴潫鏃堕棿</text>
+ <text class="info-value">{{ currentTraining.trainingDate + ' ' + currentTraining.endTime || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鐩爣</text>
+ <text class="info-value">{{ currentTraining.trainingObjectives || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍙傚姞瀵硅薄</text>
+ <text class="info-value">{{ currentTraining.participants || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鏂瑰紡</text>
+ <text class="info-value">{{ getTrainingModeLabel(currentTraining.trainingMode) || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鍦扮偣</text>
+ <text class="info-value">{{ currentTraining.placeTraining || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">璇炬椂</text>
+ <text class="info-value">{{ currentTraining.classHour || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">璇剧▼瀛﹀垎</text>
+ <text class="info-value">{{ currentTraining.projectCredits || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鎶ュ悕浜烘暟</text>
+ <text class="info-value">{{ currentTraining.nums || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ <!-- 璇剧▼璇勪环 -->
+ <view class="section">
+ <view class="section-title">璇剧▼璇勪环</view>
+ <u-form ref="formRef"
+ label-width="90"
+ :model="endform">
+ <u-form-item label="璇勪环浜�">
+ <u-input v-model="endform.assessmentUserName"
+ disabled
+ placeholder="璇烽�夋嫨璇勪环浜�" />
+ </u-form-item>
+ <u-form-item label="璇勪环鏃堕棿">
+ <u-input v-model="endform.assessmentDate"
+ disabled
+ placeholder="璇烽�夋嫨璇勪环鏃堕棿" />
+ </u-form-item>
+ <u-form-item label="鑰冩牳鏂瑰紡">
+ <u-input v-model="endform.assessmentMethod"
+ placeholder="璇疯緭鍏ヨ�冩牳鏂瑰紡" />
+ </u-form-item>
+ <u-form-item label="缁煎悎璇勪环">
+ <u-input v-model="endform.comprehensiveAssessment"
+ placeholder="璇疯緭鍏ユ湰娆¤绋嬬患鍚堣瘎浠�" />
+ </u-form-item>
+ <u-form-item label="鍩硅鎽樿">
+ <u-textarea v-model="endform.trainingAbstract"
+ :rows="4"
+ placeholder="璇疯緭鍏ュ煿璁憳瑕�" />
+ </u-form-item>
+ </u-form>
+ </view>
+ <!-- 鑰冩牳鍒楄〃 -->
+ <view class="section">
+ <view class="section-title">鑰冩牳鍒楄〃</view>
+ <view class="assessment-list">
+ <view v-for="(item, index) in endform.safeTrainingDetailsDtoList"
+ :key="index"
+ class="assessment-item">
+ <view class="assessment-info">
+ <view class="info-row">
+ <text class="label">濮撳悕锛�</text>
+ <text class="value">{{ item.nickName || '-' }}</text>
+ </view>
+ <view class="info-row">
+ <text class="label">鐢佃瘽鍙风爜锛�</text>
+ <text class="value">{{ item.phonenumber || '-' }}</text>
+ </view>
+ </view>
+ <view class="assessment-result">
+ <text class="result-label">鑰冩牳缁撴灉锛�</text>
+ <u-radio-group v-model="endform.safeTrainingDetailsDtoList[index].examinationResults"
+ :key="index"
+ size="default">
+ <u-radio label="鍚堟牸"
+ name="鍚堟牸"></u-radio>
+ <u-radio label="涓嶅悎鏍�"
+ name="涓嶅悎鏍�"></u-radio>
+ </u-radio-group>
+ </view>
+ </view>
+ </view>
+ </view>
+ <!-- 鎻愪氦鎸夐挳 -->
+ <view class="submit-btn">
+ <u-button type="primary"
+ @click="submitForm"
+ :loading="loading">鎻愪氦</u-button>
+ </view>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import { useDict } from "@/utils/dict";
+ import dayjs from "dayjs";
+ import useUserStore from "@/store/modules/user";
+ import {
+ safeTrainingGet,
+ safeTrainingSave,
+ } from "@/api/safeProduction/safetyTrainingAssessment";
+
+ // 鑾峰彇瀛楀吀鏁版嵁
+ const { safe_training_methods } = useDict("safe_training_methods");
+
+ // 椤甸潰鐘舵��
+ const loading = ref(false);
+ const currentTraining = ref({});
+ const endform = ref({
+ assessmentUserId: "",
+ assessmentUserName: "",
+ assessmentMethod: "",
+ assessmentDate: "",
+ comprehensiveAssessment: "",
+ trainingAbstract: "",
+ safeTrainingFileList: [],
+ safeTrainingDetailsDtoList: [],
+ });
+
+ // 鑾峰彇鍩硅鏂瑰紡鏍囩
+ const getTrainingModeLabel = val => {
+ if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) {
+ return val;
+ }
+ const item = safe_training_methods.value.find(
+ i => String(i.value) === String(val)
+ );
+ return item ? item.label : val;
+ };
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+ // 鎻愪氦琛ㄥ崟
+ const submitForm = () => {
+ // 楠岃瘉鑰冩牳缁撴灉
+ for (let i = 0; i < endform.value.safeTrainingDetailsDtoList.length; i++) {
+ const item = endform.value.safeTrainingDetailsDtoList[i];
+ if (!item.examinationResults) {
+ uni.showToast({
+ title: `璇烽�夋嫨${item.nickName}鐨勮�冩牳缁撴灉`,
+ icon: "none",
+ });
+ return;
+ }
+ }
+
+ loading.value = true;
+ safeTrainingSave(endform.value)
+ .then(res => {
+ loading.value = false;
+ if (res.code === 200) {
+ uni.showToast({ title: "鎻愪氦鎴愬姛", icon: "success" });
+ setTimeout(() => {
+ goBack();
+ }, 500);
+ } else {
+ uni.showToast({ title: res.msg || "鎻愪氦澶辫触", icon: "none" });
+ }
+ })
+ .catch(() => {
+ loading.value = false;
+ uni.showToast({ title: "鎻愪氦澶辫触锛岃閲嶈瘯", icon: "none" });
+ });
+ };
+
+ // 椤甸潰鍔犺浇
+ onLoad(() => {
+ const trainingId = uni.getStorageSync("safetyTrainingResultId");
+ const trainingNums = uni.getStorageSync("safetyTrainingResultNums");
+
+ if (trainingId) {
+ getTrainingDetail(trainingId, trainingNums);
+ }
+ });
+ const userStore = useUserStore();
+ const getuserInfo = () => {
+ const userInfo = {
+ id: "",
+ nickName: "",
+ };
+ userStore.getInfo().then(res => {
+ userInfo.id = res.user.userId;
+ userInfo.nickName = res.user.nickName;
+ endform.value.assessmentUserName = res.user.nickName;
+ endform.value.assessmentUserId = res.user.userId;
+ });
+ return userInfo;
+ };
+
+ // 鑾峰彇鍩硅璇︽儏
+ const getTrainingDetail = (id, trainingNums) => {
+ loading.value = true;
+ safeTrainingGet({ id })
+ .then(res => {
+ loading.value = false;
+ if (res.code === 200) {
+ currentTraining.value = res.data;
+ currentTraining.value.nums = trainingNums;
+
+ endform.value = { ...res.data };
+ // 璁剧疆榛樿鍊�
+ if (!endform.value.assessmentUserId) {
+ getuserInfo();
+ }
+
+ endform.value.assessmentDate = endform.value.assessmentDate
+ ? dayjs(endform.value.assessmentDate).format("YYYY-MM-DD")
+ : dayjs().format("YYYY-MM-DD");
+ endform.value.safeTrainingDetailsDtoList =
+ endform.value.safeTrainingDetailsDtoList || [];
+ } else {
+ uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "none" });
+ }
+ })
+ .catch(() => {
+ loading.value = false;
+ uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "none" });
+ });
+ };
+</script>
+
+<style scoped lang="scss">
+ .result-detail {
+ min-height: 100vh;
+ background: #f8f9fa;
+ }
+
+ .content {
+ padding: 16px;
+ }
+
+ .section {
+ background: #fff;
+ border-radius: 8px;
+ padding: 16px;
+ margin-bottom: 16px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ }
+
+ .section-title {
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 16px;
+ color: #333;
+ }
+
+ .info-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .info-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .info-item:last-child {
+ border-bottom: none;
+ padding-bottom: 0;
+ }
+
+ .info-label {
+ font-size: 14px;
+ color: #666;
+ width: 100px;
+ }
+
+ .info-value {
+ flex: 1;
+ font-size: 14px;
+ color: #333;
+ text-align: right;
+ }
+
+ .assessment-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .assessment-item {
+ background: #f8f9fa;
+ border-radius: 8px;
+ padding: 16px;
+ border: 1px solid #e8e8e8;
+ }
+
+ .assessment-info {
+ margin-bottom: 12px;
+ }
+
+ .info-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 8px;
+ }
+
+ .info-row:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ font-size: 14px;
+ color: #666;
+ min-width: 80px;
+ }
+
+ .value {
+ font-size: 14px;
+ color: #333;
+ flex: 1;
+ }
+
+ .assessment-result {
+ display: flex;
+ align-items: center;
+ padding-top: 8px;
+ border-top: 1px solid #e8e8e8;
+ }
+
+ .result-label {
+ font-size: 14px;
+ color: #666;
+ min-width: 80px;
+ }
+
+ .submit-btn {
+ margin-top: 24px;
+ margin-bottom: 32px;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/safeProduction/safetyTrainingAssessment/view.vue b/src/pages/safeProduction/safetyTrainingAssessment/view.vue
new file mode 100644
index 0000000..df8b991
--- /dev/null
+++ b/src/pages/safeProduction/safetyTrainingAssessment/view.vue
@@ -0,0 +1,171 @@
+<template>
+ <view class="danger-investigation-view">
+ <PageHeader title="鍩硅璇︽儏"
+ @back="goBack" />
+ <!-- 鍐呭瀹瑰櫒 -->
+ <view class="detail-content">
+ <!-- 鍩硅淇℃伅 -->
+ <view class="info-section">
+ <!-- <view class="section-title">鍩硅淇℃伅</view> -->
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="info-label">璇剧▼缂栧彿</text>
+ <text class="info-value">{{ form.courseCode || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鏃ユ湡</text>
+ <text class="info-value">{{ form.trainingDate || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">寮�濮嬫椂闂�</text>
+ <text class="info-value">{{ form.openingTime || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">缁撴潫鏃堕棿</text>
+ <text class="info-value">{{ form.endTime || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鐩爣</text>
+ <text class="info-value">{{ form.trainingObjectives || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍙傚姞瀵硅薄</text>
+ <text class="info-value">{{ form.participants || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鍐呭</text>
+ <text class="info-value">{{ form.trainingContent || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅璁插笀</text>
+ <text class="info-value">{{ form.trainingLecturer || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">椤圭洰瀛﹀垎</text>
+ <text class="info-value">{{ form.projectCredits || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鏂瑰紡</text>
+ <text class="info-value">{{ getTrainingModeLabel(form.trainingMode) || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">鍩硅鍦扮偣</text>
+ <text class="info-value">{{ form.placeTraining || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="info-label">璇炬椂</text>
+ <text class="info-value">{{ form.classHour || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import { useDict } from "@/utils/dict";
+ // 鏇挎崲 toast 鏂规硶
+ defineOptions({ name: "safety-training-view" });
+ const showToast = message => {
+ uni.showToast({ title: message, icon: "none" });
+ };
+
+ // 鑾峰彇瀛楀吀鏁版嵁
+ const { safe_training_methods } = useDict("safe_training_methods");
+
+ // 鑾峰彇鍩硅鏂瑰紡鏍囩
+ const getTrainingModeLabel = val => {
+ if (!safe_training_methods || !Array.isArray(safe_training_methods.value)) {
+ return val;
+ }
+ const item = safe_training_methods.value.find(
+ i => String(i.value) === String(val)
+ );
+ return item ? item.label : val;
+ };
+
+ // 鍩硅淇℃伅
+ const form = ref({});
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ onLoad(() => {
+ // 浠庢湰鍦板瓨鍌ㄨ幏鍙栧煿璁俊鎭�
+ const safetyTraining = uni.getStorageSync("safetyTraining");
+ if (safetyTraining) {
+ form.value = safetyTraining;
+ }
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+
+ .danger-investigation-view {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 2rem;
+ }
+
+ .detail-content {
+ padding: 20px;
+ }
+
+ .info-section {
+ background: #ffffff;
+ border-radius: 12px;
+ padding: 24px;
+ margin-bottom: 24px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ }
+
+ .section-title {
+ padding: 1rem;
+ font-size: 1rem;
+ font-weight: 500;
+ color: #303133;
+ background: #f5f5f5;
+ border-bottom: 1px solid #e4e7ed;
+ }
+
+ .info-content {
+ padding: 1rem;
+ }
+ .info-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+ }
+ .info-item {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+ .info-item:last-child {
+ margin-bottom: 0;
+ }
+
+ .info-label {
+ font-size: 14px;
+ color: #909399;
+ }
+
+ .info-value {
+ font-size: 14px;
+ color: #303133;
+ word-break: break-all;
+ }
+
+ .description-content {
+ padding: 1rem;
+ font-size: 0.875rem;
+ color: #303133;
+ line-height: 1.5;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/sales/invoiceLedger/index.vue b/src/pages/sales/invoiceLedger/index.vue
index 04ebbc2..d5d0b17 100644
--- a/src/pages/sales/invoiceLedger/index.vue
+++ b/src/pages/sales/invoiceLedger/index.vue
@@ -8,7 +8,7 @@
<view class="search-bar">
<view class="search-input">
<up-input class="search-text"
- placeholder="璇疯緭鍏ュ鎴峰悕绉�/鍚堝悓鍙锋悳绱�"
+ placeholder="璇疯緭鍏ュ鎴峰悕绉�/閿�鍞悎鍚屽彿鎼滅储"
v-model="searchForm.searchText"
@change="handleQuery"
clearable />
@@ -45,10 +45,6 @@
<view class="detail-row">
<text class="detail-label">瀹㈡埛鍚嶇О</text>
<text class="detail-value">{{ item.customerName }}</text>
- </view>
- <view class="detail-row">
- <text class="detail-label">瀹㈡埛鍚堝悓鍙�</text>
- <text class="detail-value">{{ item.customerContractNo }}</text>
</view>
<view class="detail-row">
<text class="detail-label">椤圭洰</text>
diff --git a/src/pages/sales/invoicingRegistration/index.vue b/src/pages/sales/invoicingRegistration/index.vue
index b30d1ad..7d5bcbb 100644
--- a/src/pages/sales/invoicingRegistration/index.vue
+++ b/src/pages/sales/invoicingRegistration/index.vue
@@ -44,10 +44,6 @@
<text class="detail-value">{{ item.customerName }}</text>
</view>
<view class="detail-row">
- <text class="detail-label">瀹㈡埛鍚堝悓鍙�</text>
- <text class="detail-value">{{ item.customerContractNo }}</text>
- </view>
- <view class="detail-row">
<text class="detail-label">涓氬姟鍛�</text>
<text class="detail-value">{{ item.salesman }}</text>
</view>
diff --git a/src/pages/sales/invoicingRegistration/view.vue b/src/pages/sales/invoicingRegistration/view.vue
index 85f1001..72828ff 100644
--- a/src/pages/sales/invoicingRegistration/view.vue
+++ b/src/pages/sales/invoicingRegistration/view.vue
@@ -12,10 +12,6 @@
<text class="info-value">{{ form.salesContractNo }}</text>
</view>
<view class="info-item">
- <text class="info-label">瀹㈡埛鍚堝悓鍙�</text>
- <text class="info-value highlight">{{ form.customerContractNo }}</text>
- </view>
- <view class="info-item">
<text class="info-label">瀹㈡埛鍚嶇О</text>
<text class="info-value">{{ form.customerName }}</text>
</view>
@@ -123,7 +119,6 @@
const form = ref({
id: '',
salesContractNo: '',
- customerContractNo: '',
customerId: '',
customerName: '',
projectName: '',
diff --git a/src/pages/sales/receiptPayment/index.vue b/src/pages/sales/receiptPayment/index.vue
index 1f222f6..ffd154a 100644
--- a/src/pages/sales/receiptPayment/index.vue
+++ b/src/pages/sales/receiptPayment/index.vue
@@ -141,7 +141,6 @@
const searchForm = ref({
customerName: "",
status: true,
- customerContractNo: "",
projectName: "",
});
// 鑾峰彇鏍囩鏍峰紡绫�
diff --git a/src/pages/sales/receiptPaymentHistory/index.vue b/src/pages/sales/receiptPaymentHistory/index.vue
index 1242c2b..0d148b5 100644
--- a/src/pages/sales/receiptPaymentHistory/index.vue
+++ b/src/pages/sales/receiptPaymentHistory/index.vue
@@ -56,10 +56,6 @@
<up-divider></up-divider>
<view class="item-details">
<view class="detail-row">
- <text class="detail-label">瀹㈡埛鍚堝悓鍙�</text>
- <text class="detail-value">{{ item.customerContractNo }}</text>
- </view>
- <view class="detail-row">
<text class="detail-label">瀹㈡埛鍚嶇О</text>
<text class="detail-value">{{ item.customerName }}</text>
</view>
diff --git a/src/pages/sales/receiptPaymentLedger/detail.vue b/src/pages/sales/receiptPaymentLedger/detail.vue
index 5786eea..b494332 100644
--- a/src/pages/sales/receiptPaymentLedger/detail.vue
+++ b/src/pages/sales/receiptPaymentLedger/detail.vue
@@ -54,6 +54,10 @@
<text class="detail-label">搴旀敹閲戦(鍏�)</text>
<text class="detail-value danger">{{ formatAmount(item.unReceiptPaymentAmount) }}</text>
</view>
+ <view class="detail-row">
+ <text class="detail-label">鍙戠敓鏃ユ湡</text>
+ <text class="detail-value">{{ item.receiptPaymentDate }}</text>
+ </view>
</view>
</view>
</view>
diff --git a/src/pages/sales/salesAccount/index.vue b/src/pages/sales/salesAccount/index.vue
index 8e3fdf6..250447d 100644
--- a/src/pages/sales/salesAccount/index.vue
+++ b/src/pages/sales/salesAccount/index.vue
@@ -79,12 +79,21 @@
</view>
</view>
<up-divider></up-divider>
- <u-button class="detail-button"
+ <view class="detail-buttons">
+ <u-button class="detail-button"
size="small"
type="primary"
@click="openOut(item)">
鍙戣揣鐘舵��
</u-button>
+ <u-button class="detail-button"
+ size="small"
+ type="error"
+ plain
+ @click.stop="handleDelete(item)">
+ 鍒犻櫎
+ </u-button>
+ </view>
</view>
</view>
</view>
@@ -106,7 +115,11 @@
<script setup>
import { ref } from "vue";
import { onShow } from "@dcloudio/uni-app";
- import { ledgerListPage } from "@/api/salesManagement/salesLedger";
+ import {
+ ledgerListPage,
+ delLedger,
+ productList,
+ } from "@/api/salesManagement/salesLedger";
import useUserStore from "@/store/modules/user";
import PageHeader from "@/components/PageHeader.vue";
const userStore = useUserStore();
@@ -125,6 +138,20 @@
// 閿�鍞彴璐︽暟鎹�
const ledgerList = ref([]);
+
+ // 鍒ゆ柇鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝�
+ const hasShippedProducts = products => {
+ if (!products || products.length === 0) return false;
+ return products.some(p => {
+ const statusStr = (p.shippingStatus ?? "").toString();
+ // 鍖呭惈鈥滃彂璐р�濇垨鏈夊彂璐ф棩鏈�/杞︾墝鍙疯涓哄凡鍙戣揣
+ return (
+ statusStr.includes("鍙戣揣") ||
+ !!p.shippingDate ||
+ !!p.shippingCarNumber
+ );
+ });
+ };
// 杩斿洖涓婁竴椤�
const goBack = () => {
@@ -151,6 +178,55 @@
uni.setStorageSync("outData", JSON.stringify(item));
uni.navigateTo({
url: "/pages/sales/salesAccount/out",
+ });
+ };
+
+ // 鍒犻櫎鍗曟潯閿�鍞彴璐�
+ const handleDelete = async row => {
+ if (!row || !row.id) return;
+
+ // 鑾峰彇浜у搧鍒楄〃锛岀敤浜庡垽鏂槸鍚﹀凡鍙戣揣
+ let products = row.children && row.children.length > 0 ? row.children : null;
+ if (!products) {
+ try {
+ const res = await productList({ salesLedgerId: row.id, type: 1 });
+ products = res.data || res.records || [];
+ } catch (e) {
+ products = [];
+ }
+ }
+
+ if (hasShippedProducts(products)) {
+ uni.showToast({
+ title: "宸插彂璐�/鍙戣揣瀹屾垚鐨勯攢鍞鍗曚笉鑳藉垹闄�",
+ icon: "none",
+ });
+ return;
+ }
+
+ uni.showModal({
+ title: "鍒犻櫎纭",
+ content: "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�",
+ success: async res => {
+ if (res.confirm) {
+ try {
+ showLoadingToast("澶勭悊涓�...");
+ await delLedger([row.id]);
+ closeToast();
+ uni.showToast({
+ title: "鍒犻櫎鎴愬姛",
+ icon: "success",
+ });
+ getList();
+ } catch (e) {
+ closeToast();
+ uni.showToast({
+ title: "鍒犻櫎澶辫触锛岃閲嶈瘯",
+ icon: "none",
+ });
+ }
+ }
+ },
});
};
// 澶勭悊鍙拌处淇℃伅鎿嶄綔锛堟煡鐪�/缂栬緫/鏂板锛�
@@ -209,4 +285,9 @@
<style scoped lang="scss">
@import "@/styles/sales-common.scss";
+ .detail-buttons {
+ display: flex;
+ gap: 10px;
+ justify-content: space-between;
+ }
</style>
--
Gitblit v1.9.3