brand页面交互调整

This commit is contained in:
X1627315083@163.com
2026-05-11 16:16:59 +08:00
parent 87b071c319
commit b8c844363c
19 changed files with 624 additions and 146 deletions

View File

@@ -0,0 +1,127 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
const props = defineProps({
item:{
type:Object,
default:()=>{},
},
})
const emit = defineEmits([
'viewProfile',
])
const viewProfile = (item) => {
emit('viewProfile', item)
}
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="item">
<div class="left">
<div class="portrait">
<img :src="item.portrait" alt="">
</div>
<div class="info">
<div class="name">{{ item.name }}</div>
<div class="collection">
{{ item.collectionsName }} |
{{ item?.collections?.length || 0 }} Collections
</div>
<div class="view-profile" @click="viewProfile(item)">View Profile</div>
</div>
</div>
<div class="right">
<div class="img-list">
<div class="img-item" v-for="itemImg in item?.collections?.slice(0,5)" :key="item.id">
<img :src="itemImg" alt="">
</div>
</div>
<div class="more">
<div class="icon" v-show="item?.collections?.length > 5">
<svgIcon name="brand-more" size="24" />
</div>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.item{
display: flex;
width: 100%;
height: 14rem;
justify-content: space-between;
border-bottom: 0.5px solid #C4C4C4;
> .left{
display: flex;
.portrait{
width: 8rem;
height: 8rem;
margin-right: 2.4rem;
> img{
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info{
display: flex;
flex-direction: column;
align-items: flex-start;
> .name{
font-family: "KaiseiOpti-Bold";
font-weight: 700;
font-size: 2rem;
line-height: 100%;
}
> .collection{
color: #7B7B7B;
font-family: "KaiseiOpti-Regular";
font-weight: 400;
font-size: 1.2rem;
line-height: 2.3rem;
margin-top: .4rem;
}
> .view-profile{
margin-top: 2.4rem;
border-bottom: 2px solid #585858;
background: #F9F9F9;
font-family: "KaiseiOpti-Regular";
font-weight: 400;
font-size: 1.4rem;
letter-spacing: -0.4px;
line-height: 3.4rem;
padding: 0 2.55rem;
cursor: pointer;
}
}
}
> .right{
display: flex;
> .img-list{
display: flex;
gap: 3.2rem;
> .img-item{
width: 9.2rem;
height: 12rem;
img{
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
> .more{
width: 8rem;
display: flex;
justify-content: center;
align-items: center;
}
}
}
</style>

View File

@@ -1,169 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import img from "@/assets/images/collectionStory/Rectangle.png";
//const props = defineProps({
//})
const emit = defineEmits([
'addShopping'
])
let data = reactive({
})
const list = ref([
{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},{
url: img,
title: "Windswept Burden",
price: "$100.00",
},
])
const type = ref('All')
const addShopping = (item) => {
emit('addShopping', item)
}
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="commodityList">
<div class="header">
<div class="title">
Items
</div>
<div class="menu">
<div :class="{'active': type === 'All'}" @click="type = 'All'">All</div>
<div :class="{'active': type === 'Male'}" @click="type = 'Male'">Male</div>
<div :class="{'active': type === 'Female'}" @click="type = 'Female'">Female</div>
</div>
</div>
<div class="list">
<div class="item" v-for="item in list" :key="item.url">
<CommodityItem :url="item.url" :name="item.title" :price="item.price" @addShopping="addShopping(item)"></CommodityItem>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.commodityList{
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: column;
.header{
position: sticky;
top: 0;
z-index: 2;
background-color: #fff;
.title{
font-family: "KaiseiOpti-Bold";
font-weight: 700;
font-size: 3.6rem;
line-height: 6rem;
color: #121212;
padding: 4rem 0 3.6rem 1.2rem;
}
.menu{
padding: 0 1.2rem;
display: flex;
gap: 2rem;
margin-bottom: 6rem;
> div{
min-width: 6rem;
text-align: center;
font-family: "KaiseiOpti-Bold";
font-weight: 700;
font-size: 1.98rem;
line-height: 100%;
position: relative;
color: #7B7B7B;
cursor: pointer;
&::after{
content: '';
position: absolute;
bottom: -5px;
left: 0;
display: block;
width: 100%;
border-bottom: 1px solid #232323;
display: none;
}
&.active{
color: #232323;
&::after{
display: block;
}
}
}
}
}
.list{
border-top: 0.5px solid #585858;
width: 100%;
flex: 1;
display: grid;
align-content: start;
grid-template-columns: repeat(3, 1fr);
overflow-y: auto;
/* 垂直线(右边框) */
.item{
position: relative;
padding: 1.2rem;
}
.item::before {
content: '';
position: absolute;
right: 0;
top: 0;
height: 100%;
border-right: 0.5px solid #585858;
z-index: 1;
}
/* 水平线(下边框) */
.item::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
border-bottom: 0.5px solid #585858;
z-index: 1;
}
/* 移除最后一列的右边框 */
.item:nth-child(3n)::before {
display: none;
}
}
}
</style>

View File

@@ -1,9 +1,11 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import CommodityList from "./commodity-list.vue";
import MerchantInfo from "./merchant-info.vue";
import { useRouter } from "vue-router";
import myEvent from '@/utils/myEvent'
import scListNull from '@/views/shoppingCart/sc-list-null.vue'
import brandItem from '@/views/brand/brand-item.vue'
import img from '@/assets/images/collectionStory/Rectangle.png'
//const props = defineProps({
//})
//const emit = defineEmits([
@@ -11,12 +13,96 @@ import myEvent from '@/utils/myEvent'
const router = useRouter()
let data = reactive({
})
const addShopping = (item) => {
myEvent.emit('addShopping', item)
const searchBrand = ref('')
const merchantList = ref([
])
const getMerchantData = reactive({
pageSize: 10,
pageNum: 1,
isShowMark:false,
isNoData:false,
})
const list = ref([
' 1',
'Brand 2',
'Brand 3',
'1213123 4',
'Brand 4',
'2222 4',
'B23rand 4',
'Bran112222d 4',
' 4',
])
let changeSearchBrandTime = null
const changeSearchBrand = () => {
clearTimeout(changeSearchBrandTime)
changeSearchBrandTime = setTimeout(()=>{
getMerchantData.pageNum = 1
merchantList.value = []
getMerchantData.isShowMark = false
getMerchantData.isNoData = false
},300)
}
const openDetail = (item) => {
router.push({name: 'digitalDetail', params: {id: item.id}})
const getBrandList = async () => {
if(getMerchantData.isShowMark && !getMerchantData.isNoData)return
getMerchantData.isShowMark = true
let value = {
pageSize: getMerchantData.pageSize,
pageNum: getMerchantData.pageNum,
status: 1,
}
setTimeout(()=>{
if(merchantList.value.length >= 5){
getMerchantData.isNoData = true
merchantList.value = []
return
}
getMerchantData.pageNum += 1
merchantList.value.push({
name:'Roaming Clouds',
portrait: img,
collectionsName:'by Lian Su ',
collections:[
img,img,img,
],
})
getMerchantData.isShowMark = false
},1000)
// await getPublishList(value).then((res)=>{
// if(res.content.length == 0)getMerchantData.isNoData = true
// getMerchantData.pageNum += 1
// list.value.push(...res.content)
// })
}
const vObserve = {
mounted (el,binding) {
getMerchantData.isShowMark = false
getMerchantData.isNoData = false
new IntersectionObserver(
(entries, observer) => {
// 如果不是相交,则直接返回
// console.log(entries[0]);
if (!entries[0].intersectionRatio) return;
getMerchantData.pageNum += 1
binding.value()
},
// { root:worksPage }
).observe(el);
}
}
const deleteHistory = (item) => {
list.value = list.value.filter((i) => i != item)
}
const viewProfile = (item) => {
router.push({
path:'/brand/1',
})
}
onMounted(()=>{
})
onUnmounted(()=>{
@@ -26,15 +112,52 @@ const {} = toRefs(data);
</script>
<template>
<div class="brand">
<div class="header-img">
<div class="header-img" :class="{'active': searchBrand.length > 0}">
<img src="@/assets/images/brand/brandBg.png" alt="">
<div class="text-box">
<div class="title">Brand</div>
<span>Every brand, every story discover who's behind the collections.</span>
</div>
</div>
<div class="content">
<div class="merchant-info">
<MerchantInfo></MerchantInfo>
<div class="input">
<input type="text" v-model="searchBrand" @input="changeSearchBrand" placeholder="Search brand">
<div class="icon">
<SvgIcon name="brand-search" size="32" />
</div>
</div>
<div class="commodity-list">
<CommodityList @addShopping="addShopping" @openDetail="openDetail"></CommodityList>
<div class="merchantList" v-if="searchBrand.length > 0">
<brand-item v-for="item in merchantList" :key="item.name" :item="item" @viewProfile="viewProfile"></brand-item>
<div class="end" v-show="!getMerchantData.isNoData && !getMerchantData.isShowMark">- The End-</div>
<div v-show="!getMerchantData.isNoData" class="material_content_list_loding">
<span class="page_loading" v-show="!getMerchantData.isShowMark" v-observe="getBrandList"></span>
<img v-if="getMerchantData.isShowMark" src="@/assets/images/brand/brandLoading.gif" alt="">
</div>
<div class="merchantListNull" v-if="getMerchantData.isNoData && searchBrand.length > 0">
<sc-list-null
nullImage="brand"
:showButton="false"
title="Brand No Found"
tip="Try using another keywords."
/>
</div>
</div>
<div class="null-input" v-if="searchBrand.length == 0">
<div class="title">
<div class="icon">
<SvgIcon name="brand-time" size="20" />
</div>
<span>Searching History</span>
</div>
<div class="history">
<div v-for="item in list" :key="item" @click.stop="searchBrand = item" class="item">
<span>{{item}}</span>
<div class="icon" @click.stop="deleteHistory(item)">
<SvgIcon name="brand-delete" size="18" />
</div>
</div>
</div>
</div>
</div>
<Footer></Footer>
@@ -46,34 +169,151 @@ const {} = toRefs(data);
height: 100%;
position: relative;
overflow-y: auto;
display: flex;
flex-direction: column;
.header-img{
width: 100%;
position: relative;
height: 34.4rem;
transition: all .3s;
&.active{
height: 14.7rem;
}
>img{
width: 100%;
position: absolute;
bottom: 0;
}
> .text-box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
> .title{
font-family: 'KaiseiOpti-Bold';
font-weight: 700;
font-size: 4rem;
line-height: 2.3rem;
letter-spacing: 0%;
color: #000;
}
> span{
display: block;
margin-top: 2.4rem;
font-family: 'KaiseiOpti-Regular';
font-weight: 400;
font-size: 1.6rem;
line-height: 140%;
}
}
}
.content{
>.content{
display: flex;
height: auto;
align-items: flex-start;
.merchant-info{
width: 40rem;
padding-left: 12.7rem;
padding-right: 2.7rem;
height: var(--app-view-height);
overflow-y: auto;
position: sticky;
top: 0;
&::-webkit-scrollbar{
width: 0;
height: 0;
flex-direction: column;
align-items: center;
flex: 1;
overflow: hidden;
> .input{
width: 66.6rem;
display: flex;
border-bottom: 2px solid #232323;
padding: 1.4rem 1.4rem 1.4rem 2.4rem;
background-color: #f9f9f9;
display: flex;
margin-top: 8rem;
> input{
width: 57.2rem;
line-height: 3.2rem;
padding: 0;
border: none;
font-family: 'KaiseiOpti-Regular';
font-weight: 400;
font-size: 1.6rem;
line-height: 100%;
margin-right: 2.4rem;
background-color: transparent;
outline: none;
}
> .icon{
cursor: pointer;
}
}
.commodity-list{
> .null-input{
margin-top: 8rem;
.title{
display: flex;
justify-content: center;
.icon{
margin-right: 2rem;
}
}
.history{
margin-top: 4rem;
width: 59rem;
display: flex;
flex-wrap: wrap;
justify-content: center;
column-gap: 3.2rem;
row-gap: 1.2rem;
.item{
cursor: pointer;
display: flex;
> span{
font-family: 'KaiseiOpti-Regular';
font-weight: 400;
font-size: 1.4rem;
line-height: 100%;
margin-right: .4rem;
}
}
}
}
> .merchantList{
width: 121.8rem;
margin-top: 6rem;
flex: 1;
border-left: 0.5px solid #585858;
border-right: 0.5px solid #585858;
margin-right: 9rem;
overflow-y: auto;
gap: 3.2rem;
display: flex;
flex-direction: column;
::-webkit-scrollbar{
display: none;
}
.end{
font-family: 'KaiseiOpti-Regular';
font-weight: 400;
font-size: 12px;
line-height: 140%;
height: 7rem;
display: flex;
align-items: center;
justify-content: center;
}
> .material_content_list_loding{
width: 100%;
height: 5rem;
aspect-ratio: 1/1;
overflow: hidden;
display: flex;
flex-shrink: 0;
justify-content: center;
> .page_loading{
width: 5rem;
height: 5rem;
}
> img{
width: 5rem;
height: 5rem;
object-fit: contain;
}
}
> .merchantListNull{
flex: 1;
width: 100%;
}
}
}
}

View File

@@ -1,129 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="merchantInfo">
<div class="profile">
<img src="@/assets/images/collectionStory/Rectangle.png" alt="">
</div>
<div class="info">
<div class="detail">
<div class="name">Lian Su</div>
<div class="title">Roaming Clouds</div>
</div>
<div class="contact">
<div class="title">Contact</div>
<div class="email label">
<div class="icon">
<svg-icon name="brand-email" size="24" />
</div>
<div>lian.su@urieworweoo.com</div>
</div>
<div class="phone label">
<div class="icon">
<svg-icon name="brand-call" size="24" />
</div>
<div>+86 139 4829 7710</div>
</div>
<div class="address label">
<div class="icon">
<svg-icon name="brand-link" size="24" />
</div>
<div>746312432</div>
</div>
<div class="website label">
<div class="icon">
<svg-icon name="brand-link" size="24" />
</div>
<div>https://urieworweoo.com</div>
</div>
</div>
<div class="about">
<div class="title">About</div>
<div class="content">Lian Sus work weaves understated ethnic influences into contemporary minimalism. She explores materials and silhouettes that bridge heritage and modern sensibilities. Her designs reflect a quiet dialogue between cultural memory and forward-looking innovation.</div>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.merchantInfo{
width: 100%;
height: auto;
position: relative;
padding-top: 4rem;
padding-bottom: 4rem;
.profile{
width: 20rem;
height: 20rem;
margin-left: 1.8rem;
>img{
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info{
display: flex;
flex-direction: column;
gap: 6rem;
margin-top: 4rem;
.title{
font-family: "KaiseiOpti-Bold";
font-weight: 700;
font-size: 3.4rem;
line-height: 3.6rem;
}
> .detail{
.name{
margin-bottom: .8rem;
font-weight: 500;
font-size: 1.8rem;
line-height: 100%;
color: #232323;
}
}
> .contact{
.title{
margin-bottom: 2rem;
}
.label{
display: flex;
gap: 2rem;
margin-bottom: .6rem;
font-family: "KaiseiOpti-Regular";
font-weight: 400;
font-size: 1.4rem;
line-height: 100%;
color: #585858;
&:last-child{
margin-bottom: 0;
}
}
}
> .about{
.title{
margin-bottom: 2rem;
}
.content{
font-family: "KaiseiOpti-Regular";
font-weight: 400;
font-size: 1.6rem;
line-height: 2.3rem;
color: #585858;
}
}
}
}
</style>