Просмотр исходного кода

修改项目预算,新增项目核算,编写核算编制表单

余思翰 3 недель назад
Родитель
Сommit
55979b8cce

+ 0
- 12
oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcBudgetController.java Просмотреть файл

@@ -79,18 +79,6 @@ public class CmcBudgetController extends BaseController
79 79
     @PutMapping
80 80
     public AjaxResult edit(@RequestBody CmcBudget cmcBudget)
81 81
     {
82
-        if (cmcBudget.getManagerComment() != null && cmcBudget.getZjlComment() == null) {
83
-            cmcBudget.setManager(getLoginUser().getUserId());
84
-            cmcBudget.setManagerTime(new Date());
85
-        }
86
-        if (cmcBudget.getZjlComment() != null && cmcBudget.getDszComment() == null) {
87
-            cmcBudget.setAuditor(getLoginUser().getUserId());
88
-            cmcBudget.setZjlTime(new Date());
89
-        }
90
-        if (cmcBudget.getDszComment() != null && cmcBudget.getDszTime() == null) {
91
-            cmcBudget.setApprover(getLoginUser().getUserId());
92
-            cmcBudget.setDszTime(new Date());
93
-        }
94 82
         return toAjax(cmcBudgetService.updateCmcBudget(cmcBudget));
95 83
     }
96 84
 

+ 44
- 0
oa-ui/src/api/oa/budget/check.js Просмотреть файл

