Ver código fonte

网页端:修改预算选人bug,新增设备作业记录

移动端:新增设备作业记录
余思翰 1 dia atrás
pai
commit
7b5d120189

+ 5
- 4
oa-back/ruoyi-system/src/main/java/com/ruoyi/oa/domain/CmcDeviceLog.java Ver arquivo

@@ -3,6 +3,7 @@ package com.ruoyi.oa.domain;
3 3
 import java.util.Date;
4 4
 import com.fasterxml.jackson.annotation.JsonFormat;
5 5
 import com.ruoyi.common.core.domain.entity.SysUser;
6
+
6 7
 import org.apache.commons.lang3.builder.ToStringBuilder;
7 8
 import org.apache.commons.lang3.builder.ToStringStyle;
8 9
 import com.ruoyi.common.annotation.Excel;
@@ -79,13 +80,13 @@ public class CmcDeviceLog extends BaseEntity
79 80
     private String airPressure;
80 81
 
81 82
     /** 开机时间 */
82
-    @JsonFormat(pattern = "yyyy-MM-dd")
83
-    @Excel(name = "开机时间", width = 30, dateFormat = "yyyy-MM-dd")
83
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
84
+    @Excel(name = "开机时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm")
84 85
     private Date powerOn;
85 86
 
86 87
     /** 关机时间 */
87
-    @JsonFormat(pattern = "yyyy-MM-dd")
88
-    @Excel(name = "关机时间", width = 30, dateFormat = "yyyy-MM-dd")
88
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
89
+    @Excel(name = "关机时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm")
89 90
     private Date powerOff;
90 91
 
91 92
     /** 记录员 */

+ 44
- 0
oa-ui-app/api/oa/device/deviceLog.js Ver arquivo

