add word search
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.history
|
||||
.DS_Store
|
||||
miniprogram/static/.DS_Store
|
||||
miniprogram/miniprogram_npm
|
||||
node_modules
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"onReachBottomDistance": 50,
|
||||
"usingComponents": {
|
||||
"t-slider": "tdesign-miniprogram/slider/slider",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon"
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-tag": "tdesign-miniprogram/tag/tag",
|
||||
"t-cell": "tdesign-miniprogram/cell/cell",
|
||||
"t-tabs": "tdesign-miniprogram/tabs/tabs",
|
||||
"t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel"
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,49 @@ interface IPageData {
|
||||
audioDuration: number // 音频总时长
|
||||
currentTime: number // 当前播放时间
|
||||
sliderValue: number // 进度条值(0-100)
|
||||
showDictPopup: boolean // 控制弹窗是否显示
|
||||
showDictExtended: boolean // 控制扩展内容是否显示
|
||||
wordDict: {
|
||||
ee: any
|
||||
ec: any
|
||||
expandEc: any
|
||||
etym: any
|
||||
syno: {
|
||||
word: string
|
||||
synos: Array<{
|
||||
syno: {
|
||||
ws: Array<{ w: string }>
|
||||
pos: string
|
||||
tran: string
|
||||
}
|
||||
}>
|
||||
}
|
||||
simple: any
|
||||
phrs: any
|
||||
individual: any
|
||||
collins: any
|
||||
relWord: {
|
||||
rels: Array<{
|
||||
rel: {
|
||||
pos: string
|
||||
words: Array<{
|
||||
tran: string
|
||||
word: string
|
||||
}>
|
||||
}
|
||||
}>
|
||||
}
|
||||
discriminate: {
|
||||
data: Array<{
|
||||
source: string
|
||||
usages: Array<{
|
||||
usage: string
|
||||
headword: string
|
||||
}>
|
||||
}>
|
||||
}
|
||||
}
|
||||
prototypeWord: string
|
||||
}
|
||||
|
||||
type IPageMethods = {
|
||||
@@ -59,6 +102,12 @@ type IPageMethods = {
|
||||
playStandardVoice: () => void
|
||||
resetAudioState: () => void
|
||||
handleSliderChange: (e: any) => void
|
||||
handleWordClick: (e: any) => void
|
||||
handleDictMore: () => void
|
||||
handleDictClose: () => void
|
||||
playWordAudio: (e: any) => void
|
||||
onTabsChange: (event: any) => void
|
||||
onTabsClick: (event: any) => void
|
||||
}
|
||||
|
||||
interface IPageInstance extends IPageMethods {
|
||||
@@ -87,6 +136,20 @@ Page<IPageData, IPageInstance>({
|
||||
ipas: [], // 音标的单词数组
|
||||
isScoreExpanded: false, // 评分区域是否展开
|
||||
wordScores: [], // 单词评分数组
|
||||
prototypeWord: '',
|
||||
wordDict: {
|
||||
ee: {},
|
||||
ec: {},
|
||||
expandEc: {},
|
||||
etym: {},
|
||||
syno: { word: '', synos: [] },
|
||||
simple: {},
|
||||
phrs: {},
|
||||
individual: {},
|
||||
collins: {},
|
||||
relWord: { rels: [] },
|
||||
discriminate: { data: [] }
|
||||
},
|
||||
matchTagLegend: [
|
||||
{ tag: 0, description: '匹配', color: '#ffffff' },
|
||||
{ tag: 1, description: '新增', color: '#ffebee' },
|
||||
@@ -98,7 +161,9 @@ Page<IPageData, IPageInstance>({
|
||||
isPlaying: false, // 是否正在播放音频
|
||||
audioDuration: 0, // 音频总时长
|
||||
currentTime: 0, // 当前播放时间
|
||||
sliderValue: 0 // 进度条值(0-100)
|
||||
sliderValue: 0, // 进度条值(0-100)
|
||||
showDictPopup: true, // 控制弹窗是否显示
|
||||
showDictExtended: false // 控制扩展内容是否显示
|
||||
},
|
||||
|
||||
// 切换评分区域展开状态
|
||||
@@ -508,14 +573,88 @@ Page<IPageData, IPageInstance>({
|
||||
const { word } = e.currentTarget.dataset
|
||||
if (!word) return
|
||||
|
||||
try {
|
||||
const cleanedWord = word.replace(/[.,?!*]/g, '')
|
||||
if (!cleanedWord) return
|
||||
try {
|
||||
// 调用API获取单词详情
|
||||
const wordDetail: any = await apiManager.getWordDetail(word)
|
||||
const wordDetail: any = await apiManager.getWordDetail(cleanedWord)
|
||||
console.log('获取到单词详情:', wordDetail)
|
||||
// 这里可以添加处理单词详情的逻辑,比如显示在页面上
|
||||
this.setData({
|
||||
showDictPopup: true,
|
||||
wordDict: {
|
||||
ee:wordDetail['ee'], ec:wordDetail['ec'], expandEc:wordDetail['expand_ec'],
|
||||
simple:wordDetail['simple'], phrs:wordDetail['phrs'], etym:wordDetail['etym'],
|
||||
individual:wordDetail['individual'], collins:wordDetail['collins'],
|
||||
relWord: wordDetail['rel_word'], syno: wordDetail['syno'],
|
||||
discriminate: wordDetail['discriminate']
|
||||
},
|
||||
prototypeWord: wordDetail['ec'].word[0]?.prototype
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取单词详情失败:', error)
|
||||
wx.showToast({
|
||||
title: '获取单词详情失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 点击“more”按钮,展开/收起扩展内容
|
||||
handleDictMore() {
|
||||
this.setData({
|
||||
showDictExtended: !this.data.showDictExtended
|
||||
})
|
||||
},
|
||||
|
||||
// 点击“x”按钮,关闭弹窗
|
||||
handleDictClose() {
|
||||
this.setData({
|
||||
showDictPopup: false
|
||||
})
|
||||
},
|
||||
|
||||
onTabsChange(event: any) {
|
||||
console.log(`Change tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
onTabsClick(event: any) {
|
||||
console.log(`Click tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
// 播放单词音频
|
||||
playWordAudio(e: any) {
|
||||
const { audio } = e.currentTarget.dataset
|
||||
if (!audio) return
|
||||
|
||||
// 构造音频URL
|
||||
const audioUrl = `https://dict.youdao.com/dictvoice?audio=${audio}`
|
||||
|
||||
// 创建音频上下文
|
||||
const wordAudioContext = wx.createInnerAudioContext()
|
||||
|
||||
wordAudioContext.onPlay(() => {
|
||||
console.log('开始播放单词音频')
|
||||
})
|
||||
|
||||
wordAudioContext.onError((res) => {
|
||||
console.error('播放单词音频失败:', res)
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
wordAudioContext.onEnded(() => {
|
||||
console.log('单词音频播放结束')
|
||||
wordAudioContext.destroy()
|
||||
})
|
||||
|
||||
// 设置音频源并播放
|
||||
wordAudioContext.src = audioUrl
|
||||
wordAudioContext.play()
|
||||
},
|
||||
|
||||
onLoad(options: Record<string, string>) {
|
||||
//如果有图片ID,调用接口获取文本和评分信息
|
||||
if (options.index) {
|
||||
|
||||
@@ -142,6 +142,136 @@
|
||||
<text class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 单词查询展示区域 -->
|
||||
<view class="word-popup" wx:if="{{showDictPopup}}">
|
||||
<!-- 弹窗头部:单词 + more 按钮 -->
|
||||
<view class="popup-header">
|
||||
<!-- 频率标签 -->
|
||||
<view class="frequency-tags">
|
||||
<t-tag wx:if="{{wordDict.ec.exam_type && wordDict.ec.exam_type.length > 0}}" wx:for="{{wordDict.ec.exam_type}}" wx:key="index" variant="light" theme="success" style="margin-right: 12rpx;">
|
||||
{{item}}
|
||||
</t-tag>
|
||||
</view>
|
||||
<view class="close-btn" bindtap="handleDictClose">
|
||||
<t-icon name="close" size="48rpx" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-header">
|
||||
<text wx:if="{{wordDict.simple.query}}" class="word-title">{{wordDict.simple.query}}</text>
|
||||
<text class="word-title" wx:if="{{prototypeWord}}">
|
||||
{{prototypeWord}}
|
||||
</text>
|
||||
<view class="more-btn" bindtap="handleDictMore">
|
||||
<text wx:if="{{!showDictExtended}}">More</text>
|
||||
<text wx:else>Less</text>
|
||||
<t-icon wx:if="{{!showDictExtended}}" name="chevron-up" size="48rpx"></t-icon>
|
||||
<t-icon wx:else name="chevron-down" size="48rpx"></t-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发音区域 -->
|
||||
<view class="pronounce">
|
||||
<view class="pron-item" wx:if="{{wordDict.simple && wordDict.simple.word && wordDict.simple.word.length > 0}}">
|
||||
<text wx:if="{{wordDict.simple.word[0].ukphone}}">UK:[{{wordDict.simple.word[0].ukphone}}]</text>
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].ukspeech}}" bind:click="playWordAudio" data-audio="{{wordDict.simple.word[0].ukspeech}}" name="sound" size="40rpx" />
|
||||
</view>
|
||||
<view class="pron-item" wx:if="{{wordDict.simple && wordDict.simple.word && wordDict.simple.word.length > 0}}">
|
||||
<text wx:if="{{wordDict.simple.word[0].usphone}}">US:[{{wordDict.simple.word[0].usphone}}]</text>
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].usspeech}}" bind:click="playWordAudio" data-audio="{{wordDict.simple.word[0].usspeech}}" name="sound" size="40rpx" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基础词性释义 -->
|
||||
<view class="word-meanings">
|
||||
<block wx:if="{{wordDict.ec && wordDict.ec.word && wordDict.ec.word.length > 0}}">
|
||||
<block wx:for="{{wordDict.ec.word[0].trs}}" wx:key="index">
|
||||
<block wx:for="{{item.tr}}" wx:key="index">
|
||||
<block wx:for="{{item.l.i}}" wx:key="index">
|
||||
<text>{{item}}</text>
|
||||
</block>
|
||||
</block>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 扩展内容(默认隐藏,点击 more 后显示) -->
|
||||
<t-tabs
|
||||
animation="{{ { duration: 0.1 } }}"
|
||||
defaultValue="{{0}}"
|
||||
bind:change="onTabsChange"
|
||||
bind:click="onTabsClick"
|
||||
wx:if="{{showDictExtended}}"
|
||||
>
|
||||
<t-tab-panel label="词典" value="3" wx:if="{{wordDict.ee && wordDict.ee.word && wordDict.ee.word.trs && wordDict.ee.word.trs.length > 0}}">
|
||||
<view class="dictionary">
|
||||
<view class="dictionary-content" wx:for="{{wordDict.ee.word.trs}}" wx:key="index">
|
||||
<view class="dictionary-pos">{{item.pos}}</view>
|
||||
<view class="dictionary-list" wx:for="{{item.tr}}" wx:key="index">
|
||||
<view class="word-info">{{item.l.i}}</view>
|
||||
<view class="word-exam" wx:if="{{item.exam && item.exam.i && item.exam.i.f && item.exam.i.f.l}}">
|
||||
<view wx:for="{{item.exam.i.f.l}}" wx:key="index">{{item.i}}</view>
|
||||
</view>
|
||||
<view class="word-similar" wx:if="{{item['similar-words'] && item['similar-words'].length > 0}}">
|
||||
<view wx:for="{{item['similar-words']}}" wx:key="index">{{item.similar}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</t-tab-panel>
|
||||
|
||||
<t-tab-panel wx:if="{{wordDict.phrs && wordDict.phrs.phrs && wordDict.phrs.phrs.length > 0}}" label="短语" value="0">
|
||||
<block wx:for="{{wordDict.phrs.phrs}}" wx:key="index">
|
||||
<t-cell
|
||||
title="{{item.phr.headword.l.i}}"
|
||||
description="{{item.phr.trs[0].tr.l.i}}"
|
||||
/>
|
||||
</block>
|
||||
</t-tab-panel>
|
||||
<t-tab-panel wx:if="{{wordDict.individual && wordDict.individual.pastExamSents && wordDict.individual.pastExamSents.length > 0}}" label="真题" value="1">
|
||||
<view wx:for="{{wordDict.individual.pastExamSents}}" wx:key="index" class="exam-sent">
|
||||
<view class="exam-sent-en">{{item.en}}</view>
|
||||
<view class="exam-sent-zh">{{item.zh}}</view>
|
||||
<view class="exam-sent-source">--摘自《{{item.source}}》</view>
|
||||
</view>
|
||||
</t-tab-panel>
|
||||
<t-tab-panel label="相关单词" value="2">
|
||||
<view wx:if="{{(wordDict.syno && wordDict.syno.synos && wordDict.syno.synos.length > 0) || (wordDict.relWord && wordDict.relWord.rels && wordDict.relWord.rels.length > 0) || (wordDict.discriminate && wordDict.discriminate.data && wordDict.discriminate.data.length > 0)}}">
|
||||
<view class="syno" wx:if="{{wordDict.syno && wordDict.syno.synos && wordDict.syno.synos.length > 0}}">
|
||||
<view class="syno-title">同义词</view>
|
||||
<view class="syno-list" wx:for="{{wordDict.syno.synos}}" wx:key="index">
|
||||
<view class="syno-pos">{{item.syno.pos}}</view>
|
||||
<view class="syno-tran">{{item.syno.tran}}</view>
|
||||
<view class="syno-item" wx:for="{{item.syno.ws}}" wx:key="w">{{item.w}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rel-word" wx:if="{{wordDict.relWord && wordDict.relWord.rels && wordDict.relWord.rels.length > 0}}">
|
||||
<view class="rel-word-title">相关单词</view>
|
||||
<view class="rel-word-list" wx:for="{{wordDict.relWord.rels}}" wx:key="index">
|
||||
<view class="rel-word-pos">{{item.rel.pos}}</view>
|
||||
<view class="rel-word-item" wx:for="{{item.rel.words}}" wx:key="word">
|
||||
<view class="rel-word-tran">{{item.tran}}</view>
|
||||
<view class="rel-word-word">{{item.word}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="discriminate" wx:if="{{wordDict.discriminate && wordDict.discriminate.data && wordDict.discriminate.data.length > 0}}">
|
||||
<view class="discriminate-title">区分单词</view>
|
||||
<view class="discriminate-list" wx:for="{{wordDict.discriminate.data}}" wx:key="index">
|
||||
<view class="discriminate-item" wx:for="{{item.usages}}" wx:key="headword">
|
||||
<view class="discriminate-tran">{{item.usage}}</view>
|
||||
<view class="discriminate-headword">{{item.headword}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:else class="no-related-words">
|
||||
<text class="no-related-words-text">暂无相关单词信息</text>
|
||||
</view>
|
||||
</t-tab-panel>
|
||||
</t-tabs>
|
||||
|
||||
</view>
|
||||
<!-- 遮罩层 -->
|
||||
<view class="mask" wx:if="{{isScoreExpanded}}" catchtap="toggleScoreSection"></view>
|
||||
</view>
|
||||
@@ -523,4 +523,362 @@
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 弹窗整体样式 */
|
||||
.word-popup {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-top-left-radius: 12rpx;
|
||||
border-top-right-radius: 12rpx;
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 100;
|
||||
overflow-y: scroll;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
/* 弹窗头部 */
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 频率标签容器 */
|
||||
.frequency-tags {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
min-height: 48rpx; /* 确保即使没有标签也有最小高度 */
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
.close-btn {
|
||||
margin-left: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.more-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* 发音区域 */
|
||||
.pronounce {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pron-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.sound-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
/* 基础词性释义 */
|
||||
.word-meanings {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 扩展内容区域 */
|
||||
.extended-content {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 10rpx 20rpx;
|
||||
margin-right: 10rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #007AFF;
|
||||
border-bottom: 2rpx solid #007AFF;
|
||||
}
|
||||
|
||||
.syllabus-title, .example-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.syllabus-stats {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.progress-item {
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 10rpx;
|
||||
background: #eee;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background: #007AFF;
|
||||
}
|
||||
|
||||
.example-sentence {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 真题例句样式 */
|
||||
.exam-sents {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.exam-sent {
|
||||
margin-bottom: 30rpx;
|
||||
padding: 20rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.exam-sent-en {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.exam-sent-zh {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.exam-sent-source {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.no-exam-sents {
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
/* 同义词样式 */
|
||||
.syno {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.syno-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.syno-list {
|
||||
padding: 20rpx;
|
||||
background: #f9f9f9;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.syno-pos {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.syno-tran {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.syno-item {
|
||||
display: inline-block;
|
||||
padding: 10rpx 20rpx;
|
||||
background: #e3f2fd;
|
||||
border-radius: 30rpx;
|
||||
margin-right: 15rpx;
|
||||
margin-bottom: 15rpx;
|
||||
font-size: 26rpx;
|
||||
color: #001858;
|
||||
}
|
||||
|
||||
/* 相关单词样式 */
|
||||
.rel-word {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.rel-word-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.rel-word-list {
|
||||
padding: 20rpx;
|
||||
background: #f9f9f9;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.rel-word-pos {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.rel-word-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.rel-word-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.rel-word-tran {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.rel-word-word {
|
||||
font-size: 28rpx;
|
||||
color: #001858;
|
||||
font-weight: 500;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
/* 区分单词样式 */
|
||||
.discriminate {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.discriminate-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.discriminate-list {
|
||||
padding: 20rpx;
|
||||
background: #f9f9f9;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.discriminate-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 15rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.discriminate-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.discriminate-tran {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.discriminate-headword {
|
||||
font-size: 28rpx;
|
||||
color: #001858;
|
||||
font-weight: 500;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
/* 无相关单词信息样式 */
|
||||
.no-related-words {
|
||||
padding: 40rpx 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-related-words-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 词典样式 */
|
||||
.dictionary {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.dictionary-content {
|
||||
background: #f9f9f9;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.dictionary-pos {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 15rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dictionary-list {
|
||||
padding: 15rpx 0;
|
||||
}
|
||||
|
||||
.word-info {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 15rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.word-exam {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 15rpx;
|
||||
padding: 10rpx 15rpx;
|
||||
background: #e3f2fd;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.word-similar {
|
||||
font-size: 26rpx;
|
||||
color: #001858;
|
||||
padding: 8rpx 15rpx;
|
||||
background: #fff3e0;
|
||||
border-radius: 30rpx;
|
||||
display: inline-block;
|
||||
margin-right: 10rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
BIN
miniprogram/pages/assessment/image1.png
Normal file
BIN
miniprogram/pages/assessment/image1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 571 KiB |
BIN
miniprogram/pages/assessment/image2.png
Normal file
BIN
miniprogram/pages/assessment/image2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 333 KiB |
@@ -376,6 +376,7 @@ Page({
|
||||
|
||||
// 清除API管理器中的缓存
|
||||
apiManager.clearAudioCache()
|
||||
apiManager.clearWordDetailCache()
|
||||
|
||||
wx.showToast({
|
||||
title: '缓存已清除',
|
||||
|
||||
@@ -804,9 +804,35 @@ class ApiManager {
|
||||
// 获取单词详情
|
||||
async getWordDetail(word: string): Promise<YdWordDetail> {
|
||||
console.log('获取单词详情')
|
||||
|
||||
// 首先检查本地缓存
|
||||
const cacheKey = `word_detail_${word}`
|
||||
try {
|
||||
const cachedData = wx.getStorageSync(cacheKey)
|
||||
if (cachedData) {
|
||||
console.log('使用缓存的单词详情:', word)
|
||||
return cachedData
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('读取单词详情缓存失败:', e)
|
||||
}
|
||||
|
||||
// 缓存中没有,从服务器获取
|
||||
const response = await this.request<YdWordDetail>(`/api/v1/dict/word/${encodeURIComponent(word)}`)
|
||||
const wordDetail = response.data
|
||||
|
||||
// 将结果缓存到本地存储,设置7天过期时间
|
||||
try {
|
||||
wx.setStorageSync(cacheKey, wordDetail)
|
||||
// 同时存储缓存时间,用于清理时判断
|
||||
const cacheTimeKey = `word_detail_time_${word}`
|
||||
wx.setStorageSync(cacheTimeKey, Date.now())
|
||||
} catch (e) {
|
||||
console.warn('存储单词详情缓存失败:', e)
|
||||
}
|
||||
|
||||
console.log('获取单词详情成功:', response)
|
||||
return response.data
|
||||
return wordDetail
|
||||
}
|
||||
|
||||
// 播放音频文件
|
||||
@@ -1056,6 +1082,32 @@ class ApiManager {
|
||||
keysToDelete.forEach(key => cacheStats.delete(key))
|
||||
}
|
||||
|
||||
// 清除单词详情缓存
|
||||
clearWordDetailCache(): void {
|
||||
console.log('清除单词详情缓存')
|
||||
|
||||
try {
|
||||
const storageInfo = wx.getStorageInfoSync()
|
||||
|
||||
// 查找所有单词详情相关的缓存键
|
||||
const wordDetailKeys: string[] = []
|
||||
storageInfo.keys.forEach(key => {
|
||||
if (key.startsWith('word_detail_')) {
|
||||
wordDetailKeys.push(key)
|
||||
}
|
||||
})
|
||||
|
||||
// 删除所有单词详情缓存
|
||||
wordDetailKeys.forEach(key => {
|
||||
wx.removeStorageSync(key)
|
||||
})
|
||||
|
||||
console.log('已清除单词详情缓存,数量:', wordDetailKeys.length)
|
||||
} catch (e) {
|
||||
console.error('清除单词详情缓存失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取缓存统计信息
|
||||
getCacheStats(): { audioCount: number; imageCount: number; totalSize: number; sizeByType: Record<string, number> } {
|
||||
console.log('开始获取缓存统计信息')
|
||||
|
||||
Reference in New Issue
Block a user