Browse Source

预算编制优化人员选择和设备选择

余思翰 3 days ago
parent
commit
20152464f5

+ 41
- 41
oa-ui/src/views/flowable/form/budget/addBudget.vue View File

@@ -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-06-11 11:06:16
5
+ * @LastEditTime: 2025-07-03 16:10:00
6 6
 -->
7 7
 <template>
8 8
   <div class="app-container">
@@ -247,14 +247,19 @@ export default {
247 247
       });
248 248
     },
249 249
     // 保存
250
-    preserve() {
251
-      if (!this.flag) {
252
-        this.addBudgetForm(this.budgetForm);
253
-        this.flag = true;
254
-      } else {
255
-        this.updateBudgetForm(this.budgetForm);
250
+    async preserve() {
251
+      let loadingInstance = null;
252
+      try {
253
+        loadingInstance = this.$loading({ fullscreen: true, lock: true, text: '正在保存...', background: 'rgba(0,0,0,0.2)' });
254
+        if (!this.flag) {
255
+          await this.addBudgetForm(this.budgetForm);
256
+          this.flag = true;
257
+        } else {
258
+          await this.updateBudgetForm(this.budgetForm);
259
+        }
260
+      } finally {
261
+        if (loadingInstance) loadingInstance.close();
256 262
       }
257
-      this.$message.success("正在保存......");
258 263
     },
259 264
     viewForm() {
260 265
       this.viewOpen = true;
@@ -306,39 +311,34 @@ export default {
306 311
       }
307 312
       this.$message.success("预算添加成功");
308 313
     },
309
-    updateBudgetForm(form) {
310
-      updateBudget(form);
311
-      delBudgetStaff(form.budgetId).then(async res => {
312
-        for (let user of form.chooseUser) {
313
-          user.budgetId = form.budgetId;
314
-          await addBudgetStaff(user);
315
-        }
316
-      });
317
-      delBudgetCar(form.budgetId).then(async res => {
318
-        for (let car of form.chooseCar) {
319
-          car.budgetId = form.budgetId;
320
-          await addBudgetCar(car);
321
-        }
322
-      });
323
-      delBudgetDevice(form.budgetId).then(async res => {
324
-        for (let device of form.chooseDevice) {
325
-          device.budgetId = form.budgetId;
326
-          await addBudgetDevice(device);
327
-        }
328
-      });
329
-      delBudgetSettle(form.budgetId).then(async res => {
330
-        for (let work of form.contentList) {
331
-          work.budgetId = form.budgetId;
332
-          await addBudgetSettle(work);
333
-        }
334
-      });
335
-      delSite(form.budgetId).then(async res => {
336
-        for (let site of form.expensesList) {
337
-          site.budgetId = form.budgetId;
338
-          await addSite(site);
339
-        }
340
-        this.$message.success("预算添加成功");
341
-      })
314
+    async updateBudgetForm(form) {
315
+      await updateBudget(form);
316
+      await delBudgetStaff(form.budgetId);
317
+      for (let user of form.chooseUser) {
318
+        user.budgetId = form.budgetId;
319
+        await addBudgetStaff(user);
320
+      }
321
+      await delBudgetCar(form.budgetId);
322
+      for (let car of form.chooseCar) {
323
+        car.budgetId = form.budgetId;
324
+        await addBudgetCar(car);
325
+      }
326
+      await delBudgetDevice(form.budgetId);
327
+      for (let device of form.chooseDevice) {
328
+        device.budgetId = form.budgetId;
329
+        await addBudgetDevice(device);
330
+      }
331
+      await delBudgetSettle(form.budgetId);
332
+      for (let work of form.contentList) {
333
+        work.budgetId = form.budgetId;
334
+        await addBudgetSettle(work);
335
+      }
336
+      await delSite(form.budgetId);
337
+      for (let site of form.expensesList) {
338
+        site.budgetId = form.budgetId;
339
+        await addSite(site);
340
+      }
341
+      this.$message.success("预算添加成功");
342 342
     },
343 343
     getChooseUser(val) {
344 344
       this.$set(this.budgetForm, "chooseUser", val);

+ 30
- 3
oa-ui/src/views/flowable/form/budget/components/chooseDevice.vue View File

@@ -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: 2024-09-20 09:49:18
5
+ * @LastEditTime: 2025-07-03 16:38:50
6 6
 -->
7 7
 <template>
8 8
   <div>
@@ -34,7 +34,8 @@
34 34
       </el-form-item>
35 35
     </el-form>
36 36
     <el-table border ref="chooseDeviceRef" :data="list" @selection-change="handleSelectionChange" :row-key="getRowKeys"
37
-      @current-change="handleCurrentChange" @row-dblclick="confirmChooseBySingle" :highlight-current-row="!multiple">
37
+      @current-change="handleCurrentChange" @row-dblclick="confirmChooseBySingle" :highlight-current-row="!multiple"
38
+      :selectable="isSelectable">
38 39
       <el-table-column type="selection" width="50" align="center" :reserve-selection="true" v-if="multiple" />
39 40
       <el-table-column label="设备状态" align="center" prop="status">
40 41
         <template slot-scope="scope">
@@ -84,6 +85,10 @@ export default {
84 85
     multiple: {
85 86
       type: Boolean,
86 87
       default: true
88
+    },
89
+    selectedDeviceIds: {
90
+      type: Array,
91
+      default: () => []
87 92
     }
88 93
   },
89 94
   watch: {
@@ -151,7 +156,26 @@ export default {
151 156
       return row.deviceId;
152 157
     },
153 158
     confirmChoose() {
154
-      this.$emit('chooseList', this.chooseList)
159
+      if (!this.chooseList || (Array.isArray(this.chooseList) && this.chooseList.length === 0) ||
160
+          (typeof this.chooseList === 'object' && !Array.isArray(this.chooseList) && Object.keys(this.chooseList).length === 0)) {
161
+        return;
162
+      }
163
+      let devices = Array.isArray(this.chooseList) ? this.chooseList : [this.chooseList];
164
+      // 找出已存在的设备
165
+      const existedDevices = devices.filter(d => this.selectedDeviceIds.includes(d.deviceId));
166
+      // 过滤掉已存在的设备
167
+      devices = devices.filter(d => !this.selectedDeviceIds.includes(d.deviceId));
168
+      if (devices.length === 0) {
169
+        const names = existedDevices.map(d => `${d.name}-${d.series}-${d.brand}`).join('、');
170
+        this.$message.warning(`所选设备【${names}】已存在,无法重复添加`);
171
+        return;
172
+      }
173
+      if (existedDevices.length > 0) {
174
+        const names = existedDevices.map(d => `${d.name}-${d.series}-${d.brand}`).join('、');
175
+        this.$message.warning(`设备【${names}】已存在,已自动过滤`);
176
+      }
177
+      this.$emit('chooseList', this.multiple ? devices : devices[0]);
178
+      this.clearChoose();
155 179
     },
156 180
     confirmChooseBySingle() {
157 181
       if (!this.multiple) {
@@ -206,6 +230,9 @@ export default {
206 230
       } else {
207 231
         return null
208 232
       }
233
+    },
234
+    isSelectable(row) {
235
+      return !this.selectedDeviceIds.includes(row.deviceId);
209 236
     }
210 237
   }
211 238
 }

+ 28
- 2
oa-ui/src/views/flowable/form/budget/components/choosePeople.vue View File

@@ -68,6 +68,10 @@ export default {
68 68
     multiple: {
69 69
       type: Boolean,
70 70
       default: true
71
+    },
72
+    selectedUserIds: {
73
+      type: Array,
74
+      default: () => []
71 75
     }
72 76
   },
73 77
   data() {
@@ -138,8 +142,30 @@ export default {
138 142
       return row.userId;
139 143
     },
140 144
     confirmChoose() {
141
-      if (this.chooseUser)
142
-        this.$emit('chooseUser', this.chooseUser)
145
+      // 当 this.chooseUser 为空数组或空对象时,不做操作
146
+      if (
147
+        !this.chooseUser ||
148
+        (Array.isArray(this.chooseUser) && this.chooseUser.length === 0) ||
149
+        (typeof this.chooseUser === 'object' && !Array.isArray(this.chooseUser) && Object.keys(this.chooseUser).length === 0)
150
+      ) {
151
+        return;
152
+      }
153
+      let users = Array.isArray(this.chooseUser) ? this.chooseUser : [this.chooseUser];
154
+      // 找出已存在的用户
155
+      const existedUsers = users.filter(u => this.selectedUserIds.includes(u.userId));
156
+      // 过滤掉已存在的 userId
157
+      users = users.filter(u => !this.selectedUserIds.includes(u.userId));
158
+      if (users.length === 0) {
159
+        const names = existedUsers.map(u => u.nickName).join('、');
160
+        this.$message.warning(`所选人员【${names}】已存在,无法重复添加`);
161
+        return;
162
+      }
163
+      if (existedUsers.length > 0) {
164
+        const names = existedUsers.map(u => u.nickName).join('、');
165
+        this.$message.warning(`人员【${names}】已存在,已自动过滤`);
166
+      }
167
+      this.$emit('chooseUser', this.multiple ? users : users[0]);
168
+      this.clearChoose();
143 169
     },
144 170
     confirmChooseBySingle() {
145 171
       if (!this.multiple) {

+ 17
- 7
oa-ui/src/views/flowable/form/budget/deviceTable.vue View File

@@ -4,11 +4,11 @@
4 4
       <el-form-item label="选择设备:">
5 5
         <span v-if="chooseDeviceList.length != 0">
6 6
           <el-tag effect="plain" type="success" v-for="item in chooseDeviceList" style="margin: 5px; font-size: 14px"
7
-            :key="item.code">
8
-            {{ item.name + "-" + item.series + "-" + item.brand }}
7
+            :key="item.deviceId" closable @close="removeDevice(item.deviceId)">
8
+            {{ item.name + '-' + item.series + '-' + item.brand }}
9 9
           </el-tag>
10 10
         </span>
11
-        <el-button type="success" plain icon="el-icon-plus" @click="openDevice = true" size="mini">选择</el-button>
11
+        <el-button type="success" plain icon="el-icon-plus" @click="openDevice = true" size="mini">新增</el-button>
12 12
       </el-form-item>
13 13
       <el-form-item v-if="chooseDeviceList.length != 0">
14 14
         <table border="1">
@@ -16,6 +16,7 @@
16 16
             <td :colspan="6" class="head">设备成本预算</td>
17 17
           </tr>
18 18
           <tr>
19
+            <td style="width: 100px">出厂编号</td>
19 20
             <td style="width: 120px">设备名称</td>
20 21
             <td style="width: 120px">规格型号</td>
21 22
             <td style="width: 120px">品牌</td>
@@ -24,6 +25,7 @@
24 25
             <td style="width: 100px">总额</td>
25 26
           </tr>
26 27
           <tr v-for="device in chooseDeviceList" :key="device.deviceId">
28
+            <td>{{ device.code }}</td>
27 29
             <td>{{ device.name }}</td>
28 30
             <td>{{ device.series }}</td>
29 31
             <td>{{ device.brand }}</td>
@@ -45,7 +47,7 @@
45 47
     </el-form>
46 48
     <!-- 选择设备对话框 -->
47 49
     <el-dialog title="选择设备" :visible.sync="openDevice" width="750px" append-to-body>
48
-      <chooseDevice @chooseList="getChooseDevice"></chooseDevice>
50
+      <chooseDevice @chooseList="getChooseDevice" :selectedDeviceIds="chooseDeviceList.map(d => d.deviceId)"></chooseDevice>
49 51
     </el-dialog>
50 52
   </div>
51 53
 </template>
@@ -98,6 +100,7 @@ export default {
98 100
         listBudgetDevice({ pageSize: 100, budgetId: this.budgetId }).then((res) => {
99 101
           this.chooseDeviceList = res.rows;
100 102
           for (let device of this.chooseDeviceList) {
103
+            device.code = device.device.code
101 104
             device.brand = device.device.brand
102 105
             device.depreciation = device.device.dayCost
103 106
             device.name = device.device.name
@@ -115,12 +118,19 @@ export default {
115 118
       this.form.deviceCost = deviceCost.toFixed(2)
116 119
     },
117 120
     getChooseDevice(val) {
118
-      this.chooseDeviceList = val;
121
+      // 过滤掉已存在的设备
122
+      const newDevices = val.filter(v => !this.chooseDeviceList.some(d => d.deviceId === v.deviceId));
123
+      // 追加新设备
124
+      this.chooseDeviceList = this.chooseDeviceList.concat(newDevices);
119 125
       this.openDevice = false;
120
-      for (let v of val) {
126
+      for (let v of newDevices) {
121 127
         v.depreciation = v.dayCost;
122 128
       }
123
-      this.recalculateCost(val, 'amount', 'deviceCost');
129
+      this.recalculateCost(this.chooseDeviceList, 'amount', 'deviceCost');
130
+    },
131
+    removeDevice(deviceId) {
132
+      this.chooseDeviceList = this.chooseDeviceList.filter(d => d.deviceId !== deviceId);
133
+      this.recalculateCost(this.chooseDeviceList, 'amount', 'deviceCost');
124 134
     },
125 135
     calculateDeviceTotal(device) {
126 136
       let total = Number(device.depreciation) * Number(device.days);

+ 29
- 18
oa-ui/src/views/flowable/form/budget/staffTable.vue View File

@@ -5,11 +5,11 @@
5 5
       <el-form-item label="选择内业人员:">
6 6
         <span v-if="innerUsers.length != 0">
7 7
           <el-tag effect="plain" type="success" v-for="item in innerUsers" style="margin: 5px; font-size: 14px"
8
-            :key="item.userId">
8
+            :key="item.userId" closable @close="removeUser('inner', item.userId)">
9 9
             {{ item.nickName }}
10 10
           </el-tag>
11 11
         </span>
12
-        <el-button type="success" plain icon="el-icon-plus" @click="openPeople('inner')" size="mini">选择</el-button>
12
+        <el-button type="success" plain icon="el-icon-plus" @click="openPeople('inner')" size="mini">新增</el-button>
13 13
       </el-form-item>
14 14
 
15 15
       <!-- <div class="mb20" style="color:#E23D28;font-size:12px;">
@@ -30,7 +30,7 @@
30 30
             <td style="width: 100px">预算天数</td>
31 31
             <td style="width: 100px">预算绩效</td>
32 32
             <td style="width: 100px">金额</td>
33
-            <td style="width: 100px">备注</td>
33
+            <td style="width: 160px">备注</td>
34 34
           </tr>
35 35
           <tr v-for="user, index in innerUsers" :key="user.userId">
36 36
             <td>{{ index + 1 }}</td>
@@ -40,11 +40,11 @@
40 40
               {{ user.dayCost }}
41 41
             </td>
42 42
             <td>
43
-              <el-input-number :controls="false" v-model="user.days" placeholder="请输入天数"
43
+              <el-input-number style="width: 100px" :controls="false" v-model="user.days" placeholder="请输入天数"
44 44
                 @blur="calculateUserTotal(user)"></el-input-number>
45 45
             </td>
46
-            <td>
47
-              <el-input-number :controls="false" v-model="user.performance" placeholder="请输入预算绩效"
46
+            <td>  
47
+              <el-input-number style="width: 100px" :controls="false" v-model="user.performance" placeholder="请输入预算绩效"
48 48
                 @blur="calculateUserTotal(user)"></el-input-number>
49 49
               <el-button type="text" @click="openCalculatePerformance(user)">计算绩效</el-button>
50 50
             </td>
@@ -54,8 +54,8 @@
54 54
             </td>
55 55
           </tr>
56 56
           <tr>
57
-            <td colspan="4">合计</td>
58
-            <td>{{ form.innerDays }}</td>
57
+            <td colspan="5">合计</td>
58
+            <!-- <td>{{ form.innerDays }}</td> -->
59 59
             <td>{{ form.innerSettle }}</td>
60 60
             <td>{{ form.innerStaffCost }}</td>
61 61
           </tr>
@@ -67,17 +67,17 @@
67 67
       <el-form-item label="选择外业人员:">
68 68
         <span v-if="outerUsers.length != 0">
69 69
           <el-tag effect="plain" type="success" v-for="item in outerUsers" style="margin: 5px; font-size: 14px"
70
-            :key="item.userId">
70
+            :key="item.userId" closable @close="removeUser('outer', item.userId)">
71 71
             {{ item.nickName }}
72 72
           </el-tag>
73 73
         </span>
74
-        <el-button type="success" plain icon="el-icon-plus" @click="openPeople('outer')" size="mini">选择</el-button>
74
+        <el-button type="success" plain icon="el-icon-plus" @click="openPeople('outer')" size="mini">新增</el-button>
75 75
       </el-form-item>
76 76
       <!-- 外业人员表格 -->
77 77
       <el-form-item v-if="outerUsers.length != 0">
78 78
         <table border="1">
79 79
           <tr>
80
-            <td :colspan="9" class="head">外业人员成本预算</td>
80
+            <td :colspan="10" class="head">外业人员成本预算</td>
81 81
           </tr>
82 82
           <tr>
83 83
             <td style="width: 50px">序号</td>
@@ -89,7 +89,7 @@
89 89
             <td style="width: 100px">预算系数</td>
90 90
             <td style="width: 100px">预算绩效</td>
91 91
             <td style="width: 100px">总额</td>
92
-            <td style="width: 100px">备注</td>
92
+            <td style="width: 160px">备注</td>
93 93
           </tr>
94 94
           <tr v-for="user, index in outerUsers" :key="user.userId">
95 95
             <td>{{ index + 1 }}</td>
@@ -102,11 +102,11 @@
102 102
               200
103 103
             </td>
104 104
             <td>
105
-              <el-input-number :controls="false" v-model="user.days" placeholder="请输入天数"
105
+              <el-input-number style="width: 100px" :controls="false" v-model="user.days" placeholder="请输入天数"
106 106
                 @blur="calculateUserTotal(user)"></el-input-number>
107 107
             </td>
108 108
             <td>
109
-              <el-input-number :controls="false" v-model="user.coefficient" placeholder="请输入系数"
109
+              <el-input-number style="width: 100px" :controls="false" v-model="user.coefficient" placeholder="请输入系数"
110 110
                 @blur="calculateUserTotal(user)"></el-input-number>
111 111
             </td>
112 112
             <td>
@@ -118,7 +118,7 @@
118 118
             </td>
119 119
           </tr>
120 120
           <tr>
121
-            <td colspan="6">合计</td>
121
+            <td colspan="7">合计</td>
122 122
             <td>{{ form.outerSettle }}</td>
123 123
             <td>{{ form.outerStaffCost }}</td>
124 124
           </tr>
@@ -139,7 +139,10 @@
139 139
     <!-- 选择人员对话框 -->
140 140
     <el-dialog :title="currentType === 'inner' ? '选择内业人员' : '选择外业人员'" :visible.sync="isOpenPeople" width="700px"
141 141
       append-to-body>
142
-      <choosePeople @chooseUser="getChooseUser"></choosePeople>
142
+      <choosePeople @chooseUser="getChooseUser"
143
+        :selectedUserIds="currentType === 'inner' ? innerUsers.map(u => u.userId) : outerUsers.map(u => u.userId)"
144
+        :currentType="currentType"
145
+      ></choosePeople>
143 146
     </el-dialog>
144 147
 
145 148
     <!-- 计算绩效对话框 -->
@@ -315,9 +318,9 @@ export default {
315 318
       });
316 319
       
317 320
       if (this.currentType === 'inner') {
318
-        this.innerUsers = processedUsers;
321
+        this.innerUsers = this.innerUsers.concat(processedUsers);
319 322
       } else {
320
-        this.outerUsers = processedUsers;
323
+        this.outerUsers = this.outerUsers.concat(processedUsers);
321 324
       }
322 325
       this.isOpenPeople = false;
323 326
       this.updateStaffCosts();
@@ -367,6 +370,14 @@ export default {
367 370
         this.calculateUserTotal(this.currentUser);
368 371
       }
369 372
     },
373
+    removeUser(type, userId) {
374
+      if (type === 'inner') {
375
+        this.innerUsers = this.innerUsers.filter(user => user.userId !== userId);
376
+      } else if (type === 'outer') {
377
+        this.outerUsers = this.outerUsers.filter(user => user.userId !== userId);
378
+      }
379
+      this.updateStaffCosts();
380
+    },
370 381
   },
371 382
 }
372 383
 </script>

Loading…
Cancel
Save