修复我的页面头像登录功能

This commit is contained in:
taiyi 2026-04-23 13:27:23 +08:00
parent 4204761837
commit b981e17599
8 changed files with 400 additions and 4 deletions

View File

@ -7,10 +7,28 @@ Page({
loading: false, loading: false,
error: '', error: '',
}, },
downloadTemplate() {
wx.downloadFile({
url: `${app.globalData.baseUrl}/api/v1/entries/template`,
success: (res) => {
if (res.statusCode !== 200) {
this.setData({ error: '模板下载失败' })
return
}
wx.openDocument({
filePath: res.tempFilePath,
fileType: 'xlsx',
fail: () => this.setData({ error: '模板打开失败,请先保存到本地再上传' }),
})
},
fail: () => this.setData({ error: '模板下载失败' }),
})
},
chooseFile() { chooseFile() {
wx.chooseMessageFile({ wx.chooseMessageFile({
count: 1, count: 1,
type: 'file', type: 'file',
extension: ['xlsx'],
success: (res) => { success: (res) => {
const file = res.tempFiles[0] const file = res.tempFiles[0]
this.setData({ fileName: file.name, loading: true, error: '' }) this.setData({ fileName: file.name, loading: true, error: '' })

View File

@ -8,10 +8,14 @@
<view class="content"> <view class="content">
<view class="header"> <view class="header">
<text class="title">批量上传</text> <text class="title">批量上传</text>
<text class="subtitle">上传 Excel 文件导入单词或句子。</text> <text class="subtitle">先下载模板,按模板填写后直接上传单词或句子。</text>
</view>
<view class="action-row">
<button class="action-btn ghost-btn" bindtap="downloadTemplate">下载模板</button>
<button class="action-btn primary-btn" bindtap="chooseFile">选择文件上传</button>
</view> </view>
<button class="primary-btn" bindtap="chooseFile">选择文件</button>
<view wx:if="{{fileName}}" class="info">已选择:{{fileName}}</view> <view wx:if="{{fileName}}" class="info">已选择:{{fileName}}</view>
<view wx:if="{{error}}" class="error">{{error}}</view>
<view wx:if="{{result}}" class="result-card"> <view wx:if="{{result}}" class="result-card">
<text>总数:{{result.total}}</text> <text>总数:{{result.total}}</text>
<text>成功:{{result.success}}</text> <text>成功:{{result.success}}</text>

View File

@ -1 +1 @@
page{background:#0c0e12;color:#f6f6fc}.page{min-height:100vh;background:#0c0e12;box-sizing:border-box}.topbar{display:flex;justify-content:space-between;align-items:center;padding:24rpx 32rpx;background:rgba(12,14,18,.8);backdrop-filter:blur(24px);border-bottom:1rpx solid rgba(255,255,255,.08);box-shadow:0 1rpx 20rpx rgba(0,0,0,.08)}.brand{display:flex;align-items:center;gap:18rpx}.avatar-wrap{width:64rpx;height:64rpx;border-radius:9999rpx;overflow:hidden;border:1rpx solid rgba(255,255,255,.1);flex-shrink:0}.avatar{width:100%;height:100%}.brand-text{font-size:38rpx;font-weight:800;color:#c19cff}.icon-btn{width:72rpx;height:72rpx;border-radius:9999rpx;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center}.content{height:calc(100vh - 120rpx);padding:40rpx 32rpx 32rpx;box-sizing:border-box}.header{margin-bottom:28rpx}.title{display:block;font-size:52rpx;font-weight:800}.subtitle{display:block;margin-top:10rpx;color:#aaabb0;font-size:24rpx}.layout{display:grid;grid-template-columns:1fr;gap:24rpx}.instruction-card,.upload-card,.feedback-card,.step-card,.dropzone{background:rgba(29,32,37,.56);border:1rpx solid rgba(255,255,255,.08);border-radius:28rpx;box-sizing:border-box}.instruction-card{padding:24rpx}.section-title{display:block;font-size:28rpx;font-weight:700;margin-bottom:18rpx}.steps{display:flex;flex-direction:column;gap:18rpx}.step{display:flex;align-items:stretch;gap:16rpx}.step-dot{width:44rpx;height:44rpx;border-radius:9999rpx;background:#23262c;color:#aaabb0;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:20rpx;font-weight:700;margin-top:10rpx}.active-dot{background:#c19cff;color:#000}.step-card{flex:1;padding:18rpx;background:#171a1f}.low{background:#111318}.step-title{display:block;font-size:24rpx;font-weight:700;margin-bottom:6rpx}.step-desc{display:block;font-size:20rpx;color:#aaabb0}.download{display:block;margin-top:12rpx;font-size:20rpx;color:#00e5ff}.upload-card{display:flex;flex-direction:column;gap:18rpx}.dropzone{padding:40rpx 28rpx;min-height:360rpx;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;background:rgba(29,32,37,.4)}.upload-icon{width:112rpx;height:112rpx;border-radius:9999rpx;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center;font-size:48rpx;color:#c19cff;margin-bottom:18rpx}.drop-title{display:block;font-size:34rpx;font-weight:800;margin-bottom:10rpx}.drop-desc{display:block;font-size:22rpx;color:#aaabb0;line-height:1.6;margin-bottom:24rpx}.choose-btn{border-radius:9999rpx;padding:20rpx 30rpx;background:linear-gradient(90deg,#c19cff,#9146ff);color:#fff;font-weight:700}.feedback-card{padding:24rpx;display:flex;flex-direction:column;gap:16rpx}.feedback-left{display:flex;align-items:center;gap:16rpx}.status-icon{width:56rpx;height:56rpx;border-radius:9999rpx;background:#111318;display:flex;align-items:center;justify-content:center;color:#00e5ff}.feedback-title{display:block;font-size:24rpx;font-weight:700}.feedback-file{display:block;font-size:20rpx;color:#aaabb0}.feedback-stats{display:flex;align-items:center;gap:24rpx;justify-content:flex-end}.stat{text-align:center}.stat-num{display:block;font-size:34rpx;font-weight:800}.good{color:#00e5ff}.bad{color:#aaabb0}.stat-label{display:block;font-size:18rpx;color:#aaabb0}.divider{width:1rpx;height:34rpx;background:rgba(255,255,255,.08)} page{background:#0c0e12;color:#f6f6fc}.page{min-height:100vh;background:#0c0e12;box-sizing:border-box}.topbar{display:flex;justify-content:space-between;align-items:center;padding:24rpx 32rpx;background:rgba(12,14,18,.8);backdrop-filter:blur(24px);border-bottom:1rpx solid rgba(255,255,255,.08);box-shadow:0 1rpx 20rpx rgba(0,0,0,.08)}.brand{display:flex;align-items:center;gap:18rpx}.avatar-wrap{width:64rpx;height:64rpx;border-radius:9999rpx;overflow:hidden;border:1rpx solid rgba(255,255,255,.1);flex-shrink:0}.avatar{width:100%;height:100%}.brand-text{font-size:38rpx;font-weight:800;color:#c19cff}.icon-btn{width:72rpx;height:72rpx;border-radius:9999rpx;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center}.content{height:calc(100vh - 120rpx);padding:40rpx 32rpx 32rpx;box-sizing:border-box}.header{margin-bottom:28rpx}.title{display:block;font-size:52rpx;font-weight:800}.subtitle{display:block;margin-top:10rpx;color:#aaabb0;font-size:24rpx}.layout{display:grid;grid-template-columns:1fr;gap:24rpx}.instruction-card,.upload-card,.feedback-card,.step-card,.dropzone{background:rgba(29,32,37,.56);border:1rpx solid rgba(255,255,255,.08);border-radius:28rpx;box-sizing:border-box}.instruction-card{padding:24rpx}.section-title{display:block;font-size:28rpx;font-weight:700;margin-bottom:18rpx}.steps{display:flex;flex-direction:column;gap:18rpx}.step{display:flex;align-items:stretch;gap:16rpx}.step-dot{width:44rpx;height:44rpx;border-radius:9999rpx;background:#23262c;color:#aaabb0;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:20rpx;font-weight:700;margin-top:10rpx}.active-dot{background:#c19cff;color:#000}.step-card{flex:1;padding:18rpx;background:#171a1f}.low{background:#111318}.step-title{display:block;font-size:24rpx;font-weight:700;margin-bottom:6rpx}.step-desc{display:block;font-size:20rpx;color:#aaabb0}.download{display:block;margin-top:12rpx;font-size:20rpx;color:#00e5ff}.upload-card{display:flex;flex-direction:column;gap:18rpx}.dropzone{padding:40rpx 28rpx;min-height:360rpx;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;background:rgba(29,32,37,.4)}.upload-icon{width:112rpx;height:112rpx;border-radius:9999rpx;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center;font-size:48rpx;color:#c19cff;margin-bottom:18rpx}.drop-title{display:block;font-size:34rpx;font-weight:800;margin-bottom:10rpx}.drop-desc{display:block;font-size:22rpx;color:#aaabb0;line-height:1.6;margin-bottom:24rpx}.action-row{display:flex;gap:20rpx}.action-btn{flex:1;border-radius:9999rpx;padding:22rpx 24rpx;font-size:28rpx;font-weight:700;line-height:1;text-align:center;box-sizing:border-box;border:1rpx solid transparent}.primary-btn{background:linear-gradient(90deg,#c19cff,#9146ff);color:#fff;box-shadow:0 16rpx 32rpx rgba(145,70,255,.22)}.ghost-btn{background:rgba(255,255,255,.04);color:#f6f6fc;border-color:rgba(255,255,255,.1)}.action-btn::after{border:none}.primary-btn:active{opacity:.92;transform:translateY(1rpx)}.ghost-btn:active{background:rgba(255,255,255,.08)}.info{margin-top:18rpx;padding:16rpx 20rpx;border-radius:20rpx;background:rgba(255,255,255,.04);color:#d7d7de;font-size:22rpx}.feedback-card{padding:24rpx;display:flex;flex-direction:column;gap:16rpx}.feedback-left{display:flex;align-items:center;gap:16rpx}.status-icon{width:56rpx;height:56rpx;border-radius:9999rpx;background:#111318;display:flex;align-items:center;justify-content:center;color:#00e5ff}.feedback-title{display:block;font-size:24rpx;font-weight:700}.feedback-file{display:block;font-size:20rpx;color:#aaabb0}.feedback-stats{display:flex;align-items:center;gap:24rpx;justify-content:flex-end}.stat{text-align:center}.stat-num{display:block;font-size:34rpx;font-weight:800}.good{color:#00e5ff}.bad{color:#aaabb0}.stat-label{display:block;font-size:18rpx;color:#aaabb0}.divider{width:1rpx;height:34rpx;background:rgba(255,255,255,.08)}

View File

@ -0,0 +1,70 @@
const app = getApp()
Page({
data: {
entry: null,
loading: false,
error: '',
},
onLoad(options) {
this.entryId = options.id
this.loadEntry()
},
loadEntry() {
if (!app.globalData.openid) {
this.setData({ error: '请先登录' })
return
}
if (!this.entryId) {
this.setData({ error: '缺少词条ID' })
return
}
this.setData({ loading: true, error: '' })
wx.request({
url: `${app.globalData.baseUrl}/api/v1/entries/${this.entryId}`,
header: { 'X-OpenID': app.globalData.openid },
success: (res) => {
const entry = res.data?.data || null
this.setData({ entry, error: entry ? '' : '未找到词条' })
},
fail: () => this.setData({ error: '词条加载失败' }),
complete: () => this.setData({ loading: false }),
})
},
editEntry() {
if (!this.data.entry?.id) return
wx.navigateTo({ url: `/pages/entry-edit/entry-edit?id=${this.data.entry.id}` })
},
deleteEntry() {
if (!this.data.entry?.id) return
wx.showModal({
title: '确认删除',
content: '删除后无法恢复,是否继续?',
success: (res) => {
if (!res.confirm) return
wx.request({
url: `${app.globalData.baseUrl}/api/v1/entries/${this.data.entry.id}`,
method: 'DELETE',
header: { 'X-OpenID': app.globalData.openid },
success: () => {
wx.showToast({ title: '已删除', icon: 'success' })
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage && typeof prevPage.loadList === 'function') {
prevPage.loadList()
}
wx.navigateBack({ delta: 1 })
},
})
},
})
},
goBack() {
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage && typeof prevPage.loadList === 'function') {
prevPage.loadList()
}
wx.navigateBack()
},
})

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -0,0 +1,60 @@
<view class="page">
<view class="bg-orb orb1"></view>
<view class="bg-orb orb2"></view>
<scroll-view scroll-y class="content">
<view class="hero-card {{entry && entry.entry_type === 'sentence' ? 'pink' : 'cyan'}}" wx:if="{{entry}}">
<view class="hero-top">
<view class="hero-title-group">
<view class="type-chip">{{entry.entry_type === 'sentence' ? '句子' : '单词'}}</view>
<view class="hero-actions-vertical">
<view class="mini-action" bindtap="editEntry" catchtap="editEntry">✎</view>
<view class="mini-action danger" bindtap="deleteEntry" catchtap="deleteEntry">🗑</view>
</view>
</view>
</view>
<text class="main-text">{{entry.en_text}}</text>
<text class="translate">{{entry.entry_type === 'sentence' ? '翻译:' : '释义:'}}{{entry.zh_text}}</text>
<view class="detail-badges">
<view class="badge-pill">来源:{{entry.source_type}}</view>
<view class="badge-pill">状态:{{entry.status}}</view>
</view>
</view>
<view class="header">
<text class="title">词条详情</text>
<text class="subtitle">查看单词或句子的完整信息</text>
</view>
<view wx:if="{{loading}}" class="empty-state">
<text class="empty-title">加载中...</text>
</view>
<view wx:elif="{{error}}" class="error-banner">
<text class="error-text">{{error}}</text>
</view>
<view wx:elif="{{entry}}" class="info-card">
<view class="info-row">
<text class="info-label">类型</text>
<text class="info-value">{{entry.entry_type === 'sentence' ? '句子' : '单词'}}</text>
</view>
<view class="info-row">
<text class="info-label">内容</text>
<text class="info-value">{{entry.en_text}}</text>
</view>
<view class="info-row">
<text class="info-label">{{entry.entry_type === 'sentence' ? '翻译' : '释义'}}</text>
<text class="info-value">{{entry.zh_text}}</text>
</view>
<view class="info-row" wx:if="{{entry.example_text}}">
<text class="info-label">{{entry.entry_type === 'word' ? '例句' : '补充说明'}}</text>
<text class="info-value">{{entry.example_text}}</text>
</view>
<view class="info-row">
<text class="info-label">来源</text>
<text class="info-value">{{entry.source_type}}</text>
</view>
</view>
</scroll-view>
</view>

View File

@ -0,0 +1,241 @@
page {
background: #0c0e12;
color: #f6f6fc;
}
.page {
min-height: 100vh;
background: #0c0e12;
position: relative;
overflow: hidden;
box-sizing: border-box;
}
.bg-orb {
position: absolute;
border-radius: 9999rpx;
filter: blur(110rpx);
pointer-events: none;
z-index: 0;
}
.orb1 {
width: 46vw;
height: 46vw;
top: -14vw;
right: -14vw;
background: rgba(193, 156, 255, 0.12);
}
.orb2 {
width: 54vw;
height: 54vw;
left: -18vw;
bottom: -16vw;
background: rgba(0, 227, 253, 0.08);
}
.content {
position: relative;
z-index: 1;
height: 100vh;
padding: 26rpx 32rpx 40rpx;
box-sizing: border-box;
}
.hero-card {
position: relative;
overflow: hidden;
border-radius: 34rpx;
padding: 34rpx;
border: 1rpx solid rgba(255, 255, 255, 0.08);
background: rgba(29, 32, 37, 0.72);
box-shadow: 0 18rpx 60rpx rgba(0, 0, 0, 0.18);
margin-bottom: 28rpx;
}
.hero-card::after {
content: '';
position: absolute;
inset: auto -40rpx -40rpx auto;
width: 180rpx;
height: 180rpx;
border-radius: 9999rpx;
filter: blur(24rpx);
opacity: 0.4;
}
.hero-card.cyan::after {
background: rgba(0, 227, 253, 0.45);
}
.hero-card.pink::after {
background: rgba(255, 108, 149, 0.45);
}
.hero-top {
position: relative;
z-index: 1;
display: flex;
justify-content: flex-end;
margin-bottom: 24rpx;
}
.hero-title-group {
display: flex;
align-items: flex-start;
gap: 16rpx;
}
.type-chip {
display: inline-flex;
align-items: center;
justify-content: center;
height: 60rpx;
padding: 0 22rpx;
border-radius: 9999rpx;
font-size: 22rpx;
font-weight: 700;
color: #00e3fd;
border: 1rpx solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.04);
}
.hero-actions-vertical {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.mini-action {
width: 52rpx;
height: 52rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
background: rgba(255, 255, 255, 0.06);
border: 1rpx solid rgba(255, 255, 255, 0.08);
color: #f6f6fc;
}
.mini-action.danger {
color: #ff7b9b;
}
.main-text {
position: relative;
z-index: 1;
display: block;
font-size: 46rpx;
line-height: 1.25;
font-weight: 800;
letter-spacing: -0.5rpx;
}
.translate {
position: relative;
z-index: 1;
display: block;
margin-top: 16rpx;
color: #f6f6fc;
font-size: 28rpx;
line-height: 1.7;
}
.detail-badges {
position: relative;
z-index: 1;
display: flex;
flex-wrap: wrap;
gap: 12rpx;
margin-top: 20rpx;
}
.badge-pill {
padding: 12rpx 18rpx;
border-radius: 9999rpx;
font-size: 22rpx;
color: #aaabb0;
border: 1rpx solid rgba(255, 255, 255, 0.06);
background: rgba(255, 255, 255, 0.03);
}
.header {
margin-bottom: 24rpx;
}
.title {
display: block;
font-size: 52rpx;
line-height: 1.1;
font-weight: 800;
}
.subtitle {
display: block;
margin-top: 10rpx;
color: #aaabb0;
font-size: 24rpx;
}
.info-card {
padding: 28rpx;
border-radius: 30rpx;
background: rgba(255, 255, 255, 0.04);
border: 1rpx solid rgba(255, 255, 255, 0.08);
margin-bottom: 26rpx;
}
.info-row {
display: flex;
gap: 18rpx;
padding: 18rpx 0;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.06);
}
.info-row:last-child {
border-bottom: 0;
padding-bottom: 0;
}
.info-label {
width: 120rpx;
flex-shrink: 0;
font-size: 24rpx;
color: #aaabb0;
font-weight: 700;
}
.info-value {
flex: 1;
font-size: 26rpx;
color: #f6f6fc;
line-height: 1.6;
}
.empty-state {
padding: 60rpx 20rpx;
text-align: center;
color: #aaabb0;
}
.empty-title {
display: block;
font-size: 28rpx;
font-weight: 700;
color: #f6f6fc;
}
.error-banner {
padding: 24rpx 28rpx;
border-radius: 20rpx;
background: rgba(167, 1, 56, 0.2);
border: 1rpx solid rgba(255, 110, 132, 0.35);
}
.error-text {
color: #ffb2b9;
font-size: 24rpx;
}

View File

@ -1,7 +1,7 @@
<view class="page"> <view class="page">
<scroll-view scroll-y class="content"> <scroll-view scroll-y class="content">
<view class="greeting"> <view class="greeting">
<text class="title">学习驾驶舱</text> <text class="title">你好,同学!</text>
<text class="subtitle">专注高频复习,持续积累词库</text> <text class="subtitle">专注高频复习,持续积累词库</text>
</view> </view>