@@ -0,0 +1,44 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询cmc仪器记录列表
4
+export function listDeviceLog(query) {
5
+  return request({
6
+    url: '/oa/deviceLog/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 查询cmc仪器记录详细
13
+export function getDeviceLog(logId) {
14
+  return request({
15
+    url: '/oa/deviceLog/' + logId,
16
+    method: 'get'
17
+  })
18
+}
19
+
20
+// 新增cmc仪器记录
21
+export function addDeviceLog(data) {
22
+  return request({
23
+    url: '/oa/deviceLog',
24
+    method: 'post',
25
+    data: data
26
+  })
27
+}
28
+
29
+// 修改cmc仪器记录
30
+export function updateDeviceLog(data) {
31
+  return request({
32
+    url: '/oa/deviceLog',
33
+    method: 'put',
34
+    data: data
35
+  })
36
+}
37
+
38
+// 删除cmc仪器记录
39
+export function delDeviceLog(logId) {
40
+  return request({
41
+    url: '/oa/deviceLog/' + logId,
42
+    method: 'delete'
43
+  })
44
+}

+ 7
- 0
oa-ui-app/pages.json Ver arquivo

@@ -135,6 +135,13 @@
135 135
 			{
136 136
 				"navigationBarTitleText" : "借款管理"
137 137
 			}
138
+		},
139
+		{
140
+			"path" : "pages/oa/device/deviceLog",
141
+			"style" : 
142
+			{
143
+				"navigationBarTitleText" : "设备作业记录"
144
+			}
138 145
 		}
139 146
 	],
140 147
 	"tabBar": {

+ 926
- 0
oa-ui-app/pages/oa/device/deviceLog.vue Ver arquivo

@@ -0,0 +1,926 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-06-10 09:34:55
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-06-11 16:29:46
6
+-->
7
+<template>
8
+  <view>
9
+    <scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltoupper="upper" @scrolltolower="lower"
10
+      @scroll="scroll" :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh"
11
+      :lower-threshold="50" :upper-threshold="50">
12
+      <view class="content-wrapper">
13
+        <!-- 搜索栏 -->
14
+        <view class="search-bar">
15
+          <view class="search-input-wrapper">
16
+            <uni-icons type="search" size="16" color="#999"></uni-icons>
17
+            <input class="search-input" v-model="queryParams.projectNumber" placeholder="请输入项目编号搜索"
18
+              @confirm="handleSearch" />
19
+            <uni-icons v-if="queryParams.projectNumber" type="clear" size="16" color="#999"
20
+              @click="clearSearch"></uni-icons>
21
+          </view>
22
+        </view>
23
+        <template v-if="logList.length > 0">
24
+          <view class="project-card" v-for="(item, index) in logList" :key="index">
25
+            <view class="project-card-item">
26
+              <view class="project-card-item-header">
27
+                <view class="project-info">
28
+                  <text class="project-number">{{ item.project ? item.project.projectNumber : '无项目' }}</text>
29
+                  <text class="project-name">{{ item.project ? item.project.projectName : '无项目' }}</text>
30
+                </view>
31
+                <view class="action-buttons">
32
+                  <button class="action-btn edit" v-if="isOwnRecord(item)" @click="handleEdit(item)">
33
+                    <uni-icons type="compose" size="16" color="#007AFF"></uni-icons>
34
+                  </button>
35
+                  <button class="action-btn delete" v-if="isOwnRecord(item)" @click="handleDelete(item)">
36
+                    <uni-icons type="trash" size="16" color="#FF3B30"></uni-icons>
37
+                  </button>
38
+                </view>
39
+              </view>
40
+              <view class="project-card-item-content">
41
+                <view class="info-row">
42
+                  <text class="info-label">设备名称:</text>
43
+                  <text class="info-value" v-if="item.deviceId">{{ item.device ? item.device.name : '' }}-{{ item.device
44
+                    ? item.device.brand : '' }}({{
45
+                      item.device ? item.device.code : '' }})</text>
46
+                  <text class="info-value" v-else>暂无设备</text>
47
+                </view>
48
+                <view class="info-row">
49
+                  <text class="info-label">设备类型:</text>
50
+                  <text class="info-value">{{ item.usageType }}</text>
51
+                </view>
52
+                <view class="info-row">
53
+                  <text class="info-label">使用日期:</text>
54
+                  <text class="info-value">{{ item.useDate }}</text>
55
+                </view>
56
+                <view class="info-row">
57
+                  <text class="info-label">记录员:</text>
58
+                  <text class="info-value">{{ item.user.nickName }}</text>
59
+                </view>
60
+                <view class="info-row">
61
+                  <text class="info-label">点号:</text>
62
+                  <text class="info-value">{{ item.position }}</text>
63
+                </view>
64
+                <view class="info-row">
65
+                  <text class="info-label">高值类型:</text>
66
+                  <text class="info-value">{{ item.heightType }}</text>
67
+                </view>
68
+                <view class="info-row">
69
+                  <text class="info-label">高值:</text>
70
+                  <text class="info-value">{{ item.height }}m</text>
71
+                </view>
72
+                <view class="info-row">
73
+                  <text class="info-label">天气:</text>
74
+                  <text class="info-value">{{ item.weather }}</text>
75
+                </view>
76
+                <view class="info-row">
77
+                  <text class="info-label">干温:</text>
78
+                  <text class="info-value">{{ item.dryTemperature }}°C</text>
79
+                </view>
80
+                <view class="info-row">
81
+                  <text class="info-label">湿温:</text>
82
+                  <text class="info-value">{{ item.wetTemperature }}°C</text>
83
+                </view>
84
+                <view class="info-row">
85
+                  <text class="info-label">气压:</text>
86
+                  <text class="info-value">{{ item.airPressure }}hPa</text>
87
+                </view>
88
+                <view class="info-row">
89
+                  <text class="info-label">开机时间:</text>
90
+                  <text class="info-value">{{ formatDateTime(item.powerOn) }}</text>
91
+                </view>
92
+                <view class="info-row">
93
+                  <text class="info-label">关机时间:</text>
94
+                  <text class="info-value">{{ formatDateTime(item.powerOff) }}</text>
95
+                </view>
96
+              </view>
97
+            </view>
98
+          </view>
99
+          <view class="loading-more" v-if="hasMore">
100
+            <text class="loading-text">加载中...</text>
101
+          </view>
102
+          <view class="no-more" v-else>
103
+            <text class="no-more-text">没有更多数据了</text>
104
+          </view>
105
+        </template>
106
+        <view v-else class="empty-state">
107
+          <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image>
108
+          <text class="empty-text">暂无数据</text>
109
+        </view>
110
+      </view>
111
+    </scroll-view>
112
+
113
+    <!-- 悬浮按钮 -->
114
+    <view class="fab-button" @click="handleAdd">
115
+      <uni-icons type="plusempty" size="24" color="#fff"></uni-icons>
116
+    </view>
117
+
118
+    <!-- 新增记录弹窗 -->
119
+    <uni-popup ref="addPopup" type="center">
120
+      <view class="popup-content">
121
+        <view class="popup-header">
122
+          <text class="title">{{ isEdit ? '修改记录' : '新增记录' }}</text>
123
+          <uni-icons type="close" size="20" @click="closePopup"></uni-icons>
124
+        </view>
125
+        <view class="popup-body">
126
+          <view class="form-item">
127
+            <text class="label">项目选择</text>
128
+            <view class="project-picker" @click="showProjectPicker">
129
+              <text v-if="selectedProject">{{ selectedProject.projectName }}</text>
130
+              <text v-else class="placeholder">请选择项目</text>
131
+            </view>
132
+          </view>
133
+          <view class="form-item">
134
+            <text class="label">设备选择</text>
135
+            <view class="project-picker" @click="showDevicePicker">
136
+              <text v-if="selectDevice && selectDevice.code">{{ selectDevice.name }}-{{ selectDevice.brand }}({{
137
+                selectDevice.code
138
+              }})</text>
139
+              <text v-else class="placeholder">请选择设备</text>
140
+            </view>
141
+          </view>
142
+          <view class="form-item">
143
+            <text class="label">设备类型</text>
144
+            <uni-data-select v-model="formData.usageType" :localdata="useTypeOptions" placeholder="请选择设备类型"
145
+              class="weather-select" @change="handleUseTypeChange" />
146
+          </view>
147
+          <view class="form-item">
148
+            <text class="label">使用日期</text>
149
+            <!-- <uni-datetime-picker v-model="formData.useDate" type="date" /> -->
150
+            <uv-calendar ref="calendar" mode="single" @confirm="confirmUseDate"></uv-calendar>
151
+            <view class="project-picker" @click="$refs.calendar.open()">
152
+              <text v-if="formData.useDate">{{ formData.useDate }}</text>
153
+              <text v-else class="placeholder">请选择日期</text>
154
+            </view>
155
+          </view>
156
+          <view class="form-item">
157
+            <text class="label">点号</text>
158
+            <input v-model="formData.position" placeholder="请输入点号" />
159
+          </view>
160
+          <view class="form-item">
161
+            <text class="label">高值类型</text>
162
+            <uni-data-select v-model="formData.heightType" :localdata="highTypeOptions" placeholder="请选择高值类型"
163
+              class="weather-select" @change="handleHighTypeChange" />
164
+          </view>
165
+          <view class="form-item">
166
+            <text class="label">高值(m)</text>
167
+            <input v-model="formData.height" type="number" placeholder="请输入高值" />
168
+          </view>
169
+          <view class="form-item">
170
+            <text class="label">天气</text>
171
+            <uni-data-select v-model="formData.weather" :localdata="weatherOptions" placeholder="请选择天气"
172
+              class="weather-select" />
173
+          </view>
174
+          <view class="form-item">
175
+            <text class="label">干温 (°C)</text>
176
+            <input v-model="formData.dryTemperature" type="number" placeholder="请输入干温" />
177
+          </view>
178
+          <view class="form-item">
179
+            <text class="label">湿温 (°C)</text>
180
+            <input v-model="formData.wetTemperature" type="number" placeholder="请输入湿温" />
181
+          </view>
182
+          <view class="form-item">
183
+            <text class="label">气压 (hPa)</text>
184
+            <input v-model="formData.airPressure" type="number" placeholder="请输入气压" />
185
+          </view>
186
+          <view class="form-item" v-if="formData.usageType !== '全站仪'">
187
+            <text class="label">开机时间</text>
188
+            <view class="datetime-picker" @click="openPowerOnPicker">
189
+              <text v-if="formData.powerOn">{{ formatDateTime(formData.powerOn) }}</text>
190
+              <text v-else class="placeholder">请选择开机时间</text>
191
+            </view>
192
+          </view>
193
+          <view class="form-item" v-if="formData.usageType !== '全站仪'">
194
+            <text class="label">关机时间</text>
195
+            <view class="datetime-picker" @click="openPowerOffPicker">
196
+              <text v-if="formData.powerOff">{{ formatDateTime(formData.powerOff) }}</text>
197
+              <text v-else class="placeholder">请选择关机时间</text>
198
+            </view>
199
+          </view>
200
+        </view>
201
+        <view class="popup-footer">
202
+          <button class="btn cancel" @click="closePopup">取消</button>
203
+          <button class="btn confirm" @click="submitForm">确定</button>
204
+        </view>
205
+      </view>
206
+    </uni-popup>
207
+
208
+    <!-- 项目选择器 -->
209
+    <project-picker :visible.sync="showPicker" :selected.sync="selectedProject" @confirm="handleProjectSelect" />
210
+    <!-- 设备选择器 -->
211
+    <device-picker :visible.sync="openDevice" :selected.sync="selectDevice" :multiple="false"
212
+      @confirm="handleDeviceSelect"></device-picker>
213
+    <!-- 时间选择器 -->
214
+    <uv-datetime-picker ref="powerOnPicker" v-model="formData.powerOn" mode="datetime"
215
+      @confirm="handlePowerOnConfirm"></uv-datetime-picker>
216
+    <uv-datetime-picker ref="powerOffPicker" v-model="formData.powerOff" mode="datetime"
217
+      @confirm="handlePowerOffConfirm"></uv-datetime-picker>
218
+  </view>
219
+</template>
220
+
221
+<script>
222
+import { listDeviceLog, getDeviceLog, addDeviceLog, updateDeviceLog, delDeviceLog } from '@/api/oa/device/deviceLog';
223
+import { listProject } from '@/api/oa/project/project';
224
+import ProjectPicker from '@/pages/components/ProjectPicker.vue';
225
+import DevicePicker from '@/pages/components/DevicePicker.vue';
226
+import { parseTime } from '@/utils/common';
227
+
228
+export default {
229
+  components: {
230
+    ProjectPicker,
231
+    DevicePicker
232
+  },
233
+  data() {
234
+    return {
235
+      logList: [],
236
+      scrollTop: 0,
237
+      queryParams: {
238
+        pageNum: 1,
239
+        pageSize: 10,
240
+        userId: null,
241
+        projectNumber: ''
242
+      },
243
+      showPicker: false,
244
+      selectedProject: null,
245
+      openDevice: false,
246
+      selectDevice: {},
247
+      weatherOptions: [
248
+        { text: '晴', value: '晴' },
249
+        { text: '阴', value: '阴' },
250
+        { text: '多云', value: '多云' },
251
+        { text: '雨', value: '雨' },
252
+        { text: '雪', value: '雪' }
253
+      ],
254
+      highTypeOptions: [],
255
+      useTypeOptions: [
256
+        { text: '全站仪', value: '全站仪' },
257
+        { text: 'GNSS基站', value: 'GNSS基站' },
258
+        { text: 'GNSS静态', value: 'GNSS静态' }
259
+      ],
260
+      formData: {
261
+        useDate: '',
262
+        weather: '',
263
+        position: '',
264
+        dryTemperature: '',
265
+        wetTemperature: '',
266
+        airPressure: '',
267
+        heightType: '',
268
+        height: '',
269
+        powerOn: '',
270
+        powerOff: '',
271
+        usageType: ''
272
+      },
273
+      isEdit: false,
274
+      currentLogId: null,
275
+      hasMore: true,
276
+      loading: false,
277
+      isRefreshing: false
278
+    }
279
+  },
280
+  created() {
281
+    this.getList()
282
+  },
283
+  methods: {
284
+    async getList() {
285
+      if (this.loading) return
286
+      this.loading = true
287
+
288
+      try {
289
+        if (this.$store.getters.roles.includes('leader') || this.$store.getters.roles.includes('dept')) {
290
+          this.queryParams.userId = null
291
+        } else {
292
+          this.queryParams.userId = this.$store.getters.userId
293
+        }
294
+
295
+        const res = await listDeviceLog(this.queryParams)
296
+        if (this.queryParams.pageNum === 1) {
297
+          this.logList = res.rows
298
+        } else {
299
+          this.logList = [...this.logList, ...res.rows]
300
+        }
301
+
302
+        this.hasMore = res.rows.length === this.queryParams.pageSize
303
+      } catch (error) {
304
+        uni.showToast({
305
+          title: '加载失败',
306
+          icon: 'error'
307
+        })
308
+      } finally {
309
+        this.loading = false
310
+      }
311
+    },
312
+    async onRefresh() {
313
+      this.isRefreshing = true
314
+      this.queryParams.pageNum = 1
315
+      this.hasMore = true
316
+      await this.getList()
317
+      this.isRefreshing = false
318
+    },
319
+    upper() {
320
+      // 下拉刷新
321
+      this.onRefresh()
322
+    },
323
+    lower() {
324
+      // 上拉加载更多
325
+      if (this.hasMore && !this.loading) {
326
+        this.queryParams.pageNum++
327
+        this.getList()
328
+      }
329
+    },
330
+    scroll(e) {
331
+      // 可以在这里添加滚动相关的逻辑
332
+    },
333
+    handleAdd() {
334
+      this.formData.useDate = parseTime(new Date(), '{y}-{m}-{d}');
335
+      this.$refs.addPopup.open()
336
+    },
337
+    closePopup() {
338
+      this.$refs.addPopup.close()
339
+      this.resetForm()
340
+    },
341
+    showProjectPicker() {
342
+      this.showPicker = true
343
+    },
344
+    showDevicePicker() {
345
+      this.openDevice = true
346
+    },
347
+    handleProjectSelect(project) {
348
+      this.selectedProject = project
349
+    },
350
+    handleDeviceSelect(device) {
351
+      this.selectDevice = device
352
+    },
353
+    openPowerOnPicker() {
354
+      this.$refs.powerOnPicker.open()
355
+    },
356
+    openPowerOffPicker() {
357
+      this.$refs.powerOffPicker.open()
358
+    },
359
+    handlePowerOnConfirm(e) {
360
+      this.formData.powerOn = e.value
361
+    },
362
+    handlePowerOffConfirm(e) {
363
+      this.formData.powerOff = e.value
364
+    },
365
+    confirmUseDate(e) {
366
+      this.formData.useDate = parseTime(e[0], '{y}-{m}-{d}')
367
+    },
368
+    formatDateTime(timestamp) {
369
+      if (!timestamp) return ''
370
+      const date = new Date(timestamp)
371
+      const year = date.getFullYear()
372
+      const month = String(date.getMonth() + 1).padStart(2, '0')
373
+      const day = String(date.getDate()).padStart(2, '0')
374
+      const hours = String(date.getHours()).padStart(2, '0')
375
+      const minutes = String(date.getMinutes()).padStart(2, '0')
376
+      return `${year}-${month}-${day} ${hours}:${minutes}`
377
+    },
378
+    resetForm() {
379
+      this.isEdit = false
380
+      this.currentLogId = null
381
+      this.selectedProject = null
382
+      this.formData = {
383
+        useDate: '',
384
+        weather: '',
385
+        position: '',
386
+        dryTemperature: '',
387
+        wetTemperature: '',
388
+        airPressure: '',
389
+        heightType: '',
390
+        height: '',
391
+        powerOn: '',
392
+        powerOff: '',
393
+        usageType: ''
394
+      }
395
+    },
396
+    async submitForm() {
397
+      if (!this.selectDevice) {
398
+        uni.showToast({
399
+          title: '请选择设备',
400
+          icon: 'none'
401
+        })
402
+        return
403
+      }
404
+      const params = {
405
+        ...this.formData,
406
+        projectId: this.selectedProject ? this.selectedProject.projectId : null,
407
+        deviceId: this.selectDevice.deviceId,
408
+        userId: this.$store.getters.userId,
409
+        powerOn: Number(this.formData.powerOn),
410
+        powerOff: Number(this.formData.powerOff)
411
+      }
412
+
413
+      try {
414
+        if (this.isEdit) {
415
+          await updateDeviceLog({
416
+            ...params,
417
+            logId: this.currentLogId
418
+          })
419
+          uni.showToast({
420
+            title: '修改成功',
421
+            icon: 'success'
422
+          })
423
+        } else {
424
+          await addDeviceLog(params)
425
+          uni.showToast({
426
+            title: '添加成功',
427
+            icon: 'success'
428
+          })
429
+        }
430
+        this.closePopup()
431
+        this.getList()
432
+      } catch (error) {
433
+        uni.showToast({
434
+          title: this.isEdit ? '修改失败' : '添加失败',
435
+          icon: 'error'
436
+        })
437
+      }
438
+    },
439
+    handleEdit(item) {
440
+      this.isEdit = true
441
+      this.currentLogId = item.logId
442
+      this.selectedProject = item.project
443
+      this.selectDevice = item.device
444
+      this.formData = {
445
+        useDate: item.useDate,
446
+        weather: item.weather,
447
+        position: item.position,
448
+        dryTemperature: item.dryTemperature,
449
+        wetTemperature: item.wetTemperature,
450
+        airPressure: item.airPressure,
451
+        heightType: item.heightType,
452
+        height: item.height,
453
+        powerOn: item.powerOn,
454
+        powerOff: item.powerOff,
455
+        usageType: item.usageType
456
+      }
457
+      if (item.usageType === '全站仪') {
458
+        this.highTypeOptions = [
459
+          { text: '仪器高', value: '仪器高' },
460
+          { text: '棱镜高', value: '棱镜高' }
461
+        ]
462
+      } else if (item.usageType === 'GNSS基站' || item.usageType === 'GNSS静态') {
463
+        this.highTypeOptions = [
464
+          { text: '斜高', value: '斜高' },
465
+          { text: '直高', value: '直高' },
466
+          { text: '杆高', value: '杆高' },
467
+          { text: '天线高', value: '天线高' }
468
+        ]
469
+      }
470
+      this.$refs.addPopup.open()
471
+    },
472
+    async handleDelete(item) {
473
+      try {
474
+        const [err, res] = await uni.showModal({
475
+          title: '确认删除',
476
+          content: '确定要删除这条记录吗?',
477
+          confirmColor: '#FF3B30'
478
+        })
479
+
480
+        if (err || !res.confirm) {
481
+          return
482
+        }
483
+
484
+        await delDeviceLog(item.logId)
485
+        uni.showToast({
486
+          title: '删除成功',
487
+          icon: 'success'
488
+        })
489
+        this.getList()
490
+      } catch (error) {
491
+        uni.showToast({
492
+          title: '删除失败',
493
+          icon: 'error'
494
+        })
495
+      }
496
+    },
497
+    handleHighTypeChange(value) {
498
+      this.formData.heightType = value
499
+    },
500
+    handleUseTypeChange(value) {
501
+      this.formData.usageType = value
502
+      if (value === '全站仪') {
503
+        this.highTypeOptions = [
504
+          { text: '仪器高', value: '仪器高' },
505
+          { text: '棱镜高', value: '棱镜高' }
506
+        ]
507
+      } else if (value === 'GNSS基站' || value === 'GNSS静态') {
508
+        this.highTypeOptions = [
509
+          { text: '斜高', value: '斜高' },
510
+          { text: '直高', value: '直高' },
511
+          { text: '杆高', value: '杆高' },
512
+          { text: '天线高', value: '天线高' }
513
+        ]
514
+      }
515
+      this.formData.heightType = ''
516
+    },
517
+    async handleSearch() {
518
+      this.queryParams.pageNum = 1
519
+      const res = await listProject({
520
+        pageNum: 1,
521
+        pageSize: 10,
522
+        projectNumber: this.queryParams.projectNumber
523
+      })
524
+      let projectList = res.rows;
525
+      if (projectList.length == 1) {
526
+        this.queryParams.projectId = projectList[0].projectId
527
+      } else {
528
+        this.queryParams.projectId = null
529
+      }
530
+      this.getList()
531
+    },
532
+    clearSearch() {
533
+      this.queryParams.projectNumber = ''
534
+      this.queryParams.projectId = null
535
+      this.getList()
536
+    },
537
+    isOwnRecord(item) {
538
+      return item.user.userId === this.$store.getters.userId
539
+    }
540
+  }
541
+}
542
+</script>
543
+
544
+<style lang="scss" scoped>
545
+.scroll-Y {
546
+  height: 100vh;
547
+  background: #f8f8f8;
548
+  box-sizing: border-box;
549
+  position: relative;
550
+  padding-bottom: 120rpx;
551
+}
552
+
553
+.content-wrapper {
554
+  padding: 20rpx;
555
+  min-height: 100%;
556
+}
557
+
558
+.fab-button {
559
+  position: fixed;
560
+  right: 30rpx;
561
+  bottom: 50rpx;
562
+  width: 100rpx;
563
+  height: 100rpx;
564
+  background: #007AFF;
565
+  border-radius: 50%;
566
+  display: flex;
567
+  align-items: center;
568
+  justify-content: center;
569
+  box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.3);
570
+  z-index: 99;
571
+  transition: all 0.3s;
572
+
573
+  &:active {
574
+    transform: scale(0.95);
575
+    background: #0062cc;
576
+  }
577
+}
578
+
579
+.project-card {
580
+  margin-bottom: 20rpx;
581
+  background: #fff;
582
+  border-radius: 12rpx;
583
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
584
+
585
+  &:last-child {
586
+    margin-bottom: 0;
587
+  }
588
+
589
+  &-item {
590
+    padding: 20rpx;
591
+
592
+    &-header {
593
+      display: flex;
594
+      justify-content: space-between;
595
+      align-items: center;
596
+      margin-bottom: 20rpx;
597
+      padding-bottom: 20rpx;
598
+      border-bottom: 2rpx solid #f5f5f5;
599
+
600
+      .project-info {
601
+        display: flex;
602
+        align-items: center;
603
+        gap: 20rpx;
604
+
605
+        .project-number {
606
+          font-size: 28rpx;
607
+          color: #666;
608
+          background: #f5f5f5;
609
+          padding: 4rpx 16rpx;
610
+          border-radius: 8rpx;
611
+        }
612
+
613
+        .project-name {
614
+          font-size: 32rpx;
615
+          color: #333;
616
+          font-weight: bold;
617
+        }
618
+      }
619
+
620
+      .action-buttons {
621
+        display: flex;
622
+        gap: 16rpx;
623
+
624
+        .action-btn {
625
+          width: 64rpx;
626
+          height: 64rpx;
627
+          display: flex;
628
+          align-items: center;
629
+          justify-content: center;
630
+          background: #f8f8f8;
631
+          border: none;
632
+          border-radius: 8rpx;
633
+          padding: 0;
634
+          transition: all 0.3s;
635
+
636
+          &:active {
637
+            transform: scale(0.95);
638
+          }
639
+
640
+          &.edit {
641
+            &:active {
642
+              background: #e6f2ff;
643
+            }
644
+          }
645
+
646
+          &.delete {
647
+            &:active {
648
+              background: #ffe6e6;
649
+            }
650
+          }
651
+        }
652
+      }
653
+    }
654
+
655
+    &-content {
656
+      display: flex;
657
+      flex-direction: column;
658
+      gap: 12rpx;
659
+
660
+      .info-row {
661
+        display: flex;
662
+        align-items: center;
663
+        font-size: 26rpx;
664
+        line-height: 1.5;
665
+
666
+        .info-label {
667
+          color: #666;
668
+          width: 140rpx;
669
+          flex-shrink: 0;
670
+        }
671
+
672
+        .info-value {
673
+          color: #333;
674
+          flex: 1;
675
+        }
676
+      }
677
+    }
678
+  }
679
+}
680
+
681
+.empty-state {
682
+  display: flex;
683
+  flex-direction: column;
684
+  align-items: center;
685
+  justify-content: center;
686
+  padding: 120rpx 0;
687
+
688
+  .empty-image {
689
+    width: 240rpx;
690
+    height: 240rpx;
691
+    margin-bottom: 20rpx;
692
+  }
693
+
694
+  .empty-text {
695
+    font-size: 28rpx;
696
+    color: #999;
697
+  }
698
+}
699
+
700
+.popup-content {
701
+  background: #fff;
702
+  border-radius: 24rpx;
703
+  width: 680rpx;
704
+  max-height: 75vh;
705
+
706
+  .popup-header {
707
+    display: flex;
708
+    justify-content: space-between;
709
+    align-items: center;
710
+    padding: 30rpx;
711
+    background: #f8f8f8;
712
+
713
+    .title {
714
+      font-size: 34rpx;
715
+      font-weight: 600;
716
+      color: #333;
717
+    }
718
+  }
719
+
720
+  .popup-body {
721
+    padding: 30rpx;
722
+    max-height: 60vh;
723
+    overflow-y: auto;
724
+
725
+    .form-item {
726
+      margin-bottom: 30rpx;
727
+
728
+      .label {
729
+        display: block;
730
+        font-size: 28rpx;
731
+        color: #333;
732
+        margin-bottom: 16rpx;
733
+        font-weight: 500;
734
+      }
735
+
736
+      input {
737
+        width: 100%;
738
+        height: 88rpx;
739
+        background: #f8f8f8;
740
+        border: 2rpx solid #eee;
741
+        border-radius: 12rpx;
742
+        padding: 0 24rpx;
743
+        font-size: 28rpx;
744
+        color: #333;
745
+        transition: all 0.3s;
746
+
747
+        &:focus {
748
+          border-color: #007AFF;
749
+          background: #fff;
750
+        }
751
+
752
+        &::placeholder {
753
+          color: #999;
754
+        }
755
+      }
756
+
757
+      .project-picker {
758
+        width: 100%;
759
+        height: 88rpx;
760
+        background: #f8f8f8;
761
+        border: 2rpx solid #eee;
762
+        border-radius: 12rpx;
763
+        padding: 0 24rpx;
764
+        display: flex;
765
+        align-items: center;
766
+        transition: all 0.3s;
767
+
768
+        &:active {
769
+          background: #f0f0f0;
770
+        }
771
+
772
+        .placeholder {
773
+          color: #999;
774
+          font-size: 28rpx;
775
+        }
776
+      }
777
+
778
+      .datetime-picker {
779
+        width: 100%;
780
+        height: 88rpx;
781
+        background: #f8f8f8;
782
+        border: 2rpx solid #eee;
783
+        border-radius: 12rpx;
784
+        padding: 0 24rpx;
785
+        display: flex;
786
+        align-items: center;
787
+        transition: all 0.3s;
788
+
789
+        &:active {
790
+          background: #f0f0f0;
791
+        }
792
+
793
+        .placeholder {
794
+          color: #999;
795
+          font-size: 28rpx;
796
+        }
797
+      }
798
+    }
799
+  }
800
+
801
+  .popup-footer {
802
+    display: flex;
803
+    gap: 24rpx;
804
+    padding: 30rpx;
805
+    background: #f8f8f8;
806
+    border-top: 2rpx solid #eee;
807
+
808
+    .btn {
809
+      flex: 1;
810
+      height: 88rpx;
811
+      line-height: 88rpx;
812
+      text-align: center;
813
+      border-radius: 12rpx;
814
+      font-size: 30rpx;
815
+      font-weight: 500;
816
+      transition: all 0.3s;
817
+
818
+      &.cancel {
819
+        background: #f0f0f0;
820
+        color: #666;
821
+
822
+        &:active {
823
+          background: #e0e0e0;
824
+        }
825
+      }
826
+
827
+      &.confirm {
828
+        background: #007AFF;
829
+        color: #fff;
830
+
831
+        &:active {
832
+          background: #0062cc;
833
+        }
834
+      }
835
+    }
836
+  }
837
+}
838
+
839
+.weather-select {
840
+  :deep(.uni-data-select) {
841
+    .uni-select {
842
+      height: 88rpx;
843
+      background: #f8f8f8;
844
+      border: 2rpx solid #eee;
845
+      border-radius: 12rpx;
846
+
847
+      .uni-select__input-box {
848
+        height: 88rpx;
849
+        line-height: 88rpx;
850
+        padding: 0 24rpx;
851
+      }
852
+
853
+      .uni-select__input-text {
854
+        font-size: 28rpx;
855
+        color: #333;
856
+      }
857
+
858
+      .uni-select__input-placeholder {
859
+        color: #999;
860
+      }
861
+    }
862
+  }
863
+}
864
+
865
+:deep(.uni-date) {
866
+  .uni-date__icon-clear {
867
+    display: none;
868
+  }
869
+
870
+  .uni-date-editor {
871
+    height: 88rpx;
872
+    background: #f8f8f8;
873
+    border: 2rpx solid #eee;
874
+    border-radius: 12rpx;
875
+
876
+    .uni-date__input {
877
+      height: 88rpx;
878
+      line-height: 88rpx;
879
+      font-size: 28rpx;
880
+      color: #333;
881
+    }
882
+  }
883
+}
884
+
885
+.loading-more,
886
+.no-more {
887
+  text-align: center;
888
+  padding: 20rpx 0;
889
+  margin-bottom: 120rpx;
890
+
891
+  .loading-text,
892
+  .no-more-text {
893
+    font-size: 24rpx;
894
+    color: #999;
895
+  }
896
+}
897
+
898
+.search-bar {
899
+  padding: 20rpx;
900
+  background: #fff;
901
+  margin-bottom: 20rpx;
902
+  border-radius: 12rpx;
903
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
904
+
905
+  .search-input-wrapper {
906
+    display: flex;
907
+    align-items: center;
908
+    background: #f8f8f8;
909
+    border-radius: 8rpx;
910
+    padding: 0 20rpx;
911
+    height: 72rpx;
912
+
913
+    .search-input {
914
+      flex: 1;
915
+      height: 72rpx;
916
+      margin: 0 20rpx;
917
+      font-size: 28rpx;
918
+      color: #333;
919
+
920
+      &::placeholder {
921
+        color: #999;
922
+      }
923
+    }
924
+  }
925
+}
926
+</style>

+ 23
- 5
oa-ui-app/pages/work/index.vue Ver arquivo

@@ -1,3 +1,9 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-01-16 11:17:08
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-06-10 11:02:19
6
+-->
1 7
 <template>
2 8
   <view class="work-container">
3 9
     <!-- 轮播图 -->
@@ -22,11 +28,17 @@
22 28
           </view>
23 29
         </uni-grid-item>
24 30
         <!-- <uni-grid-item>
25
-          <view class="grid-item-box" @click="openBorrow">
31
+          <view class="grid-item-box" @click="toUrlFn('borrow)">
26 32
             <u-image :fade="false" src="@/static/images/work/borrow.png" width="40px" height="40px"></u-image>
27 33
             <text class="text">借款管理</text>
28 34
           </view>
29 35
         </uni-grid-item> -->
36
+        <uni-grid-item>
37
+          <view class="grid-item-box" @click="toUrlFn('deviceLog')">
38
+            <u-image :fade="false" src="@/static/images/work/workDay.png" width="40px" height="40px"></u-image>
39
+            <text class="text">设备作业记录</text>
40
+          </view>
41
+        </uni-grid-item>
30 42
       </uni-grid>
31 43
       <!-- <uni-grid :column="4" :showBorder="false" @change="changeGrid">
32 44
         <uni-grid-item>
@@ -153,10 +165,16 @@ export default {
153 165
     openSendFlow() {
154 166
       this.$refs.popup.open();
155 167
     },
156
-    openBorrow() {
157
-      uni.navigateTo({
158
-        url: '/pages/oa/borrow/borrowList'
159
-      })
168
+    toUrlFn(type) {
169
+      if (type == 'borrow') {
170
+        uni.navigateTo({
171
+          url: '/pages/oa/borrow/borrowList'
172
+        })
173
+      } else if (type == 'deviceLog') {
174
+        uni.navigateTo({
175
+          url: '/pages/oa/device/deviceLog'
176
+        })
177
+      }
160 178
     },
161 179
     sendFlow(row) {
162 180
       let formId = new Snowflake(1n, 1n, 0n).nextId().toString();

BIN
oa-ui-app/static/images/empty.png Ver arquivo


BIN
oa-ui-app/static/images/work/workDay.png Ver arquivo


+ 8
- 9
oa-ui/src/views/flowable/form/budget/addBudget.vue Ver arquivo

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-06-21 18:51:51
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-29 13:55:21
5
+ * @LastEditTime: 2025-06-11 11:06:16
6 6
 -->
7 7
 <template>
8 8
   <div class="app-container">
@@ -18,22 +18,22 @@
18 18
     <el-descriptions title="项目信息" labelClassName="mylabel">
19 19
       <el-descriptions-item label="项目编号">{{
20 20
         project.projectNumber
21
-        }}</el-descriptions-item>
21
+      }}</el-descriptions-item>
22 22
       <el-descriptions-item label="项目名称">{{
23 23
         project.projectName
24
-        }}</el-descriptions-item>
24
+      }}</el-descriptions-item>
25 25
       <el-descriptions-item label="项目负责人">{{
26 26
         getUserName(project.projectLeader)
27
-        }}</el-descriptions-item>
27
+      }}</el-descriptions-item>
28 28
       <el-descriptions-item label="项目类型">{{
29 29
         project.projectType
30
-        }}</el-descriptions-item>
30
+      }}</el-descriptions-item>
31 31
       <el-descriptions-item label="承担部门">{{
32 32
         getDeptNames(project.undertakingDept)
33
-        }}</el-descriptions-item>
33
+      }}</el-descriptions-item>
34 34
       <el-descriptions-item label="甲方单位">{{
35 35
         project.partyA ? project.partyA.partyAName : ""
36
-        }}</el-descriptions-item>
36
+      }}</el-descriptions-item>
37 37
     </el-descriptions>
