添加 CLAUDE.md 用于 Claude Code 项目导航,包含架构说明和开发规范。 更新 AI 创作客户端至 V4.0,新增后端对接示例项目。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
109 lines
3.3 KiB
JavaScript
109 lines
3.3 KiB
JavaScript
import { reactive } from 'vue'
|
||
|
||
/**
|
||
* 简单全局状态(不用 Pinia,C端足够轻量)
|
||
*
|
||
* ★ 企业集成关键:
|
||
* - phone: 当前登录用户手机号(企业从自己的登录系统获取)
|
||
* - orgId: 机构ID(乐读派分配给企业的唯一标识)
|
||
* - sessionToken: 会话令牌(企业后端调用 /api/v1/auth/session 换取,短期有效)
|
||
*
|
||
* 企业集成流程:
|
||
* 1. 企业后端调用 POST /api/v1/auth/session { orgId, appSecret, phone } 换取 sessionToken
|
||
* 2. 企业重定向用户到 H5: ?token=sess_xxx&phone=138xxx
|
||
* 3. H5 自动读取 token,所有 API 调用使用 Authorization: Bearer sess_xxx
|
||
*
|
||
* 安全说明: appSecret 只存在于企业服务端,不会到达浏览器
|
||
*/
|
||
export const store = reactive({
|
||
phone: localStorage.getItem('le_phone') || '',
|
||
orgId: localStorage.getItem('le_orgId') || '',
|
||
appSecret: localStorage.getItem('le_appSecret') || '',
|
||
sessionToken: sessionStorage.getItem('le_sessionToken') || '', // 企业生产模式用
|
||
|
||
// 创作流程数据
|
||
imageUrl: '',
|
||
extractId: '',
|
||
characters: [],
|
||
selectedCharacter: null,
|
||
selectedStyle: '',
|
||
storyData: null,
|
||
workId: '',
|
||
workDetail: null,
|
||
|
||
setPhone(phone) {
|
||
this.phone = phone
|
||
localStorage.setItem('le_phone', phone)
|
||
},
|
||
|
||
// 开发调试模式:直接设 orgId + appSecret(HMAC 签名)
|
||
setOrg(orgId, appSecret) {
|
||
this.orgId = orgId
|
||
this.appSecret = appSecret
|
||
localStorage.setItem('le_orgId', orgId)
|
||
localStorage.setItem('le_appSecret', appSecret)
|
||
},
|
||
|
||
// 企业生产模式:通过 auth/session 换取 sessionToken(Bearer Token)
|
||
setSession(orgId, sessionToken) {
|
||
this.orgId = orgId
|
||
this.sessionToken = sessionToken
|
||
localStorage.setItem('le_orgId', orgId)
|
||
sessionStorage.setItem('le_orgId', orgId)
|
||
sessionStorage.setItem('le_sessionToken', sessionToken)
|
||
},
|
||
|
||
reset() {
|
||
this.imageUrl = ''
|
||
this.extractId = ''
|
||
this.characters = []
|
||
this.selectedCharacter = null
|
||
this.selectedStyle = ''
|
||
this.storyData = null
|
||
this.workId = ''
|
||
this.workDetail = null
|
||
localStorage.removeItem('le_workId')
|
||
},
|
||
|
||
// 企业认证回调URL
|
||
authRedirectUrl: '',
|
||
|
||
clearSession() {
|
||
this.sessionToken = ''
|
||
sessionStorage.removeItem('le_sessionToken')
|
||
},
|
||
|
||
saveRecoveryState() {
|
||
const recovery = {
|
||
path: window.location.pathname || '/',
|
||
workId: this.workId || localStorage.getItem('le_workId') || '',
|
||
imageUrl: this.imageUrl || '',
|
||
extractId: this.extractId || '',
|
||
selectedStyle: this.selectedStyle || '',
|
||
savedAt: Date.now()
|
||
}
|
||
sessionStorage.setItem('le_recovery', JSON.stringify(recovery))
|
||
},
|
||
|
||
restoreRecoveryState() {
|
||
const raw = sessionStorage.getItem('le_recovery')
|
||
if (!raw) return null
|
||
try {
|
||
const recovery = JSON.parse(raw)
|
||
if (Date.now() - recovery.savedAt > 30 * 60 * 1000) {
|
||
sessionStorage.removeItem('le_recovery')
|
||
return null
|
||
}
|
||
if (recovery.workId) this.workId = recovery.workId
|
||
if (recovery.imageUrl) this.imageUrl = recovery.imageUrl
|
||
if (recovery.extractId) this.extractId = recovery.extractId
|
||
if (recovery.selectedStyle) this.selectedStyle = recovery.selectedStyle
|
||
sessionStorage.removeItem('le_recovery')
|
||
return recovery
|
||
} catch {
|
||
sessionStorage.removeItem('le_recovery')
|
||
return null
|
||
}
|
||
}
|
||
})
|