@uxda/appkit 4.3.39 → 4.3.42

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 (141) hide show
  1. package/.cursor/skills/appkit-build-update-component-rules/SKILL.md +54 -54
  2. package/.cursor/skills/appkit-sync-component-rules/SKILL.md +60 -60
  3. package/.eslintrc.mjs +7 -7
  4. package/Appkit/347/273/204/344/273/266/344/275/277/347/224/250/350/247/204/345/210/231.md +2002 -2002
  5. package/PROJECT_DOCS.md +150 -142
  6. package/README.md +194 -194
  7. package/babel.config.js +12 -12
  8. package/dist/appkit.css +11 -6
  9. package/dist/index.js +30 -16
  10. package/package.json +82 -82
  11. package/project.config.json +15 -15
  12. package/project.tt.json +13 -13
  13. package/rollup.config.mjs +81 -81
  14. package/src/Appkit.ts +72 -72
  15. package/src/balance/api/endpoints.ts +134 -134
  16. package/src/balance/api/index.ts +118 -118
  17. package/src/balance/components/AccountView.vue +850 -834
  18. package/src/balance/components/BalanceCard.vue +210 -210
  19. package/src/balance/components/BalanceReminder.vue +84 -84
  20. package/src/balance/components/ConsumptionFilter.vue +218 -218
  21. package/src/balance/components/ConsumptionRules.vue +68 -68
  22. package/src/balance/components/DateFilter.vue +259 -259
  23. package/src/balance/components/DateRange.vue +111 -111
  24. package/src/balance/components/ListFilter.vue +62 -62
  25. package/src/balance/components/ListFilterPicker.vue +191 -191
  26. package/src/balance/components/PromoterCard.vue +308 -308
  27. package/src/balance/components/SecondBalance.vue +77 -77
  28. package/src/balance/components/Tip.vue +45 -45
  29. package/src/balance/components/index.ts +8 -8
  30. package/src/balance/types.ts +99 -99
  31. package/src/components/bt-cropper/index.vue +730 -730
  32. package/src/components/bt-cropper/utils/calcCropper.js +42 -42
  33. package/src/components/bt-cropper/utils/calcImagePosition.js +23 -23
  34. package/src/components/bt-cropper/utils/calcImageSize.js +37 -37
  35. package/src/components/bt-cropper/utils/calcPointDistance.js +12 -12
  36. package/src/components/bt-cropper/utils/calcRightAndBottom.js +7 -7
  37. package/src/components/bt-cropper/utils/ratio.js +3 -3
  38. package/src/components/bt-cropper/utils/tools.js +25 -25
  39. package/src/components/dd-area/index.vue +225 -225
  40. package/src/components/dd-icon/doc.md +21 -21
  41. package/src/components/dd-icon/index.vue +23 -23
  42. package/src/components/dd-notice-bar/index.vue +78 -78
  43. package/src/components/dd-search/doc.md +34 -34
  44. package/src/components/dd-search/index.vue +168 -168
  45. package/src/components/dd-selector/index.vue +124 -124
  46. package/src/components/dd-skeleton/doc.md +19 -19
  47. package/src/components/dd-skeleton/index.vue +36 -36
  48. package/src/global.ts +6 -6
  49. package/src/index.ts +101 -101
  50. package/src/main.scss +1 -1
  51. package/src/notice/api/endpoints.ts +54 -54
  52. package/src/notice/api/index.ts +121 -121
  53. package/src/notice/components/NoticeBanner.vue +247 -247
  54. package/src/notice/components/NoticeEntry.vue +99 -99
  55. package/src/notice/components/NoticeList.vue +311 -311
  56. package/src/notice/components/NoticeList2.vue +401 -401
  57. package/src/notice/components/NoticePopup.vue +163 -163
  58. package/src/notice/components/index.ts +6 -6
  59. package/src/notice/components/useCommonList.ts +87 -87
  60. package/src/notice/components/useNotice.ts +35 -35
  61. package/src/notice/index.ts +1 -1
  62. package/src/notice/types.ts +25 -25
  63. package/src/payment/api/config.ts +7 -7
  64. package/src/payment/api/endpoints.ts +112 -112
  65. package/src/payment/api/index.ts +108 -108
  66. package/src/payment/components/AmountPicker.vue +56 -56
  67. package/src/payment/components/RechargeResult.vue +68 -68
  68. package/src/payment/components/RechargeView.vue +420 -420
  69. package/src/payment/components/RightsPicker.vue +105 -105
  70. package/src/payment/components/TradeView.vue +627 -627
  71. package/src/payment/components/UserAgreement.vue +234 -234
  72. package/src/payment/components/index.ts +22 -22
  73. package/src/payment/components/recharge-amount.spec.ts +54 -54
  74. package/src/payment/components/recharge-amount.ts +67 -67
  75. package/src/payment/index.ts +5 -5
  76. package/src/payment/services/index.ts +16 -16
  77. package/src/payment/services/invoke-recharge.ts +25 -25
  78. package/src/payment/services/request-payment.ts +136 -136
  79. package/src/payment/types.ts +34 -34
  80. package/src/register/components/SelfRegistration.vue +233 -233
  81. package/src/register/components/index.ts +2 -2
  82. package/src/scenarios/components/SharePoster.vue +364 -364
  83. package/src/scenarios/components/index.ts +2 -2
  84. package/src/scenarios/components/poster-paste.vue +93 -93
  85. package/src/scenarios/components/share-poster.md +273 -273
  86. package/src/shared/components/AppDrawer.vue +53 -53
  87. package/src/shared/components/AppVerify.vue +137 -137
  88. package/src/shared/components/DeviceVersion.vue +78 -78
  89. package/src/shared/components/EmptyView.vue +33 -33
  90. package/src/shared/components/OcrBank.vue +202 -202
  91. package/src/shared/components/OcrBusinessLicense.vue +120 -120
  92. package/src/shared/components/OcrIcon.vue +267 -267
  93. package/src/shared/components/OcrInvoice.vue +323 -323
  94. package/src/shared/components/OfficeDocx.vue +33 -33
  95. package/src/shared/components/OfficePdf.vue +35 -35
  96. package/src/shared/components/PageHeader.vue +84 -84
  97. package/src/shared/components/index.ts +12 -12
  98. package/src/shared/composables/index.ts +10 -10
  99. package/src/shared/composables/useAmount.ts +46 -46
  100. package/src/shared/composables/useCompress.ts +64 -64
  101. package/src/shared/composables/useCountdown.ts +46 -46
  102. package/src/shared/composables/useCrypto.ts +76 -76
  103. package/src/shared/composables/useDeviceEnv.ts +61 -61
  104. package/src/shared/composables/useDragBox.ts +97 -97
  105. package/src/shared/composables/useEncode.ts +43 -43
  106. package/src/shared/composables/useLogger.ts +149 -149
  107. package/src/shared/composables/useSafeArea.ts +46 -46
  108. package/src/shared/composables/useTabbar.ts +24 -24
  109. package/src/shared/composables/useUpload.ts +106 -106
  110. package/src/shared/composables/useValidator.ts +32 -32
  111. package/src/shared/composables/useWxAuth.ts +49 -49
  112. package/src/shared/http/Http.ts +149 -149
  113. package/src/shared/http/index.ts +1 -1
  114. package/src/shared/http/types.ts +163 -163
  115. package/src/shared/index.ts +9 -9
  116. package/src/shared/tracking/directives/index.ts +40 -40
  117. package/src/shared/tracking/examples/page-tracking-template.vue +27 -27
  118. package/src/shared/weixin/index.ts +9 -9
  119. package/src/shared/weixin/jssdk.ts +104 -104
  120. package/src/shared/weixin/payment.ts +38 -38
  121. package/src/styles/vars.scss +3 -3
  122. package/src/user/api/endpoints.ts +17 -17
  123. package/src/user/api/index.ts +123 -123
  124. package/src/user/components/LoginSetting.vue +114 -114
  125. package/src/user/components/UserAuth.vue +218 -218
  126. package/src/user/components/UserBinding.vue +277 -277
  127. package/src/user/components/UserBindingSuccess.vue +80 -80
  128. package/src/user/components/UserEntry.vue +139 -139
  129. package/src/user/components/UserFeedback.vue +428 -428
  130. package/src/user/components/UserFeedbackEntry.vue +175 -175
  131. package/src/user/components/UserHeadCrop.vue +65 -65
  132. package/src/user/components/UserInfo.vue +711 -711
  133. package/src/user/components/UserResourceEmpty.vue +75 -75
  134. package/src/user/components/index.ts +23 -23
  135. package/src/user/index.ts +1 -1
  136. package/src/utils/utils.ts +33 -33
  137. package/tsconfig.json +30 -30
  138. package/types/global.d.ts +23 -23
  139. package/types/vue.d.ts +10 -10
  140. package/dist/assets/asset-3B_CoPto +0 -1
  141. package/dist/assets/asset-DcH8Kg-2 +0 -1
