dc38c3fa8b
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m26s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m26s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m59s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m22s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m22s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 6m17s
CI/CD Pipeline / Integration Tests (push) Successful in 2m51s
CI/CD Pipeline / Unit Tests (push) Successful in 11m48s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 29s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 35s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m7s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m47s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
98 lines
2.6 KiB
TypeScript
98 lines
2.6 KiB
TypeScript
import { useState, useEffect } from "react"
|
|
import { Form, message } from "antd"
|
|
import { sendVerificationCode, bindContact, type BindContactResponse } from "@/api/auth"
|
|
import { useCountdown } from "./useCountdown"
|
|
|
|
type ContactType = "email" | "phone"
|
|
|
|
interface UseBindContactFormOptions {
|
|
open: boolean
|
|
onSuccess?: (user: BindContactResponse["user"]) => void
|
|
onCancel?: () => void
|
|
}
|
|
|
|
/**
|
|
* 绑定联系方式表单 Hook
|
|
* 封装表单状态、验证码发送、提交绑定等业务逻辑
|
|
*/
|
|
export const useBindContactForm = ({ open, onSuccess }: UseBindContactFormOptions) => {
|
|
const [activeTab, setActiveTab] = useState<ContactType>("email")
|
|
const [form] = Form.useForm()
|
|
const [loading, setLoading] = useState(false)
|
|
const [codeLoading, setCodeLoading] = useState(false)
|
|
const { countdown, isRunning, start: startCountdown, reset: resetCountdown } = useCountdown(60)
|
|
|
|
/* ── 打开时重置表单 ── */
|
|
useEffect(() => {
|
|
if (open) {
|
|
form.resetFields()
|
|
resetCountdown()
|
|
}
|
|
}, [open, form, resetCountdown])
|
|
|
|
/* ── 发送验证码 ── */
|
|
const handleSendCode = async () => {
|
|
try {
|
|
const fieldName = activeTab === "email" ? "email" : "phone"
|
|
const value = form.getFieldValue(fieldName)
|
|
if (!value) {
|
|
message.warning(activeTab === "email" ? "请输入邮箱" : "请输入手机号")
|
|
return
|
|
}
|
|
setCodeLoading(true)
|
|
await sendVerificationCode({
|
|
target: activeTab,
|
|
value,
|
|
purpose: "bind",
|
|
})
|
|
message.success("验证码已发送")
|
|
startCountdown()
|
|
} catch {
|
|
// error handled by interceptor
|
|
} finally {
|
|
setCodeLoading(false)
|
|
}
|
|
}
|
|
|
|
/* ── 提交绑定 ── */
|
|
const handleSubmit = async () => {
|
|
// 1. 表单验证(失败时 Ant Design Form 会自动展示错误信息)
|
|
let values
|
|
try {
|
|
values = await form.validateFields()
|
|
} catch {
|
|
return
|
|
}
|
|
|
|
// 2. 调用绑定接口
|
|
setLoading(true)
|
|
try {
|
|
const payload =
|
|
activeTab === "email"
|
|
? { email: values.email, email_code: values.email_code }
|
|
: { phone: values.phone, phone_code: values.phone_code }
|
|
|
|
const result = await bindContact(payload)
|
|
|
|
message.success("绑定成功")
|
|
onSuccess?.(result.user)
|
|
} catch {
|
|
// API 错误由全局拦截器统一处理提示
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return {
|
|
activeTab,
|
|
setActiveTab,
|
|
form,
|
|
loading,
|
|
codeLoading,
|
|
countdown,
|
|
codeDisabled: isRunning,
|
|
handleSendCode,
|
|
handleSubmit,
|
|
}
|
|
}
|