wangqi 1 semana atrás
pai
commit
d3afa79757

+ 265
- 0
src/components/AttachmentS3ImageReturnURL.vue Ver arquivo

@@ -0,0 +1,265 @@
1
+<template>
2
+	<div style="padding: 5px;flex: 1">
3
+		<div>
4
+			<van-uploader
5
+        :disabled="readonly"
6
+        v-model="fileListTemp"
7
+				accept=".txt,.pdf,.doc,.docx,.xls,.xlsx,.wps,.et,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/*"
8
+				:after-read="uploadFile"
9
+        upload-icon="plus"
10
+        :show-upload="true"
11
+        :before-delete="onDelete"
12
+      />
13
+		</div>
14
+	</div>
15
+</template>
16
+
17
+
18
+<script setup>
19
+	import { ref, onMounted, getCurrentInstance, watch } from 'vue'
20
+  import { showFailToast, showSuccessToast, showConfirmDialog } from 'vant';
21
+	const { proxy } = getCurrentInstance()
22
+
23
+  const emit = defineEmits(['update:firstFileUrl'])
24
+
25
+	const props = defineProps({
26
+		fId: {
27
+			type: String,
28
+			default: () => ''
29
+		},
30
+		value1: {
31
+			type: String,
32
+			default: () => null
33
+		},
34
+		value2: {
35
+			type: String,
36
+			default: () => null
37
+		},
38
+		value3: {
39
+			type: String,
40
+			default: () => null
41
+		},
42
+		value4: {
43
+			type: String,
44
+			default: () => null
45
+		},
46
+		value5: {
47
+			type: String,
48
+			default: () => null
49
+		},
50
+		selectButton: {
51
+			type: Boolean,
52
+			default: () => true
53
+		},
54
+		deleteButton: {
55
+			type: Boolean,
56
+			default: () => true
57
+		},
58
+		readonly: {
59
+			type: Boolean,
60
+			default: () => false
61
+		},
62
+		isFile: {
63
+			type: Boolean,
64
+			default: () => false
65
+		}
66
+	})
67
+
68
+	onMounted(() => {
69
+		getTableData()
70
+	})
71
+
72
+	const tableData = ref([])
73
+	const getTableData = () => {
74
+		//携带自定义参数
75
+		var url = 'framework/Common/queryFileWithValues'
76
+		var param = {
77
+			fId: props.fId, //必填
78
+			value1: props.value1, //非必填
79
+			value2: props.value2, //非必填
80
+			value3: props.value3, //非必填
81
+			value4: props.value4, //非必填
82
+			value5: props.value5, //非必填
83
+		}
84
+		proxy.$axios.get(url, param).then(response => {
85
+			if (response.data.code === 0) {
86
+				tableData.value = response.data.data
87
+        fileListTemp.value = []
88
+        for (let item of tableData.value) {
89
+          fileListTemp.value.push({
90
+            id: item.id,
91
+            url: import.meta.env.VITE_BASE_API + 'framework/Common/downloadFileS3?bucket=' + bucket.value + '&id=' + item.id + '&fullfilename=' + Date.now() + item.fileName
92
+          })
93
+        }
94
+        if (fileListTemp.value.length > 0) {
95
+          emit('update:firstFileUrl', fileListTemp.value[0].url)
96
+        } else {
97
+          emit('update:firstFileUrl', null) // 或 ''
98
+        }
99
+
100
+			} else {
101
+				showFailToast('失败!' + response.data.msg)
102
+			}
103
+		})
104
+	}
105
+	const headers = ref({
106
+		token: localStorage.getItem('token'),
107
+		userId: localStorage.getItem('userId')
108
+	})
109
+	const fileListTemp = ref([])
110
+	const bucket = ref(import.meta.env.VITE_BUCKET)
111
+
112
+	/* 转成blob */
113
+	import {
114
+		atob
115
+	} from 'js-base64';
116
+
117
+	watch(props, (newVal, oldVal) => {
118
+		getTableData()
119
+	})
120
+
121
+	const uploadFile = (file) => {
122
+		const formData = new FormData()
123
+		formData.append('fId', props.fId);
124
+		formData.append('bucket', bucket.value);
125
+		formData.append('value1', props.value1);
126
+		formData.append('value2', props.value2);
127
+		formData.append('value3', props.value3);
128
+		formData.append('value4', props.value4);
129
+		formData.append('value5', props.value5);
130
+		formData.append('file', file.file);
131
+		formData.append('fileName', file.file.name);
132
+		var url = 'framework/Common/uploadFileS3'
133
+		proxy.$axios.post(url, formData, 'multipart/form-data').then(response => {
134
+			showSuccessToast('上传成功')
135
+			getTableData()
136
+		}).catch(error => {
137
+			showFailToast('上传失败' + res.data.msg)
138
+		});
139
+	}
140
+
141
+	/* 在线删除 */
142
+	const showDialogVisible = ref(false)
143
+	const deleteInfo = ref()
144
+	const handleDelete = (row) => {
145
+		showDialogVisible.value = true
146
+		deleteInfo.value = row
147
+	}
148
+
149
+	const onDelete = (file) => {
150
+    console.log(file);
151
+    showConfirmDialog({
152
+      title: '删除照片',
153
+      message:
154
+        '确定删除该照片吗?',
155
+    }).then(() => {
156
+        let url = 'framework/Common/removeFile'
157
+        let param = {
158
+          id: file.id
159
+        }
160
+        proxy.$axios.post(url, param).then(response => {
161
+          if (response.data.code === 0) {
162
+            showSuccessToast('删除成功!')
163
+            getTableData()
164
+          } else {
165
+            showFailToast('删除失败;' + response.data.msg)
166
+          }
167
+        });
168
+        return true
169
+      }).catch(() => {
170
+        return false
171
+      });
172
+	}
173
+
174
+	// 获取文件图标类名
175
+	const getFileIconClass = (fileType) => {
176
+		if (fileType === 'pdf') return 'pdf-icon';
177
+		if (fileType === 'image' || fileType === 'jpg' || fileType === 'png' || fileType === 'gif')
178
+			return 'image-icon';
179
+		if (fileType === 'doc' || fileType === 'docx') return 'doc-icon';
180
+		if (fileType === 'xls' || fileType === 'xlsx') return 'excel-icon';
181
+		if (fileType === 'txt') return 'text-icon';
182
+		return 'other-icon';
183
+	}
184
+
185
+	// 获取文件图标
186
+	const getFileIcon = (fileType) => {
187
+		if (fileType === 'pdf') return 'description';
188
+		if (fileType === 'image' || fileType === 'jpg' || fileType === 'png' || fileType === 'gif') return 'photo-o';
189
+		if (fileType === 'doc' || fileType === 'docx') return 'notes-o';
190
+		if (fileType === 'xls' || fileType === 'xlsx') return 'chart-trending-o';
191
+		if (fileType === 'txt') return 'document';
192
+		return 'description';
193
+	}
194
+
195
+	const convertBytesToSize = (bytes) => {
196
+		const kb = 1024;
197
+		const mb = kb * 1024;
198
+
199
+		if (bytes < kb) return bytes + ' B';
200
+		else if (bytes < mb) return (bytes / kb).toFixed(2) + ' KB';
201
+		else return (bytes / mb).toFixed(2) + ' MB';
202
+	}
203
+</script>
204
+
205
+<style scoped>
206
+	* {
207
+		box-sizing: border-box;
208
+		margin: 0;
209
+		padding: 0;
210
+	}
211
+
212
+	body {
213
+		font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
214
+		background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
215
+		color: #333;
216
+		line-height: 1.6;
217
+		min-height: 100vh;
218
+	}
219
+
220
+	.header h1 {
221
+		font-size: 2.5rem;
222
+		color: #1989fa;
223
+		margin-bottom: 10px;
224
+		text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
225
+	}
226
+
227
+	.header p {
228
+		font-size: 1.1rem;
229
+		color: #666;
230
+		max-width: 600px;
231
+		margin: 0 auto;
232
+	}
233
+
234
+	.section-title i {
235
+		margin-right: 10px;
236
+		font-size: 1.6rem;
237
+	}
238
+
239
+	.table-row {
240
+		background-color: white;
241
+		border-radius: 8px;
242
+		margin-bottom: 8px;
243
+		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
244
+		transition: transform 0.2s ease, box-shadow 0.2s ease;
245
+		align-items: center;
246
+	}
247
+
248
+	.table-row:hover {
249
+		transform: translateX(5px);
250
+		box-shadow: 0 5px 15px rgba(25, 137, 250, 0.15);
251
+	}
252
+
253
+	.file-name {
254
+		font-weight: 500;
255
+		white-space: nowrap;
256
+		overflow: hidden;
257
+		text-overflow: ellipsis;
258
+	}
259
+
260
+	.action-buttons {
261
+		display: flex;
262
+		gap: 10px;
263
+		justify-content: flex-start;
264
+	}
265
+</style>

+ 50
- 0
src/router/index.ts Ver arquivo

@@ -599,6 +599,56 @@ const router = createRouter({
599 599
 			name: 'accidentJuBaoLedger',
600 600
 			component: () => import('@/view/accidentManager/accidentJuBaoLedger/index.vue')
601 601
 		},
602
+		{
603
+			path: '/knowledge/accident',
604
+			name: '事故案例',
605
+			component: () => import('@/view/knowledge/accident.vue')
606
+		},
607
+		{
608
+			path: '/accidentList',
609
+			name: '事故案例编辑',
610
+			component: () => import('@/view/knowledge/accidentList.vue')
611
+		},
612
+		{
613
+			path: '/knowledge/manager',
614
+			name: '管理案例',
615
+			component: () => import('@/view/knowledge/manager.vue')
616
+		},
617
+		{
618
+			path: '/managerList',
619
+			name: '管理案例编辑',
620
+			component: () => import('@/view/knowledge/managerList.vue')
621
+		},
622
+		{
623
+			path: '/knowledge/Culture',
624
+			name: '安全文化',
625
+			component: () => import('@/view/knowledge/Culture.vue')
626
+		},
627
+		{
628
+			path: '/CultureList',
629
+			name: '安全文化编辑',
630
+			component: () => import('@/view/knowledge/CultureList.vue')
631
+		},
632
+		{
633
+			path: '/knowledge/project',
634
+			name: '项目案例库',
635
+			component: () => import('@/view/knowledge/project.vue')
636
+		},
637
+		{
638
+			path: '/projectList',
639
+			name: '项目案例库编辑',
640
+			component: () => import('@/view/knowledge/projectList.vue')
641
+		},
642
+		{
643
+			path: '/moneySafe/safeMoneyManagement',
644
+			name: '安环费用管理',
645
+			component: () => import('@/view/moneySafe/safeMoneyManagement.vue')
646
+		},
647
+		{
648
+			path: '/safeMoneyManagementList',
649
+			name: '安环费用管理编辑',
650
+			component: () => import('@/view/moneySafe/safeMoneyManagementList.vue')
651
+		}
602 652
 	]
603 653
 })
604 654
 

+ 35
- 1
src/view/Home2.vue Ver arquivo

@@ -237,6 +237,40 @@
237 237
         </van-grid-item>
238 238
       </van-grid>
239 239
     </div>
240
+    <div class="card">
241
+      <div class="title">知识共享库</div>
242
+      <van-grid :border="false" :column-num="4" v-if="showCheckTakeN">
243
+        <van-grid-item to="/knowledge/accident">
244
+          <img src="../../public/images/zd.png" width="45rpx" />
245
+          <span class="vanicon_text">事故案例</span>
246
+        </van-grid-item>
247
+        <van-grid-item to="/notice" v-if="showCheckTakeN">
248
+          <img src="../../public/images/yj.png" width="45rpx" />
249
+          <span class="vanicon_text">通知公告</span>
250
+        </van-grid-item>
251
+        <van-grid-item to="/knowledge/manager">
252
+          <img src="../../public/images/zd.png" width="45rpx" />
253
+          <span class="vanicon_text">管理案例</span>
254
+        </van-grid-item>
255
+        <van-grid-item to="/knowledge/Culture">
256
+          <img src="../../public/images/zd.png" width="45rpx" />
257
+          <span class="vanicon_text">安全环保文化</span>
258
+        </van-grid-item>
259
+        <van-grid-item to="/knowledge/project">
260
+          <img src="../../public/images/zd.png" width="45rpx" />
261
+          <span class="vanicon_text">项目案例库</span>
262
+        </van-grid-item>
263
+      </van-grid>
264
+    </div>
265
+    <div class="card">
266
+      <div class="title">安环费用管理</div>
267
+      <van-grid :border="false" :column-num="4" v-if="showCheckTakeN">
268
+        <van-grid-item to="/moneySafe/safeMoneyManagement">
269
+          <img src="../../public/images/aq.png" width="45rpx" />
270
+          <span class="vanicon_text">安环费用管理</span>
271
+        </van-grid-item>
272
+      </van-grid>
273
+    </div>
240 274
 
241 275
   </div>
242 276
 
@@ -261,7 +295,7 @@ const role = localStorage.getItem('role')[0].roleCode;
261 295
 if (role == 'SX0201' || role == 'SX0201' || role == 'SX0302' || role == 'SX0303') {
262 296
  showCheckTake.value = true;
263 297
 }
264
-if (userDesc == '贾俊臣' || userDesc == '张瑞楠') {
298
+if (userDesc == '贾俊臣' || userDesc == '张瑞楠' || userDesc == '刘焯') {
265 299
   showCheckTake.value = true;
266 300
   showCheckTakeN.value=true
267 301
 }

+ 0
- 93
src/view/accidentManager/accidentJuBao/accidentJuBao_edit/index.vue Ver arquivo

@@ -181,22 +181,6 @@ const checklistForm = ref({
181 181
   checklistType: '',
182 182
   hiddenDangerId: ''
183 183
 });
184
-const saveCheckInfo = async () => {
185
-  let url = '/safe/ActivityRecords/save';
186
-  if (checklistForm.value.checklistType === 'equipment') {
187
-    url = '/safe/EquipmentRecords/save';
188
-  }
189
-  const param = {
190
-    json: JSON.stringify(checklistForm.value)
191
-  };
192
-  const res = await proxy.$axios.post(url, param);
193
-  if (res.data.code === 0) {
194
-    showSuccessToast('新增排查记录成功!');
195
-    sessionStorage.setItem('inspectionResult', '已排查');
196
-  } else {
197
-    showFailToast('操作失败!' + res.data.msg);
198
-  }
199
-};
200 184
 
201 185
 const ifElseReadonly = ref(false)
202 186
 const title = ref('')
@@ -228,16 +212,6 @@ onMounted(async () => {
228 212
   }
229 213
 });
230 214
 
231
-const getTimeFormatter = (date) => {
232
-  const year = date.getFullYear();
233
-  const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需加 1
234
-  const day = String(date.getDate()).padStart(2, '0');
235
-  const hours = String(date.getHours()).padStart(2, '0');
236
-  const minutes = String(date.getMinutes()).padStart(2, '0');
237
-  const seconds = String(date.getSeconds()).padStart(2, '0');
238
-  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
239
-};
240
-
241 215
 /**表单*/
