闪电 3 settimane fa
parent
commit
e1f078bd60

+ 17 - 6
src/api/schedule/task.ts

3
 enum Api {
3
 enum Api {
4
   base = '/scheduleTasks/tasks',
4
   base = '/scheduleTasks/tasks',
5
   confirmBase = '/scheduleTasks/tasks/confirm',
5
   confirmBase = '/scheduleTasks/tasks/confirm',
6
+  uploadBase = '/taskAttachment/attachment',
7
+  photoBase = '/taskPhoto/photo',
6
 }
8
 }
7
 
9
 
8
 export function transferTask(data: any) {
10
 export function transferTask(data: any) {
9
-  return http.put(`${Api.base}/forward`, data, {
10
-    successMessageMode: 'message',
11
-  })
11
+  return http.put(`${Api.base}/forward`, data)
12
 }
12
 }
13
 // 关闭任务
13
 // 关闭任务
14
 export function closeTask(data: any) {
14
 export function closeTask(data: any) {
15
-  return http.put(`${Api.base}/cancel`, data, {
16
-    successMessageMode: 'message',
17
-  })
15
+  return http.put(`${Api.base}/cancel`, data)
18
 }
16
 }
19
 
17
 
20
 export function getTaskDetail(id: number) {
18
 export function getTaskDetail(id: number) {
29
 export function confirmDoneTask(id: number) {
27
 export function confirmDoneTask(id: number) {
30
   return http.put(`${Api.confirmBase}/${id}`)
28
   return http.put(`${Api.confirmBase}/${id}`)
31
 }
29
 }
30
+
31
+/**
32
+ * 处理任务附件
33
+ * @param params
34
+ * @returns
35
+ */
36
+export function dealUploadTask(params: any) {
37
+  return http.put(`${Api.uploadBase}/handle`, params)
38
+}
39
+
40
+export function dealPhotoTask(params: any) {
41
+  return http.put(`${Api.photoBase}/handle`, params)
42
+}

+ 212 - 0
src/components/AttachmentList.vue

1
+<script setup lang="ts">
2
+import { computed } from 'vue'
3
+
4
+// 组件属性定义
5
+interface Props {
6
+  files: string[] // 文件URL数组
7
+  fileNames?: string[] // 文件名数组,可选
8
+  size?: number // 卡片大小(默认50)
9
+}
10
+
11
+const props = withDefaults(defineProps<Props>(), {
12
+  fileNames: () => [],
13
+  size: 50,
14
+})
15
+
16
+// 图片文件扩展名
17
+const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
18
+
19
+/**
20
+ * 获取文件名
21
+ * @param url 文件URL
22
+ * @param index 文件索引
23
+ * @returns 文件名
24
+ */
25
+function getFileName(url: string, index: number): string {
26
+  if (props.fileNames && props.fileNames[index]) {
27
+    return props.fileNames[index]
28
+  }
29
+  // 从URL中提取文件名
30
+  const parts = url.split('/')
31
+  return parts[parts.length - 1] || `file${index + 1}`
32
+}
33
+
34
+/**
35
+ * 判断是否为图片文件
36
+ * @param fileName 文件名
37
+ * @returns 是否为图片
38
+ */
39
+function isImage(fileName: string): boolean {
40
+  const extension = fileName.split('.').pop()?.toLowerCase()
41
+  return extension ? imageExtensions.includes(extension) : false
42
+}
43
+
44
+/**
45
+ * 获取文件扩展名
46
+ * @param fileName 文件名
47
+ * @returns 文件扩展名(大写)
48
+ */
49
+function getFileExtension(fileName: string): string {
50
+  const extension = fileName.split('.').pop()?.toUpperCase()
51
+  return extension || 'FILE'
52
+}
53
+
54
+/**
55
+ * 处理文件下载
56
+ * @param url 文件URL
57
+ * @param fileName 文件名
58
+ */
59
+function handleFileDownload(url: string, fileName: string) {
60
+  // #ifdef H5
61
+  // H5平台使用a标签下载
62
+  const link = document.createElement('a')
63
+  link.href = url
64
+  link.download = fileName
65
+  link.target = '_blank'
66
+  document.body.appendChild(link)
67
+  link.click()
68
+  document.body.removeChild(link)
69
+  // #endif
70
+
71
+  // #ifndef H5
72
+  // 非H5平台使用uni.downloadFile
73
+  uni.downloadFile({
74
+    url,
75
+    success: (res) => {
76
+      if (res.statusCode === 200) {
77
+        uni.saveFile({
78
+          tempFilePath: res.tempFilePath,
79
+          success: (saveRes) => {
80
+            uni.showToast({
81
+              title: '下载成功',
82
+              icon: 'success',
83
+            })
84
+          },
85
+          fail: (err) => {
86
+            console.error('保存文件失败:', err)
87
+            uni.showToast({
88
+              title: '保存文件失败',
89
+              icon: 'error',
90
+            })
91
+          },
92
+        })
93
+      }
94
+    },
95
+    fail: (err) => {
96
+      console.error('下载文件失败:', err)
97
+      uni.showToast({
98
+        title: '下载文件失败',
99
+        icon: 'error',
100
+      })
101
+    },
102
+  })
103
+  // #endif
104
+}
105
+</script>
106
+
107
+<template>
108
+  <view class="attachment-list">
109
+    <view
110
+      v-for="(file, index) in files"
111
+      :key="index"
112
+      class="attachment-item"
113
+      :style="{ width: `${size * 4}rpx`, height: `${size * 4}rpx` }"
114
+    >
115
+      <!-- 图片文件 -->
116
+      <view v-if="isImage(getFileName(file, index))" class="image-container">
117
+        <wd-img
118
+          :width="size * 4"
119
+          :height="size * 4"
120
+          :src="file"
121
+          :enable-preview="true"
122
+        />
123
+      </view>
124
+
125
+      <!-- 其他文件 -->
126
+      <view
127
+        v-else
128
+        class="file-container"
129
+        @tap="handleFileDownload(file, getFileName(file, index))"
130
+      >
131
+        <view class="file-icon">
132
+          <wd-icon name="document" size="64rpx" />
133
+        </view>
134
+        <view class="file-extension">
135
+          {{ getFileExtension(getFileName(file, index)) }}
136
+        </view>
137
+      </view>
138
+    </view>
139
+  </view>
140
+</template>
141
+
142
+<style lang="scss" scoped>
143
+.attachment-list {
144
+  width: 100%;
145
+  display: flex;
146
+  overflow-x: auto;
147
+  padding: 10rpx 0;
148
+  scrollbar-width: thin;
149
+  scrollbar-color: #c1c1c1 #f5f5f5;
150
+
151
+  &::-webkit-scrollbar {
152
+    height: 6rpx;
153
+  }
154
+
155
+  &::-webkit-scrollbar-track {
156
+    background: #f5f5f5;
157
+    border-radius: 3rpx;
158
+  }
159
+
160
+  &::-webkit-scrollbar-thumb {
161
+    background: #c1c1c1;
162
+    border-radius: 3rpx;
163
+  }
164
+
165
+  &::-webkit-scrollbar-thumb:hover {
166
+    background: #a8a8a8;
167
+  }
168
+}
169
+
170
+.attachment-item {
171
+  margin-right: 20rpx;
172
+  border-radius: 12rpx;
173
+  overflow: hidden;
174
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
175
+  transition: transform 0.3s, box-shadow 0.3s;
176
+  flex-shrink: 0;
177
+  
178
+  &:hover {
179
+    transform: translateY(-4rpx);
180
+    box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
181
+  }
182
+}
183
+
184
+.image-container {
185
+  width: 100%;
186
+  height: 100%;
187
+  overflow: hidden;
188
+}
189
+
190
+.file-container {
191
+  width: 100%;
192
+  height: 100%;
193
+  display: flex;
194
+  flex-direction: column;
195
+  align-items: center;
196
+  justify-content: center;
197
+  background-color: #f5f7fa;
198
+  cursor: pointer;
199
+}
200
+
201
+.file-icon {
202
+  margin-bottom: 16rpx;
203
+  color: #215acd;
204
+}
205
+
206
+.file-extension {
207
+  font-size: 24rpx;
208
+  font-weight: 500;
209
+  color: #31373d;
210
+  text-transform: uppercase;
211
+}
212
+</style>

+ 27 - 19
src/pages/schedule/details/deal/index2.vue

9
             style="margin-left: 10rpx; transform: translateY(6rpx)"
9
             style="margin-left: 10rpx; transform: translateY(6rpx)"
10
             name="arrow-down"
10
             name="arrow-down"
11
             size="20px"
11
             size="20px"
12
-          ></wd-icon>
12
+          />
13
         </text>
13
         </text>
14
       </view>
14
       </view>
15
       <view>
15
       <view>
22
     </view>
22
     </view>
23
     <scroll-view class="task-container" scroll-y>
23
     <scroll-view class="task-container" scroll-y>
24
       <view class="content-main">
24
       <view class="content-main">
25
-        <view style="font-size: 36rpx; font-weight: 500; margin-bottom: 50rpx"
26
-          >油品:0#</view
27
-        >
25
+        <view style="font-size: 36rpx; font-weight: 500; margin-bottom: 50rpx">
26
+          油品:0#
27
+        </view>
28
         <wd-form ref="form" :model="model">
28
         <wd-form ref="form" :model="model">
29
           <view style="display: flex; flex-direction: column; gap: 90rpx">
29
           <view style="display: flex; flex-direction: column; gap: 90rpx">
30
             <view>
30
             <view>
31
               <view
31
               <view
32
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
32
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
33
-                >液位仪数据</view
34
               >
33
               >
34
+                液位仪数据
35
+              </view>
35
               <wd-input
36
               <wd-input
37
+                v-model="model.value1"
36
                 label="油高 h1(mm)"
38
                 label="油高 h1(mm)"
37
                 label-width="100%"
39
                 label-width="100%"
38
                 prop="value1"
40
                 prop="value1"
39
                 clearable
41
                 clearable
40
-                v-model="model.value1"
41
                 placeholder="请输入"
42
                 placeholder="请输入"
42
                 :rules="[{ required: true, message: '请填写发现问题' }]"
43
                 :rules="[{ required: true, message: '请填写发现问题' }]"
43
                 custom-class="custom-vertical-input"
44
                 custom-class="custom-vertical-input"
44
               />
45
               />
45
               <wd-input
46
               <wd-input
47
+                v-model="model.value2"
46
                 label="水高(mm)"
48
                 label="水高(mm)"
47
                 label-width="100%"
49
                 label-width="100%"
48
                 prop="value2"
50
                 prop="value2"
49
                 clearable
51
                 clearable
50
-                v-model="model.value2"
51
                 placeholder="请输入"
52
                 placeholder="请输入"
52
                 :rules="[{ required: true, message: '请填写处理措施' }]"
53
                 :rules="[{ required: true, message: '请填写处理措施' }]"
53
                 custom-class="custom-vertical-input"
54
                 custom-class="custom-vertical-input"
56
             <view>
57
             <view>
57
               <view
58
               <view
58
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
59
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
59
-                >手工量缸数据</view
60
               >
60
               >
61
+                手工量缸数据
62
+              </view>
61
               <wd-input
63
               <wd-input
64
+                v-model="model.value1"
62
                 label="油高 h1(mm)"
65
                 label="油高 h1(mm)"
63
                 label-width="100%"
66
                 label-width="100%"
64
                 prop="value1"
67
                 prop="value1"
65
                 clearable
68
                 clearable
66
-                v-model="model.value1"
67
                 placeholder="请输入"
69
                 placeholder="请输入"
68
                 :rules="[{ required: true, message: '请填写发现问题' }]"
70
                 :rules="[{ required: true, message: '请填写发现问题' }]"
69
                 custom-class="custom-vertical-input"
71
                 custom-class="custom-vertical-input"
70
               />
72
               />
71
               <wd-input
73
               <wd-input
74
+                v-model="model.value2"
72
                 label="水高(mm)"
75
                 label="水高(mm)"
73
                 label-width="100%"
76
                 label-width="100%"
74
                 prop="value2"
77
                 prop="value2"
75
                 clearable
78
                 clearable
76
-                v-model="model.value2"
77
                 placeholder="请输入"
79
                 placeholder="请输入"
78
                 :rules="[{ required: true, message: '请填写处理措施' }]"
80
                 :rules="[{ required: true, message: '请填写处理措施' }]"
79
                 custom-class="custom-vertical-input"
81
                 custom-class="custom-vertical-input"
80
               />
82
               />
81
               <wd-input
83
               <wd-input
84
+                v-model="model.value2"
82
                 label="水高高度差(mm)(h1-h2)"
85
                 label="水高高度差(mm)(h1-h2)"
83
                 label-width="100%"
86
                 label-width="100%"
84
                 prop="value2"
87
                 prop="value2"
85
                 clearable
88
                 clearable
86
-                v-model="model.value2"
87
                 placeholder="请输入"
89
                 placeholder="请输入"
88
                 :rules="[{ required: true, message: '请填写处理措施' }]"
90
                 :rules="[{ required: true, message: '请填写处理措施' }]"
89
                 custom-class="custom-vertical-input"
91
                 custom-class="custom-vertical-input"
92
             <view>
94
             <view>
93
               <view
95
               <view
94
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
96
                 style="font-size: 32rpx; font-weight: 500; margin-bottom: 30rpx"
95
-                >异常记录</view
96
               >
97
               >
98
+                异常记录
99
+              </view>
97
               <wd-textarea
100
               <wd-textarea
98
-                prop="value1"
99
                 v-model="model.value1"
101
                 v-model="model.value1"
102
+                prop="value1"
100
                 placeholder="请填写异常记录"
103
                 placeholder="请填写异常记录"
101
                 :rules="[{ required: true, message: '请填写异常记录' }]"
104
                 :rules="[{ required: true, message: '请填写异常记录' }]"
102
                 :auto-height="false"
105
                 :auto-height="false"
110
     </scroll-view>
113
     </scroll-view>
111
     <!-- 确定按钮 -->
114
     <!-- 确定按钮 -->
112
     <view class="confirm-btn">
115
     <view class="confirm-btn">
113
-      <button class="btn" @click="submitTasks">确 定</button>
116
+      <button class="btn" @click="submitTasks">
117
+        确 定
118
+      </button>
114
     </view>
119
     </view>
115
     <calendar
120
     <calendar
116
-      v-model:datePickerVisible="datePickerVisible"
117
-      @confirmDate="onconfirmDate"
121
+      v-model:date-picker-visible="datePickerVisible"
118
       :detailedtime="true"
122
       :detailedtime="true"
123
+      @confirm-date="onconfirmDate"
119
     />
124
     />
120
   </view>
125
   </view>
121
 </template>
126
 </template>
127
+
122
 <script lang="ts" setup>
128
 <script lang="ts" setup>
123
-import { ref, reactive, onMounted } from 'vue'
129
+import { onMounted, reactive, ref } from 'vue'
124
 import { useToast } from 'wot-design-uni'
130
 import { useToast } from 'wot-design-uni'
125
 import calendar from '@/utils/calendar.vue'
131
 import calendar from '@/utils/calendar.vue'
132
+
126
 const tab = ref('1缸')
133
 const tab = ref('1缸')
127
 const tabs = ['1缸', '2缸', '3缸', '4缸']
134
 const tabs = ['1缸', '2缸', '3缸', '4缸']
128
 const { success: showSuccess } = useToast()
135
 const { success: showSuccess } = useToast()
140
 
147
 
141
   currentDateTime.value = `${year}-${month}-${day} ${hours}:${minutes}`
148
   currentDateTime.value = `${year}-${month}-${day} ${hours}:${minutes}`
142
 }
149
 }
