@uxda/appkit 1.2.73 → 1.2.76

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 (41) hide show
  1. package/dist/appkit.css +829 -29
  2. package/dist/assets/asset-BnRbHhKf +88 -0
  3. package/dist/index.js +3191 -558
  4. package/package.json +2 -1
  5. package/src/balance/api/endpoints.ts +44 -44
  6. package/src/balance/types.ts +42 -42
  7. package/src/components/bt-cropper/index.vue +774 -0
  8. package/src/components/bt-cropper/utils/calcCropper.js +42 -0
  9. package/src/components/bt-cropper/utils/calcImagePosition.js +23 -0
  10. package/src/components/bt-cropper/utils/calcImageSize.js +37 -0
  11. package/src/components/bt-cropper/utils/calcPointDistance.js +12 -0
  12. package/src/components/bt-cropper/utils/calcRightAndBottom.js +7 -0
  13. package/src/components/bt-cropper/utils/ratio.js +3 -0
  14. package/src/components/bt-cropper/utils/tools.js +25 -0
  15. package/src/components/dd-search/index.vue +3 -3
  16. package/src/components/dd-skeleton/doc.md +19 -0
  17. package/src/components/dd-skeleton/index.vue +36 -0
  18. package/src/index.ts +1 -0
  19. package/src/notice/components/NoticeBanner.vue +1 -1
  20. package/src/notice/components/NoticeList.vue +3 -1
  21. package/src/notice/components/index.ts +1 -2
  22. package/src/shared/components/DeviceVersion.vue +3 -2
  23. package/src/shared/composables/index.ts +3 -0
  24. package/src/shared/composables/useCountdown.ts +46 -0
  25. package/src/shared/composables/useDragBox.ts +97 -0
  26. package/src/shared/composables/useEncode.ts +43 -0
  27. package/src/shared/composables/useValidator.ts +31 -0
  28. package/src/shared/http/Http.ts +4 -3
  29. package/src/user/api/endpoints.ts +17 -0
  30. package/src/user/api/index.ts +87 -0
  31. package/src/{notice → user}/components/LoginSetting.vue +3 -1
  32. package/src/user/components/UserBinding.vue +300 -0
  33. package/src/user/components/UserBindingSuccess.vue +80 -0
  34. package/src/user/components/UserEntry.vue +142 -0
  35. package/src/user/components/UserFeedback.vue +440 -0
  36. package/src/user/components/UserFeedbackEntry.vue +171 -0
  37. package/src/user/components/UserHeadCrop.vue +65 -0
  38. package/src/user/components/UserInfo.vue +632 -0
  39. package/src/user/components/UserResourceEmpty.vue +75 -0
  40. package/src/user/components/index.ts +21 -0
  41. package/src/user/index.ts +1 -0
