Files
ViGent2/Docs/DevLogs/Day15.md
Kevin Wong e226224119 更新
2026-02-08 19:54:11 +08:00

411 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Day 15 - 手机号登录迁移 + 账户设置功能
**日期**2026-02-02
---
## 🔐 认证系统迁移:邮箱 → 手机号
### 背景
根据业务需求将用户认证从邮箱登录迁移到手机号登录11位中国手机号
### 变更范围
| 组件 | 变更内容 |
|------|----------|
| 数据库 Schema | `email` 字段替换为 `phone` |
| 后端 API | 注册/登录/获取用户信息接口使用 `phone` |
| 前端页面 | 登录/注册页面改为手机号输入框 |
| 管理员配置 | `ADMIN_EMAIL` 改为 `ADMIN_PHONE` |
---
## 📦 后端修改
### 1. 数据库 Schema (`schema.sql`)
**文件**: `backend/database/schema.sql`
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone TEXT UNIQUE NOT NULL, -- 原 email 改为 phone
password_hash TEXT NOT NULL,
username TEXT,
role TEXT DEFAULT 'pending' CHECK (role IN ('pending', 'user', 'admin')),
is_active BOOLEAN DEFAULT FALSE,
expires_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_users_phone ON users(phone);
```
### 2. 认证 API (`auth.py`)
**文件**: `backend/app/api/auth.py`
#### 请求模型更新
```python
class RegisterRequest(BaseModel):
phone: str
password: str
username: Optional[str] = None
@field_validator('phone')
@classmethod
def validate_phone(cls, v):
if not re.match(r'^\d{11}$', v):
raise ValueError('手机号必须是11位数字')
return v
```
#### 新增修改密码接口
```python
class ChangePasswordRequest(BaseModel):
old_password: str
new_password: str
@field_validator('new_password')
@classmethod
def validate_new_password(cls, v):
if len(v) < 6:
raise ValueError('新密码长度至少6位')
return v
@router.post("/change-password")
async def change_password(request: ChangePasswordRequest, req: Request, response: Response):
"""修改密码,验证当前密码后更新"""
# 1. 验证当前密码
# 2. 更新密码 hash
# 3. 重新生成 session token
# 4. 返回新的 JWT Cookie
```
### 3. 配置更新
**文件**: `backend/app/core/config.py`
```python
# 管理员配置
ADMIN_PHONE: str = "" # 原 ADMIN_EMAIL
ADMIN_PASSWORD: str = ""
```
**文件**: `backend/.env`
```bash
ADMIN_PHONE=15549380526
ADMIN_PASSWORD=lam1988324
```
### 4. 管理员初始化 (`main.py`)
**文件**: `backend/app/main.py`
```python
@app.on_event("startup")
async def init_admin():
admin_phone = settings.ADMIN_PHONE # 原 ADMIN_EMAIL
# ... 使用 phone 字段创建管理员
```
### 5. 管理员 API (`admin.py`)
**文件**: `backend/app/api/admin.py`
```python
class UserListItem(BaseModel):
id: str
phone: str # 原 email
username: Optional[str]
role: str
is_active: bool
expires_at: Optional[str]
created_at: str
```
---
## 🖥️ 前端修改
### 1. 登录页面 (`login/page.tsx`)
**文件**: `frontend/src/app/login/page.tsx`
```tsx
const [phone, setPhone] = useState('');
// 验证手机号格式
if (!/^\d{11}$/.test(phone)) {
setError('请输入正确的11位手机号');
return;
}
<input
type="tel"
value={phone}
onChange={(e) => setPhone(e.target.value.replace(/\D/g, '').slice(0, 11))}
maxLength={11}
placeholder="请输入11位手机号"
/>
```
### 2. 注册页面 (`register/page.tsx`)
同样使用手机号输入,增加 11 位数字验证。
### 3. Auth 工具函数 (`auth.ts`)
**文件**: `frontend/src/shared/lib/auth.ts`
```typescript
export interface User {
id: string;
phone: string; // 原 email
username: string | null;
role: string;
is_active: boolean;
}
export async function login(phone: string, password: string): Promise<AuthResponse> { ... }
export async function register(phone: string, password: string, username?: string): Promise<AuthResponse> { ... }
export async function changePassword(oldPassword: string, newPassword: string): Promise<AuthResponse> { ... }
```
### 4. 首页账户设置下拉菜单 (`page.tsx`)
**文件**: `frontend/src/app/page.tsx`
将原来的"退出"按钮改为账户设置下拉菜单:
```tsx
function AccountSettingsDropdown() {
const [isOpen, setIsOpen] = useState(false);
const [showPasswordModal, setShowPasswordModal] = useState(false);
// ...
return (
<div className="relative">
<button onClick={() => setIsOpen(!isOpen)}>
</button>
{/* 下拉菜单 */}
{isOpen && (
<div className="absolute right-0 mt-2 w-40 bg-gray-800 ...">
<button onClick={() => setShowPasswordModal(true)}>
🔐
</button>
<button onClick={handleLogout} className="text-red-300">
🚪 退
</button>
</div>
)}
{/* 修改密码弹窗 */}
{showPasswordModal && (
<div className="fixed inset-0 z-50 ...">
<form onSubmit={handleChangePassword}>
<input placeholder="当前密码" />
<input placeholder="新密码" />
<input placeholder="确认新密码" />
</form>
</div>
)}
</div>
);
}
```
### 5. 管理员页面 (`admin/page.tsx`)
**文件**: `frontend/src/app/admin/page.tsx`
```tsx
interface UserListItem {
id: string;
phone: string; // 原 email
// ...
}
// 显示手机号而非邮箱
<div className="text-gray-400 text-sm">{user.phone}</div>
```
---
## 🗄️ 数据库迁移
### 迁移脚本
**文件**: `backend/database/migrate_to_phone.sql`
```sql
-- 删除旧表 (CASCADE 处理外键依赖)
DROP TABLE IF EXISTS user_sessions CASCADE;
DROP TABLE IF EXISTS social_accounts CASCADE;
DROP TABLE IF EXISTS users CASCADE;
-- 重新创建使用 phone 字段的表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
phone TEXT UNIQUE NOT NULL,
-- ...
);
-- 重新创建依赖表和索引
CREATE TABLE user_sessions (...);
CREATE TABLE social_accounts (...);
CREATE INDEX idx_users_phone ON users(phone);
```
### 执行方式
```bash
# 方式一Docker 命令
docker exec -i supabase-db psql -U postgres < backend/database/migrate_to_phone.sql
# 方式二Supabase Studio SQL Editor
# 打开 https://supabase.hbyrkj.top -> SQL Editor -> 粘贴执行
```
---
## ✅ 部署步骤
```bash
# 1. 执行数据库迁移
docker exec -i supabase-db psql -U postgres < backend/database/migrate_to_phone.sql
# 2. 重新构建前端
cd frontend && npm run build
# 3. 重启服务
pm2 restart vigent2-backend vigent2-frontend
```
---
## 📁 今日修改文件清单
| 文件 | 变更类型 | 说明 |
|------|----------|------|
| `backend/database/schema.sql` | 修改 | email → phone |
| `backend/database/migrate_to_phone.sql` | 新增 | 数据库迁移脚本 |
| `backend/app/api/auth.py` | 修改 | 手机号验证 + 修改密码 API |
| `backend/app/api/admin.py` | 修改 | UserListItem.email → phone |
| `backend/app/core/config.py` | 修改 | ADMIN_EMAIL → ADMIN_PHONE |
| `backend/app/main.py` | 修改 | 管理员初始化使用 phone |
| `backend/.env` | 修改 | ADMIN_PHONE=15549380526 |
| `frontend/src/app/login/page.tsx` | 修改 | 手机号登录 + 11位验证 |
| `frontend/src/app/register/page.tsx` | 修改 | 手机号注册 + 11位验证 |
| `frontend/src/shared/lib/auth.ts` | 修改 | phone 参数 + changePassword 函数 |
| `frontend/src/app/page.tsx` | 修改 | AccountSettingsDropdown 组件 |
| `frontend/src/app/admin/page.tsx` | 修改 | 用户列表显示手机号 |
| `frontend/src/contexts/AuthContext.tsx` | 修改 | 存储完整用户信息含 expires_at |
---
## 🆕 后续完善 (Day 15 下午)
### 账户有效期显示
在账户下拉菜单中显示用户的有效期:
| 显示情况 | 格式 |
|----------|------|
| 有设置 expires_at | `2026-03-15` |
| NULL | `永久有效` |
**相关修改**
- `backend/app/api/auth.py`: UserResponse 新增 `expires_at` 字段
- `frontend/src/contexts/AuthContext.tsx`: 存储完整用户对象
- `frontend/src/app/page.tsx`: 格式化并显示有效期
### 点击外部关闭下拉菜单
使用 `useRef` + `useEffect` 监听全局点击事件,点击菜单外部自动关闭。
### 修改密码后强制重新登录
密码修改成功后:
1. 显示"密码修改成功,正在跳转登录页..."
2. 1.5秒后调用登出 API
3. 跳转到登录页面
---
## 🔗 相关文档
- [TASK_COMPLETE.md](../TASK_COMPLETE.md) - 任务总览
- [Day14.md](./Day14.md) - 模型升级 + AI 标题标签
- [AUTH_DEPLOY.md](../AUTH_DEPLOY.md) - 认证系统部署指南
---
## 🤖 模型与功能增强 (Day 15 晚)
### 1. GLM-4.7-Flash 升级
**文件**: `backend/app/services/glm_service.py`
将文案洗稿模型从 `glm-4-flash` 升级为 `glm-4.7-flash`
```python
response = client.chat.completions.create(
model="glm-4.7-flash", # Upgrade from glm-4-flash
messages=[...],
# ...
)
```
**改进**:
- 响应速度提升
- 洗稿文案的流畅度和逻辑性增强
### 2. 独立文案提取助手
实现了独立的文案提取工具,支持从视频/音频文件或 URL 提取文字。
#### 后端实现 (`backend/app/api/tools.py`)
- **多源支持**: 文件上传 (MP4/MP3/WAV) 或 URL 下载
- **智能下载**:
- `yt-dlp`: 通用下载 (Douyin/TikTok/Bilibili)
- `Playwright`: 智能回退机制 (Bilibili Dashboard API, Douyin Cookie Bypass)
- **URL 自动清洗**: 正则提取分享文本中的 HTTP 链接
- **流程**: 下载 -> FFmpeg 转 WAV (16k) -> Whisper 识别 -> GLM-4.7 洗稿
#### 前端实现 (`frontend/src/components/ScriptExtractionModal.tsx`)
- **独立模态框**: 通过顶部导航栏打开
- **功能**:
- 链接粘贴 / 文件拖拽
- 实时进度显示 (下载 -> 识别 -> 洗稿)
- **一键填入**: 将提取结果直接填充到主输入框
- **自动识别**: 自动区分平台与链接
- **交互优化**:
- 防止误触背景关闭
- 复制功能兼容 HTTP 环境 (Fallback textArea)
### 3. 上传视频预览功能
在素材列表 (`frontend/src/app/page.tsx`) 中为上传的视频添加预览功能:
- 点击缩略图弹出视频播放模态框
- 支持下载与发布快捷跳转
---
## 📝 任务清单更新
- [x] 认证系统迁移 (手机号)
- [x] 账户管理 (密码修改/有效期)
- [x] GLM-4.7 模型升级
- [x] 独立文案提取助手 (B站/抖音支持)
- [x] 视频预览功能