@lark-apaas/coding-template-nestjs-react-fullstack 0.1.36-alpha.20260903095202 → 0.1.36-alpha.20260903185731

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/package.json +1 -1
  2. package/template/client/src/components/ui/markdown.tsx +43 -0
  3. package/template/client/src/index.css +0 -1
  4. package/template/package-lock.json +5783 -13022
  5. package/template/package.json +5 -68
  6. package/template/client/src/components/business-ui/README.md +0 -519
  7. package/template/client/src/components/business-ui/api/chats/queries.ts +0 -39
  8. package/template/client/src/components/business-ui/api/chats/service.ts +0 -29
  9. package/template/client/src/components/business-ui/api/departments/queries.ts +0 -42
  10. package/template/client/src/components/business-ui/api/departments/service.ts +0 -18
  11. package/template/client/src/components/business-ui/api/files/service.ts +0 -28
  12. package/template/client/src/components/business-ui/api/user-profiles/queries.ts +0 -42
  13. package/template/client/src/components/business-ui/api/user-profiles/service.ts +0 -23
  14. package/template/client/src/components/business-ui/api/users/queries.ts +0 -34
  15. package/template/client/src/components/business-ui/api/users/service.ts +0 -40
  16. package/template/client/src/components/business-ui/chat-select/README.md +0 -128
  17. package/template/client/src/components/business-ui/chat-select/chat-item.tsx +0 -85
  18. package/template/client/src/components/business-ui/chat-select/chat-select-tag.tsx +0 -83
  19. package/template/client/src/components/business-ui/chat-select/chat-select.tsx +0 -197
  20. package/template/client/src/components/business-ui/chat-select/index.tsx +0 -12
  21. package/template/client/src/components/business-ui/chat-select/types.ts +0 -102
  22. package/template/client/src/components/business-ui/chat-select/use-chat-value.ts +0 -180
  23. package/template/client/src/components/business-ui/chat-select/utils.ts +0 -81
  24. package/template/client/src/components/business-ui/department-select/department-item.tsx +0 -55
  25. package/template/client/src/components/business-ui/department-select/department-select-field.tsx +0 -86
  26. package/template/client/src/components/business-ui/department-select/department-select-tag.tsx +0 -56
  27. package/template/client/src/components/business-ui/department-select/department-select.tsx +0 -168
  28. package/template/client/src/components/business-ui/department-select/icon-department.tsx +0 -22
  29. package/template/client/src/components/business-ui/department-select/index.tsx +0 -7
  30. package/template/client/src/components/business-ui/department-select/types.ts +0 -15
  31. package/template/client/src/components/business-ui/department-select/utils.ts +0 -17
  32. package/template/client/src/components/business-ui/entity-combobox/base-combobox-content.tsx +0 -35
  33. package/template/client/src/components/business-ui/entity-combobox/base-combobox-empty.tsx +0 -28
  34. package/template/client/src/components/business-ui/entity-combobox/base-combobox-error.tsx +0 -35
  35. package/template/client/src/components/business-ui/entity-combobox/base-combobox-item.tsx +0 -55
  36. package/template/client/src/components/business-ui/entity-combobox/base-combobox-list.tsx +0 -174
  37. package/template/client/src/components/business-ui/entity-combobox/base-combobox-loading.tsx +0 -19
  38. package/template/client/src/components/business-ui/entity-combobox/base-combobox-search.tsx +0 -31
  39. package/template/client/src/components/business-ui/entity-combobox/base-combobox-trigger.tsx +0 -281
  40. package/template/client/src/components/business-ui/entity-combobox/base-combobox.tsx +0 -132
  41. package/template/client/src/components/business-ui/entity-combobox/context.tsx +0 -19
  42. package/template/client/src/components/business-ui/entity-combobox/entity-combobox.tsx +0 -145
  43. package/template/client/src/components/business-ui/entity-combobox/highlight-text.tsx +0 -52
  44. package/template/client/src/components/business-ui/entity-combobox/hooks.tsx +0 -21
  45. package/template/client/src/components/business-ui/entity-combobox/index.tsx +0 -31
  46. package/template/client/src/components/business-ui/entity-combobox/item-pill.tsx +0 -179
  47. package/template/client/src/components/business-ui/entity-combobox/popover-wrapper.tsx +0 -149
  48. package/template/client/src/components/business-ui/entity-combobox/search-trigger.tsx +0 -262
  49. package/template/client/src/components/business-ui/entity-combobox/shared-types.ts +0 -296
  50. package/template/client/src/components/business-ui/entity-combobox/size-variants.tsx +0 -322
  51. package/template/client/src/components/business-ui/entity-combobox/types.ts +0 -246
  52. package/template/client/src/components/business-ui/entity-combobox/use-fetch-data.tsx +0 -81
  53. package/template/client/src/components/business-ui/entity-combobox/use-infinite-scroll.tsx +0 -99
  54. package/template/client/src/components/business-ui/entity-combobox/use-popover-outside-click.tsx +0 -32
  55. package/template/client/src/components/business-ui/form/checkbox-field.tsx +0 -83
  56. package/template/client/src/components/business-ui/form/context.tsx +0 -38
  57. package/template/client/src/components/business-ui/form/field-layout.tsx +0 -91
  58. package/template/client/src/components/business-ui/form/form.tsx +0 -54
  59. package/template/client/src/components/business-ui/form/hooks/form-context.tsx +0 -4
  60. package/template/client/src/components/business-ui/form/hooks/form-utils.ts +0 -23
  61. package/template/client/src/components/business-ui/form/hooks/form.tsx +0 -40
  62. package/template/client/src/components/business-ui/form/index.tsx +0 -4
  63. package/template/client/src/components/business-ui/form/input-field.tsx +0 -74
  64. package/template/client/src/components/business-ui/form/radio-group-field.tsx +0 -138
  65. package/template/client/src/components/business-ui/form/select-field.tsx +0 -155
  66. package/template/client/src/components/business-ui/form/switch-field.tsx +0 -66
  67. package/template/client/src/components/business-ui/form/textarea-field.tsx +0 -72
  68. package/template/client/src/components/business-ui/form/types.ts +0 -32
  69. package/template/client/src/components/business-ui/tiptap-editor/README.md +0 -324
  70. package/template/client/src/components/business-ui/tiptap-editor/components/attachment-toolbar-button.tsx +0 -74
  71. package/template/client/src/components/business-ui/tiptap-editor/components/blockquote-toolbar-button.tsx +0 -41
  72. package/template/client/src/components/business-ui/tiptap-editor/components/code-block-toolbar-button.tsx +0 -41
  73. package/template/client/src/components/business-ui/tiptap-editor/components/color-highlight-toolbar-button.tsx +0 -141
  74. package/template/client/src/components/business-ui/tiptap-editor/components/heading-toolbar-button.tsx +0 -99
  75. package/template/client/src/components/business-ui/tiptap-editor/components/horizontal-rule-toolbar-button.tsx +0 -39
  76. package/template/client/src/components/business-ui/tiptap-editor/components/image-upload-toolbar-button.tsx +0 -65
  77. package/template/client/src/components/business-ui/tiptap-editor/components/link-edit-form.tsx +0 -127
  78. package/template/client/src/components/business-ui/tiptap-editor/components/link-hover-toolbar.tsx +0 -380
  79. package/template/client/src/components/business-ui/tiptap-editor/components/link-toolbar-button.tsx +0 -96
  80. package/template/client/src/components/business-ui/tiptap-editor/components/list-toolbar-button.tsx +0 -75
  81. package/template/client/src/components/business-ui/tiptap-editor/components/mark-toolbar-button.tsx +0 -118
  82. package/template/client/src/components/business-ui/tiptap-editor/components/text-align-toolbar-button.tsx +0 -84
  83. package/template/client/src/components/business-ui/tiptap-editor/components/undo-redo-toolbar-button.tsx +0 -54
  84. package/template/client/src/components/business-ui/tiptap-editor/extensions/attachment.tsx +0 -539
  85. package/template/client/src/components/business-ui/tiptap-editor/extensions/code-block-shiki.tsx +0 -236
  86. package/template/client/src/components/business-ui/tiptap-editor/extensions/complete-kit.ts +0 -260
  87. package/template/client/src/components/business-ui/tiptap-editor/extensions/image.tsx +0 -456
  88. package/template/client/src/components/business-ui/tiptap-editor/hooks/use-tiptap-editor.ts +0 -47
  89. package/template/client/src/components/business-ui/tiptap-editor/index.ts +0 -38
  90. package/template/client/src/components/business-ui/tiptap-editor/tiptap-editor-complete.tsx +0 -112
  91. package/template/client/src/components/business-ui/tiptap-editor/tiptap-editor.tsx +0 -169
  92. package/template/client/src/components/business-ui/types/user.ts +0 -74
  93. package/template/client/src/components/business-ui/user-display/index.tsx +0 -2
  94. package/template/client/src/components/business-ui/user-display/overflow-tooltip-text.tsx +0 -90
  95. package/template/client/src/components/business-ui/user-display/type.ts +0 -27
  96. package/template/client/src/components/business-ui/user-display/user-display.tsx +0 -99
  97. package/template/client/src/components/business-ui/user-display/user-with-avatar.tsx +0 -158
  98. package/template/client/src/components/business-ui/user-display/utils.ts +0 -37
  99. package/template/client/src/components/business-ui/user-profile/error-image.tsx +0 -302
  100. package/template/client/src/components/business-ui/user-profile/user-external-script.ts +0 -73
  101. package/template/client/src/components/business-ui/user-profile/user-profile.tsx +0 -370
  102. package/template/client/src/components/business-ui/user-select/index.tsx +0 -28
  103. package/template/client/src/components/business-ui/user-select/types.ts +0 -109
  104. package/template/client/src/components/business-ui/user-select/use-user-value.ts +0 -160
  105. package/template/client/src/components/business-ui/user-select/user-item.tsx +0 -98
  106. package/template/client/src/components/business-ui/user-select/user-pill.tsx +0 -140
  107. package/template/client/src/components/business-ui/user-select/user-select-tag.tsx +0 -82
  108. package/template/client/src/components/business-ui/user-select/user-select.tsx +0 -359
  109. package/template/client/src/components/business-ui/user-select/utils.tsx +0 -188
  110. package/template/client/src/components/business-ui/utils/user.ts +0 -72
  111. package/template/client/src/components/ui/streamdown.tsx +0 -186
  112. package/template/client/src/lib/shiki.ts +0 -92
