You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.7 KiB

"use client";
import { useState } from "react";
import { Truck } from "@phosphor-icons/react";
import { InputField } from "@/components/ui/input-field";
import { PrimaryButton } from "@/components/ui/primary-button";
import { ErrorBanner } from "@/components/ui/error-banner";
import { Card } from "@/components/ui/card";
import {
embedDemoLogin,
embedDemoLoginWithKey,
type EmbedDemoLoginType,
type EmbedDemoSession,
} from "@/lib/frontend/api-client";
interface EmbedDemoLoginProps {
onSuccess: (session: EmbedDemoSession) => void;
}
const LOGIN_TABS: Array<{ id: EmbedDemoLoginType; label: string }> = [
{ id: "password", label: "账号密码登录" },
{ id: "api_key", label: "API Key 登录" },
];
export function EmbedDemoLogin({ onSuccess }: EmbedDemoLoginProps) {
const [loginType, setLoginType] = useState<EmbedDemoLoginType>("password");
const [customerId, setCustomerId] = useState("");
const [password, setPassword] = useState("");
const [apiKey, setApiKey] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (loading) return;
setLoading(true);
setError(null);
const res =
loginType === "api_key"
? await embedDemoLoginWithKey("", apiKey.trim())
: await embedDemoLogin("", customerId.trim(), password);
setLoading(false);
if (res.code !== 0) {
setError(
res.message ||
(loginType === "api_key" ? "API Key 无效" : "客户编号或密码错误"),
);
return;
}
onSuccess(res.data);
};
return (
<div className="flex min-h-[60vh] items-center justify-center">
<div className="w-full max-w-md">
<div className="mb-6 flex items-center justify-center gap-2 text-primary">
<Truck size={28} weight="fill" />
<span className="text-xl font-semibold">宿</span>
</div>
<Card>
<h1 className="mb-1 text-lg font-semibold"></h1>
<p className="mb-4 text-sm text-text-secondary">
{loginType === "api_key"
? "使用管理员分配的 API Key 登录(每次进入须重新填写)"
: "使用客户编号与管理员分配的密码登录(每次进入须重新填写)"}
</p>
<div className="mb-4 flex gap-1 rounded-md bg-bg p-1">
{LOGIN_TABS.map((tab) => (
<button
key={tab.id}
type="button"
disabled={loading}
onClick={() => {
setLoginType(tab.id);
setError(null);
}}
className={`flex-1 rounded-sm px-3 py-2 text-sm font-medium transition-colors ${
loginType === tab.id
? "bg-surface text-primary shadow-card"
: "text-text-secondary hover:text-text-primary"
} ${loading ? "cursor-not-allowed opacity-50" : ""}`}
>
{tab.label}
</button>
))}
</div>
{error && (
<div className="mb-4">
<ErrorBanner>{error}</ErrorBanner>
</div>
)}
<form
onSubmit={(e) => void handleSubmit(e)}
className="space-y-4"
autoComplete="off"
>
{loginType === "api_key" ? (
<InputField
label="API Key"
name="api_key"
type="password"
placeholder="粘贴管理员分配的 API Key"
autoComplete="off"
value={apiKey}
disabled={loading}
onChange={(e) => setApiKey(e.target.value)}
/>
) : (
<>
<InputField
label="客户编号"
name="customer_id"
placeholder="例如 CUST_002"
autoComplete="off"
value={customerId}
disabled={loading}
onChange={(e) => setCustomerId(e.target.value)}
/>
<InputField
label="密码"
name="password"
type="password"
autoComplete="new-password"
value={password}
disabled={loading}
onChange={(e) => setPassword(e.target.value)}
/>
</>
)}
<PrimaryButton type="submit" loading={loading} className="w-full">
</PrimaryButton>
</form>
</Card>
</div>
</div>
);
}