@yoka-ui/ui 1.1.0 → 1.1.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/@Docs-yoka/exports.generated.md +53 -4
- package/LICENSE +21 -0
- package/dist/es/assets/image/skills.zip +0 -0
- package/dist/es/business/AiChat/aichat-logo.svg +1 -0
- package/dist/es/business/AiChat/index.js +20 -45
- package/dist/es/business/AiChat/index.js.map +2 -2
- package/dist/es/business/AiChat/index.module.less +24 -0
- package/dist/es/business/AiChat/useAiChat.js +41 -24
- package/dist/es/business/AiChat/useAiChat.js.map +2 -2
- package/dist/es/business/Editor/index.d.ts +2 -2
- package/dist/es/business/Editor/index.js.map +2 -2
- package/dist/es/business/Empty/index.d.ts +1 -1
- package/dist/es/business/Empty/index.js.map +1 -1
- package/dist/es/business/ModCommonFilter/index.d.ts +1 -0
- package/dist/es/business/ModCommonFilter/index.js.map +2 -2
- package/dist/es/business/YkLoginModule/index.d.ts +1 -0
- package/dist/es/business/YkLoginModule/index.js.map +2 -2
- package/dist/es/business/YkPorjectSelect/index.d.ts +3 -3
- package/dist/es/business/YkPorjectSelect/index.js +37 -51
- package/dist/es/business/YkPorjectSelect/index.js.map +2 -2
- package/dist/es/business/YkSqlEdit/index.d.ts +1 -0
- package/dist/es/business/YkSqlEdit/index.js.map +2 -2
- package/dist/es/components/Clock/index.d.ts +2 -2
- package/dist/es/components/Clock/index.js.map +2 -2
- package/dist/es/components/DebounceInput/index.d.ts +2 -2
- package/dist/es/components/DebounceInput/index.js.map +2 -2
- package/dist/es/components/MultipleSelect/index.d.ts +2 -2
- package/dist/es/components/MultipleSelect/index.js.map +2 -2
- package/dist/es/components/RefreshButton/index.d.ts +2 -2
- package/dist/es/components/RefreshButton/index.js.map +2 -2
- package/dist/es/components/SearchWithHistory/index.d.ts +1 -1
- package/dist/es/components/SearchWithHistory/index.js.map +1 -1
- package/dist/es/components/TextWithInput/index.d.ts +2 -5
- package/dist/es/components/TextWithInput/index.js.map +2 -2
- package/dist/es/components/TextWithToolTip/index.d.ts +2 -2
- package/dist/es/components/TextWithToolTip/index.js.map +2 -2
- package/dist/es/components/TreeTransfer/index.d.ts +1 -0
- package/dist/es/components/TreeTransfer/index.js.map +2 -2
- package/dist/es/index.d.ts +29 -0
- package/dist/es/index.js.map +2 -2
- package/dist/es/index.less +1 -0
- package/dist/lib/assets/image/skills.zip +0 -0
- package/dist/lib/business/AiChat/aichat-logo.svg +1 -0
- package/dist/lib/business/AiChat/index.js +20 -45
- package/dist/lib/business/AiChat/index.js.map +3 -3
- package/dist/lib/business/AiChat/index.module.less +24 -0
- package/dist/lib/business/AiChat/useAiChat.js +40 -22
- package/dist/lib/business/AiChat/useAiChat.js.map +2 -2
- package/dist/lib/business/Editor/index.d.ts +2 -2
- package/dist/lib/business/Editor/index.js.map +2 -2
- package/dist/lib/business/Empty/index.d.ts +1 -1
- package/dist/lib/business/Empty/index.js.map +1 -1
- package/dist/lib/business/ModCommonFilter/index.d.ts +1 -0
- package/dist/lib/business/ModCommonFilter/index.js.map +2 -2
- package/dist/lib/business/YkLoginModule/index.d.ts +1 -0
- package/dist/lib/business/YkLoginModule/index.js.map +2 -2
- package/dist/lib/business/YkPorjectSelect/index.d.ts +3 -3
- package/dist/lib/business/YkPorjectSelect/index.js +33 -27
- package/dist/lib/business/YkPorjectSelect/index.js.map +2 -2
- package/dist/lib/business/YkSqlEdit/index.d.ts +1 -0
- package/dist/lib/business/YkSqlEdit/index.js.map +2 -2
- package/dist/lib/components/Clock/index.d.ts +2 -2
- package/dist/lib/components/Clock/index.js.map +2 -2
- package/dist/lib/components/DebounceInput/index.d.ts +2 -2
- package/dist/lib/components/DebounceInput/index.js.map +2 -2
- package/dist/lib/components/MultipleSelect/index.d.ts +2 -2
- package/dist/lib/components/MultipleSelect/index.js.map +2 -2
- package/dist/lib/components/RefreshButton/index.d.ts +2 -2
- package/dist/lib/components/RefreshButton/index.js.map +2 -2
- package/dist/lib/components/SearchWithHistory/index.d.ts +1 -1
- package/dist/lib/components/SearchWithHistory/index.js.map +1 -1
- package/dist/lib/components/TextWithInput/index.d.ts +2 -5
- package/dist/lib/components/TextWithInput/index.js.map +2 -2
- package/dist/lib/components/TextWithToolTip/index.d.ts +2 -2
- package/dist/lib/components/TextWithToolTip/index.js.map +2 -2
- package/dist/lib/components/TreeTransfer/index.d.ts +1 -0
- package/dist/lib/components/TreeTransfer/index.js.map +2 -2
- package/dist/lib/index.d.ts +29 -0
- package/dist/lib/index.js.map +2 -2
- package/dist/lib/index.less +1 -0
- package/package.json +7 -3
|
@@ -40,7 +40,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
40
40
|
|
|
41
41
|
// src/business/AiChat/useAiChat.ts
|
|
42
42
|
import { message } from "antd";
|
|
43
|
-
import { useCallback, useEffect, useState } from "react";
|
|
43
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
44
44
|
import { createSSE } from "./sse";
|
|
45
45
|
function useAiChat(options) {
|
|
46
46
|
const apiPath = (options == null ? void 0 : options.apiPath) || "/api/ai/chat-stream";
|
|
@@ -50,6 +50,8 @@ function useAiChat(options) {
|
|
|
50
50
|
const [loading, setLoading] = useState(false);
|
|
51
51
|
const [cancelFn, setCancelFn] = useState(null);
|
|
52
52
|
const [visible, setVisible] = useState(false);
|
|
53
|
+
const activeSessionRef = useRef(activeSession);
|
|
54
|
+
activeSessionRef.current = activeSession;
|
|
53
55
|
useEffect(() => {
|
|
54
56
|
const loadSessions = () => __async(this, null, function* () {
|
|
55
57
|
if (options == null ? void 0 : options.onFetchSessions) {
|
|
@@ -62,12 +64,16 @@ function useAiChat(options) {
|
|
|
62
64
|
console.error("加载会话失败:", err);
|
|
63
65
|
}
|
|
64
66
|
} else {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
try {
|
|
68
|
+
const saved = localStorage.getItem(storageKey);
|
|
69
|
+
if (saved) {
|
|
70
|
+
const list = JSON.parse(saved);
|
|
71
|
+
setSessions(list);
|
|
72
|
+
if (list.length > 0)
|
|
73
|
+
setActiveSession(list[list.length - 1]);
|
|
74
|
+
}
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.error("localStorage 解析失败:", err);
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
});
|
|
@@ -122,14 +128,17 @@ function useAiChat(options) {
|
|
|
122
128
|
);
|
|
123
129
|
const deleteSession = useCallback(
|
|
124
130
|
(id, e) => {
|
|
125
|
-
var _a;
|
|
126
131
|
e.stopPropagation();
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
setSessions((prev) => {
|
|
133
|
+
var _a, _b;
|
|
134
|
+
const ns = prev.filter((x) => x.id !== id);
|
|
135
|
+
if (((_a = activeSessionRef.current) == null ? void 0 : _a.id) === id) {
|
|
136
|
+
setActiveSession((_b = ns.at(-1)) != null ? _b : null);
|
|
137
|
+
}
|
|
138
|
+
return ns;
|
|
139
|
+
});
|
|
131
140
|
},
|
|
132
|
-
[
|
|
141
|
+
[]
|
|
133
142
|
);
|
|
134
143
|
const sendQuestion = useCallback(
|
|
135
144
|
(content, regenId) => __async(this, null, function* () {
|
|
@@ -190,20 +199,28 @@ function useAiChat(options) {
|
|
|
190
199
|
sessionId: activeSession.id
|
|
191
200
|
},
|
|
192
201
|
(text) => {
|
|
193
|
-
if (!
|
|
202
|
+
if (!activeSessionRef.current)
|
|
194
203
|
return;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
204
|
+
setActiveSession((cur) => {
|
|
205
|
+
if (!cur)
|
|
206
|
+
return cur;
|
|
207
|
+
const ms = cur.messages.map((m) => m.loading ? __spreadProps(__spreadValues({}, m), { content: m.content + text }) : m);
|
|
208
|
+
const su = __spreadProps(__spreadValues({}, cur), { messages: ms });
|
|
209
|
+
setSessions((prev) => prev.map((x) => x.id === su.id ? su : x));
|
|
210
|
+
return su;
|
|
211
|
+
});
|
|
199
212
|
},
|
|
200
213
|
() => {
|
|
201
214
|
var _a2;
|
|
202
215
|
setLoading(false);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
216
|
+
setActiveSession((cur) => {
|
|
217
|
+
if (!cur)
|
|
218
|
+
return cur;
|
|
219
|
+
const ms = cur.messages.map((m) => m.loading ? __spreadProps(__spreadValues({}, m), { loading: false }) : m);
|
|
220
|
+
const su = __spreadProps(__spreadValues({}, cur), { messages: ms });
|
|
221
|
+
setSessions((prev) => prev.map((x) => x.id === su.id ? su : x));
|
|
222
|
+
return su;
|
|
223
|
+
});
|
|
207
224
|
(_a2 = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a2.call(options);
|
|
208
225
|
},
|
|
209
226
|
(err) => {
|
|
@@ -214,7 +231,7 @@ function useAiChat(options) {
|
|
|
214
231
|
(_a2 = options == null ? void 0 : options.onError) == null ? void 0 : _a2.call(options, err);
|
|
215
232
|
}
|
|
216
233
|
);
|
|
217
|
-
setCancelFn(
|
|
234
|
+
setCancelFn(cancel);
|
|
218
235
|
}
|
|
219
236
|
}),
|
|
220
237
|
[activeSession, apiPath, options]
|
|
@@ -246,7 +263,7 @@ function useAiChat(options) {
|
|
|
246
263
|
cancelFn == null ? void 0 : cancelFn();
|
|
247
264
|
setLoading(false);
|
|
248
265
|
}, [cancelFn]);
|
|
249
|
-
const toggleVisible = useCallback((v) => setVisible(v != null ? v : !
|
|
266
|
+
const toggleVisible = useCallback((v) => setVisible(v != null ? v : (prev) => !prev), []);
|
|
250
267
|
return {
|
|
251
268
|
sessions,
|
|
252
269
|
activeSession,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/business/AiChat/useAiChat.ts"],
|
|
4
|
-
"sourcesContent": ["import { message } from 'antd';\nimport { useCallback, useEffect, useState } from 'react';\nimport { createSSE } from './sse';\nimport type { ChatSession, Message, UseAiChatOptions, UseAiChatReturn } from './type';\n\nexport function useAiChat(options?: UseAiChatOptions): UseAiChatReturn {\n const apiPath = options?.apiPath || '/api/ai/chat-stream';\n const storageKey = options?.storageKey || 'ai_chat_sessions';\n\n const [sessions, setSessions] = useState<ChatSession[]>([]);\n const [activeSession, setActiveSession] = useState<ChatSession | null>(null);\n const [loading, setLoading] = useState(false);\n const [cancelFn, setCancelFn] = useState<(() => void) | null>(null);\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n const loadSessions = async () => {\n if (options?.onFetchSessions) {\n try {\n const list = await options.onFetchSessions();\n setSessions(list);\n if (list.length > 0) setActiveSession(list[list.length - 1]);\n } catch (err) {\n console.error('加载会话失败:', err);\n }\n } else {\n const saved = localStorage.getItem(storageKey);\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AACxB,SAAS,aAAa,WAAW,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { message } from 'antd';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { createSSE } from './sse';\nimport type { ChatSession, Message, UseAiChatOptions, UseAiChatReturn } from './type';\n\nexport function useAiChat(options?: UseAiChatOptions): UseAiChatReturn {\n const apiPath = options?.apiPath || '/api/ai/chat-stream';\n const storageKey = options?.storageKey || 'ai_chat_sessions';\n\n const [sessions, setSessions] = useState<ChatSession[]>([]);\n const [activeSession, setActiveSession] = useState<ChatSession | null>(null);\n const [loading, setLoading] = useState(false);\n const [cancelFn, setCancelFn] = useState<(() => void) | null>(null);\n const [visible, setVisible] = useState(false);\n\n // 使用 ref 避免 SSE 回调中的 stale closure\n const activeSessionRef = useRef(activeSession);\n activeSessionRef.current = activeSession;\n\n useEffect(() => {\n const loadSessions = async () => {\n if (options?.onFetchSessions) {\n try {\n const list = await options.onFetchSessions();\n setSessions(list);\n if (list.length > 0) setActiveSession(list[list.length - 1]);\n } catch (err) {\n console.error('加载会话失败:', err);\n }\n } else {\n try {\n const saved = localStorage.getItem(storageKey);\n if (saved) {\n const list = JSON.parse(saved);\n setSessions(list);\n if (list.length > 0) setActiveSession(list[list.length - 1]);\n }\n } catch (err) {\n console.error('localStorage 解析失败:', err);\n }\n }\n };\n loadSessions();\n }, [storageKey, options?.onFetchSessions]);\n\n useEffect(() => {\n if (!options?.onFetchSessions && sessions.length) {\n localStorage.setItem(storageKey, JSON.stringify(sessions));\n }\n }, [sessions, storageKey, options?.onFetchSessions]);\n\n const createNewSession = useCallback(async () => {\n let newSessionId: string;\n\n if (options?.onCreateSession) {\n try {\n const result = await options.onCreateSession();\n newSessionId = result.sessionId;\n } catch (err) {\n console.error('创建会话失败:', err);\n message.error('创建会话失败');\n return;\n }\n } else {\n newSessionId = Date.now().toString();\n }\n\n const s: ChatSession = {\n id: newSessionId,\n title: '新会话',\n createTime: Date.now(),\n messages: [],\n };\n setSessions((prev) => [...prev, s]);\n setActiveSession(s);\n setVisible(true);\n }, [options?.onCreateSession]);\n\n const switchSession = useCallback(\n async (id: string) => {\n if (options?.onFetchSessionDetail) {\n try {\n const detail = await options.onFetchSessionDetail(id);\n setActiveSession(detail);\n } catch (err) {\n console.error('获取会话详情失败:', err);\n message.error('获取会话详情失败');\n }\n } else {\n const s = sessions.find((x) => x.id === id);\n if (s) setActiveSession(s);\n }\n },\n [sessions, options?.onFetchSessionDetail],\n );\n\n const deleteSession = useCallback(\n (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n setSessions((prev) => {\n const ns = prev.filter((x) => x.id !== id);\n // 若删除的是当前活跃会话,切换到最后一个\n if (activeSessionRef.current?.id === id) {\n setActiveSession(ns.at(-1) ?? null);\n }\n return ns;\n });\n },\n [],\n );\n\n const sendQuestion = useCallback(\n async (content: string, regenId?: string) => {\n if (!content.trim() || !activeSession) return;\n\n if (options?.onBeforeSend) {\n const canSend = await options.onBeforeSend(content);\n if (!canSend) return;\n }\n\n const user: Message = { id: `${Date.now()}_u`, role: 'user', content };\n const ai: Message = {\n id: `${Date.now()}_ai`,\n role: 'ai',\n content: '',\n loading: true,\n };\n\n let newMsgs: Message[] = [];\n if (regenId) {\n newMsgs = activeSession.messages.map((m) => (m.id === regenId ? ai : m));\n } else {\n newMsgs = [...activeSession.messages, user, ai];\n }\n\n const updated: ChatSession = {\n ...activeSession,\n title: activeSession.messages.length === 0 ? content.slice(0, 20) : activeSession.title,\n messages: newMsgs,\n };\n setActiveSession(updated);\n setSessions((prev) => prev.map((x) => (x.id === updated.id ? updated : x)));\n\n setLoading(true);\n\n // 如果提供了 onSendMessage 回调,则使用自定义发送逻辑\n if (options?.onSendMessage) {\n try {\n await options.onSendMessage({\n sessionId: activeSession.id,\n prompt: content,\n history: updated.messages.filter((m) => !m.loading),\n });\n setLoading(false);\n const ms = updated.messages.map((m) => (m.loading ? { ...m, loading: false } : m));\n const su = { ...updated, messages: ms };\n setActiveSession(su);\n setSessions((prev) => prev.map((x) => (x.id === su.id ? su : x)));\n options?.onSuccess?.();\n } catch (err) {\n setLoading(false);\n const error = err as Error;\n message.error(`请求异常:${error.message}`);\n options?.onError?.(error);\n }\n } else {\n // 使用默认 SSE 逻辑\n const cancel = await createSSE(\n apiPath,\n {\n prompt: content,\n history: updated.messages.filter((m) => !m.loading),\n useMcp: true,\n sessionId: activeSession.id,\n },\n (text) => {\n if (!activeSessionRef.current) return;\n setActiveSession((cur) => {\n if (!cur) return cur;\n const ms = cur.messages.map((m) => (m.loading ? { ...m, content: m.content + text } : m));\n const su = { ...cur, messages: ms };\n setSessions((prev) => prev.map((x) => (x.id === su.id ? su : x)));\n return su;\n });\n },\n () => {\n setLoading(false);\n setActiveSession((cur) => {\n if (!cur) return cur;\n const ms = cur.messages.map((m) => (m.loading ? { ...m, loading: false } : m));\n const su = { ...cur, messages: ms };\n setSessions((prev) => prev.map((x) => (x.id === su.id ? su : x)));\n return su;\n });\n options?.onSuccess?.();\n },\n (err) => {\n setLoading(false);\n const errorMsg = err.message;\n message.error(`请求异常:${errorMsg}`);\n options?.onError?.(err);\n },\n );\n setCancelFn(cancel);\n }\n },\n [activeSession, apiPath, options],\n );\n\n const regenerateAnswer = useCallback(\n (msg: Message) => {\n if (!activeSession) return;\n const idx = activeSession.messages.findIndex((x) => x.id === msg.id);\n const userMsg = activeSession.messages[idx - 1];\n if (userMsg?.role === 'user') sendQuestion(userMsg.content, msg.id);\n },\n [activeSession, sendQuestion],\n );\n\n const deleteSingleMsg = useCallback(\n (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (!activeSession) return;\n const ms = activeSession.messages.filter((x) => x.id !== id);\n const up = { ...activeSession, messages: ms };\n setActiveSession(up);\n setSessions((prev) => prev.map((x) => (x.id === up.id ? up : x)));\n },\n [activeSession],\n );\n\n const cancelRequest = useCallback(() => {\n cancelFn?.();\n setLoading(false);\n }, [cancelFn]);\n\n const toggleVisible = useCallback((v?: boolean) => setVisible(v ?? ((prev) => !prev)), []);\n\n return {\n sessions,\n activeSession,\n loading,\n visible,\n createNewSession,\n switchSession,\n deleteSession,\n sendQuestion,\n regenerateAnswer,\n deleteSingleMsg,\n cancelRequest,\n toggleVisible,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["_a"]
|
|
7
7
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import '@wangeditor/editor/dist/css/style.css';
|
|
2
2
|
import React, { type FC } from 'react';
|
|
3
3
|
import './index.less';
|
|
4
|
-
type
|
|
4
|
+
export type EditorProps = {
|
|
5
5
|
value: string;
|
|
6
6
|
onChange?: (value: string) => void;
|
|
7
7
|
style?: React.CSSProperties;
|
|
8
8
|
readOnly?: boolean;
|
|
9
9
|
};
|
|
10
|
-
declare const NoteEditor: FC<
|
|
10
|
+
declare const NoteEditor: FC<EditorProps>;
|
|
11
11
|
export default NoteEditor;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/business/Editor/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { IDomEditor, IEditorConfig } from '@wangeditor/editor';\nimport { Editor } from '@wangeditor/editor-for-react';\nimport '@wangeditor/editor/dist/css/style.css'; // 引入 css\nimport React, { type FC, useEffect, useState } from 'react';\nimport './index.less';\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AACA,SAAS,cAAc;AACvB,OAAO;AACP,OAAO,SAAkB,WAAW,gBAAgB;AACpD,OAAO;AASP,IAAM,
|
|
4
|
+
"sourcesContent": ["import type { IDomEditor, IEditorConfig } from '@wangeditor/editor';\nimport { Editor } from '@wangeditor/editor-for-react';\nimport '@wangeditor/editor/dist/css/style.css'; // 引入 css\nimport React, { type FC, useEffect, useState } from 'react';\nimport './index.less';\n\nexport type EditorProps = {\n value: string;\n onChange?: (value: string) => void;\n style?: React.CSSProperties;\n readOnly?: boolean;\n};\n\nconst NoteEditor: FC<EditorProps> = ({ value, onChange, style, readOnly = false }) => {\n // editor 实例\n const [editor, setEditor] = useState<IDomEditor | null>(null);\n\n // 编辑器配置\n const editorConfig: Partial<IEditorConfig> = {\n placeholder: '请输入内容...',\n readOnly: readOnly,\n // 配置 hoverbar 菜单项\n hoverbarKeys: {\n text: {\n menuKeys: [\n 'headerSelect', // N级标题\n 'justifyLeft', // 左对齐按钮\n 'justifyCenter', // 居中按钮\n 'justifyRight', // 右对齐按钮\n 'bulletedList', // 无序列表\n 'numberedList', // 有序列表\n '|', // 分隔符\n 'color', // 字色\n 'bgColor', // 字背景\n 'bold', // 加粗按钮\n 'through', // 删除按钮(删除线)\n 'italic', // 斜体按钮\n 'underline', // 下划线按钮\n ],\n },\n },\n };\n\n // 及时销毁 editor ,重要!\n useEffect(() => {\n return () => {\n if (editor === null) return;\n editor.destroy();\n setEditor(null);\n };\n }, [editor]);\n\n return (\n <Editor\n defaultConfig={editorConfig}\n value={value}\n onCreated={setEditor}\n onChange={(editor) => onChange?.(editor.getHtml())}\n mode='default'\n style={{ ...style }}\n />\n );\n};\n\nexport default NoteEditor;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AACA,SAAS,cAAc;AACvB,OAAO;AACP,OAAO,SAAkB,WAAW,gBAAgB;AACpD,OAAO;AASP,IAAM,aAA8B,CAAC,EAAE,OAAO,UAAU,OAAO,WAAW,MAAM,MAAM;AAEpF,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA4B,IAAI;AAG5D,QAAM,eAAuC;AAAA,IAC3C,aAAa;AAAA,IACb;AAAA;AAAA,IAEA,cAAc;AAAA,MACZ,MAAM;AAAA,QACJ,UAAU;AAAA,UACR;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,UACA;AAAA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,YAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,WAAW;AAAM;AACrB,aAAO,QAAQ;AACf,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAe;AAAA,MACf;AAAA,MACA,WAAW;AAAA,MACX,UAAU,CAACA,YAAW,qCAAWA,QAAO,QAAQ;AAAA,MAChD,MAAK;AAAA,MACL,OAAO,mBAAK;AAAA;AAAA,EACd;AAEJ;AAEA,IAAO,iBAAQ;",
|
|
6
6
|
"names": ["editor"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/business/Empty/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Empty, Flex } from 'antd';\nimport type { ForwardedRef } from 'react';\nimport React from 'react';\nimport EmptyImg from './empty.png';\n\n/**\n * 空状态占位组件的 Props(ref 由 forwardRef 注入,无需在 props 中声明)\n */\
|
|
4
|
+
"sourcesContent": ["import { Empty, Flex } from 'antd';\nimport type { ForwardedRef } from 'react';\nimport React from 'react';\nimport EmptyImg from './empty.png';\n\n/**\n * 空状态占位组件的 Props(ref 由 forwardRef 注入,无需在 props 中声明)\n */\nexport type EmptyProps = {\n /** 空状态插图,不传则使用默认 empty.png */\n image?: React.ReactNode | string;\n /** 描述文案或自定义节点,默认「暂无数据」 */\n description?: string | React.ReactNode;\n /** 图片容器样式,会与默认宽高合并 */\n imageStyle?: React.CSSProperties;\n /** 根节点 Flex 的样式 */\n style?: React.CSSProperties;\n};\n\n/** 描述文字统一样式 */\nconst descriptionStyle: React.CSSProperties = {\n color: '#999',\n fontSize: 14,\n height: 20,\n lineHeight: '20px',\n};\n\n/**\n * 空状态占位:居中展示默认图 + 描述,支持自定义图片与文案,支持 ref 透传。\n */\nconst ForwardedEmptyPlaceholder = React.forwardRef(\n ({ image, description, imageStyle = {}, style = {} }: EmptyProps, ref: ForwardedRef<HTMLDivElement>) => {\n return (\n <Flex ref={ref} style={{ padding: '80px 0', ...style }} align='center' justify='center'>\n <Empty\n image={image || EmptyImg}\n styles={{\n image: {\n height: 60,\n width: 150,\n display: 'inline-block',\n ...imageStyle,\n },\n }}\n description={\n description == null || description === '' ? (\n <span style={descriptionStyle}>暂无数据</span>\n ) : typeof description === 'string' ? (\n <span style={descriptionStyle}>{description}</span>\n ) : (\n description\n )\n }\n />\n </Flex>\n );\n },\n);\n\nForwardedEmptyPlaceholder.displayName = 'Empty';\n\nexport default ForwardedEmptyPlaceholder;\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA,SAAS,OAAO,YAAY;AAE5B,OAAO,WAAW;AAClB,OAAO,cAAc;AAiBrB,IAAM,mBAAwC;AAAA,EAC5C,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AACd;AAKA,IAAM,4BAA4B,MAAM;AAAA,EACtC,CAAC,EAAE,OAAO,aAAa,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAe,QAAsC;AACtG,WACE,oCAAC,QAAK,KAAU,OAAO,iBAAE,SAAS,YAAa,QAAS,OAAM,UAAS,SAAQ,YAC7E;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,SAAS;AAAA,QAChB,QAAQ;AAAA,UACN,OAAO;AAAA,YACL,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,SAAS;AAAA,aACN;AAAA,QAEP;AAAA,QACA,aACE,eAAe,QAAQ,gBAAgB,KACrC,oCAAC,UAAK,OAAO,oBAAkB,MAAI,IACjC,OAAO,gBAAgB,WACzB,oCAAC,UAAK,OAAO,oBAAmB,WAAY,IAE5C;AAAA;AAAA,IAGN,CACF;AAAA,EAEJ;AACF;AAEA,0BAA0B,cAAc;AAExC,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/business/ModCommonFilter/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Popover, type PopoverProps } from 'antd';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport FilterButton from './components/FilterButton';\nimport PopoverContent from './components/PopoverContent';\nimport styles from './index.module.less';\nimport type { CategoryItem, ListItem, TerminalItem } from './typing';\n\n/**\n * 通用筛选器组件的 Props\n */\nexport interface ModCommonFilterProps {\n /** 当前选中的值(code 数组),受控 */\n value: string[];\n /** 选中项变化回调 */\n onChange: (value: string[]) => void;\n /** 可选列表数据 */\n list: ListItem[];\n /** 筛选维度名称,如「品类」「品牌」 */\n title: string;\n /** 按钮/标题前缀文案,如「筛选」 */\n prefixTitle?: string;\n /** 按钮左侧图标 */\n iconPrefix?: React.ReactNode;\n /** 分类列表,有则弹层左侧展示分类 Tab */\n category?: CategoryItem[];\n /** 终端列表,有则弹层内展示终端 Tab(如全部/PC/APP) */\n terminal?: TerminalItem[];\n /** 搜索框占位文案 */\n placeholder?: string;\n /** Popover 层级 */\n zIndex?: number;\n /** Popover 弹出方向 */\n placement?: PopoverProps['placement'];\n /** 透传给 antd Popover 的额外属性 */\n popoverProps?: PopoverProps;\n /** 可选列表列数(多列网格) */\n columnCount?: number;\n /** 内容区宽度 */\n contentWidth?: number;\n /** 列表行高 */\n rowHeight?: number;\n /** 是否在名称后展示 code */\n showCode?: boolean;\n /** 可选列表中每项的自定义渲染 */\n cellRender?: (item: ListItem) => React.ReactNode;\n /** 已选列表中每项的自定义渲染 */\n checkedCellRender?: (item: ListItem) => React.ReactNode;\n /** 弹层底部备注文案或节点 */\n remark?: string | React.ReactNode;\n /** 自定义触发区域,不传则使用默认 FilterButton */\n filterChildren?: React.ReactNode;\n}\n\n/**\n * 通用筛选器:点击按钮打开 Popover,内为分类 + 可选列表 + 已选列表,确认后回调 onChange。\n */\nconst ModCommonFilter: React.FC<ModCommonFilterProps> = ({\n value,\n onChange,\n list,\n title,\n prefixTitle,\n iconPrefix,\n category,\n terminal,\n placeholder = '搜索',\n zIndex = 100,\n placement = 'bottomRight',\n columnCount = 1,\n contentWidth,\n rowHeight,\n showCode = false,\n popoverProps = {},\n cellRender,\n checkedCellRender,\n remark,\n filterChildren,\n}) => {\n const [popOpen, setPopOpen] = useState(false);\n /** 弹层内当前选中的 code 列表,打开时与 value 同步 */\n const [selected, setSelected] = useState<string[]>([]);\n /** 当前选中的分类 code,空字符串表示「全部」 */\n const [categorySelected, setCategorySelected] = useState<string>('');\n\n /** 弹层打开时用外部 value 同步 selected,保证每次打开初始为当前已选 */\n useEffect(() => {\n if (popOpen) {\n setSelected(value || []);\n }\n }, [popOpen, value]);\n\n /** 分类选项列表,头部插入「全部{title}」 */\n const useCateGory = useMemo(() => {\n const newCategory: CategoryItem[] = category ? [...category] : [];\n newCategory.unshift({\n code: '',\n name: '全部' + title,\n });\n return newCategory;\n }, [category]);\n\n /** 确认:把当前选中回传并关闭弹层 */\n const handleVerify = () => {\n onChange(selected);\n setPopOpen(false);\n };\n\n /** 取消:恢复为打开前的 value 并关闭弹层 */\n const handleClear = () => {\n setSelected(value || []);\n setPopOpen(false);\n };\n\n return (\n <Popover\n className={styles.modCommonFilter}\n open={popOpen}\n onOpenChange={(open) => setPopOpen(open)}\n title={false}\n fresh={true}\n arrow={false}\n zIndex={zIndex}\n placement={placement}\n trigger='click'\n classNames={{\n body: styles.popoverBody,\n }}\n getPopupContainer={(triggerNode) => triggerNode.parentNode as HTMLElement}\n content={\n <PopoverContent\n popOpen={popOpen}\n selected={selected}\n setSelected={setSelected}\n category={useCateGory}\n terminal={terminal}\n list={list}\n placeholder={placeholder}\n title={title}\n categorySelected={categorySelected}\n setCategorySelected={setCategorySelected}\n columnCount={columnCount}\n showCode={showCode}\n contentWidth={contentWidth}\n rowHeight={rowHeight}\n cellRender={cellRender}\n checkedCellRender={checkedCellRender}\n handleVerify={handleVerify}\n handleClear={handleClear}\n remark={remark}\n />\n }\n {...popoverProps}\n >\n {filterChildren || (\n <FilterButton\n iconPrefix={iconPrefix}\n title={title}\n prefixTitle={prefixTitle}\n value={value}\n popOpen={popOpen}\n handlePopOpen={() => setPopOpen(!popOpen)}\n handleClear={() => onChange([])}\n />\n )}\n </Popover>\n );\n};\n\nexport default ModCommonFilter;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAkC;AAC3C,OAAO,SAAS,WAAW,SAAS,gBAAgB;AACpD,OAAO,kBAAkB;AACzB,OAAO,oBAAoB;AAC3B,OAAO,YAAY;
|
|
4
|
+
"sourcesContent": ["import { Popover, type PopoverProps } from 'antd';\nimport React, { useEffect, useMemo, useState } from 'react';\nimport FilterButton from './components/FilterButton';\nimport PopoverContent from './components/PopoverContent';\nimport styles from './index.module.less';\nimport type { CategoryItem, ListItem, TerminalItem } from './typing';\n\nexport type { ListItem, CategoryItem, TerminalItem } from './typing';\n\n/**\n * 通用筛选器组件的 Props\n */\nexport interface ModCommonFilterProps {\n /** 当前选中的值(code 数组),受控 */\n value: string[];\n /** 选中项变化回调 */\n onChange: (value: string[]) => void;\n /** 可选列表数据 */\n list: ListItem[];\n /** 筛选维度名称,如「品类」「品牌」 */\n title: string;\n /** 按钮/标题前缀文案,如「筛选」 */\n prefixTitle?: string;\n /** 按钮左侧图标 */\n iconPrefix?: React.ReactNode;\n /** 分类列表,有则弹层左侧展示分类 Tab */\n category?: CategoryItem[];\n /** 终端列表,有则弹层内展示终端 Tab(如全部/PC/APP) */\n terminal?: TerminalItem[];\n /** 搜索框占位文案 */\n placeholder?: string;\n /** Popover 层级 */\n zIndex?: number;\n /** Popover 弹出方向 */\n placement?: PopoverProps['placement'];\n /** 透传给 antd Popover 的额外属性 */\n popoverProps?: PopoverProps;\n /** 可选列表列数(多列网格) */\n columnCount?: number;\n /** 内容区宽度 */\n contentWidth?: number;\n /** 列表行高 */\n rowHeight?: number;\n /** 是否在名称后展示 code */\n showCode?: boolean;\n /** 可选列表中每项的自定义渲染 */\n cellRender?: (item: ListItem) => React.ReactNode;\n /** 已选列表中每项的自定义渲染 */\n checkedCellRender?: (item: ListItem) => React.ReactNode;\n /** 弹层底部备注文案或节点 */\n remark?: string | React.ReactNode;\n /** 自定义触发区域,不传则使用默认 FilterButton */\n filterChildren?: React.ReactNode;\n}\n\n/**\n * 通用筛选器:点击按钮打开 Popover,内为分类 + 可选列表 + 已选列表,确认后回调 onChange。\n */\nconst ModCommonFilter: React.FC<ModCommonFilterProps> = ({\n value,\n onChange,\n list,\n title,\n prefixTitle,\n iconPrefix,\n category,\n terminal,\n placeholder = '搜索',\n zIndex = 100,\n placement = 'bottomRight',\n columnCount = 1,\n contentWidth,\n rowHeight,\n showCode = false,\n popoverProps = {},\n cellRender,\n checkedCellRender,\n remark,\n filterChildren,\n}) => {\n const [popOpen, setPopOpen] = useState(false);\n /** 弹层内当前选中的 code 列表,打开时与 value 同步 */\n const [selected, setSelected] = useState<string[]>([]);\n /** 当前选中的分类 code,空字符串表示「全部」 */\n const [categorySelected, setCategorySelected] = useState<string>('');\n\n /** 弹层打开时用外部 value 同步 selected,保证每次打开初始为当前已选 */\n useEffect(() => {\n if (popOpen) {\n setSelected(value || []);\n }\n }, [popOpen, value]);\n\n /** 分类选项列表,头部插入「全部{title}」 */\n const useCateGory = useMemo(() => {\n const newCategory: CategoryItem[] = category ? [...category] : [];\n newCategory.unshift({\n code: '',\n name: '全部' + title,\n });\n return newCategory;\n }, [category]);\n\n /** 确认:把当前选中回传并关闭弹层 */\n const handleVerify = () => {\n onChange(selected);\n setPopOpen(false);\n };\n\n /** 取消:恢复为打开前的 value 并关闭弹层 */\n const handleClear = () => {\n setSelected(value || []);\n setPopOpen(false);\n };\n\n return (\n <Popover\n className={styles.modCommonFilter}\n open={popOpen}\n onOpenChange={(open) => setPopOpen(open)}\n title={false}\n fresh={true}\n arrow={false}\n zIndex={zIndex}\n placement={placement}\n trigger='click'\n classNames={{\n body: styles.popoverBody,\n }}\n getPopupContainer={(triggerNode) => triggerNode.parentNode as HTMLElement}\n content={\n <PopoverContent\n popOpen={popOpen}\n selected={selected}\n setSelected={setSelected}\n category={useCateGory}\n terminal={terminal}\n list={list}\n placeholder={placeholder}\n title={title}\n categorySelected={categorySelected}\n setCategorySelected={setCategorySelected}\n columnCount={columnCount}\n showCode={showCode}\n contentWidth={contentWidth}\n rowHeight={rowHeight}\n cellRender={cellRender}\n checkedCellRender={checkedCellRender}\n handleVerify={handleVerify}\n handleClear={handleClear}\n remark={remark}\n />\n }\n {...popoverProps}\n >\n {filterChildren || (\n <FilterButton\n iconPrefix={iconPrefix}\n title={title}\n prefixTitle={prefixTitle}\n value={value}\n popOpen={popOpen}\n handlePopOpen={() => setPopOpen(!popOpen)}\n handleClear={() => onChange([])}\n />\n )}\n </Popover>\n );\n};\n\nexport default ModCommonFilter;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAkC;AAC3C,OAAO,SAAS,WAAW,SAAS,gBAAgB;AACpD,OAAO,kBAAkB;AACzB,OAAO,oBAAoB;AAC3B,OAAO,YAAY;AAsDnB,IAAM,kBAAkD,CAAC;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,eAAe,CAAC;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAmB,CAAC,CAAC;AAErD,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAiB,EAAE;AAGnE,YAAU,MAAM;AACd,QAAI,SAAS;AACX,kBAAY,SAAS,CAAC,CAAC;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,SAAS,KAAK,CAAC;AAGnB,QAAM,cAAc,QAAQ,MAAM;AAChC,UAAM,cAA8B,WAAW,CAAC,GAAG,QAAQ,IAAI,CAAC;AAChE,gBAAY,QAAQ;AAAA,MAClB,MAAM;AAAA,MACN,MAAM,OAAO;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,CAAC;AAGb,QAAM,eAAe,MAAM;AACzB,aAAS,QAAQ;AACjB,eAAW,KAAK;AAAA,EAClB;AAGA,QAAM,cAAc,MAAM;AACxB,gBAAY,SAAS,CAAC,CAAC;AACvB,eAAW,KAAK;AAAA,EAClB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,OAAO;AAAA,MAClB,MAAM;AAAA,MACN,cAAc,CAAC,SAAS,WAAW,IAAI;AAAA,MACvC,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,SAAQ;AAAA,MACR,YAAY;AAAA,QACV,MAAM,OAAO;AAAA,MACf;AAAA,MACA,mBAAmB,CAAC,gBAAgB,YAAY;AAAA,MAChD,SACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,OAEE;AAAA,IAEH,kBACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,MAAM,WAAW,CAAC,OAAO;AAAA,QACxC,aAAa,MAAM,SAAS,CAAC,CAAC;AAAA;AAAA,IAChC;AAAA,EAEJ;AAEJ;AAEA,IAAO,0BAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/business/YkLoginModule/index.tsx"],
|
|
4
|
-
"sourcesContent": ["import { LoginForm } from '@ant-design/pro-form';\nimport { Flex, message, QRCode, Tabs } from 'antd';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport SmsLoginForm, { type SmsLoginFormApi } from './SmsLoginForm';\nimport styles from './styles.module.less';\n\nexport type LoginType = 'qrcode' | 'sms';\n\nexport type LoginTabItem = {\n key: LoginType;\n label: React.ReactNode;\n};\n\nexport type QrcodeApi = {\n getQrcode: () => Promise<{ qrcode: string; url: string }>;\n scanLogin: (qrcode: string) => Promise<{\n code: number;\n data?: {\n status?: number;\n msg?: string;\n };\n }>;\n};\n\nexport type LoginModuleProps = {\n title: React.ReactNode;\n tabs: LoginTabItem[];\n defaultLoginType: LoginType;\n containerStyle?: React.CSSProperties;\n actions?: React.ReactNode | ((loginType: LoginType) => React.ReactNode);\n className?: string;\n formClassName?: string;\n tabsClassName?: string;\n inputClassName?: string;\n qrcodeClassName?: string;\n qrcodeBoxClassName?: string;\n\n onFinish: (values: Record<string, unknown>) => Promise<void>;\n\n qrcode?: {\n api: QrcodeApi;\n icon: string;\n iconSize?: number;\n size?: number;\n wrapStyle?: React.CSSProperties;\n onSuccess: () => void | Promise<void>;\n };\n\n sms?: {\n api: SmsLoginFormApi;\n appKey: string;\n };\n};\n\nconst DEFAULT_QRCODE_WRAP_STYLE: React.CSSProperties = {\n padding: 10,\n display: 'flex',\n justifyContent: 'center',\n};\n\nconst LoginModule: React.FC<LoginModuleProps> = (props) => {\n const {\n title,\n tabs,\n defaultLoginType,\n containerStyle,\n actions,\n onFinish,\n qrcode,\n className = styles.root,\n formClassName = styles.form,\n tabsClassName = styles.tabs,\n inputClassName,\n qrcodeClassName = styles.qrcode,\n qrcodeBoxClassName = styles.qrcodeBox,\n sms,\n } = props;\n\n const [loginType, setLoginType] = useState<LoginType>(defaultLoginType);\n\n const [qrcodeStatus, setQrcodeStatus] = useState<'active' | 'expired' | 'loading'>('active');\n const [qrcodeUrl, setQrcodeUrl] = useState<string>('-');\n const [qrcodeValue, setQrcodeValue] = useState<string>('');\n const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const pollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shouldShowSubmitter = loginType !== 'qrcode';\n\n const resolvedActions = useMemo(() => {\n if (!actions) return undefined;\n return typeof actions === 'function' ? actions(loginType) : actions;\n }, [actions, loginType]);\n\n const safeClearTimers = useCallback(() => {\n if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n if (pollTimeoutRef.current) clearTimeout(pollTimeoutRef.current);\n pollIntervalRef.current = null;\n pollTimeoutRef.current = null;\n }, []);\n\n const handleQrcodeRefresh = useCallback(async () => {\n if (!qrcode) return;\n setQrcodeStatus('loading');\n try {\n const res = await qrcode.api.getQrcode();\n setQrcodeUrl(res.url);\n setQrcodeValue(res.qrcode);\n setQrcodeStatus('active');\n } catch {\n setQrcodeStatus('expired');\n message.error('获取二维码失败,请稍后重试');\n }\n }, [qrcode]);\n\n const enabledTabKeys = useMemo(() => new Set(tabs.map((t) => t.key)), [tabs]);\n\n useEffect(() => {\n if (enabledTabKeys.has(defaultLoginType)) {\n setLoginType(defaultLoginType);\n return;\n }\n const fallback = tabs[0]?.key;\n if (fallback) setLoginType(fallback);\n }, [defaultLoginType, enabledTabKeys, tabs]);\n\n useEffect(() => {\n if (enabledTabKeys.has(loginType)) return;\n const fallback = tabs[0]?.key;\n if (fallback) setLoginType(fallback);\n }, [enabledTabKeys, loginType, tabs]);\n\n // 切到扫码登录时刷新二维码;离开扫码登录时停止轮询并标记过期\n useEffect(() => {\n safeClearTimers();\n if (loginType !== 'qrcode') {\n setQrcodeStatus('expired');\n return;\n }\n if (!qrcode) {\n setQrcodeStatus('expired');\n return;\n }\n void handleQrcodeRefresh();\n return safeClearTimers;\n }, [handleQrcodeRefresh, loginType, qrcode, safeClearTimers]);\n\n // 扫码轮询:仅在二维码“激活 + 有值 + 在扫码 Tab”时启动\n useEffect(() => {\n safeClearTimers();\n if (!qrcode) return;\n if (loginType !== 'qrcode') return;\n if (qrcodeStatus !== 'active') return;\n if (!qrcodeValue) return;\n\n pollIntervalRef.current = setInterval(() => {\n void qrcode.api\n .scanLogin(qrcodeValue)\n .then((res) => {\n if (res.code !== 200) return;\n\n const status = res.data?.status;\n const msg = res.data?.msg ?? '扫码遇到问题,稍后重试';\n\n if (status === -1) return;\n if (status !== 1) {\n safeClearTimers();\n setQrcodeStatus('expired');\n message.error(msg, 3);\n return;\n }\n safeClearTimers();\n void qrcode.onSuccess();\n })\n .catch(() => {\n // 忽略轮询中的偶发网络错误,保持继续轮询直到超时/成功\n });\n }, 1000);\n\n pollTimeoutRef.current = setTimeout(() => {\n setQrcodeStatus('expired');\n safeClearTimers();\n }, 30000);\n\n return safeClearTimers;\n }, [loginType, qrcode, qrcodeStatus, qrcodeValue, safeClearTimers]);\n\n const tabItems = useMemo(() => tabs.map((t) => ({ key: t.key, label: t.label })), [tabs]);\n\n return (\n <div className={className} style={{ maxWidth: '500px' }}>\n <LoginForm\n className={formClassName}\n onFinish={async (values) => {\n await onFinish(values);\n }}\n title={typeof title === 'string' ? <div className={styles.title}>{title}</div> : title}\n containerStyle={containerStyle}\n submitter={shouldShowSubmitter ? undefined : (false as const)}\n actions={resolvedActions}\n >\n <Tabs\n className={tabsClassName}\n centered\n activeKey={loginType}\n onChange={(activeKey) => {\n const next = activeKey as LoginType;\n setLoginType(next);\n }}\n items={tabItems}\n />\n\n {enabledTabKeys.has('qrcode') && loginType === 'qrcode' && qrcode && (\n <div style={qrcode.wrapStyle ?? DEFAULT_QRCODE_WRAP_STYLE}>\n <div className={qrcodeBoxClassName}>\n <Flex justify='center' align='center'>\n <i className='iconfont icon-saoyisao' style={{ color: '#999999', marginRight: 10, fontSize: 14 }}></i>\n 请使用<span style={{ color: '#0A6BFD' }}>小闪扫码</span>登录\n </Flex>\n <QRCode\n icon={qrcode.icon}\n iconSize={qrcode.iconSize ?? 50}\n className={qrcodeClassName}\n size={qrcode.size ?? 240}\n value={qrcodeUrl}\n status={qrcodeStatus}\n onRefresh={handleQrcodeRefresh}\n />\n </div>\n </div>\n )}\n\n {enabledTabKeys.has('sms') && loginType === 'sms' && sms && (\n <SmsLoginForm inputClassName={inputClassName ?? ''} api={sms.api} appKey={sms.appKey} />\n )}\n </LoginForm>\n </div>\n );\n};\n\nexport default LoginModule;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,iBAAiB;AAC1B,SAAS,MAAM,SAAS,QAAQ,YAAY;AAC5C,OAAO,SAAS,aAAa,WAAW,SAAS,QAAQ,gBAAgB;AACzE,OAAO,kBAA4C;AACnD,OAAO,YAAY;
|
|
4
|
+
"sourcesContent": ["import { LoginForm } from '@ant-design/pro-form';\nimport { Flex, message, QRCode, Tabs } from 'antd';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport SmsLoginForm, { type SmsLoginFormApi } from './SmsLoginForm';\nimport styles from './styles.module.less';\n\nexport type { SmsLoginFormApi } from './SmsLoginForm';\n\nexport type LoginType = 'qrcode' | 'sms';\n\nexport type LoginTabItem = {\n key: LoginType;\n label: React.ReactNode;\n};\n\nexport type QrcodeApi = {\n getQrcode: () => Promise<{ qrcode: string; url: string }>;\n scanLogin: (qrcode: string) => Promise<{\n code: number;\n data?: {\n status?: number;\n msg?: string;\n };\n }>;\n};\n\nexport type LoginModuleProps = {\n title: React.ReactNode;\n tabs: LoginTabItem[];\n defaultLoginType: LoginType;\n containerStyle?: React.CSSProperties;\n actions?: React.ReactNode | ((loginType: LoginType) => React.ReactNode);\n className?: string;\n formClassName?: string;\n tabsClassName?: string;\n inputClassName?: string;\n qrcodeClassName?: string;\n qrcodeBoxClassName?: string;\n\n onFinish: (values: Record<string, unknown>) => Promise<void>;\n\n qrcode?: {\n api: QrcodeApi;\n icon: string;\n iconSize?: number;\n size?: number;\n wrapStyle?: React.CSSProperties;\n onSuccess: () => void | Promise<void>;\n };\n\n sms?: {\n api: SmsLoginFormApi;\n appKey: string;\n };\n};\n\nconst DEFAULT_QRCODE_WRAP_STYLE: React.CSSProperties = {\n padding: 10,\n display: 'flex',\n justifyContent: 'center',\n};\n\nconst LoginModule: React.FC<LoginModuleProps> = (props) => {\n const {\n title,\n tabs,\n defaultLoginType,\n containerStyle,\n actions,\n onFinish,\n qrcode,\n className = styles.root,\n formClassName = styles.form,\n tabsClassName = styles.tabs,\n inputClassName,\n qrcodeClassName = styles.qrcode,\n qrcodeBoxClassName = styles.qrcodeBox,\n sms,\n } = props;\n\n const [loginType, setLoginType] = useState<LoginType>(defaultLoginType);\n\n const [qrcodeStatus, setQrcodeStatus] = useState<'active' | 'expired' | 'loading'>('active');\n const [qrcodeUrl, setQrcodeUrl] = useState<string>('-');\n const [qrcodeValue, setQrcodeValue] = useState<string>('');\n const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const pollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shouldShowSubmitter = loginType !== 'qrcode';\n\n const resolvedActions = useMemo(() => {\n if (!actions) return undefined;\n return typeof actions === 'function' ? actions(loginType) : actions;\n }, [actions, loginType]);\n\n const safeClearTimers = useCallback(() => {\n if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n if (pollTimeoutRef.current) clearTimeout(pollTimeoutRef.current);\n pollIntervalRef.current = null;\n pollTimeoutRef.current = null;\n }, []);\n\n const handleQrcodeRefresh = useCallback(async () => {\n if (!qrcode) return;\n setQrcodeStatus('loading');\n try {\n const res = await qrcode.api.getQrcode();\n setQrcodeUrl(res.url);\n setQrcodeValue(res.qrcode);\n setQrcodeStatus('active');\n } catch {\n setQrcodeStatus('expired');\n message.error('获取二维码失败,请稍后重试');\n }\n }, [qrcode]);\n\n const enabledTabKeys = useMemo(() => new Set(tabs.map((t) => t.key)), [tabs]);\n\n useEffect(() => {\n if (enabledTabKeys.has(defaultLoginType)) {\n setLoginType(defaultLoginType);\n return;\n }\n const fallback = tabs[0]?.key;\n if (fallback) setLoginType(fallback);\n }, [defaultLoginType, enabledTabKeys, tabs]);\n\n useEffect(() => {\n if (enabledTabKeys.has(loginType)) return;\n const fallback = tabs[0]?.key;\n if (fallback) setLoginType(fallback);\n }, [enabledTabKeys, loginType, tabs]);\n\n // 切到扫码登录时刷新二维码;离开扫码登录时停止轮询并标记过期\n useEffect(() => {\n safeClearTimers();\n if (loginType !== 'qrcode') {\n setQrcodeStatus('expired');\n return;\n }\n if (!qrcode) {\n setQrcodeStatus('expired');\n return;\n }\n void handleQrcodeRefresh();\n return safeClearTimers;\n }, [handleQrcodeRefresh, loginType, qrcode, safeClearTimers]);\n\n // 扫码轮询:仅在二维码“激活 + 有值 + 在扫码 Tab”时启动\n useEffect(() => {\n safeClearTimers();\n if (!qrcode) return;\n if (loginType !== 'qrcode') return;\n if (qrcodeStatus !== 'active') return;\n if (!qrcodeValue) return;\n\n pollIntervalRef.current = setInterval(() => {\n void qrcode.api\n .scanLogin(qrcodeValue)\n .then((res) => {\n if (res.code !== 200) return;\n\n const status = res.data?.status;\n const msg = res.data?.msg ?? '扫码遇到问题,稍后重试';\n\n if (status === -1) return;\n if (status !== 1) {\n safeClearTimers();\n setQrcodeStatus('expired');\n message.error(msg, 3);\n return;\n }\n safeClearTimers();\n void qrcode.onSuccess();\n })\n .catch(() => {\n // 忽略轮询中的偶发网络错误,保持继续轮询直到超时/成功\n });\n }, 1000);\n\n pollTimeoutRef.current = setTimeout(() => {\n setQrcodeStatus('expired');\n safeClearTimers();\n }, 30000);\n\n return safeClearTimers;\n }, [loginType, qrcode, qrcodeStatus, qrcodeValue, safeClearTimers]);\n\n const tabItems = useMemo(() => tabs.map((t) => ({ key: t.key, label: t.label })), [tabs]);\n\n return (\n <div className={className} style={{ maxWidth: '500px' }}>\n <LoginForm\n className={formClassName}\n onFinish={async (values) => {\n await onFinish(values);\n }}\n title={typeof title === 'string' ? <div className={styles.title}>{title}</div> : title}\n containerStyle={containerStyle}\n submitter={shouldShowSubmitter ? undefined : (false as const)}\n actions={resolvedActions}\n >\n <Tabs\n className={tabsClassName}\n centered\n activeKey={loginType}\n onChange={(activeKey) => {\n const next = activeKey as LoginType;\n setLoginType(next);\n }}\n items={tabItems}\n />\n\n {enabledTabKeys.has('qrcode') && loginType === 'qrcode' && qrcode && (\n <div style={qrcode.wrapStyle ?? DEFAULT_QRCODE_WRAP_STYLE}>\n <div className={qrcodeBoxClassName}>\n <Flex justify='center' align='center'>\n <i className='iconfont icon-saoyisao' style={{ color: '#999999', marginRight: 10, fontSize: 14 }}></i>\n 请使用<span style={{ color: '#0A6BFD' }}>小闪扫码</span>登录\n </Flex>\n <QRCode\n icon={qrcode.icon}\n iconSize={qrcode.iconSize ?? 50}\n className={qrcodeClassName}\n size={qrcode.size ?? 240}\n value={qrcodeUrl}\n status={qrcodeStatus}\n onRefresh={handleQrcodeRefresh}\n />\n </div>\n </div>\n )}\n\n {enabledTabKeys.has('sms') && loginType === 'sms' && sms && (\n <SmsLoginForm inputClassName={inputClassName ?? ''} api={sms.api} appKey={sms.appKey} />\n )}\n </LoginForm>\n </div>\n );\n};\n\nexport default LoginModule;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["_a", "_b", "_c"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { type FC } from 'react';
|
|
2
2
|
/** 项目选项项 */
|
|
3
|
-
type OptionItem = {
|
|
3
|
+
export type OptionItem = {
|
|
4
4
|
/** 项目名称 */
|
|
5
5
|
label: string;
|
|
6
6
|
/** 项目 ID */
|
|
@@ -17,7 +17,7 @@ type OptionItem = {
|
|
|
17
17
|
closed?: boolean;
|
|
18
18
|
};
|
|
19
19
|
/** 项目选择器 Props */
|
|
20
|
-
type
|
|
20
|
+
export type YkPorjectSelectProps = {
|
|
21
21
|
/** 当前选中的项目 ID */
|
|
22
22
|
value: string | number;
|
|
23
23
|
/** 项目选项列表 */
|
|
@@ -47,5 +47,5 @@ type PageTypes = {
|
|
|
47
47
|
* />
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
|
-
declare const YkPorjectSelect: FC<
|
|
50
|
+
declare const YkPorjectSelect: FC<YkPorjectSelectProps>;
|
|
51
51
|
export default YkPorjectSelect;
|
|
@@ -29,32 +29,12 @@ var __objRest = (source, exclude) => {
|
|
|
29
29
|
}
|
|
30
30
|
return target;
|
|
31
31
|
};
|
|
32
|
-
var __async = (__this, __arguments, generator) => {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
var fulfilled = (value) => {
|
|
35
|
-
try {
|
|
36
|
-
step(generator.next(value));
|
|
37
|
-
} catch (e) {
|
|
38
|
-
reject(e);
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
var rejected = (value) => {
|
|
42
|
-
try {
|
|
43
|
-
step(generator.throw(value));
|
|
44
|
-
} catch (e) {
|
|
45
|
-
reject(e);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
49
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
32
|
|
|
53
33
|
// src/business/YkPorjectSelect/index.tsx
|
|
54
34
|
import { SearchOutlined } from "@ant-design/icons";
|
|
55
35
|
import { ConfigProvider, Empty, Flex, Input, Popover, Rate, Tabs, Tooltip } from "antd";
|
|
56
36
|
import classNames from "classnames";
|
|
57
|
-
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
37
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
58
38
|
import { Scrollbars } from "react-custom-scrollbars-2";
|
|
59
39
|
import TextWithTooltip from "../../components/TextWithToolTip";
|
|
60
40
|
import iconProductDefault from "./icon-product.png";
|
|
@@ -63,7 +43,7 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
63
43
|
const [open, setOpen] = useState(false);
|
|
64
44
|
const [status, setStatus] = useState("1");
|
|
65
45
|
const [searchKey, setSearchKey] = useState("");
|
|
66
|
-
const [pageHeight, setPageHeight] = useState(1e3);
|
|
46
|
+
const [pageHeight, setPageHeight] = useState(typeof window !== "undefined" ? window.innerHeight : 1e3);
|
|
67
47
|
const [localOptions, setLocalOptions] = useState(options);
|
|
68
48
|
const searchInputRef = useRef(null);
|
|
69
49
|
useEffect(() => {
|
|
@@ -109,8 +89,8 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
109
89
|
const handleTabChange = (tabKey) => {
|
|
110
90
|
setStatus(tabKey);
|
|
111
91
|
};
|
|
112
|
-
const handleStarChange = (item, val) =>
|
|
113
|
-
|
|
92
|
+
const handleStarChange = (item, val) => {
|
|
93
|
+
followedCallback == null ? void 0 : followedCallback(item, val === 1);
|
|
114
94
|
setLocalOptions(
|
|
115
95
|
(prev) => prev.map((p) => {
|
|
116
96
|
if (p.value === item.value) {
|
|
@@ -119,15 +99,14 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
119
99
|
return p;
|
|
120
100
|
})
|
|
121
101
|
);
|
|
122
|
-
});
|
|
123
|
-
const handleResize = () => {
|
|
124
|
-
const height = window.innerHeight;
|
|
125
|
-
setPageHeight(height);
|
|
126
102
|
};
|
|
103
|
+
const handleResize = useCallback(() => {
|
|
104
|
+
setPageHeight(window.innerHeight);
|
|
105
|
+
}, []);
|
|
127
106
|
useEffect(() => {
|
|
128
107
|
window.addEventListener("resize", handleResize);
|
|
129
108
|
return () => window.removeEventListener("resize", handleResize);
|
|
130
|
-
}, []);
|
|
109
|
+
}, [handleResize]);
|
|
131
110
|
const renderItem = (item) => {
|
|
132
111
|
const isDisabled = !item.followed && followedOptions.length >= 6;
|
|
133
112
|
return /* @__PURE__ */ React.createElement(Flex, { justify: "space-between", align: "center" }, /* @__PURE__ */ React.createElement("span", { className: styles.contentItemSpan, onClick: () => onChange(item.value) }, /* @__PURE__ */ React.createElement("img", { className: styles.contentItemSpanIcon, src: (item == null ? void 0 : item.icon) ? item.icon : iconProductDefault }), /* @__PURE__ */ React.createElement("div", { className: styles.contentItemSpanDev }, /* @__PURE__ */ React.createElement("div", { className: styles.contentItemSpanProName }, /* @__PURE__ */ React.createElement(
|
|
@@ -156,7 +135,7 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
156
135
|
if (isDisabled) {
|
|
157
136
|
return;
|
|
158
137
|
}
|
|
159
|
-
|
|
138
|
+
handleStarChange(item, item.followed ? 0 : 1);
|
|
160
139
|
}
|
|
161
140
|
},
|
|
162
141
|
/* @__PURE__ */ React.createElement(
|
|
@@ -206,7 +185,7 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
206
185
|
placement: "bottomLeft",
|
|
207
186
|
styles: { body: { color: "#333" } }
|
|
208
187
|
},
|
|
209
|
-
/* @__PURE__ */ React.createElement("div", { key: item.value, className: styles.ykPorjectSelectFollowedItem }, /* @__PURE__ */ React.createElement("img", { className: styles.ykPorjectSelectFollowedItemIcon, src: item.icon, alt: item.label }), /* @__PURE__ */ React.createElement("div", { className: styles.closeIcon, onClick: () =>
|
|
188
|
+
/* @__PURE__ */ React.createElement("div", { key: item.value, className: styles.ykPorjectSelectFollowedItem }, /* @__PURE__ */ React.createElement("img", { className: styles.ykPorjectSelectFollowedItemIcon, src: item.icon || iconProductDefault, alt: item.label }), /* @__PURE__ */ React.createElement("div", { className: styles.closeIcon, onClick: () => handleStarChange(item, 0) }))
|
|
210
189
|
)))), /* @__PURE__ */ React.createElement(
|
|
211
190
|
Tabs,
|
|
212
191
|
{
|
|
@@ -216,27 +195,34 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
216
195
|
activeKey: status,
|
|
217
196
|
items: tabs
|
|
218
197
|
}
|
|
219
|
-
),
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
var _b = _a, { style } = _b, props = __objRest(_b, ["style"]);
|
|
228
|
-
return /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({}, props), { style: __spreadProps(__spreadValues({}, style), { background: "#EEEEEE", borderRadius: 3, width: 6 }) }));
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
localOptions.sort((a, b) => (b.recent_visit ? 1 : 0) - (a.recent_visit ? 1 : 0)).map((item) => /* @__PURE__ */ React.createElement(
|
|
232
|
-
"div",
|
|
198
|
+
), (() => {
|
|
199
|
+
const searched = searchKey ? localOptions.filter(
|
|
200
|
+
(item) => item.label.toLowerCase().includes(searchKey.toLowerCase()) || String(item.value).includes(searchKey)
|
|
201
|
+
) : localOptions;
|
|
202
|
+
const filtered = searchKey ? searched : searched.filter((item) => status === "1" ? !item.closed : item.closed);
|
|
203
|
+
const sorted = [...filtered].sort((a, b) => (b.recent_visit ? 1 : 0) - (a.recent_visit ? 1 : 0));
|
|
204
|
+
return sorted.length === 0 ? /* @__PURE__ */ React.createElement(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE }) : /* @__PURE__ */ React.createElement("div", { className: styles.ykPorjectSelectListSection }, /* @__PURE__ */ React.createElement("div", { className: styles.contentHeader }, "全部项目"), /* @__PURE__ */ React.createElement(
|
|
205
|
+
Scrollbars,
|
|
233
206
|
{
|
|
234
|
-
|
|
235
|
-
|
|
207
|
+
className: styles.ykPorjectSelectScrollBarsBox,
|
|
208
|
+
autoHeight: true,
|
|
209
|
+
autoHide: true,
|
|
210
|
+
autoHeightMax: Math.min(450, pageHeight - 310),
|
|
211
|
+
renderThumbVertical: (_a) => {
|
|
212
|
+
var _b = _a, { style } = _b, props = __objRest(_b, ["style"]);
|
|
213
|
+
return /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({}, props), { style: __spreadProps(__spreadValues({}, style), { background: "#EEEEEE", borderRadius: 3, width: 6 }) }));
|
|
214
|
+
}
|
|
236
215
|
},
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
216
|
+
sorted.map((item) => /* @__PURE__ */ React.createElement(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
key: item.value,
|
|
220
|
+
className: classNames(styles.contentItem, item.value === value ? styles.contentItemActive : "")
|
|
221
|
+
},
|
|
222
|
+
renderItem(item)
|
|
223
|
+
))
|
|
224
|
+
));
|
|
225
|
+
})());
|
|
240
226
|
return /* @__PURE__ */ React.createElement(
|
|
241
227
|
Popover,
|
|
242
228
|
{
|
|
@@ -250,7 +236,7 @@ var YkPorjectSelect = ({ value, options, onChange, followedCallback, slot, custo
|
|
|
250
236
|
getPopupContainer: (triggerNode) => triggerNode.parentNode,
|
|
251
237
|
autoAdjustOverflow: false
|
|
252
238
|
},
|
|
253
|
-
customShow ? customShow : /* @__PURE__ */ React.createElement("div", { className: styles.ykPorjectSelectShow }, /* @__PURE__ */ React.createElement("img", { className: styles.ykPorjectSelectShowIcon, src: activeItem == null ? void 0 : activeItem.icon, alt: activeItem == null ? void 0 : activeItem.label }), /* @__PURE__ */ React.createElement("span", { className: styles.ykPorjectSelectShowText }, activeItem == null ? void 0 : activeItem.label), /* @__PURE__ */ React.createElement("i", { className: "iconfont icon-xiala" }))
|
|
239
|
+
customShow ? customShow : /* @__PURE__ */ React.createElement("div", { className: styles.ykPorjectSelectShow }, /* @__PURE__ */ React.createElement("img", { className: styles.ykPorjectSelectShowIcon, src: (activeItem == null ? void 0 : activeItem.icon) || iconProductDefault, alt: activeItem == null ? void 0 : activeItem.label }), /* @__PURE__ */ React.createElement("span", { className: styles.ykPorjectSelectShowText }, activeItem == null ? void 0 : activeItem.label), /* @__PURE__ */ React.createElement("i", { className: "iconfont icon-xiala" }))
|
|
254
240
|
);
|
|
255
241
|
};
|
|
256
242
|
var YkPorjectSelect_default = YkPorjectSelect;
|