@ruixinkeji/prism-ui 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 (48) hide show
  1. package/README.md +141 -0
  2. package/components/PrismAIAssist/PrismAIAssist.vue +98 -0
  3. package/components/PrismAddressInput/PrismAddressInput.vue +597 -0
  4. package/components/PrismCityCascadeSelect/PrismCityCascadeSelect.vue +793 -0
  5. package/components/PrismCityPicker/PrismCityPicker.vue +1008 -0
  6. package/components/PrismCitySelect/PrismCitySelect.vue +435 -0
  7. package/components/PrismCode/PrismCode.vue +749 -0
  8. package/components/PrismCodeInput/PrismCodeInput.vue +156 -0
  9. package/components/PrismDateTimePicker/PrismDateTimePicker.vue +953 -0
  10. package/components/PrismDropdown/PrismDropdown.vue +77 -0
  11. package/components/PrismGroupSticky/PrismGroupSticky.vue +352 -0
  12. package/components/PrismIdCardInput/PrismIdCardInput.vue +253 -0
  13. package/components/PrismImagePicker/PrismImagePicker.vue +457 -0
  14. package/components/PrismIndexBar/PrismIndexBar.vue +243 -0
  15. package/components/PrismLicensePlateInput/PrismLicensePlateInput.vue +1100 -0
  16. package/components/PrismMusicPlayer/PrismMusicPlayer.vue +530 -0
  17. package/components/PrismNavBar/PrismNavBar.vue +199 -0
  18. package/components/PrismSecureInput/PrismSecureInput.vue +360 -0
  19. package/components/PrismSticky/PrismSticky.vue +173 -0
  20. package/components/PrismSwiper/PrismSwiper.vue +339 -0
  21. package/components/PrismSwitch/PrismSwitch.vue +202 -0
  22. package/components/PrismTabBar/PrismTabBar.vue +147 -0
  23. package/components/PrismTabs/PrismTabs.vue +49 -0
  24. package/components/PrismVoiceInput/PrismVoiceInput.vue +529 -0
  25. package/index.d.ts +24 -0
  26. package/index.esm.js +25 -0
  27. package/index.js +25 -0
  28. package/package.json +89 -0
  29. package/styles/base.scss +227 -0
  30. package/styles/button.scss +120 -0
  31. package/styles/card.scss +306 -0
  32. package/styles/colors.scss +877 -0
  33. package/styles/data.scss +1229 -0
  34. package/styles/effects.scss +407 -0
  35. package/styles/feedback.scss +698 -0
  36. package/styles/form.scss +1574 -0
  37. package/styles/index.scss +46 -0
  38. package/styles/list.scss +184 -0
  39. package/styles/navigation.scss +554 -0
  40. package/styles/overlay.scss +182 -0
  41. package/styles/utilities.scss +134 -0
  42. package/styles/variables.scss +138 -0
  43. package/theme/blue.scss +36 -0
  44. package/theme/cyan.scss +32 -0
  45. package/theme/green.scss +32 -0
  46. package/theme/orange.scss +32 -0
  47. package/theme/purple.scss +32 -0
  48. package/theme/red.scss +32 -0
