This commit is contained in:
Felix
2025-12-22 15:47:39 +08:00
parent 9ce8044e2a
commit 023b30ec87
9 changed files with 72 additions and 396 deletions

View File

@@ -6,6 +6,7 @@
bottom: 0;
background: #f8fafc;
z-index: 999;
padding: 0 12rpx;
transform: translateY(100%);
transition: transform 0ms ease-out;
}
@@ -36,7 +37,7 @@
.legend-item { display: flex; align-items: center; gap: 8rpx; }
.color-box { width: 20rpx; height: 20rpx; border: 1rpx solid #e0e0e0; border-radius: 4rpx; }
.legend-text { font-size: 22rpx; color: #666; }
.word-scores-list { display: flex; flex-direction: column; gap: 16rpx; overflow-y: auto; border-radius: 24rpx; }
.word-scores-list { display: flex; flex-direction: column; overflow-y: auto; border-radius: 24rpx; padding-bottom: calc(20px + env(safe-area-inset-bottom));}
.word-score-item { display: flex; flex-direction: column; gap: 12rpx; padding: 20rpx; border-bottom: 2rpx solid #eee; }
.word-score-item:last-child { border-bottom: none; }
.word-header { display: flex; justify-content: space-between; align-items: center; }

View File

@@ -143,6 +143,8 @@ interface IPageData {
}
type IPageMethods = {
onImageLoaded: () => void
onBgTouchMove: (e: any) => void
updateCircleProgress: () => void
startRecording: () => void
stopRecording: () => void
@@ -176,6 +178,9 @@ type IPageMethods = {
ensureRecordPermission: () => void
onMoreTap: () => void
onSceneSentenceTap: () => void
onSentenceTouchStart: (e: any) => void
onSentenceTouchMove: (e: any) => void
onSentenceTouchEnd: () => void
noop: () => void
}
@@ -590,12 +595,6 @@ Page<IPageData, IPageInstance>({
handleRecordEnd() {
logger.info('---lisa-handleRecordEnd')
this.stopRecording()
// 淡出高亮层
this.setData({ overlayVisible: false })
const timer = setTimeout(() => {
this.setData({ highlightShow: false, highlightZoom: false, focusTransform: '', highlightWords: [] })
clearTimeout(timer)
}, 320)
},
// 点击图片预览
@@ -1716,7 +1715,7 @@ Page<IPageData, IPageInstance>({
computeDynamicLayout() {
try {
const windowInfo = wx.getWindowInfo();
const windowInfo = (wx as any).getWindowInfo ? (wx as any).getWindowInfo() : wx.getSystemInfoSync()
const wh = windowInfo.windowHeight
const ww = windowInfo.windowWidth
const rpx = ww / 750
@@ -1906,7 +1905,8 @@ Page<IPageData, IPageInstance>({
const rows: { idxs: number[], width: number }[] = []
let current: { idxs: number[], width: number } = { idxs: [], width: 0 }
scaledWidths.forEach((w, i) => {
for (let i = 0; i < scaledWidths.length; i++) {
const w = Number(scaledWidths[i])
const extra = current.idxs.length > 0 ? wordSpacing : 0
if (current.width + extra + w <= availWidth) {
current.idxs.push(i)
@@ -1915,7 +1915,7 @@ Page<IPageData, IPageInstance>({
if (current.idxs.length > 0) rows.push(current)
current = { idxs: [i], width: w }
}
})
}
if (current.idxs.length > 0) rows.push(current)
const totalHeight = rows.length * rowHeight + Math.max(rows.length - 1, 0) * rowSpacing

View File

@@ -57,7 +57,7 @@
margin-top: calc(50vh - 40rpx);
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
box-shadow: 0 -24rpx 24rpx 0 rgba(0,0,0,0.2);
box-shadow: 0 -12rpx 12rpx 0 rgba(0,0,0,0.2);
will-change: transform;
transition: transform 120ms ease-out;
}
@@ -321,261 +321,6 @@
opacity: 1;
}
.score-container {
display: flex;
flex-direction: column;
padding: 0 24rpx;
transition: all 0.3s ease-in-out;
height: 100%;
}
.score-image-container {
display: flex;
align-items: center;
padding: 0 0 0 12rpx;
min-height: 120rpx;
}
.score-text {
flex: 1;
font-size: 30rpx;
line-height: 42rpx;
color: #001858;
font-weight: 600;
word-break: break-word;
}
.expanded .score-overview {
margin-bottom: 20rpx;
}
.total-score {
flex-shrink: 0;
}
.circle-progress {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background: #f7f7f7;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.total-score-value {
font-size: 28rpx;
color: #001858;
font-weight: 600;
position: relative;
z-index: 1;
line-height: 28rpx;
}
.total-score-label {
font-size: 20rpx;
color: #666666;
position: relative;
z-index: 1;
margin-top: 8rpx;
line-height: 20rpx;
}
.score-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 16rpx;
}
.score-item {
display: flex;
align-items: center;
gap: 16rpx;
}
.score-label {
font-size: 22rpx;
color: #666666;
width: 80rpx;
text-align: right;
}
.score-content {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
}
.score-value {
font-size: 24rpx;
color: #001858;
font-weight: bold;
width: 80rpx;
text-align: right;
}
.score-item .no-score-text {
font-size: 22rpx;
color: #999;
}
.progress-fill {
height: 100%;
background: #001858;
border-radius: 3rpx;
transition: width 0.3s ease;
}
.no-score {
display: flex;
justify-content: center;
align-items: center;
height: 300rpx;
}
.no-score-text {
font-size: 32rpx;
color: #999;
}
/* 单词评分列表样式 */
.match-tag-legend {
/* margin-top: 40rpx; */
padding: 24rpx;
}
.legend-header {
display: flex;
align-items: center;
gap: 16rpx;
}
.legend-title {
font-size: 24rpx;
color: #333;
white-space: nowrap;
}
.legend-items {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.color-box {
width: 20rpx;
height: 20rpx;
border: 1rpx solid #e0e0e0;
border-radius: 4rpx;
}
.legend-text {
font-size: 22rpx;
color: #666;
}
.word-scores-list {
display: flex;
flex-direction: column;
gap: 16rpx;
/* height: calc(100vh - 420rpx); */
overflow-y: auto;
border-radius: 24rpx;
}
.word-score-item {
display: flex;
flex-direction: column;
gap: 12rpx;
padding: 20rpx;
/* border-bottom: 1rpx solid #e0e0e0; */
/* border-radius: 12rpx; */
border-bottom: 2rpx solid #eee;
}
.word-score-item:last-child {
border-bottom: none;
}
.word-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.phone-infos {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
}
.phone-info-item {
display: flex;
align-items: center;
gap: 8rpx;
padding: 6rpx 10rpx;
border-radius: 8rpx;
border: 1rpx solid rgba(0,0,0,0.06);
}
.phone-text {
font-size: 24rpx;
line-height: 24rpx;
color: #333;
}
.phone-score {
font-size: 24rpx;
line-height: 24rpx;
color: #666;
}
.word-text {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.word-score-details {
display: flex;
gap: 24rpx;
}
.word-score-row {
display: flex;
align-items: center;
gap: 8rpx;
justify-content: flex-end;
}
.word-score-label {
font-size: 22rpx;
color: #666;
}
.word-score-value {
font-size: 22rpx;
color: #333;
font-weight: 500;
text-align: right;
}
.t-sticky {
position: sticky !important;
top: 0;
z-index: 2 !important;
}
/* 高亮遮罩与单词浮层 */
.highlight-area {
position: fixed;
@@ -833,22 +578,6 @@
overflow-y: auto;
}
.score-modal-content {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #f8fafc;
z-index: 999;
transform: translateY(100%);
transition: transform 0ms ease-out;
}
.score-modal-content.show {
transform: translateY(0);
}
.score-modal-mask {
position: fixed;
top: 0;
@@ -859,79 +588,6 @@
z-index: 998;
}
.score-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
height: 48rpx;
}
.score-overview {
/* padding-top: 40rpx; */
}
.score-circles {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 24rpx;
}
.circle-item {
display: flex;
justify-content: center;
background-color: #eee;
border-radius: 50%;
}
.circle-item .circle-progress::before {
}
.circle-progress::before {
content: '';
position: absolute;
width: 100rpx;
height: 100rpx;
top: 10rpx;
left: 10rpx;
border-radius: 50%;
background: #ffffff;
}
.score-item {
display: flex;
align-items: center;
gap: 16rpx;
}
.score-label {
font-size: 22rpx;
color: #666666;
width: 80rpx;
text-align: right;
}
.score-content {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
}
.score-value {
font-size: 24rpx;
color: #001858;
font-weight: bold;
width: 80rpx;
text-align: right;
}
.score-item .no-score-text {
font-size: 22rpx;
color: #999;
}
.progress-bar {
flex: 1;
height: 6rpx;
@@ -1057,31 +713,6 @@
border-top-right-radius: 0rpx;
}
/* 弹窗头部 */
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 20rpx;
position: relative;
}
.t-sticky {
position: sticky !important;
top: 0;
z-index: 2 !important;
}
.word-title {
display: flex;
align-items: center;
font-size: 40rpx;
font-weight: bold;
}
.word-source {
font-size: 24rpx;
}
/* 频率标签容器 */
.frequency-tags {

View File

@@ -57,13 +57,13 @@ Page({
},
// 词典等级配置
dictLevel: 'LEVEL1',
dictLevel: 'level1',
dictLevelOptions: apiManager.getDictLevelOptions(),
// 应用信息
appInfo: {
version: '1.0.0', // 默认版本
buildDate: '2024-01-01'
version: '0.25.1222', // 默认版本
buildDate: '2025-12-22'
}
},

View File

@@ -97,6 +97,7 @@
<!-- <view class="scene-explain">
<text>{{scene.list[currentIndex].sceneExplanation}}</text>
</view> -->
<view class="sentence-tips">上述内容由AI生成</view>
</scroll-view>
</block>
@@ -117,9 +118,9 @@
<view wx:if="{{isRecording}}" class="mic">
<view class="mic-shadow"></view>
</view>
</view>
<t-icon name="fact-check" class="bottom-btn {{(hasScoreInfo && !isRecording) ? '' : 'disabled'}}" size="48rpx" bind:tap="onScoreTap" />
<t-icon name="chevron-right" class="bottom-btn {{(scene.list && (currentIndex >= scene.list.length - 1)) ? 'disabled' : ''}}" size="48rpx" bind:tap="onNextTap" />
</view>
<t-icon name="fact-check" class="bottom-btn {{(hasScoreInfo && !isRecording) ? '' : 'disabled'}}" size="48rpx" bind:tap="onScoreTap" />
<t-icon name="chevron-right" class="bottom-btn {{(scene.list && (currentIndex >= scene.list.length - 1)) ? 'disabled' : ''}}" size="48rpx" bind:tap="onNextTap" />
</view>
<score-modal
wx:if="{{isScoreModalOpen && hasScoreInfo}}"

View File

@@ -22,7 +22,7 @@
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: translate(-50%, -100%);
display: flex;
flex-direction: column;
align-items: center;
@@ -70,7 +70,7 @@
margin-top: 24rpx;
box-sizing: border-box;
overflow: hidden;
margin-bottom: calc(110rpx + env(safe-area-inset-bottom)) ;
margin-bottom: calc(120rpx + env(safe-area-inset-bottom)) ;
}
.sentence-content-wrapper {
display: flex;
@@ -95,6 +95,12 @@
color: #666;
text-align: center;
}
.sentence-tips {
font-size: 24rpx;
color: #dddddd;
text-align: center;
}
/* 高亮遮罩与单词浮层 */
.highlight-area {
position: fixed;
@@ -156,6 +162,7 @@
}
.mic-wrap {
position: relative;
width: 88rpx;
}
.microphone {
transition: all 0.3s ease;

View File

@@ -49,6 +49,7 @@ Page({
scrollTop: 0,
takePhoto: false,
photoPath: '',
photoExpandSrc: '',
photoImageLoaded: false,
photoExpandLoaded: false,
photoExpandTransform: '',
@@ -651,11 +652,13 @@ Page({
wx.hideLoading()
this.setData({ photoPath: String(imagePath || '').trim(), takePhoto: true })
try { await this.ensurePhotoPersistent() } catch {}
try { this.setData({ photoExpandSrc: String(this.data.photoPath || '').trim() }) } catch {}
logger.info('拍照成功:', imagePath)
// try { wx.nextTick(() => { this.scheduleExpandTransform() }) } catch (err) {}
// 直接跳转到结果页面
this.navigateToResult(imagePath)
this.navigateToResult()
} catch (error: any) {
wx.hideLoading()
@@ -686,12 +689,14 @@ Page({
wx.hideLoading()
this.setData({ photoPath: String(imagePath || '').trim(), takePhoto: true })
try { await this.ensurePhotoPersistent() } catch {}
try { this.setData({ photoExpandSrc: String(this.data.photoPath || '').trim() }) } catch {}
logger.info('选择图片成功:', imagePath)
// try { wx.nextTick(() => { this.scheduleExpandTransform() }) } catch (err) {}
// 直接跳转到结果页面
this.navigateToResult(imagePath)
this.navigateToResult()
} catch (error: any) {
wx.hideLoading()
@@ -709,6 +714,8 @@ Page({
async onPhotoImageLoad() {
try {
this.setData({ photoImageLoaded: true })
try { await this.ensurePhotoPersistent() } catch {}
try { this.setData({ photoExpandSrc: String(this.data.photoPath || '').trim() }) } catch {}
if (this.data.takePhoto && !this.data.showExpandLayer) {
try { wx.nextTick(() => { this.scheduleExpandTransform() }) } catch {}
}
@@ -749,12 +756,39 @@ Page({
persistent = fs.saveFileSync(p)
} catch (e) {}
if (persistent) {
this.setData({ photoPath: persistent })
this.setData({ photoPath: persistent, photoExpandSrc: persistent })
} else {
try {
await wx.getImageInfo({ src: p } as any)
} catch {
wx.showToast({ title: '图片加载失败', icon: 'none' })
this.setData({ photoExpandSrc: String(this.data.photoSvgData || '') })
}
}
} catch {}
},
async ensurePhotoPersistent() {
try {
const p = String(this.data.photoPath || '').trim()
if (!p) return
const userData = ((wx as any).env && (wx as any).env.USER_DATA_PATH) ? String((wx as any).env.USER_DATA_PATH) : ''
const alreadyPersistent = !!(userData && p.indexOf(userData) === 0)
if (alreadyPersistent) {
try { await wx.getImageInfo({ src: p } as any) } catch {}
try { this.setData({ photoExpandSrc: p }) } catch {}
return
}
const fs = wx.getFileSystemManager()
let persistent = ''
try { persistent = fs.saveFileSync(p) } catch (e) {}
if (persistent) {
this.setData({ photoPath: persistent, photoExpandSrc: persistent })
try { await wx.getImageInfo({ src: persistent } as any) } catch {}
} else {
try { await wx.getImageInfo({ src: p } as any) } catch {
wx.showToast({ title: '图片校验失败', icon: 'none' })
this.setData({ photoExpandSrc: String(this.data.photoSvgData || '') })
}
}
} catch {}
@@ -832,9 +866,11 @@ Page({
},
// 跳转到结果页面
async navigateToResult(imagePath: string) {
async navigateToResult() {
try {
const imagePath = String(this.data.photoPath || '').trim()
logger.info('跳转到结果页面:', imagePath)
try { await this.ensurePhotoPersistent() } catch {}
try { wx.nextTick(() => { this.scheduleExpandTransform() }) } catch (err) {}
// 跳转到结果页面并传递图片路径

View File

@@ -43,7 +43,7 @@
<view wx:if="{{takePhoto && showExpandLayer }}" class="photo-expand-layer" style="{{photoExpandTransform}} {{photoExpandTransition}}">
<view class="photo-expand-inner" style="{{photoExpandCurrentWidth ? ('width: ' + photoExpandCurrentWidth + 'px;') : ''}}">
<!-- <view class="expand-border-bg" style="{{expandBorderStyle}}"></view> -->
<image class="photo-expand-image" src="{{takePhoto ? photoPath : photoSvgData}}" mode="widthFix" bindload="onPhotoExpandLoaded" binderror="onPhotoExpandError"></image>
<image class="photo-expand-image" src="{{takePhoto ? photoExpandSrc : photoSvgData}}" mode="widthFix" bindload="onPhotoExpandLoaded" binderror="onPhotoExpandError"></image>
<view class="scanner {{scannerVisible ? 'scanner-visible' : 'scanner-hidden'}}">
<view class="star star1"></view>
<view class="star star2"></view>
@@ -125,7 +125,7 @@
<view class="wf-item {{animateWaterfall ? 'fade-in' : ''}}" wx:for="{{waterfallRight}}" wx:for-index="j" wx:key="image_id" catch:tap="onImageTap" data-image-id="{{item.image_id}}" style="animation-delay: {{j * 0.15 + 0.15}}s;">
<t-skeleton wx:if="{{item.thumbnail_loading}}" class="wf-image" row-col="{{[1]}}" animation="gradient" loading></t-skeleton>
<image wx:else class="wf-image" src="{{item.thumbnail_url}}" mode="widthFix" bindload="onWfThumbLoaded" data-image-id="{{item.image_id}}"/>
<view wx:if="{{item.thumb_lothumbnail_urladed}}" class="image-more-wrap" catchtap="noop">
<view wx:if="{{item.thumbnail_url}}" class="image-more-wrap" catchtap="noop">
<view class="mini-button" bindtap="onImageMoreTap" data-image-id="{{item.image_id}}">
<view class="ul-mini {{item.more_open ? 'active' : ''}}">
<view class="dot1"></view>

View File

@@ -941,8 +941,8 @@ class ApiManager {
console.log('开始图片识别请求:', { fileId, type, dictLevel })
const response = await this.request<{task_id: string, status: string, message: string}>('/api/v1/image/recognize/async', 'POST', {
file_id: fileId,
type: type,
dict_level: dictLevel // 添加词典等级参数
type: type
// dict_level: dictLevel // 添加词典等级参数
})
console.log('图片识别成功:', response.data)