@lark-apaas/client-toolkit 1.2.9 → 1.2.34
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/lib/antd-table.d.ts +2 -2
- package/lib/apis/aily-chat.d.ts +2 -0
- package/lib/apis/aily-chat.js +2 -0
- package/lib/apis/hooks/useScrollReveal.d.ts +1 -0
- package/lib/apis/hooks/useScrollReveal.js +1 -0
- package/lib/apis/udt-types.d.ts +4 -0
- package/lib/apis/utils/resolveAppUrl.d.ts +1 -0
- package/lib/apis/utils/resolveAppUrl.js +2 -0
- package/lib/apis/utils/scopedStorage.d.ts +1 -0
- package/lib/apis/utils/scopedStorage.js +2 -0
- package/lib/auth.d.ts +2 -1
- package/lib/auth.js +2 -2
- package/lib/components/AppContainer/api-proxy/core.js +2 -1
- package/lib/components/AppContainer/index.d.ts +5 -1
- package/lib/components/AppContainer/index.js +41 -34
- package/lib/components/AppContainer/safety.js +27 -8
- package/lib/components/AppContainer/utils/childApi.js +1 -0
- package/lib/components/AppContainer/utils/getLarkUser.js +4 -2
- package/lib/components/AppContainer/utils/observable.js +7 -1
- package/lib/components/AppContainer/utils/tea.js +1 -1
- package/lib/components/ErrorRender/index.js +5 -11
- package/lib/components/User/UserSelect.js +1 -13
- package/lib/components/theme/index.d.ts +0 -1
- package/lib/components/theme/index.js +0 -1
- package/lib/components/theme/util.d.ts +0 -2
- package/lib/components/theme/util.js +0 -108
- package/lib/components/ui/badge.d.ts +1 -1
- package/lib/components/ui/button.d.ts +2 -2
- package/lib/components/ui/button.js +1 -1
- package/lib/components/ui/confirm.d.ts +28 -0
- package/lib/components/ui/confirm.js +83 -0
- package/lib/components/ui/toast.d.ts +2 -0
- package/lib/components/ui/toast.js +53 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useCurrentUserProfile.d.ts +18 -3
- package/lib/hooks/useCurrentUserProfile.js +38 -29
- package/lib/hooks/useLogout.js +2 -17
- package/lib/hooks/useScrollReveal.d.ts +61 -0
- package/lib/hooks/useScrollReveal.js +37 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +14 -2
- package/lib/integrations/dataloom.d.ts +3 -1
- package/lib/integrations/dataloom.js +18 -10
- package/lib/integrations/getCurrentUserProfile.d.ts +7 -1
- package/lib/integrations/services/ChatService.d.ts +12 -0
- package/lib/integrations/services/ChatService.js +67 -0
- package/lib/integrations/services/DepartmentService.js +3 -2
- package/lib/integrations/services/UserProfileService.js +3 -2
- package/lib/integrations/services/UserService.d.ts +3 -1
- package/lib/integrations/services/UserService.js +23 -3
- package/lib/integrations/services/index.d.ts +1 -0
- package/lib/integrations/services/index.js +1 -0
- package/lib/integrations/services/types.d.ts +45 -0
- package/lib/logger/intercept-global-error.js +34 -25
- package/lib/logger/log-types.d.ts +4 -4
- package/lib/logger/log-types.js +1 -1
- package/lib/runtime/index.d.ts +1 -0
- package/lib/runtime/index.js +1 -0
- package/lib/runtime/react-devtools-hook.d.ts +19 -0
- package/lib/runtime/react-devtools-hook.js +20 -0
- package/lib/theme-layer.css +2 -1
- package/lib/utils/apiPath.d.ts +5 -0
- package/lib/utils/apiPath.js +5 -0
- package/lib/utils/axiosConfig.js +163 -9
- package/lib/utils/getAppId.d.ts +2 -4
- package/lib/utils/getAppId.js +2 -9
- package/lib/utils/getInitialInfo.d.ts +4 -3
- package/lib/utils/getInitialInfo.js +17 -8
- package/lib/utils/getUserProfile.js +4 -12
- package/lib/utils/hmr-api.d.ts +45 -0
- package/lib/utils/hmr-api.js +36 -0
- package/lib/utils/module-hot.d.ts +9 -5
- package/lib/utils/module-hot.js +9 -10
- package/lib/utils/postMessage.d.ts +0 -1
- package/lib/utils/postMessage.js +19 -6
- package/lib/utils/requestManager.js +1 -3
- package/lib/utils/resolveAppUrl.d.ts +27 -0
- package/lib/utils/resolveAppUrl.js +19 -0
- package/lib/utils/safeStringify.js +5 -0
- package/lib/utils/safeStringify.spec.d.ts +1 -0
- package/lib/utils/safeStringify.spec.js +125 -0
- package/lib/utils/scopedStorage.d.ts +5 -0
- package/lib/utils/scopedStorage.js +46 -0
- package/package.json +13 -6
- package/lib/apis/tools/generateImage.d.ts +0 -1
- package/lib/apis/tools/generateImage.js +0 -1
- package/lib/apis/tools/generateTextStream.d.ts +0 -1
- package/lib/apis/tools/generateTextStream.js +0 -1
- package/lib/components/theme/ui-config.d.ts +0 -1
- package/lib/components/theme/ui-config.js +0 -2
- package/lib/integrations/generateImage.d.ts +0 -1
- package/lib/integrations/generateImage.js +0 -47
- package/lib/integrations/generateTextStream.d.ts +0 -21
- package/lib/integrations/generateTextStream.js +0 -98
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { createRoot } from "react-dom/client";
|
|
4
|
+
import { Content, Description, Overlay, Portal, Root, Title } from "@radix-ui/react-dialog";
|
|
5
|
+
import { Button } from "./button.js";
|
|
6
|
+
import { clsxWithTw } from "../../utils/utils.js";
|
|
7
|
+
function showConfirm(options) {
|
|
8
|
+
const opts = 'string' == typeof options ? {
|
|
9
|
+
message: options
|
|
10
|
+
} : options;
|
|
11
|
+
const { title = '提示', message, confirmText = '确认', cancelText = '取消', variant = 'default' } = opts;
|
|
12
|
+
return new Promise((resolve)=>{
|
|
13
|
+
const container = document.createElement('div');
|
|
14
|
+
document.body.appendChild(container);
|
|
15
|
+
const root = createRoot(container);
|
|
16
|
+
function cleanup() {
|
|
17
|
+
root.unmount();
|
|
18
|
+
container.remove();
|
|
19
|
+
}
|
|
20
|
+
function handleConfirm() {
|
|
21
|
+
cleanup();
|
|
22
|
+
resolve(true);
|
|
23
|
+
}
|
|
24
|
+
function handleCancel() {
|
|
25
|
+
cleanup();
|
|
26
|
+
resolve(false);
|
|
27
|
+
}
|
|
28
|
+
root.render(/*#__PURE__*/ jsx(ConfirmDialog, {
|
|
29
|
+
title: title,
|
|
30
|
+
message: message,
|
|
31
|
+
confirmText: confirmText,
|
|
32
|
+
cancelText: cancelText,
|
|
33
|
+
variant: variant,
|
|
34
|
+
onConfirm: handleConfirm,
|
|
35
|
+
onCancel: handleCancel
|
|
36
|
+
}));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function ConfirmDialog({ title, message, confirmText, cancelText, variant, onConfirm, onCancel }) {
|
|
40
|
+
return /*#__PURE__*/ jsx(Root, {
|
|
41
|
+
defaultOpen: true,
|
|
42
|
+
onOpenChange: (open)=>{
|
|
43
|
+
if (!open) onCancel();
|
|
44
|
+
},
|
|
45
|
+
children: /*#__PURE__*/ jsxs(Portal, {
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ jsx(Overlay, {
|
|
48
|
+
className: clsxWithTw('fixed inset-0 z-[99999] bg-black/40', 'data-[state=open]:animate-in data-[state=open]:fade-in-0', 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0')
|
|
49
|
+
}),
|
|
50
|
+
/*#__PURE__*/ jsxs(Content, {
|
|
51
|
+
className: clsxWithTw('fixed left-1/2 top-1/2 z-[99999] -translate-x-1/2 -translate-y-1/2', 'w-[90vw] max-w-[400px] rounded-lg', 'bg-[var(--popover,var(--color-neutral-00,#fff))] text-[var(--popover-foreground,var(--color-neutral-950,#1f2329))]', 'border border-[var(--border,var(--color-neutral-300,#dee0e3))]', 'shadow-lg p-6', 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95', 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95'),
|
|
52
|
+
children: [
|
|
53
|
+
/*#__PURE__*/ jsx(Title, {
|
|
54
|
+
className: clsxWithTw('text-base font-medium leading-6', 'text-[var(--foreground,var(--color-neutral-950,#1f2329))]'),
|
|
55
|
+
children: title
|
|
56
|
+
}),
|
|
57
|
+
/*#__PURE__*/ jsx(Description, {
|
|
58
|
+
className: clsxWithTw('mt-2 text-sm leading-5', 'text-[var(--muted-foreground,var(--color-neutral-700,#646a73))]'),
|
|
59
|
+
children: message
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ jsxs("div", {
|
|
62
|
+
className: clsxWithTw('mt-6 flex justify-end gap-2'),
|
|
63
|
+
children: [
|
|
64
|
+
/*#__PURE__*/ jsx(Button, {
|
|
65
|
+
variant: "outline",
|
|
66
|
+
className: "!bg-transparent !text-inherit",
|
|
67
|
+
onClick: onCancel,
|
|
68
|
+
children: cancelText
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ jsx(Button, {
|
|
71
|
+
variant: variant,
|
|
72
|
+
onClick: onConfirm,
|
|
73
|
+
children: confirmText
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
]
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
export { showConfirm };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function showToast(message, duration = 3000) {
|
|
2
|
+
return new Promise((resolve)=>{
|
|
3
|
+
const toast = document.createElement('div');
|
|
4
|
+
const iconSvg = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
5
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.333a6.667 6.667 0 1 1 0 13.334A6.667 6.667 0 0 1 8 1.333ZM8 10a.667.667 0 1 0 0 1.333A.667.667 0 0 0 8 10Zm0-5.333a.667.667 0 0 0-.667.666v3.334a.667.667 0 0 0 1.334 0V5.333A.667.667 0 0 0 8 4.667Z" fill="#ff811a"/>
|
|
6
|
+
</svg>`;
|
|
7
|
+
const iconWrapper = document.createElement('span');
|
|
8
|
+
iconWrapper.innerHTML = iconSvg;
|
|
9
|
+
Object.assign(iconWrapper.style, {
|
|
10
|
+
display: 'flex',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
marginRight: '8px',
|
|
13
|
+
flexShrink: '0'
|
|
14
|
+
});
|
|
15
|
+
const textWrapper = document.createElement('span');
|
|
16
|
+
textWrapper.textContent = message;
|
|
17
|
+
toast.appendChild(iconWrapper);
|
|
18
|
+
toast.appendChild(textWrapper);
|
|
19
|
+
Object.assign(toast.style, {
|
|
20
|
+
position: 'fixed',
|
|
21
|
+
top: '32px',
|
|
22
|
+
left: '50%',
|
|
23
|
+
transform: 'translate(-50%, -50%)',
|
|
24
|
+
display: 'flex',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
padding: '12px 16px',
|
|
27
|
+
backgroundColor: '#fff',
|
|
28
|
+
color: '#1f2329',
|
|
29
|
+
border: '1px solid #dee0e3',
|
|
30
|
+
borderRadius: '6px',
|
|
31
|
+
fontSize: '14px',
|
|
32
|
+
lineHeight: '1.5',
|
|
33
|
+
zIndex: '99999',
|
|
34
|
+
maxWidth: '80vw',
|
|
35
|
+
wordBreak: 'break-word',
|
|
36
|
+
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.03), 0 3px 6px rgba(0, 0, 0, 0.05), 0 6px 18px rgba(0, 0, 0, 0.03)',
|
|
37
|
+
opacity: '0',
|
|
38
|
+
transition: 'opacity 0.3s ease'
|
|
39
|
+
});
|
|
40
|
+
document.body.appendChild(toast);
|
|
41
|
+
requestAnimationFrame(()=>{
|
|
42
|
+
toast.style.opacity = '1';
|
|
43
|
+
});
|
|
44
|
+
setTimeout(()=>{
|
|
45
|
+
toast.style.opacity = '0';
|
|
46
|
+
setTimeout(()=>{
|
|
47
|
+
document.body.removeChild(toast);
|
|
48
|
+
resolve();
|
|
49
|
+
}, 300);
|
|
50
|
+
}, duration);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export { showToast };
|
package/lib/hooks/index.d.ts
CHANGED
package/lib/hooks/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { IUserProfile } from '../apis/udt-types';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* useCurrentUserProfile 的返回类型。
|
|
4
|
+
* 初始状态为空对象 `{}`(所有字段均为 undefined),异步获取用户信息后字段才会被填充。
|
|
5
|
+
* 使用时必须通过可选链或空值合并进行安全访问,如 `userInfo?.user_id`。
|
|
6
|
+
* 判断是否已加载完成应使用 `if (!userInfo?.user_id)` 而非 `if (!userInfo)`(因为空对象是 truthy)。
|
|
7
|
+
*/
|
|
8
|
+
export type ICompatibilityUserProfile = Partial<IUserProfile & {
|
|
3
9
|
/**
|
|
4
10
|
* @deprecated please use `name`
|
|
5
11
|
*/
|
|
@@ -8,5 +14,14 @@ export interface ICompatibilityUserProfile extends IUserProfile {
|
|
|
8
14
|
* @deprecated please use `avatar`
|
|
9
15
|
*/
|
|
10
16
|
userAvatar: string;
|
|
11
|
-
}
|
|
12
|
-
export declare const useCurrentUserProfile: () =>
|
|
17
|
+
}>;
|
|
18
|
+
export declare const useCurrentUserProfile: () => Partial<IUserProfile & {
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated please use `name`
|
|
21
|
+
*/
|
|
22
|
+
userName: string;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated please use `avatar`
|
|
25
|
+
*/
|
|
26
|
+
userAvatar: string;
|
|
27
|
+
}>;
|
|
@@ -3,11 +3,25 @@ import { logger } from "../logger/index.js";
|
|
|
3
3
|
import { getCurrentUserProfile } from "../integrations/getCurrentUserProfile.js";
|
|
4
4
|
import { getDataloom } from "../integrations/dataloom.js";
|
|
5
5
|
import { isSparkRuntime } from "../utils/utils.js";
|
|
6
|
+
import { getAxiosForBackend } from "../utils/getAxiosForBackend.js";
|
|
6
7
|
function getNameFromArray(nameArray) {
|
|
7
8
|
if (!nameArray || 0 === nameArray.length) return;
|
|
8
9
|
const chineseName = nameArray.find((item)=>2052 === item.language_code);
|
|
9
10
|
return chineseName?.text ?? nameArray[0]?.text;
|
|
10
11
|
}
|
|
12
|
+
let _larkUserIdCache = null;
|
|
13
|
+
let _larkUserIdPromise = null;
|
|
14
|
+
function fetchLarkUserId() {
|
|
15
|
+
if (null !== _larkUserIdCache) return Promise.resolve(_larkUserIdCache);
|
|
16
|
+
if (_larkUserIdPromise) return _larkUserIdPromise;
|
|
17
|
+
_larkUserIdPromise = getAxiosForBackend().get('/api/authnpaas/lark-user-id').then(({ data })=>{
|
|
18
|
+
_larkUserIdCache = data?.lark_user_id || null;
|
|
19
|
+
return _larkUserIdCache;
|
|
20
|
+
}).catch(()=>null).finally(()=>{
|
|
21
|
+
_larkUserIdPromise = null;
|
|
22
|
+
});
|
|
23
|
+
return _larkUserIdPromise;
|
|
24
|
+
}
|
|
11
25
|
function getCompatibilityUserProfile() {
|
|
12
26
|
const userInfo = getCurrentUserProfile();
|
|
13
27
|
return {
|
|
@@ -19,37 +33,31 @@ function getCompatibilityUserProfile() {
|
|
|
19
33
|
const useCurrentUserProfile = ()=>{
|
|
20
34
|
const [userInfo, setUserInfo] = useState(()=>getCompatibilityUserProfile());
|
|
21
35
|
useEffect(()=>{
|
|
36
|
+
let cancelled = false;
|
|
37
|
+
const fetchAndSetUserInfo = async ()=>{
|
|
38
|
+
const dataloom = await getDataloom();
|
|
39
|
+
const result = await dataloom?.service?.session?.getUserInfo();
|
|
40
|
+
if (cancelled) return;
|
|
41
|
+
const info = result?.data?.user_info;
|
|
42
|
+
const userName = getNameFromArray(info?.name);
|
|
43
|
+
const newUserInfo = {
|
|
44
|
+
user_id: info?.user_id?.toString(),
|
|
45
|
+
email: info?.email,
|
|
46
|
+
name: userName,
|
|
47
|
+
avatar: info?.avatar?.image?.large,
|
|
48
|
+
userName: userName,
|
|
49
|
+
userAvatar: info?.avatar?.image?.large
|
|
50
|
+
};
|
|
51
|
+
const larkUserId = await fetchLarkUserId();
|
|
52
|
+
if (larkUserId) newUserInfo.lark_user_id = larkUserId;
|
|
53
|
+
if ('development' === process.env.NODE_ENV) logger.info('MiaoDaMetaInfoChanged', newUserInfo);
|
|
54
|
+
setUserInfo(newUserInfo);
|
|
55
|
+
};
|
|
22
56
|
let handleMetaInfoChanged;
|
|
23
57
|
if (isSparkRuntime()) {
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const userInfo = result?.data?.user_info;
|
|
28
|
-
const userName = getNameFromArray(userInfo?.name);
|
|
29
|
-
setUserInfo({
|
|
30
|
-
user_id: userInfo?.user_id?.toString(),
|
|
31
|
-
email: userInfo?.email,
|
|
32
|
-
name: userName,
|
|
33
|
-
avatar: userInfo?.avatar?.image?.large,
|
|
34
|
-
userName: userName,
|
|
35
|
-
userAvatar: userInfo?.avatar?.image?.large
|
|
36
|
-
});
|
|
37
|
-
})();
|
|
38
|
-
handleMetaInfoChanged = async ()=>{
|
|
39
|
-
const dataloom = await getDataloom();
|
|
40
|
-
const result = await dataloom?.service?.session?.getUserInfo();
|
|
41
|
-
const userInfo = result?.data?.user_info;
|
|
42
|
-
const userName = getNameFromArray(userInfo?.name);
|
|
43
|
-
const newUserInfo = {
|
|
44
|
-
user_id: userInfo?.user_id?.toString(),
|
|
45
|
-
email: userInfo?.email,
|
|
46
|
-
name: userName,
|
|
47
|
-
avatar: userInfo?.avatar?.image?.large,
|
|
48
|
-
userName: userName,
|
|
49
|
-
userAvatar: userInfo?.avatar?.image?.large
|
|
50
|
-
};
|
|
51
|
-
if ('development' === process.env.NODE_ENV) logger.info('MiaoDaMetaInfoChanged', newUserInfo);
|
|
52
|
-
setUserInfo(newUserInfo);
|
|
58
|
+
fetchAndSetUserInfo();
|
|
59
|
+
handleMetaInfoChanged = ()=>{
|
|
60
|
+
fetchAndSetUserInfo();
|
|
53
61
|
};
|
|
54
62
|
} else handleMetaInfoChanged = ()=>{
|
|
55
63
|
if ('development' === process.env.NODE_ENV) logger.info('MiaoDaMetaInfoChanged', getCompatibilityUserProfile());
|
|
@@ -57,6 +65,7 @@ const useCurrentUserProfile = ()=>{
|
|
|
57
65
|
};
|
|
58
66
|
window.addEventListener('MiaoDaMetaInfoChanged', handleMetaInfoChanged);
|
|
59
67
|
return ()=>{
|
|
68
|
+
cancelled = true;
|
|
60
69
|
window.removeEventListener('MiaoDaMetaInfoChanged', handleMetaInfoChanged);
|
|
61
70
|
};
|
|
62
71
|
}, []);
|
package/lib/hooks/useLogout.js
CHANGED
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { getDataloom } from "../integrations/dataloom.js";
|
|
3
|
-
import { isSparkRuntime } from "../utils/utils.js";
|
|
4
3
|
function useLogout() {
|
|
5
4
|
const [isLoading, setIsLoading] = useState(false);
|
|
6
5
|
async function handlerLogout() {
|
|
7
6
|
if ('production' !== process.env.NODE_ENV) return void console.log('只有生产环境才执行登出');
|
|
8
|
-
if (isSparkRuntime()) {
|
|
9
|
-
setIsLoading(true);
|
|
10
|
-
try {
|
|
11
|
-
const dataloom = await getDataloom();
|
|
12
|
-
await dataloom.service.session.signOut();
|
|
13
|
-
} catch (error) {
|
|
14
|
-
console.error('登出失败', error);
|
|
15
|
-
} finally{
|
|
16
|
-
setIsLoading(false);
|
|
17
|
-
}
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
7
|
setIsLoading(true);
|
|
21
8
|
try {
|
|
22
|
-
await
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
window.location.reload();
|
|
9
|
+
const dataloom = await getDataloom();
|
|
10
|
+
await dataloom.service.session.signOut();
|
|
26
11
|
} catch (error) {
|
|
27
12
|
console.error('登出失败', error);
|
|
28
13
|
} finally{
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Options for useScrollReveal hook
|
|
4
|
+
*/
|
|
5
|
+
export interface UseScrollRevealOptions<T extends HTMLElement = HTMLElement> {
|
|
6
|
+
/** Ref to the container element to scope the query (default: document.body) */
|
|
7
|
+
containerRef?: RefObject<T | null>;
|
|
8
|
+
/** IntersectionObserver threshold - element visibility percentage to trigger (default: 0.1) */
|
|
9
|
+
threshold?: number;
|
|
10
|
+
/** IntersectionObserver rootMargin - margin around root (default: '0px 0px -50px 0px') */
|
|
11
|
+
rootMargin?: string;
|
|
12
|
+
/** CSS class to add when element becomes visible (default: 'visible') */
|
|
13
|
+
visibleClass?: string;
|
|
14
|
+
/** CSS selector for elements to observe (default: '.scroll-reveal') */
|
|
15
|
+
selector?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hook to enable scroll reveal animations using IntersectionObserver.
|
|
19
|
+
*
|
|
20
|
+
* Observes elements with the specified selector and adds a visibility class
|
|
21
|
+
* when they enter the viewport.
|
|
22
|
+
*
|
|
23
|
+
* @param options - Configuration options
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Usage without parameters (queries entire document.body)
|
|
28
|
+
* import { useScrollReveal } from '@lark-apaas/client-toolkit/hooks/useScrollReveal';
|
|
29
|
+
*
|
|
30
|
+
* function MyComponent() {
|
|
31
|
+
* useScrollReveal();
|
|
32
|
+
*
|
|
33
|
+
* return <div className="scroll-reveal">I will fade in on scroll!</div>;
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* // Usage with container ref
|
|
40
|
+
* import { useRef } from 'react';
|
|
41
|
+
* import { useScrollReveal } from '@lark-apaas/client-toolkit/hooks/useScrollReveal';
|
|
42
|
+
*
|
|
43
|
+
* function MyComponent() {
|
|
44
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
45
|
+
* useScrollReveal({ containerRef });
|
|
46
|
+
*
|
|
47
|
+
* return (
|
|
48
|
+
* <div ref={containerRef}>
|
|
49
|
+
* <div className="scroll-reveal">I will fade in on scroll!</div>
|
|
50
|
+
* </div>
|
|
51
|
+
* );
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* // Usage with custom options
|
|
58
|
+
* useScrollReveal({ threshold: 0.2, visibleClass: 'animate-in' });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function useScrollReveal<T extends HTMLElement = HTMLElement>(options?: UseScrollRevealOptions<T>): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
const DEFAULT_OPTIONS = {
|
|
3
|
+
threshold: 0.1,
|
|
4
|
+
rootMargin: '0px 0px -50px 0px',
|
|
5
|
+
visibleClass: 'visible',
|
|
6
|
+
selector: '.scroll-reveal'
|
|
7
|
+
};
|
|
8
|
+
function useScrollReveal(options) {
|
|
9
|
+
const { containerRef, threshold, rootMargin, visibleClass, selector } = {
|
|
10
|
+
...DEFAULT_OPTIONS,
|
|
11
|
+
...options
|
|
12
|
+
};
|
|
13
|
+
useEffect(()=>{
|
|
14
|
+
const container = containerRef?.current ?? document.body;
|
|
15
|
+
if (!container) return;
|
|
16
|
+
const observer = new IntersectionObserver((entries)=>{
|
|
17
|
+
entries.forEach((entry)=>{
|
|
18
|
+
if (entry.isIntersecting) entry.target.classList.add(visibleClass);
|
|
19
|
+
});
|
|
20
|
+
}, {
|
|
21
|
+
threshold,
|
|
22
|
+
rootMargin
|
|
23
|
+
});
|
|
24
|
+
const elements = container.querySelectorAll(selector);
|
|
25
|
+
elements.forEach((el)=>observer.observe(el));
|
|
26
|
+
return ()=>{
|
|
27
|
+
observer.disconnect();
|
|
28
|
+
};
|
|
29
|
+
}, [
|
|
30
|
+
containerRef,
|
|
31
|
+
threshold,
|
|
32
|
+
rootMargin,
|
|
33
|
+
visibleClass,
|
|
34
|
+
selector
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
export { useScrollReveal };
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const capabilityClient: import("@lark-apaas/client-capability").CapabilityClient;
|
|
2
|
+
export { showConfirm } from './components/ui/confirm';
|
|
3
|
+
export type { ConfirmOptions } from './components/ui/confirm';
|
|
2
4
|
declare const _default: {
|
|
3
5
|
version: string;
|
|
4
6
|
};
|
package/lib/index.js
CHANGED
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { createClient } from "@lark-apaas/client-capability";
|
|
2
2
|
import { normalizeBasePath } from "./utils/utils.js";
|
|
3
|
+
import { getAppId } from "./utils/getAppId.js";
|
|
4
|
+
import { isNewPathEnabled } from "./utils/apiPath.js";
|
|
3
5
|
import { logger } from "./logger/index.js";
|
|
6
|
+
import { showToast } from "./components/ui/toast.js";
|
|
4
7
|
import { version } from "../package.json";
|
|
8
|
+
import { showConfirm } from "./components/ui/confirm.js";
|
|
9
|
+
const _appId = getAppId();
|
|
10
|
+
const _acquireUploadUrl = isNewPathEnabled() ? `/app/${_appId}/__runtime__/api/v1/studio/plugins/tmp_files/acquire_upload_url` : "/af/api/v1/studio/plugins/tmp_files/acquire_upload_url";
|
|
11
|
+
const _acquireDownloadUrl = isNewPathEnabled() ? `/app/${_appId}/__runtime__/api/v1/studio/plugins/tmp_files/acquire_download_url` : "/af/api/v1/studio/plugins/tmp_files/acquire_download_url";
|
|
5
12
|
const capabilityClient = createClient({
|
|
6
13
|
baseURL: normalizeBasePath(process.env.CLIENT_BASE_PATH),
|
|
14
|
+
acquireUploadUrl: _acquireUploadUrl,
|
|
15
|
+
acquireDownloadUrl: _acquireDownloadUrl,
|
|
7
16
|
fetchOptions: {
|
|
8
17
|
headers: {
|
|
9
18
|
'X-Suda-Csrf-Token': window.csrfToken ?? ''
|
|
10
19
|
}
|
|
11
20
|
},
|
|
12
|
-
logger: logger
|
|
21
|
+
logger: logger,
|
|
22
|
+
onRateLimitError: ()=>{
|
|
23
|
+
showToast('应用额度已耗尽,请联系应用开发者');
|
|
24
|
+
}
|
|
13
25
|
});
|
|
14
26
|
const src = {
|
|
15
27
|
version: version
|
|
16
28
|
};
|
|
17
|
-
export { capabilityClient, src as default };
|
|
29
|
+
export { capabilityClient, src as default, showConfirm };
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
declare const createDataLoomClient: (url?: string, pat?: string) => import("@data-loom/js").DataloomClient<any, "public", any>;
|
|
1
2
|
/** 获取dataloom实例 */
|
|
2
|
-
export declare function getDataloom(): Promise<
|
|
3
|
+
export declare function getDataloom(): Promise<ReturnType<typeof createDataLoomClient>>;
|
|
4
|
+
export {};
|
|
@@ -3,9 +3,11 @@ import { createClient } from "@data-loom/js";
|
|
|
3
3
|
import { getAppId } from "../utils/getAppId.js";
|
|
4
4
|
import { getInitialInfo } from "../utils/getInitialInfo.js";
|
|
5
5
|
const createDataLoomClient = (url, pat)=>{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const { baseUrl, workspace } = url ? splitWorkspaceUrl(url) : {
|
|
7
|
+
baseUrl: '',
|
|
8
|
+
workspace: ''
|
|
9
|
+
};
|
|
10
|
+
const appId = getAppId();
|
|
9
11
|
return createClient(baseUrl, pat, workspace, {
|
|
10
12
|
global: {
|
|
11
13
|
enableDataloomLog: 'production' !== process.env.NODE_ENV,
|
|
@@ -21,12 +23,18 @@ const createDataLoomClient = (url, pat)=>{
|
|
|
21
23
|
});
|
|
22
24
|
};
|
|
23
25
|
let dataloom = null;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
let pendingPromise = null;
|
|
27
|
+
function getDataloom() {
|
|
28
|
+
if (dataloom) return Promise.resolve(dataloom);
|
|
29
|
+
if (pendingPromise) return pendingPromise;
|
|
30
|
+
pendingPromise = getInitialInfo().then((info)=>{
|
|
31
|
+
const DATALOOM_CLIENT_URL = info?.app_runtime_extra?.url;
|
|
32
|
+
const DATALOOM_PAT = info?.app_runtime_extra?.token;
|
|
33
|
+
dataloom = createDataLoomClient(DATALOOM_CLIENT_URL, DATALOOM_PAT);
|
|
34
|
+
return dataloom;
|
|
35
|
+
}).finally(()=>{
|
|
36
|
+
pendingPromise = null;
|
|
37
|
+
});
|
|
38
|
+
return pendingPromise;
|
|
31
39
|
}
|
|
32
40
|
export { getDataloom };
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { IUserProfile } from '../apis/udt-types';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 获取当前用户信息。
|
|
4
|
+
* 返回 Partial<IUserProfile>,因为初始值来自 window._userInfo,
|
|
5
|
+
* 该值在运行时始终为空对象 {},所有字段均为 undefined。
|
|
6
|
+
* 异步获取用户信息后才会被填充为完整的 IUserProfile。
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCurrentUserProfile(): Partial<IUserProfile>;
|
|
3
9
|
/**
|
|
4
10
|
* @deprecated 请使用 getCurrentUserProfile 代替
|
|
5
11
|
*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BatchGetChatsResponse, SearchChatsParams, SearchChatsResponse } from './types';
|
|
2
|
+
export type ChatServiceConfig = {
|
|
3
|
+
getAppId?: () => string | null | undefined;
|
|
4
|
+
searchChatsUrl?: (appId: string) => string;
|
|
5
|
+
listChatsUrl?: (appId: string) => string;
|
|
6
|
+
};
|
|
7
|
+
export declare class ChatService {
|
|
8
|
+
private config;
|
|
9
|
+
constructor(config?: ChatServiceConfig);
|
|
10
|
+
searchChats(params: SearchChatsParams): Promise<SearchChatsResponse>;
|
|
11
|
+
listChatsByIds(chatIds: string[]): Promise<BatchGetChatsResponse>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getAppId } from "../../utils/getAppId.js";
|
|
2
|
+
const DEFAULT_CONFIG = {
|
|
3
|
+
getAppId: ()=>getAppId(),
|
|
4
|
+
searchChatsUrl: (appId)=>`/app/${appId}/__runtime__/api/v1/account/search`,
|
|
5
|
+
listChatsUrl: (appId)=>`/app/${appId}/__runtime__/api/v1/account/chat/list_chats`
|
|
6
|
+
};
|
|
7
|
+
class ChatService {
|
|
8
|
+
config;
|
|
9
|
+
constructor(config = {}){
|
|
10
|
+
this.config = {
|
|
11
|
+
...DEFAULT_CONFIG,
|
|
12
|
+
...config
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async searchChats(params) {
|
|
16
|
+
const appId = this.config.getAppId();
|
|
17
|
+
if (!appId) throw new Error('Failed to get appId');
|
|
18
|
+
const response = await fetch(this.config.searchChatsUrl(appId), {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json'
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
query: params.query,
|
|
25
|
+
filters: {
|
|
26
|
+
userParam: {
|
|
27
|
+
commonParam: {
|
|
28
|
+
searchable: false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
departmentParam: {
|
|
32
|
+
commonParam: {
|
|
33
|
+
searchable: false
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
chatParam: {
|
|
37
|
+
commonParam: {
|
|
38
|
+
searchable: true,
|
|
39
|
+
pageSize: params.pageSize ?? 100,
|
|
40
|
+
offset: params.offset ?? 0
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
credentials: 'include'
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) throw new Error('Failed to search chats');
|
|
48
|
+
return response.json();
|
|
49
|
+
}
|
|
50
|
+
async listChatsByIds(chatIds) {
|
|
51
|
+
const appId = this.config.getAppId();
|
|
52
|
+
if (!appId) throw new Error('Failed to get appId');
|
|
53
|
+
const response = await fetch(this.config.listChatsUrl(appId), {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: {
|
|
56
|
+
'Content-Type': 'application/json'
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
chatIDList: chatIds
|
|
60
|
+
}),
|
|
61
|
+
credentials: 'include'
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) throw new Error('Failed to fetch chats by ids');
|
|
64
|
+
return response.json();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export { ChatService };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { getAppId } from "../../utils/getAppId.js";
|
|
2
|
+
import { isNewPathEnabled } from "../../utils/apiPath.js";
|
|
2
3
|
const DEFAULT_CONFIG = {
|
|
3
|
-
getAppId: ()=>getAppId(
|
|
4
|
-
searchDepartmentUrl: (appId)
|
|
4
|
+
getAppId: ()=>getAppId(),
|
|
5
|
+
searchDepartmentUrl: (appId)=>isNewPathEnabled() ? `/app/${appId}/__runtime__/api/v1/account/search_department` : `/af/app/${appId}/runtime/api/v1/account/search_department`
|
|
5
6
|
};
|
|
6
7
|
class DepartmentService {
|
|
7
8
|
config;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getAppId } from "../../utils/getAppId.js";
|
|
2
|
+
import { isNewPathEnabled } from "../../utils/apiPath.js";
|
|
2
3
|
const CDN_HOST = 'https://lf3-static.bytednsdoc.com';
|
|
3
4
|
function getAssetsUrl(path) {
|
|
4
5
|
return `${CDN_HOST}${path}`;
|
|
5
6
|
}
|
|
6
7
|
const DEFAULT_CONFIG = {
|
|
7
|
-
getAppId: ()=>getAppId(
|
|
8
|
-
userProfileUrl: (appId)
|
|
8
|
+
getAppId: ()=>getAppId(),
|
|
9
|
+
userProfileUrl: (appId)=>isNewPathEnabled() ? `/app/${appId}/__runtime__/api/v1/account/user_profile` : `/af/app/${appId}/runtime/api/v1/account/user_profile`
|
|
9
10
|
};
|
|
10
11
|
class UserProfileService {
|
|
11
12
|
config;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { BatchGetUsersResponse, SearchUsersParams, SearchUsersResponse } from './types';
|
|
1
|
+
import type { BatchGetUsersResponse, ConvertExternalContactResponse, SearchUsersParams, SearchUsersResponse } from './types';
|
|
2
2
|
export type UserServiceConfig = {
|
|
3
3
|
getAppId?: () => string | null | undefined;
|
|
4
4
|
searchUserUrl?: (appId: string) => string;
|
|
5
5
|
listUsersUrl?: (appId: string) => string;
|
|
6
|
+
convertExternalContactUrl?: (appId: string) => string;
|
|
6
7
|
};
|
|
7
8
|
export declare class UserService {
|
|
8
9
|
private config;
|
|
9
10
|
constructor(config?: UserServiceConfig);
|
|
10
11
|
searchUsers(params: SearchUsersParams): Promise<SearchUsersResponse>;
|
|
11
12
|
listUsersByIds(userIds: string[]): Promise<BatchGetUsersResponse>;
|
|
13
|
+
convertExternalContact(larkUserID: string): Promise<ConvertExternalContactResponse>;
|
|
12
14
|
}
|