38 38
     <!-- <el-divider><b>间接成本</b></el-divider> -->
39 39
     <!-- 预结算 -->
@@ -54,8 +54,7 @@
54 54
     <site-expenses :budgetId="budgetForm.budgetId" :outer-users="outerUsers" @expensesList="getExpensesList"
55 55
       @siteSum="getSiteSum"></site-expenses>
56 56
     <!-- 经营相关 -->
57
-    <other-table ref="otherRef" @otherCost="getOtherCost" :budgetForm="budgetForm"
58
-      :disabled="taskName != '经营审核'"></other-table>
57
+    <other-table ref="otherRef" @otherCost="getOtherCost" :budgetForm="budgetForm" :taskName="taskName"></other-table>
59 58
     <!-- 预算备注 -->
60 59
     <el-form :model="budgetForm" style="padding: 20px 100px 0">
61 60
       <el-form-item label="预算表单备注" label-width="100px">

+ 10
- 10
oa-ui/src/views/flowable/form/budget/otherTable.vue Ver arquivo

@@ -2,11 +2,11 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-12-11 17:21:00
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-13 10:07:18
5
+ * @LastEditTime: 2025-06-11 11:05:41
6 6
 -->
7 7
 <template>
8 8
   <div>
9
-    <el-form :model="form" style="padding: 20px 100px 0" :disabled="disabled">
9
+    <el-form :model="form" style="padding: 20px 100px 0">
10 10
       <el-form-item label="经营相关:">