143
-const handleClickCalendar = () => {
150
+function handleClickCalendar() {
144
   datePickerVisible.value = true
151
   datePickerVisible.value = true
145
 }
152
 }
146
-const onconfirmDate = (date: string) => {
153
+function onconfirmDate(date: string) {
147
   currentDateTime.value = date
154
   currentDateTime.value = date
148
 }
155
 }
149
 onMounted(() => {
156
 onMounted(() => {
172
     })
179
     })
173
 }
180
 }
174
 </script>
181
 </script>
182
+
175
 <style lang="scss" scoped>
183
 <style lang="scss" scoped>
176
 .task-management {
184
 .task-management {
177
   display: flex;
185
   display: flex;

+ 69 - 93
src/pages/schedule/details/deal/inspection.vue

1
 <script lang="ts" setup>
1
 <script lang="ts" setup>
2
-import { computed, onMounted, ref } from 'vue'
3
-import { useRoute, useRouter } from 'vue-router'
2
+import { cloneDeep, isArray } from 'lodash-es'
3
+import { onMounted, ref } from 'vue'
4
+import { useRoute } from 'vue-router'
4
 import { getCheckSubItemsByTaskId, getChecktItemsByTaskId, handleCheckTask, submitCheckLogs } from '@/api/schedule/check'
5
 import { getCheckSubItemsByTaskId, getChecktItemsByTaskId, handleCheckTask, submitCheckLogs } from '@/api/schedule/check'
5
 import { getTaskDetail } from '@/api/schedule/task'
6
 import { getTaskDetail } from '@/api/schedule/task'
6
 import useUpload from '@/hooks/useUpload'
7
 import useUpload from '@/hooks/useUpload'
7
 import anomalyPop from '../popup/anomaly.vue'
8
 import anomalyPop from '../popup/anomaly.vue'
8
-import centerpopup from '../popup/centerpopup.vue'
9
 
9
 
10
 const route = useRoute()
10
 const route = useRoute()
11
 const taskId = ref(Number(route.query.id))
11
 const taskId = ref(Number(route.query.id))
12
 const checkId = ref(Number(route.query.checkId))
12
 const checkId = ref(Number(route.query.checkId))
13
-
13
+const anomalyPopRef = ref<any>(null)
14
 const popShow = ref({
14
 const popShow = ref({
15
   centerShow: false,
15
   centerShow: false,
16
   anomalyShow: false,
16
   anomalyShow: false,
17
 })
17
 })
18
 // const popShow = ref({})
18
 // const popShow = ref({})
19
-const tab = ref('前庭')
20
-
21
 const taskInfo: any = ref({})
19
 const taskInfo: any = ref({})
22
 const checkSubItems: any = ref([])
20
 const checkSubItems: any = ref([])
23
 
21
 
41
   }[]
39
   }[]
42
 }
40
 }
43
 
41
 
44
-// 任务数据
45
-// const tasks = ref<Task[]>([
46
-//   {
47
-//     id: '1',
48
-//     type: '前庭',
49
-//     description:
50
-//       '[AI] [卫生] 前庭海报整齐不歪斜,干净无灰尘污渍(立柱、灯箱、展架等)。',
51
-//     instructions: '拍照:按照示例图拍摄前庭内海报宣传物,可上传多张照片',
52
-//     examples: [
53
-//       'https://picsum.photos/id/1018/200/150',
54
-//       'https://picsum.photos/id/1019/200/150',
55
-//     ],
56
-//     images: [],
57
-//     isimages: true,
58
-//     status: 'normal',
59
-//   },
60
-//   {
61
-//     id: '2',
62
-//     type: '前庭',
63
-//     description: '[卫生] 抽油枪栓是否出现空转或存在明显渗油。',
64
-//     icon: 'help-circle',
65
-//     instructions: '',
66
-//     examples: [],
67
-//     images: [],
68
-//     isimages: false,
69
-//     status: 'normal',
70
-//     details: [{ name: '12号枪', status: 'normal' }],
71
-//   },
72
-//   {
73
-//     id: '3',
74
-//     type: '前庭',
75
-//     description:
76
-//       '[AI] [卫生] 前庭海报整齐不歪斜,干净无灰尘污渍(立柱、灯箱、展架等)。',
77
-//     instructions: '拍照:按照示例图拍摄前庭内海报宣传物,可上传多张照片',
78
-//     examples: [
79
-//       'https://picsum.photos/id/1018/200/150',
80
-//       'https://picsum.photos/id/1019/200/150',
81
-//     ],
82
-//     images: ['https://picsum.photos/id/1025/200/150'],
83
-//     isimages: true,
84
-//     status: 'normal',
85
-//   },
86
-// ])
87
-
88
 // 选择图片
42
 // 选择图片