@@ -0,0 +1,44 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询cmc项目核算列表
4
+export function listCheck(query) {
5
+  return request({
6
+    url: '/oa/check/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+// 查询cmc项目核算详细
13
+export function getCheck(checkId) {
14
+  return request({
15
+    url: '/oa/check/' + checkId,
16
+    method: 'get'
17
+  })
18
+}
19
+
20
+// 新增cmc项目核算
21
+export function addCheck(data) {
22
+  return request({
23
+    url: '/oa/check',
24
+    method: 'post',
25
+    data: data
26
+  })
27
+}
28
+
29
+// 修改cmc项目核算
30
+export function updateCheck(data) {
31
+  return request({
32
+    url: '/oa/check',
33
+    method: 'put',
34
+    data: data
35
+  })
36
+}
37
+
38
+// 删除cmc项目核算
39
+export function delCheck(checkId) {
40
+  return request({
41
+    url: '/oa/check/' + checkId,
42
+    method: 'delete'
43
+  })
44
+}

+ 6
- 6
oa-ui/src/views/flowable/form/budget/addBudget.vue Просмотреть файл

@@ -149,12 +149,12 @@
149 149
 <script>
150 150
 import { Snowflake } from "@/utils/snowFlake.js";
151 151
 import { getProject } from "@/api/oa/project/project";
152
-import { listBudget, addBudget, updateBudget, delBudget } from "@/api/oa/budget/budget.js";
153
-import { listBudgetCar, addBudgetCar, delBudgetCar } from "@/api/oa/budget/budgetCar.js";
154
-import { listBudgetStaff, addBudgetStaff, delBudgetStaff } from "@/api/oa/budget/budgetStaff.js";
155
-import { listBudgetDevice, addBudgetDevice, delBudgetDevice } from "@/api/oa/budget/budgetDevice.js";
156
-import { listBudgetSettle, addBudgetSettle, delBudgetSettle } from "@/api/oa/budget/budgetSettle.js";
157
-import { listSite, getSite, delSite, addSite, updateSite } from "@/api/oa/budget/budgetSite.js";
152
+import { listBudget, addBudget, updateBudget } from "@/api/oa/budget/budget.js";
153
+import { addBudgetCar, delBudgetCar } from "@/api/oa/budget/budgetCar.js";
154
+import { addBudgetStaff, delBudgetStaff } from "@/api/oa/budget/budgetStaff.js";
155
+import { addBudgetDevice, delBudgetDevice } from "@/api/oa/budget/budgetDevice.js";
156
+import { addBudgetSettle, delBudgetSettle } from "@/api/oa/budget/budgetSettle.js";
157
+import { delSite, addSite } from "@/api/oa/budget/budgetSite.js";
158 158
 import { getUsersDeptLeaderByDept, getUsersManageLeaderByDept, getUsersDeptLeader, getDeptLeadersByDeptId } from "@/api/system/post";
159 159
 import { complete, getNextFlowNode } from "@/api/flowable/todo";
160 160
 import budgetInfo from "./budgetInfo.vue";

+ 218
- 0
oa-ui/src/views/flowable/form/budget/adjust/adjustIndex.vue Просмотреть файл

@@ -0,0 +1,218 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-05-14 16:09:56
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-05-14 16:56:52
6
+-->
7
+<template>
8
+  <div class="app-container">
9
+    <transition name="fade-transform" mode="out-in">
10
+      <div v-if="!projectId" key="selection">
11
+        <div class="selection-header">
12
+          <h3 style="font-weight: bold; color: #FF5733;">选择核算项目</h3>
13
+        </div>
14
+        <el-form :model="queryParams" ref="queryForm" :inline="true" class="search-form">
15
+          <el-form-item prop="projectId">
16
+            <el-select v-model="queryType" style="width: 120px;">
17
+              <el-option label="项目编号" value="1"></el-option>
18
+              <el-option label="项目名称" value="2"></el-option>
19
+            </el-select>
20
+            <el-select v-model="queryParams.projectId" clearable filterable remote reserve-keyword placeholder="请输入关键字"
21
+              :remote-method="remoteMethod" :loading="loading" style="width: 300px;">
22
+              <el-option v-for="project in projectList" :key="project.projectId"
23
+                :label="project.projectNumber + '-' + project.projectName" :value="project.projectId">
24
+              </el-option>
25
+            </el-select>
26
+          </el-form-item>
27
+          <el-form-item>
28
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
29
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
30
+          </el-form-item>
31
+        </el-form>
32
+        <el-table v-loading="loading" :data="budgetList">
33
+          <el-table-column label="序号" align="center" type="index" width="60" />
34
+          <el-table-column label="项目编号" align="center" prop="project.projectNumber" />
35
+          <el-table-column label="项目名称" align="center" prop="project.projectName" />
36
+          <el-table-column label="预算总额" align="center" prop="totalBudget" />
37
+          <el-table-column label="编制人" align="center" prop="compiler">
38
+            <template slot-scope="scope">
39
+              {{ getUserName(scope.row.compiler) }}
40
+            </template>
41
+          </el-table-column>
42
+          <el-table-column label="审核人" align="center" prop="auditor">
43
+            <template slot-scope="scope">
44
+              {{ getUserName(scope.row.auditor) }}
45
+            </template>
46
+          </el-table-column>
47
+          <el-table-column label="操作" align="center" width="120">
48
+            <template slot-scope="scope">
49
+              <el-button type="primary" size="mini" @click="handleSelect(scope.row)">选择</el-button>
50
+            </template>
51
+          </el-table-column>
52
+        </el-table>
53
+        <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
54
+          :limit.sync="queryParams.pageSize" @pagination="getList" />
55
+      </div>
56
+      <div v-else key="adjust">
57
+        <div class="adjust-header" v-if="hideReturn">
58
+          <el-button icon="el-icon-back" type="text" @click="handleBack">返回选择</el-button>
59
+          <h3>预算调整</h3>
60
+        </div>
61
+        <budget-adjust :taskForm="taskForm" :taskName="taskName" :row="selectedRows"
62
+          @preserve="preserve"></budget-adjust>
63
+      </div>
64
+    </transition>
65
+  </div>
66
+</template>
67
+
68
+<script>
69
+import { listBudget, getBudget } from '@/api/oa/budget/budget';
70
+import { listCheck, getCheck, delCheck, addCheck, updateCheck } from "@/api/oa/budget/check";
71
+import { listProject } from '@/api/oa/project/project';
72
+import BudgetAdjust from './budgetAdjust.vue';
73
+export default {
74
+  props: {
75
+    taskForm: {
76
+      type: Object,
77
+      require: true
78
+    },
79
+    taskName: {
80
+      type: String,
81
+    }
82
+  },
83
+  components: {
84
+    BudgetAdjust
85
+  },
86
+  data() {
87
+    return {
88
+      loading: true,
89
+      projectId: '',
90
+      budgetList: [],
91
+      total: 0,
92
+      selectedRows: {},
93
+      queryParams: {
94
+        pageNum: 1,
95
+        pageSize: 20,
96
+        projectNumber: undefined,
97
+        projectName: undefined
98
+      },
99
+      queryType: '1',
100
+      projectList: [],
101
+      hideReturn: true
102
+    }
103
+  },
104
+  created() {
105
+    this.initForm();
106
+    this.getBudgetList();
107
+  },
108
+  methods: {
109
+    initForm() {
110
+      getCheck(this.taskForm.formId).then(res => {
111
+        if (res.data) {
112
+          this.hideReturn = false;
113
+          this.projectId = res.data.projectId;
114
+          getBudget(res.data.budgetId).then(response => {
115
+            this.selectedRows = response.data;
116
+          })
117
+        }
118
+      })
119
+    },
120
+    getBudgetList() {
121
+      listBudget(this.queryParams).then(res => {
122
+        this.budgetList = res.rows;
123
+        this.total = res.total;
124
+        this.loading = false;
125
+      });
126
+    },
127
+    handleSelect(row) {
128
+      this.projectId = row.projectId;
129
+      this.selectedRows = row;
130
+      console.log(row);
131
+    },
132
+    handleBack() {
133
+      this.projectId = '';
134
+    },
135
+    getList() {
136
+      this.loading = true;
137
+      this.getBudgetList();
138
+    },
139
+    /** 搜索按钮操作 */
140
+    handleQuery() {
141
+      this.queryParams.pageNum = 1;
142
+      this.getList();
143
+    },
144
+    /** 重置按钮操作 */
145
+    resetQuery() {
146
+      this.resetForm("queryForm");
147
+      this.handleQuery();
148
+    },
149
+    /** 重置表单 */
150
+    resetForm(refName) {
151
+      if (this.$refs[refName]) {
152
+        this.$refs[refName].resetFields();
153
+      }
154
+    },
155
+    remoteMethod(val) {
156
+      let params1 = {
157
+        pageNum: 1,
158
+        pageSize: 20,
159
+        projectNumber: val
160
+      }
161
+      let params2 = {
162
+        pageNum: 1,
163
+        pageSize: 20,
164
+        projectName: val
165
+      }
166
+      let params = {};
167
+      if (this.queryType == '1') {
168
+        params = params1
169
+      } else {
170
+        params = params2
171
+      }
172
+      listProject(params).then(res => {
173
+        this.projectList = res.rows;
174
+      })
175
+    },
176
+    preserve() {
177
+      this.hideReturn = false;
178
+      console.log(1111);
179
+    }
180
+  }
181
+}
182
+</script>
183
+
184
+<style lang="scss" scoped>
185
+.selection-header,
186
+.adjust-header {
187
+  margin-bottom: 20px;
188
+  display: flex;
189
+  align-items: center;
190
+
191
+  h3 {
192
+    margin: 0;
193
+    margin-left: 10px;
194
+  }
195
+}
196
+
197
+.search-form {
198
+  margin-bottom: 20px;
199
+  padding: 20px;
200
+  background-color: #f5f7fa;
201
+  border-radius: 4px;
202
+}
203
+
204
+.fade-transform-enter-active,
205
+.fade-transform-leave-active {
206
+  transition: all 0.5s;
207
+}
208
+
209
+.fade-transform-enter {
210
+  opacity: 0;
211
+  transform: translateX(-30px);
212
+}
213
+
214
+.fade-transform-leave-to {
215
+  opacity: 0;
216
+  transform: translateX(30px);
217
+}
218
+</style>

+ 71
- 15
oa-ui/src/views/flowable/form/budget/adjust/budgetAdjust.vue Просмотреть файл

@@ -1,11 +1,11 @@
1 1
 <!--
2 2
  * @Author: ysh
3 3
  * @Date: 2025-05-07 11:01:39
4
- * @LastEditors: 
5
- * @LastEditTime: 2025-05-12 17:18:35
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-05-14 18:27:04
6 6
 -->
7 7
 <template>
8
-  <div class="main">
8
+  <div class="main" v-loading="loading">
9 9
     <h2 class="text-center">项目直接生产成本预算—核算表</h2>
10 10
     <p style="text-align: center">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}</p>
11 11
     <el-divider></el-divider>
@@ -108,7 +108,7 @@
108 108
         </table>
109 109
       </el-descriptions-item>
110 110
       <el-descriptions-item label="内业人员成本" :span="3" v-if="innerStaffList.length > 0">
111
-        <inner-staff-cost :staffList.sync="innerStaffList"
111
+        <inner-staff-cost :staffList.sync="innerStaffList" :settleExpense="budgetForm.settleExpense"
112 112
           @update:staffList="handleInnerStaffChange"></inner-staff-cost>
113 113
       </el-descriptions-item>
114 114
       <el-descriptions-item label="外业人员成本" :span="3" v-if="outerStaffList.length > 0">
@@ -140,16 +140,22 @@
140 140
 
141 141
       </el-descriptions-item>
142 142
     </el-descriptions>
143
+    <div class="text-center mt20 mb20">
144
+      <el-button type="warning" @click="preserve()">保 存</el-button>
145
+      <el-button type="success" @click="confirmSucess()">提交下一个流程</el-button>
146
+    </div>
143 147
   </div>
144 148
 </template>
145 149
 
146 150
 <script>
151
+import { listCheck, getCheck, delCheck, addCheck, updateCheck } from "@/api/oa/budget/check";
147 152
 import { listBudget, updateBudget } from "@/api/oa/budget/budget";
148
-import { listBudgetCar, updateBudgetCar } from "@/api/oa/budget/budgetCar";
149
-import { listBudgetDevice, updateBudgetDevice } from "@/api/oa/budget/budgetDevice";
150
-import { listBudgetSettle, updateBudgetSettle } from "@/api/oa/budget/budgetSettle";
151
-import { listBudgetStaff } from "@/api/oa/budget/budgetStaff";
153
+import { listBudgetCar, updateBudgetCar, addBudgetCar, delBudgetCar } from "@/api/oa/budget/budgetCar";
154
+import { listBudgetDevice, updateBudgetDevice, addBudgetDevice, delBudgetDevice } from "@/api/oa/budget/budgetDevice";
155
+import { listBudgetSettle, updateBudgetSettle, addBudgetSettle, delBudgetSettle } from "@/api/oa/budget/budgetSettle";
156
+import { listBudgetStaff, addBudgetStaff, delBudgetStaff } from "@/api/oa/budget/budgetStaff";
152 157
 import { listProjectWork } from "@/api/oa/project/projectWork";
158
+import { listSite, delSite, addSite } from "@/api/oa/budget/budgetSite";
153 159
 import { getProject } from "@/api/oa/project/project";
154 160
 import InnerStaffCost from './components/InnerStaffCost.vue';
155 161
 import OuterStaffCost from './components/OuterStaffCost.vue';
@@ -170,6 +176,9 @@ export default {
170 176
     },
171 177
     taskName: {
172 178
       type: String,
179
+    },
180
+    row: {
181
+      type: Object,
173 182
     }
174 183
   },
175 184
   data() {
@@ -192,7 +201,7 @@ export default {
192 201
   methods: {
193 202
     initBudgetForm() {
194 203
       this.loading = true;
195
-      listBudget({ pageNum: 1, pageSize: 20, projectId: this.taskForm.formId }).then(async res => {
204
+      listBudget({ pageNum: 1, pageSize: 20, projectId: this.row.projectId }).then(async res => {
196 205
         this.budgetForm = res.rows[0];
197 206
         if (this.budgetForm) {
198 207
           const budgetId = this.budgetForm.budgetId;
@@ -205,12 +214,36 @@ export default {
205 214
           this.carList = carRes.rows;
206 215
 
207 216
           // 获取内业人员数据
208
-          let innerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId });
217
+          let innerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '内业' });
209 218
           this.innerStaffList = innerStaffRes.rows;
219
+          this.innerStaffList = this.innerStaffList.map(staff => {
220
+            return {
221
+              ...staff,
222
+              dayCost: Number(staff.dayCost).toFixed(2),
223
+              performance: Number(staff.performance).toFixed(2),
224
+              amount: Number(staff.amount).toFixed(2),
225
+              staffCost: Number(staff.staffCost).toFixed(2),
226
+              daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
227
+              performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
228
+              amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
229
+            };
230
+          });
210 231
 
211 232
           // 获取外业人员数据
212
-          let outerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId });
233
+          let outerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '外业' });
213 234
           this.outerStaffList = outerStaffRes.rows;
235
+          this.outerStaffList = this.outerStaffList.map(staff => {
236
+            return {
237
+              ...staff,
238
+              dayCost: Number(staff.dayCost).toFixed(2),
239
+              performance: Number(staff.performance).toFixed(2),
240
+              amount: Number(staff.amount).toFixed(2),
241
+              staffCost: Number(staff.staffCost).toFixed(2),
242
+              daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
243
+              performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
244
+              amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
245
+            };
246
+          });
214 247
 
215 248
           // 获取内业绩效额数据
216 249
           let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
@@ -233,17 +266,16 @@ export default {
233 266
       });
234 267
     },
235 268
     getProjectWorkList() {
236
-      getProject(this.taskForm.formId).then(res => {
269
+      getProject(this.row.projectId).then(res => {
237 270
         this.project = res.data;
238 271
       })
239
-      listProjectWork({ pageSize: 999, projectId: this.taskForm.formId }).then(res => {
272
+      listProjectWork({ pageSize: 999, projectId: this.row.projectId }).then(res => {
240 273
         this.workContentList = res.rows;
241 274
       })
242 275
     },
243 276
     // 处理内业人员数据变化
244 277
     handleInnerStaffChange(newList) {
245 278
       this.innerStaffList = newList;
246
-      console.log(newList)
247 279
       // 计算内业人员总成本
248 280
       const totalAmount = this.innerStaffList.reduce((sum, staff) => {
249 281
         return sum + (staff.amountAdjust || 0);
@@ -272,6 +304,30 @@ export default {
272 304
         // updateBudget(this.budgetForm);
273 305
       }
274 306
     },
307
+    async preserve() {
308
+      let obj = {
309
+        budgetId: this.row.budgetId,
310
+        projectId: this.row.projectId,
311
+        checkId: this.taskForm.formId
312
+      }
313
+      let checkRes = await getCheck(this.taskForm.formId);
314
+      if (!checkRes.data) {
315
+        await addCheck(obj);
316
+        this.$emit('preserve');
317
+      }
318
+      await updateBudget(this.budgetForm);
319
+      let staffList = this.innerStaffList.concat(this.outerStaffList);
320
+      delBudgetStaff(this.row.budgetId).then(async res => {
321
+        for (let staff of staffList) {
322
+          staff.budgetId = this.row.budgetId;
323
+          await addBudgetStaff(staff);
324
+        }
325
+      })
326
+      this.$message.success('保存成功');
327
+    },
328
+    confirmSucess() {
329
+
330
+    }
275 331
   },
276 332
 }
277 333
 </script>
@@ -282,7 +338,7 @@ export default {
282 338
 }
283 339
 
284 340
 .main {
285
-  width: 85%;
341
+  width: 90%;
286 342
   margin: 0 auto;
287 343
   text-align: center;
288 344
 }

+ 66
- 17
oa-ui/src/views/flowable/form/budget/adjust/components/InnerStaffCost.vue Просмотреть файл

@@ -7,13 +7,15 @@
7 7
         <td>姓名</td>
8 8
         <td>人员成本(天)</td>
9 9
         <td style="width:120px">预算天数</td>
10
-        <td>预算绩效</td>
11
-        <td style="width:120px">金额</td>
10
+        <td>固定成本合计</td>
11
+        <td>绩效成本合计</td>
12
+        <td style="width:120px">预算金额</td>
13
+        <td class="adjust" style="width:120px">核算固定成本</td>
12 14
         <td class="adjust" style="width:120px">核算天数</td>
13 15
         <td class="adjust" style="width:120px">核算绩效</td>
14 16
         <td class="adjust" style="width:120px">核算金额</td>
15 17
       </tr>
16
-      <tr v-for="staff, index in staffList" :key="'user' + staff.userId">
18
+      <tr v-for="staff, index in staffList" :key="'user' + index">
17 19
         <td>
18 20
           <!-- <el-button type="danger" icon="el-icon-minus" circle plain></el-button> -->
19 21
           <div class="delete-btn" v-if="index + 1 > lens" @click="removeStaff(index)"><i class="el-icon-remove-outline"
@@ -24,20 +26,39 @@
24 26
         <td>{{ staff.user ? staff.user.nickName : '' }}</td>
25 27
         <td>{{ staff.dayCost }}</td>
26 28
         <td>{{ staff.days }}</td>
27
-        <td>{{ staff.performance }}</td>
28
-        <td>{{ staff.amount }}</td>
29
-        <td>
29
+        <td style="text-align:right;">{{ staff.staffCost }}</td>
30
+        <td style="text-align:right;">{{ staff.performance }}</td>
31
+        <td style="text-align:right;">{{ staff.amount }}</td>
32
+        <td style="text-align:right;">{{ (staff.dayCost * staff.daysAdjust).toFixed(2) }}</td>
33
+        <td style="text-align:right;">
30 34
           <el-input-number :controls="false" style="width:100%;" v-model="staff.daysAdjust"
31 35
             @change="handleChange(staff)"></el-input-number>
32 36
         </td>
33
-        <td>
37
+        <td style="text-align:right;">
34 38
           <el-input-number :controls="false" style="width:100%;" v-model="staff.performanceAdjust"
35 39
             @change="handleChange(staff)"></el-input-number>
36 40
         </td>
37
-        <td>
41
+        <td style="text-align:right;">
38 42
           {{ staff.amountAdjust }}
39 43
         </td>
40 44
       </tr>
45
+      <tr>
46
+        <td colspan="5" class="head amount">内业人员成本合计</td>
47
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
48
+          (Number(staff.staffCost) || 0), 0).toFixed(2)}}</td>
49
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
50
+          (Number(staff.performance) || 0), 0).toFixed(2)}}</td>
51
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum + (Number(staff.amount)
52
+          || 0), 0).toFixed(2)}}</td>
53
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
54
+          ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
55
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
56
+          (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
57
+        <td class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }" style="text-align:right;">
58
+          {{staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0).toFixed(2)}}</td>
59
+        <td class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }" style="text-align:right;">
60
+          {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
61
+      </tr>
41 62
     </table>
42 63
     <div class="add-staff mt10">
43 64
       <el-button type="success" plain icon="el-icon-plus" @click="openPeople" size="mini">新增人员</el-button>
@@ -61,6 +82,10 @@ export default {
61 82
     staffList: {
62 83
       type: Array,
63 84
       default: () => []
85
+    },
86
+    settleExpense: {
87
+      type: Number,
88
+      default: 0
64 89
     }
65 90
   },
66 91
   data() {
@@ -70,19 +95,14 @@ export default {
70 95
     }
71 96
   },
72 97
   watch: {
73
-    staffList(newval, oldval) {
74
-      if (oldval.length == 0) {
75
-        this.lens = newval.length;
76
-        console.log(this.lens)
77
-      }
78
-    }
98
+
79 99
   },
80 100
   mounted() {
81
-
101
+    this.lens = this.staffList.length;
82 102
   },
83 103
   methods: {
84 104
     handleChange(staff) {
85
-      staff.amountAdjust = ((Number(staff.staffCost) * Number(staff.daysAdjust)) + Number(staff.settleAdjust)).toFixed(2)
105
+      staff.amountAdjust = ((Number(staff.dayCost || 0) * Number(staff.daysAdjust || 0)) + Number(staff.performanceAdjust || 0)).toFixed(2)
86 106
       this.$emit('update:staffList', this.staffList);
87 107
     },
88 108
     openPeople() {
@@ -93,7 +113,13 @@ export default {
93 113
         v.days = 0;
94 114
         v.settle = 0;
95 115
         v.amount = 0;
96
-        v.user = v
116
+        v.user = v;
117
+        v.dayCost = parseFloat(((v.salary.salary + 1780) * 12) / 365).toFixed(2);
118
+        v.staffCost = 0;
119
+        v.performance = 0;
120
+        v.daysAdjust = 0;
121
+        v.performanceAdjust = 0;
122
+        v.amountAdjust = 0;
97 123
       }
98 124
       this.staffList.push(...val);
99 125
       this.isOpenPeople = false;
@@ -113,6 +139,10 @@ export default {
113 139
           arr.splice(index, 1);
114 140
         }
115 141
       }).catch(() => { });
142
+    },
143
+    isPerformanceExceeded() {
144
+      const totalPerformance = this.staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0);
145
+      return totalPerformance > Number(this.settleExpense);
116 146
     }
