im-ui-mobile 0.1.10 → 0.1.11
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.
- package/components/im-avatar/im-avatar.vue +1 -1
- package/components/im-badge/im-badge.vue +1 -1
- package/components/im-button/im-button.vue +1 -1
- package/components/im-card/im-card.vue +1 -1
- package/components/im-cell/im-cell.vue +1 -1
- package/components/im-cell-switch/im-cell-switch.vue +1 -1
- package/components/im-chat-item/im-chat-item.vue +3 -3
- package/components/im-col/im-col.vue +30 -35
- package/components/im-context-menu/im-context-menu.vue +1 -1
- package/components/im-dialog/im-dialog.vue +1 -1
- package/components/im-group-rtc-join/im-group-rtc-join.vue +2 -2
- package/components/im-parse/im-parse.vue +129 -160
- package/components/im-read-receipt/im-read-receipt.vue +1 -1
- package/components/im-sku/im-sku.vue +1 -0
- package/components/im-stepper/im-stepper.vue +2 -2
- package/libs/index.ts +1 -1
- package/package.json +1 -1
- package/types/components/nav-bar.d.ts +1 -0
- package/types/components/sku.d.ts +7 -7
- package/types/index.d.ts +3 -1
- package/types/libs/index.d.ts +1 -1
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script setup lang="ts">
|
|
99
|
-
import { computed, useSlots } from 'vue'
|
|
99
|
+
import { ref, computed, watch, nextTick, useSlots } from 'vue'
|
|
100
100
|
|
|
101
101
|
// 定义类型
|
|
102
102
|
type CellType = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<view class="chat-content">
|
|
16
16
|
<view class="chat-at-text">{{ atText }}</view>
|
|
17
17
|
<view class="chat-send-name" v-if="isShowSendName">{{ chat.sendNickName + ': ' }}</view>
|
|
18
|
-
<view v-if="!isTextMessage" class="chat-content-text">{{ chat.
|
|
18
|
+
<view v-if="!isTextMessage" class="chat-content-text">{{ chat.lastMessage }}</view>
|
|
19
19
|
<rich-text v-else class="chat-content-text" :nodes="nodesText"></rich-text>
|
|
20
20
|
<view v-if="chat.isDnd" class="icon iconfont icon-dnd"></view>
|
|
21
21
|
<im-badge v-if="chat.unreadCount > 0" size="small" :max="99" :value="chat.unreadCount" />
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</template>
|
|
26
26
|
|
|
27
27
|
<script setup lang="ts">
|
|
28
|
-
import { computed } from 'vue'
|
|
28
|
+
import { ref, computed, watch, nextTick, useSlots } from 'vue'
|
|
29
29
|
import ImAvatar from '../im-avatar/im-avatar.vue'
|
|
30
30
|
import ImBadge from '../im-badge/im-badge.vue'
|
|
31
31
|
import { datetime, dom, messageType, emoji } from '../../index'
|
|
@@ -82,7 +82,7 @@ const isTextMessage = computed(() => {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
const nodesText = computed(() => {
|
|
85
|
-
const text = dom.html2Escape(props.chat?.
|
|
85
|
+
const text = dom.html2Escape(props.chat?.lastMessage || '');
|
|
86
86
|
return emoji.transform(text, 'emoji-small');
|
|
87
87
|
});
|
|
88
88
|
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{ 'im-col--gutter': hasGutter }
|
|
10
|
-
]"
|
|
11
|
-
:style="colStyle"
|
|
12
|
-
@tap="handleClick"
|
|
13
|
-
>
|
|
2
|
+
<view class="im-col" :class="[
|
|
3
|
+
`im-col--span-${span}`,
|
|
4
|
+
`im-col--offset-${offset}`,
|
|
5
|
+
`im-col--order-${order}`,
|
|
6
|
+
`im-col--align-self-${alignSelf}`,
|
|
7
|
+
{ 'im-col--gutter': hasGutter }
|
|
8
|
+
]" :style="colStyle" @tap="handleClick">
|
|
14
9
|
<slot></slot>
|
|
15
10
|
</view>
|
|
16
11
|
</template>
|
|
17
12
|
|
|
18
13
|
<script setup lang="ts">
|
|
19
|
-
import { computed, inject } from 'vue'
|
|
14
|
+
import { ref, computed, watch, nextTick, useSlots, inject } from 'vue'
|
|
20
15
|
|
|
21
16
|
// 定义 Props
|
|
22
17
|
interface Props {
|
|
@@ -26,14 +21,14 @@ interface Props {
|
|
|
26
21
|
order?: number | string
|
|
27
22
|
alignSelf?: 'auto' | 'start' | 'end' | 'center' | 'stretch'
|
|
28
23
|
flex?: string
|
|
29
|
-
|
|
24
|
+
|
|
30
25
|
// 响应式配置
|
|
31
26
|
xs?: number | string
|
|
32
27
|
sm?: number | string
|
|
33
28
|
md?: number | string
|
|
34
29
|
lg?: number | string
|
|
35
30
|
xl?: number | string
|
|
36
|
-
|
|
31
|
+
|
|
37
32
|
// 样式配置
|
|
38
33
|
width?: string
|
|
39
34
|
height?: string
|
|
@@ -42,7 +37,7 @@ interface Props {
|
|
|
42
37
|
bgColor?: string
|
|
43
38
|
borderColor?: string
|
|
44
39
|
borderRadius?: string
|
|
45
|
-
|
|
40
|
+
|
|
46
41
|
// 点击事件
|
|
47
42
|
clickable?: boolean
|
|
48
43
|
}
|
|
@@ -59,13 +54,13 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
59
54
|
order: 0,
|
|
60
55
|
alignSelf: 'auto',
|
|
61
56
|
flex: 'none',
|
|
62
|
-
|
|
57
|
+
|
|
63
58
|
xs: 0,
|
|
64
59
|
sm: 0,
|
|
65
60
|
md: 0,
|
|
66
61
|
lg: 0,
|
|
67
62
|
xl: 0,
|
|
68
|
-
|
|
63
|
+
|
|
69
64
|
width: 'auto',
|
|
70
65
|
height: 'auto',
|
|
71
66
|
margin: '0',
|
|
@@ -73,7 +68,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
73
68
|
bgColor: 'transparent',
|
|
74
69
|
borderColor: 'transparent',
|
|
75
70
|
borderRadius: '0',
|
|
76
|
-
|
|
71
|
+
|
|
77
72
|
clickable: false
|
|
78
73
|
})
|
|
79
74
|
|
|
@@ -107,28 +102,28 @@ const colStyle = computed(() => {
|
|
|
107
102
|
order: props.order,
|
|
108
103
|
alignSelf: props.alignSelf
|
|
109
104
|
}
|
|
110
|
-
|
|
105
|
+
|
|
111
106
|
// 设置 flex
|
|
112
107
|
if (props.flex !== 'none') {
|
|
113
108
|
style.flex = props.flex
|
|
114
109
|
}
|
|
115
|
-
|
|
110
|
+
|
|
116
111
|
// 设置边框
|
|
117
112
|
if (props.borderColor !== 'transparent') {
|
|
118
113
|
style.borderWidth = '2rpx'
|
|
119
114
|
style.borderStyle = 'solid'
|
|
120
115
|
}
|
|
121
|
-
|
|
116
|
+
|
|
122
117
|
// 设置 gutter
|
|
123
118
|
if (hasGutter.value) {
|
|
124
|
-
const gutter = typeof rowContext.gutter === 'number'
|
|
125
|
-
? `${rowContext.gutter}rpx`
|
|
119
|
+
const gutter = typeof rowContext.gutter === 'number'
|
|
120
|
+
? `${rowContext.gutter}rpx`
|
|
126
121
|
: rowContext.gutter
|
|
127
|
-
|
|
122
|
+
|
|
128
123
|
style.paddingLeft = `calc(${gutter} / 2)`
|
|
129
124
|
style.paddingRight = `calc(${gutter} / 2)`
|
|
130
125
|
}
|
|
131
|
-
|
|
126
|
+
|
|
132
127
|
return style
|
|
133
128
|
})
|
|
134
129
|
|
|
@@ -144,43 +139,43 @@ const handleClick = (event: any) => {
|
|
|
144
139
|
.im-col {
|
|
145
140
|
box-sizing: border-box;
|
|
146
141
|
position: relative;
|
|
147
|
-
|
|
142
|
+
|
|
148
143
|
// 基本 span 类
|
|
149
144
|
@for $i from 1 through 24 {
|
|
150
145
|
&--span-#{$i} {
|
|
151
146
|
width: calc(100% * $i / 24);
|
|
152
147
|
}
|
|
153
|
-
|
|
148
|
+
|
|
154
149
|
&--offset-#{$i} {
|
|
155
150
|
margin-left: calc(100% * $i / 24);
|
|
156
151
|
}
|
|
157
|
-
|
|
152
|
+
|
|
158
153
|
&--order-#{$i} {
|
|
159
154
|
order: $i;
|
|
160
155
|
}
|
|
161
156
|
}
|
|
162
|
-
|
|
157
|
+
|
|
163
158
|
// 对齐方式
|
|
164
159
|
&--align-self-auto {
|
|
165
160
|
align-self: auto;
|
|
166
161
|
}
|
|
167
|
-
|
|
162
|
+
|
|
168
163
|
&--align-self-start {
|
|
169
164
|
align-self: flex-start;
|
|
170
165
|
}
|
|
171
|
-
|
|
166
|
+
|
|
172
167
|
&--align-self-end {
|
|
173
168
|
align-self: flex-end;
|
|
174
169
|
}
|
|
175
|
-
|
|
170
|
+
|
|
176
171
|
&--align-self-center {
|
|
177
172
|
align-self: center;
|
|
178
173
|
}
|
|
179
|
-
|
|
174
|
+
|
|
180
175
|
&--align-self-stretch {
|
|
181
176
|
align-self: stretch;
|
|
182
177
|
}
|
|
183
|
-
|
|
178
|
+
|
|
184
179
|
// 点击效果
|
|
185
180
|
&:active {
|
|
186
181
|
&.im-col--clickable {
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
</template>
|
|
97
97
|
|
|
98
98
|
<script setup lang="ts">
|
|
99
|
-
import { ref, computed, watch, nextTick } from 'vue'
|
|
99
|
+
import { ref, computed, watch, nextTick, useSlots } from 'vue'
|
|
100
100
|
import type { Modal as ModalType } from 'im-ui-mobile'
|
|
101
101
|
import ImModal from '../im-modal/im-modal.vue'
|
|
102
102
|
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<script setup lang="ts">
|
|
25
|
+
import { ref, computed, watch, nextTick, useSlots } from 'vue'
|
|
25
26
|
import ImAvatar from '../im-avatar/im-avatar.vue'
|
|
26
27
|
import ImPopup from '../im-popup/im-popup.vue'
|
|
27
28
|
import ImModal from '../im-modal/im-modal.vue'
|
|
28
|
-
import {
|
|
29
|
-
import { UserInfo } from '../../libs';
|
|
29
|
+
import { UserInfo } from '../../libs'
|
|
30
30
|
|
|
31
31
|
interface Props {
|
|
32
32
|
groupId?: number;
|
|
@@ -2,94 +2,62 @@
|
|
|
2
2
|
<view class="im-parse" :class="customClass" :style="customStyle">
|
|
3
3
|
<!-- 解析模式 -->
|
|
4
4
|
<template v-if="mode === 'html' && content">
|
|
5
|
-
<rich-text v-if="useRichText"
|
|
6
|
-
|
|
7
|
-
:nodes="dom.nodesToHtml(parsedNodes)"
|
|
8
|
-
/>
|
|
9
|
-
<view
|
|
10
|
-
v-else
|
|
11
|
-
class="im-parse__html"
|
|
12
|
-
v-html="content"
|
|
13
|
-
@tap="handleHtmlTap"
|
|
14
|
-
/>
|
|
5
|
+
<rich-text v-if="useRichText" :id="richTextId" :nodes="dom.nodesToHtml(parsedNodes)" />
|
|
6
|
+
<view v-else class="im-parse__html" v-html="content" @tap="handleHtmlTap" />
|
|
15
7
|
</template>
|
|
16
|
-
|
|
8
|
+
|
|
17
9
|
<!-- 文本模式 -->
|
|
18
10
|
<template v-else-if="mode === 'text' && content">
|
|
19
|
-
<text
|
|
20
|
-
class="im-parse__text"
|
|
21
|
-
:style="textStyle"
|
|
22
|
-
@tap="handleTextTap"
|
|
23
|
-
>
|
|
11
|
+
<text class="im-parse__text" :style="textStyle" @tap="handleTextTap">
|
|
24
12
|
{{ processedText }}
|
|
25
13
|
</text>
|
|
26
14
|
</template>
|
|
27
|
-
|
|
15
|
+
|
|
28
16
|
<!-- Markdown 模式 -->
|
|
29
17
|
<template v-else-if="mode === 'markdown' && content">
|
|
30
18
|
<view class="im-parse__markdown">
|
|
31
19
|
<template v-for="(node, index) in markdownNodes" :key="index">
|
|
32
20
|
<!-- 标题 -->
|
|
33
|
-
<view
|
|
34
|
-
v-if="node.type === 'heading'"
|
|
35
|
-
class="im-parse__heading"
|
|
36
|
-
:class="`im-parse__heading--${node.depth}`"
|
|
37
|
-
>
|
|
21
|
+
<view v-if="node.type === 'heading'" class="im-parse__heading" :class="`im-parse__heading--${node.depth}`">
|
|
38
22
|
<text>{{ node.text }}</text>
|
|
39
23
|
</view>
|
|
40
|
-
|
|
24
|
+
|
|
41
25
|
<!-- 段落 -->
|
|
42
|
-
<view
|
|
43
|
-
v-else-if="node.type === 'paragraph'"
|
|
44
|
-
class="im-parse__paragraph"
|
|
45
|
-
>
|
|
26
|
+
<view v-else-if="node.type === 'paragraph'" class="im-parse__paragraph">
|
|
46
27
|
<text>{{ node.text }}</text>
|
|
47
28
|
</view>
|
|
48
|
-
|
|
29
|
+
|
|
49
30
|
<!-- 列表 -->
|
|
50
|
-
<view
|
|
51
|
-
|
|
52
|
-
class="im-parse__list"
|
|
53
|
-
:class="{ 'im-parse__list--ordered': node.ordered }"
|
|
54
|
-
>
|
|
55
|
-
<view
|
|
56
|
-
v-for="(item, itemIndex) in node.items"
|
|
57
|
-
:key="itemIndex"
|
|
58
|
-
class="im-parse__list-item"
|
|
59
|
-
>
|
|
31
|
+
<view v-else-if="node.type === 'list'" class="im-parse__list"
|
|
32
|
+
:class="{ 'im-parse__list--ordered': node.ordered }">
|
|
33
|
+
<view v-for="(item, itemIndex) in node.items" :key="itemIndex" class="im-parse__list-item">
|
|
60
34
|
<view class="im-parse__list-marker">
|
|
61
35
|
{{ node.ordered ? `${Number(itemIndex) + 1}.` : '•' }}
|
|
62
36
|
</view>
|
|
63
37
|
<text class="im-parse__list-text">{{ item }}</text>
|
|
64
38
|
</view>
|
|
65
39
|
</view>
|
|
66
|
-
|
|
40
|
+
|
|
67
41
|
<!-- 引用 -->
|
|
68
|
-
<view
|
|
69
|
-
v-else-if="node.type === 'blockquote'"
|
|
70
|
-
class="im-parse__blockquote"
|
|
71
|
-
>
|
|
42
|
+
<view v-else-if="node.type === 'blockquote'" class="im-parse__blockquote">
|
|
72
43
|
<text>{{ node.text }}</text>
|
|
73
44
|
</view>
|
|
74
|
-
|
|
45
|
+
|
|
75
46
|
<!-- 代码块 -->
|
|
76
|
-
<view
|
|
77
|
-
v-else-if="node.type === 'code'"
|
|
78
|
-
class="im-parse__code-block"
|
|
79
|
-
>
|
|
47
|
+
<view v-else-if="node.type === 'code'" class="im-parse__code-block">
|
|
80
48
|
<text class="im-parse__code-text">{{ node.text }}</text>
|
|
81
49
|
</view>
|
|
82
50
|
</template>
|
|
83
51
|
</view>
|
|
84
52
|
</template>
|
|
85
|
-
|
|
53
|
+
|
|
86
54
|
<!-- JSON 模式 -->
|
|
87
55
|
<template v-else-if="mode === 'json' && content">
|
|
88
56
|
<view class="im-parse__json">
|
|
89
57
|
<pre class="im-parse__json-pre">{{ formattedJson }}</pre>
|
|
90
58
|
</view>
|
|
91
59
|
</template>
|
|
92
|
-
|
|
60
|
+
|
|
93
61
|
<!-- 默认插槽 -->
|
|
94
62
|
<slot v-if="!content" name="default"></slot>
|
|
95
63
|
</view>
|
|
@@ -97,7 +65,7 @@
|
|
|
97
65
|
|
|
98
66
|
<script setup lang="ts">
|
|
99
67
|
import { ref, computed, watch } from 'vue'
|
|
100
|
-
import type{LinkData,ParseOptions} from "../../types/components/parse";
|
|
68
|
+
import type { LinkData, ParseOptions } from "../../types/components/parse";
|
|
101
69
|
import { emoji, dom } from '../../index'
|
|
102
70
|
|
|
103
71
|
// 定义 Props
|
|
@@ -105,19 +73,19 @@ interface Props {
|
|
|
105
73
|
// 内容
|
|
106
74
|
content?: string
|
|
107
75
|
modelValue?: string
|
|
108
|
-
|
|
76
|
+
|
|
109
77
|
// 解析选项
|
|
110
78
|
options?: ParseOptions
|
|
111
79
|
|
|
112
80
|
// 解析模式
|
|
113
81
|
mode?: 'html' | 'text' | 'markdown' | 'json'
|
|
114
82
|
encoding?: 'utf-8' | 'base64' | 'url'
|
|
115
|
-
|
|
83
|
+
|
|
116
84
|
// 通用配置
|
|
117
85
|
maxLength?: number
|
|
118
86
|
ellipsis?: string
|
|
119
87
|
lines?: number
|
|
120
|
-
|
|
88
|
+
|
|
121
89
|
// HTML 配置
|
|
122
90
|
useRichText?: boolean
|
|
123
91
|
space?: 'ensp' | 'emsp' | 'nbsp'
|
|
@@ -125,19 +93,19 @@ interface Props {
|
|
|
125
93
|
allowTags?: string[]
|
|
126
94
|
allowAttributes?: Record<string, string[]>
|
|
127
95
|
allowDomains?: string[]
|
|
128
|
-
|
|
96
|
+
|
|
129
97
|
// 样式配置
|
|
130
98
|
customClass?: string
|
|
131
99
|
customStyle?: string | Record<string, string>
|
|
132
100
|
textStyle?: string | Record<string, string>
|
|
133
|
-
|
|
101
|
+
|
|
134
102
|
// 功能配置
|
|
135
103
|
autolink?: boolean
|
|
136
104
|
emoji?: boolean
|
|
137
105
|
highlight?: boolean
|
|
138
106
|
lazyLoad?: boolean
|
|
139
107
|
errorFallback?: string
|
|
140
|
-
|
|
108
|
+
|
|
141
109
|
// 事件配置
|
|
142
110
|
preventDefault?: boolean
|
|
143
111
|
}
|
|
@@ -146,7 +114,7 @@ interface Props {
|
|
|
146
114
|
interface Emits {
|
|
147
115
|
(e: 'update:modelValue', value: string): void
|
|
148
116
|
(e: 'click', event: any): void
|
|
149
|
-
(e:'link-click',link: LinkData, event?: Event):void
|
|
117
|
+
(e: 'link-click', link: LinkData, event?: Event): void
|
|
150
118
|
(e: 'linkpress', url: string): void
|
|
151
119
|
(e: 'imageerror', src: string, error: Error): void
|
|
152
120
|
(e: 'imageload', src: string): void
|
|
@@ -158,7 +126,7 @@ interface Emits {
|
|
|
158
126
|
const props = withDefaults(defineProps<Props>(), {
|
|
159
127
|
content: '',
|
|
160
128
|
modelValue: '',
|
|
161
|
-
|
|
129
|
+
|
|
162
130
|
options: () => ({
|
|
163
131
|
enableLinks: true,
|
|
164
132
|
openExternalInNewWindow: true,
|
|
@@ -168,39 +136,39 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
168
136
|
|
|
169
137
|
mode: 'html',
|
|
170
138
|
encoding: 'utf-8',
|
|
171
|
-
|
|
139
|
+
|
|
172
140
|
maxLength: 0,
|
|
173
141
|
ellipsis: '...',
|
|
174
142
|
lines: 0,
|
|
175
|
-
|
|
143
|
+
|
|
176
144
|
useRichText: true,
|
|
177
145
|
space: 'ensp',
|
|
178
146
|
filterTags: () => ['script', 'style', 'iframe', 'object', 'embed'],
|
|
179
147
|
allowTags: () => [],
|
|
180
148
|
allowAttributes: () => ({}),
|
|
181
149
|
allowDomains: () => [],
|
|
182
|
-
|
|
150
|
+
|
|
183
151
|
customClass: '',
|
|
184
152
|
customStyle: () => ({}),
|
|
185
153
|
textStyle: () => ({}),
|
|
186
|
-
|
|
154
|
+
|
|
187
155
|
autolink: true,
|
|
188
156
|
emoji: false,
|
|
189
157
|
highlight: false,
|
|
190
158
|
lazyLoad: false,
|
|
191
159
|
errorFallback: '解析失败',
|
|
192
|
-
|
|
160
|
+
|
|
193
161
|
preventDefault: false
|
|
194
162
|
})
|
|
195
163
|
|
|
196
164
|
const emit = defineEmits<Emits>()
|
|
197
165
|
|
|
198
166
|
// 响应式状态
|
|
199
|
-
const richTextId = ref('richTextId'+new Date().getTime())
|
|
167
|
+
const richTextId = ref('richTextId' + new Date().getTime())
|
|
200
168
|
const parsedNodes = ref<any[]>([])
|
|
201
169
|
const markdownNodes = ref<any[]>([])
|
|
202
170
|
const lastError = ref<Error | null>(null)
|
|
203
|
-
const extractedLinks = ref<Array<{id: string, data: LinkData}>>([]) // 提取的链接数据
|
|
171
|
+
const extractedLinks = ref<Array<{ id: string, data: LinkData }>>([]) // 提取的链接数据
|
|
204
172
|
|
|
205
173
|
// 计算内容
|
|
206
174
|
const computedContent = computed(() => {
|
|
@@ -211,7 +179,7 @@ const computedContent = computed(() => {
|
|
|
211
179
|
const decodedContent = computed(() => {
|
|
212
180
|
const content = computedContent.value
|
|
213
181
|
if (!content) return ''
|
|
214
|
-
|
|
182
|
+
|
|
215
183
|
try {
|
|
216
184
|
switch (props.encoding) {
|
|
217
185
|
case 'base64':
|
|
@@ -231,27 +199,27 @@ const decodedContent = computed(() => {
|
|
|
231
199
|
// 处理文本内容
|
|
232
200
|
const processedText = computed(() => {
|
|
233
201
|
let text = decodedContent.value
|
|
234
|
-
|
|
202
|
+
|
|
235
203
|
// 处理长度限制
|
|
236
204
|
if (props.maxLength > 0 && text.length > props.maxLength) {
|
|
237
205
|
text = text.substring(0, props.maxLength) + props.ellipsis
|
|
238
206
|
}
|
|
239
|
-
|
|
207
|
+
|
|
240
208
|
// 自动链接
|
|
241
209
|
if (props.autolink) {
|
|
242
210
|
text = autoLink(text)
|
|
243
211
|
}
|
|
244
|
-
|
|
212
|
+
|
|
245
213
|
// 表情符号
|
|
246
214
|
if (props.emoji || (emoji as any).containEmoji(text)) {
|
|
247
215
|
text = parseEmoji(text)
|
|
248
216
|
}
|
|
249
|
-
|
|
217
|
+
|
|
250
218
|
// 语法高亮
|
|
251
219
|
if (props.highlight) {
|
|
252
220
|
text = highlightText(text)
|
|
253
221
|
}
|
|
254
|
-
|
|
222
|
+
|
|
255
223
|
return text
|
|
256
224
|
})
|
|
257
225
|
|
|
@@ -263,7 +231,7 @@ onMounted(() => {
|
|
|
263
231
|
// 解析 HTML 节点
|
|
264
232
|
const parseHtml = async (html: string) => {
|
|
265
233
|
if (!html) return []
|
|
266
|
-
|
|
234
|
+
|
|
267
235
|
try {
|
|
268
236
|
// 简单的 HTML 解析器
|
|
269
237
|
const nodes = parseHtmlToNodes(html)
|
|
@@ -279,7 +247,7 @@ const parseHtml = async (html: string) => {
|
|
|
279
247
|
// 解析 Markdown
|
|
280
248
|
const parseMarkdown = (markdown: string) => {
|
|
281
249
|
if (!markdown) return []
|
|
282
|
-
|
|
250
|
+
|
|
283
251
|
try {
|
|
284
252
|
const nodes = parseMarkdownToNodes(markdown)
|
|
285
253
|
emit('parse-success', nodes)
|
|
@@ -296,7 +264,7 @@ const formattedJson = computed(() => {
|
|
|
296
264
|
try {
|
|
297
265
|
const content = decodedContent.value
|
|
298
266
|
if (!content) return ''
|
|
299
|
-
|
|
267
|
+
|
|
300
268
|
const obj = JSON.parse(content)
|
|
301
269
|
return JSON.stringify(obj, null, 2)
|
|
302
270
|
} catch (error) {
|
|
@@ -307,14 +275,14 @@ const formattedJson = computed(() => {
|
|
|
307
275
|
// 简单的 HTML 解析器
|
|
308
276
|
const parseHtmlToNodes = (html: string): any[] => {
|
|
309
277
|
const nodes: any[] = []
|
|
310
|
-
|
|
278
|
+
|
|
311
279
|
// 移除危险标签
|
|
312
280
|
let safeHtml = html
|
|
313
281
|
props.filterTags.forEach(tag => {
|
|
314
282
|
const regex = new RegExp(`<${tag}[^>]*>.*?</${tag}>`, 'gis')
|
|
315
283
|
safeHtml = safeHtml.replace(regex, '')
|
|
316
284
|
})
|
|
317
|
-
|
|
285
|
+
|
|
318
286
|
// 简化的解析逻辑
|
|
319
287
|
// 实际项目中可以使用更完善的 HTML 解析库
|
|
320
288
|
const textMatch = safeHtml.match(/>(.*?)</)
|
|
@@ -324,7 +292,7 @@ const parseHtmlToNodes = (html: string): any[] => {
|
|
|
324
292
|
text: textMatch[1]
|
|
325
293
|
})
|
|
326
294
|
}
|
|
327
|
-
|
|
295
|
+
|
|
328
296
|
return nodes
|
|
329
297
|
}
|
|
330
298
|
|
|
@@ -332,12 +300,12 @@ const parseHtmlToNodes = (html: string): any[] => {
|
|
|
332
300
|
const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
333
301
|
const nodes: any[] = []
|
|
334
302
|
const lines = markdown.split('\n')
|
|
335
|
-
|
|
303
|
+
|
|
336
304
|
for (let i = 0; i < lines.length; i++) {
|
|
337
305
|
const line = lines[i].trim()
|
|
338
|
-
|
|
306
|
+
|
|
339
307
|
if (!line) continue
|
|
340
|
-
|
|
308
|
+
|
|
341
309
|
// 标题
|
|
342
310
|
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/)
|
|
343
311
|
if (headingMatch) {
|
|
@@ -348,7 +316,7 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
348
316
|
})
|
|
349
317
|
continue
|
|
350
318
|
}
|
|
351
|
-
|
|
319
|
+
|
|
352
320
|
// 列表项
|
|
353
321
|
const listMatch = line.match(/^[\*\-\+]\s+(.+)$/)
|
|
354
322
|
if (listMatch) {
|
|
@@ -358,7 +326,7 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
358
326
|
i++
|
|
359
327
|
items.push(lines[i].replace(/^[\*\-\+]\s+/, ''))
|
|
360
328
|
}
|
|
361
|
-
|
|
329
|
+
|
|
362
330
|
nodes.push({
|
|
363
331
|
type: 'list',
|
|
364
332
|
ordered: false,
|
|
@@ -366,7 +334,7 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
366
334
|
})
|
|
367
335
|
continue
|
|
368
336
|
}
|
|
369
|
-
|
|
337
|
+
|
|
370
338
|
// 数字列表
|
|
371
339
|
const orderedListMatch = line.match(/^\d+\.\s+(.+)$/)
|
|
372
340
|
if (orderedListMatch) {
|
|
@@ -375,7 +343,7 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
375
343
|
i++
|
|
376
344
|
items.push(lines[i + 1].replace(/^\d+\.\s+/, ''))
|
|
377
345
|
}
|
|
378
|
-
|
|
346
|
+
|
|
379
347
|
nodes.push({
|
|
380
348
|
type: 'list',
|
|
381
349
|
ordered: true,
|
|
@@ -383,7 +351,7 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
383
351
|
})
|
|
384
352
|
continue
|
|
385
353
|
}
|
|
386
|
-
|
|
354
|
+
|
|
387
355
|
// 引用
|
|
388
356
|
if (line.startsWith('> ')) {
|
|
389
357
|
nodes.push({
|
|
@@ -392,18 +360,18 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
392
360
|
})
|
|
393
361
|
continue
|
|
394
362
|
}
|
|
395
|
-
|
|
363
|
+
|
|
396
364
|
// 代码块
|
|
397
365
|
if (line.startsWith('```')) {
|
|
398
366
|
const language = line.substring(3).trim() || ''
|
|
399
367
|
const codeLines = []
|
|
400
|
-
|
|
368
|
+
|
|
401
369
|
while (i + 1 < lines.length && !lines[i + 1].startsWith('```')) {
|
|
402
370
|
i++
|
|
403
371
|
codeLines.push(lines[i])
|
|
404
372
|
}
|
|
405
373
|
i++ // 跳过结束的 ```
|
|
406
|
-
|
|
374
|
+
|
|
407
375
|
nodes.push({
|
|
408
376
|
type: 'code',
|
|
409
377
|
language,
|
|
@@ -411,14 +379,14 @@ const parseMarkdownToNodes = (markdown: string): any[] => {
|
|
|
411
379
|
})
|
|
412
380
|
continue
|
|
413
381
|
}
|
|
414
|
-
|
|
382
|
+
|
|
415
383
|
// 普通段落
|
|
416
384
|
nodes.push({
|
|
417
385
|
type: 'paragraph',
|
|
418
386
|
text: line
|
|
419
387
|
})
|
|
420
388
|
}
|
|
421
|
-
|
|
389
|
+
|
|
422
390
|
return nodes
|
|
423
391
|
}
|
|
424
392
|
|
|
@@ -440,13 +408,13 @@ const parseEmoji = (text: string): string => {
|
|
|
440
408
|
':*': '😘',
|
|
441
409
|
'<3': '❤️'
|
|
442
410
|
}
|
|
443
|
-
|
|
411
|
+
|
|
444
412
|
let result = text
|
|
445
413
|
Object.keys(emojiMap).forEach(key => {
|
|
446
414
|
const k = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
447
415
|
result = result.replace(new RegExp(k, 'g'), emojiMap[k])
|
|
448
416
|
})
|
|
449
|
-
|
|
417
|
+
|
|
450
418
|
return result
|
|
451
419
|
}
|
|
452
420
|
|
|
@@ -455,12 +423,12 @@ const highlightText = (text: string): string => {
|
|
|
455
423
|
// 简单的关键词高亮
|
|
456
424
|
const keywords = ['important', 'urgent', 'note', 'warning', 'info']
|
|
457
425
|
let result = text
|
|
458
|
-
|
|
426
|
+
|
|
459
427
|
keywords.forEach(keyword => {
|
|
460
428
|
const regex = new RegExp(`\\b${keyword}\\b`, 'gi')
|
|
461
429
|
result = result.replace(regex, `<span class="highlight">${keyword}</span>`)
|
|
462
430
|
})
|
|
463
|
-
|
|
431
|
+
|
|
464
432
|
return result
|
|
465
433
|
}
|
|
466
434
|
|
|
@@ -469,11 +437,11 @@ const handleLinkPress = (event: any) => {
|
|
|
469
437
|
const url = event.detail?.href
|
|
470
438
|
if (url) {
|
|
471
439
|
emit('linkpress', url)
|
|
472
|
-
|
|
440
|
+
|
|
473
441
|
if (props.preventDefault) {
|
|
474
442
|
return
|
|
475
443
|
}
|
|
476
|
-
|
|
444
|
+
|
|
477
445
|
// 检查域名是否允许
|
|
478
446
|
if (props.allowDomains.length > 0) {
|
|
479
447
|
try {
|
|
@@ -489,7 +457,7 @@ const handleLinkPress = (event: any) => {
|
|
|
489
457
|
console.error('解析URL失败:', error)
|
|
490
458
|
}
|
|
491
459
|
}
|
|
492
|
-
|
|
460
|
+
|
|
493
461
|
// 跳转到链接
|
|
494
462
|
uni.navigateTo({
|
|
495
463
|
url: `/pages/webview/webview?url=${encodeURIComponent(url)}`
|
|
@@ -504,31 +472,31 @@ const handleLinkPress = (event: any) => {
|
|
|
504
472
|
const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } => {
|
|
505
473
|
const links: LinkData[] = []
|
|
506
474
|
let linkIndex = 0
|
|
507
|
-
|
|
475
|
+
|
|
508
476
|
// 使用正则表达式匹配 a 标签
|
|
509
477
|
const linkRegex = /<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1[^>]*?>(.*?)<\/a>/gi
|
|
510
|
-
|
|
478
|
+
|
|
511
479
|
// 替换链接为可点击元素
|
|
512
480
|
const processedHtml = html.replace(linkRegex, (match, quote, url, text) => {
|
|
513
481
|
// 清理 URL
|
|
514
482
|
const cleanUrl = url.trim()
|
|
515
483
|
const cleanText = text.replace(/<[^>]*>/g, '').trim()
|
|
516
|
-
|
|
484
|
+
|
|
517
485
|
// 检查是否为外部链接
|
|
518
|
-
const isExternal = /^(https?:)?\/\//i.test(cleanUrl) &&
|
|
519
|
-
|
|
520
|
-
|
|
486
|
+
const isExternal = /^(https?:)?\/\//i.test(cleanUrl) &&
|
|
487
|
+
!cleanUrl.includes(location.hostname)
|
|
488
|
+
|
|
521
489
|
const linkData: LinkData = {
|
|
522
490
|
url: cleanUrl,
|
|
523
491
|
text: cleanText,
|
|
524
492
|
isExternal
|
|
525
493
|
}
|
|
526
|
-
|
|
494
|
+
|
|
527
495
|
links.push(linkData)
|
|
528
|
-
|
|
496
|
+
|
|
529
497
|
// 生成唯一的 ID
|
|
530
498
|
const linkId = `link-${linkIndex++}`
|
|
531
|
-
|
|
499
|
+
|
|
532
500
|
// 替换为可点击的富文本节点
|
|
533
501
|
return `<span
|
|
534
502
|
data-link-id="${linkId}"
|
|
@@ -537,7 +505,7 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
537
505
|
class="im-parse-link"
|
|
538
506
|
>${cleanText}</span>`
|
|
539
507
|
})
|
|
540
|
-
|
|
508
|
+
|
|
541
509
|
// 解析电子邮件(如果启用)
|
|
542
510
|
let finalHtml = processedHtml
|
|
543
511
|
if (props.options?.parseEmail) {
|
|
@@ -550,7 +518,7 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
550
518
|
isExternal: false
|
|
551
519
|
}
|
|
552
520
|
links.push(linkData)
|
|
553
|
-
|
|
521
|
+
|
|
554
522
|
return `<span
|
|
555
523
|
data-link-id="${emailId}"
|
|
556
524
|
data-link-url="mailto:${email}"
|
|
@@ -559,7 +527,7 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
559
527
|
>${email}</span>`
|
|
560
528
|
})
|
|
561
529
|
}
|
|
562
|
-
|
|
530
|
+
|
|
563
531
|
// 解析电话号码(如果启用)
|
|
564
532
|
if (props.options?.parsePhone) {
|
|
565
533
|
const phoneRegex = /(\+?\d[\d\s\-\(\)]{7,}\d)/g
|
|
@@ -572,7 +540,7 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
572
540
|
isExternal: false
|
|
573
541
|
}
|
|
574
542
|
links.push(linkData)
|
|
575
|
-
|
|
543
|
+
|
|
576
544
|
return `<span
|
|
577
545
|
data-link-id="${phoneId}"
|
|
578
546
|
data-link-url="tel:${cleanPhone}"
|
|
@@ -581,13 +549,13 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
581
549
|
>${phone}</span>`
|
|
582
550
|
})
|
|
583
551
|
}
|
|
584
|
-
|
|
552
|
+
|
|
585
553
|
// 提取链接信息到响应式数组
|
|
586
554
|
extractedLinks.value = links.map((link, index) => ({
|
|
587
555
|
id: `link-${index}`,
|
|
588
556
|
data: link
|
|
589
557
|
}))
|
|
590
|
-
|
|
558
|
+
|
|
591
559
|
// 返回解析后的节点(这里简化处理,实际可能需要更复杂的 HTML 解析)
|
|
592
560
|
return {
|
|
593
561
|
nodes: [{
|
|
@@ -610,12 +578,12 @@ const parseHtmlWithLinks = (html: string): { nodes: any[], links: LinkData[] } =
|
|
|
610
578
|
const handleLinkClick = (linkData: LinkData, event?: Event) => {
|
|
611
579
|
// 触发自定义事件
|
|
612
580
|
emit('link-click', linkData, event)
|
|
613
|
-
|
|
581
|
+
|
|
614
582
|
// 调用用户提供的回调
|
|
615
583
|
if (props.options?.onLinkClick) {
|
|
616
584
|
props.options.onLinkClick(linkData, event)
|
|
617
585
|
}
|
|
618
|
-
|
|
586
|
+
|
|
619
587
|
// 执行默认行为(在 uniapp 中)
|
|
620
588
|
handleDefaultLinkBehavior(linkData)
|
|
621
589
|
}
|
|
@@ -625,7 +593,7 @@ const handleLinkClick = (linkData: LinkData, event?: Event) => {
|
|
|
625
593
|
*/
|
|
626
594
|
const handleDefaultLinkBehavior = (linkData: LinkData) => {
|
|
627
595
|
const { url, isExternal } = linkData
|
|
628
|
-
|
|
596
|
+
|
|
629
597
|
// 处理邮件链接
|
|
630
598
|
if (url.startsWith('mailto:')) {
|
|
631
599
|
uni.makePhoneCall({
|
|
@@ -639,7 +607,7 @@ const handleDefaultLinkBehavior = (linkData: LinkData) => {
|
|
|
639
607
|
})
|
|
640
608
|
return
|
|
641
609
|
}
|
|
642
|
-
|
|
610
|
+
|
|
643
611
|
// 处理电话链接
|
|
644
612
|
if (url.startsWith('tel:')) {
|
|
645
613
|
uni.makePhoneCall({
|
|
@@ -653,7 +621,7 @@ const handleDefaultLinkBehavior = (linkData: LinkData) => {
|
|
|
653
621
|
})
|
|
654
622
|
return
|
|
655
623
|
}
|
|
656
|
-
|
|
624
|
+
|
|
657
625
|
// 处理网页链接
|
|
658
626
|
if (/^(https?:)?\/\//i.test(url)) {
|
|
659
627
|
// 在 uniapp 中打开网页
|
|
@@ -691,7 +659,7 @@ const handleDefaultLinkBehavior = (linkData: LinkData) => {
|
|
|
691
659
|
const handleRichTextItemClick = (event: any) => {
|
|
692
660
|
console.log('click', event)
|
|
693
661
|
const { dataset } = event.detail || {}
|
|
694
|
-
|
|
662
|
+
|
|
695
663
|
if (dataset && dataset.linkId) {
|
|
696
664
|
const linkItem = extractedLinks.value.find(item => item.id === dataset.linkId)
|
|
697
665
|
if (linkItem) {
|
|
@@ -701,7 +669,7 @@ const handleRichTextItemClick = (event: any) => {
|
|
|
701
669
|
...linkItem.data,
|
|
702
670
|
url: decodedUrl
|
|
703
671
|
}
|
|
704
|
-
|
|
672
|
+
|
|
705
673
|
handleLinkClick(linkData, event)
|
|
706
674
|
}
|
|
707
675
|
}
|
|
@@ -758,7 +726,7 @@ const handleImageLoad = (src: string) => {
|
|
|
758
726
|
// 重新解析
|
|
759
727
|
const reparse = async () => {
|
|
760
728
|
lastError.value = null
|
|
761
|
-
|
|
729
|
+
|
|
762
730
|
if (props.mode === 'html') {
|
|
763
731
|
// parsedNodes.value = await parseHtml(decodedContent.value)
|
|
764
732
|
initParse()
|
|
@@ -823,28 +791,29 @@ defineExpose({
|
|
|
823
791
|
width: 100%;
|
|
824
792
|
word-break: break-word;
|
|
825
793
|
line-height: 1.6;
|
|
826
|
-
|
|
794
|
+
|
|
827
795
|
&__html {
|
|
796
|
+
|
|
828
797
|
// HTML 样式
|
|
829
798
|
:deep(img) {
|
|
830
799
|
max-width: 100%;
|
|
831
800
|
height: auto;
|
|
832
801
|
vertical-align: middle;
|
|
833
802
|
}
|
|
834
|
-
|
|
803
|
+
|
|
835
804
|
:deep(a) {
|
|
836
805
|
color: #409eff;
|
|
837
806
|
text-decoration: none;
|
|
838
|
-
|
|
807
|
+
|
|
839
808
|
&:active {
|
|
840
809
|
opacity: 0.7;
|
|
841
810
|
}
|
|
842
811
|
}
|
|
843
|
-
|
|
812
|
+
|
|
844
813
|
:deep(p) {
|
|
845
814
|
margin: 16rpx 0;
|
|
846
815
|
}
|
|
847
|
-
|
|
816
|
+
|
|
848
817
|
:deep(h1),
|
|
849
818
|
:deep(h2),
|
|
850
819
|
:deep(h3),
|
|
@@ -854,33 +823,33 @@ defineExpose({
|
|
|
854
823
|
margin: 32rpx 0 16rpx;
|
|
855
824
|
font-weight: bold;
|
|
856
825
|
}
|
|
857
|
-
|
|
826
|
+
|
|
858
827
|
:deep(h1) {
|
|
859
828
|
font-size: 40rpx;
|
|
860
829
|
}
|
|
861
|
-
|
|
830
|
+
|
|
862
831
|
:deep(h2) {
|
|
863
832
|
font-size: 36rpx;
|
|
864
833
|
}
|
|
865
|
-
|
|
834
|
+
|
|
866
835
|
:deep(h3) {
|
|
867
836
|
font-size: 32rpx;
|
|
868
837
|
}
|
|
869
|
-
|
|
838
|
+
|
|
870
839
|
:deep(h4) {
|
|
871
840
|
font-size: 28rpx;
|
|
872
841
|
}
|
|
873
|
-
|
|
842
|
+
|
|
874
843
|
:deep(ul),
|
|
875
844
|
:deep(ol) {
|
|
876
845
|
margin: 16rpx 0;
|
|
877
846
|
padding-left: 48rpx;
|
|
878
847
|
}
|
|
879
|
-
|
|
848
|
+
|
|
880
849
|
:deep(li) {
|
|
881
850
|
margin: 8rpx 0;
|
|
882
851
|
}
|
|
883
|
-
|
|
852
|
+
|
|
884
853
|
:deep(blockquote) {
|
|
885
854
|
margin: 16rpx 0;
|
|
886
855
|
padding: 16rpx 32rpx;
|
|
@@ -888,7 +857,7 @@ defineExpose({
|
|
|
888
857
|
border-left: 8rpx solid #ddd;
|
|
889
858
|
color: #666;
|
|
890
859
|
}
|
|
891
|
-
|
|
860
|
+
|
|
892
861
|
:deep(code) {
|
|
893
862
|
padding: 4rpx 8rpx;
|
|
894
863
|
background-color: #f5f5f5;
|
|
@@ -896,44 +865,44 @@ defineExpose({
|
|
|
896
865
|
font-family: Consolas, Monaco, 'Courier New', monospace;
|
|
897
866
|
font-size: 90%;
|
|
898
867
|
}
|
|
899
|
-
|
|
868
|
+
|
|
900
869
|
:deep(pre) {
|
|
901
870
|
margin: 16rpx 0;
|
|
902
871
|
padding: 24rpx;
|
|
903
872
|
background-color: #f5f5f5;
|
|
904
873
|
border-radius: 8rpx;
|
|
905
874
|
overflow-x: auto;
|
|
906
|
-
|
|
875
|
+
|
|
907
876
|
code {
|
|
908
877
|
padding: 0;
|
|
909
878
|
background-color: transparent;
|
|
910
879
|
}
|
|
911
880
|
}
|
|
912
|
-
|
|
881
|
+
|
|
913
882
|
:deep(table) {
|
|
914
883
|
width: 100%;
|
|
915
884
|
border-collapse: collapse;
|
|
916
885
|
margin: 16rpx 0;
|
|
917
|
-
|
|
886
|
+
|
|
918
887
|
th,
|
|
919
888
|
td {
|
|
920
889
|
padding: 16rpx;
|
|
921
890
|
border: 2rpx solid #ddd;
|
|
922
891
|
text-align: left;
|
|
923
892
|
}
|
|
924
|
-
|
|
893
|
+
|
|
925
894
|
th {
|
|
926
895
|
background-color: #f5f5f5;
|
|
927
896
|
font-weight: bold;
|
|
928
897
|
}
|
|
929
898
|
}
|
|
930
899
|
}
|
|
931
|
-
|
|
900
|
+
|
|
932
901
|
&__text {
|
|
933
902
|
display: block;
|
|
934
903
|
width: 100%;
|
|
935
904
|
}
|
|
936
|
-
|
|
905
|
+
|
|
937
906
|
&__markdown {
|
|
938
907
|
.highlight {
|
|
939
908
|
background-color: #fffbe6;
|
|
@@ -942,70 +911,70 @@ defineExpose({
|
|
|
942
911
|
color: #d48806;
|
|
943
912
|
}
|
|
944
913
|
}
|
|
945
|
-
|
|
914
|
+
|
|
946
915
|
&__heading {
|
|
947
916
|
margin: 32rpx 0 16rpx;
|
|
948
917
|
font-weight: bold;
|
|
949
|
-
|
|
918
|
+
|
|
950
919
|
&--1 {
|
|
951
920
|
font-size: 40rpx;
|
|
952
921
|
}
|
|
953
|
-
|
|
922
|
+
|
|
954
923
|
&--2 {
|
|
955
924
|
font-size: 36rpx;
|
|
956
925
|
}
|
|
957
|
-
|
|
926
|
+
|
|
958
927
|
&--3 {
|
|
959
928
|
font-size: 32rpx;
|
|
960
929
|
}
|
|
961
|
-
|
|
930
|
+
|
|
962
931
|
&--4 {
|
|
963
932
|
font-size: 28rpx;
|
|
964
933
|
}
|
|
965
|
-
|
|
934
|
+
|
|
966
935
|
&--5 {
|
|
967
936
|
font-size: 26rpx;
|
|
968
937
|
}
|
|
969
|
-
|
|
938
|
+
|
|
970
939
|
&--6 {
|
|
971
940
|
font-size: 24rpx;
|
|
972
941
|
}
|
|
973
942
|
}
|
|
974
|
-
|
|
943
|
+
|
|
975
944
|
&__paragraph {
|
|
976
945
|
margin: 16rpx 0;
|
|
977
946
|
}
|
|
978
|
-
|
|
947
|
+
|
|
979
948
|
&__list {
|
|
980
949
|
margin: 16rpx 0;
|
|
981
|
-
|
|
950
|
+
|
|
982
951
|
&--ordered {
|
|
983
952
|
padding-left: 48rpx;
|
|
984
953
|
list-style-type: decimal;
|
|
985
954
|
}
|
|
986
|
-
|
|
955
|
+
|
|
987
956
|
&:not(.im-parse__list--ordered) {
|
|
988
957
|
padding-left: 48rpx;
|
|
989
958
|
list-style-type: disc;
|
|
990
959
|
}
|
|
991
960
|
}
|
|
992
|
-
|
|
961
|
+
|
|
993
962
|
&__list-item {
|
|
994
963
|
display: flex;
|
|
995
964
|
align-items: flex-start;
|
|
996
965
|
margin: 8rpx 0;
|
|
997
966
|
}
|
|
998
|
-
|
|
967
|
+
|
|
999
968
|
&__list-marker {
|
|
1000
969
|
margin-right: 16rpx;
|
|
1001
970
|
min-width: 32rpx;
|
|
1002
971
|
text-align: right;
|
|
1003
972
|
}
|
|
1004
|
-
|
|
973
|
+
|
|
1005
974
|
&__list-text {
|
|
1006
975
|
flex: 1;
|
|
1007
976
|
}
|
|
1008
|
-
|
|
977
|
+
|
|
1009
978
|
&__blockquote {
|
|
1010
979
|
margin: 16rpx 0;
|
|
1011
980
|
padding: 16rpx 32rpx;
|
|
@@ -1013,7 +982,7 @@ defineExpose({
|
|
|
1013
982
|
border-left: 8rpx solid #ddd;
|
|
1014
983
|
color: #666;
|
|
1015
984
|
}
|
|
1016
|
-
|
|
985
|
+
|
|
1017
986
|
&__code-block {
|
|
1018
987
|
margin: 16rpx 0;
|
|
1019
988
|
padding: 24rpx;
|
|
@@ -1021,18 +990,18 @@ defineExpose({
|
|
|
1021
990
|
border-radius: 8rpx;
|
|
1022
991
|
overflow-x: auto;
|
|
1023
992
|
}
|
|
1024
|
-
|
|
993
|
+
|
|
1025
994
|
&__code-text {
|
|
1026
995
|
font-family: Consolas, Monaco, 'Courier New', monospace;
|
|
1027
996
|
font-size: 90%;
|
|
1028
997
|
white-space: pre;
|
|
1029
998
|
}
|
|
1030
|
-
|
|
999
|
+
|
|
1031
1000
|
&__json {
|
|
1032
1001
|
width: 100%;
|
|
1033
1002
|
overflow-x: auto;
|
|
1034
1003
|
}
|
|
1035
|
-
|
|
1004
|
+
|
|
1036
1005
|
&__json-pre {
|
|
1037
1006
|
margin: 0;
|
|
1038
1007
|
padding: 24rpx;
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
buttonStyle,
|
|
18
18
|
isMinusDisabled ? disabledButtonStyle : {},
|
|
19
19
|
isMinusActive ? buttonActiveStyle : {}
|
|
20
|
-
]"
|
|
21
|
-
@click="onMinusClick">
|
|
20
|
+
]" @click="onMinusClick">
|
|
22
21
|
<im-icon v-if="minusIcon" :name="minusIcon" :size="iconSize" :color="buttonTextColorComputed" />
|
|
23
22
|
<text v-else-if="minusText" class="im-stepper-button-text" :style="{ color: buttonTextColorComputed }">
|
|
24
23
|
{{ minusText }}
|
|
@@ -57,6 +56,7 @@
|
|
|
57
56
|
</template>
|
|
58
57
|
|
|
59
58
|
<script lang="ts" setup>
|
|
59
|
+
import { ref, computed, watch, nextTick, useSlots } from 'vue'
|
|
60
60
|
import type { StepperProps, StepperEmits } from '../../types/components/stepper'
|
|
61
61
|
import ImIcon from '../im-icon/im-icon.vue'
|
|
62
62
|
|
package/libs/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AllowedComponentProps, VNodeProps } from '../common'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
declare interface _SkuAttr {
|
|
4
4
|
/** 属性名称 */
|
|
5
5
|
name: string;
|
|
6
6
|
/** 属性值列表 */
|
|
@@ -11,7 +11,7 @@ export interface _SkuAttr {
|
|
|
11
11
|
required?: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
declare interface _SkuAttrValue {
|
|
15
15
|
/** 属性值名称 */
|
|
16
16
|
name: string;
|
|
17
17
|
/** 属性值ID */
|
|
@@ -26,7 +26,7 @@ export interface _SkuAttrValue {
|
|
|
26
26
|
previewImgUrl?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
declare interface _SkuSpec {
|
|
30
30
|
/** 规格名称 */
|
|
31
31
|
name: string;
|
|
32
32
|
/** 规格值列表 */
|
|
@@ -37,7 +37,7 @@ export interface _SkuSpec {
|
|
|
37
37
|
required?: boolean;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
declare interface _SkuValue {
|
|
41
41
|
/** 规格值名称 */
|
|
42
42
|
name: string;
|
|
43
43
|
/** 规格值ID */
|
|
@@ -52,7 +52,7 @@ export interface _SkuValue {
|
|
|
52
52
|
previewImgUrl?: string;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
declare interface _SkuItem {
|
|
56
56
|
/** SKU ID */
|
|
57
57
|
id: string | number;
|
|
58
58
|
/** 商品ID */
|
|
@@ -75,7 +75,7 @@ export interface _SkuItem {
|
|
|
75
75
|
disabled?: boolean;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
declare interface _SkuGoodsInfo {
|
|
79
79
|
/** 商品ID */
|
|
80
80
|
id: string | number;
|
|
81
81
|
/** 商品标题 */
|
|
@@ -100,7 +100,7 @@ export interface _SkuGoodsInfo {
|
|
|
100
100
|
unit?: string;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
declare interface _SelectedSku {
|
|
104
104
|
/** 选中的属性组合 */
|
|
105
105
|
selectedAttrs: Record<string, string>;
|
|
106
106
|
/** 选中的规格组合 */
|
package/types/index.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ import validator, {
|
|
|
49
49
|
validatePassword
|
|
50
50
|
} from './utils/validator.d.ts'
|
|
51
51
|
import { EmojiType, EmojiCategoryType } from './components/emoji-picker'
|
|
52
|
-
import * as base64 from "./utils/base64.d.ts"
|
|
52
|
+
import * as base64 from "./utils/base64.d.ts"
|
|
53
53
|
|
|
54
54
|
declare module 'im-ui-mobile' {
|
|
55
55
|
export function install(): void
|
|
@@ -123,4 +123,6 @@ declare module 'im-ui-mobile' {
|
|
|
123
123
|
TERMINAL_TYPE,
|
|
124
124
|
MESSAGE_STATUS,
|
|
125
125
|
}
|
|
126
|
+
|
|
127
|
+
export * from './components/sku.d.ts'
|
|
126
128
|
}
|