89
 function chooseImage(index: number) {
43
 function chooseImage(index: number) {
90
   // 为每个上传请求创建独立的upload实例,确保能正确处理对应的任务索引
44
   // 为每个上传请求创建独立的upload实例,确保能正确处理对应的任务索引
95
       const imageUrl = res.url || ''
49
       const imageUrl = res.url || ''
96
       if (imageUrl) {
50
       if (imageUrl) {
97
         console.log('currentCheckList.value[index]', currentCheckList.value[index], imageUrl)
51
         console.log('currentCheckList.value[index]', currentCheckList.value[index], imageUrl)
98
-        if (!currentCheckList.value[index]?.dealPhoto) {
99
-          currentCheckList.value[index].dealPhoto = []
52
+        if (!currentCheckList.value[index]?.photoUrl) {
53
+          currentCheckList.value[index].photoUrl = []
100
         }
54
         }
101
         nextTick(() => {
55
         nextTick(() => {
102
-          currentCheckList.value[index].dealPhoto.push({
56
+          currentCheckList.value[index].photoUrl.push({
103
             url: imageUrl,
57
             url: imageUrl,
104
             name: res.fileName,
58
             name: res.fileName,
105
           })
59
           })
113
   uploadImage()
67
   uploadImage()
114
 }
68
 }
115
 const selectTask = ref<any>({})
69
 const selectTask = ref<any>({})
70
+const anomalyData = ref<any>({})
116
 // 切换任务状态
71
 // 切换任务状态
117
-function toggleTaskStatus(task: any) {
72
+async function toggleTaskStatus(task: any) {
118
   selectTask.value = task
73
   selectTask.value = task
74
+  // 初始化异常数据
75
+  console.log('task.formOperationIssue', task.formOperationIssue)
76
+  anomalyData.value = task.formOperationIssue || {}
119
   popShow.value.anomalyShow = true
77
   popShow.value.anomalyShow = true
78
+  await nextTick()
79
+  let problemPhoto = cloneDeep(anomalyData.value.problemPhoto)
80
+  if (problemPhoto && !isArray(problemPhoto)) {
81
+    problemPhoto = problemPhoto.split(',').map((url: string, index: number) => ({
82
+      name: url.trim(),
83
+      url: anomalyData.value.problemPhotoUrl[index],
84
+    }))
85
+  }
86
+  const data = {
87
+    ...anomalyData.value,
88
+    problemPhoto,
89
+  }
90
+  console.log('data123', data)
91
+  anomalyPopRef.value?.updateModelData(data)
120
 }
92
 }
121
 
93
 
122
 // 处理异常信息提交
94
 // 处理异常信息提交
123
 function handleAnomalySubmitted({ checkItemId, data }: { checkItemId: number, data: any }) {
95
 function handleAnomalySubmitted({ checkItemId, data }: { checkItemId: number, data: any }) {
124
   // 在 currentCheckList 中找到对应的任务
96
   // 在 currentCheckList 中找到对应的任务
125
   const taskIndex = currentCheckList.value.findIndex((item: any) => item.id === checkItemId)
97
   const taskIndex = currentCheckList.value.findIndex((item: any) => item.id === checkItemId)
98
+  console.log('taskIndex', taskIndex)
126
   if (taskIndex !== -1) {
99
   if (taskIndex !== -1) {
127
     // 在任务对象中添加标记,表明异常信息已填写
100
     // 在任务对象中添加标记,表明异常信息已填写
128
-    currentCheckList.value[taskIndex].hasAnomalyInfo = true
101
+    // currentCheckList.value[taskIndex].hasAnomalyInfo = true
129
     // 保存提交的异常数据
102
     // 保存提交的异常数据
130
-    currentCheckList.value[taskIndex].anomalyData = data
103
+    currentCheckList.value[taskIndex].formOperationIssue = data
131
   }
104
   }
105
+
106
+  popShow.value.anomalyShow = false
132
 }
107
 }
133
 
108
 
134
 // 处理 dealResult 变化
109
 // 处理 dealResult 变化
135
 function handleDealResultChange(task: any) {
110
 function handleDealResultChange(task: any) {
136
   // 当用户选择异常时,自动弹出异常信息填写抽屉
111
   // 当用户选择异常时,自动弹出异常信息填写抽屉
137
-  if (task.dealResult === '2') {
112
+  if (task.result === 2) {
113
+    anomalyData.value = task.formOperationIssue || {}
138
     toggleTaskStatus(task)
114
     toggleTaskStatus(task)
139
   }
115
   }
140
 }
116
 }
160
     const logs = []
136
     const logs = []
161
     const items = checkSubItems.value[index]?.items || []
137
     const items = checkSubItems.value[index]?.items || []
162
     currentCheckList.value.forEach((item: any, index: number) => {
138
     currentCheckList.value.forEach((item: any, index: number) => {
139
+      let result = 1
140
+      if (item.dealHasScore) {
141
+        result = (item.dealScore || 0) === item.limitScore ? 1 : 2
142
+      }
143
+      else {
144
+        result = item.result || 1
145
+      }
163
       const logInfo = {
146
       const logInfo = {
164
-        inputItem: item.dealInputItem || '', // 输入内容
147
+        inputItem: item.inputItem || '', // 输入内容
165
         itemId: item.id || '', // 检查项ID
148
         itemId: item.id || '', // 检查项ID
166
-        photo: item.dealPhoto?.map((photo: any) => photo.name).join(',') || '', // 照片
167
-        result: item.dealHasScore ? (item.dealScore || 0) === item.limitScore ? '1' : '2' : '3', // 检查结果1正常2异常3不适用
149
+        photo: item.photoUrl?.map((photo: any) => photo.name).join(',') || '', // 照片
150
+        result, // 检查结果1正常2异常3不适用
168
         score: item.dealHasScore ? item.dealScore || 0 : 0, // 分数
151
         score: item.dealHasScore ? item.dealScore || 0 : 0, // 分数
169
       }
152
       }
170
 
153
 
171
       // 做一些判断,比如必填项
154
       // 做一些判断,比如必填项
172
-      if (item.hasPhoto === 2 && !item.dealPhoto?.length) {
155
+      if (item.hasPhoto === 2 && !item.photoUrl?.length) {
173
         throw new Error('请上传照片')
156
         throw new Error('请上传照片')
174
       }
157
       }
175
 
158
 
176
-      if (item.hasInput === 1 && !item.dealInputItem) {
159
+      if (item.hasInput === 1 && !item.inputItem) {
177
         throw new Error('请输入内容')
160
         throw new Error('请输入内容')
178
       }
161
       }
179
 
162
 
180
-      if (logInfo.result === '2') {
163
+      if (logInfo.result === 2) {
181
       // 判断是否输入异常项
164
       // 判断是否输入异常项
182
       // if (!item.dealScore) {
165
       // if (!item.dealScore) {
183
       //   uni.showToast({
166
       //   uni.showToast({
264
       // 为每个任务添加 score 字段
247
       // 为每个任务添加 score 字段
265
       item.items.forEach((task: any) => {
248
       item.items.forEach((task: any) => {
266
         task.score = task.score || null
249
         task.score = task.score || null
250
+        task.photoUrl = (task.photoUrl || []).map((url: string, index: number) => ({
251
+          url,
252
+          name: task.photo.split(',')[index],
253
+        }))
267
       })
254
       })
268
     })
255
     })
269
     // 更新检查项数据
256
     // 更新检查项数据
273
   })
260
   })
274
 }
261
 }
275
 
262
 
276
-function getPhotos(item: any): Array<{ isExample: boolean, url: string }> {
277
-  const list: Array<{ isExample: boolean, url: string }> = (
278
-    item.exampleImageUrl || []
279
-  ).map((url: string) => ({
280
-    url,
281
-    isExample: true,
282
-  }));
283
-  (item.photoUrl || []).forEach((url: string) => {
284
-    list.push({
285
-      url,
286
-      isExample: false,
287
-    })
288
-  })
289
-
290
-  return list
291
-}
292
-
293
 onMounted(async () => {
263
 onMounted(async () => {
294
   await init()
264
   await init()
295
 })
265
 })
334
           </view>
304
           </view>
335
 
305
 
336
           <view v-if="task.hasInput > 0" class="input-container" style="margin-right: 1rem;">
306
           <view v-if="task.hasInput > 0" class="input-container" style="margin-right: 1rem;">
337
-            <wd-textarea v-model="task.dealInputItem" :placeholder="task.inputContent || '请输入内容'" :maxlength="100" show-word-limit />
307
+            <wd-textarea v-model="task.inputItem" :placeholder="task.inputContent || '请输入内容'" :maxlength="100" show-word-limit />
338
           </view>
308
           </view>
339
 
309
 
340
           <!-- 操作说明 -->
310
           <!-- 操作说明 -->
374
             </view>
344
             </view>
375
 
345
 
376
             <!-- 已上传图片 -->
346
             <!-- 已上传图片 -->
377
-            <view v-if="task?.dealPhoto?.length > 0" class="uploaded-images">
347
+            <view v-if="task?.photoUrl?.length > 0" class="uploaded-images">
378
               <view
348
               <view
379
-                v-for="(image, idx) in task.dealPhoto"
349
+                v-for="(image, idx) in task.photoUrl"
380
                 :key="idx"
350
                 :key="idx"
381
                 class="uploaded-image"
351
                 class="uploaded-image"
382
               >
352
               >
385
             </view>
355
             </view>
386
           </view>
356
           </view>
387
           <view v-if="task.checkResult === 1" style="margin-left: 1rem;">
357
           <view v-if="task.checkResult === 1" style="margin-left: 1rem;">
388
-            <wd-radio-group v-model="task.dealResult" shape="dot" inline @change="handleDealResultChange(task)">
389
-              <wd-radio value="1">
358
+            <wd-radio-group v-model="task.result" shape="dot" inline @change="handleDealResultChange(task)">
359
+              <wd-radio :value="1">
390
                 正常
360
                 正常
391
               </wd-radio>
361
               </wd-radio>
392
-              <wd-radio value="2">
362
+              <wd-radio :value="2">
393
                 异常
363
                 异常
394
               </wd-radio>
364
               </wd-radio>
395
-              <wd-radio value="3">
365
+              <wd-radio :value="3">
396
                 不适用
366
                 不适用
397
               </wd-radio>
367
               </wd-radio>
398
             </wd-radio-group>
368
             </wd-radio-group>
399
-            <view v-if="task.dealResult === '2'" style="margin-top: 8rpx;">
400
-              <text class="link-text" @tap="toggleTaskStatus(task)">{{ task.hasAnomalyInfo ? '点击查看异常' : '点击填写异常' }}</text>
369
+            <view v-if="task.result === 2" style="margin-top: 8rpx;">
370
+              <text class="link-text" @tap="toggleTaskStatus(task)">{{ task.formOperationIssue ? '点击查看异常' : '点击填写异常' }}</text>
401
             </view>
371
             </view>
402
           </view>
372
           </view>
403
 
373
 
416
               </view>
386
               </view>
417
             </view>
387
             </view>
418
             <view v-if="task.dealScore !== null && task.dealScore < task.limitScore && !task.dealHasScore" class="abnormal-link">
388
             <view v-if="task.dealScore !== null && task.dealScore < task.limitScore && !task.dealHasScore" class="abnormal-link">
419
-              <text class="link-text" @tap="toggleTaskStatus(task)">{{ task.hasAnomalyInfo ? '点击查看异常' : '点击填写异常(未满分必填)' }}</text>
389
+              <text class="link-text" @tap="toggleTaskStatus(task)">{{ task.formOperationIssue ? '点击查看异常' : '点击填写异常(未满分必填)' }}</text>
420
             </view>
390
             </view>
421
           </view>
391
           </view>
422
         </view>
392
         </view>
423
       </view>
393
       </view>
424
     </scroll-view>
394
     </scroll-view>
425
-    <centerpopup v-model:center-show="popShow.centerShow" />
426
-
427
-    <anomalyPop v-model:anomaly-show="popShow.anomalyShow" :task-id="taskId" :station-id="taskInfo.stationId" :check-item-id="selectTask.id" @anomaly-submitted="handleAnomalySubmitted" />
395
+    <wd-popup
396
+      v-model="popShow.anomalyShow"
397
+      custom-style="border-radius: 32rpx 32rpx 0 0; height: 80%;z-index: 100;"
398
+      position="bottom"
399
+      :safe-area-inset-bottom="true"
400
+      closable
401
+    >
402
+      <anomalyPop v-if="popShow.anomalyShow" ref="anomalyPopRef" :task-id="taskId" :station-id="taskInfo.stationId" :check-item-id="selectTask.id" :anomaly-data="anomalyData.value" @anomaly-submitted="handleAnomalySubmitted" />
403
+    </wd-popup>
428
     <!-- 确定按钮 -->
404
     <!-- 确定按钮 -->
429
     <view class="confirm-btn">
405
     <view class="confirm-btn">
430
       <button class="btn" @click="submitTasks">
406
       <button class="btn" @click="submitTasks">

+ 145 - 0
src/pages/schedule/details/deal/photo.vue

1
+<script setup lang="ts">
2
+import { onMounted, ref } from 'vue'
3
+import { useToast } from 'wot-design-uni'
4
+import { dealPhotoTask } from '@/api/schedule/task'
5
+import useUpload from '@/hooks/useUpload'
6
+
7
+const toast = useToast()
8
+
9
+definePage({
10
+  style: {
11
+    navigationBarTitleText: '拍照任务',
12
+  },
13
+})
14
+
15
+// 任务和检查项ID
16
+const taskId = ref('')
17
+const checkId = ref('')
18
+
19
+// 表单数据
20
+const formData = ref({
21
+  attachments: '',
22
+  remark: '',
23
+})
24
+
25
+// 上传图片列表
26
+const fileList = ref<any[]>([])
27
+
28
+// 上传状态
29
+const loading = ref(false)
30
+
31
+// 上传问题照片
32
+const uploadProblemPhoto: any = (file, formData, options) => {
33
+  const { customUpload } = useUpload({
34
+    fileType: 'image',
35
+  })
36
+  return customUpload(file, formData, options)
37
+}
38
+
39
+// 删除问题照片
40
+function deleteProblemPhoto(index: number) {
41
+  fileList.value.splice(index, 1)
42
+
43
+  // 更新附件字段
44
+  const fileNames = fileList.value.map((item: any) => item.name).filter(Boolean)
45
+  formData.value.attachments = fileNames.join(',')
46
+}
47
+
48
+// 提交表单
49
+async function submitForm() {
50
+  // 检查是否有图片上传
51
+  if (fileList.value.length === 0) {
52
+    toast.info('请上传图片')
53
+    return
54
+  }
55
+
56
+  // 构建请求参数
57
+  const params = {
58
+    id: taskId.value,
59
+    attachment: fileList.value.map((item: any) => item.name).join(','),
60
+    result: formData.value.remark,
61
+  }
62
+
63
+  // 开始提交,显示 loading
64
+  loading.value = true
65
+
66
+  // 调用处理任务附件接口
67
+  try {
68
+    const res: any = await dealPhotoTask(params)
69
+    if (res.code === 200) {
70
+      toast.success('提交成功')
71
+      // 跳转回上一页
72
+      setTimeout(() => {
73
+        uni.navigateBack()
74
+      }, 1500)
75
+    }
76
+    else {
77
+      toast.error(res.msg || '提交失败,请重试')
78
+      return
79
+    }
80
+  }
81
+  catch (error) {
82
+    toast.error('提交失败,请重试')
83
+    return
84
+  }
85
+  finally {
86
+    // 提交完成,隐藏 loading
87
+    loading.value = false
88
+  }
89
+}
90
+
91
+// 页面加载时获取参数
92
+onMounted(() => {
93
+  // 获取页面参数
94
+  const pages = getCurrentPages()
95
+  const currentPage = pages[pages.length - 1]
96
+  // 使用类型断言获取options
97
+  const options = (currentPage as any).options || {}
98
+  taskId.value = options.id || ''
99
+  checkId.value = options.checkId || ''
100
+})
101
+</script>
102
+
103
+<template>
104
+  <view class="page min-h-screen bg-gray-100 p-4">
105
+    <view class="rounded-lg bg-white p-4 shadow-sm">
106
+      <!-- 上传图片 -->
107
+      <view class="mb-6">
108
+        <view class="mb-4 flex items-center justify-between">
109
+          <text class="font-medium">上传图片</text>
110
+        </view>
111
+        <view>
112
+          <wd-upload
113
+            v-model:file-list="fileList"
114
+            image-mode="aspectFill"
115
+            :upload-method="uploadProblemPhoto"
116
+            @delete="deleteProblemPhoto"
117
+          />
118
+        </view>
119
+      </view>
120
+
121
+      <!-- 备注 -->
122
+      <view class="mb-6">
123
+        <text class="mb-2 block font-medium">处理结果</text>
124
+        <wd-textarea v-model="formData.remark" placeholder="请填写处理结果" auto-height :maxlength="120" clearable show-word-limit />
125
+      </view>
126
+
127
+      <!-- 提交按钮 -->
128
+      <view class="mt-8 flex justify-center">
129
+        <wd-button
130
+          type="primary"
131
+          size="large"
132
+          :loading="loading"
133
+          @click="submitForm"
134
+        >
135
+          提交
136
+        </wd-button>
137
+      </view>
138
+    </view>
139
+    <wd-toast />
140
+  </view>
141
+</template>
142
+
143
+<style lang="scss" scoped>
144
+// 保持与upload.vue一致的样式
145
+</style>

+ 161 - 14
src/pages/schedule/details/deal/upload.vue

1
-<template>
2
-  <view class="page-container">
3
-    <view class="page-header">
4
-      <view class="page-header-left">
5
-        <view class="page-header-left-title">
6
-          上传文件
7
-        </view>
8
-      </view>
9
-    </view>
10
-  </view>
11
-</template>
12
-
13
 <script setup lang="ts">
1
 <script setup lang="ts">
14
 import { onMounted, ref } from 'vue'
2
 import { onMounted, ref } from 'vue'
3
+import { useToast } from 'wot-design-uni'
4
+import { dealUploadTask } from '@/api/schedule/task'
5
+import useUpload from '@/hooks/useUpload'
6
+
7
+const toast = useToast()
15
 
8
 
16
 const taskId = ref('')
9
 const taskId = ref('')
17
 const checkId = ref('')
10
 const checkId = ref('')
18
 
11
 
12
+// 表单数据
13
+const formData = ref({
14
+  attachments: '',
15
+  remark: '',
16
+})
17
+
18
+// 上传文件列表
19
+const uploadFiles = ref<any[]>([])
20
+
21
+// 初始化useUpload
22
+const { run: uploadRun, loading: uploadLoading } = useUpload({
23
+  fileType: 'file',
24
+  success: (data) => {
25
+    console.log('上传成功:', data)
26
+
27
+    // 构建文件对象
28
+    const fileObj = {
29
+      url: data.url || '',
30
+      originalFilename: data.originalFilename || data.name || '',
31
+      name: data.fileName || data.name || '',
32
+    }
33
+
34
+    // 添加到上传文件列表
35
+    uploadFiles.value.push(fileObj)
36
+
37
+    // 更新附件字段
38
+    const fileNames = uploadFiles.value.map((f) => {
39
+      try {
40
+        const response = JSON.parse(f.response)
41
+        return response.data.fileName
42
+      }
43
+      catch (error) {
44
+        console.error('解析文件响应失败:', error)
45
+        return ''
46
+      }
47
+    }).filter(Boolean)
48
+
49
+    formData.value.attachments = fileNames.join(',')
50
+    console.log('文件名称:', formData.value.attachments)
51
+  },
52
+  error: (err) => {
53
+    console.error('上传失败:', err)
54
+    toast.error('上传失败,请重试')
55
+  },
56
+})
57
+
58
+// 处理删除文件
59
+function handleRemoveFile(file: any) {
60
+  const index = uploadFiles.value.findIndex(f => f.url === file.url)
61
+  if (index !== -1) {
62
+    uploadFiles.value.splice(index, 1)
63
+
64
+    // 更新附件字段
65
+    const fileNames = uploadFiles.value.map((f) => {
66
+      try {
67
+        const response = JSON.parse(f.response)
68
+        return response.data.fileName
69
+      }
70
+      catch (error) {
71
+        console.error('解析文件响应失败:', error)
72
+        return ''
73
+      }
74
+    }).filter(Boolean)
75
+
76
+    formData.value.attachments = fileNames.join(',')
77
+  }
78
+}
79
+
80
+// 提交表单
81
+async function submitForm() {
82
+  // 这里可以添加表单验证逻辑
83
+
84
+  // 检查是否有文件上传
85
+  if (uploadFiles.value.length === 0) {
86
+    toast.info('请上传附件')
87
+    return
88
+  }
89
+
90
+  // 构建请求参数
91
+  const params = {
92
+    taskId: Number(taskId.value),
93
+    checkId: Number(checkId.value),
94
+    ...formData.value,
95
+    id: taskId.value,
96
+    attachment: uploadFiles.value.map(f => f.name).join(','),
97
+    attachmentName: uploadFiles.value.map(f => f.originalFilename).join(','),
98
+    remark: formData.value.remark,
99
+  }
100
+
101
+  // 调用处理任务附件接口
102
+  try {
103
+    const res: any = await dealUploadTask(params)
104
+    if (res.code === 200) {
105
+      toast.success('提交成功')
106
+      // 跳转回上一页
107
+      setTimeout(() => {
108
+        uni.navigateBack()
109
+      }, 1500)
110
+    }
111
+    else {
112
+      toast.error(res.msg || '提交失败,请重试')
113
+      return
114
+    }
115
+  }
116
+  catch (error) {
117
+    toast.error('提交失败,请重试')
118
+    return
119
+  }
120
+}
121
+
122
+// 页面加载时获取参数
19
 onMounted(() => {
123
 onMounted(() => {
20
-//   taskId.value = getQueryParam('id') || ''
21
-//   checkId.value = getQueryParam('checkId') || ''
124
+  // 获取页面参数
125
+  const pages = getCurrentPages()
126
+  const currentPage = pages[pages.length - 1]
127
+  // 使用类型断言获取options
128
+  const options = (currentPage as any).options || {}
129
+  taskId.value = options.id || ''
130
+  checkId.value = options.checkId || ''
22
 })
131
 })
23
 </script>
132
 </script>
133
+
134
+<template>
135
+  <view class="page min-h-screen bg-gray-100 p-4">
136
+    <view class="rounded-lg bg-white p-4 shadow-sm">
137
+      <!-- 上传附件 -->
138
+      <view class="mb-6">
139
+        <view class="flex items-center justify-between">
140
+          <text class="font-medium">上传附件</text>
141
+          <wd-button type="text" @click="uploadRun">
142
+            点击上传附件
143
+          </wd-button>
144
+        </view>
145
+        <view v-for="(file, index) in uploadFiles" :key="index" class="mt-2 flex items-center justify-between">
146
+          <wd-icon name="close-circle" class="mr-2 text-red-500" @click="handleRemoveFile(file)" />
147
+          <wd-text :text="file.originalFilename" class="flex-1" />
148
+        </view>
149
+      </view>
150
+
151
+      <!-- 备注 -->
152
+      <view class="mb-6">
153
+        <text class="mb-2 block font-medium">备注</text>
154
+        <wd-textarea v-model="formData.remark" placeholder="请填写备注" auto-height :maxlength="120" clearable show-word-limit />
155
+      </view>
156
+
157
+      <!-- 提交按钮 -->
158
+      <view class="mt-8 flex justify-center">
159
+        <wd-button
160
+          type="primary"
161
+          size="large"
162
+          @click="submitForm"
163
+        >
164
+          提交
165
+        </wd-button>
166
+      </view>
167
+      <wd-toast />
168
+    </view>
169
+  </view>
170
+</template>

+ 199 - 157
src/pages/schedule/details/taskdetails/index.vue

1
+<script lang="ts" setup>
2
+import { ref } from 'vue'
3
+
4
+import { useRoute } from 'vue-router'
5
+import { getCheckSubItemsByTaskId, getChecktItemsByTaskId } from '@/api/schedule/check'
6
+import { getTaskDetail } from '@/api/schedule/task'
7
+
8
+const route = useRoute()
9
+const taskId = ref(Number(route.query.id))
10
+const checkId = ref(Number(route.query.checkId))
11
+const taskInfo = ref<any>({})
12
+const checkSubItems = ref<any[]>([])
13
+const activeArea = ref(0)
14
+const popupShow = ref({
15
+  centerShow: false,
16
+  bottomShow: false,
17
+})
18
+
19
+const currentCheckItem = ref<any>({})
20
+
21
+const statics = ref({
22
+  score: 0,
23
+  totalScore: 0,
24
+  totalItems: 0,
25
+  photoCount: 0,
26
+})
27
+
28
+function init() {
29
+  // 并发获取数据
30
+  Promise.all([
31
+    getTaskDetail(taskId.value),
32
+    getChecktItemsByTaskId({
33
+      checkId: checkId.value,
34
+      pageSize: 100,
35
+    }),
36
+    getCheckSubItemsByTaskId({
37
+      checkId: checkId.value,
38
+      pageSize: 100,
39
+    }),
40
+  ]).then(([taskDetailRes, checkItemsRes, checkSubItemsRes]: any) => {
41
+    if (taskDetailRes.data) {
42
+      taskInfo.value = taskDetailRes.data
43
+    }
44
+    // 处理检查项数据
45
+    checkSubItems.value = checkSubItemsRes?.rows || []
46
+    checkSubItems.value.forEach((item: any) => {
47
+      item.statics = {
48
+        score: 0,
49
+        totalScore: 0,
50
+        totalItems: 0,
51
+        photoCount: 0,
52
+      }
53
+      item.items
54
+        = checkItemsRes?.rows?.filter(
55
+          (subItem: any) => subItem.subItemId === item.id,
56
+        ) || []
57
+      // 为每个任务添加 score 字段
58
+      item.items.forEach((task: any) => {
59
+        if (task.checkResult === 2) {
60
+          item.statics.score += task.score || 0
61
+          item.statics.totalScore += (task.limitScore || 0).length
62
+        }
63
+        if (task?.result === 2) {
64
+          item.statics.totalItems += 1
65
+        }
66
+        if (task?.hasPhoto > 0 && (!task?.photoUrl || task?.photoUrl?.length === 0)) {
67
+          item.statics.photoCount += 1
68
+        }
69
+        task.score = task.score || null
70
+        task.photoUrl = (task.photoUrl || []).map((url: string, index: number) => ({
71
+          url,
72
+          name: task.photo.split(',')[index],
73
+        }))
74
+      })
75
+      // 计算总得分
76
+      statics.value.score += item.statics.score
77
+      statics.value.totalScore += item.statics.totalScore
78
+      statics.value.totalItems += item.statics.totalItems
79
+      statics.value.photoCount += item.statics.photoCount
80
+    })
81
+    // 更新检查项数据
82
+    activeArea.value = 0
83
+    currentCheckItem.value = checkSubItems.value[0] || {}
84
+  })
85
+}
86
+const toastHtml = ref('')
87
+function helpClick(task: any) {
88
+  toastHtml.value = task.checkDescription
89
+  popupShow.value.centerShow = true
90
+}
91
+
92
+function helpClose() {
93
+  toastHtml.value = ''
94
+  popupShow.value.centerShow = false
95
+}
96
+
97
+async function changeTab({ index }: { index: number }) {
98
+  currentCheckItem.value = checkSubItems.value[index] || {}
99
+}
100
+
101
+onMounted(async () => {
102
+  await init()
103
+})
104
+</script>
105
+
1
 <template>
106
 <template>
2
   <view class="task-management">
107
   <view class="task-management">
3
     <view class="fixed-area">
108
     <view class="fixed-area">
4
       <view class="head-Card">
109
       <view class="head-Card">
5
         <view class="head-Card-title">
110
         <view class="head-Card-title">
6
-          未来路加油站
111
+          {{ taskInfo.stationName || '' }}
7
         </view>
112
         </view>
8
         <view class="head-Card-tab">
113
         <view class="head-Card-tab">
9
           <view class="head-Card-tab-item">
114
           <view class="head-Card-tab-item">
10
             <view class="tab-item-num">
115
             <view class="tab-item-num">
11
-              0
116
+              {{ statics.photoCount || 0 }}
12
             </view>
117
             </view>
13
             <view class="tab-item-text">
118
             <view class="tab-item-text">
14
               无拍照
119
               无拍照
17
           <view class="head-Card-tab-item">
122
           <view class="head-Card-tab-item">
18
             <view class="tab-item-Middle">
123
             <view class="tab-item-Middle">
19
               <view class="tab-item-num">
124
               <view class="tab-item-num">
20
-                0
125
+                {{ statics.totalItems || 0 }}
21
               </view>
126
               </view>
22
               <view class="tab-item-text">
127
               <view class="tab-item-text">
23
                 异常总数
128
                 异常总数
26
           </view>
131
           </view>
27
           <view class="head-Card-tab-item">
132
           <view class="head-Card-tab-item">
28
             <view class="tab-item-num">
133
             <view class="tab-item-num">
29
-              0 /
30
-              <text style="font-size: 24rpx; font-weight: 500">10</text>
134
+              {{ statics.score || 0 }} / {{ statics.totalScore || 0 }}
31
             </view>
135
             </view>
32
             <view class="tab-item-text">
136
             <view class="tab-item-text">
33
               总得分
137
               总得分
36
         </view>
140
         </view>
37
       </view>
141
       </view>
38
       <view>
142
       <view>
39
-        <wd-tabs v-model="tab">
40
-          <block v-for="item in tabs" :key="item">
41
-            <wd-tab :title="`${item}`" :name="item" />
143
+        <wd-tabs v-model="activeArea" @click="changeTab">
144
+          <block v-for="(item, index) in checkSubItems" :key="index">
145
+            <wd-tab :title="`${item.name}`" :name="index" />
42
           </block>
146
           </block>
43
         </wd-tabs>
147
         </wd-tabs>
44
       </view>
148
       </view>
47
     <scroll-view class="task-container" scroll-y>
151
     <scroll-view class="task-container" scroll-y>
48
       <view class="task-top-left">
152
       <view class="task-top-left">
49
         <text>
153
         <text>
50
-          异常数<text style="color: #31373d; font-weight: 600"> 0</text>
154
+          异常数 <text style="color: #31373d; font-weight: 600">
155
+            {{ currentCheckItem?.statics?.totalItems || 0 }}
156
+          </text>
51
         </text>
157
         </text>
52
-        <text style="color: #31373d; font-weight: 600">|</text>
158
+        <text style="color: #31373d; font-weight: 600"> | </text>
53
         <text>
159
         <text>
54
-          得分<text style="color: #31373d; font-weight: 600"> 0/0</text>
160
+          得分 <text style="color: #31373d; font-weight: 600">
161
+            {{ currentCheckItem?.statics?.score || 0 }} / {{ currentCheckItem?.statics?.totalScore || 0 }}
162
+          </text>
55
         </text>
163
         </text>
56
       </view>
164
       </view>
57
       <view class="tasks">
165
       <view class="tasks">
58
         <view
166
         <view
59
-          v-for="(task, index) in currentTasks"
167
+          v-for="(task, index) in currentCheckItem?.items || []"
60
           :key="index"
168
           :key="index"
61
           class="task-item"
169
           class="task-item"
62
         >
170
         >
63
           <!-- 任务描述 -->
171
           <!-- 任务描述 -->
64
           <view class="task-description">
172
           <view class="task-description">
65
-            <text class="task-number">{{ index + 1 }}.</text>
173
+            <text class="task-number">{{ +index + 1 }}.</text>
66
             <text class="task-text">
174
             <text class="task-text">
67
-              {{ task.description }}
68
-              <wd-icon
69
-                v-if="task?.questionicon"
70
-                :name="task?.questionicon"
71
-                size="32rpx"
72
-                @click="() => (popupshow.centershow = true)"
73
-              />
175
+              {{ task.tagName ? `【${task.tagName.replace(/,/g, '|')}】` : '' }}
176
+              {{ task.itemName }}
177
+              <wd-icon v-if="task?.checkDescription" name="help-circle" size="16px" @click="helpClick(task)" />
74
             </text>
178
             </text>
75
           </view>
179
           </view>
76
           <!-- 操作说明-图片示例 -->
180
           <!-- 操作说明-图片示例 -->
77
           <view
181
           <view
78
-            v-if="task.instructions && task.examples.length > 0"
182
+            v-if="task.exampleImageUrl.length > 0"
79
             class="task-instructions-example"
183
             class="task-instructions-example"
80
           >
184
           >
81
-            <view class="task-instructions">
82
-              <text class="instructions-text">{{ task.instructions }}</text>
185
+            <view v-if="task.photoPrompt" class="task-instructions">
186
+              <text class="instructions-text">{{ `拍照:${task.photoPrompt}` }}</text>
83
             </view>
187
             </view>
84
             <view class="example-images">
188
             <view class="example-images">
85
               <view
189
               <view
86
-                v-for="(example, idx) in task.examples"
190
+                v-for="(example, idx) in task.exampleImageUrl"
87
                 :key="idx"
191
                 :key="idx"
88
                 class="example-image"
192
                 class="example-image"
89
               >
193
               >
93
             </view>
197
             </view>
94
           </view>
198
           </view>
95
           <!-- 已上传图片 -->
199
           <!-- 已上传图片 -->
96
-          <view v-if="task.images.length > 0" class="uploaded-images">
200
+          <view v-if="task?.photoUrl?.length > 0" class="uploaded-images">
97
             <view
201
             <view
98
-              v-for="(image, idx) in task.images"
202
+              v-for="(image, idx) in task.photoUrl"
99
               :key="idx"
203
               :key="idx"
100
               class="uploaded-image"
204
               class="uploaded-image"
101
             >
205
             >
102
-              <image :src="image" mode="aspectFill" />
206
+              <!-- <image :src="image" mode="aspectFill" /> -->
207
+              <wd-img style="width: 100%; height: 100%" :src="image.url" :enable-preview="true" />
103
             </view>
208
             </view>
104
           </view>
209
           </view>
105
           <!-- 几号枪 -->
210
           <!-- 几号枪 -->
106
-          <view v-if="task.jihaoqiang" class="jihaoqiang">
107
-            <text class="jihaoqiang-text">{{ task.jihaoqiang }}</text>
211
+          <view v-if="task?.inputItem" class="whichGun">
212
+            <text class="whichGun-text">{{ task.inputItem }}</text>
108
           </view>
213
           </view>
109
           <!-- 状态 -->
214
           <!-- 状态 -->
110
           <view class="task-status">
215
           <view class="task-status">
111
             <view>
216
             <view>
112
               <text class="status-text">
217
               <text class="status-text">
113
-                整体:{{ task.status === 'normal' ? '正常' : '异常' }}
218
+                整体:{{ task.result === 1 ? '正常' : task.result === 2 ? '异常' : '不适用' }}
114
               </text>
219
               </text>
115
             </view>
220
             </view>
116
           </view>
221
           </view>
117
-          <view v-if="task.exceptiondescription" class="exceptiondescription">
118
-            <view class="exceptiondescription-title">
222
+          <view v-if="task?.formOperationIssue?.id" class="anomalyDescription">
223
+            <view class="anomalyDescription-title">
119
               异常描述:
224
               异常描述:
120
             </view>
225
             </view>
121
-            <view class="exceptiondescription-content">
122
-              {{ task.exceptiondescription }}
226
+            <view class="anomalyDescription-content">
227
+              {{ task.formOperationIssue?.problemDescription || '' }}
123
             </view>
228
             </view>
124
           </view>
229
           </view>
125
         </view>
230
         </view>
126
       </view>
231
       </view>
127
     </scroll-view>
232
     </scroll-view>
128
-    <centerpopup v-model:centershow="popupshow.centershow" />
129
-    <bottompopup v-model:bottomshow="popupshow.bottomshow" />
130
-    <!-- 确定按钮 -->
233
+
234
+    <wd-popup
235
+      v-model="popupShow.centerShow"
236
+      custom-style="border-radius:32rpx;"
237
+      @close="helpClose"
238
+    >
239
+      <view class="popup-content">
240
+        <view style="font-size: 36rpx; font-weight: 500; color: #020917">
241
+          说明
242
+        </view>
243
+        <view style="font-size: 32rpx; font-weight: 400; color: #343a45" v-html="toastHtml" />
244
+        <view style="width: 100%">
245
+          <button class="btn" @click="helpClose">
246
+            我 知 道 了
247
+          </button>
248
+        </view>
249
+      </view>
250
+    </wd-popup>
131
     <view class="confirm-btn">
251
     <view class="confirm-btn">
132
       <button class="btn" @click="submitTasks">
252
       <button class="btn" @click="submitTasks">
133
         评 论
253
         评 论
136
   </view>
256
   </view>
137
 </template>
257
 </template>
138
 
258
 
139
-<script lang="ts" setup>
140
-import { computed, ref } from 'vue'
141
-import useUpload from '@/hooks/useUpload'
142
-import bottompopup from '../popup/bottompopup.vue'
143
-import centerpopup from '../popup/centerpopup.vue'
144
-
145
-const popupshow = ref({
146
-  centershow: false,
147
-  bottomshow: false,
148
-})
149
-// const popupshow = ref({})
150
-const tab = ref('前庭')
151
-const tabs = ['前庭', '自助服务区', '罐区', '便利店']
152
-
153
-// 定义任务类型
154
-interface Task {
155
-  id: string
156
-  type: string
157
-  description: string
158
-  icon?: string
159
-  instructions: string
160
-  examples: string[]
161
-  images: string[]
162
-  jihaoqiang: string
163
-  status: 'normal' | 'abnormal'
164
-  questionicon: string
165
-  exceptiondescription: string
166
-}
167
-
168
-// 任务数据
169
-const tasks = ref<Task[]>([
170
-  {
171
-    id: '1',
172
-    type: '前庭',
173
-    description:
174
-      '[AI] [卫生] 前庭海报整齐不歪斜,干净无灰尘污渍(立柱、灯箱、展架等)。',
175
-    instructions: '拍照:按照示例图拍摄前庭内海报宣传物,可上传多张照片',
176
-    examples: [
177
-      'https://picsum.photos/id/1018/200/150',
178
-      'https://picsum.photos/id/1019/200/150',
179
-    ],
180
-    images: [
181
-      'https://picsum.photos/id/1028/200/150',
182
-      'https://picsum.photos/id/1022/200/150',
183
-      'https://picsum.photos/id/1023/200/150',
184
-      'https://picsum.photos/id/1026/200/150',
185
-      'https://picsum.photos/id/1025/200/150',
186
-      'https://picsum.photos/id/1029/200/150',
187
-      'https://picsum.photos/id/1025/200/150',
188
-    ],
189
-    questionicon: 'help-circle',
190
-    jihaoqiang: '',
191
-    status: 'normal',
192
-    exceptiondescription: '',
193
-  },
194
-  {
195
-    id: '2',
196
-    type: '前庭',
197
-    description: '[卫生] 抽油枪栓是否出现空转或存在明显渗油。',
198
-    icon: 'help-circle',
199
-    instructions: '',
200
-    examples: [],
201
-    images: [],
202
-    questionicon: 'help-circle',
203
-    jihaoqiang: '12号枪',
204
-
205
-    status: 'normal',
206
-    exceptiondescription: '',
207
-  },
208
-  {
209
-    id: '3',
210
-    type: '前庭',
211
-    description:
212
-      '[AI] [卫生] 前庭海报整齐不歪斜,干净无灰尘污渍(立柱、灯箱、展架等)。',
213
-    instructions: '',
214
-    examples: [],
215
-    images: [],
216
-    questionicon: 'help-circle',
217
-    jihaoqiang: '13号枪',
218
-    status: 'abnormal',
219
-    exceptiondescription:
220
-      '异常描述异常描述异常描述异常描述异常描述异常描述异常描述异常描述异常描述异常描述异常描述',
221
-  },
222
-  {
223
-    id: '4',
224
-    type: '前庭',
225
-    description:
226
-      '[AI] [卫生] 前庭海报整齐不歪斜,干净无灰尘污渍(立柱、灯箱、展架等)。',
227
-    instructions: '',
228
-    examples: [],
229
-    images: [],
230
-    questionicon: 'help-circle',
231
-    jihaoqiang: '',
232
-    status: 'normal',
233
-    exceptiondescription: '',
234
-  },
235
-])
236
-
237
-// 根据当前标签筛选任务
238
-const currentTasks = computed(() => {
239
-  return tasks.value.filter(task => task.type === tab.value)
240
-})
241
-// 提交任务
242
-function submitTasks() {
243
-  console.log('提交任务', tasks.value)
244
-  // 这里可以添加提交逻辑
245
-  uni.showToast({
246
-    title: '提交成功',
247
-    icon: 'success',
248
-  })
249
-}
250
-</script>
251
-
252
 <style lang="scss" scoped>
259
 <style lang="scss" scoped>
253
 .task-management {
260
 .task-management {
254
   display: flex;
261
   display: flex;
255
   flex-direction: column;
262
   flex-direction: column;
256
-  height: 1500rpx;
263
+  min-height: 100vh;
257
   overflow: hidden;
264
   overflow: hidden;
258
   .fixed-area {
265
   .fixed-area {
259
     flex-shrink: 0;
266
     flex-shrink: 0;
326
     // padding: 0 30rpx;
333
     // padding: 0 30rpx;
327
     .task-top-left {
334
     .task-top-left {
328
       margin-left: 30rpx;
335
       margin-left: 30rpx;
329
-      width: 230rpx;
336
+      width: 250rpx;
330
       height: 52rpx;
337
       height: 52rpx;
331
       background-color: #e8f3ff;
338
       background-color: #e8f3ff;
332
       border-radius: 12rpx;
339
       border-radius: 12rpx;
416
           }
423
           }
417
         }
424
         }
418
       }
425
       }
419
-      .jihaoqiang {
426
+      .whichGun {
420
         width: 100%;
427
         width: 100%;
421
         height: 96rpx;
428
         height: 96rpx;
422
         background-color: #f5f5f5;
429
         background-color: #f5f5f5;
428
         box-sizing: border-box;
435
         box-sizing: border-box;
429
         margin-bottom: 10rpx;
436
         margin-bottom: 10rpx;
430
         border-radius: 20rpx;
437
         border-radius: 20rpx;
431
-        .jihaoqiang-text {
438
+        .whichGun-text {
432
           font-size: 28rpx;
439
           font-size: 28rpx;
433
           color: #4e5969;
440
           color: #4e5969;
434
           font-weight: 500;
441
           font-weight: 500;
446
           color: #31373d;
453
           color: #31373d;
447
         }
454
         }
448
       }
455
       }
449
-      .exceptiondescription {
456
+      .anomalyDescription {
450
         width: 100%;
457
         width: 100%;
451
         border-bottom: 1px solid #eeeeee;
458
         border-bottom: 1px solid #eeeeee;
452
         font-size: 28rpx;
459
         font-size: 28rpx;
453
         padding-bottom: 40rpx;
460
         padding-bottom: 40rpx;
454
-        .exceptiondescription-title {
461
+        .anomalyDescription-title {
455
           font-weight: 500;
462
           font-weight: 500;
456
           color: #31373d;
463
           color: #31373d;
457
         }
464
         }
458
-        .exceptiondescription-content {
465
+        .anomalyDescription-content {
459
           font-weight: 400;
466
           font-weight: 400;
460
           color: #4e5969;
467
           color: #4e5969;
461
         }
468
         }
483
 
490
 
484
   // 确定按钮
491
   // 确定按钮
485
   .confirm-btn {
492
   .confirm-btn {
493
+    position: fixed;
494
+    bottom: 0;
495
+    left: 0;
496
+    right: 0;
486
     padding: 20rpx 30rpx;
497
     padding: 20rpx 30rpx;
487
     background-color: white;
498
     background-color: white;
488
     border-top: 1rpx solid #eee;
499
     border-top: 1rpx solid #eee;
500
+    z-index: 100;
489
 
501
 
490
     .btn {
502
     .btn {
491
       width: 100%;
503
       width: 100%;
500
     }
512
     }
501
   }
513
   }
502
 }
514
 }
515
+
516
+.custom-txt {
517
+  width: 400rpx;
518
+  height: 400rpx;
519
+  display: flex;
520
+  justify-content: center;
521
+  align-items: center;
522
+  border-radius: 32rpx;
523
+}
524
+.popup-content {
525
+  width: 600rpx;
526
+  display: flex;
527
+  flex-direction: column;
528
+  justify-content: space-between;
529
+  align-items: center;
530
+  padding: 40rpx;
531
+  box-sizing: border-box;
532
+  gap: 40rpx;
533
+  .btn {
534
+    width: 100%;
535
+    height: 80rpx;
536
+    background-color: #215acd;
537
+    color: white;
538
+    font-size: 32rpx;
539
+    border-radius: 12rpx;
540
+    font-weight: 400;
541
+    border: none;
542
+    outline: none;
543
+  }
544
+}
503
 </style>
545
 </style>

+ 266 - 59
src/pages/schedule/details/index.vue

1
 <script setup lang="ts">
1
 <script setup lang="ts">
2
 import dayjs from 'dayjs'
2
 import dayjs from 'dayjs'
3
 import { keyBy } from 'lodash-es'
3
 import { keyBy } from 'lodash-es'
4
-import { ref } from 'vue'
4
+import { storeToRefs } from 'pinia'
5
+import { onMounted, ref } from 'vue'
5
 import { useRoute, useRouter } from 'vue-router'
6
 import { useRoute, useRouter } from 'vue-router'
6
 import { useMessage, useToast } from 'wot-design-uni'
7
 import { useMessage, useToast } from 'wot-design-uni'
7
-import { confirmDoneTask, getTaskDetail } from '@/api/schedule/task'
8
+import { closeTask, confirmDoneTask, getTaskDetail, transferTask } from '@/api/schedule/task'
9
+import { getAllUsers } from '@/api/system/users'
8
 
10
 
11
+import AttachmentList from '@/components/AttachmentList.vue'
12
+import { useUserStore } from '@/store'
9
 import { authStatusOptions, taskLevelOptions, taskStatusOptions } from '@/utils/dicts'
13
 import { authStatusOptions, taskLevelOptions, taskStatusOptions } from '@/utils/dicts'
10
 
14
 
11
-const message = useMessage()
15
+const userStore = useUserStore()
16
+
17
+const { userInfo } = storeToRefs(userStore)
18
+
19
+const wotMessage = useMessage()
12
 const toast = useToast()
20
 const toast = useToast()
13
 
21
 
14
 // 定义页面配置,注册路由
22
 // 定义页面配置,注册路由
27
 const taskOther: any = ref({})
35
 const taskOther: any = ref({})
28
 const taskResult: any = ref({})
36
 const taskResult: any = ref({})
29
 
37
 
38
+// 转交功能相关
39
+const users = ref<any[]>([])
40
+const value = ref<string[]>([])
41
+const customShow = ref<string>('')
42
+
30
 // 切换更多内容显示/隐藏
43
 // 切换更多内容显示/隐藏
31
 function toggleMore() {
44
 function toggleMore() {
32
   isExpanded.value = !isExpanded.value
45
   isExpanded.value = !isExpanded.value
34
 
47
 
35
 async function dealConfirmTaskEvent() {
48
 async function dealConfirmTaskEvent() {
36
 // 二次弹框确认
49
 // 二次弹框确认
37
-  message.confirm({
50
+  wotMessage.confirm({
38
     msg: `确认完成任务 ${taskInfo.value.taskName} 吗?`,
51
     msg: `确认完成任务 ${taskInfo.value.taskName} 吗?`,
39
     title: '确认完成',
52
     title: '确认完成',
40
   }).then(async () => {
53
   }).then(async () => {
64
       })
77
       })
65
       return
78
       return
66
     }
79
     }
80
+    case 'photo': {
81
+      uni.navigateTo({
82
+        url: `/pages/schedule/details/deal/photo?id=${taskInfo.value.taskList?.[0]?.id}`,
83
+      })
84
+      return
85
+    }
67
     case 'confirm': {
86
     case 'confirm': {
68
       await dealConfirmTaskEvent()
87
       await dealConfirmTaskEvent()
69
 
88
 
109
     }
128
     }
110
     case 'upload': {
129
     case 'upload': {
111
       uni.navigateTo({
130
       uni.navigateTo({
112
-        url: `/pages/schedule/details/deal/upload?id=${taskId.value}`,
131
+        url: `/pages/schedule/details/deal/upload?id=${taskInfo.value.taskList?.[0]?.id}`,
113
       })
132
       })
114
       return
133
       return
115
     }
134
     }
136
   })
155
   })