117 147
   }
118 148
 }
@@ -144,4 +174,23 @@ export default {
144 174
   cursor: pointer;
145 175
   font-size: 18px;
146 176
 }
177
+
178
+.amount {
179
+  font-weight: bold;
180
+  font-family: Arial, Helvetica, sans-serif;
181
+}
182
+
183
+.head.amount {
184
+  font-weight: bold;
185
+}
186
+
187
+.performance-error {
188
+  background-color: #fef0f0 !important;
189
+  color: #f56c6c !important;
190
+  border: 1px solid #fbc4c4 !important;
191
+}
192
+
193
+.performance-error:hover {
194
+  background-color: #fde2e2 !important;
195
+}
147 196
 </style>

+ 44
- 5
oa-ui/src/views/flowable/form/budget/adjust/components/OuterStaffCost.vue Просмотреть файл

@@ -8,7 +8,10 @@
8 8
         <td>人员成本(天)</td>
9 9
         <td style="width:120px">预算天数</td>
10 10
         <td>预算系数</td>
11
+        <td>固定成本合计</td>
12
+        <td>绩效成本合计</td>
11 13
         <td style="width:120px">金额</td>
14
+        <td class="adjust" style="width:120px">核算固定成本</td>
12 15
         <td class="adjust" style="width:120px">核算天数</td>
