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.
 
 
 
 

664 lines
15 KiB

<template>
<view class="equity-goods-page">
<image style="width: 100%" mode="widthFix"
:src="showImg(cityInfo.bannerUrl)"></image>
<view class="location-selector" v-if="addressInfo">
<AreaPicker :defaultValue="{
provinceId: addressInfo.provinceId,
cityId: addressInfo.cityId,
areaId:addressInfo.areaId
}" placeholder="请选择省市区" @change="changeAddress">
<template v-slot="{ selectedText, placeholder, currentSelection }">
<text class="location-text">{{selectedText}}</text>
<image class="dropdown-icon"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOCIgdmlld0JveD0iMCAwIDEyIDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xIDFMNiA2TDExIDEiIHN0cm9rZT0iIzk5OTk5OSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+"
mode="heightFix"></image>
</template>
</AreaPicker>
</view>
<!-- 顶部标题区域 -->
<view class="header-section">
<view class="title">{{addressInfo&&addressInfo.city}}数字资产权益产品</view>
<view class="filter-buttons">
<view class="filter-btn" @click="hanleUpdate(0)">最新上架</view>
<view class="filter-btn" @click="hanleUpdate(1)">销量</view>
</view>
</view>
<!-- 商品网格 -->
<view class="products-grid" v-if="productList.length > 0">
<view class="product-item" :style="{
'border-width':
index == productList.length - 1 || index == productList.length - 2
? 0
: '0.5rpx',
}" v-for="(item, index) in productList" :key="index" @click="goToDetail(item)">
<image class="product-image" :src="item.coverUrl.split(',')[0]" mode="aspectFill"></image>
<view class="product-info">
<view class="product-title">{{ item.title }}</view>
<view class="product-price-box">
<view class="product-price">{{ item.price }}</view>
<view class="">
<image v-if="!item.type" @click.stop="handleLikeClick(item,index)" class="heart-icon"
src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png">
</image>
<image @click.stop="handleLikeClick(item,index)" v-else class="heart-icon"
src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png">
</image>
</view>
</view>
<view class="product-details">
<text class="detail-item">限量发售{{ item.publishQuantity }}份</text>
<text class="detail-item">{{item.purchaseQuantity||0}}人付款</text>
<text class="detail-item">浏览{{item.viewQuantity||0}}</text>
</view>
</view>
</view>
</view>
<!-- 空状态展示 -->
<view class="empty-state" v-else>
<view class="empty-content">
<image class="empty-icon"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjQ1IiBzdHJva2U9IiNEREREREQiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIvPgo8cGF0aCBkPSJNMzUgNDBINjVNMzUgNTBINjVNMzUgNjBINjUiIHN0cm9rZT0iI0RERERERCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KPC9zdmc+"
mode="widthFix"></image>
<view class="empty-title">暂无商品</view>
<view class="empty-desc">当前地区暂时没有可购买的权益产品</view>
<view class="empty-tip">可以尝试切换其他地区查看</view>
</view>
</view>
<!-- 底部地图区域 -->
<view class="map-section">
<view class="map-title" @click="showReservationPopup">业务办理 | 预约参观</view>
<view class="map-container">
<map class="map-component" :latitude="cityInfo.lat" :longitude="cityInfo.lng"
:scale="mapData.scale"></map>
</view>
<view class="map-description">
<view class="location-info">
<image class="location-icon" :src="
showImg('/uploads/20250728/56804fe109efd614ba955d3110cd6750.png')
" mode="widthFix"></image>
<text class="location-name">国家文化大数据交易平台{{addressInfo&&addressInfo.city}}运营中心</text>
</view>
</view>
</view>
<!-- 预约参观弹窗 -->
<uni-popup ref="reservationPopup" type="center">
<view class="reservation-popup">
<view class="popup-header">
<text class="popup-title">预约参观</text>
<text class="popup-close" @click="closeReservationPopup">×</text>
</view>
<view class="popup-content">
<view class="input-section">
<text class="input-label">姓名</text>
<input class="reservation-input" v-model="reservationForm.name" placeholder="请输入您的姓名"
maxlength="10" />
</view>
<view class="input-section">
<text class="input-label">手机号</text>
<input class="reservation-input" v-model="reservationForm.phone" placeholder="请输入手机号码"
type="number" maxlength="11" />
</view>
<view class="popup-actions">
<button class="cancel-btn" @click="closeReservationPopup">
取消
</button>
<button class="confirm-btn" @click="confirmReservation">
确认预约
</button>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import AreaPicker from '@/components/AreaPicker.vue'
export default {
name: "EquityGoodsList",
components: {
AreaPicker
},
mixins: [require("@/mixins/myMixins.js")],
data() {
return {
productList: [
],
heartIcon: "https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png",
heartFilledIcon: "https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png",
cartIcon: "https://images.unsplash.com/photo-1563013544-824ae1b704d3?auto=format&fit=crop&w=100",
mapData: {
latitude: 31.2989,
longitude: 120.5853,
scale: 17,
},
// 预约表单数据
reservationForm: {
name: "",
phone: "",
},
sortValue: '',
addressInfo: {},
cityInfo:{}
};
},
onLoad() {
let address = uni.getStorageSync('SYS_ADDRESS_INFO')
if (address) {
this.addressInfo = JSON.parse(address)
}
this.getInfoCity()
this.geBenefitPackaget()
},
methods: {
getInfoCity() {
let code = this.addressInfo.cityId
this.Post({
cityId: code
},
"/framework/index/getUrl",
'DES'
).then((res) => {
this.cityInfo = res.data
});
},
changeAddress(e) {
console.log(e)
this.addressInfo = e
uni.setStorageSync('SYS_ADDRESS_INFO', JSON.stringify(e))
this.geBenefitPackaget()
},
hanleUpdate(e) {
this.sortValue = e
this.geBenefitPackaget()
},
handleLikeClick(item, index) {
this.Post({
packageId: item.benefitPackageId,
type: !item.type,
},
"/framework/benefitPackage/collect",
"DES"
).then((res) => {
this.productList[index].type = !item.type;
});
},
geBenefitPackaget() {
this.Post({
cityId: this.addressInfo.cityId,
sortValue: this.sortValue
},
"/framework/benefitPackage/list",
'DES'
).then((res) => {
if (res.data) {
this.productList = res.data
}
});
},
goToDetail(item) {
uni.navigateTo({
url: `/subPackages/equityGoods/detail?id=${item.benefitPackageId}`,
});
},
// 显示预约弹窗
showReservationPopup() {
this.$refs.reservationPopup.open();
},
// 关闭预约弹窗
closeReservationPopup() {
this.$refs.reservationPopup.close();
// 清空表单
this.reservationForm.name = "";
this.reservationForm.phone = "";
},
// 确认预约
async confirmReservation() {
// 表单验证
if (!this.reservationForm.name.trim()) {
uni.showToast({
title: "请输入姓名",
icon: "none",
});
return;
}
if (!this.reservationForm.phone.trim()) {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
// 手机号格式验证
const phoneRegex = /^1[3-9]\d{9}$/;
if (!phoneRegex.test(this.reservationForm.phone)) {
uni.showToast({
title: "请输入正确的手机号",
icon: "none",
});
return;
}
try {
uni.showLoading({
title: "提交中...",
});
// 提交预约信息
await this.submitReservation(this.reservationForm);
uni.hideLoading();
uni.showToast({
title: "预约成功!",
icon: "success",
});
this.closeReservationPopup();
} catch (error) {
uni.hideLoading();
uni.showToast({
title: "预约失败,请重试",
icon: "none",
});
}
},
// 提交预约信息(模拟API)
async submitReservation(formData) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟API调用
console.log("预约信息:", formData);
resolve({
success: true,
message: "预约成功",
});
}, 1500);
});
},
},
};
</script>
<style>
page {
background-color: #f5f5f5;
}
</style>
<style lang="scss" scoped>
.equity-goods-page {
min-height: 100vh;
background: #f5f5f5;
padding-bottom: 40rpx;
}
.header-section {
padding: 60rpx 30rpx 30rpx;
.title {
font-size: 36rpx;
color: #000000;
text-align: center;
margin-bottom: 30rpx;
padding-bottom: 30rpx;
font-weight: 500;
border-bottom: 0.5rpx solid #999999;
}
.filter-buttons {
display: flex;
justify-content: space-between;
gap: 40rpx;
.filter-btn {
font-size: 28rpx;
color: #000000;
border-radius: 20rpx;
transition: all 0.3s;
&.active {
background: #007aff;
color: white;
}
}
}
}
.products-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
padding: 30rpx;
.product-item {
overflow: hidden;
border-bottom: 0.5rpx solid #999999;
margin-bottom: 15rpx;
padding-bottom: 20rpx;
&:active {
transform: scale(0.98);
}
.product-image {
width: 100%;
height: 429rpx;
object-fit: cover;
border-radius: 20rpx;
}
.product-info {
padding: 20rpx 0;
.product-title {
font-size: 22rpx;
color: #000000;
margin-bottom: 16rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
}
.product-price {
font-size: 36rpx;
font-weight: 500;
color: #000000;
}
.product-details {
display: flex;
align-items: center;
justify-content: space-between;
.detail-item {
font-size: 18rpx;
color: #808080;
}
}
}
}
}
// 空状态样式
.empty-state {
padding: 80rpx 30rpx;
min-height: 400rpx;
display: flex;
align-items: center;
justify-content: center;
.empty-content {
text-align: center;
max-width: 400rpx;
.empty-icon {
width: 120rpx;
height: 120rpx;
margin: 0 auto 40rpx;
opacity: 0.6;
}
.empty-title {
font-size: 32rpx;
color: #666666;
font-weight: 500;
margin-bottom: 20rpx;
}
.empty-desc {
font-size: 26rpx;
color: #999999;
line-height: 1.5;
margin-bottom: 16rpx;
}
.empty-tip {
font-size: 24rpx;
color: #BBBBBB;
line-height: 1.4;
}
}
}
.map-section {
border-top: 0.5rpx solid #999999;
margin: 30rpx 30rpx 0;
overflow: hidden;
.map-title {
padding: 30rpx;
font-size: 22rpx;
font-weight: 500;
color: #000000;
text-align: center;
}
.map-container {
position: relative;
height: 330rpx;
border: 6rpx solid white;
border-radius: 20rpx;
transform: translateY(0);
overflow: hidden;
.map-component {
width: 100%;
height: 100%;
border-radius: 20rpx;
}
}
.map-description {
padding: 30rpx;
.location-info {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
.location-icon {
width: 40rpx;
}
.location-name {
font-size: 22rpx;
color: #808080;
}
}
}
}
.heart-icon {
width: 35rpx;
height: 30rpx;
transition: all 0.3s ease;
flex-shrink: 0;
top: -2rpx;
position: relative;
margin-right: 6rpx;
&.liked {
opacity: 1;
filter: hue-rotate(320deg) saturate(2);
}
&:active {
transform: scale(1.2);
}
}
.shop-icon {
width: 39rpx;
height: 36rpx;
transition: all 0.3s ease;
flex-shrink: 0;
margin-left: 10rpx;
&.liked {
opacity: 1;
filter: hue-rotate(320deg) saturate(2);
}
&:active {
transform: scale(1.2);
}
}
.product-price-box {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10rpx;
}
.location-selector {
position: absolute;
top: 20rpx;
left: 20rpx;
display: flex;
align-items: center;
padding: 8rpx 16rpx;
// border: 2rpx solid #e0e0e0;
border-radius: 20rpx;
min-width: 100rpx;
margin-right: 20rpx;
.location-text {
font-size: 30rpx;
color: white;
margin-right: 8rpx;
}
.dropdown-icon {
width: 24rpx;
height: 16rpx;
}
}
// 预约弹窗样式
.reservation-popup {
width: 600rpx;
background: white;
border-radius: 24rpx;
overflow: hidden;
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 32rpx 24rpx;
border-bottom: 1rpx solid #f0f0f0;
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
line-height: 1;
padding: 8rpx;
cursor: pointer;
transition: color 0.3s;
&:active {
color: #666;
}
}
}
.popup-content {
padding: 32rpx;
.input-section {
margin-bottom: 32rpx;
.input-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 16rpx;
font-weight: 500;
}
.reservation-input {
width: 100%;
height: 88rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333;
background: #fafafa;
transition: all 0.3s;
box-sizing: border-box;
&:focus {
border-color: #007aff;
background: white;
}
&::placeholder {
color: #999;
}
}
}
.popup-actions {
display: flex;
gap: 24rpx;
margin-top: 40rpx;
.cancel-btn,
.confirm-btn {
flex: 1;
height: 74rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 600;
border: none;
transition: all 0.3s;
&:active {
transform: scale(0.98);
}
}
.cancel-btn {
background: #f5f5f5;
color: #666;
&:active {
background: #e8e8e8;
}
}
.confirm-btn {
background: #007aff;
color: white;
&:active {
background: #0056cc;
}
}
}
}
}
// 地图标题点击样式
.map-title {
cursor: pointer;
transition: all 0.3s;
}
</style>