@@ -0,0 +1,300 @@
1
+ <template>
2
+ <div class="user-binding">
3
+ <div class="user-binding-layout">
4
+ <img
5
+ class="user-binding-img"
6
+ :src="`https://cdn.ddjf.com/static/images/customer-center/user-${
7
+ current === 1 ? 'binding' : 'auth'
8
+ }.png`"
9
+ />
10
+ <nut-steps :current="current" class="user-binding-steps">
11
+ <nut-step title="身份认证">1</nut-step>
12
+ <nut-step title="换绑手机">2</nut-step>
13
+ </nut-steps>
14
+ </div>
15
+
16
+ <div class="user-binding-layout user-binding-inputlayout" style="flex: 1" v-if="current === 1">
17
+ <nut-input
18
+ label="手机号码"
19
+ v-model="authState.mobile"
20
+ placeholder="请输入手机号码"
21
+ :max-length="11"
22
+ readonly
23
+ input-align="right"
24
+ />
25
+ <nut-input
26
+ label="验证码"
27
+ v-model="authState.code"
28
+ placeholder="请输入验证码"
29
+ :max-length="6"
30
+ input-align="right"
31
+ >
32
+ <template #button>
33
+ <nut-button
34
+ :disabled="countdownActive"
35
+ class="user-binding-codebtn"
36
+ type="default"
37
+ @click="onAuthCode"
38
+ >{{ countdownText }}</nut-button
39
+ >
40
+ </template>
41
+ </nut-input>
42
+
43
+ <nut-button
44
+ class="user-binding-btn"
45
+ :disabled="!authState.code"
46
+ block
47
+ type="primary"
48
+ @click="onAuth"
49
+ >提交</nut-button
50
+ >
51
+ </div>
52
+
53
+ <div class="user-binding-layout user-binding-inputlayout" style="flex: 1" v-else>
54
+ <nut-input
55
+ label="手机号码"
56
+ v-model="bindingState.mobile"
57
+ placeholder="请输入新手机号码"
58
+ :max-length="11"
59
+ input-align="right"
60
+ />
61
+ <nut-input
62
+ label="验证码"
63
+ v-model="bindingState.code"
64
+ placeholder="请输入验证码"
65
+ :max-length="6"
66
+ input-align="right"
67
+ >
68
+ <template #button>
69
+ <nut-button
70
+ :disabled="countdownActive1"
71
+ class="user-binding-codebtn"
72
+ type="default"
73
+ @click="onBindingCode"
74
+ >{{ countdownText1 }}</nut-button
75
+ >
76
+ </template>
77
+ </nut-input>
78
+
79
+ <nut-button
80
+ class="user-binding-btn"
81
+ :disabled="!bindingState.code || !bindingState.mobile"
82
+ block
83
+ type="primary"
84
+ @click="onBinding"
85
+ >提交</nut-button
86
+ >
87
+ </div>
88
+ </div>
89
+ </template>
90
+
91
+ <script lang="ts" setup>
92
+ import { ref, reactive, onMounted } from 'vue'
93
+ import { useCountdown } from '../../shared/composables/useCountdown'
94
+ import { useValidator } from '../../shared/composables/useValidator'
95
+ import Taro from '@tarojs/taro'
96
+ import { useHttp } from '../api'
97
+ import { useRouter } from '@tarojs/taro'
98
+
99
+ const { params } = useRouter()
100
+ const { countdownText, startCountdown, countdownActive } = useCountdown()
101
+ const {
102
+ countdownText: countdownText1,
103
+ startCountdown: startCountdown1,
104
+ countdownActive: countdownActive1,
105
+ } = useCountdown()
106
+ const { phoneValidator } = useValidator()
107
+ const current = ref(1)
108
+
109
+ onMounted(() => {
110
+ if (!params.mobile) {
111
+ return Taro.showToast({ title: '路径缺少mobile参数', icon: 'none' })
112
+ }
113
+ authState.mobile = params.mobile
114
+ })
115
+
116
+ /**
117
+ * 身份认证
118
+ */
119
+ const authState = reactive({
120
+ mobile: '',
121
+ code: '',
122
+ })
123
+ function onAuth() {
124
+ const $http = useHttp()
125
+
126
+ // 向当前用户的手机中发送短信验证码
127
+ $http.post('/cas/sysAccount/verify', { verifyCode: authState.code }).then((res) => {
128
+ console.log(res, 'res')
129
+ if (typeof res !== 'boolean') return
130
+
131
+ Taro.showToast({ title: '身份认证成功', icon: 'success' })
132
+ current.value++
133
+ })
134
+ }
135
+ function onAuthCode() {
136
+ const $http = useHttp()
137
+
138
+ // 向当前用户的手机中发送短信验证码
139
+ $http.get('/cas/sysAccount/getVerifyCodeToUserMobile').then((res) => {
140
+ if (typeof res !== 'boolean') return
141
+
142
+ Taro.showToast({ title: '短信发送成功,请注意查收', icon: 'none' })
143
+ startCountdown()
144
+ })
145
+ }
146
+
147
+ /**
148
+ * 换绑手机
149
+ */
150
+ const bindingState = reactive({
151
+ mobile: '',
152
+ code: '',
153
+ })
154
+ function onBinding() {
155
+ const msg = phoneValidator(bindingState.mobile)
156
+ if (msg) {
157
+ return Taro.showToast({ title: msg, icon: 'none' })
158
+ }
159
+
160
+ const $http = useHttp()
161
+
162
+ $http
163
+ .post(`/cas/sysAccount/verifyAndChangeMobile`, {
164
+ mobile: bindingState.mobile,
165
+ verifyCode: bindingState.code,
166
+ })
167
+ .then((res) => {
168
+ if (typeof res !== 'boolean') return
169
+
170
+ Taro.showToast({ title: '换绑成功', icon: 'success' })
171
+ emits('success', bindingState.mobile)
172
+ })
173
+ }
174
+ function onBindingCode() {
175
+ const msg = phoneValidator(bindingState.mobile)
176
+ if (msg) {
177
+ return Taro.showToast({ title: msg, icon: 'none' })
178
+ }
179
+ if (params.mobile === bindingState.mobile) {
180
+ return Taro.showToast({ title: '新手机号码不应与旧手机号码一致', icon: 'none' })
181
+ }
182
+
183
+ const $http = useHttp()
184
+
185
+ // 向当前用户的手机中发送短信验证码
186
+ $http.get(`/cas/sysAccount/getVerifyCodeToMobile/${bindingState.mobile}`).then((res) => {
187
+ if (typeof res !== 'boolean') return
188
+
189
+ Taro.showToast({ title: '短信发送成功,请注意查收', icon: 'none' })
190
+ startCountdown1()
191
+ })
192
+ }
193
+
194
+ // 父组件事件
195
+ const emits = defineEmits(['success'])
196
+ </script>
197
+
198
+ <style lang="scss">
199
+ .user-binding {
200
+ height: 100vh;
201
+ display: flex;
202
+ flex-direction: column;
203
+ box-sizing: border-box;
204
+ padding: 10px 12px env(safe-area-inset-bottom, 0px);
205
+ &-img {
206
+ width: 351px;
207
+ height: 192px;
208
+ }
209
+ &-layout {
210
+ position: relative;
211
+ width: 351px;
212
+ border-radius: 4px;
213
+ background: #fff;
214
+ overflow: hidden;
215
+ margin-bottom: 10px;
216
+ }
217
+ &-btn {
218
+ position: absolute;
219
+ bottom: 50px;
220
+ left: 25px;
221
+ width: calc(100% - 50px);
222
+ font-size: 16px;
223
+ background: var(--app-primary-color, #017fff);
224
+ height: 40px;
225
+ line-height: 38px;
226
+ }
227
+ &-codebtn {
228
+ height: 30px;
229
+ font-size: 12px;
230
+ padding: 0;
231
+ width: 90px;
232
+ border: none;
233
+ color: var(--app-primary-color, #017fff);
234
+ background: #f2f2f2;
235
+ }
236
+ &-steps {
237
+ margin-top: 15px;
238
+ .nut-step-line {
239
+ background: rgba(220, 220, 220, 1);
240
+ left: 60%;
241
+ right: -40%;
242
+ }
243
+ .nut-step-title {
244
+ font-weight: bold;
245
+ color: rgba(0, 0, 0, 0.4);
246
+ }
247
+ .nut-step.nut-step-wait .nut-step-icon.is-text {
248
+ background: rgba(243, 243, 243, 1);
249
+ border-color: rgba(243, 243, 243, 1);
250
+ color: rgba(0, 0, 0, 0.4);
251
+ }
252
+ .nut-step.nut-step-process .nut-step-icon.is-text {
253
+ background: var(--app-primary-color, #017fff);
254
+ border-color: var(--app-primary-color, #017fff);
255
+ }
256
+ .nut-step.nut-step-process .nut-step-title {
257
+ color: var(--app-primary-color, #017fff);
258
+ }
259
+ .nut-step-head {
260
+ margin-bottom: 8px;
261
+ }
262
+ .nut-step.nut-step-finish .nut-step-title {
263
+ color: rgba(0, 0, 0, 0.9);
264
+ }
265
+ .nut-step.nut-step-finish .nut-step-line {
266
+ background: var(--app-primary-color, #017fff);
267
+ }
268
+ .nut-step.nut-step-finish .nut-step-head {
269
+ color: var(--app-primary-color, #017fff);
270
+ border-color: var(--app-primary-color, #017fff);
271
+ }
272
+ .nut-step-icon {
273
+ width: 22px;
274
+ height: 22px;
275
+ }
276
+ }
277
+ &-inputlayout {
278
+ padding: 0 10px;
279
+ box-sizing: border-box;
280
+ .nut-input {
281
+ height: 40px;
282
+ padding: 0;
283
+ display: flex;
284
+ align-items: center;
285
+ font-size: 16px;
286
+ padding-left: 3px;
287
+ border-color: #f5f5f5;
288
+ .input-text {
289
+ width: 100%;
290
+ }
291
+ }
292
+ .nut-input-label {
293
+ color: #666;
294
+ }
295
+ }
296
+ .nut-placeholder {
297
+ color: #cccccc;
298
+ }
299
+ }
300
+ </style>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="user-binding-success">
3
+ <img
4
+ class="user-binding-success-icon"
5
+ src="https://cdn.ddjf.com/static/images/customer-center/phone-icon.png"
6
+ alt=""
7
+ />
8
+ <div class="user-binding-success-info">
9
+ {{ showEncode ? encodePhone(params.mobile || '') : params.mobile }}
10
+ </div>
11
+ <div class="user-binding-success-sbtn" @click="showEncode = !showEncode">
12
+ {{ showEncode ? '显示' : '隐藏' }}
13
+ </div>
14
+ <nut-button class="user-binding-success-btn" type="primary" @click="toBinding"
15
+ >换绑手机号码</nut-button
16
+ >
17
+ </div>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import { onMounted, ref } from 'vue'
22
+ import { useRouter } from '@tarojs/taro'
23
+ import Taro from '@tarojs/taro'
24
+ import { useEncode } from '../../shared/composables/useEncode'
25
+
26
+ const { params } = useRouter()
27
+ const { encodePhone } = useEncode()
28
+
29
+ onMounted(() => {
30
+ if (!params.mobile) {
31
+ return Taro.showToast({ title: '路径缺少mobile参数', icon: 'none' })
32
+ }
33
+ })
34
+
35
+ const showEncode = ref(true)
36
+
37
+ // 前往换绑手机号
38
+ function toBinding() {
39
+ emits('binding', params.mobile)
40
+ }
41
+
42
+ // 父组件事件
43
+ const emits = defineEmits(['binding'])
44
+ </script>
45
+
46
+ <style lang="scss">
47
+ .user-binding-success {
48
+ height: 100vh;
49
+ display: flex;
50
+ flex-direction: column;
51
+ align-items: center;
52
+ box-sizing: border-box;
53
+ background: #fff;
54
+ &-icon {
55
+ margin-top: 80px;
56
+ width: 50px;
57
+ height: 50px;
58
+ margin-bottom: 30px;
59
+ }
60
+ &-info {
61
+ font-size: 30px;
62
+ color: #000000;
63
+ font-weight: bold;
64
+ margin-bottom: 15px;
65
+ }
66
+ &-sbtn {
67
+ padding: 0 15px;
68
+ color: #017fff;
69
+ font-size: 16px;
70
+ }
71
+ &-btn {
72
+ margin-top: 80px;
73
+ width: 296px;
74
+ font-size: 16px;
75
+ background: var(--app-primary-color, #017fff);
76
+ height: 40px;
77
+ line-height: 38px;
78
+ }
79
+ }
80
+ </style>
@@ -0,0 +1,142 @@
1
+ <template>
2
+ <div class="user-entry">
3
+ <div class="user-entry-head">
4
+ <img
5
+ class="user-entry-head-img"
6
+ @click="toUser"
7
+ mode="aspectFit"
8
+ v-if="avatar"
9
+ :src="avatar"
10
+ alt=""
11
+ />
12
+ <img
13
+ class="user-entry-head-img"
14
+ mode="aspectFit"
15
+ @click="toUser1"
16
+ v-else
17
+ src="https://cdn.ddjf.com/static/images/wx-yunservice/account-head.png"
18
+ alt=""
19
+ />
20
+ </div>
21
+ <div class="user-entry-bd">
22
+ <div v-if="!mobile" class="user-entry-bd-bigtxt" @click="toLogin">
23
+ 请登录
24
+ <img
25
+ class="user-entry-bd-bigtxt-icon"
26
+ mode="aspectFit"
27
+ src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA0MCA0MSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggb3BhY2l0eT0iMC4wMSIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0wIDQwLjM1MTZINDBWMC4zNTE1NjJIMFY0MC4zNTE2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNCA4LjM1MTU2TDI2IDIwLjM1MTZMMTQgMzIuMzUxNiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4wMSIvPgo8cGF0aCBkPSJNMTQgOC4zNTE1NkwyNiAyMC4zNTE2TDE0IDMyLjM1MTYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg=="
28
+ alt=""
29
+ />
30
+ </div>
31
+ <template v-else>
32
+ <div @click="toUser" class="user-entry-bd-txt">
33
+ {{ name }}
34
+ <img
35
+ style="width: 14px; height: 14px; margin-left: 2px"
36
+ src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTExLjA4MzUgN0wxOC4wODM1IDE0TDExLjA4MzUgMjEiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS43NSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPgo="
37
+ alt=""
38
+ />
39
+ </div>
40
+ <div @click="toUser" class="user-entry-bd-smalltxt">{{ encodePhone(mobile) }}</div>
41
+ </template>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <script lang="ts" setup>
47
+ import { useEncode } from '../../shared/composables/useEncode'
48
+
49
+ const props = withDefaults(
50
+ defineProps<{
51
+ avatar?: string
52
+ mobile?: string
53
+ name?: string
54
+ }>(),
55
+ {
56
+ avatar: '',
57
+ mobile: '',
58
+ name: '',
59
+ }
60
+ )
61
+
62
+ const { encodePhone } = useEncode()
63
+
64
+ // 登录后,点击前往个人资料页
65
+ function toUser() {
66
+ emits('jump')
67
+ }
68
+
69
+ function toUser1() {
70
+ props?.mobile && toUser()
71
+ }
72
+
73
+ // 未登录时,点击前往登录
74
+ function toLogin() {
75
+ emits('login')
76
+ }
77
+
78
+ // 父组件事件
79
+ const emits = defineEmits(['jump', 'login'])
80
+ </script>
81
+
82
+ <style lang="scss">
83
+ .user-entry {
84
+ position: absolute;
85
+ left: 0;
86
+ top: 130px;
87
+ transform: translateY(-50%);
88
+ display: flex;
89
+ padding: 0 22px;
90
+ align-items: center;
91
+ width: 100%;
92
+ &-head {
93
+ position: relative;
94
+ width: 62px;
95
+ height: 62px;
96
+ margin-right: 8px;
97
+ &-img {
98
+ width: 100%;
99
+ height: 100%;
100
+ overflow: hidden;
101
+ border-radius: 50%;
102
+ border: 1.5px solid #fff;
103
+ }
104
+ &-icon {
105
+ position: absolute;
106
+ width: 15px;
107
+ height: 15px;
108
+ bottom: 2px;
109
+ left: 48px;
110
+ background: url('https://cdn.ddjf.com/static/images/wx-yunservice/edit-icon.png') center;
111
+ background-size: cover;
112
+ }
113
+ }
114
+ &-bd {
115
+ color: #fff;
116
+ &-bigtxt {
117
+ display: flex;
118
+ align-items: center;
119
+ font-size: 20px;
120
+ font-weight: 500;
121
+ line-height: 28px;
122
+ margin-left: 10px;
123
+ &-icon {
124
+ width: 20px;
125
+ }
126
+ }
127
+ &-txt {
128
+ font-size: 20px;
129
+ font-weight: 500;
130
+ line-height: 25px;
131
+ margin-bottom: 5px;
132
+ display: flex;
133
+ align-items: center;
134
+ }
135
+ &-smalltxt {
136
+ margin-top: 0;
137
+ font-size: 15px;
138
+ line-height: 21px;
139
+ }
140
+ }
141
+ }
142
+ </style>