13 16
         <td class="adjust" style="width:120px">核算系数</td>
14 17
         <td class="adjust" style="width:120px">核算金额</td>
@@ -24,19 +27,43 @@
24 27
         <td>{{ staff.dayCost }}</td>
25 28
         <td>{{ staff.days }}</td>
26 29
         <td>{{ staff.coefficient }}</td>
27
-        <td>{{ staff.amount }}</td>
28
-        <td>
30
+        <td style="text-align:right;">{{ staff.staffCost }}</td>
31
+        <td style="text-align:right;">{{ staff.performance }}</td>
32
+        <td style="text-align:right;">{{ staff.amount }}</td>
33
+        <td style="text-align:right;">{{ (staff.dayCost * staff.daysAdjust).toFixed(2) }}</td>
34
+        <td style="text-align:right;">
29 35
           <el-input-number :controls="false" style="width:100%;" v-model="staff.daysAdjust"
30 36
             @change="handleChange(staff)"></el-input-number>
31 37
         </td>
32
-        <td>
38
+        <td style="text-align:right;">
33 39
           <el-input-number :controls="false" style="width:100%;" v-model="staff.coefficientAdjust"
34 40
             @change="handleChange(staff)"></el-input-number>
35 41
         </td>
36
-        <td>
42
+        <td style="text-align:right;">
37 43
           {{ staff.amountAdjust }}
38 44
         </td>
39 45
       </tr>
46
+      <tr>
47
+        <td colspan="6" class="head amount">外业人员成本合计</td>
48
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
49
+          (Number(staff.staffCost) || 0),
50
+          0).toFixed(2)}}</td>
51
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
52
+          (Number(staff.performance) || 0),
53
+          0).toFixed(2)}}</td>
54
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
55
+          (Number(staff.amount) || 0),
56
+          0).toFixed(2)}}</td>
57
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
58
+          ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
59
+        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
60
+          (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
61
+        <td class="head amount" style="text-align:right;">
62
+         ——
63
+        </td>
64
+        <td class="head amount" style="text-align:right;">
65
+          {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
66
+      </tr>
40 67
     </table>
41 68
     <div class="add-staff mt10">
42 69
       <el-button type="success" plain icon="el-icon-plus" @click="openPeople" size="mini">新增人员</el-button>
@@ -75,10 +102,13 @@ export default {
75 102
       }
76 103
     }
77 104
   },
105
+  mounted() {
106
+    this.lens = this.staffList.length;
107
+  },
78 108
   methods: {
79 109
     handleChange(staff) {
80 110
       // 计算调整后的金额
81
-      staff.amountAdjust = (Number(staff.staffCost) * Number(staff.daysAdjust) * Number(staff.coefficientAdjust) * Number(staff.otherCoefficientAdjust)).toFixed(2)
111
+      staff.amountAdjust = (Number(staff.dayCost) * Number(staff.daysAdjust) + (200 * Number(staff.daysAdjust) * Number(staff.coefficient))).toFixed(2)
82 112
       this.$emit('update:staffList', this.staffList);
83 113
     },
84 114
     openPeople() {
@@ -141,4 +171,13 @@ export default {
141 171
   cursor: pointer;
142 172
   font-size: 18px;
143 173
 }
174
+
175
+.amount {
176
+  font-weight: bold;
177
+  font-family: Arial, Helvetica, sans-serif;
178
+}
179
+
180
+.head.amount {
181
+  font-weight: bold;
182
+}
144 183
 </style>

+ 150
- 49
oa-ui/src/views/flowable/form/budget/adjust/newBudgetInfo.vue Просмотреть файл

@@ -2,13 +2,18 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-05-07 11:01:39
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-13 18:05:08
5
+ * @LastEditTime: 2025-05-14 14:18:45
6 6
 -->
7 7
 <template>
8 8
   <div class="main" v-loading="loading">
9 9
     <h2 class="text-center">项目直接生产成本预算表</h2>
10 10
     <p style="text-align: center">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}</p>
11 11
     <el-divider></el-divider>
12
+    <div class="mt20 mb20" v-if="showAlter">
13
+      <el-alert title="任务被退回,请修改后重新提交" type="error" :closable="false">
14
+        <return-comment :taskForm="taskForm" @isReturn="isReturn"></return-comment>
15
+      </el-alert>
16
+    </div>
12 17
     <el-descriptions :column="3" border class="descriptions">
13 18
       <el-descriptions-item label="项目编号">
14 19
         {{ project.projectNumber }}
@@ -40,23 +45,12 @@
40 45
               <td style="width: 200px">备注</td>
41 46
             </tr>
42 47
             <tr v-for="(work, index) in workContentList" :key="index">
43
-              <td>
44
-                {{ work.content }}
45
-              </td>
46
-              <td>
47
-                {{ work.scale }}
48
-              </td>
49
-              <td>
50
-                {{ work.unit }}
51
-              </td>
52
-              <td>
53
-                {{ work.workload }}
54
-              </td>
55
-              <td>
56
-                {{ work.deadline }}
57
-              </td>
58
-              <td class="remark-cell">
59
-                {{ work.remark }}
48
+              <td>{{ work.content }}</td>
49
+              <td>{{ work.scale }} </td>
50
+              <td>{{ work.unit }}</td>
51
+              <td>{{ work.workload }}</td>
52
+              <td>{{ work.deadline }}</td>
53
+              <td class="remark-cell">{{ work.remark }}
60 54
               </td>
61 55
             </tr>
62 56
           </table>
@@ -97,12 +91,13 @@
97 91
             <td v-else>
98 92
               {{ work.coefficient }}
99 93
             </td>
100
-            <td style="text-align:right;">{{ work.settle ? work.settle.toFixed(2) : '0.00' }}</td>
94
+            <td style="text-align:right;">{{ work.settle ? Number(work.settle).toFixed(2) : '0.00' }}</td>
101 95
             <td class="remark-cell">{{ work.remark ? work.remark : '' }}</td>
102 96
           </tr>
103 97
           <tr>
104 98
             <td :colspan="7" class="head amount">内业绩效额合计</td>
105
-            <td :colspan="1" class="head amount" style="text-align:right;">
99
+            <td :colspan="1" class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }"
100
+              style="text-align:right;">
106 101
               {{ budgetForm.settleExpense ? budgetForm.settleExpense.toFixed(2) : '0.00' }}
