Browse Source

更新核算编制,修改预算、核算的内业绩效额

余思翰 3 weeks ago
parent
commit
5f5ab25298

+ 1
- 0
oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcCheckPriceController.java View File

131
         JSONObject price = new JSONObject();
131
         JSONObject price = new JSONObject();
132
         price.put("id", cmcCheckPriceList.get(0).getId());
132
         price.put("id", cmcCheckPriceList.get(0).getId());
133
         price.put("unit", cmcCheckPriceList.get(0).getUnit());
133
         price.put("unit", cmcCheckPriceList.get(0).getUnit());
134
+        price.put("remark", cmcCheckPriceList.get(0).getRemark());
134
         if (groundType.equals("0"))
135
         if (groundType.equals("0"))
135
             price.put("price", cmcCheckPriceList.get(0).getCommonPrice());
136
             price.put("price", cmcCheckPriceList.get(0).getCommonPrice());
136
         else
137
         else

+ 1
- 1
oa-back/ruoyi-system/src/main/java/com/ruoyi/oa/domain/CmcWage.java View File

71
     private BigDecimal payableWage;
71
     private BigDecimal payableWage;
72
 
72
 
73
     /** 公积金 */
73
     /** 公积金 */
74
-    @Excel(name = "公积金")
74
+    @Excel(name = "公积金单位部分")
75
     private BigDecimal houseFund;
75
     private BigDecimal houseFund;
76
 
76
 
77
     /** 养老保险 */
77
     /** 养老保险 */

+ 17
- 1
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcBudgetSettleMapper.xml View File

16
         <result property="settle"    column="settle"    />
16
         <result property="settle"    column="settle"    />
17
         <result property="remark"    column="remark"    />
17
         <result property="remark"    column="remark"    />
18
         <association property="cmcPrice"    javaType="CmcPrice"         resultMap="CmcPriceResult" />
18
         <association property="cmcPrice"    javaType="CmcPrice"         resultMap="CmcPriceResult" />
19
+        <association property="cmcCheckPrice"    javaType="CmcCheckPrice"         resultMap="CmcCheckPriceResult" />
19
     </resultMap>
20
     </resultMap>
20
 
21
 
21
     <resultMap type="CmcPrice" id="CmcPriceResult">
22
     <resultMap type="CmcPrice" id="CmcPriceResult">
29
         <result property="complexPrice"    column="complex_price"    />
30
         <result property="complexPrice"    column="complex_price"    />
30
     </resultMap>
31
     </resultMap>
31
 
32
 
33
+    <resultMap type="CmcCheckPrice" id="CmcCheckPriceResult">
34
+        <result property="id"    column="id"    />
35
+        <result property="workType"    column="check_work_type"    />
36
+        <result property="workItem"    column="check_work_item"    />
37
+        <result property="subItem"    column="check_sub_item"    />
38
+        <result property="scaleGrade"    column="check_scale_grade"    />
39
+        <result property="unit"    column="check_unit"    />
40
+        <result property="commonPrice"    column="check_common_price"    />
41
+        <result property="complexPrice"    column="check_complex_price"    />
42
+        <result property="remark"    column="check_remark"    />
43
+    </resultMap>
44
+
32
     <sql id="selectCmcBudgetSettleVo">
45
     <sql id="selectCmcBudgetSettleVo">
33
-        select bs.budget_settle_id, bs.budget_id, bs.content, bs.price_id, bs.check_price_id, p.work_type, p.work_item, p.sub_item, p.scale_grade, p.unit, p.common_price, p.complex_price, bs.workload, bs.coefficient, bs.ground_type, bs.settle , bs.remark from cmc_budget_settle as bs
46
+        select bs.budget_settle_id, bs.budget_id, bs.content, bs.price_id, bs.check_price_id, p.work_type, p.work_item, p.sub_item, p.scale_grade, p.unit, 
47
+        p.common_price, p.complex_price, cp.work_type as check_work_type, cp.work_item as check_work_item, cp.sub_item as check_sub_item, cp.scale_grade as check_scale_grade, 
48
+        cp.unit as check_unit, cp.common_price as check_common_price, cp.complex_price as check_complex_price, cp.remark as check_remark, bs.workload, bs.coefficient, 
49
+        bs.ground_type, bs.settle , bs.remark from cmc_budget_settle as bs
34
         left join cmc_price as p on p.id = bs.price_id
50
         left join cmc_price as p on p.id = bs.price_id
35
         left join cmc_check_price as cp on cp.id = bs.check_price_id
51
         left join cmc_check_price as cp on cp.id = bs.check_price_id
36
     </sql>
52
     </sql>

+ 11
- 2
oa-ui/src/api/oa/wage/wage.js View File

1
 /*
1
 /*
2
  * @Author: wrh
2
  * @Author: wrh
3
  * @Date: 2024-09-19 16:09:52
3
  * @Date: 2024-09-19 16:09:52
4
- * @LastEditors: wrh
5
- * @LastEditTime: 2024-09-27 11:21:46
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-05-15 10:26:51
6
  */
6
  */
7
 import request from '@/utils/request'
7
 import request from '@/utils/request'
8
 
8
 
22
     method: 'get'
22
     method: 'get'
23
   })
23
   })
24
 }
24
 }
25
+// 查询员工工资详细
26
+export function getUserDayValue(query) {
27
+  return request({
28
+    url: '/oa/wage/userDayValue',
29
+    method: 'get',
30
+    params: query
31
+  })
32
+}
33
+
25
 
34
 
26
 // 新增员工工资
35
 // 新增员工工资