242 216
 const form = ref({
243 217
   seriousInjuryCount:'',//重伤人数
@@ -318,17 +292,6 @@ const onConfirmDatetime = () => {
318 292
   dateOrTime.value = false;
319 293
 };
320 294
 
321
-const showPicker2 = ref(false);
322
-
323
-const onConfirmYhdj = ({ selectedOptions }) => {
324
-  showPicker2.value = false;
325
-  form.value.hdLevel = selectedOptions[0].value;
326
-  console.log('选择的内容', form.value);
327
-};
328
-
329
-const yhdjs = ref([{ text: '一般隐患', value: '一般隐患' },
330
-  { text: '重大隐患', value: '重大隐患' }]
331
-);
332 295
 
333 296
 const formRef = ref(null);
334 297
 const qvxiao = () => {
@@ -360,16 +323,6 @@ const baocun = async () => {
360 323
   }
361 324
 };
362 325
 
363
-const handleChangeHdSelect = (value) => {
364
-  form.value.hdSelect = value;
365
-  if (value === '隐患举报') {
366
-    isStandardFlow.value = true;
367
-  } else if (value === '即查即改') {
368
-    isStandardFlow.value = false;
369
-  }
370
-  getYHID();
371
-};
372
-
373 326
 const guid = () => {
374 327
   function S4() {
375 328
     return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
@@ -377,27 +330,6 @@ const guid = () => {
377 330
 
378 331
   return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4());
379 332
 };
380
-/* 发现人 */
381
-const leaderKey = guid();
382
-const PopupDepartmentLeaderNameRef = ref();
383
-const handleDepartmentLeaderName = () => {
384
-  PopupDepartmentLeaderNameRef.value.open();
385
-};
386
-
387
-const codeAndDesc = ref([]);
388
-const getDepartmentLeaderName = (item) => {
389
-  form.value.discoverer = item.user.userCode;
390
-  form.value.discovererDesc = item.user.userDesc;
391
-  form.value.discovererDeptCode = item.dept.deptCode;
392
-  form.value.discovererDept = item.dept.deptName;
393
-};
394
-
395
-/* 其他发现人 */
396
-const leaderKey2 = guid();
397
-const PopupDepartmentLeaderNameRef2 = ref();
398
-const handleDepartmentLeaderName2 = () => {
399
-  PopupDepartmentLeaderNameRef2.value.open();
400
-};
401 333
 
402 334
 const codeAndDesc2 = ref([]);
403 335
 const getDepartmentLeaderName2 = (items) => {
@@ -707,29 +639,4 @@ const accidentLevel = computed(()=>{
707 639
   padding-bottom: 20px;
708 640
 }
709 641
 
710
-.radio-group {
711
-  display: flex;
712
-  background-color: white;
713
-  padding: 10px;
714
-  border-radius: 5px;
715
-  margin: 10px 0;
716
-  gap: 10px;
717
-}
718
-
719
-.radio-item {
720
-  padding: 8px 12px;
721
-  border: 1px solid #222;
722
-  border-radius: 4px;
723
-  background-color: white;
724
-  cursor: pointer;
725
-  transition: background-color 0.3s ease;
726
-  /* 添加过渡效果 */
727
-}
728
-
729
-.radio-item.active {
730
-  background-color: #4285f4;
731
-  /* 选中时的蓝色 */
732
-  color: white;
733
-  border-color: #4285f4;
734
-}
735 642
 </style>

+ 617
- 0
src/view/knowledge/Culture.vue Ver arquivo

@@ -0,0 +1,617 @@
1
+<template>
2
+  <div class="h5-container">
3
+    <van-nav-bar title="安全环保文化" @click-left="onClickLeft" @click-right="handAdd">
4
+      <template #right>
5
+        <van-icon name="add" size="25" color="#000" />
6
+      </template>
7
+    </van-nav-bar>
8
+    <van-search v-model="query.caseTitle" show-action placeholder="请输入案例标题" @search="onRefresh"
9
+                @cancel="handdelectTitle" />
10
+
11
+    <!-- 项目列表 -->
12
+    <van-pull-refresh v-model="isRefreshing" success-text="刷新成功" @refresh="onRefresh">
13
+      <van-list v-model:loading="isLoading" :finished="isFinished" finished-text="没有更多了" offset="200" @load="onLoad">
14
+        <div v-for="(item, idx) in resultData" :key="item.id">
15
+          <van-swipe-cell title-style="color: #007aff" style="height: 80px;" :ref="el => getSwipeCellRef(el, idx)">
16
+            <template #default>
17
+              <div class="swipe-cell-default">
18
+                <van-cell style="min-height: 100px; padding: 0 0 0 0; display: flex; align-items: flex-start;" @click="edits(item)">
19
+                  <template #title>
20
+                    <div class="cell-title">
21
+                      {{ item.activityTitle }}
22
+                    </div>
23
+                  </template>
24
+                  <template #label>
25
+                      <div>案例编号:{{ item.caseNumber }} </div>
26
+                      <div>案例类型:{{ item.caseType }}</div>
27
+                      <div> 浏览量:{{item.viewCount}}</div>
28
+
29
+<!--                    <div style="width: 112px" :class="getStatusClass(item.isFinish)">
30
+                      类型:
31
+                      <span v-if="item.isFinish === '待学习'" style="width: 200px">待学习</span>
32
+                      <span v-else-if="item.isFinish === '已学习'" style="width: 200px">已学习</span>
33
+                      <span v-else-if="item.isFinish === '已扣除'" style="width: 200px">已扣除</span>
34
+                    </div>-->
35
+                  </template>
36
+                </van-cell>
37
+                <div class="swipe-cell-default-icon">
38
+                  <van-icon v-if="openStatus[idx]" name="arrow-double-left" @click.stop="openSwipe(idx)" />
39
+                  <van-icon v-else name="arrow-double-right" @click.stop="closeSwipe(idx)" />
40
+                </div>
41
+              </div>
42
+            </template>
43
+
44
+            <template #right>
45
+              <van-button  square class="delete-button" text="删除" v-show="item.canDelete"  @click="handleDelete(item)" />
46
+            </template>
47
+          </van-swipe-cell>
48
+        </div>
49
+
50
+      </van-list>
51
+    </van-pull-refresh>
52
+
53
+    <!-- 删除确认弹窗 -->
54
+    <van-dialog v-model:show="deleteDialogVisible" show-cancel-button @confirm="confirmDelete">
55
+      <template #title>
56
+        <div>删除确认</div>
57
+      </template>
58
+      <div style="padding: 30px;">确定要删除该项目吗?</div>
59
+    </van-dialog>
60
+
61
+  </div>
62
+</template>
63
+
64
+<script setup>
65
+import { ref, reactive, onMounted, getCurrentInstance, nextTick, toRaw } from 'vue';
66
+import { Dialog, showDialog, showSuccessToast, showToast, Toast } from 'vant';
67
+
68
+import tools from '@/tools'
69
+
70
+const { proxy } = getCurrentInstance();
71
+
72
+const onClickLeft = () => {
73
+  history.back();
74
+};
75
+const headers = ref({
76
+  token: localStorage.getItem('token'),
77
+  userId: localStorage.getItem('userId'),
78
+  dept: JSON.parse(localStorage.getItem('dept'))[0].deptCode
79
+});
80
+const switchIconState = (idx) => {
81
+  openStatus.value[idx] = !openStatus.value[idx]
82
+  openStatus.value = new Array(resultData.value.length).fill(true);
83
+}
84
+
85
+// const onClickRight = () =>{
86
+//   searchShow.value = !searchShow.value;
87
+// }
88
+
89
+const searchShow = ref(false);
90
+const query = ref({
91
+  caseNumber:'',
92
+  caseTitle:'',
93
+})
94
+
95
+
96
+
97
+const tableData = ref([]);
98
+const selectedRows = ref([]);
99
+const dialogVisibleLook = ref(false);
100
+const deleteDialogVisible = ref(false);
101
+const currentDeleteItem = ref([]);
102
+const dialogVisible = ref(false);
103
+const dialogVisibleFile = ref(false);
104
+const date = ref(null);
105
+
106
+const kz = ref(true);
107
+import { useRouter } from 'vue-router';
108
+const router = useRouter();
109
+const handAdd =  () => {
110
+
111
+  router.push({ path: "/CultureList",
112
+    query: {
113
+      mark:-1
114
+    } });
115
+
116
+};
117
+const goaddPeo = (item) => {
118
+  router.push({
119
+    path: '/addPeo',
120
+    query: {
121
+      data: JSON.stringify(item)
122
+    }
123
+  })
124
+}
125
+
126
+const edits = (row) => {
127
+  const isOwner = String(row.addId) === currentUserId;
128
+  kz.value = true;
129
+  form.value = { ...row };
130
+  router.push({ path: "/CultureList",
131
+    query: {
132
+      mark:1,
133
+      data:JSON.stringify(form.value),
134
+      readOnly: !isOwner ? 'true' : undefined
135
+    } });
136
+  //浏览量
137
+  saveManagerRecord(form.value)
138
+};
139
+
140
+const saveManagerRecord = async (formValue) => {
141
+  const payload = formValue;
142
+  payload.viewCount = String((Number(payload.viewCount) || 0) + 1);
143
+
144
+  var url = '/sgsafe/Manager/saveCulture';
145
+  var param = {
146
+    json: JSON.stringify(payload)
147
+  };
148
+  proxy.$axios.post(url, param).then(response => {
149
+    if (response.data.code == '0') {
150
+      getTableData();
151
+    }
152
+  });
153
+};
154
+const form = ref({
155
+  caseNumber:'',
156
+  caseTitle:'',
157
+  caseSource:'',
158
+  accidentLevel:'',
159
+  accidentDept:'',
160
+  accidentLocation:'',
161
+  accidentTime:'',
162
+  accidentType:'',
163
+  accidentTags:'',
164
+  casualtyCount:'',
165
+  accidentSummary:'',
166
+  preventiveMeasures:'',
167
+  fileId:'',
168
+  viewCount:'',
169
+  downloadCount:''
170
+});
171
+
172
+
173
+const isRefreshing = ref(false);
174
+const isLoading = ref(false);
175
+const isFinished = ref(false);
176
+const currentPage = ref(1);
177
+const pageSize = ref(10);
178
+const totalRows = ref(0);
179
+const resultData = ref([]);
180
+
181
+const dept=localStorage.getItem("dept")[0].deptCode;
182
+const currentUserId = String(localStorage.getItem('userId'));
183
+const getTableData = async () => {
184
+  var url = '/sgsafe/Manager/queryCulture'
185
+  var param = {
186
+    page: currentPage.value,
187
+    rows: pageSize.value,
188
+    params: JSON.stringify(query.value)
189
+  }
190
+  const response = await proxy.$axios.get(url, param);
191
+  if (response.data.code == 0) {
192
+    tableData.value = response.data.data.records.map(item => ({
193
+      ...item,
194
+      canDelete: String(item.addId) === currentUserId
195
+    }));
196
+    console.log('列表数据',tableData.value)
197
+    totalRows.value = response.data.data.total;
198
+  } else {
199
+    showToast({
200
+      type: 'error',
201
+      message: '操作失败!' + response.data.msg
202
+    });
203
+  }
204
+};
205
+const ruleIds = ref([]);
206
+
207
+const onRefresh = () => {
208
+  basicReset();
209
+  onLoad();
210
+};
211
+
212
+//*************************************
213
+
214
+
215
+
216
+//定义字典集合
217
+const dicList = ref([])
218
+
219
+const getDicList = () => {
220
+  tools.dic.getDicList([ 'case_type','SEX', 'case_source','accident_level','accident_type','sgsafe_taccidentTags']).then((response => {
221
+    console.log(JSON.stringify(response.data.data))
222
+    dicList.value = response.data.data
223
+
224
+  }))
225
+}
226
+
227
+
228
+const onLoad = async () => {
229
+  if (isRefreshing.value) {
230
+    resultData.value = [];
231
+    currentPage.value = 1;
232
+    isRefreshing.value = false;
233
+  }
234
+
235
+  getDicList()
236
+
237
+
238
+
239
+
240
+
241
+  try {
242
+    await getTableData();
243
+
244
+    if (pageSize.value * currentPage.value < totalRows.value) {
245
+      resultData.value = [...resultData.value, ...tableData.value];
246
+      openStatus.value = new Array(resultData.value.length).fill(true);
247
+      currentPage.value++;
248
+
249
+    } else {
250
+      resultData.value = [...resultData.value, ...tableData.value];
251
+      openStatus.value = new Array(resultData.value.length).fill(true);
252
+      isFinished.value = true;
253
+    }
254
+
255
+    console.log('resultData',resultData.value)
256
+  } catch (error) {
257
+    console.log(error);
258
+    isFinished.value = true;
259
+  } finally {
260
+    isLoading.value = false;
261
+  }
262
+};
263
+/* 通用方法: 重置list数据 */
264
+const basicReset = () => {
265
+  isFinished.value = false;
266
+  isLoading.value = true;
267
+  currentPage.value = 1;
268
+  resultData.value = [];
269
+};
270
+
271
+/*onMounted(() => {
272
+  handleSearch();
273
+});
274
+
275
+const handleSearch = () => {
276
+/!*  currentPage.value = 1;
277
+  isFinished.value = false;
278
+  tableData.value = [];*!/
279
+  basicReset()
280
+  onLoad()
281
+};*/
282
+
283
+const handdelectNumber = () => {
284
+  query.value.caseNumber = '';
285
+  onRefresh()
286
+};
287
+
288
+const handdelectTitle = () => {
289
+  query.value.caseTitle = '';
290
+  onRefresh()
291
+};
292
+
293
+
294
+
295
+
296
+// 定义生成编号的函数
297
+const generateCode = () => {
298
+  // 获取当前日期并格式化为 YYYYMMDD
299
+  const now = new Date();
300
+  const year = now.getFullYear();
301
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需加1
302
+  const day = String(now.getDate()).padStart(2, '0');
303
+  const formattedDate = `${year}${month}${day}`;
304
+  // 时间部分:HHmmss
305
+  const hours = String(now.getHours()).padStart(2, '0');
306
+  const minutes = String(now.getMinutes()).padStart(2, '0');
307
+  const seconds = String(now.getSeconds()).padStart(2, '0');
308
+  const formattedTime = `${hours}${minutes}${seconds}`;
309
+
310
+  // 模拟生成三位流水号(可以根据需要替换为递增逻辑)
311
+  const sequenceNumber = Math.floor(Math.random() * 1000); // 随机生成 0-999
312
+  const paddedSequence = String(sequenceNumber).padStart(3, '0'); // 补零到三位
313
+
314
+  // 拼接编号
315
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
316
+};
317
+
318
+// 使用 ref 存储生成的编号
319
+const generatedCode = ref(generateCode());
320
+
321
+// 定义重新生成编号的方法
322
+const regenerateCode = () => {
323
+  generatedCode.value = generateCode();
324
+};
325
+
326
+const handleDetailLook = (row) => {
327
+  form.value = { ...row };
328
+  proxy.$router.push({
329
+    name: 'taiZhang_detail',
330
+    query: {
331
+      form: form.value.id
332
+    }
333
+  });
334
+  // dialogVisibleLook.value = true;
335
+};
336
+const deleteData=ref({})
337
+
338
+const handleDelete = (item) => {
339
+
340
+  deleteData.value=item
341
+  const now = new Date();
342
+  const year = now.getFullYear();
343
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
344
+  const day = String(now.getDate()).padStart(2, '0');
345
+  const hours = String(now.getHours()).padStart(2, '0');
346
+  const minutes = String(now.getMinutes()).padStart(2, '0');
347
+  const seconds = String(now.getSeconds()).padStart(2, '0');
348
+  deleteData.value.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
349
+
350
+    deleteData.value.cancelFlag='1'
351
+  var url = '/sgsafe/Manager/saveCulture';
352
+  var param = {
353
+    json: JSON.stringify(deleteData.value)
354
+  };
355
+  proxy.$axios.post(url, param).then(response => {
356
+    if (response.data.code == '0') {
357
+      showSuccessToast("删除成功")
358
+      onRefresh();
359
+
360
+    } else {
361
+    }
362
+
363
+  })
364
+};
365
+
366
+
367
+const confirmDelete = () => {
368
+  for (let item of currentDeleteItem.value) {
369
+    if (item.addId !== headers.value.userId) {
370
+      showToast({
371
+        type: 'warning',
372
+        message: '只能删除自己添加的数据!'
373
+      });
374
+      return;
375
+    }
376
+  }
377
+
378
+  if (currentDeleteItem.value[0].status !== '0' && currentDeleteItem.value[0].hdSelect !== '下发隐患'
379
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
380
+    showToast({
381
+      type: 'fail',
382
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
383
+    });
384
+    return;
385
+  }
386
+  if (currentDeleteItem.value[0].status !== '2' && currentDeleteItem.value[0].hdSelect === '下发隐患'
387
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
388
+    showToast({
389
+      type: 'fail',
390
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
391
+    });
392
+    return;
393
+  }
394
+
395
+  var url = 'sgsafe/Hiddendanger/remove';
396
+  var param = {
397
+    params: JSON.stringify({ ...currentDeleteItem.value.map(x => x.id) })
398
+  };
399
+  proxy.$axios.get(url, param).then(response => {
400
+    if (response.data.code == 0) {
401
+      showToast({
402
+        type: 'success',
403
+        message: '删除成功'
404
+      });
405
+      onRefresh();
406
+    } else {
407
+      showToast({
408
+        type: 'fail',
409
+        message: '操作失败!' + response.data.msg
410
+      });
411
+    }
412
+  });
413
+};
414
+
415
+
416
+
417
+
418
+const resetForm = () => {
419
+  form.value = {
420
+    projectName: '',
421
+    projectLeader: '',
422
+    phone: '',
423
+    dept: ''
424
+  };
425
+};
426
+
427
+
428
+//处理人员code
429
+const repairLL = ref('');
430
+const repairOO = ref('');
431
+const acceptLL = ref('');
432
+
433
+const jsons = ref({});
434
+
435
+const reback = () => {
436
+  // 返回逻辑
437
+};
438
+
439
+const deleteRow = (row) => {
440
+  selectedRows.value = [row];
441
+  handleDelete(row);
442
+};
443
+
444
+const deleteRowa = (row) => {
445
+  deleteRow(row);
446
+};
447
+
448
+/**
449
+ * 按钮实现swipe-cell滑动
450
+ */
451
+const openStatus = ref([])
452
+const swipeCellRefs = ref([])
453
+const getSwipeCellRef = (el, index) => {
454
+  if (el) {
455
+    swipeCellRefs.value[index] = el;
456
+  }
457
+}
458
+const openSwipe = (idx) => {
459
+  openStatus.value = new Array(resultData.value.length).fill(true);
460
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
461
+    openStatus.value[idx] = false
462
+    swipeCellRefs.value[idx].open('right')
463
+  }
464
+  document.addEventListener('click', handleDocumentClick)
465
+}
466
+/**
467
+ * 当点击滑动单元格时,开始监听点击事件
468
+ */
469
+const handleDocumentClick = (event) => {
470
+  openStatus.value = new Array(resultData.value.length).fill(true);
471
+}
472
+
473
+const closeSwipe = (idx) => {
474
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
475
+    openStatus.value[idx] = true
476
+    swipeCellRefs.value[idx].close()
477
+  }
478
+}
479
+// *********************************** 事故案例 ************************************************
480
+
481
+
482
+
483
+
484
+
485
+</script>
486
+
487
+<style scoped>
488
+.h5-container {
489
+  width: 100%;
490
+  padding: 5px;
491
+  box-sizing: border-box;
492
+}
493
+
494
+.status-pending {
495
+  background-color: #fff3cd;
496
+  color: #856404;
497
+  padding: 2px 4px;
498
+  border-radius: 4px;
499
+}
500
+
501
+.status-registered {
502
+  background-color: #d1ecf1;
503
+  color: #0c5460;
504
+  padding: 2px 4px;
505
+  border-radius: 4px;
506
+}
507
+
508
+.status-analyzing {
509
+  background-color: #fff8e1;
510
+  color: #ff8f00;
511
+  padding: 2px 4px;
512
+  border-radius: 4px;
513
+}
514
+
515
+.status-rectifying {
516
+  background-color: #e8f5e9;
517
+  color: #2e7d32;
518
+  padding: 2px 4px;
519
+  border-radius: 4px;
520
+}
521
+
522
+.status-accepting {
523
+  background-color: #e3f2fd;
524
+  color: #1565c0;
525
+  padding: 2px 2px;
526
+  border-radius: 2px;
527
+}
528
+
529
+.status-closed {
530
+  background-color: #f8bbd0;
531
+  color: #b71c1c;
532
+  padding: 2px 2px;
533
+  border-radius: 2px;
534
+}
535
+
536
+.status-finished {
537
+  background-color: #e8eaf6;
538
+  color: #311b92;
539
+  padding: 2px 2px;
540
+  border-radius: 2px;
541
+}
542
+
543
+.status-unknown {
544
+  background-color: #efebe9;
545
+  color: #424242;
546
+  padding: 2px 2px;
547
+  border-radius: 2px;
548
+}
549
+
550
+.cell-title {
551
+  display: -webkit-box;
552
+  /* 旧版弹性盒子模型 */
553
+  -webkit-box-orient: vertical;
554
+  /* 内容垂直排列 */
555
+  -webkit-line-clamp: 2;
556
+  /* 限制显示行数 */
557
+  overflow: hidden;
558
+  /* 超出隐藏 */
559
+  text-overflow: ellipsis;
560
+  /* 省略号 */
561
+  line-height: 1.5;
562
+  /* 可选:设置行高 */
563
+  max-height: calc(1.5em * 2);
564
+  /* 可选:根据行高限制最大高度 */
565
+  font-size: 16px;
566
+  font-weight: bold;
567
+  color: #333;
568
+  /* 字号 */
569
+}
570
+
571
+.swipe-cell-default {
572
+  display: flex;
573
+  background-color: #ffffff;
574
+  justify-content: center;
575
+  align-items: center;
576
+}
577
+
578
+.swipe-cell-default-icon {
579
+  width: 60px;
580
+  display: flex;
581
+  justify-content: center;
582
+}
583
+
584
+.delete-button {
585
+  height: 100%;
586
+  border: none;
587
+  color: #ff0000;
588
+  background-image: url('@/assets/img/del.png');
589
+  background-size: auto 100%;
590
+  background-repeat: no-repeat;
591
+}
592
+
593
+.submit-button {
594
+  height: 100%;
595
+  border: none;
596
+  color: #07c160;
597
+  background-image: url('@/assets/img/sub.png');
598
+  background-size: auto 100%;
599
+  background-repeat: no-repeat;
600
+}
601
+
602
+.subsuccess {
603
+  height: 100%;
604
+  border: none;
605
+  color: #07c160;
606
+  background-image: url('@/assets/img/sub1.png');
607
+  background-size: auto 100%;
608
+  background-repeat: no-repeat;
609
+}
610
+.single-line-text {
611
+  white-space: nowrap;        /* 强制不换行 */
612
+  overflow: hidden;           /* 超出部分隐藏 */
613
+  text-overflow: ellipsis;    /* 超出显示省略号 ... */
614
+  width: 100%;                /* 或指定宽度 */
615
+  box-sizing: border-box;
616
+}
617
+</style>

+ 710
- 0
src/view/knowledge/CultureList.vue Ver arquivo

@@ -0,0 +1,710 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref , computed } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+
6
+const {
7
+  proxy
8
+} = getCurrentInstance()
9
+const accidentDictList = ref([])
10
+const columns =  ref([])
11
+const columnsLevel =  ref([])
12
+const columnsprimary=ref([])
13
+
14
+//     [
15
+//   { text: '杭州', value: 'Hangzhou' },
16
+//   { text: '宁波', value: 'Ningbo' },
17
+//   { text: '温州', value: 'Wenzhou' },
18
+//   { text: '绍兴', value: 'Shaoxing' },
19
+//   { text: '湖州', value: 'Huzhou' },
20
+// ];
21
+
22
+// 定义生成编号的函数(你已写好的逻辑)
23
+
24
+const generateCode = () => {
25
+  const now = new Date();
26
+  const year = now.getFullYear();
27
+  const month = String(now.getMonth() + 1).padStart(2, '0');
28
+  const day = String(now.getDate()).padStart(2, '0');
29
+  const formattedDate = `${year}${month}${day}`;
30
+  const hours = String(now.getHours()).padStart(2, '0');
31
+  const minutes = String(now.getMinutes()).padStart(2, '0');
32
+  const seconds = String(now.getSeconds()).padStart(2, '0');
33
+  const formattedTime = `${hours}${minutes}${seconds}`;
34
+  const sequenceNumber = Math.floor(Math.random() * 1000);
35
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
36
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
37
+};
38
+
39
+// 存储生成的编号(响应式变量)
40
+const generatedCode = ref('');
41
+
42
+// 重新生成编号的方法
43
+const regenerateCode = () => {
44
+  generatedCode.value = generateCode();
45
+};
46
+
47
+
48
+
49
+const getAccidentDicList = () => {
50
+  tools.dic.getDicList([ 'case_type','sgsafe_culture_case_type', 'case_source','primary_domain','primary_domain_two','accident_level','accident_type','sgsafe_taccidentTags','sgsafe_culture_activity_type']).then((response => {
51
+    console.log(JSON.stringify(response.data.data))
52
+    accidentDictList.value = response.data.data
53
+    console.log('case_source',accidentDictList.value.case_source)
54
+    columns.value = accidentDictList.value.sgsafe_culture_case_type.map(item => ({
55
+      text: item.dicName,
56
+      value: item.dicCode
57
+    }));
58
+    columnsLevel.value = accidentDictList.value.sgsafe_culture_activity_type.map(item => ({
59
+      text: item.dicName,
60
+      value: item.dicCode
61
+    }));
62
+    columnsprimary.value = accidentDictList.value.primary_domain.map(item => ({
63
+      text: item.dicName,
64
+      value: item.dicCode
65
+    }));
66
+
67
+
68
+    console.log('accident_level',accidentDictList.value.accident_level)
69
+
70
+  }))
71
+}
72
+
73
+
74
+const caseSourceFlag = ref(false)
75
+const accidentLevelFlag = ref(false)
76
+const primaryDomainFlag = ref(false)
77
+const primaryDomainTwoFlag = ref(false)
78
+let title = '新增事故案例'
79
+
80
+/* 返回上一级页面 */
81
+const router = useRouter()
82
+const onClickLeft = () => {
83
+  router.go(-1)
84
+}
85
+
86
+const currentYear = ref()
87
+currentYear.value = new Date().getFullYear()
88
+
89
+/* 获取用户部门信息 */
90
+const jsonArray = localStorage.getItem('dept')
91
+const deptInformation = ref([])
92
+try {
93
+  deptInformation.value = jsonArray ? JSON.parse(jsonArray) : [];
94
+} catch (error) {
95
+  deptInformation.value = [];
96
+}
97
+const deptName = deptInformation.value[0].deptName
98
+const deptCode = deptInformation.value[0].deptCode
99
+
100
+const guid = () =>  {
101
+  function S4() {
102
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
103
+  }
104
+  return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4())
105
+}
106
+const formJieguo = ref({
107
+  resultWhether:'',
108
+  resultDetail:'',
109
+  resultWhy:'',
110
+  resultFile:'',
111
+  itemsId:'',
112
+  resultFileId:'',
113
+  resType:''
114
+})
115
+const route = useRoute()
116
+let planInfo = {}
117
+const  userName1=localStorage.getItem('userName');
118
+const isEdit = ref(route.query.mark === '1');
119
+
120
+const result1=ref('')
121
+const result2=ref('')
122
+const result3=ref('')
123
+const result4=ref('')
124
+const result5=ref('')
125
+const fromVue=ref({})
126
+if (route.query.mark) {
127
+  planInfo = JSON.parse(route.query.mark)
128
+}
129
+console.log(planInfo);
130
+if (planInfo==-1){
131
+  result1.value=guid()
132
+  result2.value=guid()
133
+  result3.value=guid()
134
+  result4.value=guid()
135
+  result5.value=guid()
136
+  generatedCode.value = generateCode();
137
+
138
+}
139
+
140
+const resDetail=ref('')
141
+const ruleIds = ref([]);
142
+/*const getRuleId = () => {
143
+  var url = '/sgsafe/ExamHead/getCheckRuleId'
144
+  var param = {}
145
+  proxy.$axios.get(url, param).then(response => {
146
+    if (response.data.code == '0') {
147
+      ruleIds.value = response.data.data
148
+    } else {
149
+      console.log("1111111");
150
+    }
151
+  })
152
+  console.log('ruleIds', ruleIds)
153
+}
154
+getRuleId()*/
155
+const showRule=ref(false);
156
+const showSmit=ref(true);
157
+const distestType=ref(false)
158
+if (planInfo==1) {
159
+  console.log(planInfo);
160
+  title = '修改管理档案'
161
+  fromVue.value= JSON.parse(route.query.data)
162
+  generatedCode.value = fromVue.value.caseNumber || '';
163
+  result1.value=fromVue.value.filePlan
164
+  result2.value=fromVue.value.filePic
165
+  result3.value=fromVue.value.fileEnd
166
+  result4.value=fromVue.value.fileOther
167
+  const userIds= localStorage.getItem('userId')
168
+  if (userIds != fromVue.value.addId) {
169
+    showSmit.value=false
170
+    title = '查看管理档案'
171
+  }
172
+
173
+}
174
+ const  whether=ref(false)
175
+
176
+const planLevelList1=ref([])
177
+
178
+
179
+/* 下拉框 */
180
+const showActionSheet = ref(false)
181
+const showActionSheet1 = ref(false)
182
+const planLevelList = [
183
+  { name: '转发', value: '转发' },
184
+  { name: '内部', value: '内部' },
185
+  { name: '文章', value: '文章' }
186
+];
187
+const isdisabled=ref(true)
188
+const isdisabled2=ref(true)
189
+const onSelect = (item) => {
190
+fromVue.value.fileContent = item.name
191
+
192
+  showActionSheet.value=false
193
+}
194
+
195
+const onSelect2 = (item) => {
196
+  fromVue.value.fileType=item.name
197
+  showActionSheet2.value=false
198
+  }
199
+
200
+const onCaseSourseSelect = (item) => {
201
+  fromVue.value.caseSource=item.dicCode
202
+  caseSourceFlag.value = false
203
+}
204
+
205
+const onAccidentLevelSelect = (item) => {
206
+  fromVue.value.accidentLevel = item.dicCode
207
+  accidentLevelFlag.value = false
208
+
209
+}
210
+
211
+const displayFileName = ref('')
212
+const onSelect1 = (item) => {
213
+  console.log(item);
214
+  formJieguo.value.resultFile = item.value
215
+  result.value=formJieguo.value.resultFile
216
+  displayFileName.value = item.name
217
+
218
+  showActionSheet1.value = false
219
+}
220
+const questionIds = ref([])
221
+const actions=ref([])
222
+/*const getQuestionId = () => {
223
+  var url = '/sgsafe/AssessmentRecord/queryRuleNoPage';
224
+  var param = {};
225
+  proxy.$axios.get(url, param).then(response => {
226
+    if (response.data.code == '0') {
227
+      questionIds.value = response.data.data; // 先赋值给 questionIds.value
228
+
229
+
230
+      // ✅ 关键:使用 questionIds.value.map
231
+      actions.value = questionIds.value.map(item => ({
232
+        name: item.ruleName,
233
+        value: item.id
234
+      }));
235
+      console.log('actions:', actions.value); // 看看有没有输出
236
+    } else {
237
+      ElMessage.error('操作失败!' + response.data.msg);
238
+    }
239
+  });
240
+};
241
+getQuestionId()*/
242
+
243
+const baocun3 = (ruleFormRef) => {
244
+  console.log(formJieguo.value)
245
+  ruleFormRef.validate((valid, fields) => {
246
+    if (valid) {
247
+
248
+      var url = '/sgsafe/Manager/save';
249
+      var param = {
250
+        json: JSON.stringify(formJieguo.value)
251
+      };
252
+      proxy.$axios.post(url, param).then(response => {
253
+        if (response.data.code == '0') {
254
+          getTableData1()
255
+          ElMessage({
256
+            message: '保存成功',
257
+            type: 'success',
258
+          })
259
+          if (ruleFormRef.value) {
260
+            ruleFormRef.value.resetFields();
261
+          }
262
+          dialogVisibletemplate.value=false
263
+        } else {
264
+          ElMessage.error('操作失败!' + response.data.msg)
265
+        }
266
+
267
+      })
268
+    }
269
+  })
270
+}
271
+
272
+/* 组织树选择 */
273
+const showBottom = ref(false)
274
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
275
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
276
+const handleTableDataUserDeptUpdate = async (nodeData) => {
277
+  console.log(nodeData);
278
+  const [deptCode, deptName] = nodeData.split('-', 2); // 只按第一个 '-' 分割
279
+  fromVue.value.activityDept = deptCode.trim();
280
+  fromVue.value.activityName = deptName.trim();
281
+
282
+  showBottom.value = false
283
+}
284
+
285
+/* 组织树选择 */
286
+const showBottom1 = ref(false)
287
+
288
+const handleTableDataUserDeptUpdate1 = async (nodeData) => {
289
+  console.log('选中的部门字符串:', nodeData); // e.g. "D1101120701-型钢炼钢站"
290
+
291
+  // 确保 nodeData 是字符串
292
+  if (typeof nodeData !== 'string') {
293
+    console.warn('nodeData 不是字符串,跳过处理');
294
+    showBottom1.value = false; // 假设你有另一个 showBottom1 控制弹窗
295
+    return;
296
+  }
297
+
298
+  // 获取当前已选的 otherDept,转为数组(按逗号分割)
299
+  const currentList = fromVue.value.otherDept
300
+      ? fromVue.value.otherDept.split(',').filter(item => item.trim() !== '')
301
+      : [];
302
+
303
+  // 可选:防止重复添加
304
+  if (!currentList.includes(nodeData)) {
305
+    currentList.push(nodeData);
306
+  }
307
+
308
+  // 重新拼成逗号分隔的字符串
309
+  fromVue.value.otherDept = currentList.join(',');
310
+
311
+  showBottom1.value = false;
312
+}
313
+
314
+const addEmergencyDrillPlan = async () => {
315
+  const loadingToast = showLoadingToast({
316
+    duration: 0,
317
+    message: '加载中',
318
+    forbidClick: true
319
+  })
320
+  var url = '/sgsafe/Manager/save';
321
+  const params = {
322
+    json: JSON.stringify(fromVue.value)
323
+  }
324
+  proxy.$axios.post(url,params).then(res=>{
325
+    if (res.data.code === 0) {
326
+      loadingToast.close()
327
+      showSuccessToast('保存成功')
328
+      onClickLeft()
329
+
330
+    } else {
331
+      loadingToast.close()
332
+      showFailToast('操作失败!' + res.data.msg)
333
+    }
334
+  })
335
+}
336
+const showDatePicker = ref(false)
337
+const onDatePicker = (value) => {
338
+  const dateArr = value.selectedValues
339
+  fromVue.value.startTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
340
+  showDatePicker.value = false
341
+}
342
+const currentDate = ref([2025, 7, 25])
343
+//定义字典集合
344
+const dicList = ref([])
345
+//获取字典集合
346
+// import tools from '@/tools'
347
+const getDicList = () => {
348
+  tools.dic.getDicList(['systemTypes']).then((response => {
349
+
350
+   const rawData = response.data.data
351
+    dicList.value = rawData.systemTypes.map(item => ({
352
+      name: item.dicName,      // 必须有 name 字段!
353
+      code: item.dicCode       // 可选,保留原始 code 供后续使用
354
+    }));
355
+    console.log(JSON.stringify(dicList.value))
356
+  }))
357
+}
358
+onMounted(() => {
359
+  getAccidentDicList()
360
+  console.log('这是编辑页面')
361
+  const today = new Date()
362
+  const year = today.getFullYear()
363
+  const month = today.getMonth() + 1 // 月份从 0 开始
364
+  const day = today.getDate()
365
+  currentDate.value = [year, month, day]
366
+  currentDate1.value = [year, month, day]
367
+
368
+  //selectedDateText.value = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
369
+  getDicList()
370
+})
371
+const showActionSheet2=ref(false)
372
+/* 文件上传 */
373
+import AttachmentS3 from '@/components/AttachmentS3.vue';
374
+import OrganizationalWithLeafUser from '@/components/OrganizationalWithLeafUser.vue';
375
+
376
+const onSubmit = (values) => {
377
+  fromVue.value.caseNumber = generatedCode.value;
378
+
379
+  fromVue.value.filePlan =result1.value
380
+  fromVue.value.filePic=result2.value
381
+  fromVue.value.fileEnd =result3.value
382
+  fromVue.value.fileOther=result4.value
383
+  fromVue.value.filePicBefore=fileUrl.value
384
+  addEmergencyDrillPlan()
385
+}
386
+const leaderKeyysr = guid();
387
+const PopupDepartmentLeaderNameRefysr = ref();
388
+const handleDepartmentLeaderNameysr = () => {
389
+  PopupDepartmentLeaderNameRefysr.value.open();
390
+};
391
+const getDepartmentLeaderNameysr = (item) => {
392
+  fromVue.value.punCode = item.user.userCode;
393
+  fromVue.value.punName = item.user.userDesc;
394
+  fromVue.value.punId = item.user.id
395
+};
396
+
397
+const onCaseSourceConfirm = ({ selectedOptions }) => {
398
+  caseSourceFlag.value = false;
399
+  fromVue.value.caseType = selectedOptions[0].text;
400
+};
401
+
402
+const onAccidentLevelConfirm = ({ selectedOptions }) => {
403
+  accidentLevelFlag.value = false;
404
+  fromVue.value.caseType = selectedOptions[0].text;
405
+};
406
+
407
+const onprimaryTwoConfirm = ({ selectedOptions }) => {
408
+  primaryDomainTwoFlag.value = false;
409
+  fromVue.value.primaryDomainTwo = selectedOptions[0].text;
410
+};
411
+const selectedPrimary = ref(null)
412
+const onprimaryConfirm = ({ selectedOptions }) => {
413
+  if (!selectedOptions?.length) {
414
+    selectedPrimary.value = null;
415
+    fromVue.value.primaryDomainTwo = '';
416
+    primaryDomainFlag.value = false;
417
+    return;
418
+  }
419
+
420
+  primaryDomainFlag.value = false;
421
+  fromVue.value.primaryDomain = selectedOptions[0].text;
422
+
423
+  const primaryList = accidentDictList.value?.primary_domain || [];
424
+  const selectedItem = primaryList.find(item => item.dicName === selectedOptions[0].text);
425
+
426
+  selectedPrimary.value = selectedItem || null;
427
+  fromVue.value.primaryDomainTwo = '';
428
+};
429
+
430
+const filteredSecondaryList = computed(() =>
431
+  selectedPrimary.value?.dicValue1
432
+    ? (accidentDictList.value?.primary_domain_two || [])
433
+      .filter(item => item.dicValue1 === selectedPrimary.value.dicValue1)
434
+      .map(({ dicName, dicCode }) => ({ text: dicName, value: dicCode }))
435
+    : []
436
+);
437
+const getDepartmentJoinPerson = (userArray) => {
438
+
439
+}
440
+const currentDate1 = ref([2025, 7, 25])
441
+const showDatePicker1 = ref(false)
442
+const onDatePicker1 = (value) => {
443
+  const dateArr = value.selectedValues
444
+  fromVue.value.endTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
445
+  showDatePicker1.value = false
446
+}
447
+const fileUrl=ref('')
448
+const handleFirstFileUrl = (url) => {
449
+  console.log('第一张文件URL:', url)
450
+  fileUrl.value=url
451
+}
452
+import AttachmentS3ImageReturnURL from '@/components/AttachmentS3ImageReturnURL.vue';
453
+</script>
454
+
455
+<template>
456
+
457
+  <div class="page-container">
458
+    <van-sticky class="header">
459
+      <van-nav-bar
460
+        :title="title"
461
+        left-text="返回"
462
+        left-arrow
463
+        @click-left="onClickLeft" >
464
+      </van-nav-bar>
465
+    </van-sticky>
466
+    <div class="scroll-container">
467
+      <van-form @submit="onSubmit">
468
+<!--        <van-field-->
469
+<!--          v-model="fromVue.caseNumber"-->
470
+<!--          label="案例编号"-->
471
+<!--          name="caseNumber"-->
472
+<!--          required-->
473
+<!--          placeholder="请输入案例编号"-->
474
+<!--          :rules="[{required: true, message: '请输入文件编号'}]"-->
475
+<!--        />-->
476
+        <van-field
477
+            v-model="generatedCode"
478
+        label="案例编号"
479
+        name="caseNumber"
480
+            :readonly="true"
481
+        :rules="[{required: true, message: '编号生成失败,请点击“重新生成”'}]"
482
+        />
483
+
484
+        <van-field
485
+          v-model="fromVue.activityTitle"
486
+          label="活动主题"
487
+          name="caseTitle"
488
+          required
489
+          placeholder="请输入活动主题"
490
+          :rules="[{required: true, message: '请输入活动主题'}]"
491
+        />
492
+
493
+        <van-field
494
+          v-model="fromVue.caseType"
495
+          readonly
496
+          label="案例类型"
497
+          name="caseType"
498
+          required
499
+          @click="caseSourceFlag = true"
500
+        />
501
+        <van-field
502
+          readonly
503
+          v-model="fromVue.activityType"
504
+          label="活动形式"
505
+          name="activityType"
506
+          @click="accidentLevelFlag = true"
507
+        />
508
+
509
+        <van-field
510
+            v-model="fromVue.startTime"
511
+            readonly
512
+            label="开始时间"
513
+            name="startTime"
514
+            required
515
+            placeholder="请选择开始时间"
516
+            :rules="[{required: true, message: '请输入开始时间'}]"
517
+            @click="showDatePicker = true"
518
+        />
519
+        <van-field
520
+            v-model="fromVue.endTime"
521
+            readonly
522
+            label="结束时间"
523
+            name="endTime"
524
+            required
525
+            placeholder="请选择结束时间"
526
+            :rules="[{required: true, message: '请输入结束时间'}]"
527
+            @click="showDatePicker1 = true"
528
+        />
529
+        <van-field
530
+            readonly
531
+            v-model="fromVue.activityName"
532
+            label="主办单位"
533
+            name="perName"
534
+            @click="showBottom=true"
535
+        />
536
+        <van-field
537
+            readonly
538
+            v-model="fromVue.otherDept"
539
+            label="协办/承办单位"
540
+            name="perName"
541
+            @click="showBottom1=true"
542
+        />
543
+
544
+        <van-field
545
+            v-model="fromVue.activitySummary"
546
+            label="活动简介"
547
+            name="activitySummary"
548
+            required
549
+            rows="3"
550
+            autosize
551
+            type="textarea"
552
+            placeholder="请输入活动简介"
553
+            :rules="[{required: true, message: '请输入活动简介'}]"
554
+        />
555
+
556
+        <van-field label="活动照片">
557
+          <template #input>
558
+            <AttachmentS3ImageReturnURL style="background-color: white;" :f-id="result2"  @update:firstFileUrl="handleFirstFileUrl" />
559
+          </template>
560
+        </van-field>
561
+
562
+        <van-field label="活动方案" >
563
+          <template #input>
564
+            <AttachmentS3 :f-id="result1" />
565
+          </template>
566
+        </van-field>
567
+        <van-field label="活动总结及效果评价" >
568
+          <template #input>
569
+            <AttachmentS3 :f-id="result3" />
570
+          </template>
571
+        </van-field>
572
+        <van-field label="签到表及其他材料" >
573
+          <template #input>
574
+            <AttachmentS3 :f-id="result4" />
575
+          </template>
576
+        </van-field>
577
+        <div style="margin: 16px;">
578
+          <van-button round block type="primary" v-show='showSmit' native-type="submit">
579
+            {{ isEdit ? '保存' : '提交' }}
580
+          </van-button>
581
+        </div>
582
+      </van-form>
583
+
584
+      <van-action-sheet
585
+        v-model:show="showActionSheet"
586
+        :actions="planLevelList"
587
+        @select="onSelect"
588
+      />
589
+      <van-action-sheet
590
+        v-model:show="showActionSheet2"
591
+        :actions="dicList"
592
+        @select="onSelect2"
593
+      />
594
+
595
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
596
+        <van-picker
597
+            :columns="columns"
598
+            @cancel="caseSourceFlag = false"
599
+            @confirm="onCaseSourceConfirm"
600
+        />
601
+      </van-popup>
602
+
603
+      <van-popup v-model:show="accidentLevelFlag" round position="bottom">
604
+        <van-picker
605
+            :columns="columnsLevel"
606
+            @cancel="accidentLevelFlag = false"
607
+            @confirm="onAccidentLevelConfirm"
608
+        />
609
+      </van-popup>
610
+      <van-popup v-model:show="primaryDomainFlag" round position="bottom">
611
+        <van-picker
612
+          :columns="columnsprimary"
613
+          @cancel="primaryDomainFlag = false"
614
+          @confirm="onprimaryConfirm"
615
+        />
616
+      </van-popup>
617
+      <van-popup v-model:show="primaryDomainTwoFlag" round position="bottom">
618
+        <van-picker
619
+          :columns="filteredSecondaryList"
620
+          @cancel="primaryDomainTwoFlag = false"
621
+          @confirm="onprimaryTwoConfirm"
622
+        />
623
+      </van-popup>
624
+
625
+<!--      <van-action-sheet-->
626
+<!--          v-model:show="accidentLevelFlag"-->
627
+<!--          :actions="accidentDictList.accident_level"-->
628
+<!--          @select="onAccidentLevelSelect"-->
629
+<!--      />-->
630
+
631
+<!--      <van-action-sheet-->
632
+<!--        v-model:show="showActionSheet1"-->
633
+<!--        :actions="planLevelList1"-->
634
+<!--        field-names="{ text: 'fileName', value: 'fileId' }"-->
635
+<!--        @select="onSelect1"-->
636
+<!--      />-->
637
+
638
+      <van-popup v-model:show="showBottom" position="bottom" :style="{ height: '30%' }">
639
+        <OrganizationalWithLeaf @update:selected-node="handleTableDataUserDeptUpdate" />
640
+      </van-popup>
641
+      <van-popup v-model:show="showBottom1" position="bottom" :style="{ height: '30%' }">
642
+        <OrganizationalWithLeaf @update:selected-node="handleTableDataUserDeptUpdate1" />
643
+      </van-popup>
644
+      <van-popup v-model:show="showDatePicker" position="bottom">
645
+        <van-date-picker
646
+          v-model="currentDate"
647
+          @confirm="onDatePicker"
648
+          @cancel="showDatePicker = false" />
649
+      </van-popup>
650
+      <van-popup v-model:show="showDatePicker1" position="bottom">
651
+        <van-date-picker
652
+            v-model="currentDate1"
653
+            @confirm="onDatePicker1"
654
+            @cancel="showDatePicker1 = false" />
655
+      </van-popup>
656
+
657
+    </div>
658
+  </div>
659
+</template>
660
+
661
+<style scoped>
662
+.page-container {
663
+  height: 100vh; /* 关键:外层容器高度设为视口高度 */
664
+  display: flex;
665
+  flex-direction: column;
666
+
667
+}
668
+/*  overflow-y: auto; !* 启用垂直滚动 *!*/
669
+
670
+
671
+.scroll-container {
672
+  flex: 1;
673
+  overflow: auto;
674
+  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
675
+}
676
+
677
+/* 可选:隐藏滚动条(视觉优化) */
678
+.scroll-container::-webkit-scrollbar {
679
+  display: none;
680
+}
681
+
682
+.header, .footer {
683
+  /* 固定高度区域 */
684
+  flex-shrink: 0; /* 防止被压缩 */
685
+  background: #f5f5f5;
686
+  padding: 12px;
687
+}
688
+.row-container {
689
+  display: flex;
690
+  justify-content: space-between; /* 关键:左右分布 */
691
+  align-items: center;             /* 垂直居中 */
692
+
693
+}
694
+
695
+.cell-period-text {
696
+  font-size: 14px;
697
+  color: #333;
698
+  white-space: nowrap;
699
+  overflow: hidden;
700
+  text-overflow: ellipsis;
701
+
702
+}
703
+
704
+.mini-btn {
705
+  height: 22px;
706
+  font-size: 12px;
707
+  padding: 0 8px;
708
+  min-width: 60px;                 /* 可选:保持按钮最小宽度一致 */
709
+}
710
+</style>

+ 892
- 0
src/view/knowledge/accident.vue Ver arquivo

@@ -0,0 +1,892 @@
1
+<template>
2
+  <div class="h5-container">
3
+    <van-nav-bar title="事故案例" @click-left="onClickLeft" @click-right="handAdd">
4
+      <template #right>
5
+        <van-icon name="add" size="25" color="#000" />
6
+      </template>
7
+    </van-nav-bar>
8
+    <van-search v-model="query.caseTitle" show-action placeholder="请输入案例标题" @search="onRefresh"
9
+                @cancel="handdelectTitle" />
10
+
11
+    <!-- 项目列表 -->
12
+    <van-pull-refresh v-model="isRefreshing" success-text="刷新成功" @refresh="onRefresh">
13
+      <van-list v-model:loading="isLoading" :finished="isFinished" finished-text="没有更多了" offset="200" @load="onLoad">
14
+        <div v-for="(item, idx) in resultData" :key="item.id">
15
+          <van-swipe-cell title-style="color: #007aff" style="height: 80px;" :ref="el => getSwipeCellRef(el, idx)">
16
+            <template #default>
17
+              <div class="swipe-cell-default">
18
+                <van-cell style="min-height: 100px; padding: 0 0 0 0; display: flex; align-items: flex-start;" @click="edits(item)">
19
+                  <template #title>
20
+                    <div class="cell-title">
21
+                      {{ item.caseTitle }}
22
+                    </div>
23
+                  </template>
24
+                  <template #label>
25
+                      <div>案例编号:{{ item.caseNumber }} </div>
26
+                      <div>事故等级:{{ item.accidentLevel }}</div>
27
+                      <div> 浏览量:{{item.viewCount}}</div>
28
+
29
+<!--                    <div style="width: 112px" :class="getStatusClass(item.isFinish)">
30
+                      类型:
31
+                      <span v-if="item.isFinish === '待学习'" style="width: 200px">待学习</span>
32
+                      <span v-else-if="item.isFinish === '已学习'" style="width: 200px">已学习</span>
33
+                      <span v-else-if="item.isFinish === '已扣除'" style="width: 200px">已扣除</span>
34
+                    </div>-->
35
+                  </template>
36
+                </van-cell>
37
+                <div class="swipe-cell-default-icon">
38
+                  <van-icon v-if="openStatus[idx]" name="arrow-double-left" @click.stop="openSwipe(idx)" />
39
+                  <van-icon v-else name="arrow-double-right" @click.stop="closeSwipe(idx)" />
40
+                </div>
41
+              </div>
42
+            </template>
43
+
44
+            <template #right>
45
+              <van-button v-if="item.canDelete" square class="delete-button" text="删除" @click="handleDelete(item)" />
46
+            </template>
47
+          </van-swipe-cell>
48
+        </div>
49
+
50
+      </van-list>
51
+    </van-pull-refresh>
52
+
53
+    <!-- 删除确认弹窗 -->
54
+    <van-dialog v-model:show="deleteDialogVisible" show-cancel-button @confirm="confirmDelete">
55
+      <template #title>
56
+        <div>删除确认</div>
57
+      </template>
58
+      <div style="padding: 30px;">确定要删除该项目吗?</div>
59
+    </van-dialog>
60
+
61
+  </div>
62
+</template>
63
+
64
+<script setup>
65
+import { ref, reactive, onMounted, getCurrentInstance, nextTick, toRaw } from 'vue';
66
+import { Dialog, showDialog, showSuccessToast, showToast, Toast } from 'vant';
67
+
68
+import tools from '@/tools'
69
+
70
+const { proxy } = getCurrentInstance();
71
+
72
+const onClickLeft = () => {
73
+  history.back();
74
+};
75
+// const headers = ref({
76
+//   token: localStorage.getItem('token'),
77
+//   userId: localStorage.getItem('userId'),
78
+//   dept: JSON.parse(localStorage.getItem('dept'))[0].deptCode
79
+// });
80
+const headers = ref({
81
+  token: localStorage.getItem('token') || '',
82
+  userId: localStorage.getItem('userId') || '', // 防止 null/undefined
83
+  dept: JSON.parse(localStorage.getItem('dept'))?.[0]?.deptCode || ''
84
+});
85
+const switchIconState = (idx) => {
86
+  openStatus.value[idx] = !openStatus.value[idx]
87
+  openStatus.value = new Array(resultData.value.length).fill(true);
88
+}
89
+
90
+// const onClickRight = () =>{
91
+//   searchShow.value = !searchShow.value;
92
+// }
93
+
94
+const searchShow = ref(false);
95
+const query = ref({
96
+  caseNumber:'',
97
+  caseTitle:'',
98
+})
99
+
100
+
101
+
102
+const tableData = ref([]);
103
+const selectedRows = ref([]);
104
+const dialogVisibleLook = ref(false);
105
+const deleteDialogVisible = ref(false);
106
+const currentDeleteItem = ref([]);
107
+const dialogVisible = ref(false);
108
+const dialogVisibleFile = ref(false);
109
+const date = ref(null);
110
+
111
+const kz = ref(true);
112
+import { useRouter } from 'vue-router';
113
+const router = useRouter();
114
+const handAdd =  () => {
115
+
116
+  router.push({ path: "/accidentList",
117
+    query: {
118
+      mark:-1
119
+    } });
120
+
121
+};
122
+const goaddPeo = (item) => {
123
+  router.push({
124
+    path: '/addPeo',
125
+    query: {
126
+      data: JSON.stringify(item)
127
+    }
128
+  })
129
+}
130
+
131
+const edits = async (row) => {
132
+  const currentUserId = localStorage.getItem('userId');
133
+  const addId = row.addId;
134
+
135
+  const isOwner = String(addId).trim().toLowerCase() === String(currentUserId).trim().toLowerCase();
136
+
137
+  // 更新浏览量
138
+  await updateViewCount(row);
139
+
140
+  kz.value = true;
141
+  form.value = { ...row };
142
+  router.push({ path: "/accidentList",
143
+    query: {
144
+      mark:1,
145
+      data:JSON.stringify(form.value),
146
+      readOnly: !isOwner ? 'true' : undefined
147
+    } });
148
+};
149
+const form = ref({
150
+  caseNumber:'',
151
+  caseTitle:'',
152
+  caseSource:'',
153
+  accidentLevel:'',
154
+  accidentDept:'',
155
+  accidentLocation:'',
156
+  accidentTime:'',
157
+  accidentType:'',
158
+  accidentTags:'',
159
+  casualtyCount:'',
160
+  accidentSummary:'',
161
+  preventiveMeasures:'',
162
+  fileId:'',
163
+  viewCount:'',
164
+  downloadCount:''
165
+});
166
+
167
+const updateViewCount = async (item) => {
168
+  try {
169
+    const payload = { ...item };
170
+    // 将浏览量 +1
171
+    payload.viewCount = String((Number(payload.viewCount) || 0) + 1);
172
+
173
+    const url = '/sgsafe/Manager/saveAccident';
174
+    const param = {
175
+      json: JSON.stringify(payload)
176
+    };
177
+
178
+    const response = await proxy.$axios.post(url, param);
179
+    if (response.data.code === '0' || response.data.code === 0) {
180
+      // 更新成功后,更新本地列表中的浏览量显示
181
+      const index = resultData.value.findIndex(data => data.id === item.id);
182
+      if (index !== -1) {
183
+        resultData.value[index].viewCount = payload.viewCount;
184
+      }
185
+    }
186
+  } catch (error) {
187
+    console.error('更新浏览量失败:', error);
188
+    // 即使更新失败也不阻塞页面跳转
189
+  }
190
+};
191
+
192
+const isRefreshing = ref(false);
193
+const isLoading = ref(false);
194
+const isFinished = ref(false);
195
+const currentPage = ref(1);
196
+const pageSize = ref(10);
197
+const totalRows = ref(0);
198
+const resultData = ref([]);
199
+
200
+const dept=localStorage.getItem("dept")[0].deptCode;
201
+const currentUserId = String(localStorage.getItem('userId'));
202
+const getTableData = async () => {
203
+  var url = '/sgsafe/Manager/queryAccident'
204
+  var param = {
205
+    page: currentPage.value,
206
+    rows: pageSize.value,
207
+    params: JSON.stringify(query.value)
208
+  }
209
+  const response = await proxy.$axios.get(url, param);
210
+  if (response.data.code == 0) {
211
+    tableData.value = response.data.data.records.map(item => ({
212
+      ...item,
213
+      canDelete: String(item.addId) === currentUserId
214
+    }));
215
+    console.log('列表数据',tableData.value)
216
+    totalRows.value = response.data.data.total;
217
+  } else {
218
+    showToast({
219
+      type: 'error',
220
+      message: '操作失败!' + response.data.msg
221
+    });
222
+  }
223
+};
224
+const ruleIds = ref([]);
225
+
226
+const onRefresh = () => {
227
+  basicReset();
228
+  onLoad();
229
+};
230
+
231
+//*************************************
232
+
233
+
234
+
235
+//定义字典集合
236
+const dicList = ref([])
237
+
238
+const getDicList = () => {
239
+  tools.dic.getDicList([ 'case_type','SEX', 'case_source','accident_level','accident_type','sgsafe_taccidentTags']).then((response => {
240
+    console.log(JSON.stringify(response.data.data))
241
+    dicList.value = response.data.data
242
+
243
+  }))
244
+}
245
+
246
+
247
+const onLoad = async () => {
248
+  if (isRefreshing.value) {
249
+    resultData.value = [];
250
+    currentPage.value = 1;
251
+    isRefreshing.value = false;
252
+  }
253
+
254
+  getDicList()
255
+
256
+
257
+
258
+
259
+
260
+  try {
261
+    await getTableData();
262
+
263
+    if (pageSize.value * currentPage.value < totalRows.value) {
264
+      resultData.value = [...resultData.value, ...tableData.value];
265
+      openStatus.value = new Array(resultData.value.length).fill(true);
266
+      currentPage.value++;
267
+
268
+    } else {
269
+      resultData.value = [...resultData.value, ...tableData.value];
270
+      openStatus.value = new Array(resultData.value.length).fill(true);
271
+      isFinished.value = true;
272
+    }
273
+
274
+    console.log('resultData',resultData.value)
275
+  } catch (error) {
276
+    console.log(error);
277
+    isFinished.value = true;
278
+  } finally {
279
+    isLoading.value = false;
280
+  }
281
+};
282
+/* 通用方法: 重置list数据 */
283
+const basicReset = () => {
284
+  isFinished.value = false;
285
+  isLoading.value = true;
286
+  currentPage.value = 1;
287
+  resultData.value = [];
288
+};
289
+
290
+/*onMounted(() => {
291
+  handleSearch();
292
+});
293
+
294
+
295
+const handleSearch = () => {
296
+/!*  currentPage.value = 1;
297
+  isFinished.value = false;
298
+  tableData.value = [];*!/
299
+  basicReset()
300
+  onLoad()
301
+};*/
302
+
303
+const handdelectNumber = () => {
304
+  query.value.caseNumber = '';
305
+  onRefresh()
306
+};
307
+
308
+const handdelectTitle = () => {
309
+  query.value.caseTitle = '';
310
+  onRefresh()
311
+};
312
+
313
+
314
+
315
+
316
+// 定义生成编号的函数
317
+const generateCode = () => {
318
+  // 获取当前日期并格式化为 YYYYMMDD
319
+  const now = new Date();
320
+  const year = now.getFullYear();
321
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需加1
322
+  const day = String(now.getDate()).padStart(2, '0');
323
+  const formattedDate = `${year}${month}${day}`;
324
+  // 时间部分:HHmmss
325
+  const hours = String(now.getHours()).padStart(2, '0');
326
+  const minutes = String(now.getMinutes()).padStart(2, '0');
327
+  const seconds = String(now.getSeconds()).padStart(2, '0');
328
+  const formattedTime = `${hours}${minutes}${seconds}`;
329
+
330
+  // 模拟生成三位流水号(可以根据需要替换为递增逻辑)
331
+  const sequenceNumber = Math.floor(Math.random() * 1000); // 随机生成 0-999
332
+  const paddedSequence = String(sequenceNumber).padStart(3, '0'); // 补零到三位
333
+
334
+  // 拼接编号
335
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
336
+};
337
+
338
+// 使用 ref 存储生成的编号
339
+const generatedCode = ref(generateCode());
340
+
341
+// 定义重新生成编号的方法
342
+const regenerateCode = () => {
343
+  generatedCode.value = generateCode();
344
+};
345
+
346
+const handleDetailLook = (row) => {
347
+
348
+  form.value = { ...row };
349
+  proxy.$router.push({
350
+    name: 'taiZhang_detail',
351
+    query: {
352
+      form: form.value.id
353
+    }
354
+  });
355
+  // dialogVisibleLook.value = true;
356
+};
357
+const deleteData=ref({})
358
+
359
+const handleDelete = (item) => {
360
+  const currentUserId = headers.value.userId;
361
+  const addId = item.addId;
362
+
363
+  if (!currentUserId || !addId || String(addId).trim() !== String(currentUserId).trim()) {
364
+    showToast({
365
+      type: 'warning',
366
+      message: '无权限删除!只能删除自己添加的案例。'
367
+    });
368
+    return;
369
+  }
370
+  
371
+  deleteData.value=item
372
+  const now = new Date();
373
+  const year = now.getFullYear();
374
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
375
+  const day = String(now.getDate()).padStart(2, '0');
376
+  const hours = String(now.getHours()).padStart(2, '0');
377
+  const minutes = String(now.getMinutes()).padStart(2, '0');
378
+  const seconds = String(now.getSeconds()).padStart(2, '0');
379
+  deleteData.value.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
380
+
381
+    deleteData.value.cancelFlag='1'
382
+  var url = '/sgsafe/Manager/saveAccident';
383
+  var param = {
384
+    json: JSON.stringify(deleteData.value)
385
+  };
386
+  proxy.$axios.post(url, param).then(response => {
387
+    if (response.data.code == '0') {
388
+      showSuccessToast("删除成功")
389
+      onRefresh();
390
+
391
+    } else {
392
+    }
393
+
394
+  })
395
+};
396
+
397
+
398
+const confirmDelete = () => {
399
+  for (let item of currentDeleteItem.value) {
400
+    if (item.addId !== headers.value.userId) {
401
+      showToast({
402
+        type: 'warning',
403
+        message: '只能删除自己添加的数据!'
404
+      });
405
+      return;
406
+    }
407
+  }
408
+
409
+  if (currentDeleteItem.value[0].status !== '0' && currentDeleteItem.value[0].hdSelect !== '下发隐患'
410
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
411
+    showToast({
412
+      type: 'fail',
413
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
414
+    });
415
+    return;
416
+  }
417
+  if (currentDeleteItem.value[0].status !== '2' && currentDeleteItem.value[0].hdSelect === '下发隐患'
418
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
419
+    showToast({
420
+      type: 'fail',
421
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
422
+    });
423
+    return;
424
+  }
425
+
426
+  var url = 'sgsafe/Hiddendanger/remove';
427
+  var param = {
428
+    params: JSON.stringify({ ...currentDeleteItem.value.map(x => x.id) })
429
+  };
430
+  proxy.$axios.get(url, param).then(response => {
431
+    if (response.data.code == 0) {
432
+      showToast({
433
+        type: 'success',
434
+        message: '删除成功'
435
+      });
436
+      onRefresh();
437
+    } else {
438
+      showToast({
439
+        type: 'fail',
440
+        message: '操作失败!' + response.data.msg
441
+      });
442
+    }
443
+  });
444
+};
445
+
446
+
447
+
448
+
449
+const resetForm = () => {
450
+  form.value = {
451
+    projectName: '',
452
+    projectLeader: '',
453
+    phone: '',
454
+    dept: ''
455
+  };
456
+};
457
+
458
+const baocun = () => {
459
+  nextTick(() => {
460
+    if (form.value.hdSelect === '正常登记') {
461
+      form.value.status = '0';
462
+    } else if (form.value.hdSelect === '下发隐患') {
463
+      form.value.status = '2';
464
+    } else {
465
+      form.value.status = '-1';
466
+    }
467
+  });
468
+  // 原有保存逻辑保持不变
469
+  var url = 'sgsafe/Hiddendanger/save';
470
+  var param = {
471
+    json: JSON.stringify(form.value)
472
+  };
473
+  proxy.$axios.post(url, param).then(response => {
474
+    if (response.data.code == '0') {
475
+      showSuccessToast('保存成功!');
476
+      getTableData();
477
+      orJsons();
478
+      // clearDeptUsers()
479
+    } else {
480
+      showToast({
481
+        type: 'fail',
482
+        message: '操作失败!' + response.data.msg
483
+      });
484
+    }
485
+  });
486
+};
487
+
488
+//处理人员code
489
+const repairLL = ref('');
490
+const repairOO = ref('');
491
+const acceptLL = ref('');
492
+const orJsons = () => {
493
+  // console.log('forms',form.value)
494
+  if (form.value.hdSelect === '正常登记') {
495
+    nextTick(() => {
496
+      nextTick(() => {
497
+        repairLL.value = qq('repairLL', form.value.discoverer);//隐患发现人
498
+        nextTick(() => {
499
+          repairOO.value = qq('repairOO', form.value.discovererOther);//其他隐患发现人
500
+          nextTick(() => {
501
+            acceptLL.value = qq('acceptLL', form.value.discoverer);//隐患销号人
502
+          });
503
+        });
504
+      });
505
+
506
+      // acceptOO.value = qq('acceptOO', form.value.acceptOther)
507
+    });
508
+  } else {
509
+    // console.log('noiajdoifjpoewjfopjp')
510
+    nextTick(() => {
511
+      nextTick(() => {
512
+        repairLL.value = qq('repairLL', form.value.acceptLeader);//隐患发现人
513
+        nextTick(() => {
514
+          repairOO.value = qq('repairOO', form.value.acceptOther);//其他隐患发现人
515
+          nextTick(() => {
516
+            acceptLL.value = qq('acceptLL', form.value.discoverer);//隐患销号人
517
+          });
518
+        });
519
+      });
520
+
521
+      // acceptOO.value = qq('acceptOO', form.value.acceptOther)
522
+    });
523
+  }
524
+};
525
+
526
+const jsons = ref({});
527
+const qq = (a, val) => {
528
+  let aa = '';
529
+  var url = 'sgsafe/Hiddendanger/qqId';
530
+  var param = {
531
+    params: val
532
+  };
533
+  proxy.$axios.post(url, param).then(response => {
534
+    if (response.data.code == 0) {
535
+
536
+      aa = response.data.data;
537
+      switch (a) {
538
+        case 'repairLL':
539
+          repairLL.value = response.data.data;
540
+          // console.log('repairLL',repairLL.value);
541
+          break;
542
+        case 'repairOO':
543
+          repairOO.value = response.data.data;
544
+          // console.log('repairOO',repairLL.value);
545
+          break;
546
+        case 'acceptLL':
547
+          acceptLL.value = response.data.data;
548
+          // console.log('acceptLL',repairLL.value);
549
+          break;
550
+        default:
551
+          break;
552
+      }
553
+      jsons.value = {
554
+        hdConfirm: repairLL.value,
555
+        hdConfirmO: repairOO.value,
556
+        hdCancel: acceptLL.value
557
+      };
558
+
559
+      // 处理函数
560
+      function processValue(value) {
561
+        // 将逗号替换为分号
562
+        const replacedValue = value.replace(/,/g, ';');
563
+        // 分割值
564
+        const parts = replacedValue.split(';');
565
+        // 每个部分前加上 U_
566
+        const processedParts = parts.map(part => `U_${part.trim()}`);
567
+        // 重新组合
568
+        return processedParts.join(';');
569
+      }
570
+
571
+      // 处理整个对象
572
+      const processedData = {};
573
+      for (const key in jsons.value) {
574
+        if (jsons.value.hasOwnProperty(key)) {
575
+          processedData[key] = processValue(jsons.value[key]);
576
+        }
577
+      }
578
+
579
+      console.log('对象', toRaw(processedData));
580
+
581
+      let b = {
582
+        acceptL: processedData.hdConfirm,
583
+        acceptO: processedData.hdConfirmO,
584
+        id: form.value.id
585
+      };
586
+
587
+      if (form.value.hdSelect === '即查即改') {
588
+        b = {
589
+          hdFxr: processedData.hdCancel,
590
+          id: form.value.id
591
+        };
592
+      }
593
+
594
+      if (form.value.hdSelect === '正常登记') {
595
+        b = {
596
+          // hdConfirm: processedData.hdConfirm,
597
+          // hdConfirmO: processedData.hdConfirmO,
598
+          id: form.value.id
599
+        };
600
+      }
601
+
602
+      const aaa = JSON.stringify(toRaw(b));
603
+      sessionStorage.setItem('variables', aaa);
604
+      console.log('aaa', aaa);
605
+    } else {
606
+      showToast({
607
+        type: 'fail',
608
+        message: '操作失败!' + response.data.msg
609
+      });
610
+    }
611
+  });
612
+  return aa;
613
+};
614
+
615
+const reback = () => {
616
+  // 返回逻辑
617
+};
618
+
619
+const deleteRow = (row) => {
620
+  selectedRows.value = [row];
621
+  handleDelete(row);
622
+};
623
+
624
+const deleteRowa = (row) => {
625
+  deleteRow(row);
626
+};
627
+
628
+const bm = (val) => {
629
+  // 部门选择逻辑
630
+};
631
+
632
+//提交审批流程
633
+import { workflowSubmit, workflowCancel } from '@/tools/workflow.js';
634
+
635
+const flowId = ref('');
636
+flowId.value = 'hazardManagementFlowId';
637
+const handleSubmit2 = (val, idx) => {
638
+  openStatus.value[idx] = !openStatus.value[idx]
639
+  openStatus.value = new Array(resultData.value.length).fill(true);
640
+  console.log('提交');
641
+  console.log('selectedRows', selectedRows.value);
642
+  let row = val;
643
+  form.value = { ...row }
644
+  form.value.workCreate = headers.value.dept;
645
+
646
+  let b = {
647
+    id: form.value.id,
648
+  }
649
+  const aaa = JSON.stringify(toRaw(b))
650
+  sessionStorage.setItem('variables', aaa)
651
+
652
+  if (form.value.hdSelect === '正常登记') {
653
+    flowId.value = 'hazardManagementFlowId'
654
+  } else if (form.value.hdSelect === '下发隐患') {
655
+    flowId.value = 'hazardImmediatelyCM'
656
+    form.value.status = '2'
657
+  } else {
658
+    flowId.value = 'hazardImmediatelyCMUpdate'
659
+    form.value.status = '-1'
660
+  }
661
+
662
+  console.log('----');
663
+  console.log(flowId.value);
664
+  console.log(sessionStorage.getItem('variables'));
665
+  console.log(row.workId);
666
+  console.log(row.trackId);
667
+  let titles = '隐患排查治理'
668
+  showDialog({
669
+    title: '提示',
670
+    message: '确定提交审批?',
671
+    showCancelButton: true,
672
+    confirmButtonText: '确定',
673
+    type: 'warning',
674
+    cancelButtonText: '取消'
675
+  }
676
+  ).then(() => {
677
+    return workflowSubmit(
678
+      flowId.value,
679
+      '隐患排查治理',
680
+      '初始化提交',
681
+      // JSON.stringify({}),
682
+      sessionStorage.getItem('variables'),
683
+      row.workId,
684
+      row.trackId);
685
+  }).then((result) => {
686
+    if (result.status === 'success') {
687
+      // 将结果返回的workId和trackId保存
688
+      var url = 'sgsafe/Hiddendanger/saveProcessInfo';
689
+      console.log('id', result, row.id);
690
+      var process = {
691
+        'id': form.value.id,
692
+        'workId': result.workId,
693
+        'trackId': result.trackId
694
+      };
695
+      var param = {
696
+        json: JSON.stringify(process)
697
+      };
698
+      proxy.$axios.post(url, param).then(response => {
699
+        if (response.data.code === 0) {
700
+          form.value = response.data.data;
701
+          console.log('我要进来啦保存成功');
702
+          showToast({
703
+            type: 'success',
704
+            message: '提交审批成功'
705
+          });
706
+          onRefresh()
707
+        }
708
+      });
709
+    } else {
710
+      showToast({
711
+        type: 'error',
712
+        message: '提交审批失败,' + result.msg
713
+      });
714
+    }
715
+  }).catch(() => {
716
+    showToast({
717
+      type: 'info',
718
+      message: '已取消提交'
719
+    });
720
+  });
721
+};
722
+
723
+/**
724
+ * 按钮实现swipe-cell滑动
725
+ */
726
+const openStatus = ref([])
727
+const swipeCellRefs = ref([])
728
+const getSwipeCellRef = (el, index) => {
729
+  if (el) {
730
+    swipeCellRefs.value[index] = el;
731
+  }
732
+}
733
+const openSwipe = (idx) => {
734
+  openStatus.value = new Array(resultData.value.length).fill(true);
735
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
736
+    openStatus.value[idx] = false
737
+    swipeCellRefs.value[idx].open('right')
738
+  }
739
+  document.addEventListener('click', handleDocumentClick)
740
+}
741
+/**
742
+ * 当点击滑动单元格时,开始监听点击事件
743
+ */
744
+const handleDocumentClick = (event) => {
745
+  openStatus.value = new Array(resultData.value.length).fill(true);
746
+}
747
+
748
+const closeSwipe = (idx) => {
749
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
750
+    openStatus.value[idx] = true
751
+    swipeCellRefs.value[idx].close()
752
+  }
753
+}
754
+// *********************************** 事故案例 ************************************************
755
+
756
+
757
+
758
+
759
+
760
+</script>
761
+
762
+<style scoped>
763
+.h5-container {
764
+  width: 100%;
765
+  padding: 5px;
766
+  box-sizing: border-box;
767
+}
768
+
769
+.status-pending {
770
+  background-color: #fff3cd;
771
+  color: #856404;
772
+  padding: 2px 4px;
773
+  border-radius: 4px;
774
+}
775
+
776
+.status-registered {
777
+  background-color: #d1ecf1;
778
+  color: #0c5460;
779
+  padding: 2px 4px;
780
+  border-radius: 4px;
781
+}
782
+
783
+.status-analyzing {
784
+  background-color: #fff8e1;
785
+  color: #ff8f00;
786
+  padding: 2px 4px;
787
+  border-radius: 4px;
788
+}
789
+
790
+.status-rectifying {
791
+  background-color: #e8f5e9;
792
+  color: #2e7d32;
793
+  padding: 2px 4px;
794
+  border-radius: 4px;
795
+}
796
+
797
+.status-accepting {
798
+  background-color: #e3f2fd;
799
+  color: #1565c0;
800
+  padding: 2px 2px;
801
+  border-radius: 2px;
802
+}
803
+
804
+.status-closed {
805
+  background-color: #f8bbd0;
806
+  color: #b71c1c;
807
+  padding: 2px 2px;
808
+  border-radius: 2px;
809
+}
810
+
811
+.status-finished {
812
+  background-color: #e8eaf6;
813
+  color: #311b92;
814
+  padding: 2px 2px;
815
+  border-radius: 2px;
816
+}
817
+
818
+.status-unknown {
819
+  background-color: #efebe9;
820
+  color: #424242;
821
+  padding: 2px 2px;
822
+  border-radius: 2px;
823
+}
824
+
825
+.cell-title {
826
+  display: -webkit-box;
827
+  /* 旧版弹性盒子模型 */
828
+  -webkit-box-orient: vertical;
829
+  /* 内容垂直排列 */
830
+  -webkit-line-clamp: 2;
831
+  /* 限制显示行数 */
832
+  overflow: hidden;
833
+  /* 超出隐藏 */
834
+  text-overflow: ellipsis;
835
+  /* 省略号 */
836
+  line-height: 1.5;
837
+  /* 可选:设置行高 */
838
+  max-height: calc(1.5em * 2);
839
+  /* 可选:根据行高限制最大高度 */
840
+  font-size: 16px;
841
+  font-weight: bold;
842
+  color: #333;
843
+  /* 字号 */
844
+}
845
+
846
+.swipe-cell-default {
847
+  display: flex;
848
+  background-color: #ffffff;
849
+  justify-content: center;
850
+  align-items: center;
851
+}
852
+
853
+.swipe-cell-default-icon {
854
+  width: 60px;
855
+  display: flex;
856
+  justify-content: center;
857
+}
858
+
859
+.delete-button {
860
+  height: 100%;
861
+  border: none;
862
+  color: #ff0000;
863
+  background-image: url('@/assets/img/del.png');
864
+  background-size: auto 100%;
865
+  background-repeat: no-repeat;
866
+}
867
+
868
+.submit-button {
869
+  height: 100%;
870
+  border: none;
871
+  color: #07c160;
872
+  background-image: url('@/assets/img/sub.png');
873
+  background-size: auto 100%;
874
+  background-repeat: no-repeat;
875
+}
876
+
877
+.subsuccess {
878
+  height: 100%;
879
+  border: none;
880
+  color: #07c160;
881
+  background-image: url('@/assets/img/sub1.png');
882
+  background-size: auto 100%;
883
+  background-repeat: no-repeat;
884
+}
885
+.single-line-text {
886
+  white-space: nowrap;        /* 强制不换行 */
887
+  overflow: hidden;           /* 超出部分隐藏 */
888
+  text-overflow: ellipsis;    /* 超出显示省略号 ... */
889
+  width: 100%;                /* 或指定宽度 */
890
+  box-sizing: border-box;
891
+}
892
+</style>

