527 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<common current-name="agricultural">
<template #main>
<div class="my-shoping-car-warp">
<userHeader :title="'我的购物车 (' + total + ')'"></userHeader>
<div class="page-content-warp">
<div class="fix-top">
<div class="do-all" @click="toCheckAll">
<div class="do-all-pos">
<ischeck :value="isAll"></ischeck>
<span class="all-txt">全选</span>
</div>
</div>
<div class="batch-del" @click="doBatchDel">
<el-icon><Delete /></el-icon>
<span class="del-txt">批量删除</span>
</div>
</div>
<div class="conetnt-warp">
<div class="content-item-warp">
<div v-for="(n, index) in datalist" :key="index" class="content-item">
<div class="shop-info" @click="toCheckShop(index)">
<div class="shop-do">
<ischeck :value="n.ischeck"></ischeck>
</div>
<div class="shop-img">
<costomImg
:url="'images/ecommerce/' + 'pic.png'"
:preview-list="[getAssetsFile('images/ecommerce/' + 'pic.png')?.href ?? '']"
:is-view="false"
></costomImg>
</div>
<span class="shop-name txt-ellipsis clamp2">{{ n.shop }}</span>
</div>
<div v-if="n.goodlist && n.goodlist.length > 0" class="good-list">
<div v-for="(g, indexg) in n.goodlist" :key="indexg" class="good-item">
<div class="good-do" @click="toCheckGood(index, indexg)">
<div class="good-do-pos">
<ischeck :value="g.ischeck" size="24px"></ischeck>
</div>
</div>
<div class="good-img" @click="toCheckGood(index, indexg)">
<costomImg
:url="'images/ecommerce/' + 'pic.png'"
:preview-list="[getAssetsFile('images/ecommerce/' + 'pic.png')?.href ?? '']"
:is-view="false"
></costomImg>
</div>
<div class="good-info" @click="toCheckGood(index, indexg)">
<div class="good-info-pos">
<div class="txt-ellipsis clamp2">{{ g.title || '--' }}</div>
</div>
</div>
<div class="good-price-num">
<div class="good-price-num-pos">
<div class="price" @click="toCheckGood(index, indexg)">{{ g.price }} / {{ g.unit }}</div>
<div class="total" @click="toCheckGood(index, indexg)">{{ (g.price * g.num).toFixed(2) }}</div>
<div class="num">
<div class="right-item">
<el-input-number v-model="g.num" :min="1">
<template #suffix>
<span>{{ g.unit }}</span>
</template>
</el-input-number>
</div>
</div>
<div class="good-del" @click="doSingleDel(index, indexg)">
<span>删除</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="fix-bottom">
<div class="bottom-total">
<span class="tips">合计</span>
<span class="total">{{ totalAmout.toFixed(2) }}</span>
</div>
<div class="bottom-do">
<el-button :disabled="datalist.length == 0" :type="datalist.length != 0 ? 'primary' : 'info'" @click="toSettlement">结算</el-button>
</div>
</div>
</div>
</div>
</template>
</common>
</div>
</template>
<script setup>
import common from './components/common.vue';
import { ref, reactive, computed } from 'vue';
import { isEmpty, getAssetsFile } from '@/utils';
import { useRoute, useRouter } from 'vue-router';
import userHeader from './components/userHeader.vue';
import ischeck from './components/ischeck.vue';
import costomImg from '@/components/costomImg.vue';
import { useApp } from '@/hooks';
const app = useApp();
const route = useRoute();
const router = useRouter();
let total = ref(99);
let isAll = ref(false);
let datalist = reactive([
{
id: '01',
shop: '银河生态农产品有限公司',
shopimg: '',
ischeck: false,
goodlist: [
{ id: '001', title: '耿马镇 原生态 有机 西红柿', price: 4.9, unit: '份', num: 2, ischeck: false },
{ id: '002', title: '耿马镇 原生态 有机 西蓝花', price: 2.6, unit: '份', num: 100, ischeck: false },
],
},
{
id: '02',
shop: '方立生态农产品有限公司',
shopimg: '',
ischeck: false,
goodlist: [
{ id: '001', title: '勐撒镇 原生态 有机 大白菜', price: 4.9, unit: '/份', num: 2, ischeck: false },
{ id: '002', title: '勐撒镇 原生态 有机 生姜', price: 2.6, unit: '/份', num: 100, ischeck: false },
],
},
{
id: '03',
shop: '佳佳生态农产品有限公司',
shopimg: '',
ischeck: false,
goodlist: [
{ id: '001', title: '勐简镇 原生态 有机 花香蓝莓', price: 4.9, unit: '/份', num: 2, ischeck: false },
{ id: '002', title: '勐简镇 原生态古树茶', price: 2.6, unit: '/份', num: 100, ischeck: false },
],
},
]);
let totalAmout = computed(() => {
let num = 0;
let list = [];
if (datalist && datalist.length > 0) {
list = datalist
.map((m) => {
return m.goodlist;
})
.flat();
// console.info('totalAmout**************', list);
if (list && list.length > 0) {
num = list.reduce((acc, current) => {
return acc + (current.ischeck ? current.price * current.num : 0);
}, 0);
}
}
return num;
});
const toSettlement = () => {
router.push('/sub-operation-service/sureOrder');
};
const toCheckAll = () => {
isAll.value = !isAll.value;
console.info('操作全选', isAll.value);
if (datalist && datalist.length > 0) {
datalist.forEach((m) => {
m.ischeck = isAll.value;
if (m.goodlist && m.goodlist.length > 0) {
m.goodlist = setCheck(m.goodlist, isAll.value);
}
});
}
};
const setCheck = (data, val) => {
let list = [];
if (data && data.length > 0) {
list = data.map((m) => {
return { ...m, ischeck: val };
});
}
return list;
};
const toCheckShop = (index) => {
if (index > -1) {
datalist[index].ischeck = !datalist[index].ischeck;
if (datalist[index].goodlist && datalist[index].goodlist.length > 0) {
datalist[index].goodlist = setCheck(datalist[index].goodlist, datalist[index].ischeck);
}
setIsAll();
}
};
const toCheckGood = (indexP, index) => {
if (indexP > -1 && index > -1) {
let list = datalist[indexP].goodlist;
list[index].ischeck = !list[index].ischeck;
let len = list.length || 0;
let checkNum = list.reduce((acc, current) => {
return acc + (current.ischeck ? 1 : 0);
}, 0);
if (checkNum > 0 && checkNum < len) {
datalist[indexP].ischeck = false;
} else if (checkNum > 0 && checkNum == len) {
datalist[indexP].ischeck = true;
} else {
datalist[indexP].ischeck = false;
}
setIsAll();
}
};
const setIsAll = () => {
let len = datalist.length || 0;
let checkNum = datalist.reduce((acc, current) => {
return acc + (current.ischeck ? 1 : 0);
}, 0);
if (checkNum > 0 && checkNum < len) {
isAll.value = false;
} else if (checkNum > 0 && checkNum == len) {
isAll.value = true;
} else {
isAll.value = false;
}
};
const doSingleDel = (indexP, index) => {
if (indexP > -1 && index > -1) {
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
datalist[indexP].goodlist.splice(index, 1);
})
.catch(() => {});
}
};
//批量删除
const doBatchDel = () => {
// console.log('ischeck', datalist);
const allUnchecked = isAllUnchecked(datalist);
console.log(allUnchecked); // true 或 false
if (allUnchecked) {
app.$message({
message: '请先选择要删除的商品',
type: 'warning',
});
} else {
app
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
// 删除逻辑
const filteredData = removeCheckedItems(datalist);
// console.log(filteredData);
datalist = filteredData;
})
.catch(() => {});
}
};
// 判断是否全部未选中
function isAllUnchecked(data) {
return data.every((item) => {
// 检查当前项的 ischeck 是否为 false
const currentUnchecked = item.ischeck === false;
// 如果有子项 goodlist递归检查子项
const childrenUnchecked = item.goodlist ? item.goodlist.every((child) => child.ischeck === false) : true;
return currentUnchecked && childrenUnchecked;
});
}
//批量删除逻辑
function removeCheckedItems(data) {
return data.filter((item) => {
// 如果父项的 ischeck 为 true直接过滤掉包括所有子项
if (item.ischeck === true) {
return false;
}
// 如果父项的 ischeck 为 false但子项可能存在 ischeck 为 true 的情况
if (item.goodlist) {
item.goodlist = item.goodlist.filter((child) => child.ischeck !== true);
}
return true;
});
}
</script>
<style lang="scss" scoped>
.my-shoping-car-warp {
width: 100%;
.page-content-warp {
position: relative;
overflow: hidden;
margin: 16px 0 0 16px;
width: 100%;
height: calc(100vh - 135px);
border-radius: 16px;
background: $color-fff;
.fix-top,
.fix-bottom {
position: absolute;
left: 0;
z-index: 1;
padding: 16px;
width: 100%;
background: $color-fff;
}
.fix-top {
top: 0;
display: inline-flex;
justify-content: space-between;
.do-all,
.batch-del {
display: inline-block;
vertical-align: middle;
cursor: pointer;
}
.do-all {
display: inline-flex;
flex-direction: column;
justify-content: center;
.all-txt {
display: inline-block;
padding-left: 16px;
font-size: 16px;
vertical-align: middle;
}
}
.batch-del {
padding: 8px 16px;
font-size: 16px;
border: 1px solid $color-333;
border-radius: 16px;
.el-icon {
font-size: 18px;
}
.del-txt,
.el-icon {
display: inline-block;
vertical-align: middle;
}
.del-txt {
padding-left: 16px;
}
}
}
.fix-bottom {
bottom: 0;
display: inline-flex;
justify-content: space-between;
width: 100%;
.bottom-total,
.bottom-do {
display: inline-block;
vertical-align: middle;
}
.bottom-total {
.tips,
.total {
display: inline-block;
vertical-align: middle;
}
.tips {
font-size: 30px;
}
.total {
padding-left: 16px;
font-size: 42px;
color: $color-main;
}
.total::before {
content: '¥';
}
}
.bottom-do {
display: inline-flex;
justify-content: center;
flex-direction: column;
::v-deep() {
.el-button {
display: inline-block !important;
padding: 0 40px !important;
height: 42px !important;
font-size: 18px !important;
line-height: 42px !important;
}
}
}
}
.conetnt-warp {
overflow-y: auto;
padding: 80px 16px 96px;
width: 100%;
height: 100%;
.content-item-warp {
width: 100%;
.content-item {
margin-bottom: 16px;
width: 100%;
cursor: pointer;
.shop-info {
display: inline-flex;
justify-content: flex-start;
width: 100%;
gap: 16px;
.shop-do,
.shop-img,
.shop-name {
display: inline-block;
vertical-align: middle;
}
.shop-img {
display: inline-flex;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 4px;
flex-direction: column;
}
.shop-do {
display: inline-flex;
justify-content: center;
width: 30px;
flex-direction: column;
}
.shop-name {
width: calc(100% - 62px);
font-size: 18px;
text-align: left;
}
}
.good-list {
width: 100%;
.good-item {
display: inline-flex;
justify-content: flex-start;
margin: 8px 0;
padding-left: 16px;
width: 100%;
gap: 16px;
}
.good-do,
.good-img,
.good-info,
.good-price-num {
display: inline-block;
vertical-align: middle;
}
.good-do {
display: inline-flex;
flex-direction: column;
justify-content: center;
.good-do-pos {
}
}
.good-img {
width: 120px;
height: 120px;
}
.good-info {
display: inline-flex;
justify-content: center;
width: 200px;
flex-direction: column;
.good-info-pos {
font-size: 18px;
color: $color-666;
.txt-ellipsis {
text-align: left;
}
}
}
.good-price-num {
display: inline-flex;
justify-content: center;
width: calc(100% - 340px);
flex-direction: column;
.good-price-num-pos {
display: inline-flex;
justify-content: space-around;
gap: 16px;
.price,
.total {
font-size: 20px;
}
.price {
font-weight: 400;
}
.total {
font-weight: 700;
color: $color-main;
}
.total::before {
content: '¥';
}
.good-del {
font-size: 16px;
color: $color-999;
}
}
}
}
}
}
}
}
}
</style>