@@ -1,834 +1,850 @@
1
- <template>
2
- <div class="account-view">
3
- <div class="scroll-content">
4
- <page-header :title="Taro.getEnv() !== 'WEB' ? '我的账户' : ''" :class="{ 'with-background': scrolled > 0 }"
5
- @close="onPageHeaderClose" />
6
- <div class="row jusify-right">
7
- <div class="small-bean-button" v-track-click @click="onSecondBalanceButtonClick">
8
- <label class="label">收支明细</label>
9
- </div>
10
- </div>
11
- <div class="balance">
12
- <div class="bean-box spa-between">
13
- <div class="bean-img">
14
- <img class="bean-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/gold-bean.png" />
15
- <div class="bean-tag tag">云豆</div>
16
- </div>
17
- <div v-if="!isAppEnv || (isAppEnv && !isIOS())" class="rule" v-track-click @click="rulesPopupOpen = true">规则说明</div>
18
- </div>
19
- <div class="bean-counts spa-between">
20
- <div class="counts number">{{ formatAmount(balance.total || 0) }}</div>
21
- <div v-if="!isAppEnv || (isAppEnv && !isIOS())" class="pay" v-track-click @click="gotoRecharge">云豆充值</div>
22
- </div>
23
- </div>
24
- <Tip />
25
- <!-- <div class="rights-card" v-if="bdxLiteRight">
26
- <div class="title">风控个人风险Lite权益</div>
27
- <div class="list">
28
- <div class="item star-item">
29
- <div class="item-count">
30
- <span>{{ formatAmount(bdxLiteRight.count || 0) }}</span><span>{{ bdxLiteRight.unit }}</span>
31
- </div>
32
- <div class="item-title">
33
- <div>{{ bdxLiteRight.title }}次数</div>
34
- <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
35
- <div v-track-click @click="gotoTrade(bdxLiteRight)">风控个人风险Lite充值</div>
36
- <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
37
- </div>
38
- </div>
39
- </div>
40
- </div>
41
- </div> -->
42
- <div class="rights-card" v-if="bdxProRight">
43
- <div class="title">风控个人风险Pro权益</div>
44
- <div class="list">
45
- <div class="item star-item">
46
- <div class="item-count">
47
- <span>{{ formatAmount(bdxProRight.count || 0) }}</span><span>{{ bdxProRight.unit }}</span>
48
- </div>
49
- <div class="item-title">
50
- <div>{{ bdxProRight.title }}次数</div>
51
- <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
52
- <div v-track-click @click="gotoTrade(bdxProRight)">风控个人风险Pro充值</div>
53
- <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
54
- </div>
55
- </div>
56
- </div>
57
- </div>
58
- </div>
59
- <div class="rights-card" v-if="bdxBillRight">
60
- <div class="title">风控流水智报权益</div>
61
- <div class="list">
62
- <div class="item star-item">
63
- <div class="item-count">
64
- <span>{{ formatAmount(bdxBillRight.count || 0) }}</span><span>{{ bdxBillRight.unit }}</span>
65
- </div>
66
- <div class="item-title">
67
- <div>{{ bdxBillRight.title }}次数</div>
68
- <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
69
- <div v-track-click @click="gotoTrade(bdxBillRight)">风控流水智报充值</div>
70
- <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- </div>
76
- <div class="rights-card" v-if="balance.privileges?.corporateStar">
77
- <div class="title">企明星权益</div>
78
- <div class="list">
79
- <div class="item star-item" v-for="(item, index) in balance.privileges.corporateStar" :key="index">
80
- <div class="item-count">
81
- <span>{{ formatAmount(item.count || 0) }}</span><span>{{ item.unit }}</span>
82
- </div>
83
- <div class="item-title">
84
- <div>{{ item.title }}次数</div>
85
- <div class="item-title-button" v-if="item.id && (!isAppEnv || (isAppEnv && !isIOS()))">
86
- <div v-track-click @click="gotoTrade(item)">企明星优惠充值</div>
87
- <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
88
- </div>
89
- </div>
90
- </div>
91
- </div>
92
- </div>
93
- <div class="rights-card" v-if="balance.privileges?.aiapprove">
94
- <div class="title">AI审批权益</div>
95
- <div class="list">
96
- <div class="item star-item" v-for="(item, index) in balance.privileges.aiapprove" :key="index">
97
- <div class="item-count">{{ formatAmount(item.count || 0) }}{{ item.unit }}</div>
98
- <div class="item-title">
99
- <div>{{ item.title }}次数</div>
100
- <div class="item-title-button" v-if="item.id && (!isAppEnv || (isAppEnv && !isIOS()))">
101
- <div v-track-click @click="gotoTrade(item)">AI审批充值</div>
102
- <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
103
- </div>
104
- </div>
105
- </div>
106
- </div>
107
- </div>
108
- <div class="rights-card" v-if="balance.privileges?.signkit">
109
- <div class="title">电子签约权益</div>
110
- <div class="list">
111
- <div class="item" v-for="(item, index) in balance.privileges.signkit" :key="index">
112
- <div class="item-count">{{ formatAmount(item.count || 0) }}{{ item.unit }}</div>
113
- <div class="item-title">{{ item.title }}次数</div>
114
- </div>
115
- </div>
116
- </div>
117
- </div>
118
- </div>
119
- <nut-popup pop-class="consumption-rules-popup" v-model:visible="rulesPopupOpen" :close-on-click-overlay="false">
120
- <consumption-rules @complete="rulesPopupOpen = false" />
121
- </nut-popup>
122
- <nut-popup position="bottom" :style="{ height: '40%' }" round :close-on-click-overlay="true"
123
- v-model:visible="datePickerOpen">
124
- <date-filter v-if="datePickerOpen" :from="filtering.dateFrom" :to="filtering.dateTo" @reset="onDateReset"
125
- @complete="onDateFilterComplete" />
126
- </nut-popup>
127
- <nut-popup position="bottom" :style="{ height: '75%' }" round :close-on-click-overlay="true"
128
- v-model:visible="filterOpen">
129
- <consumption-filter :modelValue="[
130
- filtering.账户类型,
131
- filtering.收入还是支出,
132
- filtering.交易类型,
133
- filtering.权益类目,
134
- ]" @complete="onFilterComplete" />
135
- </nut-popup>
136
- <app-drawer v-model="secondBalanceOpen" title="收支明细">
137
- <div class="operation-box">
138
- <div class="operation-title spa-between" :class="{ 'with-shadow': scrolled > 0 }">
139
- <div class="search-time">
140
- <div class="title">收支明细</div>
141
- <div class="time" @click="openDateFilter" v-show="filtering.dateFrom">
142
- <div class="text number">{{ dateRangeDisplay }}</div>
143
- <img style="margin-top: -2px" class="time-icon"
144
- src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-down.png" />
145
- </div>
146
- </div>
147
- <div class="search" v-track-click @click="filterOpen = true">
148
- <span class="text">筛选</span>
149
- <img class="time-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-select-icon.png" />
150
- </div>
151
- </div>
152
- <div class="operation-list">
153
- <ScrollView class="operation-scroll" :scroll-y="true" @scroll="onScroll" :lower-threshold="100"
154
- @scrolltolower="onReachBottom">
155
- <div class="box" v-if="consumptionGroups.length > 0">
156
- <div class="box-detail" v-for="(item, index) in consumptionGroups" :key="index">
157
- <div class="title number">{{ item.date }}</div>
158
- <div class="item" v-for="(it, i) in item.consumptions" :key="i">
159
- <div class="item-type">
160
- {{ it.交易类型 }}
161
- </div>
162
- <div class="item-detail">
163
- <div class="item-info spa-between">
164
- <div>
165
- <div class="item-info-type">
166
- {{ it.账户类型 }}
167
- </div>
168
- <div class="item-info-title">{{ it.title }}</div>
169
- </div>
170
- <div class="item-info-amount number">
171
- {{ it.收入还是支出 == '支出' ? '-' : '+' }}{{ it.amount }}
172
- </div>
173
- </div>
174
- <div class="item-detail-remark">{{ it.description }}</div>
175
- </div>
176
- </div>
177
- </div>
178
- <div class="box-not-text" v-if="reachedLastPage">没有更多了</div>
179
- </div>
180
- <empty-view v-else></empty-view>
181
- </ScrollView>
182
- </div>
183
- </div>
184
- </app-drawer>
185
- </template>
186
-
187
- <script lang="ts" setup>
188
- import Taro, { useDidShow, showLoading, hideLoading } from '@tarojs/taro'
189
- import { computed, onMounted, reactive, ref, watch } from 'vue'
190
- import { endpoints, useHttp } from '../api'
191
- import { 账户流水筛选项, Balance, ConsumptionGroup, 账户流水 } from '../types'
192
- import ConsumptionFilter from './ConsumptionFilter.vue'
193
- import DateFilter from './DateFilter.vue'
194
- import ConsumptionRules from './ConsumptionRules.vue'
195
- import { AppDrawer, PageHeader, WithPaging } from '../../shared'
196
- import dayjs from 'dayjs'
197
- import EmptyView from '../../shared/components/EmptyView.vue'
198
- import Tip from './Tip.vue'
199
- import groupBy from 'lodash-es/groupBy'
200
- import { useAmount } from '../../shared/composables/useAmount'
201
- import { ScrollView } from '@tarojs/components'
202
- import { isApp } from '../../utils/utils'
203
- import { isIOS } from '../../shared/composables/useDeviceEnv'
204
-
205
- type AccountViewProps = {
206
- app: string
207
- }
208
- const props = withDefaults(defineProps<AccountViewProps>(), {
209
- app: '',
210
- })
211
-
212
- const refreshing = ref(false)
213
- const { formatAmount } = useAmount()
214
- const emit = defineEmits(['recharge', 'trade'])
215
-
216
- const filterOpen = ref<boolean>(false)
217
-
218
- // 规则说明弹窗
219
- const rulesPopupOpen = ref<boolean>(false)
220
-
221
- const filtering = reactive<账户流水筛选项>({
222
- 账户类型: '全部',
223
- 收入还是支出: '全部',
224
- 交易类型: '全部',
225
- 权益类目: '',
226
- dateFrom: '',
227
- dateTo: '',
228
- page: 1,
229
- pageSize: 20,
230
- })
231
-
232
- const reachedLastPage = ref<boolean>(false)
233
-
234
- /**
235
- * 全新搜索
236
- * 重置某些查询条件
237
- */
238
- function restartSearch() {
239
- // 从第一页开始
240
- filtering.page = 1
241
- consumptionGroups.value = []
242
- loadConsumptions()
243
- }
244
-
245
- // 时间筛选
246
- const datePickerOpen = ref<boolean>(false)
247
-
248
- function openDateFilter() {
249
- datePickerOpen.value = true
250
- }
251
-
252
- const dateRangeDisplay = computed(() => {
253
- let startTime = (filtering.dateFrom || '').replace(/-/g, '.').substring(2)
254
- let endTime = (filtering.dateTo || '').replace(/-/g, '.').substring(2)
255
- return startTime + ' - ' + endTime
256
- })
257
-
258
- const consumptionGroups = ref<ConsumptionGroup[]>([])
259
-
260
- /**
261
- * 余额数据
262
- */
263
- const balance = ref<Balance>({
264
- total: 0,
265
- privileges: {},
266
- })
267
-
268
- const activitykitPrivileges = computed(
269
- () => balance.value.privileges?.activitykit ?? [],
270
- )
271
- // const bdxLiteRight = computed(() =>
272
- // activitykitPrivileges.value.find((item: any) => item.code === 'bdxLiteQuery'),
273
- // )
274
- const bdxProRight = computed(() =>
275
- activitykitPrivileges.value.find((item: any) => item.code === 'bdxProQuery'),
276
- )
277
- const bdxBillRight = computed(() =>
278
- activitykitPrivileges.value.find((item: any) => item.code === 'bdxBillQuery'),
279
- )
280
-
281
- useDidShow(() => {
282
- if (Taro.getEnv() !== 'WEB') {
283
- Taro.setNavigationBarTitle({
284
- title: '我的账户',
285
- })
286
- }
287
- loadBalance()
288
- })
289
-
290
- function groupDataByDate(data: 账户流水[]): ConsumptionGroup[] {
291
- // 按照日期分组
292
- const groups: ConsumptionGroup[] = consumptionGroups.value || []
293
- // [
294
- // date: '2023-10-1',
295
- // consumptions: []
296
- // ]
297
- // 组装成按日期分组
298
- data.forEach((d) => {
299
- const date = dayjs(d.time).format('YYYY-MM-DD')
300
- let group: ConsumptionGroup | undefined = groups.find((g) => g.date === date)
301
- if (!group) {
302
- group = {
303
- date,
304
- consumptions: [],
305
- }
306
- groups.push(group)
307
- }
308
- group.consumptions.push(d)
309
- })
310
- groups.sort((a, b) => (a.date > b.date ? -1 : 1))
311
- return groups
312
- }
313
-
314
- /**
315
- * 请求账户流水
316
- * @param append 搜索结果累加 上拉分页时
317
- */
318
- async function loadConsumptions(append: boolean = false) {
319
- if (!append) {
320
- consumptionGroups.value = []
321
- }
322
- const $http = useHttp()
323
- showLoading({
324
- title: `加载中...`,
325
- mask: true,
326
- })
327
- $http
328
- .get<WithPaging<账户流水[]>>(endpoints.获取账户流水, {
329
- app: props.app,
330
- ...filtering,
331
- })
332
- .then((response) => {
333
- consumptionGroups.value = groupDataByDate(response.data)
334
- if (filtering.page >= response.totalPages) {
335
- filtering.page = response.totalPages
336
- reachedLastPage.value = true
337
- } else {
338
- reachedLastPage.value = false
339
- }
340
- }).finally(() => {
341
- hideLoading()
342
- })
343
- }
344
-
345
- /**
346
- * 获取账户余额明细
347
- */
348
- async function loadBalance() {
349
- const $http = useHttp()
350
- $http
351
- .get<Balance>(endpoints.获取余额明细, {
352
- app: props.app,
353
- })
354
- .then((data) => {
355
- const { privileges, total } = data
356
- const filterData = {
357
- total,
358
- privileges: groupBy(privileges, 'appCode'),
359
- }
360
- balance.value = filterData
361
- })
362
- }
363
-
364
- const onFilterComplete = (value) => {
365
- filtering.账户类型 = value[0]
366
- filtering.收入还是支出 = value[1]
367
- filtering.交易类型 = value[2]
368
- filtering.权益类目 = value[3]
369
- filterOpen.value = false
370
- restartSearch()
371
- }
372
-
373
- const onDateFilterComplete = (value) => {
374
- filtering.dateFrom = value.from
375
- filtering.dateTo = value.to
376
- datePickerOpen.value = false
377
- restartSearch()
378
- }
379
-
380
- function gotoRecharge() {
381
- emit('recharge')
382
- }
383
-
384
- function gotoTrade(item: any) {
385
- emit('trade', item)
386
- }
387
-
388
- function loadNextPage() {
389
- filtering.page++
390
- loadConsumptions(true)
391
- }
392
-
393
- // 以下这一大段处理下拉刷新、上滑分页以及弹窗与页面滑动的逻辑
394
- const scrolled = ref<number>(0)
395
-
396
- /**
397
- * 记录 scroll-view 滚动的位置
398
- */
399
- const onScroll = (e) => {
400
- const { scrollTop } = e
401
- scrolled.value = scrollTop
402
- }
403
-
404
- /**
405
- * 下拉刷新 pull down refresh
406
- */
407
- const onPullDownRefresh = () => {
408
- refreshing.value = true
409
- // 重新请求余额数据
410
- loadBalance()
411
- setTimeout(() => {
412
- refreshing.value = false
413
- }, 500)
414
- }
415
-
416
- /**
417
- * 滑动到底部请求下一页并合并查询结果
418
- */
419
- const onReachBottom = () => {
420
- console.log('到底了')
421
- if (reachedLastPage.value) {
422
- return false
423
- }
424
- loadNextPage()
425
- }
426
-
427
- const secondBalanceOpen = ref<boolean>(false)
428
-
429
- function onSecondBalanceButtonClick() {
430
- secondBalanceOpen.value = true
431
- loadConsumptions()
432
- }
433
-
434
- watch(secondBalanceOpen, () => {
435
- if (Taro.getEnv() !== 'WEB') {
436
- Taro.setNavigationBarColor({
437
- frontColor: secondBalanceOpen.value ? '#000000' : '#ffffff',
438
- backgroundColor: '#ffffff',
439
- animation: {
440
- duration: 400,
441
- timingFunc: 'easeIn',
442
- },
443
- })
444
- }
445
- })
446
-
447
- function onDateReset() {
448
- resetDateRange()
449
- datePickerOpen.value = false
450
- restartSearch()
451
- }
452
-
453
- /**
454
- * 充值筛选的起止时间
455
- */
456
- function resetDateRange() {
457
- // 筛选的起止时间
458
- filtering.dateTo = dayjs().format('YYYY-MM-DD')
459
- filtering.dateFrom = dayjs().add(-3, 'M').format('YYYY-MM-DD')
460
- }
461
-
462
- function onPageHeaderClose() {
463
- Taro.navigateBack({
464
- delta: 1,
465
- })
466
- }
467
-
468
- const isAppEnv = computed(() => {
469
- return isApp()
470
- })
471
-
472
- onMounted(() => {
473
- resetDateRange()
474
- })
475
- </script>
476
-
477
- <style lang="scss">
478
- .account-view {
479
- height: 100vh;
480
-
481
- .scroll-content {
482
- background-image: url('https://cdn.ddjf.com/static/images/customer-center/blue-bg.png');
483
- background-position: center 0;
484
- background-repeat: no-repeat;
485
- background-size: 100% 200px;
486
- }
487
-
488
- .page-header {
489
- background-color: transparent;
490
- position: sticky;
491
- top: 0;
492
- z-index: 1;
493
- transition: background-color 0.3s;
494
-
495
- &.with-background {
496
- background-color: #3b393c;
497
- color: #fff;
498
- }
499
- }
500
-
501
- .spa-between {
502
- display: flex;
503
- justify-content: space-between;
504
- align-items: center;
505
- }
506
-
507
- .row {
508
- display: flex;
509
- flex-direction: row;
510
- padding: 10px 15px;
511
- }
512
-
513
- .jusify-right {
514
- justify-content: flex-end;
515
- }
516
-
517
- .small-bean-button {
518
- height: 22px;
519
- border-radius: 11px;
520
- background-color: #fff;
521
- display: inline-flex;
522
- align-items: center;
523
- padding: 0 10px;
524
- color: #353535;
525
- font-size: 12px;
526
-
527
- .label {
528
- background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEwIDZMMTYgMTJMMTAgMThWNloiIGZpbGw9IiMzNTM1MzUiIHN0cm9rZT0iIzM1MzUzNSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo=');
529
- padding-right: 18px;
530
- background-repeat: no-repeat;
531
- background-position: right center;
532
- background-size: 16px;
533
- }
534
- }
535
-
536
- .balance {
537
- border-radius: 15px;
538
- background: linear-gradient(90deg, #FFEBC1 0%, #FFB875 100%);
539
- height: 112px;
540
- padding: 20px;
541
- margin: 0 15px;
542
- box-sizing: border-box;
543
- font-size: 10px;
544
-
545
- .bean-img {
546
- display: flex;
547
- justify-content: flex-start;
548
- align-items: center;
549
-
550
- .bean-icon {
551
- display: block;
552
- font-size: 0;
553
- width: 20px;
554
- height: 20px;
555
- margin-right: 4px;
556
- }
557
-
558
- .bean-tag {
559
- color: #353535;
560
- height: 15px;
561
- line-height: 15px;
562
- border-radius: 30px 50px 50px 0px;
563
- background: rgba(#ff8320, 0.3);
564
- padding-left: 5px;
565
- padding-right: 10px;
566
- }
567
-
568
- .tag {
569
- background: #ff8320;
570
- color: #fff;
571
- }
572
- }
573
-
574
- .rule {
575
- color: #353535;
576
- opacity: 0.5;
577
- }
578
- }
579
-
580
- .bean-counts {
581
- margin-top: 12px;
582
-
583
- .counts {
584
- color: #3d3835;
585
- font-size: 32px;
586
- font-weight: 700;
587
- }
588
-
589
- .pay {
590
- padding: 0 20px;
591
- height: 32px;
592
- line-height: 32px;
593
- background: linear-gradient(187.18deg, #353535 10.04%, #433f46 90.21%);
594
- border-radius: 16px;
595
- color: #e7caad;
596
- font-size: 15px;
597
- font-weight: 500;
598
- }
599
- }
600
- }
601
-
602
- .consumption-rules-popup {
603
- border-radius: 16px;
604
- width: 70%;
605
- max-height: 80%;
606
- padding: 24px;
607
- }
608
-
609
- .operation-box {
610
- width: 100vw;
611
- overflow: hidden;
612
- display: flex;
613
- flex-direction: column;
614
- height: calc(100vh - 87px);
615
-
616
- .operation-title {
617
- padding: 10px 15px;
618
- background: #fff;
619
- transition: box-shadow 0.3s;
620
-
621
- &.with-shadow {
622
- box-shadow: 0px 1px 10px 0px #99999933;
623
- }
624
-
625
- .text {
626
- color: #353535;
627
- font-size: 12px;
628
- opacity: 0.5;
629
- }
630
-
631
- .time-icon {
632
- display: block;
633
- font-size: 0;
634
- width: 12px;
635
- height: 12px;
636
- margin-left: 4px;
637
- }
638
-
639
- .search-time {
640
- display: flex;
641
- align-items: center;
642
-
643
- .title {
644
- color: #000;
645
- font-weight: 500;
646
- font-size: 17px;
647
- margin-right: 10px;
648
- }
649
-
650
- .time {
651
- height: 22px;
652
- padding-right: 5px;
653
- flex: 1;
654
- display: flex;
655
- align-items: center;
656
- }
657
- }
658
-
659
- .search {
660
- display: flex;
661
- align-items: center;
662
- height: 22px;
663
- padding-left: 5px;
664
- }
665
- }
666
-
667
- .spa-between {
668
- display: flex;
669
- justify-content: space-between;
670
- align-items: center;
671
- }
672
-
673
- .operation-list {
674
- flex: 1;
675
- width: 100%;
676
-
677
- .operation-scroll {
678
- height: calc(100vh - 132px);
679
- box-sizing: border-box;
680
- }
681
-
682
- .box {
683
- padding: 0 10px;
684
-
685
- &-detail {
686
- .title {
687
- line-height: 22px;
688
- font-weight: 700;
689
- font-size: 12px;
690
- color: #000;
691
- opacity: 0.5;
692
- margin-bottom: 10px;
693
- }
694
-
695
- .item {
696
- border-radius: 5px;
697
- background: rgba(255, 255, 255, 0.5);
698
- box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.05);
699
- border-radius: 5px;
700
- padding: 12px 10px;
701
- display: flex;
702
- margin-bottom: 10px;
703
-
704
- &-type {
705
- background: linear-gradient(113.95deg, #f4e2ce 1.2%, #debb9b 77.63%);
706
- width: 30px;
707
- height: 30px;
708
- border-radius: 15px;
709
- margin-right: 15px;
710
- line-height: 30px;
711
- font-size: 10px;
712
- font-weight: 500;
713
- color: #000;
714
- text-align: center;
715
- }
716
-
717
- &-detail {
718
- flex: 1;
719
-
720
- .item-info {
721
- padding: 0;
722
- font-size: 14px;
723
- font-weight: 700;
724
- color: #000;
725
-
726
- &-type {
727
- line-height: 15px;
728
- }
729
-
730
- &-title {
731
- font-weight: 400;
732
- opacity: 0.8;
733
- font-size: 11px;
734
- }
735
-
736
- &-amount {
737
- color: #9e7b5a;
738
- }
739
- }
740
-
741
- &-remark {
742
- opacity: 0.3;
743
- line-height: 15px;
744
- font-size: 10px;
745
- }
746
- }
747
- }
748
- }
749
-
750
- &-not-text {
751
- opacity: 0.4;
752
- color: #353535;
753
- font-size: 12px;
754
- line-height: 20px;
755
- margin: 0 auto 40px;
756
- text-align: center;
757
- }
758
- }
759
- }
760
- }
761
-
762
- .rights-card {
763
- margin: 10px 15px 0px;
764
- background: rgb(255, 248, 243, 0.8);
765
- border-radius: 5px;
766
- padding: 15px 20px;
767
- box-shadow: 0px 5px 18.9px 2px #0000000D;
768
-
769
-
770
- .title {
771
- height: 25px;
772
- line-height: 25px;
773
- background: rgba($color: #ff8320, $alpha: 0.3);
774
- border-radius: 20px 50px 50px 0px;
775
- color: #353535;
776
- font-size: 12px;
777
- display: inline-block;
778
- padding-left: 5px;
779
- padding-right: 12px;
780
- }
781
-
782
- .list {
783
- display: flex;
784
- flex-wrap: wrap;
785
-
786
- .item {
787
- width: 50%;
788
- margin-top: 15px;
789
-
790
- .item-count {
791
- font-size: 20px;
792
- color: #353535;
793
- font-weight: 700;
794
- line-height: 23px;
795
- }
796
-
797
- .item-title {
798
- line-height: 23px;
799
- color: #987356;
800
- font-size: 11px;
801
- display: flex;
802
- align-items: center;
803
-
804
- .item-title-button {
805
- padding: 0 14px;
806
- height: 27px;
807
- line-height: 27px;
808
- background: -webkit-linear-gradient(262.82deg, #353535 10.04%, #433f46 90.21%);
809
- background: linear-gradient(187.18deg, #353535 10.04%, #433f46 90.21%);
810
- border-radius: 14px;
811
- color: #e7caad;
812
- font-size: 12px;
813
- font-weight: 400;
814
- margin-left: 20px;
815
- display: flex;
816
- align-items: center;
817
-
818
- .button-icon {
819
- display: block;
820
- width: 12px;
821
- height: 12px;
822
- font-size: 0;
823
- margin-left: 4px;
824
- }
825
- }
826
- }
827
- }
828
-
829
- .star-item {
830
- width: 100%;
831
- }
832
- }
833
- }
834
- </style>
1
+ <template>
2
+ <div class="account-view">
3
+ <div class="scroll-content">
4
+ <page-header :title="Taro.getEnv() !== 'WEB' ? '我的账户' : ''" :class="{ 'with-background': scrolled > 0 }"
5
+ @close="onPageHeaderClose" />
6
+ <div class="row jusify-right">
7
+ <div class="small-bean-button" v-track-click @click="onSecondBalanceButtonClick">
8
+ <label class="label">收支明细</label>
9
+ </div>
10
+ </div>
11
+ <div class="balance">
12
+ <div class="bean-box spa-between">
13
+ <div class="bean-img">
14
+ <img class="bean-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/gold-bean.png" />
15
+ <div class="bean-tag tag">云豆</div>
16
+ </div>
17
+ <div v-if="!isAppEnv || (isAppEnv && !isIOS())" class="rule" v-track-click @click="rulesPopupOpen = true">规则说明</div>
18
+ </div>
19
+ <div class="bean-counts spa-between">
20
+ <div class="counts number">{{ formatAmount(balance.total || 0) }}</div>
21
+ <div v-if="props.app !== 'fnfundkit' && (!isAppEnv || (isAppEnv && !isIOS()))" class="pay" v-track-click @click="gotoRecharge">云豆充值</div>
22
+ </div>
23
+ </div>
24
+ <Tip />
25
+ <!-- <div class="rights-card" v-if="bdxLiteRight">
26
+ <div class="title">风控个人风险Lite权益</div>
27
+ <div class="list">
28
+ <div class="item star-item">
29
+ <div class="item-count">
30
+ <span>{{ formatAmount(bdxLiteRight.count || 0) }}</span><span>{{ bdxLiteRight.unit }}</span>
31
+ </div>
32
+ <div class="item-title">
33
+ <div>{{ bdxLiteRight.title }}次数</div>
34
+ <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
35
+ <div v-track-click @click="gotoTrade(bdxLiteRight)">风控个人风险Lite充值</div>
36
+ <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div> -->
42
+ <div class="rights-card" v-if="bdxProRight">
43
+ <div class="title">风控个人风险Pro权益</div>
44
+ <div class="list">
45
+ <div class="item star-item">
46
+ <div class="item-count">
47
+ <span>{{ formatAmount(bdxProRight.count || 0) }}</span><span>{{ bdxProRight.unit }}</span>
48
+ </div>
49
+ <div class="item-title">
50
+ <div>{{ bdxProRight.title }}次数</div>
51
+ <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
52
+ <div v-track-click @click="gotoTrade(bdxProRight)">风控个人风险Pro充值</div>
53
+ <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ <div class="rights-card" v-if="bdxBillRight">
60
+ <div class="title">风控流水智报权益</div>
61
+ <div class="list">
62
+ <div class="item star-item">
63
+ <div class="item-count">
64
+ <span>{{ formatAmount(bdxBillRight.count || 0) }}</span><span>{{ bdxBillRight.unit }}</span>
65
+ </div>
66
+ <div class="item-title">
67
+ <div>{{ bdxBillRight.title }}次数</div>
68
+ <div class="item-title-button" v-if="!isAppEnv || (isAppEnv && !isIOS())">
69
+ <div v-track-click @click="gotoTrade(bdxBillRight)">风控流水智报充值</div>
70
+ <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+ <div class="rights-card" v-if="balance.privileges?.corporateStar">
77
+ <div class="title">企明星权益</div>
78
+ <div class="list">
79
+ <div class="item star-item" v-for="(item, index) in balance.privileges.corporateStar" :key="index">
80
+ <div class="item-count">
81
+ <span>{{ formatAmount(item.count || 0) }}</span><span>{{ item.unit }}</span>
82
+ </div>
83
+ <div class="item-title">
84
+ <div>{{ item.title }}次数</div>
85
+ <div class="item-title-button" v-if="item.id && (!isAppEnv || (isAppEnv && !isIOS()))">
86
+ <div v-track-click @click="gotoTrade(item)">企明星优惠充值</div>
87
+ <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ <div class="rights-card" v-if="balance.privileges?.aiapprove">
94
+ <div class="title">AI审批权益</div>
95
+ <div class="list">
96
+ <div class="item star-item" v-for="(item, index) in balance.privileges.aiapprove" :key="index">
97
+ <div class="item-count">{{ formatAmount(item.count || 0) }}{{ item.unit }}</div>
98
+ <div class="item-title">
99
+ <div>{{ item.title }}次数</div>
100
+ <div class="item-title-button" v-if="item.id && (!isAppEnv || (isAppEnv && !isIOS()))">
101
+ <div v-track-click @click="gotoTrade(item)">AI审批充值</div>
102
+ <img class="button-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/button-hg.svg" />
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ <div class="rights-card" v-if="balance.privileges?.signkit">
109
+ <div class="title">电子签约权益</div>
110
+ <div class="list">
111
+ <div class="item" v-for="(item, index) in balance.privileges.signkit" :key="index">
112
+ <div class="item-count">{{ formatAmount(item.count || 0) }}{{ item.unit }}</div>
113
+ <div class="item-title">{{ item.title }}次数</div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ <nut-popup pop-class="consumption-rules-popup" v-model:visible="rulesPopupOpen" :close-on-click-overlay="false">
120
+ <consumption-rules @complete="rulesPopupOpen = false" />
121
+ </nut-popup>
122
+ <nut-popup position="bottom" :style="{ height: '40%' }" round :close-on-click-overlay="true"
123
+ v-model:visible="datePickerOpen">
124
+ <date-filter v-if="datePickerOpen" :from="filtering.dateFrom" :to="filtering.dateTo" @reset="onDateReset"
125
+ @complete="onDateFilterComplete" />
126
+ </nut-popup>
127
+ <nut-popup position="bottom" :style="{ height: '75%' }" round :close-on-click-overlay="true"
128
+ v-model:visible="filterOpen">
129
+ <consumption-filter :modelValue="[
130
+ filtering.账户类型,
131
+ filtering.收入还是支出,
132
+ filtering.交易类型,
133
+ filtering.权益类目,
134
+ ]" @complete="onFilterComplete" />
135
+ </nut-popup>
136
+ <app-drawer v-model="secondBalanceOpen" title="收支明细">
137
+ <div class="operation-box">
138
+ <div class="operation-title spa-between" :class="{ 'with-shadow': scrolled > 0 }">
139
+ <div class="search-time">
140
+ <div class="title">收支明细</div>
141
+ <div class="time" @click="openDateFilter" v-show="filtering.dateFrom">
142
+ <div class="text number">{{ dateRangeDisplay }}</div>
143
+ <img style="margin-top: -2px" class="time-icon"
144
+ src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-down.png" />
145
+ </div>
146
+ </div>
147
+ <div class="search" v-track-click @click="filterOpen = true">
148
+ <span class="text">筛选</span>
149
+ <img class="time-icon" src="https://cdn.ddjf.com/static/images/bpms-workBench/clound-bean-select-icon.png" />
150
+ </div>
151
+ </div>
152
+ <div class="operation-list">
153
+ <ScrollView class="operation-scroll" :scroll-y="true" @scroll="onScroll" :lower-threshold="100"
154
+ @scrolltolower="onReachBottom">
155
+ <div class="box" v-if="consumptionGroups.length > 0">
156
+ <div class="box-detail" v-for="(item, index) in consumptionGroups" :key="index">
157
+ <div class="title number">{{ item.date }}</div>
158
+ <div class="item" v-for="(it, i) in item.consumptions" :key="i">
159
+ <div class="item-type">
160
+ {{ it.交易类型 }}
161
+ </div>
162
+ <div class="item-detail">
163
+ <div class="item-info spa-between">
164
+ <div>
165
+ <div class="item-info-type">
166
+ {{ it.账户类型 }}
167
+ </div>
168
+ <div class="item-info-title">{{ it.title }}</div>
169
+ </div>
170
+ <div class="item-info-right">
171
+ <div class="item-info-amount number">
172
+ {{ it.收入还是支出 == '支出' ? '-' : '+' }}{{ it.amount }}
173
+ </div>
174
+ <div class="item-info-time number">{{ formatItemTime(it.time) }}</div>
175
+ </div>
176
+ </div>
177
+ <div class="item-detail-remark">{{ it.description }}</div>
178
+ </div>
179
+ </div>
180
+ </div>
181
+ <div class="box-not-text" v-if="reachedLastPage">没有更多了</div>
182
+ </div>
183
+ <empty-view v-else></empty-view>
184
+ </ScrollView>
185
+ </div>
186
+ </div>
187
+ </app-drawer>
188
+ </template>
189
+
190
+ <script lang="ts" setup>
191
+ import Taro, { useDidShow, showLoading, hideLoading } from '@tarojs/taro'
192
+ import { computed, onMounted, reactive, ref, watch } from 'vue'
193
+ import { endpoints, useHttp } from '../api'
194
+ import { 账户流水筛选项, Balance, ConsumptionGroup, 账户流水 } from '../types'
195
+ import ConsumptionFilter from './ConsumptionFilter.vue'
196
+ import DateFilter from './DateFilter.vue'
197
+ import ConsumptionRules from './ConsumptionRules.vue'
198
+ import { AppDrawer, PageHeader, WithPaging } from '../../shared'
199
+ import dayjs from 'dayjs'
200
+ import EmptyView from '../../shared/components/EmptyView.vue'
201
+ import Tip from './Tip.vue'
202
+ import groupBy from 'lodash-es/groupBy'
203
+ import { useAmount } from '../../shared/composables/useAmount'
204
+ import { ScrollView } from '@tarojs/components'
205
+ import { isApp } from '../../utils/utils'
206
+ import { isIOS } from '../../shared/composables/useDeviceEnv'
207
+
208
+ type AccountViewProps = {
209
+ app: string
210
+ }
211
+ const props = withDefaults(defineProps<AccountViewProps>(), {
212
+ app: '',
213
+ })
214
+
215
+ const refreshing = ref(false)
216
+ const { formatAmount } = useAmount()
217
+ const emit = defineEmits(['recharge', 'trade'])
218
+
219
+ const filterOpen = ref<boolean>(false)
220
+
221
+ // 规则说明弹窗
222
+ const rulesPopupOpen = ref<boolean>(false)
223
+
224
+ const filtering = reactive<账户流水筛选项>({
225
+ 账户类型: '全部',
226
+ 收入还是支出: '全部',
227
+ 交易类型: '全部',
228
+ 权益类目: '',
229
+ dateFrom: '',
230
+ dateTo: '',
231
+ page: 1,
232
+ pageSize: 20,
233
+ })
234
+
235
+ const reachedLastPage = ref<boolean>(false)
236
+
237
+ /**
238
+ * 全新搜索
239
+ * 重置某些查询条件
240
+ */
241
+ function restartSearch() {
242
+ // 从第一页开始
243
+ filtering.page = 1
244
+ consumptionGroups.value = []
245
+ loadConsumptions()
246
+ }
247
+
248
+ // 时间筛选
249
+ const datePickerOpen = ref<boolean>(false)
250
+
251
+ function openDateFilter() {
252
+ datePickerOpen.value = true
253
+ }
254
+
255
+ const dateRangeDisplay = computed(() => {
256
+ let startTime = (filtering.dateFrom || '').replace(/-/g, '.').substring(2)
257
+ let endTime = (filtering.dateTo || '').replace(/-/g, '.').substring(2)
258
+ return startTime + ' - ' + endTime
259
+ })
260
+
261
+ function formatItemTime(time: number) {
262
+ return dayjs(time).format('HH:mm:ss')
263
+ }
264
+
265
+ const consumptionGroups = ref<ConsumptionGroup[]>([])
266
+
267
+ /**
268
+ * 余额数据
269
+ */
270
+ const balance = ref<Balance>({
271
+ total: 0,
272
+ privileges: {},
273
+ })
274
+
275
+ const activitykitPrivileges = computed(
276
+ () => balance.value.privileges?.activitykit ?? [],
277
+ )
278
+ // const bdxLiteRight = computed(() =>
279
+ // activitykitPrivileges.value.find((item: any) => item.code === 'bdxLiteQuery'),
280
+ // )
281
+ const bdxProRight = computed(() =>
282
+ activitykitPrivileges.value.find((item: any) => item.code === 'bdxProQuery'),
283
+ )
284
+ const bdxBillRight = computed(() =>
285
+ activitykitPrivileges.value.find((item: any) => item.code === 'bdxBillQuery'),
286
+ )
287
+
288
+ useDidShow(() => {
289
+ if (Taro.getEnv() !== 'WEB') {
290
+ Taro.setNavigationBarTitle({
291
+ title: '我的账户',
292
+ })
293
+ }
294
+ loadBalance()
295
+ })
296
+
297
+ function groupDataByDate(data: 账户流水[]): ConsumptionGroup[] {
298
+ // 按照日期分组
299
+ const groups: ConsumptionGroup[] = consumptionGroups.value || []
300
+ // [
301
+ // date: '2023-10-1',
302
+ // consumptions: []
303
+ // ]
304
+ // 组装成按日期分组
305
+ data.forEach((d) => {
306
+ const date = dayjs(d.time).format('YYYY-MM-DD')
307
+ let group: ConsumptionGroup | undefined = groups.find((g) => g.date === date)
308
+ if (!group) {
309
+ group = {
310
+ date,
311
+ consumptions: [],
312
+ }
313
+ groups.push(group)
314
+ }
315
+ group.consumptions.push(d)
316
+ })
317
+ groups.sort((a, b) => (a.date > b.date ? -1 : 1))
318
+ return groups
319
+ }
320
+
321
+ /**
322
+ * 请求账户流水
323
+ * @param append 搜索结果累加 上拉分页时
324
+ */
325
+ async function loadConsumptions(append: boolean = false) {
326
+ if (!append) {
327
+ consumptionGroups.value = []
328
+ }
329
+ const $http = useHttp()
330
+ showLoading({
331
+ title: `加载中...`,
332
+ mask: true,
333
+ })
334
+ $http
335
+ .get<WithPaging<账户流水[]>>(endpoints.获取账户流水, {
336
+ app: props.app,
337
+ ...filtering,
338
+ })
339
+ .then((response) => {
340
+ consumptionGroups.value = groupDataByDate(response.data)
341
+ if (filtering.page >= response.totalPages) {
342
+ filtering.page = response.totalPages
343
+ reachedLastPage.value = true
344
+ } else {
345
+ reachedLastPage.value = false
346
+ }
347
+ }).finally(() => {
348
+ hideLoading()
349
+ })
350
+ }
351
+
352
+ /**
353
+ * 获取账户余额明细
354
+ */
355
+ async function loadBalance() {
356
+ const $http = useHttp()
357
+ $http
358
+ .get<Balance>(endpoints.获取余额明细, {
359
+ app: props.app,
360
+ })
361
+ .then((data) => {
362
+ const { privileges, total } = data
363
+ const filterData = {
364
+ total,
365
+ privileges: groupBy(privileges, 'appCode'),
366
+ }
367
+ balance.value = filterData
368
+ })
369
+ }
370
+
371
+ const onFilterComplete = (value) => {
372
+ filtering.账户类型 = value[0]
373
+ filtering.收入还是支出 = value[1]
374
+ filtering.交易类型 = value[2]
375
+ filtering.权益类目 = value[3]
376
+ filterOpen.value = false
377
+ restartSearch()
378
+ }
379
+
380
+ const onDateFilterComplete = (value) => {
381
+ filtering.dateFrom = value.from
382
+ filtering.dateTo = value.to
383
+ datePickerOpen.value = false
384
+ restartSearch()
385
+ }
386
+
387
+ function gotoRecharge() {
388
+ emit('recharge')
389
+ }
390
+
391
+ function gotoTrade(item: any) {
392
+ emit('trade', item)
393
+ }
394
+
395
+ function loadNextPage() {
396
+ filtering.page++
397
+ loadConsumptions(true)
398
+ }
399
+
400
+ // 以下这一大段处理下拉刷新、上滑分页以及弹窗与页面滑动的逻辑
401
+ const scrolled = ref<number>(0)
402
+
403
+ /**
404
+ * 记录 scroll-view 滚动的位置
405
+ */
406
+ const onScroll = (e) => {
407
+ const { scrollTop } = e
408
+ scrolled.value = scrollTop
409
+ }
410
+
411
+ /**
412
+ * 下拉刷新 pull down refresh
413
+ */
414
+ const onPullDownRefresh = () => {
415
+ refreshing.value = true
416
+ // 重新请求余额数据
417
+ loadBalance()
418
+ setTimeout(() => {
419
+ refreshing.value = false
420
+ }, 500)
421
+ }
422
+
423
+ /**
424
+ * 滑动到底部请求下一页并合并查询结果
425
+ */
426
+ const onReachBottom = () => {
427
+ console.log('到底了')
428
+ if (reachedLastPage.value) {
429
+ return false
430
+ }
431
+ loadNextPage()
432
+ }
433
+
434
+ const secondBalanceOpen = ref<boolean>(false)
435
+
436
+ function onSecondBalanceButtonClick() {
437
+ secondBalanceOpen.value = true
438
+ loadConsumptions()
439
+ }
440
+
441
+ watch(secondBalanceOpen, () => {
442
+ if (Taro.getEnv() !== 'WEB') {
443
+ Taro.setNavigationBarColor({
444
+ frontColor: secondBalanceOpen.value ? '#000000' : '#ffffff',
445
+ backgroundColor: '#ffffff',
446
+ animation: {
447
+ duration: 400,
448
+ timingFunc: 'easeIn',
449
+ },
450
+ })
451
+ }
452
+ })
453
+
454
+ function onDateReset() {
455
+ resetDateRange()
456
+ datePickerOpen.value = false
457
+ restartSearch()
458
+ }
459
+
460
+ /**
461
+ * 充值筛选的起止时间
462
+ */
463
+ function resetDateRange() {
464
+ // 筛选的起止时间
465
+ filtering.dateTo = dayjs().format('YYYY-MM-DD')
466
+ filtering.dateFrom = dayjs().add(-3, 'M').format('YYYY-MM-DD')
467
+ }
468
+
469
+ function onPageHeaderClose() {
470
+ Taro.navigateBack({
471
+ delta: 1,
472
+ })
473
+ }
474
+
475
+ const isAppEnv = computed(() => {
476
+ return isApp()
477
+ })
478
+
479
+ onMounted(() => {
480
+ resetDateRange()
481
+ })
482
+ </script>
483
+
484
+ <style lang="scss">
485
+ .account-view {
486
+ height: 100vh;
487
+
488
+ .scroll-content {
489
+ background-image: url('https://cdn.ddjf.com/static/images/customer-center/blue-bg.png');
490
+ background-position: center 0;
491
+ background-repeat: no-repeat;
492
+ background-size: 100% 200px;
493
+ }
494
+
495
+ .page-header {
496
+ background-color: transparent;
497
+ position: sticky;
498
+ top: 0;
499
+ z-index: 1;
500
+ transition: background-color 0.3s;
501
+
502
+ &.with-background {
503
+ background-color: #3b393c;
504
+ color: #fff;
505
+ }
506
+ }
507
+
508
+ .spa-between {
509
+ display: flex;
510
+ justify-content: space-between;
511
+ align-items: center;
512
+ }
513
+
514
+ .row {
515
+ display: flex;
516
+ flex-direction: row;
517
+ padding: 10px 15px;
518
+ }
519
+
520
+ .jusify-right {
521
+ justify-content: flex-end;
522
+ }
523
+
524
+ .small-bean-button {
525
+ height: 22px;
526
+ border-radius: 11px;
527
+ background-color: #fff;
528
+ display: inline-flex;
529
+ align-items: center;
530
+ padding: 0 10px;
531
+ color: #353535;
532
+ font-size: 12px;
533
+
534
+ .label {
535
+ background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEwIDZMMTYgMTJMMTAgMThWNloiIGZpbGw9IiMzNTM1MzUiIHN0cm9rZT0iIzM1MzUzNSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo=');
536
+ padding-right: 18px;
537
+ background-repeat: no-repeat;
538
+ background-position: right center;
539
+ background-size: 16px;
540
+ }
541
+ }
542
+
543
+ .balance {
544
+ border-radius: 15px;
545
+ background: linear-gradient(90deg, #FFEBC1 0%, #FFB875 100%);
546
+ height: 112px;
547
+ padding: 20px;
548
+ margin: 0 15px;
549
+ box-sizing: border-box;
550
+ font-size: 10px;
551
+
552
+ .bean-img {
553
+ display: flex;
554
+ justify-content: flex-start;
555
+ align-items: center;
556
+
557
+ .bean-icon {
558
+ display: block;
559
+ font-size: 0;
560
+ width: 20px;
561
+ height: 20px;
562
+ margin-right: 4px;
563
+ }
564
+
565
+ .bean-tag {
566
+ color: #353535;
567
+ height: 15px;
568
+ line-height: 15px;
569
+ border-radius: 30px 50px 50px 0px;
570
+ background: rgba(#ff8320, 0.3);
571
+ padding-left: 5px;
572
+ padding-right: 10px;
573
+ }
574
+
575
+ .tag {
576
+ background: #ff8320;
577
+ color: #fff;
578
+ }
579
+ }
580
+
581
+ .rule {
582
+ color: #353535;
583
+ opacity: 0.5;
584
+ }
585
+ }
586
+
587
+ .bean-counts {
588
+ margin-top: 12px;
589
+
590
+ .counts {
591
+ color: #3d3835;
592
+ font-size: 32px;
593
+ font-weight: 700;
594
+ }
595
+
596
+ .pay {
597
+ padding: 0 20px;
598
+ height: 32px;
599
+ line-height: 32px;
600
+ background: linear-gradient(187.18deg, #353535 10.04%, #433f46 90.21%);
601
+ border-radius: 16px;
602
+ color: #e7caad;
603
+ font-size: 15px;
604
+ font-weight: 500;
605
+ }
606
+ }
607
+ }
608
+
609
+ .consumption-rules-popup {
610
+ border-radius: 16px;
611
+ width: 70%;
612
+ max-height: 80%;
613
+ padding: 24px;
614
+ }
615
+
616
+ .operation-box {
617
+ width: 100vw;
618
+ overflow: hidden;
619
+ display: flex;
620
+ flex-direction: column;
621
+ height: calc(100vh - 87px);
622
+
623
+ .operation-title {
624
+ padding: 10px 15px;
625
+ background: #fff;
626
+ transition: box-shadow 0.3s;
627
+
628
+ &.with-shadow {
629
+ box-shadow: 0px 1px 10px 0px #99999933;
630
+ }
631
+
632
+ .text {
633
+ color: #353535;
634
+ font-size: 12px;
635
+ opacity: 0.5;
636
+ }
637
+
638
+ .time-icon {
639
+ display: block;
640
+ font-size: 0;
641
+ width: 12px;
642
+ height: 12px;
643
+ margin-left: 4px;
644
+ }
645
+
646
+ .search-time {
647
+ display: flex;
648
+ align-items: center;
649
+
650
+ .title {
651
+ color: #000;
652
+ font-weight: 500;
653
+ font-size: 17px;
654
+ margin-right: 10px;
655
+ }
656
+
657
+ .time {
658
+ height: 22px;
659
+ padding-right: 5px;
660
+ flex: 1;
661
+ display: flex;
662
+ align-items: center;
663
+ }
664
+ }
665
+
666
+ .search {
667
+ display: flex;
668
+ align-items: center;
669
+ height: 22px;
670
+ padding-left: 5px;
671
+ }
672
+ }
673
+
674
+ .spa-between {
675
+ display: flex;
676
+ justify-content: space-between;
677
+ align-items: center;
678
+ }
679
+
680
+ .operation-list {
681
+ flex: 1;
682
+ width: 100%;
683
+
684
+ .operation-scroll {
685
+ height: calc(100vh - 132px);
686
+ box-sizing: border-box;
687
+ }
688
+
689
+ .box {
690
+ padding: 0 10px;
691
+
692
+ &-detail {
693
+ .title {
694
+ line-height: 22px;
695
+ font-weight: 700;
696
+ font-size: 12px;
697
+ color: #000;
698
+ opacity: 0.5;
699
+ margin-bottom: 10px;
700
+ }
701
+
702
+ .item {
703
+ border-radius: 5px;
704
+ background: rgba(255, 255, 255, 0.5);
705
+ box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.05);
706
+ border-radius: 5px;
707
+ padding: 12px 10px;
708
+ display: flex;
709
+ margin-bottom: 10px;
710
+
711
+ &-type {
712
+ background: linear-gradient(113.95deg, #f4e2ce 1.2%, #debb9b 77.63%);
713
+ width: 30px;
714
+ height: 30px;
715
+ border-radius: 15px;
716
+ margin-right: 15px;
717
+ line-height: 30px;
718
+ font-size: 10px;
719
+ font-weight: 500;
720
+ color: #000;
721
+ text-align: center;
722
+ }
723
+
724
+ &-detail {
725
+ flex: 1;
726
+
727
+ .item-info {
728
+ padding: 0;
729
+ font-size: 14px;
730
+ font-weight: 700;
731
+ color: #000;
732
+
733
+ &-type {
734
+ }
735
+
736
+ &-title {
737
+ font-weight: 400;
738
+ opacity: 0.8;
739
+ font-size: 11px;
740
+ }
741
+
742
+ &-right {
743
+ text-align: right;
744
+ }
745
+
746
+ &-amount {
747
+ color: #9e7b5a;
748
+ }
749
+
750
+ &-time {
751
+ font-weight: 400;
752
+ opacity: 0.5;
753
+ font-size: 11px;
754
+ }
755
+ }
756
+
757
+ &-remark {
758
+ opacity: 0.3;
759
+ line-height: 15px;
760
+ font-size: 10px;
761
+ }
762
+ }
763
+ }
764
+ }
765
+
766
+ &-not-text {
767
+ opacity: 0.4;
768
+ color: #353535;
769
+ font-size: 12px;
770
+ line-height: 20px;
771
+ margin: 0 auto 40px;
772
+ text-align: center;
773
+ }
774
+ }
775
+ }
776
+ }
777
+
778
+ .rights-card {
779
+ margin: 10px 15px 0px;
780
+ background: rgb(255, 248, 243, 0.8);
781
+ border-radius: 5px;
782
+ padding: 15px 20px;
783
+ box-shadow: 0px 5px 18.9px 2px #0000000D;
784
+
785
+
786
+ .title {
787
+ height: 25px;
788
+ line-height: 25px;
789
+ background: rgba($color: #ff8320, $alpha: 0.3);
790
+ border-radius: 20px 50px 50px 0px;
791
+ color: #353535;
792
+ font-size: 12px;
793
+ display: inline-block;
794
+ padding-left: 5px;
795
+ padding-right: 12px;
796
+ }
797
+
798
+ .list {
799
+ display: flex;
800
+ flex-wrap: wrap;
801
+
802
+ .item {
803
+ width: 50%;
804
+ margin-top: 15px;
805
+
806
+ .item-count {
807
+ font-size: 20px;
808
+ color: #353535;
809
+ font-weight: 700;
810
+ line-height: 23px;
811
+ }
812
+
813
+ .item-title {
814
+ line-height: 23px;
815
+ color: #987356;
816
+ font-size: 11px;
817
+ display: flex;
818
+ align-items: center;
819
+
820
+ .item-title-button {
821
+ padding: 0 14px;
822
+ height: 27px;
823
+ line-height: 27px;
824
+ background: -webkit-linear-gradient(262.82deg, #353535 10.04%, #433f46 90.21%);
825
+ background: linear-gradient(187.18deg, #353535 10.04%, #433f46 90.21%);
826
+ border-radius: 14px;
827
+ color: #e7caad;
828
+ font-size: 12px;
829
+ font-weight: 400;
830
+ margin-left: 20px;
831
+ display: flex;
832
+ align-items: center;
833
+
834
+ .button-icon {
835
+ display: block;
836
+ width: 12px;
837
+ height: 12px;
838
+ font-size: 0;
839
+ margin-left: 4px;
840
+ }
841
+ }
842
+ }
843
+ }
844
+
845
+ .star-item {
846
+ width: 100%;
847
+ }
848
+ }
849
+ }
850
+ </style>