Skip to content

Commit 0ecba3d

Browse files
authored
Merge pull request #17 from osoulmate/main
fix: 修复多个问题
2 parents 4bfb5ad + b5d41b9 commit 0ecba3d

31 files changed

Lines changed: 2310 additions & 740 deletions

File tree

src/actions/dictionary.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
deleteDictionaryByIdDB,
1313
findOrCreateDictionaryDB,
1414
findDictionariesGivenVisibilityDB,
15+
findDictionaryByProjectIdDB
1516
} from "@/db/dictionary"
1617
import {createDictionaryEntryDB,
1718
updateDictionaryEntryByIdDB,
@@ -108,16 +109,25 @@ export async function fetchDictionaryByIdAction(id: string) {
108109
}
109110

110111
// 仅获取词典元信息(更快,避免一次性返回大量 entries)
111-
export async function fetchDictionaryMetaByIdAction(id: string) {
112+
export async function fetchDictionaryMetaByIdAction(dictionaryId: string) {
112113
try {
113-
const dictionary = await findDictionaryByIdDB(id)
114+
const dictionary = await findDictionaryByIdDB(dictionaryId)
115+
return { success: true, data: dictionary };
116+
} catch (error) {
117+
console.error("获取词典元信息失败:", error);
118+
return { success: false, error: "获取词典元信息失败" };
119+
}
120+
}
121+
// 仅获取词典元信息(更快,避免一次性返回大量 entries)
122+
export async function fetchDictionaryMetaByProjectIdAction(projectId: string) {
123+
try {
124+
const dictionary = await findDictionaryByProjectIdDB(projectId)
114125
return { success: true, data: dictionary };
115126
} catch (error) {
116127
console.error("获取词典元信息失败:", error);
117128
return { success: false, error: "获取词典元信息失败" };
118129
}
119130
}
120-
121131
// 更新词典
122132
export async function updateDictionaryAction(id: string, data: {
123133
name?: string

src/agents/pre-translate/DictLookupAgent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { BaseAgent, type AgentRunContext } from '../base'
22
import { dictionaryTool } from '../tools/dictionary'
33
import { DictEntry, TermCandidate } from '@/types/terms'
44

5-
export class DictLookupAgent extends BaseAgent<{ terms: TermCandidate[]; tenantId?: string; userId?: string; locale?: string }, DictEntry[]> {
6-
constructor(locale?: string) {
5+
export class DictLookupAgent extends BaseAgent<{ terms: TermCandidate[]; tenantId?: string; userId?: string; locale?: string ; domain?: string }, DictEntry[]> {
6+
constructor(locale?: string, domain?: string) {
77
super({
88
name: 'dict-lookup',
99
role: 'terminology_assistant',
10-
domain: 'general',
10+
domain: domain || 'general',
1111
specialty: '术语库查询', // This will be replaced by i18n
1212
locale: locale || 'zh'
1313
});

src/agents/pre-translate/MonoTermExtractAgent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { BaseAgent, type AgentRunContext } from '../base'
22
import { TermCandidate } from '@/types/terms'
33
import { createAgentI18n } from '../i18n'
44

5-
export class MonoTermExtractAgent extends BaseAgent<{ text: string; prompt?: string; locale?: string }, TermCandidate[]> {
5+
export class MonoTermExtractAgent extends BaseAgent<{ text: string; prompt?: string; locale?: string; domain?: string }, TermCandidate[]> {
66

7-
constructor(locale?: string) {
7+
constructor(locale?: string, domain?: string) {
88
super({
99
name: 'mono-term-extract',
1010
role: 'term_extractor',
11-
domain: 'general',
11+
domain: domain || 'general',
1212
quality: 'review',
1313
locale: locale || 'zh'
1414
});

src/app/(app)/auth/login/components/email-login-form.tsx

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,72 @@ import { Button } from "@/components/ui/button";
44
import { toast } from "sonner";
55
import { emailLoginAction } from "@/actions/email-login";
66
import { useTranslations } from "next-intl";
7+
import { Icons } from "@/components/icons"; // 导入图标组件
78

89
export function EmailLoginForm({ buttonText }: { buttonText?: string }) {
910
const [email, setEmail] = useState("");
1011
const [code, setCode] = useState("");
1112
const [cooldown, setCooldown] = useState(0);
1213
const [isPending, startTransition] = useTransition();
14+
const [isSendingCode, setIsSendingCode] = useState(false); // 新增:发送验证码加载状态
1315
const t = useTranslations("Auth");
1416

1517
const sendCode = async () => {
1618
if (!email) {
1719
toast.error(t("pleaseEnterEmail"));
1820
return;
1921
}
22+
23+
// 验证邮箱格式
24+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
25+
if (!emailRegex.test(email)) {
26+
toast.error(t("invalidEmailFormat"));
27+
return;
28+
}
29+
30+
setIsSendingCode(true); // 开始发送,显示加载状态
31+
2032
try {
2133
const form = new FormData();
2234
form.set('mode', 'email');
2335
form.set('email', email);
24-
const res = await fetch("/api/auth/send-code", { method: "POST", body: form });
36+
37+
// 添加超时处理
38+
const controller = new AbortController();
39+
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
40+
41+
const res = await fetch("/api/auth/send-email", {
42+
method: "POST",
43+
body: form,
44+
signal: controller.signal
45+
});
46+
47+
clearTimeout(timeoutId);
48+
2549
if (res.ok) {
2650
toast.info(process.env.NODE_ENV === "development" ? t("codeSentDev") : t("codeSent"));
2751
setCooldown(60);
2852
const timer = setInterval(() => {
2953
setCooldown((s) => {
30-
if (s <= 1) { clearInterval(timer); return 0; }
54+
if (s <= 1) {
55+
clearInterval(timer);
56+
return 0;
57+
}
3158
return s - 1;
3259
});
3360
}, 1000);
3461
} else {
35-
toast.error(t("sendFailed"));
62+
const errorData = await res.json().catch(() => ({}));
63+
toast.error(errorData.message || t("sendFailed"));
3664
}
3765
} catch (e: any) {
38-
toast.error(`${t("sendFailed")}${e.message}`);
66+
if (e.name === 'AbortError') {
67+
toast.error(t("requestTimeout"));
68+
} else {
69+
toast.error(`${t("sendFailed")}${e.message}`);
70+
}
71+
} finally {
72+
setIsSendingCode(false); // 结束发送,隐藏加载状态
3973
}
4074
};
4175

@@ -50,7 +84,7 @@ export function EmailLoginForm({ buttonText }: { buttonText?: string }) {
5084

5185
return (
5286
<form onSubmit={onSubmit} className="space-y-4">
53-
<div className="flex flex-col justify-center gap-2 space-y-4">
87+
<div className="flex flex-col justify-center gap-2 space-y-4">
5488
{/* 邮箱 */}
5589
<div>
5690
<div className="mb-1 text-sm">{t("email")}</div>
@@ -62,7 +96,8 @@ export function EmailLoginForm({ buttonText }: { buttonText?: string }) {
6296
value={email}
6397
onChange={(e) => setEmail(e.target.value)}
6498
required
65-
className="mx-6 w-full p-1 bg-transparent outline-none border-none focus-visible:border-none focus-visible:ring-0 hover:border-none hover:ring-0"
99+
disabled={isSendingCode} // 发送时禁用邮箱输入
100+
className="mx-6 w-full p-1 bg-transparent outline-none border-none focus-visible:border-none focus-visible:ring-0 hover:border-none hover:ring-0 disabled:opacity-50 disabled:cursor-not-allowed"
66101
/>
67102
</div>
68103
</div>
@@ -77,32 +112,54 @@ export function EmailLoginForm({ buttonText }: { buttonText?: string }) {
77112
type="text"
78113
value={code}
79114
onChange={(e) => setCode(e.target.value)}
80-
className="mx-6 w-full p-1 bg-transparent outline-none border-none shadow-none focus-visible:border-none focus-visible:ring-0 hover:border-none hover:ring-0"
115+
disabled={isSendingCode} // 发送时禁用验证码输入
116+
className="mx-6 w-full p-1 bg-transparent outline-none border-none shadow-none focus-visible:border-none focus-visible:ring-0 hover:border-none hover:ring-0 disabled:opacity-50 disabled:cursor-not-allowed"
81117
/>
82118
<Button
83119
type="button"
84120
variant="link"
85121
size="sm"
86122
onClick={sendCode}
87-
disabled={cooldown > 0}
88-
className="mr-2 text-primary"
123+
disabled={cooldown > 0 || isSendingCode || !email}
124+
className="mr-2 text-primary min-w-[100px] transition-all duration-300"
89125
>
90-
{cooldown > 0 ? t("retryAfter", { seconds: cooldown }) : t("getCode")}
126+
{isSendingCode ? (
127+
<div className="flex items-center gap-2">
128+
<Icons.spinner className="h-4 w-4 animate-spin" />
129+
<span>{t("sending")}</span>
130+
</div>
131+
) : cooldown > 0 ? (
132+
<div className="flex items-center gap-2">
133+
<span>{t("retryAfter", { seconds: cooldown })}</span>
134+
</div>
135+
) : (
136+
<div className="flex items-center gap-2">
137+
<span>{t("getCode")}</span>
138+
</div>
139+
)}
91140
</Button>
92141
</div>
93142
</div>
94143

95-
{/* 条款提示已移除 */}
96-
97144
{/* 提交按钮 */}
98145
<div className="space-y-4 pb-2">
99-
<Button type="submit" variant="default" className="w-full transition delay-150 duration-300" disabled={isPending}>
100-
{buttonText || t("login")}
146+
<Button
147+
type="submit"
148+
variant="default"
149+
className="w-full transition delay-150 duration-300"
150+
disabled={isPending || isSendingCode}
151+
>
152+
{isPending ? (
153+
<div className="flex items-center gap-2">
154+
<Icons.spinner className="h-4 w-4 animate-spin" />
155+
<span>{t("loggingIn")}</span>
156+
</div>
157+
) : (
158+
buttonText || t("login")
159+
)}
101160
</Button>
102161
</div>
103162
</div>
104163
</form>
105164
);
106-
}
107-
108-
165+
}

src/app/(app)/auth/register/components/register-card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const RegisterCard = () => {
1919
const form = new FormData();
2020
form.set('mode', 'email');
2121
form.set('email', email.trim());
22-
const r = await fetch('/api/auth/send-code', { method: 'POST', body: form });
22+
const r = await fetch('/api/auth/send-email', { method: 'POST', body: form });
2323
if (!r.ok) throw new Error(t("sendFailed"));
2424
toast.info(process.env.NODE_ENV === 'development' ? t("codeSentDev") : t("codeSent"));
2525
setCooldown(60);

0 commit comments

Comments
 (0)