🎨 新增订单页,优化用户首页

This commit is contained in:
2025-08-19 19:49:19 +08:00
parent 6353eeed0b
commit 306cb10f9b
4 changed files with 217 additions and 88 deletions

View File

@@ -30,13 +30,18 @@ const API = {
addFood: data => net.post('/food', data, true), // 添加菜品菜谱
updateFood: data => net.put('/food', data, true), // 更新菜品菜谱
deleteFood: data => net.delete('/food', data, true), // 删除菜品菜谱
createOrder: data => net.post('/order', data, true), // 创建订单
// 菜品分类相关接口
getFoodCategoryList: (params = {}) => net.get('/food/category/list', params, true), // 获取菜品分类列表(支持 page/pageSize
addFoodCategory: data => net.post('/food/category', data, true), // 添加菜品分类
updateFoodCategory: data => net.put('/food/category', data, true), // 更新菜品分类
deleteFoodCategory: data => net.delete('/food/category', data, true) // 删除菜品分类
deleteFoodCategory: data => net.delete('/food/category', data, true), // 删除菜品分类
// 订单相关接口
createOrder: data => net.post('/order', data, true), // 创建订单
getOrderList: (params = {}) => net.get('/order/list', params, true), // 获取订单列表,只需要userId和date参数
getOrderDetail: (id) => net.get(`/order/${id}`, {}, true), // 获取订单详情
deleteOrder: data => net.delete('/order', data, true), // 删除订单
};
export default API

View File