+ 753
- 0
src/view/knowledge/accidentList.vue Ver arquivo

@@ -0,0 +1,753 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref , computed } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+import OrganizationalWithLeafUserOne from '@/components/OrganizationalWithLeafUserOne.vue';
6
+const {
7
+  proxy
8
+} = getCurrentInstance()
9
+const accidentDictList = ref([])
10
+const columns =  ref([])
11
+const columnsLevel =  ref([])
12
+
13
+//     [
14
+//   { text: '杭州', value: 'Hangzhou' },
15
+//   { text: '宁波', value: 'Ningbo' },
16
+//   { text: '温州', value: 'Wenzhou' },
17
+//   { text: '绍兴', value: 'Shaoxing' },
18
+//   { text: '湖州', value: 'Huzhou' },
19
+// ];
20
+
21
+// 定义生成编号的函数(你已写好的逻辑)
22
+
23
+const generateCode = () => {
24
+  const now = new Date();
25
+  const year = now.getFullYear();
26
+  const month = String(now.getMonth() + 1).padStart(2, '0');
27
+  const day = String(now.getDate()).padStart(2, '0');
28
+  const formattedDate = `${year}${month}${day}`;
29
+  const hours = String(now.getHours()).padStart(2, '0');
30
+  const minutes = String(now.getMinutes()).padStart(2, '0');
31
+  const seconds = String(now.getSeconds()).padStart(2, '0');
32
+  const formattedTime = `${hours}${minutes}${seconds}`;
33
+  const sequenceNumber = Math.floor(Math.random() * 1000);
34
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
35
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
36
+};
37
+
38
+// 存储生成的编号(响应式变量)
39
+const generatedCode = ref(generateCode());
40
+
41
+// 重新生成编号的方法
42
+const regenerateCode = () => {
43
+  generatedCode.value = generateCode();
44
+};
45
+
46
+
47
+
48
+const getAccidentDicList = () => {
49
+  tools.dic.getDicList([ 'case_type','SEX', 'case_source','accident_level','accident_type','sgsafe_taccidentTags']).then((response => {
50
+    console.log(JSON.stringify(response.data.data))
51
+    accidentDictList.value = response.data.data
52
+    console.log('case_source',accidentDictList.value.case_source)
53
+    columns.value = accidentDictList.value.case_source.map(item => ({
54
+      text: item.dicName,
55
+      value: item.dicCode
56
+    }));
57
+    columnsLevel.value = accidentDictList.value.accident_level.map(item => ({
58
+      text: item.dicName,
59
+      value: item.dicCode
60
+    }));
61
+
62
+
63
+    console.log('accident_level',accidentDictList.value.accident_level)
64
+
65
+  }))
66
+}
67
+
68
+
69
+const caseSourceFlag = ref(false)
70
+const accidentLevelFlag = ref(false)
71
+let title = '新增事故案例'
72
+
73
+/* 返回上一级页面 */
74
+const router = useRouter()
75
+const onClickLeft = () => {
76
+  router.go(-1)
77
+}
78
+
79
+const currentYear = ref()
80
+currentYear.value = new Date().getFullYear()
81
+
82
+/* 获取用户部门信息 */
83
+const jsonArray = localStorage.getItem('dept')
84
+const deptInformation = ref([])
85
+try {
86
+  deptInformation.value = jsonArray ? JSON.parse(jsonArray) : [];
87
+} catch (error) {
88
+  deptInformation.value = [];
89
+}
90
+const deptName = deptInformation.value[0].deptName
91
+const deptCode = deptInformation.value[0].deptCode
92
+
93
+const guid = () =>  {
94
+  function S4() {
95
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
96
+  }
97
+  return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4())
98
+}
99
+const formJieguo = ref({
100
+  resultWhether:'',
101
+  resultDetail:'',
102
+  resultWhy:'',
103
+  resultFile:'',
104
+  itemsId:'',
105
+  resultFileId:'',
106
+  resType:''
107
+})
108
+const route = useRoute()
109
+let planInfo = {}
110
+const  userName1=localStorage.getItem('userName');
111
+const isEdit = ref(route.query.mark === '1');
112
+const isReadOnly = ref(route.query.readOnly === 'true');
113
+const isCaseSubmitted = computed(() => isReadOnly.value && isEdit.value);
114
+const result=ref('')
115
+const fromVue=ref({})
116
+if (route.query.mark) {
117
+  planInfo = JSON.parse(route.query.mark)
118
+}
119
+console.log(planInfo);
120
+// 新增模式
121
+if (planInfo==-1){
122
+  const caseNumber = generateCode();
123
+  const fileId = ref()
124
+  result.value= caseNumber
125
+  //初始化 fromVue
126
+  fromVue.value = {
127
+    caseNumber: caseNumber,
128
+    caseTitle: '',
129
+    caseSource: '',
130
+    accidentLevel: '',
131
+    accidentDept: '',
132
+    accidentLocation: '',
133
+    accidentTime: '',
134
+    accidentType: '',
135
+    accidentTags: '',
136
+    casualtyCount: '',
137
+    accidentSummary: '',
138
+    preventiveMeasures: '',
139
+    fileId: fileId,
140
+    viewCount: '0',
141
+    downloadCount: '0'
142
+  };
143
+  console.log( result.value);
144
+}
145
+
146
+const resDetail=ref('')
147
+const ruleIds = ref([]);
148
+/*const getRuleId = () => {
149
+  var url = '/sgsafe/ExamHead/getCheckRuleId'
150
+  var param = {}
151
+  proxy.$axios.get(url, param).then(response => {
152
+    if (response.data.code == '0') {
153
+      ruleIds.value = response.data.data
154
+    } else {
155
+      console.log("1111111");
156
+    }
157
+  })
158
+  console.log('ruleIds', ruleIds)
159
+}
160
+getRuleId()*/
161
+const showRule=ref(false);
162
+
163
+const distestType=ref(false)
164
+if (planInfo==1) {
165
+  console.log(planInfo);
166
+  title = '查看事故案例'
167
+  fromVue.value= JSON.parse(route.query.data)
168
+  if (!fromVue.value.fileId) {
169
+    const newFileId = guid();
170
+    fromVue.value.fileId = newFileId;
171
+    result.value = newFileId;
172
+  } else {
173
+    result.value = fromVue.value.fileId;
174
+  }
175
+
176
+  console.log('编辑模式 - fileId:', result.value);
177
+}
178
+ const  whether=ref(false)
179
+
180
+const planLevelList1=ref([])
181
+
182
+const onConfirmDatetime = () => {
183
+  const year = currentDate.value[0];
184
+  const month = currentDate.value[1].toString().padStart(2, '0');
185
+  const day = currentDate.value[2].toString().padStart(2, '0');
186
+  const hours = currentTime.value[0].toString().padStart(2, '0');
187
+  const minutes = currentTime.value[1].toString().padStart(2, '0');
188
+  const seconds = currentTime.value[2].toString().padStart(2, '0');
189
+
190
+  fromVue.value.accidentTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
191
+  showDatetimePicker.value = false;
192
+  dateOrTime.value = false;
193
+};
194
+
195
+
196
+const showDatetimePicker = ref(false);
197
+const currentTime = ref();
198
+const minDate = ref();
199
+const maxDate = ref();
200
+
201
+const dateOrTime = ref(false);
202
+const onDateConfirm = () => {
203
+  // 日期选择确认后的处理
204
+  dateOrTime.value = true;
205
+};
206
+const resetDatetime = () => {
207
+  dateOrTime.value = false;
208
+
209
+  // 初始化日期和时间
210
+  if (fromVue.value.accidentTime) {
211
+    const dt = new Date(fromVue.value.accidentTime);
212
+    currentDate.value = [dt.getFullYear(), dt.getMonth() + 1, dt.getDate()];
213
+    currentTime.value = [
214
+      String(dt.getHours()).padStart(2, '0'),
215
+      String(dt.getMinutes()).padStart(2, '0'),
216
+      String(dt.getSeconds()).padStart(2, '0')
217
+    ];
218
+  } else {
219
+    const now = new Date();
220
+    currentDate.value = [now.getFullYear(), now.getMonth() + 1, now.getDate()];
221
+    currentTime.value = [
222
+      String(now.getHours()).padStart(2, '0'),
223
+      String(now.getMinutes()).padStart(2, '0'),
224
+      String(now.getSeconds()).padStart(2, '0')
225
+    ];
226
+  }
227
+};
228
+const cancelDatePicker = () => {
229
+  showDatetimePicker.value = false;
230
+  resetDatetime();
231
+};
232
+
233
+// 时间选择器取消
234
+const cancelTimePicker = () => {
235
+  resetDatetime();
236
+  // 重置为当前时间或从表单获取时间
237
+  if (fromVue.value.accidentTime) {
238
+    const dt = new Date(fromVue.value.accidentTime);
239
+    currentTime.value = [
240
+      String(dt.getHours()).padStart(2, '0'),
241
+      String(dt.getMinutes()).padStart(2, '0'),
242
+      String(dt.getSeconds()).padStart(2, '0')
243
+    ];
244
+  } else {
245
+    const now = new Date();
246
+    currentTime.value = [
247
+      String(now.getHours()).padStart(2, '0'),
248
+      String(now.getMinutes()).padStart(2, '0'),
249
+      String(now.getSeconds()).padStart(2, '0')
250
+    ];
251
+  }
252
+};
253
+
254
+
255
+/* 下拉框 */
256
+const showActionSheet = ref(false)
257
+const showActionSheet1 = ref(false)
258
+const planLevelList = [
259
+  { name: '转发', value: '转发' },
260
+  { name: '内部', value: '内部' },
261
+  { name: '文章', value: '文章' }
262
+];
263
+const isdisabled=ref(true)
264
+const isdisabled2=ref(true)
265
+const onSelect = (item) => {
266
+fromVue.value.fileContent = item.name
267
+
268
+  showActionSheet.value=false
269
+}
270
+
271
+const onSelect2 = (item) => {
272
+  fromVue.value.fileType=item.name
273
+  showActionSheet2.value=false
274
+  }
275
+
276
+const onCaseSourseSelect = (item) => {
277
+  fromVue.value.caseSource=item.dicCode
278
+  caseSourceFlag.value = false
279
+}
280
+
281
+const onAccidentLevelSelect = (item) => {
282
+  fromVue.value.accidentLevel = item.dicCode
283
+  accidentLevelFlag.value = false
284
+
285
+}
286
+
287
+const displayFileName = ref('')
288
+const onSelect1 = (item) => {
289
+  console.log(item);
290
+  formJieguo.value.resultFile = item.value
291
+  result.value=formJieguo.value.resultFile
292
+  displayFileName.value = item.name
293
+  console.log(result.value);
294
+  showActionSheet1.value = false
295
+}
296
+const questionIds = ref([])
297
+const actions=ref([])
298
+/*const getQuestionId = () => {
299
+  var url = '/sgsafe/AssessmentRecord/queryRuleNoPage';
300
+  var param = {};
301
+  proxy.$axios.get(url, param).then(response => {
302
+    if (response.data.code == '0') {
303
+      questionIds.value = response.data.data; // 先赋值给 questionIds.value
304
+
305
+
306
+      // ✅ 关键:使用 questionIds.value.map
307
+      actions.value = questionIds.value.map(item => ({
308
+        name: item.ruleName,
309
+        value: item.id
310
+      }));
311
+      console.log('actions:', actions.value); // 看看有没有输出
312
+    } else {
313
+      ElMessage.error('操作失败!' + response.data.msg);
314
+    }
315
+  });
316
+};
317
+getQuestionId()*/
318
+
319
+const baocun3 = (ruleFormRef) => {
320
+  console.log(formJieguo.value)
321
+  ruleFormRef.validate((valid, fields) => {
322
+    if (valid) {
323
+
324
+      var url = '/sgsafe/ItemsResult/save';
325
+      var param = {
326
+        json: JSON.stringify(formJieguo.value)
327
+      };
328
+      proxy.$axios.post(url, param).then(response => {
329
+        if (response.data.code == '0') {
330
+          getTableData1()
331
+          ElMessage({
332
+            message: '保存成功',
333
+            type: 'success',
334
+          })
335
+          if (ruleFormRef.value) {
336
+            ruleFormRef.value.resetFields();
337
+          }
338
+          dialogVisibletemplate.value=false
339
+        } else {
340
+          ElMessage.error('操作失败!' + response.data.msg)
341
+        }
342
+
343
+      })
344
+    }
345
+  })
346
+}
347
+
348
+/* 组织树选择 */
349
+const showBottom = ref(false)
350
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
351
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
352
+const handleTableDataUserDeptUpdate = async (nodeData) => {
353
+  formJieguo.value.drillDept = nodeData.deptCode + '-' + nodeData.deptName
354
+  showBottom.value = false
355
+}
356
+
357
+const addEmergencyDrillPlan = async () => {
358
+  const loadingToast = showLoadingToast({
359
+    duration: 0,
360
+    message: '加载中',
361
+    forbidClick: true
362
+  })
363
+  
364
+  fromVue.value.fileId = result.value
365
+
366
+  var url = '/sgsafe/Manager/saveAccident';
367
+  const params = {
368
+    json: JSON.stringify(fromVue.value)
369
+  }
370
+  proxy.$axios.post(url,params).then(res=>{
371
+    if (res.data.code === 0) {
372
+      loadingToast.close()
373
+      showSuccessToast('保存成功')
374
+      onClickLeft()
375
+
376
+    } else {
377
+      loadingToast.close()
378
+      showFailToast('操作失败!' + res.data.msg)
379
+    }
380
+  })
381
+}
382
+const showDatePicker = ref(false)
383
+const onDatePicker = (value) => {
384
+  const dateArr = value.selectedValues
385
+  fromVue.value.checkTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
386
+  showDatePicker.value = false
387
+}
388
+const currentDate = ref([2025, 7, 25])
389
+//定义字典集合
390
+const dicList = ref([])
391
+//获取字典集合
392
+// import tools from '@/tools'
393
+const getDicList = () => {
394
+  tools.dic.getDicList(['systemTypes']).then((response => {
395
+
396
+   const rawData = response.data.data
397
+    dicList.value = rawData.systemTypes.map(item => ({
398
+      name: item.dicName,      // 必须有 name 字段!
399
+      code: item.dicCode       // 可选,保留原始 code 供后续使用
400
+    }));
401
+    console.log(JSON.stringify(dicList.value))
402
+  }))
403
+}
404
+onMounted(() => {
405
+  getAccidentDicList()
406
+  console.log('这是编辑页面')
407
+  const today = new Date()
408
+  const year = today.getFullYear()
409
+  const month = today.getMonth() + 1 // 月份从 0 开始
410
+  const day = today.getDate()
411
+  currentDate.value = [year, month, day]
412
+  // 初始化时间
413
+  currentTime.value = [today.getHours(), today.getMinutes(), today.getSeconds()];
414
+  // 如果是编辑模式且有已有的事故时间,解析并初始化
415
+  if (isEdit.value && fromVue.value.accidentTime) {
416
+    try {
417
+      // 解析格式如 "2025-01-15 14:30:00" 的时间字符串
418
+      const timeStr = fromVue.value.accidentTime;
419
+      const [datePart, timePart] = timeStr.split(' ');
420
+      if (datePart && timePart) {
421
+        const [year, month, day] = datePart.split('-').map(Number);
422
+        const [hours, minutes, seconds] = timePart.split(':').map(Number);
423
+        currentDate.value = [year, month, day];
424
+        currentTime.value = [hours || 0, minutes || 0, seconds || 0];
425
+      }
426
+    } catch (error) {
427
+      console.error('解析事故时间失败:', error);
428
+    }
429
+  }
430
+  //selectedDateText.value = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
431
+  getDicList()
432
+})
433
+const showActionSheet2=ref(false)
434
+/* 文件上传 */
435
+import AttachmentS3 from '@/components/AttachmentS3.vue';
436
+
437
+const onSubmit = (values) => {
438
+  addEmergencyDrillPlan()
439
+}
440
+const leaderKeyysr = guid();
441
+const PopupDepartmentLeaderNameRefysr = ref();
442
+const handleDepartmentLeaderNameysr = () => {
443
+  PopupDepartmentLeaderNameRefysr.value.open();
444
+};
445
+const getDepartmentLeaderNameysr = (item) => {
446
+  fromVue.value.punCode = item.user.userCode;
447
+  fromVue.value.punName = item.user.userDesc;
448
+  fromVue.value.punId = item.user.id
449
+};
450
+
451
+const onCaseSourceConfirm = ({ selectedOptions }) => {
452
+  caseSourceFlag.value = false;
453
+  fromVue.value.caseSource = selectedOptions[0].text;
454
+};
455
+
456
+const onAccidentLevelConfirm = ({ selectedOptions }) => {
457
+  accidentLevelFlag.value = false;
458
+  fromVue.value.accidentLevel = selectedOptions[0].text;
459
+};
460
+
461
+</script>
462
+
463
+<template>
464
+
465
+  <div class="page-container">
466
+    <van-sticky class="header">
467
+      <van-nav-bar
468
+        :title="title"
469
+        left-text="返回"
470
+        left-arrow
471
+        @click-left="onClickLeft" >
472
+      </van-nav-bar>
473
+    </van-sticky>
474
+    <div class="scroll-container">
475
+      <van-form @submit="onSubmit">
476
+<!--        <van-field-->
477
+<!--          v-model="fromVue.caseNumber"-->
478
+<!--          label="案例编号"-->
479
+<!--          name="caseNumber"-->
480
+<!--          required-->
481
+<!--          placeholder="请输入案例编号"-->
482
+<!--          :rules="[{required: true, message: '请输入文件编号'}]"-->
483
+<!--        />-->
484
+        <van-field
485
+            v-model="fromVue.caseNumber"
486
+        label="案例编号"
487
+        name="caseNumber"
488
+            readonly
489
+        :rules="[{required: true, message: '编号生成失败,请点击“重新生成”'}]"
490
+        />
491
+
492
+        <van-field
493
+          v-model="fromVue.caseTitle"
494
+          label="案例标题"
495
+          name="caseTitle"
496
+          :readonly="isCaseSubmitted"
497
+          required
498
+          placeholder="请输入案例标题"
499
+          :rules="[{required: true, message: '请输入标题名称'}]"
500
+        />
501
+
502
+        <van-field
503
+          v-model="fromVue.caseSource"
504
+          readonly
505
+          label="案例来源"
506
+          name="caseSource"
507
+          :readonly="isCaseSubmitted"
508
+          @click="!isCaseSubmitted && (caseSourceFlag = true)"
509
+        />
510
+        <van-field
511
+          readonly
512
+          v-model="fromVue.accidentLevel"
513
+          label="事故等级"
514
+          name="accidentLevel"
515
+          :readonly="isCaseSubmitted"
516
+          @click="!isCaseSubmitted && (accidentLevelFlag = true)"
517
+        />
518
+
519
+        <van-field
520
+            v-model="fromVue.accidentDept"
521
+            label="事故单位"
522
+            name="accidentDept"
523
+            placeholder="请输入事故单位"
524
+            :readonly="isCaseSubmitted"
525
+            :rules="[{required: true, message: '请输入事故单位'}]"
526
+        />
527
+
528
+        <van-field
529
+            v-model="fromVue.accidentLocation"
530
+            label="事故地点"
531
+            name="accidentLocation"
532
+            :readonly="isCaseSubmitted"
533
+            placeholder="请输入事故地点"
534
+            :rules="[{required: true, message: '请输入事故地点'}]"
535
+        />
536
+
537
+<!--        //时间-->
538
+        <van-field
539
+            v-model="fromVue.accidentTime"
540
+            is-link
541
+            readonly
542
+            name="datetime"
543
+            label="发生时间"
544
+            :colon="true"
545
+            placeholder="点击选择日期和时间"
546
+            @click="showDatetimePicker = !isCaseSubmitted"
547
+            :rules="[{ required:true, message: '请选择内容' }]"
548
+        />
549
+
550
+        <van-popup
551
+            v-model:show="showDatetimePicker"
552
+            position="bottom"
553
+            round
554
+            style="max-height: 50vh;"
555
+        >
556
+          <van-date-picker
557
+              v-if="!dateOrTime"
558
+              v-model="currentDate"
559
+              title="选择日期"
560
+              :min-date="minDate"
561
+              :max-date="maxDate"
562
+              @confirm="onDateConfirm"
563
+              @cancel="cancelDatePicker"
564
+          >
565
+            <template #confirm>
566
+              <van-button type="primary" @click="onDateConfirm">下一步</van-button>
567
+            </template>
568
+            <template #cancel>
569
+              <van-button type="danger" @click="cancelDatePicker">取消</van-button>
570
+            </template>
571
+          </van-date-picker>
572
+
573
+          <van-time-picker
574
+              v-if="dateOrTime"
575
+              v-model="currentTime"
576
+              title="选择时间"
577
+              :columns-type="['hour', 'minute', 'second']"
578
+              @confirm="onConfirmDatetime"
579
+              @cancel="cancelTimePicker"
580
+          >
581
+            <template #confirm>
582
+              <van-button type="primary" @click="onConfirmDatetime">确定</van-button>
583
+            </template>
584
+            <template #cancel>
585
+              <van-button type="danger" @click="cancelTimePicker">取消</van-button>
586
+            </template>
587
+          </van-time-picker>
588
+        </van-popup>
589
+<!--        // 标签-->
590
+
591
+        <van-field
592
+            v-model="fromVue.accidentTags"
593
+            label="关键词/标签"
594
+            name="accidentTags"
595
+            :readonly="isCaseSubmitted"
596
+            :rules="[{required: true, message: '请输入事故关键词/标签”'}]"
597
+        />
598
+
599
+        <van-field
600
+            v-model="fromVue.casualtyCount"
601
+            label="事故造成后果"
602
+            name="casualtyCount"
603
+            rows="1"
604
+            autosize
605
+            type="textarea"
606
+            placeholder="请输入事故造成后果"
607
+            :readonly="isCaseSubmitted"
608
+            :rules="[{required: true, message: '请输入事故造成后果'}]"
609
+        />
610
+        <van-field
611
+            v-model="fromVue.accidentSummary"
612
+            label="事故简要经过"
613
+            name="accidentSummary"
614
+            rows="3"
615
+            autosize
616
+            type="textarea"
617
+            placeholder="请输入事故简要经过"
618
+            :readonly="isCaseSubmitted"
619
+            :rules="[{required: true, message: '请输入事故简要经过'}]"
620
+        />
621
+        <van-field
622
+            v-model="fromVue.preventiveMeasures"
623
+            label="防范与整改措施"
624
+            name="preventiveMeasures"
625
+            rows="3"
626
+            autosize
627
+            type="textarea"
628
+            placeholder="请输入防范与整改措施"
629
+            :readonly="isCaseSubmitted"
630
+            :rules="[{required: true, message: '请输入防范与整改措施'}]"
631
+        />
632
+
633
+        <van-field label="附件上传" >
634
+          <template #input>
635
+            <AttachmentS3 :f-id="result" />
636
+          </template>
637
+        </van-field>
638
+        <div style="margin: 16px;">
639
+          <van-button v-if="!isReadOnly" round block type="primary" native-type="submit">
640
+            {{ isEdit ? '保存' : '提交' }}
641
+          </van-button>
642
+        </div>
643
+      </van-form>
644
+
645
+      <van-action-sheet
646
+        v-model:show="showActionSheet"
647
+        :actions="planLevelList"
648
+        @select="onSelect"
649
+      />
650
+      <van-action-sheet
651
+        v-model:show="showActionSheet2"
652
+        :actions="dicList"
653
+        @select="onSelect2"
654
+      />
655
+
656
+      <van-action-sheet
657
+          v-model:show="caseSourceFlag"
658
+          :actions="accidentDictList.case_source"
659
+          @select="onCaseSourseSelect"
660
+      />
661
+
662
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
663
+        <van-picker
664
+            :columns="columns"
665
+            @cancel="caseSourceFlag = false"
666
+            @confirm="onCaseSourceConfirm"
667
+        />
668
+      </van-popup>
669
+
670
+      <van-popup v-model:show="accidentLevelFlag" round position="bottom">
671
+        <van-picker
672
+            :columns="columnsLevel"
673
+            @cancel="accidentLevelFlag = false"
674
+            @confirm="onAccidentLevelConfirm"
675
+        />
676
+      </van-popup>
677
+
678
+<!--      <van-action-sheet-->
679
+<!--          v-model:show="accidentLevelFlag"-->
680
+<!--          :actions="accidentDictList.accident_level"-->
681
+<!--          @select="onAccidentLevelSelect"-->
682
+<!--      />-->
683
+
684
+<!--      <van-action-sheet-->
685
+<!--        v-model:show="showActionSheet1"-->
686
+<!--        :actions="planLevelList1"-->
687
+<!--        field-names="{ text: 'fileName', value: 'fileId' }"-->
688
+<!--        @select="onSelect1"-->
689
+<!--      />-->
690
+
691
+      <van-popup v-model:show="showBottom" position="bottom" :style="{ height: '30%' }">
692
+        <OrganizationalWithLeaf @update:selected-node="handleTableDataUserDeptUpdate" />
693
+      </van-popup>
694
+      <van-popup v-model:show="showDatePicker" position="bottom">
695
+        <van-date-picker
696
+          v-model="currentDate"
697
+          @confirm="onDatePicker"
698
+          @cancel="showDatePicker = false" />
699
+      </van-popup>
700
+    </div>
701
+  </div>
702
+</template>
703
+
704
+<style scoped>
705
+.page-container {
706
+  height: 100vh; /* 关键:外层容器高度设为视口高度 */
707
+  display: flex;
708
+  flex-direction: column;
709
+
710
+}
711
+/*  overflow-y: auto; !* 启用垂直滚动 *!*/
712
+
713
+
714
+.scroll-container {
715
+  flex: 1;
716
+  overflow: auto;
717
+  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
718
+}
719
+
720
+/* 可选:隐藏滚动条(视觉优化) */
721
+.scroll-container::-webkit-scrollbar {
722
+  display: none;
723
+}
724
+
725
+.header, .footer {
726
+  /* 固定高度区域 */
727
+  flex-shrink: 0; /* 防止被压缩 */
728
+  background: #f5f5f5;
729
+  padding: 12px;
730
+}
731
+.row-container {
732
+  display: flex;
733
+  justify-content: space-between; /* 关键:左右分布 */
734
+  align-items: center;             /* 垂直居中 */
735
+
736
+}
737
+
738
+.cell-period-text {
739
+  font-size: 14px;
740
+  color: #333;
741
+  white-space: nowrap;
742
+  overflow: hidden;
743
+  text-overflow: ellipsis;
744
+
745
+}
746
+
747
+.mini-btn {
748
+  height: 22px;
749
+  font-size: 12px;
750
+  padding: 0 8px;
751
+  min-width: 60px;                 /* 可选:保持按钮最小宽度一致 */
752
+}
753
+</style>