137
 }
156
 }
138
 
157
 
158
+// 获取用户列表
159
+async function getUserList() {
160
+  console.log('调用getAllUsers时的stationId:', taskInfo.value.stationId)
161
+  const res: any = await getAllUsers({
162
+    pageNum: 10000,
163
+    stationId: taskInfo.value.stationId,
164
+  })
165
+  if (res.code === 200) {
166
+    users.value = res.data.map((item: any) => ({
167
+      label: item.nickName,
168
+      value: item.userId,
169
+    }))
170
+  }
171
+}
172
+
173
+// 选择器确认事件
174
+function handleTransferTask({ value, selectedItems }: any) {
175
+  console.log('value:', value[0], taskInfo.value.executorId)
176
+  if (value.length === 0) {
177
+    toast.error('请选择执行人')
178
+    return
179
+  }
180
+
181
+  if (value[0] === taskInfo.value.executorId) {
182
+    toast.error('不能将任务转交给当前执行人')
183
+    console.log('不能将任务转交给当前执行人', toast)
184
+
185
+    return
186
+  }
187
+
188
+  wotMessage.confirm({
189
+    msg: `确认将任务 ${taskInfo.value.taskName} 转交给 ${selectedItems.map((item: any) => item.label).join(', ')} 吗?`,
190
+    title: '确认转交',
191
+  }).then(async () => {
192
+    try {
193
+      const res: any = await transferTask({
194
+        id: taskInfo.value.id || 0,
195
+        executorId: value[0],
196
+      })
197
+      if (res.code !== 200) {
198
+        toast.error(res.msg || '操作失败')
199
+        return
200
+      }
201
+
202
+      toast.success('转交任务成功')
203
+      await init()
204
+    }
205
+    catch {
206
+      toast.error('操作失败')
207
+    }
208
+  }).catch(() => {
209
+    return
210
+  })
211
+}
212
+
139
 /**
213
 /**
140
  * 获取任务时间
214
  * 获取任务时间
141
  * @returns 任务时间字符串
215
  * @returns 任务时间字符串
154
   console.log('downloadFile:', file, fileName)
228
   console.log('downloadFile:', file, fileName)
155
 }
229
 }
156
 
230
 
231
+const buttons = ref({
232
+  deal: false,
233
+  transfer: false,
234
+  close: false,
235
+})
236
+
157
 async function init() {
237
 async function init() {
158
   const res: any = await getTaskDetail(taskId.value)
238
   const res: any = await getTaskDetail(taskId.value)
159
   taskInfo.value = res.data || {}
239
   taskInfo.value = res.data || {}
160
   if (!taskInfo.value.status) {
240
   if (!taskInfo.value.status) {
161
     taskInfo.value.status = 0
241
     taskInfo.value.status = 0
162
   }
242
   }
243
+  console.log(userInfo.value)
244
+
245
+  if (taskInfo.value.status === 1) {
246
+    if (taskInfo.value.executorId === userInfo.value.user?.userId) {
247
+      buttons.value.deal = true
248
+    }
249
+    if (userInfo.value.user?.createBy === taskInfo.value.createBy || userInfo.value.user?.post?.type === '"headquarters"' || (taskInfo.value?.taskTemplate?.isMust === 0 && taskInfo.value.executorId === userInfo.value.user?.userId)) {
250
+      buttons.value.close = true
251
+
252
+      if (taskInfo.value.authStatus === 0) {
253
+        buttons.value.transfer = true
254
+      }
255
+    }
256
+  }
257
+
163
   // 假设从接口返回数据中获取taskOther和taskResult
258
   // 假设从接口返回数据中获取taskOther和taskResult
164
   taskOther.value.taskTypeName = taskInfo.value?.formTypeName || '-'
259
   taskOther.value.taskTypeName = taskInfo.value?.formTypeName || '-'
165
 
260
 
195
     taskOther.value.taskFrequencyName
290
     taskOther.value.taskFrequencyName
196
       = taskInfo.value?.taskTemplate?.taskFrequencyName || '-'
291
       = taskInfo.value?.taskTemplate?.taskFrequencyName || '-'
197
   }
292
   }
293
+
294
+  // 获取用户列表
295
+  if (taskInfo.value.stationId) {
296
+    await getUserList()
297
+  }
198
 }
298
 }
199
 
299
 
200
 // 状态标签配置
300
 // 状态标签配置
206
 // 授权状态标签配置
306
 // 授权状态标签配置
207
 const authStatusConfig: any = keyBy(authStatusOptions, 'value')
307
 const authStatusConfig: any = keyBy(authStatusOptions, 'value')
208
 
308
 
209
-onMounted(async () => {
309
+function goDetail() {
310
+  uni.navigateTo({
311
+    url: `/pages/schedule/details/detail/inspection?id=${taskId.value}&checkId=${taskInfo.value.taskList[0].id}`,
312
+  })
313
+}
314
+
315
+/**
316
+ * 关闭任务按钮点击事件
317
+ */
318
+async function closeTaskEvent() {
319
+  // 二次弹框确认
320
+  wotMessage.confirm({
321
+    msg: `确认关闭任务 ${taskInfo.value.taskName} 吗?`,
322
+    title: '确认关闭',
323
+  }).then(async () => {
324
+    try {
325
+      await closeTask({
326
+        id: taskInfo.value.id || 0,
327
+      })
328
+
329
+      toast.success('关闭任务成功')
330
+      await init()
331
+    }
332
+    catch {
333
+      toast.error('操作失败')
334
+    }
335
+  }).catch(() => {
336
+    return
337
+  })
338
+}
339
+
340
+onShow(async () => {
210
   await init()
341
   await init()
211
 })