@@ -104,6 +104,13 @@
"enablePullDownRefresh": false
}
},
{
"path": "pages/order/my-orders",
"style": {
"navigationBarTitleText": "订单",
"enablePullDownRefresh": true
}
},
{
"path": "pages/diary/diary",
"style": {

View File

@@ -0,0 +1,185 @@
<template>
<view class="orders-container">
<view class="summary">
<text>一共记录了{{ total }}个订单</text>
</view>
<view class="calendar-box">
<uni-calendar
ref="calendarRef"
:insert="true"
:lunar="false"
:start-date="'2000-01-01'"
:end-date="'2100-12-31'"
:date="selectedDate"
@change="onDateChange"
@monthSwitch="onMonthSwitch"
/>
</view>
<view class="orders-list">
<view v-for="order in orders" :key="order.id" class="order-card">
<view class="card-header">
<text class="order-date">{{ formatDate(order.date || selectedDate) }} {{ order.time || '' }}</text>
<view class="card-actions">
<view class="act-btn" @click.stop="onEvaluate(order)">
<uni-icons type="compose" size="18" color="#999" />
<text class="act-text">评价</text>
</view>
<view class="act-btn" @click.stop="onDelete(order)">
<uni-icons type="trash" size="18" color="#999" />
<text class="act-text">删除</text>
</view>
</view>
</view>
<view v-if="isExpanded(order.id)" class="list">
<view v-for="(food, idx) in order.Foods || []" :key="food.ID || idx" class="list-item">
<image :src="food.img" mode="aspectFill" class="list-thumb" />
<view class="list-info">
<text class="name">{{ food.name }}</text>
<text class="qty">x1</text>
</view>
</view>
</view>
<view v-else class="grid">
<view v-for="(food, idx) in order.Foods || []" :key="food.ID || idx" class="grid-item">
<image :src="food.img" mode="aspectFill" class="grid-thumb" />
<text class="grid-name">{{ food.name }}</text>
</view>
</view>
<view class="toggle" @click="toggleExpand(order.id)">
<uni-icons :type="isExpanded(order.id) ? 'arrowup' : 'arrowdown'" size="18" color="#999" />
</view>
</view>
<view v-if="orders.length === 0" class="empty">
<uni-icons type="paperclip" size="80" color="#ddd" />
<text class="empty-text">这里空空如也~</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { onPullDownRefresh, onShow } from '@dcloudio/uni-app'
import api from '@/api'
const orders = ref([])
const selectedDate = ref('')
const calendarRef = ref(null)
const total = computed(() => orders.value.length)
const expandedSet = ref(new Set())
const isExpanded = (id) => expandedSet.value.has(id)
const toggleExpand = (id) => {
const s = new Set(expandedSet.value)
if (s.has(id)) s.delete(id)
else s.add(id)
expandedSet.value = s
}
const onEvaluate = () => { uni.showToast({ title: '评价功能开发中', icon: 'none' }) }
const getToday = () => {
const d = new Date()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${d.getFullYear()}-${m}-${day}`
}
const getUserId = async () => {
const c1 = uni.getStorageSync('userInfo')
if (c1?.ID) return c1.ID
const c2 = uni.getStorageSync('user')
if (c2?.ID) return c2.ID
const res = await api.getUserInfo()
return res?.data?.ID || null
}
const loadOrders = async () => {
const userId = await getUserId()
if (!userId) return
const res = await api.getOrderList({ userId, date: selectedDate.value })
if (res?.code === 0) orders.value = res.data || []
}
const onDateChange = (e) => {
selectedDate.value = e.fulldate || e.value || selectedDate.value
loadOrders()
}
const onMonthSwitch = () => {}
onMounted(() => {
selectedDate.value = getToday()
loadOrders()
})
onShow(() => {
// 返回页面时确保数据最新
loadOrders()
})
onPullDownRefresh(() => {
loadOrders().finally(() => uni.stopPullDownRefresh())
})
const onDelete = (order) => {
uni.showModal({
title: '删除确认',
content: '确定删除该订单吗?',
success: async (res) => {
if (res.confirm) {
const r = await api.deleteOrder({ id: order.id })
if (r?.code === 0) {
uni.showToast({ title: '删除成功', icon: 'success' })
loadOrders()
} else {
uni.showToast({ title: r?.msg || '删除失败', icon: 'none' })
}
}
}
})
}
const formatDate = (s) => s?.replace(/T.*/, '') || ''
</script>
<style lang="scss" scoped>
.orders-container {
min-height: 100vh;
background: linear-gradient(135deg, #FFE4E1 0%, #F3E8FF 50%, #E6E6FA 100%);
padding-bottom: 40rpx;
}
.summary { padding: 20rpx 24rpx; color: #666; }
.calendar-box { margin: 0 16rpx 20rpx; background: #fff; border-radius: 16rpx; overflow: hidden; box-shadow: 0 6rpx 18rpx rgba(140,82,255,.08); }
.orders-list { padding: 0 20rpx; }
.order-card {
background: #fff; border-radius: 16rpx; padding: 16rpx; box-shadow: 0 6rpx 18rpx rgba(0,0,0,.05); margin: 16rpx 0;
.card-header { display:flex; align-items:center; justify-content:space-between; padding-bottom: 12rpx; border-bottom: 1rpx solid #f0f0f0; }
.order-date { color:#666; font-size: 26rpx; }
.card-actions { display:flex; gap: 16rpx; }
.act-btn { display:flex; align-items:center; gap: 6rpx; }
.act-text { color:#999; font-size: 22rpx; }
.grid { display:flex; gap: 16rpx; padding: 14rpx 0; }
.grid-item { text-align:center; }
.grid-thumb { width: 140rpx; height: 140rpx; border-radius: 12rpx; object-fit: cover; }
.grid-name { display:block; margin-top: 8rpx; font-size: 24rpx; color:#333; }
.list { padding: 6rpx 0; }
.list-item { display:flex; align-items:center; padding: 16rpx 0; border-bottom: 1rpx dashed #eee; }
.list-item:last-child { border-bottom: none; }
.list-thumb { width: 120rpx; height: 120rpx; border-radius: 12rpx; margin-right: 14rpx; object-fit: cover; }
.list-info { display:flex; align-items:center; justify-content:space-between; flex:1; }
.name { font-size: 28rpx; color:#333; }
.qty { color:#999; font-size: 24rpx; }
.toggle { text-align:center; padding: 6rpx 0; }
}
.empty { text-align: center; padding: 100rpx 0; color:#aaa; .empty-text{ display:block; margin-top: 12rpx; } }
</style>

View File

@@ -12,10 +12,6 @@
<view class="user-info">
<text class="user-name">{{ userInfo.nickname }}</text>
<text class="user-id">ID: {{ userInfo.userId }}</text>
<view class="user-level">
<uni-icons type="star" size="16" color="#FFD700"></uni-icons>
<text class="level-text">{{ userInfo.level }}</text>
</view>
</view>
<view class="user-actions">
<view class="action-btn" @click="editProfile">
@@ -33,9 +29,9 @@
<view class="function-list">
<view class="function-item" @click="goToMyRecipes">
<view class="function-icon">
<uni-icons type="book" size="14" color="#FF6B9D"></uni-icons>
<uni-icons type="cart" size="24" color="#FF6B9D"></uni-icons>
</view>
<text class="function-name">我的菜谱</text>
<text class="function-name">我的订单</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
<view class="function-item" @click="goToMyDiaries">
@@ -47,67 +43,14 @@
</view>
<view class="function-item" @click="goToMyGoals">
<view class="function-icon">
<uni-icons type="target" size="14" color="#1890ff"></uni-icons>
<uni-icons type="grid" size="24" color="#1890ff"></uni-icons>
</view>
<text class="function-name">我的目标</text>
<text class="function-name">我的模板</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
</view>
</view>
<view class="function-group">
<view class="group-title">设置</view>
<view class="function-list">
<view class="function-item" @click="goToSettings">
<view class="function-icon">
<uni-icons type="setting" size="24" color="#722ed1"></uni-icons>
</view>
<text class="function-name">应用设置</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
<view class="function-item" @click="goToPrivacy">
<view class="function-icon">
<uni-icons type="lock" size="24" color="#fa8c16"></uni-icons>
</view>
<text class="function-name">隐私设置</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
<view class="function-item" @click="goToNotification">
<view class="function-icon">
<uni-icons type="bell" size="24" color="#13c2c2"></uni-icons>
</view>
<text class="function-name">消息通知</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
</view>
</view>
<view class="function-group">
<view class="group-title">其他</view>
<view class="function-list">
<view class="function-item" @click="goToHelp">
<view class="function-icon">
<uni-icons type="question-circle" size="24" color="#eb2f96"></uni-icons>
</view>
<text class="function-name">帮助中心</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
<view class="function-item" @click="goToFeedback">
<view class="function-icon">
<uni-icons type="chat" size="24" color="#fa541c"></uni-icons>
</view>
<text class="function-name">意见反馈</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
<view class="function-item" @click="goToAbout">
<view class="function-icon">
<uni-icons type="info-circle" size="24" color="#2f54eb"></uni-icons>
</view>
<text class="function-name">关于我们</text>
<uni-icons type="right" size="16" color="#ccc"></uni-icons>
</view>
</view>
</view>
</view>
<!-- 退出登录按钮 -->
@@ -305,8 +248,8 @@ const editProfile = () => {
}
const goToMyRecipes = () => {
uni.switchTab({
url: '/pages/recipe/recipe'
uni.navigateTo({
url: '/pages/order/my-orders'
})
}
@@ -452,34 +395,23 @@ onMounted(() => {
}
}
.user-info {
flex: 1;
.user-info {
flex: 1;
margin-left: 20rpx;
.user-name {
display: block;
font-size: 36rpx;
font-weight: bold;
margin-bottom: 10rpx;
}
.user-name {
display: block;
font-size: 36rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.user-id {
display: block;
font-size: 24rpx;
opacity: 0.8;
margin-bottom: 15rpx;
}
.user-level {
display: flex;
align-items: center;
gap: 8rpx;
.level-text {
.user-id {
display: block;
font-size: 24rpx;
opacity: 0.9;
opacity: 0.8;
}
}
}
.user-actions {
.action-btn {