+ 617
- 0
src/view/knowledge/manager.vue Ver arquivo

@@ -0,0 +1,617 @@
1
+<template>
2
+  <div class="h5-container">
3
+    <van-nav-bar title="管理案例" @click-left="onClickLeft" @click-right="handAdd">
4
+      <template #right>
5
+        <van-icon name="add" size="25" color="#000" />
6
+      </template>
7
+    </van-nav-bar>
8
+    <van-search v-model="query.caseTitle" show-action placeholder="请输入案例标题" @search="onRefresh"
9
+                @cancel="handdelectTitle" />
10
+
11
+    <!-- 项目列表 -->
12
+    <van-pull-refresh v-model="isRefreshing" success-text="刷新成功" @refresh="onRefresh">
13
+      <van-list v-model:loading="isLoading" :finished="isFinished" finished-text="没有更多了" offset="200" @load="onLoad">
14
+        <div v-for="(item, idx) in resultData" :key="item.id">
15
+          <van-swipe-cell title-style="color: #007aff" style="height: 80px;" :ref="el => getSwipeCellRef(el, idx)">
16
+            <template #default>
17
+              <div class="swipe-cell-default">
18
+                <van-cell style="min-height: 100px; padding: 0 0 0 0; display: flex; align-items: flex-start;" @click="edits(item)">
19
+                  <template #title>
20
+                    <div class="cell-title">
21
+                      {{ item.caseTitle }}
22
+                    </div>
23
+                  </template>
24
+                  <template #label>
25
+                      <div>案例编号:{{ item.caseNumber }} </div>
26
+                      <div>案例类型:{{ item.caseType }}</div>
27
+                      <div> 浏览量:{{item.viewCount}}</div>
28
+
29
+<!--                    <div style="width: 112px" :class="getStatusClass(item.isFinish)">
30
+                      类型:
31
+                      <span v-if="item.isFinish === '待学习'" style="width: 200px">待学习</span>
32
+                      <span v-else-if="item.isFinish === '已学习'" style="width: 200px">已学习</span>
33
+                      <span v-else-if="item.isFinish === '已扣除'" style="width: 200px">已扣除</span>
34
+                    </div>-->
35
+                  </template>
36
+                </van-cell>
37
+                <div class="swipe-cell-default-icon">
38
+                  <van-icon v-if="openStatus[idx]" name="arrow-double-left" @click.stop="openSwipe(idx)" />
39
+                  <van-icon v-else name="arrow-double-right" @click.stop="closeSwipe(idx)" />
40
+                </div>
41
+              </div>
42
+            </template>
43
+
44
+            <template #right>
45
+              <van-button  square class="delete-button" text="删除" v-show="item.canDelete"  @click="handleDelete(item)" />
46
+            </template>
47
+          </van-swipe-cell>
48
+        </div>
49
+
50
+      </van-list>
51
+    </van-pull-refresh>
52
+
53
+    <!-- 删除确认弹窗 -->
54
+    <van-dialog v-model:show="deleteDialogVisible" show-cancel-button @confirm="confirmDelete">
55
+      <template #title>
56
+        <div>删除确认</div>
57
+      </template>
58
+      <div style="padding: 30px;">确定要删除该项目吗?</div>
59
+    </van-dialog>
60
+
61
+  </div>
62
+</template>
63
+
64
+<script setup>
65
+import { ref, reactive, onMounted, getCurrentInstance, nextTick, toRaw } from 'vue';
66
+import { Dialog, showDialog, showSuccessToast, showToast, Toast } from 'vant';
67
+
68
+import tools from '@/tools'
69
+
70
+const { proxy } = getCurrentInstance();
71
+
72
+const onClickLeft = () => {
73
+  history.back();
74
+};
75
+const headers = ref({
76
+  token: localStorage.getItem('token'),
77
+  userId: localStorage.getItem('userId'),
78
+  dept: JSON.parse(localStorage.getItem('dept'))[0].deptCode
79
+});
80
+const switchIconState = (idx) => {
81
+  openStatus.value[idx] = !openStatus.value[idx]
82
+  openStatus.value = new Array(resultData.value.length).fill(true);
83
+}
84
+
85
+// const onClickRight = () =>{
86
+//   searchShow.value = !searchShow.value;
87
+// }
88
+
89
+const searchShow = ref(false);
90
+const query = ref({
91
+  caseNumber:'',
92
+  caseTitle:'',
93
+})
94
+
95
+
96
+
97
+const tableData = ref([]);
98
+const selectedRows = ref([]);
99
+const dialogVisibleLook = ref(false);
100
+const deleteDialogVisible = ref(false);
101
+const currentDeleteItem = ref([]);
102
+const dialogVisible = ref(false);
103
+const dialogVisibleFile = ref(false);
104
+const date = ref(null);
105
+
106
+const kz = ref(true);
107
+import { useRouter } from 'vue-router';
108
+const router = useRouter();
109
+const handAdd =  () => {
110
+
111
+  router.push({ path: "/managerList",
112
+    query: {
113
+      mark:-1
114
+    } });
115
+
116
+};
117
+const goaddPeo = (item) => {
118
+  router.push({
119
+    path: '/addPeo',
120
+    query: {
121
+      data: JSON.stringify(item)
122
+    }
123
+  })
124
+}
125
+
126
+const edits = (row) => {
127
+  const isOwner = String(row.addId) === currentUserId;
128
+  kz.value = true;
129
+  form.value = { ...row };
130
+  router.push({ path: "/managerList",
131
+    query: {
132
+      mark:1,
133
+      data:JSON.stringify(form.value),
134
+      readOnly: !isOwner ? 'true' : undefined
135
+    } });
136
+  //浏览量
137
+  saveManagerRecord(form.value)
138
+};
139
+
140
+const saveManagerRecord = async (formValue) => {
141
+  const payload = formValue;
142
+  payload.viewCount = String((Number(payload.viewCount) || 0) + 1);
143
+
144
+  var url = '/sgsafe/Manager/save';
145
+  var param = {
146
+    json: JSON.stringify(payload)
147
+  };
148
+  proxy.$axios.post(url, param).then(response => {
149
+    if (response.data.code == '0') {
150
+      getTableData();
151
+    }
152
+  });
153
+};
154
+const form = ref({
155
+  caseNumber:'',
156
+  caseTitle:'',
157
+  caseSource:'',
158
+  accidentLevel:'',
159
+  accidentDept:'',
160
+  accidentLocation:'',
161
+  accidentTime:'',
162
+  accidentType:'',
163
+  accidentTags:'',
164
+  casualtyCount:'',
165
+  accidentSummary:'',
166
+  preventiveMeasures:'',
167
+  fileId:'',
168
+  viewCount:'',
169
+  downloadCount:''
170
+});
171
+
172
+
173
+const isRefreshing = ref(false);
174
+const isLoading = ref(false);
175
+const isFinished = ref(false);
176
+const currentPage = ref(1);
177
+const pageSize = ref(10);
178
+const totalRows = ref(0);
179
+const resultData = ref([]);
180
+
181
+const dept=localStorage.getItem("dept")[0].deptCode;
182
+const currentUserId = String(localStorage.getItem('userId'));
183
+const getTableData = async () => {
184
+  var url = '/sgsafe/Manager/query'
185
+  var param = {
186
+    page: currentPage.value,
187
+    rows: pageSize.value,
188
+    params: JSON.stringify(query.value)
189
+  }
190
+  const response = await proxy.$axios.get(url, param);
191
+  if (response.data.code == 0) {
192
+    tableData.value = response.data.data.records.map(item => ({
193
+      ...item,
194
+      canDelete: String(item.addId) === currentUserId
195
+    }));
196
+    console.log('列表数据',tableData.value)
197
+    totalRows.value = response.data.data.total;
198
+  } else {
199
+    showToast({
200
+      type: 'error',
201
+      message: '操作失败!' + response.data.msg
202
+    });
203
+  }
204
+};
205
+const ruleIds = ref([]);
206
+
207
+const onRefresh = () => {
208
+  basicReset();
209
+  onLoad();
210
+};
211
+
212
+//*************************************
213
+
214
+
215
+
216
+//定义字典集合
217
+const dicList = ref([])
218
+
219
+const getDicList = () => {
220
+  tools.dic.getDicList([ 'case_type','SEX', 'case_source','accident_level','accident_type','sgsafe_taccidentTags']).then((response => {
221
+    console.log(JSON.stringify(response.data.data))
222
+    dicList.value = response.data.data
223
+
224
+  }))
225
+}
226
+
227
+
228
+const onLoad = async () => {
229
+  if (isRefreshing.value) {
230
+    resultData.value = [];
231
+    currentPage.value = 1;
232
+    isRefreshing.value = false;
233
+  }
234
+
235
+  getDicList()
236
+
237
+
238
+
239
+
240
+
241
+  try {
242
+    await getTableData();
243
+
244
+    if (pageSize.value * currentPage.value < totalRows.value) {
245
+      resultData.value = [...resultData.value, ...tableData.value];
246
+      openStatus.value = new Array(resultData.value.length).fill(true);
247
+      currentPage.value++;
248
+
249
+    } else {
250
+      resultData.value = [...resultData.value, ...tableData.value];
251
+      openStatus.value = new Array(resultData.value.length).fill(true);
252
+      isFinished.value = true;
253
+    }
254
+
255
+    console.log('resultData',resultData.value)
256
+  } catch (error) {
257
+    console.log(error);
258
+    isFinished.value = true;
259
+  } finally {
260
+    isLoading.value = false;
261
+  }
262
+};
263
+/* 通用方法: 重置list数据 */
264
+const basicReset = () => {
265
+  isFinished.value = false;
266
+  isLoading.value = true;
267
+  currentPage.value = 1;
268
+  resultData.value = [];
269
+};
270
+
271
+/*onMounted(() => {
272
+  handleSearch();
273
+});
274
+
275
+const handleSearch = () => {
276
+/!*  currentPage.value = 1;
277
+  isFinished.value = false;
278
+  tableData.value = [];*!/
279
+  basicReset()
280
+  onLoad()
281
+};*/
282
+
283
+const handdelectNumber = () => {
284
+  query.value.caseNumber = '';
285
+  onRefresh()
286
+};
287
+
288
+const handdelectTitle = () => {
289
+  query.value.caseTitle = '';
290
+  onRefresh()
291
+};
292
+
293
+
294
+
295
+
296
+// 定义生成编号的函数
297
+const generateCode = () => {
298
+  // 获取当前日期并格式化为 YYYYMMDD
299
+  const now = new Date();
300
+  const year = now.getFullYear();
301
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需加1
302
+  const day = String(now.getDate()).padStart(2, '0');
303
+  const formattedDate = `${year}${month}${day}`;
304
+  // 时间部分:HHmmss
305
+  const hours = String(now.getHours()).padStart(2, '0');
306
+  const minutes = String(now.getMinutes()).padStart(2, '0');
307
+  const seconds = String(now.getSeconds()).padStart(2, '0');
308
+  const formattedTime = `${hours}${minutes}${seconds}`;
309
+
310
+  // 模拟生成三位流水号(可以根据需要替换为递增逻辑)
311
+  const sequenceNumber = Math.floor(Math.random() * 1000); // 随机生成 0-999
312
+  const paddedSequence = String(sequenceNumber).padStart(3, '0'); // 补零到三位
313
+
314
+  // 拼接编号
315
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
316
+};
317
+
318
+// 使用 ref 存储生成的编号
319
+const generatedCode = ref(generateCode());
320
+
321
+// 定义重新生成编号的方法
322
+const regenerateCode = () => {
323
+  generatedCode.value = generateCode();
324
+};
325
+
326
+const handleDetailLook = (row) => {
327
+  form.value = { ...row };
328
+  proxy.$router.push({
329
+    name: 'taiZhang_detail',
330
+    query: {
331
+      form: form.value.id
332
+    }
333
+  });
334
+  // dialogVisibleLook.value = true;
335
+};
336
+const deleteData=ref({})
337
+
338
+const handleDelete = (item) => {
339
+
340
+  deleteData.value=item
341
+  const now = new Date();
342
+  const year = now.getFullYear();
343
+  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
344
+  const day = String(now.getDate()).padStart(2, '0');
345
+  const hours = String(now.getHours()).padStart(2, '0');
346
+  const minutes = String(now.getMinutes()).padStart(2, '0');
347
+  const seconds = String(now.getSeconds()).padStart(2, '0');
348
+  deleteData.value.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
349
+
350
+    deleteData.value.cancelFlag='1'
351
+  var url = '/sgsafe/Manager/save';
352
+  var param = {
353
+    json: JSON.stringify(deleteData.value)
354
+  };
355
+  proxy.$axios.post(url, param).then(response => {
356
+    if (response.data.code == '0') {
357
+      showSuccessToast("删除成功")
358
+      onRefresh();
359
+
360
+    } else {
361
+    }
362
+
363
+  })
364
+};
365
+
366
+
367
+const confirmDelete = () => {
368
+  for (let item of currentDeleteItem.value) {
369
+    if (item.addId !== headers.value.userId) {
370
+      showToast({
371
+        type: 'warning',
372
+        message: '只能删除自己添加的数据!'
373
+      });
374
+      return;
375
+    }
376
+  }
377
+
378
+  if (currentDeleteItem.value[0].status !== '0' && currentDeleteItem.value[0].hdSelect !== '下发隐患'
379
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
380
+    showToast({
381
+      type: 'fail',
382
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
383
+    });
384
+    return;
385
+  }
386
+  if (currentDeleteItem.value[0].status !== '2' && currentDeleteItem.value[0].hdSelect === '下发隐患'
387
+    && currentDeleteItem.value[0].hdSelect !== '即查即改') {
388
+    showToast({
389
+      type: 'fail',
390
+      message: '只有尚未提交流程的记录或回到起点的流程经过作废后才可以删除!'
391
+    });
392
+    return;
393
+  }
394
+
395
+  var url = 'sgsafe/Hiddendanger/remove';
396
+  var param = {
397
+    params: JSON.stringify({ ...currentDeleteItem.value.map(x => x.id) })
398
+  };
399
+  proxy.$axios.get(url, param).then(response => {
400
+    if (response.data.code == 0) {
401
+      showToast({
402
+        type: 'success',
403
+        message: '删除成功'
404
+      });
405
+      onRefresh();
406
+    } else {
407
+      showToast({
408
+        type: 'fail',
409
+        message: '操作失败!' + response.data.msg
410
+      });
411
+    }
412
+  });
413
+};
414
+
415
+
416
+
417
+
418
+const resetForm = () => {
419
+  form.value = {
420
+    projectName: '',
421
+    projectLeader: '',
422
+    phone: '',
423
+    dept: ''
424
+  };
425
+};
426
+
427
+
428
+//处理人员code
429
+const repairLL = ref('');
430
+const repairOO = ref('');
431
+const acceptLL = ref('');
432
+
433
+const jsons = ref({});
434
+
435
+const reback = () => {
436
+  // 返回逻辑
437
+};
438
+
439
+const deleteRow = (row) => {
440
+  selectedRows.value = [row];
441
+  handleDelete(row);
442
+};
443
+
444
+const deleteRowa = (row) => {
445
+  deleteRow(row);
446
+};
447
+
448
+/**
449
+ * 按钮实现swipe-cell滑动
450
+ */
451
+const openStatus = ref([])
452
+const swipeCellRefs = ref([])
453
+const getSwipeCellRef = (el, index) => {
454
+  if (el) {
455
+    swipeCellRefs.value[index] = el;
456
+  }
457
+}
458
+const openSwipe = (idx) => {
459
+  openStatus.value = new Array(resultData.value.length).fill(true);
460
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
461
+    openStatus.value[idx] = false
462
+    swipeCellRefs.value[idx].open('right')
463
+  }
464
+  document.addEventListener('click', handleDocumentClick)
465
+}
466
+/**
467
+ * 当点击滑动单元格时,开始监听点击事件
468
+ */
469
+const handleDocumentClick = (event) => {
470
+  openStatus.value = new Array(resultData.value.length).fill(true);
471
+}
472
+
473
+const closeSwipe = (idx) => {
474
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
475
+    openStatus.value[idx] = true
476
+    swipeCellRefs.value[idx].close()
477
+  }
478
+}
479
+// *********************************** 事故案例 ************************************************
480
+
481
+
482
+
483
+
484
+
485
+</script>
486
+
487
+<style scoped>
488
+.h5-container {
489
+  width: 100%;
490
+  padding: 5px;
491
+  box-sizing: border-box;
492
+}
493
+
494
+.status-pending {
495
+  background-color: #fff3cd;
496
+  color: #856404;
497
+  padding: 2px 4px;
498
+  border-radius: 4px;
499
+}
500
+
501
+.status-registered {
502
+  background-color: #d1ecf1;
503
+  color: #0c5460;
504
+  padding: 2px 4px;
505
+  border-radius: 4px;
506
+}
507
+
508
+.status-analyzing {
509
+  background-color: #fff8e1;
510
+  color: #ff8f00;
511
+  padding: 2px 4px;
512
+  border-radius: 4px;
513
+}
514
+
515
+.status-rectifying {
516
+  background-color: #e8f5e9;
517
+  color: #2e7d32;
518
+  padding: 2px 4px;
519
+  border-radius: 4px;
520
+}
521
+
522
+.status-accepting {
523
+  background-color: #e3f2fd;
524
+  color: #1565c0;
525
+  padding: 2px 2px;
526
+  border-radius: 2px;
527
+}
528
+
529
+.status-closed {
530
+  background-color: #f8bbd0;
531
+  color: #b71c1c;
532
+  padding: 2px 2px;
533
+  border-radius: 2px;
534
+}
535
+
536
+.status-finished {
537
+  background-color: #e8eaf6;
538
+  color: #311b92;
539
+  padding: 2px 2px;
540
+  border-radius: 2px;
541
+}
542
+
543
+.status-unknown {
544
+  background-color: #efebe9;
545
+  color: #424242;
546
+  padding: 2px 2px;
547
+  border-radius: 2px;
548
+}
549
+
550
+.cell-title {
551
+  display: -webkit-box;
552
+  /* 旧版弹性盒子模型 */
553
+  -webkit-box-orient: vertical;
554
+  /* 内容垂直排列 */
555
+  -webkit-line-clamp: 2;
556
+  /* 限制显示行数 */
557
+  overflow: hidden;
558
+  /* 超出隐藏 */
559
+  text-overflow: ellipsis;
560
+  /* 省略号 */
561
+  line-height: 1.5;
562
+  /* 可选:设置行高 */
563
+  max-height: calc(1.5em * 2);
564
+  /* 可选:根据行高限制最大高度 */
565
+  font-size: 16px;
566
+  font-weight: bold;
567
+  color: #333;
568
+  /* 字号 */
569
+}
570
+
571
+.swipe-cell-default {
572
+  display: flex;
573
+  background-color: #ffffff;
574
+  justify-content: center;
575
+  align-items: center;
576
+}
577
+
578
+.swipe-cell-default-icon {
579
+  width: 60px;
580
+  display: flex;
581
+  justify-content: center;
582
+}
583
+
584
+.delete-button {
585
+  height: 100%;
586
+  border: none;
587
+  color: #ff0000;
588
+  background-image: url('@/assets/img/del.png');
589
+  background-size: auto 100%;
590
+  background-repeat: no-repeat;
591
+}
592
+
593
+.submit-button {
594
+  height: 100%;
595
+  border: none;
596
+  color: #07c160;
597
+  background-image: url('@/assets/img/sub.png');
598
+  background-size: auto 100%;
599
+  background-repeat: no-repeat;
600
+}
601
+
602
+.subsuccess {
603
+  height: 100%;
604
+  border: none;
605
+  color: #07c160;
606
+  background-image: url('@/assets/img/sub1.png');
607
+  background-size: auto 100%;
608
+  background-repeat: no-repeat;
609
+}
610
+.single-line-text {
611
+  white-space: nowrap;        /* 强制不换行 */
612
+  overflow: hidden;           /* 超出部分隐藏 */
613
+  text-overflow: ellipsis;    /* 超出显示省略号 ... */
614
+  width: 100%;                /* 或指定宽度 */
615
+  box-sizing: border-box;
616
+}
617
+</style>

