@tfdesign/b-end 1.0.4
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/AI_READ_FIRST.md +131 -0
- package/LICENSE +21 -0
- package/README.md +353 -0
- package/package.json +67 -0
- package/scripts/check-tfds-contract.mjs +334 -0
- package/scripts/check-tfds-integration.mjs +263 -0
- package/scripts/postinstall-cursor-skill.mjs +382 -0
- package/scripts/setup.mjs +520 -0
- package/skills/tfds/CHECKLIST.md +205 -0
- package/skills/tfds/COMMON_FAILURES.md +238 -0
- package/skills/tfds/DESIGN_PRINCIPLES.md +477 -0
- package/skills/tfds/GLOBAL_DESIGN_RULES.md +636 -0
- package/skills/tfds/LAYOUT_RECIPES.md +140 -0
- package/skills/tfds/LAYOUT_RULES.md +1355 -0
- package/skills/tfds/PAGE_ARCHETYPES.md +201 -0
- package/skills/tfds/SKILL.md +188 -0
- package/skills/tfds/components.index.json +7305 -0
- package/skills/tfds/components.summary.json +1809 -0
- package/src/_b_end_runtime/components/AiSuggestionShared.jsx +166 -0
- package/src/_b_end_runtime/components/Avatar.jsx +325 -0
- package/src/_b_end_runtime/components/Avatar.tokens.js +76 -0
- package/src/_b_end_runtime/components/AvatarGridPreview.jsx +56 -0
- package/src/_b_end_runtime/components/AvatarGroup.jsx +80 -0
- package/src/_b_end_runtime/components/AvatarGroup.tokens.js +28 -0
- package/src/_b_end_runtime/components/Button.jsx +144 -0
- package/src/_b_end_runtime/components/Button.tokens.js +90 -0
- package/src/_b_end_runtime/components/Card.jsx +460 -0
- package/src/_b_end_runtime/components/Card.tokens.js +124 -0
- package/src/_b_end_runtime/components/CardPreview.jsx +51 -0
- package/src/_b_end_runtime/components/ChatBubble.jsx +384 -0
- package/src/_b_end_runtime/components/ChatBubble.tokens.js +60 -0
- package/src/_b_end_runtime/components/ChatBubblePreview.jsx +129 -0
- package/src/_b_end_runtime/components/ChatInput.jsx +1399 -0
- package/src/_b_end_runtime/components/ChatInput.tokens.js +75 -0
- package/src/_b_end_runtime/components/ChatMessage.jsx +2215 -0
- package/src/_b_end_runtime/components/ChatMessage.tokens.js +257 -0
- package/src/_b_end_runtime/components/ChatMessagePreview.jsx +388 -0
- package/src/_b_end_runtime/components/Checkbox.jsx +317 -0
- package/src/_b_end_runtime/components/Checkbox.tokens.js +59 -0
- package/src/_b_end_runtime/components/ConversationList.jsx +1264 -0
- package/src/_b_end_runtime/components/ConversationList.tokens.js +135 -0
- package/src/_b_end_runtime/components/ConversationListPreview.jsx +108 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.jsx +324 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.tokens.js +69 -0
- package/src/_b_end_runtime/components/DatePicker.jsx +739 -0
- package/src/_b_end_runtime/components/DatePicker.tokens.js +99 -0
- package/src/_b_end_runtime/components/Empty.jsx +141 -0
- package/src/_b_end_runtime/components/Empty.tokens.js +40 -0
- package/src/_b_end_runtime/components/Form.jsx +609 -0
- package/src/_b_end_runtime/components/Form.tokens.js +77 -0
- package/src/_b_end_runtime/components/FormFieldStack.jsx +123 -0
- package/src/_b_end_runtime/components/FormFieldStack.tokens.js +12 -0
- package/src/_b_end_runtime/components/FormTitle.jsx +119 -0
- package/src/_b_end_runtime/components/FormTitle.tokens.js +87 -0
- package/src/_b_end_runtime/components/FullScreenPage.jsx +97 -0
- package/src/_b_end_runtime/components/FullScreenPage.tokens.js +19 -0
- package/src/_b_end_runtime/components/Icon.jsx +172 -0
- package/src/_b_end_runtime/components/Icon.tokens.js +26 -0
- package/src/_b_end_runtime/components/IconGridPreview.jsx +277 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.jsx +620 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.tokens.js +71 -0
- package/src/_b_end_runtime/components/InfoDisplayPanelPreview.jsx +133 -0
- package/src/_b_end_runtime/components/Input.jsx +258 -0
- package/src/_b_end_runtime/components/Input.tokens.js +68 -0
- package/src/_b_end_runtime/components/InputNumber.jsx +242 -0
- package/src/_b_end_runtime/components/InputNumber.tokens.js +55 -0
- package/src/_b_end_runtime/components/Modal.jsx +155 -0
- package/src/_b_end_runtime/components/Modal.tokens.js +73 -0
- package/src/_b_end_runtime/components/NavBar.jsx +842 -0
- package/src/_b_end_runtime/components/NavBar.tokens.js +97 -0
- package/src/_b_end_runtime/components/NavBarPreview.jsx +11 -0
- package/src/_b_end_runtime/components/Radio.jsx +227 -0
- package/src/_b_end_runtime/components/Radio.tokens.js +59 -0
- package/src/_b_end_runtime/components/Select.jsx +766 -0
- package/src/_b_end_runtime/components/Select.tokens.js +99 -0
- package/src/_b_end_runtime/components/Sheet.jsx +132 -0
- package/src/_b_end_runtime/components/Sheet.tokens.js +61 -0
- package/src/_b_end_runtime/components/Slider.jsx +346 -0
- package/src/_b_end_runtime/components/Slider.tokens.js +47 -0
- package/src/_b_end_runtime/components/Switch.jsx +124 -0
- package/src/_b_end_runtime/components/Switch.tokens.js +38 -0
- package/src/_b_end_runtime/components/Table.jsx +1338 -0
- package/src/_b_end_runtime/components/Table.tokens.js +147 -0
- package/src/_b_end_runtime/components/TablePreview.jsx +599 -0
- package/src/_b_end_runtime/components/Tabs.jsx +149 -0
- package/src/_b_end_runtime/components/Tabs.tokens.js +102 -0
- package/src/_b_end_runtime/components/Tag.jsx +199 -0
- package/src/_b_end_runtime/components/Tag.tokens.js +171 -0
- package/src/_b_end_runtime/components/TagBar.jsx +1134 -0
- package/src/_b_end_runtime/components/TagBar.tokens.js +75 -0
- package/src/_b_end_runtime/components/TagGridPreview.jsx +23 -0
- package/src/_b_end_runtime/components/TagInput.jsx +382 -0
- package/src/_b_end_runtime/components/TagInput.tokens.js +52 -0
- package/src/_b_end_runtime/components/TextArea.jsx +363 -0
- package/src/_b_end_runtime/components/TextArea.tokens.js +65 -0
- package/src/_b_end_runtime/components/TimePicker.jsx +444 -0
- package/src/_b_end_runtime/components/TimePicker.tokens.js +77 -0
- package/src/_b_end_runtime/components/Toast.jsx +120 -0
- package/src/_b_end_runtime/components/Toast.tokens.js +146 -0
- package/src/_b_end_runtime/components/Tooltip.jsx +282 -0
- package/src/_b_end_runtime/components/Tooltip.tokens.js +48 -0
- package/src/_b_end_runtime/components/TooltipPreview.jsx +50 -0
- package/src/_b_end_runtime/components/Upload.jsx +455 -0
- package/src/_b_end_runtime/components/Upload.tokens.js +47 -0
- package/src/_b_end_runtime/components/avatar-assets/avatar-default.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-1.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-2.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-3.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-4.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-5.png +0 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-1.svg +40 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-2.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/construction.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/failure.svg +49 -0
- package/src/_b_end_runtime/components/empty-assets/idle.svg +34 -0
- package/src/_b_end_runtime/components/empty-assets/no-access.svg +36 -0
- package/src/_b_end_runtime/components/empty-assets/no-content.svg +77 -0
- package/src/_b_end_runtime/components/empty-assets/no-result.svg +61 -0
- package/src/_b_end_runtime/components/empty-assets/not-found.svg +46 -0
- package/src/_b_end_runtime/components/empty-assets/success.svg +38 -0
- package/src/_b_end_runtime/components/file-type-assets/batch-report.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/catcat.svg +21 -0
- package/src/_b_end_runtime/components/file-type-assets/code.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/conversation.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/document.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-card.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-sheet.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/image.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/index.js +105 -0
- package/src/_b_end_runtime/components/file-type-assets/knowledge.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pdf.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pe.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/strategy.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/table.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/webpage.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/xmind.png +0 -0
- package/src/_b_end_runtime/components/icons/icon-data.js +12496 -0
- package/src/_b_end_runtime/components/nav-bar-assets/bytehi-logo-mark.svg +21 -0
- package/src/_b_end_runtime/components/table-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-assets/icon-chevron-down.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/checkbox.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon-chevron-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-handle.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-tree-triangle-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/switch.png +0 -0
- package/src/_b_end_runtime/components/tagShared.js +3 -0
- package/src/_b_end_runtime/components/team-avatar-assets/chengcheng-murphy.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/duan-ran.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/guo-zhezhi.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/li-siru.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/liu-delin.png +0 -0
- package/src/_b_end_runtime/components.js +3499 -0
- package/src/_b_end_runtime/index.js +9 -0
- package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +395 -0
- package/src/_b_end_runtime/page-patterns/ChatConversationPattern.jsx +989 -0
- package/src/_b_end_runtime/page-patterns/ChatHomePagePattern.jsx +281 -0
- package/src/_b_end_runtime/page-patterns/CopilotPagePattern.jsx +380 -0
- package/src/_b_end_runtime/page-patterns/CustomerServiceWorkspaceFramePattern.jsx +392 -0
- package/src/_b_end_runtime/page-patterns/IMConversationPattern.jsx +590 -0
- package/src/_b_end_runtime/page-patterns/McpManagementPage.jsx +237 -0
- package/src/_b_end_runtime/page-patterns/StrategyListPage.jsx +189 -0
- package/src/_b_end_runtime/page-patterns/TabTopBarListPage.jsx +594 -0
- package/src/_b_end_runtime/page-patterns/VariableManagementPage.jsx +87 -0
- package/src/_b_end_runtime/page-patterns/pageListShared.jsx +177 -0
- package/src/_b_end_runtime/patterns.js +428 -0
- package/src/_b_end_runtime/preview-registry.jsx +4719 -0
- package/src/_b_end_runtime/teamMembers.js +56 -0
- package/src/_b_end_runtime/tokens.js +500 -0
- package/src/index.d.ts +1073 -0
- package/src/index.js +52 -0
- package/theme.css +350 -0
|
@@ -0,0 +1,4719 @@
|
|
|
1
|
+
// B端设计系统 — 预览注册表
|
|
2
|
+
//
|
|
3
|
+
// 平台预览配置,和组件规范(components.js / 三件套)分离。
|
|
4
|
+
// 每个组件一段:挂组件引用、TOKEN_MAP、预览控制项、控制值→Props 的映射。
|
|
5
|
+
|
|
6
|
+
import { Plus, Heart, Star, Zap, Search, Eye } from 'lucide-react';
|
|
7
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
8
|
+
import AvatarGridPreview from './components/AvatarGridPreview';
|
|
9
|
+
import AvatarGroup from './components/AvatarGroup';
|
|
10
|
+
import Button from './components/Button';
|
|
11
|
+
import Tabs from './components/Tabs';
|
|
12
|
+
import Modal from './components/Modal';
|
|
13
|
+
import Sheet from './components/Sheet';
|
|
14
|
+
import FormTitle from './components/FormTitle';
|
|
15
|
+
import Form, { FORM_FIELD_TYPES, FORM_SAMPLE_ITEMS } from './components/Form';
|
|
16
|
+
import FormFieldStack from './components/FormFieldStack';
|
|
17
|
+
import Input from './components/Input';
|
|
18
|
+
import TextArea from './components/TextArea';
|
|
19
|
+
import InputNumber from './components/InputNumber';
|
|
20
|
+
import Select from './components/Select';
|
|
21
|
+
import RadioGroup, { Radio } from './components/Radio';
|
|
22
|
+
import CheckboxGroup, { Checkbox } from './components/Checkbox';
|
|
23
|
+
import Switch from './components/Switch';
|
|
24
|
+
import ChatBubblePreview from './components/ChatBubblePreview';
|
|
25
|
+
import ChatInput from './components/ChatInput';
|
|
26
|
+
import ChatMessagePreview from './components/ChatMessagePreview';
|
|
27
|
+
import CardPreview from './components/CardPreview';
|
|
28
|
+
import ConversationListPreview from './components/ConversationListPreview';
|
|
29
|
+
import InfoDisplayPanelPreview from './components/InfoDisplayPanelPreview';
|
|
30
|
+
import NavBarPreview from './components/NavBarPreview';
|
|
31
|
+
import TagBar, { TAGBAR_SAMPLE_BUSINESSES, TAGBAR_SAMPLE_ITEMS } from './components/TagBar';
|
|
32
|
+
import Icon from './components/Icon';
|
|
33
|
+
import IconGridPreview from './components/IconGridPreview';
|
|
34
|
+
import Slider from './components/Slider';
|
|
35
|
+
import Upload from './components/Upload';
|
|
36
|
+
import DatePicker from './components/DatePicker';
|
|
37
|
+
import TimePicker from './components/TimePicker';
|
|
38
|
+
import Toast from './components/Toast';
|
|
39
|
+
import Tag from './components/Tag';
|
|
40
|
+
import TagInput from './components/TagInput';
|
|
41
|
+
import TagGridPreview from './components/TagGridPreview';
|
|
42
|
+
import TablePreview, {
|
|
43
|
+
TABLE_VARIANT_OPTIONS,
|
|
44
|
+
TABLE_COLUMN_TYPE_OPTIONS,
|
|
45
|
+
TABLE_CELL_SIZE_OPTIONS,
|
|
46
|
+
buildTableUsageFromControls,
|
|
47
|
+
} from './components/TablePreview';
|
|
48
|
+
import TooltipPreview from './components/TooltipPreview';
|
|
49
|
+
import { AVATAR_TOKEN_MAP } from './components/Avatar.tokens';
|
|
50
|
+
import { AVATAR_GROUP_TOKEN_MAP } from './components/AvatarGroup.tokens';
|
|
51
|
+
import { BUTTON_TOKEN_MAP } from './components/Button.tokens';
|
|
52
|
+
import { TABS_TOKEN_MAP } from './components/Tabs.tokens';
|
|
53
|
+
import { MODAL_TOKEN_MAP } from './components/Modal.tokens';
|
|
54
|
+
import { SHEET_TOKEN_MAP } from './components/Sheet.tokens';
|
|
55
|
+
import { FORM_TITLE_TOKEN_MAP } from './components/FormTitle.tokens';
|
|
56
|
+
import { FORM_TOKEN_MAP } from './components/Form.tokens';
|
|
57
|
+
import { FORM_FIELD_STACK_TOKEN_MAP } from './components/FormFieldStack.tokens';
|
|
58
|
+
import { INPUT_TOKEN_MAP } from './components/Input.tokens';
|
|
59
|
+
import { TEXTAREA_TOKEN_MAP } from './components/TextArea.tokens';
|
|
60
|
+
import { INPUT_NUMBER_TOKEN_MAP } from './components/InputNumber.tokens';
|
|
61
|
+
import { SELECT_TOKEN_MAP } from './components/Select.tokens';
|
|
62
|
+
import { RADIO_TOKEN_MAP } from './components/Radio.tokens';
|
|
63
|
+
import { CHECKBOX_TOKEN_MAP } from './components/Checkbox.tokens';
|
|
64
|
+
import { SWITCH_TOKEN_MAP } from './components/Switch.tokens';
|
|
65
|
+
import { CHATBUBBLE_TOKEN_MAP } from './components/ChatBubble.tokens';
|
|
66
|
+
import { CHATINPUT_TOKEN_MAP } from './components/ChatInput.tokens';
|
|
67
|
+
import { CHAT_MESSAGE_TOKEN_MAP } from './components/ChatMessage.tokens';
|
|
68
|
+
import { CARD_TOKEN_MAP } from './components/Card.tokens';
|
|
69
|
+
import { CONVERSATION_LIST_TOKEN_MAP } from './components/ConversationList.tokens';
|
|
70
|
+
import { INFO_DISPLAY_PANEL_TOKEN_MAP } from './components/InfoDisplayPanel.tokens';
|
|
71
|
+
import { NAVBAR_TOKEN_MAP } from './components/NavBar.tokens';
|
|
72
|
+
import { TAGBAR_TOKEN_MAP } from './components/TagBar.tokens';
|
|
73
|
+
import { ICON_TOKEN_MAP } from './components/Icon.tokens';
|
|
74
|
+
import { SLIDER_TOKEN_MAP } from './components/Slider.tokens';
|
|
75
|
+
import { UPLOAD_TOKEN_MAP } from './components/Upload.tokens';
|
|
76
|
+
import { DATEPICKER_TOKEN_MAP } from './components/DatePicker.tokens';
|
|
77
|
+
import { TIMEPICKER_TOKEN_MAP } from './components/TimePicker.tokens';
|
|
78
|
+
import { TOAST_TOKEN_MAP } from './components/Toast.tokens';
|
|
79
|
+
import { TAG_TOKEN_MAP } from './components/Tag.tokens';
|
|
80
|
+
import { TAGINPUT_TOKEN_MAP } from './components/TagInput.tokens';
|
|
81
|
+
import { TABLE_TOKEN_MAP } from './components/Table.tokens';
|
|
82
|
+
import { TOOLTIP_TOKEN_MAP } from './components/Tooltip.tokens';
|
|
83
|
+
import avatarJsxRaw from './components/Avatar.jsx?raw';
|
|
84
|
+
import avatarGroupJsxRaw from './components/AvatarGroup.jsx?raw';
|
|
85
|
+
import buttonJsxRaw from './components/Button.jsx?raw';
|
|
86
|
+
import tabsJsxRaw from './components/Tabs.jsx?raw';
|
|
87
|
+
import modalJsxRaw from './components/Modal.jsx?raw';
|
|
88
|
+
import sheetJsxRaw from './components/Sheet.jsx?raw';
|
|
89
|
+
import formTitleJsxRaw from './components/FormTitle.jsx?raw';
|
|
90
|
+
import formJsxRaw from './components/Form.jsx?raw';
|
|
91
|
+
import formFieldStackJsxRaw from './components/FormFieldStack.jsx?raw';
|
|
92
|
+
import inputJsxRaw from './components/Input.jsx?raw';
|
|
93
|
+
import textareaJsxRaw from './components/TextArea.jsx?raw';
|
|
94
|
+
import inputNumberJsxRaw from './components/InputNumber.jsx?raw';
|
|
95
|
+
import selectJsxRaw from './components/Select.jsx?raw';
|
|
96
|
+
import radioJsxRaw from './components/Radio.jsx?raw';
|
|
97
|
+
import checkboxJsxRaw from './components/Checkbox.jsx?raw';
|
|
98
|
+
import switchJsxRaw from './components/Switch.jsx?raw';
|
|
99
|
+
import chatBubbleJsxRaw from './components/ChatBubble.jsx?raw';
|
|
100
|
+
import chatInputJsxRaw from './components/ChatInput.jsx?raw';
|
|
101
|
+
import chatMessageJsxRaw from './components/ChatMessage.jsx?raw';
|
|
102
|
+
import cardJsxRaw from './components/Card.jsx?raw';
|
|
103
|
+
import conversationListJsxRaw from './components/ConversationList.jsx?raw';
|
|
104
|
+
import infoDisplayPanelJsxRaw from './components/InfoDisplayPanel.jsx?raw';
|
|
105
|
+
import navBarJsxRaw from './components/NavBar.jsx?raw';
|
|
106
|
+
import tagBarJsxRaw from './components/TagBar.jsx?raw';
|
|
107
|
+
import iconJsxRaw from './components/Icon.jsx?raw';
|
|
108
|
+
|
|
109
|
+
import sliderJsxRaw from './components/Slider.jsx?raw';
|
|
110
|
+
import uploadJsxRaw from './components/Upload.jsx?raw';
|
|
111
|
+
import datePickerJsxRaw from './components/DatePicker.jsx?raw';
|
|
112
|
+
import timePickerJsxRaw from './components/TimePicker.jsx?raw';
|
|
113
|
+
import toastJsxRaw from './components/Toast.jsx?raw';
|
|
114
|
+
import tagJsxRaw from './components/Tag.jsx?raw';
|
|
115
|
+
import tagInputJsxRaw from './components/TagInput.jsx?raw';
|
|
116
|
+
import tableJsxRaw from './components/Table.jsx?raw';
|
|
117
|
+
import tooltipJsxRaw from './components/Tooltip.jsx?raw';
|
|
118
|
+
import Empty from './components/Empty';
|
|
119
|
+
import { EMPTY_TOKEN_MAP } from './components/Empty.tokens';
|
|
120
|
+
import emptyJsxRaw from './components/Empty.jsx?raw';
|
|
121
|
+
import FullScreenPage from './components/FullScreenPage';
|
|
122
|
+
import { FULL_SCREEN_PAGE_TOKEN_MAP } from './components/FullScreenPage.tokens';
|
|
123
|
+
import fullScreenPageJsxRaw from './components/FullScreenPage.jsx?raw';
|
|
124
|
+
|
|
125
|
+
/** 预览用:切换「初始开/关」时通过 key 重挂载,避免 defaultChecked 仅在 mount 生效 */
|
|
126
|
+
function SwitchPreview({ variant = 'brand', defaultChecked, disabled }) {
|
|
127
|
+
return (
|
|
128
|
+
<Switch
|
|
129
|
+
key={`sw-${defaultChecked}-${disabled}`}
|
|
130
|
+
variant={variant}
|
|
131
|
+
defaultChecked={defaultChecked}
|
|
132
|
+
disabled={disabled}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const SLIDER_PREVIEW_MARKS = { 0: '0%', 25: '25%', 50: '50%', 75: '75%', 100: '100%' };
|
|
138
|
+
const SLIDER_PREVIEW_MARKS_TEXT = JSON.stringify(SLIDER_PREVIEW_MARKS, null, 2);
|
|
139
|
+
const SLIDER_PREVIEW_DEFAULTS = {
|
|
140
|
+
min: 0,
|
|
141
|
+
max: 100,
|
|
142
|
+
step: 1,
|
|
143
|
+
showTooltip: true,
|
|
144
|
+
defaultValueRangeText: '[20, 80]',
|
|
145
|
+
defaultValueSingleText: '50',
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
function composeHidden(hiddenA, hiddenB) {
|
|
149
|
+
if (!hiddenA) return hiddenB;
|
|
150
|
+
if (!hiddenB) return hiddenA;
|
|
151
|
+
return (ctx) => hiddenA(ctx) || hiddenB(ctx);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getSliderControlIds(prefix = '') {
|
|
155
|
+
const buildId = (name) => (prefix ? `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}` : name);
|
|
156
|
+
return {
|
|
157
|
+
initialKey: buildId('initialKey'),
|
|
158
|
+
min: buildId('min'),
|
|
159
|
+
max: buildId('max'),
|
|
160
|
+
step: buildId('step'),
|
|
161
|
+
defaultValueText: buildId('defaultValueText'),
|
|
162
|
+
showTooltip: buildId('showTooltip'),
|
|
163
|
+
hasMarks: buildId('hasMarks'),
|
|
164
|
+
marksText: buildId('marksText'),
|
|
165
|
+
disabled: buildId('disabled'),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function resolveSliderPreviewDefaultValueText(initialKey = 'range') {
|
|
170
|
+
return initialKey === 'single'
|
|
171
|
+
? SLIDER_PREVIEW_DEFAULTS.defaultValueSingleText
|
|
172
|
+
: SLIDER_PREVIEW_DEFAULTS.defaultValueRangeText;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function parseSliderPreviewDefaultValue(raw, initialKey) {
|
|
176
|
+
const fallback = initialKey === 'single' ? 50 : [20, 80];
|
|
177
|
+
if (typeof raw === 'number') return initialKey === 'single' ? raw : [20, 80];
|
|
178
|
+
const text = String(raw ?? '').trim();
|
|
179
|
+
if (!text) return fallback;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const parsed = JSON.parse(text);
|
|
183
|
+
if (initialKey === 'single') {
|
|
184
|
+
const num = Array.isArray(parsed) ? Number(parsed[0]) : Number(parsed);
|
|
185
|
+
return Number.isFinite(num) ? num : fallback;
|
|
186
|
+
}
|
|
187
|
+
if (Array.isArray(parsed)) {
|
|
188
|
+
const values = parsed.slice(0, 2).map((item) => Number(item)).filter((item) => Number.isFinite(item));
|
|
189
|
+
if (values.length === 2) return values;
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
if (initialKey === 'single') {
|
|
193
|
+
const num = Number(text);
|
|
194
|
+
if (Number.isFinite(num)) return num;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return fallback;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function parseSliderPreviewMarks(text, enabled) {
|
|
202
|
+
if (!enabled) return undefined;
|
|
203
|
+
const raw = String(text ?? '').trim();
|
|
204
|
+
if (!raw) return SLIDER_PREVIEW_MARKS;
|
|
205
|
+
try {
|
|
206
|
+
const parsed = JSON.parse(raw);
|
|
207
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
} catch {
|
|
211
|
+
return SLIDER_PREVIEW_MARKS;
|
|
212
|
+
}
|
|
213
|
+
return SLIDER_PREVIEW_MARKS;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function buildSliderPreviewControls(prefix = '', hidden) {
|
|
217
|
+
const ids = getSliderControlIds(prefix);
|
|
218
|
+
return [
|
|
219
|
+
{
|
|
220
|
+
id: ids.initialKey,
|
|
221
|
+
label: '初始模式',
|
|
222
|
+
type: 'seg',
|
|
223
|
+
options: [
|
|
224
|
+
{ id: 'range', label: '区间' },
|
|
225
|
+
{ id: 'single', label: '单值' },
|
|
226
|
+
],
|
|
227
|
+
default: 'range',
|
|
228
|
+
hidden,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: ids.min,
|
|
232
|
+
label: '最小值',
|
|
233
|
+
type: 'number',
|
|
234
|
+
default: SLIDER_PREVIEW_DEFAULTS.min,
|
|
235
|
+
hidden,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: ids.max,
|
|
239
|
+
label: '最大值',
|
|
240
|
+
type: 'number',
|
|
241
|
+
default: SLIDER_PREVIEW_DEFAULTS.max,
|
|
242
|
+
hidden,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: ids.step,
|
|
246
|
+
label: '步长',
|
|
247
|
+
type: 'number',
|
|
248
|
+
default: SLIDER_PREVIEW_DEFAULTS.step,
|
|
249
|
+
hidden,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: ids.defaultValueText,
|
|
253
|
+
label: '默认值',
|
|
254
|
+
type: 'text',
|
|
255
|
+
default: resolveSliderPreviewDefaultValueText('range'),
|
|
256
|
+
hidden,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: ids.showTooltip,
|
|
260
|
+
label: '提示气泡',
|
|
261
|
+
type: 'switch',
|
|
262
|
+
default: SLIDER_PREVIEW_DEFAULTS.showTooltip,
|
|
263
|
+
hidden,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: ids.hasMarks,
|
|
267
|
+
label: '刻度',
|
|
268
|
+
type: 'seg',
|
|
269
|
+
options: [
|
|
270
|
+
{ id: 'on', label: '显示' },
|
|
271
|
+
{ id: 'off', label: '隐藏' },
|
|
272
|
+
],
|
|
273
|
+
default: 'off',
|
|
274
|
+
hidden,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: ids.marksText,
|
|
278
|
+
label: '刻度配置',
|
|
279
|
+
type: 'textarea',
|
|
280
|
+
default: SLIDER_PREVIEW_MARKS_TEXT,
|
|
281
|
+
hidden: composeHidden(hidden, ({ controlValues }) => (controlValues[ids.hasMarks] || 'off') !== 'on'),
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: ids.disabled,
|
|
285
|
+
label: '禁用',
|
|
286
|
+
type: 'switch',
|
|
287
|
+
default: false,
|
|
288
|
+
hidden,
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function normalizeSliderPreviewControls(nextControlValues, prevControlValues, changedControlId, prefix = '') {
|
|
294
|
+
const ids = getSliderControlIds(prefix);
|
|
295
|
+
const next = { ...nextControlValues };
|
|
296
|
+
const nextInitialKey = next[ids.initialKey] || 'range';
|
|
297
|
+
const prevInitialKey = prevControlValues?.[ids.initialKey] || 'range';
|
|
298
|
+
const prevDefaultText = prevControlValues?.[ids.defaultValueText];
|
|
299
|
+
const nextDefaultText = next[ids.defaultValueText];
|
|
300
|
+
|
|
301
|
+
if (changedControlId === '__init__' || nextDefaultText == null || nextDefaultText === '') {
|
|
302
|
+
next[ids.defaultValueText] = resolveSliderPreviewDefaultValueText(nextInitialKey);
|
|
303
|
+
} else if (changedControlId === ids.initialKey) {
|
|
304
|
+
const prevTemplate = resolveSliderPreviewDefaultValueText(prevInitialKey);
|
|
305
|
+
if (prevDefaultText == null || prevDefaultText === prevTemplate || nextDefaultText === prevTemplate) {
|
|
306
|
+
next[ids.defaultValueText] = resolveSliderPreviewDefaultValueText(nextInitialKey);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (changedControlId === '__init__' || changedControlId === ids.hasMarks) {
|
|
311
|
+
if ((next[ids.hasMarks] || 'off') === 'on' && !String(next[ids.marksText] || '').trim()) {
|
|
312
|
+
next[ids.marksText] = SLIDER_PREVIEW_MARKS_TEXT;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return next;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function buildSliderPreviewProps(controlValues, prefix = '') {
|
|
320
|
+
const ids = getSliderControlIds(prefix);
|
|
321
|
+
const initialKey = controlValues[ids.initialKey] || 'range';
|
|
322
|
+
const min = Number(controlValues[ids.min]);
|
|
323
|
+
const max = Number(controlValues[ids.max]);
|
|
324
|
+
const safeMin = Number.isFinite(min) ? min : SLIDER_PREVIEW_DEFAULTS.min;
|
|
325
|
+
const safeMaxCandidate = Number.isFinite(max) ? max : SLIDER_PREVIEW_DEFAULTS.max;
|
|
326
|
+
const safeMax = safeMaxCandidate > safeMin ? safeMaxCandidate : safeMin + 1;
|
|
327
|
+
const step = Number(controlValues[ids.step]);
|
|
328
|
+
const safeStep = Number.isFinite(step) && step > 0 ? step : SLIDER_PREVIEW_DEFAULTS.step;
|
|
329
|
+
const showTooltip = controlValues[ids.showTooltip] !== false;
|
|
330
|
+
const disabled = controlValues[ids.disabled] === true;
|
|
331
|
+
const marksEnabled = (controlValues[ids.hasMarks] || 'off') === 'on';
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
initialKey,
|
|
335
|
+
min: safeMin,
|
|
336
|
+
max: safeMax,
|
|
337
|
+
step: safeStep,
|
|
338
|
+
defaultValue: parseSliderPreviewDefaultValue(controlValues[ids.defaultValueText], initialKey),
|
|
339
|
+
showTooltip,
|
|
340
|
+
marks: parseSliderPreviewMarks(controlValues[ids.marksText], marksEnabled),
|
|
341
|
+
disabled,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function formatUsageLiteral(value) {
|
|
346
|
+
if (value === undefined) return undefined;
|
|
347
|
+
if (typeof value === 'string') return `'${value}'`;
|
|
348
|
+
return JSON.stringify(value);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** 预览用:key 保证切换配置时非受控 defaultValue 生效 */
|
|
352
|
+
function SliderPreview({ min, max, step, defaultValue, showTooltip, marks, disabled, initialKey }) {
|
|
353
|
+
return (
|
|
354
|
+
<Slider
|
|
355
|
+
key={`sl-${initialKey}-${min}-${max}-${step}-${Boolean(marks)}-${disabled}-${JSON.stringify(defaultValue)}`}
|
|
356
|
+
min={min}
|
|
357
|
+
max={max}
|
|
358
|
+
step={step}
|
|
359
|
+
defaultValue={defaultValue}
|
|
360
|
+
showTooltip={showTooltip}
|
|
361
|
+
marks={marks}
|
|
362
|
+
disabled={disabled}
|
|
363
|
+
/>
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const INPUT_SINGLE_SUGGESTIONS = [
|
|
368
|
+
'您好,您的问题已收到,抖音客服正在为您核实处理。',
|
|
369
|
+
'您好,这边已为您记录反馈,正在同步专员跟进。',
|
|
370
|
+
'您好,当前问题我们正在核查中,请您稍候查看处理结果。',
|
|
371
|
+
];
|
|
372
|
+
|
|
373
|
+
const INPUT_MULTI_SUGGESTION_GROUPS = [
|
|
374
|
+
[
|
|
375
|
+
'您好,正在为您核实,请稍候。',
|
|
376
|
+
'抱歉给您带来不便,这边已经帮您加急处理。',
|
|
377
|
+
'您好,您反馈的问题我们已经收到,建议您先提供订单号和问题截图,方便抖音客服尽快为您核实处理。',
|
|
378
|
+
],
|
|
379
|
+
[
|
|
380
|
+
'您好,这边先帮您登记反馈。',
|
|
381
|
+
'请您放心,当前问题已经提交相关同学加急排查。',
|
|
382
|
+
'为了更快帮您确认处理进度,建议您补充订单编号、联系方式以及具体异常时间,抖音客服会尽快协助您跟进。',
|
|
383
|
+
],
|
|
384
|
+
[
|
|
385
|
+
'您好,已收到您的咨询。',
|
|
386
|
+
'很抱歉给您带来困扰,这边正在为您核实具体原因。',
|
|
387
|
+
'若方便的话,您可以补充问题页面截图和操作路径,我们会结合账号信息一并核查,尽快给您同步处理结果。',
|
|
388
|
+
],
|
|
389
|
+
];
|
|
390
|
+
|
|
391
|
+
const TEXTAREA_SINGLE_SUGGESTIONS = [
|
|
392
|
+
'根据当前对话内容,建议先记录用户诉求、异常现象和下一步处理动作。',
|
|
393
|
+
'建议在备注中补充订单号、问题发生时间和已核查结果,方便后续继续跟进。',
|
|
394
|
+
'可先生成一版客服备注草稿,后续结合人工判断再做补充和修订。',
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
const TEXTAREA_MULTI_SUGGESTION_GROUPS = [
|
|
398
|
+
[
|
|
399
|
+
'根据当前对话内容,建议先记录用户诉求、异常现象和下一步处理动作。',
|
|
400
|
+
'建议在备注中补充订单号、问题发生时间和已核查结果,方便后续继续跟进。',
|
|
401
|
+
],
|
|
402
|
+
[
|
|
403
|
+
'建议优先整理用户诉求、处理时效和需补充的材料信息。',
|
|
404
|
+
'如果需要后续交接,可一并记录当前判责结论和预计回访时间。',
|
|
405
|
+
],
|
|
406
|
+
[
|
|
407
|
+
'可先形成一版标准备注草稿,再结合人工判断补充风险说明。',
|
|
408
|
+
'建议在草稿中明确“已同步处理”“待用户补充资料”“下一步动作”这三类信息。',
|
|
409
|
+
],
|
|
410
|
+
];
|
|
411
|
+
|
|
412
|
+
const TAGINPUT_AI_SUGGESTION_GROUPS = [
|
|
413
|
+
[
|
|
414
|
+
['改签', '门店变更'],
|
|
415
|
+
['退款', '售后处理'],
|
|
416
|
+
['物流异常', '催办'],
|
|
417
|
+
],
|
|
418
|
+
[
|
|
419
|
+
['优惠券', '核销异常'],
|
|
420
|
+
['客服回访', '待跟进'],
|
|
421
|
+
['资损风险', '升级处理'],
|
|
422
|
+
],
|
|
423
|
+
[
|
|
424
|
+
['履约异常', '商家侧'],
|
|
425
|
+
['平台规则', '需复核'],
|
|
426
|
+
['用户反馈', '已记录'],
|
|
427
|
+
],
|
|
428
|
+
];
|
|
429
|
+
|
|
430
|
+
/** 预览用:key 随「填充 / 超长演示」切换重置非受控初值 */
|
|
431
|
+
function TextAreaPreview({
|
|
432
|
+
variant = 'default',
|
|
433
|
+
fillMode = 'empty',
|
|
434
|
+
countOverflow = false,
|
|
435
|
+
disabled = false,
|
|
436
|
+
status = 'default',
|
|
437
|
+
resize = 'vertical',
|
|
438
|
+
fillHeight = false,
|
|
439
|
+
minRows = 3,
|
|
440
|
+
aiSuggestion,
|
|
441
|
+
aiSuggestions,
|
|
442
|
+
}) {
|
|
443
|
+
const isCodeVariant = variant === 'code';
|
|
444
|
+
const sample = isCodeVariant
|
|
445
|
+
? '# 角色\n你是抖音安全中心的小安智能助手,负责理解用户诉求并给出清晰答案。\n\n# 注意\n1. 回答前先判断是否需要调用知识库。\n2. 需要给出可执行、可验证的处理建议。'
|
|
446
|
+
: '我们非常高兴地向您介绍我们的最新产品 HiUI。HiUI是一个创新的在线客服解决方案,旨在帮助企业更好地理解并服务他们的客户。';
|
|
447
|
+
const defaultValue = fillMode === 'filled' ? sample : '';
|
|
448
|
+
const enforceMaxLength = !countOverflow;
|
|
449
|
+
const minRowsSafe = Math.min(5, Math.max(1, Math.round(Number(minRows)) || 3));
|
|
450
|
+
/** 仅「超长计数=开」时展示右下角字数区;关闭后整块不渲染,总高度随 minRows+正文收缩 */
|
|
451
|
+
const showCountDemo = Boolean(countOverflow);
|
|
452
|
+
const [singleIndex, setSingleIndex] = useState(0);
|
|
453
|
+
const [multiIndex, setMultiIndex] = useState(0);
|
|
454
|
+
const hasSingleSuggestion = typeof aiSuggestion === 'string' && aiSuggestion.trim().length > 0;
|
|
455
|
+
const hasMultiSuggestions = Array.isArray(aiSuggestions) && aiSuggestions.length > 0;
|
|
456
|
+
|
|
457
|
+
const handleRefresh = useCallback(() => {
|
|
458
|
+
if (hasMultiSuggestions) {
|
|
459
|
+
setMultiIndex((prev) => (prev + 1) % TEXTAREA_MULTI_SUGGESTION_GROUPS.length);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (hasSingleSuggestion) {
|
|
463
|
+
setSingleIndex((prev) => (prev + 1) % TEXTAREA_SINGLE_SUGGESTIONS.length);
|
|
464
|
+
}
|
|
465
|
+
}, [hasMultiSuggestions, hasSingleSuggestion]);
|
|
466
|
+
|
|
467
|
+
return (
|
|
468
|
+
<TextArea
|
|
469
|
+
key={`textarea-${variant}-${fillMode}-${countOverflow}-${disabled}-${status}-${resize}-${fillHeight}-${minRowsSafe}`}
|
|
470
|
+
variant={variant}
|
|
471
|
+
minRows={minRowsSafe}
|
|
472
|
+
status={status}
|
|
473
|
+
disabled={disabled}
|
|
474
|
+
placeholder={isCodeVariant ? '请输入 System Prompt、JSON 或代码' : '请输入'}
|
|
475
|
+
defaultValue={defaultValue}
|
|
476
|
+
showCount={showCountDemo}
|
|
477
|
+
{...(showCountDemo ? { maxLength: 140, enforceMaxLength } : {})}
|
|
478
|
+
resize={resize}
|
|
479
|
+
fillHeight={fillHeight}
|
|
480
|
+
aiSuggestion={hasSingleSuggestion ? TEXTAREA_SINGLE_SUGGESTIONS[singleIndex] : undefined}
|
|
481
|
+
aiSuggestions={hasMultiSuggestions ? TEXTAREA_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
|
|
482
|
+
onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
|
|
483
|
+
className={fillHeight ? 'flex-1 min-h-0 w-full' : (isCodeVariant ? 'w-[520px]' : '')}
|
|
484
|
+
/>
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function InputPreview(props) {
|
|
489
|
+
const { aiSuggestion, aiSuggestions, onRefreshAiSuggestions: _ignored, ...rest } = props;
|
|
490
|
+
const [singleIndex, setSingleIndex] = useState(0);
|
|
491
|
+
const [multiIndex, setMultiIndex] = useState(0);
|
|
492
|
+
const hasSingleSuggestion = typeof aiSuggestion === 'string' && aiSuggestion.trim().length > 0;
|
|
493
|
+
const hasMultiSuggestions = Array.isArray(aiSuggestions) && aiSuggestions.length > 0;
|
|
494
|
+
|
|
495
|
+
const handleRefresh = useCallback(() => {
|
|
496
|
+
if (hasMultiSuggestions) {
|
|
497
|
+
setMultiIndex((prev) => (prev + 1) % INPUT_MULTI_SUGGESTION_GROUPS.length);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (hasSingleSuggestion) {
|
|
501
|
+
setSingleIndex((prev) => (prev + 1) % INPUT_SINGLE_SUGGESTIONS.length);
|
|
502
|
+
}
|
|
503
|
+
}, [hasMultiSuggestions, hasSingleSuggestion]);
|
|
504
|
+
|
|
505
|
+
return (
|
|
506
|
+
<Input
|
|
507
|
+
{...rest}
|
|
508
|
+
aiSuggestion={hasSingleSuggestion ? INPUT_SINGLE_SUGGESTIONS[singleIndex] : undefined}
|
|
509
|
+
aiSuggestions={hasMultiSuggestions ? INPUT_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
|
|
510
|
+
onRefreshAiSuggestions={hasSingleSuggestion || hasMultiSuggestions ? handleRefresh : undefined}
|
|
511
|
+
/>
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** 预览用:key 保证切换初始值 / 内外置按钮 / 禁用时非受控值重置 */
|
|
516
|
+
function InputNumberPreview({ content = 'empty', buttonMode = 'outer', disabled = false, status = 'default' }) {
|
|
517
|
+
const defaultValue = content === 'filled' ? 12 : undefined;
|
|
518
|
+
const innerButtons = buttonMode === 'inner';
|
|
519
|
+
return (
|
|
520
|
+
<InputNumber
|
|
521
|
+
key={`input-number-${content}-${buttonMode}-${disabled}-${status}`}
|
|
522
|
+
status={status}
|
|
523
|
+
disabled={disabled}
|
|
524
|
+
innerButtons={innerButtons}
|
|
525
|
+
defaultValue={defaultValue}
|
|
526
|
+
min={0}
|
|
527
|
+
max={99}
|
|
528
|
+
step={1}
|
|
529
|
+
placeholder="请输入"
|
|
530
|
+
/>
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const SELECT_DEMO_FEW = [
|
|
535
|
+
{ value: 'zj', label: '浙江省' },
|
|
536
|
+
{ value: 'js', label: '江苏省' },
|
|
537
|
+
{ value: 'sh', label: '上海市' },
|
|
538
|
+
];
|
|
539
|
+
|
|
540
|
+
const SELECT_DEMO_MANY = [
|
|
541
|
+
...SELECT_DEMO_FEW,
|
|
542
|
+
{ value: 'bj', label: '北京市' },
|
|
543
|
+
{ value: 'gd', label: '广东省' },
|
|
544
|
+
{ value: 'sc', label: '四川省' },
|
|
545
|
+
{ value: 'hub', label: '湖北省' },
|
|
546
|
+
{ value: 'hen', label: '河南省' },
|
|
547
|
+
];
|
|
548
|
+
|
|
549
|
+
const SELECT_TAG_OPTIONS = [
|
|
550
|
+
{ value: 'brand', label: '标签', variant: 'grey' },
|
|
551
|
+
{ value: 'risk', label: '标签', variant: 'grey' },
|
|
552
|
+
{ value: 'service', label: '标签', variant: 'grey' },
|
|
553
|
+
{ value: 'quality', label: '标签', variant: 'grey' },
|
|
554
|
+
{ value: 'growth', label: '标签', variant: 'grey' },
|
|
555
|
+
{ value: 'content', label: '标签', variant: 'grey' },
|
|
556
|
+
];
|
|
557
|
+
|
|
558
|
+
const SELECT_AI_SINGLE_SUGGESTIONS = ['江苏省', '上海市', '浙江省'];
|
|
559
|
+
|
|
560
|
+
const SELECT_AI_MULTI_SUGGESTION_GROUPS = [
|
|
561
|
+
['江苏省', '上海市', '浙江省'],
|
|
562
|
+
['上海市', '浙江省', '江苏省'],
|
|
563
|
+
['浙江省', '江苏省', '上海市'],
|
|
564
|
+
];
|
|
565
|
+
|
|
566
|
+
const DATEPICKER_SAMPLE_VALUE = {
|
|
567
|
+
date: '2019-03-15',
|
|
568
|
+
datetime: '2019-03-15 16:00:00',
|
|
569
|
+
daterange: ['2019-03-15', '2019-03-16'],
|
|
570
|
+
datetimerange: ['2019-03-15 09:00:00', '2019-03-16 16:00:00'],
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const TIMEPICKER_SAMPLE_VALUE = {
|
|
574
|
+
time: '12:15',
|
|
575
|
+
timerange: ['09:30', '18:00'],
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
const UPLOAD_SAMPLE_IMAGE_A = `data:image/svg+xml;utf8,${encodeURIComponent(
|
|
579
|
+
`<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><defs><linearGradient id='g1' x1='0' y1='0' x2='1' y2='1'><stop offset='0%' stop-color='#2B90D9'/><stop offset='100%' stop-color='#0A355A'/></linearGradient></defs><rect width='96' height='96' fill='url(#g1)'/><circle cx='72' cy='24' r='10' fill='rgba(255,255,255,0.28)'/><path d='M0 66C13 52 25 49 38 56C50 62 59 60 69 51C76 45 85 43 96 45V96H0Z' fill='rgba(255,255,255,0.24)'/></svg>`
|
|
580
|
+
)}`;
|
|
581
|
+
|
|
582
|
+
const UPLOAD_SAMPLE_IMAGE_B = `data:image/svg+xml;utf8,${encodeURIComponent(
|
|
583
|
+
`<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><defs><linearGradient id='g2' x1='0' y1='0' x2='1' y2='1'><stop offset='0%' stop-color='#0C4867'/><stop offset='100%' stop-color='#0A243A'/></linearGradient></defs><rect width='96' height='96' fill='url(#g2)'/><ellipse cx='49' cy='50' rx='22' ry='14' fill='rgba(255,255,255,0.22)'/><circle cx='49' cy='50' r='6' fill='rgba(255,255,255,0.85)'/></svg>`
|
|
584
|
+
)}`;
|
|
585
|
+
|
|
586
|
+
const CHATBUBBLE_PRESET_MESSAGES = {
|
|
587
|
+
incoming: {
|
|
588
|
+
single: ['为什么我无法设置点赞列表查看权限'],
|
|
589
|
+
multiple: ['为什么我无法设置点赞列表查看权限', '那怎么看自己的直播回放?'],
|
|
590
|
+
},
|
|
591
|
+
outgoing: {
|
|
592
|
+
single: ['您好,因产品功能更新,“作品点赞信息”设置开关正逐步下线中'],
|
|
593
|
+
multiple: [
|
|
594
|
+
'您好,因产品功能更新,“作品点赞信息”设置开关正逐步下线中',
|
|
595
|
+
'目前不支持设置“作品点赞信息”权限。该功能下线后,您发布的作品的点赞列表仅对您自己可见。',
|
|
596
|
+
],
|
|
597
|
+
},
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const CHATBUBBLE_PRESET_TIMESTAMPS = {
|
|
601
|
+
incoming: {
|
|
602
|
+
single: ['2026-02-26 10:24:14'],
|
|
603
|
+
multiple: ['2026-02-26 10:24:14', '2026-02-26 10:26:08'],
|
|
604
|
+
},
|
|
605
|
+
outgoing: {
|
|
606
|
+
single: ['2026-02-26 10:25:03'],
|
|
607
|
+
multiple: ['2026-02-26 10:25:03', '2026-02-26 10:26:44'],
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
/** 预览用:key 保证切换初始选中 / 禁用 / 枚举时 defaultValue 生效 */
|
|
612
|
+
function RadioPreview({ variant, layout, disabled, initialKey }) {
|
|
613
|
+
const defaultValue = initialKey === 'a' ? 'a' : initialKey === 'b' ? 'b' : undefined;
|
|
614
|
+
return (
|
|
615
|
+
<RadioGroup
|
|
616
|
+
key={`rp-${variant}-${layout}-${disabled}-${initialKey}`}
|
|
617
|
+
variant={variant}
|
|
618
|
+
layout={layout}
|
|
619
|
+
disabled={disabled}
|
|
620
|
+
defaultValue={defaultValue}
|
|
621
|
+
>
|
|
622
|
+
<Radio value="a">选项 A</Radio>
|
|
623
|
+
<Radio value="b">选项 B</Radio>
|
|
624
|
+
<Radio value="c" disabled>选项 C(单项禁用)</Radio>
|
|
625
|
+
</RadioGroup>
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/** 预览用:组模式用 defaultValue 数组;半选模式为单独 Checkbox */
|
|
630
|
+
function CheckboxPreview({ variant, size, layout, disabled, initialKey, previewMode }) {
|
|
631
|
+
if (previewMode === 'indeterminate') {
|
|
632
|
+
return (
|
|
633
|
+
<Checkbox
|
|
634
|
+
key={`cb-ind-${variant}-${size}-${disabled}`}
|
|
635
|
+
variant={variant}
|
|
636
|
+
size={size}
|
|
637
|
+
disabled={disabled}
|
|
638
|
+
indeterminate
|
|
639
|
+
>
|
|
640
|
+
半选状态(树形父级)
|
|
641
|
+
</Checkbox>
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
let defaultValue = [];
|
|
645
|
+
if (initialKey === 'a') defaultValue = ['a'];
|
|
646
|
+
else if (initialKey === 'ab') defaultValue = ['a', 'b'];
|
|
647
|
+
return (
|
|
648
|
+
<CheckboxGroup
|
|
649
|
+
key={`cbg-${variant}-${size}-${layout}-${disabled}-${initialKey}`}
|
|
650
|
+
variant={variant}
|
|
651
|
+
size={size}
|
|
652
|
+
layout={layout}
|
|
653
|
+
disabled={disabled}
|
|
654
|
+
defaultValue={defaultValue}
|
|
655
|
+
>
|
|
656
|
+
<Checkbox value="a">选项 A</Checkbox>
|
|
657
|
+
<Checkbox value="b">选项 B</Checkbox>
|
|
658
|
+
<Checkbox value="c" disabled>选项 C(单项禁用)</Checkbox>
|
|
659
|
+
</CheckboxGroup>
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/** 预览用:key 保证切换「初始值 / 选项量 / 禁用」时非受控 defaultValue 生效 */
|
|
664
|
+
function SelectPreview({ status, disabled, initial, optionMode, selectType, aiSuggestion, aiSuggestions }) {
|
|
665
|
+
const isTagSelect = selectType === 'tag';
|
|
666
|
+
const options = isTagSelect
|
|
667
|
+
? SELECT_TAG_OPTIONS
|
|
668
|
+
: optionMode === 'many'
|
|
669
|
+
? SELECT_DEMO_MANY
|
|
670
|
+
: SELECT_DEMO_FEW;
|
|
671
|
+
const [singleIndex, setSingleIndex] = useState(0);
|
|
672
|
+
const [multiIndex, setMultiIndex] = useState(0);
|
|
673
|
+
const hasSingleSuggestion = typeof aiSuggestion === 'string' && aiSuggestion.trim().length > 0;
|
|
674
|
+
const hasMultiSuggestions = Array.isArray(aiSuggestions) && aiSuggestions.length > 0;
|
|
675
|
+
const defaultValue = initial === 'selected'
|
|
676
|
+
? (isTagSelect ? ['brand', 'risk'] : 'js')
|
|
677
|
+
: undefined;
|
|
678
|
+
|
|
679
|
+
const handleRefresh = useCallback(() => {
|
|
680
|
+
if (hasMultiSuggestions) {
|
|
681
|
+
setMultiIndex((prev) => (prev + 1) % SELECT_AI_MULTI_SUGGESTION_GROUPS.length);
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
if (hasSingleSuggestion) {
|
|
685
|
+
setSingleIndex((prev) => (prev + 1) % SELECT_AI_SINGLE_SUGGESTIONS.length);
|
|
686
|
+
}
|
|
687
|
+
}, [hasMultiSuggestions, hasSingleSuggestion]);
|
|
688
|
+
|
|
689
|
+
return (
|
|
690
|
+
<div className="w-[300px] max-w-full">
|
|
691
|
+
<Select
|
|
692
|
+
key={`selp-${selectType}-${initial}-${optionMode}-${disabled}-${status}`}
|
|
693
|
+
mode={isTagSelect ? 'tag' : 'default'}
|
|
694
|
+
options={options}
|
|
695
|
+
defaultValue={defaultValue}
|
|
696
|
+
placeholder="请选择"
|
|
697
|
+
status={status}
|
|
698
|
+
disabled={disabled}
|
|
699
|
+
allowClear
|
|
700
|
+
aiSuggestion={!isTagSelect && hasSingleSuggestion ? SELECT_AI_SINGLE_SUGGESTIONS[singleIndex] : undefined}
|
|
701
|
+
aiSuggestions={!isTagSelect && hasMultiSuggestions ? SELECT_AI_MULTI_SUGGESTION_GROUPS[multiIndex] : undefined}
|
|
702
|
+
onRefreshAiSuggestions={!isTagSelect && (hasSingleSuggestion || hasMultiSuggestions) ? handleRefresh : undefined}
|
|
703
|
+
/>
|
|
704
|
+
</div>
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const FORM_FIELD_LABELS = {
|
|
709
|
+
input: 'Input',
|
|
710
|
+
'input-number': 'InputNumber',
|
|
711
|
+
textarea: 'TextArea',
|
|
712
|
+
select: 'Select',
|
|
713
|
+
checkbox: 'Checkbox',
|
|
714
|
+
radio: 'RadioGroup',
|
|
715
|
+
switch: 'Switch',
|
|
716
|
+
'date-picker': 'DatePicker',
|
|
717
|
+
'time-picker': 'TimePicker',
|
|
718
|
+
slider: 'Slider',
|
|
719
|
+
upload: 'Upload',
|
|
720
|
+
'input-group': 'InputGroup',
|
|
721
|
+
'tag-input': 'TagInput',
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
const TAGINPUT_SAMPLE_TAGS = [
|
|
725
|
+
'标签',
|
|
726
|
+
'标签',
|
|
727
|
+
'标签',
|
|
728
|
+
'标签',
|
|
729
|
+
'标签',
|
|
730
|
+
'标签',
|
|
731
|
+
];
|
|
732
|
+
|
|
733
|
+
const FORM_FIELD_ATOM_ENUM_PROPS = {
|
|
734
|
+
radio: [
|
|
735
|
+
{ name: 'controlVariant', type: 'enum', options: ['brand', 'black'], default: 'brand' },
|
|
736
|
+
{ name: 'controlLayout', type: 'enum', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
737
|
+
],
|
|
738
|
+
checkbox: [
|
|
739
|
+
{ name: 'controlVariant', type: 'enum', options: ['brand', 'black'], default: 'brand' },
|
|
740
|
+
{ name: 'controlLayout', type: 'enum', options: ['horizontal', 'vertical'], default: 'horizontal' },
|
|
741
|
+
],
|
|
742
|
+
switch: [
|
|
743
|
+
{ name: 'controlVariant', type: 'enum', options: ['brand', 'black'], default: 'black' },
|
|
744
|
+
],
|
|
745
|
+
'date-picker': [
|
|
746
|
+
{ name: 'pickerType', type: 'enum', options: ['date', 'datetime', 'daterange', 'datetimerange'], default: 'date' },
|
|
747
|
+
],
|
|
748
|
+
'time-picker': [
|
|
749
|
+
{ name: 'timePickerType', type: 'enum', options: ['time', 'timerange'], default: 'time' },
|
|
750
|
+
],
|
|
751
|
+
'input-number': [
|
|
752
|
+
{ name: 'inputNumberButtons', type: 'enum', options: ['outer', 'inner'], default: 'outer' },
|
|
753
|
+
],
|
|
754
|
+
/** 与 TextArea 组件详情「配置」侧栏顺序、选项 id、默认项一致(内容→超长计数→状态→默认高度→状态→高度适配) */
|
|
755
|
+
textarea: [
|
|
756
|
+
{ name: 'fillMode', type: 'enum', options: ['empty', 'filled'], default: 'empty' },
|
|
757
|
+
{ name: 'countOverflow', type: 'enum', options: ['off', 'on'], default: 'off' },
|
|
758
|
+
{ name: 'state', type: 'enum', options: ['default', 'disabled'], default: 'default' },
|
|
759
|
+
{ name: 'minRows', type: 'enum', options: [1, 2, 3, 4, 5], default: 3 },
|
|
760
|
+
{ name: 'status', type: 'enum', options: ['default', 'error'], default: 'default' },
|
|
761
|
+
{ name: 'resize', type: 'enum', options: ['vertical', 'none'], default: 'vertical' },
|
|
762
|
+
],
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
const FORM_TEXTAREA_SAMPLE =
|
|
766
|
+
'我们非常高兴地向您介绍我们的最新产品 HiUI。HiUI是一个创新的在线客服解决方案,旨在帮助企业更好地理解并服务他们的客户。';
|
|
767
|
+
|
|
768
|
+
function getFormFieldAtomEnumProps(fieldType) {
|
|
769
|
+
return FORM_FIELD_ATOM_ENUM_PROPS[fieldType] || [];
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function buildFormFieldAtomProps(fieldType, enums, controlValues = {}) {
|
|
773
|
+
if (fieldType === 'radio' || fieldType === 'checkbox') {
|
|
774
|
+
return {
|
|
775
|
+
variant: enums.controlVariant || 'brand',
|
|
776
|
+
layout: enums.controlLayout || 'horizontal',
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
if (fieldType === 'switch') {
|
|
780
|
+
return {
|
|
781
|
+
variant: enums.controlVariant || 'black',
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
if (fieldType === 'date-picker') {
|
|
785
|
+
return {
|
|
786
|
+
pickerType: enums.pickerType || 'date',
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
if (fieldType === 'time-picker') {
|
|
790
|
+
return {
|
|
791
|
+
pickerType: ['time', 'timerange'].includes(enums.timePickerType) ? enums.timePickerType : 'time',
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
if (fieldType === 'input-number') {
|
|
795
|
+
return {
|
|
796
|
+
innerButtons: enums.inputNumberButtons === 'inner',
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
if (fieldType === 'textarea') {
|
|
800
|
+
const fillMode = enums.fillMode === 'filled' ? 'filled' : 'empty';
|
|
801
|
+
const countOn = enums.countOverflow === 'on';
|
|
802
|
+
const disabled = enums.state === 'disabled';
|
|
803
|
+
const row = Number(enums.minRows);
|
|
804
|
+
const minRows = [1, 2, 3, 4, 5].includes(row) ? row : 3;
|
|
805
|
+
const status = enums.status === 'error' ? 'error' : 'default';
|
|
806
|
+
const resize = enums.resize === 'none' ? 'none' : 'vertical';
|
|
807
|
+
|
|
808
|
+
const props = {
|
|
809
|
+
minRows,
|
|
810
|
+
resize,
|
|
811
|
+
disabled,
|
|
812
|
+
};
|
|
813
|
+
if (status === 'error') props.status = 'error';
|
|
814
|
+
if (fillMode === 'filled') props.defaultValue = FORM_TEXTAREA_SAMPLE;
|
|
815
|
+
if (countOn) {
|
|
816
|
+
props.showCount = true;
|
|
817
|
+
props.maxLength = 140;
|
|
818
|
+
props.enforceMaxLength = false;
|
|
819
|
+
}
|
|
820
|
+
return props;
|
|
821
|
+
}
|
|
822
|
+
if (fieldType === 'slider') {
|
|
823
|
+
return buildSliderPreviewProps(controlValues, 'slider');
|
|
824
|
+
}
|
|
825
|
+
return {};
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function TagInputPreview({ content, widthMode, disabled, status, tagVariant, tagSize, showAiSuggestions = true }) {
|
|
829
|
+
const defaultValue = content === 'filled' ? TAGINPUT_SAMPLE_TAGS : [];
|
|
830
|
+
const widthClass = widthMode === 'narrow' ? '!w-[220px]' : widthMode === 'wide' ? '!w-[420px]' : '';
|
|
831
|
+
const [suggestionIndex, setSuggestionIndex] = useState(0);
|
|
832
|
+
const handleRefresh = useCallback(() => {
|
|
833
|
+
setSuggestionIndex((prev) => (prev + 1) % TAGINPUT_AI_SUGGESTION_GROUPS.length);
|
|
834
|
+
}, []);
|
|
835
|
+
return (
|
|
836
|
+
<TagInput
|
|
837
|
+
key={`tag-input-${content}-${widthMode}-${disabled}-${status}-${tagVariant}-${tagSize}`}
|
|
838
|
+
status={status}
|
|
839
|
+
disabled={disabled}
|
|
840
|
+
defaultValue={defaultValue}
|
|
841
|
+
placeholder="请输入"
|
|
842
|
+
tagVariant={tagVariant}
|
|
843
|
+
tagSize={tagSize}
|
|
844
|
+
aiSuggestions={showAiSuggestions ? TAGINPUT_AI_SUGGESTION_GROUPS[suggestionIndex] : undefined}
|
|
845
|
+
onRefreshAiSuggestions={showAiSuggestions ? handleRefresh : undefined}
|
|
846
|
+
className={widthClass}
|
|
847
|
+
/>
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function buildFormPreviewItems({ previewMode, fieldType, labelPosition, helpMode, validationState, fieldAtomProps }) {
|
|
852
|
+
if (previewMode === 'all') {
|
|
853
|
+
return FORM_SAMPLE_ITEMS.map((item) => ({
|
|
854
|
+
...item,
|
|
855
|
+
id: `${item.id}-all`,
|
|
856
|
+
labelPosition: 'top',
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const type = FORM_FIELD_TYPES.includes(fieldType) ? fieldType : 'input';
|
|
861
|
+
return [{
|
|
862
|
+
id: `form-${type}`,
|
|
863
|
+
label: '字段标题',
|
|
864
|
+
type,
|
|
865
|
+
required: true,
|
|
866
|
+
labelPosition,
|
|
867
|
+
middleHelpText: helpMode === 'middle' ? '提示文案' : undefined,
|
|
868
|
+
helpText: helpMode === 'bottom' ? '提示文案' : undefined,
|
|
869
|
+
error: validationState === 'error',
|
|
870
|
+
defaultValue: type === 'radio'
|
|
871
|
+
? 'a'
|
|
872
|
+
: type === 'checkbox'
|
|
873
|
+
? ['a']
|
|
874
|
+
: type === 'tag-input'
|
|
875
|
+
? TAGINPUT_SAMPLE_TAGS
|
|
876
|
+
: undefined,
|
|
877
|
+
...fieldAtomProps,
|
|
878
|
+
}];
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function FormPreview({
|
|
882
|
+
previewMode,
|
|
883
|
+
fieldType,
|
|
884
|
+
labelPosition,
|
|
885
|
+
helpMode,
|
|
886
|
+
validationState,
|
|
887
|
+
size,
|
|
888
|
+
labelOptional,
|
|
889
|
+
labelRequired,
|
|
890
|
+
labelAi,
|
|
891
|
+
labelHelp,
|
|
892
|
+
fieldAtomProps,
|
|
893
|
+
}) {
|
|
894
|
+
const baseItems = buildFormPreviewItems({
|
|
895
|
+
previewMode,
|
|
896
|
+
fieldType,
|
|
897
|
+
labelPosition,
|
|
898
|
+
helpMode,
|
|
899
|
+
validationState,
|
|
900
|
+
fieldAtomProps,
|
|
901
|
+
});
|
|
902
|
+
const sliderDefaultValue = previewMode === 'single' && fieldType === 'slider'
|
|
903
|
+
? fieldAtomProps.defaultValue
|
|
904
|
+
: undefined;
|
|
905
|
+
const [sliderValue, setSliderValue] = useState(sliderDefaultValue);
|
|
906
|
+
|
|
907
|
+
useEffect(() => {
|
|
908
|
+
setSliderValue(Array.isArray(sliderDefaultValue) ? [...sliderDefaultValue] : sliderDefaultValue);
|
|
909
|
+
}, [sliderDefaultValue, fieldType, helpMode, labelPosition, previewMode, size, validationState]);
|
|
910
|
+
|
|
911
|
+
const items = previewMode === 'single' && fieldType === 'slider'
|
|
912
|
+
? baseItems.map((item) => ({
|
|
913
|
+
...item,
|
|
914
|
+
value: sliderValue,
|
|
915
|
+
defaultValue: undefined,
|
|
916
|
+
onChange: setSliderValue,
|
|
917
|
+
onAfterChange: setSliderValue,
|
|
918
|
+
}))
|
|
919
|
+
: baseItems;
|
|
920
|
+
|
|
921
|
+
return (
|
|
922
|
+
<Form
|
|
923
|
+
key={`form-${previewMode}-${fieldType}-${labelPosition}-${helpMode}-${validationState}-${size}-${labelOptional}-${labelRequired}-${labelAi}-${labelHelp}-${JSON.stringify(fieldAtomProps || {})}`}
|
|
924
|
+
layout="vertical"
|
|
925
|
+
columns={1}
|
|
926
|
+
labelPosition={labelPosition}
|
|
927
|
+
size={size}
|
|
928
|
+
labelOptional={labelOptional}
|
|
929
|
+
labelRequired={labelRequired}
|
|
930
|
+
labelAi={labelAi}
|
|
931
|
+
labelHelp={labelHelp}
|
|
932
|
+
items={items}
|
|
933
|
+
className={previewMode === 'all' ? '!gap-10' : ''}
|
|
934
|
+
/>
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
export const PREVIEW_REGISTRY = {
|
|
939
|
+
avatar: {
|
|
940
|
+
component: AvatarGridPreview,
|
|
941
|
+
tokenMap: AVATAR_TOKEN_MAP,
|
|
942
|
+
jsxSource: avatarJsxRaw,
|
|
943
|
+
|
|
944
|
+
controls: [
|
|
945
|
+
{
|
|
946
|
+
id: 'type',
|
|
947
|
+
label: '场景',
|
|
948
|
+
type: 'seg',
|
|
949
|
+
options: [
|
|
950
|
+
{ id: 'all', label: '全部' },
|
|
951
|
+
{ id: 'image', label: '图片' },
|
|
952
|
+
{ id: 'eng', label: '英文' },
|
|
953
|
+
{ id: 'ch', label: '中文' },
|
|
954
|
+
{ id: 'fallback', label: '兜底' },
|
|
955
|
+
{ id: 'robot', label: '机器人' },
|
|
956
|
+
{ id: 'ai', label: 'AI头像' },
|
|
957
|
+
],
|
|
958
|
+
default: 'all',
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
id: 'previewMode',
|
|
962
|
+
label: '预览',
|
|
963
|
+
type: 'seg',
|
|
964
|
+
options: [
|
|
965
|
+
{ id: 'matrix', label: '矩阵' },
|
|
966
|
+
{ id: 'single', label: '单个' },
|
|
967
|
+
],
|
|
968
|
+
default: 'matrix',
|
|
969
|
+
},
|
|
970
|
+
],
|
|
971
|
+
|
|
972
|
+
mapProps: (cv, enums) => ({
|
|
973
|
+
previewMode: cv.previewMode || 'matrix',
|
|
974
|
+
shape: enums.shape || 'round',
|
|
975
|
+
size: enums.size || 'default',
|
|
976
|
+
type: cv.type || enums.type || 'image',
|
|
977
|
+
}),
|
|
978
|
+
|
|
979
|
+
getVisibleEnumProps: ({ enumProps, controlValues }) => (
|
|
980
|
+
(controlValues.previewMode || 'matrix') === 'matrix'
|
|
981
|
+
? enumProps.filter((prop) => prop.name === 'shape')
|
|
982
|
+
: enumProps
|
|
983
|
+
),
|
|
984
|
+
|
|
985
|
+
generateUsage: (enums, cv) => {
|
|
986
|
+
const lines = [`import Avatar from './components/Avatar';`];
|
|
987
|
+
const shape = enums.shape || 'round';
|
|
988
|
+
const isMatrix = (cv.previewMode || 'matrix') === 'matrix';
|
|
989
|
+
const size = isMatrix ? 'default' : (enums.size || 'default');
|
|
990
|
+
const selectedType = cv.type || enums.type || 'all';
|
|
991
|
+
const type = selectedType === 'all' ? 'image' : selectedType;
|
|
992
|
+
const props = [];
|
|
993
|
+
|
|
994
|
+
if (shape !== 'round') props.push(`shape="${shape}"`);
|
|
995
|
+
if (size !== 'default') props.push(`size="${size}"`);
|
|
996
|
+
if (type !== 'image') props.push(`type="${type}"`);
|
|
997
|
+
|
|
998
|
+
if (type === 'image') {
|
|
999
|
+
props.push('alt="用户头像"');
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
if (type === 'eng') {
|
|
1003
|
+
props.push(`label="${size === 'xxs' || size === 'mini' || size === 'xs' ? 'T' : 'TF'}"`);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (type === 'ch') {
|
|
1007
|
+
props.push(`label="${size === 'default' || size === 'm' ? '体服' : '体'}"`);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
lines.push('');
|
|
1011
|
+
lines.push('<Avatar');
|
|
1012
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
1013
|
+
lines.push('/>');
|
|
1014
|
+
return lines.join('\n');
|
|
1015
|
+
},
|
|
1016
|
+
},
|
|
1017
|
+
|
|
1018
|
+
'avatar-group': {
|
|
1019
|
+
component: AvatarGroup,
|
|
1020
|
+
tokenMap: AVATAR_GROUP_TOKEN_MAP,
|
|
1021
|
+
jsxSource: avatarGroupJsxRaw,
|
|
1022
|
+
|
|
1023
|
+
controls: [],
|
|
1024
|
+
|
|
1025
|
+
mapProps: (cv, enums) => ({
|
|
1026
|
+
size: enums.size || 's',
|
|
1027
|
+
}),
|
|
1028
|
+
|
|
1029
|
+
generateUsage: (enums) => {
|
|
1030
|
+
const lines = [`import AvatarGroup from './components/AvatarGroup';`];
|
|
1031
|
+
const size = enums.size || 's';
|
|
1032
|
+
const props = [];
|
|
1033
|
+
|
|
1034
|
+
if (size !== 's') props.push(`size="${size}"`);
|
|
1035
|
+
|
|
1036
|
+
lines.push('');
|
|
1037
|
+
lines.push('<AvatarGroup');
|
|
1038
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
1039
|
+
lines.push('/>');
|
|
1040
|
+
return lines.join('\n');
|
|
1041
|
+
},
|
|
1042
|
+
},
|
|
1043
|
+
|
|
1044
|
+
icon: {
|
|
1045
|
+
component: Icon,
|
|
1046
|
+
gridComponent: IconGridPreview,
|
|
1047
|
+
tokenMap: ICON_TOKEN_MAP,
|
|
1048
|
+
jsxSource: iconJsxRaw,
|
|
1049
|
+
previewType: 'icon-grid',
|
|
1050
|
+
|
|
1051
|
+
controls: [],
|
|
1052
|
+
|
|
1053
|
+
mapProps: (cv, enums) => ({
|
|
1054
|
+
name: 'check-stroked',
|
|
1055
|
+
}),
|
|
1056
|
+
|
|
1057
|
+
generateUsage: (enums) => {
|
|
1058
|
+
const lines = [`import Icon from './components/Icon';`];
|
|
1059
|
+
lines.push(`import { ICON_CATEGORIES } from './components/icons/icon-data';`);
|
|
1060
|
+
lines.push('');
|
|
1061
|
+
lines.push(`<Icon name="图标名称" size="${enums.size || 'sm'}" />`);
|
|
1062
|
+
return lines.join('\n');
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1065
|
+
|
|
1066
|
+
card: {
|
|
1067
|
+
component: CardPreview,
|
|
1068
|
+
tokenMap: CARD_TOKEN_MAP,
|
|
1069
|
+
jsxSource: cardJsxRaw,
|
|
1070
|
+
configHiddenEnums: ['type', 'infoIconTone', 'infoMetaBadgeVariant', 'dataIconTone'],
|
|
1071
|
+
enumTitles: {
|
|
1072
|
+
color: '颜色',
|
|
1073
|
+
infoIconStyle: '图标样式',
|
|
1074
|
+
infoLayout: '图标位置',
|
|
1075
|
+
productInfoLayout: '图标位置',
|
|
1076
|
+
dataIconVisible: '是否显示图标',
|
|
1077
|
+
dataIconStyle: '图标样式',
|
|
1078
|
+
},
|
|
1079
|
+
|
|
1080
|
+
controls: [
|
|
1081
|
+
{
|
|
1082
|
+
id: 'category',
|
|
1083
|
+
label: '分类',
|
|
1084
|
+
type: 'seg',
|
|
1085
|
+
options: [
|
|
1086
|
+
{ id: 'default', label: '数据卡片' },
|
|
1087
|
+
{ id: 'product', label: '商品卡片' },
|
|
1088
|
+
{ id: 'info', label: '信息卡片' },
|
|
1089
|
+
],
|
|
1090
|
+
default: 'default',
|
|
1091
|
+
},
|
|
1092
|
+
],
|
|
1093
|
+
|
|
1094
|
+
mapProps: (cv, enums) => {
|
|
1095
|
+
const type = cv.category === 'product' || cv.category === 'info' ? cv.category : 'data';
|
|
1096
|
+
return {
|
|
1097
|
+
type,
|
|
1098
|
+
color: enums.color || 'white',
|
|
1099
|
+
infoIconTone: enums.infoIconTone || 'pink',
|
|
1100
|
+
infoIconStyle: enums.infoIconStyle || 'inverse',
|
|
1101
|
+
infoLayout: type === 'info'
|
|
1102
|
+
? (enums.infoLayout || 'icon-right')
|
|
1103
|
+
: (enums.productInfoLayout || 'default'),
|
|
1104
|
+
infoMetaBadgeVariant: undefined,
|
|
1105
|
+
dataIconVisible: enums.dataIconVisible || 'hidden',
|
|
1106
|
+
dataIconStyle: enums.dataIconStyle || 'inverse',
|
|
1107
|
+
};
|
|
1108
|
+
},
|
|
1109
|
+
|
|
1110
|
+
getVisibleEnumProps: ({ enumProps, controlValues = {} }) => {
|
|
1111
|
+
const category = controlValues.category || 'default';
|
|
1112
|
+
const props = enumProps || [];
|
|
1113
|
+
if (category === 'info') {
|
|
1114
|
+
return props.filter((prop) => ['color', 'infoIconStyle', 'infoLayout'].includes(prop.name));
|
|
1115
|
+
}
|
|
1116
|
+
if (category === 'product') {
|
|
1117
|
+
const colorProp = props.find((prop) => prop.name === 'color');
|
|
1118
|
+
const layoutProp = props.find((prop) => prop.name === 'infoLayout');
|
|
1119
|
+
return [
|
|
1120
|
+
colorProp,
|
|
1121
|
+
layoutProp ? { ...layoutProp, name: 'productInfoLayout', default: 'default' } : null,
|
|
1122
|
+
].filter(Boolean);
|
|
1123
|
+
}
|
|
1124
|
+
return props.filter((prop) => ['color', 'dataIconVisible', 'dataIconStyle'].includes(prop.name));
|
|
1125
|
+
},
|
|
1126
|
+
|
|
1127
|
+
generateUsage: (enums, cv = {}) => {
|
|
1128
|
+
const lines = [`import Card from './components/Card';`];
|
|
1129
|
+
const color = enums.color || 'white';
|
|
1130
|
+
const type = cv.category === 'product' || cv.category === 'info' ? cv.category : 'data';
|
|
1131
|
+
lines.push('');
|
|
1132
|
+
|
|
1133
|
+
if (type === 'data') {
|
|
1134
|
+
lines.push('const stats = [');
|
|
1135
|
+
lines.push(" { iconName: 'users-01-stroked', value: '1,289' },");
|
|
1136
|
+
lines.push(" { iconName: 'message-chat-square-stroked', value: '1,289' },");
|
|
1137
|
+
lines.push(" { iconName: 'hearts-stroked', value: '276' },");
|
|
1138
|
+
lines.push('];');
|
|
1139
|
+
lines.push('');
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
if (color === 'grey') {
|
|
1143
|
+
lines.push('/* 白色背景容器里,推荐使用灰底 Card 做层次分隔 */');
|
|
1144
|
+
lines.push('<div className="bg-white p-6">');
|
|
1145
|
+
} else {
|
|
1146
|
+
lines.push('/* 灰色背景容器里,推荐使用白底 Card 做内容承载 */');
|
|
1147
|
+
lines.push('<div className="bg-blueGrey-200 p-6">');
|
|
1148
|
+
}
|
|
1149
|
+
lines.push(' <Card');
|
|
1150
|
+
if (type === 'product') lines.push(' type="product"');
|
|
1151
|
+
if (type === 'info') lines.push(' type="info"');
|
|
1152
|
+
if (color !== 'white') lines.push(` color="${color}"`);
|
|
1153
|
+
if (type === 'product') {
|
|
1154
|
+
lines.push(' title="海底捞门店通用双人套餐"');
|
|
1155
|
+
lines.push(' description="数量 1 · ¥128.00 · 月售 2,361"');
|
|
1156
|
+
lines.push(` infoLayout="${enums.productInfoLayout || 'default'}"`);
|
|
1157
|
+
lines.push(' productStatus="已使用"');
|
|
1158
|
+
} else if (type === 'info') {
|
|
1159
|
+
lines.push(' title="抖音 AI 创作助手"');
|
|
1160
|
+
lines.push(' description="抖音官方 AI 创作能力,支持短视频脚本、标题推荐、封面文案和热点灵感生成,帮助创作者提升内容生产效率。"');
|
|
1161
|
+
lines.push(' infoIconName="magic-wand-01-stroked"');
|
|
1162
|
+
lines.push(` infoIconStyle="${enums.infoIconStyle || 'inverse'}"`);
|
|
1163
|
+
lines.push(` infoLayout="${enums.infoLayout || 'icon-right'}"`);
|
|
1164
|
+
lines.push(' infoMetaBadge="官方能力"');
|
|
1165
|
+
lines.push(' infoMetaLabel="段然"');
|
|
1166
|
+
lines.push(' infoStats={[');
|
|
1167
|
+
lines.push(' { iconName: "users-01-stroked", value: "128.6K" },');
|
|
1168
|
+
lines.push(' { iconName: "star-01-stroked", value: "4.9" },');
|
|
1169
|
+
lines.push(' { iconName: "play-circle-stroked", value: "立即体验" },');
|
|
1170
|
+
lines.push(' ]}');
|
|
1171
|
+
} else {
|
|
1172
|
+
lines.push(' title="更新用户资料"');
|
|
1173
|
+
lines.push(' description="更新用户个人资料信息,支持修改昵称、头像、简介等。"');
|
|
1174
|
+
lines.push(' stats={stats}');
|
|
1175
|
+
lines.push(' tags={["社区", "收藏星标"]}');
|
|
1176
|
+
if ((enums.dataIconVisible || 'hidden') === 'visible') {
|
|
1177
|
+
lines.push(' dataIconVisible="visible"');
|
|
1178
|
+
lines.push(' dataIconName="edit-04-stroked"');
|
|
1179
|
+
lines.push(` dataIconStyle="${enums.dataIconStyle || 'inverse'}"`);
|
|
1180
|
+
}
|
|
1181
|
+
lines.push(' actionAriaLabel="查看详情"');
|
|
1182
|
+
lines.push(' onAction={() => {}}');
|
|
1183
|
+
}
|
|
1184
|
+
lines.push(' />');
|
|
1185
|
+
lines.push('</div>');
|
|
1186
|
+
return lines.join('\n');
|
|
1187
|
+
},
|
|
1188
|
+
},
|
|
1189
|
+
|
|
1190
|
+
'conversation-list': {
|
|
1191
|
+
component: ConversationListPreview,
|
|
1192
|
+
tokenMap: CONVERSATION_LIST_TOKEN_MAP,
|
|
1193
|
+
jsxSource: conversationListJsxRaw,
|
|
1194
|
+
hideBaseVariantControl: true,
|
|
1195
|
+
controls: [
|
|
1196
|
+
{
|
|
1197
|
+
id: 'previewVariant',
|
|
1198
|
+
label: '变体',
|
|
1199
|
+
type: 'seg',
|
|
1200
|
+
options: [
|
|
1201
|
+
{ id: 'default', label: '默认列表' },
|
|
1202
|
+
{ id: 'card', label: '卡片列表' },
|
|
1203
|
+
],
|
|
1204
|
+
default: 'default',
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
id: 'defaultPreviewMode',
|
|
1208
|
+
label: '组件状态',
|
|
1209
|
+
type: 'seg',
|
|
1210
|
+
options: [
|
|
1211
|
+
{ id: 'expanded', label: '平铺' },
|
|
1212
|
+
{ id: 'collapsed', label: '收起' },
|
|
1213
|
+
],
|
|
1214
|
+
default: 'expanded',
|
|
1215
|
+
hidden: ({ controlValues }) => (controlValues.previewVariant || 'default') !== 'default',
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
id: 'cardPreviewMode',
|
|
1219
|
+
label: '组件状态',
|
|
1220
|
+
type: 'seg',
|
|
1221
|
+
options: [
|
|
1222
|
+
{ id: 'card-all', label: '全部' },
|
|
1223
|
+
{ id: 'card-replied', label: '已回复' },
|
|
1224
|
+
{ id: 'card-generating', label: '生成中' },
|
|
1225
|
+
{ id: 'card-editable', label: '可发送' },
|
|
1226
|
+
],
|
|
1227
|
+
default: 'card-all',
|
|
1228
|
+
hidden: ({ controlValues }) => (controlValues.previewVariant || 'default') !== 'card',
|
|
1229
|
+
},
|
|
1230
|
+
],
|
|
1231
|
+
|
|
1232
|
+
mapProps: (cv) => {
|
|
1233
|
+
const variant = cv.previewVariant || 'default';
|
|
1234
|
+
const previewMode = variant === 'card'
|
|
1235
|
+
? (cv.cardPreviewMode || 'card-all')
|
|
1236
|
+
: (cv.defaultPreviewMode || 'expanded');
|
|
1237
|
+
|
|
1238
|
+
return {
|
|
1239
|
+
variant,
|
|
1240
|
+
previewMode,
|
|
1241
|
+
};
|
|
1242
|
+
},
|
|
1243
|
+
|
|
1244
|
+
getVisibleEnumProps: ({ enumProps }) => enumProps.filter(
|
|
1245
|
+
(prop) => prop.name !== 'variant' && prop.name !== 'defaultVariant'
|
|
1246
|
+
),
|
|
1247
|
+
|
|
1248
|
+
generateUsage: (_enums, cv = {}) => {
|
|
1249
|
+
const variant = cv.previewVariant || 'default';
|
|
1250
|
+
const previewMode = variant === 'card'
|
|
1251
|
+
? (cv.cardPreviewMode || 'card-all')
|
|
1252
|
+
: (cv.defaultPreviewMode || 'expanded');
|
|
1253
|
+
|
|
1254
|
+
if (previewMode === 'card-replied') {
|
|
1255
|
+
return [
|
|
1256
|
+
`import ConversationList from './components/ConversationList';`,
|
|
1257
|
+
'',
|
|
1258
|
+
'<ConversationList',
|
|
1259
|
+
' variant="card"',
|
|
1260
|
+
' sections={[{',
|
|
1261
|
+
' id: "pending",',
|
|
1262
|
+
' title: "待干预",',
|
|
1263
|
+
' count: 1,',
|
|
1264
|
+
' items: [{',
|
|
1265
|
+
' id: "pending-1",',
|
|
1266
|
+
' title: "抖音账号解封",',
|
|
1267
|
+
' userName: "小兔叽掉毛毛🐰",',
|
|
1268
|
+
' orderId: "2918575148379876",',
|
|
1269
|
+
' time: "3分钟前",',
|
|
1270
|
+
' avatarSrc: avatarUrl,',
|
|
1271
|
+
' tags: [{ label: "待干预", variant: "grey", iconName: "alarm-clock-stroked" }],',
|
|
1272
|
+
' messages: [',
|
|
1273
|
+
' { id: "m1", role: "user", text: "但是我不知道问题出在哪里" },',
|
|
1274
|
+
' { id: "m2", role: "user", text: "你帮我看下这个有啥问题呢" },',
|
|
1275
|
+
' { id: "m3", role: "agent", text: "《抖音网络社区自律公约》:抖音app-我-右上角≡-设置-抖音规则中心,这是咱们抖音官方的一个规则呢" },',
|
|
1276
|
+
' { id: "m4", role: "user", text: "好的明白了,谢谢,没其他问题了" },',
|
|
1277
|
+
' ],',
|
|
1278
|
+
' status: "replied",',
|
|
1279
|
+
' draftText: "",',
|
|
1280
|
+
' }],',
|
|
1281
|
+
' }]}',
|
|
1282
|
+
'/>',
|
|
1283
|
+
].join('\n');
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
if (previewMode === 'card-generating') {
|
|
1287
|
+
return [
|
|
1288
|
+
`import ConversationList from './components/ConversationList';`,
|
|
1289
|
+
'',
|
|
1290
|
+
'<ConversationList',
|
|
1291
|
+
' variant="card"',
|
|
1292
|
+
' sections={[{',
|
|
1293
|
+
' id: "pending",',
|
|
1294
|
+
' title: "待干预",',
|
|
1295
|
+
' count: 1,',
|
|
1296
|
+
' items: [{',
|
|
1297
|
+
' id: "pending-1",',
|
|
1298
|
+
' title: "酒旅·仲裁退款",',
|
|
1299
|
+
' userName: "小兔叽掉毛毛🐰",',
|
|
1300
|
+
' orderId: "2918575148379876",',
|
|
1301
|
+
' time: "13:32",',
|
|
1302
|
+
' avatarSrc: avatarUrl,',
|
|
1303
|
+
' tags: [{ label: "异常监控提醒", variant: "grey" }, { label: "待干预", variant: "red" }],',
|
|
1304
|
+
' messages: [',
|
|
1305
|
+
' { id: "m1", role: "user", text: "但是我不知道问题出在哪里" },',
|
|
1306
|
+
' { id: "m2", role: "user", text: "你帮我看下这个有啥问题呢" },',
|
|
1307
|
+
' { id: "m3", role: "agent", text: "《抖音网络社区自律公约》:抖音app-我-右上角≡-设置-抖音规则中心,这是咱们抖音官方的一个规则呢" },',
|
|
1308
|
+
' { id: "m4", role: "user", text: "好的明白了,谢谢,没其他问题了" },',
|
|
1309
|
+
' ],',
|
|
1310
|
+
' status: "generating",',
|
|
1311
|
+
' draftText: "",',
|
|
1312
|
+
' }],',
|
|
1313
|
+
' }]}',
|
|
1314
|
+
'/>',
|
|
1315
|
+
].join('\n');
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
if (previewMode === 'card-editable') {
|
|
1319
|
+
return [
|
|
1320
|
+
`import ConversationList from './components/ConversationList';`,
|
|
1321
|
+
'',
|
|
1322
|
+
'<ConversationList',
|
|
1323
|
+
' variant="card"',
|
|
1324
|
+
' sections={[{',
|
|
1325
|
+
' id: "managed",',
|
|
1326
|
+
' title: "托管中",',
|
|
1327
|
+
' count: 1,',
|
|
1328
|
+
' items: [{',
|
|
1329
|
+
' id: "managed-1",',
|
|
1330
|
+
' title: "物流状态异常跟进",',
|
|
1331
|
+
' userName: "软软想吃糖葫芦",',
|
|
1332
|
+
' orderId: "2918575148472390",',
|
|
1333
|
+
' time: "11:22",',
|
|
1334
|
+
' avatarSrc: avatarUrl,',
|
|
1335
|
+
' tags: [{ label: "24时30分", variant: "grey", iconName: "alarm-clock-stroked" }, { label: "托管中", variant: "green" }],',
|
|
1336
|
+
' messages: [',
|
|
1337
|
+
' { id: "m1", role: "user", text: "你帮我看下这个有啥问题呢" },',
|
|
1338
|
+
' { id: "m2", role: "agent", text: "《抖音网络社区自律公约》:抖音app-我-右上角≡-设置-抖音规则中心,这是咱们抖音官方的一个规则呢" },',
|
|
1339
|
+
' { id: "m3", role: "user", text: "好的明白了,谢谢,没其他问题了" },',
|
|
1340
|
+
' ],',
|
|
1341
|
+
' status: "editable",',
|
|
1342
|
+
' draftText: "祝您生活愉快~如果您觉得我的服务态度还可以的话,辛苦您点击左下角结束服务为本次服务点亮小星星哦~",',
|
|
1343
|
+
' }],',
|
|
1344
|
+
' }]}',
|
|
1345
|
+
'/>',
|
|
1346
|
+
].join('\n');
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return [
|
|
1350
|
+
`import ConversationList from './components/ConversationList';`,
|
|
1351
|
+
'',
|
|
1352
|
+
'<ConversationList',
|
|
1353
|
+
' activeTab="all"',
|
|
1354
|
+
' activeItemId="managed-1"',
|
|
1355
|
+
' onTabChange={(tabId) => setCurrentTab(tabId)}',
|
|
1356
|
+
' onItemClick={(item) => openConversation(item.id)}',
|
|
1357
|
+
'/>',
|
|
1358
|
+
].join('\n');
|
|
1359
|
+
},
|
|
1360
|
+
},
|
|
1361
|
+
|
|
1362
|
+
'info-display-panel': {
|
|
1363
|
+
component: InfoDisplayPanelPreview,
|
|
1364
|
+
tokenMap: INFO_DISPLAY_PANEL_TOKEN_MAP,
|
|
1365
|
+
jsxSource: infoDisplayPanelJsxRaw,
|
|
1366
|
+
hideBaseVariantControl: true,
|
|
1367
|
+
|
|
1368
|
+
getPreviewAreaStyle: () => ({
|
|
1369
|
+
flexDirection: 'column',
|
|
1370
|
+
alignItems: 'stretch',
|
|
1371
|
+
justifyContent: 'flex-start',
|
|
1372
|
+
overflow: 'auto',
|
|
1373
|
+
padding: 24,
|
|
1374
|
+
}),
|
|
1375
|
+
|
|
1376
|
+
getPreviewScalerStyle: () => ({
|
|
1377
|
+
width: '100%',
|
|
1378
|
+
minWidth: 0,
|
|
1379
|
+
boxSizing: 'border-box',
|
|
1380
|
+
}),
|
|
1381
|
+
|
|
1382
|
+
getPreviewItemStyle: () => ({
|
|
1383
|
+
width: '100%',
|
|
1384
|
+
minWidth: 0,
|
|
1385
|
+
height: 520,
|
|
1386
|
+
display: 'flex',
|
|
1387
|
+
alignSelf: 'stretch',
|
|
1388
|
+
}),
|
|
1389
|
+
|
|
1390
|
+
controls: [
|
|
1391
|
+
{
|
|
1392
|
+
id: 'contentCount',
|
|
1393
|
+
label: '内容数量',
|
|
1394
|
+
type: 'seg',
|
|
1395
|
+
options: [
|
|
1396
|
+
{ id: 'single', label: '单Tab' },
|
|
1397
|
+
{ id: 'multi', label: '多Tab' },
|
|
1398
|
+
],
|
|
1399
|
+
default: 'multi',
|
|
1400
|
+
},
|
|
1401
|
+
],
|
|
1402
|
+
|
|
1403
|
+
mapProps: (cv) => ({
|
|
1404
|
+
__previewKey: 'info-display-panel',
|
|
1405
|
+
contentCount: cv.contentCount || 'multi',
|
|
1406
|
+
}),
|
|
1407
|
+
|
|
1408
|
+
generateUsage: (_enums, cv) => {
|
|
1409
|
+
const isSingleTab = (cv.contentCount || 'multi') === 'single';
|
|
1410
|
+
const lines = [`import InfoDisplayPanel from './components/InfoDisplayPanel';`, ''];
|
|
1411
|
+
lines.push('<InfoDisplayPanel');
|
|
1412
|
+
if (isSingleTab) {
|
|
1413
|
+
lines.push(' panels={[');
|
|
1414
|
+
lines.push(' { id: "profile", tabs: [{ id: "profile", label: "用户信息" }] },');
|
|
1415
|
+
lines.push(' ]}');
|
|
1416
|
+
} else {
|
|
1417
|
+
lines.push(' panels={[');
|
|
1418
|
+
lines.push(' { id: "assistant", tabs: [{ id: "assistant", label: "托管助手" }] },');
|
|
1419
|
+
lines.push(' { id: "tickets", tabs: [{ id: "history", label: "历史工单" }, { id: "logs", label: "工单日志" }, { id: "tools", label: "信息工具" }] },');
|
|
1420
|
+
lines.push(' { id: "info", tabs: [{ id: "video", label: "视频信息" }, { id: "user", label: "用户命中实验" }, { id: "records", label: "沟通记录" }] },');
|
|
1421
|
+
lines.push(' ]}');
|
|
1422
|
+
}
|
|
1423
|
+
lines.push(' renderPanelContent={({ panel }) => (');
|
|
1424
|
+
lines.push(' <div className="rounded-md border border-border-default bg-blueGrey-50 p-3">');
|
|
1425
|
+
lines.push(' {/* 每栏内容区固定 p-4 + gap-4;这里放具体业务详情、工单卡片或表单块 */}');
|
|
1426
|
+
lines.push(' {panel.id}');
|
|
1427
|
+
lines.push(' </div>');
|
|
1428
|
+
lines.push(' )}');
|
|
1429
|
+
lines.push('/>');
|
|
1430
|
+
return lines.join('\n');
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
|
|
1434
|
+
'nav-bar': {
|
|
1435
|
+
component: NavBarPreview,
|
|
1436
|
+
tokenMap: NAVBAR_TOKEN_MAP,
|
|
1437
|
+
jsxSource: navBarJsxRaw,
|
|
1438
|
+
controls: [
|
|
1439
|
+
{
|
|
1440
|
+
id: 'platform',
|
|
1441
|
+
label: '平台',
|
|
1442
|
+
type: 'seg',
|
|
1443
|
+
options: [
|
|
1444
|
+
{ id: 'ola', label: 'OLA' },
|
|
1445
|
+
{ id: 'bytehi', label: 'ByteHi' },
|
|
1446
|
+
],
|
|
1447
|
+
default: 'ola',
|
|
1448
|
+
},
|
|
1449
|
+
{
|
|
1450
|
+
id: 'utilityActions',
|
|
1451
|
+
label: '底部操作',
|
|
1452
|
+
type: 'seg',
|
|
1453
|
+
options: [
|
|
1454
|
+
{ id: 'hidden', label: '隐藏' },
|
|
1455
|
+
{ id: 'visible', label: '显示' },
|
|
1456
|
+
],
|
|
1457
|
+
default: 'hidden',
|
|
1458
|
+
},
|
|
1459
|
+
],
|
|
1460
|
+
|
|
1461
|
+
getVisibleEnumProps: ({ enumProps }) => enumProps.filter((prop) => prop.name !== 'avatarType' && prop.name !== 'platform' && prop.name !== 'promptText'),
|
|
1462
|
+
|
|
1463
|
+
mapProps: (cv, enums) => ({
|
|
1464
|
+
platform: cv.platform || 'ola',
|
|
1465
|
+
brandName: cv.platform === 'bytehi' ? 'ByteHi' : 'OLA',
|
|
1466
|
+
showUtilityActions: cv.utilityActions === 'visible',
|
|
1467
|
+
utilityItems: cv.utilityActions === 'visible'
|
|
1468
|
+
? (cv.platform === 'bytehi'
|
|
1469
|
+
? [
|
|
1470
|
+
{ id: 'guide', label: '操作指南', iconName: 'help-circle-stroked' },
|
|
1471
|
+
{ id: 'message', label: '消息', iconName: 'bell-03-stroked' },
|
|
1472
|
+
]
|
|
1473
|
+
: [
|
|
1474
|
+
{ id: 'notice', label: '通知消息', iconName: 'bell-03-stroked' },
|
|
1475
|
+
{ id: 'settings', label: '系统设置', iconName: 'settings-02-stroked' },
|
|
1476
|
+
])
|
|
1477
|
+
: [],
|
|
1478
|
+
avatarType: enums.avatarType || 'image',
|
|
1479
|
+
}),
|
|
1480
|
+
|
|
1481
|
+
getPreviewAreaStyle: () => ({
|
|
1482
|
+
alignItems: 'stretch',
|
|
1483
|
+
justifyContent: 'flex-start',
|
|
1484
|
+
padding: '0 24px 0 0',
|
|
1485
|
+
}),
|
|
1486
|
+
|
|
1487
|
+
getPreviewItemStyle: () => ({
|
|
1488
|
+
display: 'flex',
|
|
1489
|
+
alignItems: 'stretch',
|
|
1490
|
+
justifyContent: 'flex-start',
|
|
1491
|
+
height: '100%',
|
|
1492
|
+
minHeight: '100%',
|
|
1493
|
+
alignSelf: 'stretch',
|
|
1494
|
+
}),
|
|
1495
|
+
|
|
1496
|
+
generateUsage: (enums, cv = {}) => {
|
|
1497
|
+
const avatarType = enums.avatarType || 'image';
|
|
1498
|
+
const platform = cv.platform || 'ola';
|
|
1499
|
+
const utilityActions = cv.utilityActions || 'hidden';
|
|
1500
|
+
const lines = [`import NavBar from './components/NavBar';`];
|
|
1501
|
+
|
|
1502
|
+
if (platform === 'ola') {
|
|
1503
|
+
lines.push('');
|
|
1504
|
+
lines.push('const appBusinesses = [');
|
|
1505
|
+
lines.push(" { id: 'douyin-community', label: '抖音社区', iconSrc: 'icon-logo-douyin' },");
|
|
1506
|
+
lines.push(" { id: 'douyin-local-services', label: '抖音生活服务', iconSrc: 'icon-logo-douyin' },");
|
|
1507
|
+
lines.push(" { id: 'douyin-ecommerce', label: '抖音电商', iconSrc: 'icon-logo-douyin' },");
|
|
1508
|
+
lines.push('];');
|
|
1509
|
+
lines.push('');
|
|
1510
|
+
lines.push('const navItems = [');
|
|
1511
|
+
lines.push(" { id: 'strategy', label: '策略管理', iconName: 'if-stroked' },");
|
|
1512
|
+
lines.push(" { id: 'knowledge', label: '知识与案例', iconName: 'book-open-01-stroked' },");
|
|
1513
|
+
lines.push(" { id: 'tools', label: '工具管理', iconName: 'tool-01-stroked' },");
|
|
1514
|
+
lines.push(" { id: 'insight', label: '对话洞察', iconName: 'message-chat-circle-stroked' },");
|
|
1515
|
+
lines.push(" { id: 'monitor', label: '智能盯盘', iconName: 'grid-03-stroked' },");
|
|
1516
|
+
lines.push('];');
|
|
1517
|
+
}
|
|
1518
|
+
if (platform === 'ola' && utilityActions === 'visible') {
|
|
1519
|
+
lines.push('');
|
|
1520
|
+
lines.push('const utilityItems = [');
|
|
1521
|
+
lines.push(" { id: 'notice', label: '通知消息', iconName: 'bell-03-stroked' },");
|
|
1522
|
+
lines.push(" { id: 'settings', label: '系统设置', iconName: 'settings-02-stroked' },");
|
|
1523
|
+
lines.push('];');
|
|
1524
|
+
}
|
|
1525
|
+
if (platform === 'bytehi' && utilityActions === 'visible') {
|
|
1526
|
+
lines.push('');
|
|
1527
|
+
lines.push('const utilityItems = [');
|
|
1528
|
+
lines.push(" { id: 'guide', label: '操作指南', iconName: 'help-circle-stroked' },");
|
|
1529
|
+
lines.push(" { id: 'message', label: '消息', iconName: 'bell-03-stroked' },");
|
|
1530
|
+
lines.push('];');
|
|
1531
|
+
}
|
|
1532
|
+
lines.push('');
|
|
1533
|
+
lines.push('<NavBar');
|
|
1534
|
+
if (platform !== 'ola') lines.push(` platform="${platform}"`);
|
|
1535
|
+
if (platform === 'bytehi') lines.push(' brandName="ByteHi"');
|
|
1536
|
+
if (avatarType !== 'image') lines.push(` avatarType="${avatarType}"`);
|
|
1537
|
+
if (utilityActions === 'visible') lines.push(' showUtilityActions');
|
|
1538
|
+
if (platform === 'ola') lines.push(' appBusinesses={appBusinesses}');
|
|
1539
|
+
if (platform === 'ola') lines.push(' navItems={navItems}');
|
|
1540
|
+
if (utilityActions === 'visible') lines.push(' utilityItems={utilityItems}');
|
|
1541
|
+
lines.push('/>');
|
|
1542
|
+
return lines.join('\n');
|
|
1543
|
+
},
|
|
1544
|
+
},
|
|
1545
|
+
|
|
1546
|
+
'tag-bar': {
|
|
1547
|
+
component: TagBar,
|
|
1548
|
+
tokenMap: TAGBAR_TOKEN_MAP,
|
|
1549
|
+
jsxSource: tagBarJsxRaw,
|
|
1550
|
+
controls: [
|
|
1551
|
+
{
|
|
1552
|
+
id: 'layout',
|
|
1553
|
+
label: '布局',
|
|
1554
|
+
type: 'seg',
|
|
1555
|
+
options: [
|
|
1556
|
+
{ id: 'expanded', label: '展开' },
|
|
1557
|
+
{ id: 'collapsed', label: '收起' },
|
|
1558
|
+
],
|
|
1559
|
+
default: 'expanded',
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
id: 'searchable',
|
|
1563
|
+
label: '搜索',
|
|
1564
|
+
type: 'seg',
|
|
1565
|
+
options: [
|
|
1566
|
+
{ id: 'on', label: '开启' },
|
|
1567
|
+
{ id: 'off', label: '关闭' },
|
|
1568
|
+
],
|
|
1569
|
+
default: 'on',
|
|
1570
|
+
},
|
|
1571
|
+
],
|
|
1572
|
+
|
|
1573
|
+
mapProps: (cv) => {
|
|
1574
|
+
const layout = cv.layout || 'expanded';
|
|
1575
|
+
const searchable = (cv.searchable || 'on') === 'on';
|
|
1576
|
+
const businesses = TAGBAR_SAMPLE_BUSINESSES;
|
|
1577
|
+
const expandedIds = ['account', 'account-registration-login'];
|
|
1578
|
+
|
|
1579
|
+
return {
|
|
1580
|
+
key: `tagbar-preview-${layout}-${searchable ? 'search' : 'nosearch'}`,
|
|
1581
|
+
businesses,
|
|
1582
|
+
defaultBusinessId: businesses[0]?.id || 'douyin-community',
|
|
1583
|
+
items: TAGBAR_SAMPLE_ITEMS,
|
|
1584
|
+
defaultSelectedItemId: 'account-registration-login-field-1',
|
|
1585
|
+
defaultExpandedIds: expandedIds,
|
|
1586
|
+
searchable,
|
|
1587
|
+
collapsible: true,
|
|
1588
|
+
defaultCollapsed: layout === 'collapsed',
|
|
1589
|
+
defaultSearchValue: '',
|
|
1590
|
+
};
|
|
1591
|
+
},
|
|
1592
|
+
|
|
1593
|
+
getPreviewAreaStyle: () => ({
|
|
1594
|
+
alignItems: 'stretch',
|
|
1595
|
+
justifyContent: 'flex-start',
|
|
1596
|
+
padding: '0 24px 0 0',
|
|
1597
|
+
}),
|
|
1598
|
+
|
|
1599
|
+
getPreviewItemStyle: () => ({
|
|
1600
|
+
display: 'flex',
|
|
1601
|
+
alignItems: 'stretch',
|
|
1602
|
+
justifyContent: 'flex-start',
|
|
1603
|
+
height: '100%',
|
|
1604
|
+
minHeight: '100%',
|
|
1605
|
+
alignSelf: 'stretch',
|
|
1606
|
+
}),
|
|
1607
|
+
|
|
1608
|
+
generateUsage: (_, cv = {}) => {
|
|
1609
|
+
const layout = cv.layout || 'expanded';
|
|
1610
|
+
const searchable = (cv.searchable || 'on') === 'on';
|
|
1611
|
+
const lines = [`import TagBar from './components/TagBar';`];
|
|
1612
|
+
|
|
1613
|
+
lines.push('');
|
|
1614
|
+
lines.push('const businesses = [');
|
|
1615
|
+
lines.push(" { id: 'douyin-community', label: '抖音社区' },");
|
|
1616
|
+
lines.push(" { id: 'douyin-ecommerce', label: '抖音电商' },");
|
|
1617
|
+
lines.push(" { id: 'douyin-local-services', label: '抖音生活服务' },");
|
|
1618
|
+
lines.push('];');
|
|
1619
|
+
lines.push('');
|
|
1620
|
+
lines.push('const items = [');
|
|
1621
|
+
lines.push(" { id: 'account', label: '账号', iconName: 'user-01-stroked', iconBgToken: 'brand-50', children: [{ id: 'account-registration', label: '账号注册/登录', children: [{ id: 'account-register-too-many', label: '注册时提示「注册账号过多」' }, { id: 'account-face-fail', label: '注册/登录时用户刷脸/实名认证失败' }] }, { id: 'account-punishment', label: '账号处罚' }, { id: 'account-auth', label: '实名认证' }] },");
|
|
1622
|
+
lines.push(" { id: 'base-product', label: '基础产品', iconName: 'layers-two-01-stroked', iconBgToken: 'blue-50' },");
|
|
1623
|
+
lines.push(" { id: 'social', label: '社交', iconName: 'heart-circle-stroked', iconBgToken: 'pink-50' },");
|
|
1624
|
+
lines.push('];');
|
|
1625
|
+
lines.push('');
|
|
1626
|
+
lines.push('{/* 双白卡场景:外层白圆角 + overflow-visible;勿用 tone="panel" 冒充白卡 */}');
|
|
1627
|
+
lines.push('<div style={{ background: "var(--color-white)", borderRadius: 12, overflow: "visible", width: 240 }}>');
|
|
1628
|
+
lines.push(' <TagBar');
|
|
1629
|
+
lines.push(' businesses={businesses}');
|
|
1630
|
+
lines.push(' items={items}');
|
|
1631
|
+
lines.push(' defaultBusinessId="douyin-community"');
|
|
1632
|
+
lines.push(' defaultSelectedItemId="account-registration-login-field-1"');
|
|
1633
|
+
lines.push(" defaultExpandedIds={['account', 'account-registration-login']}");
|
|
1634
|
+
if (layout === 'collapsed') lines.push(' defaultCollapsed');
|
|
1635
|
+
if (searchable) lines.push(' searchable');
|
|
1636
|
+
lines.push(' collapsible');
|
|
1637
|
+
lines.push(' tone="transparent"');
|
|
1638
|
+
lines.push(' className="!border-r-0"');
|
|
1639
|
+
lines.push(' style={{ background: "transparent" }}');
|
|
1640
|
+
lines.push(' />');
|
|
1641
|
+
lines.push('</div>');
|
|
1642
|
+
return lines.join('\n');
|
|
1643
|
+
},
|
|
1644
|
+
},
|
|
1645
|
+
|
|
1646
|
+
'chat-bubble': {
|
|
1647
|
+
component: ChatBubblePreview,
|
|
1648
|
+
tokenMap: CHATBUBBLE_TOKEN_MAP,
|
|
1649
|
+
jsxSource: chatBubbleJsxRaw,
|
|
1650
|
+
hideBaseVariantControl: true,
|
|
1651
|
+
enumTitles: {
|
|
1652
|
+
incomingTone: '左侧气泡色',
|
|
1653
|
+
outgoingTone: '右侧气泡色',
|
|
1654
|
+
},
|
|
1655
|
+
|
|
1656
|
+
controls: [
|
|
1657
|
+
{
|
|
1658
|
+
id: 'previewVariant',
|
|
1659
|
+
label: '变体',
|
|
1660
|
+
type: 'seg',
|
|
1661
|
+
options: [
|
|
1662
|
+
{ id: 'incoming', label: '左侧' },
|
|
1663
|
+
{ id: 'outgoing', label: '右侧' },
|
|
1664
|
+
{ id: 'both', label: '左+右' },
|
|
1665
|
+
],
|
|
1666
|
+
default: 'outgoing',
|
|
1667
|
+
},
|
|
1668
|
+
],
|
|
1669
|
+
|
|
1670
|
+
mapProps: (cv, enums) => {
|
|
1671
|
+
const previewVariant = cv.previewVariant || 'outgoing';
|
|
1672
|
+
const variant = previewVariant === 'both' ? 'incoming' : previewVariant;
|
|
1673
|
+
const layout = enums.layout || 'single';
|
|
1674
|
+
const supportsOutgoingControls = previewVariant === 'outgoing' || previewVariant === 'both';
|
|
1675
|
+
const resolvedReceipt = supportsOutgoingControls ? (enums.receipt || 'hidden') : 'hidden';
|
|
1676
|
+
return {
|
|
1677
|
+
previewVariant,
|
|
1678
|
+
variant,
|
|
1679
|
+
layout,
|
|
1680
|
+
avatarType: enums.avatarType || 'image',
|
|
1681
|
+
size: enums.size || 'default',
|
|
1682
|
+
incomingTone: enums.incomingTone || 'default',
|
|
1683
|
+
outgoingTone: enums.outgoingTone || 'white',
|
|
1684
|
+
receipt: resolvedReceipt,
|
|
1685
|
+
messages: CHATBUBBLE_PRESET_MESSAGES[variant]?.[layout] || CHATBUBBLE_PRESET_MESSAGES.incoming.single,
|
|
1686
|
+
timestamps: CHATBUBBLE_PRESET_TIMESTAMPS[variant]?.[layout] || CHATBUBBLE_PRESET_TIMESTAMPS.incoming.single,
|
|
1687
|
+
avatarAlt: variant === 'incoming' ? '用户头像' : '客服头像',
|
|
1688
|
+
};
|
|
1689
|
+
},
|
|
1690
|
+
|
|
1691
|
+
getVisibleEnumProps: ({ controlValues, enumProps }) => {
|
|
1692
|
+
const previewVariant = controlValues.previewVariant || 'outgoing';
|
|
1693
|
+
return enumProps.filter((prop) => {
|
|
1694
|
+
if (prop.name === 'variant') return false;
|
|
1695
|
+
if (prop.name === 'receipt' && previewVariant === 'incoming') return false;
|
|
1696
|
+
/* 变体与气泡色联动:仅左侧预览只配左侧色;仅右侧只配右侧色;左+右同时展示两侧 */
|
|
1697
|
+
if (prop.name === 'incomingTone' && previewVariant === 'outgoing') return false;
|
|
1698
|
+
if (prop.name === 'outgoingTone' && previewVariant === 'incoming') return false;
|
|
1699
|
+
return true;
|
|
1700
|
+
});
|
|
1701
|
+
},
|
|
1702
|
+
|
|
1703
|
+
generateUsage: (enums, cv) => {
|
|
1704
|
+
const lines = [`import ChatBubble from './components/ChatBubble';`];
|
|
1705
|
+
const previewVariant = cv.previewVariant || 'outgoing';
|
|
1706
|
+
const variant = previewVariant === 'both' ? 'incoming' : previewVariant;
|
|
1707
|
+
const layout = enums.layout || 'single';
|
|
1708
|
+
const avatarType = enums.avatarType || 'image';
|
|
1709
|
+
const size = enums.size || 'default';
|
|
1710
|
+
const incomingTone = enums.incomingTone || 'default';
|
|
1711
|
+
const outgoingTone = enums.outgoingTone || 'white';
|
|
1712
|
+
const receipt = variant === 'outgoing' || previewVariant === 'both' ? (enums.receipt || 'hidden') : 'hidden';
|
|
1713
|
+
const messages = CHATBUBBLE_PRESET_MESSAGES[variant]?.[layout] || CHATBUBBLE_PRESET_MESSAGES.incoming.single;
|
|
1714
|
+
const timestamps = CHATBUBBLE_PRESET_TIMESTAMPS[variant]?.[layout] || CHATBUBBLE_PRESET_TIMESTAMPS.incoming.single;
|
|
1715
|
+
|
|
1716
|
+
if (previewVariant === 'both') {
|
|
1717
|
+
lines.push('');
|
|
1718
|
+
lines.push('const incomingMessages = [');
|
|
1719
|
+
lines.push(' "为什么我无法设置点赞列表查看权限",');
|
|
1720
|
+
lines.push('];');
|
|
1721
|
+
lines.push('const incomingTimestamps = ["2026-02-26 10:24:14"];');
|
|
1722
|
+
lines.push('');
|
|
1723
|
+
lines.push(`const outgoingMessages = [`);
|
|
1724
|
+
(layout === 'multiple' ? CHATBUBBLE_PRESET_MESSAGES.outgoing.multiple : CHATBUBBLE_PRESET_MESSAGES.outgoing.single).forEach((message) => {
|
|
1725
|
+
lines.push(` "${message}",`);
|
|
1726
|
+
});
|
|
1727
|
+
lines.push('];');
|
|
1728
|
+
lines.push(`const outgoingTimestamps = [`);
|
|
1729
|
+
(layout === 'multiple' ? CHATBUBBLE_PRESET_TIMESTAMPS.outgoing.multiple : CHATBUBBLE_PRESET_TIMESTAMPS.outgoing.single).forEach((time) => {
|
|
1730
|
+
lines.push(` "${time}",`);
|
|
1731
|
+
});
|
|
1732
|
+
lines.push('];');
|
|
1733
|
+
if (layout === 'multiple') {
|
|
1734
|
+
lines.push('');
|
|
1735
|
+
lines.push('const trailingIncomingMessages = [');
|
|
1736
|
+
lines.push(' "那怎么看自己的直播回放?",');
|
|
1737
|
+
lines.push('];');
|
|
1738
|
+
lines.push('const trailingIncomingTimestamps = ["2026-02-26 10:26:08"];');
|
|
1739
|
+
}
|
|
1740
|
+
lines.push('');
|
|
1741
|
+
lines.push('<>');
|
|
1742
|
+
lines.push(' <ChatBubble');
|
|
1743
|
+
if (incomingTone !== 'default') lines.push(` incomingTone="${incomingTone}"`);
|
|
1744
|
+
lines.push(' messages={incomingMessages}');
|
|
1745
|
+
lines.push(' timestamps={incomingTimestamps}');
|
|
1746
|
+
lines.push(' />');
|
|
1747
|
+
lines.push(' <div className="h-4" />');
|
|
1748
|
+
lines.push(' <ChatBubble');
|
|
1749
|
+
lines.push(' variant="outgoing"');
|
|
1750
|
+
if (layout !== 'single') lines.push(` layout="${layout}"`);
|
|
1751
|
+
if (avatarType !== 'image') lines.push(` avatarType="${avatarType}"`);
|
|
1752
|
+
if (size !== 'default') lines.push(` size="${size}"`);
|
|
1753
|
+
if (outgoingTone !== 'white') lines.push(` outgoingTone="${outgoingTone}"`);
|
|
1754
|
+
if (receipt !== 'hidden') lines.push(` receipt="${receipt}"`);
|
|
1755
|
+
lines.push(' messages={outgoingMessages}');
|
|
1756
|
+
lines.push(' timestamps={outgoingTimestamps}');
|
|
1757
|
+
lines.push(' />');
|
|
1758
|
+
if (layout === 'multiple') {
|
|
1759
|
+
lines.push(' <div className="h-4" />');
|
|
1760
|
+
lines.push(' <ChatBubble');
|
|
1761
|
+
if (incomingTone !== 'default') lines.push(` incomingTone="${incomingTone}"`);
|
|
1762
|
+
lines.push(' messages={trailingIncomingMessages}');
|
|
1763
|
+
lines.push(' timestamps={trailingIncomingTimestamps}');
|
|
1764
|
+
lines.push(' />');
|
|
1765
|
+
}
|
|
1766
|
+
lines.push('</>');
|
|
1767
|
+
return lines.join('\n');
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
lines.push('');
|
|
1771
|
+
lines.push('const messages = [');
|
|
1772
|
+
messages.forEach((message) => {
|
|
1773
|
+
lines.push(` "${message}",`);
|
|
1774
|
+
});
|
|
1775
|
+
lines.push('];');
|
|
1776
|
+
lines.push('const timestamps = [');
|
|
1777
|
+
timestamps.forEach((time) => {
|
|
1778
|
+
lines.push(` "${time}",`);
|
|
1779
|
+
});
|
|
1780
|
+
lines.push('];');
|
|
1781
|
+
lines.push('');
|
|
1782
|
+
lines.push('<ChatBubble');
|
|
1783
|
+
if (variant !== 'incoming') lines.push(` variant="${variant}"`);
|
|
1784
|
+
if (layout !== 'single') lines.push(` layout="${layout}"`);
|
|
1785
|
+
if (avatarType !== 'image') lines.push(` avatarType="${avatarType}"`);
|
|
1786
|
+
if (size !== 'default') lines.push(` size="${size}"`);
|
|
1787
|
+
if (previewVariant === 'incoming' && incomingTone !== 'default') {
|
|
1788
|
+
lines.push(` incomingTone="${incomingTone}"`);
|
|
1789
|
+
}
|
|
1790
|
+
if (previewVariant === 'outgoing' && outgoingTone !== 'white') {
|
|
1791
|
+
lines.push(` outgoingTone="${outgoingTone}"`);
|
|
1792
|
+
}
|
|
1793
|
+
if (receipt !== 'hidden') lines.push(` receipt="${receipt}"`);
|
|
1794
|
+
lines.push(' messages={messages}');
|
|
1795
|
+
lines.push(' timestamps={timestamps}');
|
|
1796
|
+
lines.push('/>');
|
|
1797
|
+
return lines.join('\n');
|
|
1798
|
+
},
|
|
1799
|
+
},
|
|
1800
|
+
|
|
1801
|
+
'chat-input': {
|
|
1802
|
+
component: ChatInput,
|
|
1803
|
+
tokenMap: CHATINPUT_TOKEN_MAP,
|
|
1804
|
+
jsxSource: chatInputJsxRaw,
|
|
1805
|
+
|
|
1806
|
+
controls: [
|
|
1807
|
+
{
|
|
1808
|
+
id: 'seedContent', label: '示例内容', type: 'switch',
|
|
1809
|
+
default: false,
|
|
1810
|
+
},
|
|
1811
|
+
],
|
|
1812
|
+
|
|
1813
|
+
/* 容器宽度走 TOKEN_MAP「容器 → 宽度」配置(T2 非 token 固定值),默认 500px;
|
|
1814
|
+
* 用户在属性面板改 width 后,directStyleOverrides.width 会同步到 wrapper */
|
|
1815
|
+
getPreviewItemStyle: ({ directStyleOverrides } = {}) => ({
|
|
1816
|
+
width: directStyleOverrides?.width || '500px',
|
|
1817
|
+
maxWidth: '100%',
|
|
1818
|
+
}),
|
|
1819
|
+
|
|
1820
|
+
/* ── 按 variant 自动套合理默认文案;seedContent=filled 时给 ChatInput 注入示例填充态 ── */
|
|
1821
|
+
mapProps: (controls, enums) => {
|
|
1822
|
+
const v = enums.variant || 'default';
|
|
1823
|
+
const seed = controls.seedContent === true;
|
|
1824
|
+
|
|
1825
|
+
if (v === 'busy') {
|
|
1826
|
+
return {
|
|
1827
|
+
catBarText: '正在查询数据接口「execute_agent/API/interface/Function call Name」',
|
|
1828
|
+
statusText: '已耗时 3 min,运行结束后会通过飞书消息告知',
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
if (v === 'readonly') {
|
|
1832
|
+
return {
|
|
1833
|
+
statusText: '来自其他成员的任务分享,当前页面仅支持预览',
|
|
1834
|
+
actionText: '继续对话',
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
/* default / default-sm / im-basic / replying:仅在 seed 开启时注入预览数据 */
|
|
1838
|
+
return seed ? { _seedContent: true } : {};
|
|
1839
|
+
},
|
|
1840
|
+
|
|
1841
|
+
generateUsage: (enums) => {
|
|
1842
|
+
const lines = [`import ChatInput from './components/ChatInput';`];
|
|
1843
|
+
const v = enums.variant || 'default';
|
|
1844
|
+
lines.push('');
|
|
1845
|
+
lines.push('<ChatInput');
|
|
1846
|
+
if (v !== 'default') lines.push(` variant="${v}"`);
|
|
1847
|
+
if (v === 'busy') {
|
|
1848
|
+
lines.push(' catBarText="正在查询数据接口"');
|
|
1849
|
+
lines.push(' statusText="已耗时 3 min,运行结束后会通过飞书消息告知"');
|
|
1850
|
+
lines.push(' onStop={() => {}}');
|
|
1851
|
+
} else if (v === 'readonly') {
|
|
1852
|
+
lines.push(' statusText="来自其他成员的任务分享,当前页面仅支持预览"');
|
|
1853
|
+
lines.push(' actionText="继续对话"');
|
|
1854
|
+
lines.push(' onAction={() => {}}');
|
|
1855
|
+
} else if (v === 'im-basic') {
|
|
1856
|
+
lines.push(' placeholder="说点什么…"');
|
|
1857
|
+
lines.push(' acceptFiles="image/*"');
|
|
1858
|
+
lines.push(' onImEmojiClick={() => {}}');
|
|
1859
|
+
}
|
|
1860
|
+
lines.push('/>');
|
|
1861
|
+
return lines.join('\n');
|
|
1862
|
+
},
|
|
1863
|
+
},
|
|
1864
|
+
|
|
1865
|
+
'chat-message': {
|
|
1866
|
+
component: ChatMessagePreview,
|
|
1867
|
+
tokenMap: CHAT_MESSAGE_TOKEN_MAP,
|
|
1868
|
+
jsxSource: chatMessageJsxRaw,
|
|
1869
|
+
|
|
1870
|
+
getPreviewAreaStyle: () => ({
|
|
1871
|
+
alignItems: 'stretch',
|
|
1872
|
+
justifyContent: 'flex-start',
|
|
1873
|
+
overflow: 'auto',
|
|
1874
|
+
padding: '12px',
|
|
1875
|
+
}),
|
|
1876
|
+
|
|
1877
|
+
getPreviewItemStyle: () => ({
|
|
1878
|
+
width: '100%',
|
|
1879
|
+
minWidth: 0,
|
|
1880
|
+
alignSelf: 'stretch',
|
|
1881
|
+
}),
|
|
1882
|
+
|
|
1883
|
+
getPreviewScalerStyle: () => ({
|
|
1884
|
+
width: '100%',
|
|
1885
|
+
minWidth: 0,
|
|
1886
|
+
transformOrigin: 'left top',
|
|
1887
|
+
}),
|
|
1888
|
+
|
|
1889
|
+
/* 每个子组件的"变体"使用独立 control id,避免共用 'variant' key 互相覆盖
|
|
1890
|
+
* subComponent → variant control id 映射 */
|
|
1891
|
+
controls: [
|
|
1892
|
+
{
|
|
1893
|
+
id: 'subComponent',
|
|
1894
|
+
label: '子组件',
|
|
1895
|
+
type: 'seg',
|
|
1896
|
+
options: [
|
|
1897
|
+
{ id: 'execution-flow', label: '执行流' },
|
|
1898
|
+
{ id: 'text-reply', label: '文本回复' },
|
|
1899
|
+
{ id: 'deep-thinking', label: '深度思考' },
|
|
1900
|
+
{ id: 'card', label: '卡片' },
|
|
1901
|
+
{ id: 'user-message', label: '用户消息' },
|
|
1902
|
+
{ id: 'ai-avatar', label: 'AI头像+名称' },
|
|
1903
|
+
{ id: 'conversation', label: '对话流' },
|
|
1904
|
+
{ id: 'artifact', label: '产物' },
|
|
1905
|
+
{ id: 'action-bar', label: '操作栏' },
|
|
1906
|
+
{ id: 'follow-up', label: '追问' },
|
|
1907
|
+
],
|
|
1908
|
+
default: 'execution-flow',
|
|
1909
|
+
},
|
|
1910
|
+
{
|
|
1911
|
+
id: 'executionFlowVariant',
|
|
1912
|
+
label: '变体',
|
|
1913
|
+
type: 'seg',
|
|
1914
|
+
options: [
|
|
1915
|
+
{ id: 'completed', label: '已完成' },
|
|
1916
|
+
{ id: 'running', label: '执行中' },
|
|
1917
|
+
],
|
|
1918
|
+
default: 'completed',
|
|
1919
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'execution-flow',
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
id: 'deepThinkingVariant',
|
|
1923
|
+
label: '变体',
|
|
1924
|
+
type: 'seg',
|
|
1925
|
+
options: [
|
|
1926
|
+
{ id: 'thinking', label: '思考中' },
|
|
1927
|
+
{ id: 'expanded', label: '展开' },
|
|
1928
|
+
{ id: 'collapsed', label: '折叠' },
|
|
1929
|
+
],
|
|
1930
|
+
default: 'expanded',
|
|
1931
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'deep-thinking',
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
id: 'userMessageVariant',
|
|
1935
|
+
label: '变体',
|
|
1936
|
+
type: 'seg',
|
|
1937
|
+
options: [
|
|
1938
|
+
{ id: 'text', label: '纯文本' },
|
|
1939
|
+
{ id: 'mixed-tag', label: '文本+@TAG' },
|
|
1940
|
+
{ id: 'with-attachment', label: '带附件' },
|
|
1941
|
+
{ id: 'with-quote', label: '带划词引用' },
|
|
1942
|
+
],
|
|
1943
|
+
default: 'text',
|
|
1944
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'user-message',
|
|
1945
|
+
},
|
|
1946
|
+
{
|
|
1947
|
+
id: 'aiAvatarVariant',
|
|
1948
|
+
label: '变体',
|
|
1949
|
+
type: 'seg',
|
|
1950
|
+
options: [
|
|
1951
|
+
{ id: 'default', label: '默认' },
|
|
1952
|
+
{ id: 'loading', label: '加载中' },
|
|
1953
|
+
],
|
|
1954
|
+
default: 'default',
|
|
1955
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'ai-avatar',
|
|
1956
|
+
},
|
|
1957
|
+
{
|
|
1958
|
+
id: 'cardVariant',
|
|
1959
|
+
label: '变体',
|
|
1960
|
+
type: 'seg',
|
|
1961
|
+
options: [
|
|
1962
|
+
{ id: 'task-plan', label: '任务规划' },
|
|
1963
|
+
{ id: 'config-form', label: '配置表单' },
|
|
1964
|
+
],
|
|
1965
|
+
default: 'task-plan',
|
|
1966
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'card',
|
|
1967
|
+
},
|
|
1968
|
+
{
|
|
1969
|
+
id: 'artifactVariant',
|
|
1970
|
+
label: '变体',
|
|
1971
|
+
type: 'seg',
|
|
1972
|
+
options: [
|
|
1973
|
+
{ id: 'icon', label: '产物图标' },
|
|
1974
|
+
{ id: 'card', label: '产物卡片' },
|
|
1975
|
+
{ id: 'group', label: '产物组' },
|
|
1976
|
+
],
|
|
1977
|
+
default: 'group',
|
|
1978
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'artifact',
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
id: 'conversationVariant',
|
|
1982
|
+
label: '变体',
|
|
1983
|
+
type: 'seg',
|
|
1984
|
+
options: [
|
|
1985
|
+
{ id: 'ai-rich', label: 'AI完整回复' },
|
|
1986
|
+
{ id: 'multi-turn', label: '多轮对话' },
|
|
1987
|
+
{ id: 'ai-task-plan', label: 'AI任务规划' },
|
|
1988
|
+
],
|
|
1989
|
+
default: 'ai-rich',
|
|
1990
|
+
hidden: ({ controlValues }) => (controlValues.subComponent || 'execution-flow') !== 'conversation',
|
|
1991
|
+
},
|
|
1992
|
+
],
|
|
1993
|
+
|
|
1994
|
+
/* 子组件 → 该子组件的 variant control id(mapProps & generateUsage 共用查表) */
|
|
1995
|
+
_variantKey: (sub) => ({
|
|
1996
|
+
'execution-flow': 'executionFlowVariant',
|
|
1997
|
+
'text-reply': null,
|
|
1998
|
+
'deep-thinking': 'deepThinkingVariant',
|
|
1999
|
+
'card': 'cardVariant',
|
|
2000
|
+
'user-message': 'userMessageVariant',
|
|
2001
|
+
'ai-avatar': 'aiAvatarVariant',
|
|
2002
|
+
'conversation': 'conversationVariant',
|
|
2003
|
+
'artifact': 'artifactVariant',
|
|
2004
|
+
'action-bar': null,
|
|
2005
|
+
'follow-up': null,
|
|
2006
|
+
})[sub],
|
|
2007
|
+
|
|
2008
|
+
mapProps: (cv) => {
|
|
2009
|
+
const sub = cv.subComponent || 'execution-flow';
|
|
2010
|
+
const variantKey = ({
|
|
2011
|
+
'execution-flow': 'executionFlowVariant',
|
|
2012
|
+
'deep-thinking': 'deepThinkingVariant',
|
|
2013
|
+
'card': 'cardVariant',
|
|
2014
|
+
'user-message': 'userMessageVariant',
|
|
2015
|
+
'ai-avatar': 'aiAvatarVariant',
|
|
2016
|
+
'conversation': 'conversationVariant',
|
|
2017
|
+
'artifact': 'artifactVariant',
|
|
2018
|
+
})[sub];
|
|
2019
|
+
const variant = variantKey ? cv[variantKey] : 'default';
|
|
2020
|
+
return {
|
|
2021
|
+
subComponent: sub,
|
|
2022
|
+
variant: variant || 'default',
|
|
2023
|
+
};
|
|
2024
|
+
},
|
|
2025
|
+
|
|
2026
|
+
enumTitles: {
|
|
2027
|
+
userBubbleTone: '消息气泡背景色',
|
|
2028
|
+
},
|
|
2029
|
+
|
|
2030
|
+
getVisibleEnumProps: ({ enumProps, controlValues }) => {
|
|
2031
|
+
const sub = controlValues.subComponent || 'execution-flow';
|
|
2032
|
+
return enumProps.filter((prop) => {
|
|
2033
|
+
if (prop.name !== 'userBubbleTone') return false;
|
|
2034
|
+
return sub === 'user-message' || sub === 'conversation';
|
|
2035
|
+
});
|
|
2036
|
+
},
|
|
2037
|
+
|
|
2038
|
+
generateUsage: (enums, cv) => {
|
|
2039
|
+
const sub = cv.subComponent || 'execution-flow';
|
|
2040
|
+
const variantKey = ({
|
|
2041
|
+
'execution-flow': 'executionFlowVariant',
|
|
2042
|
+
'deep-thinking': 'deepThinkingVariant',
|
|
2043
|
+
'card': 'cardVariant',
|
|
2044
|
+
'user-message': 'userMessageVariant',
|
|
2045
|
+
'ai-avatar': 'aiAvatarVariant',
|
|
2046
|
+
'conversation': 'conversationVariant',
|
|
2047
|
+
'artifact': 'artifactVariant',
|
|
2048
|
+
})[sub];
|
|
2049
|
+
const variant = (variantKey ? cv[variantKey] : 'default') || 'default';
|
|
2050
|
+
const userBubbleTone = enums.userBubbleTone || 'auto';
|
|
2051
|
+
const userBubbleToneLine = userBubbleTone === 'auto' ? null : ` userBubbleTone="${userBubbleTone}"`;
|
|
2052
|
+
|
|
2053
|
+
const usageMap = {
|
|
2054
|
+
'execution-flow': {
|
|
2055
|
+
completed: [
|
|
2056
|
+
'<ChatMessage',
|
|
2057
|
+
' title={DEFAULT_CHAT_TITLE}',
|
|
2058
|
+
' steps={DEFAULT_CHAT_STEPS}',
|
|
2059
|
+
'/>',
|
|
2060
|
+
],
|
|
2061
|
+
running: [
|
|
2062
|
+
'<ChatMessage',
|
|
2063
|
+
' status="processing"',
|
|
2064
|
+
' title={DEFAULT_CHAT_TITLE}',
|
|
2065
|
+
' steps={DEFAULT_CHAT_STEPS.slice(0, 2)}',
|
|
2066
|
+
'/>',
|
|
2067
|
+
],
|
|
2068
|
+
},
|
|
2069
|
+
'text-reply': {
|
|
2070
|
+
default: [
|
|
2071
|
+
'<ChatMessage',
|
|
2072
|
+
' header',
|
|
2073
|
+
' title=""',
|
|
2074
|
+
' steps={null}',
|
|
2075
|
+
' resultText="收到,我先去拉平台规则和商家补充条款,分析完会给你一份统一答复口径。"',
|
|
2076
|
+
' actions',
|
|
2077
|
+
' timestamp="18:16"',
|
|
2078
|
+
'/>',
|
|
2079
|
+
],
|
|
2080
|
+
},
|
|
2081
|
+
'deep-thinking': {
|
|
2082
|
+
thinking: [
|
|
2083
|
+
'<ChatMessage',
|
|
2084
|
+
' header',
|
|
2085
|
+
' status="thinking"',
|
|
2086
|
+
' steps={null}',
|
|
2087
|
+
' thinking={{ state: "thinking", inProgressLabel: "深度思考中 ..." }}',
|
|
2088
|
+
'/>',
|
|
2089
|
+
],
|
|
2090
|
+
expanded: [
|
|
2091
|
+
'<ChatMessage',
|
|
2092
|
+
' header',
|
|
2093
|
+
' title=""',
|
|
2094
|
+
' steps={null}',
|
|
2095
|
+
' thinking={{ ...DEFAULT_CHAT_THINKING, state: "completed", defaultExpanded: true }}',
|
|
2096
|
+
' resultText="好的,我将开始为您分析。"',
|
|
2097
|
+
' actions',
|
|
2098
|
+
' timestamp="18:16"',
|
|
2099
|
+
'/>',
|
|
2100
|
+
],
|
|
2101
|
+
collapsed: [
|
|
2102
|
+
'<ChatMessage',
|
|
2103
|
+
' header',
|
|
2104
|
+
' title=""',
|
|
2105
|
+
' steps={null}',
|
|
2106
|
+
' thinking={{ ...DEFAULT_CHAT_THINKING, state: "completed", defaultExpanded: false }}',
|
|
2107
|
+
' resultText="好的,我将开始为您分析。"',
|
|
2108
|
+
' actions',
|
|
2109
|
+
' timestamp="18:16"',
|
|
2110
|
+
'/>',
|
|
2111
|
+
],
|
|
2112
|
+
},
|
|
2113
|
+
'card': {
|
|
2114
|
+
'task-plan': [
|
|
2115
|
+
'<ChatMessage',
|
|
2116
|
+
' header',
|
|
2117
|
+
' title=""',
|
|
2118
|
+
' steps={null}',
|
|
2119
|
+
' plan={DEFAULT_CHAT_PLAN}',
|
|
2120
|
+
' actions',
|
|
2121
|
+
' timestamp="18:16"',
|
|
2122
|
+
'/>',
|
|
2123
|
+
],
|
|
2124
|
+
'config-form': [
|
|
2125
|
+
'<ChatMessage',
|
|
2126
|
+
' header',
|
|
2127
|
+
' title=""',
|
|
2128
|
+
' steps={null}',
|
|
2129
|
+
' confirms={DEFAULT_CHAT_CONFIRMS}',
|
|
2130
|
+
' actions',
|
|
2131
|
+
' timestamp="18:16"',
|
|
2132
|
+
'/>',
|
|
2133
|
+
],
|
|
2134
|
+
},
|
|
2135
|
+
'user-message': {
|
|
2136
|
+
text: [
|
|
2137
|
+
'<ChatMessage',
|
|
2138
|
+
' role="user"',
|
|
2139
|
+
userBubbleToneLine,
|
|
2140
|
+
' timestamp="14:02"',
|
|
2141
|
+
' userContent={[{ type: "text", value: "帮我整理一下抖音电商的售后政策" }]}',
|
|
2142
|
+
' actions',
|
|
2143
|
+
'/>',
|
|
2144
|
+
],
|
|
2145
|
+
'mixed-tag': [
|
|
2146
|
+
'<ChatMessage',
|
|
2147
|
+
' role="user"',
|
|
2148
|
+
userBubbleToneLine,
|
|
2149
|
+
' timestamp="14:05"',
|
|
2150
|
+
' userContent={[',
|
|
2151
|
+
' { type: "text", value: "分析一批" },',
|
|
2152
|
+
' { type: "entity", icon: "message-chat-square-stroked", label: "智能会话:社交私信", tone: "teal", showChevron: true },',
|
|
2153
|
+
' { type: "text", value: "的问题与机会点" },',
|
|
2154
|
+
' ]}',
|
|
2155
|
+
' actions',
|
|
2156
|
+
'/>',
|
|
2157
|
+
],
|
|
2158
|
+
'with-attachment': [
|
|
2159
|
+
'<ChatMessage',
|
|
2160
|
+
' role="user"',
|
|
2161
|
+
userBubbleToneLine,
|
|
2162
|
+
' timestamp="14:08"',
|
|
2163
|
+
' userContent={[{ type: "text", value: "附件里是售后规则汇编,请基于这两份文件输出统一答复口径" }]}',
|
|
2164
|
+
' userAttachments={[',
|
|
2165
|
+
' { name: "抖音电商售后政策汇编.pdf", size: 327680 },',
|
|
2166
|
+
' { name: "商家补充协议-生鲜定制.pdf", size: 184320 },',
|
|
2167
|
+
' ]}',
|
|
2168
|
+
' actions',
|
|
2169
|
+
'/>',
|
|
2170
|
+
],
|
|
2171
|
+
'with-quote': [
|
|
2172
|
+
'<ChatMessage',
|
|
2173
|
+
' role="user"',
|
|
2174
|
+
userBubbleToneLine,
|
|
2175
|
+
' timestamp="14:10"',
|
|
2176
|
+
' userContent={[{ type: "text", value: "请帮我复盘这次服务的完整链路,并着重分析[用户评价未解决]的原因。生成飞书文档和一份完整的前端页面" }]}',
|
|
2177
|
+
' userQuote={{',
|
|
2178
|
+
' iconName: "type-01-stroked",',
|
|
2179
|
+
' cornerIconName: "corner-up-right-stroked",',
|
|
2180
|
+
' title: "接口出参",',
|
|
2181
|
+
' description: "具体内容具体内容具体内容具体内容具体内容具体内",',
|
|
2182
|
+
' }}',
|
|
2183
|
+
' actions',
|
|
2184
|
+
'/>',
|
|
2185
|
+
],
|
|
2186
|
+
},
|
|
2187
|
+
'ai-avatar': {
|
|
2188
|
+
default: [
|
|
2189
|
+
'<ChatMessage',
|
|
2190
|
+
' header',
|
|
2191
|
+
' title=""',
|
|
2192
|
+
' steps={null}',
|
|
2193
|
+
' timestamp="18:16"',
|
|
2194
|
+
'/>',
|
|
2195
|
+
],
|
|
2196
|
+
loading: [
|
|
2197
|
+
'<ChatMessage',
|
|
2198
|
+
' header',
|
|
2199
|
+
' status="requesting"',
|
|
2200
|
+
' steps={null}',
|
|
2201
|
+
'/>',
|
|
2202
|
+
],
|
|
2203
|
+
},
|
|
2204
|
+
'conversation': {
|
|
2205
|
+
'ai-rich': [
|
|
2206
|
+
'/* 单条 AI 完整回复:头像 + 文本 + 产物 + 控制条 + 追问 */',
|
|
2207
|
+
'<ChatMessage',
|
|
2208
|
+
' header',
|
|
2209
|
+
' title=""',
|
|
2210
|
+
' steps={null}',
|
|
2211
|
+
' resultText={DEFAULT_CHAT_RESULT}',
|
|
2212
|
+
' resultArtifacts={DEFAULT_CHAT_RESULT_ARTIFACTS}',
|
|
2213
|
+
' actions',
|
|
2214
|
+
' followUps={DEFAULT_CHAT_FOLLOW_UPS}',
|
|
2215
|
+
' timestamp="18:16"',
|
|
2216
|
+
'/>',
|
|
2217
|
+
],
|
|
2218
|
+
'multi-turn': [
|
|
2219
|
+
'/* 多轮对话流:每条 ChatMessage 独立 hover 隔离',
|
|
2220
|
+
' 仅最新一条 actions={{ historyMode: false }} 常显操作栏',
|
|
2221
|
+
' 其余消息 historyMode=true → 默认隐藏,hover 当条才显示 */',
|
|
2222
|
+
'<>',
|
|
2223
|
+
' <ChatMessage role="user" timestamp="14:02"',
|
|
2224
|
+
userBubbleTone === 'auto' ? null : ` userBubbleTone="${userBubbleTone}"`,
|
|
2225
|
+
' userContent={[{ type: "text", value: "帮我整理一下抖音电商的售后政策" }]}',
|
|
2226
|
+
' actions={{ historyMode: true }} />',
|
|
2227
|
+
' <ChatMessage header title="" steps={null} timestamp="14:02"',
|
|
2228
|
+
' resultText="收到,我整理完给你统一答复口径。"',
|
|
2229
|
+
' actions={{ historyMode: true }} />',
|
|
2230
|
+
' <ChatMessage role="user" timestamp="14:05"',
|
|
2231
|
+
userBubbleTone === 'auto' ? null : ` userBubbleTone="${userBubbleTone}"`,
|
|
2232
|
+
' userContent={[{ type: "text", value: "拒收场景也要分商家原因和用户原因" }]}',
|
|
2233
|
+
' actions={{ historyMode: true }} />',
|
|
2234
|
+
' <ChatMessage header title="" steps={null} timestamp="14:05"',
|
|
2235
|
+
' resultText="好的,拒收的两类责任划分单独开一节。"',
|
|
2236
|
+
' actions />',
|
|
2237
|
+
'</>',
|
|
2238
|
+
],
|
|
2239
|
+
'ai-task-plan': [
|
|
2240
|
+
'/* AI 任务规划:头像 + 引导文本(leadText) + 任务规划卡片',
|
|
2241
|
+
' leadText 展示在卡片上方;待用户点主按钮前操作栏自动隐藏,处理后才显示 */',
|
|
2242
|
+
'<ChatMessage',
|
|
2243
|
+
' header',
|
|
2244
|
+
' title=""',
|
|
2245
|
+
' steps={null}',
|
|
2246
|
+
' leadText="我开始规划啦,请稍后..."',
|
|
2247
|
+
' plan={DEFAULT_CHAT_PLAN}',
|
|
2248
|
+
' actions',
|
|
2249
|
+
' timestamp="18:16"',
|
|
2250
|
+
'/>',
|
|
2251
|
+
],
|
|
2252
|
+
},
|
|
2253
|
+
'artifact': {
|
|
2254
|
+
icon: [
|
|
2255
|
+
'import { ArtifactIcon } from "./ChatMessage";',
|
|
2256
|
+
'',
|
|
2257
|
+
'/* 单个产物图标(atom):type 取自 file-type-assets 共享 lookup',
|
|
2258
|
+
' 支持类型:pdf | code | pe | xmind | image | document | table | webpage',
|
|
2259
|
+
' knowledge | strategy | conversation | batch-report',
|
|
2260
|
+
' feishu | feishu-card | feishu-sheet */',
|
|
2261
|
+
'<ArtifactIcon type="pdf" size={32} />',
|
|
2262
|
+
],
|
|
2263
|
+
card: [
|
|
2264
|
+
'import { ResultArtifactCard } from "./ChatMessage";',
|
|
2265
|
+
'',
|
|
2266
|
+
'<ResultArtifactCard',
|
|
2267
|
+
' artifact={{',
|
|
2268
|
+
' type: "pdf",',
|
|
2269
|
+
' title: "AI 品牌提案.pdf",',
|
|
2270
|
+
' meta: "370.3 KB",',
|
|
2271
|
+
' }}',
|
|
2272
|
+
'/>',
|
|
2273
|
+
],
|
|
2274
|
+
group: [
|
|
2275
|
+
'import { ResultArtifactGroup, ALL_ARTIFACT_TYPES } from "./ChatMessage";',
|
|
2276
|
+
'',
|
|
2277
|
+
'/* 直接传入完整 15 种产物类型,纵向排列 */',
|
|
2278
|
+
'<ResultArtifactGroup artifacts={ALL_ARTIFACT_TYPES} />',
|
|
2279
|
+
],
|
|
2280
|
+
},
|
|
2281
|
+
'action-bar': {
|
|
2282
|
+
default: [
|
|
2283
|
+
'<ChatMessage',
|
|
2284
|
+
' title=""',
|
|
2285
|
+
' steps={null}',
|
|
2286
|
+
' actions',
|
|
2287
|
+
' timestamp="18:16"',
|
|
2288
|
+
'/>',
|
|
2289
|
+
],
|
|
2290
|
+
},
|
|
2291
|
+
'follow-up': {
|
|
2292
|
+
default: [
|
|
2293
|
+
'<ChatMessage',
|
|
2294
|
+
' title=""',
|
|
2295
|
+
' steps={null}',
|
|
2296
|
+
' followUps={DEFAULT_CHAT_FOLLOW_UPS}',
|
|
2297
|
+
' actions',
|
|
2298
|
+
' timestamp="18:16"',
|
|
2299
|
+
'/>',
|
|
2300
|
+
],
|
|
2301
|
+
},
|
|
2302
|
+
};
|
|
2303
|
+
|
|
2304
|
+
const bucket = usageMap[sub] || usageMap['text-reply'];
|
|
2305
|
+
const lines = bucket[variant] || bucket.default || Object.values(bucket)[0];
|
|
2306
|
+
return [
|
|
2307
|
+
`import ChatMessage from './components/ChatMessage';`,
|
|
2308
|
+
'',
|
|
2309
|
+
...lines.filter(Boolean),
|
|
2310
|
+
].join('\n');
|
|
2311
|
+
},
|
|
2312
|
+
},
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
|
|
2316
|
+
button: {
|
|
2317
|
+
component: Button,
|
|
2318
|
+
tokenMap: BUTTON_TOKEN_MAP,
|
|
2319
|
+
jsxSource: buttonJsxRaw,
|
|
2320
|
+
|
|
2321
|
+
controls: [
|
|
2322
|
+
{
|
|
2323
|
+
id: 'contentType', label: '类型', type: 'seg',
|
|
2324
|
+
options: [
|
|
2325
|
+
{ id: 'text', label: '仅字' },
|
|
2326
|
+
{ id: 'icon', label: '仅icon' },
|
|
2327
|
+
{ id: 'both', label: 'icon+字' },
|
|
2328
|
+
],
|
|
2329
|
+
default: 'text',
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
id: 'state', label: '状态', type: 'seg',
|
|
2333
|
+
options: [
|
|
2334
|
+
{ id: 'default', label: '默认' },
|
|
2335
|
+
{ id: 'loading', label: '加载' },
|
|
2336
|
+
{ id: 'disabled', label: '禁用' },
|
|
2337
|
+
],
|
|
2338
|
+
default: 'default',
|
|
2339
|
+
},
|
|
2340
|
+
],
|
|
2341
|
+
|
|
2342
|
+
mapProps: (cv) => {
|
|
2343
|
+
const ct = cv.contentType;
|
|
2344
|
+
const hasIcon = ct === 'icon' || ct === 'both';
|
|
2345
|
+
return {
|
|
2346
|
+
icon: hasIcon ? <Plus size={16} /> : undefined,
|
|
2347
|
+
iconOnly: ct === 'icon',
|
|
2348
|
+
tooltip: ct === 'icon' ? '添加' : undefined,
|
|
2349
|
+
children: ct !== 'icon' ? '按钮文本' : undefined,
|
|
2350
|
+
loading: cv.state === 'loading',
|
|
2351
|
+
disabled: cv.state === 'disabled',
|
|
2352
|
+
};
|
|
2353
|
+
},
|
|
2354
|
+
|
|
2355
|
+
generateUsage: (enums, cv) => {
|
|
2356
|
+
const lines = [`import Button from './components/Button';`];
|
|
2357
|
+
const ct = cv.contentType || 'text';
|
|
2358
|
+
const st = cv.state || 'default';
|
|
2359
|
+
const props = [];
|
|
2360
|
+
props.push(`variant="${enums.variant || 'primary'}"`);
|
|
2361
|
+
props.push(`size="${enums.size || 'md'}"`);
|
|
2362
|
+
if (enums.radius && enums.radius !== 'rounded') props.push(`radius="${enums.radius}"`);
|
|
2363
|
+
if (ct === 'icon') {
|
|
2364
|
+
props.push('iconOnly');
|
|
2365
|
+
props.push('tooltip="添加"');
|
|
2366
|
+
props.push('icon={<Plus size={16} />}');
|
|
2367
|
+
} else if (ct === 'both') {
|
|
2368
|
+
props.push('icon={<Plus size={16} />}');
|
|
2369
|
+
}
|
|
2370
|
+
if (st === 'loading') props.push('loading');
|
|
2371
|
+
if (st === 'disabled') props.push('disabled');
|
|
2372
|
+
|
|
2373
|
+
lines.push('');
|
|
2374
|
+
if (ct === 'icon') {
|
|
2375
|
+
lines.push(`<Button`);
|
|
2376
|
+
props.forEach(p => lines.push(` ${p}`));
|
|
2377
|
+
lines.push('/>');
|
|
2378
|
+
} else {
|
|
2379
|
+
lines.push(`<Button`);
|
|
2380
|
+
props.forEach(p => lines.push(` ${p}`));
|
|
2381
|
+
lines.push('>');
|
|
2382
|
+
lines.push(' 按钮文本');
|
|
2383
|
+
lines.push('</Button>');
|
|
2384
|
+
}
|
|
2385
|
+
return lines.join('\n');
|
|
2386
|
+
},
|
|
2387
|
+
},
|
|
2388
|
+
|
|
2389
|
+
tabs: {
|
|
2390
|
+
component: Tabs,
|
|
2391
|
+
tokenMap: TABS_TOKEN_MAP,
|
|
2392
|
+
jsxSource: tabsJsxRaw,
|
|
2393
|
+
|
|
2394
|
+
controls: [
|
|
2395
|
+
{
|
|
2396
|
+
id: 'iconMode', label: '图标', type: 'seg',
|
|
2397
|
+
options: [
|
|
2398
|
+
{ id: 'none', label: '无图标' },
|
|
2399
|
+
{ id: 'withIcon', label: '带图标' },
|
|
2400
|
+
],
|
|
2401
|
+
default: 'none',
|
|
2402
|
+
},
|
|
2403
|
+
],
|
|
2404
|
+
|
|
2405
|
+
mapProps: (cv) => {
|
|
2406
|
+
const showIcon = cv.iconMode === 'withIcon';
|
|
2407
|
+
const items = [
|
|
2408
|
+
{ label: '标签一', icon: showIcon ? <Heart size={16} /> : undefined },
|
|
2409
|
+
{ label: '标签二', icon: showIcon ? <Star size={16} /> : undefined },
|
|
2410
|
+
{ label: '标签三', icon: showIcon ? <Zap size={16} /> : undefined },
|
|
2411
|
+
];
|
|
2412
|
+
return { items };
|
|
2413
|
+
},
|
|
2414
|
+
|
|
2415
|
+
generateUsage: (enums, cv) => {
|
|
2416
|
+
const lines = [`import Tabs from './components/Tabs';`];
|
|
2417
|
+
const showIcon = cv.iconMode === 'withIcon';
|
|
2418
|
+
const variant = enums.variant || 'line';
|
|
2419
|
+
|
|
2420
|
+
lines.push('');
|
|
2421
|
+
if (variant === 'segment') {
|
|
2422
|
+
lines.push('{/* 卡片内小模块切换 / 主区顶部布局切换:默认优先 segment */}');
|
|
2423
|
+
}
|
|
2424
|
+
lines.push('<Tabs');
|
|
2425
|
+
lines.push(` variant="${variant}"`);
|
|
2426
|
+
if (enums.size && enums.size !== 'sm') {
|
|
2427
|
+
lines.push(` size="${enums.size}"`);
|
|
2428
|
+
}
|
|
2429
|
+
if (showIcon) {
|
|
2430
|
+
lines.push(' items={[');
|
|
2431
|
+
lines.push(" { label: '标签一', icon: <Heart size={16} /> },");
|
|
2432
|
+
lines.push(" { label: '标签二', icon: <Star size={16} /> },");
|
|
2433
|
+
lines.push(" { label: '标签三', icon: <Zap size={16} /> },");
|
|
2434
|
+
lines.push(' ]}');
|
|
2435
|
+
} else {
|
|
2436
|
+
lines.push(' items={[');
|
|
2437
|
+
lines.push(" { label: '标签一' },");
|
|
2438
|
+
lines.push(" { label: '标签二' },");
|
|
2439
|
+
lines.push(" { label: '标签三' },");
|
|
2440
|
+
lines.push(' ]}');
|
|
2441
|
+
}
|
|
2442
|
+
lines.push('/>');
|
|
2443
|
+
return lines.join('\n');
|
|
2444
|
+
},
|
|
2445
|
+
},
|
|
2446
|
+
'form-title': {
|
|
2447
|
+
component: FormTitle,
|
|
2448
|
+
tokenMap: FORM_TITLE_TOKEN_MAP,
|
|
2449
|
+
jsxSource: formTitleJsxRaw,
|
|
2450
|
+
|
|
2451
|
+
controls: [
|
|
2452
|
+
{
|
|
2453
|
+
id: 'showDescription',
|
|
2454
|
+
label: '描述文案',
|
|
2455
|
+
type: 'seg',
|
|
2456
|
+
options: [
|
|
2457
|
+
{ id: 'on', label: '显示' },
|
|
2458
|
+
{ id: 'off', label: '隐藏' },
|
|
2459
|
+
],
|
|
2460
|
+
default: 'off',
|
|
2461
|
+
},
|
|
2462
|
+
{
|
|
2463
|
+
id: 'titleTag',
|
|
2464
|
+
label: '标题后缀',
|
|
2465
|
+
type: 'seg',
|
|
2466
|
+
options: [
|
|
2467
|
+
{ id: 'off', label: '无' },
|
|
2468
|
+
{ id: 'on', label: 'Tag' },
|
|
2469
|
+
],
|
|
2470
|
+
default: 'off',
|
|
2471
|
+
},
|
|
2472
|
+
],
|
|
2473
|
+
|
|
2474
|
+
mapProps: (cv, enums) => {
|
|
2475
|
+
const variant = enums.variant || 'form';
|
|
2476
|
+
const sampleMap = {
|
|
2477
|
+
form: { title: '表单标题', description: '一级标题描述' },
|
|
2478
|
+
'level-1': { title: '一级标题', description: '一级标题描述' },
|
|
2479
|
+
'level-2': { title: '二级标题', description: '二级标题描述' },
|
|
2480
|
+
'level-3': { title: '三级标题', description: '二级标题描述' },
|
|
2481
|
+
card: { title: '卡片标题', description: '二级标题描述' },
|
|
2482
|
+
};
|
|
2483
|
+
const sample = sampleMap[variant] || sampleMap.form;
|
|
2484
|
+
return {
|
|
2485
|
+
variant,
|
|
2486
|
+
title: sample.title,
|
|
2487
|
+
titleSuffix: cv.titleTag === 'on' ? <Tag variant="grey" size="m">0 条消息</Tag> : null,
|
|
2488
|
+
description: cv.showDescription === 'on' ? sample.description : '',
|
|
2489
|
+
showDescription: cv.showDescription === 'on',
|
|
2490
|
+
};
|
|
2491
|
+
},
|
|
2492
|
+
|
|
2493
|
+
generateUsage: (enums, cv) => {
|
|
2494
|
+
const showDescription = cv.showDescription === 'on';
|
|
2495
|
+
const showTitleTag = cv.titleTag === 'on';
|
|
2496
|
+
const variant = enums.variant || 'form';
|
|
2497
|
+
const sampleMap = {
|
|
2498
|
+
form: { title: '表单标题', description: '一级标题描述' },
|
|
2499
|
+
'level-1': { title: '一级标题', description: '一级标题描述' },
|
|
2500
|
+
'level-2': { title: '二级标题', description: '二级标题描述' },
|
|
2501
|
+
'level-3': { title: '三级标题', description: '二级标题描述' },
|
|
2502
|
+
card: { title: '卡片标题', description: '二级标题描述' },
|
|
2503
|
+
};
|
|
2504
|
+
const sample = sampleMap[variant] || sampleMap.form;
|
|
2505
|
+
const lines = [`import FormTitle from './components/FormTitle';`];
|
|
2506
|
+
if (showTitleTag) {
|
|
2507
|
+
lines.push(`import Tag from './components/Tag';`);
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
lines.push('');
|
|
2511
|
+
if (variant === 'level-1' && !showDescription) {
|
|
2512
|
+
lines.push('{/* 列表/管理页白卡顶栏:level-1 + 无描述;与按钮同行用 flex justify-between */}');
|
|
2513
|
+
}
|
|
2514
|
+
lines.push('<FormTitle');
|
|
2515
|
+
if (variant !== 'form') lines.push(` variant="${variant}"`);
|
|
2516
|
+
lines.push(` title="${sample.title}"`);
|
|
2517
|
+
if (showTitleTag) {
|
|
2518
|
+
lines.push(' titleSuffix={<Tag variant="grey" size="m">0 条消息</Tag>}');
|
|
2519
|
+
}
|
|
2520
|
+
if (showDescription) {
|
|
2521
|
+
lines.push(` description="${sample.description}"`);
|
|
2522
|
+
lines.push(' showDescription');
|
|
2523
|
+
}
|
|
2524
|
+
lines.push('/>');
|
|
2525
|
+
return lines.join('\n');
|
|
2526
|
+
},
|
|
2527
|
+
},
|
|
2528
|
+
|
|
2529
|
+
form: {
|
|
2530
|
+
component: FormPreview,
|
|
2531
|
+
tokenMap: FORM_TOKEN_MAP,
|
|
2532
|
+
|
|
2533
|
+
normalizeControlValues: ({ changedControlId, nextControlValues, prevControlValues }) => (
|
|
2534
|
+
normalizeSliderPreviewControls(nextControlValues, prevControlValues, changedControlId, 'slider')
|
|
2535
|
+
),
|
|
2536
|
+
|
|
2537
|
+
getPreviewAreaStyle: ({ controlValues }) => ({
|
|
2538
|
+
alignItems: (controlValues.previewMode || 'single') === 'all' ? 'flex-start' : 'center',
|
|
2539
|
+
justifyContent: (controlValues.previewMode || 'single') === 'all' ? 'flex-start' : 'center',
|
|
2540
|
+
overflow: 'auto',
|
|
2541
|
+
padding: '48px',
|
|
2542
|
+
}),
|
|
2543
|
+
|
|
2544
|
+
getPreviewItemStyle: ({ controlValues }) => ({
|
|
2545
|
+
width: controlValues.previewMode === 'all' ? 'max-content' : 'auto',
|
|
2546
|
+
minWidth: controlValues.previewMode === 'all' ? '300px' : undefined,
|
|
2547
|
+
display: 'flex',
|
|
2548
|
+
alignItems: controlValues.previewMode === 'all' ? 'flex-start' : 'center',
|
|
2549
|
+
justifyContent: controlValues.previewMode === 'all' ? 'flex-start' : 'center',
|
|
2550
|
+
}),
|
|
2551
|
+
|
|
2552
|
+
controls: [
|
|
2553
|
+
{
|
|
2554
|
+
id: 'previewMode',
|
|
2555
|
+
label: '预览',
|
|
2556
|
+
type: 'seg',
|
|
2557
|
+
options: [
|
|
2558
|
+
{ id: 'single', label: '单项' },
|
|
2559
|
+
{ id: 'all', label: '全集' },
|
|
2560
|
+
],
|
|
2561
|
+
default: 'single',
|
|
2562
|
+
},
|
|
2563
|
+
{
|
|
2564
|
+
id: 'fieldType',
|
|
2565
|
+
label: '字段类型',
|
|
2566
|
+
type: 'select',
|
|
2567
|
+
options: FORM_FIELD_TYPES.map((id) => ({ id, label: FORM_FIELD_LABELS[id] || id })),
|
|
2568
|
+
default: 'input',
|
|
2569
|
+
hidden: ({ controlValues }) => (controlValues.previewMode || 'single') === 'all',
|
|
2570
|
+
},
|
|
2571
|
+
{
|
|
2572
|
+
id: 'labelPosition',
|
|
2573
|
+
label: '标签位置',
|
|
2574
|
+
type: 'seg',
|
|
2575
|
+
options: [
|
|
2576
|
+
{ id: 'top', label: '顶部' },
|
|
2577
|
+
{ id: 'left', label: '左侧' },
|
|
2578
|
+
],
|
|
2579
|
+
default: 'top',
|
|
2580
|
+
hidden: ({ controlValues }) => (controlValues.previewMode || 'single') === 'all',
|
|
2581
|
+
},
|
|
2582
|
+
{
|
|
2583
|
+
id: 'helpMode',
|
|
2584
|
+
label: '提示',
|
|
2585
|
+
type: 'seg',
|
|
2586
|
+
options: [
|
|
2587
|
+
{ id: 'none', label: '无' },
|
|
2588
|
+
{ id: 'middle', label: '中部' },
|
|
2589
|
+
{ id: 'bottom', label: '底部' },
|
|
2590
|
+
],
|
|
2591
|
+
default: 'none',
|
|
2592
|
+
hidden: ({ controlValues }) => (controlValues.previewMode || 'single') === 'all',
|
|
2593
|
+
},
|
|
2594
|
+
{
|
|
2595
|
+
id: 'validationState',
|
|
2596
|
+
label: '校验',
|
|
2597
|
+
type: 'seg',
|
|
2598
|
+
options: [
|
|
2599
|
+
{ id: 'default', label: '默认' },
|
|
2600
|
+
{ id: 'error', label: '错误' },
|
|
2601
|
+
],
|
|
2602
|
+
default: 'default',
|
|
2603
|
+
hidden: ({ controlValues }) => (controlValues.previewMode || 'single') === 'all',
|
|
2604
|
+
},
|
|
2605
|
+
{
|
|
2606
|
+
id: 'labelOptional',
|
|
2607
|
+
label: '标题-可选',
|
|
2608
|
+
type: 'switch',
|
|
2609
|
+
default: false,
|
|
2610
|
+
},
|
|
2611
|
+
{
|
|
2612
|
+
id: 'labelRequired',
|
|
2613
|
+
label: '标题-必填',
|
|
2614
|
+
type: 'switch',
|
|
2615
|
+
default: false,
|
|
2616
|
+
},
|
|
2617
|
+
{
|
|
2618
|
+
id: 'labelAi',
|
|
2619
|
+
label: '标题-AI',
|
|
2620
|
+
type: 'switch',
|
|
2621
|
+
default: false,
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
id: 'labelHelp',
|
|
2625
|
+
label: '标题-Help',
|
|
2626
|
+
type: 'switch',
|
|
2627
|
+
default: false,
|
|
2628
|
+
},
|
|
2629
|
+
...buildSliderPreviewControls('slider', ({ controlValues }) => {
|
|
2630
|
+
const previewMode = controlValues.previewMode || 'single';
|
|
2631
|
+
return previewMode === 'all' || (controlValues.fieldType || 'input') !== 'slider';
|
|
2632
|
+
}),
|
|
2633
|
+
],
|
|
2634
|
+
|
|
2635
|
+
enumTitles: {
|
|
2636
|
+
controlVariant: '组件颜色',
|
|
2637
|
+
controlLayout: '组件排列',
|
|
2638
|
+
pickerType: '日期类型',
|
|
2639
|
+
timePickerType: '时间类型',
|
|
2640
|
+
inputNumberButtons: '按钮位置',
|
|
2641
|
+
},
|
|
2642
|
+
|
|
2643
|
+
getVisibleEnumProps: ({ enumProps, controlValues }) => {
|
|
2644
|
+
const previewMode = controlValues.previewMode || 'single';
|
|
2645
|
+
if (previewMode === 'all') return [];
|
|
2646
|
+
return getFormFieldAtomEnumProps(controlValues.fieldType || 'input');
|
|
2647
|
+
},
|
|
2648
|
+
|
|
2649
|
+
mapProps: (cv, enums) => ({
|
|
2650
|
+
previewMode: cv.previewMode || 'single',
|
|
2651
|
+
fieldType: cv.fieldType || 'input',
|
|
2652
|
+
labelPosition: cv.labelPosition || 'top',
|
|
2653
|
+
helpMode: cv.helpMode || 'none',
|
|
2654
|
+
validationState: cv.validationState || 'default',
|
|
2655
|
+
size: 'md',
|
|
2656
|
+
labelOptional: cv.labelOptional === true,
|
|
2657
|
+
labelRequired: cv.labelRequired === true,
|
|
2658
|
+
labelAi: cv.labelAi === true,
|
|
2659
|
+
labelHelp: cv.labelHelp === true,
|
|
2660
|
+
fieldAtomProps: buildFormFieldAtomProps(cv.fieldType || 'input', enums, cv),
|
|
2661
|
+
}),
|
|
2662
|
+
|
|
2663
|
+
generateUsage: (enums, cv) => {
|
|
2664
|
+
const lines = [`import Form from './components/Form';`];
|
|
2665
|
+
const previewMode = cv.previewMode || 'single';
|
|
2666
|
+
const fieldType = cv.fieldType || 'input';
|
|
2667
|
+
const labelPosition = cv.labelPosition || 'top';
|
|
2668
|
+
const helpMode = cv.helpMode || 'none';
|
|
2669
|
+
const validationState = cv.validationState || 'default';
|
|
2670
|
+
const labelOptional = cv.labelOptional === true;
|
|
2671
|
+
const labelRequired = cv.labelRequired === true;
|
|
2672
|
+
const labelAi = cv.labelAi === true;
|
|
2673
|
+
const labelHelp = cv.labelHelp === true;
|
|
2674
|
+
const fieldAtomProps = buildFormFieldAtomProps(fieldType, enums, cv);
|
|
2675
|
+
|
|
2676
|
+
if (previewMode === 'all') {
|
|
2677
|
+
lines.push('');
|
|
2678
|
+
lines.push('<Form className="!gap-10" />');
|
|
2679
|
+
return lines.join('\n');
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
lines.push('');
|
|
2683
|
+
lines.push('const items = [{');
|
|
2684
|
+
lines.push(" id: 'field-1',");
|
|
2685
|
+
lines.push(" label: '字段标题',");
|
|
2686
|
+
lines.push(` type: '${fieldType}',`);
|
|
2687
|
+
lines.push(' required: true,');
|
|
2688
|
+
if (helpMode === 'middle') lines.push(" middleHelpText: '提示文案',");
|
|
2689
|
+
if (helpMode === 'bottom') lines.push(" helpText: '提示文案',");
|
|
2690
|
+
if (validationState === 'error') lines.push(" error: true, errorText: '该项目为必填项',");
|
|
2691
|
+
if (fieldType === 'radio' || fieldType === 'checkbox') {
|
|
2692
|
+
if (fieldAtomProps.variant !== 'brand') lines.push(` variant: '${fieldAtomProps.variant}',`);
|
|
2693
|
+
if (fieldAtomProps.layout !== 'horizontal') lines.push(` layout: '${fieldAtomProps.layout}',`);
|
|
2694
|
+
}
|
|
2695
|
+
if (fieldType === 'switch') {
|
|
2696
|
+
if (fieldAtomProps.variant !== 'black') lines.push(` variant: '${fieldAtomProps.variant}',`);
|
|
2697
|
+
}
|
|
2698
|
+
if (fieldType === 'date-picker' && fieldAtomProps.pickerType !== 'date') {
|
|
2699
|
+
lines.push(` pickerType: '${fieldAtomProps.pickerType}',`);
|
|
2700
|
+
}
|
|
2701
|
+
if (fieldType === 'time-picker' && fieldAtomProps.pickerType !== 'time') {
|
|
2702
|
+
lines.push(` pickerType: '${fieldAtomProps.pickerType}',`);
|
|
2703
|
+
}
|
|
2704
|
+
if (fieldType === 'input-number' && fieldAtomProps.innerButtons) {
|
|
2705
|
+
lines.push(' innerButtons: true,');
|
|
2706
|
+
}
|
|
2707
|
+
if (fieldType === 'textarea') {
|
|
2708
|
+
if (enums.fillMode === 'filled') {
|
|
2709
|
+
lines.push(` defaultValue: '${FORM_TEXTAREA_SAMPLE.slice(0, 48)}…',`);
|
|
2710
|
+
}
|
|
2711
|
+
if (enums.countOverflow === 'on') {
|
|
2712
|
+
lines.push(' showCount: true,');
|
|
2713
|
+
lines.push(' maxLength: 140,');
|
|
2714
|
+
lines.push(' enforceMaxLength: false,');
|
|
2715
|
+
}
|
|
2716
|
+
if (enums.state === 'disabled') lines.push(' disabled: true,');
|
|
2717
|
+
if (enums.minRows != null && enums.minRows !== 3) lines.push(` minRows: ${enums.minRows},`);
|
|
2718
|
+
if (enums.status === 'error') lines.push(' status: "error",');
|
|
2719
|
+
if (enums.resize === 'none') lines.push(' resize: "none",');
|
|
2720
|
+
}
|
|
2721
|
+
if (fieldType === 'slider') {
|
|
2722
|
+
const sliderDefaultValue = formatUsageLiteral(fieldAtomProps.defaultValue);
|
|
2723
|
+
const sliderMarks = formatUsageLiteral(fieldAtomProps.marks);
|
|
2724
|
+
if (fieldAtomProps.min !== SLIDER_PREVIEW_DEFAULTS.min) lines.push(` min: ${fieldAtomProps.min},`);
|
|
2725
|
+
if (fieldAtomProps.max !== SLIDER_PREVIEW_DEFAULTS.max) lines.push(` max: ${fieldAtomProps.max},`);
|
|
2726
|
+
if (fieldAtomProps.step !== SLIDER_PREVIEW_DEFAULTS.step) lines.push(` step: ${fieldAtomProps.step},`);
|
|
2727
|
+
if (sliderDefaultValue) lines.push(` defaultValue: ${sliderDefaultValue},`);
|
|
2728
|
+
if (fieldAtomProps.showTooltip === false) lines.push(' showTooltip: false,');
|
|
2729
|
+
if (sliderMarks) lines.push(` marks: ${sliderMarks},`);
|
|
2730
|
+
if (fieldAtomProps.disabled) lines.push(' disabled: true,');
|
|
2731
|
+
lines.push(' onChange: (value) => {},');
|
|
2732
|
+
lines.push(' onAfterChange: (value) => {},');
|
|
2733
|
+
}
|
|
2734
|
+
lines.push('}];');
|
|
2735
|
+
lines.push('');
|
|
2736
|
+
lines.push('<Form');
|
|
2737
|
+
if (labelPosition !== 'top') lines.push(` labelPosition="${labelPosition}"`);
|
|
2738
|
+
if (labelOptional) lines.push(' labelOptional');
|
|
2739
|
+
if (labelRequired) lines.push(' labelRequired');
|
|
2740
|
+
if (labelHelp) lines.push(' labelHelp');
|
|
2741
|
+
if (labelAi) lines.push(' labelAi');
|
|
2742
|
+
lines.push(' items={items}');
|
|
2743
|
+
lines.push('/>');
|
|
2744
|
+
return lines.join('\n');
|
|
2745
|
+
},
|
|
2746
|
+
},
|
|
2747
|
+
|
|
2748
|
+
'form-field-stack': {
|
|
2749
|
+
component: FormFieldStack,
|
|
2750
|
+
tokenMap: FORM_FIELD_STACK_TOKEN_MAP,
|
|
2751
|
+
jsxSource: formFieldStackJsxRaw,
|
|
2752
|
+
|
|
2753
|
+
getPreviewAreaStyle: () => ({
|
|
2754
|
+
/* 默认 .detail-preview-area 为横向 flex,子级 scaler 会随内容收缩宽度;
|
|
2755
|
+
改为纵向 + stretch,让 scaler 在横轴上占满预览区,内部 w-full 才能生效 */
|
|
2756
|
+
flexDirection: 'column',
|
|
2757
|
+
alignItems: 'stretch',
|
|
2758
|
+
justifyContent: 'flex-start',
|
|
2759
|
+
overflow: 'auto',
|
|
2760
|
+
padding: 0,
|
|
2761
|
+
}),
|
|
2762
|
+
|
|
2763
|
+
getPreviewScalerStyle: () => ({
|
|
2764
|
+
width: '100%',
|
|
2765
|
+
minWidth: 0,
|
|
2766
|
+
boxSizing: 'border-box',
|
|
2767
|
+
}),
|
|
2768
|
+
|
|
2769
|
+
getPreviewItemStyle: () => ({
|
|
2770
|
+
width: '100%',
|
|
2771
|
+
minWidth: 0,
|
|
2772
|
+
flex: '1 1 auto',
|
|
2773
|
+
alignSelf: 'stretch',
|
|
2774
|
+
display: 'flex',
|
|
2775
|
+
justifyContent: 'flex-start',
|
|
2776
|
+
alignItems: 'stretch',
|
|
2777
|
+
}),
|
|
2778
|
+
|
|
2779
|
+
configHiddenEnums: ['stackLayout'],
|
|
2780
|
+
|
|
2781
|
+
controls: [
|
|
2782
|
+
{
|
|
2783
|
+
id: 'stackLayout',
|
|
2784
|
+
label: '布局',
|
|
2785
|
+
type: 'seg',
|
|
2786
|
+
options: [
|
|
2787
|
+
{ id: 'select-stack', label: '纯下拉' },
|
|
2788
|
+
{ id: 'mixed-fields', label: '多类型' },
|
|
2789
|
+
],
|
|
2790
|
+
default: 'select-stack',
|
|
2791
|
+
},
|
|
2792
|
+
],
|
|
2793
|
+
|
|
2794
|
+
mapProps: (cv, enums) => {
|
|
2795
|
+
const stackLayout = cv.stackLayout || enums.stackLayout || 'select-stack';
|
|
2796
|
+
return {
|
|
2797
|
+
stackLayout,
|
|
2798
|
+
__previewKey: `form-field-stack-${stackLayout}`,
|
|
2799
|
+
};
|
|
2800
|
+
},
|
|
2801
|
+
|
|
2802
|
+
generateUsage: (enums, cv) => {
|
|
2803
|
+
const stackLayout = cv.stackLayout || enums.stackLayout || 'select-stack';
|
|
2804
|
+
const lines = ["import FormFieldStack from './components/FormFieldStack';", ''];
|
|
2805
|
+
lines.push('export default function Example() {');
|
|
2806
|
+
if (stackLayout === 'mixed-fields') {
|
|
2807
|
+
lines.push(' return <FormFieldStack stackLayout="mixed-fields" />;');
|
|
2808
|
+
} else {
|
|
2809
|
+
lines.push(' return <FormFieldStack />;');
|
|
2810
|
+
}
|
|
2811
|
+
lines.push('}');
|
|
2812
|
+
return lines.join('\n');
|
|
2813
|
+
},
|
|
2814
|
+
},
|
|
2815
|
+
|
|
2816
|
+
input: {
|
|
2817
|
+
component: InputPreview,
|
|
2818
|
+
tokenMap: INPUT_TOKEN_MAP,
|
|
2819
|
+
jsxSource: inputJsxRaw,
|
|
2820
|
+
|
|
2821
|
+
getPreviewAreaStyle: () => ({
|
|
2822
|
+
alignItems: 'flex-start',
|
|
2823
|
+
justifyContent: 'center',
|
|
2824
|
+
overflow: 'auto',
|
|
2825
|
+
paddingTop: '96px',
|
|
2826
|
+
}),
|
|
2827
|
+
|
|
2828
|
+
getPreviewItemStyle: () => ({
|
|
2829
|
+
width: '100%',
|
|
2830
|
+
display: 'flex',
|
|
2831
|
+
justifyContent: 'center',
|
|
2832
|
+
alignItems: 'flex-start',
|
|
2833
|
+
flex: '0 0 auto',
|
|
2834
|
+
}),
|
|
2835
|
+
|
|
2836
|
+
controls: [
|
|
2837
|
+
{
|
|
2838
|
+
id: 'addonType', label: '附加元素', type: 'seg',
|
|
2839
|
+
options: [
|
|
2840
|
+
{ id: 'none', label: '无' },
|
|
2841
|
+
{ id: 'prefix', label: '前缀' },
|
|
2842
|
+
{ id: 'suffix', label: '后缀' },
|
|
2843
|
+
{ id: 'both', label: '前+后' },
|
|
2844
|
+
],
|
|
2845
|
+
default: 'none',
|
|
2846
|
+
},
|
|
2847
|
+
{
|
|
2848
|
+
id: 'state', label: '状态', type: 'seg',
|
|
2849
|
+
options: [
|
|
2850
|
+
{ id: 'default', label: '默认' },
|
|
2851
|
+
{ id: 'disabled', label: '禁用' },
|
|
2852
|
+
],
|
|
2853
|
+
default: 'default',
|
|
2854
|
+
},
|
|
2855
|
+
{
|
|
2856
|
+
id: 'suggestionMode', label: 'AI推荐',
|
|
2857
|
+
type: 'seg',
|
|
2858
|
+
options: [
|
|
2859
|
+
{ id: 'off', label: '隐藏' },
|
|
2860
|
+
{ id: 'on', label: '显示' },
|
|
2861
|
+
],
|
|
2862
|
+
default: 'off',
|
|
2863
|
+
},
|
|
2864
|
+
{
|
|
2865
|
+
id: 'suggestionType', label: '推荐形式',
|
|
2866
|
+
type: 'seg',
|
|
2867
|
+
options: [
|
|
2868
|
+
{ id: 'single', label: '单条' },
|
|
2869
|
+
{ id: 'multi', label: '多条' },
|
|
2870
|
+
],
|
|
2871
|
+
default: 'single',
|
|
2872
|
+
hidden: ({ controlValues }) => (controlValues.suggestionMode || 'off') !== 'on',
|
|
2873
|
+
},
|
|
2874
|
+
],
|
|
2875
|
+
|
|
2876
|
+
mapProps: (cv) => {
|
|
2877
|
+
const addon = cv.addonType || 'none';
|
|
2878
|
+
const st = cv.state || 'default';
|
|
2879
|
+
const hasPrefix = addon === 'prefix' || addon === 'both';
|
|
2880
|
+
const hasSuffix = addon === 'suffix' || addon === 'both';
|
|
2881
|
+
const showSuggestion = cv.suggestionMode === 'on';
|
|
2882
|
+
const isMultiSuggestion = cv.suggestionType === 'multi';
|
|
2883
|
+
return {
|
|
2884
|
+
prefix: hasPrefix ? <Search size={16} /> : undefined,
|
|
2885
|
+
suffix: hasSuffix ? <Eye size={16} /> : undefined,
|
|
2886
|
+
disabled: st === 'disabled',
|
|
2887
|
+
allowClear: true,
|
|
2888
|
+
aiSuggestion: showSuggestion && !isMultiSuggestion ? INPUT_SINGLE_SUGGESTIONS[0] : undefined,
|
|
2889
|
+
aiSuggestions: showSuggestion && isMultiSuggestion
|
|
2890
|
+
? INPUT_MULTI_SUGGESTION_GROUPS[0]
|
|
2891
|
+
: undefined,
|
|
2892
|
+
placeholder: '请输入',
|
|
2893
|
+
};
|
|
2894
|
+
},
|
|
2895
|
+
|
|
2896
|
+
generateUsage: (enums, cv) => {
|
|
2897
|
+
const lines = [`import Input from './components/Input';`];
|
|
2898
|
+
const addon = cv.addonType || 'none';
|
|
2899
|
+
const st = cv.state || 'default';
|
|
2900
|
+
const props = [];
|
|
2901
|
+
if (enums.status && enums.status !== 'default') props.push(`status="${enums.status}"`);
|
|
2902
|
+
if (addon === 'prefix' || addon === 'both') props.push('prefix={<Search size={16} />}');
|
|
2903
|
+
if (addon === 'suffix' || addon === 'both') props.push('suffix={<Eye size={16} />}');
|
|
2904
|
+
if (st === 'disabled') props.push('disabled');
|
|
2905
|
+
if (cv.suggestionMode === 'on' && cv.suggestionType === 'single') {
|
|
2906
|
+
props.push('aiSuggestion="您好,您的问题已收到,抖音客服正在为您核实处理。"');
|
|
2907
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
2908
|
+
}
|
|
2909
|
+
if (cv.suggestionMode === 'on' && cv.suggestionType === 'multi') {
|
|
2910
|
+
props.push('aiSuggestions={["您好,正在为您核实,请稍候。", "抱歉给您带来不便,这边已经帮您加急处理。", "您好,您反馈的问题我们已经收到,建议您先提供订单号和问题截图,方便抖音客服尽快为您核实处理。"]}');
|
|
2911
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
2912
|
+
}
|
|
2913
|
+
props.push('placeholder="请输入"');
|
|
2914
|
+
|
|
2915
|
+
lines.push('');
|
|
2916
|
+
lines.push('<Input');
|
|
2917
|
+
props.forEach(p => lines.push(` ${p}`));
|
|
2918
|
+
lines.push('/>');
|
|
2919
|
+
return lines.join('\n');
|
|
2920
|
+
},
|
|
2921
|
+
},
|
|
2922
|
+
|
|
2923
|
+
textarea: {
|
|
2924
|
+
component: TextAreaPreview,
|
|
2925
|
+
tokenMap: TEXTAREA_TOKEN_MAP,
|
|
2926
|
+
jsxSource: textareaJsxRaw,
|
|
2927
|
+
|
|
2928
|
+
getPreviewAreaStyle: () => ({
|
|
2929
|
+
alignItems: 'flex-start',
|
|
2930
|
+
justifyContent: 'center',
|
|
2931
|
+
overflow: 'auto',
|
|
2932
|
+
paddingTop: '96px',
|
|
2933
|
+
}),
|
|
2934
|
+
|
|
2935
|
+
getPreviewItemStyle: () => ({
|
|
2936
|
+
width: '100%',
|
|
2937
|
+
display: 'flex',
|
|
2938
|
+
justifyContent: 'center',
|
|
2939
|
+
alignItems: 'flex-start',
|
|
2940
|
+
flex: '0 0 auto',
|
|
2941
|
+
}),
|
|
2942
|
+
|
|
2943
|
+
controls: [
|
|
2944
|
+
{
|
|
2945
|
+
id: 'fillMode',
|
|
2946
|
+
label: '内容',
|
|
2947
|
+
type: 'seg',
|
|
2948
|
+
options: [
|
|
2949
|
+
{ id: 'empty', label: '空' },
|
|
2950
|
+
{ id: 'filled', label: '有值' },
|
|
2951
|
+
],
|
|
2952
|
+
default: 'empty',
|
|
2953
|
+
},
|
|
2954
|
+
{
|
|
2955
|
+
id: 'countOverflow',
|
|
2956
|
+
label: '超长计数',
|
|
2957
|
+
type: 'seg',
|
|
2958
|
+
options: [
|
|
2959
|
+
{ id: 'off', label: '关' },
|
|
2960
|
+
{ id: 'on', label: '开' },
|
|
2961
|
+
],
|
|
2962
|
+
default: 'off',
|
|
2963
|
+
},
|
|
2964
|
+
{
|
|
2965
|
+
id: 'state',
|
|
2966
|
+
label: '状态',
|
|
2967
|
+
type: 'seg',
|
|
2968
|
+
options: [
|
|
2969
|
+
{ id: 'default', label: '默认可用' },
|
|
2970
|
+
{ id: 'disabled', label: '禁用' },
|
|
2971
|
+
],
|
|
2972
|
+
default: 'default',
|
|
2973
|
+
},
|
|
2974
|
+
{
|
|
2975
|
+
id: 'suggestionMode',
|
|
2976
|
+
label: 'AI推荐',
|
|
2977
|
+
type: 'seg',
|
|
2978
|
+
options: [
|
|
2979
|
+
{ id: 'off', label: '隐藏' },
|
|
2980
|
+
{ id: 'on', label: '显示' },
|
|
2981
|
+
],
|
|
2982
|
+
default: 'off',
|
|
2983
|
+
},
|
|
2984
|
+
{
|
|
2985
|
+
id: 'suggestionType',
|
|
2986
|
+
label: '推荐形式',
|
|
2987
|
+
type: 'seg',
|
|
2988
|
+
options: [
|
|
2989
|
+
{ id: 'single', label: '单条' },
|
|
2990
|
+
{ id: 'multi', label: '多条' },
|
|
2991
|
+
],
|
|
2992
|
+
default: 'single',
|
|
2993
|
+
hidden: ({ controlValues }) => (controlValues.suggestionMode || 'off') !== 'on',
|
|
2994
|
+
},
|
|
2995
|
+
],
|
|
2996
|
+
|
|
2997
|
+
mapProps: (cv) => {
|
|
2998
|
+
const showSuggestion = cv.suggestionMode === 'on';
|
|
2999
|
+
const isMultiSuggestion = cv.suggestionType === 'multi';
|
|
3000
|
+
return {
|
|
3001
|
+
fillMode: cv.fillMode || 'empty',
|
|
3002
|
+
countOverflow: cv.countOverflow === 'on',
|
|
3003
|
+
disabled: cv.state === 'disabled',
|
|
3004
|
+
aiSuggestion: showSuggestion && !isMultiSuggestion ? TEXTAREA_SINGLE_SUGGESTIONS[0] : undefined,
|
|
3005
|
+
aiSuggestions: showSuggestion && isMultiSuggestion ? TEXTAREA_MULTI_SUGGESTION_GROUPS[0] : undefined,
|
|
3006
|
+
};
|
|
3007
|
+
},
|
|
3008
|
+
|
|
3009
|
+
generateUsage: (enums, cv) => {
|
|
3010
|
+
const lines = [`import TextArea from './components/TextArea';`];
|
|
3011
|
+
const props = [];
|
|
3012
|
+
if (enums.variant && enums.variant !== 'default') props.push(`variant="${enums.variant}"`);
|
|
3013
|
+
if (enums.minRows != null && enums.minRows !== 3) props.push(`minRows={${enums.minRows}}`);
|
|
3014
|
+
if (enums.status && enums.status !== 'default') props.push(`status="${enums.status}"`);
|
|
3015
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3016
|
+
props.push(enums.variant === 'code' ? 'placeholder="请输入 System Prompt、JSON 或代码"' : 'placeholder="请输入"');
|
|
3017
|
+
if (cv.countOverflow === 'on') {
|
|
3018
|
+
props.push('showCount');
|
|
3019
|
+
props.push('maxLength={140}');
|
|
3020
|
+
props.push('enforceMaxLength={false}');
|
|
3021
|
+
}
|
|
3022
|
+
if (cv.suggestionMode === 'on' && cv.suggestionType === 'single') {
|
|
3023
|
+
props.push('aiSuggestion="根据当前对话内容,建议先记录用户诉求、异常现象和下一步处理动作。"');
|
|
3024
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
3025
|
+
}
|
|
3026
|
+
if (cv.suggestionMode === 'on' && cv.suggestionType === 'multi') {
|
|
3027
|
+
props.push('aiSuggestions={["建议优先整理用户诉求、处理时效和需补充的材料信息。", "如果需要后续交接,可一并记录当前判责结论和预计回访时间。"]}');
|
|
3028
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
3029
|
+
}
|
|
3030
|
+
if (cv.fillMode === 'filled') {
|
|
3031
|
+
props.push(enums.variant === 'code'
|
|
3032
|
+
? 'defaultValue={"# 角色\\n你是抖音安全中心的小安智能助手…"}'
|
|
3033
|
+
: 'defaultValue="我们非常高兴地向您介绍我们的最新产品 HiUI…"');
|
|
3034
|
+
}
|
|
3035
|
+
if (enums.resize === 'none') {
|
|
3036
|
+
props.push('resize="none"');
|
|
3037
|
+
}
|
|
3038
|
+
if (enums.fillHeight) {
|
|
3039
|
+
props.push('fillHeight');
|
|
3040
|
+
props.push('className="flex-1 min-h-0 w-full"');
|
|
3041
|
+
} else if (enums.variant === 'code') {
|
|
3042
|
+
props.push('className="w-[520px]"');
|
|
3043
|
+
}
|
|
3044
|
+
lines.push('');
|
|
3045
|
+
lines.push('<TextArea');
|
|
3046
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3047
|
+
lines.push('/>');
|
|
3048
|
+
return lines.join('\n');
|
|
3049
|
+
},
|
|
3050
|
+
},
|
|
3051
|
+
|
|
3052
|
+
'input-number': {
|
|
3053
|
+
component: InputNumberPreview,
|
|
3054
|
+
tokenMap: INPUT_NUMBER_TOKEN_MAP,
|
|
3055
|
+
jsxSource: inputNumberJsxRaw,
|
|
3056
|
+
|
|
3057
|
+
getPreviewAreaStyle: () => ({
|
|
3058
|
+
alignItems: 'flex-start',
|
|
3059
|
+
justifyContent: 'center',
|
|
3060
|
+
overflow: 'auto',
|
|
3061
|
+
paddingTop: '96px',
|
|
3062
|
+
}),
|
|
3063
|
+
|
|
3064
|
+
getPreviewItemStyle: () => ({
|
|
3065
|
+
width: '100%',
|
|
3066
|
+
display: 'flex',
|
|
3067
|
+
justifyContent: 'center',
|
|
3068
|
+
alignItems: 'flex-start',
|
|
3069
|
+
flex: '0 0 auto',
|
|
3070
|
+
}),
|
|
3071
|
+
|
|
3072
|
+
controls: [
|
|
3073
|
+
{
|
|
3074
|
+
id: 'buttonMode',
|
|
3075
|
+
label: '按钮',
|
|
3076
|
+
type: 'seg',
|
|
3077
|
+
options: [
|
|
3078
|
+
{ id: 'outer', label: '外置' },
|
|
3079
|
+
{ id: 'inner', label: '内置' },
|
|
3080
|
+
],
|
|
3081
|
+
default: 'outer',
|
|
3082
|
+
},
|
|
3083
|
+
{
|
|
3084
|
+
id: 'content',
|
|
3085
|
+
label: '内容',
|
|
3086
|
+
type: 'seg',
|
|
3087
|
+
options: [
|
|
3088
|
+
{ id: 'empty', label: '无值' },
|
|
3089
|
+
{ id: 'filled', label: '有值' },
|
|
3090
|
+
],
|
|
3091
|
+
default: 'empty',
|
|
3092
|
+
},
|
|
3093
|
+
{
|
|
3094
|
+
id: 'state',
|
|
3095
|
+
label: '状态',
|
|
3096
|
+
type: 'seg',
|
|
3097
|
+
options: [
|
|
3098
|
+
{ id: 'default', label: '默认' },
|
|
3099
|
+
{ id: 'disabled', label: '禁用' },
|
|
3100
|
+
],
|
|
3101
|
+
default: 'default',
|
|
3102
|
+
},
|
|
3103
|
+
],
|
|
3104
|
+
|
|
3105
|
+
mapProps: (cv, enums) => ({
|
|
3106
|
+
buttonMode: cv.buttonMode || 'outer',
|
|
3107
|
+
content: cv.content || 'empty',
|
|
3108
|
+
disabled: cv.state === 'disabled',
|
|
3109
|
+
status: enums.status || 'default',
|
|
3110
|
+
}),
|
|
3111
|
+
|
|
3112
|
+
generateUsage: (enums, cv) => {
|
|
3113
|
+
const lines = [`import InputNumber from './components/InputNumber';`];
|
|
3114
|
+
const props = [];
|
|
3115
|
+
const buttonMode = cv.buttonMode || 'outer';
|
|
3116
|
+
const content = cv.content || 'empty';
|
|
3117
|
+
if (enums.status && enums.status !== 'default') props.push(`status="${enums.status}"`);
|
|
3118
|
+
if (buttonMode === 'inner') props.push('innerButtons');
|
|
3119
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3120
|
+
if (content === 'filled') props.push('defaultValue={12}');
|
|
3121
|
+
props.push('min={0}');
|
|
3122
|
+
props.push('max={99}');
|
|
3123
|
+
props.push('step={1}');
|
|
3124
|
+
props.push('placeholder="请输入"');
|
|
3125
|
+
|
|
3126
|
+
lines.push('');
|
|
3127
|
+
lines.push('<InputNumber');
|
|
3128
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3129
|
+
lines.push('/>');
|
|
3130
|
+
return lines.join('\n');
|
|
3131
|
+
},
|
|
3132
|
+
},
|
|
3133
|
+
|
|
3134
|
+
radio: {
|
|
3135
|
+
component: RadioPreview,
|
|
3136
|
+
tokenMap: RADIO_TOKEN_MAP,
|
|
3137
|
+
jsxSource: radioJsxRaw,
|
|
3138
|
+
|
|
3139
|
+
controls: [
|
|
3140
|
+
{
|
|
3141
|
+
id: 'initialKey',
|
|
3142
|
+
label: '初始选中',
|
|
3143
|
+
type: 'seg',
|
|
3144
|
+
options: [
|
|
3145
|
+
{ id: 'none', label: '无' },
|
|
3146
|
+
{ id: 'a', label: 'A' },
|
|
3147
|
+
{ id: 'b', label: 'B' },
|
|
3148
|
+
],
|
|
3149
|
+
default: 'none',
|
|
3150
|
+
},
|
|
3151
|
+
{
|
|
3152
|
+
id: 'state',
|
|
3153
|
+
label: '交互',
|
|
3154
|
+
type: 'seg',
|
|
3155
|
+
options: [
|
|
3156
|
+
{ id: 'default', label: '可点' },
|
|
3157
|
+
{ id: 'disabled', label: '禁用' },
|
|
3158
|
+
],
|
|
3159
|
+
default: 'default',
|
|
3160
|
+
},
|
|
3161
|
+
],
|
|
3162
|
+
|
|
3163
|
+
mapProps: (cv) => ({
|
|
3164
|
+
initialKey: cv.initialKey || 'none',
|
|
3165
|
+
disabled: cv.state === 'disabled',
|
|
3166
|
+
}),
|
|
3167
|
+
|
|
3168
|
+
generateUsage: (enums, cv) => {
|
|
3169
|
+
const lines = [`import RadioGroup, { Radio } from './components/Radio';`];
|
|
3170
|
+
const props = [];
|
|
3171
|
+
if (enums.variant && enums.variant !== 'brand') props.push(`variant="${enums.variant}"`);
|
|
3172
|
+
if (enums.layout && enums.layout !== 'vertical') props.push(`layout="${enums.layout}"`);
|
|
3173
|
+
if (cv.initialKey === 'a') props.push('defaultValue="a"');
|
|
3174
|
+
if (cv.initialKey === 'b') props.push('defaultValue="b"');
|
|
3175
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3176
|
+
props.push('onChange={(value) => {}}');
|
|
3177
|
+
lines.push('');
|
|
3178
|
+
lines.push('<RadioGroup');
|
|
3179
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3180
|
+
lines.push('>');
|
|
3181
|
+
lines.push(' <Radio value="a">选项 A</Radio>');
|
|
3182
|
+
lines.push(' <Radio value="b">选项 B</Radio>');
|
|
3183
|
+
lines.push(' <Radio value="c" disabled>选项 C(单项禁用)</Radio>');
|
|
3184
|
+
lines.push('</RadioGroup>');
|
|
3185
|
+
return lines.join('\n');
|
|
3186
|
+
},
|
|
3187
|
+
},
|
|
3188
|
+
|
|
3189
|
+
checkbox: {
|
|
3190
|
+
component: CheckboxPreview,
|
|
3191
|
+
tokenMap: CHECKBOX_TOKEN_MAP,
|
|
3192
|
+
jsxSource: checkboxJsxRaw,
|
|
3193
|
+
|
|
3194
|
+
controls: [
|
|
3195
|
+
{
|
|
3196
|
+
id: 'previewMode',
|
|
3197
|
+
label: '预览',
|
|
3198
|
+
type: 'seg',
|
|
3199
|
+
options: [
|
|
3200
|
+
{ id: 'group', label: '多选组' },
|
|
3201
|
+
{ id: 'indeterminate', label: '半选' },
|
|
3202
|
+
],
|
|
3203
|
+
default: 'group',
|
|
3204
|
+
},
|
|
3205
|
+
{
|
|
3206
|
+
id: 'initialKey',
|
|
3207
|
+
label: '初始选中',
|
|
3208
|
+
type: 'seg',
|
|
3209
|
+
options: [
|
|
3210
|
+
{ id: 'none', label: '无' },
|
|
3211
|
+
{ id: 'a', label: 'A' },
|
|
3212
|
+
{ id: 'ab', label: 'A+B' },
|
|
3213
|
+
],
|
|
3214
|
+
default: 'none',
|
|
3215
|
+
},
|
|
3216
|
+
{
|
|
3217
|
+
id: 'state',
|
|
3218
|
+
label: '交互',
|
|
3219
|
+
type: 'seg',
|
|
3220
|
+
options: [
|
|
3221
|
+
{ id: 'default', label: '可点' },
|
|
3222
|
+
{ id: 'disabled', label: '禁用' },
|
|
3223
|
+
],
|
|
3224
|
+
default: 'default',
|
|
3225
|
+
},
|
|
3226
|
+
],
|
|
3227
|
+
|
|
3228
|
+
mapProps: (cv) => ({
|
|
3229
|
+
previewMode: cv.previewMode || 'group',
|
|
3230
|
+
initialKey: cv.initialKey || 'none',
|
|
3231
|
+
disabled: cv.state === 'disabled',
|
|
3232
|
+
}),
|
|
3233
|
+
|
|
3234
|
+
generateUsage: (enums, cv) => {
|
|
3235
|
+
const lines = [`import CheckboxGroup, { Checkbox } from './components/Checkbox';`];
|
|
3236
|
+
const props = [];
|
|
3237
|
+
if (enums.variant && enums.variant !== 'brand') props.push(`variant="${enums.variant}"`);
|
|
3238
|
+
if (enums.size && enums.size !== 'md') props.push(`size="${enums.size}"`);
|
|
3239
|
+
if (enums.layout && enums.layout !== 'vertical') props.push(`layout="${enums.layout}"`);
|
|
3240
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3241
|
+
|
|
3242
|
+
if (cv.previewMode === 'indeterminate') {
|
|
3243
|
+
lines.push('');
|
|
3244
|
+
lines.push('<Checkbox');
|
|
3245
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3246
|
+
lines.push(' indeterminate');
|
|
3247
|
+
lines.push('>');
|
|
3248
|
+
lines.push(' 部分子项已选');
|
|
3249
|
+
lines.push('</Checkbox>');
|
|
3250
|
+
return lines.join('\n');
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3253
|
+
if (cv.initialKey === 'a') props.push('defaultValue={["a"]}');
|
|
3254
|
+
if (cv.initialKey === 'ab') props.push('defaultValue={["a","b"]}');
|
|
3255
|
+
props.push('onChange={(values) => {}}');
|
|
3256
|
+
lines.push('');
|
|
3257
|
+
lines.push('<CheckboxGroup');
|
|
3258
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3259
|
+
lines.push('>');
|
|
3260
|
+
lines.push(' <Checkbox value="a">选项 A</Checkbox>');
|
|
3261
|
+
lines.push(' <Checkbox value="b">选项 B</Checkbox>');
|
|
3262
|
+
lines.push(' <Checkbox value="c" disabled>选项 C(单项禁用)</Checkbox>');
|
|
3263
|
+
lines.push('</CheckboxGroup>');
|
|
3264
|
+
return lines.join('\n');
|
|
3265
|
+
},
|
|
3266
|
+
},
|
|
3267
|
+
|
|
3268
|
+
select: {
|
|
3269
|
+
component: SelectPreview,
|
|
3270
|
+
tokenMap: SELECT_TOKEN_MAP,
|
|
3271
|
+
jsxSource: selectJsxRaw,
|
|
3272
|
+
configHiddenEnums: ['mode', 'tagVariant', 'tagSize'],
|
|
3273
|
+
|
|
3274
|
+
controls: [
|
|
3275
|
+
{
|
|
3276
|
+
id: 'selectType',
|
|
3277
|
+
label: '类型',
|
|
3278
|
+
type: 'seg',
|
|
3279
|
+
options: [
|
|
3280
|
+
{ id: 'default', label: '默认' },
|
|
3281
|
+
{ id: 'tag', label: '标签' },
|
|
3282
|
+
],
|
|
3283
|
+
default: 'default',
|
|
3284
|
+
},
|
|
3285
|
+
{
|
|
3286
|
+
id: 'initial',
|
|
3287
|
+
label: '初始值',
|
|
3288
|
+
type: 'seg',
|
|
3289
|
+
options: [
|
|
3290
|
+
{ id: 'empty', label: '空' },
|
|
3291
|
+
{ id: 'selected', label: '已选' },
|
|
3292
|
+
],
|
|
3293
|
+
default: 'empty',
|
|
3294
|
+
},
|
|
3295
|
+
{
|
|
3296
|
+
id: 'optionMode',
|
|
3297
|
+
label: '选项量',
|
|
3298
|
+
type: 'seg',
|
|
3299
|
+
options: [
|
|
3300
|
+
{ id: 'few', label: '少' },
|
|
3301
|
+
{ id: 'many', label: '多' },
|
|
3302
|
+
],
|
|
3303
|
+
default: 'few',
|
|
3304
|
+
hidden: ({ controlValues }) => (controlValues.selectType || 'default') === 'tag',
|
|
3305
|
+
},
|
|
3306
|
+
{
|
|
3307
|
+
id: 'state',
|
|
3308
|
+
label: '交互',
|
|
3309
|
+
type: 'seg',
|
|
3310
|
+
options: [
|
|
3311
|
+
{ id: 'default', label: '可点' },
|
|
3312
|
+
{ id: 'disabled', label: '禁用' },
|
|
3313
|
+
],
|
|
3314
|
+
default: 'default',
|
|
3315
|
+
},
|
|
3316
|
+
{
|
|
3317
|
+
id: 'suggestionMode',
|
|
3318
|
+
label: 'AI推荐',
|
|
3319
|
+
type: 'seg',
|
|
3320
|
+
options: [
|
|
3321
|
+
{ id: 'off', label: '隐藏' },
|
|
3322
|
+
{ id: 'on', label: '显示' },
|
|
3323
|
+
],
|
|
3324
|
+
default: 'off',
|
|
3325
|
+
hidden: ({ controlValues }) => (controlValues.selectType || 'default') === 'tag',
|
|
3326
|
+
},
|
|
3327
|
+
{
|
|
3328
|
+
id: 'suggestionType',
|
|
3329
|
+
label: '推荐形式',
|
|
3330
|
+
type: 'seg',
|
|
3331
|
+
options: [
|
|
3332
|
+
{ id: 'single', label: '单条' },
|
|
3333
|
+
{ id: 'multi', label: '多条' },
|
|
3334
|
+
],
|
|
3335
|
+
default: 'single',
|
|
3336
|
+
hidden: ({ controlValues }) => (
|
|
3337
|
+
(controlValues.selectType || 'default') === 'tag'
|
|
3338
|
+
|| (controlValues.suggestionMode || 'off') !== 'on'
|
|
3339
|
+
),
|
|
3340
|
+
},
|
|
3341
|
+
],
|
|
3342
|
+
|
|
3343
|
+
mapProps: (cv) => {
|
|
3344
|
+
const showSuggestion = cv.suggestionMode === 'on' && (cv.selectType || 'default') === 'default';
|
|
3345
|
+
const isMultiSuggestion = cv.suggestionType === 'multi';
|
|
3346
|
+
return {
|
|
3347
|
+
selectType: cv.selectType || 'default',
|
|
3348
|
+
initial: cv.initial || 'empty',
|
|
3349
|
+
optionMode: cv.optionMode || 'few',
|
|
3350
|
+
disabled: cv.state === 'disabled',
|
|
3351
|
+
aiSuggestion: showSuggestion && !isMultiSuggestion ? SELECT_AI_SINGLE_SUGGESTIONS[0] : undefined,
|
|
3352
|
+
aiSuggestions: showSuggestion && isMultiSuggestion ? SELECT_AI_MULTI_SUGGESTION_GROUPS[0] : undefined,
|
|
3353
|
+
};
|
|
3354
|
+
},
|
|
3355
|
+
|
|
3356
|
+
generateUsage: (enums, cv) => {
|
|
3357
|
+
const lines = [`import Select from './components/Select';`];
|
|
3358
|
+
const props = [];
|
|
3359
|
+
const selectType = cv.selectType || 'default';
|
|
3360
|
+
const isTagSelect = selectType === 'tag';
|
|
3361
|
+
const showSuggestion = cv.suggestionMode === 'on' && !isTagSelect;
|
|
3362
|
+
const isMultiSuggestion = cv.suggestionType === 'multi';
|
|
3363
|
+
if (enums.status && enums.status !== 'default') props.push(`status="${enums.status}"`);
|
|
3364
|
+
if (isTagSelect) props.push('mode="tag"');
|
|
3365
|
+
if (cv.initial === 'selected') {
|
|
3366
|
+
props.push(isTagSelect ? 'defaultValue={["brand", "risk"]}' : 'defaultValue="js"');
|
|
3367
|
+
}
|
|
3368
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3369
|
+
props.push('allowClear');
|
|
3370
|
+
if (showSuggestion && !isMultiSuggestion) {
|
|
3371
|
+
props.push('aiSuggestion="江苏省"');
|
|
3372
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
3373
|
+
}
|
|
3374
|
+
if (showSuggestion && isMultiSuggestion) {
|
|
3375
|
+
props.push('aiSuggestions={["江苏省", "上海市", "浙江省"]}');
|
|
3376
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
3377
|
+
}
|
|
3378
|
+
props.push('placeholder="请选择"');
|
|
3379
|
+
lines.push('');
|
|
3380
|
+
lines.push('const options = [');
|
|
3381
|
+
if (isTagSelect) {
|
|
3382
|
+
lines.push(" { value: 'brand', label: '标签', variant: 'grey' },");
|
|
3383
|
+
lines.push(" { value: 'risk', label: '标签', variant: 'grey' },");
|
|
3384
|
+
lines.push(" { value: 'service', label: '标签', variant: 'grey' },");
|
|
3385
|
+
} else {
|
|
3386
|
+
lines.push(" { value: 'zj', label: '浙江省' },");
|
|
3387
|
+
lines.push(" { value: 'js', label: '江苏省' },");
|
|
3388
|
+
lines.push(" { value: 'sh', label: '上海市' },");
|
|
3389
|
+
}
|
|
3390
|
+
lines.push('];');
|
|
3391
|
+
lines.push('');
|
|
3392
|
+
lines.push('<Select');
|
|
3393
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3394
|
+
lines.push(' options={options}');
|
|
3395
|
+
lines.push(' onChange={(value, option) => {}}');
|
|
3396
|
+
lines.push('/>');
|
|
3397
|
+
return lines.join('\n');
|
|
3398
|
+
},
|
|
3399
|
+
},
|
|
3400
|
+
|
|
3401
|
+
switch: {
|
|
3402
|
+
component: SwitchPreview,
|
|
3403
|
+
tokenMap: SWITCH_TOKEN_MAP,
|
|
3404
|
+
jsxSource: switchJsxRaw,
|
|
3405
|
+
|
|
3406
|
+
controls: [
|
|
3407
|
+
{
|
|
3408
|
+
id: 'initial',
|
|
3409
|
+
label: '初始状态',
|
|
3410
|
+
type: 'seg',
|
|
3411
|
+
options: [
|
|
3412
|
+
{ id: 'off', label: '关' },
|
|
3413
|
+
{ id: 'on', label: '开' },
|
|
3414
|
+
],
|
|
3415
|
+
default: 'off',
|
|
3416
|
+
},
|
|
3417
|
+
{
|
|
3418
|
+
id: 'state',
|
|
3419
|
+
label: '交互',
|
|
3420
|
+
type: 'seg',
|
|
3421
|
+
options: [
|
|
3422
|
+
{ id: 'default', label: '可点' },
|
|
3423
|
+
{ id: 'disabled', label: '禁用' },
|
|
3424
|
+
],
|
|
3425
|
+
default: 'default',
|
|
3426
|
+
},
|
|
3427
|
+
],
|
|
3428
|
+
|
|
3429
|
+
mapProps: (cv) => ({
|
|
3430
|
+
defaultChecked: cv.initial === 'on',
|
|
3431
|
+
disabled: cv.state === 'disabled',
|
|
3432
|
+
}),
|
|
3433
|
+
|
|
3434
|
+
generateUsage: (enums, cv) => {
|
|
3435
|
+
const lines = [`import Switch from './components/Switch';`];
|
|
3436
|
+
const props = [];
|
|
3437
|
+
if (enums.variant && enums.variant !== 'brand') props.push(`variant="${enums.variant}"`);
|
|
3438
|
+
if (cv.initial === 'on') props.push('defaultChecked');
|
|
3439
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
3440
|
+
lines.push('');
|
|
3441
|
+
lines.push('<Switch');
|
|
3442
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3443
|
+
lines.push('/>');
|
|
3444
|
+
return lines.join('\n');
|
|
3445
|
+
},
|
|
3446
|
+
},
|
|
3447
|
+
|
|
3448
|
+
slider: {
|
|
3449
|
+
component: SliderPreview,
|
|
3450
|
+
tokenMap: SLIDER_TOKEN_MAP,
|
|
3451
|
+
jsxSource: sliderJsxRaw,
|
|
3452
|
+
|
|
3453
|
+
controls: buildSliderPreviewControls(),
|
|
3454
|
+
|
|
3455
|
+
normalizeControlValues: ({ changedControlId, nextControlValues, prevControlValues }) => (
|
|
3456
|
+
normalizeSliderPreviewControls(nextControlValues, prevControlValues, changedControlId)
|
|
3457
|
+
),
|
|
3458
|
+
|
|
3459
|
+
mapProps: (cv) => ({
|
|
3460
|
+
...buildSliderPreviewProps(cv),
|
|
3461
|
+
}),
|
|
3462
|
+
|
|
3463
|
+
generateUsage: (enums, cv) => {
|
|
3464
|
+
const lines = [`import Slider from './components/Slider';`];
|
|
3465
|
+
const sliderProps = buildSliderPreviewProps(cv);
|
|
3466
|
+
const props = [];
|
|
3467
|
+
|
|
3468
|
+
if (sliderProps.min !== SLIDER_PREVIEW_DEFAULTS.min) props.push(`min={${sliderProps.min}}`);
|
|
3469
|
+
if (sliderProps.max !== SLIDER_PREVIEW_DEFAULTS.max) props.push(`max={${sliderProps.max}}`);
|
|
3470
|
+
if (sliderProps.step !== SLIDER_PREVIEW_DEFAULTS.step) props.push(`step={${sliderProps.step}}`);
|
|
3471
|
+
props.push(`defaultValue={${formatUsageLiteral(sliderProps.defaultValue)}}`);
|
|
3472
|
+
if (sliderProps.showTooltip === false) props.push('showTooltip={false}');
|
|
3473
|
+
if (sliderProps.marks) props.push(`marks={${formatUsageLiteral(sliderProps.marks)}}`);
|
|
3474
|
+
if (sliderProps.disabled) props.push('disabled');
|
|
3475
|
+
props.push('onChange={(value) => {}}');
|
|
3476
|
+
props.push('onAfterChange={(value) => {}}');
|
|
3477
|
+
|
|
3478
|
+
lines.push('');
|
|
3479
|
+
lines.push('<Slider');
|
|
3480
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3481
|
+
lines.push('/>');
|
|
3482
|
+
return lines.join('\n');
|
|
3483
|
+
},
|
|
3484
|
+
},
|
|
3485
|
+
|
|
3486
|
+
modal: {
|
|
3487
|
+
component: Modal,
|
|
3488
|
+
tokenMap: MODAL_TOKEN_MAP,
|
|
3489
|
+
jsxSource: modalJsxRaw,
|
|
3490
|
+
|
|
3491
|
+
controls: [
|
|
3492
|
+
{
|
|
3493
|
+
id: 'subtitleMode',
|
|
3494
|
+
label: '副标题',
|
|
3495
|
+
type: 'seg',
|
|
3496
|
+
options: [
|
|
3497
|
+
{ id: 'on', label: '显示' },
|
|
3498
|
+
{ id: 'off', label: '隐藏' },
|
|
3499
|
+
],
|
|
3500
|
+
default: 'on',
|
|
3501
|
+
},
|
|
3502
|
+
{
|
|
3503
|
+
id: 'footerHintMode',
|
|
3504
|
+
label: '底部提示',
|
|
3505
|
+
type: 'seg',
|
|
3506
|
+
options: [
|
|
3507
|
+
{ id: 'on', label: '显示' },
|
|
3508
|
+
{ id: 'off', label: '隐藏' },
|
|
3509
|
+
],
|
|
3510
|
+
default: 'on',
|
|
3511
|
+
},
|
|
3512
|
+
],
|
|
3513
|
+
|
|
3514
|
+
mapProps: (cv, enums) => {
|
|
3515
|
+
const layout = enums?.layout || 'center';
|
|
3516
|
+
return {
|
|
3517
|
+
layout,
|
|
3518
|
+
size: enums?.size || 'md',
|
|
3519
|
+
subtitle: cv.subtitleMode === 'off' ? null : '模态副标题',
|
|
3520
|
+
showFooterHint: cv.footerHintMode !== 'off',
|
|
3521
|
+
/* fullscreen 变体需要 mt-auto 停靠底部,通过 className 注入 */
|
|
3522
|
+
className: layout === 'fullscreen' ? 'mt-auto' : '',
|
|
3523
|
+
onClose: () => {},
|
|
3524
|
+
onCancel: () => {},
|
|
3525
|
+
onConfirm: () => {},
|
|
3526
|
+
};
|
|
3527
|
+
},
|
|
3528
|
+
|
|
3529
|
+
/* center → 按 size 给定固定宽度,高度自适应
|
|
3530
|
+
* fullscreen → previewArea 改为 flex-col,scaler 撑满区域高度,
|
|
3531
|
+
* Modal 作为 scaler 的直接 flex 子元素、mt-auto 停靠底部,
|
|
3532
|
+
* max-h-[calc(100%-24px)] 此时可正确计算(parent = scaler 有定高)*/
|
|
3533
|
+
getPreviewItemStyle: ({ enumValues } = {}) => {
|
|
3534
|
+
if ((enumValues?.layout || 'center') === 'fullscreen') {
|
|
3535
|
+
return null; // Modal 直接作为 scaler 子节点,无需额外 wrapper
|
|
3536
|
+
}
|
|
3537
|
+
const widthMap = { sm: 450, md: 684, lg: 920 };
|
|
3538
|
+
const w = widthMap[enumValues?.size] || widthMap.md;
|
|
3539
|
+
return { width: `${w}px`, maxWidth: '100%' };
|
|
3540
|
+
},
|
|
3541
|
+
|
|
3542
|
+
getPreviewAreaStyle: ({ enumValues } = {}) => {
|
|
3543
|
+
if ((enumValues?.layout || 'center') === 'fullscreen') {
|
|
3544
|
+
return { padding: 0, display: 'flex', flexDirection: 'column', alignItems: 'stretch', overflow: 'hidden' };
|
|
3545
|
+
}
|
|
3546
|
+
return {};
|
|
3547
|
+
},
|
|
3548
|
+
|
|
3549
|
+
getPreviewScalerStyle: ({ enumValues } = {}) => {
|
|
3550
|
+
if ((enumValues?.layout || 'center') === 'fullscreen') {
|
|
3551
|
+
return {
|
|
3552
|
+
alignSelf: 'stretch',
|
|
3553
|
+
flex: 1,
|
|
3554
|
+
display: 'flex',
|
|
3555
|
+
flexDirection: 'column',
|
|
3556
|
+
alignItems: 'stretch',
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
return {};
|
|
3560
|
+
},
|
|
3561
|
+
|
|
3562
|
+
generateUsage: (enums, cv) => {
|
|
3563
|
+
const lines = [`import Modal from './components/Modal';`];
|
|
3564
|
+
const layout = enums?.layout || 'center';
|
|
3565
|
+
const sub = cv.subtitleMode === 'off';
|
|
3566
|
+
const noHint = cv.footerHintMode === 'off';
|
|
3567
|
+
lines.push('');
|
|
3568
|
+
if (layout === 'fullscreen') {
|
|
3569
|
+
lines.push('/* 外层须是 flex-col 定高容器,面板通过 mt-auto 停靠底部 */');
|
|
3570
|
+
lines.push('<div className="fixed inset-0 flex flex-col">');
|
|
3571
|
+
lines.push(' <Modal');
|
|
3572
|
+
lines.push(' layout="fullscreen"');
|
|
3573
|
+
lines.push(' title="模态标题"');
|
|
3574
|
+
lines.push(sub ? ' subtitle={null}' : ' subtitle="模态副标题"');
|
|
3575
|
+
if (noHint) lines.push(' showFooterHint={false}');
|
|
3576
|
+
lines.push(' className="mt-auto"');
|
|
3577
|
+
lines.push(' onClose={() => {}}');
|
|
3578
|
+
lines.push(' onCancel={() => {}}');
|
|
3579
|
+
lines.push(' onConfirm={() => {}}');
|
|
3580
|
+
lines.push(' >');
|
|
3581
|
+
lines.push(' {/* 内容区域 */}');
|
|
3582
|
+
lines.push(' </Modal>');
|
|
3583
|
+
lines.push('</div>');
|
|
3584
|
+
} else {
|
|
3585
|
+
lines.push('<Modal');
|
|
3586
|
+
if (enums.size && enums.size !== 'md') lines.push(` size="${enums.size}"`);
|
|
3587
|
+
lines.push(' title="模态标题"');
|
|
3588
|
+
lines.push(sub ? ' subtitle={null}' : ' subtitle="模态副标题"');
|
|
3589
|
+
if (noHint) lines.push(' showFooterHint={false}');
|
|
3590
|
+
lines.push(' onClose={() => {}}');
|
|
3591
|
+
lines.push(' onCancel={() => {}}');
|
|
3592
|
+
lines.push(' onConfirm={() => {}}');
|
|
3593
|
+
lines.push('>');
|
|
3594
|
+
lines.push(' {/* 内容区域 */}');
|
|
3595
|
+
lines.push('</Modal>');
|
|
3596
|
+
}
|
|
3597
|
+
return lines.join('\n');
|
|
3598
|
+
},
|
|
3599
|
+
},
|
|
3600
|
+
sheet: {
|
|
3601
|
+
component: Sheet,
|
|
3602
|
+
tokenMap: SHEET_TOKEN_MAP,
|
|
3603
|
+
jsxSource: sheetJsxRaw,
|
|
3604
|
+
|
|
3605
|
+
controls: [
|
|
3606
|
+
{
|
|
3607
|
+
id: 'subtitleMode',
|
|
3608
|
+
label: '副标题',
|
|
3609
|
+
type: 'seg',
|
|
3610
|
+
options: [
|
|
3611
|
+
{ id: 'on', label: '显示' },
|
|
3612
|
+
{ id: 'off', label: '隐藏' },
|
|
3613
|
+
],
|
|
3614
|
+
default: 'on',
|
|
3615
|
+
},
|
|
3616
|
+
{
|
|
3617
|
+
id: 'footerHintMode',
|
|
3618
|
+
label: '底部提示',
|
|
3619
|
+
type: 'seg',
|
|
3620
|
+
options: [
|
|
3621
|
+
{ id: 'on', label: '显示' },
|
|
3622
|
+
{ id: 'off', label: '隐藏' },
|
|
3623
|
+
],
|
|
3624
|
+
default: 'on',
|
|
3625
|
+
},
|
|
3626
|
+
],
|
|
3627
|
+
|
|
3628
|
+
mapProps: (cv, enums) => ({
|
|
3629
|
+
size: enums?.size || 'md',
|
|
3630
|
+
subtitle: cv.subtitleMode === 'off' ? null : '侧边副标题',
|
|
3631
|
+
showFooterHint: cv.footerHintMode !== 'off',
|
|
3632
|
+
onClose: () => {},
|
|
3633
|
+
onCancel: () => {},
|
|
3634
|
+
onConfirm: () => {},
|
|
3635
|
+
}),
|
|
3636
|
+
|
|
3637
|
+
getPreviewAreaStyle: () => ({
|
|
3638
|
+
padding: 0,
|
|
3639
|
+
alignItems: 'stretch',
|
|
3640
|
+
justifyContent: 'flex-end',
|
|
3641
|
+
}),
|
|
3642
|
+
|
|
3643
|
+
getPreviewScalerStyle: () => ({
|
|
3644
|
+
alignSelf: 'stretch',
|
|
3645
|
+
display: 'flex',
|
|
3646
|
+
alignItems: 'stretch',
|
|
3647
|
+
justifyContent: 'flex-end',
|
|
3648
|
+
transformOrigin: 'right top',
|
|
3649
|
+
}),
|
|
3650
|
+
|
|
3651
|
+
getPreviewItemStyle: ({ enumValues } = {}) => {
|
|
3652
|
+
const widthMap = { sm: 400, md: 560, lg: 800 };
|
|
3653
|
+
const w = widthMap[enumValues?.size] || widthMap.md;
|
|
3654
|
+
return { width: `${w}px`, maxWidth: '100%', alignSelf: 'stretch' };
|
|
3655
|
+
},
|
|
3656
|
+
|
|
3657
|
+
generateUsage: (enums, cv) => {
|
|
3658
|
+
const lines = [`import Sheet from './components/Sheet';`];
|
|
3659
|
+
const sub = cv.subtitleMode === 'off';
|
|
3660
|
+
const noHint = cv.footerHintMode === 'off';
|
|
3661
|
+
lines.push('');
|
|
3662
|
+
lines.push('<Sheet');
|
|
3663
|
+
if (enums.size && enums.size !== 'md') lines.push(` size="${enums.size}"`);
|
|
3664
|
+
lines.push(' title="侧边标题"');
|
|
3665
|
+
lines.push(sub ? ' subtitle={null}' : ' subtitle="侧边副标题"');
|
|
3666
|
+
if (noHint) lines.push(' showFooterHint={false}');
|
|
3667
|
+
lines.push(' onClose={() => {}}');
|
|
3668
|
+
lines.push(' onCancel={() => {}}');
|
|
3669
|
+
lines.push(' onConfirm={() => {}}');
|
|
3670
|
+
lines.push('>');
|
|
3671
|
+
lines.push(' {/* 内容区域 */}');
|
|
3672
|
+
lines.push('</Sheet>');
|
|
3673
|
+
return lines.join('\n');
|
|
3674
|
+
},
|
|
3675
|
+
},
|
|
3676
|
+
upload: {
|
|
3677
|
+
component: Upload,
|
|
3678
|
+
tokenMap: UPLOAD_TOKEN_MAP,
|
|
3679
|
+
jsxSource: uploadJsxRaw,
|
|
3680
|
+
|
|
3681
|
+
controls: [
|
|
3682
|
+
{
|
|
3683
|
+
id: 'content',
|
|
3684
|
+
label: '内容',
|
|
3685
|
+
type: 'seg',
|
|
3686
|
+
options: [
|
|
3687
|
+
{ id: 'empty', label: '无图' },
|
|
3688
|
+
{ id: 'filled', label: '有图' },
|
|
3689
|
+
],
|
|
3690
|
+
default: 'filled',
|
|
3691
|
+
},
|
|
3692
|
+
{
|
|
3693
|
+
id: 'state',
|
|
3694
|
+
label: '状态',
|
|
3695
|
+
type: 'seg',
|
|
3696
|
+
options: [
|
|
3697
|
+
{ id: 'default', label: '默认' },
|
|
3698
|
+
{ id: 'hover', label: '悬浮' },
|
|
3699
|
+
{ id: 'uploading', label: '上传中' },
|
|
3700
|
+
{ id: 'error', label: '异常' },
|
|
3701
|
+
{ id: 'disabled', label: '禁用' },
|
|
3702
|
+
],
|
|
3703
|
+
default: 'default',
|
|
3704
|
+
},
|
|
3705
|
+
],
|
|
3706
|
+
|
|
3707
|
+
mapProps: (cv) => {
|
|
3708
|
+
const state = cv.state || 'default';
|
|
3709
|
+
const content = cv.content || 'filled';
|
|
3710
|
+
const disabled = state === 'disabled';
|
|
3711
|
+
|
|
3712
|
+
const baseA = { uid: 'img-a', name: 'cover-a.png', url: UPLOAD_SAMPLE_IMAGE_A, status: 'done' };
|
|
3713
|
+
const baseB = { uid: 'img-b', name: 'cover-b.png', url: UPLOAD_SAMPLE_IMAGE_B, status: 'done' };
|
|
3714
|
+
|
|
3715
|
+
let previewList = [];
|
|
3716
|
+
if (content !== 'empty') {
|
|
3717
|
+
if (state === 'uploading') {
|
|
3718
|
+
previewList = [baseA, { ...baseB, status: 'uploading', percent: 56 }];
|
|
3719
|
+
} else if (state === 'error') {
|
|
3720
|
+
previewList = [baseA, { ...baseB, status: 'error' }];
|
|
3721
|
+
} else if (state === 'hover') {
|
|
3722
|
+
previewList = [{ ...baseA, showRemove: true }];
|
|
3723
|
+
} else {
|
|
3724
|
+
previewList = [baseA];
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
return {
|
|
3729
|
+
accept: 'image/*',
|
|
3730
|
+
multiple: true,
|
|
3731
|
+
limit: 3,
|
|
3732
|
+
disabled,
|
|
3733
|
+
defaultValue: previewList,
|
|
3734
|
+
__previewKey: `upload-${content}-${state}`,
|
|
3735
|
+
};
|
|
3736
|
+
},
|
|
3737
|
+
|
|
3738
|
+
generateUsage: (enums, cv) => {
|
|
3739
|
+
const lines = [`import Upload from './components/Upload';`];
|
|
3740
|
+
const state = cv.state || 'default';
|
|
3741
|
+
const content = cv.content || 'filled';
|
|
3742
|
+
const props = [];
|
|
3743
|
+
|
|
3744
|
+
props.push('accept="image/*"');
|
|
3745
|
+
props.push('multiple');
|
|
3746
|
+
props.push('limit={3}');
|
|
3747
|
+
|
|
3748
|
+
if (state === 'disabled') {
|
|
3749
|
+
props.push('disabled');
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
if (content === 'filled') {
|
|
3753
|
+
props.push(`defaultValue={[{ uid: 'img-1', name: 'cover.png', url: 'https://example.com/cover.png', status: 'done' }]}`);
|
|
3754
|
+
}
|
|
3755
|
+
|
|
3756
|
+
props.push('onChange={(fileList) => {}}');
|
|
3757
|
+
|
|
3758
|
+
lines.push('');
|
|
3759
|
+
lines.push('<Upload');
|
|
3760
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3761
|
+
lines.push('/>');
|
|
3762
|
+
return lines.join('\n');
|
|
3763
|
+
},
|
|
3764
|
+
},
|
|
3765
|
+
|
|
3766
|
+
'date-picker': {
|
|
3767
|
+
component: DatePicker,
|
|
3768
|
+
tokenMap: DATEPICKER_TOKEN_MAP,
|
|
3769
|
+
jsxSource: datePickerJsxRaw,
|
|
3770
|
+
|
|
3771
|
+
getPreviewItemStyle: ({ controlValues }) => {
|
|
3772
|
+
const type = controlValues.previewType || 'date';
|
|
3773
|
+
const isOpen = controlValues.panel !== 'closed';
|
|
3774
|
+
const panelHeight = (type === 'datetime' || type === 'datetimerange') ? 348 : 312;
|
|
3775
|
+
const panelGap = 4;
|
|
3776
|
+
|
|
3777
|
+
if (isOpen) {
|
|
3778
|
+
return {
|
|
3779
|
+
transform: `translateY(-${Math.round((panelHeight + panelGap) / 2)}px)`,
|
|
3780
|
+
transition: 'transform 180ms ease',
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
return {
|
|
3785
|
+
transform: 'translateY(-56px)',
|
|
3786
|
+
transition: 'transform 180ms ease',
|
|
3787
|
+
};
|
|
3788
|
+
},
|
|
3789
|
+
|
|
3790
|
+
controls: [
|
|
3791
|
+
{
|
|
3792
|
+
id: 'previewType',
|
|
3793
|
+
label: '类型',
|
|
3794
|
+
type: 'seg',
|
|
3795
|
+
options: [
|
|
3796
|
+
{ id: 'date', label: '日期' },
|
|
3797
|
+
{ id: 'datetime', label: '日期时间' },
|
|
3798
|
+
{ id: 'daterange', label: '日期范围' },
|
|
3799
|
+
{ id: 'datetimerange', label: '日期时间范围' },
|
|
3800
|
+
],
|
|
3801
|
+
default: 'date',
|
|
3802
|
+
},
|
|
3803
|
+
{
|
|
3804
|
+
id: 'valueState',
|
|
3805
|
+
label: '内容',
|
|
3806
|
+
type: 'seg',
|
|
3807
|
+
options: [
|
|
3808
|
+
{ id: 'empty', label: '无值' },
|
|
3809
|
+
{ id: 'filled', label: '有值' },
|
|
3810
|
+
],
|
|
3811
|
+
default: 'empty',
|
|
3812
|
+
},
|
|
3813
|
+
{
|
|
3814
|
+
id: 'state',
|
|
3815
|
+
label: '状态',
|
|
3816
|
+
type: 'seg',
|
|
3817
|
+
options: [
|
|
3818
|
+
{ id: 'default', label: '默认' },
|
|
3819
|
+
{ id: 'disabled', label: '禁用' },
|
|
3820
|
+
],
|
|
3821
|
+
default: 'default',
|
|
3822
|
+
},
|
|
3823
|
+
{
|
|
3824
|
+
id: 'panel',
|
|
3825
|
+
label: '面板',
|
|
3826
|
+
type: 'seg',
|
|
3827
|
+
options: [
|
|
3828
|
+
{ id: 'open', label: '展开' },
|
|
3829
|
+
{ id: 'closed', label: '收起' },
|
|
3830
|
+
],
|
|
3831
|
+
default: 'open',
|
|
3832
|
+
},
|
|
3833
|
+
],
|
|
3834
|
+
|
|
3835
|
+
mapProps: (cv) => {
|
|
3836
|
+
const type = cv.previewType || 'date';
|
|
3837
|
+
const isFilled = cv.valueState === 'filled';
|
|
3838
|
+
return {
|
|
3839
|
+
type,
|
|
3840
|
+
disabled: cv.state === 'disabled',
|
|
3841
|
+
value: isFilled ? DATEPICKER_SAMPLE_VALUE[type] : undefined,
|
|
3842
|
+
defaultOpen: cv.panel !== 'closed',
|
|
3843
|
+
};
|
|
3844
|
+
},
|
|
3845
|
+
|
|
3846
|
+
generateUsage: (enums, cv) => {
|
|
3847
|
+
const lines = [`import DatePicker from './components/DatePicker';`];
|
|
3848
|
+
const type = cv.previewType || enums.type || 'date';
|
|
3849
|
+
const isFilled = cv.valueState === 'filled';
|
|
3850
|
+
const props = [];
|
|
3851
|
+
|
|
3852
|
+
props.push(`type="${type}"`);
|
|
3853
|
+
|
|
3854
|
+
if (cv.state === 'disabled') {
|
|
3855
|
+
props.push('disabled');
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
if (cv.panel !== 'closed') {
|
|
3859
|
+
props.push('defaultOpen');
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
if (isFilled) {
|
|
3863
|
+
const sample = DATEPICKER_SAMPLE_VALUE[type];
|
|
3864
|
+
if (Array.isArray(sample)) {
|
|
3865
|
+
props.push(`defaultValue={["${sample[0]}", "${sample[1]}"]}`);
|
|
3866
|
+
} else {
|
|
3867
|
+
props.push(`defaultValue="${sample}"`);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
lines.push('');
|
|
3872
|
+
lines.push('<DatePicker');
|
|
3873
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3874
|
+
lines.push('/>');
|
|
3875
|
+
return lines.join('\n');
|
|
3876
|
+
},
|
|
3877
|
+
},
|
|
3878
|
+
|
|
3879
|
+
'time-picker': {
|
|
3880
|
+
component: TimePicker,
|
|
3881
|
+
tokenMap: TIMEPICKER_TOKEN_MAP,
|
|
3882
|
+
jsxSource: timePickerJsxRaw,
|
|
3883
|
+
|
|
3884
|
+
getPreviewItemStyle: ({ controlValues }) => {
|
|
3885
|
+
const type = controlValues.previewType || 'time';
|
|
3886
|
+
const isOpen = controlValues.panel !== 'closed';
|
|
3887
|
+
const panelHeight = type === 'timerange' ? 304 : 252;
|
|
3888
|
+
const panelGap = 4;
|
|
3889
|
+
|
|
3890
|
+
if (isOpen) {
|
|
3891
|
+
return {
|
|
3892
|
+
transform: `translateY(-${Math.round((panelHeight + panelGap) / 2)}px)`,
|
|
3893
|
+
transition: 'transform 180ms ease',
|
|
3894
|
+
};
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3897
|
+
return {
|
|
3898
|
+
transform: 'translateY(-56px)',
|
|
3899
|
+
transition: 'transform 180ms ease',
|
|
3900
|
+
};
|
|
3901
|
+
},
|
|
3902
|
+
|
|
3903
|
+
controls: [
|
|
3904
|
+
{
|
|
3905
|
+
id: 'previewType',
|
|
3906
|
+
label: '类型',
|
|
3907
|
+
type: 'seg',
|
|
3908
|
+
options: [
|
|
3909
|
+
{ id: 'time', label: '时间' },
|
|
3910
|
+
{ id: 'timerange', label: '时间范围' },
|
|
3911
|
+
],
|
|
3912
|
+
default: 'time',
|
|
3913
|
+
},
|
|
3914
|
+
{
|
|
3915
|
+
id: 'valueState',
|
|
3916
|
+
label: '内容',
|
|
3917
|
+
type: 'seg',
|
|
3918
|
+
options: [
|
|
3919
|
+
{ id: 'empty', label: '无值' },
|
|
3920
|
+
{ id: 'filled', label: '有值' },
|
|
3921
|
+
],
|
|
3922
|
+
default: 'empty',
|
|
3923
|
+
},
|
|
3924
|
+
{
|
|
3925
|
+
id: 'state',
|
|
3926
|
+
label: '状态',
|
|
3927
|
+
type: 'seg',
|
|
3928
|
+
options: [
|
|
3929
|
+
{ id: 'default', label: '默认' },
|
|
3930
|
+
{ id: 'disabled', label: '禁用' },
|
|
3931
|
+
],
|
|
3932
|
+
default: 'default',
|
|
3933
|
+
},
|
|
3934
|
+
{
|
|
3935
|
+
id: 'panel',
|
|
3936
|
+
label: '面板',
|
|
3937
|
+
type: 'seg',
|
|
3938
|
+
options: [
|
|
3939
|
+
{ id: 'open', label: '展开' },
|
|
3940
|
+
{ id: 'closed', label: '收起' },
|
|
3941
|
+
],
|
|
3942
|
+
default: 'open',
|
|
3943
|
+
},
|
|
3944
|
+
],
|
|
3945
|
+
|
|
3946
|
+
mapProps: (cv) => {
|
|
3947
|
+
const type = cv.previewType || 'time';
|
|
3948
|
+
const isFilled = cv.valueState === 'filled';
|
|
3949
|
+
return {
|
|
3950
|
+
type,
|
|
3951
|
+
disabled: cv.state === 'disabled',
|
|
3952
|
+
defaultValue: isFilled ? TIMEPICKER_SAMPLE_VALUE[type] : undefined,
|
|
3953
|
+
defaultOpen: cv.panel !== 'closed',
|
|
3954
|
+
};
|
|
3955
|
+
},
|
|
3956
|
+
|
|
3957
|
+
generateUsage: (enums, cv) => {
|
|
3958
|
+
const lines = [`import TimePicker from './components/TimePicker';`];
|
|
3959
|
+
const type = cv.previewType || enums.type || 'time';
|
|
3960
|
+
const isFilled = cv.valueState === 'filled';
|
|
3961
|
+
const props = [];
|
|
3962
|
+
|
|
3963
|
+
props.push(`type="${type}"`);
|
|
3964
|
+
|
|
3965
|
+
if (cv.state === 'disabled') {
|
|
3966
|
+
props.push('disabled');
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
if (cv.panel !== 'closed') {
|
|
3970
|
+
props.push('defaultOpen');
|
|
3971
|
+
}
|
|
3972
|
+
|
|
3973
|
+
if (isFilled) {
|
|
3974
|
+
const sample = TIMEPICKER_SAMPLE_VALUE[type];
|
|
3975
|
+
if (Array.isArray(sample)) {
|
|
3976
|
+
props.push(`defaultValue={["${sample[0]}", "${sample[1]}"]}`);
|
|
3977
|
+
} else {
|
|
3978
|
+
props.push(`defaultValue="${sample}"`);
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
lines.push('');
|
|
3983
|
+
lines.push('<TimePicker');
|
|
3984
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
3985
|
+
lines.push('/>');
|
|
3986
|
+
return lines.join('\n');
|
|
3987
|
+
},
|
|
3988
|
+
},
|
|
3989
|
+
|
|
3990
|
+
'tag-input': {
|
|
3991
|
+
component: TagInputPreview,
|
|
3992
|
+
tokenMap: TAGINPUT_TOKEN_MAP,
|
|
3993
|
+
jsxSource: tagInputJsxRaw,
|
|
3994
|
+
|
|
3995
|
+
getPreviewAreaStyle: () => ({
|
|
3996
|
+
alignItems: 'flex-start',
|
|
3997
|
+
justifyContent: 'center',
|
|
3998
|
+
overflow: 'auto',
|
|
3999
|
+
paddingTop: '96px',
|
|
4000
|
+
}),
|
|
4001
|
+
|
|
4002
|
+
getPreviewItemStyle: () => ({
|
|
4003
|
+
width: '100%',
|
|
4004
|
+
display: 'flex',
|
|
4005
|
+
justifyContent: 'center',
|
|
4006
|
+
alignItems: 'flex-start',
|
|
4007
|
+
flex: '0 0 auto',
|
|
4008
|
+
}),
|
|
4009
|
+
|
|
4010
|
+
controls: [
|
|
4011
|
+
{
|
|
4012
|
+
id: 'content',
|
|
4013
|
+
label: '内容',
|
|
4014
|
+
type: 'seg',
|
|
4015
|
+
options: [
|
|
4016
|
+
{ id: 'empty', label: '空' },
|
|
4017
|
+
{ id: 'filled', label: '有值' },
|
|
4018
|
+
],
|
|
4019
|
+
default: 'filled',
|
|
4020
|
+
},
|
|
4021
|
+
{
|
|
4022
|
+
id: 'widthMode',
|
|
4023
|
+
label: '宽度',
|
|
4024
|
+
type: 'seg',
|
|
4025
|
+
options: [
|
|
4026
|
+
{ id: 'default', label: '默认' },
|
|
4027
|
+
{ id: 'narrow', label: '窄' },
|
|
4028
|
+
{ id: 'wide', label: '宽' },
|
|
4029
|
+
],
|
|
4030
|
+
default: 'default',
|
|
4031
|
+
},
|
|
4032
|
+
{
|
|
4033
|
+
id: 'state',
|
|
4034
|
+
label: '交互',
|
|
4035
|
+
type: 'seg',
|
|
4036
|
+
options: [
|
|
4037
|
+
{ id: 'default', label: '可点' },
|
|
4038
|
+
{ id: 'disabled', label: '禁用' },
|
|
4039
|
+
],
|
|
4040
|
+
default: 'default',
|
|
4041
|
+
},
|
|
4042
|
+
{
|
|
4043
|
+
id: 'suggestionMode',
|
|
4044
|
+
label: 'AI推荐',
|
|
4045
|
+
type: 'seg',
|
|
4046
|
+
options: [
|
|
4047
|
+
{ id: 'off', label: '隐藏' },
|
|
4048
|
+
{ id: 'on', label: '显示' },
|
|
4049
|
+
],
|
|
4050
|
+
default: 'on',
|
|
4051
|
+
},
|
|
4052
|
+
],
|
|
4053
|
+
|
|
4054
|
+
mapProps: (cv, enums) => ({
|
|
4055
|
+
content: cv.content || 'filled',
|
|
4056
|
+
widthMode: cv.widthMode || 'default',
|
|
4057
|
+
disabled: cv.state === 'disabled',
|
|
4058
|
+
size: enums.size || 'md',
|
|
4059
|
+
status: enums.status || 'default',
|
|
4060
|
+
tagVariant: enums.tagVariant || 'grey',
|
|
4061
|
+
tagSize: enums.tagSize || 'm',
|
|
4062
|
+
showAiSuggestions: (cv.suggestionMode || 'on') === 'on',
|
|
4063
|
+
}),
|
|
4064
|
+
|
|
4065
|
+
generateUsage: (enums, cv) => {
|
|
4066
|
+
const lines = [`import TagInput from './components/TagInput';`];
|
|
4067
|
+
const content = cv.content || 'filled';
|
|
4068
|
+
const widthMode = cv.widthMode || 'default';
|
|
4069
|
+
const props = [];
|
|
4070
|
+
if (enums.status && enums.status !== 'default') props.push(`status="${enums.status}"`);
|
|
4071
|
+
if (enums.tagVariant && enums.tagVariant !== 'grey') props.push(`tagVariant="${enums.tagVariant}"`);
|
|
4072
|
+
if (enums.tagSize && enums.tagSize !== 'm') props.push(`tagSize="${enums.tagSize}"`);
|
|
4073
|
+
if (cv.state === 'disabled') props.push('disabled');
|
|
4074
|
+
if (widthMode === 'narrow') props.push('className="!w-[220px]"');
|
|
4075
|
+
if (widthMode === 'wide') props.push('className="!w-[420px]"');
|
|
4076
|
+
props.push('placeholder="请输入"');
|
|
4077
|
+
if (content === 'filled') {
|
|
4078
|
+
props.push('defaultValue={["标签", "标签", "标签", "标签", "标签", "标签"]}');
|
|
4079
|
+
}
|
|
4080
|
+
if ((cv.suggestionMode || 'on') === 'on') {
|
|
4081
|
+
props.push('aiSuggestions={[["改签", "门店变更"], ["退款", "售后处理"], ["物流异常", "催办"]]}');
|
|
4082
|
+
props.push('onRefreshAiSuggestions={() => {}}');
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
lines.push('');
|
|
4086
|
+
lines.push('<TagInput');
|
|
4087
|
+
props.forEach((p) => lines.push(` ${p}`));
|
|
4088
|
+
lines.push('/>');
|
|
4089
|
+
return lines.join('\n');
|
|
4090
|
+
},
|
|
4091
|
+
},
|
|
4092
|
+
|
|
4093
|
+
tag: {
|
|
4094
|
+
component: TagGridPreview,
|
|
4095
|
+
tokenMap: TAG_TOKEN_MAP,
|
|
4096
|
+
jsxSource: tagJsxRaw,
|
|
4097
|
+
|
|
4098
|
+
controls: [
|
|
4099
|
+
{
|
|
4100
|
+
id: 'fontWeight',
|
|
4101
|
+
label: '字体粗细',
|
|
4102
|
+
type: 'seg',
|
|
4103
|
+
options: [
|
|
4104
|
+
{ id: 'regular', label: '细体' },
|
|
4105
|
+
{ id: 'bold', label: '粗体' },
|
|
4106
|
+
],
|
|
4107
|
+
default: 'bold',
|
|
4108
|
+
},
|
|
4109
|
+
{
|
|
4110
|
+
id: 'radius',
|
|
4111
|
+
label: '圆角',
|
|
4112
|
+
type: 'seg',
|
|
4113
|
+
options: [
|
|
4114
|
+
{ id: 'md', label: '圆角' },
|
|
4115
|
+
{ id: 'full', label: '全圆' },
|
|
4116
|
+
],
|
|
4117
|
+
default: 'md',
|
|
4118
|
+
},
|
|
4119
|
+
{
|
|
4120
|
+
id: 'showIcon',
|
|
4121
|
+
label: '显示图标',
|
|
4122
|
+
type: 'seg',
|
|
4123
|
+
options: [
|
|
4124
|
+
{ id: 'off', label: '隐藏' },
|
|
4125
|
+
{ id: 'on', label: '显示' },
|
|
4126
|
+
],
|
|
4127
|
+
default: 'off',
|
|
4128
|
+
},
|
|
4129
|
+
{
|
|
4130
|
+
id: 'closable',
|
|
4131
|
+
label: '关闭按钮',
|
|
4132
|
+
type: 'seg',
|
|
4133
|
+
options: [
|
|
4134
|
+
{ id: 'off', label: '隐藏' },
|
|
4135
|
+
{ id: 'on', label: '显示' },
|
|
4136
|
+
],
|
|
4137
|
+
default: 'off',
|
|
4138
|
+
},
|
|
4139
|
+
],
|
|
4140
|
+
|
|
4141
|
+
mapProps: (cv, enums) => {
|
|
4142
|
+
const closable = cv.closable === 'on';
|
|
4143
|
+
const showIcon = cv.showIcon === 'on';
|
|
4144
|
+
const radius = cv.radius || 'md';
|
|
4145
|
+
return {
|
|
4146
|
+
showIcon,
|
|
4147
|
+
iconName: 'tag-01-stroked',
|
|
4148
|
+
closable,
|
|
4149
|
+
fontWeight: cv.fontWeight || 'bold',
|
|
4150
|
+
radius,
|
|
4151
|
+
variant: enums.variant,
|
|
4152
|
+
size: enums.size || 's',
|
|
4153
|
+
onClose: closable ? () => {} : undefined,
|
|
4154
|
+
};
|
|
4155
|
+
},
|
|
4156
|
+
|
|
4157
|
+
generateUsage: (enums, cv) => {
|
|
4158
|
+
const lines = [`import Tag from './components/Tag';`];
|
|
4159
|
+
const variant = enums.variant || 'brand';
|
|
4160
|
+
const size = enums.size || 's';
|
|
4161
|
+
const fontWeight = cv.fontWeight || 'bold';
|
|
4162
|
+
const radius = cv.radius || 'md';
|
|
4163
|
+
const showIcon = cv.showIcon === 'on';
|
|
4164
|
+
const closable = cv.closable === 'on';
|
|
4165
|
+
|
|
4166
|
+
lines.push('');
|
|
4167
|
+
lines.push('<Tag');
|
|
4168
|
+
if (variant !== 'brand') lines.push(` variant="${variant}"`);
|
|
4169
|
+
if (fontWeight !== 'bold') lines.push(` fontWeight="${fontWeight}"`);
|
|
4170
|
+
if (size !== 's') lines.push(` size="${size}"`);
|
|
4171
|
+
if (radius !== 'md') lines.push(` radius="${radius}"`);
|
|
4172
|
+
if (showIcon) lines.push(' showIcon');
|
|
4173
|
+
if (closable) lines.push(' closable');
|
|
4174
|
+
if (closable) lines.push(' onClose={() => {}}');
|
|
4175
|
+
lines.push('>');
|
|
4176
|
+
lines.push(' 标签');
|
|
4177
|
+
lines.push('</Tag>');
|
|
4178
|
+
return lines.join('\n');
|
|
4179
|
+
},
|
|
4180
|
+
},
|
|
4181
|
+
|
|
4182
|
+
table: {
|
|
4183
|
+
component: TablePreview,
|
|
4184
|
+
tokenMap: TABLE_TOKEN_MAP,
|
|
4185
|
+
jsxSource: tableJsxRaw,
|
|
4186
|
+
hideBaseVariantControl: true,
|
|
4187
|
+
|
|
4188
|
+
getPreviewAreaStyle: () => ({
|
|
4189
|
+
alignItems: 'stretch',
|
|
4190
|
+
justifyContent: 'flex-start',
|
|
4191
|
+
padding: '24px',
|
|
4192
|
+
overflow: 'auto',
|
|
4193
|
+
}),
|
|
4194
|
+
|
|
4195
|
+
getPreviewItemStyle: () => ({
|
|
4196
|
+
width: '100%',
|
|
4197
|
+
height: '100%',
|
|
4198
|
+
maxWidth: '100%',
|
|
4199
|
+
alignSelf: 'stretch',
|
|
4200
|
+
minWidth: '0',
|
|
4201
|
+
minHeight: '0',
|
|
4202
|
+
display: 'flex',
|
|
4203
|
+
}),
|
|
4204
|
+
|
|
4205
|
+
getPreviewScalerStyle: () => ({
|
|
4206
|
+
width: '100%',
|
|
4207
|
+
height: '100%',
|
|
4208
|
+
minWidth: '0',
|
|
4209
|
+
minHeight: '0',
|
|
4210
|
+
display: 'flex',
|
|
4211
|
+
flex: '1 1 auto',
|
|
4212
|
+
transformOrigin: 'top center',
|
|
4213
|
+
}),
|
|
4214
|
+
|
|
4215
|
+
controls: [
|
|
4216
|
+
{
|
|
4217
|
+
id: 'tableVariant',
|
|
4218
|
+
label: '表格类型',
|
|
4219
|
+
type: 'seg',
|
|
4220
|
+
options: TABLE_VARIANT_OPTIONS,
|
|
4221
|
+
default: 'table',
|
|
4222
|
+
},
|
|
4223
|
+
{
|
|
4224
|
+
id: 'paginationMode',
|
|
4225
|
+
label: '分页',
|
|
4226
|
+
type: 'seg',
|
|
4227
|
+
options: [
|
|
4228
|
+
{ id: 'on', label: '显示' },
|
|
4229
|
+
{ id: 'off', label: '隐藏' },
|
|
4230
|
+
],
|
|
4231
|
+
default: 'on',
|
|
4232
|
+
},
|
|
4233
|
+
{
|
|
4234
|
+
id: 'pageSizeMode',
|
|
4235
|
+
label: '每页',
|
|
4236
|
+
type: 'seg',
|
|
4237
|
+
options: [
|
|
4238
|
+
{ id: '10', label: '10条' },
|
|
4239
|
+
{ id: '20', label: '20条' },
|
|
4240
|
+
],
|
|
4241
|
+
default: '20',
|
|
4242
|
+
hidden: ({ controlValues }) => (controlValues.paginationMode || 'on') === 'off',
|
|
4243
|
+
},
|
|
4244
|
+
{
|
|
4245
|
+
id: 'tableSize',
|
|
4246
|
+
label: '尺寸',
|
|
4247
|
+
type: 'seg',
|
|
4248
|
+
options: TABLE_CELL_SIZE_OPTIONS,
|
|
4249
|
+
default: 'default',
|
|
4250
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form',
|
|
4251
|
+
},
|
|
4252
|
+
{
|
|
4253
|
+
id: 'fixedColumnsMode',
|
|
4254
|
+
label: '固定栏',
|
|
4255
|
+
type: 'seg',
|
|
4256
|
+
options: [
|
|
4257
|
+
{ id: 'none', label: '不固定' },
|
|
4258
|
+
{ id: 'first', label: '固定第一栏' },
|
|
4259
|
+
{ id: 'last', label: '固定尾栏' },
|
|
4260
|
+
{ id: 'both', label: '首尾固定' },
|
|
4261
|
+
],
|
|
4262
|
+
default: 'none',
|
|
4263
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form',
|
|
4264
|
+
},
|
|
4265
|
+
{
|
|
4266
|
+
id: 'headerCount',
|
|
4267
|
+
label: '表头数量',
|
|
4268
|
+
type: 'seg',
|
|
4269
|
+
options: [
|
|
4270
|
+
{ id: '2', label: '2' },
|
|
4271
|
+
{ id: '3', label: '3' },
|
|
4272
|
+
{ id: '4', label: '4' },
|
|
4273
|
+
{ id: '5', label: '5' },
|
|
4274
|
+
{ id: '6', label: '6' },
|
|
4275
|
+
],
|
|
4276
|
+
default: '5',
|
|
4277
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form',
|
|
4278
|
+
},
|
|
4279
|
+
{
|
|
4280
|
+
id: 'activeColumn2',
|
|
4281
|
+
label: '当前列',
|
|
4282
|
+
type: 'list',
|
|
4283
|
+
options: Array.from({ length: 2 }, (_, index) => ({
|
|
4284
|
+
id: `column${index + 1}`,
|
|
4285
|
+
label: `第${index + 1}列`,
|
|
4286
|
+
})),
|
|
4287
|
+
default: 'column1',
|
|
4288
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form' || (controlValues.headerCount || '6') !== '2',
|
|
4289
|
+
},
|
|
4290
|
+
{
|
|
4291
|
+
id: 'activeColumn3',
|
|
4292
|
+
label: '当前列',
|
|
4293
|
+
type: 'list',
|
|
4294
|
+
options: Array.from({ length: 3 }, (_, index) => ({
|
|
4295
|
+
id: `column${index + 1}`,
|
|
4296
|
+
label: `第${index + 1}列`,
|
|
4297
|
+
})),
|
|
4298
|
+
default: 'column1',
|
|
4299
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form' || (controlValues.headerCount || '6') !== '3',
|
|
4300
|
+
},
|
|
4301
|
+
{
|
|
4302
|
+
id: 'activeColumn4',
|
|
4303
|
+
label: '当前列',
|
|
4304
|
+
type: 'list',
|
|
4305
|
+
options: Array.from({ length: 4 }, (_, index) => ({
|
|
4306
|
+
id: `column${index + 1}`,
|
|
4307
|
+
label: `第${index + 1}列`,
|
|
4308
|
+
})),
|
|
4309
|
+
default: 'column1',
|
|
4310
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form' || (controlValues.headerCount || '6') !== '4',
|
|
4311
|
+
},
|
|
4312
|
+
{
|
|
4313
|
+
id: 'activeColumn5',
|
|
4314
|
+
label: '当前列',
|
|
4315
|
+
type: 'list',
|
|
4316
|
+
options: Array.from({ length: 5 }, (_, index) => ({
|
|
4317
|
+
id: `column${index + 1}`,
|
|
4318
|
+
label: `第${index + 1}列`,
|
|
4319
|
+
})),
|
|
4320
|
+
default: 'column1',
|
|
4321
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form' || (controlValues.headerCount || '6') !== '5',
|
|
4322
|
+
},
|
|
4323
|
+
{
|
|
4324
|
+
id: 'activeColumn6',
|
|
4325
|
+
label: '当前列',
|
|
4326
|
+
type: 'list',
|
|
4327
|
+
options: Array.from({ length: 6 }, (_, index) => ({
|
|
4328
|
+
id: `column${index + 1}`,
|
|
4329
|
+
label: `第${index + 1}列`,
|
|
4330
|
+
})),
|
|
4331
|
+
default: 'column1',
|
|
4332
|
+
hidden: ({ controlValues }) => (controlValues.tableVariant || 'table') === 'card-form' || (controlValues.headerCount || '6') !== '6',
|
|
4333
|
+
},
|
|
4334
|
+
...Array.from({ length: 6 }, (_, index) => ([
|
|
4335
|
+
{
|
|
4336
|
+
id: `column${index + 1}Type`,
|
|
4337
|
+
label: '表单类型',
|
|
4338
|
+
type: 'list',
|
|
4339
|
+
options: TABLE_COLUMN_TYPE_OPTIONS,
|
|
4340
|
+
default: ['link', 'tag', 'text', 'avatar', 'datetime', 'actions'][index] || 'text',
|
|
4341
|
+
hidden: ({ controlValues }) => {
|
|
4342
|
+
if ((controlValues.tableVariant || 'table') === 'card-form') return true;
|
|
4343
|
+
const headerCount = controlValues.headerCount || '6';
|
|
4344
|
+
const activeColumn =
|
|
4345
|
+
controlValues[`activeColumn${headerCount}`] || 'column1';
|
|
4346
|
+
return Number(headerCount) < index + 1 || activeColumn !== `column${index + 1}`;
|
|
4347
|
+
},
|
|
4348
|
+
},
|
|
4349
|
+
])).flat(),
|
|
4350
|
+
],
|
|
4351
|
+
|
|
4352
|
+
mapProps: (cv) => ({
|
|
4353
|
+
tableVariant: cv.tableVariant || 'table',
|
|
4354
|
+
paginationMode: cv.paginationMode || 'on',
|
|
4355
|
+
pageSizeMode: cv.pageSizeMode || '20',
|
|
4356
|
+
tableSize: cv.tableSize || 'default',
|
|
4357
|
+
fixedColumnsMode: cv.fixedColumnsMode || 'none',
|
|
4358
|
+
headerCount: cv.headerCount || '5',
|
|
4359
|
+
column1Type: cv.column1Type || 'link',
|
|
4360
|
+
column2Type: cv.column2Type || 'tag',
|
|
4361
|
+
column3Type: cv.column3Type || 'text',
|
|
4362
|
+
column4Type: cv.column4Type || 'avatar',
|
|
4363
|
+
column5Type: cv.column5Type || 'datetime',
|
|
4364
|
+
column6Type: cv.column6Type || 'actions',
|
|
4365
|
+
}),
|
|
4366
|
+
|
|
4367
|
+
generateUsage: (_enumValues, controlValues) => buildTableUsageFromControls(controlValues),
|
|
4368
|
+
},
|
|
4369
|
+
|
|
4370
|
+
toast: {
|
|
4371
|
+
component: Toast,
|
|
4372
|
+
tokenMap: TOAST_TOKEN_MAP,
|
|
4373
|
+
jsxSource: toastJsxRaw,
|
|
4374
|
+
|
|
4375
|
+
controls: [
|
|
4376
|
+
{
|
|
4377
|
+
id: 'actions',
|
|
4378
|
+
label: '文字操作',
|
|
4379
|
+
type: 'seg',
|
|
4380
|
+
options: [
|
|
4381
|
+
{ id: 'none', label: '无' },
|
|
4382
|
+
{ id: 'single', label: '一项' },
|
|
4383
|
+
{ id: 'dual', label: '两项' },
|
|
4384
|
+
],
|
|
4385
|
+
default: 'none',
|
|
4386
|
+
},
|
|
4387
|
+
],
|
|
4388
|
+
|
|
4389
|
+
mapProps: (cv, enums) => {
|
|
4390
|
+
const type = enums.type || 'info';
|
|
4391
|
+
const messages = {
|
|
4392
|
+
info: '补充信息或状态切换',
|
|
4393
|
+
success: '表单保存成功',
|
|
4394
|
+
warning: '可能出现的错误',
|
|
4395
|
+
error: '已经出现的错误',
|
|
4396
|
+
};
|
|
4397
|
+
const showClose = enums.showClose !== false;
|
|
4398
|
+
const noop = () => {};
|
|
4399
|
+
const actions =
|
|
4400
|
+
cv.actions === 'dual'
|
|
4401
|
+
? [
|
|
4402
|
+
{ label: '操作1', onClick: noop },
|
|
4403
|
+
{ label: '操作2', onClick: noop },
|
|
4404
|
+
]
|
|
4405
|
+
: cv.actions === 'single'
|
|
4406
|
+
? [{ label: '操作1', onClick: noop }]
|
|
4407
|
+
: undefined;
|
|
4408
|
+
return {
|
|
4409
|
+
type,
|
|
4410
|
+
message: messages[type] || messages.info,
|
|
4411
|
+
bordered: enums.bordered !== false,
|
|
4412
|
+
showClose,
|
|
4413
|
+
onClose: showClose ? () => {} : undefined,
|
|
4414
|
+
actions,
|
|
4415
|
+
};
|
|
4416
|
+
},
|
|
4417
|
+
|
|
4418
|
+
generateUsage: (enums, cv) => {
|
|
4419
|
+
const type = enums.type || 'info';
|
|
4420
|
+
const messages = {
|
|
4421
|
+
info: '补充信息或状态切换',
|
|
4422
|
+
success: '表单保存成功',
|
|
4423
|
+
warning: '可能出现的错误',
|
|
4424
|
+
error: '已经出现的错误',
|
|
4425
|
+
};
|
|
4426
|
+
const msg = messages[type] || messages.info;
|
|
4427
|
+
const showClose = enums.showClose !== false;
|
|
4428
|
+
const bordered = enums.bordered !== false;
|
|
4429
|
+
const lines = [`import Toast from './components/Toast';`, ''];
|
|
4430
|
+
lines.push('<Toast');
|
|
4431
|
+
lines.push(` type="${type}"`);
|
|
4432
|
+
lines.push(` message="${msg}"`);
|
|
4433
|
+
if (cv.actions === 'single') {
|
|
4434
|
+
lines.push(` actions={[{ label: '操作1', onClick: () => {} }]}`);
|
|
4435
|
+
} else if (cv.actions === 'dual') {
|
|
4436
|
+
lines.push(' actions={[');
|
|
4437
|
+
lines.push(` { label: '操作1', onClick: () => {} },`);
|
|
4438
|
+
lines.push(` { label: '操作2', onClick: () => {} },`);
|
|
4439
|
+
lines.push(' ]}');
|
|
4440
|
+
}
|
|
4441
|
+
if (!bordered) lines.push(' bordered={false}');
|
|
4442
|
+
if (showClose) lines.push(' onClose={() => {}}');
|
|
4443
|
+
else lines.push(' showClose={false}');
|
|
4444
|
+
lines.push('/>');
|
|
4445
|
+
return lines.join('\n');
|
|
4446
|
+
},
|
|
4447
|
+
},
|
|
4448
|
+
|
|
4449
|
+
tooltip: {
|
|
4450
|
+
component: TooltipPreview,
|
|
4451
|
+
tokenMap: TOOLTIP_TOKEN_MAP,
|
|
4452
|
+
jsxSource: tooltipJsxRaw,
|
|
4453
|
+
|
|
4454
|
+
controls: [
|
|
4455
|
+
{
|
|
4456
|
+
id: 'mode',
|
|
4457
|
+
label: '展示模式',
|
|
4458
|
+
type: 'seg',
|
|
4459
|
+
options: [
|
|
4460
|
+
{ id: 'pinned', label: '常驻' },
|
|
4461
|
+
{ id: 'hover', label: '悬浮触发' },
|
|
4462
|
+
],
|
|
4463
|
+
default: 'pinned',
|
|
4464
|
+
},
|
|
4465
|
+
{
|
|
4466
|
+
id: 'contentLength',
|
|
4467
|
+
label: '内容长度',
|
|
4468
|
+
type: 'seg',
|
|
4469
|
+
options: [
|
|
4470
|
+
{ id: 'short', label: '短' },
|
|
4471
|
+
{ id: 'medium', label: '中' },
|
|
4472
|
+
{ id: 'long', label: '多行' },
|
|
4473
|
+
],
|
|
4474
|
+
default: 'long',
|
|
4475
|
+
},
|
|
4476
|
+
],
|
|
4477
|
+
|
|
4478
|
+
mapProps: (cv, enums) => {
|
|
4479
|
+
const contentMap = {
|
|
4480
|
+
short: '这是一段提示',
|
|
4481
|
+
medium: '提示信息:保存后无法撤销',
|
|
4482
|
+
long: '这是一段较长的多行提示文案。\n用于演示气泡最大宽度 280px 时的自动换行效果。',
|
|
4483
|
+
};
|
|
4484
|
+
return {
|
|
4485
|
+
placement: enums.placement || 'top',
|
|
4486
|
+
arrow: enums.arrow !== false,
|
|
4487
|
+
autoFlip: enums.autoFlip !== false,
|
|
4488
|
+
mode: cv.mode || 'pinned',
|
|
4489
|
+
content: contentMap[cv.contentLength] || contentMap.long,
|
|
4490
|
+
triggerLabel: '触发元素',
|
|
4491
|
+
};
|
|
4492
|
+
},
|
|
4493
|
+
|
|
4494
|
+
generateUsage: (enums, cv) => {
|
|
4495
|
+
const placement = enums.placement || 'top';
|
|
4496
|
+
const arrow = enums.arrow !== false;
|
|
4497
|
+
const autoFlip = enums.autoFlip !== false;
|
|
4498
|
+
const contentMap = {
|
|
4499
|
+
short: '这是一段提示',
|
|
4500
|
+
medium: '提示信息:保存后无法撤销',
|
|
4501
|
+
long: '这是一段较长的多行提示文案。\\n用于演示气泡最大宽度 280px 时的自动换行效果。',
|
|
4502
|
+
};
|
|
4503
|
+
const content = contentMap[cv.contentLength] || contentMap.long;
|
|
4504
|
+
|
|
4505
|
+
const lines = [`import Tooltip from './components/Tooltip';`];
|
|
4506
|
+
lines.push('');
|
|
4507
|
+
lines.push('<Tooltip');
|
|
4508
|
+
lines.push(` content={\`${content}\`}`);
|
|
4509
|
+
if (placement !== 'top') lines.push(` placement="${placement}"`);
|
|
4510
|
+
if (!arrow) lines.push(' arrow={false}');
|
|
4511
|
+
if (!autoFlip) lines.push(' autoFlip={false}');
|
|
4512
|
+
lines.push('>');
|
|
4513
|
+
lines.push(' <Button>悬浮我</Button>');
|
|
4514
|
+
lines.push('</Tooltip>');
|
|
4515
|
+
return lines.join('\n');
|
|
4516
|
+
},
|
|
4517
|
+
},
|
|
4518
|
+
|
|
4519
|
+
empty: {
|
|
4520
|
+
component: Empty,
|
|
4521
|
+
tokenMap: EMPTY_TOKEN_MAP,
|
|
4522
|
+
jsxSource: emptyJsxRaw,
|
|
4523
|
+
|
|
4524
|
+
// 场景示例:每种场景对应一套最自然的内容组合
|
|
4525
|
+
// buttonLayout 已是枚举 prop,在左侧面板直接切换,无需在 controls 重复
|
|
4526
|
+
controls: [
|
|
4527
|
+
{
|
|
4528
|
+
id: 'scenario',
|
|
4529
|
+
label: '场景示例',
|
|
4530
|
+
type: 'seg',
|
|
4531
|
+
options: [
|
|
4532
|
+
{ id: 'default', label: '通用空状态' },
|
|
4533
|
+
{ id: 'no-result', label: '搜索无结果' },
|
|
4534
|
+
{ id: 'error', label: '加载失败' },
|
|
4535
|
+
],
|
|
4536
|
+
default: 'default',
|
|
4537
|
+
},
|
|
4538
|
+
],
|
|
4539
|
+
|
|
4540
|
+
mapProps: (cv, enums) => {
|
|
4541
|
+
const illustrationType = enums.illustrationType || 'no-content';
|
|
4542
|
+
const buttonLayout = enums.buttonLayout || 'row';
|
|
4543
|
+
const scenario = cv.scenario || 'default';
|
|
4544
|
+
|
|
4545
|
+
// 加载失败:链接行模式,无标题/按钮
|
|
4546
|
+
if (scenario === 'error') {
|
|
4547
|
+
return {
|
|
4548
|
+
illustrationType: 'failure',
|
|
4549
|
+
linkPrefix: '页面显示失败,',
|
|
4550
|
+
linkText: '刷新重试',
|
|
4551
|
+
};
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
// 搜索无结果:有标题+描述,无操作按钮(纯说明)
|
|
4555
|
+
if (scenario === 'no-result') {
|
|
4556
|
+
return {
|
|
4557
|
+
illustrationType: 'no-result',
|
|
4558
|
+
buttonLayout,
|
|
4559
|
+
title: '未找到搜索结果',
|
|
4560
|
+
description: '请尝试更换关键词或清除筛选条件',
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
// 通用空状态:标题 + 描述 + 双按钮,buttonLayout 控制横排/竖排
|
|
4565
|
+
return {
|
|
4566
|
+
illustrationType,
|
|
4567
|
+
buttonLayout,
|
|
4568
|
+
title: '空状态标题',
|
|
4569
|
+
description: '这是一段对当前空状态的描述文本',
|
|
4570
|
+
primaryLabel: '一级按钮',
|
|
4571
|
+
secondaryLabel: buttonLayout === 'row' ? '二级按钮' : '',
|
|
4572
|
+
tertiaryLabel: buttonLayout === 'column' ? '文字按钮' : '',
|
|
4573
|
+
};
|
|
4574
|
+
},
|
|
4575
|
+
|
|
4576
|
+
generateUsage: (enums, cv) => {
|
|
4577
|
+
const illustrationType = enums.illustrationType || 'no-content';
|
|
4578
|
+
const buttonLayout = enums.buttonLayout || 'row';
|
|
4579
|
+
const scenario = cv.scenario || 'default';
|
|
4580
|
+
|
|
4581
|
+
const lines = [`import Empty from './components/Empty';`, ''];
|
|
4582
|
+
|
|
4583
|
+
if (scenario === 'error') {
|
|
4584
|
+
lines.push('<Empty');
|
|
4585
|
+
lines.push(' illustrationType="failure"');
|
|
4586
|
+
lines.push(' linkPrefix="页面显示失败,"');
|
|
4587
|
+
lines.push(' linkText="刷新重试"');
|
|
4588
|
+
lines.push('/>');
|
|
4589
|
+
return lines.join('\n');
|
|
4590
|
+
}
|
|
4591
|
+
|
|
4592
|
+
if (scenario === 'no-result') {
|
|
4593
|
+
lines.push('<Empty');
|
|
4594
|
+
lines.push(' illustrationType="no-result"');
|
|
4595
|
+
lines.push(' title="未找到搜索结果"');
|
|
4596
|
+
lines.push(' description="请尝试更换关键词或清除筛选条件"');
|
|
4597
|
+
lines.push('/>');
|
|
4598
|
+
return lines.join('\n');
|
|
4599
|
+
}
|
|
4600
|
+
|
|
4601
|
+
// 通用空状态
|
|
4602
|
+
lines.push('<Empty');
|
|
4603
|
+
if (illustrationType !== 'no-content') lines.push(` illustrationType="${illustrationType}"`);
|
|
4604
|
+
if (buttonLayout !== 'row') lines.push(` buttonLayout="${buttonLayout}"`);
|
|
4605
|
+
lines.push(' title="空状态标题"');
|
|
4606
|
+
lines.push(' description="这是一段对当前空状态的描述文本"');
|
|
4607
|
+
lines.push(' primaryLabel="一级按钮"');
|
|
4608
|
+
if (buttonLayout === 'row') lines.push(' secondaryLabel="二级按钮"');
|
|
4609
|
+
if (buttonLayout === 'column') lines.push(' tertiaryLabel="文字按钮"');
|
|
4610
|
+
lines.push('/>');
|
|
4611
|
+
return lines.join('\n');
|
|
4612
|
+
},
|
|
4613
|
+
},
|
|
4614
|
+
|
|
4615
|
+
'full-screen-page': {
|
|
4616
|
+
component: FullScreenPage,
|
|
4617
|
+
tokenMap: FULL_SCREEN_PAGE_TOKEN_MAP,
|
|
4618
|
+
jsxSource: fullScreenPageJsxRaw,
|
|
4619
|
+
previewBgBinding: 'bg',
|
|
4620
|
+
|
|
4621
|
+
/* 预览区:去掉默认 padding,撑满布局给的高度;overflow hidden + 圆角裁边 */
|
|
4622
|
+
getPreviewAreaStyle: () => ({
|
|
4623
|
+
overflow: 'hidden',
|
|
4624
|
+
borderRadius: '8px',
|
|
4625
|
+
padding: 0,
|
|
4626
|
+
alignItems: 'stretch',
|
|
4627
|
+
}),
|
|
4628
|
+
/* scaler 跟随预览区高度拉伸,作为 contained FullScreenPage 的尺寸容器 */
|
|
4629
|
+
getPreviewScalerStyle: () => ({
|
|
4630
|
+
width: '100%',
|
|
4631
|
+
alignSelf: 'stretch',
|
|
4632
|
+
display: 'flex',
|
|
4633
|
+
flexDirection: 'column',
|
|
4634
|
+
}),
|
|
4635
|
+
|
|
4636
|
+
controls: [],
|
|
4637
|
+
|
|
4638
|
+
mapProps: (cv, enums) => {
|
|
4639
|
+
const bg = enums.bg || 'white';
|
|
4640
|
+
|
|
4641
|
+
/* 步骤卡片标题行(与 BasePageFramePattern 的 QACardHeader 对齐) */
|
|
4642
|
+
const StepCardHeader = ({ step, title, hint }) => (
|
|
4643
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '20px 24px', flexShrink: 0 }}>
|
|
4644
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
|
4645
|
+
<div style={{ width: 20, height: 20, borderRadius: 6, background: '#1C1C23', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
|
4646
|
+
<span style={{ fontSize: 12, fontWeight: 600, color: '#fff', lineHeight: 1 }}>{step}</span>
|
|
4647
|
+
</div>
|
|
4648
|
+
<span style={{ fontSize: 16, fontWeight: 600, color: '#182230', lineHeight: '22px' }}>{title}</span>
|
|
4649
|
+
</div>
|
|
4650
|
+
{hint && <span style={{ fontSize: 14, color: '#475467', lineHeight: '20px' }}>{hint}</span>}
|
|
4651
|
+
</div>
|
|
4652
|
+
);
|
|
4653
|
+
|
|
4654
|
+
/* 卡片样式:灰底=白底填充,白底=透明+灰描边 */
|
|
4655
|
+
const cardStyle = bg === 'grey'
|
|
4656
|
+
? { background: '#FFFFFF', borderRadius: '12px', overflow: 'hidden' }
|
|
4657
|
+
: { background: 'transparent', border: '1px solid #E4E7EC', borderRadius: '12px', overflow: 'hidden' };
|
|
4658
|
+
|
|
4659
|
+
const demoContent = (
|
|
4660
|
+
<div style={{ display: 'flex', flex: 1, minHeight: 0, gap: '8px', padding: '16px' }}>
|
|
4661
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, ...cardStyle }}>
|
|
4662
|
+
<StepCardHeader step="1" title="步骤标题一" hint="辅助信息" />
|
|
4663
|
+
</div>
|
|
4664
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, ...cardStyle }}>
|
|
4665
|
+
<StepCardHeader step="2" title="步骤标题二" />
|
|
4666
|
+
</div>
|
|
4667
|
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, ...cardStyle }}>
|
|
4668
|
+
<StepCardHeader step="3" title="步骤标题三" />
|
|
4669
|
+
</div>
|
|
4670
|
+
</div>
|
|
4671
|
+
);
|
|
4672
|
+
|
|
4673
|
+
return {
|
|
4674
|
+
bg,
|
|
4675
|
+
contained: true,
|
|
4676
|
+
title: '创建QA对',
|
|
4677
|
+
onBack: () => {},
|
|
4678
|
+
headerActions: (
|
|
4679
|
+
<div style={{ display: 'flex', gap: '8px' }}>
|
|
4680
|
+
<Button variant="outline-black">保存草稿</Button>
|
|
4681
|
+
<Button variant="primary">发布</Button>
|
|
4682
|
+
</div>
|
|
4683
|
+
),
|
|
4684
|
+
children: demoContent,
|
|
4685
|
+
};
|
|
4686
|
+
},
|
|
4687
|
+
|
|
4688
|
+
generateUsage: (enums, cv) => {
|
|
4689
|
+
const bg = enums.bg || 'white';
|
|
4690
|
+
const lines = [`import FullScreenPage from './components/FullScreenPage';`, ''];
|
|
4691
|
+
lines.push('<FullScreenPage');
|
|
4692
|
+
if (bg !== 'white') lines.push(` bg="${bg}"`);
|
|
4693
|
+
lines.push(' title="创建QA对"');
|
|
4694
|
+
lines.push(' onBack={() => handleBack()}');
|
|
4695
|
+
lines.push(' headerActions={');
|
|
4696
|
+
lines.push(' <>');
|
|
4697
|
+
lines.push(' <Button variant="outline-black">保存草稿</Button>');
|
|
4698
|
+
lines.push(' <Button variant="primary">发布</Button>');
|
|
4699
|
+
lines.push(' </>');
|
|
4700
|
+
lines.push(' }');
|
|
4701
|
+
lines.push('>');
|
|
4702
|
+
if (bg === 'grey') {
|
|
4703
|
+
lines.push(' {/* 灰底模式:页面是浅灰底,内部面板必须切换为白卡样式 */}');
|
|
4704
|
+
lines.push(' <div className="flex gap-4 p-6 h-full">');
|
|
4705
|
+
lines.push(' <div className="flex-1 bg-white rounded-xl p-6">主编辑面板</div>');
|
|
4706
|
+
lines.push(' <div className="w-60 bg-white rounded-xl p-6">配置侧栏面板</div>');
|
|
4707
|
+
lines.push(' </div>');
|
|
4708
|
+
} else {
|
|
4709
|
+
lines.push(' {/* 白底模式:页面保持一体化,内部面板用描边样式,不再叠加白卡 */}');
|
|
4710
|
+
lines.push(' <div className="flex gap-4 p-6 h-full">');
|
|
4711
|
+
lines.push(' <div className="flex-1 rounded-xl border border-border-default p-6">基础信息面板</div>');
|
|
4712
|
+
lines.push(' <div className="w-60 rounded-xl border border-border-default p-6">辅助配置面板</div>');
|
|
4713
|
+
lines.push(' </div>');
|
|
4714
|
+
}
|
|
4715
|
+
lines.push('</FullScreenPage>');
|
|
4716
|
+
return lines.join('\n');
|
|
4717
|
+
},
|
|
4718
|
+
},
|
|
4719
|
+
};
|