init push
This commit is contained in:
8
web/admin/src/hooks/index.tsx
Normal file
8
web/admin/src/hooks/index.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
export { useBindCaptcha } from './useBindCaptcha';
|
||||
export { useCommitPendingInput } from './useCommitPendingInput';
|
||||
export { useURLSearchParams } from './useURLSearchParams';
|
||||
export {
|
||||
useFeatureValue,
|
||||
useFeatureValueSupported,
|
||||
useVersionInfo,
|
||||
} from './useVersionFeature';
|
||||
67
web/admin/src/hooks/useBindCaptcha.ts
Normal file
67
web/admin/src/hooks/useBindCaptcha.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { message } from '@ctzhian/ui';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export function useBindCaptcha(
|
||||
id: string,
|
||||
{
|
||||
init = false,
|
||||
businessId = '0195ea3c-ab47-73f3-9f8e-e72b8fd7f089',
|
||||
}: { init: boolean; businessId?: string },
|
||||
) {
|
||||
const captcha = useRef<any>({});
|
||||
const resolveRef = useRef<any>(null);
|
||||
const [load, setLoad] = useState(false);
|
||||
const [token, setToken] = useState<string>();
|
||||
|
||||
const initCaptcha = () => {
|
||||
captcha.current = new (window as any).SCaptcha({
|
||||
businessid: businessId,
|
||||
action: 'pow',
|
||||
position: 'mask',
|
||||
});
|
||||
captcha.current!.bind(
|
||||
('#' + id).replace(/:/g, '\\:'),
|
||||
(action: any, data: any) => {
|
||||
if (action === 'finished') {
|
||||
captcha.current.reset();
|
||||
if (data) {
|
||||
setToken(data);
|
||||
resolveRef.current(data);
|
||||
} else {
|
||||
message.error('验证失败');
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
const oldStart = captcha.current.start.bind(captcha.current);
|
||||
captcha.current.start = (e: any) => {
|
||||
oldStart(e);
|
||||
return new Promise(resolve => {
|
||||
resolveRef.current = resolve;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const loadCaptcha = () => {
|
||||
const script = document.createElement('script');
|
||||
script.src =
|
||||
'https://0195ea3c-ab47-73f3-9f8e-e72b8fd7f089.safepoint.s-captcha-r1.com/v1/static/web.js';
|
||||
document.body.appendChild(script);
|
||||
script.onload = () => {
|
||||
setLoad(true);
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (init) {
|
||||
if (!load) {
|
||||
loadCaptcha();
|
||||
} else {
|
||||
initCaptcha();
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [init, load]);
|
||||
|
||||
return [captcha, token] as [any, string];
|
||||
}
|
||||
37
web/admin/src/hooks/useCommitPendingInput.tsx
Normal file
37
web/admin/src/hooks/useCommitPendingInput.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
export function useCommitPendingInput<T>({
|
||||
value,
|
||||
setValue,
|
||||
}: {
|
||||
value: T[];
|
||||
setValue: (v: T[]) => void;
|
||||
}) {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
// 用于同步获取最新值(解决闭包问题)
|
||||
const valueRef = useRef(value);
|
||||
valueRef.current = value;
|
||||
|
||||
// 提交未完成的输入
|
||||
const commit = () => {
|
||||
const trimmed = inputValue.trim();
|
||||
if (trimmed) {
|
||||
const newValue = [...valueRef.current, trimmed as T];
|
||||
setValue(newValue);
|
||||
setInputValue('');
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
/** 已提交的值 */
|
||||
value,
|
||||
/** 设置已提交的值(用于外部修改) */
|
||||
setValue,
|
||||
/** 当前输入框中的临时值 */
|
||||
inputValue,
|
||||
/** 设置临时值 */
|
||||
setInputValue,
|
||||
/** 提交未完成的输入 */
|
||||
commit,
|
||||
};
|
||||
}
|
||||
26
web/admin/src/hooks/useDebounceAppPreviewData.tsx
Normal file
26
web/admin/src/hooks/useDebounceAppPreviewData.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useAppDispatch } from '@/store';
|
||||
import { setAppPreviewData } from '@/store/slices/config';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
const useDebounceAppPreviewData = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const debouncedDispatch = useMemo(
|
||||
() =>
|
||||
debounce((data: any) => {
|
||||
dispatch(setAppPreviewData(data));
|
||||
}, 500),
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
debouncedDispatch.cancel();
|
||||
};
|
||||
}, [debouncedDispatch]);
|
||||
|
||||
return debouncedDispatch;
|
||||
};
|
||||
|
||||
export default useDebounceAppPreviewData;
|
||||
28
web/admin/src/hooks/useURLSearchParams.tsx
Normal file
28
web/admin/src/hooks/useURLSearchParams.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { filterEmpty } from '@/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocation, useSearchParams } from 'react-router-dom';
|
||||
|
||||
export const useURLSearchParams = (): [
|
||||
URLSearchParams,
|
||||
(other: Record<string, string> | null) => void,
|
||||
] => {
|
||||
const { search } = useLocation();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [params, setParams] = useState<Record<string, string>>({});
|
||||
|
||||
const setURLSearchParams = (other: Record<string, string> | null) => {
|
||||
if (other === null) setSearchParams({});
|
||||
else setSearchParams(filterEmpty({ ...params, ...other }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const obj: Record<string, string> = {};
|
||||
searchParams.forEach((value, key) => {
|
||||
obj[key] = value;
|
||||
});
|
||||
setParams(obj);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [search]);
|
||||
|
||||
return [searchParams, setURLSearchParams];
|
||||
};
|
||||
34
web/admin/src/hooks/useVersionFeature.ts
Normal file
34
web/admin/src/hooks/useVersionFeature.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
FeatureStatus,
|
||||
VersionInfoMap,
|
||||
VersionInfo,
|
||||
getFeatureValue,
|
||||
} from '@/constant/version';
|
||||
import { ConstsLicenseEdition } from '@/request/types';
|
||||
import { useAppSelector } from '@/store';
|
||||
|
||||
export const useFeatureValue = <K extends keyof VersionInfo['features']>(
|
||||
key: K,
|
||||
): VersionInfo['features'][K] => {
|
||||
const { license } = useAppSelector(state => state.config);
|
||||
return getFeatureValue(license.edition!, key);
|
||||
};
|
||||
|
||||
export const useFeatureValueSupported = (
|
||||
key: keyof VersionInfo['features'],
|
||||
) => {
|
||||
const { license } = useAppSelector(state => state.config);
|
||||
return (
|
||||
getFeatureValue(license.edition!, key) === FeatureStatus.SUPPORTED ||
|
||||
getFeatureValue(license.edition!, key) === FeatureStatus.ADVANCED
|
||||
);
|
||||
};
|
||||
|
||||
export const useVersionInfo = () => {
|
||||
const { license } = useAppSelector(state => state.config);
|
||||
return (
|
||||
VersionInfoMap[
|
||||
license.edition ?? ConstsLicenseEdition.LicenseEditionFree
|
||||
] || VersionInfoMap[ConstsLicenseEdition.LicenseEditionFree]
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user