浏览代码

修改网页端车辆管理界面;

新增移动端设备审批表单
余思翰 1 个月前
父节点
当前提交
8f1ae5a3ac

+ 1
- 1
oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcCarApprovalController.java 查看文件

@@ -133,7 +133,7 @@ public class CmcCarApprovalController extends BaseController
133 133
      */
134 134
     @Log(title = "用车审批表", businessType = BusinessType.UPDATE)
135 135
     @PutMapping( "/modify")
136
-    public AjaxResult modify(@RequestParam("form")String formData)
136
+    public AjaxResult modify(@RequestBody String formData)
137 137
     {
138 138
         JSONObject formDataJson = JSONObject.parse(formData);
139 139
         CmcCarApproval cmcCarApproval = cmcCarApprovalService.selectCmcCarApprovalByCarApplyId(formDataJson.getString("carApplyId"));

+ 2
- 2
oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcDeviceApprovalController.java 查看文件

@@ -90,7 +90,7 @@ public class CmcDeviceApprovalController extends BaseController
90 90
      */
91 91
     @Log(title = "cmc设备审批", businessType = BusinessType.INSERT)
92 92
     @PostMapping("/submit")
93
-    public AjaxResult submit(@RequestParam("form")String formData)
93
+    public AjaxResult submit(@RequestBody String formData)
94 94
     {
95 95
         JSONObject formDataJson = JSONObject.parse(formData);
96 96
         CmcDeviceApproval cmcDeviceApproval = new CmcDeviceApproval();
@@ -136,7 +136,7 @@ public class CmcDeviceApprovalController extends BaseController
136 136
      */
137 137
     @Log(title = "cmc设备审批", businessType = BusinessType.UPDATE)
138 138
     @PutMapping("/modify")
139
-    public AjaxResult modify(@RequestParam("form")String formData)
139
+    public AjaxResult modify(@RequestBody String formData)
140 140
     {
141 141
         JSONObject formDataJson = JSONObject.parse(formData);
142 142
         CmcDeviceApproval cmcDeviceApproval = cmcDeviceApprovalService.selectCmcDeviceApprovalByDeviceApplyId(formDataJson.getString("deviceApplyId"));

+ 1
- 1
oa-ui-app/api/oa/device/deviceApproval.js 查看文件

@@ -2,7 +2,7 @@
2 2
  * @Author: wrh
3 3
  * @Date: 2024-03-05 17:24:50
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-03-07 10:27:26
5
+ * @LastEditTime: 2025-04-15 09:25:55
6 6
  */
7 7
 import request from '@/utils/request'
8 8
 

+ 128
- 0
oa-ui-app/api/system/role.js 查看文件

@@ -0,0 +1,128 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询角色列表
4
+export function listRole(query) {
5
+  return request({
6
+    url: '/system/role/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 查询角色详细
13
+export function getRole(roleId) {
14
+  return request({
15
+    url: '/system/role/' + roleId,
16
+    method: 'get'
17
+  })
18
+}
19
+
20
+// 查询角色详细
21
+export function getUserByRole(roleId) {
22
+  return request({
23
+    url: '/system/role/getUserByRole',
24
+    method: 'get',    
25
+    params: roleId
26
+  })
27
+}
28
+
29
+// 新增角色
30
+export function addRole(data) {
31
+  return request({
32
+    url: '/system/role',
33
+    method: 'post',
34
+    data: data
35
+  })
36
+}
37
+
38
+// 修改角色
39
+export function updateRole(data) {
40
+  return request({
41
+    url: '/system/role',
42
+    method: 'put',
43
+    data: data
44
+  })
45
+}
46
+
47
+// 角色数据权限
48
+export function dataScope(data) {
49
+  return request({
50
+    url: '/system/role/dataScope',
51
+    method: 'put',
52
+    data: data
53
+  })
54
+}
55
+
56
+// 角色状态修改
57
+export function changeRoleStatus(roleId, status) {
58
+  const data = {
59
+    roleId,
60
+    status
61
+  }
62
+  return request({
63
+    url: '/system/role/changeStatus',
64
+    method: 'put',
65
+    data: data
66
+  })
67
+}
68
+
69
+// 删除角色
70
+export function delRole(roleId) {
71
+  return request({
72
+    url: '/system/role/' + roleId,
73
+    method: 'delete'
74
+  })
75
+}
76
+
77
+// 查询角色已授权用户列表
78
+export function allocatedUserList(query) {
79
+  return request({
80
+    url: '/system/role/authUser/allocatedList',
81
+    method: 'get',
82
+    params: query
83
+  })
84
+}
85
+
86
+// 查询角色未授权用户列表
87
+export function unallocatedUserList(query) {
88
+  return request({
89
+    url: '/system/role/authUser/unallocatedList',
90
+    method: 'get',
91
+    params: query
92
+  })
93
+}
94
+
95
+// 取消用户授权角色
96
+export function authUserCancel(data) {
97
+  return request({
98
+    url: '/system/role/authUser/cancel',
99
+    method: 'put',
100
+    data: data
101
+  })
102
+}
103
+
104
+// 批量取消用户授权角色
105
+export function authUserCancelAll(data) {
106
+  return request({
107
+    url: '/system/role/authUser/cancelAll',
108
+    method: 'put',
109
+    params: data
110
+  })
111
+}
112
+
113
+// 授权用户选择
114
+export function authUserSelectAll(data) {
115
+  return request({
116
+    url: '/system/role/authUser/selectAll',
117
+    method: 'put',
118
+    params: data
119
+  })
120
+}
121
+
122
+// 根据角色ID查询部门树结构
123
+export function deptTreeSelect(roleId) {
124
+  return request({
125
+    url: '/system/role/deptTree/' + roleId,
126
+    method: 'get'
127
+  })
128
+}

+ 2
- 1
oa-ui-app/config.js 查看文件

@@ -2,12 +2,13 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-01-16 11:17:07
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-04-11 09:21:58
5
+ * @LastEditTime: 2025-04-14 16:44:31
6 6
  */
7 7
 // 应用全局配置
8 8
 module.exports = {
9 9
   // baseUrl: 'https://vue.ruoyi.vip/prod-api',
10 10
   baseUrl: 'http://192.168.28.108:8080',
11
+  // baseUrl: 'http://oa.sccehui.com:6200/prod-api',
11 12
   // baseUrl: '/prod-api',
12 13
   // 应用信息
13 14
   appInfo: {

+ 20
- 5
oa-ui-app/pages/components/DevicePicker.vue 查看文件

@@ -3,14 +3,17 @@
3 3
     <view class="modal-container">
4 4
       <!-- 搜索表单 -->
5 5
       <view class="search-box">
6
-        <uni-data-select v-model="queryParams.status" :localdata="statusOptions" style="width: 200rpx;"
7
-          :clearable="false" @change="handleSearch">
8
-        </uni-data-select>
6
+        <!-- <uni-data-select v-model="queryParams.status" :localdata="statusOptions" style="width: 200rpx;"
7
+          :clearable="false" @change="handleSearch" disabled>
8
+        </uni-data-select> -->
9 9
 
10
-        <uni-easyinput v-model="queryParams.code" placeholder="出厂编号" @confirm="handleSearch" clearable>
10
+        <uni-easyinput v-model="queryParams.code" placeholder="出厂编号" @change="handleSearch" clearable>
11 11
         </uni-easyinput>
12 12
 
13
-        <uni-easyinput v-model="queryParams.name" placeholder="设备名称" @confirm="handleSearch" clearable>
13
+        <uni-easyinput v-model="queryParams.name" placeholder="设备名称" @change="handleSearch" clearable>
14
+        </uni-easyinput>
15
+
16
+        <uni-easyinput v-model="queryParams.brand" placeholder="设备品牌" @change="handleSearch" clearable>
14 17
         </uni-easyinput>
15 18
       </view>
16 19
 
@@ -143,6 +146,17 @@ export default {
143 146
           this.list = [...this.list, ...res.rows];
144 147
         }
145 148
 
149
+        // 保持已选择的设备状态
150
+        const selectedDeviceIds = this.selectedList.map(item => item.deviceId);
151
+        this.list.forEach(item => {
152
+          if (selectedDeviceIds.includes(item.deviceId)) {
153
+            const selectedItem = this.selectedList.find(s => s.deviceId === item.deviceId);
154
+            if (selectedItem) {
155
+              Object.assign(item, selectedItem);
156
+            }
157
+          }
158
+        });
159
+
146 160
         this.hasMore = res.total > this.queryParams.pageNum * this.queryParams.pageSize;
147 161
         this.queryParams.pageNum++;
148 162
       } finally {
@@ -196,6 +210,7 @@ export default {
196 210
 
197 211
     // 加载更多
198 212
     loadMore() {
213
+      if (!this.hasMore || this.loading) return;
199 214
       this.loadData();
200 215
     },
201 216
 

+ 164
- 0
oa-ui-app/pages/components/RepairDevicePicker.vue 查看文件

@@ -0,0 +1,164 @@
1
+<template>
2
+  <uni-popup ref="popup" type="center">
3
+    <view class="popup-content">
4
+      <view class="popup-header">
5
+        <text class="title">选择需维修设备</text>
6
+        <uni-icons type="closeempty" size="24" @click="close"></uni-icons>
7
+      </view>
8
+      <view class="popup-body">
9
+        <view class="device-list">
10
+          <view class="device-item" 
11
+            v-for="(item, index) in deviceList" 
12
+            :key="index"
13
+            :class="{ 'selected': isSelected(item.deviceId) }"
14
+            @click="toggleSelection(item)">
15
+            <view class="device-info">
16
+              <text class="device-name">{{ item.name }}</text>
17
+              <text class="device-code">出厂编号:{{ item.code }}</text>
18
+            </view>
19
+            <uni-icons 
20
+              :type="isSelected(item.deviceId) ? 'checkbox-filled' : 'circle'" 
21
+              :color="isSelected(item.deviceId) ? '#67c23a' : '#999'"
22
+              size="20">
23
+            </uni-icons>
24
+          </view>
25
+        </view>
26
+      </view>
27
+      <view class="popup-footer">
28
+        <uv-button type="default" @click="close">取消</uv-button>
29
+        <uv-button type="primary" @click="confirm">确认</uv-button>
30
+      </view>
31
+    </view>
32
+  </uni-popup>
33
+</template>
34
+
35
+<script>
36
+export default {
37
+  name: 'RepairDevicePicker',
38
+  props: {
39
+    visible: {
40
+      type: Boolean,
41
+      default: false
42
+    },
43
+    deviceList: {
44
+      type: Array,
45
+      default: () => []
46
+    },
47
+    selectedDevices: {
48
+      type: Array,
49
+      default: () => []
50
+    }
51
+  },
52
+  data() {
53
+    return {
54
+      tempSelected: []
55
+    }
56
+  },
57
+  watch: {
58
+    visible(val) {
59
+      if (val) {
60
+        this.$refs.popup.open();
61
+        this.tempSelected = [...this.selectedDevices];
62
+      } else {
63
+        this.$refs.popup.close();
64
+      }
65
+    },
66
+    selectedDevices: {
67
+      handler(val) {
68
+        this.tempSelected = [...val];
69
+      },
70
+      immediate: true
71
+    }
72
+  },
73
+  methods: {
74
+    isSelected(deviceId) {
75
+      return this.tempSelected.includes(deviceId);
76
+    },
77
+    toggleSelection(device) {
78
+      const index = this.tempSelected.indexOf(device.deviceId);
79
+      if (index === -1) {
80
+        this.tempSelected.push(device.deviceId);
81
+      } else {
82
+        this.tempSelected.splice(index, 1);
83
+      }
84
+    },
85
+    close() {
86
+      this.$emit('update:visible', false);
87
+    },
88
+    confirm() {
89
+      this.$emit('update:selectedDevices', this.tempSelected);
90
+      this.close();
91
+    }
92
+  }
93
+}
94
+</script>
95
+
96
+<style lang="scss" scoped>
97
+.popup-content {
98
+  width: 600rpx;
99
+  background: #fff;
100
+  border-radius: 12rpx;
101
+  overflow: hidden;
102
+}
103
+
104
+.popup-header {
105
+  padding: 20rpx;
106
+  display: flex;
107
+  justify-content: space-between;
108
+  align-items: center;
109
+  border-bottom: 1rpx solid #eee;
110
+  
111
+  .title {
112
+    font-size: 32rpx;
113
+    font-weight: bold;
114
+  }
115
+}
116
+
117
+.popup-body {
118
+  max-height: 600rpx;
119
+  overflow-y: auto;
120
+  padding: 20rpx;
121
+}
122
+
123
+.device-list {
124
+  .device-item {
125
+    display: flex;
126
+    justify-content: space-between;
127
+    align-items: center;
128
+    padding: 20rpx;
129
+    border-bottom: 1rpx solid #eee;
130
+    
131
+    &:last-child {
132
+      border-bottom: none;
133
+    }
134
+    
135
+    &.selected {
136
+      background-color: rgba(103, 194, 58, 0.05);
137
+    }
138
+    
139
+    .device-info {
140
+      flex: 1;
141
+      
142
+      .device-name {
143
+        font-size: 28rpx;
144
+        color: #333;
145
+        display: block;
146
+        margin-bottom: 8rpx;
147
+      }
148
+      
149
+      .device-code {
150
+        font-size: 24rpx;
151
+        color: #666;
152
+      }
153
+    }
154
+  }
155
+}
156
+
157
+.popup-footer {
158
+  padding: 20rpx;
159
+  display: flex;
160
+  justify-content: flex-end;
161
+  gap: 20rpx;
162
+  border-top: 1rpx solid #eee;
163
+}
164
+</style> 

+ 6
- 4
oa-ui-app/pages/components/flowNote.vue 查看文件

@@ -6,10 +6,12 @@
6 6
 -->
7 7
 <template>
8 8
   <view>
9
-    <uv-steps :current="currentNum">
10
-      <uv-steps-item :error="item.comment && item.comment.type == '退回意见'" v-for="item, index in flowRecordList"
11
-        :key="'f' + index" :title="item.taskName" :desc="item.finishTime"></uv-steps-item>
12
-    </uv-steps>
9
+    <scroll-view scroll-x="true">
10
+      <uv-steps :current="currentNum">
11
+        <uv-steps-item :error="item.comment && item.comment.type == '退回意见'" v-for="item, index in flowRecordList"
12
+          :key="'f' + index" :title="item.taskName" :desc="item.finishTime"></uv-steps-item>
13
+      </uv-steps>
14
+    </scroll-view>
13 15
     <view class="custom-block danger" v-if="isRetrun">
14 16
       <uni-title type="h3" title="任务被退回,请修改后重新提交" color="#900"></uni-title>
15 17
       <view>

+ 648
- 147
oa-ui-app/pages/form/device/device.vue 查看文件

@@ -31,41 +31,60 @@
31 31
       </uni-forms-item>
32 32
 
33 33
       <!-- 设备选择 -->
34
-      <uni-forms-item label="选择设备" required class="form-item" name="devices">
34
+      <uni-forms-item label="申请设备" required class="form-item" name="devices"
35
+        v-if="taskName != '安排设备' && taskName != '归还确认'">
35 36
         <uv-button type="primary" @click="openDevice = true" v-if="taskName == '设备申请'">+ 选择设备</uv-button>
36
-        <device-picker :visible.sync="openDevice" :selected.sync="selectDevice"
37
+        <device-picker :visible.sync="openDevice" :selected.sync="selectDevice" :multiple="!isReplaceMode"
37 38
           @confirm="handleDeviceConfirm"></device-picker>
38
-        <uni-table v-if="deviceList.length > 0">
39
-          <uni-tr>
40
-            <uni-th>序号</uni-th>
41
-            <uni-th>出厂编号</uni-th>
42
-            <uni-th>设备品牌</uni-th>
43
-            <uni-th>设备名称</uni-th>
44
-            <uni-th>规格型号</uni-th>
45
-            <uni-th>存放地址</uni-th>
46
-          </uni-tr>
47
-          <uni-tr v-for="(item, index) in deviceList" :key="index">
48
-            <uni-td>{{ index + 1 }}</uni-td>
49
-            <uni-td>{{ item.code }}</uni-td>
50
-            <uni-td>{{ item.brand }}</uni-td>
51
-            <uni-td>{{ item.name }}</uni-td>
52
-            <uni-td>{{ item.series }}</uni-td>
53
-            <uni-td>{{ item.place }}</uni-td>
54
-          </uni-tr>
55
-        </uni-table>
39
+        <view class="device-cards" v-if="deviceList.length > 0">
40
+          <view class="device-card" v-for="(item, index) in deviceList" :key="index">
41
+            <view class="card-header">
42
+              <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
43
+            </view>
44
+            <view class="card-content">
45
+              <view class="card-row">
46
+                <view class="card-item">
47
+                  <text class="label">设备名称:</text>
48
+                  <text class="value">{{ item.name }}</text>
49
+                </view>
50
+              </view>
51
+              <view class="card-row">
52
+                <view class="card-item">
53
+                  <text class="label">设备品牌:</text>
54
+                  <text class="value">{{ item.brand }}</text>
55
+                </view>
56
+                <view class="card-item">
57
+                  <text class="label">存放地址:</text>
58
+                  <text class="value">{{ item.place }}</text>
59
+                </view>
60
+              </view>
61
+              <view class="card-row">
62
+                <view class="card-item">
63
+                  <text class="label">规格型号:</text>
64
+                  <text class="value">{{ item.series }}</text>
65
+                </view>
66
+              </view>
67
+            </view>
68
+          </view>
69
+        </view>
56 70
       </uni-forms-item>
57 71
 
58 72
       <!-- 申领事由 -->
59 73
       <uni-forms-item label="申领事由" required class="form-item" name="applyReason">
60
-        <uni-easyinput type="textarea" v-model="form.applyReason" placeholder="请输入申领事由"
61
-          :disabled="taskName != '设备申请'" />
74
+        <uv-textarea v-model="form.applyReason" placeholder="请输入申领事由" :disabled="taskName != '设备申请'"></uv-textarea>
62 75
       </uni-forms-item>
63 76
 
64 77
       <!-- 日期选择 -->
65 78
       <view class="date-range">
66 79
         <uni-forms-item label="使用日期" required class="form-item" name="dateRange">
67
-          <uni-datetime-picker v-model="dateRange" type="daterange" rangeSeparator="至" :clearIcon="false"
68
-            :disabled="taskName != '设备申请'" @change="handleDateRangeChange" />
80
+          <uni-datetime-picker v-model="form.dateRange" type="daterange" rangeSeparator="至" :clearIcon="false"
81
+            v-if="taskName == '设备申请'" @change="handleDateRangeChange" />
82
+          <view class="date-display" v-else>
83
+            <uni-icons type="calendar" size="16"></uni-icons>
84
+            <text class="date-text">{{ form.beginDate }}</text>
85
+            <text class="date-separator">至</text>
86
+            <text class="date-text">{{ form.endDate }}</text>
87
+          </view>
69 88
         </uni-forms-item>
70 89
         <uni-forms-item label="共计" class="form-item">
71 90
           <text>{{ form.days + '天' }}</text>
@@ -73,88 +92,159 @@
73 92
       </view>
74 93
 
75 94
       <!-- 安排设备意见 -->
76
-      <uni-forms-item label="拟发放设备" class="form-item" v-if="taskName == '安排设备'">
77
-        <uni-table v-if="modifyDeviceList.length > 0">
78
-          <uni-tr>
79
-            <uni-th>序号</uni-th>
80
-            <uni-th>出厂编号</uni-th>
81
-            <uni-th>设备品牌</uni-th>
82
-            <uni-th>设备名称</uni-th>
83
-            <uni-th>规格型号</uni-th>
84
-            <uni-th>存放地址</uni-th>
85
-            <uni-th>操作</uni-th>
86
-          </uni-tr>
87
-          <uni-tr v-for="(item, index) in modifyDeviceList" :key="index">
88
-            <uni-td>{{ index + 1 }}</uni-td>
89
-            <uni-td>{{ item.code }}</uni-td>
90
-            <uni-td>{{ item.brand }}</uni-td>
91
-            <uni-td>{{ item.name }}</uni-td>
92
-            <uni-td>{{ item.series }}</uni-td>
93
-            <uni-td>{{ item.place }}</uni-td>
94
-            <uni-td>
95
+      <uni-forms-item label="拟发放设备" required class="form-item" v-if="taskName != '设备申请' && taskName != '归还确认'">
96
+        <view class="device-cards" v-if="modifyDeviceList.length > 0">
97
+          <view class="device-card" v-for="(item, index) in modifyDeviceList" :key="index">
98
+            <view class="card-header">
99
+              <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
100
+            </view>
101
+            <view class="card-content">
102
+              <view class="card-row">
103
+                <view class="card-item">
104
+                  <text class="label">设备名称:</text>
105
+                  <text class="value">{{ item.name }}</text>
106
+                </view>
107
+              </view>
108
+              <view class="card-row">
109
+                <view class="card-item">
110
+                  <text class="label">设备品牌:</text>
111
+                  <text class="value">{{ item.brand }}</text>
112
+                </view>
113
+                <view class="card-item">
114
+                  <text class="label">存放地址:</text>
115
+                  <text class="value">{{ item.place }}</text>
116
+                </view>
117
+              </view>
118
+              <view class="card-row">
119
+                <view class="card-item">
120
+                  <text class="label">规格型号:</text>
121
+                  <text class="value">{{ item.series }}</text>
122
+                </view>
123
+              </view>
124
+            </view>
125
+            <view class="card-actions" v-if="taskName == '安排设备'">
95 126
               <uv-button type="primary" size="mini" @click="replaceRowData(item, index)">重新选择</uv-button>
96 127
               <uv-button type="error" size="mini" @click="deleteRowData(item, index)">删除</uv-button>
97
-            </uni-td>
98
-          </uni-tr>
99
-        </uni-table>
128
+            </view>
129
+          </view>
130
+        </view>
100 131
         <uv-button type="primary" @click="addRowdata()" v-if="taskName == '安排设备'">新增设备</uv-button>
101 132
       </uni-forms-item>
102 133
 
103 134
       <!-- 安排设备意见 -->
104
-      <uni-forms-item label="安排设备意见" class="form-item" v-if="taskName == '安排设备'">
105
-        <uni-easyinput type="textarea" v-model="form.dispatchComment" placeholder="请输入安排设备意见"
106
-          :disabled="taskName != '安排设备'" />
135
+      <uni-forms-item label="安排设备意见" required class="form-item" name="dispatchComment" v-if="taskName != '设备申请'">
136
+        <uv-textarea v-model="form.dispatchComment" placeholder="请输入安排设备意见"
137
+          :disabled="taskName != '安排设备'"></uv-textarea>
138
+        <auditor :name="form.dispatcher ? form.dispatchUser.nickName : ''" :time="form.dispatchTime"></auditor>
107 139
       </uni-forms-item>
108 140
 
109 141
       <!-- 分管审核意见 -->
110
-      <uni-forms-item label="分管审核意见" class="form-item" v-if="taskName == '分管审核'">
111
-        <uni-easyinput type="textarea" v-model="form.managerComment" placeholder="请输入分管审核意见"
112
-          :disabled="taskName != '分管审核'" />
142
+      <uni-forms-item label="分管审核意见" required name="managerComment" class="form-item"
143
+        v-if="taskName != '设备申请' && taskName != '安排设备'">
144
+        <uv-textarea v-model="form.managerComment" placeholder="请输入分管审核意见" :disabled="taskName != '分管审核'"></uv-textarea>
145
+        <auditor :name="form.managerUser ? form.managerUser.nickName : ''" :time="form.managerTime"></auditor>
113 146
       </uni-forms-item>
114 147
 
115 148
       <!-- 归还确认 -->
116
-      <uni-forms-item label="已归还设备" class="form-item" v-if="taskName == '归还确认'">
117
-        <uni-table v-if="returnDevicesList.length > 0">
118
-          <uni-tr>
119
-            <uni-th>序号</uni-th>
120
-            <uni-th>出厂编号</uni-th>
121
-            <uni-th>设备品牌</uni-th>
122
-            <uni-th>设备名称</uni-th>
123
-            <uni-th>规格型号</uni-th>
124
-            <uni-th>存放地址</uni-th>
125
-          </uni-tr>
126
-          <uni-tr v-for="(item, index) in returnDevicesList" :key="index">
127
-            <uni-td>{{ index + 1 }}</uni-td>
128
-            <uni-td>{{ item.code }}</uni-td>
129
-            <uni-td>{{ item.brand }}</uni-td>
130
-            <uni-td>{{ item.name }}</uni-td>
131
-            <uni-td>{{ item.series }}</uni-td>
132
-            <uni-td>{{ item.place }}</uni-td>
133
-          </uni-tr>
134
-        </uni-table>
149
+      <uni-forms-item label="已归还设备" required class="form-item" v-if="taskName == '' || taskName == '归还确认'">
150
+        <text style="color: #a69494;" v-if="taskName == '归还确认'">Tips:请点击卡片,切换归还状态</text>
151
+        <view class="device-cards" v-if="returnDevicesList.length > 0">
152
+          <view class="device-card" v-for="(item, index) in returnDevicesList" :key="index"
153
+            :class="{ 'selected': isDeviceSelected(item.deviceId) }" @click="toggleDeviceSelection(item)">
154
+            <view class="card-header">
155
+              <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
156
+              <view class="return-tag" v-if="isDeviceSelected(item.deviceId)">
157
+                <uni-tag type="success" text="已归还" size="small"></uni-tag>
158
+              </view>
159
+            </view>
160
+            <view class="card-content">
161
+              <view class="card-row">
162
+                <view class="card-item">
163
+                  <text class="label">设备名称:</text>
164
+                  <text class="value">{{ item.name }}</text>
165
+                </view>
166
+              </view>
167
+              <view class="card-row">
168
+                <view class="card-item">
169
+                  <text class="label">设备品牌:</text>
170
+                  <text class="value">{{ item.brand }}</text>
171
+                </view>
172
+                <view class="card-item">
173
+                  <text class="label">存放地址:</text>
174
+                  <text class="value">{{ item.place }}</text>
175
+                </view>
176
+              </view>
177
+              <view class="card-row">
178
+                <view class="card-item">
179
+                  <text class="label">规格型号:</text>
180
+                  <text class="value">{{ item.series }}</text>
181
+                </view>
182
+              </view>
183
+            </view>
184
+          </view>
185
+        </view>
135 186
       </uni-forms-item>
136 187
 
137 188
       <!-- 需维修设备 -->
138
-      <uni-forms-item label="需维修设备" class="form-item" v-if="taskName == '归还确认'">
139
-        <uni-data-select v-model="form.repairDevices" :localdata="modifyDeviceList" multiple
140
-          :disabled="taskName != '归还确认'" />
189
+      <uni-forms-item label="需维修设备" class="form-item" v-if="taskName == '' || taskName == '归还确认'">
190
+        <uv-button type="primary" @click="openRepairDevice = true" v-if="taskName == '归还确认'">+ 选择需维修设备</uv-button>
191
+        <repair-device-picker :visible.sync="openRepairDevice" :deviceList="modifyDeviceList"
192
+          :selectedDevices.sync="form.repairDevices"></repair-device-picker>
193
+        <view class="device-cards" v-if="repairDevicesList.length > 0">
194
+          <view class="device-card repair-card" v-for="(item, index) in repairDevicesList" :key="index">
195
+            <view class="card-header">
196
+              <text class="card-title">{{ index + 1 }}. 出厂编号:{{ item.code }}</text>
197
+              <view class="repair-tag">
198
+                <uni-tag type="error" text="需维修" size="small"></uni-tag>
199
+              </view>
200
+            </view>
201
+            <view class="card-content">
202
+              <view class="card-row">
203
+                <view class="card-item">
204
+                  <text class="label">设备名称:</text>
205
+                  <text class="value">{{ item.name }}</text>
206
+                </view>
207
+              </view>
208
+              <view class="card-row">
209
+                <view class="card-item">
210
+                  <text class="label">设备品牌:</text>
211
+                  <text class="value">{{ item.brand }}</text>
212
+                </view>
213
+                <view class="card-item">
214
+                  <text class="label">存放地址:</text>
215
+                  <text class="value">{{ item.place }}</text>
216
+                </view>
217
+              </view>
218
+              <view class="card-row">
219
+                <view class="card-item">
220
+                  <text class="label">规格型号:</text>
221
+                  <text class="value">{{ item.series }}</text>
222
+                </view>
223
+              </view>
224
+            </view>
225
+          </view>
226
+        </view>
227
+        <view v-else>
228
+          <uni-tag type="success" text="没有需维修的设备" size="small"></uni-tag>
229
+        </view>
141 230
       </uni-forms-item>
142 231
 
143 232
       <!-- 备注 -->
144
-      <uni-forms-item label="备注" class="form-item" v-if="taskName == '归还确认'">
145
-        <uni-easyinput type="textarea" v-model="form.remark" placeholder="请输入备注" :disabled="taskName != '归还确认'" />
233
+      <uni-forms-item label="备注" class="form-item" v-if="taskName == '' || taskName == '归还确认'">
234
+        <uv-textarea v-model="form.remark" placeholder="请输入备注" :disabled="taskName != '归还确认'"></uv-textarea>
146 235
       </uni-forms-item>
147 236
 
148 237
       <!-- 归还日期 -->
149
-      <uni-forms-item label="归还日期" class="form-item" v-if="taskName == '归还确认'">
238
+      <uni-forms-item label="归还日期" required name="returnDate" class="form-item"
239
+        v-if="taskName == '' || taskName == '归还确认'">
150 240
         <uni-datetime-picker v-model="form.returnDate" type="date" :disabled="taskName != '归还确认'" />
151 241
       </uni-forms-item>
152 242
 
153 243
       <!-- 操作按钮 -->
154
-      <view class="form-actions">
155
-        <uv-button style="margin-bottom: 5px;" type="warning" @click="saves">保存</uv-button>
244
+      <view class="form-actions" v-if="taskName">
156 245
         <uv-button type="primary" @click="submit" v-if="taskName == '设备申请'">提交申请</uv-button>
157 246
         <template v-else>
247
+          <uv-button style="margin-bottom: 5px;" type="warning" @click="saves">保存</uv-button>
158 248
           <uv-button type="primary" @click="completeApply">完成审批</uv-button>
159 249
         </template>
160 250
       </view>
@@ -164,18 +254,27 @@
164 254
 
165 255
 <script>
166 256
 import { parseTime } from "@/utils/common.js"
167
-import { listDeviceApproval, getDeviceApproval, updateDeviceApproval, submitDeviceApproval, modifyDeviceApproval } from '@/api/oa/device/deviceApproval'
257
+import { getDeviceApproval, submitDeviceApproval, modifyDeviceApproval } from '@/api/oa/device/deviceApproval'
258
+import { complete, getNextFlowNode } from "@/api/flowable/todo";
259
+import { getProject } from "@/api/oa/project/project";
260
+import { getDevice } from "@/api/oa/device/device";
261
+import { getUserByRole } from "@/api/system/role";
262
+import { getUsersManageLeader } from '@/api/system/post.js'
168 263
 import FlowNote from '@/pages/components/flowNote.vue';
169 264
 import ProjectPicker from '@/pages/components/ProjectPicker.vue';
170 265
 import ProjectInfo from '@/pages/components/ProjectInfo.vue';
171 266
 import DevicePicker from "@/pages/components/DevicePicker.vue";
267
+import Auditor from "@/pages/components/auditor.vue";
268
+import RepairDevicePicker from "@/pages/components/RepairDevicePicker.vue";
172 269
 
173 270
 export default {
174 271
   components: {
175 272
     FlowNote,
176 273
     ProjectPicker,
177 274
     ProjectInfo,
178
-    DevicePicker
275
+    DevicePicker,
276
+    Auditor,
277
+    RepairDevicePicker
179 278
   },
180 279
   props: {
181 280
     taskForm: Object,
@@ -200,15 +299,17 @@ export default {
200 299
         applyReason: '',
201 300
         beginDate: '',
202 301
         endDate: '',
302
+        dateRange: [],
203 303
         days: 0,
204 304
         dispatchComment: '',
205 305
         managerComment: '',
206 306
         devices: [],
307
+        modifyDevices: [],
308
+        returnDevices: [],
207 309
         repairDevices: [],
208 310
         remark: '',
209 311
         returnDate: ''
210 312
       },
211
-      dateRange: [],
212 313
       rules: {
213 314
         projectId: {
214 315
           rules: [{ required: true, errorMessage: '请选择项目' }]
@@ -220,7 +321,56 @@ export default {
220 321
           rules: [{ required: true, errorMessage: '请输入申领事由' }]
221 322
         },
222 323
         dateRange: {
223
-          rules: [{ required: true, errorMessage: '请选择使用日期' }]
324
+          rules: [{
325
+            required: this.taskName === '设备申请',
326
+            errorMessage: '请选择使用日期',
327
+            validateFunction: (rule, value, data, callback) => {
328
+              if (!value || value.length !== 2 || !value[0] || !value[1]) {
329
+                callback('请选择使用日期');
330
+              } else {
331
+                callback();
332
+              }
333
+            }
334
+          }]
335
+        },
336
+        dispatchComment: {
337
+          rules: [{
338
+            required: true,
339
+            errorMessage: '请输入安排设备意见',
340
+            validateFunction: (rule, value, data, callback) => {
341
+              if (this.taskName === '安排设备' && !value) {
342
+                callback('请输入安排设备意见');
343
+              } else {
344
+                callback();
345
+              }
346
+            }
347
+          }]
348
+        },
349
+        managerComment: {
350
+          rules: [{
351
+            required: true,
352
+            errorMessage: '请输入分管审核意见',
353
+            validateFunction: (rule, value, data, callback) => {
354
+              if (this.taskName === '分管审核' && !value) {
355
+                callback('请输入分管审核意见');
356
+              } else {
357
+                callback();
358
+              }
359
+            }
360
+          }]
361
+        },
362
+        returnDate: {
363
+          rules: [{
364
+            required: true,
365
+            errorMessage: '请选择归还日期',
366
+            validateFunction: (rule, value, data, callback) => {
367
+              if (this.taskName === '归还确认' && !value) {
368
+                callback('请选择归还日期');
369
+              } else {
370
+                callback();
371
+              }
372
+            }
373
+          }]
224 374
         }
225 375
       },
226 376
       applierUserName: '',
@@ -232,20 +382,119 @@ export default {
232 382
       deviceList: [],
233 383
       modifyDeviceList: [],
234 384
       returnDevicesList: [],
235
-      formTotal: 0
385
+      formTotal: 0,
386
+      currentIndex: -1,
387
+      isReplaceMode: false,
388
+      openRepairDevice: false,
389
+      repairDevicesList: []
236 390
     };
237 391
   },
392
+  watch: {
393
+    'form.repairDevices': {
394
+      handler(newVal) {
395
+        this.updateRepairDevicesList();
396
+      },
397
+      immediate: true
398
+    }
399
+  },
238 400
   methods: {
239
-    initForm() {
240
-      getDeviceApproval(this.taskForm.formId).then(res => {
401
+    async initForm() {
402
+      try {
403
+        const res = await getDeviceApproval(this.taskForm.formId);
241 404
         if (res.data) {
242 405
           this.formTotal = 1;
243 406
           this.form = res.data;
244
-          this.deviceList = res.data.devices || [];
245
-          this.modifyDeviceList = res.data.modifyDevices || [];
246
-          this.returnDevicesList = res.data.returnDevices || [];
407
+          this.applierUserName = res.data.applierUser.nickName;
408
+          const project = await getProject(res.data.projectId);
409
+          this.projectObj = project.data;
410
+          // 初始化申请设备
411
+          if (res.data.devices) {
412
+            const deviceIds = res.data.devices.split(',').map(id => parseInt(id));
413
+            this.form.devices = res.data.devices.split(',');
414
+            this.deviceList = [];
415
+            this.selectDevice = [];
416
+
417
+            for (const id of deviceIds) {
418
+              const response = await getDevice(id);
419
+              if (response.data) {
420
+                this.deviceList.push(response.data);
421
+                this.selectDevice.push(response.data);
422
+              }
423
+            }
424
+          } else {
425
+            this.deviceList = [];
426
+          }
427
+
428
+          // 初始化拟发放设备列表
429
+          if (res.data.modifyDevices) {
430
+            const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
431
+              ? res.data.modifyDevices.split(',').map(id => parseInt(id))
432
+              : Array.isArray(res.data.modifyDevices)
433
+                ? res.data.modifyDevices.map(id => parseInt(id))
434
+                : [];
435
+            this.form.modifyDevices = res.data.modifyDevices.split(',');
436
+            this.modifyDeviceList = [];
437
+
438
+            for (const id of modifyDeviceIds) {
439
+              const response = await getDevice(id);
440
+              if (response.data) {
441
+                this.modifyDeviceList.push(response.data);
442
+              }
443
+            }
444
+          } else if (this.taskName === '安排设备') {
445
+            this.modifyDeviceList = [...this.deviceList];
446
+          } else {
447
+            this.modifyDeviceList = [];
448
+          }
449
+
450
+          // 初始化归还设备列表
451
+          if (res.data.returnDevices) {
452
+            const returnDeviceIds = typeof res.data.returnDevices === 'string'
453
+              ? res.data.returnDevices.split(',').map(id => parseInt(id))
454
+              : Array.isArray(res.data.returnDevices)
455
+                ? res.data.returnDevices.map(id => parseInt(id))
456
+                : [];
457
+            this.form.returnDevices = returnDeviceIds;
458
+
459
+            // 获取所有拟发放的设备
460
+            const modifyDeviceIds = typeof res.data.modifyDevices === 'string'
461
+              ? res.data.modifyDevices.split(',').map(id => parseInt(id))
462
+              : Array.isArray(res.data.modifyDevices)
463
+                ? res.data.modifyDevices.map(id => parseInt(id))
464
+                : [];
465
+
466
+            this.returnDevicesList = [];
467
+            for (const id of modifyDeviceIds) {
468
+              const response = await getDevice(id);
469
+              if (response.data) {
470
+                this.returnDevicesList.push(response.data);
471
+              }
472
+            }
473
+          } else if (this.taskName === '归还确认') {
474
+            // 在归还确认节点,使用拟发放的设备列表
475
+            this.returnDevicesList = [...this.modifyDeviceList];
476
+            this.form.returnDevices = []; // 初始化空数组
477
+          } else {
478
+            this.returnDevicesList = [];
479
+            this.form.returnDevices = []; // 初始化空数组
480
+          }
481
+
482
+          // 初始化维修设备列表
483
+          if (res.data.repairDevices) {
484
+            const repairDeviceIds = typeof res.data.repairDevices === 'string'
485
+              ? res.data.repairDevices.split(',').map(id => parseInt(id))
486
+              : Array.isArray(res.data.repairDevices)
487
+                ? res.data.repairDevices.map(id => parseInt(id))
488
+                : [];
489
+            this.form.repairDevices = repairDeviceIds;
490
+            this.updateRepairDevicesList();
491
+          } else if (this.taskName === '归还确认') {
492
+            this.form.repairDevices = [];
493
+            this.repairDevicesList = [];
494
+          }
495
+
247 496
           if (this.form.beginDate && this.form.endDate) {
248
-            this.dateRange = [this.form.beginDate, this.form.endDate];
497
+            this.form.dateRange = [this.form.beginDate, this.form.endDate];
249 498
           }
250 499
         } else {
251 500
           this.form.applier = this.$store.getters.userId;
@@ -254,8 +503,16 @@ export default {
254 503
           this.form.user.nickName = name[0];
255 504
           this.form.dept.deptName = name[1];
256 505
           this.formTotal = 0;
506
+          this.form.returnDevices = []; // 初始化空数组
507
+          this.form.repairDevices = []; // 初始化空数组
257 508
         }
258
-      });
509
+      } catch (error) {
510
+        console.error('初始化表单失败:', error);
511
+        uni.showToast({
512
+          title: '初始化表单失败',
513
+          icon: 'error'
514
+        });
515
+      }
259 516
     },
260 517
     handleConfirm(project) {
261 518
       this.selectedProject = project;
@@ -263,14 +520,27 @@ export default {
263 520
       this.form.projectId = project.projectId;
264 521
     },
265 522
     handleDeviceConfirm(devices) {
266
-      this.deviceList = Array.isArray(devices) ? devices : [devices];
267
-      this.form.devices = this.deviceList.map(item => item.deviceId);
523
+      if (this.taskName === '安排设备') {
524
+        if (this.currentIndex >= 0) {
525
+          // 替换指定位置的设备,确保只使用第一个选中的设备
526
+          const selectedDevice = Array.isArray(devices) ? devices[0] : devices;
527
+          this.modifyDeviceList.splice(this.currentIndex, 1, selectedDevice);
528
+        } else {
529
+          // 新增设备
530
+          this.modifyDeviceList.push(...devices);
531
+        }
532
+        this.isReplaceMode = false;
533
+      } else {
534
+        this.deviceList = Array.isArray(devices) ? devices : [devices];
535
+        this.form.devices = this.deviceList.map(item => item.deviceId);
536
+      }
268 537
     },
269 538
     handleDateRangeChange(e) {
270 539
       if (Array.isArray(e) && e.length === 2) {
271 540
         const [start, end] = e;
272 541
         this.form.beginDate = start;
273 542
         this.form.endDate = end;
543
+        this.form.dateRange = [start, end];
274 544
         this.calculateDay();
275 545
       }
276 546
     },
@@ -286,62 +556,70 @@ export default {
286 556
     replaceRowData(row, index) {
287 557
       this.openDevice = true;
288 558
       this.currentIndex = index;
559
+      this.isReplaceMode = true;
560
+      // 在安排设备节点时,设置当前选中的设备
561
+      if (this.taskName === '安排设备') {
562
+        this.selectDevice = [row];
563
+      }
289 564
     },
290 565
     deleteRowData(row, index) {
291
-      this.modifyDeviceList.splice(index, 1);
566
+      uni.showModal({
567
+        title: '确认删除',
568
+        content: '确定要删除该设备吗?',
569
+        success: (res) => {
570
+          if (res.confirm) {
571
+            this.modifyDeviceList.splice(index, 1);
572
+          }
573
+        }
574
+      });
292 575
     },
293 576
     addRowdata() {
294 577
       this.openDevice = true;
295 578
       this.currentIndex = -1;
579
+      this.isReplaceMode = false;
580
+      // 在安排设备节点时,清空已选设备
581
+      if (this.taskName === '安排设备') {
582
+        this.selectDevice = [];
583
+      }
296 584
     },
297 585
     submit() {
298 586
       this.$refs.form.validate().then(() => {
299
-        submitDeviceApproval(this.form).then(res => {
300
-          uni.showToast({
301
-            title: '提交成功',
302
-            icon: 'success'
303
-          });
304
-          uni.navigateBack();
305
-        });
306
-      });
307
-    },
308
-    saves() {
309
-      try {
310
-        // 构建提交数据
311 587
         let submitData = {
312 588
           ...this.form,
313
-          formId: this.taskForm.formId,
314
-          deviceApplyId: this.taskForm.formId,
589
+          ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
590
+          ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
315 591
         };
316
-        let formData = new FormData();
317 592
         let jsonForm = JSON.stringify(submitData);
318
-        formData.append("form", jsonForm);
319
-        console.log(formData.get('form'));
320
-        // 根据表单状态选择接口
321
-        if (this.formTotal !== 0) {
322
-          modifyDeviceApproval(formData).then(res => {
323
-            console.log('修改响应:', res);
324
-            if (res.code === 200) {
325
-              uni.showToast({
326
-                title: '保存成功',
327
-                icon: 'success'
328
-              });
329
-            } else {
330
-              uni.showToast({
331
-                title: res.msg || '保存失败',
332
-                icon: 'error'
333
-              });
334
-            }
335
-          }).catch(error => {
336
-            console.error('修改错误:', error);
593
+        submitDeviceApproval(jsonForm).then(res => {
594
+          // 获取下一个流程节点
595
+          this.getNextFlowNodeApproval().then(() => {
337 596
             uni.showToast({
338
-              title: error.message || '保存失败',
339
-              icon: 'error'
597
+              title: '提交成功',
598
+              icon: 'success'
340 599
             });
341
-          });
342
-        } else {
343
-          submitDeviceApproval(formData).then(res => {
344
-            console.log('提交响应:', res);
600
+            setTimeout(() => {
601
+              uni.switchTab({
602
+                url: '/pages/message/index'
603
+              })
604
+            }, 500);
605
+          })
606
+        });
607
+      });
608
+    },
609
+    saves() {
610
+      try {
611
+        this.$refs.form.validate().then(() => {
612
+          let submitData = {
613
+            ...this.form,
614
+            ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
615
+            ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
616
+          };
617
+          // 在安排设备节点时,添加拟发放设备列表
618
+          if (this.taskName === '安排设备') {
619
+            submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
620
+          }
621
+          let jsonForm = JSON.stringify(submitData);
622
+          modifyDeviceApproval(jsonForm).then(res => {
345 623
             if (res.code === 200) {
346 624
               uni.showToast({
347 625
                 title: '保存成功',
@@ -353,14 +631,8 @@ export default {
353 631
                 icon: 'error'
354 632
               });
355 633
             }
356
-          }).catch(error => {
357
-            console.error('提交错误:', error);
358
-            uni.showToast({
359
-              title: error.message || '保存失败',
360
-              icon: 'error'
361
-            });
362
-          });
363
-        }
634
+          })
635
+        })
364 636
       } catch (error) {
365 637
         console.error('保存方法错误:', error);
366 638
         uni.showToast({
@@ -370,13 +642,122 @@ export default {
370 642
       }
371 643
     },
372 644
     completeApply() {
373
-      modifyDeviceApproval(this.form).then(res => {
374
-        uni.showToast({
375
-          title: '审批完成',
376
-          icon: 'success'
645
+      this.$refs.form.validate().then(() => {
646
+        // 在归还确认节点时,检查所有设备是否都已归还
647
+        if (this.taskName === '归还确认') {
648
+          const allDevices = this.modifyDeviceList.map(item => item.deviceId);
649
+          const returnedDevices = this.form.returnDevices || [];
650
+          const unreturnedDevices = allDevices.filter(id => !returnedDevices.includes(id));
651
+
652
+          if (unreturnedDevices.length > 0) {
653
+            uni.showToast({
654
+              title: '请确认所有设备都已归还',
655
+              icon: 'none'
656
+            });
657
+            return;
658
+          }
659
+        }
660
+
661
+        uni.showModal({
662
+          title: '提示',
663
+          content: '确定提交审批吗?',
664
+          success: (res) => {
665
+            if (res.confirm) {
666
+              let submitData = {
667
+                ...this.form,
668
+                ...(this.form.formId ? {} : { formId: this.taskForm.formId }),
669
+                ...(this.form.deviceApplyId ? {} : { deviceApplyId: this.taskForm.formId })
670
+              };
671
+              // 在安排设备节点时,添加拟发放设备列表
672
+              if (this.taskName === '安排设备') {
673
+                submitData.modifyDevices = this.modifyDeviceList.map(item => item.deviceId);
674
+              }
675
+              let jsonForm = JSON.stringify(submitData);
676
+              modifyDeviceApproval(jsonForm).then(res => {
677
+                // 获取下一个流程节点
678
+                getNextFlowNode({ taskId: this.taskForm.taskId }).then(res => {
679
+                  this.getNextFlowNodeApproval().then(() => {
680
+                    uni.showToast({
681
+                      title: '提交成功',
682
+                      icon: 'success'
683
+                    });
684
+                    setTimeout(() => {
685
+                      uni.switchTab({
686
+                        url: '/pages/message/index'
687
+                      });
688
+                    }, 500);
689
+                  });
690
+                });
691
+              });
692
+            }
693
+          }
377 694
         });
378
-        uni.navigateBack();
379 695
       });
696
+    },
697
+    // 获取下一个审批人
698
+    getNextFlowNodeApproval() {
699
+      return new Promise((resolve, reject) => {
700
+        const handleComplete = (response) => {
701
+          this.$modal.msgSuccess(response.msg);
702
+          resolve();
703
+        };
704
+
705
+        const setApprovalAndComplete = (result) => {
706
+          this.$set(this.taskForm.variables, "approval", result.data[0]);
707
+          complete(this.taskForm).then(handleComplete).catch(reject);
708
+        };
709
+
710
+        switch (this.taskName) {
711
+          case '设备申请':
712
+          case '分管审核':
713
+            getUserByRole({ roleId: 4 }).then(setApprovalAndComplete).catch(reject);
714
+            break;
715
+
716
+          case '安排设备':
717
+            getUsersManageLeader({ userId: this.form.applier }).then(res => {
718
+              const userIds = res.data.map(user => user.userId);
719
+              this.$set(this.taskForm.variables, "approvalList", userIds);
720
+              complete(this.taskForm).then(handleComplete).catch(reject);
721
+            }).catch(reject);
722
+            break;
723
+
724
+          case '归还确认':
725
+            this.$modal.confirm('最后一个节点,提交将结束流程,是否提交?')
726
+              .then(() => complete(this.taskForm).then(handleComplete).catch(reject))
727
+              .catch(reject);
728
+            break;
729
+        }
730
+      });
731
+    },
732
+    isDeviceSelected(deviceId) {
733
+      return this.form.returnDevices && this.form.returnDevices.includes(deviceId);
734
+    },
735
+    toggleDeviceSelection(device) {
736
+      if (this.taskName !== '归还确认') return;
737
+      // 确保 returnDevices 是数组
738
+      if (!Array.isArray(this.form.returnDevices)) {
739
+        this.form.returnDevices = [];
740
+      }
741
+      const index = this.form.returnDevices.indexOf(device.deviceId);
742
+      if (index === -1) {
743
+        // 添加设备到已归还列表
744
+        this.form.returnDevices.push(device.deviceId);
745
+      } else {
746
+        // 从已归还列表中移除设备
747
+        this.form.returnDevices.splice(index, 1);
748
+      }
749
+    },
750
+    updateRepairDevicesList() {
751
+      // 如果 repairDevices 是字符串,转换为数组
752
+      if (typeof this.form.repairDevices === 'string') {
753
+        this.form.repairDevices = this.form.repairDevices.split(',').map(id => parseInt(id));
754
+      } else if (!Array.isArray(this.form.repairDevices)) {
755
+        this.form.repairDevices = [];
756
+      }
757
+
758
+      this.repairDevicesList = this.modifyDeviceList.filter(device =>
759
+        this.form.repairDevices.includes(device.deviceId)
760
+      );
380 761
     }
381 762
   }
382 763
 }
@@ -409,6 +790,11 @@ export default {
409 790
   gap: 32rpx;
410 791
 }
411 792
 
793
+.date-text {
794
+  margin: 0 10px;
795
+  font-weight: bold;
796
+}
797
+
412 798
 .form-actions {
413 799
   justify-content: center;
414 800
   gap: 32rpx;
@@ -418,4 +804,119 @@ export default {
418 804
 ::v-deep .uni-forms-item__label {
419 805
   font-weight: bold;
420 806
 }
807
+
808
+.device-cards {
809
+  margin-top: 20rpx;
810
+}
811
+
812
+.device-card {
813
+  background: #fff;
814
+  border-radius: 12rpx;
815
+  margin-bottom: 20rpx;
816
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
817
+  overflow: hidden;
818
+  transition: all 0.3s ease;
819
+  cursor: pointer;
820
+
821
+  &.selected {
822
+    border: 2rpx solid #67c23a;
823
+    background-color: rgba(103, 194, 58, 0.05);
824
+  }
825
+}
826
+
827
+.card-header {
828
+  padding: 16rpx 20rpx;
829
+  background: #f5f7fa;
830
+  border-bottom: 1rpx solid #eee;
831
+  display: flex;
832
+  justify-content: space-between;
833
+  align-items: center;
834
+}
835
+
836
+.return-tag {
837
+  margin-left: 10rpx;
838
+}
839
+
840
+.card-title {
841
+  font-size: 28rpx;
842
+  font-weight: bold;
843
+  color: #333;
844
+  display: block;
845
+  overflow: hidden;
846
+  text-overflow: ellipsis;
847
+  white-space: nowrap;
848
+}
849
+
850
+.card-content {
851
+  padding: 16rpx 20rpx;
852
+}
853
+
854
+.card-row {
855
+  display: flex;
856
+  margin-bottom: 12rpx;
857
+
858
+  &:last-child {
859
+    margin-bottom: 0;
860
+  }
861
+}
862
+
863
+.card-item {
864
+  flex: 1;
865
+  display: flex;
866
+  align-items: center;
867
+  font-size: 26rpx;
868
+  line-height: 1.4;
869
+  padding: 0 10rpx;
870
+  min-width: 0; // 防止内容溢出
871
+
872
+  .label {
873
+    color: #666;
874
+    flex-shrink: 0;
875
+    margin-right: 8rpx;
876
+  }
877
+
878
+  .value {
879
+    color: #333;
880
+    flex: 1;
881
+    overflow: hidden;
882
+    text-overflow: ellipsis;
883
+    white-space: nowrap;
884
+  }
885
+}
886
+
887
+.card-actions {
888
+  padding: 16rpx 20rpx;
889
+  display: flex;
890
+  justify-content: flex-end;
891
+  gap: 20rpx;
892
+  border-top: 1rpx solid #eee;
893
+}
894
+
895
+.device-card {
896
+  background: #fff;
897
+  border-radius: 12rpx;
898
+  margin-bottom: 20rpx;
899
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
900
+  overflow: hidden;
901
+  transition: all 0.3s ease;
902
+  cursor: pointer;
903
+
904
+  &.repair-card {
905
+    border: 2rpx solid #f56c6c;
906
+    background-color: rgba(245, 108, 108, 0.05);
907
+  }
908
+}
909
+
910
+.card-header {
911
+  padding: 16rpx 20rpx;
912
+  background: #f5f7fa;
913
+  border-bottom: 1rpx solid #eee;
914
+  display: flex;
915
+  justify-content: space-between;
916
+  align-items: center;
917
+}
918
+
919
+.repair-tag {
920
+  margin-left: 10rpx;
921
+}
421 922
 </style>

+ 7
- 2
oa-ui-app/pages/message/apply/detail.vue 查看文件

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-02-06 09:48:52
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-04-11 15:37:23
5
+ * @LastEditTime: 2025-04-16 15:12:13
6 6
 -->
7 7
 <template>
8 8
 	<view>
@@ -20,13 +20,15 @@ import {
20 20
 import Declare from '@/pages/form/declare/declare.vue';
21 21
 import Borrow from "@/pages/form/borrow/borrow.vue";
22 22
 import Device from "@/pages/form/device/device.vue";
23
+import Car from "@/pages/form/car/car.vue";
23 24
 import EmptyBox from "../../emptyBox.vue";
24 25
 export default {
25 26
 	components: {
26 27
 		Declare,
27 28
 		EmptyBox,
28 29
 		Borrow,
29
-		Device
30
+		Device,
31
+		Car,
30 32
 	},
31 33
 	data() {
32 34
 		return {
@@ -83,6 +85,9 @@ export default {
83 85
 				case '设备审批':
84 86
 					this.currentForm = 'Device';
85 87
 					break;
88
+				case '用车审批':
89
+					this.currentForm = 'Car';
90
+					break;
86 91
 				default:
87 92
 					console.log('未知流程');
88 93
 					this.isEmpty = true;

+ 6
- 0
oa-ui-app/utils/request.js 查看文件

@@ -1,3 +1,9 @@
1
+/*
2
+ * @Author: ysh
3
+ * @Date: 2025-01-16 11:17:24
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-04-15 09:10:07
6
+ */
1 7
 import store from '@/store'
2 8
 import config from '@/config'
3 9
 import { getToken } from '@/utils/auth'

+ 4
- 12
oa-ui/src/views/flowable/form/oa/carForm.vue 查看文件

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-02-29 11:44:28
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-01-16 16:10:27
5
+ * @LastEditTime: 2025-04-15 10:27:30
6 6
 -->
7 7
 
8 8
 <template>
@@ -532,12 +532,10 @@ export default {
532 532
         if (valid) {
533 533
           this.form.carApplyId = this.taskForm.formId;
534 534
           this.form.drivers = this.chooseDriver;
535
-          let formData = new FormData();
536 535
           let jsonForm = JSON.stringify(this.form);
537
-          formData.append("form", jsonForm);
538 536
           const params = { taskId: this.taskForm.taskId };
539 537
           if (this.formTotal != 0) {
540
-            modifyCarApproval(formData);
538
+            modifyCarApproval(jsonForm);
541 539
           } else {
542 540
             this.form.cars = '';
543 541
             this.form.drivers = '';
@@ -546,7 +544,6 @@ export default {
546 544
           // // 获取下一个流程节点
547 545
           getNextFlowNode(params).then(res => {
548 546
             const data = res.data;
549
-            this.taskForm.formData = formData;
550 547
             this.getNextFlowNodeApproval();
551 548
           })
552 549
         } else {
@@ -561,10 +558,8 @@ export default {
561 558
           return
562 559
         }
563 560
       }
564
-      let formData = new FormData();
565 561
       let jsonForm = JSON.stringify(this.form);
566
-      formData.append("form", jsonForm);
567
-      modifyCarApproval(formData).then(res => {
562
+      modifyCarApproval(jsonForm).then(res => {
568 563
         this.$message.success('保存成功')
569 564
       });
570 565
     },
@@ -573,15 +568,12 @@ export default {
573 568
         if (valid) {
574 569
           this.form.formId = this.taskForm.formId;
575 570
           this.form.carApplyId = this.taskForm.formId;
576
-          let formData = new FormData();
577 571
           let jsonForm = JSON.stringify(this.form);
578
-          formData.append("form", jsonForm);
579
-          modifyCarApproval(formData);
572
+          modifyCarApproval(jsonForm);
580 573
           const params = { taskId: this.taskForm.taskId };
581 574
           // 获取下一个流程节点
582 575
           getNextFlowNode(params).then(res => {
583 576
             const data = res.data;
584
-            this.taskForm.formData = formData;
585 577
             this.getNextFlowNodeApproval();
586 578
           })
587 579
         } else {

+ 5
- 13
oa-ui/src/views/flowable/form/oa/deviceForm.vue 查看文件

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-03-07 13:44:39
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-04-14 15:27:27
5
+ * @LastEditTime: 2025-04-15 17:17:46
6 6
 -->
7 7
 
8 8
 <template>
@@ -437,19 +437,16 @@ export default {
437 437
       this.$refs['deviceForm'].validate((valid) => {
438 438
         if (valid) {
439 439
           this.form.formId = this.taskForm.formId;
440
-          let formData = new FormData();
441 440
           let jsonForm = JSON.stringify(this.form);
442
-          formData.append("form", jsonForm);
443 441
           const params = { taskId: this.taskForm.taskId };
444 442
           if (this.formTotal != 0) {
445
-            modifyDeviceApproval(formData);
443
+            modifyDeviceApproval(jsonForm);
446 444
           } else {
447
-            submitDeviceApproval(formData);
445
+            submitDeviceApproval(jsonForm);
448 446
           }
449 447
           // 获取下一个流程节点
450 448
           getNextFlowNode(params).then(res => {
451 449
             const data = res.data;
452
-            this.taskForm.formData = formData;
453 450
             this.getNextFlowNodeApproval();
454 451
           })
455 452
         } else {
@@ -462,11 +459,9 @@ export default {
462 459
         if (valid) {
463 460
           this.form.formId = this.taskForm.formId;
464 461
           this.form.deviceApplyId = this.taskForm.formId;
465
-          let formData = new FormData();
466 462
           let jsonForm = JSON.stringify(this.form);
467
-          formData.append("form", jsonForm);
468 463
           if (this.formTotal != 0) {
469
-            modifyDeviceApproval(formData).then(res => {
464
+            modifyDeviceApproval(jsonForm).then(res => {
470 465
               this.$message.success('保存成功')
471 466
             });
472 467
           }
@@ -480,15 +475,12 @@ export default {
480 475
         if (valid) {
481 476
           this.form.formId = this.taskForm.formId;
482 477
           this.form.deviceApplyId = this.taskForm.formId;
483
-          let formData = new FormData();
484 478
           let jsonForm = JSON.stringify(this.form);
485
-          formData.append("form", jsonForm);
486
-          modifyDeviceApproval(formData);
479
+          modifyDeviceApproval(jsonForm);
487 480
           const params = { taskId: this.taskForm.taskId };
488 481
           // 获取下一个流程节点
489 482
           getNextFlowNode(params).then(res => {
490 483
             const data = res.data;
491
-            this.taskForm.formData = formData;
492 484
             this.getNextFlowNodeApproval();
493 485
           })
494 486
         } else {

+ 21
- 0
oa-ui/src/views/oa/car/detail.vue 查看文件

@@ -62,6 +62,27 @@
62 62
         </template>
63 63
         {{ carInfo.expectKm }}
64 64
       </el-descriptions-item>
65
+      <el-descriptions-item>
66
+        <template slot="label">
67
+          <svg-icon slot="prefix" icon-class="cost" class="el-input__icon input-icon" />
68
+          油耗(元/km)
69
+        </template>
70
+        {{ carInfo.fuel }}
71
+      </el-descriptions-item>
72
+      <el-descriptions-item>
73
+        <template slot="label">
74
+          <svg-icon slot="prefix" icon-class="cost" class="el-input__icon input-icon" />
75
+          保险(元/天)
76
+        </template>
77
+        {{ carInfo.insurance }}
78
+      </el-descriptions-item>
79
+      <el-descriptions-item>
80
+        <template slot="label">
81
+          <svg-icon slot="prefix" icon-class="cost" class="el-input__icon input-icon" />
82
+          维修(元/天)
83
+        </template>
84
+        {{ carInfo.maintenance }}
85
+      </el-descriptions-item>
65 86
       <el-descriptions-item>
66 87
         <template slot="label">
67 88
           <svg-icon slot="prefix" icon-class="JamYelpSquare" class="el-input__icon input-icon" />

+ 28
- 1
oa-ui/src/views/oa/car/index.vue 查看文件

@@ -66,6 +66,21 @@
66 66
           {{ scope.row.expectKm + '万千米' }}
67 67
         </template>
68 68
       </el-table-column>
69
+      <el-table-column label="油耗(km)" align="center" prop="fuel" >
70
+        <template slot-scope="scope">
71
+          {{ scope.row.fuel + '元' }}
72
+        </template>
73
+      </el-table-column>
74
+      <el-table-column label="保险(天)" align="center" prop="insurance" >
75
+        <template slot-scope="scope">
76
+          {{ scope.row.insurance + '元' }}
77
+        </template>
78
+      </el-table-column>
79
+      <el-table-column label="维修(天)" align="center" prop="maintenance" >
80
+        <template slot-scope="scope">
81
+          {{ scope.row.maintenance + '元' }}
82
+        </template>
83
+      </el-table-column>
69 84
       <el-table-column label="单日成本" align="center" prop="dayCost" >
70 85
         <template slot-scope="scope">
71 86
           {{ scope.row.dayCost + '元' }}
@@ -90,7 +105,7 @@
90 105
 
91 106
     <!-- 添加或修改cmc车辆信息对话框 -->
92 107
     <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
93
-      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
108
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
94 109
         <el-form-item label="车牌号" prop="licensePlate">
95 110
           <el-input v-model="form.licensePlate" placeholder="请输入车牌号" />
96 111
         </el-form-item>
@@ -117,6 +132,18 @@
117 132
           <el-input v-model="form.expectKm" placeholder="请输入里程" style="width:130px;margin-right:10px;" />
118 133
           <span>万千米</span>
119 134
         </el-form-item>
135
+        <el-form-item label="油耗(元/km)" prop="cost">
136
+          <el-input style="width:130px;margin-right:10px;" v-model="form.fuel" placeholder="请输入金额" />
137
+          <span>元</span>
138
+        </el-form-item>
139
+        <el-form-item label="保险(元/天)" prop="cost">
140
+          <el-input style="width:130px;margin-right:10px;" v-model="form.insurance" placeholder="请输入金额" />
141
+          <span>元</span>
142
+        </el-form-item>
143
+        <el-form-item label="维修(元/天)" prop="cost">
144
+          <el-input style="width:130px;margin-right:10px;" v-model="form.maintenance" placeholder="请输入金额" />
145
+          <span>元</span>
146
+        </el-form-item>
120 147
         <el-form-item label="驾驶员" prop="driver">
121 148
           <el-select v-model="form.driver" filterable placeholder="请选择" clearable>
122 149
             <el-option v-for="item in driverList" :key="item.userId" :label="item.nickName" :value="item.userId">

正在加载...
取消
保存