342
 })
343
+
344
+onMounted(async () => {
345
+  // await init()
346
+})
212
 </script>
347
 </script>
213
 
348
 
214
 <template>
349
 <template>
245
     <!-- 标准指引 -->
380
     <!-- 标准指引 -->
246
     <view class="section">
381
     <view class="section">
247
       <view class="section-title">
382
       <view class="section-title">
248
-        任务信息
383
+        基础信息
249
       </view>
384
       </view>
250
       <view class="standard-guide">
385
       <view class="standard-guide">
251
         <view class="guide-item">
386
         <view class="guide-item">
268
           <view class="guide-label">
403
           <view class="guide-label">
269
             执行人
404
             执行人
270
           </view>
405
           </view>
271
-          <view class="guide-value">
406
+          <view class="guide-value flex items-center justify-between">
272
             {{ taskInfo.executorName || '-' }}
407
             {{ taskInfo.executorName || '-' }}
408
+            <wd-select-picker
409
+              v-model="value"
410
+              title="选择转交人"
411
+              filterable :max="1" use-default-slot :columns="users" style="z-index:101" @confirm="handleTransferTask"
412
+            >
413
+              <wd-button v-if="buttons.transfer" type="text">
414
+                转交
415
+              </wd-button>
416
+            </wd-select-picker>
273
           </view>
