You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
6.9 KiB
244 lines
6.9 KiB
10 months ago
|
<!--商品列表,收藏商品、我的足迹使用-->
|
||
|
<template>
|
||
|
<div class="productList">
|
||
|
<div v-if="type === 'collect_products'" class="acea-row row-middle mbtom20">
|
||
|
<el-button size="large" round plain @click="isBatch = !isBatch">{{ isBatch ? '批量操作' : '取消' }}</el-button>
|
||
|
<div v-show="!isBatch" class="allSelect">
|
||
|
<div class="checkbox-wrapper">
|
||
|
<label class="well-check acea-row row-middle">
|
||
|
<input type="checkbox" name="" value="" v-model="isAllSelect" />
|
||
|
<i class="icon cursors allIcon" style="top: 11px"></i>
|
||
|
<span class="checkAll fontColor333 fonts14 cursors">全选</span>
|
||
|
</label>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div v-show="!isBatch" class="fontColor333 fonts14 cursors" @click.stop="handleAllCancel">取消收藏</div>
|
||
|
</div>
|
||
|
<div v-loading="loading">
|
||
|
<div v-if="type === 'collect_products'" class="products">
|
||
|
<div v-for="(item, index) in list" :key="index">
|
||
|
<div class="item">
|
||
|
<div v-show="!isBatch" class="smegma b-rd-16px">
|
||
|
<div class="checkbox-wrapper one-checkbox">
|
||
|
<label class="well-check">
|
||
|
<input type="checkbox" name="" value="" v-model="item.checked" />
|
||
|
<span class="icon top-20px cursors oneIcon"></span>
|
||
|
</label>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div v-show="isBatch" class="btn font12 cursors" @click.stop="handleCancel(item.productId)">取消收藏</div>
|
||
|
<el-image class="backImg img" :src="item.image" lazy @click="handlerNuxtLink(item)"></el-image>
|
||
|
<div class="cent" @click="handlerNuxtLink(item)">
|
||
|
<div class="name text-14px text-#333 line2">{{ item.name }}</div>
|
||
|
<div class="price font12 fontColor333">
|
||
|
<span class="oppoSans-M">¥</span><span class="font20 dinProSemiBold">{{ item.price }}</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div v-else>
|
||
|
<div v-for="(item, index) in list" :key="item.id" class="mb-30px">
|
||
|
<div class="text-14px fontColor333 mb-18px text font-500 ml-10px">{{ item.date }}</div>
|
||
|
<div class="products">
|
||
|
<div v-for="(itm, i) in item.list" :key="i" class="item" @click="handlerNuxtLink(itm)">
|
||
|
<el-image class="backImg img" :src="itm.image" lazy :style="{opacity:itm.isShow?'1':'.5'}"></el-image>
|
||
|
<div class="cent">
|
||
|
<div class="name text-14px line2" :class="itm.isShow?'fontColor333':'text-#CCCCCC'">{{ itm.name }}</div>
|
||
|
<div v-if="itm.isShow" class="price font12 fontColor333">
|
||
|
<span class="oppoSans-M">¥</span><span class="font20 dinProSemiBold">{{ itm.price }}</span>
|
||
|
</div>
|
||
|
<div v-else class="fontColor333 text-14px oppoSans-R">商品已下架</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts" setup>
|
||
|
import {addressDelApi, getCollectCancelProApi} from '~/server/userApi'
|
||
|
import { ElButton, Image } from 'element-plus'
|
||
|
import feedback from '@/utils/feedback'
|
||
|
import { linkNavigateTo } from '~/utils/util'
|
||
|
import { ref, toRefs } from 'vue'
|
||
|
const props = defineProps({
|
||
|
//列表数据
|
||
|
list: {
|
||
|
type: Array,
|
||
|
default: [],
|
||
|
},
|
||
|
//用于区分是足迹还是商品收藏,browsing_history足迹,collect_products商品收藏
|
||
|
type: {
|
||
|
type: String,
|
||
|
default: '',
|
||
|
},
|
||
|
})
|
||
|
const { list } = toRefs(props)
|
||
|
const loading = ref(false)
|
||
|
|
||
|
/**
|
||
|
* 地址跳转
|
||
|
*/
|
||
|
const handlerNuxtLink = async (item: any) => {
|
||
|
if(!item.isShow) return
|
||
|
linkNavigateTo(`/product/detail/${item.productId}`, { type: 'normal' })
|
||
|
}
|
||
|
|
||
|
//选中的值,将isAllSelect定义成计算属性
|
||
|
const isAllSelect = computed({
|
||
|
get() {
|
||
|
let flag = list.value.map((item: any) => {
|
||
|
if (!item.checked) {
|
||
|
return false
|
||
|
} else {
|
||
|
return true
|
||
|
}
|
||
|
})
|
||
|
return !flag.includes(false)
|
||
|
},
|
||
|
set(newVal) {
|
||
|
if (newVal) {
|
||
|
list.value.map((value: any, _index, _array) => {
|
||
|
value.checked = true
|
||
|
})
|
||
|
} else {
|
||
|
list.value.map((value: any, _index, _array) => {
|
||
|
value.checked = false
|
||
|
})
|
||
|
}
|
||
|
},
|
||
|
})
|
||
|
|
||
|
//批量操作控制显示隐藏
|
||
|
const isBatch = ref(true)
|
||
|
|
||
|
//全部取消收藏
|
||
|
const handleAllCancel = async () => {
|
||
|
let idArr = [] as any
|
||
|
Object.keys(list.value).forEach((item: any) => {
|
||
|
if (list.value[item].checked) idArr.push(list.value[item].productId)
|
||
|
})
|
||
|
if (idArr.length === 0) return feedback.msgWarning('请至少选择一个商品')
|
||
|
let ids = idArr.join(',')
|
||
|
await onCancel(ids)
|
||
|
}
|
||
|
|
||
|
//单独取消收藏
|
||
|
const handleCancel = async (id: string) => {
|
||
|
await onCancel(id)
|
||
|
}
|
||
|
//取消请求
|
||
|
const onCancel = async (id: string) => {
|
||
|
await feedback.confirm('确认取消收藏吗?')
|
||
|
try {
|
||
|
await getCollectCancelProApi({ ids: id })
|
||
|
feedback.msgSuccess('取消成功')
|
||
|
loading.value = false
|
||
|
emit('handleComplete')
|
||
|
}catch (e) {
|
||
|
loading.value = false
|
||
|
}
|
||
|
}
|
||
|
const emit = defineEmits(['handleComplete'])
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
@import '@/assets/scss/checkbox.scss';
|
||
|
:deep(.el-button){
|
||
|
width: 90px !important;
|
||
|
height: 32px !important;
|
||
|
--el-button-text-color: #333333 !important;
|
||
|
font-size: 14px !important;
|
||
|
}
|
||
|
.allIcon{
|
||
|
width: 18px !important;
|
||
|
height: 18px !important;
|
||
|
}
|
||
|
.oneIcon{
|
||
|
width: 20px !important;
|
||
|
height: 20px !important;
|
||
|
}
|
||
|
.one-checkbox input:checked + .icon{
|
||
|
background-size: 18px 13px !important;
|
||
|
}
|
||
|
.top-20px {
|
||
|
top: 28px !important;
|
||
|
left: 10px !important;
|
||
|
background-color: #fff;
|
||
|
}
|
||
|
.smegma {
|
||
|
background-color: rgba(0, 0, 0, 0.2);
|
||
|
transition: opacity 0.5s ease-in-out;
|
||
|
width: 228px;
|
||
|
height: 100%;
|
||
|
position: absolute;
|
||
|
z-index: 999;
|
||
|
}
|
||
|
.allSelect {
|
||
|
margin-left: 20px;
|
||
|
margin-right: 20px;
|
||
|
position: relative;
|
||
|
.checkAll {
|
||
|
margin-left: 10px;
|
||
|
}
|
||
|
}
|
||
|
.products {
|
||
|
position: relative;
|
||
|
display: grid;
|
||
|
grid-template-columns: repeat(4, 1fr);
|
||
|
grid-row-gap: 16px;
|
||
|
grid-column-gap: 16px;
|
||
|
grid-template-rows: auto;
|
||
|
.item {
|
||
|
width: 228px;
|
||
|
border-radius: 16px;
|
||
|
border: 1px solid #eeeeee;
|
||
|
position: relative;
|
||
|
cursor: pointer;
|
||
|
|
||
|
// opacity: 0;
|
||
|
.btn {
|
||
|
cursor: pointer;
|
||
|
width: 70px;
|
||
|
height: 26px;
|
||
|
background: #000000;
|
||
|
border-radius: 4px 4px 4px 4px;
|
||
|
opacity: 0.5;
|
||
|
position: absolute;
|
||
|
z-index: 1;
|
||
|
text-align: center;
|
||
|
line-height: 26px;
|
||
|
color: #fff;
|
||
|
display: none;
|
||
|
left: 10px;
|
||
|
top: 10px;
|
||
|
}
|
||
|
}
|
||
|
.item:hover .btn {
|
||
|
display: block;
|
||
|
}
|
||
|
.backImg {
|
||
|
width: 227px;
|
||
|
height: 227px;
|
||
|
display: inline-block !important;
|
||
|
border-radius: 16px 16px 0 0;
|
||
|
}
|
||
|
.cent {
|
||
|
margin-top: -4px;
|
||
|
height: 112px;
|
||
|
padding: 15px 20px 20px 20px;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
justify-content: space-between;
|
||
|
}
|
||
|
.price {
|
||
|
span {
|
||
|
font-weight: 600;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</style>
|