107 102
             </td>
108 103
             <td></td>
@@ -126,27 +121,28 @@
126 121
             <td>{{ staff.user ? staff.user.nickName : '' }}</td>
127 122
             <td>{{ staff.dayCost }}</td>
128 123
             <td v-if="taskName == '分管审核'">
129
-              <el-input-number style="width:80px;" :controls="false" v-model="staff.days" :min="0"
130
-                :step="0.01" @change="(val) => updateInnerStaffAmount(staff, val, 'days')"></el-input-number>
124
+              <el-input-number style="width:80px;" :controls="false" v-model="staff.days" :min="0" :step="0.01"
125
+                @change="(val) => updateInnerStaffAmount(staff, val, 'days')"></el-input-number>
131 126
             </td>
132 127
             <td v-else>{{ staff.days }}</td>
133 128
             <td style="text-align:right;">{{ staff.staffCost }}</td>
134 129
             <td v-if="taskName == '分管审核'">
135
-              <el-input-number style="width:80px;" :controls="false" v-model="staff.performance" :min="0"
136
-                :step="0.01" @change="(val) => updateInnerStaffAmount(staff, val, 'performance')"></el-input-number>
130
+              <el-input-number style="width:80px;" :controls="false" v-model="staff.performance" :min="0" :step="0.01"
131
+                @change="(val) => updateInnerStaffAmount(staff, val, 'performance')"></el-input-number>
137 132
             </td>
138
-            <td v-else style="text-align:right;">{{ staff.performance }}</td>
133
+            <td v-else>{{ staff.performance }}</td>
139 134
             <td style="text-align:right;">{{ staff.amount }}</td>
140 135
             <td class="remark-cell">{{ staff.remark }}</td>
141
-          </tr> 
136
+          </tr>
142 137
           <tr>
143 138
             <td colspan="4" class="head amount">内业人员成本合计</td>
144 139
             <td class="head amount" style="text-align:right;">{{innerStaffList.reduce((sum, staff) => sum +
145 140
               (Number(staff.staffCost) || 0),
146 141
               0).toFixed(2)}}</td>
147
-            <td class="head amount" style="text-align:right;">{{innerStaffList.reduce((sum, staff) => sum +
148
-              (Number(staff.performance) || 0),
149
-              0).toFixed(2)}}</td>
142
+            <td class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }" style="text-align:right;">
143
+              {{innerStaffList.reduce((sum, staff) => sum +
144
+                (Number(staff.performance) || 0),
145
+                0).toFixed(2)}}</td>
150 146
             <td class="head amount" style="text-align:right;">{{innerStaffList.reduce((sum, staff) => sum +
151 147
               (Number(staff.amount) || 0),
152 148
               0).toFixed(2)}}</td>
@@ -173,13 +169,13 @@
173 169
             <td>{{ staff.dayCost }}</td>
174 170
             <td>200</td>
175 171
             <td v-if="taskName == '分管审核'">
176
-              <el-input-number style="width:80px;" :controls="false" v-model="staff.days" :min="0"
177
-                :step="0.01" @change="(val) => updateOuterStaffAmount(staff, val, 'days')"></el-input-number>
172
+              <el-input-number style="width:80px;" :controls="false" v-model="staff.days" :min="0" :step="0.01"
173
+                @change="(val) => updateOuterStaffAmount(staff, val, 'days')"></el-input-number>
178 174
             </td>
179 175
             <td v-else>{{ staff.days }}</td>
180 176
             <td v-if="taskName == '分管审核'">
181
-              <el-input-number style="width:80px;" :controls="false" v-model="staff.coefficient" :min="0"
182
-                :step="0.01" @change="(val) => updateOuterStaffAmount(staff, val, 'coefficient')"></el-input-number>
177
+              <el-input-number style="width:80px;" :controls="false" v-model="staff.coefficient" :min="0" :step="0.01"
178
+                @change="(val) => updateOuterStaffAmount(staff, val, 'coefficient')"></el-input-number>
183 179
             </td>
184 180
             <td v-else>{{ staff.coefficient }}</td>
185 181
             <td style="text-align:right;">{{ staff.staffCost }}</td>
@@ -215,8 +211,8 @@
215 211
             <td>{{ car.car ? car.car.licensePlate : '' }}</td>
216 212
             <td>{{ car.car ? car.car.dayCost : '' }}</td>
217 213
             <td v-if="taskName == '分管审核'">
218
-              <el-input-number style="width:80px;" :controls="false" v-model="car.days" :min="0"
219
-                :step="0.01" @change="(val) => updateCarAmount(car, val)"></el-input-number>
214
+              <el-input-number style="width:80px;" :controls="false" v-model="car.days" :min="0" :step="0.01"
215
+                @change="(val) => updateCarAmount(car, val)"></el-input-number>
220 216
             </td>
221 217
             <td v-else>{{ car.days }}</td>
222 218
             <td style="text-align:right;">{{ car.amount }}</td>
@@ -247,8 +243,8 @@
247 243
             <td>{{ device.device ? device.device.brand : '' }}</td>
248 244
             <td>{{ device.device ? device.device.dayCost : '' }}</td>
249 245
             <td v-if="taskName == '分管审核'">
250
-              <el-input-number style="width:80px;" :controls="false" v-model="device.days" :min="0"
251
-                :step="0.01" @change="(val) => updateDeviceAmount(device, val)"></el-input-number>
246
+              <el-input-number style="width:80px;" :controls="false" v-model="device.days" :min="0" :step="0.01"
247
+                @change="(val) => updateDeviceAmount(device, val)"></el-input-number>
252 248
             </td>
253 249
             <td v-else>{{ device.days }}</td>
254 250
             <td style="text-align:right;">{{ device.amount }}</td>
@@ -266,13 +262,17 @@
266 262
           <tr style="background-color:#f8f8f9">
267 263
             <td>序号</td>
268 264
             <td>开支项</td>
269
-            <td>金额</td>
265
+            <td style="min-width:120px">金额</td>
270 266
             <td>备注</td>
271 267
           </tr>
272 268
           <tr v-for="site, index in siteList" :key="'site' + site.expenseId">
273 269
             <td>{{ index + 1 }}</td>
274 270
             <td>{{ site.name }}</td>
275
-            <td style="text-align:right;">{{ site.amount }}</td>
271
+            <td v-if="taskName == '分管审核'">
272
+              <el-input-number style="width:100%;" :controls="false" v-model="site.amount" :min="0" :step="0.01"
273
+                @change="(val) => updateSiteAmount(site, val)"></el-input-number>
274
+            </td>
275
+            <td v-else style="text-align:right;">{{ site.amount }}</td>
276 276
             <td class="remark-cell">{{ site.remark }}</td>
