feat(pc-client): 第二批登录、会话、聊天与添加同事界面按规范收口

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
编码工程师
2026-08-20 03:51:28 +08:00
co-authored by Cursor multica-agent
parent d1657ea29f
commit a44537da4e
20 changed files with 520 additions and 298 deletions
+38 -16
View File
@@ -4,7 +4,6 @@ import { t } from "i18next";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { feedbackToast } from "@/utils/common";
import { setIMProfile } from "@/utils/storage";
interface LoginResult {
@@ -18,7 +17,11 @@ interface LoginResult {
};
}
const LoginForm = () => {
type LoginFormProps = {
onBanner: (text: string) => void;
};
const LoginForm = ({ onBanner }: LoginFormProps) => {
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
@@ -34,17 +37,14 @@ const LoginForm = () => {
},
);
if (res.code !== 0 || !res.data) {
feedbackToast({
msg: res.msg || t("toast.accessFailed"),
error: res.msg || "login failed",
});
onBanner(t("toast.staffOrPasswordWrong"));
return;
}
const { userID, imToken } = res.data;
setIMProfile({ chatToken: imToken, imToken, userID });
navigate("/chat");
} catch (error) {
feedbackToast({ msg: "登录失败,请检查网络后重试", error });
} catch {
onBanner(t("toast.networkRetry"));
} finally {
setLoading(false);
}
@@ -52,22 +52,30 @@ const LoginForm = () => {
return (
<>
<div className="flex flex-row items-center justify-between">
<div className="text-xl font-medium">{t("placeholder.welcome")}</div>
<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"
labelCol={{ prefixCls: "custom-form-item" }}
validateTrigger={["onSubmit"]}
>
<Form.Item
label={t("placeholder.staffNo")}
name="staffNo"
rules={[{ required: true, message: t("toast.inputStaffNo") }]}
>
<Input allowClear placeholder={t("toast.inputStaffNo")} />
<Input
allowClear
placeholder={t("toast.inputStaffNo")}
style={{ height: 40, borderRadius: 8, backgroundColor: "var(--search-bg)" }}
disabled={loading}
/>
</Form.Item>
<Form.Item
@@ -75,14 +83,28 @@ const LoginForm = () => {
name="password"
rules={[{ required: true, message: t("toast.inputPassword") }]}
>
<Input.Password allowClear placeholder={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-4 mt-10">
<Button type="primary" htmlType="submit" block loading={loading}>
{t("placeholder.login")}
<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>
</>
);