feat: 样式修改

This commit is contained in:
Blizzard
2026-02-10 17:22:53 +08:00
parent 6f88bc656b
commit e97fd30fa3
28 changed files with 2097 additions and 903 deletions
+102
View File
@@ -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"
}
}
+103
View File
@@ -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>
+278
View File
@@ -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;
}