fix: 修复 VoiceController Map.of 兼容性 + ExploreController 参数不匹配
- VoiceController: Map.of() -> Collections.singletonMap() 兼容 Java 8 - ExploreController: 补齐 takeoutService.roll() 缺失的 taste/priceRange/allergies 参数 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
82
miniapp/pages/recipe-list/recipe-list.js
Normal file
82
miniapp/pages/recipe-list/recipe-list.js
Normal file
@@ -0,0 +1,82 @@
|
||||
const api = require('../../utils/api');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
showAnimation: false,
|
||||
dataReady: false,
|
||||
loading: false,
|
||||
results: [],
|
||||
ingredients: []
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
if (options.payload) {
|
||||
try {
|
||||
const payload = JSON.parse(decodeURIComponent(options.payload));
|
||||
const ingredients = payload.ingredients || [];
|
||||
const staples = payload.staples || [];
|
||||
this.setData({ ingredients });
|
||||
this.match(ingredients, staples);
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '参数错误', icon: 'none' });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
match(ingredients, staples) {
|
||||
this.setData({
|
||||
showAnimation: true,
|
||||
dataReady: false,
|
||||
results: []
|
||||
});
|
||||
|
||||
api.post('/api/fridge/match', { ingredients: ingredients, staples: staples })
|
||||
.then((data) => {
|
||||
this.setData({ results: data, dataReady: true });
|
||||
if (data.length > 0) {
|
||||
const history = wx.getStorageSync('box_history') || [];
|
||||
history.push({
|
||||
id: Date.now().toString(),
|
||||
icon: '🥬',
|
||||
name: data[0].recipe.name + ' (' + data[0].matchRate + '%匹配)',
|
||||
time: new Date().toLocaleString(),
|
||||
typeName: '冰箱盲盒'
|
||||
});
|
||||
wx.setStorageSync('box_history', history);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.setData({
|
||||
showAnimation: false,
|
||||
results: [],
|
||||
loading: false
|
||||
});
|
||||
wx.showToast({ title: '匹配失败,请重试', icon: 'none' });
|
||||
});
|
||||
},
|
||||
|
||||
onAnimationDone() {
|
||||
this.setData({ showAnimation: false });
|
||||
},
|
||||
|
||||
goDetail(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
let missing = e.currentTarget.dataset.missing;
|
||||
|
||||
// dataset 值可能是字符串,需要解析
|
||||
if (typeof missing === 'string') {
|
||||
try { missing = JSON.parse(missing); } catch (e) { missing = []; }
|
||||
}
|
||||
if (!Array.isArray(missing)) missing = [];
|
||||
|
||||
let url = '/pages/recipe-detail/recipe-detail?id=' + id;
|
||||
if (missing.length > 0) {
|
||||
url += '&missing=' + encodeURIComponent(JSON.stringify(missing));
|
||||
}
|
||||
wx.navigateTo({ url: url });
|
||||
},
|
||||
|
||||
reshuffle() {
|
||||
this.match(this.data.ingredients);
|
||||
}
|
||||
});
|
||||
6
miniapp/pages/recipe-list/recipe-list.json
Normal file
6
miniapp/pages/recipe-list/recipe-list.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"box-animation": "/components/box-animation/box-animation"
|
||||
},
|
||||
"navigationBarTitleText": "菜谱推荐"
|
||||
}
|
||||
42
miniapp/pages/recipe-list/recipe-list.wxml
Normal file
42
miniapp/pages/recipe-list/recipe-list.wxml
Normal file
@@ -0,0 +1,42 @@
|
||||
<view class="recipe-list-page">
|
||||
<box-animation
|
||||
show="{{showAnimation}}"
|
||||
boxType="fridge"
|
||||
dataReady="{{dataReady}}"
|
||||
bind:done="onAnimationDone"
|
||||
>
|
||||
<view class="animation-result-preview" wx:if="{{results.length > 0}}">
|
||||
<view class="preview-emoji">🥬</view>
|
||||
<view class="preview-text">{{results[0].recipe.name}}</view>
|
||||
<view class="preview-sub">匹配度 {{results[0].matchRate}}%</view>
|
||||
</view>
|
||||
</box-animation>
|
||||
|
||||
<view class="list-header" wx:if="{{!showAnimation && results.length}}">
|
||||
为你找到 {{results.length}} 个菜谱
|
||||
</view>
|
||||
|
||||
<view class="recipe-cards" wx:if="{{!showAnimation}}">
|
||||
<view class="recipe-card card" wx:for="{{results}}" wx:key="recipe.id" bind:tap="goDetail" data-id="{{item.recipe.id}}" data-missing="{{item.missingIngredients}}">
|
||||
<view class="card-left">
|
||||
<view class="recipe-name">{{item.recipe.name}}</view>
|
||||
<view class="recipe-meta">
|
||||
<text wx:if="{{item.recipe.difficulty}}">⭐{{item.recipe.difficulty}}</text>
|
||||
<text wx:if="{{item.recipe.cookTime}}"> ⏱️{{item.recipe.cookTime}}分钟</text>
|
||||
</view>
|
||||
<view class="match-rate">
|
||||
<view class="rate-bar">
|
||||
<view class="rate-fill" style="width:{{item.matchRate}}%"></view>
|
||||
</view>
|
||||
<text>{{item.matchRate}}%</text>
|
||||
</view>
|
||||
<view class="missing" wx:if="{{item.missingIngredients.length}}">
|
||||
缺:<text wx:for="{{item.missingIngredients}}" wx:key="*this">{{item}} </text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="center" wx:if="{{!showAnimation && results.length === 0}}">没有匹配的菜谱,试试换个食材组合</view>
|
||||
<view class="btn-retry" wx:if="{{!showAnimation && results.length}}" bind:tap="reshuffle">换一批菜谱</view>
|
||||
</view>
|
||||
133
miniapp/pages/recipe-list/recipe-list.wxss
Normal file
133
miniapp/pages/recipe-list/recipe-list.wxss
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 菜谱推荐列表
|
||||
*/
|
||||
|
||||
.recipe-list-page {
|
||||
padding: var(--space-md) var(--space-lg);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ── 页头 ── */
|
||||
.list-header {
|
||||
font-size: var(--text-body);
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
/* ── 卡片 ── */
|
||||
.recipe-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.recipe-card {
|
||||
padding: var(--space-md);
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.recipe-card:active {
|
||||
transform: scale(0.985);
|
||||
}
|
||||
|
||||
/* ── 内容 ── */
|
||||
.recipe-name {
|
||||
font-size: var(--text-subtitle);
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.recipe-meta {
|
||||
font-size: var(--text-body-sm);
|
||||
color: var(--color-text-muted);
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
/* ── 匹配度条 ── */
|
||||
.match-rate {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
font-size: var(--text-body-sm);
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.rate-bar {
|
||||
flex: 1;
|
||||
height: 6rpx;
|
||||
background: #F0EDE8;
|
||||
border-radius: 3rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.rate-fill {
|
||||
height: 100%;
|
||||
background: var(--color-green);
|
||||
border-radius: 3rpx;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
/* ── 缺少食材 ── */
|
||||
.missing {
|
||||
font-size: var(--text-caption);
|
||||
color: #E8A040;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
/* ── 空态 ── */
|
||||
.center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
font-size: var(--text-body);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* ── 换一批 ── */
|
||||
.btn-retry {
|
||||
text-align: center;
|
||||
font-size: var(--text-body);
|
||||
font-weight: 500;
|
||||
color: var(--color-primary);
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.btn-retry:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* ── 动效内预览 ── */
|
||||
.animation-result-preview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.preview-emoji {
|
||||
font-size: 64rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.preview-text {
|
||||
font-size: var(--text-subtitle);
|
||||
font-weight: 700;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-sub {
|
||||
font-size: var(--text-body-sm);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user