Files
aida_front/src/views/SellerDashboard/MyListings/main/content.vue
X1627315083@163.com d42a1bef8d fix
2026-04-29 14:49:58 +08:00

468 lines
11 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { VueDraggable } from "vue-draggable-plus"
import contentItem from "./contentItem.vue"
import selectMenu from '@/component/modules/selectMenu.vue'
import deleteDrafts from './deleteDrafts.vue'
import { Https } from '@/tool/https'
import { message } from 'ant-design-vue'
import { useRouter } from 'vue-router'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
showDrafts: false,
})
const publishData = reactive({
pageSize: 10,
pageNum: 1,
isShowMark:false,
isNoData:false,
})
const noPublishData = reactive({
pageSize: 10,
pageNum: 1,
isShowMark:false,
isNoData:false,
})
const list = ref([
])
const list2 = ref([
])
const config = ref({
"data-container-type": "root",
"data-parent-id": "null",
animation: 250,
handle: ".item", // 可拖动的元素
"ghost-class": "ghost", // 拖动时的类名
"chosen-class": "chosen", // 选中时的类名
"drag-class": "drag", // 拖动时的类名
"swap-threshold": 0.5,
"empty-insert-threshold": 5,
"force-fallback": false,
"fallback-tolerance": 3,
"scroll-sensitivity": 100,
"scroll-speed": 10,
onEnd: (e) => {}
})
const domSize = ref('Small')
const domSizeList = ref([
{
label:'Small',
value:'Small',
},
{
label:'Medium',
value:'Medium',
},
{
label:'Large',
value:'Large',
},
])
const visible = ref(false)
const deleteDraftsRef = ref(null)
const router = useRouter()
const deleteDraft = (item: any)=>{
deleteDraftsRef.value.open(item,()=>{
putListingStatus(item,2).then(()=>{
list2.value = list2.value.filter((v: any)=>v.id != item.id)
})
})
}
const vObserve = {
mounted (el,binding) {
// console.log(binding.instance);
data.isShowMark = false
data.isNoData = false
let parentDom = el.parentNode
new IntersectionObserver(
(entries, observer) => {
// 如果不是相交,则直接返回
// console.log(entries[0]);
if (!entries[0].intersectionRatio) return;
data.pageNum += 1
binding.value()
},
// { root:worksPage }
).observe(el);
}
}
const getPublishedData = async ()=>{
if(publishData.isShowMark && !publishData.isNoData)return
publishData.isShowMark = true
let value = {
pageSize: publishData.pageSize,
pageNum: publishData.pageNum,
status: 1,
}
await getPublishList(value).then((res)=>{
if(res.content.length == 0)publishData.isNoData = true
publishData.pageNum += 1
list.value.push(...res.content)
})
publishData.isShowMark = false
}
const getNoPublishedData = async ()=>{
if(noPublishData.isShowMark && !noPublishData.isNoData)return
noPublishData.isShowMark = true
let value = {
pageSize: noPublishData.pageSize,
pageNum: noPublishData.pageNum,
status: 0,
}
await getPublishList(value).then((res)=>{
if(res.content.length == 0)noPublishData.isNoData = true
noPublishData.pageNum += 1
list2.value.push(...res.content)
})
noPublishData.isShowMark = false
}
const getPublishList = (data:any)=>{
return new Promise<void>((resolve, reject) => {
Https.axiosGet(Https.httpUrls.getListingList,{params:data}).then((res:any)=>{
resolve(res)
}).catch((err:any)=>{
reject(err)
})
})
}
const putListingStatus = async (item,status:number)=>{
return new Promise<void>((resolve, reject) => {
let data = {
id:item.id,
status:status,
}
Https.axiosPut(Https.httpUrls.putListingStatus,data).then((res:any)=>{
resolve(res)
}).catch((err:any)=>{
reject(err)
})
})
}
const draftListing = async (item: any)=>{
//数组前面添加item
await putListingStatus(item,0).then(()=>{
list2.value.unshift(item)
list.value = list.value.filter((v: any)=>v.id != item.id)
})
message.success('Product moved to drafts and stats reset.')
}
const publishListing = async (item: any)=>{
await putListingStatus(item,1).then(()=>{
list.value.unshift(item)
list2.value = list2.value.filter((v: any)=>v.id != item.id)
})
message.success('Item is now live on the Marketplace.')
}
const editListing = (item: any)=>{
router.push({
path:'/home/seller/myListings/edit',
state: {
id:item.id,
type:'edit'
}
})
}
const listingsBoxRef = ref(null) as any
let resizeObserver = null as any
const gap = ref({
Small: '16px',
Medium: '24px',
Large: '30px',
})
//根据宽度设置列表宽度
let upDataDomWidthTime = null
const setDomSize = (width: number)=>{
if(!listingsBoxRef.value)return
let listDom = listingsBoxRef.value.querySelector('.list')
let listItemDom = listDom.querySelector('.item')
let offsetWidth = listItemDom?.getBoundingClientRect?.()?.width
let lineNum = Math.floor(width / offsetWidth)
let itemNum = Math.floor((width - (lineNum - 1) * parseInt(gap.value[domSize.value])) / offsetWidth)
listDom.style.maxWidth = ((itemNum - 1) * parseInt(gap.value[domSize.value]) + itemNum * (offsetWidth)) + 'px'
}
const changeDomSize = ()=>{
setTimeout(()=>{
setDomSize(listingsBoxRef.value.clientWidth)
},350)
}
const unfoldDrafits = ()=>{
data.showDrafts = !data.showDrafts
}
onMounted(()=>{
// 创建观察器
nextTick(()=>{
resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const width = entry.contentRect.width
if(upDataDomWidthTime)clearTimeout(upDataDomWidthTime)
upDataDomWidthTime = setTimeout(()=>{
setDomSize(width)
},200)
}
})
// 开始监听
if(resizeObserver)resizeObserver.observe(listingsBoxRef.value)
})
})
onUnmounted(()=>{
// 停止监听
if(listingsBoxRef?.value)resizeObserver?.unobserve(listingsBoxRef?.value)
})
defineExpose({})
const { showDrafts } = toRefs(data);
</script>
<template>
<div class="listings">
<div class="listingsBox listingsBox1">
<div class="box" :class="domSize" ref="listingsBoxRef">
<div class="title">
<div class="left">
<i class="fi fi-rs-comments"></i>
<span>Active Listings</span>
</div>
<div class="right">
<div class="generalModel_state">
<div>
<selectMenu
:selectList="domSizeList"
@change="changeDomSize"
:isBtnOpen='true'
:style="{
'border-radius':'0rem',
'border':'none',
'font-weight': '900',
'line-height': '3rem',
'height': '3rem',
'background': 'rgba(0,0,0,0)',
}"
v-model:select="domSize"
>
<template v-slot:btnText>
{{ $t('Header.Size') }}
</template>
</selectMenu>
</div>
</div>
</div>
</div>
<VueDraggable
v-model="list"
class="list"
:style="{gap: gap[domSize] || '1.6rem'}"
v-bind="config"
:group="{
name: 'sortable',
pull: false,
put: true
}"
>
<contentItem
v-for="v in list"
:key="v.id"
:item="v"
type="listings"
:domSize="domSize"
@draftListing="draftListing"
@editListing="editListing"
/>
<div v-show="!publishData.isNoData" class="material_content_list_loding">
<span class="page_loading" v-show="!publishData.isShowMark" v-observe="getPublishedData"></span>
<span v-show="publishData.isShowMark">
<a-spin size="large" />
</span>
</div>
</VueDraggable>
</div>
<div class="openOrCloseDrafts" :class="{'active': showDrafts}" @click="unfoldDrafits">
<span class="icon iconfont icon-xiala"></span>
</div>
</div>
<div class="listingsBox listingsBox2" :class="{'active': showDrafts}">
<div class="box Small">
<div class="title">
<div class="left">
<i class="fi fi-rs-comments"></i>
<span>Drafts</span>
</div>
</div>
<VueDraggable
v-model="list2"
class="list2"
v-bind="config"
:group="{
name: 'sortable',
pull: false,
put: true
}"
>
<contentItem
v-for="v in list2"
:key="v.id"
:item="v"
domSize="Small"
type="drafts"
@deleteDraft="deleteDraft"
@editListing="editListing"
@publishListing="publishListing"
/>
<div v-show="!noPublishData.isNoData" class="material_content_list_loding">
<span class="page_loading" v-show="!noPublishData.isShowMark" v-observe="getNoPublishedData"></span>
<span v-show="noPublishData.isShowMark">
<a-spin size="large" />
</span>
</div>
</VueDraggable>
</div>
</div>
<deleteDrafts ref="deleteDraftsRef" v-model:visible="visible"></deleteDrafts>
</div>
</template>
<style lang="less" scoped>
.listings{
position: absolute;
width: 100%;
height: 100%;
display: flex;
gap: 2rem;
.listingsBox{
background-color: #f9fafa;
border-radius: 2rem;
position: relative;
// overflow: hidden;
display: flex;
transition: all .3s;
.box{
width: 100%;
padding: 2.4rem 0;
padding-bottom: 0;
flex-direction: column;
overflow: hidden;
display: flex;
flex: 1;
padding: 2.4rem 4rem;
> .title{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
> .left{
display: flex;
justify-content: space-between;
align-items: center;
font-family: pingfang_heavy;
font-weight: 400;
font-size: 1.8rem;
line-height: 130%;
letter-spacing: 0%;
gap: 1.2rem;
align-content: flex-start;
> i{
display: flex;
justify-content: space-between;
align-items: center;
font-size: 2.4rem;
}
}
}
.list2{
gap: 1.6rem;
width: 100%;
.item{
width: 19.2rem;
}
}
.list,.list2{
display: flex;
flex-wrap: wrap;
// flex: 1;
margin: 0 auto;
align-items: flex-start;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
> .material_content_list_loding{
width: 100%;
height: 5rem;
aspect-ratio: 1/1;
overflow: hidden;
display: flex;
justify-content: center;
> img{
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
}
}
.listingsBox1{
width: 100%;
flex: 1;
}
.listingsBox2{
width: 48.8rem;
overflow: hidden;
&.active{
width: 0;
}
.box{
width: 48.8rem;
}
}
.openOrCloseDrafts{
position: absolute;
width: 3.4rem;
height: 8rem;
border-top-right-radius: 2rem;
border-bottom-right-radius: 2rem;
border-width: 1.5px, 1.5px, 1.5px, 0px;
border-style: solid;
border-color: #000000;
right: 1.5px;
top: 50%;
transform: translate(100%,-50%);
cursor: pointer;
transition: all 0.3s ease-in-out;
border-left: none;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
z-index: 2;
> span{
transform: rotate(-90deg);
transition: all .3s;
}
&.active{
> span{
transform: rotate(90deg);
}
}
&:hover{
width: 4.5rem;
}
}
}
</style>