11 11
         <table border="1">
12 12
           <tr class="head">
@@ -18,7 +18,7 @@
18 18
             <td>外协费用</td>
19 19
             <td>
20 20
               <el-input-number :controls="false" style="width:100%;" v-model="form.outExpense"
21
-                @blur="computedDirectExpense()"></el-input-number>
21
+                @blur="computedDirectExpense()" :disabled="taskName != '预算编制' && taskName != '经营审核'"></el-input-number>
22 22
             </td>
23 23
             <td>
24 24
               <el-input type="textarea" v-model="form.outRemark"></el-input>
@@ -28,7 +28,7 @@
28 28
             <td>保函费用</td>
29 29
             <td>
30 30
               <el-input-number :controls="false" style="width:100%;" v-model="form.letterExpense"
31
-                @blur="computedDirectExpense()"></el-input-number>
31
+                @blur="computedDirectExpense()" :disabled="taskName != '经营审核'"></el-input-number>
32 32
             </td>
33 33
             <td>
34 34
               <el-input type="textarea" v-model="form.letterRemark"></el-input>
@@ -38,7 +38,7 @@
38 38
             <td>中标服务费</td>
39 39
             <td>
40 40
               <el-input-number :controls="false" style="width:100%;" v-model="form.winExpense"
41
-                @blur="computedDirectExpense()"></el-input-number>
41
+                @blur="computedDirectExpense()" :disabled="taskName != '经营审核'"></el-input-number>
42 42
             </td>