277 277
           </tr>
278 278
           <tr>
@@ -362,20 +362,24 @@
362 362
           </tr>
363 363
           <tr>
364 364
             <td>人员成本</td>
365
-            <td style="text-align:right;">{{ isNaN(budgetForm.staffCost) ? 0 : Number(budgetForm.staffCost).toFixed(2) }}</td>
365
+            <td style="text-align:right;">{{ isNaN(budgetForm.staffCost) ? 0 : Number(budgetForm.staffCost).toFixed(2)
366
+            }}</td>
366 367
           </tr>
367 368
           <tr>
368 369
             <td>车辆成本</td>
369
-            <td style="text-align:right;">{{ isNaN(budgetForm.carCost) ? 0 : Number(budgetForm.carCost).toFixed(2) }}</td>
370
+            <td style="text-align:right;">{{ isNaN(budgetForm.carCost) ? 0 : Number(budgetForm.carCost).toFixed(2) }}
371
+            </td>
370 372
           </tr>
371 373
           <tr>
372 374
             <td>设备成本</td>
373
-            <td style="text-align:right;">{{ isNaN(budgetForm.deviceCost) ? 0 : Number(budgetForm.deviceCost).toFixed(2) }}</td>
375
+            <td style="text-align:right;">{{ isNaN(budgetForm.deviceCost) ? 0 : Number(budgetForm.deviceCost).toFixed(2)
376
+            }}</td>
374 377
           </tr>
375 378
           <tr>
376 379
             <td>现场开支成本</td>
377
-            <td style="text-align:right;">{{ isNaN(budgetForm.siteSum) ? 0 : Number(budgetForm.siteSum).toFixed(2) }}</td>
378
-          </tr> 
380
+            <td style="text-align:right;">{{ isNaN(budgetForm.siteSum) ? 0 : Number(budgetForm.siteSum).toFixed(2) }}
381
+            </td>
382
+          </tr>
379 383
           <tr>
380 384
             <td>经营相关成本</td>
381 385
             <td style="text-align:right;">{{ isNaN(totalJYAmount) ? 0 : Number(totalJYAmount).toFixed(2) }}</td>
@@ -386,6 +390,20 @@
386 390
           </tr>
387 391
         </table>
388 392
       </el-descriptions-item>
393
+      <el-descriptions-item label="合同总价" :span="3" v-if="$store.getters.roles.includes('leader')">
394
+        <table border="1" style="width:100%;">
395
+          <tr style="background-color:#f8f8f9">
396
+            <td>序号</td>
397
+            <td>合同名称</td>
398
+            <td>合同总价</td>
399
+          </tr>
400
+          <tr v-for="contract, index in contractList" :key="contract.contractId">
401
+            <td>{{ index + 1 }}</td>
402
+            <td>{{ contract.contractName }}</td>
403
+            <td>{{ contract.amount }}</td>
404
+          </tr>
405
+        </table>
406
+      </el-descriptions-item>
389 407
       <el-descriptions-item label="分管领导审核意见" :span="3">
390 408
         <div v-if="taskName == '分管审核' && !budgetForm.managerComment" class="alert alert-warning"
391 409
           style="padding: 10px; border: 1px solid #f0ad4e; background-color: #fcf8e3; color: #8a6d3b;">
@@ -434,12 +452,14 @@ import { listBudget, updateBudget } from "@/api/oa/budget/budget";
434 452
 import { listBudgetCar, updateBudgetCar } from "@/api/oa/budget/budgetCar";
435 453
 import { listBudgetDevice, updateBudgetDevice } from "@/api/oa/budget/budgetDevice";
436 454
 import { listBudgetSettle, updateBudgetSettle } from "@/api/oa/budget/budgetSettle";
437
-import { listBudgetStaff } from "@/api/oa/budget/budgetStaff";
455
+import { listBudgetStaff, updateBudgetStaff } from "@/api/oa/budget/budgetStaff";
438 456
 import { listProjectWork } from "@/api/oa/project/projectWork";
439
-import { listSite } from "@/api/oa/budget/budgetSite.js";
457
+import { listSite, updateSite } from "@/api/oa/budget/budgetSite.js";
440 458
 import { getProject } from "@/api/oa/project/project";
441 459
 import { getUsersManageLeader, getUserByPost } from "@/api/system/post";
442 460
 import { complete, getNextFlowNode } from "@/api/flowable/todo";
461
+import { listProjectContract } from "@/api/oa/contract/projectContract";
462
+import { getContract } from "@/api/oa/contract/contract";
443 463
 import InnerStaffCost from './components/InnerStaffCost.vue';
444 464
 import OuterStaffCost from './components/OuterStaffCost.vue';
445 465
 import CarCost from './components/CarCost.vue';
@@ -479,11 +499,14 @@ export default {
479 499
       siteList: [],
480 500
       totalJYAmount: 0,
481 501
       returnOpen: false,
502
+      contractList: [],
503
+      showAlter: true,
482 504
     }
483 505
   },
484 506
   created() {
485 507
     this.initBudgetForm();
486 508
     this.getProjectWorkList();
509
+    this.getContractInfo();
487 510
   },
488 511
   methods: {
489 512
     initBudgetForm() {
@@ -567,12 +590,29 @@ export default {
567 590
           let siteRes = await listSite({ pageSize: 100, budgetId });
568 591
           this.siteList = siteRes.rows;
569 592
           this.budgetForm.siteSum = this.siteList.reduce((sum, site) => sum + (Number(site.amount) || 0), 0);
593
+
594
+          // 检查内业人员绩效总额是否超过内业绩效总额
595
+          const totalPerformance = this.innerStaffList.reduce((sum, staff) => sum + (Number(staff.performance) || 0), 0);
596
+          if (totalPerformance > Number(this.budgetForm.settleExpense)) {
597
+            this.$message.warning('内业人员绩效总额超过内业绩效总额,请检查');
598
+          }
570 599
         }
571 600
         this.loading = false;
572 601
       }).catch(() => {
573 602
         this.loading = false;
574 603
       });
575 604
     },
605
+    getContractInfo() {
606
+      listProjectContract({ projectId: this.taskForm.formId }).then(res => {
607
+        let contractIds = res.rows;
608
+        this.contractList = [];
609
+        for (let contractId of contractIds) {
610
+          getContract(contractId.contractId).then(response => {
611
+            this.contractList.push(response.data);
612
+          })
613
+        }
614
+      })
615
+    },
576 616
     safeNumber(value) {
577 617
       const num = Number(value);
578 618
       return isNaN(num) ? 0 : num;
@@ -586,6 +626,7 @@ export default {
586 626
       })
587 627
     },
588 628
     async preserve() {
629
+      this.$message.warning('正在保存,请勿关闭页面');
589 630
       if (this.taskName == '分管审核') {
590 631
         this.budgetForm.manager = this.$store.getters.userId;
591 632
         this.budgetForm.managerTime = this.parseTime(new Date(), '{y}-{m}-{d}');
@@ -593,6 +634,16 @@ export default {
593 634
         this.budgetForm.auditor = this.$store.getters.userId;
594 635
         this.budgetForm.zjlTime = this.parseTime(new Date(), '{y}-{m}-{d}');
595 636
       }
637
+      if (this.taskName != '经营审核') {
638
+        await Promise.all([
639
+          ...this.carList.map(car => updateBudgetCar(car)),
640
+          ...this.deviceList.map(device => updateBudgetDevice(device)),
641
+          ...this.innerStaffList.map(staff => updateBudgetStaff(staff)),
642
+          ...this.outerStaffList.map(staff => updateBudgetStaff(staff)),
643
+          ...this.workList.map(work => updateBudgetSettle(work)),
644
+          ...this.siteList.map(site => updateSite(site))
645
+        ]);
646
+      }
596 647
       await updateBudget(this.budgetForm)
597 648
       this.$message.success('保存成功');
598 649
     },
@@ -611,10 +662,19 @@ export default {
611 662
             return
612 663
           }
613 664
           let zjlRes = await getUserByPost({ postName: '总经理' });
614
-          let zjlUserId = zjlRes.data.userId;
665
+          let zjlUserId = zjlRes.data[0].userId;
615 666
           this.$set(this.taskForm.variables, 'approval', zjlUserId);
616 667
         }
