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:
王鹏
2026-05-08 20:02:27 +08:00
commit 802b4ba229
98 changed files with 5761 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
const app = getApp();
const api = require('../../utils/api');
const loc = require('../../utils/location');
const storage = require('../../utils/storage');
Page({
data: {
showAnimation: false,
dataReady: false,
result: null,
error: '',
distanceText: '',
deliveryInfo: ''
},
onLoad() {
this.roll();
},
roll() {
this.setData({
showAnimation: true,
dataReady: false,
error: '',
result: null
});
const prefs = storage.get('user_prefs', {});
loc.getLocation().then((pos) => {
return api.post('/api/takeout/roll', {
latitude: pos.latitude,
longitude: pos.longitude,
openid: 'anonymous',
taste: prefs.taste || '都可以',
priceRange: prefs.priceRange || 'all',
allergies: prefs.allergies || ''
});
}).then((data) => {
const distKm = ((data.distance || 0) / 1000).toFixed(1);
const deliveryTime = data.deliveryTime || '';
const minOrder = data.minOrder || '';
const deliveryFee = data.deliveryFee ? ('配送费' + data.deliveryFee) : '';
const parts = [deliveryTime, minOrder, deliveryFee].filter(Boolean);
this.setData({
result: data,
distanceText: distKm + 'km',
deliveryInfo: parts.join(' · '),
dataReady: true
});
}).catch((err) => {
this.setData({
showAnimation: false,
error: err.message || '附近喵星人占领了,换片区域试试?'
});
});
},
onAnimationDone() {
this.setData({ showAnimation: false });
},
goOrder() {
const shop = this.data.result;
if (!shop) return;
const shopName = shop.name || '';
const shopAddress = shop.address || '';
const lat = app.globalData.location ? app.globalData.location.latitude : 0;
const lng = app.globalData.location ? app.globalData.location.longitude : 0;
wx.showActionSheet({
itemList: ['美团外卖', '饿了么', '查看地图位置'],
success: (res) => {
if (res.tapIndex === 0) {
this.openMeituan(shopName);
} else if (res.tapIndex === 1) {
this.openEleme(shopName);
} else if (res.tapIndex === 2) {
wx.openLocation({
latitude: shop.latitude || lat,
longitude: shop.longitude || lng,
name: shopName,
address: shopAddress,
scale: 16
});
}
},
fail: () => {
this.openMeituan(shopName);
}
});
},
openMeituan(name) {
wx.navigateToMiniProgram({
appId: 'wxde8ac0a21135c07d',
path: '',
extraData: { query: name },
success: () => {
this.saveRecord(this.data.result);
},
fail: () => {
wx.showToast({ title: '请安装美团外卖 APP', icon: 'none', duration: 2000 });
}
});
},
openEleme(name) {
wx.navigateToMiniProgram({
appId: 'wxece3a9a4c82f58c9',
path: '',
extraData: { query: name },
success: () => {
this.saveRecord(this.data.result);
},
fail: () => {
wx.showToast({ title: '请安装饿了么 APP', icon: 'none', duration: 2000 });
}
});
},
retry() {
this.roll();
},
saveRecord(data) {
const history = wx.getStorageSync('box_history') || [];
history.push({
id: Date.now().toString(),
icon: '🛵',
name: data.name,
time: new Date().toLocaleString(),
typeName: '外卖盲盒'
});
wx.setStorageSync('box_history', history);
}
});

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {
"result-card": "/components/result-card/result-card",
"box-animation": "/components/box-animation/box-animation"
},
"navigationBarTitleText": "外卖盲盒"
}

View File

@@ -0,0 +1,41 @@
<view class="takeout-page">
<!-- 错误态 -->
<view class="empty" wx:if="{{error}}">
<view class="empty-icon">😿</view>
<view>{{error}}</view>
<button class="btn-primary" style="margin-top:32rpx" bind:tap="retry">换个区域试试</button>
</view>
<!-- 结果区(动效结束后展示) -->
<view class="result-area" wx:if="{{!showAnimation && result}}">
<view class="result-title">🎉 你抽到的外卖是…</view>
<result-card
imageUrl="{{result.imageUrl}}"
name="{{result.name}}"
rating="{{result.rating}}"
avgPrice="{{result.avgPrice}}"
distance="{{distanceText}}"
extra="{{deliveryInfo}}"
recommendReason="{{result.recommendReason}}"
signatureDishes="{{result.signatureDishes}}"
/>
<view class="actions">
<button class="btn-primary btn-main" bind:tap="goOrder">去下单</button>
<view class="btn-retry" bind:tap="retry">再开一个</view>
</view>
</view>
<!-- 开盒动效覆盖层 -->
<box-animation
show="{{showAnimation}}"
boxType="takeout"
dataReady="{{dataReady}}"
bind:done="onAnimationDone"
>
<view class="animation-result-preview" wx:if="{{result}}">
<view class="preview-emoji">🛵</view>
<view class="preview-text">{{result.name}}</view>
<view class="preview-sub" wx:if="{{result.rating}}">⭐ {{result.rating}}</view>
</view>
</box-animation>
</view>

View File

@@ -0,0 +1,93 @@
/*
* 外卖结果页
* 流程:动效覆盖层(加载+揭晓)→ 结果展示
*/
.takeout-page {
padding: var(--space-md);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
}
/* ── 结果区(动效结束后) ── */
.result-area {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.result-title {
font-size: var(--text-subtitle);
font-weight: 600;
color: var(--color-text);
margin: var(--space-md) 0 var(--space-md);
text-align: center;
}
.actions {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin-top: var(--space-lg);
}
.btn-main {
width: 80%;
}
.btn-retry {
margin-top: var(--space-md);
font-size: var(--text-body-sm);
color: var(--color-text-muted);
padding: var(--space-sm);
}
.btn-retry:active {
color: var(--color-primary);
}
/* ── 错误态 ── */
.empty {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 200rpx;
font-size: var(--text-body);
color: var(--color-text-secondary);
}
.empty-icon {
font-size: 80rpx;
margin-bottom: var(--space-md);
opacity: 0.6;
}
/* ── 动效内预览Act 3 slot 内容) ── */
.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;
}