@@ -1,197 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useCallback, useMemo } from 'react';
4
-
5
- import { searchChats } from '@client/src/components/business-ui/api/chats/service';
6
- import { ChatItem } from '@client/src/components/business-ui/chat-select/chat-item';
7
- import { ChatSelectTag } from '@client/src/components/business-ui/chat-select/chat-select-tag';
8
- import type {
9
- Chat,
10
- ChatSelectProps,
11
- } from '@client/src/components/business-ui/chat-select/types';
12
- import { useChatValue } from '@client/src/components/business-ui/chat-select/use-chat-value';
13
- import { chatInfoToChat } from '@client/src/components/business-ui/chat-select/utils';
14
- import { BaseCombobox } from '@client/src/components/business-ui/entity-combobox/base-combobox';
15
- import { useEntityComboboxContext } from '@client/src/components/business-ui/entity-combobox/context';
16
-
17
- function createChatsFetcher(pageSize: number = 100) {
18
- return async (search: string) => {
19
- const response = await searchChats({ query: search, pageSize });
20
- const chatList = response?.data?.result?.chatResult?.items || [];
21
- return { items: chatList.map((chat) => chatInfoToChat(chat)) };
22
- };
23
- }
24
-
25
- // 内部包装组件用于获取 context 中的 size
26
- const ChatItemWrapper = ({
27
- chatValue,
28
- isSelected,
29
- className,
30
- disabled,
31
- }: {
32
- chatValue: Chat;
33
- isSelected: boolean;
34
- className?: string;
35
- disabled?: boolean;
36
- }) => {
37
- const { size, searchValue } = useEntityComboboxContext();
38
- return (
39
- <ChatItem
40
- chatValue={chatValue}
41
- isSelected={isSelected}
42
- className={className}
43
- size={size}
44
- searchKeyword={searchValue}
45
- disabled={disabled}
46
- />
47
- );
48
- };
49
-
50
- const ChatSelectTagWrapper = ({
51
- chatValue,
52
- onClose,
53
- className,
54
- disabled,
55
- isLoading,
56
- }: {
57
- chatValue: Chat;
58
- onClose: (value: Chat, e: React.MouseEvent) => void;
59
- className?: string;
60
- disabled?: boolean;
61
- isLoading?: boolean;
62
- }) => {
63
- const { size } = useEntityComboboxContext();
64
- return (
65
- <ChatSelectTag
66
- chatValue={chatValue}
67
- onClose={onClose}
68
- className={className}
69
- size={size}
70
- disabled={disabled}
71
- isLoading={isLoading}
72
- />
73
- );
74
- };
75
-
76
- export const ChatSelect: React.FC<ChatSelectProps> = (props) => {
77
- const {
78
- size = 'medium',
79
- triggerType = 'button',
80
- renderTrigger,
81
- multiple = false,
82
- value,
83
- valueType = 'string',
84
- defaultValue,
85
- onChange,
86
- defaultOpen,
87
- disabled,
88
- autoFocus,
89
- required,
90
- name,
91
- className,
92
- classNames,
93
- placeholder = '请选择',
94
- emptyText = '没有匹配结果,换个关键词试试吧',
95
- tagClosable,
96
- maxTagCount,
97
- onSelect,
98
- onDeselect,
99
- onClear,
100
- onFocus,
101
- onBlur,
102
- slotProps,
103
- getOptionDisabled,
104
- } = props;
105
-
106
- const isControlled = value !== undefined;
107
-
108
- // 使用 useChatValue 处理不同类型的 value(包括 defaultValue)
109
- const { internalValue, isLoading, toExternalValue } = useChatValue(
110
- value ?? null,
111
- multiple,
112
- valueType,
113
- );
114
-
115
- // 同样处理 defaultValue,确保 ID 字符串类型的 defaultValue 也能正确解析
116
- const { internalValue: internalDefaultValue } = useChatValue(
117
- defaultValue ?? null,
118
- multiple,
119
- valueType,
120
- );
121
-
122
- const fetchFn = useMemo(() => createChatsFetcher(), []);
123
-
124
- // 包装 onChange,根据输入模式转换输出格式
125
- const handleChange = useCallback(
126
- (newValue: Chat | Chat[] | null) => {
127
- if (!onChange) return;
128
-
129
- const externalValue = toExternalValue(newValue, multiple);
130
- (onChange as (value: unknown) => void)(externalValue);
131
- },
132
- [onChange, toExternalValue, multiple],
133
- );
134
-
135
- const renderTagWithLoading = useCallback(
136
- (
137
- chatValue: Chat,
138
- onClose: (value: Chat, e: React.MouseEvent) => void,
139
- tagDisabled?: boolean,
140
- ) => (
141
- <ChatSelectTagWrapper
142
- key={chatValue.id}
143
- chatValue={chatValue}
144
- onClose={onClose}
145
- disabled={tagDisabled}
146
- isLoading={isLoading}
147
- />
148
- ),
149
- [isLoading],
150
- );
151
-
152
- return (
153
- <BaseCombobox
154
- autoFocus={autoFocus}
155
- className={className}
156
- classNames={classNames}
157
- debounce={300}
158
- defaultOpen={defaultOpen}
159
- defaultValue={internalDefaultValue}
160
- disabled={disabled}
161
- emptyText={emptyText}
162
- fetchFn={fetchFn}
163
- getItemLabel={(chatValue: Chat) => chatValue.name}
164
- getItemValue={(chatValue: Chat) => chatValue}
165
- getOptionDisabled={getOptionDisabled}
166
- maxTagCount={maxTagCount}
167
- multiple={multiple}
168
- name={name}
169
- onBlur={onBlur}
170
- onChange={handleChange}
171
- onClear={onClear}
172
- onDeselect={onDeselect}
173
- onFocus={onFocus}
174
- onSelect={onSelect}
175
- placeholder={placeholder}
176
- renderItem={(chatValue, isSelected, itemClassName, itemDisabled) => (
177
- <ChatItemWrapper
178
- key={chatValue.id}
179
- chatValue={chatValue}
180
- isSelected={isSelected}
181
- className={itemClassName}
182
- disabled={itemDisabled}
183
- />
184
- )}
185
- renderTag={renderTagWithLoading}
186
- renderTrigger={renderTrigger}
187
- required={required}
188
- searchPlaceholder=""
189
- showSearch
190
- size={size}
191
- slotProps={slotProps}
192
- tagClosable={tagClosable}
193
- triggerType={triggerType}
194
- value={isControlled ? internalValue : undefined}
195
- />
196
- );
197
- };
@@ -1,12 +0,0 @@
1
- export { ChatSelect } from '@client/src/components/business-ui/chat-select/chat-select';
2
- export type {
3
- ChatInfo,
4
- Chat,
5
- ChatSelectProps,
6
- ChatSelectValue,
7
- ValueType as ChatSelectValueType,
8
- } from '@client/src/components/business-ui/chat-select/types';
9
- export {
10
- extractIdsFromValue,
11
- isIdModeValue,
12
- } from '@client/src/components/business-ui/chat-select/utils';
@@ -1,102 +0,0 @@
1
- import type {
2
- BaseEntitySelectProps,
3
- ItemValue,
4
- } from '@client/src/components/business-ui/entity-combobox/shared-types';
5
- import type { I18nText } from '@client/src/components/business-ui/entity-combobox/types';
6
-
7
- export type { I18nText };
8
-
9
- /**
10
- * 群组原始信息(对应 SearchChatEntity)
11
- */
12
- export type ChatInfo = {
13
- /** 群组 ID */
14
- chatID: string;
15
- /** 群组名称(国际化文本) */
16
- name: I18nText;
17
- /** 头像:URL 或 16 进制 RGB 颜色 */
18
- avatar: string;
19
- /** 是否是外部群 */
20
- isExternal?: boolean;
21
- /** 群成员数量(不包括机器人) */
22
- userCount?: number;
23
- };
24
-
25
- /**
26
- * 标准化后的群组数据(用于 BaseCombobox)
27
- */
28
- export type Chat = ItemValue<ChatInfo>;
29
-
30
- /**
31
- * 值类型
32
- * - 'string': value 为 chatID 字符串
33
- * - 'object': value 为 Chat 对象
34
- * @default 'string'
35
- */
36
- export type ValueType = 'string' | 'object';
37
-
38
- /**
39
- * 根据 valueType 和 multiple 推断 value 类型
40
- */
41
- export type InferValue<
42
- V extends ValueType,
43
- M extends boolean,
44
- > = V extends 'string'
45
- ? M extends true
46
- ? string[]
47
- : string | null
48
- : M extends true
49
- ? Chat[]
50
- : Chat | null;
51
-
52
- type ChatSelectBaseProps<
53
- V extends ValueType = 'string',
54
- M extends boolean = false,
55
- > = Omit<
56
- BaseEntitySelectProps<Chat>,
57
- 'value' | 'defaultValue' | 'onChange'
58
- > & {
59
- /**
60
- * 值类型
61
- * - 'string': value 为 chatID 字符串
62
- * - 'object': value 为 Chat 对象
63
- * @default 'string'
64
- */
65
- valueType?: V;
66
- /**
67
- * 是否多选
68
- * @default false
69
- */
70
- multiple?: M;
71
- /**
72
- * 当前值
73
- */
74
- value?: InferValue<V, M>;
75
- /**
76
- * 默认值
77
- */
78
- defaultValue?: InferValue<V, M>;
79
- /**
80
- * 值变化回调
81
- */
82
- onChange?: (value: InferValue<V, M>) => void;
83
- };
84
-
85
- /**
86
- * ChatSelect 组件 Props
87
- *
88
- * 类型组合:
89
- * | valueType | multiple | value 类型 |
90
- * |-----------|----------|------------|
91
- * | 'string' | false | string \| null |
92
- * | 'string' | true | string[] |
93
- * | 'object' | false | Chat \| null |
94
- * | 'object' | true | Chat[] |
95
- */
96
- export type ChatSelectProps =
97
- | ChatSelectBaseProps<'string', false>
98
- | ChatSelectBaseProps<'string', true>
99
- | ChatSelectBaseProps<'object', false>
100
- | ChatSelectBaseProps<'object', true>;
101
-
102
- export type ChatSelectValue = Chat | Chat[] | string | string[] | null;
@@ -1,180 +0,0 @@
1
- 'use client';
2
-
3
- import { useCallback, useEffect, useMemo, useState } from 'react';
4
-
5
- import { listChatsByIds } from '@client/src/components/business-ui/api/chats/service';
6
- import type {
7
- Chat,
8
- ChatSelectValue,
9
- ValueType,
10
- } from '@client/src/components/business-ui/chat-select/types';
11
- import {
12
- chatInfoToChat,
13
- createUnknownChat,
14
- extractIdsFromValue,
15
- } from '@client/src/components/business-ui/chat-select/utils';
16
-
17
- export type UseChatValueResult = {
18
- /**
19
- * 标准化后的内部 value(Chat 对象格式)
20
- * 用于传递给 BaseCombobox
21
- */
22
- internalValue: Chat | Chat[] | null;
23
-
24
- /**
25
- * 是否正在加载群组信息
26
- */
27
- isLoading: boolean;
28
-
29
- /**
30
- * 将内部 Chat 对象转换回外部格式
31
- * ID 模式时返回字符串,对象模式时返回 Chat
32
- */
33
- toExternalValue: (
34
- internalVal: Chat | Chat[] | null,
35
- multiple: boolean,
36
- ) => ChatSelectValue;
37
- };
38
-
39
- /**
40
- * 处理 ChatSelect 的 value 类型转换
41
- *
42
- * - 根据 valueType 决定 value 是 chatID 字符串还是 Chat 对象
43
- * - ID 模式下调用搜索 API 获取完整群组信息
44
- * - 无效 ID 生成 "未知群组" 占位
45
- *
46
- * @param value - 外部传入的 value
47
- * @param multiple - 是否多选模式
48
- * @param valueType - 值类型,'string' 表示 ID 模式,'object' 表示 Chat 对象模式
49
- */
50
- export function useChatValue(
51
- value: ChatSelectValue,
52
- multiple: boolean = false,
53
- valueType: ValueType = 'string',
54
- ): UseChatValueResult {
55
- const isIdMode = valueType === 'string';
56
-
57
- const [resolvedChats, setResolvedChats] = useState<Map<string, Chat>>(
58
- new Map(),
59
- );
60
- const [isLoading, setIsLoading] = useState(false);
61
-
62
- const currentIds = useMemo(() => extractIdsFromValue(value), [value]);
63
-
64
- const missingIds = useMemo(() => {
65
- if (!isIdMode) return [];
66
- return currentIds.filter((id) => !resolvedChats.has(String(id)));
67
- }, [isIdMode, currentIds, resolvedChats]);
68
-
69
- // 稳定化 missingIds 引用
70
- const missingIdsKey = missingIds.join(',');
71
-
72
- useEffect(() => {
73
- if (!missingIdsKey) {
74
- return;
75
- }
76
-
77
- const ids = missingIdsKey.split(',');
78
- let cancelled = false;
79
-
80
- const fetchData = async () => {
81
- setIsLoading(true);
82
- try {
83
- const response = await listChatsByIds(ids);
84
- if (cancelled) return;
85
-
86
- const chatInfoMap = response?.data?.chatInfoMap || {};
87
- setResolvedChats((prev) => {
88
- const next = new Map(prev);
89
- for (const [chatId, chatInfo] of Object.entries(chatInfoMap)) {
90
- const chat = chatInfoToChat(chatInfo);
91
- next.set(String(chatId), chat);
92
- }
93
- // 标记未找到的 ID 为未知群组
94
- for (const id of ids) {
95
- if (!next.has(String(id))) {
96
- next.set(String(id), createUnknownChat(id));
97
- }
98
- }
99
- return next;
100
- });
101
- } catch (error) {
102
- console.error('Failed to resolve chat IDs:', error);
103
- if (!cancelled) {
104
- setResolvedChats((prev) => {
105
- const next = new Map(prev);
106
- for (const id of ids) {
107
- if (!next.has(String(id))) {
108
- next.set(String(id), createUnknownChat(id));
109
- }
110
- }
111
- return next;
112
- });
113
- }
114
- } finally {
115
- if (!cancelled) {
116
- setIsLoading(false);
117
- }
118
- }
119
- };
120
-
121
- fetchData();
122
-
123
- return () => {
124
- cancelled = true;
125
- };
126
- }, [missingIdsKey]);
127
-
128
- const internalValue = useMemo((): Chat | Chat[] | null => {
129
- if (value === null || value === undefined) {
130
- return multiple ? [] : null;
131
- }
132
-
133
- if (Array.isArray(value) && value.length === 0) {
134
- return [];
135
- }
136
-
137
- if (!isIdMode) {
138
- return value as Chat | Chat[];
139
- }
140
-
141
- const chats = currentIds
142
- .map((id) => resolvedChats.get(String(id)))
143
- .filter((c): c is Chat => c !== undefined);
144
-
145
- if (multiple) {
146
- return chats;
147
- }
148
-
149
- return chats[0] ?? null;
150
- }, [value, isIdMode, currentIds, resolvedChats, multiple]);
151
-
152
- const toExternalValue = useCallback(
153
- (
154
- internalVal: Chat | Chat[] | null,
155
- isMultiple: boolean,
156
- ): ChatSelectValue => {
157
- if (internalVal === null) {
158
- return null;
159
- }
160
-
161
- if (isIdMode) {
162
- // ID 模式:返回 string 或 string[]
163
- if (isMultiple) {
164
- return (internalVal as Chat[]).map((c) => String(c.id));
165
- }
166
- return String((internalVal as Chat).id);
167
- }
168
-
169
- // Object 模式:直接返回 Chat 对象
170
- return internalVal;
171
- },
172
- [isIdMode],
173
- );
174
-
175
- return {
176
- internalValue,
177
- isLoading,
178
- toExternalValue,
179
- };
180
- }
@@ -1,81 +0,0 @@
1
- import type { Chat, ChatInfo, ChatSelectValue, I18nText } from './types';
2
-
3
- /**
4
- * 获取国际化文本显示值(独立实现,不依赖其他组件)
5
- */
6
- function getI18nText(text: I18nText | string | undefined): string {
7
- if (!text) return '';
8
- if (typeof text === 'string') return text;
9
- return text.zh_cn || text.en_us || text.ja_jp || '';
10
- }
11
-
12
- /**
13
- * 获取群组显示名称
14
- */
15
- export function getChatDisplayName(name: ChatInfo['name']): string {
16
- return getI18nText(name);
17
- }
18
-
19
- /**
20
- * ChatInfo → Chat 标准化转换
21
- */
22
- export function chatInfoToChat(chatInfo: ChatInfo): Chat {
23
- return {
24
- id: chatInfo.chatID,
25
- name: getChatDisplayName(chatInfo.name),
26
- avatar: chatInfo.avatar,
27
- raw: chatInfo,
28
- };
29
- }
30
-
31
- /**
32
- * 创建未知群组占位(ID 无法解析时使用)
33
- */
34
- export function createUnknownChat(id: string): Chat {
35
- return {
36
- id,
37
- name: '未知群组',
38
- avatar: '',
39
- raw: undefined,
40
- };
41
- }
42
-
43
- /**
44
- * 判断 value 是否为 ID 模式(字符串或字符串数组)
45
- */
46
- export function isIdModeValue(
47
- value: ChatSelectValue,
48
- ): value is string | string[] {
49
- if (value === null || value === undefined) {
50
- return false;
51
- }
52
- if (typeof value === 'string') {
53
- return true;
54
- }
55
- if (Array.isArray(value) && value.length > 0) {
56
- return typeof value[0] === 'string';
57
- }
58
- return false;
59
- }
60
-
61
- /**
62
- * 从 value 中提取 ID 列表
63
- */
64
- export function extractIdsFromValue(value: ChatSelectValue): string[] {
65
- if (value === null || value === undefined) {
66
- return [];
67
- }
68
- if (typeof value === 'string') {
69
- return [value];
70
- }
71
- if (Array.isArray(value)) {
72
- if (value.length === 0) {
73
- return [];
74
- }
75
- if (typeof value[0] === 'string') {
76
- return value as string[];
77
- }
78
- return (value as Chat[]).map((c) => c.id);
79
- }
80
- return [(value as Chat).id];
81
- }
@@ -1,55 +0,0 @@
1
- 'use client';
2
-
3
- import { IconDepartment } from '@client/src/components/business-ui/department-select/icon-department';
4
- import type { Department } from '@client/src/components/business-ui/department-select/types';
5
- import { BaseComboboxItem } from '@client/src/components/business-ui/entity-combobox/base-combobox-item';
6
- import { HighlightText } from '@client/src/components/business-ui/entity-combobox/highlight-text';
7
- import {
8
- listItemAvatarVariants,
9
- listItemNameVariants,
10
- listItemVariants,
11
- type ComboboxSize,
12
- } from '@client/src/components/business-ui/entity-combobox/size-variants';
13
- import { cn } from '@/lib/utils';
14
-
15
- export const DepartmentItem = ({
16
- departmentValue,
17
- isSelected,
18
- className,
19
- size = 'medium',
20
- searchKeyword,
21
- disabled,
22
- }: {
23
- departmentValue: Department;
24
- isSelected: boolean;
25
- className?: string;
26
- size?: ComboboxSize;
27
- searchKeyword?: string;
28
- disabled?: boolean;
29
- }) => {
30
- return (
31
- <BaseComboboxItem
32
- item={departmentValue}
33
- getItemValue={(item) => item}
34
- isSelected={isSelected}
35
- className={cn(listItemVariants({ size }), className)}
36
- disabled={disabled}
37
- >
38
- <div
39
- className={cn(
40
- 'flex items-center justify-center',
41
- listItemAvatarVariants({ size }),
42
- )}
43
- >
44
- <IconDepartment className={listItemAvatarVariants({ size })} />
45
- </div>
46
- <div className="flex min-w-0 flex-1 flex-col">
47
- <HighlightText
48
- text={departmentValue.name}
49
- highlight={searchKeyword}
50
- className={listItemNameVariants({ size })}
51
- />
52
- </div>
53
- </BaseComboboxItem>
54
- );
55
- };
@@ -1,86 +0,0 @@
1
- import {
2
- DepartmentSelect,
3
- type DepartmentSelectProps,
4
- } from '@client/src/components/business-ui/department-select';
5
- import type { Department } from '@client/src/components/business-ui/department-select/types';
6
- import { useFormGlobalProps } from '@client/src/components/business-ui/form/context';
7
- import { FieldLayout } from '@client/src/components/business-ui/form/field-layout';
8
- import { useFieldContext } from '@client/src/components/business-ui/form/hooks/form-context';
9
- import {
10
- useFieldName,
11
- useFieldValidation,
12
- } from '@client/src/components/business-ui/form/hooks/form-utils';
13
- import type {
14
- CommonFieldProps,
15
- FieldLayoutClassNames,
16
- FieldLayoutStyles,
17
- } from '@client/src/components/business-ui/form/types';
18
-
19
- type DepartmentSelectFieldProps = CommonFieldProps &
20
- Omit<
21
- DepartmentSelectProps,
22
- 'value' | 'onChange' | 'defaultValue' | 'name' | 'required'
23
- > & {
24
- classNames?: Partial<
25
- FieldLayoutClassNames & {
26
- DepartmentSelect: string;
27
- }
28
- >;
29
- styles?: Partial<
30
- FieldLayoutStyles & {
31
- DepartmentSelect: React.CSSProperties;
32
- }
33
- >;
34
- };
35
-
36
- export function DepartmentSelectField(props: DepartmentSelectFieldProps) {
37
- const {
38
- label,
39
- description,
40
- required,
41
- disabled,
42
- classNames,
43
- layout = 'vertical',
44
- styles,
45
- multiple,
46
- ...departmentSelectProps
47
- } = props;
48
-
49
- const field = useFieldContext<Department | Department[] | null>();
50
- const { isInvalid, errorMessage } = useFieldValidation();
51
- const { layout: formLayout } = useFormGlobalProps();
52
- const name = useFieldName();
53
-
54
- const {
55
- DepartmentSelect: departmentSelectClassName,
56
- ...fieldLayoutClassNames
57
- } = classNames ?? {};
58
- const fieldLayoutStyles = styles ?? {};
59
-
60
- return (
61
- <FieldLayout
62
- label={label}
63
- description={description}
64
- isInvalid={isInvalid}
65
- required={required ?? false}
66
- layout={layout ?? formLayout ?? 'vertical'}
67
- classNames={fieldLayoutClassNames ?? {}}
68
- styles={fieldLayoutStyles ?? {}}
69
- errorMessage={errorMessage}
70
- name={name}
71
- >
72
- <DepartmentSelect
73
- {...departmentSelectProps}
74
- multiple={multiple}
75
- value={field.state.value ?? (multiple ? [] : null)}
76
- onChange={(value: Department | Department[] | null) => {
77
- field.handleChange(value);
78
- }}
79
- disabled={disabled ?? false}
80
- name={name}
81
- required={required}
82
- className={departmentSelectClassName}
83
- />
84
- </FieldLayout>
85
- );
86
- }