+ 632
- 0
src/view/knowledge/managerList.vue Ver arquivo

@@ -0,0 +1,632 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref , computed } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+import OrganizationalWithLeafUserOne from '@/components/OrganizationalWithLeafUserOne.vue';
6
+const {
7
+  proxy
8
+} = getCurrentInstance()
9
+const accidentDictList = ref([])
10
+const columns =  ref([])
11
+const columnsLevel =  ref([])
12
+const columnsprimary=ref([])
13
+
14
+//     [
15
+//   { text: '杭州', value: 'Hangzhou' },
16
+//   { text: '宁波', value: 'Ningbo' },
17
+//   { text: '温州', value: 'Wenzhou' },
18
+//   { text: '绍兴', value: 'Shaoxing' },
19
+//   { text: '湖州', value: 'Huzhou' },
20
+// ];
21
+
22
+// 定义生成编号的函数(你已写好的逻辑)
23
+
24
+const generateCode = () => {
25
+  const now = new Date();
26
+  const year = now.getFullYear();
27
+  const month = String(now.getMonth() + 1).padStart(2, '0');
28
+  const day = String(now.getDate()).padStart(2, '0');
29
+  const formattedDate = `${year}${month}${day}`;
30
+  const hours = String(now.getHours()).padStart(2, '0');
31
+  const minutes = String(now.getMinutes()).padStart(2, '0');
32
+  const seconds = String(now.getSeconds()).padStart(2, '0');
33
+  const formattedTime = `${hours}${minutes}${seconds}`;
34
+  const sequenceNumber = Math.floor(Math.random() * 1000);
35
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
36
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
37
+};
38
+
39
+// 存储生成的编号(响应式变量)
40
+const generatedCode = ref('');
41
+
42
+// 重新生成编号的方法
43
+const regenerateCode = () => {
44
+  generatedCode.value = generateCode();
45
+};
46
+
47
+
48
+
49
+const getAccidentDicList = () => {
50
+  tools.dic.getDicList([ 'case_type','SEX', 'case_source','primary_domain','primary_domain_two','accident_level','accident_type','sgsafe_taccidentTags']).then((response => {
51
+    console.log(JSON.stringify(response.data.data))
52
+    accidentDictList.value = response.data.data
53
+    console.log('case_source',accidentDictList.value.case_source)
54
+    columns.value = accidentDictList.value.case_source.map(item => ({
55
+      text: item.dicName,
56
+      value: item.dicCode
57
+    }));
58
+    columnsLevel.value = accidentDictList.value.case_type.map(item => ({
59
+      text: item.dicName,
60
+      value: item.dicCode
61
+    }));
62
+    columnsprimary.value = accidentDictList.value.primary_domain.map(item => ({
63
+      text: item.dicName,
64
+      value: item.dicCode
65
+    }));
66
+
67
+
68
+    console.log('accident_level',accidentDictList.value.accident_level)
69
+
70
+  }))
71
+}
72
+
73
+
74
+const caseSourceFlag = ref(false)
75
+const accidentLevelFlag = ref(false)
76
+const primaryDomainFlag = ref(false)
77
+const primaryDomainTwoFlag = ref(false)
78
+let title = '新增事故案例'
79
+
80
+/* 返回上一级页面 */
81
+const router = useRouter()
82
+const onClickLeft = () => {
83
+  router.go(-1)
84
+}
85
+
86
+const currentYear = ref()
87
+currentYear.value = new Date().getFullYear()
88
+
89
+/* 获取用户部门信息 */
90
+const jsonArray = localStorage.getItem('dept')
91
+const deptInformation = ref([])
92
+try {
93
+  deptInformation.value = jsonArray ? JSON.parse(jsonArray) : [];
94
+} catch (error) {
95
+  deptInformation.value = [];
96
+}
97
+const deptName = deptInformation.value[0].deptName
98
+const deptCode = deptInformation.value[0].deptCode
99
+
100
+const guid = () =>  {
101
+  function S4() {
102
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
103
+  }
104
+  return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4())
105
+}
106
+const formJieguo = ref({
107
+  resultWhether:'',
108
+  resultDetail:'',
109
+  resultWhy:'',
110
+  resultFile:'',
111
+  itemsId:'',
112
+  resultFileId:'',
113
+  resType:''
114
+})
115
+const route = useRoute()
116
+let planInfo = {}
117
+const  userName1=localStorage.getItem('userName');
118
+const isEdit = ref(route.query.mark === '1');
119
+
120
+const result=ref('')
121
+const fromVue=ref({})
122
+if (route.query.mark) {
123
+  planInfo = JSON.parse(route.query.mark)
124
+}
125
+console.log(planInfo);
126
+if (planInfo==-1){
127
+  result.value=guid()
128
+  generatedCode.value = generateCode();
129
+  console.log( result.value);
130
+}
131
+
132
+const resDetail=ref('')
133
+const ruleIds = ref([]);
134
+/*const getRuleId = () => {
135
+  var url = '/sgsafe/ExamHead/getCheckRuleId'
136
+  var param = {}
137
+  proxy.$axios.get(url, param).then(response => {
138
+    if (response.data.code == '0') {
139
+      ruleIds.value = response.data.data
140
+    } else {
141
+      console.log("1111111");
142
+    }
143
+  })
144
+  console.log('ruleIds', ruleIds)
145
+}
146
+getRuleId()*/
147
+const showRule=ref(false);
148
+const showSmit=ref(true);
149
+const distestType=ref(false)
150
+if (planInfo==1) {
151
+  console.log(planInfo);
152
+  title = '修改管理档案'
153
+  fromVue.value= JSON.parse(route.query.data)
154
+  generatedCode.value = fromVue.value.caseNumber || '';
155
+  result.value=fromVue.value.fileId
156
+  const userIds= localStorage.getItem('userId')
157
+  if (userIds != fromVue.value.addId) {
158
+    showSmit.value=false
159
+    title = '查看管理档案'
160
+  }
161
+  console.log(result.value);
162
+}
163
+ const  whether=ref(false)
164
+
165
+const planLevelList1=ref([])
166
+
167
+
168
+/* 下拉框 */
169
+const showActionSheet = ref(false)
170
+const showActionSheet1 = ref(false)
171
+const planLevelList = [
172
+  { name: '转发', value: '转发' },
173
+  { name: '内部', value: '内部' },
174
+  { name: '文章', value: '文章' }
175
+];
176
+const isdisabled=ref(true)
177
+const isdisabled2=ref(true)
178
+const onSelect = (item) => {
179
+fromVue.value.fileContent = item.name
180
+
181
+  showActionSheet.value=false
182
+}
183
+
184
+const onSelect2 = (item) => {
185
+  fromVue.value.fileType=item.name
186
+  showActionSheet2.value=false
187
+  }
188
+
189
+const onCaseSourseSelect = (item) => {
190
+  fromVue.value.caseSource=item.dicCode
191
+  caseSourceFlag.value = false
192
+}
193
+
194
+const onAccidentLevelSelect = (item) => {
195
+  fromVue.value.accidentLevel = item.dicCode
196
+  accidentLevelFlag.value = false
197
+
198
+}
199
+
200
+const displayFileName = ref('')
201
+const onSelect1 = (item) => {
202
+  console.log(item);
203
+  formJieguo.value.resultFile = item.value
204
+  result.value=formJieguo.value.resultFile
205
+  displayFileName.value = item.name
206
+  console.log(result.value);
207
+  showActionSheet1.value = false
208
+}
209
+const questionIds = ref([])
210
+const actions=ref([])
211
+/*const getQuestionId = () => {
212
+  var url = '/sgsafe/AssessmentRecord/queryRuleNoPage';
213
+  var param = {};
214
+  proxy.$axios.get(url, param).then(response => {
215
+    if (response.data.code == '0') {
216
+      questionIds.value = response.data.data; // 先赋值给 questionIds.value
217
+
218
+
219
+      // ✅ 关键:使用 questionIds.value.map
220
+      actions.value = questionIds.value.map(item => ({
221
+        name: item.ruleName,
222
+        value: item.id
223
+      }));
224
+      console.log('actions:', actions.value); // 看看有没有输出
225
+    } else {
226
+      ElMessage.error('操作失败!' + response.data.msg);
227
+    }
228
+  });
229
+};
230
+getQuestionId()*/
231
+
232
+const baocun3 = (ruleFormRef) => {
233
+  console.log(formJieguo.value)
234
+  ruleFormRef.validate((valid, fields) => {
235
+    if (valid) {
236
+
237
+      var url = '/sgsafe/Manager/save';
238
+      var param = {
239
+        json: JSON.stringify(formJieguo.value)
240
+      };
241
+      proxy.$axios.post(url, param).then(response => {
242
+        if (response.data.code == '0') {
243
+          getTableData1()
244
+          ElMessage({
245
+            message: '保存成功',
246
+            type: 'success',
247
+          })
248
+          if (ruleFormRef.value) {
249
+            ruleFormRef.value.resetFields();
250
+          }
251
+          dialogVisibletemplate.value=false
252
+        } else {
253
+          ElMessage.error('操作失败!' + response.data.msg)
254
+        }
255
+
256
+      })
257
+    }
258
+  })
259
+}
260
+
261
+/* 组织树选择 */
262
+const showBottom = ref(false)
263
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
264
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
265
+const handleTableDataUserDeptUpdate = async (nodeData) => {
266
+  formJieguo.value.drillDept = nodeData.deptCode + '-' + nodeData.deptName
267
+  showBottom.value = false
268
+}
269
+
270
+const addEmergencyDrillPlan = async () => {
271
+  const loadingToast = showLoadingToast({
272
+    duration: 0,
273
+    message: '加载中',
274
+    forbidClick: true
275
+  })
276
+  var url = '/sgsafe/Manager/save';
277
+  const params = {
278
+    json: JSON.stringify(fromVue.value)
279
+  }
280
+  proxy.$axios.post(url,params).then(res=>{
281
+    if (res.data.code === 0) {
282
+      loadingToast.close()
283
+      showSuccessToast('保存成功')
284
+      onClickLeft()
285
+
286
+    } else {
287
+      loadingToast.close()
288
+      showFailToast('操作失败!' + res.data.msg)
289
+    }
290
+  })
291
+}
292
+const showDatePicker = ref(false)
293
+const onDatePicker = (value) => {
294
+  const dateArr = value.selectedValues
295
+  fromVue.value.checkTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
296
+  showDatePicker.value = false
297
+}
298
+const currentDate = ref([2025, 7, 25])
299
+//定义字典集合
300
+const dicList = ref([])
301
+//获取字典集合
302
+// import tools from '@/tools'
303
+const getDicList = () => {
304
+  tools.dic.getDicList(['systemTypes']).then((response => {
305
+
306
+   const rawData = response.data.data
307
+    dicList.value = rawData.systemTypes.map(item => ({
308
+      name: item.dicName,      // 必须有 name 字段!
309
+      code: item.dicCode       // 可选,保留原始 code 供后续使用
310
+    }));
311
+    console.log(JSON.stringify(dicList.value))
312
+  }))
313
+}
314
+onMounted(() => {
315
+  getAccidentDicList()
316
+  console.log('这是编辑页面')
317
+  const today = new Date()
318
+  const year = today.getFullYear()
319
+  const month = today.getMonth() + 1 // 月份从 0 开始
320
+  const day = today.getDate()
321
+  currentDate.value = [year, month, day]
322
+  //selectedDateText.value = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
323
+  getDicList()
324
+})
325
+const showActionSheet2=ref(false)
326
+/* 文件上传 */
327
+import AttachmentS3 from '@/components/AttachmentS3.vue';
328
+
329
+const onSubmit = (values) => {
330
+  fromVue.value.caseNumber = generatedCode.value;
331
+  fromVue.value.fileId = generatedCode.value;
332
+  addEmergencyDrillPlan()
333
+}
334
+const leaderKeyysr = guid();
335
+const PopupDepartmentLeaderNameRefysr = ref();
336
+const handleDepartmentLeaderNameysr = () => {
337
+  PopupDepartmentLeaderNameRefysr.value.open();
338
+};
339
+const getDepartmentLeaderNameysr = (item) => {
340
+  fromVue.value.punCode = item.user.userCode;
341
+  fromVue.value.punName = item.user.userDesc;
342
+  fromVue.value.punId = item.user.id
343
+};
344
+
345
+const onCaseSourceConfirm = ({ selectedOptions }) => {
346
+  caseSourceFlag.value = false;
347
+  fromVue.value.caseSource = selectedOptions[0].text;
348
+};
349
+
350
+const onAccidentLevelConfirm = ({ selectedOptions }) => {
351
+  accidentLevelFlag.value = false;
352
+  fromVue.value.caseType = selectedOptions[0].text;
353
+};
354
+
355
+const onprimaryTwoConfirm = ({ selectedOptions }) => {
356
+  primaryDomainTwoFlag.value = false;
357
+  fromVue.value.primaryDomainTwo = selectedOptions[0].text;
358
+};
359
+const selectedPrimary = ref(null)
360
+const onprimaryConfirm = ({ selectedOptions }) => {
361
+  if (!selectedOptions?.length) {
362
+    selectedPrimary.value = null;
363
+    fromVue.value.primaryDomainTwo = '';
364
+    primaryDomainFlag.value = false;
365
+    return;
366
+  }
367
+
368
+  primaryDomainFlag.value = false;
369
+  fromVue.value.primaryDomain = selectedOptions[0].text;
370
+
371
+  const primaryList = accidentDictList.value?.primary_domain || [];
372
+  const selectedItem = primaryList.find(item => item.dicName === selectedOptions[0].text);
373
+
374
+  selectedPrimary.value = selectedItem || null;
375
+  fromVue.value.primaryDomainTwo = '';
376
+};
377
+
378
+const filteredSecondaryList = computed(() =>
379
+  selectedPrimary.value?.dicValue1
380
+    ? (accidentDictList.value?.primary_domain_two || [])
381
+      .filter(item => item.dicValue1 === selectedPrimary.value.dicValue1)
382
+      .map(({ dicName, dicCode }) => ({ text: dicName, value: dicCode }))
383
+    : []
384
+);
385
+
386
+
387
+</script>
388
+
389
+<template>
390
+
391
+  <div class="page-container">
392
+    <van-sticky class="header">
393
+      <van-nav-bar
394
+        :title="title"
395
+        left-text="返回"
396
+        left-arrow
397
+        @click-left="onClickLeft" >
398
+      </van-nav-bar>
399
+    </van-sticky>
400
+    <div class="scroll-container">
401
+      <van-form @submit="onSubmit">
402
+<!--        <van-field-->
403
+<!--          v-model="fromVue.caseNumber"-->
404
+<!--          label="案例编号"-->
405
+<!--          name="caseNumber"-->
406
+<!--          required-->
407
+<!--          placeholder="请输入案例编号"-->
408
+<!--          :rules="[{required: true, message: '请输入文件编号'}]"-->
409
+<!--        />-->
410
+        <van-field
411
+            v-model="generatedCode"
412
+        label="案例编号"
413
+        name="caseNumber"
414
+            :readonly="true"
415
+        :rules="[{required: true, message: '编号生成失败,请点击“重新生成”'}]"
416
+        />
417
+
418
+        <van-field
419
+          v-model="fromVue.caseTitle"
420
+          label="案例标题"
421
+          name="caseTitle"
422
+          required
423
+          placeholder="请输入案例标题"
424
+          :rules="[{required: true, message: '请输入文件名称'}]"
425
+        />
426
+
427
+        <van-field
428
+          v-model="fromVue.caseSource"
429
+          readonly
430
+          label="案例来源"
431
+          name="caseSource"
432
+          required
433
+          @click="caseSourceFlag = true"
434
+        />
435
+        <van-field
436
+          readonly
437
+          v-model="fromVue.caseType"
438
+          label="案例类型"
439
+          name="caseType"
440
+          @click="accidentLevelFlag = true"
441
+        />
442
+        <van-field
443
+          readonly
444
+          v-model="fromVue.primaryDomain"
445
+          label="专业领域一级分类"
446
+          name="primaryDomain"
447
+          @click="primaryDomainFlag = true"
448
+        />
449
+        <van-field
450
+          readonly
451
+          v-model="fromVue.primaryDomainTwo"
452
+          label="专业领域二级分类"
453
+          name="primaryDomainTwo"
454
+          @click="primaryDomainTwoFlag = true"
455
+        />
456
+        <van-field
457
+          v-model="fromVue.tags"
458
+          label="标签"
459
+          name="tags"
460
+          required
461
+          placeholder="请输入案例标题"
462
+          :rules="[{required: true, message: '请输入标签'}]"
463
+        />
464
+
465
+        <van-field
466
+            v-model="fromVue.caseSummary"
467
+            label="案例摘要"
468
+            name="caseSummary"
469
+            required
470
+            rows="1"
471
+            autosize
472
+            type="textarea"
473
+            placeholder="请输入案例摘要"
474
+            :rules="[{required: true, message: '请输入案例摘要'}]"
475
+        />
476
+        <van-field
477
+            v-model="fromVue.highLights"
478
+            label="创新点与亮点"
479
+            name="highLights"
480
+            required
481
+            rows="3"
482
+            autosize
483
+            type="textarea"
484
+            placeholder="请输入创新点与亮点"
485
+            :rules="[{required: true, message: '请输入创新点与亮点'}]"
486
+        />
487
+        <van-field
488
+            v-model="fromVue.resultsValue"
489
+            label="应用成效与价值"
490
+            name="resultsValue"
491
+            required
492
+            rows="3"
493
+            autosize
494
+            type="textarea"
495
+            placeholder="请输入应用成效与价值"
496
+            :rules="[{required: true, message: '请输入应用成效与价值'}]"
497
+        />
498
+        <van-field label="附件上传" >
499
+          <template #input>
500
+            <AttachmentS3 :f-id="result" />
501
+          </template>
502
+        </van-field>
503
+        <div style="margin: 16px;">
504
+          <van-button round block type="primary" v-show='showSmit' native-type="submit">
505
+            {{ isEdit ? '保存' : '提交' }}
506
+          </van-button>
507
+        </div>
508
+      </van-form>
509
+
510
+      <van-action-sheet
511
+        v-model:show="showActionSheet"
512
+        :actions="planLevelList"
513
+        @select="onSelect"
514
+      />
515
+      <van-action-sheet
516
+        v-model:show="showActionSheet2"
517
+        :actions="dicList"
518
+        @select="onSelect2"
519
+      />
520
+
521
+      <van-action-sheet
522
+          v-model:show="caseSourceFlag"
523
+          :actions="accidentDictList.case_source"
524
+          @select="onCaseSourseSelect"
525
+      />
526
+
527
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
528
+        <van-picker
529
+            :columns="columns"
530
+            @cancel="caseSourceFlag = false"
531
+            @confirm="onCaseSourceConfirm"
532
+        />
533
+      </van-popup>
534
+
535
+      <van-popup v-model:show="accidentLevelFlag" round position="bottom">
536
+        <van-picker
537
+            :columns="columnsLevel"
538
+            @cancel="accidentLevelFlag = false"
539
+            @confirm="onAccidentLevelConfirm"
540
+        />
541
+      </van-popup>
542
+      <van-popup v-model:show="primaryDomainFlag" round position="bottom">
543
+        <van-picker
544
+          :columns="columnsprimary"
545
+          @cancel="primaryDomainFlag = false"
546
+          @confirm="onprimaryConfirm"
547
+        />
548
+      </van-popup>
549
+      <van-popup v-model:show="primaryDomainTwoFlag" round position="bottom">
550
+        <van-picker
551
+          :columns="filteredSecondaryList"
552
+          @cancel="primaryDomainTwoFlag = false"
553
+          @confirm="onprimaryTwoConfirm"
554
+        />
555
+      </van-popup>
556
+
557
+<!--      <van-action-sheet-->
558
+<!--          v-model:show="accidentLevelFlag"-->
559
+<!--          :actions="accidentDictList.accident_level"-->
560
+<!--          @select="onAccidentLevelSelect"-->
561
+<!--      />-->
562
+
563
+<!--      <van-action-sheet-->
564
+<!--        v-model:show="showActionSheet1"-->
565
+<!--        :actions="planLevelList1"-->
566
+<!--        field-names="{ text: 'fileName', value: 'fileId' }"-->
567
+<!--        @select="onSelect1"-->
568
+<!--      />-->
569
+
570
+      <van-popup v-model:show="showBottom" position="bottom" :style="{ height: '30%' }">
571
+        <OrganizationalWithLeaf @update:selected-node="handleTableDataUserDeptUpdate" />
572
+      </van-popup>
573
+      <van-popup v-model:show="showDatePicker" position="bottom">
574
+        <van-date-picker
575
+          v-model="currentDate"
576
+          @confirm="onDatePicker"
577
+          @cancel="showDatePicker = false" />
578
+      </van-popup>
579
+    </div>
580
+  </div>
581
+</template>
582
+
583
+<style scoped>
584
+.page-container {
585
+  height: 100vh; /* 关键:外层容器高度设为视口高度 */
586
+  display: flex;
587
+  flex-direction: column;
588
+
589
+}
590
+/*  overflow-y: auto; !* 启用垂直滚动 *!*/
591
+
592
+
593
+.scroll-container {
594
+  flex: 1;
595
+  overflow: auto;
596
+  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
597
+}
598
+
599
+/* 可选:隐藏滚动条(视觉优化) */
600
+.scroll-container::-webkit-scrollbar {
601
+  display: none;
602
+}
603
+
604
+.header, .footer {
605
+  /* 固定高度区域 */
606
+  flex-shrink: 0; /* 防止被压缩 */
607
+  background: #f5f5f5;
608
+  padding: 12px;
609
+}
610
+.row-container {
611
+  display: flex;
612
+  justify-content: space-between; /* 关键:左右分布 */
613
+  align-items: center;             /* 垂直居中 */
614
+
615
+}
616
+
617
+.cell-period-text {
618
+  font-size: 14px;
619
+  color: #333;
620
+  white-space: nowrap;
621
+  overflow: hidden;
622
+  text-overflow: ellipsis;
623
+
624
+}
625
+
626
+.mini-btn {
627
+  height: 22px;
628
+  font-size: 12px;
629
+  padding: 0 8px;
630
+  min-width: 60px;                 /* 可选:保持按钮最小宽度一致 */
631
+}
632
+</style>

+ 363
- 0
src/view/knowledge/project.vue Ver arquivo

