update
This commit is contained in:
parent
a9dea3af14
commit
0fbd474799
4
App.vue
4
App.vue
@ -26,4 +26,8 @@
|
||||
.justify-between{
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
img,image{
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
100
components/AddToCart.vue
Normal file
100
components/AddToCart.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<view class="bottom-control">
|
||||
<view class="cart flex-center">
|
||||
<text class="iconfont icon-Buy cart-icon"></text>
|
||||
<text class="cart-price">{{(carts.price/100).toFixed(2)}}元</text>
|
||||
</view>
|
||||
<view class="add-to-cart" @click="addFoodToCart">
|
||||
<text>加入购物车</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, onMounted, ref } from "vue";
|
||||
import { addToCart, cartList } from "../service/api";
|
||||
defineComponent({ name: "AddToCart" })
|
||||
const props = defineProps<{ id : any }>()
|
||||
const carts = ref({
|
||||
price: 0,
|
||||
count: 0
|
||||
})
|
||||
const loadCartList = () => {
|
||||
cartList().then((list) => {
|
||||
let count = 0, price = 0;
|
||||
list.forEach(c => {
|
||||
count += c.count;
|
||||
price += c.count * c.foodPrice
|
||||
})
|
||||
carts.value = {
|
||||
count,
|
||||
price,
|
||||
}
|
||||
})
|
||||
}
|
||||
onMounted(loadCartList)
|
||||
function addFoodToCart(){
|
||||
if(props.id){
|
||||
addToCart(props.id).then(loadCartList).catch(()=>{
|
||||
uni.showToast({
|
||||
title: '加入购物车失败'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$bottom-height: 44px;
|
||||
|
||||
.bottom-control {
|
||||
position: fixed;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
bottom: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
border-radius: 40px;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
||||
line-height: $bottom-height;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.add-to-cart {}
|
||||
|
||||
.add-to-cart {
|
||||
background-color: $uni-color-primary;
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
color: #fff;
|
||||
border-radius: $bottom-height;
|
||||
height: $bottom-height;
|
||||
transform: translateX(1px);
|
||||
box-sizing: border-box;
|
||||
|
||||
&:active {
|
||||
background-color: $uni-color-primary-1;
|
||||
}
|
||||
}
|
||||
|
||||
.cart {
|
||||
height: $bottom-height;
|
||||
color: $uni-color-primary;
|
||||
border-radius: $bottom-height;
|
||||
padding: 0 20px;
|
||||
|
||||
&:active {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-icon {
|
||||
font-size: 28px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.cart-price {}
|
||||
</style>
|
52
components/CustNavBar/CustNavBar.vue
Normal file
52
components/CustNavBar/CustNavBar.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<view class="title-bar flex-center">
|
||||
<view class="back" @click="back">
|
||||
<text class="iconfont icon-packup"></text>
|
||||
</view>
|
||||
<view class="content"><slot></slot></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CustNavBar",
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods:{
|
||||
back(){
|
||||
uni.navigateBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.title-bar{
|
||||
position: fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
padding:10px;
|
||||
z-index: 2;
|
||||
}
|
||||
.back{
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 40px;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
}
|
||||
.icon-packup{
|
||||
transform: rotate(-90deg);
|
||||
font-size: 20px;
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
top:-1px
|
||||
}
|
||||
.content{
|
||||
flex:1;
|
||||
}
|
||||
</style>
|
5
components/index.ts
Normal file
5
components/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import AddToCart from './AddToCart.vue';
|
||||
|
||||
export {
|
||||
AddToCart
|
||||
}
|
47
pages.json
47
pages.json
@ -3,6 +3,9 @@
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"path": "pages/order/index",
|
||||
@ -16,26 +19,32 @@
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "pages/index/search",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "pages/index/detail",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "pages/index/category",
|
||||
"style": {
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
,{
|
||||
"path" : "pages/index/search",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}
|
||||
,{
|
||||
"path" : "pages/index/detail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "我爱外卖",
|
||||
|
94
pages/index/category.vue
Normal file
94
pages/index/category.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<view class="page-category">
|
||||
<view class="my-nav">
|
||||
<CustNavBar>
|
||||
<view class="search-input-container">
|
||||
<view class="search-inut">搜索 鱼香肉丝 试试</view>
|
||||
</view>
|
||||
</CustNavBar>
|
||||
</view>
|
||||
<view class="category-list-container">
|
||||
<view class="left-category">
|
||||
<view class="category-item" v-for="c in categorys"
|
||||
:class="{active:c.id == activeCategory}" :key="c.id"
|
||||
@click="loadListByCid(c.id)">
|
||||
<text>{{c.title}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="foods-list-container">
|
||||
<FoodsList v-if="foodsList" :foodsList="foodsList"></FoodsList>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { allCategories, loadCategoryGoods } from "../../service/api";
|
||||
import { CategoryModel } from "../../service/models";
|
||||
|
||||
const foodsList = ref([])
|
||||
const categorys = ref<CategoryModel[]>([])
|
||||
const activeCategory = ref(0)
|
||||
allCategories().then(list => {
|
||||
categorys.value = list
|
||||
})
|
||||
function loadListByCid(cid: number){
|
||||
activeCategory.value = cid
|
||||
loadCategoryGoods(cid).then(list=>{
|
||||
foodsList.value = list;
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-category {
|
||||
min-height: 100vh;
|
||||
|
||||
.my-nav {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.search-input-container {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.search-inut {
|
||||
border: solid 1px $uni-color-primary;
|
||||
width: 100%;
|
||||
border-radius: 30px;
|
||||
box-sizing: border-box;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.category-list-container {
|
||||
height: calc(100vh - 50px);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.left-category {
|
||||
height: 100%;
|
||||
background-color: #eee;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
padding: 10px 0;
|
||||
&.active{
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.foods-list-container{
|
||||
flex:1;
|
||||
overflow-y: auto;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,27 +1,32 @@
|
||||
<template>
|
||||
<view class="page-detail" v-if="f">
|
||||
<view class="foods-cover">
|
||||
<image class="cover" :src="f.cover" mode=""></image>
|
||||
</view>
|
||||
<view class="foods-name">
|
||||
<text>{{f.title}}</text>
|
||||
</view>
|
||||
<view class="sale-count">
|
||||
<text>{{f.saleCount}}</text>
|
||||
</view>
|
||||
<view class="sale-control">
|
||||
<view class="sale-price">
|
||||
<text class="price">{{f.price}}</text>
|
||||
<text class="coupon">{{f.coupon}}</text>
|
||||
<CustNavBar></CustNavBar>
|
||||
<view class="foods-basic">
|
||||
<view class="foods-cover">
|
||||
<image class="cover" :src="f.cover" mode=""></image>
|
||||
</view>
|
||||
<view class="add-to-cart">
|
||||
<text class="iconfont icon-add"></text>
|
||||
<text>加入购物车</text>
|
||||
<view class="foods-info-wrapper">
|
||||
<view class="foods-name">
|
||||
<text>{{f.title}}</text>
|
||||
</view>
|
||||
<view class="sale-control flex-center justify-between">
|
||||
<view class="sale-count">
|
||||
<text>销量{{f.saleCount}} </text>
|
||||
</view>
|
||||
<view class="sale-price">
|
||||
<text class="unit">¥</text>
|
||||
<text
|
||||
class="price">{{f.coupon ? (((f.price+f.coupon)/100).toFixed(2)) : (f.price/100).toFixed(2)}}</text>
|
||||
<text v-if="f.coupon && f.coupon != 0" class="coupon-price">{{(f.price/100).toFixed(2)}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="coupon-info">
|
||||
{{f.couponDesc}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="foods-detail-content" v-html="f.content">
|
||||
|
||||
</view>
|
||||
<view class="foods-detail-content" v-html="f.content"></view>
|
||||
<AddToCart :id="id || 0" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -29,26 +34,97 @@
|
||||
import { foodsDetail } from '../../service/api';
|
||||
import { ref } from "vue";
|
||||
import { FoodsModel } from '../../service/models';
|
||||
import { AddToCart } from '../../components'
|
||||
const props = defineProps<{
|
||||
id : any
|
||||
id ?: any
|
||||
}>();
|
||||
const f = ref<FoodsModel>()
|
||||
foodsDetail(props.id).then((foods) => {
|
||||
foodsDetail(Number(props.id || 1)).then((foods) => {
|
||||
uni.setNavigationBarTitle({
|
||||
title: foods.title
|
||||
})
|
||||
f.value = foods
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-detail{
|
||||
img,image,umi-image{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.foods-cover{
|
||||
.cover{
|
||||
display: block;
|
||||
width: 100%;
|
||||
.page-detail {
|
||||
background-color: $uni-color-primary;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 10px;
|
||||
|
||||
img,
|
||||
image,
|
||||
umi-image {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.foods-basic {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.foods-cover {
|
||||
.cover {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 340px;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-info {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.foods-info-wrapper {
|
||||
padding: 15px;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
bottom: -60px;
|
||||
}
|
||||
|
||||
.foods-detail-content {
|
||||
background-color: #fff;
|
||||
margin: 80px 20px 20px;
|
||||
border-radius: 10px;
|
||||
padding: 15px 15px 50px;
|
||||
}
|
||||
|
||||
.foods-name {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.sale-count {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.sale-price {
|
||||
.unit {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 18px;
|
||||
color: $uni-color-primary;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
@ -20,7 +20,7 @@
|
||||
<view class="title">{{c.id}}{{c.title}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<FoodsList :foodsList="foodsList"></FoodsList>
|
||||
<FoodsList v-if="foodsList" :foodsList="foodsList"></FoodsList>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -50,20 +50,16 @@
|
||||
}
|
||||
})
|
||||
|
||||
function loadFoodByCid(cid) {
|
||||
uni.request({
|
||||
url: API_URL + '/api/food/category/' + cid,
|
||||
success(ret) {
|
||||
foodsList.value = ret.data.data
|
||||
// console.log(ret.data.data)
|
||||
}
|
||||
function loadFoodByCid(cid : any) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/index/category?cid=${cid}`
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function showSearchPage(){
|
||||
|
||||
function showSearchPage() {
|
||||
uni.navigateTo({
|
||||
url:'/pages/index/search'
|
||||
url: '/pages/index/search'
|
||||
})
|
||||
}
|
||||
|
||||
@ -148,9 +144,8 @@
|
||||
box-sizing: border-box;
|
||||
|
||||
image {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
@ -1,4 +1,4 @@
|
||||
import { FoodsModel, ResponseModel } from "./models"
|
||||
import { CartModel, CategoryModel, FoodsModel, ResponseModel } from "./models"
|
||||
|
||||
export const API_URL = 'http://localhost:8080'
|
||||
function request<T>(url : string, method : 'GET' | 'POST' = 'GET', data : any = null) {
|
||||
@ -32,11 +32,19 @@ function request<T>(url : string, method : 'GET' | 'POST' = 'GET', data : any =
|
||||
}
|
||||
export function foodsDetail(id : any) {
|
||||
return request<FoodsModel>(`/api/food/${id}`)
|
||||
// uni.request({
|
||||
// url: API_URL + '/api/food/recommend',
|
||||
// success(ret) {
|
||||
// foodsList.value = ret.data.data
|
||||
// // console.log(ret.data.data)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
export function addToCart(fid : any, count = 1) {
|
||||
return request(`/api/carts`, 'POST', {
|
||||
fid, count
|
||||
})
|
||||
}
|
||||
export function cartList() {
|
||||
return request<CartModel[]>(`/api/carts/list`)
|
||||
}
|
||||
|
||||
export function allCategories() {
|
||||
return request<CategoryModel[]>(`/api/category`);
|
||||
}
|
||||
export function loadCategoryGoods(cid : any) {
|
||||
return request<FoodsModel[]>(`/api/food/category/${cid}`);
|
||||
}
|
@ -29,4 +29,31 @@ export type FoodsModel = {
|
||||
recommendEndTime ?: any;
|
||||
saleCount : number;
|
||||
state : number;
|
||||
}
|
||||
export interface CartModel {
|
||||
createBy?: any;
|
||||
createTime: string;
|
||||
updateBy?: any;
|
||||
updateTime?: any;
|
||||
remark?: any;
|
||||
fid: number;
|
||||
uid: number;
|
||||
foodsCover: string;
|
||||
foodsTitle: string;
|
||||
foodPrice: number;
|
||||
count: number;
|
||||
state: number;
|
||||
}
|
||||
|
||||
export interface CategoryModel {
|
||||
createBy?: any;
|
||||
createTime: string;
|
||||
updateBy?: any;
|
||||
updateTime: string;
|
||||
remark?: any;
|
||||
id: number;
|
||||
title: string;
|
||||
sort: number;
|
||||
cover: string;
|
||||
state: number;
|
||||
}
|
5
uni.scss
5
uni.scss
@ -16,6 +16,7 @@
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #ff5801;
|
||||
$uni-color-primary-1: #ff4203;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
@ -74,7 +75,3 @@ $uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
||||
|
||||
img,image{
|
||||
max-width: 100%;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user