瀏覽代碼

网页端:修改预算有问题的地方

移动端:新增用车管理和借款管理
余思翰 2 月之前
父節點
當前提交
c45b03d217

+ 25
- 1
oa-ui-app/pages.json 查看文件

@@ -133,7 +133,24 @@
133 133
 			"path" : "pages/oa/borrow/borrowList",
134 134
 			"style" : 
135 135
 			{
136
-				"navigationBarTitleText" : "借款管理"
136
+				"navigationBarTitleText" : "借款管理",
137
+				"enablePullDownRefresh": true
138
+			}
139
+		},
140
+		{
141
+			"path" : "pages/oa/car/carList",
142
+			"style" : 
143
+			{
144
+				"navigationBarTitleText" : "用车管理",
145
+				"enablePullDownRefresh": true
146
+			}
147
+		},
148
+		{
149
+			"path" : "pages/oa/car/useCarList",
150
+			"style" : 
151
+			{
152
+				"navigationBarTitleText" : "派出记录",
153
+				"enablePullDownRefresh": true
137 154
 			}
138 155
 		},
139 156
 		{
@@ -142,6 +159,13 @@
142 159
 			{
143 160
 				"navigationBarTitleText" : "设备作业记录"
144 161
 			}
162
+		},
163
+		{
164
+			"path" : "pages/components/formInfo",
165
+			"style" : 
166
+			{
167
+				"navigationBarTitleText" : "表单信息"
168
+			}
145 169
 		}
146 170
 	],
147 171
 	"tabBar": {

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

@@ -2,7 +2,7 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-03-17 10:04:51
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-03-28 14:29:11
5
+ * @LastEditTime: 2025-06-16 17:08:15
6 6
 -->
7 7
 <template>
8 8
   <view>
@@ -39,6 +39,9 @@ export default {
39 39
     }
40 40
   },
41 41
   created() {
42
+    if (!this.taskForm.procInsId) {
43
+      return
44
+    }
42 45
     this.getFlowRecordList(this.taskForm.procInsId, this.taskForm.deployId);
43 46
   },
