af-mobile-client-vue3 1.4.26 → 1.4.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.4.26",
4
+ "version": "1.4.28",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
@@ -111,6 +111,7 @@ const props = defineProps<{
111
111
  isWorkOrder?: boolean
112
112
  workOrderData?: any
113
113
  serviceName?: string
114
+ showGroup?: boolean
114
115
  }>()
115
116
 
116
117
  const emit = defineEmits<{
@@ -131,7 +132,6 @@ const showAddItemModal = ref(false)
131
132
  const showQrCodePayment = ref(false)
132
133
  // 材料组相关状态
133
134
  const showAddGroupModal = ref(false)
134
- const GroupShow = ref(false)
135
135
  // 子组件的响应组件引用
136
136
  const printRef = ref()
137
137
  // 收费类型数据
@@ -154,14 +154,13 @@ const useGridUploader = computed(() => {
154
154
  return config.fileTypes && config.fileTypes.length > 0
155
155
  })
156
156
 
157
+ // 是否显示添加材料组按钮
158
+ const showAddGroupButton = computed(() => {
159
+ return props.showGroup ?? false
160
+ })
157
161
  // 初始化获取配置
158
162
  async function initConfig() {
159
163
  try {
160
- // 获取其他收费类型配置
161
- const webMobileConfig = await getConfigByNameAsync('webMobileConfig', props.serviceName || import.meta.env.VITE_APP_SYSTEM_NAME)
162
- if (webMobileConfig) {
163
- GroupShow.value = webMobileConfig.setting.materialGroup
164
- }
165
164
  // 新的收费类型数据
166
165
  await runLogic('getMaterialInfo', {
167
166
  f_org_id: currUser.resources.orgid,
@@ -270,6 +269,14 @@ function removeChargeItem(itemId: number) {
270
269
  chargeItems.value = chargeItems.value.filter(item => item.id !== itemId)
271
270
  }
272
271
 
272
+ // 更新费用项
273
+ function updateChargeItem(updatedItem: ChargeItem) {
274
+ const index = chargeItems.value.findIndex(item => item.id === updatedItem.id)
275
+ if (index !== -1) {
276
+ chargeItems.value[index] = updatedItem
277
+ }
278
+ }
279
+
273
280
  // 生成收据
274
281
  function generateReceipt() {
275
282
  // 验证是否有费用项
@@ -436,7 +443,7 @@ function onFileRemoved(): void {
436
443
  <CardHeader title="费用项目">
437
444
  <template #extra>
438
445
  <VanButton
439
- v-if="GroupShow"
446
+ v-if="showAddGroupButton"
440
447
  type="primary"
441
448
  size="small"
442
449
  icon="plus"
@@ -468,6 +475,7 @@ function onFileRemoved(): void {
468
475
  :is-work-order="props.isWorkOrder"
469
476
  :work-order-data="props.workOrderData"
470
477
  @remove="removeChargeItem"
478
+ @update="updateChargeItem"
471
479
  />
472
480
  </template>
473
481
  <p v-else class="text-gray-400 text-center">
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { Icon as VanIcon } from 'vant'
2
+ import { Field as VanField, Icon as VanIcon } from 'vant'
3
+ import { computed, ref, watch } from 'vue'
3
4
 
4
5
  interface ChargeItem {
5
6
  id: number
@@ -7,24 +8,101 @@ interface ChargeItem {
7
8
  workOrderId?: string
8
9
  type: string
9
10
  item: string
11
+ model?: string
10
12
  unitPrice: number
11
13
  quantity: number
12
14
  total: string
13
15
  }
14
16
 
15
- defineProps<{
17
+ const props = defineProps<{
16
18
  item: ChargeItem
17
19
  index: number
18
20
  isWorkOrder?: boolean
19
21
  workOrderData?: any
20
22
  }>()
21
23
 
22
- defineEmits<{
24
+ const emit = defineEmits<{
23
25
  (e: 'remove', id: number): void
26
+ (e: 'update', item: ChargeItem): void
24
27
  }>()
25
28
 
26
- function formatPrice(price: number): string {
27
- return price.toFixed(2)
29
+ // 本地状态,用于双向绑定
30
+ const localUnitPrice = ref(props.item.unitPrice.toString())
31
+ const localQuantity = ref(props.item.quantity.toString())
32
+ const item = computed(() => props.item)
33
+
34
+ // 监听 props 变化,同步本地状态
35
+ watch(() => props.item.unitPrice, (newVal) => {
36
+ localUnitPrice.value = newVal.toString()
37
+ })
38
+
39
+ watch(() => props.item.quantity, (newVal) => {
40
+ localQuantity.value = newVal.toString()
41
+ })
42
+
43
+ // 计算小计
44
+ const total = computed(() => {
45
+ const price = Number.parseFloat(localUnitPrice.value) || 0
46
+ const qty = Number.parseInt(localQuantity.value) || 0
47
+ return (price * qty).toFixed(2)
48
+ })
49
+
50
+ // 处理单价变化 - 限制9位整数2位小数
51
+ function handleUnitPriceChange(value: string) {
52
+ // 移除非数字和小数点的字符
53
+ let cleaned = value.replace(/[^\d.]/g, '')
54
+
55
+ // 限制小数点后最多2位
56
+ const parts = cleaned.split('.')
57
+ if (parts.length > 2) {
58
+ cleaned = `${parts[0]}.${parts.slice(1).join('')}`
59
+ }
60
+ if (parts[1] && parts[1].length > 2) {
61
+ cleaned = `${parts[0]}.${parts[1].slice(0, 2)}`
62
+ }
63
+
64
+ // 限制整数部分最多9位
65
+ if (parts[0] && parts[0].length > 9) {
66
+ cleaned = parts[0].slice(0, 9) + (parts[1] ? `.${parts[1]}` : '')
67
+ }
68
+
69
+ // 更新值
70
+ localUnitPrice.value = cleaned
71
+ updateItem()
72
+ }
73
+
74
+ // 处理数量变化 - 限制5位整数
75
+ function handleQuantityChange(value: string) {
76
+ // 只允许数字,限制最多5位
77
+ let cleaned = value.replace(/\D/g, '')
78
+ if (cleaned.length > 5) {
79
+ cleaned = cleaned.slice(0, 5)
80
+ }
81
+
82
+ // 更新值
83
+ localQuantity.value = cleaned
84
+ updateItem()
85
+ }
86
+
87
+ // 更新费用项
88
+ function updateItem() {
89
+ const price = Number.parseFloat(localUnitPrice.value) || 0
90
+ const qty = Number.parseInt(localQuantity.value) || 0
91
+
92
+ // 只有当价格和数量都大于0时才更新
93
+ if (price > 0 && qty > 0) {
94
+ const updatedItem: ChargeItem = {
95
+ ...props.item,
96
+ unitPrice: price,
97
+ quantity: qty,
98
+ total: total.value,
99
+ }
100
+ emit('update', updatedItem)
101
+ }
102
+ else if (localUnitPrice.value === '' || localQuantity.value === '') {
103
+ // 如果输入为空,不更新,保持原值
104
+
105
+ }
28
106
  }
29
107
  </script>
30
108
 
@@ -50,6 +128,14 @@ function formatPrice(price: number): string {
50
128
  {{ item.workOrderCode }}
51
129
  </p>
52
130
  </div>
131
+ <div class="other-charge-item__field">
132
+ <p class="other-charge-item__label">
133
+ 小计
134
+ </p>
135
+ <p class="other-charge-item__value--info">
136
+ ¥{{ total }}
137
+ </p>
138
+ </div>
53
139
  <div class="other-charge-item__field">
54
140
  <p class="other-charge-item__label">
55
141
  收费类型
@@ -73,25 +159,27 @@ function formatPrice(price: number): string {
73
159
  <p class="other-charge-item__label">
74
160
  单价
75
161
  </p>
76
- <p class="other-charge-item__value">
77
- ¥{{ formatPrice(item.unitPrice) }}
78
- </p>
162
+ <VanField
163
+ :model-value="localUnitPrice"
164
+ type="number"
165
+ placeholder="限制9位整数2位小数"
166
+ @update:model-value="handleUnitPriceChange"
167
+ >
168
+ <template #prefix>
169
+ <span class="other-charge-item__prefix">¥</span>
170
+ </template>
171
+ </VanField>
79
172
  </div>
80
173
  <div class="other-charge-item__field">
81
174
  <p class="other-charge-item__label">
82
175
  数量
83
176
  </p>
84
- <p class="other-charge-item__value">
85
- {{ item.quantity }}
86
- </p>
87
- </div>
88
- <div class="other-charge-item__field">
89
- <p class="other-charge-item__label">
90
- 小计
91
- </p>
92
- <p class="other-charge-item__value--highlight">
93
- ¥{{ item.total }}
94
- </p>
177
+ <VanField
178
+ :model-value="localQuantity"
179
+ type="number"
180
+ placeholder="限制5位整数"
181
+ @update:model-value="handleQuantityChange"
182
+ />
95
183
  </div>
96
184
  </div>
97
185
  </div>
@@ -108,8 +196,9 @@ function formatPrice(price: number): string {
108
196
  &__header {
109
197
  display: flex;
110
198
  justify-content: space-between;
111
- align-items: flex-start;
199
+ align-items: center;
112
200
  margin-bottom: 8px;
201
+ gap: 8px;
113
202
  }
114
203
 
115
204
  &__title {
@@ -117,17 +206,40 @@ function formatPrice(price: number): string {
117
206
  font-weight: 500;
118
207
  color: #374151;
119
208
  margin: 0;
209
+ flex-shrink: 0;
210
+ }
211
+ &__value--info {
212
+ font-size: 14px;
213
+ font-weight: 500;
214
+ color: #2563eb;
120
215
  }
121
-
122
216
  &__delete {
123
217
  color: #ef4444;
124
218
  font-size: 16px;
219
+ flex-shrink: 0;
220
+ cursor: pointer;
125
221
 
126
222
  &:active {
127
223
  color: #b91c1c;
128
224
  }
129
225
  }
130
226
 
227
+ :deep(.van-field) {
228
+ background-color: #ffffff;
229
+ border-radius: 4px;
230
+ padding: 8px 12px;
231
+ }
232
+
233
+ :deep(.van-field__control) {
234
+ background-color: #ffffff;
235
+ color: #1f2937;
236
+ font-size: 14px;
237
+ }
238
+
239
+ :deep(.van-field__label) {
240
+ display: none;
241
+ }
242
+
131
243
  &__info {
132
244
  display: grid;
133
245
  grid-template-columns: 1fr 1fr;
@@ -137,18 +249,14 @@ function formatPrice(price: number): string {
137
249
 
138
250
  &__details {
139
251
  display: grid;
140
- grid-template-columns: 1fr 1fr 1fr;
252
+ grid-template-columns: 1fr 1fr;
141
253
  gap: 12px;
142
254
  }
143
255
 
144
- &__field {
145
- margin-bottom: 0;
146
- }
147
-
148
256
  &__label {
149
257
  font-size: 12px;
150
258
  color: #6b7280;
151
- margin: 0 0 2px 0;
259
+ margin: 0 0 4px 0;
152
260
  }
153
261
 
154
262
  &__value {
@@ -156,13 +264,12 @@ function formatPrice(price: number): string {
156
264
  font-weight: 500;
157
265
  color: #1f2937;
158
266
  margin: 0;
267
+ }
159
268
 
160
- &--highlight {
161
- font-size: 14px;
162
- font-weight: 500;
163
- color: #2563eb;
164
- margin: 0;
165
- }
269
+ &__prefix {
270
+ color: #6b7280;
271
+ font-size: 14px;
272
+ margin-right: 4px;
166
273
  }
167
274
  }
168
275
  </style>
@@ -33,6 +33,7 @@ onMounted(() => {
33
33
  v-if="loading"
34
34
  :user="userinfo"
35
35
  :is-work-order="true"
36
+ :show-group="true"
36
37
  :service-name="serviceName"
37
38
  :work-order-data="workOrderData"
38
39
  @close-operation="backList"