617
-        return
668
+        else if (this.taskName == '总经理审核') {
669
+          if (!this.budgetForm.zjlComment) {
670
+            this.$message.error('请填写审核意见')
671
+            return
672
+          }
673
+          let dszRes = await getUserByPost({ postName: '董事长' });
674
+          let dszUserId = dszRes.data[0].userId;
675
+          this.$set(this.taskForm.variables, 'approval', dszUserId);
676
+          this.$set(this.taskForm.variables, "skip", true);
677
+        }
618 678
         //提交到下一个流程
619 679
         getNextFlowNode({ taskId: this.taskForm.taskId }).then(res => {
620 680
           complete(this.taskForm).then(response => {
@@ -630,7 +690,6 @@ export default {
630 690
         Number(this.budgetForm.winExpense || 0) +
631 691
         Number(this.budgetForm.taxExpense || 0) +
632 692
         Number(this.budgetForm.travelExpense || 0);
633
-      // Calculate total budget by adding all components
634 693
       const innerStaffTotal = this.innerStaffList.reduce((sum, staff) => sum + (Number(staff.amount) || 0), 0);
635 694
       const outerStaffTotal = this.outerStaffList.reduce((sum, staff) => sum + (Number(staff.amount) || 0), 0);
636 695
       const carTotal = this.carList.reduce((sum, car) => sum + (Number(car.amount) || 0), 0);
@@ -666,8 +725,13 @@ export default {
666 725
       staff.amount = (Number(staff.staffCost) + Number(staff.performance)).toFixed(2);
667 726
       let innerStaffTotal = this.innerStaffList.reduce((sum, staff) => sum + (Number(staff.amount) || 0), 0);
668 727
       let outerStaffTotal = this.outerStaffList.reduce((sum, staff) => sum + (Number(staff.amount) || 0), 0);
728
+      let innerStaffPerformance = this.innerStaffList.reduce((sum, staff) => sum + (Number(staff.performance) || 0), 0);
669 729
       this.budgetForm.staffCost = (innerStaffTotal + outerStaffTotal).toFixed(2);
670 730
       this.updateTotalJYAmount();
731
+      if (innerStaffPerformance > this.budgetForm.settleExpense) {
732
+        this.$message.error('内业人员成本超过内业绩效总额,请修改');
733
+        return;
734
+      }
671 735
     },
672 736
     updateOuterStaffAmount(staff, value, field) {
673 737
       staff[field] = value;
@@ -681,18 +745,37 @@ export default {
681 745
     updateCarAmount(car, value) {
682 746
       car.days = value;
683 747
       car.amount = (Number(car.car.dayCost) * Number(car.days)).toFixed(2);
748
+      let carTotal = this.carList.reduce((sum, car) => sum + (Number(car.amount) || 0), 0);
749
+      this.budgetForm.carCost = carTotal.toFixed(2);
684 750
       this.updateTotalJYAmount();
685 751
     },
686 752
     updateDeviceAmount(device, value) {
687 753
       device.days = value;
688 754
       device.amount = (Number(device.device.dayCost) * Number(device.days)).toFixed(2);
755
+      let deviceTotal = this.deviceList.reduce((sum, device) => sum + (Number(device.amount) || 0), 0);
756
+      this.budgetForm.deviceCost = deviceTotal.toFixed(2);
689 757
       this.updateTotalJYAmount();
690 758
     },
759
+    updateSiteAmount(site, value) {
760
+      site.amount = value;
761
+      let siteTotal = this.siteList.reduce((sum, site) => sum + (Number(site.amount) || 0), 0);
762
+      this.budgetForm.siteSum = siteTotal.toFixed(2);
763
+      this.updateTotalJYAmount();
764
+    },
765
+    isPerformanceExceeded() {
766
+      const totalPerformance = this.innerStaffList.reduce((sum, staff) => sum + (Number(staff.performance) || 0), 0);
767
+      return totalPerformance > Number(this.budgetForm.settleExpense);
768
+    },
769
+    isReturn(val) {
770
+      this.showAlter = val;
771
+    },
691 772
   },
692 773
 }
693 774
 </script>
694 775
 
695 776
 <style lang="scss" scoped>
777
+@import "@/assets/styles/element-reset.scss";
778
+
696 779
 .mylabel {
697 780
   font-weight: bold;
698 781
 }
@@ -794,4 +877,22 @@ table {
794 877
   line-height: 30px;
795 878
   /* 如果需要垂直居中 */
796 879
 }
880
+
881
+.performance-error {
882
+  background-color: #fef0f0 !important;
883
+  color: #f56c6c !important;
884
+  border: 1px solid #fbc4c4 !important;
885
+}
886
+
887
+.performance-error:hover {
888
+  background-color: #fde2e2 !important;
889
+}
890
+
891
+.performance-error .el-input-number {
892
+  .el-input__inner {
893
+    background-color: #fef0f0;
894
+    border-color: #f56c6c;
895
+    color: #f56c6c;
896
+  }
897
+}
797 898
 </style>

+ 6
- 2
oa-ui/src/views/flowable/form/components/detailDisplay.vue Просмотреть файл

@@ -54,6 +54,8 @@
54 54
       @goBack="goBack"></performance-form>
55 55
     <study-form :taskName="taskName" :taskForm="taskForm" v-else-if="taskForm.procDefName == '参培审核'"
56 56
       @goBack="goBack"></study-form>
57
+    <adjust-index :taskName="taskName" :taskForm="taskForm" v-else-if="taskForm.procDefName == '项目核算'"
58
+      @goBack="goBack"></adjust-index>
57 59
   </div>
58 60
 </template>
59 61
 
@@ -86,7 +88,8 @@ import declareForm from '@/views/flowable/form/work/declareForm.vue';
86 88
 import procureForm from '@/views/flowable/form/procure/procureForm.vue';
87 89
 import outsourceForm from '@/views/flowable/form/outsource/outsourceForm.vue';
88 90
 import PerformanceForm from '@/views/flowable/form/performance/performanceForm.vue';
89
-import StudyForm from "@/views/flowable/form//oa/studyForm.vue";
91
+import StudyForm from "@/views/flowable/form/oa/studyForm.vue";
92
+import AdjustIndex from '@/views/flowable/form/budget/adjust/adjustIndex.vue';
90 93
 export default {
91 94
   components: {
92 95
     ScTable,
@@ -117,7 +120,8 @@ export default {
117 120
     procureForm,
118 121
     outsourceForm,
119 122
     PerformanceForm,
120
-    StudyForm
123
+    StudyForm,
124
+    AdjustIndex,
121 125
   },
122 126
   props: {
123 127
     taskForm: {

+ 5
- 42
oa-ui/src/views/flowable/task/myProcess/index.vue Просмотреть файл

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-01-03 09:23:11
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-04 14:27:27
5
+ * @LastEditTime: 2025-05-14 15:41:49
6 6
 -->
7 7
 <template>
8 8
   <div class="app-container">
@@ -75,18 +75,6 @@
75 75
 
76 76
     <!-- 发起流程 -->
77 77
     <el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
78
-      <div v-if="$store.getters.userId == 1">
79
-        <el-select v-model="queryType" style="width: 120px;">
80
-          <el-option label="项目编号" value="1"></el-option>
81
-          <el-option label="项目名称" value="2"></el-option>
82
-        </el-select>
83
-        <el-select v-model="projectId" clearable filterable remote reserve-keyword placeholder="请输入关键字"
84
-          :remote-method="remoteMethod" style="width: 300px;">
85
-          <el-option v-for="project in projectList" :key="project.projectId"
86
-            :label="project.projectNumber + '-' + project.projectName" :value="project.projectId">
87
-          </el-option>
88
-        </el-select>
89
-      </div>
90 78
       <progress-tree :definitionList="definitionList" @confirm="handleStartProcess"
91 79
         @close="open = false"></progress-tree>
92 80
     </el-dialog>
@@ -127,8 +115,6 @@ export default {
127 115
   },
128 116
   data() {
129 117
     return {
130
-      queryType: '1',
131
-      projectId: '',
132 118
       projectList: [],
133 119
       // 遮罩层
134 120
       loading: true,
@@ -292,27 +278,6 @@ export default {
292 278
         })
293 279
       }
294 280
     },
295
-    remoteMethod(val) {
296
-      let params1 = {
297
-        pageNum: 1,
298
-        pageSize: 20,
299
-        projectNumber: val
300
-      }
301
-      let params2 = {
302
-        pageNum: 1,
303
-        pageSize: 20,
304
-        projectName: val
305
-      }
306
-      let params = {};
307
-      if (this.queryType == '1') {
308
-        params = params1
309
-      } else {
310
-        params = params2
311
-      }
312
-      listProject(params).then(res => {
313
-        this.projectList = res.rows;
314
-      })
315
-    },
316 281
     /** 新增按钮操作 */
317 282
     handleAdd() {
318 283
       this.open = true;
@@ -338,10 +303,10 @@ export default {
338 303
           return
339 304
         }
340 305
       }
341
-      // if (row.category == "assess" || row.category == "car" || ) {
342 306
       let formId = new Snowflake(1n, 1n, 0n).nextId().toString();
343 307
       getNextFlowNodeByStart({ deploymentId: row.deploymentId, variables: { formId: formId } }).then(res => {
344 308
         let data = res.data;
309
+        debugger
345 310
         if (data.dataType === 'dynamic' && row.name != '项目预算') {
346 311
           if (data.type === 'assignee') { // 指定人员
347 312
             this.checkSendUser = true;
@@ -369,8 +334,8 @@ export default {
369 334
             variables.variables = formData;
370 335
             let routePath = this.getRoutePath(row);
371 336
             if (row.name == '项目预算') {
372
-              variables.approval = 1;
373
-              formData.formId = this.projectId;
337
+              variables.approval = this.$store.getters.userId;
338
+              formData.formId = row.projectId;
374 339
             }
375 340
             // 启动流程并将表单数据加入流程变量
376 341
             definitionStart(row.id, JSON.stringify(variables)).then(res => {
@@ -384,10 +349,8 @@ export default {
384 349
                 if (records.length == 1) {
385 350
                   records = records[0]
386 351
                 }
387
-                if(row.name == '项目预算'){
352
+                if (row.name == '项目预算') {
388 353
                   this.open = false;
389
-                  this.getList();
390
-                  return
391 354
                 }
392 355
                 this.$router.push({
393 356
                   path: routePath,

+ 78
- 5
oa-ui/src/views/flowable/task/myProcess/progressTree.vue Просмотреть файл

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2024-04-18 15:14:45
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-02-26 15:03:14
5
+ * @LastEditTime: 2025-05-14 15:40:11
6 6
 -->
7 7
 <template>
8 8
   <div>
@@ -24,10 +24,33 @@
24 24
       <el-button type="primary" @click="confirm">确定</el-button>
25 25
       <el-button @click="$emit('close')">取消</el-button>
26 26
     </div>
27
+
28
+    <!-- 项目编号选择对话框 -->
29
+    <el-dialog title="请选择将要发起预算的项目" :visible.sync="projectDialogVisible" width="30%" append-to-body>
30
+      <el-form :model="projectForm" label-width="80px">
31
+        <el-form-item>
32
+          <el-select v-model="queryType" style="width: 120px;">
33
+            <el-option label="项目编号" value="1"></el-option>
34
+            <el-option label="项目名称" value="2"></el-option>
35
+          </el-select>
36
+          <el-select v-model="projectId" clearable filterable remote reserve-keyword placeholder="请输入关键字"
37
+            :remote-method="remoteMethod" style="width: 300px;">
38
+            <el-option v-for="project in projectList" :key="project.projectId"
39
+              :label="project.projectNumber + '-' + project.projectName" :value="project.projectId">
40
+            </el-option>
41
+          </el-select>
42
+        </el-form-item>
43
+      </el-form>
44
+      <div slot="footer" class="dialog-footer">
45
+        <el-button @click="projectDialogVisible = false">取 消</el-button>
46
+        <el-button type="primary" @click="handleProjectConfirm">确 定</el-button>
47
+      </div>
48
+    </el-dialog>
27 49
   </div>
28 50
 </template>
29 51
 
30 52
 <script>
53
+import { listProject } from '@/api/oa/project/project';
31 54
 export default {
32 55
   props: {
33 56
     definitionList: {
@@ -47,7 +70,15 @@ export default {
47 70
         children: "children",
48 71
         label: "name",
49 72
       },
50
-      clickNode: {}
73
+      clickNode: {},
74
+      projectDialogVisible: false,
75
+      projectForm: {
76
+        projectId: ''
77
+      },
78
+      projectList: [], // 项目列表数据
79
+      timeout: null,
80
+      queryType: '1',
81
+      projectId: ''
51 82
     };
52 83
   },
53 84
   mounted() { },
@@ -80,10 +111,15 @@ export default {
80 111
           this.treeData[0].children.push(i);
81 112
         }
82 113
         else if (i.category == "project") {
83
-          if (i.name != "项目预算" && i.name != "安全交底" && i.name != "技术交底" && i.name != "技术方案")
114
+          if (i.name != "项目预算" && i.name != "安全交底" && i.name != "技术交底" && i.name != "技术方案" && i.name != "项目核算")
84 115
             this.treeData[1].children.push(i);
85 116
           if (i.name == "项目预算") {
86
-            if (this.$store.getters.userId == 1) {
117
+            if (this.$store.getters.roles.includes('projectLeader')) {
118
+              this.treeData[1].children.push(i);
119
+            }
120
+          }
121
+          if (i.name == "项目核算") {
122
+            if (this.$store.getters.roles.includes('nfinance')) {
87 123
               this.treeData[1].children.push(i);
88 124
             }
89 125
           }
@@ -100,7 +136,44 @@ export default {
100 136
       this.clickNode = data
101 137
     },
102 138
     confirm() {
103
-      this.$emit('confirm', this.clickNode)
139
+      if (this.clickNode.name == "项目预算") {
140
+        this.projectDialogVisible = true;
141
+      } else {
142
+        this.$emit('confirm', this.clickNode)
143
+      }
144
+    },
145
+    remoteMethod(val) {
146
+      let params1 = {
147
+        pageNum: 1,
148
+        pageSize: 20,
149
+        projectNumber: val
150
+      }
151
+      let params2 = {
152
+        pageNum: 1,
153
+        pageSize: 20,
154
+        projectName: val
155
+      }
156
+      let params = {};
157
+      if (this.queryType == '1') {
158
+        params = params1
159
+      } else {
160
+        params = params2
161
+      }
162
+      listProject(params).then(res => {
163
+        this.projectList = res.rows;
164
+      })
165
+    },
166
+    handleProjectConfirm() {
167
+      if (!this.projectId) {
168
+        this.$message.warning('请选择项目');
169
+        return;
170
+      }
171
+      const selectedData = {
172
+        ...this.clickNode,
173
+        projectId: this.projectId,
174
+      };
175
+      this.$emit('confirm', selectedData);
176
+      this.projectDialogVisible = false;
104 177
     }
105 178
   },
106 179
 };

Загрузка…
Отмена
Сохранить