1.productService代码如下:
点击查看代码
public async Task<List<ProductDto>> GetProductByProductNos(params string[] postProductNos)
{
var productNoList = postProductNos.Distinct().ToList();
var productNos = ProductRepo.GetList(s => productNoList.Contains(s.ProductNo));
var productDtos = Mapper.Map<List<Product>, List<ProductDto>>(productNos);
var productSales = await GetProductSalesByProductNo(productDtos.Select(s => s.ProductNo).ToArray());
productDtos.ForEach(s =>
{
s.ProductSale = productSales.Where(c => c.ProductNo == s.ProductNo).FirstOrDefault();
});
return productDtos;
}
点击查看代码
<template>
<div>
<div class="cart-list">
<ul>
<li v-for="type in types" :key="type.typeNo">
<p>
<i
:class="{ 'cart-select': type.typeSelected }"
@click="onSelectType(type)"
>√</i
>
<span>{{ transTypeWhenNull(type.typeName) }}</span>
</p>
<template v-for="cart in carts" :key="cart.cartGuid">
<div v-if="cart.productDto?.typeNo == type.typeNo">
<i
:class="{ 'cart-select': cart.cartSelected }"
@click="onSelectCart(cart)"
>√</i
>
<img src="" alt="" />
<p class="p-name">{{ cart.productDto?.productName }}</p>
<p class="p-price">
¥{{ cart.productDto?.productSale?.salePrice ?? 0 }}
</p>
<p class="p-num">
<span class="sub-num" @click="onSubNum(cart)">-</span>
<input v-model="cart.productNum" @change="onChangeNum(cart)" />
<span class="add0num" @click="onAddNum(cart)">+</span>
<b>块</b>
</p>
</div>
</template>
</li>
</ul>
</div>
<div class="total-pad">
<i :class="{ 'cart-select': isAllSelected }">√</i>
<span>全选</span>
<span>
合计:¥ <b>{{ totalPrice }}</b>
</span>
<button>确定下单</button>
</div>
</div>
</template>
<script>
import { reactive, toRefs, onMounted, watch } from 'vue'
import { getCarts } from '@/httpRequests/ShoppingCartRequest'
export default {
// mounted() {
// this.$store.comm
// this.$store.dispatch('setFootMenuIndexAsync', 2)
// },
setup() {
//数据发生改变时,这个方式不能及时获取变化后的数据
//const productNumRef = ref()
const shoppingCartInfo = reactive({
carts: [],
types: [],
isAllSelected: true,
// buyNum: 1,
totalPrice: 0,
onAddNum(cart) {
cart.productNum++
},
onSubNum(cart) {
if (cart.productNum > 1) {
cart.productNum--
}
},
onChangeNum(cart) {
var currNum = event.target.value
if (!isNaN(currNum) && currNum > 0) {
cart.productNum = currNum
} else {
event.target.value = cart.productNum
}
},
/**
* 获取购物车信息
*/
onGetShoppingCarts: async () => {
var customerNo = localStorage['customerNo']
var res = await getCarts(customerNo)
shoppingCartInfo.carts = res.carts
shoppingCartInfo.types = res.types
// console.log(res)
},
/**
* 点击选择购物车时触发
*/
onSelectCart: (cart) => {
cart.cartSelected = !cart.cartSelected
//找到类型中对应设置物品的类型
// var type = shoppingCartInfo.types.filter(
// (m) => m.typeNo == cart.productDto?.typeNo
// )[0]
// var cartsOfType = shoppingCartInfo.carts.filter(
// (s) => s.productDto?.typeNo == type?.typeNo
// )
// shoppingCartInfo.checkTypeSelected()
},
/**
* 检测选择类型时触发
*/
onSelectType: (type) => {
type.typeSelected = !type.typeSelected
shoppingCartInfo.carts
.filter((s) => s.productDto?.typeNo == type?.typeNo)
.forEach((s) => {
s.cartSelected = type.typeSelected
})
// shoppingCartInfo.checkAllSelected()
},
/**
* 检测是否选中某一类下的所有物品
*/
checkTypeSelected: () => {
shoppingCartInfo.types.forEach((type) => {
var cartsOfType = shoppingCartInfo.carts.filter(
(s) => s.productDto?.typeNo == type?.typeNo
)
//查看当前类型下的物品是否都被选择,是则将属于类型选中
//否则不选中
if (cartsOfType.every((m) => m.cartSelected)) {
type.typeSelected = true
} else {
type.typeSelected = false
}
})
shoppingCartInfo.checkAllSelected()
},
/**
* 检测是否选中所有物品时触发
*/
checkAllSelected: () => {
if (shoppingCartInfo.carts.every((m) => m.cartSelected)) {
shoppingCartInfo.isAllSelected = true
} else {
shoppingCartInfo.isAllSelected = false
}
},
/**
* 计算总价
*/
calcTotalPrice: () => {
shoppingCartInfo.totalPrice = 0
shoppingCartInfo.carts
.filter((m) => m.cartSelected == true)
.forEach((c) => {
var singlePrice = c.productDto?.productSale?.salePrice ?? 0
shoppingCartInfo.totalPrice += singlePrice * c.productNum
})
},
transTypeWhenNull: (typeName) => typeName ?? '未分类产品',
})
/**
* 对carts进行深度监听
*/
watch(
() => shoppingCartInfo.carts,
(newValue, oldValue) => {
shoppingCartInfo.checkTypeSelected()
shoppingCartInfo.calcTotalPrice()
//
},
{
//是否深度监听,一般监听对象或者数组,咱都需要深度监听
deep: true,
}
)
/**
* 页面加载时触发
*/
onMounted(() => {
shoppingCartInfo.onGetShoppingCarts()
shoppingCartInfo.checkTypeSelected()
shoppingCartInfo.calcTotalPrice()
})
return { ...toRefs(shoppingCartInfo) }
},
}
</script>
<style lang="scss" scoped>
.cart-list {
text-align: left;
ul {
margin-bottom: 108px;
li {
background-color: #fff;
margin-bottom: 12px;
> p {
padding-left: 46px;
position: relative;
height: 46px;
border-bottom: 1px solid #ddd;
i {
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
position: absolute;
left: 13px;
top: 13px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
span {
display: inline-block;
border-left: 3px solid crimson;
height: 28px;
margin: 9px 0;
padding-left: 8px;
line-height: 30px;
}
}
div {
padding-left: 46px;
position: relative;
height: 98px;
padding: 8px 14px 8px 148px;
i {
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
position: absolute;
left: 13px;
top: 28px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
img {
68px;
height: 68px;
background-color: #ccc;
position: absolute;
left: 58px;
top: 20px;
}
p.p-name {
font-size: 13px;
margin-top: 10px;
height: 30px;
}
p.p-price {
font-size: 13px;
height: 20px;
color: crimson;
}
p.p-num {
text-align: right;
padding-right: 20px;
span {
display: inline-block;
18px;
height: 18px;
border: 1px solid crimson;
color: crimson;
border-radius: 9px;
text-align: center;
line-height: 18px;
}
input {
28px;
border: none 0px;
outline: none;
text-align: center;
}
b {
font-weight: normal;
margin-left: 10px;
font-size: 13px;
}
}
}
}
}
}
.total-pad {
height: 58px;
100%;
background-color: #383838;
position: fixed;
left: 0;
bottom: 40px;
i {
display: inline-block;
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
background-color: #fff;
margin-left: 13px;
margin-top: 20px;
vertical-align: bottom;
height: 18px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
span {
color: #fff;
margin-left: 6px;
font-size: 13px;
b {
font-size: 15px;
}
}
button {
float: right;
height: 58px;
120px;
border: 0 none;
background-color: #ddd;
color: #aaa;
font-size: 15px;
font-weight: bold;
}
}
</style>
点击查看代码
/// <summary>
/// 指定更新某个字段
/// </summary>
/// <param name="cartGuid"></param>
/// <param name="cartSelected"></param>
/// <returns></returns>
public async Task<bool> UpdateCartSelected(ShoppingCartSelectedEditDto dto)
{
//EFcore部分更新
try
{
ShoppingCart cart = new()
{
CartGuid = dto.CartGuid,
CartSelected = dto.CartSelected
};
Context.Attach(cart);
Context.Entry(cart).Property(m => m.CartSelected).IsModified = true;
return (await Context.SaveChangesAsync()) > 0;
}
catch (System.Exception)
{
return false;
throw;
}
}
4.修改部分更新的接口,为了让它更新多行数据,多次savechange会影响性能
点击查看代码
/// <summary>
/// 指定更新某个字段
/// </summary>
/// <param name="cartGuid"></param>
/// <param name="cartSelected"></param>
/// <returns></returns>
public async Task<bool> UpdateCartSelected(ShoppingCartSelectedEditDto dto)
{
//EFcore部分更新
try
{
foreach (var cartGuid in dto.CartGuids)
{
ShoppingCart cart = new()
{
CartGuid = cartGuid,
CartSelected = dto.CartSelected
};
Context.Attach(cart);
Context.Entry(cart).Property(m => m.CartSelected).IsModified = true;
}
return (await Context.SaveChangesAsync()) > 0;
}
catch (System.Exception)
{
return false;
throw;
}
}
点击查看代码
<template>
<div>
<div class="cart-list">
<ul>
<li v-for="type in types" :key="type.typeNo">
<p>
<i
:class="{ 'cart-select': type.typeSelected }"
@click="onSelectType(type)"
>√</i
>
<span>{{ transTypeWhenNull(type.typeName) }}</span>
</p>
<template v-for="cart in carts" :key="cart.cartGuid">
<div v-if="cart.productDto?.typeNo == type.typeNo">
<i
:class="{ 'cart-select': cart.cartSelected }"
@click="onSelectCart(cart)"
>√</i
>
<img src="" alt="" />
<p class="p-name">{{ cart.productDto?.productName }}</p>
<p class="p-price">
¥{{ cart.productDto?.productSale?.salePrice ?? 0 }}
</p>
<p class="p-num">
<span class="sub-num" @click="onSubNum(cart)">-</span>
<input v-model="cart.productNum" @change="onChangeNum(cart)" />
<span class="add0num" @click="onAddNum(cart)">+</span>
<b>块</b>
</p>
</div>
</template>
</li>
</ul>
</div>
<div class="total-pad">
<i :class="{ 'cart-select': isAllSelected }">√</i>
<span>全选</span>
<span>
合计:¥ <b>{{ totalPrice }}</b>
</span>
<button>确定下单</button>
</div>
</div>
</template>
<script>
import { reactive, toRefs, onMounted, watch } from 'vue'
import { getCarts, updateCartSelect } from '@/httpRequests/ShoppingCartRequest'
export default {
// mounted() {
// this.$store.comm
// this.$store.dispatch('setFootMenuIndexAsync', 2)
// },
setup() {
//数据发生改变时,这个方式不能及时获取变化后的数据
//const productNumRef = ref()
const shoppingCartInfo = reactive({
carts: [],
types: [],
isAllSelected: true,
// buyNum: 1,
totalPrice: 0,
onAddNum(cart) {
cart.productNum++
},
onSubNum(cart) {
if (cart.productNum > 1) {
cart.productNum--
}
},
onChangeNum(cart) {
var currNum = event.target.value
if (!isNaN(currNum) && currNum > 0) {
cart.productNum = currNum
} else {
event.target.value = cart.productNum
}
},
/**
* 获取购物车信息
*/
onGetShoppingCarts: async () => {
var customerNo = localStorage['customerNo']
var res = await getCarts(customerNo)
shoppingCartInfo.carts = res.carts
shoppingCartInfo.types = res.types
// console.log(res)
},
/**
* 点击选择购物车时触发
*/
onSelectCart: (cart) => {
cart.cartSelected = !cart.cartSelected
var cartGuids = []
cartGuids.push(cart.cartGuid)
updateCartSelect(cartGuids, cart.cartSelected)
//找到类型中对应设置物品的类型
// var type = shoppingCartInfo.types.filter(
// (m) => m.typeNo == cart.productDto?.typeNo
// )[0]
// var cartsOfType = shoppingCartInfo.carts.filter(
// (s) => s.productDto?.typeNo == type?.typeNo
// )
// shoppingCartInfo.checkTypeSelected()
},
/**
* 检测选择类型时触发
*/
onSelectType: (type) => {
var cartGuids = []
type.typeSelected = !type.typeSelected
shoppingCartInfo.carts
.filter((s) => s.productDto?.typeNo == type?.typeNo)
.forEach((s) => {
cartGuids.push(s.cartGuid)
s.cartSelected = type.typeSelected
})
updateCartSelect(cartGuids, type.typeSelected)
// shoppingCartInfo.checkAllSelected()
},
/**
* 检测是否选中某一类下的所有物品
*/
checkTypeSelected: () => {
shoppingCartInfo.types.forEach((type) => {
var cartsOfType = shoppingCartInfo.carts.filter(
(s) => s.productDto?.typeNo == type?.typeNo
)
//查看当前类型下的物品是否都被选择,是则将属于类型选中
//否则不选中
if (cartsOfType.every((m) => m.cartSelected)) {
type.typeSelected = true
} else {
type.typeSelected = false
}
})
shoppingCartInfo.checkAllSelected()
},
/**
* 检测是否选中所有物品时触发
*/
checkAllSelected: () => {
if (shoppingCartInfo.carts.every((m) => m.cartSelected)) {
var cartGuids = []
shoppingCartInfo.isAllSelected = true
shoppingCartInfo.carts.filter((s) => {
cartGuids.push(s.cartGuid)
})
updateCartSelect(cartGuids, true)
} else {
shoppingCartInfo.isAllSelected = false
}
},
/**
* 计算总价
*/
calcTotalPrice: () => {
shoppingCartInfo.totalPrice = 0
shoppingCartInfo.carts
.filter((m) => m.cartSelected == true)
.forEach((c) => {
var singlePrice = c.productDto?.productSale?.salePrice ?? 0
shoppingCartInfo.totalPrice += singlePrice * c.productNum
})
},
transTypeWhenNull: (typeName) => typeName ?? '未分类产品',
})
/**
* 对carts进行深度监听
*/
watch(
() => shoppingCartInfo.carts,
(newValue, oldValue) => {
shoppingCartInfo.checkTypeSelected()
shoppingCartInfo.calcTotalPrice()
//
},
{
//是否深度监听,一般监听对象或者数组,咱都需要深度监听
deep: true,
}
)
/**
* 页面加载时触发
*/
onMounted(() => {
shoppingCartInfo.onGetShoppingCarts()
shoppingCartInfo.checkTypeSelected()
shoppingCartInfo.calcTotalPrice()
})
return { ...toRefs(shoppingCartInfo) }
},
}
</script>
<style lang="scss" scoped>
.cart-list {
text-align: left;
ul {
margin-bottom: 108px;
li {
background-color: #fff;
margin-bottom: 12px;
> p {
padding-left: 46px;
position: relative;
height: 46px;
border-bottom: 1px solid #ddd;
i {
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
position: absolute;
left: 13px;
top: 13px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
span {
display: inline-block;
border-left: 3px solid crimson;
height: 28px;
margin: 9px 0;
padding-left: 8px;
line-height: 30px;
}
}
div {
padding-left: 46px;
position: relative;
height: 98px;
padding: 8px 14px 8px 148px;
i {
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
position: absolute;
left: 13px;
top: 28px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
img {
68px;
height: 68px;
background-color: #ccc;
position: absolute;
left: 58px;
top: 20px;
}
p.p-name {
font-size: 13px;
margin-top: 10px;
height: 30px;
}
p.p-price {
font-size: 13px;
height: 20px;
color: crimson;
}
p.p-num {
text-align: right;
padding-right: 20px;
span {
display: inline-block;
18px;
height: 18px;
border: 1px solid crimson;
color: crimson;
border-radius: 9px;
text-align: center;
line-height: 18px;
}
input {
28px;
border: none 0px;
outline: none;
text-align: center;
}
b {
font-weight: normal;
margin-left: 10px;
font-size: 13px;
}
}
}
}
}
}
.total-pad {
height: 58px;
100%;
background-color: #383838;
position: fixed;
left: 0;
bottom: 40px;
i {
display: inline-block;
border: 1px solid #a9a9a9;
18px;
height: 18px;
line-height: 18px;
border-radius: 18px;
background-color: #fff;
margin-left: 13px;
margin-top: 20px;
vertical-align: bottom;
height: 18px;
text-align: center;
font-size: 12px;
color: #fff;
font-style: normal;
}
i.cart-select {
background-color: crimson;
border: 1px solid crimson;
}
span {
color: #fff;
margin-left: 6px;
font-size: 13px;
b {
font-size: 15px;
}
}
button {
float: right;
height: 58px;
120px;
border: 0 none;
background-color: #ddd;
color: #aaa;
font-size: 15px;
font-weight: bold;
}
}
</style>
6.计算购物车数量
点击查看代码
/// <summary>
/// 获取购物车数量
/// </summary>
/// <param name="customerNo"></param>
/// <returns></returns>
public async Task<int> GetShoppingCartNum(string customerNo)
{
var carts = await CartRepo.GetListAsync(s => s.CustomerNo == customerNo && s.CartSelected);
var currentCartNum = 0;
carts.ForEach(c =>
{
currentCartNum += c.ProductNum;
});
return currentCartNum;
}
7.main.vue代码如下:
点击查看代码
<template>
<div>
<div class="user-box">
<div class="user-info">
<div class="user-head">
<img src="/img/dealerImgs/picUser.png" alt="" class="" />
</div>
<p class="user-name">安徽安庆王跃争</p>
<p>销售员:菜菜</p>
<p>单位地址:安庆市光彩大市场四期C区</p>
</div>
</div>
<div class="menu-item">
<img src="/img/dealerImgs/purchase_order.png" alt="" />
<div class="menu-info">
<p class="m-title">我的订单</p>
<p class="m-info">未完成的订单:8个</p>
</div>
</div>
<div class="menu-item">
<img src="/img/dealerImgs/shopping212.png" alt="" />
<div class="menu-info">
<p class="m-title">购物车</p>
<p class="m-info">购物车中有:{{ shoppingCartNum }}个待下单的物品</p>
</div>
</div>
<div class="menu-item">
<img src="/img/dealerImgs/door.png" alt="" />
<div class="menu-info">
<p class="m-title">退出账号</p>
<p class="m-info">退出当前帐号</p>
</div>
</div>
</div>
</template>
<script>
import { getCartNum } from '../httpRequests/mainRequest'
import { shoppingCartNum } from '@/store'
import { onMounted } from 'vue'
export default {
setup() {
const onGetCartNum = async () => {
var customerNo = localStorage['customerNo']
shoppingCartNum.value = await getCartNum(customerNo)
}
onMounted(async () => {
await onGetCartNum()
})
return { shoppingCartNum }
},
}
</script>
<style lang="scss" scoped>
body {
background-color: #ccc;
}
.user-box {
padding: 10px;
background-color: #fff;
.user-info {
padding: 25px 0 25px 80px;
height: 100px;
border-radius: 10px;
position: relative;
background: -webkit-linear-gradient(left, #b70101, #f20505);
p {
color: #fff;
text-align: left;
font-size: 14px;
margin-bottom: 16px;
color: hsla(0, 0%, 100%, 0.7);
}
p.user-name {
letter-spacing: 2px;
font-weight: bold;
font-size: 16px;
color: #fff;
}
.user-head {
40px;
height: 40px;
border-radius: 40px;
border: 2px solid #fff;
overflow: hidden;
background-color: #fff;
position: absolute;
top: 36px;
left: 20px;
img {
40px;
height: 40px;
}
}
}
}
.menu-item {
text-align-last: left;
height: 60px;
background-color: #fff;
margin-top: 10px;
padding: 6px;
position: relative;
padding-left: 60px;
img {
position: absolute;
top: 20px;
left: 20px;
}
.menu-info {
p.m-title {
margin-top: 10px;
font-weight: bold;
font-size: 15px;
}
p.m-info {
margin-top: 8px;
font-size: 12px;
}
}
}
</style>