27
 export function addWage(data) {
36
 export function addWage(data) {

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

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-06-21 18:51:51
3
  * @Date: 2024-06-21 18:51:51
4
  * @LastEditors: Please set LastEditors
4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-13 16:51:36
5
+ * @LastEditTime: 2025-05-15 18:12:10
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
135
       <el-button type="primary" @click="submitNextFlow" v-if="taskName == '预算批准'">提交下一个流程</el-button>
135
       <el-button type="primary" @click="submitNextFlow" v-if="taskName == '预算批准'">提交下一个流程</el-button>
136
       <el-button type="primary" @click="submitNextFlow" v-else>结算批准</el-button>
136
       <el-button type="primary" @click="submitNextFlow" v-else>结算批准</el-button>
137
     </div>
137
     </div>
138
-    <el-dialog title="表单预览" :visible.sync="viewOpen" width="70%" append-to-body>
138
+    <el-dialog title="表单预览" :visible.sync="viewOpen" width="75%" append-to-body>
139
       <!-- <budget-info :taskName="taskName" :taskForm="taskForm" @goBack="$emit('goBack')"></budget-info> -->
139
       <!-- <budget-info :taskName="taskName" :taskForm="taskForm" @goBack="$emit('goBack')"></budget-info> -->
140
       <new-budget-info :taskName="taskName" :taskForm="taskForm"></new-budget-info>
140
       <new-budget-info :taskName="taskName" :taskForm="taskForm"></new-budget-info>
141
     </el-dialog>
141
     </el-dialog>
162
 import ReturnBtn from "@/views/flowable/form/components/flowBtn/returnBtn.vue";
162
 import ReturnBtn from "@/views/flowable/form/components/flowBtn/returnBtn.vue";
163
 import CarTable from "./carTable.vue";
163
 import CarTable from "./carTable.vue";
164
 import MoneyTable from "./moneyTable.vue";
164
 import MoneyTable from "./moneyTable.vue";
165
-import PeopleTable from "./staffTable.vue";
166
 import DeviceTable from "./deviceTable.vue";
165
 import DeviceTable from "./deviceTable.vue";
167
 import OtherTable from "./otherTable.vue";
166
 import OtherTable from "./otherTable.vue";
168
 import SiteExpenses from "./siteExpenses.vue";
167
 import SiteExpenses from "./siteExpenses.vue";
169
 import BudgetAdjust from "./adjust/budgetAdjust.vue";
168
 import BudgetAdjust from "./adjust/budgetAdjust.vue";
170
 import NewBudgetInfo from './adjust/newBudgetInfo.vue';
169
 import NewBudgetInfo from './adjust/newBudgetInfo.vue';
170
+
171
 export default {
171
 export default {
172
   components: {
172
   components: {
173
     ReturnComment,
173
     ReturnComment,
174
     ReturnBtn,
174
     ReturnBtn,
175
-    PeopleTable,
175
+    PeopleTable: () => import("./staffTable.vue"),
176
     CarTable,
176
     CarTable,
177
     DeviceTable,
177
     DeviceTable,
178
     MoneyTable,
178
     MoneyTable,

+ 104
- 65
oa-ui/src/views/flowable/form/budget/adjust/budgetAdjust.vue View File

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-05-07 11:01:39
3
  * @Date: 2025-05-07 11:01:39
4
  * @LastEditors: Please set LastEditors
4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-14 18:27:04
5
+ * @LastEditTime: 2025-05-15 18:32:55
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="main" v-loading="loading">
8
   <div class="main" v-loading="loading">
40
               <td style="width: 200px">备注</td>
40
               <td style="width: 200px">备注</td>
41
             </tr>
41
             </tr>
42
             <tr v-for="(work, index) in workContentList" :key="index">
42
             <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>
59
-                {{ work.remark }}
60
-              </td>
43
+              <td>{{ work.content }}</td>
44
+              <td>{{ work.scale }}</td>
45
+              <td>{{ work.unit }}</td>
46
+              <td>{{ work.workload }}</td>
47
+              <td>{{ work.deadline }}</td>
48
+              <td style="text-align:left;">{{ work.remark }}</td>
61
             </tr>
49
             </tr>
62
           </table>
50
           </table>
63
         </div>
51
         </div>
67
           <tr style="background-color:#f8f8f9" v-if="workList.length != 0">
55
           <tr style="background-color:#f8f8f9" v-if="workList.length != 0">
68
             <td style="min-width:50px">工作简述</td>
56
             <td style="min-width:50px">工作简述</td>
69
             <td style="min-width:50px">工作内容</td>
57
             <td style="min-width:50px">工作内容</td>
58
+            <td style="min-width:50px">内容细项</td>
70
             <td style="min-width:50px">比例尺/等级</td>
59
             <td style="min-width:50px">比例尺/等级</td>
71
             <td style="min-width:50px">数量</td>
60
             <td style="min-width:50px">数量</td>
72
             <td style="min-width:50px">单价</td>
61
             <td style="min-width:50px">单价</td>
77
           </tr>
66
           </tr>
78
           <tr v-for="work in workList">
67
           <tr v-for="work in workList">
79
             <td>{{ work.content }}</td>
68
             <td>{{ work.content }}</td>
80
-            <td>{{ work.cmcPrice ? work.cmcPrice.workItem : '' }}</td>
69
+            <td>{{ work.workItem }}</td>
70
+            <td>{{ work.subItem }}</td>
81
             <td>
71
             <td>
82
               {{ work.scaleGrade }}
72
               {{ work.scaleGrade }}
83
             </td>
73
             </td>
93
             <td>{{ work.remark ? work.remark : '' }}</td>
83
             <td>{{ work.remark ? work.remark : '' }}</td>
94
           </tr>
84
           </tr>
95
           <tr>
85
           <tr>
96
-            <td :colspan="7" class="head">内业绩效额合计</td>
86
+            <td :colspan="8" class="head">内业绩效额合计</td>
97
             <td :colspan="1" class="head" style="text-align:right;">
87
             <td :colspan="1" class="head" style="text-align:right;">
98
               {{ budgetForm.settleExpense ? budgetForm.settleExpense.toFixed(2) : '0.00' }}
88
               {{ budgetForm.settleExpense ? budgetForm.settleExpense.toFixed(2) : '0.00' }}
99
             </td>
89
             </td>
100
             <td></td>
90
             <td></td>
101
           </tr>
91
           </tr>
102
           <tr style="color:#F56C6C">
92
           <tr style="color:#F56C6C">
103
-            <td :colspan="7" class="head">内业核算绩效额</td>
93
+            <td :colspan="8" class="head">内业核算绩效额</td>
104
             <td :colspan="1" class="head">
94
             <td :colspan="1" class="head">
105
               <el-input-number v-model="budgetForm.settleAdjust" :controls="false" style="width:100%"></el-input-number>
95
               <el-input-number v-model="budgetForm.settleAdjust" :controls="false" style="width:100%"></el-input-number>
106
             </td>
96
             </td>
109
       </el-descriptions-item>
99
       </el-descriptions-item>
110
       <el-descriptions-item label="内业人员成本" :span="3" v-if="innerStaffList.length > 0">
100
       <el-descriptions-item label="内业人员成本" :span="3" v-if="innerStaffList.length > 0">
111
         <inner-staff-cost :staffList.sync="innerStaffList" :settleExpense="budgetForm.settleExpense"
101
         <inner-staff-cost :staffList.sync="innerStaffList" :settleExpense="budgetForm.settleExpense"
112
-          @update:staffList="handleInnerStaffChange"></inner-staff-cost>
102
+          :settleAdjust="budgetForm.settleAdjust" @update:staffList="handleInnerStaffChange"></inner-staff-cost>
113
       </el-descriptions-item>
103
       </el-descriptions-item>
114
       <el-descriptions-item label="外业人员成本" :span="3" v-if="outerStaffList.length > 0">
104
       <el-descriptions-item label="外业人员成本" :span="3" v-if="outerStaffList.length > 0">
115
         <outer-staff-cost :staffList.sync="outerStaffList"
105
         <outer-staff-cost :staffList.sync="outerStaffList"
116
           @update:staffList="handleOuterStaffChange"></outer-staff-cost>
106
           @update:staffList="handleOuterStaffChange"></outer-staff-cost>
117
       </el-descriptions-item>
107
       </el-descriptions-item>
118
       <el-descriptions-item label="车辆成本" :span="3" v-if="carList.length > 0">
108
       <el-descriptions-item label="车辆成本" :span="3" v-if="carList.length > 0">
119
-        <car-cost :carList.sync="carList"></car-cost>
109
+        <car-cost :carList.sync="carList" @update:carList="handleCarChange"></car-cost>
120
       </el-descriptions-item>
110
       </el-descriptions-item>
121
       <el-descriptions-item label="设备成本" :span="3" v-if="deviceList.length > 0">
111
       <el-descriptions-item label="设备成本" :span="3" v-if="deviceList.length > 0">
122
-        <device-cost :deviceList.sync="deviceList"></device-cost>
112
+        <device-cost :deviceList.sync="deviceList" @update:deviceList="handleDeviceChange"></device-cost>
123
       </el-descriptions-item>
113
       </el-descriptions-item>
124
       <el-descriptions-item label="现场开支" :span="3">
114
       <el-descriptions-item label="现场开支" :span="3">
125
-        <table border="1" style="width:100%;">
126
-          <tr style="background-color:#f8f8f9">
127
-            <td>开支项</td>
128
-            <td>金额</td>
129
-            <td class="adjust">核算金额</td>
130
-          </tr>
131
-          <tr>
132
-
133
-          </tr>
134
-        </table>
115
+        <site-cost :siteList.sync="siteList" @update:siteList="handleSiteChange"></site-cost>
135
       </el-descriptions-item>
116
       </el-descriptions-item>
136
       <el-descriptions-item label="经营相关" :span="3">
117
       <el-descriptions-item label="经营相关" :span="3">
137
-
118
+        <business-cost :budgetForm.sync="budgetForm" @update:budgetForm="handleBusinessChange"></business-cost>
138
       </el-descriptions-item>
119
       </el-descriptions-item>
139
       <el-descriptions-item label="预算外开销" :span="3">
120
       <el-descriptions-item label="预算外开销" :span="3">
140
 
121
 
161
 import OuterStaffCost from './components/OuterStaffCost.vue';
142
 import OuterStaffCost from './components/OuterStaffCost.vue';
162
 import CarCost from './components/CarCost.vue';
143
 import CarCost from './components/CarCost.vue';
163
 import DeviceCost from './components/DeviceCost.vue';
144
 import DeviceCost from './components/DeviceCost.vue';
164
-
145
+import SiteCost from '@/views/flowable/form/budget/adjust/components/SiteCost.vue';
146
+import BusinessCost from '@/views/flowable/form/budget/adjust/components/businessCost.vue';
165
 export default {
147
 export default {
166
   components: {
148
   components: {
167
     InnerStaffCost,
149
     InnerStaffCost,
168
     OuterStaffCost,
150
     OuterStaffCost,
169
     CarCost,
151
     CarCost,
170
-    DeviceCost
152
+    DeviceCost,
153
+    SiteCost,
154
+    BusinessCost
171
   },
155
   },
172
   props: {
156
   props: {
173
     taskForm: {
157
     taskForm: {
192
       outerStaffList: [],
176
       outerStaffList: [],
193
       carList: [],
177
       carList: [],
194
       deviceList: [],
178
       deviceList: [],
179
+      siteList: []
195
     }
180
     }
196
   },
181
   },
197
   created() {
182
   created() {
205
         this.budgetForm = res.rows[0];
190
         this.budgetForm = res.rows[0];
206
         if (this.budgetForm) {
191
         if (this.budgetForm) {
207
           const budgetId = this.budgetForm.budgetId;
192
           const budgetId = this.budgetForm.budgetId;
193
+          this.budgetForm.outExpense = Number(this.budgetForm.outExpense).toFixed(2);
194
+          this.budgetForm.letterExpense = Number(this.budgetForm.letterExpense).toFixed(2);
195
+          this.budgetForm.winExpense = Number(this.budgetForm.winExpense).toFixed(2);
196
+          this.budgetForm.taxExpense = Number(this.budgetForm.taxExpense).toFixed(2);
197
+          this.budgetForm.travelExpense = Number(this.budgetForm.travelExpense).toFixed(2);
198
+          this.budgetForm.totalBudget = Number(this.budgetForm.totalBudget).toFixed(2);
208
           // 获取设备数据
199
           // 获取设备数据
209
           let deviceRes = await listBudgetDevice({ pageSize: 100, budgetId });
200
           let deviceRes = await listBudgetDevice({ pageSize: 100, budgetId });
210
           this.deviceList = deviceRes.rows;
201
           this.deviceList = deviceRes.rows;
211
-
202
+          this.deviceList = this.deviceList.map(device => {
203
+            return {
204
+              ...device,
205
+              depreciation: Number(device.depreciation).toFixed(2),
206
+              amount: Number(device.amount).toFixed(2),
207
+              amountAdjust: device.amountAdjust ? Number(device.amountAdjust).toFixed(2) : 0
208
+            };
209
+          });
212
           // 获取车辆数据
210
           // 获取车辆数据
213
           let carRes = await listBudgetCar({ pageSize: 100, budgetId });
211
           let carRes = await listBudgetCar({ pageSize: 100, budgetId });
214
           this.carList = carRes.rows;
212
           this.carList = carRes.rows;
213
+          this.carList = this.carList.map(car => {
214
+            return {
215
+              ...car,
216
+              depreciation: Number(car.depreciation).toFixed(2),
217
+              amount: Number(car.amount).toFixed(2),
218
+              amountAdjust: car.amountAdjust ? Number(car.amountAdjust).toFixed(2) : 0
219
+            };
220
+          });
215
 
221
 
216
           // 获取内业人员数据
222
           // 获取内业人员数据
217
           let innerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '内业' });
223
           let innerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '内业' });
249
           let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
255
           let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
250
           this.workList = settleRes.rows;
256
           this.workList = settleRes.rows;
251
           for (let work of this.workList) {
257
           for (let work of this.workList) {
252
-            if (work.groundType == '0') {
253
-              work.price = work.cmcPrice.commonPrice
254
-              work.scaleGrade = work.cmcPrice.scaleGrade
255
-              work.unit = work.cmcPrice.unit
258
+            if (work.checkPriceId) {
259
+              work.workType = work.cmcCheckPrice.workType
260
+              work.workItem = work.cmcCheckPrice.workItem
261
+              work.subItem = work.cmcCheckPrice.subItem
262
+              work.scaleGrade = work.cmcCheckPrice.scaleGrade
263
+              work.unit = work.cmcCheckPrice.unit
264
+              if (work.groundType == '0') {
265
+                work.price = work.cmcCheckPrice.commonPrice
266
+              } else {
267
+                work.price = work.cmcCheckPrice.complexPrice
268
+              }
256
             } else {
269
             } else {
257
-              work.price = work.cmcPrice.complexPrice
270
+              work.workType = work.cmcPrice.workType
271
+              work.workItem = work.cmcPrice.workItem
272
+              work.subItem = work.cmcPrice.subItem
258
               work.scaleGrade = work.cmcPrice.scaleGrade
273
               work.scaleGrade = work.cmcPrice.scaleGrade
259
               work.unit = work.cmcPrice.unit
274
               work.unit = work.cmcPrice.unit
275
+              if (work.groundType == '0') {
276
+                work.price = work.cmcPrice.commonPrice
277
+              } else {
278
+                work.price = work.cmcPrice.complexPrice
279
+              }
260
             }
280
             }
261
           }
281
           }
282
+
283
+          // 获取现场开支
284
+          let siteRes = await listSite({ pageSize: 100, budgetId });
285
+          this.siteList = siteRes.rows;
286
+          this.siteList = this.siteList.map(site => {
287
+            return {
288
+              ...site,
289
+              amount: Number(site.amount).toFixed(2),
290
+              amountAdjust: site.amountAdjust ? Number(site.amountAdjust).toFixed(2) : 0
291
+            };
292
+          });
262
         }
293
         }
263
         this.loading = false;
294
         this.loading = false;
264
       }).catch(() => {
295
       }).catch(() => {
276
     // 处理内业人员数据变化
307
     // 处理内业人员数据变化
277
     handleInnerStaffChange(newList) {
308
     handleInnerStaffChange(newList) {
278
       this.innerStaffList = newList;
309
       this.innerStaffList = newList;
279
-      // 计算内业人员总成本
280
-      const totalAmount = this.innerStaffList.reduce((sum, staff) => {
281
-        return sum + (staff.amountAdjust || 0);
282
-      }, 0);
283
-
284
-      // 更新预算表单中的内业人员成本
285
-      if (this.budgetForm) {
286
-        this.budgetForm.innerStaffAmount = totalAmount;
287
-        // 可以在这里调用API保存数据
288
-        // updateBudget(this.budgetForm);
289
-      }
310
+      console.log(this.innerStaffList);
290
     },
311
     },
291
 
312
 
292
     // 处理外业人员数据变化
313
     // 处理外业人员数据变化
293
     handleOuterStaffChange(newList) {
314
     handleOuterStaffChange(newList) {
294
       this.outerStaffList = newList;
315
       this.outerStaffList = newList;
295
-      // 计算外业人员总成本
296
-      const totalAmount = this.outerStaffList.reduce((sum, staff) => {
297
-        return sum + (staff.amountAdjust || 0);
298
-      }, 0);
316
+    },
317
+    // 处理车辆数据变化
318
+    handleCarChange(newList) {
319
+      this.carList = newList;
320
+    },
321
+    // 处理设备数据变化
322
+    handleDeviceChange(newList) {
323
+      this.deviceList = newList;
324
+    },
325
+    // 处理现场开支数据变化
326
+    handleSiteChange(newList) {
327
+      this.siteList = newList;
328
+      console.log(this.siteList);
329
+    },
330
+    // 处理经营相关数据变化
331
+    handleBusinessChange(newData) {
299
 
332
 
300
-      // 更新预算表单中的外业人员成本
301
-      if (this.budgetForm) {
302
-        this.budgetForm.outerStaffAmount = totalAmount;
303
-        // 可以在这里调用API保存数据
304
-        // updateBudget(this.budgetForm);
305
-      }
306
     },
333
     },
307
     async preserve() {
334
     async preserve() {
308
       let obj = {
335
       let obj = {
323
           await addBudgetStaff(staff);
350
           await addBudgetStaff(staff);
324
         }
351
         }
325
       })
352
       })
353
+      delBudgetCar(this.row.budgetId).then(async res => {
354
+        for (let car of this.carList) {
355
+          car.budgetId = this.row.budgetId;
356
+          await addBudgetCar(car);
357
+        }
358
+      })
359
+      delBudgetDevice(this.row.budgetId).then(async res => {
360
+        for (let device of this.deviceList) {
361
+          device.budgetId = this.row.budgetId;
362
+          await addBudgetDevice(device);
363
+        }
364
+      })
326
       this.$message.success('保存成功');
365
       this.$message.success('保存成功');
327
     },
366
     },
328
     confirmSucess() {
367
     confirmSucess() {

+ 103
- 10
oa-ui/src/views/flowable/form/budget/adjust/components/CarCost.vue View File

1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-05-08 14:18:15
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-05-15 14:55:55
6
+-->
1
 <template>
7
 <template>
2
   <div class="car-cost">
8
   <div class="car-cost">
3
     <table border="1" style="width:100%;">
9
     <table border="1" style="width:100%;">
4
       <tr style="background-color:#f8f8f9">
10
       <tr style="background-color:#f8f8f9">
11
+        <td></td>
5
         <td>车牌号</td>
12
         <td>车牌号</td>
6
         <td>折旧成本(天)</td>
13
         <td>折旧成本(天)</td>
7
         <td>预算天数</td>
14
         <td>预算天数</td>
9
         <td class="adjust">核算天数</td>
16
         <td class="adjust">核算天数</td>
10
         <td class="adjust">核算金额</td>
17
         <td class="adjust">核算金额</td>
11
       </tr>
18
       </tr>
12
-      <tr v-for="car in carList" :key="'car' + car.carId">
13
-        <td>{{ car.car ? car.car.licensePlate : '' }}</td>
14
-        <td>{{ car.car ? car.car.dayCost : '' }}</td>
15
-        <td>{{ car.days }}</td>
16
-        <td>{{ car.amount }}</td>
19
+      <tr v-for="car, index in carList" :key="'car' + car.carId">
17
         <td>
20
         <td>
18
-          <el-input-number :controls="false" style="width:100%;" v-model="car.daysAdjust" @change="handleChange"></el-input-number>
21
+          <div class="delete-btn" @click="removeCar(car, index)"><i class="el-icon-remove-outline"
22
+              style="color:#F56C6C"></i>
23
+          </div>
19
         </td>
24
         </td>
20
-        <td>
21
-          <el-input-number :controls="false" style="width:100%;" v-model="car.amountAdjust" @change="handleChange"></el-input-number>
25
+        <td>{{ car.car ? car.car.licensePlate : '' }}</td>
26
+        <td style="text-align:right;">{{ car.car ? car.car.dayCost : '' }}</td>
27
+        <td style="text-align:right;">{{ car.days }}</td>
28
+        <td style="text-align:right;">{{ car.amount }}</td>
29
+        <td style="text-align:right;">
30
+          <el-input-number :controls="false" style="width:100%;" v-model="car.daysAdjust"
31
+            @change="handleChange(car)"></el-input-number>
32
+        </td>
33
+        <td style="text-align:right;">
34
+          {{ car.amountAdjust }}
22
         </td>
35
         </td>
23
       </tr>
36
       </tr>
37
+      <tr>
38
+        <td colspan="2" class="amount">车辆成本合计</td>
39
+        <td class="amount" style="text-align:right;">{{carList.reduce((sum, car) => sum +
40
+          (Number(car.depreciation) || 0), 0).toFixed(2)}}</td>
41
+        <td class="amount" style="text-align:right;">{{carList.reduce((sum, car) => sum +
42
+          (Number(car.days) || 0), 0).toFixed(2)}}</td>
43
+        <td class="amount" style="text-align:right;">{{carList.reduce((sum, car) => sum +
44
+          (Number(car.amount) || 0), 0).toFixed(2)}}</td>
45
+        <td class="amount" style="text-align:right;">{{carList.reduce((sum, car) => sum +
46
+          (Number(car.daysAdjust) || 0), 0).toFixed(2)}}</td>
47
+        <td class="amount" style="text-align:right;">{{carList.reduce((sum, car) => sum +
48
+          (Number(car.amountAdjust) || 0), 0).toFixed(2)}}</td>
49
+      </tr>
24
     </table>
50
     </table>
51
+    <div class="mt10">
52
+      <el-button type="success" plain icon="el-icon-plus" @click="openCar" size="mini">新增车辆</el-button>
53
+    </div>
54
+    <!-- 选择车辆对话框 -->
55
+    <el-dialog title="选择车辆" :visible.sync="isOpenCar" width="700px" append-to-body>
56
+      <choose-car @chooseList="getChooseCar"></choose-car>
57
+    </el-dialog>
25
   </div>
58
   </div>
26
 </template>
59
 </template>
27
 
60
 
28
 <script>
61
 <script>
62
+import ChooseCar from '../../components/chooseCar.vue'
63
+
29
 export default {
64
 export default {
30
   name: 'CarCost',
65
   name: 'CarCost',
66
+  components: {
67
+    ChooseCar
68
+  },
31
   props: {
69
   props: {
32
     carList: {
70
     carList: {
33
       type: Array,
71
       type: Array,
34
       default: () => []
72
       default: () => []
35
     }
73
     }
36
   },
74
   },
75
+  data() {
76
+    return {
77
+      isOpenCar: false
78
+    }
79
+  },
37
   methods: {
80
   methods: {
38
-    handleChange() {
81
+    handleChange(car) {
82
+      car.amountAdjust = (Number(car.car.dayCost) * Number(car.daysAdjust)).toFixed(2);
83
+      this.$emit('update:carList', this.carList);
84
+    },
85
+    openCar() {
86
+      this.isOpenCar = true;
87
+    },
88
+    removeCar(car, index) {
89
+      this.$confirm('确实移除【' + car.car.licensePlate + '】吗', '提示', {
90
+        confirmButtonText: '确定',
91
+        cancelButtonText: '取消',
92
+        type: 'warning'
93
+      }).then(() => {
94
+        let arr = this.carList;
95
+        if (arr.length == 1) {
96
+          return;
97
+        }
98
+        if (index >= 0 && index < arr.length) {
99
+          arr.splice(index, 1);
100
+        }
101
+        this.$emit('update:carList', this.carList);
102
+      }).catch(() => { });
103
+    },
104
+    getChooseCar(val) {
105
+      let arr = [];
106
+      for (let car of val) {
107
+        let obj = {
108
+          carId: car.carId,
109
+          car: car,
110
+          days: 0,
111
+          depreciation: car.dayCost,
112
+          amount: 0,
113
+          daysAdjust: 0,
114
+          amountAdjust: 0,
115
+        }
116
+        arr.push(obj);
117
+      }
118
+      this.carList.push(...arr);
119
+      this.isOpenCar = false;
39
       this.$emit('update:carList', this.carList);
120
       this.$emit('update:carList', this.carList);
40
     }
121
     }
41
   }
122
   }
48
     text-align: center;
129
     text-align: center;
49
     border-collapse: collapse;
130
     border-collapse: collapse;
50
     margin: 0 auto;
131
     margin: 0 auto;
132
+
51
     td {
133
     td {
52
       padding: 5px;
134
       padding: 5px;
53
     }
135
     }
54
   }
136
   }
137
+
55
   .adjust {
138
   .adjust {
56
     color: #F56C6C;
139
     color: #F56C6C;
57
     width: 120px;
140
     width: 120px;
58
   }
141
   }
59
 }
142
 }
60
-</style> 
143
+
144
+.delete-btn {
145
+  cursor: pointer;
146
+  font-size: 18px;
147
+}
148
+
149
+.amount {
150
+  font-weight: bold;
151
+  font-family: Arial, Helvetica, sans-serif;
152
+}
153
+</style>

+ 93
- 14
oa-ui/src/views/flowable/form/budget/adjust/components/DeviceCost.vue View File

2
   <div class="device-cost">
2
   <div class="device-cost">
3
     <table border="1" style="width:100%;">
3
     <table border="1" style="width:100%;">
4
       <tr style="background-color:#f8f8f9">
4
       <tr style="background-color:#f8f8f9">
5
+        <td></td>
5
         <td>设备名称</td>
6
         <td>设备名称</td>
7
+        <td>出厂编号</td>
6
         <td>规格型号</td>
8
         <td>规格型号</td>
7
         <td>品牌</td>
9
         <td>品牌</td>
8
-        <td>折旧成本(天)</td>
9
-        <td>预算天数</td>
10
-        <td>金额</td>
11
-        <td class="adjust">核算天数</td>
12
-        <td class="adjust">核算金额</td>
10
+        <td style="min-width: 120px;">折旧成本(天)</td>
11
+        <td style="min-width: 80px;">预算天数</td>
12
+        <td style="min-width: 80px;">金额</td>
13
+        <td style="min-width: 80px;" class="adjust">核算天数</td>
14
+        <td style="min-width: 80px;" class="adjust">核算金额</td>
13
       </tr>
15
       </tr>
14
-      <tr v-for="device in deviceList" :key="'device' + device.deviceId">
16
+      <tr v-for="device, index in deviceList" :key="'device' + device.deviceId">
17
+        <td>
18
+          <div class="delete-btn" @click="removeDevice(device, index)">
19
+            <i class="el-icon-remove-outline" style="color:#F56C6C"></i>
20
+          </div>
21
+        </td>
15
         <td>{{ device.device ? device.device.name : '' }}</td>
22
         <td>{{ device.device ? device.device.name : '' }}</td>
23
+        <td>{{ device.device ? device.device.code : '' }}</td>
16
         <td>{{ device.device ? device.device.series : '' }}</td>
24
         <td>{{ device.device ? device.device.series : '' }}</td>
17
         <td>{{ device.device ? device.device.brand : '' }}</td>
25
         <td>{{ device.device ? device.device.brand : '' }}</td>
18
-        <td>{{ device.device ? device.device.dayCost : '' }}</td>
19
-        <td>{{ device.days }}</td>
20
-        <td>{{ device.amount }}</td>
21
-        <td>
22
-          <el-input-number :controls="false" style="width:100%;" v-model="device.daysAdjust" @change="handleChange"></el-input-number>
26
+        <td style="text-align:right;">{{ device.device ? device.device.dayCost : '' }}</td>
27
+        <td style="text-align:right;">{{ device.days }}</td>
28
+        <td style="text-align:right;">{{ device.amount }}</td>
29
+        <td style="text-align:right;">
30
+          <el-input-number :controls="false" style="width:100%;" v-model="device.daysAdjust" @change="handleChange(device)"></el-input-number>
23
         </td>
31
         </td>
24
-        <td>
25
-          <el-input-number :controls="false" style="width:100%;" v-model="device.amountAdjust" @change="handleChange"></el-input-number>
32
+        <td style="text-align:right;">
33
+          {{ device.amountAdjust }}
26
         </td>
34
         </td>
27
       </tr>
35
       </tr>
36
+      <!-- <tr>
37
+        <td colspan="4" class="amount">设备成本合计</td>
38
+        <td class="amount" style="text-align:right;">{{deviceList.reduce((sum, device) => sum + (Number(device.device?.dayCost) || 0), 0).toFixed(2)}}</td>
39
+        <td class="amount" style="text-align:right;">{{deviceList.reduce((sum, device) => sum + (Number(device.days) || 0), 0).toFixed(2)}}</td>
40
+        <td class="amount" style="text-align:right;">{{deviceList.reduce((sum, device) => sum + (Number(device.amount) || 0), 0).toFixed(2)}}</td>
41
+        <td class="amount" style="text-align:right;">{{deviceList.reduce((sum, device) => sum + (Number(device.daysAdjust) || 0), 0).toFixed(2)}}</td>
42
+        <td class="amount" style="text-align:right;">{{deviceList.reduce((sum, device) => sum + (Number(device.amountAdjust) || 0), 0).toFixed(2)}}</td>
43
+      </tr> -->
28
     </table>
44
     </table>
45
+    <div class="mt10">
46
+      <el-button type="success" plain icon="el-icon-plus" @click="openDevice" size="mini">新增设备</el-button>
47
+    </div>
48
+    <!-- 选择设备对话框 -->
49
+    <el-dialog title="选择设备" :visible.sync="isOpenDevice" width="700px" append-to-body>
50
+      <choose-device @chooseList="getChooseDevice"></choose-device>
51
+    </el-dialog>
29
   </div>
52
   </div>
30
 </template>
53
 </template>
31
 
54
 
32
 <script>
55
 <script>
56
+import ChooseDevice from '../../components/chooseDevice.vue'
57
+
33
 export default {
58
 export default {
34
   name: 'DeviceCost',
59
   name: 'DeviceCost',
60
+  components: {
61
+    ChooseDevice
62
+  },
35
   props: {
63
   props: {
36
     deviceList: {
64
     deviceList: {
37
       type: Array,
65
       type: Array,
38
       default: () => []
66
       default: () => []
39
     }
67
     }
40
   },
68
   },
69
+  data() {
70
+    return {
71
+      isOpenDevice: false
72
+    }
73
+  },
41
   methods: {
74
   methods: {
42
-    handleChange() {
75
+    handleChange(device) {
76
+      device.amountAdjust = (Number(device.device.dayCost) * Number(device.daysAdjust)).toFixed(2);
77
+      this.$emit('update:deviceList', this.deviceList);
78
+    },
79
+    openDevice() {
80
+      this.isOpenDevice = true;
81
+    },
82
+    removeDevice(device, index) {
83
+      this.$confirm('确实移除【' + device.device.name + '】吗', '提示', {
84
+        confirmButtonText: '确定',
85
+        cancelButtonText: '取消',
86
+        type: 'warning'
87
+      }).then(() => {
88
+        let arr = this.deviceList;
89
+        if (arr.length == 1) {
90
+          return;
91
+        }
92
+        if (index >= 0 && index < arr.length) {
93
+          arr.splice(index, 1);
94
+        }
95
+        this.$emit('update:deviceList', this.deviceList);
96
+      }).catch(() => { });
97
+    },
98
+    getChooseDevice(val) {
99
+      let arr = [];
100
+      for (let device of val) {
101
+        let obj = {
102
+          deviceId: device.deviceId,
103
+          device: device,
104
+          days: 0,
105
+          depreciation: device.dayCost,
106
+          amount: 0,
107
+          daysAdjust: 0,
108
+          amountAdjust: 0,
109
+        }
110
+        arr.push(obj);
111
+      }
112
+      this.deviceList.push(...arr);
113
+      this.isOpenDevice = false;
43
       this.$emit('update:deviceList', this.deviceList);
114
       this.$emit('update:deviceList', this.deviceList);
44
     }
115
     }
45
   }
116
   }
60
     color: #F56C6C;
131
     color: #F56C6C;
61
     width: 120px;
132
     width: 120px;
62
   }
133
   }
134
+  .delete-btn {
135
+    cursor: pointer;
136
+    font-size: 18px;
137
+  }
138
+  .amount {
139
+    font-weight: bold;
140
+    font-family: Arial, Helvetica, sans-serif;
141
+  }
63
 }
142
 }