43 43
             <td>
44 44
               <el-input type="textarea" v-model="form.winRemark"></el-input>
@@ -48,7 +48,7 @@
48 48
             <td>税费</td>
49 49
             <td>
50 50
               <el-input-number :controls="false" style="width:100%;" v-model="form.taxExpense"
51
-                @blur="computedDirectExpense()"></el-input-number>
51
+                @blur="computedDirectExpense()" :disabled="taskName != '经营审核'"></el-input-number>
52 52
             </td>
53 53
             <td>
54 54
               <el-input type="textarea" v-model="form.taxRemark"></el-input>
@@ -58,7 +58,7 @@
58 58
             <td>管理出差</td>
59 59
             <td>
60 60
               <el-input-number :controls="false" style="width:100%;" v-model="form.travelExpense"
61
-                @blur="computedDirectExpense()"></el-input-number>
61
+                @blur="computedDirectExpense()" :disabled="taskName != '经营审核'"></el-input-number>
62 62
             </td>
63 63
             <td>
64 64
               <el-input type="textarea" v-model="form.travelRemark"></el-input>
@@ -83,9 +83,9 @@ export default {
83 83
       type: Object,
84 84
       default: ''
85 85
     },
86
-    disabled: {
87
-      type: Boolean,
88
-      default: true
86
+    taskName: {
87
+      type: String,
88
+      default: ''
89 89
     }
90 90
   },
