@uxda/appkit 4.0.0 → 4.0.2

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 (108) hide show
  1. package/.eslintrc.mjs +7 -7
  2. package/README.md +187 -187
  3. package/babel.config.js +12 -12
  4. package/dist/appkit.css +855 -36
  5. package/dist/assets/asset-DcH8Kg-2 +1 -0
  6. package/dist/index.js +3355 -610
  7. package/package.json +80 -78
  8. package/project.config.json +15 -15
  9. package/project.tt.json +13 -13
  10. package/rollup.config.mjs +56 -54
  11. package/src/Appkit.ts +65 -65
  12. package/src/balance/api/endpoints.ts +126 -126
  13. package/src/balance/api/index.ts +82 -82
  14. package/src/balance/components/AccountView.vue +748 -748
  15. package/src/balance/components/BalanceCard.vue +209 -209
  16. package/src/balance/components/BalanceReminder.vue +85 -85
  17. package/src/balance/components/ConsumptionFilter.vue +218 -218
  18. package/src/balance/components/ConsumptionRules.vue +68 -68
  19. package/src/balance/components/DateFilter.vue +226 -236
  20. package/src/balance/components/SecondBalance.vue +71 -71
  21. package/src/balance/components/Tip.vue +45 -45
  22. package/src/balance/components/index.ts +9 -9
  23. package/src/balance/types.ts +90 -90
  24. package/src/components/bt-cropper/index.vue +774 -0
  25. package/src/components/bt-cropper/utils/calcCropper.js +42 -0
  26. package/src/components/bt-cropper/utils/calcImagePosition.js +23 -0
  27. package/src/components/bt-cropper/utils/calcImageSize.js +37 -0
  28. package/src/components/bt-cropper/utils/calcPointDistance.js +12 -0
  29. package/src/components/bt-cropper/utils/calcRightAndBottom.js +7 -0
  30. package/src/components/bt-cropper/utils/ratio.js +3 -0
  31. package/src/components/bt-cropper/utils/tools.js +25 -0
  32. package/src/components/dd-area/index.vue +225 -225
  33. package/src/components/dd-icon/doc.md +21 -21
  34. package/src/components/dd-icon/index.vue +23 -23
  35. package/src/components/dd-notice-bar/index.vue +78 -78
  36. package/src/components/dd-search/doc.md +34 -34
  37. package/src/components/dd-search/index.vue +168 -168
  38. package/src/components/dd-selector/index.vue +124 -124
  39. package/src/components/dd-skeleton/doc.md +19 -0
  40. package/src/components/dd-skeleton/index.vue +36 -0
  41. package/src/components/ocr-id/index.vue +114 -114
  42. package/src/components/ocr-id/types.d.ts +12 -12
  43. package/src/global.ts +6 -6
  44. package/src/index.ts +89 -88
  45. package/src/main.scss +1 -1
  46. package/src/notice/api/endpoints.ts +17 -17
  47. package/src/notice/api/index.ts +82 -82
  48. package/src/notice/components/NoticeBanner.vue +243 -243
  49. package/src/notice/components/NoticeEntry.vue +99 -99
  50. package/src/notice/components/NoticeList.vue +315 -278
  51. package/src/notice/components/NoticePopup.vue +161 -163
  52. package/src/notice/components/index.ts +5 -6
  53. package/src/notice/components/useCommonList.ts +86 -86
  54. package/src/notice/components/useNotice.ts +35 -35
  55. package/src/notice/index.ts +1 -1
  56. package/src/notice/types.ts +25 -25
  57. package/src/payment/api/config.ts +7 -7
  58. package/src/payment/api/endpoints.ts +103 -103
  59. package/src/payment/api/index.ts +71 -71
  60. package/src/payment/components/AmountPicker.vue +93 -93
  61. package/src/payment/components/RechargeResult.vue +69 -69
  62. package/src/payment/components/RechargeView.vue +154 -154
  63. package/src/payment/components/RightsPicker.vue +105 -105
  64. package/src/payment/components/TradeView.vue +298 -298
  65. package/src/payment/components/UserAgreement.vue +234 -142
  66. package/src/payment/components/index.ts +22 -22
  67. package/src/payment/index.ts +5 -5
  68. package/src/payment/services/index.ts +16 -16
  69. package/src/payment/services/invoke-recharge.ts +25 -25
  70. package/src/payment/services/request-payment.ts +58 -58
  71. package/src/payment/types.ts +28 -28
  72. package/src/register/components/SelfRegistration.vue +254 -228
  73. package/src/register/components/index.ts +2 -2
  74. package/src/shared/components/AppDrawer.vue +58 -58
  75. package/src/shared/components/DeviceVersion.vue +68 -67
  76. package/src/shared/components/EmptyView.vue +33 -33
  77. package/src/shared/components/PageHeader.vue +79 -79
  78. package/src/shared/components/index.ts +5 -5
  79. package/src/shared/composables/index.ts +5 -2
  80. package/src/shared/composables/useCountdown.ts +46 -0
  81. package/src/shared/composables/useDragBox.ts +97 -0
  82. package/src/shared/composables/useEncode.ts +43 -0
  83. package/src/shared/composables/useSafeArea.ts +46 -46
  84. package/src/shared/composables/useTabbar.ts +24 -24
  85. package/src/shared/composables/useValidator.ts +31 -0
  86. package/src/shared/http/Http.ts +136 -135
  87. package/src/shared/http/index.ts +1 -1
  88. package/src/shared/http/types.ts +157 -157
  89. package/src/shared/index.ts +3 -3
  90. package/src/shared/weixin/payment.ts +38 -38
  91. package/src/styles/fonts.scss +2 -2
  92. package/src/styles/vars.scss +3 -3
  93. package/src/user/api/endpoints.ts +17 -0
  94. package/src/user/api/index.ts +87 -0
  95. package/src/{notice → user}/components/LoginSetting.vue +114 -112
  96. package/src/user/components/UserBinding.vue +307 -0
  97. package/src/user/components/UserBindingSuccess.vue +80 -0
  98. package/src/user/components/UserEntry.vue +142 -0
  99. package/src/user/components/UserFeedback.vue +440 -0
  100. package/src/user/components/UserFeedbackEntry.vue +192 -0
  101. package/src/user/components/UserHeadCrop.vue +65 -0
  102. package/src/user/components/UserInfo.vue +632 -0
  103. package/src/user/components/UserResourceEmpty.vue +75 -0
  104. package/src/user/components/index.ts +21 -0
  105. package/src/user/index.ts +1 -0
  106. package/tsconfig.json +30 -30
  107. package/types/global.d.ts +21 -21
  108. package/types/vue.d.ts +10 -10