64
 </style> 
143
 </style> 

+ 44
- 31
oa-ui/src/views/flowable/form/budget/adjust/components/InnerStaffCost.vue View File

3
     <table border="1" style="width:100%">
3
     <table border="1" style="width:100%">
4
       <tr style="background-color:#f8f8f9">
4
       <tr style="background-color:#f8f8f9">
5
         <td></td>
5
         <td></td>
6
-        <td>序号</td>
7
-        <td>姓名</td>
8
-        <td>人员成本(天)</td>
9
-        <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>
14
-        <td class="adjust" style="width:120px">核算天数</td>
15
-        <td class="adjust" style="width:120px">核算绩效</td>
16
-        <td class="adjust" style="width:120px">核算金额</td>
6
+        <td style="min-width:50px;">序号</td>
7
+        <td style="min-width:80px;">姓名</td>
8
+        <td style="min-width:80px;">人员成本(天)</td>
9
+        <td style="min-width:80px;">预算天数</td>
10
+        <td style="min-width:80px;">固定成本合计</td>
11
+        <td style="min-width:80px;">绩效成本合计</td>
12
+        <td style="width:120px;min-width:80px;">预算金额</td>
13
+        <td class="adjust" style="width:120px;min-width:80px;">核算固定成本</td>
14
+        <td class="adjust" style="width:120px;min-width:80px;">核算天数</td>
15
+        <td class="adjust" style="width:120px;min-width:80px;">核算绩效</td>
16
+        <td class="adjust" style="width:120px;min-width:80px;">核算金额</td>
17
       </tr>