@@ -0,0 +1,77 @@
1
+ <template>
2
+ <view class="prism-dropdown">
3
+ <view class="prism-dropdown__bar">
4
+ <view
5
+ v-for="(item, index) in menuList"
6
+ :key="index"
7
+ class="prism-dropdown__item"
8
+ :class="{ 'prism-dropdown__item--active': activeIndex === index }"
9
+ @click="toggleDropdown(index)"
10
+ >
11
+ <text>{{ item.value }}</text>
12
+ <text class="prism-dropdown__arrow fa fa-chevron-down"></text>
13
+ </view>
14
+ </view>
15
+
16
+ <!-- 下拉面板 -->
17
+ <view
18
+ v-for="(item, index) in menuList"
19
+ :key="'popup-' + index"
20
+ class="prism-dropdown__popup"
21
+ :class="{ 'prism-dropdown__popup--show': activeIndex === index }"
22
+ >
23
+ <view
24
+ v-for="opt in item.options"
25
+ :key="opt"
26
+ class="prism-dropdown__option"
27
+ :class="{ 'prism-dropdown__option--selected': item.value === opt }"
28
+ @click="selectOption(index, opt)"
29
+ >
30
+ <text>{{ opt }}</text>
31
+ <text class="prism-dropdown__check fa fa-check"></text>
32
+ </view>
33
+ </view>
34
+
35
+ <!-- 遮罩层 -->
36
+ <view
37
+ class="prism-dropdown__mask"
38
+ :class="{ 'prism-dropdown__mask--show': activeIndex >= 0 }"
39
+ @click="closeDropdown"
40
+ ></view>
41
+ </view>
42
+ </template>
43
+
44
+ <script setup>
45
+ import { ref, watch } from 'vue';
46
+
47
+ const props = defineProps({
48
+ menus: {
49
+ type: Array,
50
+ required: true
51
+ // 格式: [{ title: '排序', value: '综合排序', options: ['综合排序', '销量优先'] }]
52
+ }
53
+ });
54
+
55
+ const emit = defineEmits(['change']);
56
+
57
+ const activeIndex = ref(-1);
58
+ const menuList = ref([...props.menus]);
59
+
60
+ watch(() => props.menus, (val) => {
61
+ menuList.value = [...val];
62
+ }, { deep: true });
63
+
64
+ function toggleDropdown(index) {
65
+ activeIndex.value = activeIndex.value === index ? -1 : index;
66
+ }
67
+
68
+ function closeDropdown() {
69
+ activeIndex.value = -1;
70
+ }
71
+
72
+ function selectOption(index, opt) {
73
+ menuList.value[index].value = opt;
74
+ activeIndex.value = -1;
75
+ emit('change', { index, value: opt, menu: menuList.value[index] });
76
+ }
77
+ </script>
@@ -0,0 +1,352 @@
1
+ <template>
2
+ <view class="prism-group-sticky-wrapper" :style="{ height: height }">
3
+ <scroll-view
4
+ class="prism-group-sticky"
5
+ scroll-y
6
+ :scroll-top="scrollTop"
7
+ :enhanced="true"
8
+ :show-scrollbar="false"
9
+ style="height: 100%"
10
+ @scroll="onScroll"
11
+ >
12
+ <slot></slot>
13
+ </scroll-view>
14
+
15
+ <!-- 右侧索引条 -->
16
+ <view
17
+ v-if="showIndexBar && indexList.length"
18
+ class="prism-index-bar"
19
+ @touchstart="onIndexTouchStart"
20
+ @touchmove.stop.prevent="onIndexTouchMove"
21
+ @touchend="onIndexTouchEnd"
22
+ >
23
+ <view
24
+ v-for="item in indexList"
25
+ :key="item"
26
+ class="index-item"
27
+ :class="{ active: currentIndex === item }"
28
+ >{{ item }}</view>
29
+ </view>
30
+
31
+ <!-- 气泡提示(移到索引条外部) -->
32
+ <view
33
+ v-if="showIndicator"
34
+ class="index-indicator"
35
+ :style="{ top: indicatorTop + 'px' }"
36
+ >{{ currentIndex }}</view>
37
+ </view>
38
+ </template>
39
+
40
+ <script setup>
41
+ import { ref, nextTick, getCurrentInstance } from 'vue';
42
+
43
+ const props = defineProps({
44
+ // 索引列表
45
+ indexList: {
46
+ type: Array,
47
+ default: () => []
48
+ },
49
+ // 是否显示索引条
50
+ showIndexBar: {
51
+ type: Boolean,
52
+ default: false
53
+ },
54
+ // 容器高度
55
+ height: {
56
+ type: String,
57
+ default: '100%'
58
+ }
59
+ });
60
+
61
+ const emit = defineEmits(['index-change']);
62
+ const instance = getCurrentInstance();
63
+
64
+ // 当前选中的索引
65
+ const currentIndex = ref('');
66
+ // 是否显示气泡
67
+ const showIndicator = ref(false);
68
+ // 气泡位置
69
+ const indicatorTop = ref(0);
70
+ // 滚动位置
71
+ const scrollTop = ref(0);
72
+ // 当前实际滚动位置
73
+ let currentScrollTop = 0;
74
+ // 索引条位置信息
75
+ let indexBarRect = null;
76
+ // 各分组位置缓存
77
+ let groupPositions = {};
78
+
79
+ // 根据触摸位置计算当前字母
80
+ const getLetterByTouch = (touchY) => {
81
+ if (!indexBarRect || !props.indexList.length) return '';
82
+ const itemHeight = indexBarRect.height / props.indexList.length;
83
+ const relativeY = touchY - indexBarRect.top;
84
+ const index = Math.floor(relativeY / itemHeight);
85
+ if (index < 0) return props.indexList[0];
86
+ if (index >= props.indexList.length) return props.indexList[props.indexList.length - 1];
87
+ return props.indexList[index];
88
+ };
89
+
90
+ // 计算各分组位置
91
+ const calculateGroupPositions = () => {
92
+ groupPositions = {};
93
+ props.indexList.forEach(letter => {
94
+ const el = document.getElementById(`group-${letter}`);
95
+ if (el) {
96
+ groupPositions[letter] = el.offsetTop;
97
+ }
98
+ });
99
+ };
100
+
101
+ // 滚动到指定字母
102
+ const scrollToLetter = (letter) => {
103
+ // 确保位置已计算
104
+ if (!groupPositions[letter]) {
105
+ calculateGroupPositions();
106
+ }
107
+
108
+ const targetTop = groupPositions[letter];
109
+ if (targetTop !== undefined) {
110
+ // 需要设置一个不同的值才能触发滚动
111
+ scrollTop.value = targetTop + 0.1;
112
+ nextTick(() => {
113
+ scrollTop.value = targetTop;
114
+ });
115
+ }
116
+ };
117
+
118
+ // 滚动事件
119
+ const onScroll = (e) => {
120
+ currentScrollTop = e.detail.scrollTop;
121
+ };
122
+
123
+ // 更新选中字母
124
+ const updateLetter = (touchY) => {
125
+ // 更新气泡位置
126
+ indicatorTop.value = touchY;
127
+
128
+ const letter = getLetterByTouch(touchY);
129
+ if (letter) {
130
+ // 每次都更新 currentIndex,确保激活状态及时变化
131
+ currentIndex.value = letter;
132
+ scrollToLetter(letter);
133
+ emit('index-change', letter);
134
+ }
135
+ };
136
+
137
+ // 触摸开始
138
+ const onIndexTouchStart = (e) => {
139
+ showIndicator.value = true;
140
+ const touchY = e.touches[0].clientY;
141
+ indicatorTop.value = touchY;
142
+
143
+ // 获取索引条位置并更新字母
144
+ uni.createSelectorQuery()
145
+ .in(instance)
146
+ .select('.prism-index-bar')
147
+ .boundingClientRect((rect) => {
148
+ if (rect) {
149
+ indexBarRect = rect;
150
+ const letter = getLetterByTouch(touchY);
151
+ if (letter) {
152
+ currentIndex.value = letter;
153
+ scrollToLetter(letter);
154
+ emit('index-change', letter);
155
+ }
156
+ }
157
+ })
158
+ .exec();
159
+ };
160
+
161
+ // 触摸移动
162
+ const onIndexTouchMove = (e) => {
163
+ const touchY = e.touches[0].clientY;
164
+ if (indexBarRect) {
165
+ updateLetter(touchY);
166
+ }
167
+ };
168
+
169
+ // 触摸结束
170
+ const onIndexTouchEnd = () => {
171
+ showIndicator.value = false;
172
+ };
173
+ </script>
174
+
175
+ <style lang="scss">
176
+ .prism-group-sticky-wrapper {
177
+ position: relative;
178
+ height: 100%;
179
+ }
180
+
181
+ .prism-group-sticky {
182
+ height: 100%;
183
+
184
+ // H5 环境下让 scroll-view 内部容器支持 sticky
185
+ :deep(.uni-scroll-view-content) {
186
+ height: auto !important;
187
+ }
188
+
189
+ // 分组索引头(吸顶)
190
+ :deep(.group-index) {
191
+ position: -webkit-sticky;
192
+ position: sticky;
193
+ top: -1px;
194
+ z-index: 10;
195
+ margin: 0;
196
+ padding: 12rpx 24rpx;
197
+ padding-top: calc(12rpx + 1px);
198
+ font-size: 26rpx;
199
+ font-weight: 600;
200
+ color: var(--prism-primary-color, #3478F6);
201
+ background: var(--prism-bg-color-page, #F7F8FA);
202
+ }
203
+
204
+ .dark-mode & :deep(.group-index) {
205
+ background: var(--prism-bg-color-page, #121212);
206
+ }
207
+
208
+ // 分组内容项
209
+ :deep(.group-item) {
210
+ display: flex;
211
+ align-items: center;
212
+ min-height: 88rpx;
213
+ padding: 24rpx 32rpx;
214
+ background: var(--prism-bg-color-card, #FFFFFF);
215
+ border-bottom: 1rpx solid var(--prism-border-color-light, #F2F3F5);
216
+ font-size: 28rpx;
217
+ color: var(--prism-text-primary, #1D2129);
218
+ }
219
+
220
+ .dark-mode & :deep(.group-item) {
221
+ background: var(--prism-bg-color-card, #242424);
222
+ border-bottom-color: var(--prism-border-color-light, #2D2D2D);
223
+ }
224
+
225
+ // 每个分组的最后一个 item(后面紧跟 group-index 或者是最后一个)
226
+ :deep(.group-item:has(+ .group-index)),
227
+ :deep(.group-item:last-child) {
228
+ border-radius: 0 0 16rpx 16rpx;
229
+ border-bottom: none;
230
+ }
231
+
232
+ :deep(.group-item:active) {
233
+ background: var(--prism-bg-color, #F2F2F2);
234
+ }
235
+
236
+ .dark-mode & :deep(.group-item:active) {
237
+ background: var(--prism-bg-color, #1A1A1A);
238
+ }
239
+
240
+ // 第一个 group-item(紧跟在 group-index 后面)- 顶部圆角
241
+ :deep(.group-index + .group-item) {
242
+ border-radius: 16rpx 16rpx 0 0;
243
+ }
244
+
245
+ // 分组只有一个 item 时 - 全圆角
246
+ :deep(.group-index + .group-item:has(+ .group-index)),
247
+ :deep(.group-index + .group-item:last-child) {
248
+ border-radius: 16rpx;
249
+ }
250
+
251
+ // 头像(可选)
252
+ .group-avatar {
253
+ width: 80rpx;
254
+ height: 80rpx;
255
+ border-radius: 50%;
256
+ margin-right: 24rpx;
257
+ background: var(--prism-primary-light, #EBF2FF);
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ font-size: 28rpx;
262
+ font-weight: 600;
263
+ color: var(--prism-primary-color, #3478F6);
264
+ flex-shrink: 0;
265
+
266
+ .dark-mode & {
267
+ background: rgba(52, 120, 246, 0.15);
268
+ }
269
+ }
270
+
271
+ // 信息区(可选)
272
+ .group-info {
273
+ flex: 1;
274
+ min-width: 0;
275
+
276
+ .group-title {
277
+ font-size: 30rpx;
278
+ font-weight: 500;
279
+ color: var(--prism-text-primary, #1D2129);
280
+ margin-bottom: 4rpx;
281
+
282
+ .dark-mode & {
283
+ color: var(--prism-text-primary, #E5E6EB);
284
+ }
285
+ }
286
+
287
+ .group-desc {
288
+ font-size: 24rpx;
289
+ color: var(--prism-text-secondary, #86909C);
290
+ overflow: hidden;
291
+ text-overflow: ellipsis;
292
+ white-space: nowrap;
293
+ }
294
+ }
295
+ }
296
+
297
+ // 右侧索引条
298
+ .prism-index-bar {
299
+ position: absolute;
300
+ right: 0;
301
+ top: 50%;
302
+ transform: translateY(-50%);
303
+ z-index: 100;
304
+ display: flex;
305
+ flex-direction: column;
306
+ align-items: center;
307
+ padding: 12rpx 16rpx 12rpx 24rpx;
308
+ background: rgba(255, 255, 255, 0.02);
309
+ border-radius: 20rpx 0 0 20rpx;
310
+ -webkit-backdrop-filter: blur(8px);
311
+ backdrop-filter: blur(8px);
312
+
313
+ .index-item {
314
+ width: 36rpx;
315
+ height: 36rpx;
316
+ display: flex;
317
+ align-items: center;
318
+ justify-content: center;
319
+ font-size: 22rpx;
320
+ color: var(--prism-text-primary, #1D2129);
321
+ font-weight: 500;
322
+ background: transparent;
323
+
324
+ &:active,
325
+ &.active {
326
+ color: var(--prism-primary-color, #3478F6);
327
+ font-weight: 600;
328
+ }
329
+ }
330
+ }
331
+
332
+ // 气泡提示
333
+ .index-indicator {
334
+ position: fixed;
335
+ right: 120rpx;
336
+ width: 100rpx;
337
+ height: 100rpx;
338
+ margin-top: -50rpx;
339
+ border-radius: 50%;
340
+ background: rgba(52, 120, 246, 0.8);
341
+ -webkit-backdrop-filter: blur(10px);
342
+ backdrop-filter: blur(10px);
343
+ color: #FFFFFF;
344
+ font-size: 48rpx;
345
+ font-weight: 600;
346
+ display: flex;
347
+ align-items: center;
348
+ justify-content: center;
349
+ box-shadow: 0 8rpx 32rpx rgba(52, 120, 246, 0.3);
350
+ z-index: 1000;
351
+ }
352
+ </style>
@@ -0,0 +1,253 @@
1
+ <template>
2
+ <view class="prism-id-card-input" :class="{ 'dark-mode': appStore.isDarkMode }">
3
+ <!-- 身份证号输入框 -->
4
+ <view class="id-card-input-wrapper">
5
+ <input
6
+ class="id-card-input"
7
+ type="idcard"
8
+ :value="displayValue"
9
+ :placeholder="placeholder"
10
+ placeholder-class="id-placeholder"
11
+ :maxlength="21"
12
+ @input="handleInput"
13
+ @focus="onFocus"
14
+ @blur="onBlur"
15
+ />
16
+ </view>
17
+
18
+ <!-- 身份证信息解析 -->
19
+ <view class="id-info" v-if="showInfo && parsedInfo.valid">
20
+ <view class="info-item">
21
+ <text class="info-label">地区:</text>
22
+ <text class="info-value">{{ parsedInfo.region }}</text>
23
+ </view>
24
+ <view class="info-item">
25
+ <text class="info-label">出生日期:</text>
26
+ <text class="info-value">{{ parsedInfo.birthday }}</text>
27
+ </view>
28
+ <view class="info-item">
29
+ <text class="info-label">性别:</text>
30
+ <text class="info-value">{{ parsedInfo.gender }}</text>
31
+ </view>
32
+ </view>
33
+ </view>
34
+ </template>
35
+
36
+ <script setup>
37
+ import { ref, computed, watch } from 'vue';
38
+ import { useAppStore } from '@/store/app';
39
+
40
+ const props = defineProps({
41
+ modelValue: {
42
+ type: String,
43
+ default: ''
44
+ },
45
+ showInfo: {
46
+ type: Boolean,
47
+ default: true
48
+ },
49
+ placeholder: {
50
+ type: String,
51
+ default: '请输入身份证号'
52
+ }
53
+ });
54
+
55
+ const emit = defineEmits(['update:modelValue', 'complete', 'valid']);
56
+
57
+ const appStore = useAppStore();
58
+ const idValue = ref(props.modelValue);
59
+ const lastDisplayLength = ref(0);
60
+
61
+ // 格式化显示值(6-8-4 格式,用空格分隔)
62
+ const displayValue = computed(() => {
63
+ const val = idValue.value;
64
+ if (!val) return '';
65
+
66
+ let result = '';
67
+ for (let i = 0; i < val.length; i++) {
68
+ if (i === 6 || i === 14) {
69
+ result += ' ';
70
+ }
71
+ result += val[i];
72
+ }
73
+ return result;
74
+ });
75
+
76
+ // 解析身份证信息
77
+ const parsedInfo = computed(() => {
78
+ const id = idValue.value;
79
+ if (id.length !== 18) {
80
+ return { valid: false };
81
+ }
82
+
83
+ // 验证校验码
84
+ const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
85
+ const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
86
+ let sum = 0;
87
+ for (let i = 0; i < 17; i++) {
88
+ sum += parseInt(id[i]) * weights[i];
89
+ }
90
+ const checkCode = checkCodes[sum % 11];
91
+ if (id[17].toUpperCase() !== checkCode) {
92
+ return { valid: false };
93
+ }
94
+
95
+ // 解析出生日期
96
+ const year = id.substring(6, 10);
97
+ const month = id.substring(10, 12);
98
+ const day = id.substring(12, 14);
99
+ const birthday = `${year}年${month}月${day}日`;
100
+
101
+ // 解析性别
102
+ const genderCode = parseInt(id[16]);
103
+ const gender = genderCode % 2 === 1 ? '男' : '女';
104
+
105
+ return {
106
+ valid: true,
107
+ region: '—',
108
+ birthday,
109
+ gender
110
+ };
111
+ });
112
+
113
+ function onFocus() {
114
+ // 焦点事件
115
+ }
116
+
117
+ function onBlur() {
118
+ // 失焦事件
119
+ }
120
+
121
+ function handleInput(e) {
122
+ const inputValue = e.detail.value;
123
+ const oldLength = lastDisplayLength.value;
124
+ const newLength = inputValue.length;
125
+
126
+ // 去掉空格,只允许数字和X
127
+ let value = inputValue.replace(/\s/g, '').toUpperCase().replace(/[^0-9X]/g, '');
128
+
129
+ // 判断是否是删除操作,并且删除到了空格位置
130
+ // 空格位置在显示值的第7位(索引6)和第16位(索引15)
131
+ if (newLength < oldLength) {
132
+ // 删除操作
133
+ const deletedPos = oldLength - 1;
134
+ // 如果删除的是空格后的第一个字符,需要额外删除一个字符
135
+ if (deletedPos === 7 || deletedPos === 16) {
136
+ // 删除到空格位置了,再删一个
137
+ const actualPos = deletedPos === 7 ? 6 : 14;
138
+ value = value.slice(0, actualPos - 1) + value.slice(actualPos);
139
+ }
140
+ }
141
+
142
+ // X只能在最后一位
143
+ if (value.length < 18) {
144
+ value = value.replace(/X/g, '');
145
+ } else if (value.length === 18 && value[17] === 'X') {
146
+ value = value.slice(0, 17).replace(/X/g, '') + 'X';
147
+ } else {
148
+ value = value.replace(/X/g, '');
149
+ }
150
+
151
+ value = value.slice(0, 18);
152
+ idValue.value = value;
153
+ emit('update:modelValue', value);
154
+
155
+ // 更新上次显示长度
156
+ lastDisplayLength.value = displayValue.value.length;
157
+
158
+ if (value.length === 18) {
159
+ emit('complete', value);
160
+ if (parsedInfo.value.valid) {
161
+ emit('valid', parsedInfo.value);
162
+ }
163
+ }
164
+ }
165
+
166
+ watch(() => props.modelValue, (val) => {
167
+ idValue.value = val;
168
+ });
169
+ </script>
170
+
171
+ <style lang="scss">
172
+ .prism-id-card-input {
173
+ .id-card-input-wrapper {
174
+ background: var(--prism-input-bg, #EBEEF2);
175
+ border-radius: 12rpx;
176
+ padding: 0 24rpx;
177
+ height: 88rpx;
178
+ display: flex;
179
+ align-items: center;
180
+ transition: all 0.3s ease;
181
+
182
+ &:focus-within {
183
+ background: var(--prism-primary-light, #E3EEFF);
184
+ }
185
+ }
186
+
187
+ .id-card-input {
188
+ flex: 1;
189
+ font-size: 32rpx;
190
+ font-weight: 500;
191
+ color: var(--prism-text-primary, #1D2129);
192
+ letter-spacing: 2rpx;
193
+ }
194
+
195
+ .id-placeholder {
196
+ color: var(--prism-text-placeholder, #86909C);
197
+ font-weight: 400;
198
+ }
199
+
200
+ .id-info {
201
+ margin-top: 24rpx;
202
+ padding: 20rpx;
203
+ background: rgba(52, 120, 246, 0.08);
204
+ border-radius: 12rpx;
205
+ display: flex;
206
+ flex-wrap: wrap;
207
+ gap: 16rpx;
208
+
209
+ .info-item {
210
+ display: flex;
211
+ align-items: center;
212
+
213
+ .info-label {
214
+ font-size: 24rpx;
215
+ color: var(--prism-text-secondary, #86909C);
216
+ }
217
+
218
+ .info-value {
219
+ font-size: 24rpx;
220
+ color: var(--prism-text-primary, #1D2129);
221
+ font-weight: 500;
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ .dark-mode .prism-id-card-input {
228
+ .id-card-input-wrapper {
229
+ background: var(--prism-input-bg, #2A2A2A);
230
+
231
+ &:focus-within {
232
+ background: rgba(52, 120, 246, 0.12);
233
+ box-shadow: 0 0 0 2rpx rgba(52, 120, 246, 0.4), 0 4rpx 16rpx rgba(52, 120, 246, 0.15);
234
+ }
235
+ }
236
+
237
+ .id-card-input {
238
+ color: var(--prism-text-primary, #E5E6EB);
239
+ }
240
+
241
+ .id-placeholder {
242
+ color: var(--prism-text-placeholder, #6B7785);
243
+ }
244
+
245
+ .id-info {
246
+ background: rgba(52, 120, 246, 0.15);
247
+
248
+ .info-value {
249
+ color: var(--prism-text-primary, #E5E6EB);
250
+ }
251
+ }
252
+ }
253
+ </style>