TTeamDesk 学习手册

src/features/auth/auth-form.tsx

此代码来自构建时的仓库快照。修改源码后重新构建即可更新。

tsx
'use client';
import { useState } from 'react';
import { Alert, Button, Card, Form, Input, Tabs } from 'antd';
import { authClient } from '@/lib/auth-client';

export function AuthForm() {
  const [mode, setMode] = useState('login');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');
  async function submit(values: {
    email: string;
    password: string;
    name?: string;
  }) {
    setBusy(true);
    setError('');
    try {
      const result =
        mode === 'login'
          ? await authClient.signIn.email({
              email: values.email.trim().toLowerCase(),
              password: values.password,
            })
          : await authClient.signUp.email({
              email: values.email.trim().toLowerCase(),
              password: values.password,
              name: values.name!.trim(),
            });
      if (result.error) {
        setError(
          mode === 'login'
            ? '登录失败,请检查邮箱和密码后重试'
            : '注册失败,请检查输入或尝试登录已有账号',
        );
        return;
      }
      // 完整刷新销毁上一账号的查询缓存和草稿,避免同一浏览器切换账号时残留数据。
      // 登录身份发生变化时刻意完整刷新,销毁上一账号的内存缓存。
      // eslint-disable-next-line @next/next/no-location-assign-relative-destination
      window.location.assign('/');
    } catch {
      setError('网络连接失败,请稍后重试');
    } finally {
      setBusy(false);
    }
  }
  return (
    <main className="mx-auto flex min-h-screen max-w-md items-center px-5 py-12">
      <Card className="w-full" title="TeamDesk · 团队客服平台">
        <p className="mb-5 text-slate-500">
          登录后进入你的团队,协作处理每一张工单。
        </p>
        <Tabs
          activeKey={mode}
          onChange={(key) => {
            setMode(key);
            setError('');
          }}
          items={[
            { key: 'login', label: '登录' },
            { key: 'register', label: '注册' },
          ]}
        />
        {error && (
          <Alert className="mb-4" type="error" showIcon title={error} />
        )}
        <Form key={mode} layout="vertical" onFinish={submit} disabled={busy}>
          {mode === 'register' && (
            <Form.Item
              label="姓名"
              name="name"
              rules={[
                { required: true, whitespace: true, message: '请输入姓名' },
                { max: 80 },
              ]}
            >
              <Input autoComplete="name" />
            </Form.Item>
          )}
          <Form.Item
            label="邮箱"
            name="email"
            rules={[
              { required: true, message: '请输入邮箱' },
              { type: 'email', message: '请输入有效邮箱' },
            ]}
          >
            <Input autoComplete="email" />
          </Form.Item>
          <Form.Item
            label="密码"
            name="password"
            rules={[
              { required: true, message: '请输入密码' },
              ...(mode === 'register'
                ? [
                    { min: 10, message: '密码至少 10 字符' },
                    { max: 128, message: '密码最多 128 字符' },
                  ]
                : []),
            ]}
          >
            <Input.Password
              autoComplete={
                mode === 'login' ? 'current-password' : 'new-password'
              }
            />
          </Form.Item>
          <Button htmlType="submit" type="primary" block loading={busy}>
            {mode === 'login' ? '登录' : '注册并登录'}
          </Button>
        </Form>
      </Card>
    </main>
  );
}

搜索教程

输入关键词,搜索全部章节。

阅读设置

外观
正文字号

从一张工单出发,读懂数据如何流转。

设置与进度仅保存在当前浏览器。