@uxda/appkit 1.0.0

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 (52) hide show
  1. package/.eslintrc.mjs +8 -0
  2. package/README.md +147 -0
  3. package/babel.config.js +12 -0
  4. package/dist/appkit.css +3 -0
  5. package/dist/index.js +1755 -0
  6. package/dist/styles.css +1 -0
  7. package/package.json +73 -0
  8. package/project.config.json +15 -0
  9. package/project.tt.json +13 -0
  10. package/rollup.config.js +55 -0
  11. package/src/Appkit.ts +41 -0
  12. package/src/balance/api/endpoints.ts +108 -0
  13. package/src/balance/api/index.ts +25 -0
  14. package/src/balance/components/AccountView.vue +519 -0
  15. package/src/balance/components/BalanceCard.vue +181 -0
  16. package/src/balance/components/BalanceReminder.vue +82 -0
  17. package/src/balance/components/ConsumptionFilter.vue +176 -0
  18. package/src/balance/components/ConsumptionRules.vue +70 -0
  19. package/src/balance/components/DateFilter.vue +219 -0
  20. package/src/balance/components/index.ts +9 -0
  21. package/src/balance/index.ts +1 -0
  22. package/src/balance/types.ts +92 -0
  23. package/src/global.ts +7 -0
  24. package/src/index.ts +51 -0
  25. package/src/main.scss +1 -0
  26. package/src/payment/README.md +0 -0
  27. package/src/payment/api/config.ts +8 -0
  28. package/src/payment/api/endpoints.ts +75 -0
  29. package/src/payment/api/index.ts +25 -0
  30. package/src/payment/components/AmountPicker.vue +109 -0
  31. package/src/payment/components/RechargeView.vue +146 -0
  32. package/src/payment/components/UserAgreement.vue +111 -0
  33. package/src/payment/components/index.ts +16 -0
  34. package/src/payment/consts.ts +1 -0
  35. package/src/payment/index.ts +1 -0
  36. package/src/payment/services/index.ts +17 -0
  37. package/src/payment/services/invoke-recharge.ts +25 -0
  38. package/src/payment/services/request-payment.ts +32 -0
  39. package/src/payment/types.ts +24 -0
  40. package/src/shared/components/AppDrawer.vue +53 -0
  41. package/src/shared/components/PageHeader.vue +75 -0
  42. package/src/shared/components/index.ts +7 -0
  43. package/src/shared/http/Http.ts +124 -0
  44. package/src/shared/http/index.ts +2 -0
  45. package/src/shared/http/types.ts +100 -0
  46. package/src/shared/index.ts +3 -0
  47. package/src/shared/weixin/index.ts +1 -0
  48. package/src/shared/weixin/payment.ts +37 -0
  49. package/src/styles/vars.scss +4 -0
  50. package/tsconfig.json +30 -0
  51. package/types/global.d.ts +22 -0
  52. package/types/vue.d.ts +10 -0
