af-mobile-client-vue3 1.4.14 → 1.4.16

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/src/components/common/otherCharge/ChargePrintSelectorAndRemarks.vue +132 -0
  3. package/src/components/common/otherCharge/CodePayment.vue +351 -0
  4. package/src/components/common/otherCharge/FileUploader.vue +599 -0
  5. package/src/components/common/otherCharge/GridFileUploader.vue +840 -0
  6. package/src/components/common/otherCharge/PaymentMethodSelector.vue +202 -0
  7. package/src/components/common/otherCharge/PaymentMethodSelectorCard.vue +45 -0
  8. package/src/components/common/otherCharge/ReceiptModal.vue +269 -0
  9. package/src/components/common/otherCharge/index.ts +43 -0
  10. package/src/components/core/Signature/SignatureComponent.vue +312 -0
  11. package/src/components/core/Signature/signature.ts +38 -0
  12. package/src/components/data/OtherCharge/OtherChargeForm.vue +736 -0
  13. package/src/components/data/OtherCharge/OtherChargeItem.vue +166 -0
  14. package/src/components/data/OtherCharge/OtherChargeItemModal.vue +529 -0
  15. package/src/components/data/XBadge/index.vue +1 -1
  16. package/src/components/data/XFormItem/index.vue +0 -2
  17. package/src/router/routes.ts +421 -421
  18. package/src/stores/modules/setting.ts +1 -0
  19. package/src/stores/modules/user.ts +1 -1
  20. package/src/utils/queryFormDefaultRangePicker.ts +57 -57
  21. package/src/views/component/XCellListView/index.vue +138 -104
  22. package/src/views/component/XFormGroupView/index.vue +82 -78
  23. package/src/views/component/XFormView/index.vue +46 -41
  24. package/src/views/user/login/LoginForm.vue +5 -9
  25. package/vite.config.ts +2 -9