17
       </tr>
18
       <tr v-for="staff, index in staffList" :key="'user' + index">
18
       <tr v-for="staff, index in staffList" :key="'user' + index">
19
         <td>
19
         <td>
20
           <!-- <el-button type="danger" icon="el-icon-minus" circle plain></el-button> -->
20
           <!-- <el-button type="danger" icon="el-icon-minus" circle plain></el-button> -->
21
-          <div class="delete-btn" v-if="index + 1 > lens" @click="removeStaff(index)"><i class="el-icon-remove-outline"
21
+          <div class="delete-btn" @click="removeStaff(staff, index)"><i class="el-icon-remove-outline"
22
               style="color:#F56C6C"></i>
22
               style="color:#F56C6C"></i>
23
           </div>
23
           </div>
24
         </td>
24
         </td>
46
         <td colspan="5" class="head amount">内业人员成本合计</td>
46
         <td colspan="5" class="head amount">内业人员成本合计</td>
47
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
47
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
48
           (Number(staff.staffCost) || 0), 0).toFixed(2)}}</td>
48
           (Number(staff.staffCost) || 0), 0).toFixed(2)}}</td>
49
-        <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
49
+        <td class="head amount"  :class="{ 'performance-error': isPerformanceExceeded() }" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
50
           (Number(staff.performance) || 0), 0).toFixed(2)}}</td>
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)
51
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum + (Number(staff.amount)
52
           || 0), 0).toFixed(2)}}</td>
52
           || 0), 0).toFixed(2)}}</td>
54
           ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
54
           ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
55
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
55
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
56
           (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
56
           (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
57
-        <td class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }" style="text-align:right;">
57
+        <td class="head amount" :class="{ 'performance-error': isPerformanceAdjustExceeded() }" style="text-align:right;">
58
           {{staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0).toFixed(2)}}</td>
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;">
59
+        <td class="head amount" style="text-align:right;">
60
           {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
60
           {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
61
       </tr>
61
       </tr>
62
     </table>
62
     </table>
86
     settleExpense: {
86
     settleExpense: {
87
       type: Number,
87
       type: Number,
88
       default: 0
88
       default: 0
89
+    },
90
+    settleAdjust: {
91
+      type: Number,
92
+      default: 0
89
     }
93
     }
90
   },
94
   },
91
   data() {
95
   data() {
92
     return {
96
     return {
93
       isOpenPeople: false,
97
       isOpenPeople: false,
94
-      lens: 0,
95
     }
98
     }
96
   },
99
   },
97
   watch: {
100
   watch: {
98
 
101
 
99
   },
102
   },
100
   mounted() {
103
   mounted() {
101
-    this.lens = this.staffList.length;
102
   },
104
   },
103
   methods: {
105
   methods: {
104
     handleChange(staff) {
106
     handleChange(staff) {
109
       this.isOpenPeople = true;
111
       this.isOpenPeople = true;
110
     },
112
     },
111
     getChooseUser(val) {
113
     getChooseUser(val) {
114
+      let arr = [];
112
       for (let v of val) {
115
       for (let v of val) {
113
-        v.days = 0;
114
-        v.settle = 0;
115
-        v.amount = 0;
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;
116
+        let dayCost = (parseFloat(((v.salary.salary + 1780) * 12) / 365) + v.socialSecurityUnit + v.houseFund).toFixed(2);
117
+        let obj = {};
118
+        obj.days = 0;
119
+        obj.settle = 0;
120
+        obj.amount = 0;
121
+        obj.user = v;
122
+        obj.dayCost = dayCost;
123
+        obj.staffCost = 0;
124
+        obj.performance = 0;
125
+        obj.salary = v.salary;
126
+        obj.userId = v.userId;
127
+        this.$set(obj, 'type', '内业');
128
+        this.$set(obj, 'daysAdjust', 0);
129
+        this.$set(obj, 'performanceAdjust', 0);
130
+        this.$set(obj, 'amountAdjust', 0);
131
+        arr.push(obj);
123
       }
132
       }
124
-      this.staffList.push(...val);
133
+      this.staffList.push(...arr);
125
       this.isOpenPeople = false;
134
       this.isOpenPeople = false;
126
       this.$emit('update:staffList', this.staffList);
135
       this.$emit('update:staffList', this.staffList);
127
     },
136
     },
128
-    removeStaff(index) {
129
-      this.$confirm('确实移除该人员吗', '提示', {
137
+    removeStaff(staff, index) {
138
+      this.$confirm('确实移除【' + staff.user.nickName + '】吗', '提示', {
130
         confirmButtonText: '确定',
139
         confirmButtonText: '确定',
131
         cancelButtonText: '取消',
140
         cancelButtonText: '取消',
132
         type: 'warning'
141
         type: 'warning'
141
       }).catch(() => { });
150
       }).catch(() => { });
142
     },
151
     },
143
     isPerformanceExceeded() {
152
     isPerformanceExceeded() {
144
-      const totalPerformance = this.staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0);
153
+      const totalPerformance = this.staffList.reduce((sum, staff) => sum + (Number(staff.performance) || 0), 0);
145
       return totalPerformance > Number(this.settleExpense);
154
       return totalPerformance > Number(this.settleExpense);
155
+    },
156
+    isPerformanceAdjustExceeded() {
157
+      const totalPerformanceAdjust = this.staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0);
158
+      return totalPerformanceAdjust > Number(this.settleAdjust);
146
     }
159
     }
147
   }
160
   }
148
 }
161
 }

+ 45
- 26
oa-ui/src/views/flowable/form/budget/adjust/components/OuterStaffCost.vue View File

3
     <table border="1" style="width:100%">
3
     <table border="1" style="width:100%">
4
       <tr style="background-color:#f8f8f9">
4
       <tr style="background-color:#f8f8f9">
5
         <td></td>
5
         <td></td>