@@ -0,0 +1,363 @@
1
+<template>
2
+  <div class="h5-container">
3
+    <van-nav-bar title="项目案例" @click-left="onClickLeft" @click-right="handAdd">
4
+      <template #right>
5
+        <van-icon name="add" size="25" color="#000" />
6
+      </template>
7
+    </van-nav-bar>
8
+    
9
+    <van-search 
10
+      v-model="query.projectName" 
11
+      show-action 
12
+      placeholder="请输入项目名称" 
13
+      @search="onRefresh"
14
+      @cancel="handleClearSearch" 
15
+    />
16
+
17
+    <!-- 项目列表 -->
18
+    <van-pull-refresh v-model="isRefreshing" success-text="刷新成功" @refresh="onRefresh">
19
+      <van-list 
20
+        v-model:loading="isLoading" 
21
+        :finished="isFinished" 
22
+        finished-text="没有更多了" 
23
+        offset="200" 
24
+        @load="onLoad"
25
+      >
26
+        <div v-for="(item, idx) in resultData" :key="item.id">
27
+          <van-swipe-cell 
28
+            title-style="color: #007aff" 
29
+            style="height: 80px;" 
30
+            :ref="el => getSwipeCellRef(el, idx)"
31
+          >
32
+            <template #default>
33
+              <div class="swipe-cell-default">
34
+                <van-cell 
35
+                  style="min-height: 120px; padding: 0 0 0 0; display: flex; align-items: flex-start;" 
36
+                  @click="edits(item)"
37
+                >
38
+                  <template #title>
39
+                    <div class="cell-title">
40
+                      {{ item.projectName }}
41
+                    </div>
42
+                  </template>
43
+                  <template #label>
44
+                    <div>案例编号:{{ item.caseNumber }}</div>
45
+                    <div>案例类型:{{ item.caseType }}</div>
46
+                    <div>浏览量:{{ item.viewCount }}</div>
47
+                  </template>
48
+                </van-cell>
49
+                <div class="swipe-cell-default-icon">
50
+                  <van-icon 
51
+                    v-if="openStatus[idx]" 
52
+                    name="arrow-double-left" 
53
+                    @click.stop="openSwipe(idx)" 
54
+                  />
55
+                  <van-icon 
56
+                    v-else 
57
+                    name="arrow-double-right" 
58
+                    @click.stop="closeSwipe(idx)" 
59
+                  />
60
+                </div>
61
+              </div>
62
+            </template>
63
+
64
+            <template #right>
65
+              <van-button 
66
+                v-if="item.canDelete" 
67
+                square 
68
+                class="delete-button" 
69
+                text="删除" 
70
+                @click="handleDelete(item)" 
71
+              />
72
+            </template>
73
+          </van-swipe-cell>
74
+        </div>
75
+      </van-list>
76
+    </van-pull-refresh>
77
+  </div>
78
+</template>
79
+
80
+<script setup>
81
+import { ref, getCurrentInstance } from 'vue';
82
+import { useRouter } from 'vue-router';
83
+import { showDialog, showSuccessToast, showToast } from 'vant';
84
+
85
+const { proxy } = getCurrentInstance();
86
+const router = useRouter();
87
+
88
+const onClickLeft = () => {
89
+  history.back();
90
+};
91
+
92
+const query = ref({
93
+  caseNumber: '',
94
+  projectName: ''
95
+});
96
+
97
+const isRefreshing = ref(false);
98
+const isLoading = ref(false);
99
+const isFinished = ref(false);
100
+const currentPage = ref(1);
101
+const pageSize = ref(10);
102
+const totalRows = ref(0);
103
+const resultData = ref([]);
104
+const tableData = ref([]);
105
+
106
+const currentUserId = String(localStorage.getItem('userId'));
107
+
108
+// 获取列表数据
109
+const getTableData = async () => {
110
+  const url = '/sgsafe/Manager/queryProject';
111
+  const param = {
112
+    page: currentPage.value,
113
+    rows: pageSize.value,
114
+    params: JSON.stringify(query.value)
115
+  };
116
+  
117
+  const response = await proxy.$axios.get(url, param);
118
+  if (response.data.code == 0) {
119
+    tableData.value = response.data.data.records.map(item => ({
120
+      ...item,
121
+      canDelete: String(item.addId) === currentUserId
122
+    }));
123
+    console.log('列表数据', tableData.value);
124
+    totalRows.value = response.data.data.total;
125
+  } else {
126
+    showToast({
127
+      type: 'error',
128
+      message: '操作失败!' + response.data.msg
129
+    });
130
+  }
131
+};
132
+
133
+// 刷新
134
+const onRefresh = () => {
135
+  basicReset();
136
+  onLoad();
137
+};
138
+
139
+// 加载数据
140
+const onLoad = async () => {
141
+  if (isRefreshing.value) {
142
+    resultData.value = [];
143
+    currentPage.value = 1;
144
+    isRefreshing.value = false;
145
+  }
146
+
147
+  try {
148
+    await getTableData();
149
+
150
+    if (pageSize.value * currentPage.value < totalRows.value) {
151
+      resultData.value = [...resultData.value, ...tableData.value];
152
+      openStatus.value = new Array(resultData.value.length).fill(true);
153
+      currentPage.value++;
154
+    } else {
155
+      resultData.value = [...resultData.value, ...tableData.value];
156
+      openStatus.value = new Array(resultData.value.length).fill(true);
157
+      isFinished.value = true;
158
+    }
159
+
160
+    console.log('resultData', resultData.value);
161
+  } catch (error) {
162
+    console.log(error);
163
+    isFinished.value = true;
164
+  } finally {
165
+    isLoading.value = false;
166
+  }
167
+};
168
+
169
+// 重置列表
170
+const basicReset = () => {
171
+  isFinished.value = false;
172
+  isLoading.value = true;
173
+  currentPage.value = 1;
174
+  resultData.value = [];
175
+};
176
+
177
+// 清空搜索
178
+const handleClearSearch = () => {
179
+  query.value.projectName = '';
180
+  onRefresh();
181
+};
182
+
183
+// 新增
184
+const handAdd = () => {
185
+  router.push({ 
186
+    path: "/projectList",
187
+    query: { mark: -1 } 
188
+  });
189
+};
190
+
191
+// 编辑/查看
192
+const edits = async (row) => {
193
+  const currentUserId = localStorage.getItem('userId');
194
+  const addId = row.addId;
195
+  const isOwner = String(addId).trim().toLowerCase() === String(currentUserId).trim().toLowerCase();
196
+
197
+  // 更新浏览量
198
+  await updateViewCount(row);
199
+
200
+  router.push({ 
201
+    path: "/projectList",
202
+    query: {
203
+      mark: 1,
204
+      data: JSON.stringify(row),
205
+      readOnly: !isOwner ? 'true' : undefined
206
+    } 
207
+  });
208
+};
209
+
210
+// 更新浏览量
211
+const updateViewCount = async (item) => {
212
+  try {
213
+    const payload = { ...item };
214
+    payload.viewCount = String((Number(payload.viewCount) || 0) + 1);
215
+
216
+    const url = '/sgsafe/Manager/saveProject';
217
+    const param = {
218
+      json: JSON.stringify(payload)
219
+    };
220
+
221
+    const response = await proxy.$axios.post(url, param);
222
+    if (response.data.code === '0' || response.data.code === 0) {
223
+      const index = resultData.value.findIndex(data => data.id === item.id);
224
+      if (index !== -1) {
225
+        resultData.value[index].viewCount = payload.viewCount;
226
+      }
227
+    }
228
+  } catch (error) {
229
+    console.error('更新浏览量失败:', error);
230
+  }
231
+};
232
+
233
+// 删除
234
+const handleDelete = (item) => {
235
+  const currentUserId = localStorage.getItem('userId');
236
+  const addId = item.addId;
237
+  
238
+  if (!currentUserId || !addId || String(addId).trim() !== String(currentUserId).trim()) {
239
+    showToast({
240
+      type: 'warning',
241
+      message: '无权限删除!只能删除自己添加的案例。'
242
+    });
243
+    return;
244
+  }
245
+  
246
+  showDialog({
247
+    title: '删除确认',
248
+    message: `确定要删除项目"${item.projectName}"吗?删除后将无法恢复。`,
249
+    showCancelButton: true,
250
+    confirmButtonText: '确定删除',
251
+    cancelButtonText: '取消',
252
+  }).then(() => {
253
+    executeDelete(item);
254
+  }).catch(() => {
255
+    console.log('取消删除');
256
+  });
257
+};
258
+
259
+// 执行删除
260
+const executeDelete = (item) => {
261
+  const deleteData = { ...item };
262
+  const now = new Date();
263
+  const year = now.getFullYear();
264
+  const month = String(now.getMonth() + 1).padStart(2, '0');
265
+  const day = String(now.getDate()).padStart(2, '0');
266
+  const hours = String(now.getHours()).padStart(2, '0');
267
+  const minutes = String(now.getMinutes()).padStart(2, '0');
268
+  const seconds = String(now.getSeconds()).padStart(2, '0');
269
+  deleteData.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
270
+  deleteData.cancelFlag = '1';
271
+  
272
+  const url = '/sgsafe/Manager/saveProject';
273
+  const param = {
274
+    json: JSON.stringify(deleteData)
275
+  };
276
+  
277
+  proxy.$axios.post(url, param).then(response => {
278
+    if (response.data.code == '0' || response.data.code === 0) {
279
+      showSuccessToast("删除成功");
280
+      onRefresh();
281
+    } else {
282
+      showToast({
283
+        type: 'fail',
284
+        message: '删除失败:' + (response.data.msg || '未知错误')
285
+      });
286
+    }
287
+  }).catch(error => {
288
+    showToast({
289
+      type: 'fail',
290
+      message: '删除失败:网络错误'
291
+    });
292
+    console.error('删除失败:', error);
293
+  });
294
+};
295
+
296
+// 滑动单元格控制
297
+const openStatus = ref([]);
298
+const swipeCellRefs = ref([]);
299
+
300
+const getSwipeCellRef = (el, index) => {
301
+  if (el) {
302
+    swipeCellRefs.value[index] = el;
303
+  }
304
+};
305
+
306
+const openSwipe = (idx) => {
307
+  openStatus.value = new Array(resultData.value.length).fill(true);
308
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
309
+    openStatus.value[idx] = false;
310
+    swipeCellRefs.value[idx].open('right');
311
+  }
312
+};
313
+
314
+const closeSwipe = (idx) => {
315
+  if (idx >= 0 && idx < swipeCellRefs.value.length) {
316
+    openStatus.value[idx] = true;
317
+    swipeCellRefs.value[idx].close();
318
+  }
319
+};
320
+</script>
321
+
322
+<style scoped>
323
+.h5-container {
324
+  width: 100%;
325
+  padding: 5px;
326
+  box-sizing: border-box;
327
+}
328
+
329
+.cell-title {
330
+  display: -webkit-box;
331
+  -webkit-box-orient: vertical;
332
+  -webkit-line-clamp: 2;
333
+  overflow: hidden;
334
+  text-overflow: ellipsis;
335
+  line-height: 1.5;
336
+  max-height: calc(1.5em * 2);
337
+  font-size: 16px;
338
+  font-weight: bold;
339
+  color: #333;
340
+}
341
+
342
+.swipe-cell-default {
343
+  display: flex;
344
+  background-color: #ffffff;
345
+  justify-content: center;
346
+  align-items: center;
347
+}
348
+
349
+.swipe-cell-default-icon {
350
+  width: 60px;
351
+  display: flex;
352
+  justify-content: center;
353
+}
354
+
355
+.delete-button {
356
+  height: 100%;
357
+  border: none;
358
+  color: #ff0000;
359
+  background-image: url('@/assets/img/del.png');
360
+  background-size: auto 100%;
361
+  background-repeat: no-repeat;
362
+}
363
+</style>

+ 563
- 0
src/view/knowledge/projectList.vue Ver arquivo

@@ -0,0 +1,563 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref, computed } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+const {
6
+  proxy
7
+} = getCurrentInstance()
8
+
9
+const projectDictList = ref([])
10
+const caseTypeColumns = ref([])
11
+const caseSourceColumns = ref([])
12
+
13
+// 定义生成编号的函数
14
+const generateCode = () => {
15
+  const now = new Date();
16
+  const year = now.getFullYear();
17
+  const month = String(now.getMonth() + 1).padStart(2, '0');
18
+  const day = String(now.getDate()).padStart(2, '0');
19
+  const formattedDate = `${year}${month}${day}`;
20
+  const hours = String(now.getHours()).padStart(2, '0');
21
+  const minutes = String(now.getMinutes()).padStart(2, '0');
22
+  const seconds = String(now.getSeconds()).padStart(2, '0');
23
+  const formattedTime = `${hours}${minutes}${seconds}`;
24
+  const sequenceNumber = Math.floor(Math.random() * 1000);
25
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
26
+  return `XMAL${formattedDate}${formattedTime}${paddedSequence}`;
27
+};
28
+
29
+// 获取字典数据
30
+const getProjectDicList = () => {
31
+  tools.dic.getDicList(['sgsafe_project_case_type', 'sgsafe_project_case_source']).then((response => {
32
+    console.log(JSON.stringify(response.data.data))
33
+    projectDictList.value = response.data.data
34
+    
35
+    caseTypeColumns.value = projectDictList.value.sgsafe_project_case_type?.map(item => ({
36
+      text: item.dicName,
37
+      value: item.dicCode
38
+    })) || [];
39
+    
40
+    caseSourceColumns.value = projectDictList.value.sgsafe_project_case_source?.map(item => ({
41
+      text: item.dicName,
42
+      value: item.dicCode
43
+    })) || [];
44
+    
45
+    console.log('案例类型:', caseTypeColumns.value)
46
+  }))
47
+}
48
+
49
+const caseTypeFlag = ref(false)
50
+const caseSourceFlag = ref(false)
51
+let title = '新增项目案例'
52
+
53
+/* 返回上一级页面 */
54
+const router = useRouter()
55
+const onClickLeft = () => {
56
+  router.go(-1)
57
+}
58
+
59
+const guid = () => {
60
+  function S4() {
61
+    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
62
+  }
63
+  return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4())
64
+}
65
+
66
+const route = useRoute()
67
+let planInfo = {}
68
+const isEdit = ref(route.query.mark === '1');
69
+const isReadOnly = ref(route.query.readOnly === 'true');
70
+const isCaseSubmitted = computed(() => isReadOnly.value && isEdit.value);
71
+const result = ref('')
72
+const fromVue = ref({})
73
+
74
+if (route.query.mark) {
75
+  planInfo = JSON.parse(route.query.mark)
76
+}
77
+
78
+
79
+// 新增模式
80
+if (planInfo == -1) {
81
+  const caseNumber = generateCode();
82
+  result.value = caseNumber;
83
+  
84
+  fromVue.value = {
85
+    caseNumber: caseNumber,
86
+    projectName: '',
87
+    caseType: '',
88
+    caseSource: '',
89
+    startTime: '',
90
+    endTime: '',
91
+    tags: '',
92
+    caseSummary: '',
93
+    highLights: '',
94
+    resultsValue: '',
95
+    fileId: caseNumber,
96
+    viewCount: '0',
97
+    downloadCount: '0'
98
+  };
99
+  
100
+}
101
+
102
+// 编辑模式
103
+if (planInfo == 1) {
104
+  title = '查看项目案例'
105
+  fromVue.value = JSON.parse(route.query.data)
106
+  
107
+  // 清理微秒格式
108
+  if (fromVue.value.startTime && String(fromVue.value.startTime).includes('.')) {
109
+    fromVue.value.startTime = String(fromVue.value.startTime).split('.')[0];
110
+  }
111
+  if (fromVue.value.endTime && String(fromVue.value.endTime).includes('.')) {
112
+    fromVue.value.endTime = String(fromVue.value.endTime).split('.')[0];
113
+  }
114
+  
115
+  // fileId 与 caseNumber 保持一致
116
+  if (!fromVue.value.fileId || fromVue.value.fileId !== fromVue.value.caseNumber) {
117
+    fromVue.value.fileId = fromVue.value.caseNumber;
118
+  }
119
+  result.value = fromVue.value.fileId;
120
+}
121
+
122
+// 时间选择器
123
+const showStartTimePicker = ref(false);
124
+const showEndTimePicker = ref(false);
125
+const currentStartDate = ref([2025, 1, 1])
126
+const currentEndDate = ref([2025, 1, 1])
127
+const currentStartTime = ref([0, 0, 0]);
128
+const currentEndTime = ref([0, 0, 0]);
129
+const minDate = ref(new Date(1900, 0, 1));
130
+const maxDate = ref(new Date(2100, 11, 31));
131
+
132
+const startDateOrTime = ref(false);
133
+const endDateOrTime = ref(false);
134
+
135
+// 开始时间选择
136
+const onStartDateConfirm = () => {
137
+  startDateOrTime.value = true;
138
+};
139
+
140
+const onConfirmStartDatetime = () => {
141
+  const year = currentStartDate.value[0];
142
+  const month = currentStartDate.value[1].toString().padStart(2, '0');
143
+  const day = currentStartDate.value[2].toString().padStart(2, '0');
144
+  const hours = currentStartTime.value[0].toString().padStart(2, '0');
145
+  const minutes = currentStartTime.value[1].toString().padStart(2, '0');
146
+  const seconds = currentStartTime.value[2].toString().padStart(2, '0');
147
+
148
+  fromVue.value.startTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
149
+  showStartTimePicker.value = false;
150
+  startDateOrTime.value = false;
151
+};
152
+
153
+const cancelStartDatePicker = () => {
154
+  showStartTimePicker.value = false;
155
+  startDateOrTime.value = false;
156
+};
157
+
158
+const cancelStartTimePicker = () => {
159
+  showStartTimePicker.value = false;
160
+  startDateOrTime.value = false;
161
+};
162
+
163
+// 结束时间选择
164
+const onEndDateConfirm = () => {
165
+  endDateOrTime.value = true;
166
+};
167
+
168
+const onConfirmEndDatetime = () => {
169
+  const year = currentEndDate.value[0];
170
+  const month = currentEndDate.value[1].toString().padStart(2, '0');
171
+  const day = currentEndDate.value[2].toString().padStart(2, '0');
172
+  const hours = currentEndTime.value[0].toString().padStart(2, '0');
173
+  const minutes = currentEndTime.value[1].toString().padStart(2, '0');
174
+  const seconds = currentEndTime.value[2].toString().padStart(2, '0');
175
+
176
+  fromVue.value.endTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
177
+  showEndTimePicker.value = false;
178
+  endDateOrTime.value = false;
179
+};
180
+
181
+const cancelEndDatePicker = () => {
182
+  showEndTimePicker.value = false;
183
+  endDateOrTime.value = false;
184
+};
185
+
186
+const cancelEndTimePicker = () => {
187
+  showEndTimePicker.value = false;
188
+  endDateOrTime.value = false;
189
+};
190
+
191
+// 标签选择
192
+const addTag = (item) => {
193
+  if (isCaseSubmitted.value) return;
194
+  
195
+  const valueToStore = item.value?.trim() || '';
196
+  if (!valueToStore) return;
197
+
198
+  const currentTags = fromVue.value.tags
199
+    ? fromVue.value.tags.split(',').map(t => t.trim()).filter(Boolean)
200
+    : [];
201
+
202
+  if (currentTags.includes(valueToStore)) return;
203
+
204
+  currentTags.push(valueToStore);
205
+  fromVue.value.tags = currentTags.join(', ');
206
+};
207
+
208
+/* 组织树选择 */
209
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
210
+
211
+// 保存
212
+const addEmergencyDrillPlan = async () => {
213
+  const loadingToast = showLoadingToast({
214
+    duration: 0,
215
+    message: '加载中',
216
+    forbidClick: true
217
+  })
218
+  
219
+  fromVue.value.fileId = result.value
220
+
221
+  var url = '/sgsafe/Manager/saveProject';
222
+  const params = {
223
+    json: JSON.stringify(fromVue.value)
224
+  }
225
+  proxy.$axios.post(url, params).then(res => {
226
+    if (res.data.code === 0 || res.data.code === '0') {
227
+      loadingToast.close()
228
+      showSuccessToast('保存成功')
229
+      onClickLeft()
230
+    } else {
231
+      loadingToast.close()
232
+      showFailToast('操作失败!' + res.data.msg)
233
+    }
234
+  }).catch(error => {
235
+    loadingToast.close()
236
+    showFailToast('保存失败: 网络错误')
237
+    console.error('保存失败:', error)
238
+  })
239
+}
240
+
241
+onMounted(() => {
242
+  getProjectDicList()
243
+  const today = new Date()
244
+  const year = today.getFullYear()
245
+  const month = today.getMonth() + 1
246
+  const day = today.getDate()
247
+  currentStartDate.value = [year, month, day]
248
+  currentEndDate.value = [year, month, day]
249
+  currentStartTime.value = [today.getHours(), today.getMinutes(), today.getSeconds()];
250
+  currentEndTime.value = [today.getHours(), today.getMinutes(), today.getSeconds()];
251
+  
252
+  // 如果是编辑模式且有已有的时间,解析并初始化
253
+  if (isEdit.value) {
254
+    if (fromVue.value.startTime) {
255
+      try {
256
+        const timeStr = fromVue.value.startTime;
257
+        const [datePart, timePart] = timeStr.split(' ');
258
+        if (datePart && timePart) {
259
+          const [year, month, day] = datePart.split('-').map(Number);
260
+          const [hours, minutes, seconds] = timePart.split(':').map(Number);
261
+          currentStartDate.value = [year, month, day];
262
+          currentStartTime.value = [hours || 0, minutes || 0, seconds || 0];
263
+        }
264
+      } catch (error) {
265
+        // 解析失败,使用默认值
266
+      }
267
+    }
268
+    
269
+    if (fromVue.value.endTime) {
270
+      try {
271
+        const timeStr = fromVue.value.endTime;
272
+        const [datePart, timePart] = timeStr.split(' ');
273
+        if (datePart && timePart) {
274
+          const [year, month, day] = datePart.split('-').map(Number);
275
+          const [hours, minutes, seconds] = timePart.split(':').map(Number);
276
+          currentEndDate.value = [year, month, day];
277
+          currentEndTime.value = [hours || 0, minutes || 0, seconds || 0];
278
+        }
279
+      } catch (error) {
280
+        // 解析失败,使用默认值
281
+      }
282
+    }
283
+  }
284
+})
285
+
286
+/* 文件上传 */
287
+import AttachmentS3 from '@/components/AttachmentS3.vue';
288
+
289
+const onSubmit = (values) => {
290
+  addEmergencyDrillPlan()
291
+}
292
+
293
+const onCaseTypeConfirm = ({ selectedOptions }) => {
294
+  caseTypeFlag.value = false;
295
+  fromVue.value.caseType = selectedOptions[0].text;
296
+};
297
+
298
+const onCaseSourceConfirm = ({ selectedOptions }) => {
299
+  caseSourceFlag.value = false;
300
+  fromVue.value.caseSource = selectedOptions[0].text;
301
+};
302
+
303
+</script>
304
+
305
+<template>
306
+
307
+  <div class="page-container">
308
+    <van-sticky class="header">
309
+      <van-nav-bar
310
+        :title="title"
311
+        left-text="返回"
312
+        left-arrow
313
+        @click-left="onClickLeft" >
314
+      </van-nav-bar>
315
+    </van-sticky>
316
+    <div class="scroll-container">
317
+      <van-form @submit="onSubmit">
318
+        <van-field
319
+            v-model="fromVue.caseNumber"
320
+            label="案例编号"
321
+            name="caseNumber"
322
+            readonly
323
+            :rules="[{required: true, message: '编号生成失败'}]"
324
+        />
325
+
326
+        <van-field
327
+          v-model="fromVue.projectName"
328
+          label="项目名称"
329
+          name="projectName"
330
+          :readonly="isCaseSubmitted"
331
+          required
332
+          placeholder="请输入项目名称"
333
+          :rules="[{required: true, message: '请输入项目名称'}]"
334
+        />
335
+
336
+        <van-field
337
+          v-model="fromVue.caseType"
338
+          readonly
339
+          label="案例类型"
340
+          name="caseType"
341
+          required
342
+          placeholder="请选择案例类型"
343
+          :rules="[{required: true, message: '请选择案例类型'}]"
344
+          @click="!isCaseSubmitted && (caseTypeFlag = true)"
345
+        />
346
+        
347
+        <van-field
348
+          v-model="fromVue.caseSource"
349
+          readonly
350
+          label="案例来源"
351
+          name="caseSource"
352
+          placeholder="请选择案例来源"
353
+          @click="!isCaseSubmitted && (caseSourceFlag = true)"
354
+        />
355
+
356
+        <!-- 开始时间 -->
357
+        <van-field
358
+            v-model="fromVue.startTime"
359
+            is-link
360
+            readonly
361
+            name="startTime"
362
+            label="开始时间"
363
+            :colon="true"
364
+            placeholder="点击选择开始时间"
365
+            @click="!isCaseSubmitted && (showStartTimePicker = true)"
366
+        />
367
+
368
+        <!-- 结束时间 -->
369
+        <van-field
370
+            v-model="fromVue.endTime"
371
+            is-link
372
+            readonly
373
+            name="endTime"
374
+            label="结束时间"
375
+            :colon="true"
376
+            placeholder="点击选择结束时间"
377
+            @click="!isCaseSubmitted && (showEndTimePicker = true)"
378
+        />
379
+
380
+        <!-- 关键词/标签 -->
381
+        <van-field
382
+            v-model="fromVue.tags"
383
+            label="关键词/标签"
384
+            name="tags"
385
+            placeholder="请手动输入标签,多个标签用逗号分隔"
386
+            :readonly="isCaseSubmitted"
387
+        />
388
+        
389
+        <!-- 标签按钮 -->
390
+        <!-- 整个 van-cell 删除 -->
391
+
392
+        <van-field
393
+            v-model="fromVue.caseSummary"
394
+            label="案例摘要"
395
+            name="caseSummary"
396
+            rows="3"
397
+            autosize
398
+            type="textarea"
399
+            placeholder="请输入案例摘要"
400
+            :readonly="isCaseSubmitted"
401
+        />
402
+        
403
+        <van-field
404
+            v-model="fromVue.highLights"
405
+            label="创新点与亮点"
406
+            name="highLights"
407
+            rows="3"
408
+            autosize
409
+            type="textarea"
410
+            placeholder="请输入创新点与亮点"
411
+            :readonly="isCaseSubmitted"
412
+        />
413
+        
414
+        <van-field
415
+            v-model="fromVue.resultsValue"
416
+            label="应用成效与价值"
417
+            name="resultsValue"
418
+            rows="3"
419
+            autosize
420
+            type="textarea"
421
+            placeholder="请输入应用成效与价值"
422
+            :readonly="isCaseSubmitted"
423
+        />
424
+
425
+        <van-field label="附件上传" >
426
+          <template #input>
427
+            <AttachmentS3 :f-id="result" :readonly="isCaseSubmitted" />
428
+          </template>
429
+        </van-field>
430
+        
431
+        <div style="margin: 16px;">
432
+          <van-button v-if="!isReadOnly" round block type="primary" native-type="submit">
433
+            {{ isEdit ? '保存' : '提交' }}
434
+          </van-button>
435
+        </div>
436
+      </van-form>
437
+
438
+      <!-- 案例类型选择器 -->
439
+      <van-popup v-model:show="caseTypeFlag" round position="bottom">
440
+        <van-picker
441
+            :columns="caseTypeColumns"
442
+            @cancel="caseTypeFlag = false"
443
+            @confirm="onCaseTypeConfirm"
444
+        />
445
+      </van-popup>
446
+
447
+      <!-- 案例来源选择器 -->
448
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
449
+        <van-picker
450
+            :columns="caseSourceColumns"
451
+            @cancel="caseSourceFlag = false"
452
+            @confirm="onCaseSourceConfirm"
453
+        />
454
+      </van-popup>
455
+
456
+      <!-- 开始时间选择器 -->
457
+      <van-popup
458
+          v-model:show="showStartTimePicker"
459
+          position="bottom"
460
+          round
461
+          style="max-height: 50vh;"
462
+      >
463
+        <van-date-picker
464
+            v-if="!startDateOrTime"
465
+            v-model="currentStartDate"
466
+            title="选择开始日期"
467
+            :min-date="minDate"
468
+            :max-date="maxDate"
469
+            @confirm="onStartDateConfirm"
470
+            @cancel="cancelStartDatePicker"
471
+        >
472
+          <template #confirm>
473
+            <van-button type="primary" @click="onStartDateConfirm">下一步</van-button>
474
+          </template>
475
+          <template #cancel>
476
+            <van-button type="danger" @click="cancelStartDatePicker">取消</van-button>
477
+          </template>
478
+        </van-date-picker>
479
+
480
+        <van-time-picker
481
+            v-if="startDateOrTime"
482
+            v-model="currentStartTime"
483
+            title="选择开始时间"
484
+            :columns-type="['hour', 'minute', 'second']"
485
+            @confirm="onConfirmStartDatetime"
486
+            @cancel="cancelStartTimePicker"
487
+        >
488
+          <template #confirm>
489
+            <van-button type="primary" @click="onConfirmStartDatetime">确定</van-button>
490
+          </template>
491
+          <template #cancel>
492
+            <van-button type="danger" @click="cancelStartTimePicker">取消</van-button>
493
+          </template>
494
+        </van-time-picker>
495
+      </van-popup>
496
+
497
+      <!-- 结束时间选择器 -->
498
+      <van-popup
499
+          v-model:show="showEndTimePicker"
500
+          position="bottom"
501
+          round
502
+          style="max-height: 50vh;"
503
+      >
504
+        <van-date-picker
505
+            v-if="!endDateOrTime"
506
+            v-model="currentEndDate"
507
+            title="选择结束日期"
508
+            :min-date="minDate"
509
+            :max-date="maxDate"
510
+            @confirm="onEndDateConfirm"
511
+            @cancel="cancelEndDatePicker"
512
+        >
513
+          <template #confirm>
514
+            <van-button type="primary" @click="onEndDateConfirm">下一步</van-button>
515
+          </template>
516
+          <template #cancel>
517
+            <van-button type="danger" @click="cancelEndDatePicker">取消</van-button>
518
+          </template>
519
+        </van-date-picker>
520
+
521
+        <van-time-picker
522
+            v-if="endDateOrTime"
523
+            v-model="currentEndTime"
524
+            title="选择结束时间"
525
+            :columns-type="['hour', 'minute', 'second']"
526
+            @confirm="onConfirmEndDatetime"
527
+            @cancel="cancelEndTimePicker"
528
+        >
529
+          <template #confirm>
530
+            <van-button type="primary" @click="onConfirmEndDatetime">确定</van-button>
531
+          </template>
532
+          <template #cancel>
533
+            <van-button type="danger" @click="cancelEndTimePicker">取消</van-button>
534
+          </template>
535
+        </van-time-picker>
536
+      </van-popup>
537
+    </div>
538
+  </div>
539
+</template>
540
+
541
+<style scoped>
542
+.page-container {
543
+  height: 100vh;
544
+  display: flex;
545
+  flex-direction: column;
546
+}
547
+
548
+.scroll-container {
549
+  flex: 1;
550
+  overflow: auto;
551
+  -webkit-overflow-scrolling: touch;
552
+}
553
+
554
+.scroll-container::-webkit-scrollbar {
555
+  display: none;
556
+}
557
+
558
+.header, .footer {
559
+  flex-shrink: 0;
560
+  background: #f5f5f5;
561
+  padding: 12px;
562
+}
563
+</style>

+ 698
- 0
src/view/moneySafe/safeMoneyManagement.vue Ver arquivo