@@ -0,0 +1,202 @@
1
+ <script setup lang="ts">
2
+ import CardHeader from '@af-mobile-client-vue3/components/data/CardContainer/CardHeader.vue'
3
+ import { computed, ref } from 'vue'
4
+ // import useBusinessStore from '@/stores/modules/business'
5
+
6
+ interface PaymentMethod {
7
+ label: string
8
+ value: string
9
+ icon: string
10
+ color: string
11
+ }
12
+
13
+ const props = defineProps({
14
+ modelValue: {
15
+ type: String,
16
+ required: true,
17
+ },
18
+ title: {
19
+ type: String,
20
+ default: '支付方式',
21
+ },
22
+ allowedMethods: {
23
+ type: Array as () => string[],
24
+ default: null,
25
+ },
26
+ icon: {
27
+ type: String,
28
+ default: 'fa-credit-card',
29
+ },
30
+ user: {
31
+ type: Object,
32
+ default: () => {},
33
+ },
34
+ })
35
+
36
+ const emit = defineEmits(['update:modelValue'])
37
+ const businessStore = props.user
38
+ const userInfo = ref({ ...businessStore })
39
+ const defaultMethods: PaymentMethod[] = [
40
+ {
41
+ value: '现金缴费',
42
+ label: '现金缴费',
43
+ icon: 'i-fa6-solid-money-bill-wave',
44
+ color: 'red',
45
+ },
46
+ {
47
+ value: '扫码支付',
48
+ label: '扫码支付',
49
+ icon: 'i-fa6-solid-qrcode',
50
+ color: 'blue',
51
+ },
52
+ {
53
+ value: '微信支付',
54
+ label: '微信支付',
55
+ icon: 'i-fa-brands-weixin',
56
+ color: 'green',
57
+ },
58
+ {
59
+ value: '支付宝支付',
60
+ label: '支付宝支付',
61
+ icon: 'i-fa-brands-alipay',
62
+ color: 'blue',
63
+ },
64
+ ]
65
+
66
+ const displayMethods = computed(() => {
67
+ if (userInfo.value.f_orgid === '1767') {
68
+ return defaultMethods.filter(method =>
69
+ method.value === '微信支付',
70
+ )
71
+ }
72
+ else {
73
+ if (!props.allowedMethods) {
74
+ return defaultMethods
75
+ }
76
+ return defaultMethods.filter(method =>
77
+ props.allowedMethods.includes(method.value),
78
+ )
79
+ }
80
+ })
81
+
82
+ function handleSelect(value: string) {
83
+ console.log(value)
84
+ emit('update:modelValue', value)
85
+ }
86
+ </script>
87
+
88
+ <template>
89
+ <div class="payment-method-selector">
90
+ <div class="payment-method-selector__header">
91
+ <CardHeader :title="title" />
92
+ </div>
93
+ <div class="payment-method-selector__body">
94
+ <div class="payment-method-selector__grid">
95
+ <div
96
+ v-for="method in displayMethods"
97
+ :key="method.value"
98
+ class="payment-method-selector__item"
99
+ :class="{ 'payment-method-selector__item--active': modelValue === method.value }"
100
+ @click="handleSelect(method.value)"
101
+ >
102
+ <div class="payment-method-selector__icon-wrap" :class="`payment-method-selector__icon-wrap--${method.color}`">
103
+ <div class="payment-method-selector__icon" :class="[method.icon]" />
104
+ </div>
105
+ <span class="payment-method-selector__label" :class="{ 'payment-method-selector__label--active': modelValue === method.value }">
106
+ {{ method.label }}
107
+ </span>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </template>
113
+
114
+ <style lang="less" scoped>
115
+ .payment-method-selector {
116
+ &__header {
117
+ margin-bottom: 12px;
118
+ }
119
+
120
+ &__grid {
121
+ display: grid;
122
+ grid-template-columns: repeat(2, 1fr);
123
+ gap: 12px;
124
+
125
+ @media (min-width: 768px) {
126
+ grid-template-columns: repeat(4, 1fr);
127
+ }
128
+ }
129
+
130
+ &__item {
131
+ display: flex;
132
+ align-items: center;
133
+ padding: 8px;
134
+ cursor: pointer;
135
+ border: 1px solid #e5e7eb;
136
+ border-radius: 8px;
137
+ background-color: #fff;
138
+ transition: all 0.2s ease;
139
+
140
+ &:hover {
141
+ background-color: #f9fafb;
142
+ }
143
+
144
+ &--active {
145
+ background-color: #ebf5ff;
146
+ border-color: #3b82f6;
147
+ box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2);
148
+ }
149
+ }
150
+
151
+ &__icon-wrap {
152
+ width: 32px;
153
+ height: 32px;
154
+ border-radius: 50%;
155
+ display: flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ margin-right: 8px;
159
+ flex-shrink: 0;
160
+
161
+ &--green {
162
+ background-color: #dcfce7;
163
+
164
+ .payment-method-selector__icon {
165
+ color: #16a34a;
166
+ }
167
+ }
168
+
169
+ &--blue {
170
+ background-color: #dbeafe;
171
+
172
+ .payment-method-selector__icon {
173
+ color: #2563eb;
174
+ }
175
+ }
176
+
177
+ &--red {
178
+ background-color: #fff0f0;
179
+
180
+ .payment-method-selector__icon {
181
+ color: #d32f2f;
182
+ }
183
+ }
184
+ }
185
+
186
+ &__icon {
187
+ width: 16px;
188
+ height: 16px;
189
+ display: inline-block;
190
+ }
191
+
192
+ &__label {
193
+ font-size: 12px;
194
+ font-weight: 500;
195
+ color: #6b7280;
196
+
197
+ &--active {
198
+ color: #2563eb;
199
+ }
200
+ }
201
+ }
202
+ </style>
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ import CardContainer from '@af-mobile-client-vue3/components/data/CardContainer/CardContainer.vue'
3
+ import PaymentMethodSelector from './PaymentMethodSelector.vue'
4
+
5
+ defineProps({
6
+ modelValue: {
7
+ type: String,
8
+ required: true,
9
+ },
10
+ title: {
11
+ type: String,
12
+ default: '支付方式',
13
+ },
14
+ allowedMethods: {
15
+ type: Array as () => string[],
16
+ default: null,
17
+ },
18
+ className: {
19
+ type: String,
20
+ default: '',
21
+ },
22
+ user: {
23
+ type: Object,
24
+ default: () => {},
25
+ },
26
+ })
27
+
28
+ const emit = defineEmits(['update:modelValue'])
29
+
30
+ function handleUpdate(value: string) {
31
+ emit('update:modelValue', value)
32
+ }
33
+ </script>
34
+
35
+ <template>
36
+ <CardContainer :class="className">
37
+ <PaymentMethodSelector
38
+ :model-value="modelValue"
39
+ :title="title"
40
+ :allowed-methods="allowedMethods"
41
+ :user="user"
42
+ @update:model-value="handleUpdate"
43
+ />
44
+ </CardContainer>
45
+ </template>
@@ -0,0 +1,269 @@
1
+ <script setup lang="ts">
2
+ import { runLogic } from '@af-mobile-client-vue3/services/api/common'
3
+ import { mobileUtil } from '@af-mobile-client-vue3/utils/mobileUtil'
4
+ import { defineEmits, onUnmounted, ref, watch } from 'vue'
5
+
6
+ interface PrintItem {
7
+ type?: string
8
+ text?: string
9
+ align?: 'left' | 'center' | 'right'
10
+ isbold?: boolean
11
+ fontsize?: number
12
+ value?: number
13
+ unit?: string
14
+ [key: string]: any
15
+ }
16
+
17
+ const props = defineProps({
18
+ title: {
19
+ type: String,
20
+ default: '电子凭证',
21
+ },
22
+ subTitle: {
23
+ type: String,
24
+ default: '',
25
+ },
26
+ showSaveButton: {
27
+ type: Boolean,
28
+ default: true,
29
+ },
30
+ saveButtonText: {
31
+ type: String,
32
+ default: '打印',
33
+ },
34
+ closeButtonText: {
35
+ type: String,
36
+ default: '完成',
37
+ },
38
+ })
39
+
40
+ const emit = defineEmits(['update:show', 'ok', 'close'])
41
+
42
+ // 保存原始滚动位置和样式
43
+ const scrollPosition = ref(0)
44
+ const documentWidth = ref(0)
45
+ // 是否显示弹窗
46
+ const show = ref(false)
47
+ // 打印列表
48
+ const printList = ref<PrintItem[]>([])
49
+ // 获取祖父组件的方法
50
+ // const success = inject('success')
51
+
52
+ // 锁定滚动
53
+ function lockScroll() {
54
+ // 保存当前滚动位置
55
+ scrollPosition.value = window.pageYOffset
56
+ // 保存文档原始宽度以防止滚动条消失导致的页面抖动
57
+ documentWidth.value = document.documentElement.clientWidth
58
+ // 弹窗打开时,给body添加类以禁止滚动
59
+ document.body.classList.add('receipt-modal-open')
60
+ // 设置body的top位置,保持视觉位置不变
61
+ document.body.style.top = `-${scrollPosition.value}px`
62
+ // 保持页面宽度不变,防止滚动条消失导致的布局偏移
63
+ document.body.style.width = `${documentWidth.value}px`
64
+ }
65
+
66
+ // 解除滚动锁定
67
+ function unlockScroll() {
68
+ // 弹窗关闭时,移除禁止滚动的类
69
+ document.body.classList.remove('receipt-modal-open')
70
+ // 恢复body样式
71
+ document.body.style.top = ''
72
+ document.body.style.width = ''
73
+ // 恢复滚动位置
74
+ window.scrollTo(0, scrollPosition.value)
75
+ }
76
+
77
+ // 调用Logic组织打印参数
78
+ async function printParams(printLogic: string, printId: string, otherParams?: any) {
79
+ try {
80
+ printList.value = await runLogic(printLogic, { id: printId, otherParams })
81
+ console.log('打印参数==', printList.value)
82
+ if (printList.value.length > 0) {
83
+ show.value = true
84
+ }
85
+ else {
86
+ // 没查到数据默认不打印
87
+ close()
88
+ }
89
+ }
90
+ catch (error) {
91
+ console.error('Error calling logic:', error)
92
+ }
93
+ }
94
+
95
+ // 打印
96
+ function ok() {
97
+ // 实际项目中应添加收据截图保存逻辑
98
+ mobileUtil.execute({
99
+ funcName: 'print',
100
+ param: { data: printList.value },
101
+ callbackFunc: (result) => {
102
+ // emit('ok', { status: true })
103
+ emit('close', { status: true })
104
+ },
105
+ })
106
+ }
107
+
108
+ // 关闭弹窗
109
+ function close() {
110
+ show.value = false
111
+ emit('close', { status: true })
112
+ // if (typeof success === 'function') {
113
+ // success()
114
+ // }
115
+ }
116
+
117
+ // 监听show变化,控制body滚动
118
+ watch(() => show.value, (newVal, oldVal) => {
119
+ if (newVal && !oldVal) {
120
+ lockScroll()
121
+ }
122
+ else if (!newVal && oldVal) {
123
+ unlockScroll()
124
+ }
125
+ }, { immediate: true })
126
+
127
+ // 组件卸载时确保移除类和恢复滚动
128
+ onUnmounted(() => {
129
+ if (document.body.classList.contains('receipt-modal-open')) {
130
+ unlockScroll()
131
+ }
132
+ })
133
+
134
+ // 暴露组织参数的给父组件调用
135
+ defineExpose({ printParams, close })
136
+ </script>
137
+
138
+ <template>
139
+ <van-popup
140
+ :show="show"
141
+
142
+ :close-on-click-overlay="false"
143
+ position="center"
144
+ round lock-scroll
145
+ class="receipt-modal"
146
+ :style="{ width: '90%', maxWidth: '375px' }"
147
+ >
148
+ <div class="receipt-modal-container">
149
+ <div class="receipt-modal-header">
150
+ <div class="receipt-modal-title-container">
151
+ <div class="receipt-modal-title">
152
+ {{ props.title }}
153
+ </div>
154
+ <div v-if="subTitle" class="receipt-modal-subtitle">
155
+ {{ props.subTitle }}
156
+ </div>
157
+ </div>
158
+ </div>
159
+ <div class="receipt-modal-content">
160
+ <template v-for="(item, index) in printList" :key="index">
161
+ <div
162
+ v-if="item?.text !== undefined"
163
+ class="print-list-item"
164
+ :style="{
165
+ 'text-align': item.align || undefined,
166
+ 'font-weight': item.isbold ? 'bold' : undefined,
167
+ 'font-size': item.fontsize ? `${item.fontsize * 7}px` : undefined,
168
+ 'color': '#6b7280',
169
+ }"
170
+ >
171
+ {{ item.text }}
172
+ </div>
173
+ </template>
174
+ </div>
175
+ <div class="receipt-modal-footer">
176
+ <van-button
177
+ v-if="showSaveButton"
178
+ class="save-button"
179
+ type="primary"
180
+ @click="ok"
181
+ >
182
+ {{ saveButtonText }}
183
+ </van-button>
184
+ <van-button class="close-button" @click="close">
185
+ {{ closeButtonText }}
186
+ </van-button>
187
+ </div>
188
+ </div>
189
+ </van-popup>
190
+ </template>
191
+
192
+ <style lang="less">
193
+ /* 全局样式,不使用scoped */
194
+ body.receipt-modal-open {
195
+ overflow: hidden !important;
196
+ position: fixed !important;
197
+ width: 100% !important;
198
+ height: 100% !important;
199
+ left: 0 !important;
200
+ /* top设置由JS动态控制 */
201
+ }
202
+ </style>
203
+
204
+ <style lang="less" scoped>
205
+ .receipt-modal {
206
+ z-index: 1000;
207
+ border-radius: 8px;
208
+ overflow: hidden;
209
+ }
210
+
211
+ .receipt-modal-container {
212
+ display: flex;
213
+ flex-direction: column;
214
+ max-height: 80vh;
215
+ padding: 16px;
216
+ box-sizing: border-box;
217
+ }
218
+
219
+ .receipt-modal-header {
220
+ display: flex;
221
+ justify-content: center;
222
+ align-items: center;
223
+ margin-bottom: 16px;
224
+ }
225
+
226
+ .receipt-modal-title-container {
227
+ text-align: center;
228
+ }
229
+
230
+ .receipt-modal-title {
231
+ font-size: 18px;
232
+ font-weight: bold;
233
+ }
234
+
235
+ .receipt-modal-subtitle {
236
+ font-size: 14px;
237
+ color: #666;
238
+ margin-top: 4px;
239
+ }
240
+
241
+ .receipt-modal-content {
242
+ flex: 1;
243
+ overflow-y: auto;
244
+ max-height: 50vh;
245
+ }
246
+
247
+ .receipt-modal-footer {
248
+ display: flex;
249
+ justify-content: space-between;
250
+ gap: 12px;
251
+ margin-top: 16px;
252
+ padding-bottom: 8px;
253
+ padding-left: 16px;
254
+ padding-right: 16px;
255
+ }
256
+
257
+ .save-button,
258
+ .close-button {
259
+ flex: 1;
260
+ height: 36px;
261
+ font-size: 14px;
262
+ max-width: 120px;
263
+ }
264
+
265
+ .print-list-item {
266
+ padding: 8px 0;
267
+ // border-bottom: 1px solid #eee;
268
+ }
269
+ </style>
@@ -0,0 +1,43 @@
1
+ import CardContainer from '@af-mobile-client-vue3/components/data/CardContainer/CardContainer.vue'
2
+ import CardHeader from '@af-mobile-client-vue3/components/data/CardContainer/CardHeader.vue'
3
+ import ChargePrintSelectorAndRemarks from './ChargePrintSelectorAndRemarks.vue'
4
+ import CodePayment from './CodePayment.vue'
5
+ import FileUploader from './FileUploader.vue'
6
+ // import FormField from './FormField.vue'
7
+ import GridFileUploader from './GridFileUploader.vue'
8
+ // import InfoCard from './InfoCard.vue'
9
+ import PaymentMethodSelector from './PaymentMethodSelector.vue'
10
+ import PaymentMethodSelectorCard from './PaymentMethodSelectorCard.vue'
11
+ import ReceiptModal from './ReceiptModal.vue'
12
+ // import SafetyGuideModal from './SafetyGuideModal.vue'
13
+
14
+ export {
15
+ CardContainer,
16
+ CardHeader,
17
+ ChargePrintSelectorAndRemarks,
18
+ CodePayment,
19
+ FileUploader,
20
+ // FormField,
21
+ GridFileUploader,
22
+ // InfoCard,
23
+ PaymentMethodSelector,
24
+ PaymentMethodSelectorCard,
25
+ ReceiptModal,
26
+ // SafetyGuideModal,
27
+ }
28
+
29
+ export default {
30
+ install(app: any) {
31
+ app.component('CardContainer', CardContainer)
32
+ app.component('CardHeader', CardHeader)
33
+ // app.component('FormField', FormField)
34
+ // app.component('InfoCard', InfoCard)
35
+ app.component('PaymentMethodSelector', PaymentMethodSelector)
36
+ app.component('PaymentMethodSelectorCard', PaymentMethodSelectorCard)
37
+ app.component('ChargePrintSelectorAndRemarks', ChargePrintSelectorAndRemarks)
38
+ app.component('FileUploader', FileUploader)
39
+ app.component('GridFileUploader', GridFileUploader)
40
+ app.component('ReceiptModal', ReceiptModal)
41
+ // app.component('SafetyGuideModal', SafetyGuideModal)
42
+ },
43
+ }