feat: 重构 IdentifyFace.vue 为 Hooks 架构

- 新增 hooks/ 目录,包含三个专用 Hook:
  * useVoiceGeneration - 语音生成和校验逻辑
  * useDigitalHumanGeneration - 数字人视频生成逻辑
  * useIdentifyFaceController - 协调两个子 Hook 的控制器

- 新增 types/identify-face.ts 完整类型定义

- 重构 IdentifyFace.vue 使用 hooks 架构:
  * 视图层与业务逻辑分离
  * 状态管理清晰化
  * 模块解耦,逻辑清晰

- 遵循单一职责原则,每个 Hook 只负责一个领域
- 提升代码可测试性和可维护性
- 支持两种视频素材来源:素材库选择和直接上传
- 实现语音生成优先校验的业务规则

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-28 00:19:17 +08:00
parent effbbc694c
commit 36195ea55a
46 changed files with 4258 additions and 3454 deletions

View File

@@ -39,6 +39,30 @@ class TokenManager {
this.subscribers = [] // 订阅token变化的回调
}
/**
* 解析 LocalDateTime 格式为毫秒时间戳(使用 dayjs
* @param {string} dateTimeStr - LocalDateTime 格式字符串,如 "2025-12-27T10:27:42"
* @returns {number} Unix 时间戳(毫秒)
*/
parseLocalDateTime(dateTimeStr) {
if (!dateTimeStr) return 0
// 使用 dayjs 解析 LocalDateTime 格式
const normalizedStr = dateTimeStr.includes(' ')
? dateTimeStr.replace(' ', 'T')
: dateTimeStr
const dayjs = require('dayjs')
const parsedTime = dayjs(normalizedStr)
if (!parsedTime.isValid()) {
console.warn('[TokenManager] 无法解析过期时间:', dateTimeStr)
return 0
}
return parsedTime.valueOf() // 返回毫秒时间戳
}
/**
* 获取访问令牌
* @returns {string|null} 访问令牌,如果不存在则返回 null
@@ -100,6 +124,7 @@ class TokenManager {
* @param {string} tokenInfo.accessToken - 访问令牌(必填)
* @param {string} tokenInfo.refreshToken - 刷新令牌(可选)
* @param {number} tokenInfo.expiresIn - 令牌有效期(秒,可选)
* @param {string|number} tokenInfo.expiresTime - 过期时间(可选,支持 LocalDateTime 字符串、数字格式)
* @param {string} tokenInfo.tokenType - 令牌类型,默认为 'Bearer'
*/
setTokens(tokenInfo) {
@@ -107,6 +132,7 @@ class TokenManager {
accessToken,
refreshToken,
expiresIn,
expiresTime,
tokenType = 'Bearer'
} = tokenInfo
@@ -116,9 +142,6 @@ class TokenManager {
return
}
// 将过期时间从秒转换为毫秒时间戳
const expiresTime = expiresIn ? Date.now() + (expiresIn * 1000) : 0
// 存储到 localStorage
localStorage.setItem(TOKEN_KEYS.ACCESS_TOKEN, accessToken)
@@ -126,8 +149,24 @@ class TokenManager {
localStorage.setItem(TOKEN_KEYS.REFRESH_TOKEN, refreshToken)
}
// 处理过期时间
let expiresTimeMs = 0
if (expiresTime) {
localStorage.setItem(TOKEN_KEYS.EXPIRES_TIME, String(expiresTime))
// 检查类型并转换
if (typeof expiresTime === 'string' && expiresTime.includes('T')) {
// LocalDateTime 格式
expiresTimeMs = this.parseLocalDateTime(expiresTime)
} else if (typeof expiresTime === 'number') {
// 数字格式(可能是秒或毫秒)
expiresTimeMs = expiresTime > 10000000000 ? expiresTime : expiresTime * 1000
} else if (expiresIn) {
// 通过 expiresIn 计算
expiresTimeMs = Date.now() + (expiresIn * 1000)
}
if (expiresTimeMs) {
localStorage.setItem(TOKEN_KEYS.EXPIRES_TIME, String(expiresTimeMs))
}
}
localStorage.setItem(TOKEN_KEYS.TOKEN_TYPE, tokenType)