更新登录功能,切换为注册账号登录

This commit is contained in:
taiyi 2026-05-13 14:40:57 +08:00
parent 6ec1860410
commit 6ec4b114da
24 changed files with 315 additions and 191 deletions

View File

@ -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 || [])

View File

@ -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)

View File

@ -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 }),

View File

@ -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()

View File

@ -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,

View File

@ -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 })

View File

@ -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)

View File

@ -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()

View File

@ -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,

20
me/file_content_needed.py Normal file
View File

@ -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")

293
me/me.js
View File

@ -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
}

View File

@ -6,10 +6,19 @@
<text class="empty-subtitle">正在获取个人信息</text>
</view>
<view wx:elif="{{!openid}}" class="empty-state">
<text class="empty-title">还未登录</text>
<text class="empty-subtitle">请点击下方按钮手动登录后继续使用</text>
<button class="secondary-btn error-btn" bindtap="manualLogin">手动登录</button>
<view wx:elif="{{!username}}" class="empty-state">
<text class="empty-title">账号登录</text>
<text class="empty-subtitle">使用账号密码登录,或先注册一个新账号</text>
<view class="auth-switch">
<view class="auth-chip {{authMode === 'login' ? 'active' : ''}}" data-mode="login" bindtap="onAuthModeChange">登录</view>
<view class="auth-chip {{authMode === 'register' ? 'active' : ''}}" data-mode="register" bindtap="onAuthModeChange">注册</view>
</view>
<view class="auth-card">
<input class="auth-input" placeholder="请输入账号" value="{{authForm.username}}" data-field="username" bindinput="onAuthInput" />
<input class="auth-input" password="true" placeholder="请输入密码" value="{{authForm.password}}" data-field="password" bindinput="onAuthInput" />
<input wx:if="{{authMode === 'register'}}" class="auth-input" placeholder="请输入昵称" value="{{authForm.nickname}}" data-field="nickname" bindinput="onAuthInput" />
<button class="auth-submit" bindtap="submitAuth">{{authMode === 'register' ? '注册并登录' : '登录'}}</button>
</view>
</view>
<view wx:elif="{{error}}" class="error-banner">
@ -35,12 +44,12 @@
</view>
</view>
<view wx:if="{{openid && badges === 0}}" class="empty-state small">
<view wx:if="{{username && badges === 0}}" class="empty-state small">
<text class="empty-title">还没有解锁成就</text>
<text class="empty-subtitle">继续复习和打卡,成就会逐渐点亮</text>
</view>
<view wx:if="{{openid}}" class="grid-2">
<view wx:if="{{username}}" class="grid-2">
<view class="glass-card accent-tertiary" bindtap="goTo" data-url="/package-stats/pages/achievements/achievements">
<view class="card-glow"></view>
<view class="card-icon icon-tertiary">🏅</view>
@ -85,6 +94,8 @@
<text class="settings-text">设置中心</text>
<view class="chevron"></view>
</view>
<button wx:if="{{username}}" class="logout-btn" bindtap="logout">退出登录</button>
</scroll-view>
<view wx:if="{{showNicknameModal}}" class="modal-mask" bindtap="closeNicknameModal">
@ -106,4 +117,4 @@
<view class="nav-item" bindtap="goToReview"><text class="nav-icon">↻</text><text class="nav-label">复习</text></view>
<view class="nav-item active"><text class="nav-icon">☺</text><text class="nav-label">我的</text></view>
</view>
</view>
</view>

View File

@ -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
}
}

View File

@ -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)

View File

@ -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 || [])

View File

@ -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 }),

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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' })

View File

@ -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,

View File

@ -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)

View File

@ -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' })

View File

@ -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' }),