@@ -0,0 +1,519 @@
1
+ <template>
2
+ <div class="consumption-view">
3
+ <div class="header">
4
+ <div class="header_card">
5
+ <div class="clound-bean">
6
+ <div class="bean-box spa-between">
7
+ <div class="bean-img">
8
+ <img
9
+ class="bean-icon"
10
+ src="https://cdn.ddjf.com/static/images/bpms-workBench/gold-bean.png" />
11
+ <div class="bean-tag tag">云豆</div>
12
+ </div>
13
+ <div class="rule" @click="rulesPopupOpen = true">规则说明</div>
14
+ </div>
15
+ <div class="bean-counts spa-between">
16
+ <div class="counts">{{ balance.total || 0 }}</div>
17
+ <div class="pay" @click="gotoRecharge">云豆充值</div>
18
+ </div>
19
+ </div>
20
+ <div class="line"></div>
21
+ <div
22
+ class="small-clound-bean clound-bean"
23
+ v-if="balance.privileges.length > 0">
24
+ <div class="bean-box spa-between">
25
+ <div class="bean-img">
26
+ <div class="bean-tag">小云豆</div>
27
+ </div>
28
+ </div>
29
+ <div class="bean-list">
30
+ <template v-for="item in balance.privileges" :key="item">
31
+ <div class="bean-list-item">
32
+ <div class="counts">
33
+ {{ item.amount }}
34
+ </div>
35
+ <div class="title">
36
+ {{ item.title }}
37
+ </div>
38
+ </div>
39
+ </template>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ <div class="operation-title spa-between">
45
+ <div class="search-time">
46
+ <div class="title">收支明细</div>
47
+ <div class="time" @click="openDateFilter" v-show="filtering.dateFrom">
48
+ <div class="text">{{ dataRangeDisplay }}</div>
49
+ <img
50
+ class="time-icon"
51
+ src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-down.png" />
52
+ </div>
53
+ </div>
54
+ <div class="search" @click="filterOpen = true">
55
+ <span class="text">筛选</span>
56
+ <img
57
+ class="time-icon"
58
+ src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-select-icon.png" />
59
+ </div>
60
+ </div>
61
+ <div class="operation-list">
62
+ <div class="box" v-if="consumptionGroups.list.length > 0">
63
+ <div class="box-detail" v-for="(item, index) in consumptionGroups.list" :key="index">
64
+ <div class="title">{{ item.date }}</div>
65
+ <div
66
+ class="item"
67
+ v-for="(it, i) in item.consumptions"
68
+ :key="i">
69
+ <div class="item-type">
70
+ {{ it.type }}
71
+ </div>
72
+ <div class="item-detail">
73
+ <div class="item-info spa-between">
74
+ <div>
75
+ <div class="item-info-type">
76
+ {{ it.position }}
77
+ </div>
78
+ <div class="item-info-title">{{ it.title }}</div>
79
+ </div>
80
+ <div class="item-info-amount">
81
+ {{ it.direction == '支出' ? '-' : '+' }}{{ it.amount }}
82
+ </div>
83
+ </div>
84
+ <div class="item-detail-remark">{{ it.description }}</div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ <div class="box-not-text">没有更多了</div>
89
+ </div>
90
+ <div v-else class="info-not">
91
+ <img
92
+ class="info-not-img"
93
+ src="https://cdn.ddjf.com/static/images/fnfundkit/bean-no-thing.png" />
94
+ <div class="info-not-text">暂无数据</div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ <nut-popup
99
+ pop-class="consumption-rules-popup"
100
+ v-model:visible="rulesPopupOpen"
101
+ :close-on-click-overlay="false">
102
+ <consumption-rules @complete="rulesPopupOpen = false" />
103
+ </nut-popup>
104
+ <nut-popup
105
+ position="bottom"
106
+ :style="{ height: '40%' }"
107
+ round
108
+ :close-on-click-overlay="true"
109
+ v-model:visible="datePickerOpen">
110
+ <date-filter
111
+ v-if="datePickerOpen"
112
+ :from="filtering.dateFrom"
113
+ :to="filtering.dateTo"
114
+ @complete="onDateFilterComplete"/>
115
+ </nut-popup>
116
+ <nut-popup
117
+ position="bottom"
118
+ :style="{ height: '70%' }"
119
+ round
120
+ :close-on-click-overlay="false"
121
+ v-model:visible="filterOpen">
122
+ <consumption-filter :modelValue="[
123
+ filtering.position,
124
+ filtering.direction,
125
+ filtering.type,
126
+ ]" @complete="onFilterComplete" />
127
+ </nut-popup>
128
+ <div class="back-to-top" @click="backToTop" v-show="scrollY > 300">
129
+ <img
130
+ class="back-to-top-icon"
131
+ src="https://cdn.ddjf.com/static/images/bpms-workBench/top.png" />
132
+ </div>
133
+ <balance-reminder v-model="balanceReminderOpen" />
134
+ </template>
135
+
136
+ <script lang="ts" setup>
137
+ import Taro, { usePageScroll } from '@tarojs/taro'
138
+ import { computed, onMounted, reactive, ref } from 'vue'
139
+ import { endpoints, makeHttp } from '../api'
140
+ import { ConsumptionFiltering, ConsumptionGroups, Balance } from '../types'
141
+ import ConsumptionFilter from './ConsumptionFilter.vue'
142
+ import DateFilter from './DateFilter.vue'
143
+ import ConsumptionRules from './ConsumptionRules.vue'
144
+ import BalanceReminder from './BalanceReminder.vue'
145
+
146
+ const emit = defineEmits(['recharge'])
147
+
148
+ const filterOpen = ref<boolean>(false)
149
+
150
+ // 规则说明弹窗
151
+ const rulesPopupOpen = ref<boolean>(false)
152
+
153
+ const filtering = reactive<ConsumptionFiltering>({
154
+ position: '全部',
155
+ direction: '全部',
156
+ type: '全部',
157
+ dateFrom: '',
158
+ dateTo: ''
159
+ })
160
+
161
+ // 时间筛选
162
+ const datePickerOpen = ref<boolean>(false)
163
+
164
+ function openDateFilter () {
165
+ datePickerOpen.value = true
166
+ }
167
+
168
+ const dataRangeDisplay = computed(() => {
169
+ let startTime = filtering.dateFrom?.replace(/-/g, '.').substring(2)
170
+ let endTime = filtering.dateTo?.replace(/-/g, '.').substring(2)
171
+ return startTime + ' - ' + endTime
172
+ })
173
+
174
+ const consumptionGroups = ref<ConsumptionGroups>({
175
+ from: '',
176
+ to: '',
177
+ list: []
178
+ })
179
+
180
+ const balance = ref<Balance>({
181
+ total: 0,
182
+ privileges: []
183
+ })
184
+
185
+ onMounted(() => {
186
+ Taro.setNavigationBarTitle({
187
+ title: '我的账户',
188
+ })
189
+ loadConsumptions(true)
190
+ loadBalance()
191
+ })
192
+
193
+ async function loadConsumptions (firstTime?: boolean) {
194
+ const $http = makeHttp()
195
+ Taro.showLoading({
196
+ title: `加载中...`,
197
+ mask: true,
198
+ })
199
+ $http.get<ConsumptionGroups>(endpoints.getOperations, filtering).then(data => {
200
+ consumptionGroups.value = data
201
+ if (firstTime) {
202
+ filtering.dateFrom = data.from
203
+ filtering.dateTo = data.to
204
+ }
205
+ })
206
+ Taro.hideLoading()
207
+ }
208
+
209
+ async function loadBalance() {
210
+ const $http = makeHttp()
211
+ $http.get<Balance>(endpoints.getBalance, {
212
+ }).then(data => {
213
+ balance.value = data
214
+ })
215
+ }
216
+
217
+ const onFilterComplete = (value) => {
218
+ filtering.position = value[0]
219
+ filtering.direction = value[1]
220
+ filtering.type = value[2]
221
+ filterOpen.value = false
222
+ loadConsumptions()
223
+ }
224
+
225
+ const onDateFilterComplete = (value) => {
226
+ filtering.dateFrom = value.from
227
+ filtering.dateTo = value.to
228
+ datePickerOpen.value = false
229
+ loadConsumptions()
230
+ }
231
+
232
+ function backToTop() {
233
+ Taro.pageScrollTo({
234
+ scrollTop: 0,
235
+ duration: 300, // 滚动到顶部的动画持续时间
236
+ })
237
+ }
238
+
239
+ function gotoRecharge () {
240
+ balanceReminderOpen.value = true
241
+ emit('recharge')
242
+ }
243
+
244
+ const balanceReminderOpen = ref(false)
245
+
246
+ const scrollY = ref<number>(0)
247
+ usePageScroll((e) => {
248
+ const { scrollTop } = e
249
+ scrollY.value = scrollTop
250
+ })
251
+ </script>
252
+
253
+ <style lang="scss">
254
+ .consumption-view {
255
+ .spa-between {
256
+ padding: 0 0 0 10px;
257
+ display: flex;
258
+ justify-content: space-between;
259
+ align-items: center;
260
+ }
261
+ .header {
262
+ position: relative;
263
+ background: linear-gradient(187.18deg, #353535 10.04%, #433f46 90.21%);
264
+ background-size: 100% 106px;
265
+ padding-top: 20px;
266
+ background-repeat: no-repeat;
267
+ &_card {
268
+ background: linear-gradient(104.85deg, #f4e2ce 1.88%, #debb9b 98.18%);
269
+ border-radius: 15px;
270
+ padding: 10px;
271
+ margin: 0 15px;
272
+ .clound-bean {
273
+ .bean-box {
274
+ font-size: 10px;
275
+ .bean-img {
276
+ display: flex;
277
+ justify-content: start;
278
+ align-items: center;
279
+ .bean-icon {
280
+ display: block;
281
+ font-size: 0;
282
+ width: 20px;
283
+ height: 20px;
284
+ margin-right: 4px;
285
+ }
286
+ .bean-tag {
287
+ color: #353535;
288
+ height: 15px;
289
+ line-height: 15px;
290
+ border-radius: 30px 50px 50px 0px;
291
+ background: rgba(#ff8320, 0.3);
292
+ padding-left: 5px;
293
+ padding-right: 10px;
294
+ }
295
+ .tag {
296
+ background: #ff8320;
297
+ color: #fff;
298
+ }
299
+ }
300
+ .rule {
301
+ color: #353535;
302
+ opacity: 0.5;
303
+ }
304
+ }
305
+ .bean-counts {
306
+ margin-top: 5px;
307
+ .counts {
308
+ color: #3d3835;
309
+ font-size: 32px;
310
+ font-weight: 700;
311
+ }
312
+ .pay {
313
+ padding: 0 20px;
314
+ height: 32px;
315
+ line-height: 32px;
316
+ background: linear-gradient(
317
+ 187.18deg,
318
+ #353535 10.04%,
319
+ #433f46 90.21%
320
+ );
321
+ border-radius: 16px;
322
+ color: #e7caad;
323
+ font-size: 15px;
324
+ font-weight: 500;
325
+ }
326
+ }
327
+ }
328
+ .line {
329
+ height: 3px;
330
+ width: 100%;
331
+ margin: 10px 0;
332
+ background: linear-gradient(90deg, #e7c39f 0.84%, #e6c9ad 27.74%);
333
+ }
334
+ .small-clound-bean {
335
+ margin-top: 20px;
336
+ .bean-list {
337
+ margin-top: 8px;
338
+ display: flex;
339
+ flex-wrap: wrap;
340
+ &-item {
341
+ width: 50%;
342
+ line-height: 23px;
343
+ padding-left: 10px;
344
+ box-sizing: border-box;
345
+ margin-bottom: 10px;
346
+ .counts {
347
+ color: #353535;
348
+ font-size: 20px;
349
+ font-weight: 700;
350
+ }
351
+ .title {
352
+ color: #987356;
353
+ font-weight: 400;
354
+ font-size: 11px;
355
+ }
356
+ }
357
+ &-item:nth-child(2n) {
358
+ padding-left: 30px;
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ .operation-title {
365
+ padding: 10px 15px;
366
+ background: #fff;
367
+ position: sticky;
368
+ z-index: 10;
369
+ top: 0;
370
+ .text {
371
+ color: #353535;
372
+ font-size: 12px;
373
+ opacity: 0.5;
374
+ }
375
+ .time-icon {
376
+ display: block;
377
+ font-size: 0;
378
+ width: 12px;
379
+ height: 12px;
380
+ margin-left: 4px;
381
+ }
382
+ .search-time {
383
+ display: flex;
384
+ align-items: center;
385
+ .title {
386
+ color: #000;
387
+ font-weight: 500;
388
+ font-size: 17px;
389
+ margin-right: 10px;
390
+ }
391
+ .time {
392
+ flex: 1;
393
+ display: flex;
394
+ align-items: center;
395
+ }
396
+ }
397
+ .search {
398
+ display: flex;
399
+ align-items: center;
400
+ }
401
+ }
402
+ .operation-list {
403
+ margin: 0 15px;
404
+ .box {
405
+ &-detail {
406
+ .title {
407
+ line-height: 22px;
408
+ font-weight: 700;
409
+ font-size: 12px;
410
+ color: #000;
411
+ opacity: 0.5;
412
+ margin-bottom: 10px;
413
+ }
414
+ .item {
415
+ box-shadow: 0px 5px 18px 2px #00000029;
416
+ border-radius: 5px;
417
+ padding: 12px 10px;
418
+ display: flex;
419
+ margin-bottom: 10px;
420
+ &-type {
421
+ background: linear-gradient(
422
+ 113.95deg,
423
+ #f4e2ce 1.2%,
424
+ #debb9b 77.63%
425
+ );
426
+ width: 30px;
427
+ height: 30px;
428
+ border-radius: 15px;
429
+ margin-right: 15px;
430
+ line-height: 30px;
431
+ font-size: 10px;
432
+ font-weight: 500;
433
+ color: #000;
434
+ text-align: center;
435
+ }
436
+ &-detail {
437
+ flex: 1;
438
+ .item-info {
439
+ padding: 0;
440
+ font-size: 14px;
441
+ font-weight: 700;
442
+ color: #000;
443
+ &-type {
444
+ line-height: 15px;
445
+ }
446
+ &-title {
447
+ font-weight: 400;
448
+ opacity: 0.8;
449
+ font-size: 11px;
450
+ }
451
+ &-amount {
452
+ color: #9e7b5a;
453
+ }
454
+ }
455
+ &-remark {
456
+ opacity: 0.3;
457
+ line-height: 15px;
458
+ font-size: 10px;
459
+ }
460
+ }
461
+ }
462
+ }
463
+ &-not-text {
464
+ opacity: 0.4;
465
+ color: #353535;
466
+ font-size: 12px;
467
+ line-height: 20px;
468
+ margin: 0 auto 40px;
469
+ text-align: center;
470
+ }
471
+ }
472
+ &-not {
473
+ display: flex;
474
+ flex-direction: column;
475
+ justify-content: center;
476
+ align-items: center;
477
+ margin-top: 80px;
478
+ &-img {
479
+ display: block;
480
+ font-size: 0;
481
+ width: 144px;
482
+ height: 80px;
483
+ }
484
+ &-text {
485
+ opacity: 0.4;
486
+ color: #353535;
487
+ font-size: 12px;
488
+ line-height: 28px;
489
+ }
490
+ }
491
+ }
492
+ }
493
+ .back-to-top {
494
+ width: 38px;
495
+ height: 38px;
496
+ border-radius: 19px;
497
+ position: fixed;
498
+ right: 15px;
499
+ bottom: 100px;
500
+ background: #FFF2E5;
501
+ display: flex;
502
+ align-items: center;
503
+ justify-content: center;
504
+ &-icon {
505
+ display: block;
506
+ font-size: 0;
507
+ width: 19px;
508
+ height: 19px;
509
+ }
510
+ }
511
+
512
+ .consumption-rules-popup {
513
+ border-radius: 16px;
514
+ width: 70%;
515
+ height: 70%;
516
+ padding: 24px;
517
+ }
518
+ </style>
519
+ ../../payment/services/remind-insufficient
@@ -0,0 +1,181 @@
1
+ <template>
2
+ <div class="account-card">
3
+ <div class="card">
4
+ <div class="card-row">
5
+ <div class="card-row-left">
6
+ <div class="bean-box">
7
+ <div class="bean-icon-box">
8
+ <img class="bean-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/gold-bean.png" />
9
+ </div>
10
+ <span class="baan-name">云豆</span>
11
+ </div>
12
+ <div class="bean-nums">{{ balance.total }}</div>
13
+ </div>
14
+ <div class="card-row-right">
15
+ <div class="account-info-entry" @click="gotoDetail">
16
+ <div class="account-info-name">账户明细</div>
17
+ <div class="account-info-icon">
18
+ <img class="icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/gold-to.png" />
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ <div class="line"></div>
24
+ <div class="card-row">
25
+ <div class="card-row-left desc">仅云豆可充值,小云豆为平台赠送</div>
26
+ <div class="card-row-right">
27
+ <div class="pay" @click="gotoRecharge">
28
+ <div>充值</div>
29
+ <img class="pay-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/bean-right.png" />
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { onMounted, ref } from 'vue'
39
+ import { endpoints, makeHttp } from '../api'
40
+ import { Balance } from '../types'
41
+
42
+ const balance = ref<Balance>({
43
+ total: 0,
44
+ privileges: []
45
+ })
46
+
47
+ const gotoRecharge = () => {
48
+ emit('recharge')
49
+ }
50
+
51
+ async function loadBalance () {
52
+ const $http = makeHttp()
53
+ $http.get<Balance>(endpoints.getBalance, {
54
+ }).then(data => {
55
+ balance.value = data
56
+ })
57
+ }
58
+
59
+ const emit = defineEmits([
60
+ /**
61
+ * 跳账户详情
62
+ */
63
+ 'drill',
64
+ /**
65
+ * 跳充值页
66
+ */
67
+ 'recharge'
68
+ ])
69
+
70
+ function gotoDetail () {
71
+ emit('drill')
72
+ }
73
+
74
+ onMounted(() => {
75
+ loadBalance()
76
+ })
77
+
78
+ </script>
79
+
80
+ <style lang="scss">
81
+ .account-card{
82
+ .card{
83
+ background: #2F2F2F;
84
+ border-radius: 10px;
85
+ padding: 13px 20px;
86
+ margin: 0;
87
+ .card-row{
88
+ display: flex;
89
+ justify-content: space-between;
90
+ align-items: center;
91
+ .card-row-left{
92
+ display: flex;
93
+ flex-direction: column;
94
+ .bean-box{
95
+ display: flex;
96
+ align-items: center;
97
+ .bean-icon-box{
98
+ width: 20px;
99
+ height: 20px;
100
+ margin-right: 8px;
101
+ .bean-icon{
102
+ display: block;
103
+ font-size: 0;
104
+ width: 100%;
105
+ height: 100%;
106
+ }
107
+ }
108
+ .baan-name{
109
+ color: #F3D59D;
110
+ font-weight: 600;
111
+ font-size: 11px;
112
+ }
113
+ }
114
+ .bean-nums{
115
+ color: #fff;
116
+ line-height: 22px;
117
+ font-weight: 500;
118
+ font-size: 16px;
119
+ margin-top: 3px;
120
+ }
121
+ }
122
+ .desc{
123
+ font-size: 10px;
124
+ color: #ccc;
125
+ line-height: 14px;
126
+ }
127
+ }
128
+ .line{
129
+ margin: 6px 0px 8px 0px;
130
+ height: 1px;
131
+ background: #C3C3C3;
132
+ opacity: 0.2;
133
+ }
134
+ .card-row-right{
135
+ .pay{
136
+ padding: 0 8px;
137
+ line-height: 18px;
138
+ color: #FFD6A5;
139
+ border: 1px solid #FFD6A5;
140
+ border-radius: 9px;
141
+ font-size: 12px;
142
+ display: flex;
143
+ align-items: center;
144
+ .pay-icon{
145
+ display: block;
146
+ font-size: 0;
147
+ width: 3px;
148
+ height: 6px;
149
+ margin-left: 6px;
150
+ }
151
+ }
152
+ .account-info-entry{
153
+ display: flex;
154
+ align-items: center;
155
+ padding: 0 10px;
156
+ height: 28px;
157
+ line-height: 28px;
158
+ border-radius: 14px;
159
+ background: linear-gradient(90deg, #FFEBC1 0%, #FFD7A7 52.29%, #FFB875 100%);
160
+ .account-info-name{
161
+ color: #975213;
162
+ font-size: 13px;
163
+ font-weight: 500;
164
+ margin-right: 8px;
165
+ }
166
+ .account-info-icon{
167
+ width: 14px;
168
+ height: 14px;
169
+ border-radius: 7px;
170
+ .icon{
171
+ display: block;
172
+ font-size: 0;
173
+ width: 100%;
174
+ height: 100%;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ </style>