feat: 样式修改
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import request from '../../../utils/request';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
records: [],
|
||||
loading: true,
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
hasMore: true,
|
||||
expandedId: '', // Track which card is expanded
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadRecords();
|
||||
},
|
||||
|
||||
async loadRecords() {
|
||||
this.setData({ loading: true });
|
||||
try {
|
||||
const res = await request.post('/classify/myClassifyLog', {
|
||||
page: this.data.page,
|
||||
pageSize: this.data.pageSize,
|
||||
});
|
||||
const list = (res.list || []).map(item => this._transformRecord(item));
|
||||
this.setData({
|
||||
records: this.data.page === 1 ? list : [...this.data.records, ...list],
|
||||
total: res.total || 0,
|
||||
hasMore: list.length >= this.data.pageSize,
|
||||
loading: false,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Load identify history failed', err);
|
||||
this.setData({ loading: false });
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
_transformRecord(item) {
|
||||
const allResults = item.allResults || [];
|
||||
const topResult = allResults[0] || {};
|
||||
const otherResults = allResults.slice(1);
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
time: this._formatTime(item.createdAt),
|
||||
dateStr: item.createdAtStr || '',
|
||||
topName: topResult.name || '未知植物',
|
||||
topScore: topResult.score ? Math.round(topResult.score * 100) : 0,
|
||||
topImage: topResult.baike_info?.image_url || '',
|
||||
topDesc: topResult.baike_info?.description || '',
|
||||
topBaikeUrl: topResult.baike_info?.baike_url || '',
|
||||
otherResults: otherResults.map(r => ({
|
||||
name: r.name || '未知',
|
||||
score: r.score ? Math.round(r.score * 100) : 0,
|
||||
hasInfo: !!r.baike_info,
|
||||
})),
|
||||
};
|
||||
},
|
||||
|
||||
toggleExpand(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
this.setData({
|
||||
expandedId: this.data.expandedId === id ? '' : id,
|
||||
});
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
if (!this.data.hasMore || this.data.loading) return;
|
||||
this.setData({ page: this.data.page + 1 }, () => {
|
||||
this.loadRecords();
|
||||
});
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.setData({ page: 1, hasMore: true }, () => {
|
||||
this.loadRecords().then(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_formatTime(dateStr) {
|
||||
if (!dateStr) return '';
|
||||
const d = new Date(dateStr);
|
||||
const now = new Date();
|
||||
const diffMs = now - d;
|
||||
const diffMin = Math.floor(diffMs / 60000);
|
||||
if (diffMin < 1) return '刚刚';
|
||||
if (diffMin < 60) return diffMin + '分钟前';
|
||||
const diffHour = Math.floor(diffMin / 60);
|
||||
if (diffHour < 24) return diffHour + '小时前';
|
||||
const diffDay = Math.floor(diffHour / 24);
|
||||
if (diffDay < 7) return diffDay + '天前';
|
||||
|
||||
const month = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
const hour = d.getHours().toString().padStart(2, '0');
|
||||
const min = d.getMinutes().toString().padStart(2, '0');
|
||||
return `${month}-${day} ${hour}:${min}`;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"navigationBarTitleText": "识别记录",
|
||||
"usingComponents": {
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-image": "tdesign-miniprogram/image/image",
|
||||
"t-empty": "tdesign-miniprogram/empty/empty",
|
||||
"t-loading": "tdesign-miniprogram/loading/loading"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<view class="history-page">
|
||||
|
||||
<!-- Loading -->
|
||||
<view wx:if="{{loading && records.length === 0}}" class="loading-wrap">
|
||||
<t-loading theme="circular" size="48rpx" text="加载中..." />
|
||||
</view>
|
||||
|
||||
<!-- Empty -->
|
||||
<view wx:elif="{{!loading && records.length === 0}}" class="empty-wrap">
|
||||
<view class="empty-icon">
|
||||
<t-icon name="scan" size="120rpx" color="#D1D5DB" />
|
||||
</view>
|
||||
<text class="empty-title">暂无识别记录</text>
|
||||
<text class="empty-hint">去百科页面拍照识别植物吧</text>
|
||||
</view>
|
||||
|
||||
<!-- Record List -->
|
||||
<view wx:else class="record-list">
|
||||
<view wx:for="{{records}}" wx:key="id" class="record-card" bindtap="toggleExpand" data-id="{{item.id}}">
|
||||
|
||||
<!-- Card Header -->
|
||||
<view class="card-header">
|
||||
<view class="card-thumb">
|
||||
<t-image
|
||||
wx:if="{{item.topImage}}"
|
||||
src="{{item.topImage}}"
|
||||
mode="aspectFill"
|
||||
width="120rpx"
|
||||
height="120rpx"
|
||||
shape="round"
|
||||
/>
|
||||
<view wx:else class="thumb-placeholder">
|
||||
<t-icon name="image" size="48rpx" color="#D1D5DB" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-info">
|
||||
<view class="card-name-row">
|
||||
<text class="card-name">{{item.topName}}</text>
|
||||
<view class="score-badge" style="background: {{item.topScore >= 80 ? '#E8F5E9' : item.topScore >= 50 ? '#FFF8E1' : '#FBE9E7'}}; color: {{item.topScore >= 80 ? '#2E7D32' : item.topScore >= 50 ? '#F57F17' : '#D84315'}}">
|
||||
{{item.topScore}}%
|
||||
</view>
|
||||
</view>
|
||||
<text class="card-time">{{item.time}}</text>
|
||||
<view wx:if="{{item.otherResults.length > 0}}" class="other-hint">
|
||||
<text>还可能是: </text>
|
||||
<text wx:for="{{item.otherResults}}" wx:for-item="other" wx:key="name" class="other-name">{{other.name}}{{index < item.otherResults.length - 1 ? '、' : ''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="expand-arrow {{expandedId === item.id ? 'expanded' : ''}}">
|
||||
<t-icon name="chevron-down" size="32rpx" color="#C5C5C5" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Expanded Detail -->
|
||||
<view wx:if="{{expandedId === item.id}}" class="card-detail">
|
||||
<!-- Description -->
|
||||
<view wx:if="{{item.topDesc}}" class="detail-desc">
|
||||
<text class="desc-text">{{item.topDesc}}</text>
|
||||
</view>
|
||||
|
||||
<!-- All Results -->
|
||||
<view class="detail-results">
|
||||
<text class="detail-label">识别结果排名</text>
|
||||
<view class="result-bars">
|
||||
<!-- Top result -->
|
||||
<view class="result-bar-item">
|
||||
<text class="bar-name">{{item.topName}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill top" style="width: {{item.topScore}}%"></view>
|
||||
</view>
|
||||
<text class="bar-score">{{item.topScore}}%</text>
|
||||
</view>
|
||||
<!-- Other results -->
|
||||
<view wx:for="{{item.otherResults}}" wx:for-item="other" wx:key="name" class="result-bar-item">
|
||||
<text class="bar-name">{{other.name}}</text>
|
||||
<view class="bar-track">
|
||||
<view class="bar-fill" style="width: {{other.score}}%"></view>
|
||||
</view>
|
||||
<text class="bar-score">{{other.score}}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-meta">
|
||||
<t-icon name="time" size="24rpx" color="#9CA3AF" />
|
||||
<text class="meta-text">{{item.dateStr}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- Load More -->
|
||||
<view wx:if="{{loading && records.length > 0}}" class="load-more">
|
||||
<t-loading theme="circular" size="36rpx" text="加载更多..." />
|
||||
</view>
|
||||
<view wx:elif="{{!hasMore && records.length > 0}}" class="no-more">
|
||||
<text>— 没有更多了 —</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,278 @@
|
||||
/* pages/profile/identify-history/index.wxss */
|
||||
|
||||
.history-page {
|
||||
min-height: 100vh;
|
||||
background: #F4F6F0;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Loading & Empty */
|
||||
.loading-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
.empty-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 200rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
background: #F3F4F6;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #6B7280;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 26rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* Record List */
|
||||
.record-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
padding-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.record-card {
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.02);
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.record-card:active {
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* Card Header */
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.card-thumb {
|
||||
flex-shrink: 0;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.thumb-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #F3F4F6;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.card-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.card-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #1F2937;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.score-badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.card-time {
|
||||
font-size: 24rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.other-hint {
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.other-name {
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.expand-arrow {
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.expand-arrow.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Card Detail (Expanded) */
|
||||
.card-detail {
|
||||
margin-top: 28rpx;
|
||||
padding-top: 28rpx;
|
||||
border-top: 2rpx solid #F3F4F6;
|
||||
animation: fadeSlideDown 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeSlideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-16rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Description */
|
||||
.detail-desc {
|
||||
background: #F4F6F0;
|
||||
border-radius: 20rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.desc-text {
|
||||
font-size: 26rpx;
|
||||
line-height: 1.7;
|
||||
color: #4B5563;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Result Bars */
|
||||
.detail-results {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #6B7280;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.result-bars {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.result-bar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.bar-name {
|
||||
width: 120rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.bar-track {
|
||||
flex: 1;
|
||||
height: 16rpx;
|
||||
background: #F3F4F6;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
background: linear-gradient(90deg, #A5D6A7, #66BB6A);
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.bar-fill.top {
|
||||
background: linear-gradient(90deg, #66BB6A, #388E3C);
|
||||
}
|
||||
|
||||
.bar-score {
|
||||
width: 80rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #6B7280;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Meta */
|
||||
.detail-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding-top: 16rpx;
|
||||
}
|
||||
|
||||
.meta-text {
|
||||
font-size: 22rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* Load More */
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 32rpx 0;
|
||||
font-size: 24rpx;
|
||||
color: #D1D5DB;
|
||||
}
|
||||
Reference in New Issue
Block a user