@@ -0,0 +1,698 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, watch, ref, computed } from 'vue';
3
+import { useRouter } from 'vue-router';
4
+const {
5
+  proxy
6
+} = getCurrentInstance()
7
+
8
+/* 通用方法: 重置list数据 */
9
+const basicReset = () => {
10
+  finished.value = false;
11
+  loading.value = true;
12
+  pageNum.value = 1
13
+  resultData.value = []
14
+}
15
+
16
+
17
+const dictList = ref([])
18
+
19
+/* 返回上一级页面 */
20
+const router = useRouter()
21
+
22
+/* 在线预览实现 */
23
+import {Base64} from "js-base64";
24
+const linShiFid=ref({
25
+  fileId:''
26
+})
27
+const handlePreview = (fileId) => {
28
+  if (fetchData.value.ruleName) {
29
+    sessionStorage.setItem("ruleName", fetchData.value.ruleName)
30
+  }
31
+  if (fetchData.value.ruleScope) {
32
+    sessionStorage.setItem("ruleScope", fetchData.value.ruleScope)
33
+  }
34
+  linShiFid.value.fileId= fileId
35
+  getTableDataQueryFile()
36
+}
37
+const bucket = ref(import.meta.env.VITE_BUCKET)
38
+const getTableDataQueryFile = () => {
39
+  var url = 'framework/Common/queryFileWithValues'
40
+  var param = {
41
+    fId: linShiFid.value.fileId,
42
+  }
43
+  proxy.$axios.get(url, param).then(response => {
44
+    if (response.data.code == 0) {
45
+      const downloadPath = import.meta.env.VITE_BASE_API + '/framework/Common/downloadFileS3?bucket='+ bucket.value + '&id='
46
+      const fileListWithUrls = response.data.data.map(file => ({
47
+        ...file,
48
+        url: `${downloadPath}${file.id}`, // 添加完整的下载路径
49
+        thumbUrl: `${downloadPath}${file.id}`, // 如果需要缩略图,可以使用相同的路径
50
+        name: file.fileName, // 确保有文件名属性
51
+        status: file.status, // 确保有状态属性
52
+        id: file.id
53
+      }));
54
+
55
+      var originUrl = import.meta.env.VITE_PREVIEW_BASE_API + 'framework/Common/downloadFileS3?bucket=' + bucket.value +'&id=' + fileListWithUrls[0].id
56
+      var previewUrl = originUrl + '&fullfilename=' + Date.now() + fileListWithUrls[0].name
57
+      var url = import.meta.env.VITE_PREVIEW_API + 'onlinePreview?url=' + encodeURIComponent(Base64.encode(
58
+        previewUrl)) + '&officePreviewType=pdf'
59
+      window.open(url);
60
+    } else {
61
+      showFailToast('失败!' + response.data.msg)
62
+    }
63
+  })
64
+}
65
+
66
+/* 查询数据 */
67
+const pageNum = ref(1)
68
+const pageSize = ref(10)
69
+const total = ref(0)
70
+const totalMoney = ref(0) // 费用总金额
71
+
72
+// 计算平均单笔费用
73
+const averageExpense = computed(() => {
74
+  return total.value > 0 ? (totalMoney.value / total.value).toFixed(2) : '0.00'
75
+})
76
+const resultData = ref([])
77
+// const fetchData = ref({
78
+//   ruleName:'',
79
+//   ruleScope: ''
80
+// })
81
+
82
+const onSearch = () => {
83
+  basicReset()
84
+  onLoad()
85
+}
86
+
87
+const resetCondition = () => {
88
+  basicReset()
89
+  fetchData.value = {
90
+    moneyDept: '',
91
+    moneyType: '',
92
+    moneyTypeId: '',
93
+    useTimeStart: '',
94
+    useTimeEnd: ''
95
+  }
96
+  onLoad()
97
+}
98
+
99
+const queryList = ref([])
100
+
101
+/* 查询请求 */
102
+const queryFetch = async () => {
103
+
104
+  fetchData.value.ruleScope = postBackRegimeScope.value
105
+
106
+  if (sessionStorage.getItem("ruleName")) {
107
+    fetchData.value.ruleName = sessionStorage.getItem("ruleName")
108
+    sessionStorage.removeItem("ruleName")
109
+  }
110
+  if (sessionStorage.getItem("ruleScope")) {
111
+    const deptInfo = sessionStorage.getItem("ruleScope")
112
+    fetchData.value.ruleScope = deptInfo
113
+    postBackRegimeScope.value = deptInfo
114
+    currentDeptName.value = deptInfo.split('-')[1]
115
+    sessionStorage.removeItem("ruleScope")
116
+  }
117
+  // if(currentDeptName.value) {
118
+  //   fetchData.value.moneyDept = currentDeptName.value
119
+  // }
120
+
121
+  // 构建查询参数,确保 moneyType 字段正确传递
122
+  // 如果 moneyType 是 dicCode,需要转换为名称进行查询(因为后端使用 like 查询,数据库中存储的是名称)
123
+  let moneyTypeForQuery = fetchData.value.moneyType || ''
124
+  if (moneyTypeForQuery && moneyTypeMap.value[moneyTypeForQuery]) {
125
+    // 如果是 dicCode,转换为名称进行查询
126
+    moneyTypeForQuery = moneyTypeMap.value[moneyTypeForQuery]
127
+  } else if (moneyTypeForQuery && moneyTypeMap.value[String(moneyTypeForQuery)]) {
128
+    // 兼容字符串类型的 dicCode
129
+    moneyTypeForQuery = moneyTypeMap.value[String(moneyTypeForQuery)]
130
+  }
131
+  
132
+  const queryParams = {
133
+    moneyDept: fetchData.value.moneyDept || '',
134
+    moneyType: moneyTypeForQuery, // 传递名称(因为后端使用 like 查询)
135
+    useTimeStart: fetchData.value.useTimeStart || '',
136
+    useTimeEnd: fetchData.value.useTimeEnd || ''
137
+  }
138
+  
139
+  console.log('查询参数:', queryParams)
140
+
141
+  const url = '/sgsafe/MoneySafe/query'
142
+  const param = {
143
+    page: pageNum.value,
144
+    rows: pageSize.value,
145
+    params: JSON.stringify(queryParams)
146
+  }
147
+  try {
148
+    const res = await proxy.$axios.post(url,param);
149
+    console.log('查询结果:', res.data)
150
+    if (res.data.code === 0) {
151
+      total.value = res.data.data.total
152
+      // 添加 canDelete 属性
153
+      const currentUserId = String(localStorage.getItem('userId') || '');
154
+      queryList.value = res.data.data.records.map(item => ({
155
+        ...item,
156
+        canDelete: String(item.addId || '') === currentUserId
157
+      }))
158
+      // 获取费用总金额
159
+      totalMoney.value = res.data.data.totalMoney || 0
160
+    } else {
161
+      console.log('操作失败!' + res.data.msg)
162
+    }
163
+  } catch (error) {
164
+    console.error('请求出错:', error);
165
+  }
166
+};
167
+/* 列表加载与下拉刷新 */
168
+// const list = ref([]);
169
+const refreshing = ref(false)
170
+const loading = ref(false)
171
+const finished = ref(false)
172
+
173
+const onRefresh = () => {
174
+  basicReset()
175
+  onLoad();
176
+};
177
+
178
+const onLoad = async () => {
179
+  if (refreshing.value) {
180
+    resultData.value = [];
181
+    pageNum.value = 1;
182
+    refreshing.value = false;
183
+  }
184
+  getDicList()
185
+  try {
186
+    await  queryFetch();
187
+    if (pageSize.value * pageNum.value < total.value) {
188
+      resultData.value = [...queryList.value,...resultData.value ]
189
+      pageNum.value++;
190
+    } else {
191
+      resultData.value = [...queryList.value,...resultData.value ]
192
+      finished.value = true;
193
+    }
194
+  } catch (error) {
195
+    console.log(error);
196
+    finished.value = true;
197
+  } finally {
198
+    loading.value = false;
199
+  }
200
+};
201
+
202
+/* 组织树选择 */
203
+const showBottom = ref(false)
204
+const postBackRegimeScope = ref()
205
+const currentDeptName = ref()
206
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
207
+import { showFailToast, showDialog, showSuccessToast } from 'vant';
208
+import tools from "@/tools/index.js";
209
+const showPickerHandle = () => {
210
+  showBottom.value = true
211
+}
212
+
213
+const handleTableDataUserDeptUpdate = async (nodeData) => {
214
+  postBackRegimeScope.value = nodeData
215
+  currentDeptName.value = nodeData.split('-')[1]
216
+  // 关键:用户主动选择部门时,设置查询条件
217
+  fetchData.value.moneyDept = nodeData
218
+  basicReset()
219
+  await onLoad()
220
+  showBottom.value = false
221
+}
222
+
223
+const getDeptInfo = (currentDeptInfo) => {
224
+  // 只用于初始化显示当前组织名称,不设置查询条件
225
+  postBackRegimeScope.value = currentDeptInfo
226
+  currentDeptName.value = currentDeptInfo.split('-')[1]
227
+  // 注意:这里不设置 fetchData.value.moneyDept,让查询条件保持为空
228
+  // 这样页面初始化时会显示所有数据
229
+}
230
+
231
+// 添加页面初始化逻辑
232
+onMounted(() => {
233
+  // 页面加载时,先查询所有数据(不设置部门条件)
234
+  getDicList()
235
+  basicReset()
236
+  onLoad()
237
+})
238
+
239
+//日期
240
+const fetchData = ref({
241
+  moneyDept: '', // 所属部门
242
+  moneyType: '', // 费用类型(dicCode,用于查询)
243
+  moneyTypeId: '', // 费用类型ID(兼容字段)
244
+  useTimeStart: '', // 使用日期开始
245
+  useTimeEnd: '' // 使用日期结束
246
+})
247
+
248
+// 添加日期范围处理
249
+const dateRange = ref([])
250
+watch(dateRange, (newVal) => {
251
+  if (newVal && newVal.length === 2) {
252
+    fetchData.value.useTimeStart = newVal[0]
253
+    fetchData.value.useTimeEnd = newVal[1]
254
+  } else {
255
+    fetchData.value.useTimeStart = ''
256
+    fetchData.value.useTimeEnd = ''
257
+  }
258
+})
259
+
260
+const guid = () => {
261
+  const chars = '0123456789abcdefghijklmnopqrstuvwxyz'
262
+  const length = chars.length
263
+  const randomString = (len) => {
264
+    const array = new Uint8Array(len)
265
+    crypto.getRandomValues(array)
266
+    return Array.from(array)
267
+        .map(byte => chars[byte % length])
268
+        .join('');
269
+  }
270
+  return `${randomString(8)}${randomString(8)}${randomString(8)}${randomString(8)}`;
271
+}
272
+const moneySafeForm = ref({
273
+  id: '',
274
+  moneyDept: '', // 所属部门
275
+  moneyNumber: '', // 投入费用
276
+  useTime: '', // 使用日期
277
+  moneyType: '', // 费用类型
278
+  moneyIn: '', // 资金来源
279
+  moneyOut: '', // 资金使用情况说明
280
+  otherDec: '', // 备注
281
+  fileId: guid(), // 附件ID
282
+  moneyTypeId:'' // 费用类型ID
283
+})
284
+
285
+const showStartTimePicker = ref(false);
286
+const showEndTimePicker = ref(false);
287
+
288
+// 临时存储选中的日期(因为 van-date-picker 需要数组格式)
289
+const tempStartTime = ref([2024, 1, 1]);
290
+const tempEndTime = ref([2024, 1, 1]);
291
+
292
+// 格式化日期为 YYYY-MM-DD
293
+const formatDate = (dateArray) => {
294
+  const [year, month, day] = dateArray;
295
+  return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
296
+};
297
+
298
+ const confirmStartTime = async () => {
299
+  fetchData.value.useTimeStart = formatDate(tempStartTime.value);
300
+  showStartTimePicker.value = false;
301
+  if(fetchData.value.useTimeStart) {
302
+   await queryFetch()
303
+    resultData.value = queryList.value
304
+
305
+  }
306
+};
307
+
308
+const confirmEndTime = async () => {
309
+  fetchData.value.useTimeEnd = formatDate(tempEndTime.value);
310
+  showEndTimePicker.value = false;
311
+  if(fetchData.value.useTimeEnd) {
312
+    await queryFetch()
313
+    resultData.value = queryList.value
314
+
315
+  }
316
+  console.log('选中的日期:', fetchData.value.useTimeEnd)
317
+};
318
+
319
+const showPicker = ref(false)
320
+// const columns = ref([{ text: '劳动保护用品', value: '劳动保护用品' },
321
+//   { text: '安全工作激励', value: '安全工作激励' },
322
+//   { text: '安全培训教育', value: '安全培训教育' },
323
+//   { text: '检测与检验', value: '检测与检验' },
324
+//   { text: '职业健康查体', value: '职业健康查体' },
325
+//   { text: '应急与防护设施', value: '应急与防护设施' },
326
+//   { text: '安全改造整改', value: '安全改造整改' },
327
+//   { text: '其他', value: '其他' },
328
+//
329
+// ])
330
+const columns = ref([])
331
+const dicList = ref([])
332
+const moneyTypeMap = ref({}) // 映射表:dicCode -> dicName,用于将数字转换为名称显示
333
+
334
+
335
+const getDicList = () => {
336
+  tools.dic.getDicList(['MONEY_TYPE']).then((response => {
337
+
338
+    dictList.value = response.data.data
339
+    columns.value = dictList.value.MONEY_TYPE.map(item => ({
340
+      text: item.dicName,
341
+      value: item.dicName // Web端保存的是 dicCode
342
+    }))
343
+  })).catch(error => {
344
+    console.error('获取字典数据出错:', error)
345
+    columns.value = []
346
+  })
347
+}
348
+
349
+// 根据 dicCode 获取费用类型名称(用于显示转换)
350
+const getMoneyTypeName = (value) => {
351
+  if (!value) return ''
352
+  
353
+  // 先尝试直接查找(支持 dicCode)
354
+  if (moneyTypeMap.value[value]) {
355
+    return moneyTypeMap.value[value]
356
+  }
357
+  
358
+  // 尝试转换为字符串查找(兼容数字类型的 dicCode)
359
+  const strValue = String(value)
360
+  if (moneyTypeMap.value[strValue]) {
361
+    return moneyTypeMap.value[strValue]
362
+  }
363
+  
364
+  // 如果找不到,可能是 H5 端保存的名称(直接返回)
365
+  return value
366
+}
367
+
368
+const onConfirm = async (value) => {
369
+  // value 是选中的值
370
+  const selectedOption = value.selectedOptions[0]
371
+  // 保存 dicCode 到 moneyType(用于查询)
372
+  fetchData.value.moneyType = selectedOption.value
373
+  // 同时保存到 moneyTypeId(如果后端需要)
374
+  if (!fetchData.value.moneyTypeId) {
375
+    fetchData.value.moneyTypeId = selectedOption.value
376
+  }
377
+  showPicker.value = false // 关闭弹窗
378
+  // 重置分页并查询
379
+  basicReset()
380
+  await queryFetch()
381
+  resultData.value = queryList.value
382
+  console.log('选中的值:', selectedOption)
383
+  console.log('查询条件 moneyType:', fetchData.value.moneyType)
384
+}
385
+
386
+const handAdd =  () => {
387
+  router.push({ path: "/safeMoneyManagementList",
388
+    query: {
389
+      mark:-1,
390
+      deptName: '测试部门名称'
391
+    } });
392
+};
393
+const kz = ref(true);
394
+
395
+const edits = async (row) => {
396
+  const currentUserId = localStorage.getItem('userId');
397
+  const addId = row.addId;
398
+
399
+  const isOwner = String(addId).trim().toLowerCase() === String(currentUserId).trim().toLowerCase();
400
+
401
+  kz.value = true;
402
+  moneySafeForm.value = { ...row };
403
+  router.push({ path: "/safeMoneyManagementList",
404
+    query: {
405
+      mark:1,
406
+      data:JSON.stringify(moneySafeForm.value),
407
+      readOnly: !isOwner ? 'true' : undefined  // 如果不是所有者,设置为只读
408
+    } });
409
+};
410
+
411
+// 删除数据
412
+const deleteData = ref({})
413
+
414
+// 处理删除
415
+const handleDelete = (item) => {
416
+  const currentUserId = localStorage.getItem('userId');
417
+  const addId = item.addId;
418
+
419
+  if (!currentUserId || !addId || String(addId).trim() !== String(currentUserId).trim()) {
420
+    showFailToast('无权限删除!只能删除自己添加的记录。');
421
+    return;
422
+  }
423
+  
424
+  showDialog({
425
+    title: '删除确认',
426
+    message: '确定要删除该费用记录吗?删除后将无法恢复。',
427
+    showCancelButton: true,
428
+    confirmButtonText: '确定删除',
429
+    cancelButtonText: '取消',
430
+  }).then(() => {
431
+    executeDelete(item);
432
+  }).catch(() => {
433
+    console.log('取消删除');
434
+  });
435
+};
436
+
437
+// 执行删除
438
+const executeDelete = (item) => {
439
+  const deleteDataItem = { ...item };
440
+  const now = new Date();
441
+  const year = now.getFullYear();
442
+  const month = String(now.getMonth() + 1).padStart(2, '0');
443
+  const day = String(now.getDate()).padStart(2, '0');
444
+  const hours = String(now.getHours()).padStart(2, '0');
445
+  const minutes = String(now.getMinutes()).padStart(2, '0');
446
+  const seconds = String(now.getSeconds()).padStart(2, '0');
447
+  deleteDataItem.cancelTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
448
+  deleteDataItem.cancelFlag = '1';
449
+  
450
+  const url = '/sgsafe/MoneySafe/save';
451
+  const param = {
452
+    json: JSON.stringify(deleteDataItem)
453
+  };
454
+  
455
+  proxy.$axios.post(url, param).then(response => {
456
+    if (response.data.code == '0' || response.data.code === 0) {
457
+      showSuccessToast("删除成功");
458
+      onRefresh();
459
+    } else {
460
+      showFailToast('删除失败:' + (response.data.msg || '未知错误'));
461
+    }
462
+  }).catch(error => {
463
+    showFailToast('删除失败:网络错误');
464
+    console.error('删除失败:', error);
465
+  });
466
+};
467
+
468
+
469
+</script>
470
+
471
+<template>
472
+  <div class="page-container">
473
+    <van-sticky>
474
+      <van-nav-bar title="安环费用管理"  @click-right="handAdd" >
475
+      <template #right>
476
+        <van-icon name="add" size="25" color="#000" />
477
+      </template>
478
+      </van-nav-bar>
479
+    </van-sticky>
480
+    
481
+    <!-- 统计信息卡片 -->
482
+    <div class="statistics-container">
483
+      <div class="stat-item">
484
+        <div class="stat-label">费用总笔数</div>
485
+        <div class="stat-value">{{ total }}</div>
486
+      </div>
487
+      <div class="stat-item">
488
+        <div class="stat-label">费用总金额(元)</div>
489
+        <div class="stat-value">{{ totalMoney.toLocaleString() }}</div>
490
+      </div>
491
+      <div class="stat-item">
492
+        <div class="stat-label">平均单笔费用(元)</div>
493
+        <div class="stat-value">{{ averageExpense }}</div>
494
+      </div>
495
+    </div>
496
+    
497
+    <!-- 原有的查询表单 -->
498
+    <van-field
499
+        v-model="currentDeptName"
500
+        label="当前组织"
501
+        placeholder="请选择组织架构"
502
+        readonly
503
+        right-icon="arrow-down"
504
+        @click="showPickerHandle()"
505
+    />
506
+
507
+    <van-field
508
+        :model-value="getMoneyTypeName(fetchData.moneyType)"
509
+        is-link
510
+        readonly
511
+        name="picker"
512
+        label="费用类型"
513
+        placeholder="请选择"
514
+        @click="showPicker = true"
515
+    />
516
+    <van-popup v-model:show="showPicker" position="bottom">
517
+      <van-picker
518
+          :columns="columns"
519
+          @confirm="onConfirm"
520
+          @cancel="showPicker = false"
521
+      />
522
+    </van-popup>
523
+
524
+    <van-field
525
+        v-model="fetchData.useTimeStart"
526
+        is-link
527
+        readonly
528
+        name="useTimeStart"
529
+        label="开始时间"
530
+        :colon="true"
531
+        placeholder="点击选择开始时间"
532
+        @click="showStartTimePicker = true"
533
+    />
534
+    <!-- 结束时间 -->
535
+    <van-field
536
+        v-model="fetchData.useTimeEnd"
537
+        is-link
538
+        readonly
539
+        name="useTimeEnd"
540
+        label="结束时间"
541
+        :colon="true"
542
+        placeholder="点击选择结束时间"
543
+        @click="showEndTimePicker = true"
544
+    />
545
+    <!-- 开始时间选择器 -->
546
+    <van-popup v-model:show="showStartTimePicker" position="bottom">
547
+      <van-date-picker
548
+          v-model="tempStartTime"
549
+          type="date"
550
+          @confirm="confirmStartTime"
551
+          @cancel="showStartTimePicker = false"
552
+          :columns-type="['year', 'month', 'day']"
553
+      />
554
+    </van-popup>
555
+
556
+    <!-- 结束时间选择器 -->
557
+    <van-popup v-model:show="showEndTimePicker" position="bottom">
558
+      <van-date-picker
559
+          v-model="tempEndTime"
560
+          type="date"
561
+          @confirm="confirmEndTime"
562
+          @cancel="showEndTimePicker = false"
563
+          :columns-type="['year', 'month', 'day']"
564
+      />
565
+    </van-popup>
566
+
567
+    <div class="scroll-container">
568
+      <van-pull-refresh
569
+        v-model="refreshing"
570
+        success-text="刷新成功"
571
+        @refresh="onRefresh"
572
+      >
573
+        <van-list
574
+          class="listDiv"
575
+          v-model:loading="loading"
576
+          :finished="finished"
577
+          :immediate-check="false"
578
+          finished-text="没有更多了"
579
+          @load="onLoad"
580
+        >
581
+          <div v-for="item in resultData" :key="item.id" class="card">
582
+            <van-swipe-cell>
583
+              <template #default>
584
+                <van-cell @click="edits(item)" :border="false" is-link>
585
+                  <template #title>
586
+                    <span class="bold-title" style="margin-left: 4px;">
587
+                      <div>所属类型:{{ getMoneyTypeName(item.moneyType) }}</div>
588
+                    </span>
589
+                  </template>
590
+                  <template #label>
591
+                    <div class="label-content">
592
+                      <div>费用来源:{{ item.moneyIn }}</div>
593
+                      <div>投入费用:{{ item.moneyNumber }}</div>
594
+                    </div>
595
+                  </template>
596
+                </van-cell>
597
+              </template>
598
+              <template #right>
599
+                <van-button 
600
+                  v-if="item.canDelete" 
601
+                  square 
602
+                  class="delete-button" 
603
+                  text="删除" 
604
+                  @click="handleDelete(item)" 
605
+                />
606
+              </template>
607
+            </van-swipe-cell>
608
+          </div>
609
+        </van-list>
610
+      </van-pull-refresh>
611
+    </div>
612
+
613
+    <van-popup :close-on-click-overlay="false" :lazy-render="false" v-model:show="showBottom" position="bottom">
614
+      <OrganizationalWithLeaf @init="getDeptInfo" @close="showBottom = false" @update:selected-node="handleTableDataUserDeptUpdate" />
615
+    </van-popup>
616
+  </div>
617
+</template>
618
+
619
+<style scoped>
620
+.page-container {
621
+  height: 100vh;
622
+  display: flex;
623
+  flex-direction: column;
624
+
625
+}
626
+
627
+.scroll-container {
628
+  flex: 1;
629
+  overflow: auto;
630
+  -webkit-overflow-scrolling: touch;
631
+}
632
+
633
+.scroll-container::-webkit-scrollbar {
634
+  display: none;
635
+}
636
+
637
+.card {
638
+  margin: 10px;
639
+  border-radius: 8px;
640
+  overflow: hidden;
641
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
642
+  background-color: #fff;
643
+}
644
+
645
+.label-content {
646
+  display: flex;
647
+  flex-direction: column;
648
+  gap: 4px;
649
+}
650
+
651
+.bold-title {
652
+  font-weight: bold;
653
+  color: #333;
654
+}
655
+
656
+.statistics-container {
657
+  display: flex;
658
+  justify-content: space-around;
659
+  align-items: center;
660
+  padding: 16px;
661
+  background-color: #fff;
662
+  margin-bottom: 8px;
663
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
664
+}
665
+
666
+.stat-item {
667
+  flex: 1;
668
+  text-align: center;
669
+  display: flex;
670
+  flex-direction: column;
671
+  align-items: center;
672
+}
673
+
674
+.stat-item:not(:last-child) {
675
+  border-right: 1px solid #ebedf0;
676
+}
677
+
678
+.stat-label {
679
+  font-size: 12px;
680
+  color: #969799;
681
+  margin-bottom: 8px;
682
+}
683
+
684
+.stat-value {
685
+  font-size: 18px;
686
+  font-weight: bold;
687
+  color: #323233;
688
+}
689
+
690
+.delete-button {
691
+  height: 100%;
692
+  border: none;
693
+  color: #fff;
694
+  background-color: #ee0a24;
695
+  font-size: 16px;
696
+  padding: 0 20px;
697
+}
698
+</style>

+ 680
- 0
src/view/moneySafe/safeMoneyManagementList.vue Ver arquivo

@@ -0,0 +1,680 @@
1
+<script setup>
2
+import { getCurrentInstance, onMounted, ref , computed, nextTick } from 'vue';
3
+import { useRoute, useRouter } from 'vue-router';
4
+import tools from '@/tools'
5
+import OrganizationalWithLeafUserOne from '@/components/OrganizationalWithLeafUserOne.vue';
6
+const {
7
+  proxy
8
+} = getCurrentInstance()
9
+const accidentDictList = ref([])
10
+const columns =  ref([])
11
+const columnsLevel = ref([])
12
+
13
+
14
+const columnsIn = ref([{text: '公司专项', value: '公司专项'},
15
+    {text: '自筹', value: '自筹'},
16
+    {text: '其他', value: '其他'},])
17
+
18
+// 定义生成编号的函数(你已写好的逻辑)
19
+
20
+const generateCode = () => {
21
+  const now = new Date();
22
+  const year = now.getFullYear();
23
+  const month = String(now.getMonth() + 1).padStart(2, '0');
24
+  const day = String(now.getDate()).padStart(2, '0');
25
+  const formattedDate = `${year}${month}${day}`;
26
+  const hours = String(now.getHours()).padStart(2, '0');
27
+  const minutes = String(now.getMinutes()).padStart(2, '0');
28
+  const seconds = String(now.getSeconds()).padStart(2, '0');
29
+  const formattedTime = `${hours}${minutes}${seconds}`;
30
+  const sequenceNumber = Math.floor(Math.random() * 1000);
31
+  const paddedSequence = String(sequenceNumber).padStart(3, '0');
32
+  return `SGAL${formattedDate}${formattedTime}${paddedSequence}`;
33
+};
34
+
35
+// 存储生成的编号(响应式变量)
36
+const generatedCode = ref(generateCode());
37
+
38
+// 重新生成编号的方法
39
+const regenerateCode = () => {
40
+  generatedCode.value = generateCode();
41
+};
42
+
43
+const caseSourceFlag = ref(false)
44
+const moneyTypeFlag = ref(false)
45
+const moneyInFlag = ref(false)
46
+
47
+let title = '新增安全生产费用登记'
48
+
49
+/* 返回上一级页面 */
50
+const router = useRouter()
51
+
52
+
53
+
54
+
55
+const onClickLeft = () => {
56
+  router.go(-1)
57
+}
58
+
59
+const currentYear = ref()
60
+currentYear.value = new Date().getFullYear()
61
+
62
+/* 获取用户部门信息 */
63
+const jsonArray = localStorage.getItem('dept')
64
+const deptInformation = ref([])
65
+try {
66
+  deptInformation.value = jsonArray ? JSON.parse(jsonArray) : [];
67
+} catch (error) {
68
+  deptInformation.value = [];
69
+}
70
+const deptName = deptInformation.value[0].deptName
71
+const deptCode = deptInformation.value[0].deptCode
72
+
73
+const guid = () =>  {
74
+  function S4() {
75
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
76
+  }
77
+  return (S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4())
78
+}
79
+const formJieguo = ref({
80
+  resultWhether:'',
81
+  resultDetail:'',
82
+  resultWhy:'',
83
+  resultFile:'',
84
+  itemsId:'',
85
+  resultFileId:'',
86
+  resType:''
87
+})
88
+const route = useRoute()
89
+
90
+const currentDeptName = ref('')
91
+console.log('获取路由传值信息',route)
92
+currentDeptName.value = route.query.deptName
93
+let planInfo = {}
94
+const  userName1=localStorage.getItem('userName');
95
+const isEdit = ref(route.query.mark === '1');
96
+const isReadOnly = ref(route.query.readOnly === 'true');
97
+const isCaseSubmitted = computed(() => isReadOnly.value && isEdit.value);
98
+const result=ref('')
99
+
100
+const moneySafeForm = ref({
101
+  id: '',
102
+  moneyDept: '', // 所属部门
103
+  moneyNumber: '', // 投入费用
104
+  useTime: '', // 使用日期
105
+  moneyType: '', // 费用类型
106
+  moneyIn: '', // 资金来源
107
+  moneyOut: '', // 资金使用情况说明
108
+  otherDec: '', // 备注
109
+  fileId: guid(), // 附件ID
110
+  moneyTypeId:'' // 费用类型ID
111
+})
112
+if (route.query.mark) {
113
+  planInfo = JSON.parse(route.query.mark)
114
+}
115
+
116
+console.log(planInfo);
117
+// 新增模式
118
+if (planInfo==-1){
119
+  const caseNumber = generateCode();
120
+  const fileId = ref()
121
+  result.value= caseNumber
122
+  //初始化 moneySafeForm
123
+  moneySafeForm.value = {
124
+    id: '',
125
+    moneyDept: '', // 所属部门
126
+    moneyNumber: '', // 投入费用
127
+    useTime: '', // 使用日期
128
+    moneyType: '', // 费用类型
129
+    moneyIn: '', // 资金来源
130
+    moneyOut: '', // 资金使用情况说明
131
+    otherDec: '', // 备注
132
+    fileId: guid(), // 附件ID
133
+    moneyTypeId:'' // 费用类型ID
134
+  };
135
+  console.log( result.value);
136
+}
137
+if (planInfo==1) {
138
+  console.log(planInfo);
139
+  title = '查看安环费用管理'
140
+  moneySafeForm.value= JSON.parse(route.query.data)
141
+  if (!moneySafeForm.value.fileId) {
142
+    const newFileId = guid();
143
+    moneySafeForm.value.fileId = newFileId;
144
+    result.value = newFileId;
145
+  } else {
146
+    result.value = moneySafeForm.value.fileId;
147
+  }
148
+
149
+  console.log('编辑模式 - fileId:', result.value);
150
+}
151
+
152
+const moneySafeFormRef = ref()
153
+const moneySafeFormRules = ref({
154
+  moneyDept: [{ required: true, message: '请输入所属部门' }],
155
+  moneyNumber: [{ required: true, message: '请输入投入费用' }],
156
+  useTime: [{ required: true, message: '请选择使用日期' }],
157
+  moneyType: [{ required: true, message: '请选择费用类型' }],
158
+  moneyIn: [{ required: true, message: '请选择资金来源' }],
159
+  moneyOut: [{ required: true, message: '请输入资金使用情况说明' }]
160
+})
161
+
162
+
163
+const resDetail=ref('')
164
+const ruleIds = ref([]);
165
+/*const getRuleId = () => {
166
+  var url = '/sgsafe/ExamHead/getCheckRuleId'
167
+  var param = {}
168
+  proxy.$axios.get(url, param).then(response => {
169
+    if (response.data.code == '0') {
170
+      ruleIds.value = response.data.data
171
+    } else {
172
+      console.log("1111111");
173
+    }
174
+  })
175
+  console.log('ruleIds', ruleIds)
176
+}
177
+getRuleId()*/
178
+
179
+const onConfirmDatetime = () => {
180
+  const year = currentDate.value[0];
181
+  const month = currentDate.value[1].toString().padStart(2, '0');
182
+  const day = currentDate.value[2].toString().padStart(2, '0');
183
+
184
+  moneySafeForm.value.useTime = `${year}-${month}-${day}`;
185
+  showDatetimePicker.value = false;
186
+  dateOrTime.value = false;
187
+};
188
+
189
+
190
+const showDatetimePicker = ref(false);
191
+const currentTime = ref();
192
+const minDate = ref(new Date(1900, 0, 1)); // 初始化最小日期
193
+const maxDate = ref(new Date(2100, 11, 31)); // 初始化最大日期
194
+
195
+const dateOrTime = ref(false);
196
+const onDateConfirm = () => {
197
+  // 日期选择确认后的处理
198
+  moneySafeForm.value.useTime = currentDate.value[0] + '-' + currentDate.value[1] + '-' + currentDate.value[2];
199
+  showDatetimePicker.value = false
200
+};
201
+const resetDatetime = () => {
202
+  dateOrTime.value = false;
203
+
204
+  // 初始化日期和时间
205
+  if (moneySafeForm.value.useTime) {
206
+    // 修复:使用 useTime 而不是 accidentTime
207
+    const dt = new Date(moneySafeForm.value.useTime);
208
+    currentDate.value = [dt.getFullYear(), dt.getMonth() + 1, dt.getDate()];
209
+  } else {
210
+    const now = new Date();
211
+    currentDate.value = [now.getFullYear(), now.getMonth() + 1, now.getDate()];
212
+  }
213
+};
214
+const cancelDatePicker = () => {
215
+  // 先关闭弹窗,避免在关闭过程中触发重置导致错误
216
+  showDatetimePicker.value = false;
217
+  // 使用 nextTick 确保弹窗关闭后再重置,避免状态冲突
218
+  nextTick(() => {
219
+    resetDatetime();
220
+  });
221
+};
222
+
223
+// 时间选择器取消
224
+const cancelTimePicker = () => {
225
+  resetDatetime();
226
+  // 重置为当前时间或从表单获取时间
227
+  if (moneySafeForm.value.useTime) {
228
+    const dt = new Date(moneySafeForm.value.useTime);
229
+  } else {
230
+    const now = new Date();
231
+    currentTime.value = [
232
+      String(now.getHours()).padStart(2, '0'),
233
+      String(now.getMinutes()).padStart(2, '0'),
234
+      String(now.getSeconds()).padStart(2, '0')
235
+    ];
236
+  }
237
+};
238
+
239
+
240
+/* 下拉框 */
241
+const showActionSheet = ref(false)
242
+const showActionSheet1 = ref(false)
243
+const planLevelList = [
244
+  { name: '转发', value: '转发' },
245
+  { name: '内部', value: '内部' },
246
+  { name: '文章', value: '文章' }
247
+];
248
+const isdisabled=ref(true)
249
+const isdisabled2=ref(true)
250
+const onSelect = (item) => {
251
+  moneySafeForm.value.fileContent = item.name
252
+
253
+  showActionSheet.value=false
254
+}
255
+
256
+const onSelect2 = (item) => {
257
+  moneySafeForm.value.fileType=item.name
258
+  showActionSheet2.value=false
259
+  }
260
+
261
+const onCaseSourseSelect = (item) => {
262
+  moneySafeForm.value.caseSource=item.dicCode
263
+  caseSourceFlag.value = false
264
+}
265
+
266
+const onAccidentLevelSelect = (item) => {
267
+  moneySafeForm.value.accidentLevel = item.dicCode
268
+  moneyTypeFlag.value = false
269
+
270
+}
271
+
272
+const displayFileName = ref('')
273
+const onSelect1 = (item) => {
274
+  console.log(item);
275
+  formJieguo.value.resultFile = item.value
276
+  result.value=formJieguo.value.resultFile
277
+  displayFileName.value = item.name
278
+  console.log(result.value);
279
+  showActionSheet1.value = false
280
+}
281
+const questionIds = ref([])
282
+const actions=ref([])
283
+/*const getQuestionId = () => {
284
+  var url = '/sgsafe/AssessmentRecord/queryRuleNoPage';
285
+  var param = {};
286
+  proxy.$axios.get(url, param).then(response => {
287
+    if (response.data.code == '0') {
288
+      questionIds.value = response.data.data; // 先赋值给 questionIds.value
289
+
290
+
291
+      // ✅ 关键:使用 questionIds.value.map
292
+      actions.value = questionIds.value.map(item => ({
293
+        name: item.ruleName,
294
+        value: item.id
295
+      }));
296
+      console.log('actions:', actions.value); // 看看有没有输出
297
+    } else {
298
+      ElMessage.error('操作失败!' + response.data.msg);
299
+    }
300
+  });
301
+};
302
+getQuestionId()*/
303
+
304
+const baocun3 = (ruleFormRef) => {
305
+  console.log(formJieguo.value)
306
+  ruleFormRef.validate((valid, fields) => {
307
+    if (valid) {
308
+
309
+      var url = '/sgsafe/ItemsResult/save';
310
+      var param = {
311
+        json: JSON.stringify(formJieguo.value)
312
+      };
313
+      proxy.$axios.post(url, param).then(response => {
314
+        if (response.data.code == '0') {
315
+          getTableData1()
316
+          ElMessage({
317
+            message: '保存成功',
318
+            type: 'success',
319
+          })
320
+          if (ruleFormRef.value) {
321
+            ruleFormRef.value.resetFields();
322
+          }
323
+          dialogVisibletemplate.value=false
324
+        } else {
325
+          ElMessage.error('操作失败!' + response.data.msg)
326
+        }
327
+
328
+      })
329
+    }
330
+  })
331
+}
332
+
333
+/* 组织树选择 */
334
+const showBottom = ref(false)
335
+import OrganizationalWithLeaf from '@/components/OrganizationalWithLeaf.vue';
336
+import { showFailToast, showLoadingToast, showSuccessToast } from 'vant';
337
+const handleTableDataUserDeptUpdate = async (nodeData) => {
338
+  moneySafeForm.value.moneyDept = nodeData
339
+  showBottom.value = false
340
+}
341
+
342
+const addEmergencyDrillPlan = async () => {
343
+  const loadingToast = showLoadingToast({
344
+    duration: 0,
345
+    message: '加载中',
346
+    forbidClick: true
347
+  })
348
+
349
+  moneySafeForm.value.fileId = result.value
350
+
351
+  var url = '/sgsafe/MoneySafe/save';
352
+  const params = {
353
+    json: JSON.stringify(moneySafeForm.value)
354
+  }
355
+  proxy.$axios.post(url,params).then(res=>{
356
+    if (res.data.code === 0) {
357
+      loadingToast.close()
358
+      showSuccessToast('保存成功')
359
+      onClickLeft()
360
+
361
+    } else {
362
+      loadingToast.close()
363
+      showFailToast('操作失败!' + res.data.msg)
364
+    }
365
+  })
366
+}
367
+const showDatePicker = ref(false)
368
+const onDatePicker = (value) => {
369
+  const dateArr = value.selectedValues
370
+  moneySafeForm.value.checkTime = dateArr[0] + '-' + dateArr[1] + '-' + dateArr[2]
371
+  showDatePicker.value = false
372
+}
373
+const currentDate = ref([2025, 7, 25])
374
+//定义字典集合
375
+const dicList = ref([])
376
+const dictList = ref([])
377
+
378
+const getDicList = () => {
379
+  tools.dic.getDicList(['MONEY_TYPE']).then((response => {
380
+
381
+    dictList.value = response.data.data
382
+    columnsLevel.value = dictList.value.MONEY_TYPE.map(item => ({
383
+      text: item.dicName,
384
+      value: item.dicName // Web端保存的是 dicCode
385
+    }))
386
+  })).catch(error => {
387
+    console.error('获取字典数据出错:', error)
388
+    columns.value = []
389
+  })
390
+}
391
+onMounted(() => {
392
+  //getAccidentDicList()
393
+  console.log('这是编辑页面')
394
+  const today = new Date()
395
+  const year = today.getFullYear()
396
+  const month = today.getMonth() + 1 // 月份从 0 开始
397
+  const day = today.getDate()
398
+  currentDate.value = [year, month, day]
399
+  
400
+  // 确保 minDate 和 maxDate 已初始化
401
+  if (!minDate.value) {
402
+    minDate.value = new Date(1900, 0, 1);
403
+  }
404
+  if (!maxDate.value) {
405
+    maxDate.value = new Date(2100, 11, 31);
406
+  }
407
+  
408
+  // 初始化时间
409
+  currentTime.value = [today.getHours(), today.getMinutes(), today.getSeconds()];
410
+  // 如果是编辑模式且有已有的使用日期,解析并初始化
411
+  if (isEdit.value && moneySafeForm.value.useTime) {
412
+    try {
413
+      // 解析格式如 "2025-01-15" 的日期字符串
414
+      const dateStr = moneySafeForm.value.useTime;
415
+      const [year, month, day] = dateStr.split('-').map(Number);
416
+      if (year && month && day) {
417
+        currentDate.value = [year, month, day];
418
+      }
419
+    } catch (error) {
420
+      console.error('解析使用日期失败:', error);
421
+    }
422
+  }
423
+  getDicList()
424
+})
425
+const showActionSheet2=ref(false)
426
+/* 文件上传 */
427
+import AttachmentS3 from '@/components/AttachmentS3.vue';
428
+
429
+const onSubmit = (values) => {
430
+  addEmergencyDrillPlan()
431
+}
432
+const leaderKeyysr = guid();
433
+const PopupDepartmentLeaderNameRefysr = ref();
434
+const handleDepartmentLeaderNameysr = () => {
435
+  PopupDepartmentLeaderNameRefysr.value.open();
436
+};
437
+const getDepartmentLeaderNameysr = (item) => {
438
+  moneySafeForm.value.punCode = item.user.userCode;
439
+  moneySafeForm.value.punName = item.user.userDesc;
440
+  moneySafeForm.value.punId = item.user.id
441
+};
442
+
443
+const onCaseSourceConfirm = ({ selectedOptions }) => {
444
+  caseSourceFlag.value = false;
445
+  moneySafeForm.value.caseSource = selectedOptions[0].text;
446
+};
447
+
448
+const moneyTypeLevelConfirm = ({ selectedOptions }) => {
449
+  moneyTypeFlag.value = false;
450
+  moneySafeForm.value.moneyTypeId = selectedOptions[0].value;
451
+  moneySafeForm.value.moneyType = selectedOptions[0].text;
452
+};
453
+
454
+const moneyInConfirm = ({ selectedOptions }) => {
455
+  moneyInFlag.value = false;
456
+  moneySafeForm.value.moneyIn = selectedOptions[0].text;
457
+};
458
+
459
+const getDeptInfo = (currentDeptInfo) => {
460
+  // 如果需要初始化部门信息,可以在这里处理
461
+  // 例如:moneySafeForm.value.moneyDept = currentDeptInfo
462
+}
463
+</script>
464
+
465
+<template>
466
+
467
+  <div class="page-container">
468
+    <van-sticky class="header">
469
+      <van-nav-bar
470
+        :title="title"
471
+        left-text="返回"
472
+        left-arrow
473
+        @click-left="onClickLeft" >
474
+      </van-nav-bar>
475
+    </van-sticky>
476
+    <div class="scroll-container">
477
+      <van-form @submit="onSubmit">
478
+        <van-field
479
+            v-model="moneySafeForm.moneyDept"
480
+        label="所属部门"
481
+        name="moneyDept"
482
+        readonly
483
+        placeholder="请选择所属部门"
484
+        @click="!isCaseSubmitted && (showBottom = true)"
485
+        :rules="[{required: true, message: '请选择所属部门'}]"
486
+        required
487
+      />
488
+
489
+        <van-field
490
+          v-model="moneySafeForm.moneyNumber"
491
+          label="投入费用"
492
+          name="moneyNumber"
493
+          :readonly="isCaseSubmitted"
494
+          required
495
+          placeholder="请输入投入费用"
496
+          :rules="[{required: true, message: '请输入投入费用'}]"
497
+        />
498
+
499
+        <!--        //时间-->
500
+        <van-field
501
+            v-model="moneySafeForm.useTime"
502
+            is-link
503
+            readonly
504
+            name="useTime"
505
+            label="使用日期"
506
+            :colon="true"
507
+            placeholder="点击选择日期"
508
+            @click="showDatetimePicker = !isCaseSubmitted"
509
+            :rules="[{ required:true, message: '请点击选择日期' }]"
510
+            required
511
+        />
512
+        <van-popup
513
+            v-model:show="showDatetimePicker"
514
+            position="bottom"
515
+            round
516
+            style="max-height: 50vh;"
517
+        >
518
+          <van-date-picker
519
+              v-model="currentDate"
520
+              title="选择日期"
521
+              :min-date="minDate"
522
+              :max-date="maxDate"
523
+              @confirm="onDateConfirm"
524
+              @cancel="cancelDatePicker"
525
+          >
526
+            <template #confirm>
527
+              <van-button type="primary" @click="onDateConfirm">确认</van-button>
528
+            </template>
529
+            <template #cancel>
530
+              <van-button type="danger" @click="cancelDatePicker">取消</van-button>
531
+            </template>
532
+          </van-date-picker>
533
+
534
+        </van-popup>
535
+
536
+
537
+        <van-field
538
+          v-model="moneySafeForm.moneyType"
539
+          is-link
540
+          readonly
541
+          label="费用类型"
542
+          name="moneyType"
543
+          placeholder="请选择"
544
+          @click="!isCaseSubmitted && (moneyTypeFlag = true)"
545
+          :rules="[{required: true, message: '请选择费用类型'}]"
546
+          required
547
+        />
548
+
549
+        <van-field
550
+            v-model="moneySafeForm.moneyIn"
551
+            is-link
552
+            readonly
553
+            label="资金来源"
554
+            name="moneyIn"
555
+            placeholder="请选择"
556
+            :rules="[{required: true, message: '请选择资金来源'}]"
557
+            @click="!isCaseSubmitted && (moneyInFlag = true)"
558
+            required
559
+        />
560
+
561
+        <van-field
562
+            v-model="moneySafeForm.moneyOut"
563
+            label="资金使用情况说明"
564
+            name="casualtyCount"
565
+            rows="1"
566
+            autosize
567
+            type="textarea"
568
+            placeholder="请输入事故造成后果"
569
+            :readonly="isCaseSubmitted"
570
+            :rules="[{required: true, message: '请输入事故造成后果'}]"
571
+            required
572
+        />
573
+        <van-field
574
+            v-model="moneySafeForm.otherDec"
575
+            label="备注"
576
+            name="accidentSummary"
577
+            rows="3"
578
+            autosize
579
+            type="textarea"
580
+            placeholder="请输入事故简要经过"
581
+            :readonly="isCaseSubmitted"
582
+        />
583
+        <div style="margin: 16px;">
584
+          <van-button v-if="!isReadOnly" round block type="primary" native-type="submit">
585
+            {{ isEdit ? '保存' : '提交' }}
586
+          </van-button>
587
+        </div>
588
+      </van-form>
589
+
590
+      <van-action-sheet
591
+        v-model:show="showActionSheet"
592
+        :actions="planLevelList"
593
+        @select="onSelect"
594
+      />
595
+      <van-action-sheet
596
+        v-model:show="showActionSheet2"
597
+        :actions="dicList"
598
+        @select="onSelect2"
599
+      />
600
+
601
+      <van-action-sheet
602
+          v-model:show="caseSourceFlag"
603
+          :actions="accidentDictList.case_source"
604
+          @select="onCaseSourseSelect"
605
+      />
606
+
607
+      <van-popup v-model:show="caseSourceFlag" round position="bottom">
608
+        <van-picker
609
+            :columns="columns"
610
+            @cancel="caseSourceFlag = false"
611
+            @confirm="onCaseSourceConfirm"
612
+        />
613
+      </van-popup>
614
+
615
+      <van-popup v-model:show="moneyTypeFlag" round position="bottom">
616
+        <van-picker
617
+            :columns="columnsLevel"
618
+            @cancel="moneyTypeFlag = false"
619
+            @confirm="moneyTypeLevelConfirm"
620
+        />
621
+      </van-popup>
622
+
623
+      <van-popup v-model:show="moneyInFlag" round position="bottom">
624
+        <van-picker
625
+            :columns="columnsIn"
626
+            @cancel="moneyInFlag = false"
627
+            @confirm="moneyInConfirm"
628
+        />
629
+      </van-popup>
630
+
631
+      <van-popup 
632
+        :close-on-click-overlay="false" 
633
+        :lazy-render="false" 
634
+        v-model:show="showBottom" 
635
+        position="bottom"
636
+      >
637
+        <OrganizationalWithLeaf 
638
+          @init="getDeptInfo" 
639
+          @close="showBottom = false" 
640
+          @update:selected-node="handleTableDataUserDeptUpdate" 
641
+        />
642
+      </van-popup>
643
+      <van-popup v-model:show="showDatePicker" position="bottom">
644
+        <van-date-picker
645
+          v-model="currentDate"
646
+          @confirm="onDatePicker"
647
+          @cancel="showDatePicker = false" />
648
+      </van-popup>
649
+    </div>
650
+  </div>
651
+</template>
652
+
653
+<style scoped>
654
+.page-container {
655
+  height: 100vh; /* 关键:外层容器高度设为视口高度 */
656
+  display: flex;
657
+  flex-direction: column;
658
+
659
+}
660
+/*  overflow-y: auto; !* 启用垂直滚动 *!*/
661
+
662
+
663
+.scroll-container {
664
+  flex: 1;
665
+  overflow: auto;
666
+  -webkit-overflow-scrolling: touch; /* iOS 平滑滚动 */
667
+}
668
+
669
+/* 可选:隐藏滚动条(视觉优化) */
670
+.scroll-container::-webkit-scrollbar {
671
+  display: none;
672
+}
673
+
674
+.header, .footer {
675
+  /* 固定高度区域 */
676
+  flex-shrink: 0; /* 防止被压缩 */
677
+  background: #f5f5f5;
678
+  padding: 12px;
679
+}
680
+</style>

