@anker-in/campaign-ui 0.2.11-beta.34 → 0.2.11-beta.35
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/dist/cjs/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/cjs/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.d.ts +51 -0
- package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.js +41 -0
- package/dist/cjs/components/LiveChatWidget/components/ComplianceDialog.js.map +7 -0
- package/dist/cjs/components/LiveChatWidget/index.d.ts +1 -1
- package/dist/cjs/components/LiveChatWidget/index.js +1 -1
- package/dist/cjs/components/LiveChatWidget/index.js.map +2 -2
- package/dist/cjs/components/LiveChatWidget/types.d.ts +38 -0
- package/dist/cjs/components/LiveChatWidget/types.js.map +1 -1
- package/dist/cjs/stories/LiveChatWidget.stories.d.ts +14 -0
- package/dist/cjs/stories/LiveChatWidget.stories.js +76 -7
- package/dist/cjs/stories/LiveChatWidget.stories.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js +1 -1
- package/dist/esm/components/LiveChatWidget/LiveChatWidget.js.map +3 -3
- package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.d.ts +51 -0
- package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.js +41 -0
- package/dist/esm/components/LiveChatWidget/components/ComplianceDialog.js.map +7 -0
- package/dist/esm/components/LiveChatWidget/index.d.ts +1 -1
- package/dist/esm/components/LiveChatWidget/index.js +1 -1
- package/dist/esm/components/LiveChatWidget/index.js.map +2 -2
- package/dist/esm/components/LiveChatWidget/types.d.ts +38 -0
- package/dist/esm/stories/LiveChatWidget.stories.d.ts +14 -0
- package/dist/esm/stories/LiveChatWidget.stories.js +76 -7
- package/dist/esm/stories/LiveChatWidget.stories.js.map +3 -3
- package/package.json +5 -3
- package/src/components/LiveChatWidget/LiveChatWidget.tsx +65 -1
- package/src/components/LiveChatWidget/components/ComplianceDialog.tsx +229 -0
- package/src/components/LiveChatWidget/index.tsx +1 -0
- package/src/components/LiveChatWidget/types.ts +48 -0
- package/src/stories/LiveChatWidget.stories.tsx +131 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 法规协议弹窗组件
|
|
3
|
+
* 在用户首次点击聊天气泡时显示,用户同意后才打开聊天窗口
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useState, useCallback } from 'react'
|
|
7
|
+
import * as Dialog from '@radix-ui/react-dialog'
|
|
8
|
+
import type { ComplianceDialogConfig } from '../types'
|
|
9
|
+
|
|
10
|
+
export interface ComplianceDialogProps {
|
|
11
|
+
/**
|
|
12
|
+
* 是否打开弹窗
|
|
13
|
+
*/
|
|
14
|
+
open: boolean
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 弹窗配置
|
|
18
|
+
*/
|
|
19
|
+
config: ComplianceDialogConfig
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 用户点击同意按钮的回调
|
|
23
|
+
*/
|
|
24
|
+
onAgree: () => void
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 用户关闭弹窗的回调(点击遮罩或关闭按钮)
|
|
28
|
+
*/
|
|
29
|
+
onClose: () => void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 法规协议弹窗组件
|
|
34
|
+
*
|
|
35
|
+
* 功能:
|
|
36
|
+
* - 显示法规协议内容
|
|
37
|
+
* - 必须勾选复选框才能点击同意按钮
|
|
38
|
+
* - 支持在文本中嵌入链接
|
|
39
|
+
* - 响应式设计,移动端友好
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* <ComplianceDialog
|
|
44
|
+
* open={showCompliance}
|
|
45
|
+
* config={{
|
|
46
|
+
* title: "Hi! I'm your eufy AI assistant.",
|
|
47
|
+
* content: "AI-generated responses can be inaccurate...",
|
|
48
|
+
* checkboxText: "By starting to use \"Live Chat\", you agree to Anker's {link}.",
|
|
49
|
+
* linkText: "LIVE CHAT PRIVACY NOTICE",
|
|
50
|
+
* linkUrl: "https://www.anker.com/privacy",
|
|
51
|
+
* agreeButtonText: "Agree"
|
|
52
|
+
* }}
|
|
53
|
+
* onAgree={() => setShowCompliance(false)}
|
|
54
|
+
* onClose={() => setShowCompliance(false)}
|
|
55
|
+
* />
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const ComplianceDialog: React.FC<ComplianceDialogProps> = ({
|
|
59
|
+
open,
|
|
60
|
+
config,
|
|
61
|
+
onAgree,
|
|
62
|
+
onClose,
|
|
63
|
+
}) => {
|
|
64
|
+
const [isChecked, setIsChecked] = useState(false)
|
|
65
|
+
|
|
66
|
+
const handleAgree = useCallback(() => {
|
|
67
|
+
if (isChecked) {
|
|
68
|
+
onAgree()
|
|
69
|
+
// 重置勾选状态,以便下次打开时重新勾选
|
|
70
|
+
setIsChecked(false)
|
|
71
|
+
}
|
|
72
|
+
}, [isChecked, onAgree])
|
|
73
|
+
|
|
74
|
+
const handleOpenChange = useCallback((open: boolean) => {
|
|
75
|
+
if (!open) {
|
|
76
|
+
onClose()
|
|
77
|
+
// 重置勾选状态
|
|
78
|
+
setIsChecked(false)
|
|
79
|
+
}
|
|
80
|
+
}, [onClose])
|
|
81
|
+
|
|
82
|
+
// 处理点击事件,防止点击链接时触发 checkbox
|
|
83
|
+
const handleCheckboxLabelClick = useCallback((e: React.MouseEvent) => {
|
|
84
|
+
// 如果点击的是链接,阻止冒泡
|
|
85
|
+
if ((e.target as HTMLElement).tagName === 'A') {
|
|
86
|
+
e.stopPropagation()
|
|
87
|
+
}
|
|
88
|
+
}, [])
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Dialog.Root open={open} onOpenChange={handleOpenChange}>
|
|
92
|
+
<Dialog.Portal>
|
|
93
|
+
{/* 遮罩层 - 隐藏 */}
|
|
94
|
+
<Dialog.Overlay className="hidden" />
|
|
95
|
+
|
|
96
|
+
{/* 弹窗内容 */}
|
|
97
|
+
<Dialog.Content
|
|
98
|
+
className="
|
|
99
|
+
fixed z-[9998] bg-white overflow-hidden flex flex-col
|
|
100
|
+
animate-in slide-in-from-bottom-4 fade-in duration-300
|
|
101
|
+
max-md:bottom-0 max-md:left-0 max-md:right-0 max-md:w-screen max-md:max-h-[80%]
|
|
102
|
+
max-md:rounded-t-2xl max-md:shadow-[0_-4px_20px_rgba(0,0,0,0.15)]
|
|
103
|
+
md:bottom-4 md:right-4 md:w-[390px] md:max-h-[70vh]
|
|
104
|
+
md:rounded-2xl md:shadow-xl
|
|
105
|
+
2xl:max-h-[720px]
|
|
106
|
+
"
|
|
107
|
+
>
|
|
108
|
+
{/* Header - 包含关闭按钮(右上角) */}
|
|
109
|
+
<div className="flex items-center justify-end px-4 pt-4 pb-2 flex-shrink-0 max-md:px-6 max-sm:px-5">
|
|
110
|
+
<Dialog.Close asChild>
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
className="
|
|
114
|
+
w-6 h-6
|
|
115
|
+
flex items-center justify-center
|
|
116
|
+
border-0 bg-transparent text-gray-500
|
|
117
|
+
cursor-pointer
|
|
118
|
+
"
|
|
119
|
+
aria-label="关闭"
|
|
120
|
+
>
|
|
121
|
+
<svg
|
|
122
|
+
width="20"
|
|
123
|
+
height="20"
|
|
124
|
+
className="text-[#3C3C3B]"
|
|
125
|
+
viewBox="0 0 20 20"
|
|
126
|
+
fill="none"
|
|
127
|
+
stroke="currentColor"
|
|
128
|
+
strokeWidth="2"
|
|
129
|
+
strokeLinecap="round"
|
|
130
|
+
strokeLinejoin="round"
|
|
131
|
+
>
|
|
132
|
+
<line x1="15" y1="5" x2="5" y2="15" />
|
|
133
|
+
<line x1="5" y1="5" x2="15" y2="15" />
|
|
134
|
+
</svg>
|
|
135
|
+
</button>
|
|
136
|
+
</Dialog.Close>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
{/* Body - 可滚动内容区域 */}
|
|
140
|
+
<div className="flex-1 overflow-y-auto px-4 pb-4 max-md:px-6 max-md:pb-6 max-sm:px-5 max-sm:pb-5">
|
|
141
|
+
{/* 标题 */}
|
|
142
|
+
<Dialog.Title
|
|
143
|
+
className="
|
|
144
|
+
text-[18px] font-bold text-[#080A0F]
|
|
145
|
+
mb-1 leading-[1.4] tracking-tight
|
|
146
|
+
"
|
|
147
|
+
>
|
|
148
|
+
{config.title}
|
|
149
|
+
</Dialog.Title>
|
|
150
|
+
|
|
151
|
+
{/* 内容 */}
|
|
152
|
+
<div
|
|
153
|
+
className="
|
|
154
|
+
text-[16px] font-bold leading-[1.4] text-[#080A0F]
|
|
155
|
+
tracking-tight
|
|
156
|
+
mb-2
|
|
157
|
+
"
|
|
158
|
+
dangerouslySetInnerHTML={{ __html: config.content }}
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
{/* 勾选框 */}
|
|
162
|
+
<label
|
|
163
|
+
className="
|
|
164
|
+
flex items-center gap-2 mb-4
|
|
165
|
+
cursor-pointer select-none
|
|
166
|
+
"
|
|
167
|
+
onClick={handleCheckboxLabelClick}
|
|
168
|
+
>
|
|
169
|
+
<input
|
|
170
|
+
type="checkbox"
|
|
171
|
+
className="absolute opacity-0 w-0 h-0"
|
|
172
|
+
checked={isChecked}
|
|
173
|
+
onChange={e => setIsChecked(e.target.checked)}
|
|
174
|
+
/>
|
|
175
|
+
<span
|
|
176
|
+
className={`
|
|
177
|
+
flex-shrink-0 w-4 h-4 mt-0.5
|
|
178
|
+
border-[1px] rounded-[2px] flex items-center justify-center
|
|
179
|
+
transition-all duration-200 ease-in-out
|
|
180
|
+
${isChecked ? 'bg-[#080A0F] border-[#080A0F] text-white' : 'bg-white border-[#2A2C32]'}
|
|
181
|
+
`}
|
|
182
|
+
>
|
|
183
|
+
{isChecked && (
|
|
184
|
+
<svg
|
|
185
|
+
width="12"
|
|
186
|
+
height="10"
|
|
187
|
+
viewBox="0 0 12 10"
|
|
188
|
+
fill="none"
|
|
189
|
+
stroke="currentColor"
|
|
190
|
+
strokeWidth="2"
|
|
191
|
+
strokeLinecap="round"
|
|
192
|
+
strokeLinejoin="round"
|
|
193
|
+
>
|
|
194
|
+
<polyline points="1.5 5 4.5 8 10.5 2" />
|
|
195
|
+
</svg>
|
|
196
|
+
)}
|
|
197
|
+
</span>
|
|
198
|
+
<span
|
|
199
|
+
className="
|
|
200
|
+
flex-1 text-[14px] leading-[1.4] text-[#080A0F]
|
|
201
|
+
tracking-tight font-bold
|
|
202
|
+
[&_a]:underline
|
|
203
|
+
"
|
|
204
|
+
dangerouslySetInnerHTML={{ __html: config.checkboxText }}
|
|
205
|
+
/>
|
|
206
|
+
</label>
|
|
207
|
+
|
|
208
|
+
{/* 同意按钮 */}
|
|
209
|
+
<button
|
|
210
|
+
type="button"
|
|
211
|
+
className={`
|
|
212
|
+
w-full px-5 py-[10px]
|
|
213
|
+
border-0 rounded-[19px]
|
|
214
|
+
text-[14px] leading-[1.2]
|
|
215
|
+
tracking-tighter font-bold
|
|
216
|
+
transition-all duration-200 ease-in-out text-white
|
|
217
|
+
${isChecked ? 'bg-[#080A0F] cursor-pointer ' : 'bg-[#767880] cursor-not-allowed'}
|
|
218
|
+
`}
|
|
219
|
+
onClick={handleAgree}
|
|
220
|
+
disabled={!isChecked}
|
|
221
|
+
>
|
|
222
|
+
{config.agreeButtonText || 'Agree'}
|
|
223
|
+
</button>
|
|
224
|
+
</div>
|
|
225
|
+
</Dialog.Content>
|
|
226
|
+
</Dialog.Portal>
|
|
227
|
+
</Dialog.Root>
|
|
228
|
+
)
|
|
229
|
+
}
|
|
@@ -702,6 +702,47 @@ export interface CommonText {
|
|
|
702
702
|
total?: string
|
|
703
703
|
}
|
|
704
704
|
|
|
705
|
+
// ============================================================================
|
|
706
|
+
// Compliance Dialog Types (法规协议弹窗)
|
|
707
|
+
// ============================================================================
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* 法规协议弹窗配置
|
|
711
|
+
*/
|
|
712
|
+
export interface ComplianceDialogConfig {
|
|
713
|
+
/**
|
|
714
|
+
* 弹窗标题
|
|
715
|
+
* @example "Hi! I'm your eufy AI assistant."
|
|
716
|
+
*/
|
|
717
|
+
title: string
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* 弹窗内容文本(支持 HTML)
|
|
721
|
+
* @example "AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data"
|
|
722
|
+
*/
|
|
723
|
+
content: string
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* 勾选框文本(支持完整 HTML,包括链接)
|
|
727
|
+
* 可以直接包含 <a> 标签等 HTML 元素
|
|
728
|
+
* @example "By starting to use \"Live Chat\", you agree to Anker's <a href=\"https://www.anker.com/privacy\" target=\"_blank\">LIVE CHAT PRIVACY NOTICE</a>."
|
|
729
|
+
*/
|
|
730
|
+
checkboxText: string
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* 同意按钮文本
|
|
734
|
+
* @default "Agree"
|
|
735
|
+
*/
|
|
736
|
+
agreeButtonText?: string
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Cookie 名称,用于记录用户同意状态
|
|
740
|
+
* Cookie 有效期为 365 天
|
|
741
|
+
* @default "livechat_compliance_agreed"
|
|
742
|
+
*/
|
|
743
|
+
cookieName?: string
|
|
744
|
+
}
|
|
745
|
+
|
|
705
746
|
// ============================================================================
|
|
706
747
|
// Component Props Types (组件 Props)
|
|
707
748
|
// ============================================================================
|
|
@@ -932,6 +973,13 @@ export interface LiveChatWidgetProps {
|
|
|
932
973
|
* @default "The above content is provided by AI, for reference."
|
|
933
974
|
*/
|
|
934
975
|
bottomTips?: string
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* 法规协议弹窗配置
|
|
979
|
+
* 提供此参数将在用户首次点击聊天气泡时显示法规协议弹窗
|
|
980
|
+
* 用户同意后才会打开聊天窗口
|
|
981
|
+
*/
|
|
982
|
+
complianceConfig?: ComplianceDialogConfig
|
|
935
983
|
}
|
|
936
984
|
|
|
937
985
|
export interface MessageRenderer {
|
|
@@ -574,6 +574,137 @@ export const WithRecaptcha: Story = {
|
|
|
574
574
|
},
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
+
/**
|
|
578
|
+
* 法规协议弹窗
|
|
579
|
+
*
|
|
580
|
+
* 演示如何配置法规协议弹窗,在用户首次点击聊天气泡时显示。
|
|
581
|
+
*
|
|
582
|
+
* 用户必须同意协议后才能打开聊天窗口。
|
|
583
|
+
*/
|
|
584
|
+
export const WithComplianceDialog: Story = {
|
|
585
|
+
args: {
|
|
586
|
+
loginUserId: 'test_test',
|
|
587
|
+
apiBaseUrl: 'http://172.16.38.183:3003',
|
|
588
|
+
site: 'beta.eufy.com',
|
|
589
|
+
channelCode: 'dtc',
|
|
590
|
+
title: 'eufy AI Assistant',
|
|
591
|
+
|
|
592
|
+
// 法规协议弹窗配置
|
|
593
|
+
complianceConfig: {
|
|
594
|
+
title: "Hi! I'm your eufy AI assistant.",
|
|
595
|
+
content: "AI-generated responses can be inaccurate. Please verify important info. Do not input sensitive personal data",
|
|
596
|
+
checkboxText: 'By starting to use "Live Chat", you agree to Anker\'s <a href="https://www.anker.com/pages/privacy-policy" target="_blank" rel="noopener noreferrer" style="text-decoration: underline;">LIVE CHAT PRIVACY NOTICE</a>.',
|
|
597
|
+
agreeButtonText: "Agree"
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
parameters: {
|
|
601
|
+
docs: {
|
|
602
|
+
description: {
|
|
603
|
+
story: `
|
|
604
|
+
### 法规协议弹窗功能
|
|
605
|
+
|
|
606
|
+
使用 \`complianceConfig\` 属性可以在用户首次点击聊天气泡时显示法规协议弹窗。
|
|
607
|
+
|
|
608
|
+
**功能特性:**
|
|
609
|
+
|
|
610
|
+
- ✅ 用户必须勾选复选框才能点击"同意"按钮
|
|
611
|
+
- ✅ 支持在勾选框文本中嵌入链接(使用 \`{link}\` 占位符)
|
|
612
|
+
- ✅ 支持 HTML 格式的内容文本
|
|
613
|
+
- ✅ 同意后自动打开聊天窗口
|
|
614
|
+
- ✅ 关闭弹窗不会打开聊天窗口
|
|
615
|
+
- ✅ 同意后再次点击气泡直接打开聊天(无需重复同意)
|
|
616
|
+
- ✅ 响应式设计,移动端友好
|
|
617
|
+
- ✅ **与聊天窗口位置一致**(右下角或底部固定)
|
|
618
|
+
- ✅ **无遮罩层设计**,不遮挡页面内容
|
|
619
|
+
|
|
620
|
+
**测试步骤:**
|
|
621
|
+
|
|
622
|
+
1. 点击聊天气泡按钮
|
|
623
|
+
2. 查看弹出的法规协议弹窗
|
|
624
|
+
3. 尝试不勾选复选框时点击"Agree"按钮(按钮应该是禁用状态)
|
|
625
|
+
4. 勾选复选框后点击"Agree"
|
|
626
|
+
5. 观察弹窗关闭并自动打开聊天窗口
|
|
627
|
+
6. 关闭聊天窗口后再次点击气泡(应该直接打开聊天,不再显示法规弹窗)
|
|
628
|
+
|
|
629
|
+
**配置项说明:**
|
|
630
|
+
|
|
631
|
+
\`\`\`typescript
|
|
632
|
+
complianceConfig: {
|
|
633
|
+
title: string // 弹窗标题
|
|
634
|
+
content: string // 内容文本(支持 HTML)
|
|
635
|
+
checkboxText: string // 勾选框文本(支持完整 HTML,包括 <a> 标签)
|
|
636
|
+
agreeButtonText?: string // 同意按钮文案(默认 "Agree")
|
|
637
|
+
}
|
|
638
|
+
\`\`\`
|
|
639
|
+
|
|
640
|
+
**示例:**
|
|
641
|
+
|
|
642
|
+
\`\`\`tsx
|
|
643
|
+
checkboxText: 'By starting to use "Live Chat", you agree to <a href="https://example.com/privacy" target="_blank">PRIVACY NOTICE</a>.'
|
|
644
|
+
\`\`\`
|
|
645
|
+
|
|
646
|
+
**样式定制:**
|
|
647
|
+
|
|
648
|
+
所有样式通过 CSS 类名暴露,可以全局覆盖:
|
|
649
|
+
|
|
650
|
+
\`\`\`css
|
|
651
|
+
.livechat-compliance-content { /* 弹窗主体 */ }
|
|
652
|
+
.livechat-compliance-title { /* 标题 */ }
|
|
653
|
+
.livechat-compliance-text { /* 内容文本 */ }
|
|
654
|
+
.livechat-compliance-checkbox { /* 复选框 */ }
|
|
655
|
+
.livechat-compliance-link { /* 链接 */ }
|
|
656
|
+
.livechat-compliance-button { /* 同意按钮 */ }
|
|
657
|
+
\`\`\`
|
|
658
|
+
`,
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* 法规协议弹窗 - 无链接版本
|
|
666
|
+
*
|
|
667
|
+
* 演示不包含链接的简化版法规协议弹窗。
|
|
668
|
+
*/
|
|
669
|
+
export const WithComplianceDialogNoLink: Story = {
|
|
670
|
+
args: {
|
|
671
|
+
loginUserId: 'test_test',
|
|
672
|
+
apiBaseUrl: 'http://172.16.38.183:3003',
|
|
673
|
+
site: 'beta.eufy.com',
|
|
674
|
+
channelCode: 'dtc',
|
|
675
|
+
title: 'AI Assistant',
|
|
676
|
+
|
|
677
|
+
// 简化版法规协议(不包含链接)
|
|
678
|
+
complianceConfig: {
|
|
679
|
+
title: "Welcome to AI Chat Support",
|
|
680
|
+
content: "By using this service, you agree to our terms of service and privacy policy. AI responses may contain errors. Please verify important information.",
|
|
681
|
+
checkboxText: "I have read and agree to the terms and conditions",
|
|
682
|
+
agreeButtonText: "Continue"
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
parameters: {
|
|
686
|
+
docs: {
|
|
687
|
+
description: {
|
|
688
|
+
story: `
|
|
689
|
+
### 简化版法规协议弹窗
|
|
690
|
+
|
|
691
|
+
如果不需要在勾选框中显示链接,可以省略 \`linkText\` 和 \`linkUrl\` 属性。
|
|
692
|
+
|
|
693
|
+
这个版本适用于:
|
|
694
|
+
- 简单的用户协议确认
|
|
695
|
+
- 免责声明
|
|
696
|
+
- 服务条款同意
|
|
697
|
+
|
|
698
|
+
**与完整版的区别:**
|
|
699
|
+
- 不包含可点击的链接
|
|
700
|
+
- 勾选框文本为纯文本
|
|
701
|
+
- 配置更简单
|
|
702
|
+
`,
|
|
703
|
+
},
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
}
|
|
707
|
+
|
|
577
708
|
/**
|
|
578
709
|
* 自定义产品卡片渲染
|
|
579
710
|
*
|