417
           </view>
274
         </view>
418
         </view>
275
         <view class="guide-item">
419
         <view class="guide-item">
320
             {{ getTaskTime() || '-' }}
464
             {{ getTaskTime() || '-' }}
321
           </view>
465
           </view>
322
         </view>
466
         </view>
323
-        <!-- <view class="guide-item">
324
-          <view class="guide-label">
325
-            任务描述
326
-          </view>
327
-          <view class="guide-value">
328
-            {{ taskInfo.description || '-' }}
329
-          </view>
330
-        </view> -->
331
-        <view v-if="taskInfo.descriptionFilesUrl && taskInfo.descriptionFilesUrl.length > 0" class="guide-item">
467
+
468
+        <view v-if="taskInfo.descriptionFilesUrl && taskInfo.descriptionFilesUrl.length > 0" class="guide-item attachment-guide-item">
332
           <view class="guide-label">
469
           <view class="guide-label">
333
             详情附件
470
             详情附件
334
           </view>
471
           </view>
335
           <view class="guide-value">
472
           <view class="guide-value">
336
-            <!-- 使用wot-ui样式显示附件 -->
337
-            <view class="attachment-list">
338
-              <wd-tag
339
-                v-for="(file, index) in taskInfo.descriptionFilesUrl"
340
-                :key="index"
341
-                custom-class="attachment-tag"
342
-                type="primary"
343
-                plain
344
-              >
345
-                附件{{ index + 1 }}
346
-              </wd-tag>
347
-            </view>
473
+            <!-- 使用附件列表组件显示附件 -->
474
+            <AttachmentList
475
+              :files="taskInfo.descriptionFilesUrl"
476
+              :size="30"
477
+            />
348
           </view>
478
           </view>
349
         </view>
479
         </view>
480
+      </view>
481
+    </view>
482
+
483
+    <view v-if="taskInfo.status === 3" class="section">
484
+      <view class="section-title">
485
+        处理结果
486
+      </view>
487
+      <view class="standard-guide">
350
         <view v-if="taskResult.handleContent || taskInfo.cancelReason" class="guide-item">
488
         <view v-if="taskResult.handleContent || taskInfo.cancelReason" class="guide-item">
351
           <view class="guide-label">
489
           <view class="guide-label">
352
             处理情况
490
             处理情况
363
             {{ taskInfo.completeTime || taskInfo.cancelTime || '-' }}
501
             {{ taskInfo.completeTime || taskInfo.cancelTime || '-' }}