44 47
   methods: {

+ 34
- 0
oa-ui-app/pages/components/formInfo.vue 查看文件

@@ -0,0 +1,34 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-06-16 16:26:24
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-06-16 17:09:31
6
+-->
7
+<template>
8
+  <view>
9
+    <borrow :taskForm="taskForm" :taskName="''" v-if="types == 'borrow'"></borrow>
10
+  </view>
11
+</template>
12
+
13
+<script>
14
+import borrow from '@/pages/form/borrow/borrow.vue'
15
+export default {
16
+  components: { borrow },
17
+  created() {
18
+    if (this.$route.query.formType == 'borrow') {
19
+      this.taskForm.formId = this.$route.query.formId
20
+      this.types = 'borrow'
21
+    }
22
+  },
23
+  data() {
24
+    return {
25
+      taskForm: {
26
+        formId: ''
27
+      },
28
+      types: ''
29
+    }
30
+  },
31
+}
32
+</script>
33
+
34
+<style lang="scss" scoped></style>

+ 390
- 45
oa-ui-app/pages/oa/borrow/borrowList.vue 查看文件

@@ -1,15 +1,91 @@
1 1
 <template>
2 2
   <view class="container">
3 3
     <uv-tabs :list="tabList" @click="clickTab"></uv-tabs>
4
-    <view>
5
-      
6
-    </view>
4
+    <mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption"
5
+      :up="upOption" :fixed="false" :top="10" style="padding: 30rpx;">
6
+      <view>
7
+        <view v-for="(item, index) in borrowList" :key="index" class="modern-card">
8
+          <view class="modern-card-header" v-if="selectedTab === '项目借款'">
9
+            <view class="modern-card-title">
10
+              <text class="project-number">{{ item.projectNumber }}</text>
11
+              <text class="project-name">{{ item.project ? item.project.projectName : '' }}</text>
12
+            </view>
13
+          </view>
14
+          <view class="modern-card-header" v-else>
15
+            <view class="modern-card-title">
16
+              <text class="project-name">{{ item.applyReason }}</text>
17
+            </view>
18
+          </view>
19
+          <view class="modern-card-body">
20
+            <view class="avatar-section">
21
+              <view class="avatar">
22
+                <text>{{ item.applierUser.nickName ? item.applierUser.nickName[0] : '' }}</text>
23
+              </view>
24
+              <view>
25
+                <text class="applier-name">{{ item.applierUser.nickName }}</text>
26
+                <text class="dept-name">{{ item.dept.deptName }}</text>
27
+              </view>
28
+            </view>
29
+            <view class="info-row">
30
+              <text class="info-label">申请时间:</text>
31
+              <text class="info-value">{{ item.applyDate }}</text>
32
+            </view>
33
+            <view class="info-row">
34
+              <text class="info-label">申请说明:</text>
35
+              <text class="info-value">{{ item.remark }}</text>
36
+            </view>
37
+            <view class="info-row">
38
+              <text class="info-label">申请金额:</text>
39
+              <text class="amount-highlight-detail">¥{{ item.applyAmount }}</text>
40
+            </view>
41
+            <view class="info-row">
42
+              <text class="info-label">核准金额:</text>
43
+              <text class="manager-amount-highlight-detail">¥{{ item.managerAmount }}</text>
44
+            </view>
45
+          </view>
46
+          <view class="modern-card-footer">
47
+            <button class="footer-btn detail-btn" @click="openDetailPopup(item.borrowId)">查看明细</button>
48
+            <button class="footer-btn form-btn" @click="openFormInfo(item)">表单信息</button>
49
+          </view>
50
+        </view>
51
+      </view> 
52
+    </mescroll-uni>
53
+    <uv-popup ref="detailPopup" mode="bottom">
54
+      <view class="popup-detail-list" @touchmove.stop>
55
+        <view class="popup-close-btn" @click="$refs.detailPopup.close()">×</view>
56
+        <view class="popup-detail-title">借款明细</view>
57
+        <view v-for="(item, index) in detailList" :key="item.borrowDetailId" class="popup-detail-item">
58
+          <view class="popup-detail-index">{{ index + 1 }}</view>
59
+          <view class="popup-detail-main">
60
+            <view class="popup-detail-row">
61
+              <text class="popup-detail-label">开支项目:</text>
62
+              <text class="popup-detail-value">{{ item.borrowItem }}</text>
63
+            </view>
64
+            <view class="popup-detail-row">
65
+              <text class="popup-detail-label">单价×数量:</text>
66
+              <text class="popup-detail-value">¥{{ item.price }} × {{ item.quantity }}{{ item.unit }}</text>
67
+            </view>
68
+            <view class="popup-detail-row">
69
+              <text class="popup-detail-label">申请金额:</text>
70
+              <text class="popup-detail-amount">¥{{ item.applyAmount }}</text>
71
+            </view>
72
+            <view class="popup-detail-row" v-if="item.managerAmount">
73
+              <text class="popup-detail-label">核准金额:</text>
74
+              <text class="popup-detail-manager-amount">¥{{ item.managerAmount }}</text>
75
+            </view>
76
+          </view>
77
+        </view>
78
+      </view>
79
+    </uv-popup>
7 80
   </view>
8 81
 </template>
9 82
 
10 83
 <script>
11
-
84
+import { listBorrow } from '@/api/oa/borrow/borrow';
85
+import { listBorrowDetail, addBorrowDetail, updateBorrowDetail, delBorrowDetail, delBorrowDetailByDetailId } from "@/api/oa/borrow/borrowDetail";
86
+import MescrollMixin from '@/uni_modules/mescroll/components/mescroll-uni/mescroll-mixins.js'
12 87
 export default {
88
+  mixins: [MescrollMixin],
13 89
   data() {
14 90
     return {
15 91
       tabList: [{
@@ -24,59 +100,91 @@ export default {
24 100
         name: '团委借款'
25 101
       }],
26 102
       selectedTab: '项目借款',
27
-      isSearchExpanded: false,
103
+      mescroll: null, // mescroll实例
104
+      downOption: {
105
+        auto: true,
106
+        textOutOffset: '下拉刷新',
107
+        textLoading: '加载中...'
108
+      },
109
+      upOption: {
110
+        auto: false,
111
+        page: { num: 1, size: 10 },
112
+        noMoreSize: 5,
113
+        empty: { tip: '暂无借款数据' },
114
+        textNoMore: '~ 没有更多数据了 ~'
115
+      },
116
+      borrowList: [],
28 117
       queryParams: {
29
-        projectId: '',
30
-        applier: '',
31
-        borrowUsage: ''
118
+        pageNum: 1,
119
+        pageSize: 10,
120
+        borrowUsage: '0'
32 121
       },
33
-      borrowUsageList: [
34
-        {
35
-          value: '0',
36
-          text: '项目借款'
37
-        },
38
-        {
39
-          value: '1',
40
-          text: '非项目借款'
41
-        },
42
-        {
43
-          value: '2',
44
-          text: '工会借款'
45
-        },
46
-        {
47
-          value: '3',
48
-          text: '党委借款'
49
-        },
50
-        {
51
-          value: '4',
52
-          text: '团委借款'
53
-        }
54
-      ],
55
-      selectedBorrowUsage: '项目借款'
122
+      detailList: []
56 123
     }
57 124
   },
125
+  onLoad: function (options) {
126
+    uni.startPullDownRefresh();
127
+  },
58 128
   methods: {
59
-    toggleSearch() {
60
-      this.isSearchExpanded = !this.isSearchExpanded;
129
+    // 加载数据
130
+    async loadData() {
131
+      try {
132
+        const res = await listBorrow(this.queryParams)
133
+        return { data: res.rows, total: res.total }
134
+      } catch (e) {
135
+        return { data: [], error: true }
136
+      }
61 137
     },
62
-    handleQuery() {
63
-      console.log(this.queryParams);
138
+    mescrollInit(mescroll) {
139
+      this.mescroll = mescroll;
64 140
     },
65
-    resetQuery() {
66
-      this.queryParams = {
67
-        projectNumber: '',
68
-        projectName: '',
69
-        leader: '',
70
-        dept: ''
71
-      };
141
+    // mescroll下拉刷新回调
142
+    async downCallback() {
143
+      this.borrowList = []; // 清空列表
144
+      this.queryParams.pageNum = 1
145
+      const res = await this.loadData()
146
+      if (res.error) {
147
+        this.mescroll.endErr();
148
+      } else {
149
+        this.borrowList = res.data;
150
+        this.mescroll.endSuccess(res.data.length, res.total);
151
+      }
152
+      uni.stopPullDownRefresh();
72 153
     },
73
-    handleBorrowUsageChange(e) {
74
-      this.selectedBorrowUsage = this.borrowUsageList[e.target.value].text;
154
+    // mescroll上拉加载回调
155
+    async upCallback(page) {
156
+      this.queryParams.pageNum = page.num
157
+      const res = await this.loadData()
158
+      if (res.error) {
159
+        this.mescroll.endErr();
160
+      } else {
161
+        this.borrowList = this.borrowList.concat(res.data)
162
+        this.mescroll.endSuccess(res.data.length, res.total);
163
+      }
75 164
     },
76 165
     clickTab(obj) {
77
-      console.log(obj);
78 166
       let index = obj.index;
79 167
       this.selectedTab = this.tabList[index].name;
168
+      let param = [
169
+        { name: '项目借款', value: '0' },
170
+        { name: '非项目借款', value: '1' },
171
+        { name: '工会借款', value: '2' },
172
+        { name: '党委借款', value: '3' },
173
+        { name: '团委借款', value: '4' }
174
+      ]
175
+      this.queryParams.borrowUsage = param[index].value;
176
+      uni.startPullDownRefresh();
177
+    },
178
+    openDetailPopup(borrowId) {
179
+      listBorrowDetail({ borrowId: borrowId, pageNum: 1, pageSize: 200 }).then(res => {
180
+        this.detailList = res.rows;
181
+        this.$refs.detailPopup.open();
182
+      })
183
+    },
184
+    openFormInfo(item) {
185
+      uni.navigateTo({
186
+        url: `/pages/components/formInfo?formId=${item.borrowId}&formType=borrow`
187
+      });
80 188
     }
81 189
   }
82 190
 }
@@ -156,4 +264,241 @@ export default {
156 264
 .search-buttons button {
157 265
   flex: 1;
158 266
 }
267
+
268
+.modern-card {
269
+  background: #fff;
270
+  border-radius: 18rpx;
271
+  margin-bottom: 32rpx;
272
+  box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
273
+  overflow: hidden;
274
+  transition: box-shadow 0.2s;
275
+  border: 1rpx solid #f0f0f0;
276
+}
277
+
278
+.modern-card-header {
279
+  display: flex;
280
+  justify-content: space-between;
281
+  align-items: center;
282
+  background: linear-gradient(90deg, #e0e7ff 0%, #f8fafc 100%);
283
+  padding: 24rpx 28rpx 16rpx 28rpx;
284
+}
285
+
286
+.modern-card-title {
287
+  display: flex;
288
+  flex-direction: column;
289
+}
290
+
291
+.project-number {
292
+  font-size: 26rpx;
293
+  color: #6366f1;
294
+  font-weight: 600;
295
+}
296
+
297
+.project-name {
298
+  font-size: 28rpx;
299
+  color: #22223b;
300
+  font-weight: bold;
301
+  margin-top: 4rpx;
302
+}
303
+
304
+.amount-highlight {
305
+  background: #fef3c7;
306
+  color: #d97706;
307
+  font-size: 32rpx;
308
+  font-weight: bold;
309
+  border-radius: 10rpx;
310
+  padding: 8rpx 20rpx;
311
+  min-width: 120rpx;
312
+  text-align: center;
313
+}
314
+
315
+.amount-highlight-detail {
316
+  background: #fef3c7;
317
+  color: #d97706;
318
+  font-size: 28rpx;
319
+  font-weight: bold;
320
+  border-radius: 10rpx;
321
+  padding: 4rpx 18rpx;
322
+  margin-left: 8rpx;
323
+}
324
+
325
+.manager-amount-highlight-detail {
326
+  background: #d4f3e9;
327
+  color: #10b981;
328
+  font-size: 28rpx;
329
+  font-weight: bold;
330
+  border-radius: 10rpx;
331
+  padding: 4rpx 18rpx;
332
+  margin-left: 8rpx;
333
+}
334
+
335
+.modern-card-body {
336
+  padding: 20rpx 28rpx 24rpx 28rpx;
337
+}
338
+
339
+.avatar-section {
340
+  display: flex;
341
+  align-items: center;
342
+  margin-bottom: 18rpx;
343
+}
344
+
345
+.avatar {
346
+  width: 56rpx;
347
+  height: 56rpx;
348
+  border-radius: 50%;
349
+  background: #a5b4fc;
350
+  color: #fff;
351
+  display: flex;
352
+  align-items: center;
353
+  justify-content: center;
354
+  font-size: 28rpx;
355
+  font-weight: bold;
356
+  margin-right: 18rpx;
357
+}
358
+
359
+.applier-name {
360
+  font-size: 28rpx;
361
+  color: #22223b;
362
+  font-weight: 500;
363
+}
364
+
365
+.dept-name {
366
+  font-size: 24rpx;
367
+  color: #64748b;
368
+  margin-left: 8rpx;
369
+}
370
+
371
+.info-row {
372
+  display: flex;
373
+  margin-bottom: 10rpx;
374
+}
375
+
376
+.info-label {
377
+  color: #64748b;
378
+  font-size: 24rpx;
379
+  min-width: 120rpx;
380
+}
381
+
382
+.info-value {
383
+  color: #22223b;
384
+  font-size: 24rpx;
385
+  flex: 1;
386
+  word-break: break-all;
387
+}
388
+
389
+.modern-card-footer {
390
+  display: flex;
391
+  justify-content: flex-end;
392
+  gap: 20rpx;
393
+  padding: 16rpx 28rpx 20rpx 28rpx;
394
+  border-top: 1px solid #f0f0f0;
395
+  background: #fafbfc;
396
+}
397
+
398
+.footer-btn {
399
+  font-size: 26rpx;
400
+  border-radius: 8rpx;
401
+  border: none;
402
+  outline: none;
403
+  background: #e0e7ff;
404
+  color: #3b3b4f;
405
+}
406
+
407
+.detail-btn {
408
+  background: #6366f1;
409
+  color: #fff;
410
+}
411
+
412
+.form-btn {
413
+  background: #f4c542;
414
+  color: #fff;
415
+}
416
+
417
+.popup-detail-list {
418
+  padding: 32rpx 24rpx 48rpx 24rpx;
419
+  background: #fff;
420
+  border-radius: 24rpx 24rpx 0 0;
421
+  min-height: 300rpx;
422
+  max-height: 70vh;
423
+  overflow-y: auto;
424
+  position: relative;
425
+}
426
+
427
+.popup-detail-title {
428
+  font-size: 32rpx;
429
+  font-weight: bold;
430
+  color: #22223b;
431
+  margin-bottom: 24rpx;
432
+  text-align: center;
433
+}
434
+
435
+.popup-detail-item {
436
+  display: flex;
437
+  align-items: flex-start;
438
+  background: #f7f8fa;
439
+  border-radius: 12rpx;
440
+  margin-bottom: 18rpx;
441
+  padding: 18rpx 16rpx;
442
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
443
+}
444
+
445
+.popup-detail-index {
446
+  width: 44rpx;
447
+  height: 44rpx;
448
+  background: #6366f1;
449
+  color: #fff;
450
+  border-radius: 50%;
451
+  display: flex;
452
+  align-items: center;
453
+  justify-content: center;
454
+  font-size: 24rpx;
455
+  font-weight: bold;
456
+  margin-right: 18rpx;
457
+}
458
+
459
+.popup-detail-main {
460
+  flex: 1;
461
+}
462
+
463
+.popup-detail-row {
464
+  display: flex;
465
+  align-items: center;
466
+  margin-bottom: 8rpx;
467
+}
468
+
469
+.popup-detail-label {
470
+  color: #64748b;
471
+  font-size: 24rpx;
472
+  min-width: 120rpx;
473
+}
474
+
475
+.popup-detail-value {
476
+  color: #22223b;
477
+  font-size: 24rpx;
478
+}
479
+
480
+.popup-detail-amount {
481
+  color: #d97706;
482
+  font-size: 28rpx;
483
+  font-weight: bold;
484
+  margin-left: 8rpx;
485
+}
486
+
487
+.popup-detail-manager-amount {
488
+  color: #10b981;
489
+  font-size: 28rpx;
490
+  font-weight: bold;
491
+  margin-left: 8rpx;
492
+}
493
+
494
+.popup-close-btn {
495
+  position: absolute;
496
+  right: 24rpx;
497
+  top: 18rpx;
498
+  font-size: 40rpx;
499
+  color: #999;
500
+  z-index: 10;
501
+  cursor: pointer;
502
+  line-height: 1;
503
+}
159 504
 </style>

+ 483
- 0
oa-ui-app/pages/oa/car/carList.vue 查看文件

@@ -0,0 +1,483 @@
1
+<template>
2
+  <view class="container">
3
+    <uv-tabs :list="tabList" @click="clickTab"></uv-tabs>
4
+    <view style="padding-top: 20rpx;">
5
+      <uv-input placeholder="请输入车牌号" shape="circle" prefixIcon="search" prefixIconStyle="font-size: 22px;color: #909399"
6
+        @confirm="handleSearchCar"></uv-input>
7
+    </view>
8
+    <mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption"
9
+      :up="upOption" :fixed="false" :top="10" style="padding: 30rpx;">
10
+      <view>
11
+        <view v-for="item, index in carList" :key="'car' + index" class="modern-card">
12
+          <view class="modern-card-header">
13
+            <view class="modern-card-title">
14
+              <text class="car-plate">{{ item.licensePlate }}</text>
15
+            </view>
16
+            <view class="car-status" :class="'status-' + item.status">{{ getStatusText(item.status) }}</view>
17
+          </view>
18
+          <view class="modern-card-body">
19
+            <view class="avatar-section">
20
+              <view class="avatar">
21
+                <text>{{ item.driverUser ? item.driverUser.nickName[0] : '无' }}</text>
22
+              </view>
23
+              <view>
24
+                <text class="applier-name">{{ item.driverUser ? item.driverUser.nickName : '无' }}</text>
25
+                <text class="dept-name">驾驶员</text>
26
+              </view>
27
+            </view>
28
+            <view class="info-row">
29
+              <text class="info-label">品牌:</text>
30
+              <text class="info-value">{{ item.brand }}</text>
31
+            </view>
32
+            <view class="info-row">
33
+              <text class="info-label">购置时间:</text>
34
+              <text class="info-value">{{ item.acquisitionTime }}</text>
35
+            </view>
36
+            <view class="info-row">
37
+              <text class="info-label">是否为租车:</text>
38
+              <text class="info-value">{{ item.isRent == "0" ? '否' : '是' }}</text>
39
+            </view>
40
+            <view class="info-row">
41
+              <text class="info-label">油耗(km):</text>
42
+              <text>{{ item.fuel }}元</text>
43
+            </view>
44
+            <view class="info-row">
45
+              <text class="info-label">保险(天):</text>
46
+              <text>{{ item.insurance }}元</text>
47
+            </view>
48
+            <view class="info-row">
49
+              <text class="info-label">维修(天):</text>
50
+              <text>{{ item.maintenance }}元</text>
51
+            </view>
52
+            <view class="info-row">
53
+              <text class="info-label">单日成本:</text>
54
+              <text class="manager-amount-highlight-detail">¥{{ item.dayCost }}</text>
55
+            </view>
56
+          </view>
57
+          <view class="modern-card-footer">
58
+            <button class="footer-btn detail-btn" @click="showExpenseList(item)">维保记录</button>
59
+            <button class="footer-btn detail-btn2" @click="showUseCarList(item)">派出记录</button>
60
+          </view>
61
+        </view>
62
+      </view>
63
+    </mescroll-uni>
64
+    <uv-popup ref="expensePopup" mode="bottom">
65
+      <view class="popup-detail-list" @touchmove.stop>
66
+        <view class="popup-close-btn" @click="$refs.expensePopup.close()">×</view>
67
+        <view class="popup-detail-title">维保记录</view>
68
+        <view v-for="item, index in expenseList" :key="'c' + index" class="popup-detail-item"
69
+          v-if="expenseList.length > 0">
70
+          <view class="popup-detail-main">
71
+            <view class="popup-detail-row">
72
+              <text class="popup-detail-label">负责人:</text>
73
+              <text class="popup-detail-value">{{ item.user ? item.user.nickName : '' }}</text>
74
+            </view>
75
+            <view class="popup-detail-row">
76
+              <text class="popup-detail-label">费用类型:</text>
77
+              <text class="popup-detail-value">{{ item.expenseType }}</text>
78
+            </view>
79
+            <view class="popup-detail-row">
80
+              <text class="popup-detail-label">费用金额:</text>
81
+              <text class="popup-detail-value">{{ item.expense }}</text>
82
+            </view>
83
+            <view class="popup-detail-row">
84
+              <text class="popup-detail-label">发生日期:</text>
85
+              <text class="popup-detail-value">{{ item.occurDate }}</text>
86
+            </view>
87
+            <view class="popup-detail-row">
88
+              <text class="popup-detail-label">备注:</text>
89
+              <text class="popup-detail-value">{{ item.remark }}</text>
90
+            </view>
91
+          </view>
92
+        </view>
93
+        <view v-else>
94
+          <view class="popup-detail-empty">暂无维保记录</view>
95
+        </view>
96
+      </view>
97
+    </uv-popup>
98
+  </view>
99
+</template>
100
+
101
+<script>
102
+import { listCar, getCar, delCar, addCar, updateCar } from "@/api/oa/car/car";
103
+import { listDeviceExpense, getDeviceExpense, delDeviceExpense, addDeviceExpense, updateDeviceExpense } from "@/api/oa/device/deviceExpense";
104
+import MescrollMixin from '@/uni_modules/mescroll/components/mescroll-uni/mescroll-mixins.js';
105
+export default {
106
+  mixins: [MescrollMixin],
107
+  data() {
108
+    return {
109
+      tabList: [{
110
+        name: '可使用',
111
+        value: '1'
112
+      }, {
113
+        name: '已派出',
114
+        value: '0'
115
+      }, {
116
+        name: '已还车',
117
+        value: '3'
118
+      }, {
119
+        name: '已报废',
120
+        value: '4'
121
+      }],
122
+      selectedTab: '可使用',
123
+      carList: [],
124
+      expenseList: [],
125
+      queryParams: {
126
+        pageNum: 1,
127
+        pageSize: 50,
128
+        licensePlate: null,
129
+        driver: null,
130
+        status: '1'
131
+      },
132
+      mescroll: null,
133
+      downOption: {
134
+        auto: true,
135
+        textOutOffset: '下拉刷新',
136
+        textLoading: '加载中...'
137
+      },
138
+      upOption: {
139
+        auto: false,
140
+        page: { num: 1, size: 50 },
141
+        noMoreSize: 5,
142
+        empty: { tip: '暂无借款数据' },
143
+        textNoMore: '~ 没有更多数据了 ~'
144
+      },
145
+    }
146
+  },
147
+  onLoad: function (options) {
148
+    uni.startPullDownRefresh();
149
+  },
150
+  methods: {
151
+    handleSearchCar(e) {
152
+      this.queryParams.licensePlate = e;
153
+      uni.startPullDownRefresh();
154
+    },
155
+    clickTab(obj) {
156
+      let index = obj.index;
157
+      this.selectedTab = this.tabList[index].name;
158
+      this.queryParams.status = this.tabList[index].value;
159
+      uni.startPullDownRefresh();
160
+    },
161
+    // 加载数据
162
+    async loadData() {
163
+      try {
164
+        let res = null;
165
+        res = await listCar(this.queryParams)
166
+        return { data: res.rows, total: res.total }
167
+      } catch (error) {
168
+        console.error(error);
169
+        return { data: [] };
170
+      }
171
+    },
172
+    mescrollInit(mescroll) {
173
+      this.mescroll = mescroll;
174
+    },
175
+    async downCallback() {
176
+      this.carList = []; // 清空列表
177
+      this.queryParams.pageNum = 1
178
+      const res = await this.loadData()
179
+      if (res.error) {
180
+        this.mescroll.endErr();
181
+      } else {
182
+        this.carList = res.data;
183
+        this.mescroll.endSuccess(res.data.length, res.total);
184
+      }
185
+      uni.stopPullDownRefresh();
186
+    },
187
+    async upCallback(page) {
188
+      this.queryParams.pageNum = page.num
189
+      const res = await this.loadData()
190
+      if (res.error) {
191
+        this.mescroll.endErr();
192
+      } else {
193
+        this.carList = this.carList.concat(res.data);
194
+        this.mescroll.endSuccess(res.data.length, res.total);
195
+      }
196
+    },
197
+    getStatusText(status) {
198
+      switch (status) {
199
+        case '0': return '已派出';
200
+        case '1': return '可使用';
201
+        case '4': return '已报废';
202
+        case '3': return '已还车';
203
+        default: return '未知';
204
+      }
205
+    },
206
+    showExpenseList(item) {
207
+      listDeviceExpense({ carId: item.carId, pageNum: 1, pageSize: 100 }).then(res => {
208
+        this.expenseList = res.rows;
209
+        this.$refs.expensePopup.open();
210
+      })
211
+    },
212
+    showUseCarList(item) {
213
+      uni.navigateTo({
214
+        url: `/pages/oa/car/useCarList?carId=${item.carId}&licensePlate=${item.licensePlate}`
215
+      })
216
+    }
217
+  }
218
+}
219
+</script>
220
+
221
+<style lang="scss" scoped>
222
+.container {
223
+  padding: 20rpx;
224
+  background-color: #f5f5f5;
225
+  height: 100vh;
226
+  display: flex;
227
+  flex-direction: column;
228
+}
229
+
230
+.modern-card {
231
+  background: #fff;
232
+  border-radius: 18rpx;
233
+  margin-bottom: 32rpx;
234
+  box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
235
+  overflow: hidden;
236
+  transition: box-shadow 0.2s;
237
+  border: 1rpx solid #f0f0f0;
238
+}
239
+
240
+.modern-card-header {
241
+  display: flex;
242
+  justify-content: space-between;
243
+  align-items: center;
244
+  background: linear-gradient(90deg, #e0e7ff 0%, #f8fafc 100%);
245
+  padding: 24rpx 28rpx 16rpx 28rpx;
246
+}
247
+
248
+.modern-card-title {
249
+  display: flex;
250
+  flex-direction: column;
251
+}
252
+
253
+.car-plate {
254
+  font-size: 32rpx;
255
+  color: #22223b;
256
+  font-weight: bold;
257
+  margin-bottom: 8rpx;
258
+}
259
+
260
+.car-status {
261
+  font-size: 24rpx;
262
+  font-weight: 500;
263
+  padding: 4rpx 16rpx;
264
+  border-radius: 8rpx;
265
+  display: inline-block;
266
+  width: fit-content;
267
+}
268
+
269
+.status-0 {
270
+  background: #fef3c7;
271
+  color: #d97706;
272
+}
273
+
274
+/* 已派出 */
275
+.status-1 {
276
+  background: #d4f3e9;
277
+  color: #10b981;
278
+}
279
+
280
+/* 可使用 */
281
+.status-4 {
282
+  background: #fee2e2;
283
+  color: #ef4444;
284
+}
285
+
286
+/* 已报废 */
287
+.status-3 {
288
+  background: #dbeafe;
289
+  color: #3b82f6;
290
+}
291
+
292
+/* 已还车 */
293
+
294
+.modern-card-body {
295
+  padding: 20rpx 28rpx 24rpx 28rpx;
296
+}
297
+
298
+.avatar-section {
299
+  display: flex;
300
+  align-items: center;
301
+  margin-bottom: 18rpx;
302
+}
303
+
304
+.avatar {
305
+  width: 56rpx;
306
+  height: 56rpx;
307
+  border-radius: 50%;
308
+  background: #a5b4fc;
309
+  color: #fff;
310
+  display: flex;
311
+  align-items: center;
312
+  justify-content: center;
313
+  font-size: 28rpx;
314
+  font-weight: bold;
315
+  margin-right: 18rpx;
316
+}
317
+
318
+.applier-name {
319
+  font-size: 28rpx;
320
+  color: #22223b;
321
+  font-weight: 500;
322
+}
323
+
324
+.dept-name {
325
+  font-size: 24rpx;
326
+  color: #64748b;
327
+  margin-left: 8rpx;
328
+}
329
+
330
+.info-row {
331
+  display: flex;
332
+  margin-bottom: 10rpx;
333
+}
334
+
335
+.info-label {
336
+  color: #64748b;
337
+  font-size: 24rpx;
338
+  min-width: 120rpx;
339
+}
340
+
341
+.info-value {
342
+  color: #22223b;
343
+  font-size: 24rpx;
344
+  flex: 1;
345
+  word-break: break-all;
346
+}
347
+
348
+.amount-highlight-detail {
349
+  background: #fef3c7;
350
+  color: #d97706;
351
+  font-size: 28rpx;
352
+  font-weight: bold;
353
+  border-radius: 10rpx;
354
+  padding: 4rpx 18rpx;
355
+  margin-left: 8rpx;
356
+}
357
+
358
+.manager-amount-highlight-detail {
359
+  background: #d4f3e9;
360
+  color: #10b981;
361
+  font-size: 28rpx;
362
+  font-weight: bold;
363
+  border-radius: 10rpx;
364
+  padding: 4rpx 18rpx;
365
+  margin-left: 8rpx;
366
+}
367
+
368
+.modern-card-footer {
369
+  display: flex;
370
+  justify-content: flex-end;
371
+  gap: 20rpx;
372
+  padding: 16rpx 28rpx 20rpx 28rpx;
373
+  border-top: 1px solid #f0f0f0;
374
+  background: #fafbfc;
375
+}
376
+
377
+.footer-btn {
378
+  font-size: 26rpx;
379
+  border-radius: 8rpx;
380
+  border: none;
381
+  outline: none;
382
+  background: #e0e7ff;
383
+  color: #3b3b4f;
384
+}
385
+
386
+.detail-btn {
387
+  background: #6366f1;
388
+  color: #fff;
389
+}
390
+
391
+.detail-btn2 {
392
+  background: #f4c542;
393
+  color: #fff;
394
+}
395
+
396
+.popup-detail-list {
397
+  padding: 32rpx 24rpx 48rpx 24rpx;
398
+  background: #fff;
399
+  border-radius: 24rpx 24rpx 0 0;
400
+  min-height: 300rpx;
401
+  max-height: 70vh;
402
+  overflow-y: auto;
403
+  position: relative;
404
+}
405
+
406
+.popup-detail-title {
407
+  font-size: 32rpx;
408
+  font-weight: bold;
409
+  color: #22223b;
410
+  margin-bottom: 24rpx;
411
+  text-align: center;
412
+}
413
+
414
+.popup-detail-item {
415
+  display: flex;
416
+  align-items: flex-start;
417
+  background: #f7f8fa;
418
+  border-radius: 12rpx;
419
+  margin-bottom: 18rpx;
420
+  padding: 18rpx 16rpx;
421
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
422
+}
423
+
424
+.popup-detail-index {
425
+  width: 44rpx;
426
+  height: 44rpx;
427
+  background: #6366f1;
428
+  color: #fff;
429
+  border-radius: 50%;
430
+  display: flex;
431
+  align-items: center;
432
+  justify-content: center;
433
+  font-size: 24rpx;
434
+  font-weight: bold;
435
+  margin-right: 18rpx;
436
+}
437
+
438
+.popup-detail-main {
439
+  flex: 1;
440
+}
441
+
442
+.popup-detail-row {
443
+  display: flex;
444
+  align-items: center;
445
+  margin-bottom: 8rpx;
446
+}
447
+
448
+.popup-detail-label {
449
+  color: #64748b;
450
+  font-size: 24rpx;
451
+  min-width: 120rpx;
452
+}
453
+
454
+.popup-detail-value {
455
+  color: #22223b;
456
+  font-size: 24rpx;
457
+}
458
+
459
+.popup-detail-amount {
460
+  color: #d97706;
461
+  font-size: 28rpx;
462
+  font-weight: bold;
463
+  margin-left: 8rpx;
464
+}
465
+
466
+.popup-detail-manager-amount {
467
+  color: #10b981;
468
+  font-size: 28rpx;
469
+  font-weight: bold;
470
+  margin-left: 8rpx;
471
+}
472
+
473
+.popup-close-btn {
474
+  position: absolute;
475
+  right: 24rpx;
476
+  top: 18rpx;
477
+  font-size: 40rpx;
478
+  color: #999;
479
+  z-index: 10;
480
+  cursor: pointer;
481
+  line-height: 1;
482
+}
483
+</style>

+ 313
- 0
oa-ui-app/pages/oa/car/useCarList.vue 查看文件

@@ -0,0 +1,313 @@
1
+<!--
2
+ * @Author: ysh
3
+ * @Date: 2025-06-18 15:39:56
4
+ * @LastEditors: Please set LastEditors
5
+ * @LastEditTime: 2025-06-19 11:26:48
6
+-->
7
+<template>
8
+  <view class="container">
9
+    <mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption"
10
+      :up="upOption" :fixed="false" :top="10" style="padding: 30rpx;">
11
+      <view v-for="item, index in useCarList" :key="'car' + index" class="modern-card">
12
+        <view class="modern-card-header">
13
+          <view class="modern-card-title">
14
+            <view class="car-status" :class="'status-' + item.carUsage">{{ getStatusText(item.carUsage) }}</view>
15
+          </view>
16
+        </view>
17
+        <view class="modern-card-body">
18
+          <view class="avatar-section">
19
+            <view class="avatar">
20
+              <text>{{ item.applierUser ? item.applierUser.nickName[0] : '无' }}</text>
21
+            </view>
22
+            <view>
23
+              <text class="applier-name">{{ item.applierUser ? item.applierUser.nickName : '无' }}</text>
24
+              <text class="dept-name">{{ item.dept ? item.dept.deptName : '无' }}</text>
25
+            </view>
26
+          </view>
27
+          <view class="info-row">
28
+            <text class="info-label">用车时间:</text>
29
+            <text class="info-value">{{ item.beginDate + ' 至 ' + item.endDate }}</text>
30
+          </view>
31
+          <view class="info-row">
32
+            <text class="info-label">用车事由:</text>
33
+            <text class="info-value">{{ item.applyReason }}</text>
34
+          </view>
35
+          <view class="info-row" v-if="item.carUsage == '0'">
36
+            <text class="info-label">项目编号:</text>
37
+            <text class="info-value">{{ item.project ? item.project.projectNumber : '无' }}</text>
38
+          </view>
39
+          <view class="info-row" v-if="item.carUsage == '0'">
40
+            <text class="info-label">项目名称:</text>
41
+            <text class="info-value">{{ item.project ? item.project.projectName : '无' }}</text>
42
+          </view>
43
+        </view>
44
+      </view>
45
+    </mescroll-uni>
46
+  </view>
47
+</template>
48
+
49
+<script>
50
+import { listCarApproval } from "@/api/oa/car/carApproval";
51
+export default {
52
+  data() {
53
+    return {
54
+      carId: '',
55
+      licensePlate: '',
56
+      useCarList: [],
57
+      mescroll: null,
58
+      queryParams: {
59
+        pageNum: 1,
60
+        pageSize: 20
61
+      },
62
+      downOption: {
63
+        auto: true,
64
+        textOutOffset: '下拉刷新',
65
+        textLoading: '加载中...'
66
+      },
67
+      upOption: {
68
+        auto: false,
69
+        page: { num: 1, size: 20 },
70
+        noMoreSize: 5,
71
+        empty: { tip: '暂无借款数据' },
72
+        textNoMore: '~ 没有更多数据了 ~'
73
+      },
74
+    }
75
+  },
76
+  onLoad(options) {
77
+    this.carId = options.carId;
78
+    this.licensePlate = options.licensePlate;
79
+    uni.setNavigationBarTitle({
80
+      title: this.licensePlate + '派车记录'
81
+    })
82
+    uni.startPullDownRefresh();
83
+  },
84
+  methods: {
85
+    // 加载数据
86
+    async loadData() {
87
+      try {
88
+        let res = null;
89
+        res = await listCarApproval({ carId: this.carId, cars: this.carId, ...this.queryParams })
90
+        return { data: res.rows, total: res.total }
91
+      } catch (error) {
92
+        console.error(error);
93
+        return { data: [] };
94
+      }
95
+    },
96
+    mescrollInit(mescroll) {
97
+      this.mescroll = mescroll;
98
+    },
99
+    async downCallback() {
100
+      this.useCarList = []; // 清空列表
101
+      this.queryParams.pageNum = 1
102
+      const res = await this.loadData()
103
+      if (res.error) {
104
+        this.mescroll.endErr();
105
+      } else {
106
+        this.useCarList = res.data;
107
+        this.mescroll.endSuccess(res.data.length, res.total);
108
+      }
109
+      uni.stopPullDownRefresh();
110
+    },
111
+    async upCallback(page) {
112
+      this.queryParams.pageNum = page.num
113
+      const res = await this.loadData()
114
+      if (res.error) {
115
+        this.mescroll.endErr();
116
+      } else {
117
+        this.useCarList = this.useCarList.concat(res.data);
118
+        this.mescroll.endSuccess(res.data.length, res.total);
119
+      }
120
+    },
121
+    getStatusText(status) {
122
+      switch (status) {
123
+        case '0':
124
+          return '项目用车';
125
+        case '1':
126
+          return '非项目用车';
127
+        case '2':
128
+          return '工会用车';
129
+        case '3':
130
+          return '党委用车';
131
+        case '4':
132
+          return '团委用车';
133
+      }
134
+    }
135
+  }
136
+}
137
+</script>
138
+
139
+<style lang="scss" scoped>
140
+.container {
141
+  padding: 20rpx;
142
+  background-color: #f5f5f5;
143
+  height: 100vh;
144
+  display: flex;
145
+  flex-direction: column;
146
+}
147
+
148
+.modern-card {
149
+  background: #fff;
150
+  border-radius: 18rpx;
151
+  margin-bottom: 32rpx;
152
+  box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
153
+  overflow: hidden;
154
+  transition: box-shadow 0.2s;
155
+  border: 1rpx solid #f0f0f0;
156
+}
157
+
158
+.modern-card-header {
159
+  display: flex;
160
+  justify-content: space-between;
161
+  align-items: center;
162
+  background: linear-gradient(90deg, #e0e7ff 0%, #f8fafc 100%);
163
+  padding: 24rpx 28rpx 16rpx 28rpx;
164
+}
165
+
166
+.modern-card-title {
167
+  display: flex;
168
+  flex-direction: column;
169
+}
170
+
171
+.car-plate {
172
+  font-size: 32rpx;
173
+  color: #22223b;
174
+  font-weight: bold;
175
+  margin-bottom: 8rpx;
176
+}
177
+
178
+.car-status {
179
+  font-size: 24rpx;
180
+  font-weight: 500;
181
+  padding: 4rpx 16rpx;
182
+  border-radius: 8rpx;
183
+  display: inline-block;
184
+  width: fit-content;
185
+}
186
+
187
+.status-0 {
188
+  background: #fef3c7;
189
+  color: #d97706;
190
+}
191
+
192
+/* 已派出 */
193
+.status-1 {
194
+  background: #d4f3e9;
195
+  color: #10b981;
196
+}
197
+
198
+/* 可使用 */
199
+.status-4 {
200
+  background: #fee2e2;
201
+  color: #ef4444;
202
+}
203
+
204
+/* 已报废 */
205
+.status-3 {
206
+  background: #dbeafe;
207
+  color: #3b82f6;
208
+}
209
+
210
+/* 已还车 */
211
+
212
+.modern-card-body {
213
+  padding: 20rpx 28rpx 24rpx 28rpx;
214
+}
215
+
216
+.avatar-section {
217
+  display: flex;
218
+  align-items: center;
219
+  margin-bottom: 18rpx;
220
+}
221
+
222
+.avatar {
223
+  width: 56rpx;
224
+  height: 56rpx;
225
+  border-radius: 50%;
226
+  background: #a5b4fc;
227
+  color: #fff;
228
+  display: flex;
229
+  align-items: center;
230
+  justify-content: center;
231
+  font-size: 28rpx;
232
+  font-weight: bold;
233
+  margin-right: 18rpx;
234
+}
235
+
236
+.applier-name {
237
+  font-size: 28rpx;
238
+  color: #22223b;
239
+  font-weight: 500;
240
+}
241
+
242
+.dept-name {
243
+  font-size: 24rpx;
244
+  color: #64748b;
245
+  margin-left: 8rpx;
246
+}
247
+
248
+.info-row {
249
+  display: flex;
250
+  margin-bottom: 10rpx;
251
+}
252
+
253
+.info-label {
254
+  color: #64748b;
255
+  font-size: 24rpx;
256
+  min-width: 120rpx;
257
+}
258
+
259
+.info-value {
260
+  color: #22223b;
261
+  font-size: 24rpx;
262
+  flex: 1;
263
+  word-break: break-all;
264
+}
265
+
266
+.amount-highlight-detail {
267
+  background: #fef3c7;
268
+  color: #d97706;
269
+  font-size: 28rpx;
270
+  font-weight: bold;
271
+  border-radius: 10rpx;
272
+  padding: 4rpx 18rpx;
273
+  margin-left: 8rpx;
274
+}
275
+
276
+.manager-amount-highlight-detail {
277
+  background: #d4f3e9;
278
+  color: #10b981;
279
+  font-size: 28rpx;
280
+  font-weight: bold;
281
+  border-radius: 10rpx;
282
+  padding: 4rpx 18rpx;
283
+  margin-left: 8rpx;
284
+}
285
+
286
+.modern-card-footer {
287
+  display: flex;
288
+  justify-content: flex-end;
289
+  gap: 20rpx;
290
+  padding: 16rpx 28rpx 20rpx 28rpx;
291
+  border-top: 1px solid #f0f0f0;
292
+  background: #fafbfc;
293
+}
294
+
295
+.footer-btn {
296
+  font-size: 26rpx;
297
+  border-radius: 8rpx;
298
+  border: none;
299
+  outline: none;
300
+  background: #e0e7ff;
301
+  color: #3b3b4f;
302
+}
303
+
304
+.detail-btn {
305
+  background: #6366f1;
306
+  color: #fff;
307
+}
308
+
309
+.detail-btn2 {
310
+  background: #f4c542;
311
+  color: #fff;
312
+}
313
+</style>

+ 53
- 80
oa-ui-app/pages/work/index.vue 查看文件

@@ -2,7 +2,13 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-01-16 11:17:08
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-06-10 11:02:19
5
+ * @LastEditTime: 2025-06-17 15:18:44
6
+-->
7
+<!--
8
+ * @Author: ysh
9
+ * @Date: 2025-01-16 11:17:08
10
+ * @LastEditors: Please set LastEditors
11
+ * @LastEditTime: 2025-06-17 14:54:35
6 12
 -->
7 13
 <template>
8 14
   <view class="work-container">
@@ -21,81 +27,13 @@
21 27
     <uni-section title="常用操作" type="line"></uni-section>
22 28
     <view class="grid-body">
23 29
       <uni-grid :column="4" :showBorder="false">
24
-        <uni-grid-item>
25
-          <view class="grid-item-box" @click="openSendFlow">
26
-            <u-image :fade="false" src="@/static/images/work/sendFlow.png" width="40px" height="40px"></u-image>
27
-            <text class="text">发起流程</text>
28
-          </view>
29
-        </uni-grid-item>
30
-        <!-- <uni-grid-item>
31
-          <view class="grid-item-box" @click="toUrlFn('borrow)">
32
-            <u-image :fade="false" src="@/static/images/work/borrow.png" width="40px" height="40px"></u-image>
33
-            <text class="text">借款管理</text>
34
-          </view>
35
-        </uni-grid-item> -->
36
-        <uni-grid-item>
37
-          <view class="grid-item-box" @click="toUrlFn('deviceLog')">
38
-            <u-image :fade="false" src="@/static/images/work/workDay.png" width="40px" height="40px"></u-image>
39
-            <text class="text">设备作业记录</text>
30
+        <uni-grid-item v-for="item in gridList" :key="item.url" v-if="item.hasPermi">
31
+          <view class="grid-item-box" @click="toUrlFn(item.url)">
32
+            <u-image :fade="false" :src="item.icon" width="40px" height="40px"></u-image>
33
+            <text class="text">{{ item.name }}</text>
40 34
           </view>
41 35
         </uni-grid-item>
42 36
       </uni-grid>
43
-      <!-- <uni-grid :column="4" :showBorder="false" @change="changeGrid">
44
-        <uni-grid-item>
45
-          <view class="grid-item-box">
46
-            <uni-icons type="person-filled" size="30"></uni-icons>
47
-            <text class="text">用户管理</text>
48
-          </view>
49
-        </uni-grid-item>
50
-        <uni-grid-item>
51
-          <view class="grid-item-box">
52
-            <uni-icons type="staff-filled" size="30"></uni-icons>
53
-            <text class="text">角色管理</text>
54
-          </view>
55
-        </uni-grid-item>
56
-        <uni-grid-item>
57
-          <view class="grid-item-box">
58
-            <uni-icons type="color" size="30"></uni-icons>
59
-            <text class="text">菜单管理</text>
60
-          </view>
61
-        </uni-grid-item>
62
-        <uni-grid-item>
63
-          <view class="grid-item-box">
64
-            <uni-icons type="settings-filled" size="30"></uni-icons>
65
-            <text class="text">部门管理</text>
66
-          </view>
67
-        </uni-grid-item>
68
-        <uni-grid-item>
69
-          <view class="grid-item-box">
70
-            <uni-icons type="heart-filled" size="30"></uni-icons>
71
-            <text class="text">岗位管理</text>
72
-          </view>
73
-        </uni-grid-item>
74
-        <uni-grid-item>
75
-          <view class="grid-item-box">
76
-            <uni-icons type="bars" size="30"></uni-icons>
77
-            <text class="text">字典管理</text>
78
-          </view>
79
-        </uni-grid-item>
80
-        <uni-grid-item>
81
-          <view class="grid-item-box">
82
-            <uni-icons type="gear-filled" size="30"></uni-icons>
83
-            <text class="text">参数设置</text>
84
-          </view>
85
-        </uni-grid-item>
86
-        <uni-grid-item>
87
-          <view class="grid-item-box">
88
-            <uni-icons type="chat-filled" size="30"></uni-icons>
89
-            <text class="text">通知公告</text>
90
-          </view>
91
-        </uni-grid-item>
92
-        <uni-grid-item>
93
-          <view class="grid-item-box">
94
-            <uni-icons type="wallet-filled" size="30"></uni-icons>
95
-            <text class="text">日志管理</text>
96
-          </view>
97
-        </uni-grid-item>
98
-      </uni-grid> -->
99 37
     </view>
100 38
 
101 39
     <uv-popup ref="popup" mode="bottom">
@@ -113,6 +51,7 @@ import { listDefinition } from "@/api/flowable/definition";
113 51
 import { Snowflake } from '@/utils/snowFlake.js';
114 52
 import { getNextFlowNodeByStart, todoList } from "@/api/flowable/todo";
115 53
 import { definitionStart, flowXmlAndNode } from "@/api/flowable/definition";
54
+import { checkPermi, checkRole } from "@/utils/permission";
116 55
 export default {
117 56
   data() {
118 57
     return {
@@ -126,7 +65,38 @@ export default {
126 65
       },
127 66
       {
128 67
         image: '/static/images/banner/banner03.jpg'
129
-      }
68
+      }],
69
+      gridList: [
70
+        {
71
+          name: '发起流程',
72
+          icon: '/static/images/work/sendFlow.png',
73
+          url: 'sendFlow',
74
+          hasPermi: true
75
+        },
76
+        {
77
+          name: '借款管理',
78
+          icon: '/static/images/work/borrow.png',
79
+          url: 'borrow',
80
+          hasPermi: checkPermi(['oa:borrow:list'])
81
+        },
82
+        {
83
+          name: '用车管理',
84
+          icon: '/static/images/work/car.png',
85
+          url: 'car',
86
+          hasPermi: checkPermi(['oa:car:list'])
87
+        },
88
+        {
89
+          name: '设备管理',
90
+          icon: '/static/images/work/device.png',
91
+          url: 'device',
92
+          hasPermi: checkPermi(['oa:device:list'])
93
+        },
94
+        {
95
+          name: '设备作业记录',
96
+          icon: '/static/images/work/workDay.png',
97
+          url: 'deviceLog',
98
+          hasPermi: checkPermi(['oa:deviceLog:list'])
99
+        }
130 100
       ],
131 101
       flowList: ['借款审批', '用车审批', '设备审批', '工作填报'],
132 102
       sendFlowList: [],
@@ -153,18 +123,14 @@ export default {
153 123
     this.getDefinitionList();
154 124
   },
155 125
   methods: {
126
+    checkPermi,
127
+    checkRole,
156 128
     clickBannerItem(item) {
157 129
       console.info(item)
158 130
     },
159 131
     changeSwiper(e) {
160 132
       this.current = e.detail.current
161 133
     },
162
-    changeGrid(e) {
163
-      this.$modal.showToast('模块建设中~')
164
-    },
165
-    openSendFlow() {
166
-      this.$refs.popup.open();
167
-    },
168 134
     toUrlFn(type) {
169 135
       if (type == 'borrow') {
170 136
         uni.navigateTo({
@@ -174,6 +140,13 @@ export default {
174 140
         uni.navigateTo({
175 141
           url: '/pages/oa/device/deviceLog'
176 142
         })
143
+      } else if (type == 'car') {
144
+        uni.navigateTo({
145
+          url: '/pages/oa/car/carList'
146
+        })
147
+      }
148
+      else {
149
+        this.$modal.showToast('模块建设中~')
177 150
       }
178 151
     },
179 152
     sendFlow(row) {

二進制
oa-ui-app/static/images/work/car.png 查看文件


二進制
oa-ui-app/static/images/work/device.png 查看文件


二進制
oa-ui-app/static/images/work/staff.png 查看文件


+ 164
- 132
oa-ui/src/views/flowable/form/budget/adjust/budgetAdjust.vue 查看文件

@@ -2,10 +2,10 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-05-07 11:01:39
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-21 17:06:38
5
+ * @LastEditTime: 2025-06-19 16:25:11
6 6
 -->
7 7
 <template>
8
-  <div class="main" v-loading="loading">
8
+  <div class="main">
9 9
     <h2 class="text-center">项目直接生产成本预算—核算表</h2>
10 10
     <p style="text-align: center">
11 11
       编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}
@@ -17,7 +17,7 @@
17 17
       </el-alert>
18 18
     </div>
19 19
     <el-divider></el-divider>
20
-    <el-descriptions :column="3" border class="descriptions">
20
+    <el-descriptions :column="3" border class="descriptions" v-loading="loading" :element-loading-text="loadingText">
21 21
       <el-descriptions-item label="项目编号">
22 22
         {{ project.projectNumber }}
23 23
       </el-descriptions-item>
@@ -156,7 +156,8 @@
156 156
           @update:deviceList="handleDeviceChange"></device-cost>
157 157
       </el-descriptions-item>
158 158
       <el-descriptions-item label="现场开支" :span="3">
159
-        <site-cost :siteList.sync="siteList" :taskName="taskName" @update:siteList="handleSiteChange"></site-cost>
159
+        <site-cost :siteList.sync="siteList" :taskName="taskName" @update:siteList="handleSiteChange"
160
+          @updateList="updateSiteList"></site-cost>
160 161
       </el-descriptions-item>
161 162
       <el-descriptions-item label="合同总价" :span="3" v-hasRole="['leader', 'finance', 'nfinance', 'admin']">
162 163
         <table border="1" style="width:100%;" v-if="contractList.length > 0">
@@ -458,6 +459,8 @@ export default {
458 459
       },
459 460
       contractList: [],
460 461
       subContractList: [],
462
+      budgetId: '',
463
+      loadingText: '加载中...'
461 464
     }
462 465
   },
463 466
   async created() {
@@ -477,7 +480,28 @@ export default {
477 480
         this.budgetForm = res.rows[0];
478 481
         if (this.budgetForm) {
479 482
           const budgetId = this.budgetForm.budgetId;
480
-          // 经营相关
483
+          this.budgetId = budgetId;
484
+          
485
+          // 并发获取所有数据
486
+          const [
487
+            deviceRes,
488
+            carRes,
489
+            innerStaffRes,
490
+            outerStaffRes,
491
+            settleRes,
492
+            siteRes,
493
+            otherRes
494
+          ] = await Promise.all([
495
+            listBudgetDevice({ pageSize: 100, budgetId }),
496
+            listBudgetCar({ pageSize: 100, budgetId }),
497
+            listBudgetStaff({ pageSize: 100, budgetId, type: '内业' }),
498
+            listBudgetStaff({ pageSize: 100, budgetId, type: '外业' }),
499
+            listBudgetSettle({ pageSize: 100, budgetId }),
500
+            listSite({ pageSize: 100, budgetId }),
501
+            listOther({ pageSize: 100, budgetId })
502
+          ]);
503
+
504
+          // 经营相关数据处理
481 505
           this.budgetForm.outExpense = Number(this.budgetForm.outExpense).toFixed(2);
482 506
           this.budgetForm.letterExpense = Number(this.budgetForm.letterExpense).toFixed(2);
483 507
           this.budgetForm.winExpense = Number(this.budgetForm.winExpense).toFixed(2);
@@ -501,70 +525,52 @@ export default {
501 525
             Number(this.budgetForm.taxAdjust || 0) +
502 526
             Number(this.budgetForm.travelAdjust || 0);
503 527
 
504
-
505
-          // 获取设备数据
506
-          let deviceRes = await listBudgetDevice({ pageSize: 100, budgetId });
507
-          this.deviceList = deviceRes.rows;
508
-          this.deviceList = this.deviceList.map(device => {
509
-            return {
510
-              ...device,
511
-              depreciation: Number(device.depreciation).toFixed(2),
512
-              amount: Number(device.amount).toFixed(2),
513
-              amountAdjust: device.amountAdjust ? Number(device.amountAdjust).toFixed(2) : 0
514
-            };
515
-          });
528
+          // 处理设备数据
529
+          this.deviceList = deviceRes.rows.map(device => ({
530
+            ...device,
531
+            depreciation: Number(device.depreciation).toFixed(2),
532
+            amount: Number(device.amount).toFixed(2),
533
+            amountAdjust: device.amountAdjust ? Number(device.amountAdjust).toFixed(2) : 0
534
+          }));
516 535
           this.checkDeviceCost = this.deviceList.reduce((sum, device) => sum + Number(device.amountAdjust || 0), 0).toFixed(2);
517 536
 
518
-          // 获取车辆数据
519
-          let carRes = await listBudgetCar({ pageSize: 100, budgetId });
520
-          this.carList = carRes.rows;
521
-          this.carList = this.carList.map(car => {
522
-            return {
523
-              ...car,
524
-              depreciation: Number(car.depreciation).toFixed(2),
525
-              amount: Number(car.amount).toFixed(2),
526
-              amountAdjust: car.amountAdjust ? Number(car.amountAdjust).toFixed(2) : 0
527
-            };
528
-          });
537
+          // 处理车辆数据
538
+          this.carList = carRes.rows.map(car => ({
539
+            ...car,
540
+            depreciation: Number(car.depreciation).toFixed(2),
541
+            amount: Number(car.amount).toFixed(2),
542
+            amountAdjust: car.amountAdjust ? Number(car.amountAdjust).toFixed(2) : 0
543
+          }));
529 544
           this.checkCarCost = this.carList.reduce((sum, car) => sum + Number(car.amountAdjust || 0), 0).toFixed(2);
530 545
 
531
-          // 获取内业人员数据
532
-          let innerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '内业' });
533
-          this.innerStaffList = innerStaffRes.rows;
534
-          this.innerStaffList = this.innerStaffList.map(staff => {
535
-            return {
536
-              ...staff,
537
-              dayCost: Number(staff.dayCost).toFixed(2),
538
-              performance: Number(staff.performance).toFixed(2),
539
-              amount: Number(staff.amount).toFixed(2),
540
-              staffCost: Number(staff.staffCost).toFixed(2),
541
-              daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
542
-              performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
543
-              amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
544
-            };
545
-          });
546
+          // 处理内业人员数据
547
+          this.innerStaffList = innerStaffRes.rows.map(staff => ({
548
+            ...staff,
549
+            dayCost: Number(staff.dayCost).toFixed(2),
550
+            performance: Number(staff.performance).toFixed(2),
551
+            amount: Number(staff.amount).toFixed(2),
552
+            staffCost: Number(staff.staffCost).toFixed(2),
553
+            daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
554
+            performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
555
+            amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
556
+          }));
546 557
           let innerCheckCost = this.innerStaffList.reduce((sum, staff) => sum + Number(staff.amountAdjust || 0), 0);
547 558
 
548
-          // 获取外业人员数据
549
-          let outerStaffRes = await listBudgetStaff({ pageSize: 100, budgetId, type: '外业' });
550
-          this.outerStaffList = outerStaffRes.rows;
551
-          this.outerStaffList = this.outerStaffList.map(staff => {
552
-            return {
553
-              ...staff,
554
-              dayCost: Number(staff.dayCost).toFixed(2),
555
-              performance: Number(staff.performance).toFixed(2),
556
-              amount: Number(staff.amount).toFixed(2),
557
-              staffCost: Number(staff.staffCost).toFixed(2),
558
-              daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
559
-              performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
560
-              amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
561
-            };
562
-          });
559
+          // 处理外业人员数据
560
+          this.outerStaffList = outerStaffRes.rows.map(staff => ({
561
+            ...staff,
562
+            dayCost: Number(staff.dayCost).toFixed(2),
563
+            performance: Number(staff.performance).toFixed(2),
564
+            amount: Number(staff.amount).toFixed(2),
565
+            staffCost: Number(staff.staffCost).toFixed(2),
566
+            daysAdjust: staff.daysAdjust ? Number(staff.daysAdjust).toFixed(2) : 0,
567
+            performanceAdjust: staff.performanceAdjust ? Number(staff.performanceAdjust).toFixed(2) : 0,
568
+            amountAdjust: staff.amountAdjust ? Number(staff.amountAdjust).toFixed(2) : 0
569
+          }));
563 570
           let outerCheckCost = this.outerStaffList.reduce((sum, staff) => sum + Number(staff.amountAdjust || 0), 0);
564 571
           this.checkStaffCost = (innerCheckCost + outerCheckCost).toFixed(2);
565 572
 
566
-          // 获取内业绩效额数据
567
-          let settleRes = await listBudgetSettle({ pageSize: 100, budgetId });
573
+          // 处理内业绩效额数据
568 574
           this.workList = settleRes.rows;
569 575
           for (let work of this.workList) {
570 576
             if (work.checkPriceId) {
@@ -592,37 +598,21 @@ export default {
592 598
             }
593 599
           }
594 600
 
595
-          // 获取现场开支
596
-          let siteRes = await listSite({ pageSize: 100, budgetId });
597
-          this.siteList = siteRes.rows;
598
-          this.siteList = this.siteList.map(site => {
599
-            return {
600
-              ...site,
601
-              amount: Number(site.amount).toFixed(2),
602
-              amountAdjust: site.amountAdjust ? Number(site.amountAdjust).toFixed(2) : 0
603
-            };
604
-          });
601
+          // 处理现场开支
602
+          this.siteList = siteRes.rows.map(site => ({
603
+            ...site,
604
+            amount: Number(site.amount).toFixed(2),
605
+            amountAdjust: site.amountAdjust ? Number(site.amountAdjust).toFixed(2) : 0
606
+          }));
605 607
           this.budgetForm.siteSum = this.siteList.reduce((sum, site) => sum + Number(site.amount || 0), 0).toFixed(2);
606 608
           this.checkSiteCost = this.siteList.reduce((sum, site) => sum + Number(site.amountAdjust || 0), 0).toFixed(2);
607 609
 
608
-          this.siteList = this.siteList.map(site => {
609
-            return {
610
-              ...site,
611
-              amount: Number(site.amount).toFixed(2),
612
-              amountAdjust: site.amountAdjust ? Number(site.amountAdjust).toFixed(2) : 0
613
-            };
614
-          });
615
-
616
-          // 获取预算外开销
617
-          let otherRes = await listOther({ pageSize: 100, budgetId });
618
-          this.otherList = otherRes.rows;
619
-          this.otherList = this.otherList.map(other => {
620
-            return {
621
-              ...other,
622
-              amount: Number(other.amount).toFixed(2),
623
-              amountAdjust: other.amountAdjust ? Number(other.amountAdjust).toFixed(2) : 0
624
-            };
625
-          });
610
+          // 处理预算外开销
611
+          this.otherList = otherRes.rows.map(other => ({
612
+            ...other,
613
+            amount: Number(other.amount).toFixed(2),
614
+            amountAdjust: other.amountAdjust ? Number(other.amountAdjust).toFixed(2) : 0
615
+          }));
626 616
           this.checkOtherCost = this.otherList.reduce((sum, other) => sum + Number(other.amountAdjust || 0), 0).toFixed(2);
627 617
           this.totalBudgetAdjust = (Number(this.checkStaffCost) + Number(this.checkCarCost) + Number(this.checkDeviceCost)
628 618
             + Number(this.checkSiteCost) + Number(this.checkJYAmount) + Number(this.checkOtherCost)).toFixed(2);
@@ -764,6 +754,18 @@ export default {
764 754
       this.checkSiteCost = this.siteList.reduce((sum, site) => sum + (Number(site.amountAdjust) || 0), 0).toFixed(2);
765 755
       this.getTotalBudgetAdjust();
766 756
     },
757
+    async updateSiteList() {
758
+      // 获取现场开支
759
+      let siteRes = await listSite({ pageSize: 100, budgetId: this.budgetId });
760
+      this.siteList = siteRes.rows.map(site => ({
761
+        ...site,
762
+        amount: Number(site.amount).toFixed(2),
763
+        amountAdjust: site.amountAdjust ? Number(site.amountAdjust).toFixed(2) : 0
764
+      }));
765
+      
766
+      this.budgetForm.siteSum = this.siteList.reduce((sum, site) => sum + Number(site.amount || 0), 0).toFixed(2);
767
+      this.checkSiteCost = this.siteList.reduce((sum, site) => sum + Number(site.amountAdjust || 0), 0).toFixed(2);
768
+    },
767 769
     // 处理经营相关数据变化
768 770
     handleBusinessChange(newData) {
769 771
       this.budgetForm.outAdjust = newData.outAdjust;
@@ -794,56 +796,86 @@ export default {
794 796
     },
795 797
     // 保存
796 798
     async preserve() {
797
-      let obj = {
798
-        budgetId: this.row.budgetId,
799
-        projectId: this.row.projectId,
800
-        checkId: this.taskForm.formId
801
-      }
802
-      if (!this.checkForm.checkId) {
803
-        await addCheck(obj);
804
-        this.$emit('preserve');
805
-      } else {
806
-        await updateCheck(this.checkForm);
807
-      }
808
-      await updateBudget(this.budgetForm);
799
+      this.loading = true;
800
+      this.loadingText = '保存中...';
801
+      this.$message.warning('保存中...');
802
+      try {
803
+        let obj = {
804
+          budgetId: this.row.budgetId,
805
+          projectId: this.row.projectId,
806
+          checkId: this.taskForm.formId
807
+        }
808
+        
809
+        // 并发处理基础数据保存
810
+        const savePromises = [];
811
+        
812
+        if (!this.checkForm.checkId) {
813
+          savePromises.push(addCheck(obj));
814
+          this.$emit('preserve');
815
+        } else {
816
+          savePromises.push(updateCheck(this.checkForm));
817
+        }
818
+        savePromises.push(updateBudget(this.budgetForm));
809 819
 
810
-      if (this.taskName == '核算编制') {
811
-        // 更新人员
812
-        let staffList = this.innerStaffList.concat(this.outerStaffList);
813
-        delBudgetStaff(this.row.budgetId).then(async res => {
814
-          for (let staff of staffList) {
820
+        if (this.taskName == '核算编制') {
821
+          // 并发处理所有删除操作
822
+          const deletePromises = [
823
+            delBudgetStaff(this.row.budgetId),
824
+            delBudgetCar(this.row.budgetId),
825
+            delBudgetDevice(this.row.budgetId),
826
+            delOther(this.row.budgetId)
827
+          ];
828
+          
829
+          await Promise.all(deletePromises);
830
+          
831
+          // 并发处理所有新增操作
832
+          const addPromises = [];
833
+          
834
+          // 人员数据(保持顺序)
835
+          const staffList = this.innerStaffList.concat(this.outerStaffList);
836
+          staffList.forEach(staff => {
815 837
             staff.budgetId = this.row.budgetId;
816
-            await addBudgetStaff(staff);
817
-          }
818
-        })
819
-        // 更新车辆
820
-        delBudgetCar(this.row.budgetId).then(async res => {
821
-          for (let car of this.carList) {
838
+            addPromises.push(addBudgetStaff(staff));
839
+          });
840
+          
841
+          // 车辆数据(保持顺序)
842
+          this.carList.forEach(car => {
822 843
             car.budgetId = this.row.budgetId;
823
-            await addBudgetCar(car);
824
-          }
825
-        })
826
-        // 更新设备
827
-        delBudgetDevice(this.row.budgetId).then(async res => {
828
-          for (let device of this.deviceList) {
844
+            addPromises.push(addBudgetCar(car));
845
+          });
846
+          
847
+          // 设备数据(保持顺序)
848
+          this.deviceList.forEach(device => {
829 849
             device.budgetId = this.row.budgetId;
830
-            await addBudgetDevice(device);
831
-          }
832
-        })
833
-        // 更新现场开支
834
-        for (let site of this.siteList) {
835
-          await updateSite(site);
836
-        }
837
-        // 更新预算外开销
838
-        delOther(this.row.budgetId).then(async res => {
839
-          for (let other of this.otherList) {
850
+            addPromises.push(addBudgetDevice(device));
851
+          });
852
+          
853
+          // 预算外开销数据(保持顺序)
854
+          this.otherList.forEach(other => {
840 855
             other.budgetId = this.row.budgetId;
841
-            await addOther(other);
842
-          }
843
-        })
856
+            addPromises.push(addOther(other));
857
+          });
858
+          
859
+          // 现场开支更新(保持顺序)
860
+          this.siteList.forEach(site => {
861
+            addPromises.push(updateSite(site));
862
+          });
863
+          
864
+          // 并发执行所有新增操作
865
+          await Promise.all(addPromises);
866
+        }
867
+        
868
+        // 等待基础数据保存完成
869
+        await Promise.all(savePromises);
870
+        
871
+        this.$message.success('保存成功');
872
+      } catch (error) {
873
+        console.error('保存失败:', error);
874
+        this.$message.error('保存失败,请重试');
875
+      } finally {
876
+        this.loading = false;
877
+        this.loadingText = '加载中...';
844 878
       }
845
-
846
-      this.$message.success('保存成功');
847 879
     },
848 880
     confirmSucess() {
849 881
       this.preserve();

+ 49
- 6
oa-ui/src/views/flowable/form/budget/adjust/components/SiteCost.vue 查看文件

@@ -2,25 +2,25 @@
2 2
  * @Author: ysh
3 3
  * @Date: 2025-05-15 15:30:09
4 4
  * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-19 11:24:43
5
+ * @LastEditTime: 2025-06-19 16:13:39
6 6
 -->
7 7
 <template>
8 8
   <div class="site-cost">
9 9
     <table border="1" style="width:100%;">
10 10
       <tr style="background-color:#f8f8f9">
11 11
         <td style="width: 50px;">序号</td>
12
-        <td>开支项</td>
13
-        <td>金额</td>
12
+        <td style="min-width: 100px;">开支项</td>
13
+        <td style="min-width: 100px;">金额</td>
14 14
         <td class="adjust">核算金额</td>
15 15
         <td>备注</td>
16 16
       </tr>
17 17
       <tr v-for="site, index in siteList" :key="site.id">
18 18
         <td>{{ index + 1 }}</td>
19 19
         <td>{{ site.name }}</td>
20
-        <td style="text-align: right;">{{ site.amount }}</td>
20
+        <td style="text-align: right;">{{ Number(site.amount).toFixed(2) }}</td>
21 21
         <td style="text-align: right;">
22
-          <el-input-number v-if="taskName === '核算编制'" :controls="false" v-model="site.amountAdjust" placeholder="请输入核算金额"
23
-            @change="handleSiteChange(site)" />
22
+          <el-input-number v-if="taskName === '核算编制'" :controls="false" v-model="site.amountAdjust"
23
+            placeholder="请输入核算金额" @change="handleSiteChange(site)" />
24 24
           <span v-else>{{ site.amountAdjust }}</span>
25 25
         </td>
26 26
         <td style="text-align: left;">{{ site.remark }}</td>
@@ -33,10 +33,35 @@
33 33
           || 0), 0).toFixed(2)}}</td>
34 34
       </tr>
35 35
     </table>
36
+    <div class="mt10">
37
+      <el-button type="success" plain icon="el-icon-plus" @click="isOpenSite = true" size="mini">新增开支项</el-button>
38
+    </div>
39
+    <!-- 添加现场开支对话框 -->
40
+    <el-dialog title="添加现场开支" :visible.sync="isOpenSite" width="700px" append-to-body>
41
+      <el-form :model="siteForm" label-width="120px">
42
+        <el-form-item label="开支项">
43
+          <el-input v-model="siteForm.name" placeholder="请输入开支项" />
44
+        </el-form-item>
45
+        <el-form-item label="金额">
46
+          {{ siteForm.amount }}
47
+        </el-form-item>
48
+        <el-form-item label="核算金额">
49
+          <el-input-number v-model="siteForm.amountAdjust" placeholder="请输入核算金额" :controls="false" />
50
+        </el-form-item>
51
+        <el-form-item label="备注">
52
+          <el-input type="textarea" :rows="3" v-model="siteForm.remark" placeholder="请输入备注" />
53
+        </el-form-item>
54
+      </el-form>
55
+      <div slot="footer" class="dialog-footer">
56
+        <el-button @click="isOpenSite = false">取 消</el-button>
57
+        <el-button type="primary" @click="addSiteConfirm">确 定</el-button>
58
+      </div>
59
+    </el-dialog>
36 60
   </div>
37 61
 </template>
38 62
 
39 63
 <script>
64
+import { addSite } from "@/api/oa/budget/budgetSite";
40 65
 export default {
41 66
   props: {
42 67
     siteList: {
@@ -48,9 +73,27 @@ export default {
48 73
       default: ''
49 74
     }
50 75
   },
76
+  data() {
77
+    return {
78
+      isOpenSite: false,
79
+      siteForm: {
80
+        name: '',
81
+        amount: 0,
82
+        amountAdjust: 0,
83
+        remark: ''
84
+      }
85
+    }
86
+  },
51 87
   methods: {
52 88
     handleSiteChange(site) {
53 89
       this.$emit('update:siteList', this.siteList);
90
+    },
91
+    async addSiteConfirm() {
92
+      const budgetId = this.siteList[0].budgetId;
93
+      this.siteForm.budgetId = budgetId;
94
+      await addSite(this.siteForm)
95
+      this.isOpenSite = false;
96
+      this.$emit('updateList');
54 97
     }
55 98
   },
56 99
 }

+ 1
- 1
oa-ui/src/views/flowable/form/budget/adjust/components/otherCost.vue 查看文件

@@ -36,7 +36,7 @@
36 36
         </td>
37 37
       </tr>
38 38
       <tr>
39
-        <td colspan="3" class="amount">预算外开支合计</td>
39
+        <td colspan="3" class="amount">现场外开支合计</td>
40 40
         <td class="amount" style="text-align: right;">{{otherList.reduce((sum, other) => sum +
41 41
           (Number(other.amountAdjust) || 0), 0).toFixed(2)}}</td>
42 42
       </tr>

+ 0
- 3
oa-ui/src/views/flowable/form/budget/moneyTable.vue 查看文件

@@ -428,9 +428,6 @@ export default {
428 428
     },
429 429
     deletWorkItem(index) {
430 430
       let arr = this.contentList;
431
-      if (arr.length == 1) {
432
-        return;
433
-      }
434 431
       if (index >= 0 && index < arr.length) {
435 432
         arr.splice(index, 1);
436 433
       }

Loading…
取消
儲存