搜索结果列表页面开发
This commit is contained in:
332
src/utils/hooks/useForm.ts
Normal file
332
src/utils/hooks/useForm.ts
Normal file
@@ -0,0 +1,332 @@
|
||||
import { computed, ref, reactive, shallowRef, onBeforeUnmount, watchEffect, nextTick } from 'vue';
|
||||
import type { FormListProps } from '@/components/Form/types';
|
||||
import type { Ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAccount } from './useAccount';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import { emitEvent } from '@/utils/eventBus';
|
||||
|
||||
export function useFormInteraction(currentForm: Ref<FormListProps[]>, flag: boolean = false, extraStatus: Ref<boolean> = ref(true)) {
|
||||
const router = useRouter();
|
||||
const { RecordInfo } = useAccount();
|
||||
let interval: any = null;
|
||||
const cacheForm = reactive<{ mobile: string, verificationcode: string, countdownSecond: number, user_id: string, mask: string }>({
|
||||
mobile: '',
|
||||
verificationcode: '',
|
||||
countdownSecond: 59,
|
||||
user_id: '',
|
||||
mask: ''
|
||||
});
|
||||
// 表单错误信息
|
||||
const formErrors = reactive<Record<string, string>>({});
|
||||
// 额外验证参数
|
||||
const extraErrors = reactive<{ agreement: string, requestInfo: string }>({
|
||||
agreement: '',
|
||||
requestInfo: ''
|
||||
});
|
||||
// 协议是否抖动
|
||||
const AgreementWarn = ref(false);
|
||||
// 禁用提交
|
||||
const disabled = ref(true);
|
||||
// 协议状态
|
||||
const status = ref(flag);
|
||||
// 表单ref
|
||||
const FormRef = shallowRef<any>(null);
|
||||
// 按钮loading
|
||||
const loading = ref(false);
|
||||
|
||||
/** 密码框文字间距样式 */
|
||||
const PasswordInputSpacing = computed(() => {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera;
|
||||
const isIos = /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream;
|
||||
return isIos ? '0px' : '-1px';
|
||||
});
|
||||
|
||||
/** 当前表单错误信息 */
|
||||
const errorMsg = computed(() => {
|
||||
const keys = Object.keys(formErrors);
|
||||
if (currentForm.value?.length) {
|
||||
const obj = currentForm.value.find(item => keys.includes(item.key) && formErrors[item.key]);
|
||||
if (FormRef.value) {
|
||||
const filterKeys = keys.filter(key => key !== obj?.key && formErrors[key]);
|
||||
filterKeys.length && FormRef.value?.ClearFormFields(filterKeys);
|
||||
hackMsgError(obj?.key === 'verificationcode' || obj?.key === 'code');
|
||||
}
|
||||
if (obj) {
|
||||
return formErrors[obj.key];
|
||||
}
|
||||
return extraErrors.agreement || extraErrors.requestInfo || '';
|
||||
} else {
|
||||
return extraErrors.agreement || extraErrors.requestInfo || '';
|
||||
}
|
||||
});
|
||||
|
||||
/** 设置表单单个字段校验信息 */
|
||||
const setFormErrorKey = (conf: { errors: Record<string, any[]> } | Record<string, any>) => {
|
||||
let message: string = '';
|
||||
let key: string = '';
|
||||
if (Object.prototype.hasOwnProperty.call(conf, 'errors')) {
|
||||
const { errors } = conf;
|
||||
key = Object.keys(errors)[0];
|
||||
const formDict = errors[key];
|
||||
message = formDict?.length ? formDict[0].message : '';
|
||||
} else {
|
||||
key = Object.keys(conf)[0];
|
||||
message = (conf as Record<string, any>)[key];
|
||||
}
|
||||
formErrors[key] = message;
|
||||
};
|
||||
|
||||
/** 捕获整个表单校验信息 */
|
||||
const catchFormErrors = (conf: { errors: Record<string, any[]> }) => {
|
||||
const { errors } = conf;
|
||||
for (const key in errors) {
|
||||
const obj: Record<string, string> = {};
|
||||
obj[key] = errors[key][0].message as string;
|
||||
setFormErrorKey(obj);
|
||||
}
|
||||
};
|
||||
/** 清空表单校验信息 */
|
||||
const clearFormError = (key?: string) => {
|
||||
if (key) {
|
||||
formErrors[key] = '';
|
||||
} else {
|
||||
for (const key in formErrors) {
|
||||
formErrors[key] = '';
|
||||
}
|
||||
for (const key in extraErrors) {
|
||||
extraErrors[key as keyof typeof extraErrors] = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 表单字段change事件 */
|
||||
const handleFormChange = (conf: { key: string, errors: Record<string, any> | null, source: Record<string, any> }) => {
|
||||
const { key, errors } = conf;
|
||||
if (errors) {
|
||||
setFormErrorKey({ errors });
|
||||
} else {
|
||||
formErrors[key] = '';
|
||||
}
|
||||
nextTick(() => {
|
||||
const keys = Object.keys(formErrors);
|
||||
if (currentForm.value?.length) {
|
||||
const obj = currentForm.value.find(item => keys.includes(item.key) && formErrors[item.key]);
|
||||
if (FormRef.value) {
|
||||
const filterKeys = keys.filter(k => k !== obj?.key && formErrors[k]);
|
||||
if (filterKeys.length) {
|
||||
FormRef.value?.ClearFormFields(filterKeys);
|
||||
} else {
|
||||
obj && !errors && FormRef.value?.ValidateFormKeys([obj.key]);
|
||||
}
|
||||
}
|
||||
hackMsgError(obj?.key === 'verificationcode' || obj?.key === 'code');
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 表单input事件 */
|
||||
const handleFormInput = (val: boolean) => {
|
||||
disabled.value = val;
|
||||
};
|
||||
/** 第三方登录 */
|
||||
const handleAuthLogin = (type: 'csdn' | 'gitee' | 'github' | 'mobile', callback?: Function, returnUrl? :string) => {
|
||||
if (localStorage.getItem('access_token')) {
|
||||
callback?.();
|
||||
} else {
|
||||
if (type === 'mobile') {
|
||||
if (returnUrl) {
|
||||
router.push('/loginByPhone?returnUrl=' + returnUrl);
|
||||
} else {
|
||||
router.push('/loginByPhone');
|
||||
}
|
||||
} else {
|
||||
if (!status.value) {
|
||||
extraErrors.agreement = `请阅读并同意用户协议以及其隐私政策`;
|
||||
AgreementWarn.value = true;
|
||||
setTimeout(() => {
|
||||
AgreementWarn.value = false;
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
if (localStorage.getItem('utm_source')) {
|
||||
localStorage.removeItem('utm_source');
|
||||
}
|
||||
// 保存登录前页面地址
|
||||
localStorage.setItem('loginReturnUrl', returnUrl || '');
|
||||
// window.location.href = 'http://localhost:5173/oauth/callback';
|
||||
const url = `${(import.meta as any).env.VITE_API_HOST}${(import.meta as any).env.VITE_PASSPORT_PREFIX || ''}/api/v1/oauth/login/${type}`;
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 提交表单 */
|
||||
const handleSubmit = async(callback: (config: Record<string, any>) => Promise<void>, extraInfo: string = '') => {
|
||||
if (!status.value) {
|
||||
extraErrors.agreement = extraInfo || '请阅读并同意用户协议以及隐私政策';
|
||||
AgreementWarn.value = true;
|
||||
setTimeout(() => {
|
||||
AgreementWarn.value = false;
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
extraErrors.agreement = '';
|
||||
if (FormRef.value) {
|
||||
const formData = await FormRef.value.ValidateForm();
|
||||
if (formData.type === 'success') {
|
||||
loading.value = true;
|
||||
clearFormError();
|
||||
await callback(formData.forms);
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
} else {
|
||||
catchFormErrors(formData);
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 倒计时 */
|
||||
const handleCountDown = async(conf: { key: string, value: any, sourceKey: string }, callback: () => Promise<boolean>) => {
|
||||
const formData = await FormRef.value.ValidateFormKeys([conf.key]);
|
||||
if (formData.type === 'success') {
|
||||
clearFormError(conf.key);
|
||||
const status = await callback();
|
||||
status && resetMsgStatus(conf.sourceKey);
|
||||
} else {
|
||||
setFormErrorKey(formData);
|
||||
}
|
||||
};
|
||||
/** gitcode 外链url */
|
||||
const links = {
|
||||
'agreement': 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E6%9C%8D%E5%8A%A1%E6%9D%A1%E6%AC%BE.md',
|
||||
'privacy': 'https://gitcode.com/Gitcode-offical-team/GitCode-Docs/blob/main/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%2F%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96.md'
|
||||
};
|
||||
/** 华为云 外链url */
|
||||
const links_hw = {
|
||||
agreement: 'https://www.huaweicloud.com/declaration/sa_cua.html',
|
||||
privacy: 'https://www.huaweicloud.com/declaration/sa_prp.html'
|
||||
};
|
||||
/** 展示声明 */
|
||||
const handleDisplay = (type: 'agreement' | 'privacy', class_type: 'gitcode' | 'hw' = 'gitcode') => {
|
||||
const link = class_type === 'gitcode' ? links[type] : links_hw[type];
|
||||
window.open(link);
|
||||
};
|
||||
|
||||
/** 重置短信按钮状态 */
|
||||
const resetMsgStatus = (key: string, status: boolean = true) => {
|
||||
if (currentForm.value?.length) {
|
||||
currentForm.value.forEach(item => {
|
||||
if (item.key === key) {
|
||||
if (item.props) {
|
||||
item.props.countdown = status;
|
||||
}
|
||||
}
|
||||
});
|
||||
status && toCountDown(key);
|
||||
}
|
||||
};
|
||||
|
||||
/** 缓存倒计时间 */
|
||||
const toCountDown = (key: string) => {
|
||||
if (!interval) {
|
||||
if (cacheForm.countdownSecond === 0) {
|
||||
cacheForm.countdownSecond = 59;
|
||||
}
|
||||
interval = setInterval(() => {
|
||||
if (cacheForm.countdownSecond >= 1) {
|
||||
cacheForm.countdownSecond -= 1;
|
||||
} else {
|
||||
if (localStorage.getItem('cache_countdown')) {
|
||||
localStorage.removeItem('cache_countdown');
|
||||
}
|
||||
cacheForm.countdownSecond = 59;
|
||||
interval && clearInterval(interval);
|
||||
interval = null;
|
||||
resetMsgStatus(key, false);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
/** 存贮用户信息以及跳转 */
|
||||
const saveUserInfo = (conf: any, returnUrl?: any) => {
|
||||
const { username, email } = conf;
|
||||
RecordInfo(conf);
|
||||
Message.success({
|
||||
message: '欢迎来到Gitcode!',
|
||||
onClose: () => {
|
||||
emitEvent('notice');
|
||||
}
|
||||
});
|
||||
if (`${username}@gitcode.com` === email) { // 需要修改默认邮箱的弹窗
|
||||
localStorage.setItem('validator_email', 'invalid');
|
||||
} else {
|
||||
localStorage.setItem('validator_email', 'valid');
|
||||
}
|
||||
if (returnUrl) {
|
||||
location.href = returnUrl;
|
||||
} else {
|
||||
router.replace('/');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* redirect绑定华为云
|
||||
* @deprecated
|
||||
*/
|
||||
const redirectBind = (config: { user_id: string, mask: string, mobile: string }) => {
|
||||
for (const key in config) {
|
||||
cacheForm[key as keyof typeof config] = config[key as keyof typeof config];
|
||||
}
|
||||
// router.replace({
|
||||
// path: '/bindPhone',
|
||||
// query: config
|
||||
// });
|
||||
};
|
||||
|
||||
/** hack短信弹窗错误样式 */
|
||||
const hackMsgError = (show_error: boolean) => {
|
||||
const el = document.querySelector('.g-input-button');
|
||||
if (el) {
|
||||
if (show_error) {
|
||||
(el as HTMLElement).style.borderColor = 'var(--devui-danger-line, #f66f6a)';
|
||||
} else {
|
||||
(el as HTMLElement).style.borderColor = 'rgba(230, 230, 232, 1)';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if (status.value && extraStatus.value && extraErrors.agreement) {
|
||||
extraErrors.agreement = '';
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
hackMsgError(false);
|
||||
});
|
||||
|
||||
return {
|
||||
AgreementWarn,
|
||||
status,
|
||||
disabled,
|
||||
FormRef,
|
||||
cacheForm,
|
||||
formErrors,
|
||||
PasswordInputSpacing,
|
||||
extraErrors,
|
||||
errorMsg,
|
||||
loading,
|
||||
setFormErrorKey,
|
||||
catchFormErrors,
|
||||
clearFormError,
|
||||
toCountDown,
|
||||
handleFormChange,
|
||||
handleFormInput,
|
||||
handleAuthLogin,
|
||||
handleCountDown,
|
||||
handleDisplay,
|
||||
handleSubmit,
|
||||
saveUserInfo
|
||||
// redirectBind
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user