364
           </view>
502
           </view>
365
         </view>
503
         </view>
366
-        <view v-if="taskResult.files && taskResult.files.length > 0" class="guide-item">
504
+        <view v-if="taskResult.files && taskResult.files.length > 0" class="guide-item attachment-guide-item">
367
           <view class="guide-label">
505
           <view class="guide-label">
368
             处理附件
506
             处理附件
369
           </view>
507
           </view>
370
           <view class="guide-value">
508
           <view class="guide-value">
371
-            <!-- 使用wot-ui样式显示附件列表 -->
372
-            <view class="attachment-list">
373
-              <wd-tag
374
-                v-for="(file, index) in taskResult.files"
375
-                :key="index"
376
-                custom-class="attachment-tag"
377
-                type="success"
378
-                plain
379
-                @click="downloadFile(file, taskResult.fileNames[index] || `附件${index + 1}`)"
380
-              >
381
-                {{ taskResult.fileNames[index] || `附件${index + 1}` }}
382
-              </wd-tag>
383
-            </view>
509
+            <!-- 使用附件列表组件显示附件 -->
510
+            <AttachmentList
511
+              :files="taskResult.files"
512
+              :file-names="taskResult.fileNames"
513
+              :size="30"
514
+            />
384
           </view>
515
           </view>
385
         </view>
516
         </view>
386
       </view>
517
       </view>
416
       </view>
547
       </view>
417
     </view>
548
     </view>
418
 
549
 
419
-    <view class="detail-btn" @tap="dealTaskEvent">
420
-      <text>处理任务</text>
550
+    <!-- 按钮容器 -->
551
+    <view class="btn-container">
552
+      <!-- 关闭任务按钮 -->
553
+      <wd-button
554
+        v-if="buttons.close"
555
+        type="error"
556
+        class="close-btn"
557
+        @click="closeTaskEvent"
558
+      >
559
+        关闭任务
560
+      </wd-button>
561
+      <!-- 处理任务按钮 -->
562
+      <wd-button
563
+        v-if="buttons.deal"
564
+        type="primary"
565
+        class="deal-btn"
566
+        @click="dealTaskEvent"
567
+      >
568
+        处理任务
569
+      </wd-button>
570
+    </view>
571
+
572
+    <!-- 查看详情按钮 -->
573
+    <view class="view-detail-container">
574
+      <wd-button
575
+        v-if="[3].includes(taskInfo.status)"
576
+        type="primary"
577
+        class="view-detail-btn"
578
+        @click="goDetail"
579
+      >
580
+        查看详情
581
+      </wd-button>
421
     </view>
582
     </view>
422
     <!-- <view class="detail-btn" @tap="viewDetails2">
583
     <!-- <view class="detail-btn" @tap="viewDetails2">
423
       <text>查 看 详 情2</text>
584
       <text>查 看 详 情2</text>
425
     <view class="detail-btn" @tap="viewDetails3">
586
     <view class="detail-btn" @tap="viewDetails3">
426
       <text>查 看 详 情3</text>
587
       <text>查 看 详 情3</text>
427
     </view> -->
588
     </view> -->
589
+    <wd-message-box />
590
+    <wd-toast />
428
   </view>
591
   </view>
429
 </template>
592
 </template>
430
 
593
 
432
 .details-box {
595
 .details-box {
433
   display: flex;
596
   display: flex;
434
   flex-direction: column;
597
   flex-direction: column;
435
-  padding: 30rpx 24rpx;
598
+  padding: 30rpx 24rpx 160rpx;
436
   background-color: #ffffff;
599
   background-color: #ffffff;
437
 
600
 
438
   .details-box-title {
601
   .details-box-title {
506
   .standard-guide {
669
   .standard-guide {
507
     .guide-item {
670
     .guide-item {
508
       display: flex;
671
       display: flex;
672
+      align-items: center;
509
       margin-bottom: 24rpx;
673
       margin-bottom: 24rpx;
510
 
674
 
511
       &:last-child {
675
       &:last-child {
517
         font-size: 28rpx;
681
         font-size: 28rpx;
518
         color: #6c757d;
682
         color: #6c757d;
519
         font-weight: 400;
683
         font-weight: 400;
684
+        line-height: 52rpx;
520
       }
685
       }
521
 
686
 
522
       .guide-value {
687
       .guide-value {
524
         font-size: 28rpx;
689
         font-size: 28rpx;
525
         font-weight: 400;
690
         font-weight: 400;
526
         color: #31373d;
691
         color: #31373d;
692
+        line-height: 52rpx;
693
+      }
694
+
695
+      // 调整转交按钮样式,确保不改变行高
696
+      .guide-value :deep(.wd-button) {
697
+        margin: 0;
698
+        padding: 0;
699
+        height: auto;
700
+        line-height: 52rpx;
701
+      }
702
+
703
+      .guide-value :deep(.wd-button__text) {
704
+        margin: 0;
705
+        padding: 0;
706
+        line-height: 52rpx;
707
+      }
708
+    }
709
+
710
+    // 附件列表特殊样式
711
+    .attachment-guide-item {
712
+      flex-direction: column;
713
+      align-items: flex-start;
714
+
715
+      .guide-label {
716
+        margin-bottom: 12rpx;
717
+      }
718
+
719
+      .guide-value {
720
+        width: 100%;
527
       }
721
       }
528
     }
722
     }
529
   }
723
   }
547
     }
741
     }
548
   }
742
   }
549
 
743
 
550
-  // 查看详情按钮
551
-  .detail-btn {
744
+  // 按钮容器
745
+  .btn-container {
552
     display: flex;
746
     display: flex;
553
-    align-items: center;
554
-    justify-content: center;
747
+    gap: 16rpx;
748
+    position: fixed;
749
+    bottom: 32rpx;
750
+    left: 24rpx;
751
+    right: 24rpx;
752
+    z-index: 100;
753
+  }
754
+
755
+  // 并排放置的按钮样式
756
+  .btn-container .wd-button {
757
+    flex: 1;
555
     height: 96rpx;
758
     height: 96rpx;
556
-    background-color: #215acd;
557
-    border-radius: 14rpx;
558
-    margin-bottom: 32rpx;
759
+    font-size: 32rpx;
760
+  }
761
+
762
+  // 查看详情按钮容器
763
+  .view-detail-container {
559
     position: fixed;
764
     position: fixed;
560
     bottom: 32rpx;
765
     bottom: 32rpx;
561
     left: 24rpx;
766
     left: 24rpx;
562
     right: 24rpx;
767
     right: 24rpx;
563
-    z-index: 999;
564
-    text {
565
-      font-size: 32rpx;
566
-      color: #ffffff;
567
-      font-weight: 500;
568
-    }
768
+    z-index: 100;
769
+  }
770
+
771
+  // 查看详情按钮样式
772
+  .view-detail-btn {
773
+    width: 100%;
774
+    height: 96rpx;
775
+    font-size: 32rpx;
569
   }
776
   }
570
 
777
 
571
   // 更多内容样式
778
   // 更多内容样式

+ 160 - 173
src/pages/schedule/details/popup/anomaly.vue

8
 import { getAllUsers } from '@/api/system/users'
8
 import { getAllUsers } from '@/api/system/users'
9
 import useUpload from '@/hooks/useUpload'
9
 import useUpload from '@/hooks/useUpload'
10
 // import { useUserStore } from '@/store'
10
 // import { useUserStore } from '@/store'
11
-import calendar from '@/utils/calendar.vue'
11
+// import calendar from '@/utils/calendar.vue'
12
 
12
 
13
 const props = defineProps({
13
 const props = defineProps({
14
-  anomalyShow: {
15
-    type: Boolean,
16
-    default: false,
17
-  },
18
   taskId: {
14
   taskId: {
19
     type: Number,
15
     type: Number,
20
     default: 0,
16
     default: 0,
27
     type: Number,
23
     type: Number,
28
     default: 0,
24
     default: 0,
29
   },
25
   },
26
+  anomalyData: {
27
+    type: Object,
28
+    default: () => ({}),
29
+  },
30
 })
30
 })
31
 const emit = defineEmits(['update:anomalyShow', 'anomaly-submitted'])
31
 const emit = defineEmits(['update:anomalyShow', 'anomaly-submitted'])
32
 console.log(props.stationId)
32
 console.log(props.stationId)
34
 const users = ref<any[]>([])
34
 const users = ref<any[]>([])
35
 // const userStore = useUserStore()
35
 // const userStore = useUserStore()
36
 // const { userInfo } = storeToRefs(userStore)
36
 // const { userInfo } = storeToRefs(userStore)
37
-function handleClose() {
38
-  emit('update:anomalyShow', false)
39
-}
40
 
37
 
41
 async function getUserList() {
38
 async function getUserList() {
42
   console.log('调用getAllUsers时的stationId:', props.stationId)
39
   console.log('调用getAllUsers时的stationId:', props.stationId)
96
   correlationTaskId: '',
93
   correlationTaskId: '',
97
 })
94
 })
98
 
95
 
99
-const form = ref()
100
-const loading = ref(false)
101
-const action: string
102
-  = ''
103
-
104
-const datePickerVisible = ref(false)
96
+// 更新 model 数据
97
+function updateModelData(data: any) {
98
+  if (!data)
99
+    return
105
 
100
 
106
-function handleClickCalendar() {
107
-  datePickerVisible.value = true
108
-}
109
-function onconfirmDate(date: string) {
110
-  model.deadline = date
101
+  model.isTransferTask = data.isTransferTask?.toString() || '1'
102
+  model.problemDescription = data.problemDescription || ''
103
+  model.handlingSuggestion = data.handlingSuggestion || ''
104
+  model.deadline = data.deadline || ''
105
+  model.executorId = data.executorId ? [Number(data.executorId)] : []
106
+  model.ccTo = data.ccTo ? data.ccTo.split(',').map((item: string) => Number(item.trim())) : []
107
+  model.problemPhoto = data.problemPhoto || []
108
+  model.tags = data.tags ? data.tags.split(',').map((item: string) => Number(item.trim())) : []
109
+  model.correlationTaskId = data.correlationTaskId?.toString() || ''
111
 }
110
 }
112
 
111
 
112
+const form = ref()
113
+const loading = ref(false)
114
+
113
 // 上传问题照片
115
 // 上传问题照片
