Files
tongxunruanjian/pc-client/src/pages/login/LoginForm.tsx
T
bbc4dce0b6 fix: 验收包写入公司内网地址,避免 Windows 空 VITE 与 Android 假域名
Windows 补 .env.production 与 endpoints 兜底;Android 默认 host/端口改为内网,启动后重写 HttpUtil/ApiService,Urls 改为 getter。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-08-20 16:21:40 +08:00

115 lines
3.1 KiB
TypeScript

import { Button, Form, Input } from "antd";
import axios from "axios";
import { t } from "i18next";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { ACCOUNT_URL } from "@/config/endpoints";
import { setIMProfile } from "@/utils/storage";
interface LoginResult {
code: number;
msg: string;
data?: {
userID: string;
nickname: string;
imToken: string;
expireTimeSeconds?: number;
};
}
type LoginFormProps = {
onBanner: (text: string) => void;
};
const LoginForm = ({ onBanner }: LoginFormProps) => {
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const onFinish = async (values: { staffNo: string; password: string }) => {
setLoading(true);
try {
const { data: res } = await axios.post<LoginResult>(
`${ACCOUNT_URL}/api/login`,
{
staffNo: values.staffNo.trim(),
password: values.password,
platformID: window.electronAPI?.getPlatform() ?? 5,
},
);
if (res.code !== 0 || !res.data) {
onBanner(t("toast.staffOrPasswordWrong"));
return;
}
const { userID, imToken } = res.data;
setIMProfile({ chatToken: imToken, imToken, userID });
navigate("/chat");
} catch {
onBanner(t("toast.networkRetry"));
} finally {
setLoading(false);
}
};
return (
<>
<div className="text-center text-xl font-bold text-[var(--base-black)]">
{t("placeholder.title")}
</div>
<div className="mt-1 text-center text-sm text-[var(--sub-text)]">
{t("placeholder.internalComms")}
</div>
<Form
className="mt-8"
layout="vertical"
onFinish={onFinish}
autoComplete="off"
validateTrigger={["onSubmit"]}
>
<Form.Item
label={t("placeholder.staffNo")}
name="staffNo"
rules={[{ required: true, message: t("toast.inputStaffNo") }]}
>
<Input
allowClear
placeholder={t("toast.inputStaffNo")}
style={{ height: 40, borderRadius: 8, backgroundColor: "var(--search-bg)" }}
disabled={loading}
/>
</Form.Item>
<Form.Item
label={t("placeholder.password")}
name="password"
rules={[{ required: true, message: t("toast.inputPassword") }]}
>
<Input.Password
allowClear
placeholder={t("toast.inputPassword")}
style={{ height: 40, borderRadius: 8, backgroundColor: "var(--search-bg)" }}
disabled={loading}
/>
</Form.Item>
<Form.Item className="mb-2 mt-8">
<Button
type="primary"
htmlType="submit"
block
loading={loading}
style={{ height: 40, borderRadius: 8 }}
>
{loading ? t("placeholder.loggingIn") : t("placeholder.login")}
</Button>
</Form.Item>
<div className="text-center text-xs text-[var(--sub-text)]">
{t("placeholder.agreeInternal")}
</div>
</Form>
</>
);
};
export default LoginForm;