91 91
   data() {

+ 9
- 3
oa-ui/src/views/flowable/form/budget/staffTable.vue Ver arquivo

@@ -147,6 +147,7 @@
147 147
 import { listBudgetStaff, addBudgetStaff, delBudgetStaff } from "@/api/oa/budget/budgetStaff.js";
148 148
 import choosePeople from './components/choosePeople.vue';
149 149
 import calculatePerformance from './components/calculatePerformance.vue';
150
+import { getUserDayValue } from "@/api/oa/wage/wage";
150 151
 export default {
151 152
   components: {
152 153
     choosePeople,
@@ -214,9 +215,14 @@ export default {
214 215
           const allUsers = res.rows;
215 216
           this.innerUsers = allUsers.filter(user => user.type === '内业');
216 217
           this.outerUsers = allUsers.filter(user => user.type === '外业');
218
+          let month = this.parseTime(new Date(), '{y}-{m}')
217 219
           for (let user of [...this.innerUsers, ...this.outerUsers]) {
218 220
             user.nickName = this.getUserName(user.userId);
219 221
             user.deptName = this.getDeptName(user.user.deptId);
222
+            getUserDayValue({ userId: user.userId, payMonth: month }).then(res => {
223
+              user.socialSecurityUnit = res.data.socialSecurityUnit;
224
+              user.houseFund = res.data.houseFund;
225
+            })
220 226
           }
221 227
           this.initStaffCost()
222 228
         })
@@ -283,7 +289,7 @@ export default {
283 289
         let dayCost;
284 290
         if (!v.salary) {
285 291
           v.salary = { salary: 0 }
286
-          dayCost = 0;
292
+          dayCost = ((1780 * 12) / 365).toFixed(2);
287 293
         } else {
288 294
           dayCost = (parseFloat(((v.salary.salary + 1780) * 12) / 365) + v.socialSecurityUnit + v.houseFund).toFixed(2);
289 295
         }
@@ -322,10 +328,10 @@ export default {
322 328
         // 外业人员计算方式
323 329
         user.performance = (200 * Number(user.days) * Number(user.coefficient)).toFixed(2);
324 330
       }
325
-      if (!user.dayCost && user.salary && user.salary.salary != 0) {
331
+      if (user.dayCost && user.salary && user.salary.salary != 0) {
326 332
         user.dayCost = (parseFloat(((user.salary.salary + 1780) * 12) / 365) + user.socialSecurityUnit + user.houseFund).toFixed(2);
327 333
       } else {
328
-        user.dayCost = 0;
334
+        user.dayCost = ((1780 * 12) / 365).toFixed(2);
329 335
       }
330 336
       let staffCost = Number(user.dayCost) * Number(user.days)
331 337
       total = user.dayCost * Number(user.days) + Number(user.performance);

+ 529
- 0
oa-ui/src/views/oa/declare/log.vue Ver arquivo

@@ -0,0 +1,529 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
4
+      <el-form-item label="项目编号" prop="projectId">
5
+        <el-select v-model="queryParams.projectId" clearable filterable remote reserve-keyword placeholder="请输入项目编号"
6
+          :remote-method="remoteMethod" :loading="loading" style="width: 400px;" @change="handleQuery">
7
+          <el-option v-for="project in projectList" :key="project.projectId"
8
+            :label="project.projectNumber + '-' + project.projectName" :value="project.projectId">
9
+          </el-option>
10
+        </el-select>
11
+      </el-form-item>
12
+      <el-form-item label="使用日期" prop="useDate">
13
+        <el-date-picker clearable v-model="queryParams.useDate" type="date" value-format="yyyy-MM-dd"
14
+          placeholder="请选择使用日期">
15
+        </el-date-picker>
16
+      </el-form-item>
17
+      <el-form-item label="记录员" prop="userId" v-hasRole="['admin', 'leader', 'dept']">
18
+        <el-select v-model="queryParams.userId" filterable clearable @change="handleQuery">
19
+          <el-option v-for="item in $store.state.user.userList" :key="item.userId" :label="item.nickName"
20
+            :value="item.userId">
21
+          </el-option>
22
+        </el-select>
23
+      </el-form-item>
24
+      <el-form-item>
25
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
26
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
27
+      </el-form-item>
28
+    </el-form>
29
+
30
+    <el-row :gutter="10" class="mb8">
31
+      <el-col :span="1.5">
32
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
33
+          v-hasPermi="['oa:deviceLog:add']">新增</el-button>
34
+      </el-col>
35
+      <el-col :span="1.5">
36
+        <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
37
+          v-if="hasEditPermission">修改</el-button>
38
+      </el-col>
39
+      <el-col :span="1.5">
40
+        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
41
+          v-hasPermi="['oa:deviceLog:remove']">删除</el-button>
42
+      </el-col>
43
+      <el-col :span="1.5">
44
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
45
+          v-hasPermi="['oa:deviceLog:export']">导出</el-button>
46
+      </el-col>
47
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
48
+    </el-row>
49
+
50
+    <el-table v-loading="loading" :data="deviceLogList" @selection-change="handleSelectionChange">
51
+      <el-table-column type="selection" width="55" align="center" />
52
+      <el-table-column label="项目编号" align="center" prop="project.projectNumber">
53
+        <template slot-scope="scope">
54
+          <span v-if="scope.row.projectId">{{ scope.row.project.projectNumber }}</span>
55
+          <span v-else>--</span>
56
+        </template>
57
+      </el-table-column>
58
+      <el-table-column label="项目名称" align="center" prop="project.projectName" width="180">
59
+        <template slot-scope="scope">
60
+          <span v-if="scope.row.projectId">{{ scope.row.project.projectName }}</span>
61
+          <span v-else>--</span>
62
+        </template>
63
+      </el-table-column>
64
+      <el-table-column label="设备名称" align="center" prop="device.name">
65
+        <template slot-scope="scope">
66
+          <span v-if="scope.row.deviceId">{{ scope.row.device.name }}-{{ scope.row.device.brand }}({{
67
+            scope.row.device.code }})</span>
68
+          <span v-else>--</span>
69
+        </template>
70
+      </el-table-column>
71
+      <el-table-column label="设备类型" align="center" prop="usageType" />
72
+      <el-table-column label="使用日期" align="center" prop="useDate" width="120">
73
+        <template slot-scope="scope">
74
+          <span>{{ parseTime(scope.row.useDate, '{y}-{m}-{d}') }}</span>
75
+        </template>
76
+      </el-table-column>
77
+      <el-table-column label="天气" align="center" prop="weather" />
78
+      <el-table-column label="点号" align="center" prop="position" />
79
+      <el-table-column label="高值类型" align="center" prop="heightType" />
80
+      <el-table-column label="高值(m)" align="center" prop="height" />
81
+      <el-table-column label="干温(°C)" align="center" prop="dryTemperature" />
82
+      <el-table-column label="湿温(°C)" align="center" prop="wetTemperature" />
83
+      <el-table-column label="气压(hPa)" align="center" prop="airPressure" />
84
+      <el-table-column label="开机时间" align="center" prop="powerOn" width="150">
85
+        <template slot-scope="scope">
86
+          <span>{{ parseTime(scope.row.powerOn, '{y}-{m}-{d} {h}:{i}') }}</span>
87
+        </template>
88
+      </el-table-column>
89
+      <el-table-column label="关机时间" align="center" prop="powerOff" width="150">
90
+        <template slot-scope="scope">
91
+          <span>{{ parseTime(scope.row.powerOff, '{y}-{m}-{d} {h}:{i}') }}</span>
92
+        </template>
93
+      </el-table-column>
94
+      <el-table-column label="记录员" align="center" prop="user.nickName" />
95
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
96
+        <template slot-scope="scope">
97
+          <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
98
+            v-hasPermi="['oa:deviceLog:list']">查看</el-button>
99
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
100
+            v-if="hasEditPermission(scope.row)" v-hasPermi="['oa:deviceLog:edit']">修改</el-button>
101
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
102
+            v-if="hasEditPermission(scope.row)" v-hasPermi="['oa:deviceLog:remove']">删除</el-button>
103
+        </template>
104
+      </el-table-column>
105
+    </el-table>
106
+
107
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
108
+      @pagination="getList" />
109
+
110
+    <!-- 添加或修改cmc仪器记录对话框 -->
111
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
112
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px" :disabled="isView">
113
+        <el-row :gutter="20">
114
+          <el-col :span="24">
115
+            <el-form-item label="项目名称" prop="projectId">
116
+              <span class="like-input mr10" v-if="form.projectId">{{ form.project.projectNumber + '-' +
117
+                form.project.projectName
118
+              }}</span>
119
+              <span class="like-input mr10" v-else>暂无项目</span>
120
+              <el-button icon="el-icon-plus" type="primary" @click="prOpen = true" size="mini">选择项目</el-button>
121
+            </el-form-item>
122
+          </el-col>
123
+          <el-col :span="24">
124
+            <el-form-item label="设备名称" prop="deviceId">
125
+              <span class="like-input mr10" v-if="form.deviceId">{{ form.device.name + '-' + form.device.brand + '(' +
126
+                form.device.code + ')' }}</span>
127
+              <span class="like-input mr10" v-else>暂无设备</span>
128
+              <el-button icon="el-icon-plus" type="primary" @click="deviceOpen = true" size="mini">选择设备</el-button>
129
+            </el-form-item>
130
+          </el-col>
131
+          <el-col :span="12">
132
+            <el-form-item label="设备类型" prop="usageType">
133
+              <el-select v-model="form.usageType" placeholder="请选择设备类型" style="width: 100%;"
134
+                @change="handleUseTypeChange">
135
+                <el-option v-for="item in useTypeOptions" :key="item.value" :label="item.label" :value="item.value">
136
+                </el-option>
137
+              </el-select>
138
+            </el-form-item>
139
+          </el-col>
140
+          <el-col :span="12">
141
+            <el-form-item label="使用日期" prop="useDate">
142
+              <el-date-picker clearable v-model="form.useDate" type="date" value-format="yyyy-MM-dd"
143
+                placeholder="请选择使用日期" style="width: 100%;">
144
+              </el-date-picker>
145
+            </el-form-item>
146
+          </el-col>
147
+          <el-col :span="12">
148
+            <el-form-item label="点号" prop="position">
149
+              <el-input v-model="form.position" placeholder="请输入点号" />
150
+            </el-form-item>
151
+          </el-col>
152
+          <el-col :span="12">
153
+            <el-form-item label="高值类型" prop="heightType">
154
+              <el-select v-model="form.heightType" placeholder="请选择高值类型" style="width: 100%;">
155
+                <el-option v-for="item in highTypeOptions" :key="item.value" :label="item.label" :value="item.value">
156
+                </el-option>
157
+              </el-select>
158
+            </el-form-item>
159
+          </el-col>
160
+          <el-col :span="12">
161
+            <el-form-item label="高值(m)" prop="height">
162
+              <el-input v-model="form.height" type="number" placeholder="请输入高值" />
163
+            </el-form-item>
164
+          </el-col>
165
+          <el-col :span="12">
166
+            <el-form-item label="天气" prop="weather">
167
+              <el-select v-model="form.weather" placeholder="请选择天气" style="width: 100%;">
168
+                <el-option v-for="item in weatherOptions" :key="item.value" :label="item.label" :value="item.value">
169
+                </el-option>
170
+              </el-select>
171
+            </el-form-item>
172
+          </el-col>
173
+          <el-col :span="12">
174
+            <el-form-item label="干温(°C)" prop="dryTemperature">
175
+              <el-input v-model="form.dryTemperature" type="number" placeholder="请输入干温" />
176
+            </el-form-item>
177
+          </el-col>
178
+          <el-col :span="12">
179
+            <el-form-item label="湿温(°C)" prop="wetTemperature">
180
+              <el-input v-model="form.wetTemperature" type="number" placeholder="请输入湿温" />
181
+            </el-form-item>
182
+          </el-col>
183
+          <el-col :span="12">
184
+            <el-form-item label="气压(hPa)" prop="airPressure">
185
+              <el-input v-model="form.airPressure" type="number" placeholder="请输入气压" />
186
+            </el-form-item>
187
+          </el-col>
188
+          <el-col :span="12">
189
+            <el-form-item label="开机时间" prop="powerOn">
190
+              <el-date-picker clearable v-model="form.powerOn" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
191
+                placeholder="请选择开机时间" style="width: 100%;">
192
+              </el-date-picker>
193
+            </el-form-item>
194
+          </el-col>
195
+          <el-col :span="12">
196
+            <el-form-item label="关机时间" prop="powerOff">
197
+              <el-date-picker clearable v-model="form.powerOff" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
198
+                placeholder="请选择关机时间" style="width: 100%;">
199
+              </el-date-picker>
200
+            </el-form-item>
201
+          </el-col>
202
+        </el-row>
203
+      </el-form>
204
+      <div slot="footer" class="dialog-footer">
205
+        <el-button type="primary" @click="submitForm">确 定</el-button>
206
+        <el-button @click="cancel">取 消</el-button>
207
+      </div>
208
+    </el-dialog>
209
+
210
+    <el-dialog title="选择项目" :visible.sync="prOpen" width="60%" append-to-body>
211
+      <choose-project @chooseProject="confirmProject"></choose-project>
212
+    </el-dialog>
213
+    <el-dialog title="选择设备" :visible.sync="deviceOpen" width="60%" append-to-body>
214
+      <choose-device @chooseList="confirmDevice"></choose-device>
215
+    </el-dialog>
216
+  </div>
217
+</template>
218
+
219
+<script>
220
+import { listDeviceLog, getDeviceLog, delDeviceLog, addDeviceLog, updateDeviceLog } from "@/api/oa/device/deviceLog";
221
+import { listProject, getProject } from "@/api/oa/project/project";
222
+import { listDevice, getDevice } from "@/api/oa/device/device";
223
+import chooseProject from '@/views/flowable/form/components/chooseProject.vue';
224
+import chooseDevice from '@/views/flowable/form/budget/components/chooseDevice.vue';
225
+
226
+export default {
227
+  name: "DeviceLog",
228
+  components: {
229
+    chooseProject,
230
+    chooseDevice
231
+  },
232
+  data() {
233
+    return {
234
+      // 遮罩层
235
+      loading: true,
236
+      // 选中数组
237
+      ids: [],
238
+      // 非单个禁用
239
+      single: true,
240
+      // 非多个禁用
241
+      multiple: true,
242
+      // 显示搜索条件
243
+      showSearch: true,
244
+      // 总条数
245
+      total: 0,
246
+      // cmc仪器记录表格数据
247
+      deviceLogList: [],
248
+      // 弹出层标题
249
+      title: "",
250
+      // 是否显示弹出层
251
+      open: false,
252
+      // 查询参数
253
+      queryParams: {
254
+        pageNum: 1,
255
+        pageSize: 10,
256
+        deviceId: null,
257
+        projectId: null,
258
+        usageType: null,
259
+        useDate: null,
260
+        weather: null,
261
+        position: null,
262
+        heightType: null,
263
+        dryTemperature: null,
264
+        wetTemperature: null,
265
+        airPressure: null,
266
+        powerOn: null,
267
+        powerOff: null,
268
+        userId: null
269
+      },
270
+      // 表单参数
271
+      form: {},
272
+      // 表单校验
273
+      rules: {
274
+        usageType: [
275
+          { required: true, message: "请选择设备类型", trigger: "change" }
276
+        ],
277
+        useDate: [
278
+          { required: true, message: "请选择使用日期", trigger: "change" }
279
+        ],
280
+        position: [
281
+          { required: true, message: "请输入点号", trigger: "blur" }
282
+        ],
283
+        heightType: [
284
+          { required: true, message: "请选择高值类型", trigger: "change" }
285
+        ],
286
+        height: [
287
+          { required: true, message: "请输入高值", trigger: "blur" }
288
+        ],
289
+      },
290
+      projectList: [],
291
+      deviceList: [],
292
+      weatherOptions: [
293
+        { label: '晴', value: '晴' },
294
+        { label: '阴', value: '阴' },
295
+        { label: '多云', value: '多云' },
296
+        { label: '雨', value: '雨' },
297
+        { label: '雪', value: '雪' }
298
+      ],
299
+      highTypeOptions: [],
300
+      useTypeOptions: [
301
+        { label: '全站仪', value: '全站仪' },
302
+        { label: 'GNSS基站', value: 'GNSS基站' },
303
+        { label: 'GNSS静态', value: 'GNSS静态' }
304
+      ],
305
+      prOpen: false,
306
+      deviceOpen: false,
307
+      isView: false,
308
+      // 添加计算属性
309
+      hasEditPermission: function (row) {
310
+        // 如果是表格行数据,则检查该行记录的所有者
311
+        if (row) {
312
+          // 如果是管理员或部门领导,可以编辑所有记录
313
+          if (this.$store.getters.roles.includes('admin')) {
314
+            return true;
315
+          }
316
+          // 普通用户只能编辑自己的记录
317
+          return row.userId === this.$store.getters.userId;
318
+        }
319
+        // 如果是顶部按钮,则根据角色判断
320
+        return this.$store.getters.roles.includes('admin') ||
321
+          this.$store.getters.roles.includes('leader') ||
322
+          this.$store.getters.roles.includes('dept');
323
+      }
324
+    };
325
+  },
326
+  created() {
327
+    this.getList();
328
+    this.getProjectList();
329
+  },
330
+  methods: {
331
+    /** 查询cmc仪器记录列表 */
332
+    getList() {
333
+      this.loading = true;
334
+      if (this.$store.getters.roles.includes('leader') || this.$store.getters.roles.includes('dept')) {
335
+        this.queryParams.userId = null
336
+      } else {
337
+        this.queryParams.userId = this.$store.getters.userId
338
+      }
339
+      listDeviceLog(this.queryParams).then(response => {
340
+        this.deviceLogList = response.rows;
341
+        this.total = response.total;
342
+        this.loading = false;
343
+      });
344
+    },
345
+    // 取消按钮
346
+    cancel() {
347
+      this.open = false;
348
+      this.reset();
349
+    },
350
+    // 表单重置
351
+    reset() {
352
+      this.form = {
353
+        logId: null,
354
+        deviceId: null,
355
+        projectId: null,
356
+        usageType: null,
357
+        useDate: null,
358
+        weather: null,
359
+        position: null,
360
+        heightType: null,
361
+        dryTemperature: null,
362
+        wetTemperature: null,
363
+        airPressure: null,
364
+        powerOn: null,
365
+        powerOff: null,
366
+        userId: null
367
+      };
368
+      this.resetForm("form");
369
+    },
370
+    /** 搜索按钮操作 */
371
+    handleQuery() {
372
+      this.queryParams.pageNum = 1;
373
+      this.getList();
374
+    },
375
+    /** 重置按钮操作 */
376
+    resetQuery() {
377
+      this.resetForm("queryForm");
378
+      this.handleQuery();
379
+    },
380
+    // 多选框选中数据
381
+    handleSelectionChange(selection) {
382
+      this.ids = selection.map(item => item.logId)
383
+      this.single = selection.length !== 1
384
+      this.multiple = !selection.length
385
+    },
386
+    /** 新增按钮操作 */
387
+    handleAdd() {
388
+      this.reset();
389
+      this.open = true;
390
+      this.title = "添加设备使用记录";
391
+      this.isView = false;
392
+      this.form.powerOn = new Date().toISOString().slice(0, 19).replace('T', ' ');
393
+      this.form.powerOff = new Date().toISOString().slice(0, 19).replace('T', ' ');
394
+    },
395
+    handleView(row) {
396
+      const logId = row.logId || this.ids;
397
+      getDeviceLog(logId).then(res => {
398
+        this.form = res.data;
399
+        this.handleUseTypeChange(row.usageType);
400
+        this.open = true;
401
+        this.title = "查看设备使用记录";
402
+        this.isView = true;
403
+      })
404
+    },
405
+    /** 修改按钮操作 */
406
+    async handleUpdate(row) {
407
+      this.reset();
408
+      const logId = row.logId || this.ids;
409
+      getDeviceLog(logId).then(res => {
410
+        this.form = res.data;
411
+        this.handleUseTypeChange(row.usageType);
412
+        this.open = true;
413
+        this.title = "修改设备使用记录";
414
+        this.isView = false;
415
+      })
416
+    },
417
+    confirmProject(project) {
418
+      if (project.length != 1) {
419
+        this.$message.error("项目只能选择一个!");
420
+        return;
421
+      }
422
+      this.form.project = project[0];
423
+      this.form.projectId = project[0].projectId;
424
+      this.prOpen = false;
425
+    },
426
+    confirmDevice(device) {
427
+      if (device.length != 1) {
428
+        this.$message.error("设备只能选择一个!");
429
+        return;
430
+      }
431
+      this.form.device = device[0];
432
+      this.form.deviceId = device[0].deviceId;
433
+      this.deviceOpen = false;
434
+    },
435
+    /** 提交按钮 */
436
+    submitForm() {
437
+      this.$refs["form"].validate(valid => {
438
+        if (valid) {
439
+          const params = {
440
+            ...this.form,
441
+            userId: this.$store.getters.userId
442
+          };
443
+
444
+          if (this.form.logId != null) {
445
+            updateDeviceLog(params).then(response => {
446
+              this.$modal.msgSuccess("修改成功");
447
+              this.open = false;
448
+              this.getList();
449
+            }).catch(() => {
450
+              this.$modal.msgError("修改失败");
451
+            });
452
+          } else {
453
+            addDeviceLog(params).then(response => {
454
+              this.$modal.msgSuccess("新增成功");
455
+              this.open = false;
456
+              this.getList();
457
+            }).catch(() => {
458
+              this.$modal.msgError("新增失败");
459
+            });
460
+          }
461
+        }
462
+      });
463
+    },
464
+    /** 删除按钮操作 */
465
+    handleDelete(row) {
466
+      const logIds = row.logId || this.ids;
467
+      this.$modal.confirm('是否确认删除cmc仪器记录编号为"' + logIds + '"的数据项?').then(() => {
468
+        return delDeviceLog(logIds);
469
+      }).then(() => {
470
+        this.getList();
471
+        this.$modal.msgSuccess("删除成功");
472
+      }).catch(() => {
473
+        this.$modal.msgError("删除失败");
474
+      });
475
+    },
476
+    /** 导出按钮操作 */
477
+    handleExport() {
478
+      this.download('oa/deviceLog/export', {
479
+        ...this.queryParams
480
+      }, `deviceLog_${new Date().getTime()}.xlsx`)
481
+    },
482
+    remoteMethod(val) {
483
+      listProject({
484
+        pageNum: 1,
485
+        pageSize: 20,
486
+        projectNumber: val
487
+      }).then(res => {
488
+        this.projectList = res.rows;
489
+      })
490
+    },
491
+    getProjectList() {
492
+      listProject({
493
+        pageNum: 1,
494
+        pageSize: 20,
495
+      }).then(res => {
496
+        this.projectList = res.rows;
497
+      })
498
+    },
499
+    // 设备类型变更
500
+    handleUseTypeChange(value) {
501
+      if (value === '全站仪') {
502
+        this.highTypeOptions = [
503
+          { label: '仪器高', value: '仪器高' },
504
+          { label: '棱镜高', value: '棱镜高' }
505
+        ];
506
+      } else if (value === 'GNSS基站' || value === 'GNSS静态') {
507
+        this.highTypeOptions = [
508
+          { label: '斜高', value: '斜高' },
509
+          { label: '直高', value: '直高' },
510
+          { label: '杆高', value: '杆高' },
511
+          { label: '天线高', value: '天线高' }
512
+        ];
513
+      }
514
+    }
515
+  }
516
+};
517
+</script>
518
+<style lang="scss" scoped>
519
+@import "@/assets/styles/element-reset.scss";
520
+
521
+.like-input {
522
+  border: 1px solid #dcdfe6;
523
+  border-radius: 4px;
524
+  padding: 0 10px;
525
+  height: 32px;
526
+  line-height: 32px;
527
+  display: inline-block;
528
+}
529
+</style>

Carregando…
Cancelar
Salvar