114
 const uploadProblemPhoto: any = (file, formData, options) => {
116
 const uploadProblemPhoto: any = (file, formData, options) => {
115
   const { customUpload } = useUpload({
117
   const { customUpload } = useUpload({
123
   model.problemPhoto.splice(index, 1)
125
   model.problemPhoto.splice(index, 1)
124
 }
126
 }
125
 
127
 
126
-// 删除处理照片
127
-function deleteHandlingPhoto(index: number) {
128
-  model.handlingPhoto.splice(index, 1)
129
-}
130
-
131
-// 验证截止时间是否大于当前时间
132
-function validateDeadline(value: number | string, resolve: (valid: boolean) => void) {
133
-  const now = Date.now()
134
-  // 检查value类型,如果是字符串则转换为时间戳
135
-  const deadline = typeof value === 'string' ? new Date(value).getTime() : value
136
-  if (deadline < now) {
137
-    showSuccess({ msg: '截止时间不能小于当前时间' })
138
-    resolve(false)
139
-  }
140
-  else {
141
-    resolve(true)
142
-  }
143
-}
144
 function handleSubmit() {
128
 function handleSubmit() {
145
   form.value
129
   form.value
146
     .validate()
130
     .validate()
168
 
152
 
169
         submitIssue(submitData)
153
         submitIssue(submitData)
170
           .then((res) => {
154
           .then((res) => {
171
-            console.log(res, 'res')
172
             // 提交成功后向父组件传递数据
155
             // 提交成功后向父组件传递数据
173
-            emit('anomaly-submitted', { checkItemId: props.checkItemId, data: submitData })
174
-            // showSuccess({
175
-            //   msg: '校验通过,数据已提交',
176
-            // })
156
+            emit('anomaly-submitted', { checkItemId: props.checkItemId, data: {
157
+              ...submitData,
158
+              problemPhoto: model.problemPhoto,
159
+            } })
160
+
161
+            console.log(res, 'res')
162
+            // 重置表单数据
163
+            model.isTransferTask = '1'
164
+            model.problemDescription = ''
165
+            model.handlingSuggestion = ''
166
+            model.deadline = ''
167
+            model.executorId = ''
168
+            model.ccTo = []
169
+            model.handlingMeasure = ''
170
+            model.handlingPhoto = []
171
+            model.problemPhoto = []
172
+            model.tags = []
173
+            model.correlationTaskId = ''
177
           })
174
           })
178
           .catch((error) => {
175
           .catch((error) => {
179
             console.log(error, 'error')
176
             console.log(error, 'error')
202
     getUserList()
199
     getUserList()
203
   }
200
   }
204
 }, { immediate: false })
201
 }, { immediate: false })
202
+
203
+defineExpose({
204
+  updateModelData,
205
+})
205
 </script>
206
 </script>
206
 
207
 
207
 <template>
208
 <template>
208
   <view>
209
   <view>
209
-    <wd-popup
210
-      v-model="props.anomalyShow"
211
-      custom-style="border-radius: 32rpx 32rpx 0 0; height: 80%;z-index: 100;"
212
-      position="bottom"
213
-      :safe-area-inset-bottom="true"
214
-      closable
215
-      @close="handleClose"
216
-    >
217
-      <view class="popup-content">
218
-        <view class="content-header">
219
-          <text style="font-size: 34rpx; font-weight: 500; color: #464c51">
220
-            异常情况
221
-          </text>
222
-        </view>
223
-        <view class="content-main">
224
-          <wd-form ref="form" :model="model">
225
-            <view style="display: flex; flex-direction: column; gap: 40rpx; padding-bottom: 100rpx;">
226
-              <view>
227
-                <view style="font-size: 32rpx; font-weight: 500; color: #31373d">
228
-                  是否转任务
229
-                </view>
230
-                <view
231
-                  style="
210
+    <view class="popup-content">
211
+      <view class="content-header">
212
+        <text style="font-size: 34rpx; font-weight: 500; color: #464c51">
213
+          异常情况
214
+        </text>
215
+      </view>
216
+      <view class="content-main">
217
+        <wd-form ref="form" :model="model">
218
+          <view style="display: flex; flex-direction: column; gap: 40rpx; padding-bottom: 100rpx;">
219
+            <view>
220
+              <view style="font-size: 32rpx; font-weight: 500; color: #31373d">
221
+                是否转任务
222
+              </view>
223
+              <view
224
+                style="
232
                     font-size: 28rpx;
225
                     font-size: 28rpx;
233
                     font-weight: 400;
226
                     font-weight: 400;
234
                     color: #4e5969;
227
                     color: #4e5969;
235
                     margin-bottom: 20rpx;
228
                     margin-bottom: 20rpx;
236
                   "
229
                   "
237
-                >
238
-                  转任务后会出现在执行人的任务日程视图中
239
-                </view>
240
-                <wd-radio-group v-model="model.isTransferTask" shape="dot" inline>
241
-                  <view style="display: flex; gap: 260rpx">
242
-                    <wd-radio value="1">
243
-                      是
244
-                    </wd-radio>
245
-                    <wd-radio value="0">
246
-                      否
247
-                    </wd-radio>
248
-                  </view>
249
-                </wd-radio-group>
230
+              >
231
+                转任务后会出现在执行人的任务日程视图中
250
               </view>
232
               </view>
251
-              <wd-input
252
-                v-model="model.problemDescription"
253
-                label="问题描述"
254
-                label-width="100%"
255
-                prop="problemDescription"
256
-                clearable
257
-                placeholder="请输入"
258
-                :rules="[{ required: true, message: '请填写问题描述' }]"
259
-                custom-class="custom-vertical-input"
260
-              />
261
-              <view class="custom-vertical-select">
262
-                <view
263
-                  style="
233
+              <wd-radio-group v-model="model.isTransferTask" shape="dot" inline>
234
+                <view style="display: flex; gap: 260rpx">
235
+                  <wd-radio value="1">
236
+                    是
237
+                  </wd-radio>
238
+                  <wd-radio value="0">
239
+                    否
240
+                  </wd-radio>
241
+                </view>
242
+              </wd-radio-group>
243
+            </view>
244
+            <wd-input
245
+              v-model="model.problemDescription"
246
+              label="问题描述"
247
+              label-width="100%"
248
+              prop="problemDescription"
249
+              clearable
250
+              placeholder="请输入"
251
+              :rules="[{ required: true, message: '请填写问题描述' }]"
252
+              custom-class="custom-vertical-input"
253
+            />
254
+            <view class="custom-vertical-select">
255
+              <view
256
+                style="
264
                     margin-bottom: 10rpx;
257
                     margin-bottom: 10rpx;
265
                     font-size: 28rpx;
258
                     font-size: 28rpx;
266
                     font-weight: 500;
259
                     font-weight: 500;
267
                     color: #333;
260
                     color: #333;
268
                   "
261
                   "
269
-                >
270
-                  标签
271
-                </view>
272
-                <wd-select-picker
273
-                  v-model="model.tags" :columns="tags" filterable
274
-                  :max="1"
275
-                  placeholder="请选择"
276
-                />
262
+              >
263
+                标签
277
               </view>
264
               </view>
278
-              <wd-input
279
-                v-model="model.handlingSuggestion"
280
-                label="处理建议"
281
-                label-width="100%"
282
-                prop="handlingSuggestion"
283
-                clearable
284
-                placeholder="请输入"
285
-                custom-class="custom-vertical-input"
265
+              <wd-select-picker
266
+                v-model="model.tags" :columns="tags" filterable
267
+                :max="1"
268
+                placeholder="请选择"
286
               />
269
               />
287
-              <view class="custom-vertical-select">
288
-                <view
289
-                  style="
270
+            </view>
271
+            <wd-input
272
+              v-model="model.handlingSuggestion"
273
+              label="处理建议"
274
+              label-width="100%"
275
+              prop="handlingSuggestion"
276
+              clearable
277
+              placeholder="请输入"
278
+              custom-class="custom-vertical-input"
279
+            />
280
+            <view class="custom-vertical-select">
281
+              <view
282
+                style="
290
                     margin-bottom: 10rpx;
283
                     margin-bottom: 10rpx;
291
                     font-size: 28rpx;
284
                     font-size: 28rpx;
292
                     font-weight: 500;
285
                     font-weight: 500;
293
                     color: #333;
286
                     color: #333;
294
                   "
287
                   "
295
-                >
296
-                  <text style="color: red; margin-right: 4rpx; font-size: 28rpx;">* </text>截止时间
297
-                </view>
298
-                <wd-datetime-picker
299
-                  v-model="model.deadline"
300
-                  type="date"
301
-                  use-second
302
-                  :min-date="new Date().getTime()"
303
-                  :max-date="new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).getTime()"
304
-                  prop="deadline"
305
-                  :rules="[{ required: true, message: '请选择截止时间' }]"
306
-                />
288
+              >
289
+                <text style="color: red; margin-right: 4rpx; font-size: 28rpx;">* </text>截止时间
307
               </view>
290
               </view>
308
-              <view>
309
-                <view
310
-                  style="
291
+              <wd-datetime-picker
292
+                v-model="model.deadline"
293
+                type="date"
294
+                use-second
295
+                :min-date="new Date().getTime()"
296
+                :max-date="new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).getTime()"
297
+                prop="deadline"
298
+                :rules="[{ required: true, message: '请选择截止时间' }]"
299
+              />
300
+            </view>
301
+            <view>
302
+              <view
303
+                style="
311
                     margin-bottom: 10rpx;
304
                     margin-bottom: 10rpx;
312
                     font-size: 28rpx;
305
                     font-size: 28rpx;
313
                     font-weight: 500;
306
                     font-weight: 500;
314
                     color: #333;
307
                     color: #333;
315
                   "
308
                   "
316
-                >
317
-                  问题照片
318
-                </view>
319
-                <view>
320
-                  <wd-upload
321
-                    v-model:file-list="model.problemPhoto"
322
-                    image-mode="aspectFill"
323
-                    :upload-method="uploadProblemPhoto"
324
-                    @delete="deleteProblemPhoto"
325
-                  />
326
-                </view>
309
+              >
310
+                问题照片
327
               </view>
311
               </view>
328
-              <view class="custom-vertical-select">
329
-                <view
330
-                  style="
312
+              <view>
313
+                <wd-upload
314
+                  v-model:file-list="model.problemPhoto"
315
+                  image-mode="aspectFill"
316
+                  :upload-method="uploadProblemPhoto"
317
+                  @delete="deleteProblemPhoto"
318
+                />
319
+              </view>
320
+            </view>
321
+            <view class="custom-vertical-select">
322
+              <view
323
+                style="
331
                     margin-bottom: 10rpx;
324
                     margin-bottom: 10rpx;
332
                     font-size: 28rpx;
325
                     font-size: 28rpx;
333
                     font-weight: 500;
326
                     font-weight: 500;
334
                     color: #333;
327
                     color: #333;
335
                   "
328
                   "
336
-                >
337
-                  <text style="color: red; margin-right: 4rpx; font-size: 28rpx;">* </text>执行人
338
-                </view>
339
-                <wd-select-picker
340
-                  v-model="model.executorId" :columns="users" filterable
341
-                  placeholder="请选择"
342
-                  prop="executorId"
343
-                  :max="1"
344
-                  :rules="[{ required: true, message: '请选择执行人' }]"
345
-                />
329
+              >
330
+                <text style="color: red; margin-right: 4rpx; font-size: 28rpx;">* </text>执行人
346
               </view>
331
               </view>
347
-              <view class="custom-vertical-select">
348
-                <view
349
-                  style="
332
+              <wd-select-picker
333
+                v-model="model.executorId" :columns="users" filterable
334
+                placeholder="请选择"
335
+                prop="executorId"
336
+                :max="1"
337
+                :rules="[{ required: true, message: '请选择执行人' }]"
338
+              />
339
+            </view>
340
+            <view class="custom-vertical-select">
341
+              <view
342
+                style="
350
                     margin-bottom: 10rpx;
343
                     margin-bottom: 10rpx;
351
                     font-size: 28rpx;
344
                     font-size: 28rpx;
352
                     font-weight: 500;
345
                     font-weight: 500;
353
                     color: #333;
346
                     color: #333;
354
                   "
347
                   "
355
-                >
356
-                  抄送人
357
-                </view>
358
-                <wd-select-picker
359
-                  v-model="model.ccTo" :columns="users" filterable
360
-                  placeholder="请选择"
361
-                />
348
+              >
349
+                抄送人
362
               </view>
350
               </view>
351
+              <wd-select-picker
352
+                v-model="model.ccTo" :columns="users" filterable
353
+                placeholder="请选择"
354
+              />
363
             </view>
355
             </view>
364
-          </wd-form>
365
-        </view>
366
-        <view class="footer">
367
-          <button class="btn" :disabled="loading" @click="handleSubmit">
368
-            <wd-loading v-if="loading" size="20px" color="#ffffff" />
369
-            <text v-else>提 交</text>
370
-          </button>
371
-        </view>
356
+          </view>
357
+        </wd-form>
358
+      </view>
359
+      <view class="footer">
360
+        <button class="btn" :disabled="loading" @click="handleSubmit">
361
+          <wd-loading v-if="loading" size="20px" color="#ffffff" />
362
+          <text v-else>提 交</text>
363
+        </button>
372
       </view>
364
       </view>
373
-    </wd-popup>
374
-    <calendar
375
-      v-model:date-picker-visible="datePickerVisible"
376
-      :detailedtime="false"
377
-      @confirm-date="onconfirmDate"
378
-    />
365
+    </view>
379
   </view>
366
   </view>
380
 </template>
367
 </template>
381
 
368
 

+ 0 - 72
src/pages/schedule/details/popup/centerpopup.vue

1
-<template>
2
-  <view>
3
-    <wd-popup
4
-      v-model="props.centershow"
5
-      custom-style="border-radius:32rpx;"
6
-      @close="handleClose"
7
-    >
8
-      <view class="popup-content">
9
-        <view style="font-size: 36rpx; font-weight: 500; color: #020917"
10
-          >说明</view
11
-        >
12
-        <view style="font-size: 32rpx; font-weight: 400; color: #343a45">
13
-          出入口清洁:【运营手册-第九章-第 2节】<br />
14
-          1、清洁要求:绿化带修葺良好,草地清洁;<br />
15
-          2、清洁频率:绿化带每非天繁忙时间至少检查清洁一次。
16
-        </view>
17
-        <view style="width: 100%">
18
-          <button class="btn" @click="handleClose">我 知 道 了</button>
19
-        </view>
20
-      </view>
21
-    </wd-popup>
22
-  </view>
23
-</template>
24
-
25
-<script setup lang="ts">
26
-import { defineProps, defineEmits } from 'vue'
27
-const props = defineProps({
28
-  centershow: {
29
-    type: Boolean,
30
-    default: false,
31
-  },
32
-  bottomshow: {
33
-    type: Boolean,
34
-    default: false,
35
-  },
36
-})
37
-const emit = defineEmits(['update:centershow', 'update:bottomshow'])
38
-const handleClose = () => {
39
-  emit('update:centershow', false)
40
-}
41
-</script>
42
-<style lang="scss" scoped>
43
-.custom-txt {
44
-  width: 400rpx;
45
-  height: 400rpx;
46
-  display: flex;
47
-  justify-content: center;
48
-  align-items: center;
49
-  border-radius: 32rpx;
50
-}
51
-.popup-content {
52
-  width: 600rpx;
53
-  display: flex;
54
-  flex-direction: column;
55
-  justify-content: space-between;
56
-  align-items: center;
57
-  padding: 40rpx;
58
-  box-sizing: border-box;
59
-  gap: 40rpx;
60
-  .btn {
61
-    width: 100%;
62
-    height: 80rpx;
63
-    background-color: #215acd;
64
-    color: white;
65
-    font-size: 32rpx;
66
-    border-radius: 12rpx;
67
-    font-weight: 400;
68
-    border: none;
69
-    outline: none;
70
-  }
71
-}
72
-</style>