+ 67
- 67
src/view/yinhuan/JuBaoheLedger_detail/index.vue Ver arquivo

@@ -22,9 +22,9 @@
22 22
           margin: 0 -10px 10px -10px;">奖励信息</div>
23 23
           <van-field v-model="form.bonusAmount" name="奖励金额" label="奖励金额" :colon="true" readonly clickable @touchstart.stop="showBonusAmount = true" />
24 24
           <van-number-keyboard
25
-            v-model="form.bonusAmount"
26
-            :show="showBonusAmount"
27
-            @blur="showBonusAmount = false"
25
+              v-model="form.bonusAmount"
26
+              :show="showBonusAmount"
27
+              @blur="showBonusAmount = false"
28 28
           />
29 29
           <van-divider :style="{ color: '#7e98b2', borderColor: '#60708a', padding: '0 16px' }" />
30 30
           <van-field border v-model="form.bonusDetail" name="奖励详情" label="奖励详情"
@@ -35,22 +35,22 @@
35 35
           <div style="color: #4C93E6;font-size: 14px;margin-left: 0px;background-color: #f5f5f5;padding: 8px 12px;
36 36
           margin: 0 -10px 10px -10px;">隐患信息</div>
37 37
           <van-field border v-model="form.hdId" name="隐患编号" label="隐患编号" :colon="true" placeholder=""
38
-            :readonly="form.status > 0" />
38
+                     :readonly="form.status > 0" />
39 39
           <van-field is-link :colon="true" readonly v-model="form.hdType" required label="隐患类型" placeholder="选择隐患类型"
40
-            @click="showPicker = true" :rules="[{ required: true, message: '请选择内容' }]" />
40
+                     @click="showPicker = true" :rules="[{ required: true, message: '请选择内容' }]" />
41 41
           <van-popup v-model:show="showPicker" round position="bottom">
42 42
             <van-picker :columns="yhlxs" @cancel="showPicker = false" @confirm="onConfirmYhlx" />
43 43
           </van-popup>
44 44
 
45 45
           <van-field readonly v-model="form.discoveryTime" is-link name="datetime" label="发现时间" :colon="true"
46
-            placeholder="点击选择日期和时间" @click="showDatetimePicker = true" required
47
-            :rules="[{ required: true, message: '请选择内容' }]" />
46
+                     placeholder="点击选择日期和时间" @click="showDatetimePicker = true" required
47
+                     :rules="[{ required: true, message: '请选择内容' }]" />
48 48
           <van-popup v-if="!form.status > 0" v-model:show="showDatetimePicker" position="bottom" round
49
-            style="height: 60%">
49
+                     style="height: 60%">
50 50
             <van-date-picker v-model="currentDate" title="选择日期" :min-date="minDate" :max-date="maxDate"
51
-              @confirm="onDateConfirm" @cancel="showDatetimePicker = false" />
51
+                             @confirm="onDateConfirm" @cancel="showDatetimePicker = false" />
52 52
             <van-time-picker v-model="currentTime" title="选择时间" :columns-type="['hour', 'minute', 'second']"
53
-              @confirm="onTimeConfirm" @cancel="showDatetimePicker = false" />
53
+                             @confirm="onTimeConfirm" @cancel="showDatetimePicker = false" />
54 54
             <div style="display: flex; justify-content: space-between; padding: 10px;">
55 55
               <van-button type="danger" @click="showDatetimePicker = false">取消</van-button>
56 56
               <van-button type="primary" @click="onConfirmDatetime">确定</van-button>
@@ -59,16 +59,16 @@
59 59
           <van-field readonly v-model="form.hdLocation" :colon="true" label="隐患区域" name="隐患区域"
60 60
                      required :rules="[{ required: true, message: '请选择' }]" @click="handleDepartmentLeaderName" />
61 61
           <van-field readonly v-model="form.discovererDesc" :colon="true" label="发现人" name="发现人" placeholder="请选择发现人"
62
-            required :rules="[{ required: true, message: '请选择' }]" @click="handleDepartmentLeaderName" />
62
+                     required :rules="[{ required: true, message: '请选择' }]" @click="handleDepartmentLeaderName" />
63 63
           <OrganizationalWithLeafUserOne v-if="!form.status > 0" ref="PopupDepartmentLeaderNameRef"
64
-            @receive-from-child="getDepartmentLeaderName" :main-key="leaderKey" />
64
+                                         @receive-from-child="getDepartmentLeaderName" :main-key="leaderKey" />
65 65
           <van-field :readonly="form.status > 0" border v-model="form.hdDescription" name="隐患描述" label="隐患描述"
66
-            :colon="true" placeholder="请输入内容" required :rules="[{ required: true, message: '请输入内容' }]" type="textarea"
67
-            rows="1" autosize />
66
+                     :colon="true" placeholder="请输入内容" required :rules="[{ required: true, message: '请输入内容' }]" type="textarea"
67
+                     rows="1" autosize />
68 68
 
69 69
           <van-field v-if="form.hdSelect !== '下发隐患'" is-link :colon="true" readonly v-model="form.hdLevel" required
70
-            label="隐患等级" placeholder="选择等级" @click="showPicker2 = true"
71
-            :rules="[{ required: true, message: '请选择内容' }]" />
70
+                     label="隐患等级" placeholder="选择等级" @click="showPicker2 = true"
71
+                     :rules="[{ required: true, message: '请选择内容' }]" />
72 72
           <van-popup v-if="!form.status > 0" v-model:show="showPicker2" round position="bottom">
73 73
             <van-picker :columns="yhdjs" @cancel="showPicker2 = false" @confirm="onConfirmYhdj" />
74 74
           </van-popup>
@@ -82,23 +82,23 @@
82 82
           <div v-if="form.status > 0" style="color: #4C93E6;font-size: 14px;margin-left: 0px;background-color: #f5f5f5;padding: 8px 12px;
83 83
           margin: 0 -10px 10px -10px;">隐患分析确认</div>
84 84
           <van-field v-if="form.status > 0" readonly v-model="form.repairLeaderDesc" :colon="true" label="整改人"
85
-            name="整改人" placeholder="请选择整改人" required :rules="[{ required: true, message: '请选择' }]"
86
-            @click="handleDepartmentLeaderNamezgr" />
85
+                     name="整改人" placeholder="请选择整改人" required :rules="[{ required: true, message: '请选择' }]"
86
+                     @click="handleDepartmentLeaderNamezgr" />
87 87
           <OrganizationalWithLeafUserOne ref="PopupDepartmentLeaderNameRefzgr"
88
-            @receive-from-child="getDepartmentLeaderNamezgr" :main-key="leaderKeyzgr" />
89
-          
88
+                                         @receive-from-child="getDepartmentLeaderNamezgr" :main-key="leaderKeyzgr" />
89
+
90 90
           <van-field v-if="form.status > 0" border
91
-            v-model="form.repairSuggest" name="整改建议" label="整改建议" :colon="true" placeholder="请输入整改建议" required
92
-            :rules="[{ required: true, message: '请输入整改建议' }]" type="textarea" rows="1" autosize />
91
+                     v-model="form.repairSuggest" name="整改建议" label="整改建议" :colon="true" placeholder="请输入整改建议" required
92
+                     :rules="[{ required: true, message: '请输入整改建议' }]" type="textarea" rows="1" autosize />
93 93
 
94 94
           <van-field v-if="form.status > 0"
95
-            v-model="form.repairDdl" is-link readonly name="datetime" label="整改期限" :colon="true" placeholder="点击选择整改期限"
96
-            @click="showDatetimePicker2 = true" required :rules="[{ required: true, message: '请选择整改期限' }]" />
95
+                     v-model="form.repairDdl" is-link readonly name="datetime" label="整改期限" :colon="true" placeholder="点击选择整改期限"
96
+                     @click="showDatetimePicker2 = true" required :rules="[{ required: true, message: '请选择整改期限' }]" />
97 97
           <van-popup v-model:show="showDatetimePicker2" position="bottom" round style="height: 60%">
98 98
             <van-date-picker v-model="currentDate2" title="选择日期" :min-date="minDate2" :max-date="maxDate2"
99
-              @confirm="onDateConfirm2" @cancel="showDatetimePicker2 = false" />
99
+                             @confirm="onDateConfirm2" @cancel="showDatetimePicker2 = false" />
100 100
             <van-time-picker v-model="currentTime2" title="选择时间" :columns-type="['hour', 'minute', 'second']"
101
-              @confirm="onTimeConfirm2" @cancel="showDatetimePicker2 = false" />
101
+                             @confirm="onTimeConfirm2" @cancel="showDatetimePicker2 = false" />
102 102
             <div style="display: flex; justify-content: space-between; padding: 10px;">
103 103
               <van-button type="danger" @click="showDatetimePicker2 = false">取消</van-button>
104 104
               <van-button type="primary" @click="onConfirmDatetime2">确定</van-button>
@@ -107,48 +107,48 @@
107 107
 
108 108
           <!--        部门选择-->
109 109
           <van-field v-if="form.status > 0" v-model="form.repairDept" label="整改部门"
110
-            placeholder="请选择整改部门" readonly right-icon="arrow-down" @click="showPickerHandle" required
111
-            :rules="[{ required: true, message: '请选择' }]" />
110
+                     placeholder="请选择整改部门" readonly right-icon="arrow-down" @click="showPickerHandle" required
111
+                     :rules="[{ required: true, message: '请选择' }]" />
112 112
           <!--        部门弹出框-->
113 113
           <van-popup v-model:show="showBottom" position="bottom">
114 114
             <OrganizationalWithLeaf @update:selected-node="handleTableDataUserDeptUpdate" />
115 115
           </van-popup>
116 116
 
117 117
           <van-field v-if="form.status > 0 && form.hdSelect !== '即查即改' && false" readonly v-model="form.acceptLeaderDesc"
118
-            :colon="true" label="验收人" name="验收人" placeholder="请选择验收人" required
119
-            :rules="[{ required: true, message: '请选择' }]" @click="handleDepartmentLeaderNameysr" />
118
+                     :colon="true" label="验收人" name="验收人" placeholder="请选择验收人" required
119
+                     :rules="[{ required: true, message: '请选择' }]" @click="handleDepartmentLeaderNameysr" />
120 120
           <OrganizationalWithLeafUserOne ref="PopupDepartmentLeaderNameRefysr"
121
-            @receive-from-child="getDepartmentLeaderNameysr" :main-key="leaderKeyysr" />
121
+                                         @receive-from-child="getDepartmentLeaderNameysr" :main-key="leaderKeyysr" />
122 122
 
123 123
           <van-field v-if="form.status > 0 && form.hdSelect !== '下发隐患' && form.hdSelect !== '即查即改' && false" readonly border
124
-            v-model="form.acceptOtherDesc" name="其他验收人" label="其他验收人" :colon="true" placeholder="请选择其他验收人"
125
-            @click="handleDepartmentLeaderName2qtysr" required :rules="[{ required: true, message: '请选择' }]" />
124
+                     v-model="form.acceptOtherDesc" name="其他验收人" label="其他验收人" :colon="true" placeholder="请选择其他验收人"
125
+                     @click="handleDepartmentLeaderName2qtysr" required :rules="[{ required: true, message: '请选择' }]" />
126 126
           <OrganizationalWithLeafUser ref="PopupDepartmentLeaderNameRef2qtysr"
127
-            @receive-from-child="getDepartmentLeaderName2qtysr" :main-key="leaderKey2qtysr" />
127
+                                      @receive-from-child="getDepartmentLeaderName2qtysr" :main-key="leaderKey2qtysr" />
128 128
 
129 129
           <van-field label-width="300px" v-if="form.status > 1 && form.hdSelect !== '下发隐患'" :colon="true" readonly label="临时管控现场图片" />
130 130
           <AttachmentS3Image style="background-color: white;" v-if="form.status > 1 && form.hdSelect !== '下发隐患'"
131
-            :f-id="form.hdPicId + 'lsgkxctp'" />
131
+                             :f-id="form.hdPicId + 'lsgkxctp'" />
132 132
           <van-field label-width="300px" v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'" :colon="true"
133
-            readonly label="临时管控告知书" />
133
+                     readonly label="临时管控告知书" />
134 134
           <AttachmentS3 style="background-color: white;"
135
-            v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'"
136
-            :f-id="form.hdPicId + 'lsgkwj'" />
135
+                        v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'"
136
+                        :f-id="form.hdPicId + 'lsgkwj'" />
137 137
           <van-field v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'" :colon="true"
138
-            readonly label="销号单" />
138
+                     readonly label="销号单" />
139 139
           <AttachmentS3 style="background-color: white;"
140
-            v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'"
141
-            :f-id="form.hdPicId + 'xhdwj'" />
140
+                        v-if="form.status > 1 && form.hdSelect !== '即查即改' && form.hdSelect !== '下发隐患'"
141
+                        :f-id="form.hdPicId + 'xhdwj'" />
142 142
           <van-field v-if="form.status > 1" v-model="form.picAfter" :colon="true" readonly label="整改后图片" />
143 143
           <AttachmentS3Image style="background-color: white;" v-if="form.status > 1" :f-id="form.hdPicId + 'zgh'" />
144 144
 
145 145
           <van-field label-width="110px" v-if="form.status > 1" border v-model="form.repairDescription" name="整改后情况描述" label="整改后情况描述"
146
-            :colon="true" placeholder="请输入整改后情况描述" required :rules="[{ required: true, message: '请输入内容' }]"
147
-            type="textarea" rows="1" autosize />
146
+                     :colon="true" placeholder="请输入整改后情况描述" required :rules="[{ required: true, message: '请输入内容' }]"
147
+                     type="textarea" rows="1" autosize />
148 148
 
149 149
           <van-field v-if="form.status > 3 && false" border v-model="form.hdRoot" name="隐患溯源" label="隐患溯源" :colon="true"
150
-            placeholder="请输入隐患溯源" required :rules="[{ required: true, message: '请输入内容' }]" type="textarea" rows="1"
151
-            autosize />
150
+                     placeholder="请输入隐患溯源" required :rules="[{ required: true, message: '请输入内容' }]" type="textarea" rows="1"
151
+                     autosize />
152 152
 
153 153
         </van-form>
154 154
 
@@ -184,32 +184,32 @@
184 184
 
185 185
 
186 186
   <van-dialog v-model:show="showDialog" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
187
-    :cancel-button-text="cancelButtonText" @confirm="handleJumpRejectStart" @cancel="handleCancel">
187
+              :cancel-button-text="cancelButtonText" @confirm="handleJumpRejectStart" @cancel="handleCancel">
188 188
     <div>确定退回?</div>
189 189
   </van-dialog>
190 190
 
191 191
   <van-dialog v-model:show="showDialog2" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
192
-    :cancel-button-text="cancelButtonText" @confirm="handleGetBack" @cancel="handleCancel">
192
+              :cancel-button-text="cancelButtonText" @confirm="handleGetBack" @cancel="handleCancel">
193 193
     <div>确定退回?</div>
194 194
   </van-dialog>
195 195
 
196 196
   <van-dialog v-model:show="showDialog3" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
197
-    :cancel-button-text="cancelButtonText" @confirm="handleStop" @cancel="handleCancel">
197
+              :cancel-button-text="cancelButtonText" @confirm="handleStop" @cancel="handleCancel">
198 198
     <div>确定退回?</div>
199 199
   </van-dialog>
200 200
 
201 201
   <van-dialog v-model:show="showDialog4" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
202
-    :cancel-button-text="cancelButtonText" @confirm="handleReaded" @cancel="handleCancel">
202
+              :cancel-button-text="cancelButtonText" @confirm="handleReaded" @cancel="handleCancel">
203 203
     <div>确定退回?</div>
204 204
   </van-dialog>
205 205
 
206 206
   <van-dialog v-model:show="showDialog5" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
207
-    :cancel-button-text="cancelButtonText" @confirm="handleReject" @cancel="handleCancel">
207
+              :cancel-button-text="cancelButtonText" @confirm="handleReject" @cancel="handleCancel">
208 208
     <div>确定退回?</div>
209 209
   </van-dialog>
210 210
 
211 211
   <van-dialog v-model:show="showDialog7" title="提示" show-cancel-button :confirm-button-text="confirmButtonText"
212
-    :cancel-button-text="cancelButtonText" @confirm="handleConfirmSubmitQueDing" @cancel="handleCancel">
212
+              :cancel-button-text="cancelButtonText" @confirm="handleConfirmSubmitQueDing" @cancel="handleCancel">
213 213
     <div>确定退回?</div>
214 214
   </van-dialog>
215 215
 </template>
@@ -323,8 +323,8 @@ const showConfirmDialog7 = () => {
323 323
 const handleConfirmSubmit = (nodeName) => {
324 324
   variables.value = oldVariables.value;
325 325
   if (sessionStorage.getItem('variables') !== null
326
-    && sessionStorage.getItem('variables') !== undefined
327
-    && sessionStorage.getItem('variables') !== '') {
326
+      && sessionStorage.getItem('variables') !== undefined
327
+      && sessionStorage.getItem('variables') !== '') {
328 328
     const newVariables = JSON.parse(sessionStorage.getItem('variables'));
329 329
 
330 330
     variables.value = { ...oldVariables.value, ...newVariables };
@@ -419,13 +419,13 @@ const buttonType = (buttonId) => {
419 419
 };
420 420
 const shouldShowButton = (buttonId) => {
421 421
   return buttonId === 'submit'
422
-    || buttonId === 'reject'
423
-    // || buttonId === 'jumpreject'
424
-    || buttonId === 'jumprejectstart'
425
-    || buttonId === 'stop'
426
-    || buttonId === 'getback'
427
-    || buttonId === 'readed'
428
-    || buttonId === 'move';
422
+      || buttonId === 'reject'
423
+      // || buttonId === 'jumpreject'
424
+      || buttonId === 'jumprejectstart'
425
+      || buttonId === 'stop'
426
+      || buttonId === 'getback'
427
+      || buttonId === 'readed'
428
+      || buttonId === 'move';
429 429
 };
430 430
 
431 431
 import style from '@/tools/style';
@@ -665,8 +665,8 @@ const handleTabsClick = (tab, event, item) => {
665 665
     getHistory();
666 666
   } else if (activeTab.value == 'image') {
667 667
     urlFrame.value =
668
-      `${import.meta.env.VITE_WORKFLOW_ADDR}` + '/horizon-workflow-boot/workflow/module/designer/index.html?workid=' + workId
669
-        .value + '&showtype=2&dataid=' + workId.value;
668
+        `${import.meta.env.VITE_WORKFLOW_ADDR}` + '/horizon-workflow-boot/workflow/module/designer/index.html?workid=' + workId
669
+            .value + '&showtype=2&dataid=' + workId.value;
670 670
   }
671 671
 };
672 672
 
@@ -911,8 +911,8 @@ const variables = ref({});
911 911
 const handlePreSubmit = () => {
912 912
   variables.value = oldVariables.value;
913 913
   if (sessionStorage.getItem('variables') !== null
914
-    && sessionStorage.getItem('variables') !== undefined
915
-    && sessionStorage.getItem('variables') !== '') {
914
+      && sessionStorage.getItem('variables') !== undefined
915
+      && sessionStorage.getItem('variables') !== '') {
916 916
     const newVariables = JSON.parse(sessionStorage.getItem('variables'));
917 917
     variables.value = { ...oldVariables.value, ...newVariables };
918 918
   }
@@ -944,7 +944,7 @@ const handlePreSubmit = () => {
944 944
         // 后续就只有一个节点,不需要选择节点
945 945
         if (nextNodes && nextNodes.length === 1) {
946 946
           if ((nextNodes[0].authors.Author && nextNodes[0].authors.Author.initAuthor)
947
-            || (nextNodes[0].authors.Author && nextNodes[0].authors.Author.selectAuthor === undefined)) {
947
+              || (nextNodes[0].authors.Author && nextNodes[0].authors.Author.selectAuthor === undefined)) {
948 948
 
949 949
             var positions = undefined;
950 950
             var depts = undefined;
@@ -975,7 +975,7 @@ const handlePreSubmit = () => {
975 975
             }
976 976
 
977 977
             if (nextNodes[0].authors.Author.initAuthor === undefined
978
-              && nextNodes[0].authors.Author.selectAuthor === undefined) {
978
+                && nextNodes[0].authors.Author.selectAuthor === undefined) {
979 979
               getDataPost();
980 980
               getDataDeptTree();
981 981
             }
@@ -1385,7 +1385,7 @@ const onConfirmYhdj = ({ selectedOptions }) => {
1385 1385
 };
1386 1386
 
1387 1387
 const yhdjs = ref([{ text: '一般隐患', value: '一般隐患' },
1388
-{ text: '重大隐患', value: '重大隐患' }]
1388
+  { text: '重大隐患', value: '重大隐患' }]
1389 1389
 );
1390 1390
 
1391 1391
 const formRef = ref(null);

Carregando…
Cancelar
Salvar