6
-        <td>序号</td>
7
-        <td>姓名</td>
8
-        <td>人员成本(天)</td>
9
-        <td style="width:120px">预算天数</td>
10
-        <td>预算系数</td>
11
-        <td>固定成本合计</td>
12
-        <td>绩效成本合计</td>
13
-        <td style="width:120px">金额</td>
14
-        <td class="adjust" style="width:120px">核算固定成本</td>
15
-        <td class="adjust" style="width:120px">核算天数</td>
16
-        <td class="adjust" style="width:120px">核算系数</td>
17
-        <td class="adjust" style="width:120px">核算金额</td>
6
+        <td style="min-width:50px;">序号</td>
7
+        <td style="min-width:80px;">姓名</td>
8
+        <td style="min-width:80px;">人员成本(天)</td>
9
+        <td style="min-width:80px;">预算天数</td>
10
+        <td style="min-width:80px;">预算系数</td>
11
+        <td style="min-width:100px;">固定成本合计</td>
12
+        <td style="min-width:100px;">绩效成本合计</td>
13
+        <td style="width:120px;min-width:80px;">预算金额</td>
14
+        <td class="adjust" style="width:120px;min-width:80px;">核算固定成本</td>
15
+        <td class="adjust" style="width:120px;min-width:80px;">核算天数</td>
16
+        <td class="adjust" style="width:120px;min-width:80px;">核算系数</td>
17
+        <td class="adjust" style="width:120px;min-width:80px;">核算绩效</td>
18
+        <td class="adjust" style="width:120px;min-width:80px;">核算金额</td>
18
       </tr>
19
       </tr>
19
       <tr v-for="staff, index in staffList" :key="'user' + staff.userId">
20
       <tr v-for="staff, index in staffList" :key="'user' + staff.userId">
20
         <td>
21
         <td>
21
-          <div class="delete-btn" v-if="index + 1 > lens" @click="removeStaff(index)">
22
+          <div class="delete-btn" @click="removeStaff(staff, index)">
22
             <i class="el-icon-remove-outline" style="color:#F56C6C"></i>
23
             <i class="el-icon-remove-outline" style="color:#F56C6C"></i>
23
           </div>
24
           </div>
24
         </td>
25
         </td>
39
           <el-input-number :controls="false" style="width:100%;" v-model="staff.coefficientAdjust"
40
           <el-input-number :controls="false" style="width:100%;" v-model="staff.coefficientAdjust"
40
             @change="handleChange(staff)"></el-input-number>
41
             @change="handleChange(staff)"></el-input-number>
41
         </td>
42
         </td>
43
+        <td style="text-align:right;">
44
+          {{ staff.performanceAdjust }}
45
+        </td>
42
         <td style="text-align:right;">
46
         <td style="text-align:right;">
43
           {{ staff.amountAdjust }}
47
           {{ staff.amountAdjust }}
44
         </td>
48
         </td>
58
           ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
62
           ((staff.dayCost * staff.daysAdjust)), 0).toFixed(2)}}</td>
