Refactor UUID generation, remove unused logger and encryption utilities, and clean up request handling

- Updated `generateUUID` function for improved readability and performance.
- Deleted `logger.ts`, `other.ts`, `request.ts`, `storage.ts`, `tansParams.ts`, and `validate.ts` as they were no longer needed.
- Simplified TypeScript configuration by removing unnecessary paths and aliases.
- Enhanced Vite configuration for better project structure and maintainability.
This commit is contained in:
DEV_DSW
2026-04-17 15:38:08 +08:00
parent b1dea9a5c2
commit 79bea4f107
360 changed files with 14495 additions and 30856 deletions

227
src/pages/Login/index.tsx Normal file
View File

@@ -0,0 +1,227 @@
import { type ChangeEvent, type FormEvent, useEffect, useMemo, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import blueLogo from '../../assets/images/login/blue_logo.png';
import loginBackground from '../../assets/images/login/login_bg.png';
import loginIllustration from '../../assets/images/login/logo.png';
import userIcon from '../../assets/images/login/user_icon.png';
import TitleBar from '../../components/layout/TitleBar';
import { resolvePostLoginPath } from '../../router/auth';
import {
createCaptchaState,
getCaptchaImageUrl,
loginWithPassword,
persistLoginTokens,
type LoginFormValues,
} from './auth';
type FormErrors = Partial<Record<'username' | 'password' | 'code' | 'submit', string>>;
const INITIAL_FORM: LoginFormValues = {
username: '',
password: '',
code: '',
randomStr: '',
};
export default function LoginPage() {
const navigate = useNavigate();
const location = useLocation();
const platform = (window as any).api?.platform ?? '';
const [form, setForm] = useState<LoginFormValues>(INITIAL_FORM);
const [errors, setErrors] = useState<FormErrors>({});
const [submitting, setSubmitting] = useState(false);
const captchaUrl = useMemo(
() => (form.randomStr ? getCaptchaImageUrl(form.randomStr) : ''),
[form.randomStr],
);
useEffect(() => {
setForm((current) => ({ ...current, ...createCaptchaState() }));
}, []);
function refreshCaptcha(clearSubmitError = true): void {
setForm((current) => ({
...current,
code: '',
...createCaptchaState(),
}));
setErrors((current) => ({
...current,
code: undefined,
submit: clearSubmitError ? undefined : current.submit,
}));
}
function updateField<K extends keyof LoginFormValues>(key: K, value: LoginFormValues[K]): void {
setForm((current) => ({ ...current, [key]: value }));
setErrors((current) => ({ ...current, [key]: undefined, submit: undefined }));
}
function validate(values: LoginFormValues): FormErrors {
const nextErrors: FormErrors = {};
if (!values.username.trim()) nextErrors.username = '请输入用户名';
if (!values.password.trim()) nextErrors.password = '请输入密码';
if (!values.code.trim()) nextErrors.code = '请输入验证码';
return nextErrors;
}
async function handleSubmit(event: FormEvent<HTMLFormElement>): Promise<void> {
event.preventDefault();
const trimmedValues: LoginFormValues = {
...form,
username: form.username.trim(),
password: form.password.trim(),
code: form.code.trim(),
};
const nextErrors = validate(trimmedValues);
if (Object.keys(nextErrors).length > 0) {
setErrors(nextErrors);
return;
}
setSubmitting(true);
setErrors({});
try {
const result = await loginWithPassword(trimmedValues);
persistLoginTokens(result);
navigate(resolvePostLoginPath(location.state as { from?: string } | null), { replace: true });
} catch (error) {
setErrors({
submit: error instanceof Error ? error.message : '登录失败,请稍后重试',
});
refreshCaptcha(false);
} finally {
setSubmitting(false);
}
}
function handleInputChange(
key: 'username' | 'password' | 'code',
event: ChangeEvent<HTMLInputElement>,
): void {
updateField(key, event.target.value);
}
return (
<div
className="h-screen flex flex-col"
style={{
backgroundImage: `url(${loginBackground})`,
backgroundSize: '100% 100%',
backgroundPosition: '0 0',
backgroundRepeat: 'no-repeat',
}}
>
<TitleBar variant="light" />
<main
className={['box-border pl-2 pr-2 pb-2 flex-auto flex', platform !== 'linux' ? 'pt-2' : 'pt-11'].join(' ')}
>
<div className="w-[836px] box-border rounded-2xl border border-black/5 bg-white p-8 shadow-[0_18px_50px_rgba(15,23,42,0.12)] dark:border-[#2a2a2d] dark:bg-[#1b1b1d]">
<div className="flex items-center">
<img className="w-12 h-12" src={blueLogo} alt="zn-ai" />
</div>
<div className="mb-6 box-border flex flex-col items-center justify-center pt-10">
<img className="mb-3 h-20 w-20" src={userIcon} alt="" />
<div className="mb-1 text-[24px] leading-[32px] font-medium text-gray-800 dark:text-gray-100">
zn-ai
</div>
<div className="text-[16px] leading-[24px] text-gray-500 dark:text-gray-400">
</div>
</div>
<form className="mx-auto flex w-[392px] flex-col gap-4" onSubmit={handleSubmit}>
<div>
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-username">
</label>
<input
id="login-username"
className="h-10 w-full rounded-[10px] border border-black/10 bg-gray-50 px-4 text-[14px] text-gray-800 outline-none transition focus:border-[#2B7FFF] dark:border-[#2a2a2d] dark:bg-[#222225] dark:text-gray-100"
autoComplete="username"
disabled={submitting}
placeholder="请输入用户名"
value={form.username}
onChange={(event) => handleInputChange('username', event)}
/>
{errors.username ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.username}</div> : null}
</div>
<div>
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-password">
</label>
<input
id="login-password"
className="h-10 w-full rounded-[10px] border border-black/10 bg-gray-50 px-4 text-[14px] text-gray-800 outline-none transition focus:border-[#2B7FFF] dark:border-[#2a2a2d] dark:bg-[#222225] dark:text-gray-100"
autoComplete="current-password"
disabled={submitting}
placeholder="请输入密码"
type="password"
value={form.password}
onChange={(event) => handleInputChange('password', event)}
/>
{errors.password ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.password}</div> : null}
</div>
<div>
<label className="mb-2 block text-[14px] text-gray-600 dark:text-gray-300" htmlFor="login-code">
</label>
<div className="flex gap-3">
<input
id="login-code"
className="h-10 min-w-0 flex-1 rounded-[10px] border border-black/10 bg-gray-50 px-4 text-[14px] text-gray-800 outline-none transition focus:border-[#2B7FFF] dark:border-[#2a2a2d] dark:bg-[#222225] dark:text-gray-100"
autoComplete="off"
disabled={submitting}
placeholder="请输入验证码"
value={form.code}
onChange={(event) => handleInputChange('code', event)}
/>
<button
type="button"
className="h-10 w-24 overflow-hidden rounded-[10px] border border-black/10 bg-white p-0 transition hover:border-[#2B7FFF] disabled:cursor-not-allowed dark:border-[#2a2a2d] dark:bg-[#222225]"
disabled={submitting || !captchaUrl}
onClick={refreshCaptcha}
>
{captchaUrl ? (
<img className="h-full w-full object-cover" src={captchaUrl} alt="验证码" />
) : (
<span className="text-[12px] text-[#99A0AE]"></span>
)}
</button>
</div>
{errors.code ? <div className="pt-2 text-[12px] text-[#dc2626]">{errors.code}</div> : null}
</div>
{errors.submit ? (
<div className="rounded-[10px] border border-[#fecaca] bg-[#fef2f2] px-3 py-2 text-[13px] text-[#b91c1c]">
{errors.submit}
</div>
) : null}
<button
type="submit"
className="mt-4 w-full rounded-lg bg-blue-600 py-2 text-white transition hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-blue-300"
disabled={submitting}
>
{submitting ? '登录中...' : '登录'}
</button>
</form>
</div>
<img className="ml-2 w-[540px] max-w-[48vw] self-center object-contain" src={loginIllustration} alt="" />
</main>
</div>
);
}