@@ -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>
@@ -0,0 +1,440 @@
1
+ <template>
2
+ <div class="user-feedback" :class="{ isSuccess }">
3
+ <div v-if="!isSuccess" class="user-feedback-wrap">
4
+ <div class="user-feedback-head">
5
+ <div class="user-feedback-head-info">1.系统使用过程中,遇到系统问题可通过此途径反馈。</div>
6
+ <div class="user-feedback-head-info">
7
+ 2.尽量在出问题的页面直接点击“问题反馈”,系统将后台获取当前页面信息,以便快速定位问题页。
8
+ </div>
9
+ <div class="user-feedback-head-info">
10
+ 3.问题描述请尽可能详细描述操作步骤,如涉及订单或客户信息,尽量附上订单编号/客户姓名等关键信息,以便快速定位问题。
11
+ </div>
12
+ <div class="user-feedback-head-info">4.问题描述支持上传图片及截图,视频不能超过50M。</div>
13
+ </div>
14
+
15
+ <div class="user-feedback-tit">补充描述</div>
16
+ <div class="user-feedback-body">
17
+ <editor
18
+ id="myEditor"
19
+ :show-img-resize="true"
20
+ class="user-feedback-editor"
21
+ placeholder="请输入补充描述"
22
+ />
23
+ <div class="user-feedback-handle">
24
+ <div
25
+ class="user-feedback-handle-item"
26
+ v-for="(item, key) in formState.attachment"
27
+ :key="key"
28
+ >
29
+ <template v-if="item.status === 'done'">
30
+ <img
31
+ v-if="item.type === 'image'"
32
+ class="user-feedback-handle-item-img"
33
+ mode="aspectFit"
34
+ :src="item.url"
35
+ />
36
+ <video class="user-feedback-handle-item-img" :src="item.url" v-else />
37
+ <div class="user-feedback-handle-item-close" @click="onDelete(key)">
38
+ <img
39
+ class="user-feedback-handle-item-close-img"
40
+ src="https://cdn.ddjf.com/static/images/customer-center/close-filled.png"
41
+ />
42
+ </div>
43
+ </template>
44
+ <img
45
+ class="user-feedback-handle-item-loading"
46
+ mode="aspectFit"
47
+ src="https://cdn.ddjf.com/static/images/customer-center/loading.png"
48
+ alt=""
49
+ />
50
+ </div>
51
+ <div class="user-feedback-handle-item" @click="toUpload">+</div>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="user-feedback-footer">
56
+ <nut-button class="user-feedback-footer-btn" plain type="primary" @click="onCancel"
57
+ >最小化</nut-button
58
+ >
59
+ <nut-button class="user-feedback-footer-btn" type="primary" @click="onOk">反馈</nut-button>
60
+ </div>
61
+ </div>
62
+ <div class="user-feedback-wrap" v-else>
63
+ <img
64
+ class="user-feedback-success-img"
65
+ mode="aspectFit"
66
+ src="https://cdn.ddjf.com/static/images/customer-center/success-icon.png"
67
+ />
68
+ <div class="user-feedback-success-info">提交成功</div>
69
+ </div>
70
+ </div>
71
+ </template>
72
+
73
+ <script lang="ts" setup>
74
+ import Taro from '@tarojs/taro'
75
+ import { onMounted, reactive, ref } from 'vue'
76
+ import { useAppKitOptions } from '../../Appkit'
77
+ import { useHttp } from '../api'
78
+
79
+ interface FormStateType {
80
+ content: string
81
+ attachment: any[]
82
+ }
83
+
84
+ const props = withDefaults(
85
+ defineProps<{
86
+ app?: string
87
+ traceIds: string
88
+ value?: FormStateType | null
89
+ captureScreen?: any
90
+ }>(),
91
+ {
92
+ app: '',
93
+ traceIds: '',
94
+ value: null,
95
+ captureScreen: () => {},
96
+ }
97
+ )
98
+
99
+ onMounted(() => {
100
+ setTimeout(() => {
101
+ initEditor()
102
+ }, 500)
103
+ })
104
+
105
+ const formState = reactive<FormStateType>({
106
+ content: '',
107
+ attachment: [],
108
+ })
109
+ const isSuccess = ref(false) // 反馈提交成功标记
110
+
111
+ const editorCtx = ref()
112
+ // 编辑器初始化
113
+ function initEditor() {
114
+ const query = Taro.createSelectorQuery()
115
+ query
116
+ .select('#myEditor')
117
+ .context((res) => {
118
+ editorCtx.value = res.context
119
+
120
+ if (props.value) {
121
+ if (props.value.content) {
122
+ formState.content = props.value.content
123
+ editorCtx.value.setContents({
124
+ html: props.value.content,
125
+ })
126
+ }
127
+ if (props.value.attachment && props.value.attachment.length) {
128
+ formState.attachment = props.value.attachment
129
+ }
130
+ }
131
+ })
132
+ .exec()
133
+ }
134
+
135
+ // 上传图片、视频
136
+ function toUpload() {
137
+ if (formState.attachment.length >= 20) {
138
+ return Taro.showToast({
139
+ title: '最多上传20份附件',
140
+ icon: 'none',
141
+ })
142
+ }
143
+ Taro.chooseMedia({
144
+ count: 20 - formState.attachment.length,
145
+ mediaType: ['mix'],
146
+ maxDuration: 60,
147
+ success: async (res) => {
148
+ console.log(res.tempFiles, 'res.tempFiles')
149
+ for (const item of res.tempFiles) {
150
+ if (item.fileType === 'video') {
151
+ if (item.size > 1024 * 1024 * 50) {
152
+ return Taro.showToast({
153
+ title: '视频大小不能超过50M',
154
+ icon: 'none',
155
+ })
156
+ }
157
+ }
158
+
159
+ formState.attachment.push({
160
+ url: item.tempFilePath,
161
+ type: item.fileType,
162
+ status: 'uploading',
163
+ })
164
+ await uploadFile(formState.attachment[formState.attachment.length - 1])
165
+ }
166
+ },
167
+ })
168
+ }
169
+
170
+ // 文件上传请求
171
+ async function uploadFile(item: any) {
172
+ const appkitOptions = useAppKitOptions()
173
+ const token = appkitOptions.tempToken() || appkitOptions.token()
174
+
175
+ let Res: any = await Taro.uploadFile({
176
+ url: `${appkitOptions.baseUrl()}/saas-base/file/upload`,
177
+ filePath: item.url,
178
+ name: 'file',
179
+ formData: {
180
+ objectNo: `${token}${Date.now()}`,
181
+ objectTypeCode: `PROBLEM_FEEDBACK_MINI`,
182
+ },
183
+ header: { token },
184
+ })
185
+
186
+ const res = JSON.parse(Res.data)
187
+ if (res.success) {
188
+ item.url = res.result
189
+ item.status = 'done'
190
+ }
191
+ }
192
+
193
+ // 删除附件
194
+ function onDelete(index: number) {
195
+ formState.attachment.splice(index, 1)
196
+ }
197
+
198
+ // 点击最小化
199
+ function onCancel() {
200
+ editorCtx.value.getContents({
201
+ success: (res) => {
202
+ const html = res.html
203
+ formState.content = html
204
+
205
+ if (html && html !== '<p><br></p>') {
206
+ formState.content = html
207
+ }
208
+ emits('minimize', formState)
209
+ Taro.navigateBack()
210
+ },
211
+ })
212
+ }
213
+
214
+ // 点击确定反馈时
215
+ function onOk() {
216
+ editorCtx.value.getContents({
217
+ success: (res) => {
218
+ const html = res.html
219
+ if (html === '<p><br></p>' || !html) {
220
+ Taro.showToast({
221
+ title: '请输入问题描述',
222
+ icon: 'none',
223
+ })
224
+ } else {
225
+ formState.content = html
226
+ requestFeedback()
227
+ }
228
+ },
229
+ })
230
+ }
231
+
232
+ // 请求反馈接口
233
+ function requestFeedback() {
234
+ const $http = useHttp()
235
+ const appkitOptions = useAppKitOptions()
236
+
237
+ Taro.showLoading({
238
+ title: '反馈中...',
239
+ })
240
+
241
+ const attachment = JSON.parse(
242
+ JSON.stringify(
243
+ formState.attachment
244
+ .filter((item) => item.status === 'done')
245
+ .map((item) => ({ url: item.url, type: item.type }))
246
+ )
247
+ )
248
+ if (props.captureScreen && Object.keys(props.captureScreen).length) {
249
+ attachment.push({
250
+ captureScreen: props.captureScreen,
251
+ })
252
+ }
253
+
254
+ const sendData = {
255
+ appCode: props.app || appkitOptions.app(),
256
+ content: formState.content,
257
+ id: '',
258
+ remarks: '',
259
+ title: '',
260
+ traceIds: props.traceIds,
261
+ device: 'MINI',
262
+ attachment: JSON.stringify(attachment),
263
+ }
264
+ $http
265
+ .post('/saas-base/problemFeedback/add', sendData)
266
+ .then(() => {
267
+ Taro.hideLoading()
268
+ emits('success')
269
+ // Taro.showToast({ title: '反馈提交成功', icon: 'none' })
270
+ // Taro.navigateBack()
271
+ isSuccess.value = true
272
+ clearFormState()
273
+ })
274
+ .catch(() => {
275
+ Taro.hideLoading()
276
+ })
277
+ }
278
+
279
+ // 反馈成功后,清空反馈内容
280
+ function clearFormState() {
281
+ formState.content = ''
282
+ formState.attachment = []
283
+ }
284
+
285
+ // 父组件事件
286
+ const emits = defineEmits(['minimize', 'success'])
287
+ </script>
288
+
289
+ <style lang="scss">
290
+ .user-feedback {
291
+ margin: 10px 12px;
292
+ padding-bottom: calc(75px + env(safe-area-inset-bottom, 0px));
293
+ min-height: 100vh;
294
+ box-sizing: border-box;
295
+ overflow: hidden;
296
+ &.isSuccess {
297
+ margin: 0;
298
+ padding: 0;
299
+ height: 100%;
300
+ .user-feedback-wrap {
301
+ height: 100vh;
302
+ align-items: center;
303
+ }
304
+ }
305
+ &-wrap {
306
+ min-height: calc(100vh - calc(75px + env(safe-area-inset-bottom, 0px)));
307
+ height: 100%;
308
+ background: #fff;
309
+ display: flex;
310
+ flex-direction: column;
311
+ box-sizing: border-box;
312
+ padding: 10px;
313
+ border-radius: 5px;
314
+ }
315
+ &-head {
316
+ background: #f2f9ff;
317
+ padding: 15px;
318
+ border-radius: 2px;
319
+ font-size: 12px;
320
+ margin-bottom: 8px;
321
+ &-info {
322
+ padding-left: 9px;
323
+ text-indent: -9px;
324
+ }
325
+ }
326
+ &-tit {
327
+ height: 44px;
328
+ display: flex;
329
+ align-items: center;
330
+ color: #1a1a1a;
331
+ font-weight: 500;
332
+ font-size: 17px;
333
+ }
334
+ &-body {
335
+ border-radius: 4px 4px 0px 0px;
336
+ display: flex;
337
+ flex-direction: column;
338
+ overflow: hidden;
339
+ }
340
+ &-editor {
341
+ padding: 10px;
342
+ font-size: 14px;
343
+ background: #f5f5f5;
344
+ overflow-y: auto;
345
+ min-height: 165px;
346
+ }
347
+ &-handle {
348
+ display: flex;
349
+ align-items: center;
350
+ flex-wrap: wrap;
351
+ margin-top: 10px;
352
+ margin-right: -4px;
353
+ &-item {
354
+ position: relative;
355
+ border-radius: 2px;
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: center;
359
+ width: 79px;
360
+ height: 79px;
361
+ background: #f5f5f5;
362
+ font-size: 30px;
363
+ color: rgba(53, 53, 53, 0.3);
364
+ margin-right: 4px;
365
+ margin-bottom: 4px;
366
+ &-img {
367
+ max-width: 100%;
368
+ max-height: 100%;
369
+ }
370
+ &-close {
371
+ position: absolute;
372
+ top: -2px;
373
+ right: -2px;
374
+ width: 20px;
375
+ height: 20px;
376
+ display: flex;
377
+ justify-content: center;
378
+ align-items: center;
379
+ &-img {
380
+ width: 10px;
381
+ height: 10px;
382
+ }
383
+ }
384
+ &-loading {
385
+ width: 17px;
386
+ height: 17px;
387
+ animation: rotate 2s linear infinite;
388
+ }
389
+ }
390
+ }
391
+ .ql-editor.ql-blank:before {
392
+ color: rgba(0, 0, 0, 0.3);
393
+ font-style: normal;
394
+ }
395
+
396
+ &-footer {
397
+ position: fixed;
398
+ z-index: 10;
399
+ bottom: 0;
400
+ left: 0;
401
+ width: 100%;
402
+ min-height: 63px;
403
+ background: #ffffff;
404
+ box-shadow: 0 -3px 11px 0 rgba(224, 224, 224, 0.5);
405
+ padding: 10px 12px calc(8px + env(safe-area-inset-bottom, 0px));
406
+ display: flex;
407
+ justify-content: space-between;
408
+ box-sizing: border-box;
409
+ &-btn {
410
+ flex: 1;
411
+ &:first-child {
412
+ margin-right: 10px;
413
+ }
414
+ }
415
+ }
416
+
417
+ &-success {
418
+ &-img {
419
+ width: 87px;
420
+ height: 90px;
421
+ margin-top: 110px;
422
+ margin-bottom: 20px;
423
+ }
424
+ &-info {
425
+ color: #353535;
426
+ font-size: 16px;
427
+ font-weight: 500;
428
+ }
429
+ }
430
+
431
+ @keyframes rotate {
432
+ from {
433
+ transform: rotate(0);
434
+ }
435
+ to {
436
+ transform: rotate(360deg);
437
+ }
438
+ }
439
+ }
440
+ </style>