59
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
63
         <td class="head amount" style="text-align:right;">{{staffList.reduce((sum, staff) => sum +
60
           (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
64
           (Number(staff.daysAdjust) || 0), 0).toFixed(2)}}</td>
65
+        <td class="head amount">
66
+          ——
67
+        </td>
61
         <td class="head amount" style="text-align:right;">
68
         <td class="head amount" style="text-align:right;">
62
-         ——
69
+          {{staffList.reduce((sum, staff) => sum + (Number(staff.performanceAdjust) || 0), 0).toFixed(2)}}
63
         </td>
70
         </td>
64
         <td class="head amount" style="text-align:right;">
71
         <td class="head amount" style="text-align:right;">
65
           {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
72
           {{staffList.reduce((sum, staff) => sum + (Number(staff.amountAdjust) || 0), 0).toFixed(2)}}</td>
92
   data() {
99
   data() {
93
     return {
100
     return {
94
       isOpenPeople: false,
101
       isOpenPeople: false,
95
-      lens: 0
96
     }
102
     }
97
   },
103
   },
98
   watch: {
104
   watch: {
99
     staffList(newval, oldval) {
105
     staffList(newval, oldval) {
100
       if (oldval.length == 0) {
106
       if (oldval.length == 0) {
101
-        this.lens = newval.length;
107
+
102
       }
108
       }
103
     }
109
     }
104
   },
110
   },
105
   mounted() {
111
   mounted() {
106
-    this.lens = this.staffList.length;
112
+
107
   },
113
   },
108
   methods: {
114
   methods: {
109
     handleChange(staff) {
115
     handleChange(staff) {
110
       // 计算调整后的金额
116
       // 计算调整后的金额
111
-      staff.amountAdjust = (Number(staff.dayCost) * Number(staff.daysAdjust) + (200 * Number(staff.daysAdjust) * Number(staff.coefficient))).toFixed(2)
117
+      staff.performanceAdjust = (200 * Number(staff.daysAdjust) * Number(staff.coefficientAdjust)).toFixed(2)
118
+      staff.amountAdjust = (Number(staff.dayCost) * Number(staff.daysAdjust) + Number(staff.performanceAdjust)).toFixed(2)
112
       this.$emit('update:staffList', this.staffList);
119
       this.$emit('update:staffList', this.staffList);
113
     },
120
     },
114
     openPeople() {
121
     openPeople() {
115
       this.isOpenPeople = true;
122
       this.isOpenPeople = true;
116
     },
123
     },
117
     getChooseUser(val) {
124
     getChooseUser(val) {
125
+      let arr = [];
118
       for (let v of val) {
126
       for (let v of val) {
119
-        v.daysAdjust = 0;
120
-        v.coefficientAdjust = 1;
121
-        v.otherCoefficientAdjust = 1;
122
-        v.amountAdjust = 0;
123
-        v.user = v;
127
+        let dayCost = (parseFloat(((v.salary.salary + 1780) * 12) / 365) + v.socialSecurityUnit + v.houseFund).toFixed(2);
128
+        let obj = {};
129
+        obj.user = v;
130
+        obj.dayCost = dayCost;
131
+        obj.staffCost = 0;
132
+        obj.performance = 0;
133
+        obj.amount = 0;
134
+        obj.days = 0;
135
+        obj.coefficient = 1;
136
+        obj.salary = v.salary;
137
+        obj.userId = v.userId;
138
+        this.$set(obj, 'type', '外业');
139
+        this.$set(obj, 'daysAdjust', 0);
140
+        this.$set(obj, 'coefficientAdjust', 0);
141
+        this.$set(obj, 'amountAdjust', 0);
142
+        arr.push(obj);
124
       }
143
       }
125
-      this.staffList.push(...val);
144
+      this.staffList.push(...arr);
126
       this.isOpenPeople = false;
145
       this.isOpenPeople = false;
127
       this.$emit('update:staffList', this.staffList);
146
       this.$emit('update:staffList', this.staffList);
128
     },
147
     },
129
-    removeStaff(index) {
130
-      this.$confirm('确实移除该人员吗', '提示', {
148
+    removeStaff(staff, index) {
149
+      this.$confirm('确实移除【' + staff.user.nickName + '】吗', '提示', {
131
         confirmButtonText: '确定',
150
         confirmButtonText: '确定',
132
         cancelButtonText: '取消',
151
         cancelButtonText: '取消',
133
         type: 'warning'
152
         type: 'warning'

+ 70
- 0
oa-ui/src/views/flowable/form/budget/adjust/components/SiteCost.vue View File

1
+<template>
2
+  <div class="site-cost">
3
+    <table border="1" style="width:100%;">
4
+      <tr style="background-color:#f8f8f9">
5
+        <td>开支项</td>
6
+        <td>金额</td>
7
+        <td class="adjust">核算金额</td>
8
+      </tr>
9
+      <tr v-for="site in siteList" :key="site.id">
10
+        <td>{{ site.name }}</td>
11
+        <td style="text-align: right;">{{ site.amount }}</td>
12
+        <td>
13
+          <el-input-number :controls="false" v-model="site.amountAdjust" placeholder="请输入核算金额"
14
+            @change="handleSiteChange(site)" />
15
+        </td>
16
+      </tr>
17
+      <tr>
18
+        <td class="amount" colspan="1">现场开支合计</td>
19
+        <td class="amount" style="text-align: right;">{{siteList.reduce((sum, site) => sum + (Number(site.amount)
20
+          || 0), 0).toFixed(2)}}</td>
21
+        <td class="amount" style="text-align: right;">{{siteList.reduce((sum, site) => sum + (Number(site.amountAdjust)
22
+          || 0), 0).toFixed(2)}}</td>
23
+      </tr>
24
+    </table>
25
+  </div>
26
+</template>
27
+
28
+<script>
29
+export default {
30
+  props: {
31
+    siteList: {
32
+      type: Array,
33
+      default: () => []
34
+    }
35
+  },
36
+  methods: {
37
+    handleSiteChange(site) {
38
+      this.$emit('update:siteList', this.siteList);
39
+    }
40
+  },
41
+}
42
+</script>
43
+
44
+<style lang="scss" scoped>
45
+.site-cost {
46
+  .add-staff {
47
+    margin-bottom: 10px;
48
+  }
49
+
50
+  table {
51
+    text-align: center;
52
+    border-collapse: collapse;
53
+    margin: 0 auto;
54
+
55
+    td {
56
+      padding: 5px;
57
+    }
58
+  }
59
+
60
+  .adjust {
61
+    color: #F56C6C;
62
+    width: 120px;
63
+  }
64
+}
65
+
66
+.amount {
67
+  font-weight: bold;
68
+  font-family: Arial, Helvetica, sans-serif;
69
+}
70
+</style>

+ 144
- 0
oa-ui/src/views/flowable/form/budget/adjust/components/businessCost.vue View File

1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-05-15 18:24:27
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-05-15 18:37:17
6
+-->
7
+<template>
8
+  <div class="business-cost">
9
+    <table border="1" style="width:100%;">
10
+      <tr style="background-color:#f8f8f9">
11
+        <td>序号</td>
12
+        <td>名称</td>
13
+        <td>金额</td>
14
+        <td class="adjust">核算金额</td>
15
+        <td>备注</td>
16
+      </tr>
17
+      <tr>
18
+        <td>{{ 1 }}</td>
19
+        <td>外协费用</td>
20
+        <td style="text-align:right;">
21
+          {{ budgetForm.outExpense }}
22
+        </td>
23
+        <td style="text-align:right;">
24
+          <el-input-number :controls="false" v-model="budgetForm.outExpenseAdjust" :min="0" :step="0.01"
25
+            @change="updateTotalJYAmount"></el-input-number>
26
+        </td>
27
+        <td class="remark-cell">{{ budgetForm.outRemark }}</td>
28
+      </tr>
29
+      <tr>
30
+        <td>{{ 2 }}</td>
31
+        <td>保函费用</td>
32
+        <td style="text-align:right;">
33
+          {{ budgetForm.letterExpense }}
34
+        </td>
35
+        <td style="text-align:right;">
36
+          <el-input-number :controls="false" v-model="budgetForm.letterExpenseAdjust" :min="0" :step="0.01"
37
+            @change="updateTotalJYAmount"></el-input-number>
38
+        </td>
39
+        <td class="remark-cell">{{ budgetForm.letterRemark }}</td>
40
+      </tr>
41
+      <tr>
42
+        <td>{{ 3 }}</td>
43
+        <td>中标服务费</td>
44
+        <td style="text-align:right;">
45
+          {{ budgetForm.winExpense }}
46
+        </td>
47
+        <td class="remark-cell">{{ budgetForm.winRemark }}</td>
48
+      </tr>
49
+      <tr>
50
+        <td>{{ 4 }}</td>
51
+        <td>税费</td>
52
+        <td style="text-align:right;">
53
+          {{ budgetForm.taxExpense }}
54
+        </td>
55
+        <td style="text-align:right;">
56
+          <el-input-number :controls="false" v-model="budgetForm.taxExpenseAdjust" :min="0" :step="0.01"
57
+            @change="updateTotalJYAmount"></el-input-number>
58
+        </td>
59
+        <td class="remark-cell">{{ budgetForm.taxRemark }}</td>
60
+      </tr>
61
+      <tr>
62
+        <td>{{ 5 }}</td>
63
+        <td>差旅费用</td>
64
+        <td style="text-align:right;">
65
+          {{ budgetForm.travelExpense }}
66
+        </td>
67
+        <td style="text-align:right;">
68
+          <el-input-number :controls="false" v-model="budgetForm.travelExpenseAdjust" :min="0" :step="0.01"
69
+            @change="updateTotalJYAmount"></el-input-number>
70
+        </td>
71
+        <td class="remark-cell">{{ budgetForm.travelRemark }}</td>
72
+      </tr>
73
+      <tr>
74
+        <td colspan="2" class="amount">经营相关合计</td>
75
+        <td class="amount" style="text-align:right;">
76
+          {{ totalJYAmount }}
77
+        </td>
78
+        <td class="amount" style="text-align:right;">
79
+          {{ totalJYAmountAdjust }}
80
+        </td>
81
+      </tr>
82
+    </table>
83
+  </div>
84
+</template>
85
+
86
+<script>
87
+export default {
88
+  props: {
89
+    budgetForm: {
90
+      type: Object,
91
+      required: true
92
+    }
93
+  },
94
+  data() {
95
+    return {
96
+      totalJYAmount: 0,
97
+      totalJYAmountAdjust: 0
98
+    }
99
+  },
100
+  created() {
101
+    this.initTotalJYAmount();
102
+  },
103
+  methods: {
104
+    initTotalJYAmount() {
105
+      this.totalJYAmount = ((Number(this.budgetForm.outExpense) || 0) + (Number(this.budgetForm.letterExpense) || 0) + (Number(this.budgetForm.winExpense) || 0) + (Number(this.budgetForm.taxExpense) || 0) + (Number(this.budgetForm.travelExpense) || 0)).toFixed(2)
106
+    },
107
+    updateTotalJYAmount() {
108
+      this.totalJYAmountAdjust = ((Number(this.budgetForm.outExpenseAdjust) || 0) + (Number(this.budgetForm.letterExpenseAdjust) || 0) + (Number(this.budgetForm.winExpenseAdjust) || 0) + (Number(this.budgetForm.taxExpenseAdjust) || 0) + (Number(this.budgetForm.travelExpenseAdjust) || 0)).toFixed(2)
109
+    }
110
+  }
111
+}
112
+</script>
113
+
114
+<style lang="scss" scoped>
115
+.business-cost {
116
+  .add-staff {
117
+    margin-bottom: 10px;
118
+  }
119
+
120
+  table {
121
+    text-align: center;
122
+    border-collapse: collapse;
123
+    margin: 0 auto;
124
+
125
+    td {
126
+      padding: 5px;
127
+    }
128
+  }
129
+
130
+  .adjust {
131
+    color: #F56C6C;
132
+    width: 120px;
133
+  }
134
+}
135
+
136
+.amount {
137
+  font-weight: bold;
138
+  font-family: Arial, Helvetica, sans-serif;
139
+}
140
+
141
+.remark-cell {
142
+  text-align: left;
143
+}
144
+</style>

+ 25
- 9
oa-ui/src/views/flowable/form/budget/adjust/newBudgetInfo.vue View File

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-05-07 11:01:39
3
  * @Date: 2025-05-07 11:01:39
4
  * @LastEditors: Please set LastEditors
4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-14 14:18:45
5
+ * @LastEditTime: 2025-05-15 17:40:52
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="main" v-loading="loading">
8
   <div class="main" v-loading="loading">
61
           <tr style="background-color:#f8f8f9" v-if="workList.length != 0">
61
           <tr style="background-color:#f8f8f9" v-if="workList.length != 0">
62
             <td style="min-width:50px">工作简述</td>
62
             <td style="min-width:50px">工作简述</td>
63
             <td style="min-width:50px">工作内容</td>
63
             <td style="min-width:50px">工作内容</td>
64
+            <td style="min-width:50px">内容细项</td>
64
             <td style="min-width:50px">比例尺/等级</td>
65
             <td style="min-width:50px">比例尺/等级</td>
65
             <td style="min-width:50px">数量</td>
66
             <td style="min-width:50px">数量</td>
66
             <td style="min-width:50px">单价</td>
67
             <td style="min-width:50px">单价</td>
71
           </tr>
72
           </tr>
72
           <tr v-for="work in workList">
73
           <tr v-for="work in workList">
73
             <td>{{ work.content }}</td>
74
             <td>{{ work.content }}</td>
74
-            <td>{{ work.cmcPrice ? work.cmcPrice.workItem : '' }}</td>
75
+            <td>{{ work.workItem }}</td>
76
+            <td>{{ work.subItem }}</td>
75
             <td>
77
             <td>
76
               {{ work.scaleGrade }}
78
               {{ work.scaleGrade }}
77
             </td>
79
             </td>
95
             <td class="remark-cell">{{ work.remark ? work.remark : '' }}</td>
97
             <td class="remark-cell">{{ work.remark ? work.remark : '' }}</td>
96
           </tr>
98
           </tr>
97
           <tr>
99
           <tr>
98
-            <td :colspan="7" class="head amount">内业绩效额合计</td>
100
+            <td :colspan="8" class="head amount">内业绩效额合计</td>
99
             <td :colspan="1" class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }"
101
             <td :colspan="1" class="head amount" :class="{ 'performance-error': isPerformanceExceeded() }"
100
               style="text-align:right;">
102
               style="text-align:right;">
101
               {{ budgetForm.settleExpense ? budgetForm.settleExpense.toFixed(2) : '0.00' }}
103
               {{ budgetForm.settleExpense ? budgetForm.settleExpense.toFixed(2) : '0.00' }}
130
               <el-input-number style="width:80px;" :controls="false" v-model="staff.performance" :min="0" :step="0.01"
132
               <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>
133
                 @change="(val) => updateInnerStaffAmount(staff, val, 'performance')"></el-input-number>
132
             </td>
134
             </td>
133
-            <td v-else>{{ staff.performance }}</td>
135
+            <td v-else style="text-align:right;">{{ staff.performance }}</td>
134
             <td style="text-align:right;">{{ staff.amount }}</td>
136
             <td style="text-align:right;">{{ staff.amount }}</td>
135
             <td class="remark-cell">{{ staff.remark }}</td>
137
             <td class="remark-cell">{{ staff.remark }}</td>
136
           </tr>
138
           </tr>
576
           let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
578
           let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
577
           this.workList = settleRes.rows;
579
           this.workList = settleRes.rows;
578
           for (let work of this.workList) {
580
           for (let work of this.workList) {
579
-            if (work.groundType == '0') {
580
-              work.price = work.cmcPrice.commonPrice
581
-              work.scaleGrade = work.cmcPrice.scaleGrade
582
-              work.unit = work.cmcPrice.unit
581
+            if (work.checkPriceId) {
582
+              work.workType = work.cmcCheckPrice.workType
583
+              work.workItem = work.cmcCheckPrice.workItem
584
+              work.subItem = work.cmcCheckPrice.subItem
585
+              work.scaleGrade = work.cmcCheckPrice.scaleGrade
586
+              work.unit = work.cmcCheckPrice.unit
587
+              if (work.groundType == '0') {
588
+                work.price = work.cmcCheckPrice.commonPrice
589
+              } else {
590
+                work.price = work.cmcCheckPrice.complexPrice
591
+              }
583
             } else {
592
             } else {
584
-              work.price = work.cmcPrice.complexPrice
593
+              work.workType = work.cmcPrice.workType
594
+              work.workItem = work.cmcPrice.workItem
595
+              work.subItem = work.cmcPrice.subItem
585
               work.scaleGrade = work.cmcPrice.scaleGrade
596
               work.scaleGrade = work.cmcPrice.scaleGrade
586
               work.unit = work.cmcPrice.unit
597
               work.unit = work.cmcPrice.unit
598
+              if (work.groundType == '0') {
599
+                work.price = work.cmcPrice.commonPrice
600
+              } else {
601
+                work.price = work.cmcPrice.complexPrice
602
+              }
587
             }
603
             }
588
           }
604
           }
589
           // 获取现场开支
605
           // 获取现场开支

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

58
 <script>
58
 <script>
59
 import { listUser, deptTreeSelect } from "@/api/system/user";
59
 import { listUser, deptTreeSelect } from "@/api/system/user";
60
 import { listDept } from "@/api/system/dept";
60
 import { listDept } from "@/api/system/dept";
61
+import { getUserDayValue } from "@/api/oa/wage/wage";
61
 export default {
62
 export default {
62
   dicts: ['sys_normal_disable', 'sys_user_sex', 'sys_user_titles', 'sys_user_certificates', 'sys_user_pmlevel', 'sys_user_postlevel', 'sys_user_salarylevel'],
63
   dicts: ['sys_normal_disable', 'sys_user_sex', 'sys_user_titles', 'sys_user_certificates', 'sys_user_pmlevel', 'sys_user_postlevel', 'sys_user_salarylevel'],
63
   props: {
64
   props: {
93
     getList() {
94
     getList() {
94
       listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
95
       listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
95
         this.userList = response.rows.filter(item => item.status != '1' && item.status != '2')
96
         this.userList = response.rows.filter(item => item.status != '1' && item.status != '2')
97
+        let month = this.parseTime(new Date(), '{y}-{m}')
98
+        this.userList.forEach(item => {
99
+          getUserDayValue({ userId: item.userId, payMonth: month }).then(res => {
100
+            if (res.data) {
101
+              item.socialSecurityUnit = res.data.socialSecurityUnit
102
+              item.houseFund = res.data.houseFund
103
+            }
104
+          })
105
+        })
96
         this.total = response.total;
106
         this.total = response.total;
97
       });
107
       });
98
     },
108
     },

+ 77
- 42
oa-ui/src/views/flowable/form/budget/moneyTable.vue View File

16
             <td colspan="4">备注</td>
16
             <td colspan="4">备注</td>
17
           </tr>
17
           </tr>
18
           <tr v-for="(work, index) in workList" :key="index">
18
           <tr v-for="(work, index) in workList" :key="index">
19
-            <td>
20
-              {{ index + 1 }}
21
-            </td>
22
-            <td colspan="2">
23
-              {{ work.content }}
24
-            </td>
25
-            <td>
26
-              {{ work.scale }}
27
-            </td>
28
-            <td>
29
-              {{ work.unit }}
30
-            </td>
31
-            <td>
32
-              {{ work.workload }}
33
-            </td>
34
-            <td>
35
-              {{ work.deadline }}
36
-            </td>
37
-            <td colspan="4">
38
-              {{ work.remark }}
39
-            </td>
19
+            <td>{{ index + 1 }}</td>
20
+            <td colspan="2">{{ work.content }}</td>
21
+            <td>{{ work.scale }}</td>
22
+            <td>{{ work.unit }}</td>
23
+            <td>{{ work.workload }}</td>
24
+            <td> {{ work.deadline }}</td>
25
+            <td colspan="4">{{ work.remark }}</td>
40
           </tr>
26
           </tr>
41
         </table>
27
         </table>
42
       </el-form-item>
28
       </el-form-item>
47
           </tr>
33
           </tr>
48
           <tr class="content-head">
34
           <tr class="content-head">
49
             <td style="width: 100px;">工作简述</td>
35
             <td style="width: 100px;">工作简述</td>
50
-            <td style="width: 100px;">工作类别</td>
51
-            <td style="width: 100px;">工作项目</td>
36
+            <!-- <td style="width: 100px;">工作类别</td> -->
37
+            <td style="width: 100px;">工作内容</td>
38
+            <td style="width: 100px;">内容细项</td>
52
             <td style="width: 80px;">比例尺/等级</td>
39
             <td style="width: 80px;">比例尺/等级</td>
53
             <td style="width: 80px;">地类类型</td>
40
             <td style="width: 80px;">地类类型</td>
54
             <td style="width: 50px;">单价</td>
41
             <td style="width: 50px;">单价</td>
67
               <el-input type="textarea" v-model="work.content"></el-input>
54
               <el-input type="textarea" v-model="work.content"></el-input>
68
             </td>
55
             </td>
69
             <!-- 选择工作类别 -->
56
             <!-- 选择工作类别 -->
70
-            <td>
57
+            <!-- <td>
71
               <el-select v-model="work.workType" :style="{ width: '100%' }"
58
               <el-select v-model="work.workType" :style="{ width: '100%' }"
72
                 @change="getWorkItemList(work, work.workType)">
59
                 @change="getWorkItemList(work, work.workType)">
73
                 <el-option v-for="item in workTypeList" :key="item.value" :label="item.label" :value="item.value">
60
                 <el-option v-for="item in workTypeList" :key="item.value" :label="item.label" :value="item.value">
74
                 </el-option>
61
                 </el-option>
75
               </el-select>
62
               </el-select>
76
-            </td>
63
+            </td> -->
77
             <!-- 选择工作项目 -->
64
             <!-- 选择工作项目 -->
78
             <td>
65
             <td>
79
               <el-select v-model="work.workItem" :style="{ width: '100%' }" :remote="true"
66
               <el-select v-model="work.workItem" :style="{ width: '100%' }" :remote="true"
80
                 @change="getScaleGradeList(work, work.workItem)">
67
                 @change="getScaleGradeList(work, work.workItem)">
81
-                <el-option v-for="item in work.workSelect.workItemList" :key="item.value" :label="item.label"
68
+                <el-option v-for="item in workItemList" :key="item.value" :label="item.label" :value="item.value">
69
+                </el-option>
70
+              </el-select>
71
+            </td>
72
+            <!-- 选择内容细项 -->
73
+            <td>
74
+              <el-select v-model="work.subItem" :style="{ width: '100%' }" :remote="true"
75
+                @change="setRemarkBySubItem(work, work.subItem)">
76
+                <el-option v-for="item in work.workSelect.subItemList" :key="item.value" :label="item.label"
82
                   :value="item.value">
77
                   :value="item.value">
83
                 </el-option>
78
                 </el-option>
84
               </el-select>
79
               </el-select>
120
               <el-input-number v-model="work.coefficient" :controls="false" :precision="2" :step="0.01" :max="10"
115
               <el-input-number v-model="work.coefficient" :controls="false" :precision="2" :step="0.01" :max="10"
121
                 @blur="getTotal(work)" style="width:60px;">
116
                 @blur="getTotal(work)" style="width:60px;">
122
               </el-input-number>
117
               </el-input-number>
123
-              <el-tooltip content="系数备注" placement="right-start">
118
+              <!-- <el-tooltip content="系数备注" placement="right-start">
124
                 <el-button icon="el-icon-info" type="text" @click="getCoefficientRemark(work.workType)"></el-button>
119
                 <el-button icon="el-icon-info" type="text" @click="getCoefficientRemark(work.workType)"></el-button>
125
-              </el-tooltip>
120
+              </el-tooltip> -->
126
 
121
 
127
             </td>
122
             </td>
128
             <!-- 备注 -->
123
             <!-- 备注 -->
149
 import { listProjectWork } from "@/api/oa/project/projectWork";
144
 import { listProjectWork } from "@/api/oa/project/projectWork";
150
 import { getPriceRemarkByWorkType } from '@/api/oa/price/price'
145
 import { getPriceRemarkByWorkType } from '@/api/oa/price/price'
151
 import { listBudgetSettle, addBudgetSettle, delBudgetSettle } from "@/api/oa/budget/budgetSettle.js";
146
 import { listBudgetSettle, addBudgetSettle, delBudgetSettle } from "@/api/oa/budget/budgetSettle.js";
152
-import { getWorkTypeList, getWorkItemList, getSubItemList, getScaleGradeList, getUnitPrice } from '@/api/oa/price/price'
147
+// import { getWorkTypeList, getWorkItemList, getSubItemList, getScaleGradeList, getUnitPrice } from '@/api/oa/price/price'
148
+import { getWorkTypeList, getWorkItemList, getSubItemList, getScaleGradeList, getUnitPrice } from '@/api/oa/price/checkPrice'
153
 export default {
149
 export default {
154
   props: {
150
   props: {
155
     projectId: {
151
     projectId: {
166
       form: {},
162
       form: {},
167
       workList: [],//项目概况工作列表
163
       workList: [],//项目概况工作列表
168
       workTypeList: [],
164
       workTypeList: [],
165
+      workItemList: [],
169
       contentList: [
166
       contentList: [
170
         {
167
         {
171
           content: '',
168
           content: '',
172
           workType: '',
169
           workType: '',
173
           workItem: '',
170
           workItem: '',
171
+          subItem: '',
174
           scaleGrade: '',
172
           scaleGrade: '',
175
           groundType: '0',
173
           groundType: '0',
176
           price: '',
174
           price: '',
204
     },
202
     },
205
     contentList: {
203
     contentList: {
206
       handler(newVal) {
204
       handler(newVal) {
207
-        let list = newVal.filter(item => item.priceId);
205
+        let list = newVal.filter(item => item.checkPriceId);
208
         this.$emit('contentList', list)
206
         this.$emit('contentList', list)
209
       },
207
       },
210
       immediate: true, // 立即生效
208
       immediate: true, // 立即生效
213
   },
211
   },
214
   created() {
212
   created() {
215
     this.initTable();
213
     this.initTable();
216
-    this.initWorkTypeList();
214
+    // this.initWorkTypeList();
215
+    this.initWorkItemList();
217
   },
216
   },
218
   methods: {
217
   methods: {
219
     initTable() {
218
     initTable() {
249
           subItemLoading: true,
248
           subItemLoading: true,
250
           scaleGradeLoading: true,
249
           scaleGradeLoading: true,
251
         })
250
         })
252
-        this.$set(c, 'workType', c.cmcPrice.workType)
253
-        this.$set(c, 'scaleGrade', c.cmcPrice.scaleGrade)
254
-        this.$set(c, 'workItem', c.cmcPrice.workItem)
255
-        this.$set(c, 'unit', c.cmcPrice.unit)
256
-        if (c.groundType == '0') {
257
-          this.$set(c, 'price', c.cmcPrice.commonPrice)
251
+        if (c.checkPriceId) {
252
+          this.$set(c, 'workType', c.cmcCheckPrice.workType)
253
+          this.$set(c, 'workItem', c.cmcCheckPrice.workItem)
254
+          this.$set(c, 'subItem', c.cmcCheckPrice.subItem)
255
+          this.$set(c, 'scaleGrade', c.cmcCheckPrice.scaleGrade)
256
+          this.$set(c, 'unit', c.cmcCheckPrice.unit)
257
+          if (c.groundType == '0') {
258
+            this.$set(c, 'price', c.cmcCheckPrice.commonPrice)
259
+          } else {
260
+            this.$set(c, 'price', c.cmcCheckPrice.complexPrice)
261
+          }
258
         } else {
262
         } else {
259
-          this.$set(c, 'price', c.cmcPrice.complexPrice)
263
+          this.$set(c, 'workType', c.cmcPrice.workType)
264
+          this.$set(c, 'scaleGrade', c.cmcPrice.scaleGrade)
265
+          this.$set(c, 'workItem', c.cmcPrice.workItem)
266
+          this.$set(c, 'unit', c.cmcPrice.unit)
267
+          this.$set(c, 'groundType', c.cmcPrice.groundType)
268
+          if (c.groundType == '0') {
269
+            this.$set(c, 'price', c.cmcPrice.commonPrice)
270
+          } else {
271
+            this.$set(c, 'price', c.cmcPrice.complexPrice)
272
+          }
260
         }
273
         }
261
         this.getTotal(c)
274
         this.getTotal(c)
262
       }
275
       }
269
         }
282
         }
270
       });
283
       });
271
     },
284
     },
285
+    initWorkItemList() {
286
+      getWorkItemList({ workType: '内业' }).then(res => {
287
+        if (res) {
288
+          this.workItemList = this.setArray(res);
289
+        }
290
+      })
291
+    },
272
     /* 获取工作项目 */
292
     /* 获取工作项目 */
273
     getWorkItemList(work, workType) {
293
     getWorkItemList(work, workType) {
274
       getWorkItemList({ workType: workType }).then(res => {
294
       getWorkItemList({ workType: workType }).then(res => {
281
         }
301
         }
282
       })
302
       })
283
     },
303
     },
304
+    // 获取内容细项
305
+    getWorkSubItemList(work, workItem) {
306
+      getSubItemList({ workItem }).then(res => {
307
+        if (res) {
308
+          let subItemList = this.setArray(res);
309
+          work.workSelect.subItemList = subItemList;
310
+          this.$set(work, 'subItem', subItemList[0].label);
311
+          this.$set(work, 'remark', subItemList[0].remark);
312
+        }
313
+      })
314
+    },
315
+    // 设置备注
316
+    setRemarkBySubItem(work) {
317
+      this.getUnitPrice(work, work.workItem, work.subItem, work.scaleGrade, work.groundType);
318
+    },
284
     /* 获取比例尺 */
319
     /* 获取比例尺 */
285
     getScaleGradeList(work, workItem) {
320
     getScaleGradeList(work, workItem) {
321
+      this.getWorkSubItemList(work, workItem);
286
       if (work.scale) {
322
       if (work.scale) {
287
         this.$set(work, 'scaleGrade', work.scale);
323
         this.$set(work, 'scaleGrade', work.scale);
288
         if (work.groundType == undefined) {
324
         if (work.groundType == undefined) {
295
             let scaleGradeList = this.setArray(res);
331
             let scaleGradeList = this.setArray(res);
296
             work.workSelect.scaleGradeLoading = false;
332
             work.workSelect.scaleGradeLoading = false;
297
             work.workSelect.scaleGradeList = scaleGradeList;
333
             work.workSelect.scaleGradeList = scaleGradeList;
298
-            this.$set(work, 'scaleGrade', scaleGradeList[0].label)
299
-            // work.scaleGrade = scaleGradeList[0].label;
334
+            this.$set(work, 'scaleGrade', scaleGradeList[0].label);
300
             if (work.scaleGrade == undefined) {
335
             if (work.scaleGrade == undefined) {
301
               this.$set(work, 'scaleGrade', '无');
336
               this.$set(work, 'scaleGrade', '无');
302
             }
337
             }
312
     getUnitPrice(work, workItem, subItem, scaleGrade, groundType) {
347
     getUnitPrice(work, workItem, subItem, scaleGrade, groundType) {
313
       getUnitPrice({ workItem, subItem, scaleGrade, groundType: groundType }).then(res => {
348
       getUnitPrice({ workItem, subItem, scaleGrade, groundType: groundType }).then(res => {
314
         if (res.length != 0) {
349
         if (res.length != 0) {
315
-          work.priceId = res.data.id;
350
+          work.checkPriceId = res.data.id;
316
           this.$set(work, 'price', res.data.price)
351
           this.$set(work, 'price', res.data.price)
317
           this.$set(work, 'unit', res.data.unit)
352
           this.$set(work, 'unit', res.data.unit)
318
           this.$set(work, 'coefficient', 1)
353
           this.$set(work, 'coefficient', 1)
354
+          this.$set(work, 'remark', res.data.remark)
319
           if (work.workload != undefined || work.workload != '') {
355
           if (work.workload != undefined || work.workload != '') {
320
-
321
             this.getTotal(work);
356
             this.getTotal(work);
322
           }
357
           }
323
         }
358
         }

+ 3
- 2
oa-ui/src/views/flowable/form/budget/staffTable.vue View File

280
         if (v.deptId === 115) {
280
         if (v.deptId === 115) {
281
           v.salary = { salary: 7898.75 }
281
           v.salary = { salary: 7898.75 }
282
         }
282
         }
283
+        let dayCost = (parseFloat(((v.salary.salary + 1780) * 12) / 365) + v.socialSecurityUnit + v.houseFund).toFixed(2);
283
         v.type = this.currentType === 'inner' ? '内业' : '外业';
284
         v.type = this.currentType === 'inner' ? '内业' : '外业';
284
         v.days = 0; // 初始化天数为0
285
         v.days = 0; // 初始化天数为0
285
         v.staffCost = 0; // 初始化成本为0
286
         v.staffCost = 0; // 初始化成本为0
286
         v.coefficient = 1; // 初始化系数为1
287
         v.coefficient = 1; // 初始化系数为1
287
         v.otherCoefficient = 1; // 初始化其他系数为1
288
         v.otherCoefficient = 1; // 初始化其他系数为1
288
-        v.userDays = parseFloat(((v.salary.salary + 1780) * 12) / 365).toFixed(2);
289
+        v.dayCost = dayCost;
289
       }
290
       }
290
       if (this.currentType === 'inner') {
291
       if (this.currentType === 'inner') {
291
         this.innerUsers = val;
292
         this.innerUsers = val;
316
         user.performance = 200 * Number(user.days) * Number(user.coefficient);
317
         user.performance = 200 * Number(user.days) * Number(user.coefficient);
317
       }
318
       }
318
       if (!user.dayCost) {
319
       if (!user.dayCost) {
319
-        user.dayCost = parseFloat(((user.salary.salary + 1780) * 12) / 365).toFixed(2)
320
+        user.dayCost = (parseFloat(((user.salary.salary + 1780) * 12) / 365) + user.socialSecurityUnit + user.houseFund).toFixed(2);
320
       }
321
       }
321
       let staffCost = Number(user.dayCost) * Number(user.days)
322
       let staffCost = Number(user.dayCost) * Number(user.days)
322
       total = user.dayCost * Number(user.days) + Number(user.performance);
323
       total = user.dayCost * Number(user.days) + Number(user.performance);

+ 91
- 16
oa-ui/src/views/oa/wage/index.vue View File

8
           </el-option>
8
           </el-option>
9
         </el-select>
9
         </el-select>
10
       </el-form-item>
10
       </el-form-item>
11
-      <el-form-item label="发放日期" prop="payDay">
12
-        <el-date-picker clearable v-model="queryParams.payDay" type="date" value-format="yyyy-MM-dd"
13
-          placeholder="请选择发放日期">
14
-        </el-date-picker>
15
-      </el-form-item>
16
       <el-form-item label="发放月份" prop="payMonth">
11
       <el-form-item label="发放月份" prop="payMonth">
17
-        <el-date-picker clearable v-model="queryParams.payMonth" type="date" value-format="yyyy-MM-dd"
12
+        <el-date-picker clearable v-model="queryParams.payMonth" type="month" value-format="yyyy-MM-dd"
18
           placeholder="请选择发放月份">
13
           placeholder="请选择发放月份">
19
         </el-date-picker>
14
         </el-date-picker>
20
       </el-form-item>
15
       </el-form-item>
43
       </el-col> -->
38
       </el-col> -->
44
       <el-col :span="1.5">
39
       <el-col :span="1.5">
45
         <el-button type="warning" plain icon="el-icon-upload2" size="mini" @click="handleImport"
40
         <el-button type="warning" plain icon="el-icon-upload2" size="mini" @click="handleImport"
46
-          v-hasPermi="['oa:wage:export']">导入</el-button>
41
+          v-hasPermi="['oa:wage:export']">上传社保公积金</el-button>
47
       </el-col>
42
       </el-col>
48
-    
43
+
49
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
44
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
50
     </el-row>
45
     </el-row>
51
 
46
 
64
       <el-table-column label="高温补贴" align="center" prop="highTemperatureSubsidy" />
59
       <el-table-column label="高温补贴" align="center" prop="highTemperatureSubsidy" />
65
       <el-table-column label="考勤扣款" align="center" prop="attendanceDeduct" />
60
       <el-table-column label="考勤扣款" align="center" prop="attendanceDeduct" />
66
       <el-table-column label="应发小计" align="center" prop="payableWage" /> -->
61
       <el-table-column label="应发小计" align="center" prop="payableWage" /> -->
67
-      <el-table-column label="公积金" align="center" prop="houseFund" />
62
+      <el-table-column label="公积金单位部分" align="center" prop="houseFund" />
68
       <!-- <el-table-column label="养老保险" align="center" prop="endowmentInsurance" />
63
       <!-- <el-table-column label="养老保险" align="center" prop="endowmentInsurance" />
69
       <el-table-column label="失业保险" align="center" prop="unemploymentInsurance" />
64
       <el-table-column label="失业保险" align="center" prop="unemploymentInsurance" />
70
       <el-table-column label="医疗保险" align="center" prop="medicalInsurance" />
65
       <el-table-column label="医疗保险" align="center" prop="medicalInsurance" />
73
       <el-table-column label="社保单位部分" align="center" prop="socialSecurityUnit" />
68
       <el-table-column label="社保单位部分" align="center" prop="socialSecurityUnit" />
74
       <!-- <el-table-column label="个税" align="center" prop="individualIncomeTax" />
69
       <!-- <el-table-column label="个税" align="center" prop="individualIncomeTax" />
75
       <el-table-column label="实发工资" align="center" prop="paidWage" /> -->
70
       <el-table-column label="实发工资" align="center" prop="paidWage" /> -->
76
-      <el-table-column label="发放日期" align="center" prop="payDay" width="180">
71
+      <!-- <el-table-column label="发放日期" align="center" prop="payDay" width="180">
77
         <template slot-scope="scope">
72
         <template slot-scope="scope">
78
           <span>{{ parseTime(scope.row.payDay, '{y}-{m}-{d}') }}</span>
73
           <span>{{ parseTime(scope.row.payDay, '{y}-{m}-{d}') }}</span>
79
         </template>
74
         </template>
80
-      </el-table-column>
75
+      </el-table-column> -->
81
       <el-table-column label="发放月份" align="center" prop="payMonth" width="180">
76
       <el-table-column label="发放月份" align="center" prop="payMonth" width="180">
82
         <template slot-scope="scope">
77
         <template slot-scope="scope">
83
-          <span>{{ parseTime(scope.row.payMonth, '{y}-{m}-{d}') }}</span>
78
+          <span>{{ parseTime(scope.row.payMonth, '{y}-{m}') }}</span>
84
         </template>
79
         </template>
85
       </el-table-column>
80
       </el-table-column>
86
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
81
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
97
       @pagination="getList" />
92
       @pagination="getList" />
98
 
93
 
99
     <!-- 添加或修改员工工资对话框 -->
94
     <!-- 添加或修改员工工资对话框 -->
100
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
95
+    <el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
101
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
96
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
102
         <el-form-item label="员工id" prop="userId">
97
         <el-form-item label="员工id" prop="userId">
103
           <el-input v-model="form.userId" placeholder="请输入员工id" />
98
           <el-input v-model="form.userId" placeholder="请输入员工id" />
173
         <el-button @click="cancel">取 消</el-button>
168
         <el-button @click="cancel">取 消</el-button>
174
       </div>
169
       </div>
175
     </el-dialog>
170
     </el-dialog>
171
+    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
172
+      <el-upload ref="uploadRef" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url"
173
+        :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-change="handleFileUploadChange"
174
+        :on-success="handleFileSuccess" :auto-upload="false" drag v-loading="uploadLoading"
175
+        element-loading-text="正在上传,请稍等">
176
+        <i class="el-icon-upload"></i>
177
+        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
178
+        <template #tip>
179
+          <div class="el-upload__tip text-center">
180
+            <span>仅允许导入xls、xlsx格式文件。</span>
181
+            <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
182
+              @click="importTemplate">下载模板</el-link>
183
+          </div>
184
+        </template>
185
+      </el-upload>
186
+      <template #footer>
187
+        <div class="dialog-footer">
188
+          <el-button type="primary" @click="submitUpload">确 定</el-button>
189
+          <el-button @click="upload.open = false">取 消</el-button>
190
+        </div>
191
+      </template>
192
+    </el-dialog>
176
   </div>
193
   </div>
177
 </template>
194
 </template>
178
 
195
 
179
 <script>
196
 <script>
180
 import { listWage, getWage, delWage, addWage, updateWage } from "@/api/oa/wage/wage";
197
 import { listWage, getWage, delWage, addWage, updateWage } from "@/api/oa/wage/wage";
198
+import { downloadTemplate } from "@/api/file/project";
199
+import { getToken } from "@/utils/auth";
181
 
200
 
182
 export default {
201
 export default {
183
   name: "Wage",
202
   name: "Wage",
232
       form: {},
251
       form: {},
233
       // 表单校验
252
       // 表单校验
234
       rules: {
253
       rules: {
235
-      }
254
+      },
255
+      upload: {
256
+        // 是否显示弹出层(用户导入)
257
+        open: false,
258
+        // 弹出层标题(用户导入)
259
+        title: "上传社保公积金",
260
+        // 是否禁用上传
261
+        isUploading: false,
262
+        // 是否更新已经存在的用户数据
263
+        updateSupport: 0,
264
+        // 设置上传的请求头部'Content-Type': 'multipart/form-data', 
265
+        headers: { 'Authorization': "Bearer " + getToken() },
266
+        data: undefined,
267
+        // 上传的地址
268
+        url: process.env.VUE_APP_BASE_API + "/oa/wage/uploadSheet"
269
+      },
270
+      uploadLoading: false,
271
+      uploadFormData: undefined,
236
     };
272
     };
237
   },
273
   },
238
   created() {
274
   created() {
351
       }, `wage_${new Date().getTime()}.xlsx`)
387
       }, `wage_${new Date().getTime()}.xlsx`)
352
     },
388
     },
353
     handleImport() {
389
     handleImport() {
354
-
355
-    }
390
+      this.upload.open = true;
391
+    },
392
+    /**Excel文件上传中处理 */
393
+    handleFileUploadProgress(event, file, fileList) {
394
+      this.upload.isUploading = true;
395
+      this.uploadLoading = true;
396
+    },
397
+    /* Excel文件改变时 */
398
+    handleFileUploadChange(file, fileList) {
399
+      if (fileList.length > 1) {
400
+        fileList.splice(0, 1);
401
+      }
402
+      this.uploadFormData = new FormData();
403
+      this.uploadFormData.append("file", file);
404
+      this.upload.data = this.uploadFormData;
405
+    },
406
+    /** Excel文件上传成功处理 */
407
+    handleFileSuccess(response, file, fileList) {
408
+      this.upload.open = false;
409
+      this.upload.isUploading = false;
410
+      this.uploadLoading = false;
411
+      this.fileList = [];
412
+      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
413
+      this.$refs["uploadRef"].clearFiles();
414
+      this.getList();
415
+    },
416
+    /* Excel上传提交按钮 */
417
+    submitUpload() {
418
+      this.$refs['uploadRef'].submit();
419
+    },
420
+    /* 下载模板 */
421
+    importTemplate() {
422
+      const path = "http://127.0.0.1:8080/profile/template/userWage.xlsx"
423
+      // const path = "http://oa.sccehui.com:6104/prod-api/profile/template/cg-template.xlsx"
424
+      downloadTemplate(path).then(res => {
425
+        const blob = new Blob([res])
426
+        saveAs(blob, '社保公积金模版.xlsx');
427
+      });
428
+      // this.download("file/achievement/importTemplate", {
429
+      // }, `成果表模板.xlsx`);
430
+    },
356
   }
431
   }
357
 };
432
 };
358
 </script>
433
 </script>

Loading…
Cancel
Save