diff --git a/achievements/achievements.js b/achievements/achievements.js index d4c63a4..93e7845 100644 --- a/achievements/achievements.js +++ b/achievements/achievements.js @@ -137,7 +137,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/achievements`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const list = this.decorateList(res.data?.data || []) const sections = this.buildSections(list) @@ -156,7 +156,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/achievements/refresh`, method: 'POST', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const payload = res.data?.data || {} const list = this.decorateList(payload.achievements || []) diff --git a/batch-upload/batch-upload.js b/batch-upload/batch-upload.js index 9702b18..c24c3d0 100644 --- a/batch-upload/batch-upload.js +++ b/batch-upload/batch-upload.js @@ -36,7 +36,7 @@ Page({ url: `${app.globalData.baseUrl}/api/v1/entries/upload-file`, filePath: file.path, name: 'file', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (uploadRes) => { try { const payload = JSON.parse(uploadRes.data) diff --git a/checkin-detail/checkin-detail.js b/checkin-detail/checkin-detail.js index 64fefe5..ebf6e22 100644 --- a/checkin-detail/checkin-detail.js +++ b/checkin-detail/checkin-detail.js @@ -13,7 +13,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/checkin/stats`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => this.setData({ stats: res.data?.data || null }), fail: () => this.setData({ error: '打卡数据加载失败' }), complete: () => this.setData({ loading: false }), diff --git a/entry-detail/entry-detail.js b/entry-detail/entry-detail.js index 704d528..550b214 100644 --- a/entry-detail/entry-detail.js +++ b/entry-detail/entry-detail.js @@ -11,7 +11,7 @@ Page({ this.loadEntry() }, loadEntry() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '请先登录' }) return } @@ -22,7 +22,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${this.entryId}`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { const entry = res.data?.data || null this.setData({ entry, error: entry ? '' : '未找到词条' }) @@ -45,7 +45,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${this.data.entry.id}`, method: 'DELETE', - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: () => { wx.showToast({ title: '已删除', icon: 'success' }) const pages = getCurrentPages() diff --git a/entry-edit/entry-edit.js b/entry-edit/entry-edit.js index 6b9f5d5..a0331f1 100644 --- a/entry-edit/entry-edit.js +++ b/entry-edit/entry-edit.js @@ -17,14 +17,14 @@ Page({ if (entryId) this.loadEntry(entryId) }, loadEntry(entryId) { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '请先登录' }) return } this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${entryId}`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { const entry = res.data?.data if (!entry) { @@ -71,7 +71,7 @@ Page({ wx.navigateBack() }, save() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { wx.showToast({ title: '请先登录', icon: 'none' }) return } @@ -83,7 +83,7 @@ Page({ wx.request({ url, method, - header: { 'Content-Type': 'application/json', 'X-OpenID': app.globalData.openid }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': app.globalData.authToken }, data: this.data.isEditMode ? { entry_type: this.data.entryType, diff --git a/index/index.js b/index/index.js index 8cae738..9bc753d 100644 --- a/index/index.js +++ b/index/index.js @@ -12,13 +12,13 @@ Page({ async loadStats() { this.setData({ loading: true, error: '' }) await app.ensureLogin() - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '登录失败,请稍后重试', loading: false }) return } wx.request({ url: `${app.globalData.baseUrl}/api/v1/home/stats`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { const payload = res.data?.data if (payload) this.setData({ stats: payload }) diff --git a/manage/batch-upload/batch-upload.js b/manage/batch-upload/batch-upload.js index 9702b18..c24c3d0 100644 --- a/manage/batch-upload/batch-upload.js +++ b/manage/batch-upload/batch-upload.js @@ -36,7 +36,7 @@ Page({ url: `${app.globalData.baseUrl}/api/v1/entries/upload-file`, filePath: file.path, name: 'file', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (uploadRes) => { try { const payload = JSON.parse(uploadRes.data) diff --git a/manage/entry-detail/entry-detail.js b/manage/entry-detail/entry-detail.js index 942cb41..97c2901 100644 --- a/manage/entry-detail/entry-detail.js +++ b/manage/entry-detail/entry-detail.js @@ -11,7 +11,7 @@ Page({ this.loadEntry() }, loadEntry() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '????' }) return } @@ -22,7 +22,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${this.entryId}`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { const entry = res.data?.data || null this.setData({ entry, error: entry ? '' : '?????' }) @@ -45,7 +45,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${this.data.entry.id}`, method: 'DELETE', - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: () => { wx.showToast({ title: '???', icon: 'success' }) const pages = getCurrentPages() diff --git a/manage/entry-edit/entry-edit.js b/manage/entry-edit/entry-edit.js index 6b9f5d5..a0331f1 100644 --- a/manage/entry-edit/entry-edit.js +++ b/manage/entry-edit/entry-edit.js @@ -17,14 +17,14 @@ Page({ if (entryId) this.loadEntry(entryId) }, loadEntry(entryId) { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '请先登录' }) return } this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/entries/${entryId}`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { const entry = res.data?.data if (!entry) { @@ -71,7 +71,7 @@ Page({ wx.navigateBack() }, save() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { wx.showToast({ title: '请先登录', icon: 'none' }) return } @@ -83,7 +83,7 @@ Page({ wx.request({ url, method, - header: { 'Content-Type': 'application/json', 'X-OpenID': app.globalData.openid }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': app.globalData.authToken }, data: this.data.isEditMode ? { entry_type: this.data.entryType, diff --git a/me/file_content_needed.py b/me/file_content_needed.py new file mode 100644 index 0000000..d3109e1 --- /dev/null +++ b/me/file_content_needed.py @@ -0,0 +1,20 @@ +from sqlalchemy import BigInteger, Column, DateTime, String, func +from sqlalchemy.orm import relationship + +from app.db.session import Base + + +class User(Base): + __tablename__ = "users" + + id = Column(BigInteger, primary_key=True, autoincrement=True) + openid = Column(String(64), nullable=False, unique=True, index=True) + username = Column(String(64), nullable=True, unique=True, index=True) + password = Column(String(128), nullable=True) + login_type = Column(String(20), nullable=False, default="wechat") + nickname = Column(String(100), nullable=True) + avatar_url = Column(String(255), nullable=True) + created_at = Column(DateTime, nullable=False, server_default=func.now()) + updated_at = Column(DateTime, nullable=False, server_default=func.now(), onupdate=func.now()) + + entries = relationship("Entry", back_populates="user") diff --git a/me/me.js b/me/me.js index 565ea0c..770a089 100644 --- a/me/me.js +++ b/me/me.js @@ -7,10 +7,10 @@ function normalizeAvatarUrl(avatarUrl, baseUrl) { function requestFailHint(errMsg) { const m = String(errMsg || '').toLowerCase() - if (m.includes('domain') || m.includes('合法域名')) return '域名未在公众平台配置,或未开启 HTTPS' - if (m.includes('ssl') || m.includes('certificate')) return 'HTTPS 证书异常,请检查服务器证书' + if (m.includes('domain')) return '域名未配置或未开启 HTTPS' + if (m.includes('ssl') || m.includes('certificate')) return 'HTTPS 证书异常,请检查服务端配置' if (m.includes('timeout') || m.includes('timed out')) return '连接超时,请稍后重试' - return '网络异常,请检查网络后重试' + return '网络异常,请稍后重试' } const DEFAULT_AVATAR = 'data:image/svg+xml;utf8,' + encodeURIComponent(` @@ -32,91 +32,148 @@ Page({ data: { name: '', nickname: '', + username: '', days: 0, badges: 0, - openid: '', avatarUrl: '', defaultAvatarUrl: DEFAULT_AVATAR, loading: false, error: '', showNicknameModal: false, nicknameDraft: '', + authMode: 'login', + authForm: { + username: '', + password: '', + nickname: '', + }, }, onShow() { this.loadProfile() }, - async loadProfile() { - const openid = app.globalData.openid || wx.getStorageSync('openid') || '' - if (!openid) { - this.setData({ - loading: false, - openid: '', - name: '未登录', - nickname: '未登录', - avatarUrl: '', - nicknameDraft: '', - badges: 0, - days: 0, - error: '', - }) + isLoggedIn() { + return !!app.globalData.authToken + }, + onAuthModeChange(e) { + this.setData({ authMode: e.currentTarget.dataset.mode || 'login', error: '' }) + }, + onAuthInput(e) { + const { field } = e.currentTarget.dataset + const value = e.detail.value || '' + this.setData({ [`authForm.${field}`]: value }) + }, + submitAuth() { + const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl + const mode = this.data.authMode + const username = (this.data.authForm.username || '').trim() + const password = (this.data.authForm.password || '').trim() + const nickname = (this.data.authForm.nickname || '').trim() + + if (!username || !password) { + wx.showToast({ title: '请输入账号和密码', icon: 'none' }) return } + + if (mode === 'register' && !nickname) { + wx.showToast({ title: '请输入昵称', icon: 'none' }) + return + } + this.setData({ loading: true, error: '' }) - app.globalData.openid = openid - const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl - let profileErrMsg = '' wx.request({ - url: `${baseUrl}/api/v1/auth/profile?openid=${encodeURIComponent(openid)}`, - method: 'GET', + url: `${baseUrl}/api/v1/auth/${mode === 'register' ? 'register' : 'login'}`, + method: 'POST', + header: { 'Content-Type': 'application/json' }, + data: mode === 'register' ? { username, password, nickname } : { username, password }, success: (res) => { - const body = res.data || {} - const ok = res.statusCode >= 200 && res.statusCode < 300 && body.code === 0 && body.data - if (!ok) { - profileErrMsg = '个人信息加载失败,请稍后重试' - const storedAvatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || '' - const normalizedAvatar = normalizeAvatarUrl(storedAvatarUrl, baseUrl) - this.setData({ - openid, - name: '考研战士', - nickname: '考研战士', - avatarUrl: normalizedAvatar, - nicknameDraft: '考研战士', - error: profileErrMsg, - }) + const payload = res.data?.data || null + if (res.statusCode < 200 || res.statusCode >= 300 || !payload?.auth_token) { + const message = res.data?.detail || res.data?.message || `${mode === 'register' ? '注册' : '登录'}失败` + this.setData({ error: message }) + wx.showToast({ title: message, icon: 'none' }) return } - const profile = body.data - const avatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || profile.avatar_url || '' - const nickname = profile.nickname || '考研战士' - const normalizedAvatar = normalizeAvatarUrl(avatarUrl, baseUrl) - profileErrMsg = '' + + app.setLoginSession(payload) this.setData({ - openid, - name: nickname, - nickname, - avatarUrl: normalizedAvatar, - nicknameDraft: nickname, - days: Number(profile.days || 0), + authForm: { username: '', password: '', nickname: '' }, + username: payload.username || '', + }) + wx.showToast({ title: mode === 'register' ? '注册成功' : '登录成功', icon: 'success' }) + this.loadProfile() + }, + fail: (err) => { + const message = requestFailHint(err.errMsg) + this.setData({ error: message }) + wx.showToast({ title: message, icon: 'none' }) + }, + complete: () => this.setData({ loading: false }), + }) + }, + loadProfile() { + const token = app.ensureLogin() + Promise.resolve(token).then((authToken) => { + if (!authToken) { + this.setData({ + loading: false, + name: '未登录', + nickname: '未登录', + username: '', + avatarUrl: '', + nicknameDraft: '', + badges: 0, + days: 0, error: '', }) - }, - fail: () => { - profileErrMsg = '个人信息加载失败,请稍后重试' - const storedAvatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || '' - const normalizedAvatar = normalizeAvatarUrl(storedAvatarUrl, baseUrl) - this.setData({ - openid, - name: '考研战士', - nickname: '考研战士', - avatarUrl: normalizedAvatar, - nicknameDraft: '考研战士', - error: profileErrMsg, - }) - }, - complete: () => { - this.loadAchievements(profileErrMsg) - this.setData({ loading: false }) - }, + return + } + + this.setData({ loading: true, error: '' }) + const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl + wx.request({ + url: `${baseUrl}/api/v1/auth/profile`, + method: 'GET', + header: app.getAuthHeader(), + success: (res) => { + const body = res.data || {} + const profile = body.data + const ok = res.statusCode >= 200 && res.statusCode < 300 && body.code === 0 && profile + if (!ok) { + const message = body.detail || body.message || '个人信息加载失败' + this.setData({ error: message }) + return + } + + const identity = profile.username || app.globalData.currentUser?.username || '' + const avatarUrl = wx.getStorageSync(`avatarUrl:${identity}`) || profile.avatar_url || '' + const normalizedAvatar = normalizeAvatarUrl(avatarUrl, baseUrl) + const nickname = profile.nickname || identity || '考研战士' + + app.globalData.currentUser = { + ...(app.globalData.currentUser || {}), + id: profile.id, + username: profile.username || '', + nickname, + loginType: profile.login_type || 'account', + } + wx.setStorageSync('currentUser', app.globalData.currentUser) + + this.setData({ + name: nickname, + nickname, + username: profile.username || '', + avatarUrl: normalizedAvatar, + nicknameDraft: nickname, + days: Number(profile.days || 0), + error: '', + }) + this.loadAchievements() + }, + fail: (err) => { + this.setData({ error: requestFailHint(err.errMsg) }) + }, + complete: () => this.setData({ loading: false }), + }) }) }, openNicknameModal() { @@ -132,7 +189,7 @@ Page({ this.setData({ nicknameDraft: e.detail.value }) }, saveNickname() { - if (!app.globalData.openid) return + if (!this.isLoggedIn()) return const nickname = (this.data.nicknameDraft || '').trim() if (!nickname) { wx.showToast({ title: '请输入昵称', icon: 'none' }) @@ -141,11 +198,14 @@ Page({ wx.request({ url: `${app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl}/api/v1/auth/profile`, method: 'PUT', - header: { 'Content-Type': 'application/json' }, - data: { openid: app.globalData.openid, nickname }, + header: app.getAuthHeader({ 'Content-Type': 'application/json' }), + data: { nickname }, success: (res) => { const profile = res.data?.data || {} const nextNickname = profile.nickname || nickname + const currentUser = { ...(app.globalData.currentUser || {}), nickname: nextNickname } + app.globalData.currentUser = currentUser + wx.setStorageSync('currentUser', currentUser) this.setData({ nickname: nextNickname, name: nextNickname, nicknameDraft: nextNickname, showNicknameModal: false }) wx.showToast({ title: '保存成功', icon: 'success' }) }, @@ -154,7 +214,7 @@ Page({ }, onChooseAvatar(e) { const tempPath = e.detail?.avatarUrl || '' - if (!app.globalData.openid) { + if (!this.isLoggedIn()) { wx.showToast({ title: '请先登录', icon: 'none' }) return } @@ -164,24 +224,22 @@ Page({ } const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl wx.uploadFile({ - url: `${baseUrl}/api/v1/auth/avatar?openid=${encodeURIComponent(app.globalData.openid)}`, + url: `${baseUrl}/api/v1/auth/avatar`, filePath: tempPath, name: 'file', + header: app.getAuthHeader(), success: (uploadRes) => { try { const payload = JSON.parse(uploadRes.data || '{}') - const ok = - uploadRes.statusCode >= 200 && - uploadRes.statusCode < 300 && - payload.code === 0 && - payload.data + const ok = uploadRes.statusCode >= 200 && uploadRes.statusCode < 300 && payload.code === 0 && payload.data if (!ok) { wx.showToast({ title: payload.message || '头像上传失败', icon: 'none' }) return } const rel = payload.data.avatar_url || '' const full = normalizeAvatarUrl(rel, baseUrl) - wx.setStorageSync(`avatarUrl:${app.globalData.openid}`, full) + const key = this.data.username || app.globalData.currentUser?.username || '' + if (key) wx.setStorageSync(`avatarUrl:${key}`, full) this.setData({ avatarUrl: full }) wx.showToast({ title: '头像已更新', icon: 'success' }) } catch { @@ -191,77 +249,46 @@ Page({ fail: (err) => wx.showToast({ title: requestFailHint(err.errMsg), icon: 'none' }), }) }, - loadAchievements(profileErrMsg) { - if (!app.globalData.openid) { - this.setData({ error: '登录状态已失效,请重新进入页面' }) - return - } + loadAchievements() { + if (!this.isLoggedIn()) return const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl - const achFail = '成就数据加载失败,请稍后重试' wx.request({ url: `${baseUrl}/api/v1/achievements`, - header: { 'X-OpenID': app.globalData.openid }, + header: app.getAuthHeader(), success: (res) => { const body = res.data || {} const ok = res.statusCode >= 200 && res.statusCode < 300 && body.code === 0 && Array.isArray(body.data) - if (!ok) { - this.setData({ error: profileErrMsg ? `${profileErrMsg};${achFail}` : achFail }) - return - } - const list = body.data - const badges = list.filter((i) => i.is_unlocked).length - this.setData({ badges, error: profileErrMsg || '' }) - }, - fail: (err) => { - const netHint = requestFailHint(err.errMsg) - const line = profileErrMsg ? `${profileErrMsg};${achFail}` : achFail - this.setData({ error: `${line}(${netHint})` }) + if (!ok) return + const badges = body.data.filter((i) => i.is_unlocked).length + this.setData({ badges }) }, }) }, - manualLogin() { - wx.login({ - success: (res) => { - const code = res.code || '' - console.log('[login] wx.login success', res) - console.log('[login] code', code) - if (!code) { - wx.showToast({ title: '登录失败,请重试', icon: 'none' }) - return - } - wx.request({ - url: `${app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl}/api/v1/auth/wx-login`, - method: 'POST', - header: { 'Content-Type': 'application/json' }, - data: { code }, - success: (loginRes) => { - console.log('[login] wx-login success', loginRes) - const payload = loginRes.data?.data || {} - if (loginRes.statusCode >= 200 && loginRes.statusCode < 300 && loginRes.data?.code === 0 && payload.openid) { - app.globalData.openid = payload.openid - wx.setStorageSync('openid', payload.openid) - wx.showToast({ title: '登录成功', icon: 'success' }) - this.loadProfile() - return - } - console.log('[login] wx-login invalid response', loginRes.data) - wx.showToast({ title: '登录接口异常,请稍后重试', icon: 'none' }) - }, - fail: (err) => { - console.log('[login] wx-login fail', err) - wx.showToast({ title: requestFailHint(err.errMsg), icon: 'none' }) - }, + logout() { + if (!this.isLoggedIn()) return + wx.request({ + url: `${app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl}/api/v1/auth/logout`, + method: 'POST', + header: app.getAuthHeader(), + complete: () => { + app.clearLoginSession() + this.setData({ + name: '未登录', + nickname: '未登录', + username: '', + avatarUrl: '', + nicknameDraft: '', + badges: 0, + days: 0, + error: '', }) - }, - fail: (err) => { - console.log('[login] wx.login fail', err) - wx.showToast({ title: '登录失败,请重试', icon: 'none' }) + wx.showToast({ title: '已退出登录', icon: 'success' }) }, }) }, goTo(e) { const { url } = e.currentTarget.dataset - if (!app.globalData.openid) { + if (!this.isLoggedIn()) { wx.showToast({ title: '请先登录', icon: 'none' }) return } diff --git a/me/me.wxml b/me/me.wxml index 54209fc..69cce1a 100644 --- a/me/me.wxml +++ b/me/me.wxml @@ -6,10 +6,19 @@ 正在获取个人信息 - - 还未登录 - 请点击下方按钮手动登录后继续使用 - + + 账号登录 + 使用账号密码登录,或先注册一个新账号 + + 登录 + 注册 + + + + + + + @@ -35,12 +44,12 @@ - + 还没有解锁成就 继续复习和打卡,成就会逐渐点亮 - + 🏅 @@ -85,6 +94,8 @@ 设置中心 + + @@ -106,4 +117,4 @@ 复习 我的 - \ No newline at end of file + diff --git a/me/me.wxss b/me/me.wxss index ed2acd7..ae884d9 100644 --- a/me/me.wxss +++ b/me/me.wxss @@ -79,6 +79,62 @@ page { min-width: 200rpx } +.auth-switch { + display: flex; + gap: 20rpx; + margin: 32rpx 0 24rpx +} + +.auth-chip { + min-width: 160rpx; + padding: 18rpx 0; + border-radius: 9999rpx; + background: rgba(255, 255, 255, .05); + border: 1rpx solid rgba(255, 255, 255, .08); + font-size: 24rpx; + font-weight: 700; + color: #aaabb0 +} + +.auth-chip.active { + color: #0c0e12; + background: linear-gradient(135deg, #00e3fd, #c19cff) +} + +.auth-card { + width: 100%; + padding: 28rpx; + border-radius: 28rpx; + border: 1rpx solid rgba(255, 255, 255, .08); + background: rgba(23, 26, 31, .72); + box-sizing: border-box +} + +.auth-input { + width: 100%; + height: 84rpx; + margin-bottom: 18rpx; + padding: 0 24rpx; + border-radius: 18rpx; + border: 1rpx solid rgba(255, 255, 255, .08); + background: #111318; + color: #f6f6fc; + font-size: 26rpx; + box-sizing: border-box +} + +.auth-submit { + margin-top: 12rpx; + border: none; + border-radius: 20rpx; + height: 84rpx; + line-height: 84rpx; + background: linear-gradient(135deg, #c19cff, #9146ff); + color: #fff; + font-size: 28rpx; + font-weight: 700 +} + .hero-section { display: flex; align-items: center; @@ -381,6 +437,16 @@ page { box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, .1) } +.logout-btn { + margin-top: 28rpx; + border: 1rpx solid rgba(255, 110, 132, .35); + border-radius: 24rpx; + background: rgba(255, 110, 132, .08); + color: #ff6e84; + font-size: 26rpx; + font-weight: 700 +} + .settings-icon { width: 96rpx; height: 96rpx; @@ -542,4 +608,4 @@ page { .nav-label { font-size: 20rpx -} \ No newline at end of file +} diff --git a/progress-list/progress-list.js b/progress-list/progress-list.js index 2158244..688fafe 100644 --- a/progress-list/progress-list.js +++ b/progress-list/progress-list.js @@ -31,7 +31,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/progress/review`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const reviewList = res.data?.data || [] const grouped = groupByType(reviewList) @@ -41,7 +41,7 @@ Page({ }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/progress/mastered`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const masteredList = res.data?.data || [] const grouped = groupByType(masteredList) diff --git a/progress/achievements/achievements.js b/progress/achievements/achievements.js index 02174a0..d30e5de 100644 --- a/progress/achievements/achievements.js +++ b/progress/achievements/achievements.js @@ -142,7 +142,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/achievements`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const list = this.decorateList(res.data?.data || []) const sections = this.buildSections(list) @@ -161,7 +161,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/achievements/refresh`, method: 'POST', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const payload = res.data?.data || {} const list = this.decorateList(payload.achievements || []) diff --git a/progress/checkin-detail/checkin-detail.js b/progress/checkin-detail/checkin-detail.js index 64fefe5..ebf6e22 100644 --- a/progress/checkin-detail/checkin-detail.js +++ b/progress/checkin-detail/checkin-detail.js @@ -13,7 +13,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/checkin/stats`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => this.setData({ stats: res.data?.data || null }), fail: () => this.setData({ error: '打卡数据加载失败' }), complete: () => this.setData({ loading: false }), diff --git a/progress/progress-list/progress-list.js b/progress/progress-list/progress-list.js index 2158244..688fafe 100644 --- a/progress/progress-list/progress-list.js +++ b/progress/progress-list/progress-list.js @@ -31,7 +31,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/progress/review`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const reviewList = res.data?.data || [] const grouped = groupByType(reviewList) @@ -41,7 +41,7 @@ Page({ }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/progress/mastered`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const masteredList = res.data?.data || [] const grouped = groupByType(masteredList) diff --git a/review-config/review-config.js b/review-config/review-config.js index be521bf..d4f3454 100644 --- a/review-config/review-config.js +++ b/review-config/review-config.js @@ -69,15 +69,15 @@ Page({ const question_mode = questionModeMap[this.data.activeMode] const scope_config = {} this.setData({ loading: true, error: '' }) - app.ensureLogin().then((openid) => { - if (!openid) { + app.ensureLogin().then((authToken) => { + if (!authToken) { this.setData({ loading: false, error: '请先登录后再开始复习' }) return } wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/generate`, method: 'POST', - header: { 'Content-Type': 'application/json', 'X-OpenID': openid }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': authToken }, data: { scope_type, scope_config, diff --git a/review-result/review-result.js b/review-result/review-result.js index d72a6a6..1d55ba0 100644 --- a/review-result/review-result.js +++ b/review-result/review-result.js @@ -30,7 +30,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/review-result?session_id=${sessionId}`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const data = res.data?.data || {} const total = Number(data.total || 0) diff --git a/review-session/review-session.js b/review-session/review-session.js index d250558..e5aed33 100644 --- a/review-session/review-session.js +++ b/review-session/review-session.js @@ -46,13 +46,13 @@ Page({ this.loadSettingsAndQuestions() }, loadSettingsAndQuestions() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '请先登录' }) return } wx.request({ url: `${app.globalData.baseUrl}/api/v1/settings`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { app.globalData.userSettings = res.data?.data || {} this.setData({ settings: getReviewSettings() }) @@ -128,7 +128,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/questions?session_id=${session.id}`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { if (res.statusCode < 200 || res.statusCode >= 300) { const message = res.data?.detail || res.data?.message || '题目加载失败' @@ -339,7 +339,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/submit`, method: 'POST', - header: { 'Content-Type': 'application/json', 'X-OpenID': app.globalData.openid || '' }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': app.globalData.authToken || '' }, data: payload, success: (res) => { const result = res.data?.data || {} @@ -422,7 +422,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/finish?session_id=${app.globalData.reviewSessionMeta.id}`, method: 'POST', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: () => wx.navigateTo({ url: '/pages/review-result/review-result' }), fail: () => { wx.showToast({ title: '提交结果失败,已本地完成', icon: 'none' }) diff --git a/review/review-config/review-config.js b/review/review-config/review-config.js index cd1a5e0..3c84c06 100644 --- a/review/review-config/review-config.js +++ b/review/review-config/review-config.js @@ -69,15 +69,15 @@ Page({ const question_mode = questionModeMap[this.data.activeMode] const scope_config = {} this.setData({ loading: true, error: '' }) - app.ensureLogin().then((openid) => { - if (!openid) { + app.ensureLogin().then((authToken) => { + if (!authToken) { this.setData({ loading: false, error: '??????????' }) return } wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/generate`, method: 'POST', - header: { 'Content-Type': 'application/json', 'X-OpenID': openid }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': authToken }, data: { scope_type, scope_config, diff --git a/review/review-result/review-result.js b/review/review-result/review-result.js index 205f3b4..30abd3b 100644 --- a/review/review-result/review-result.js +++ b/review/review-result/review-result.js @@ -30,7 +30,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/review-result?session_id=${sessionId}`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { const data = res.data?.data || {} const total = Number(data.total || 0) diff --git a/review/review-session/review-session.js b/review/review-session/review-session.js index 8dfef90..9710229 100644 --- a/review/review-session/review-session.js +++ b/review/review-session/review-session.js @@ -46,13 +46,13 @@ Page({ this.loadSettingsAndQuestions() }, loadSettingsAndQuestions() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '????' }) return } wx.request({ url: `${app.globalData.baseUrl}/api/v1/settings`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { app.globalData.userSettings = res.data?.data || {} this.setData({ settings: getReviewSettings() }) @@ -128,7 +128,7 @@ Page({ this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/questions?session_id=${session.id}`, - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: (res) => { if (res.statusCode < 200 || res.statusCode >= 300) { const message = res.data?.detail || res.data?.message || '??????' @@ -339,7 +339,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/submit`, method: 'POST', - header: { 'Content-Type': 'application/json', 'X-OpenID': app.globalData.openid || '' }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': app.globalData.authToken || '' }, data: payload, success: (res) => { const result = res.data?.data || {} @@ -422,7 +422,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/review/finish?session_id=${app.globalData.reviewSessionMeta.id}`, method: 'POST', - header: { 'X-OpenID': app.globalData.openid || '' }, + header: { 'X-Auth-Token': app.globalData.authToken || '' }, success: () => wx.navigateTo({ url: '/pages/review/review-result/review-result' }), fail: () => { wx.showToast({ title: '????????????', icon: 'none' }) diff --git a/settings/settings.js b/settings/settings.js index 8bd73ba..bd7de0d 100644 --- a/settings/settings.js +++ b/settings/settings.js @@ -38,14 +38,14 @@ Page({ }) }, loadSettings() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { this.setData({ error: '请先登录' }) return } this.setData({ loading: true, error: '' }) wx.request({ url: `${app.globalData.baseUrl}/api/v1/settings`, - header: { 'X-OpenID': app.globalData.openid }, + header: { 'X-Auth-Token': app.globalData.authToken }, success: (res) => { this.syncDerivedState(res.data?.data || null) }, @@ -93,7 +93,7 @@ Page({ this.setData({ settings }) }, save() { - if (!app.globalData.openid) { + if (!app.globalData.authToken) { wx.showToast({ title: '请先登录', icon: 'none' }) return } @@ -101,7 +101,7 @@ Page({ wx.request({ url: `${app.globalData.baseUrl}/api/v1/settings`, method: 'PUT', - header: { 'Content-Type': 'application/json', 'X-OpenID': app.globalData.openid }, + header: { 'Content-Type': 'application/json', 'X-Auth-Token': app.globalData.authToken }, data: settings, success: () => wx.showToast({ title: '已保存', icon: 'success' }), fail: () => wx.showToast({ title: '保存失败', icon: 'none' }),