|
|
- <template>
- <view class="container">
- <!-- 顶部banner -->
- <banner-swiper :banner-list="bannerList" height="320rpx" :fallback-image="recycle_banner"
- video-id-prefix="recycle-video"></banner-swiper>
-
-
- <!-- 商品列表 -->
- <view class="goods-list">
- <!-- 左侧分类导航 -->
- <view class="category-nav">
- <view v-for="(category, index) in categories" :key="category.id || index" class="category-item"
- :class="{ active: currentCategory === index }" @click="switchCategory(index)">
- <view class="category-dot" v-if="getCategoryItemCount(index) > 0">{{ getCategoryItemCount(index) }}</view>
- {{ category.title }}
- </view>
- </view>
-
- <!-- 右侧商品列表 -->
- <scroll-view class="goods-content" scroll-y @scrolltolower="loadMoreGoods">
- <view class="goods-section">
- <view class="goods-item" v-for="(item, index) in recycleList" :key="index">
- <view class="goods-img-container">
- <image v-if="item.image" :src="item.image" class="goods-item-img" mode="aspectFit" />
- <!-- 品牌标签 -->
- <view class="brand-tag" v-if="item.isPin === 'Y'">品牌</view>
- </view>
- <view class="goods-info-wrap">
- <view class="goods-header">
- <text class="goods-name">{{ item.name }}</text>
- </view>
- <text class="goods-desc">{{ item.service }}</text>
- <view class="rules-brand-row">
- <view class="rules-link" @click="showRules(item)" v-if="item.isRecycleRules == '1'">
- <view class="rules">
- <text>回收规则</text>
- <uni-icons type="right" size="14" color="#999"></uni-icons>
- </view>
- </view>
- <!-- <view class="brand-check-placeholder" v-if="item.isPin === 'Y'">
- <view class="brand-check" @click="checkBrand(index)">
- <text>查看品牌</text>
- <uni-icons type="right" size="12" color="#ff7a0e"></uni-icons>
- </view>
- </view> -->
- </view>
- <view class="goods-info">
- <view class="price-info">
- <text class="price-symbol">¥</text>
- <text class="price-value" v-if="!item.maxPrice || item.maxPrice == item.price">{{ item.price }}</text>
- <text class="price-value" v-else>{{ item.price }}-{{ item.maxPrice }}</text>
- <text class="price-unit">/{{ item.unit || '件' }}</text>
- </view>
- <view class="quantity-control">
- <button class="btn-minus" @click="updateQuantity(index, -1)">-</button>
- <text class="quantity">{{ getItemTotalQuantity(item) }}</text>
- <button class="btn-plus" @click="updateQuantity(index, 1)">+</button>
- </view>
- </view>
- </view>
- </view>
- </view>
-
- <!-- 不可回收商品 -->
- <view class="other-unrecycle-card">
- <!-- 使用商品分类数据中的icon -->
- <image class="other-unrecycle-img" :src="categories[currentCategory]?.icon" mode="aspectFit" />
- <view class="other-unrecycle-info">
- <!-- 主标题和副标题用接口返回的otherTitle和otherSubTitle -->
- <view class="other-unrecycle-title">{{ categories[currentCategory]?.otherTitle }}</view>
- <view class="other-unrecycle-desc">{{ categories[currentCategory]?.otherSubTitle }}</view>
- <view class="other-unrecycle-price-row">
- <text class="other-unrecycle-price">¥ — /{{ categories[currentCategory]?.unit || '件' }}</text>
- </view>
- </view>
- <button class="other-unrecycle-btn" open-type="contact">+</button>
- </view>
- <view v-if="loadingMore" class="loading-more">加载中...</view>
- <view v-else-if="finished" class="loading-more">没有更多了</view>
- </scroll-view>
- </view>
-
- <!-- 固定底部区域 -->
- <view class="fixed-bottom-wrap" v-if="!showDetailPanel">
- <view class="green-tip-bar">
- 回收范围仅支持回收以上品类,按件回收预计比称重回收多
- <text class="tip-highlight"> {{ extraRecycleAmount.display }}</text>
- </view>
- <view class="bottom-bar">
- <view class="bottom-left">
- <view class="summary-row">
- <text class="summary-label">已选 <text class="summary-count">{{ totalCount }}</text> {{ totalUnitText }}
- 预计回收可得</text>
- <uni-icons type="help" size="18" color="#b2b2b2" style="margin: 0 8rpx;" @tap="showPriceInfoPopups" />
- </view>
- <view class="amount-row" @click="toggleDetailPanel">
- <uni-icons :type="showDetailPanel ? 'up' : 'down'" size="18" color="#5e5e5e"
- style="margin-right: 8rpx;vertical-align: middle;" />
- <text class="amount" v-if="priceRange.min === priceRange.max">¥{{ priceRange.min }}</text>
- <text class="amount" v-else>¥{{ priceRange.min }}-{{ priceRange.max }}</text>
- </view>
- </view>
- <button class="submit-btn" @click="submitOrder">预约上门取件</button>
- </view>
- <view class="bottom-bar-divider"></view>
- </view>
-
- <!-- 明细弹窗遮罩和弹窗 -->
- <view v-if="showDetailPanel" class="detail-popup-mask" @click.self="toggleDetailPanel">
- <view class="detail-popup" @click.stop>
- <view class="detail-popup-close" @click="toggleDetailPanel">×</view>
- <view class="green-tip-bar popup-green-tip">
- 回收范围仅支持回收以上品类,按件回收预计比称重回收多
- <text class="tip-highlight"> {{ extraRecycleAmount.display }}</text>
- </view>
- <view class="panel-header">
- <text class="panel-title">已选商品明细</text>
- </view>
- <scroll-view class="panel-list popup-panel-list" scroll-y>
- <!-- @click="openProductDetail(item)" -->
- <view v-for="(item, idx) in selectedProducts" :key="item.uniqueKey || idx"
- class="panel-item">
- <view class="panel-img-container">
- <image v-if="item.styleImage || item.image" :src="item.styleImage || item.image" class="panel-item-img" mode="aspectFit" />
- <!-- 品牌标签 -->
- <view class="panel-brand-tag" v-if="item.brandId">品牌</view>
- </view>
- <view class="panel-item-info">
- <!-- <text class="panel-item-name">{{ item.name }}</text> -->
- <!-- <text class="panel-item-desc" v-if="item.brandName && item.styleName">品牌:{{ item.brandName }} | 款式:{{ item.styleName }}</text> -->
- <text class="panel-item-name">{{ item.brandName || item.name }}</text>
- <text class="panel-item-desc" v-if="item.styleName">{{ item.styleName }}</text>
- <text class="panel-item-desc" v-else>{{ item.service }}</text>
- <text class="panel-item-price" v-if="!item.maxPrice || item.maxPrice == item.price">¥{{ item.price }}/{{
- item.unit || '件' }}</text>
- <text class="panel-item-price" v-else>¥{{ item.price }}-{{ item.maxPrice }}/{{ item.unit || '件' }}</text>
- </view>
- <view class="panel-quantity-control">
- <button class="btn-minus" @click.stop="updateQuantityByProduct(item, -1)">-</button>
- <!-- <button class="btn-minus">-</button> -->
- <text class="quantity">{{ item.quantity }}</text>
- <button class="btn-plus" @click.stop="updateQuantityByProduct(item, 1)">+</button>
- <!-- <button class="btn-plus">+</button> -->
- </view>
- </view>
- </scroll-view>
- <view class="popup-bottom-bar">
- <view class="bottom-left">
- <view class="summary-row">
- <text class="summary-label">已选 <text class="summary-count">{{ totalCount }}</text> {{ totalUnitText }}
- 预计回收可得</text>
- <uni-icons type="help" size="18" color="#b2b2b2" style="margin: 0 8rpx;" @tap="showPriceInfoPopups" />
- </view>
- <view class="amount-row" @click="toggleDetailPanel">
- <uni-icons :type="showDetailPanel ? 'up' : 'down'" size="18" color="#5e5e5e"
- style="margin-right: 8rpx;vertical-align: middle;" />
- <text class="amount" v-if="priceRange.min === priceRange.max">¥{{ priceRange.min }}</text>
- <text class="amount" v-else>¥{{ priceRange.min }}-{{ priceRange.max }}</text>
- </view>
- </view>
- <button class="submit-btn" @click="submitOrder">预约上门取件</button>
- </view>
-
- <!-- 添加衣物浮窗按钮 -->
- <view class="floating-add-btn" @click="addMoreItems">
- <text class="floating-btn-text">添加衣物</text>
- </view>
- </view>
- </view>
-
- <!-- 价格说明弹窗 -->
- <view v-if="showPriceInfoPopup" class="price-info-popup-mask" @click.self="closePriceInfoPopup">
- <view class="price-info-popup">
- <view class="price-info-popup-title">回收规则</view>
- <scroll-view class="price-info-popup-content" scroll-y>
- <!-- <view class="price-info-section">
- <view class="price-info-heading">关于旧衣质检</view>
- <view class="price-info-text">请确认本次回收旧衣是可以进行二次穿着的程度,如回收旧衣有破损磨损、开线变形、起球发黄、染色污渍、配饰脱落或款式老旧等问题,无法通过质检。</view>
- </view>
- <view class="price-info-section">
- <view class="price-info-heading">质检报告</view>
- <view class="price-info-text">回收商收到衣后1-3个工作日内完成衣质检报告。</view>
- </view>
- <view class="price-info-section">
- <view class="price-info-heading">质检结果与回收价格</view>
- <view class="price-info-text">若回收旧衣质检通过,质检价格与用户提交订单时的预估价格一致,回收商将按照预估价打款至您的小程序账户余额。</view>
- </view> -->
- <uv-parse :content="huodong_text"></uv-parse>
- </scroll-view>
- <button class="price-info-popup-btn" @click="closePriceInfoPopup">我知道了</button>
- </view>
- </view>
-
- <!-- 根据角色显示不同的导航栏 -->
- <tabbar v-if="ishow" select="recycle"></tabbar>
-
- <!-- 品牌选择组件 -->
- <brand-selector ref="brandSelector" @brand-confirm="onBrandConfirm" @reduce-select="onReduceSelect"
- @close="onBrandSelectorClose" @get-existing-quantities="getExistingQuantities"></brand-selector>
-
- <!-- 规则弹窗组件 -->
- <rule-popup ref="rulePopup" :confirm-content="recycle_toast" @rule-confirm="onRuleConfirm"
- @pickup-cancel="handlePickupCancel" @pickup-confirm="handlePickupAgree"></rule-popup>
-
- <!-- 商品明细弹窗组件 -->
- <product-detail-popup ref="productDetailPopup" @confirm-changes="onDetailConfirmChanges" @close="onDetailPopupClose"></product-detail-popup>
-
- </view>
- </template>
-
- <script>
- import tabBarMixin from '../mixins/tabBarMixin.js'
- import { pinyin } from '../../utils/pinyin.js'
- import tabbar from '../../compoent/base/tabbar.vue'
- import brandSelector from '../../compoent/recycle/brand-selector.vue'
- import bannerSwiper from '../../compoent/base/banner-swiper.vue'
- import rulePopup from '../../compoent/base/rule-popup.vue'
- import productDetailPopup from '../../compoent/recycle/product-detail-popup.vue'
- export default {
- mixins: [tabBarMixin],
- components: {
- tabbar,
- brandSelector,
- bannerSwiper,
- rulePopup,
- productDetailPopup
- },
- data() {
- return {
- value: 1,
- ishow: true,
- // 动态数据
- allProducts: {}, // { [categoryId]: [商品数组] }
- allProductsPage: {}, // { [categoryId]: 当前已加载页码 }
- allProductsTotal: {}, // { [categoryId]: 总数 }
- pageSize: 10,
- currentCategory: 0,
- tabbarHeight: 0,
- showDetailPanel: false,
- ruleImgUrl: '/static/回收/回收规则.png',
- brandCache: {}, // 为每个商品缓存品牌信息 { productId: [brandList] }
- loadingMore: false,
- finished: false,
- pendingBrandIndex: null, // 记录待加一的品牌商品index
- showPriceInfoPopup: false,
- isWaitingForBrandSelection: false, // 等待品牌选择的标志
- reduceItem: null, // 待减少数量的商品
- viewedRuleItems: new Set(), // 已查看过规则的商品ID集合
- loadOptions: null, // 保存options参数
- userInfo: null, // 用户信息
- isUserBlacklisted: false, // 用户是否被拉黑
- currentProductId: null, // 当前查看品牌的商品ID
- searchTimer: null, // 搜索防抖定时器
- isFromPickupFlow: false, // 标记是否来自预约流程
- hasShownFirstTimeRules: false // 标记是否已显示过首次访问规则
- }
- },
- computed: {
- recycle_banner() {
- const item = getApp().globalData.configData.find(i => i.keyName === 'recycle_banner')
- return item ? item.keyContent : ''
- },
- re_key_numer() {
- const item = getApp().globalData.configData.find(i => i.keyName === 're_key_numer')
- return item ? parseFloat(item.keyContent) : 0.066
- },
- recycle_toast() {
- const item = getApp().globalData.configData.find(i => i.keyName === 'recycle_toast')
- return item ? item.keyContent : ''
- },
- huodong_text() {
- const item = getApp().globalData.configData.find(i => i.keyName === 'huodong_text')
- return item ? item.keyContent : ''
- },
- // 当前分类的商品列表
- recycleList() {
- const currentCategoryId = this.categories[this.currentCategory]?.id
- return this.allProducts[currentCategoryId] || []
- },
- // 计算总数量
- totalCount() {
- return Object.values(this.allProducts).reduce((total, categoryItems) => {
- return total + categoryItems.reduce((sum, item) => {
- // 如果商品有品牌款式数量,汇总所有品牌款式的数量
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- return sum + Object.values(item.brandStyleQuantities).reduce((styleSum, qty) => styleSum + qty, 0)
- }
- // 如果商品有品牌数量,汇总所有品牌的数量
- if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- return sum + Object.values(item.brandQuantities).reduce((brandSum, qty) => brandSum + qty, 0)
- }
- // 否则使用原来的quantity字段
- return sum + (item.quantity || 0)
- }, 0)
- }, 0)
- },
- // 计算总单位文本
- totalUnitText() {
- // 获取所有已选商品的单位
- const units = new Set()
- Object.values(this.allProducts).forEach(categoryItems => {
- categoryItems.forEach(item => {
- let hasQuantity = false
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- hasQuantity = Object.values(item.brandStyleQuantities).some(qty => qty > 0)
- } else if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- hasQuantity = Object.values(item.brandQuantities).some(qty => qty > 0)
- } else {
- hasQuantity = (item.quantity || 0) > 0
- }
-
- if (hasQuantity) {
- units.add(item.unit || '件')
- }
- })
- })
-
- // 如果只有一种单位,显示单位;如果混合多种单位,显示"项"
- if (units.size === 0) return '件'
- if (units.size === 1) return Array.from(units)[0]
- return '项'
- },
- // 计算总价格范围
- totalPriceRange() {
- const result = Object.values(this.allProducts).reduce((categoryTotal, categoryItems) => {
- return categoryItems.reduce((sum, item) => {
- // 如果商品有品牌款式数量,使用款式价格计算
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- Object.entries(item.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
- if (quantity > 0 && item.styleCache && item.styleCache[uniqueKey]) {
- const styleInfo = item.styleCache[uniqueKey].styleInfo
- const minPrice = Number(styleInfo.minPrice) || 0
- const maxPrice = Number(styleInfo.maxPrice) || Number(styleInfo.minPrice) || 0
- sum.min += quantity * minPrice
- sum.max += quantity * maxPrice
- }
- })
- } else {
- let itemQuantity = 0
- // 如果商品有品牌数量,汇总所有品牌的数量
- if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- itemQuantity = Object.values(item.brandQuantities).reduce((brandSum, qty) => brandSum + qty, 0)
- } else {
- itemQuantity = item.quantity || 0
- }
-
- if (itemQuantity > 0) {
- const minPrice = Number(item.price) || 0
- const maxPrice = Number(item.maxPrice) || Number(item.price) || 0
- sum.min += itemQuantity * minPrice
- sum.max += itemQuantity * maxPrice
- }
- }
-
- return sum
- }, categoryTotal)
- }, { min: 0, max: 0 })
-
- return {
- min: result.min.toFixed(1),
- max: result.max.toFixed(1)
- }
- },
- // 计算总价格 (保持兼容性,使用最低价格)
- totalPrice() {
- return this.totalPriceRange.min
- },
- // 计算价格范围
- priceRange() {
- if (this.totalCount === 0) {
- return {
- min: '0.0',
- max: '0.0'
- }
- }
- return this.totalPriceRange
- },
- selectedProducts() {
- // 返回所有分类下所有已选商品,按品牌款式分组
- const products = []
- Object.values(this.allProducts).flat().forEach(item => {
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- // 按品牌款式分别添加
- Object.entries(item.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
- if (quantity > 0 && item.styleCache && item.styleCache[uniqueKey]) {
- const { brandInfo, styleInfo } = item.styleCache[uniqueKey]
- products.push({
- ...item,
- quantity: quantity,
- brandId: brandInfo.id,
- brandName: brandInfo.name,
- brandImage: brandInfo.logo,
- styleId: styleInfo.id,
- styleName: styleInfo.name,
- styleImage: styleInfo.image,
- price: styleInfo.minPrice, // 使用款式价格
- maxPrice: styleInfo.maxPrice,
- name: item.name, // 保持原商品名称
- uniqueKey: `${item.id}_${uniqueKey}` // 用于区分同商品不同品牌款式
- })
- }
- })
- } else if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- // 按品牌分别添加(兼容旧数据)
- Object.entries(item.brandQuantities).forEach(([brandId, quantity]) => {
- if (quantity > 0) {
- const brandInfo = this.getBrandInfo(brandId)
- products.push({
- ...item,
- quantity: quantity,
- brandId: brandId,
- brandName: brandInfo ? brandInfo.name : '未知品牌',
- brandImage: brandInfo ? brandInfo.logo : '',
- uniqueKey: `${item.id}_${brandId}` // 用于区分同商品不同品牌
- })
- }
- })
- } else if (item.quantity > 0) {
- // 没有品牌的商品
- products.push({
- ...item,
- uniqueKey: item.id
- })
- }
- })
- return products
- },
-
- bannerList() {
- return getApp().globalData.bannerList || []
- },
- categories() {
- const list = getApp().globalData.pricePreviewList || []
- return list.sort((a, b) => a.sort - b.sort)
- // return list.filter(item => item.pid === '0').sort((a, b) => a.sort - b.sort)
- },
- minMoney() {
- const config = getApp().globalData.configData || [];
- const item = config.find(i => i.keyName === 'min_money');
- return item ? parseFloat(item.keyContent) : 0;
- },
- minMumber() {
- const config = getApp().globalData.configData || [];
- const item = config.find(i => i.keyName === 'min_number');
- return item ? parseFloat(item.keyContent) : 0;
- },
- // 计算比预计回收多的金额(商品回收价格 - (商品回收价格 * 0.066))
- extraRecycleAmount() {
- const minPrice = parseFloat(this.priceRange.min) || 0;
- const maxPrice = parseFloat(this.priceRange.max) || 0;
-
- if (minPrice === 0 && maxPrice === 0) {
- return {
- min: '0.00',
- max: '0.00',
- display: '0.00元'
- };
- }
-
- let re_key_numer = this.re_key_numer || 0.066
-
- // 计算减去6.6%后的金额
- const minExtra = minPrice - (minPrice * re_key_numer);
- const maxExtra = maxPrice - (maxPrice * re_key_numer);
-
- // 如果最小值和最大值相等,显示单个值
- if (minPrice === maxPrice) {
- return {
- min: minExtra.toFixed(2),
- max: maxExtra.toFixed(2),
- display: `${minExtra.toFixed(2)}元`
- };
- }
-
- // 显示区间
- return {
- min: minExtra.toFixed(2),
- max: maxExtra.toFixed(2),
- display: `${minExtra.toFixed(2)}-${maxExtra.toFixed(2)}元`
- };
- },
-
- },
- methods: {
- showPriceInfoPopups() {
- console.log('showPriceInfoPopup called');
- this.isFromPickupFlow = false // 标记是从帮助按钮触发
- this.showPriceInfoPopup = true
- },
- getSelectKey() {
- const keys = ['home', 'recycle', 'my']
- return keys[this.value] || 'recycle'
- },
- fetchGoodsList(categoryId, page = 1, callback) {
- this.$api('getClassGoodsList', {
- classId: categoryId,
- pageNo: page,
- pageSize: this.pageSize
- }, res => {
- if (res.code === 200 && res.result && Array.isArray(res.result.records)) {
- const oldList = this.allProducts[categoryId] || []
- const newList = page === 1 ? res.result.records : oldList.concat(res.result.records)
- this.$set(this.allProducts, categoryId, newList)
- this.$set(this.allProductsPage, categoryId, page)
- this.$set(this.allProductsTotal, categoryId, res.result.total)
- }
- if (callback) callback()
- })
- },
- // 获取分类商品总数
- getCategoryItemCount(index) {
- const categoryId = this.categories[index]?.id
- const categoryItems = this.allProducts[categoryId] || []
- return categoryItems.reduce((sum, item) => {
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- return sum + Object.values(item.brandStyleQuantities).reduce((styleSum, qty) => styleSum + qty, 0)
- }
- if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- return sum + Object.values(item.brandQuantities).reduce((brandSum, qty) => brandSum + qty, 0)
- }
- return sum + (item.quantity || 0)
- }, 0)
- },
- // 切换分类
- switchCategory(index) {
- this.currentCategory = index
- this.loadingMore = false
- this.finished = false
- const categoryId = this.categories[index]?.id
- // console.log(categoryId,'switchCategory')
- if (!this.allProducts[categoryId]) {
- this.fetchGoodsList(categoryId, 1)
- }
- },
- // 更新商品数量
- updateQuantity(index, delta) {
- const categoryId = this.categories[this.currentCategory]?.id
- const item = this.allProducts[categoryId]?.[index]
- if (!item) return
-
- // 如果是减少数量且delta为负数
- if (delta < 0) {
- // 检查是否有多个品牌款式
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 1) {
- // 有多个品牌款式,显示选择弹窗
- this.reduceItem = { item, index, delta }
- const reduceStyleList = Object.entries(item.brandStyleQuantities)
- .filter(([uniqueKey, quantity]) => quantity > 0)
- .map(([uniqueKey, quantity]) => {
- const cacheInfo = item.styleCache[uniqueKey]
- return {
- uniqueKey,
- quantity,
- name: cacheInfo ? `${cacheInfo.brandInfo.name} - ${cacheInfo.styleInfo.name}` : '未知款式',
- logo: cacheInfo ? cacheInfo.brandInfo.logo : ''
- }
- })
- this.$refs.brandSelector.openReducePopup(reduceStyleList)
- return
- } else if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length === 1) {
- // 只有一个品牌款式,直接减少
- const uniqueKey = Object.keys(item.brandStyleQuantities)[0]
- const currentQty = item.brandStyleQuantities[uniqueKey] || 0
- const newQty = Math.max(0, currentQty + delta)
- this.$set(item.brandStyleQuantities, uniqueKey, newQty)
-
- // 如果数量为0,删除该品牌款式
- if (newQty === 0) {
- delete item.brandStyleQuantities[uniqueKey]
- if (item.styleCache && item.styleCache[uniqueKey]) {
- delete item.styleCache[uniqueKey]
- }
- }
- return
- } else if (item.brandQuantities && Object.keys(item.brandQuantities).length > 1) {
- // 有多个品牌,显示选择弹窗(兼容旧数据)
- this.reduceItem = { item, index, delta }
- const reduceBrandList = Object.entries(item.brandQuantities)
- .filter(([brandId, quantity]) => quantity > 0)
- .map(([brandId, quantity]) => {
- const brandInfo = this.getBrandInfo(brandId)
- return {
- brandId,
- quantity,
- name: brandInfo ? brandInfo.name : '未知品牌',
- logo: brandInfo ? brandInfo.logo : ''
- }
- })
- this.$refs.brandSelector.openReducePopup(reduceBrandList)
- return
- } else if (item.brandQuantities && Object.keys(item.brandQuantities).length === 1) {
- // 只有一个品牌,直接减少(兼容旧数据)
- const brandId = Object.keys(item.brandQuantities)[0]
- const currentQty = item.brandQuantities[brandId] || 0
- const newQty = Math.max(0, currentQty + delta)
- this.$set(item.brandQuantities, brandId, newQty)
-
- // 如果数量为0,删除该品牌
- if (newQty === 0) {
- delete item.brandQuantities[brandId]
- }
- return
- } else {
- // 没有品牌数量,使用原来的逻辑
- let newQuantity = (item.quantity || 0) + delta
- if (newQuantity < 0) newQuantity = 0
- this.$set(item, 'quantity', newQuantity)
- return
- }
- }
-
- // 品牌商品且数量为0且加一时
- if (item.isPin === 'Y' && (item.quantity || 0) === 0 && delta > 0) {
- this.pendingBrandIndex = index
- // 检查是否需要显示回收规则
- if (item.isRecycleRules === 'Y') {
- this.isWaitingForBrandSelection = true;
- this.showRules(item); // 先显示回收规则
- } else {
- // 不需要显示规则,直接打开品牌选择
- this.$refs.brandSelector.open(item.id)
- }
- return
- }
- // 无品牌商品,数量为0且加一时
- if (item.isPin !== 'Y' && (item.quantity || 0) === 0 && delta > 0) {
- this.pendingBrandIndex = index
- // 检查是否需要显示回收规则
- if (item.isRecycleRules === 'Y') {
- this.isWaitingForBrandSelection = false; // 标记为无品牌
- this.showRules(item)
- } else {
- // 不需要显示规则,直接加数量
- let newQuantity = (item.quantity || 0) + delta
- if (newQuantity < 0) newQuantity = 0
- this.$set(item, 'quantity', newQuantity)
- this.pendingBrandIndex = null
- }
- return
- }
- // 其它情况直接加数量
- let newQuantity = (item.quantity || 0) + delta
- if (newQuantity < 0) newQuantity = 0
- this.$set(item, 'quantity', newQuantity)
- },
- // 处理品牌确认事件(新的款式选择流程)
- onBrandConfirm(data) {
- if (this.pendingBrandIndex !== null) {
- const categoryId = this.categories[this.currentCategory]?.id
- const item = this.allProducts[categoryId]?.[this.pendingBrandIndex]
- if (item && data.selectedStyles && data.selectedStyles.length > 0) {
- // 初始化品牌款式数量对象
- if (!item.brandStyleQuantities) {
- this.$set(item, 'brandStyleQuantities', {})
- }
-
- // 清理当前品牌的所有款式数据
- const brandPrefix = `${data.brandInfo.id}_`
- Object.keys(item.brandStyleQuantities).forEach(key => {
- if (key.startsWith(brandPrefix)) {
- delete item.brandStyleQuantities[key]
- if (item.styleCache && item.styleCache[key]) {
- delete item.styleCache[key]
- }
- }
- })
-
- // 为每个选中的款式设置数量(只保存有数量的款式)
- data.selectedStyles.forEach(style => {
- if (style.quantity > 0) {
- const uniqueKey = `${data.brandInfo.id}_${style.id}`
- this.$set(item.brandStyleQuantities, uniqueKey, style.quantity)
-
- // 缓存款式信息用于后续显示
- if (!item.styleCache) {
- this.$set(item, 'styleCache', {})
- }
- this.$set(item.styleCache, uniqueKey, {
- brandInfo: data.brandInfo,
- styleInfo: style
- })
- }
- })
-
- // 清除原来的quantity和brandQuantities(如果存在)
- if (item.quantity) {
- this.$set(item, 'quantity', 0)
- }
- if (item.brandQuantities) {
- this.$set(item, 'brandQuantities', {})
- }
-
- // 品牌选择完成后自动打开商品明细弹窗
- this.$nextTick(() => {
- this.showDetailPanel = true
- })
- }
- this.pendingBrandIndex = null
- }
- },
-
- // 处理减少品牌选择事件
- onReduceSelect(selectInfo) {
- const { item, index, delta } = this.reduceItem
-
- if (selectInfo.uniqueKey) {
- // 新的品牌款式减少逻辑
- const currentQty = item.brandStyleQuantities[selectInfo.uniqueKey] || 0
- const newQty = Math.max(0, currentQty + delta)
-
- this.$set(item.brandStyleQuantities, selectInfo.uniqueKey, newQty)
-
- // 如果数量为0,删除该品牌款式
- if (newQty === 0) {
- delete item.brandStyleQuantities[selectInfo.uniqueKey]
- if (item.styleCache && item.styleCache[selectInfo.uniqueKey]) {
- delete item.styleCache[selectInfo.uniqueKey]
- }
- }
- } else if (selectInfo.brandId) {
- // 兼容旧的品牌减少逻辑
- const currentQty = item.brandQuantities[selectInfo.brandId] || 0
- const newQty = Math.max(0, currentQty + delta)
-
- this.$set(item.brandQuantities, selectInfo.brandId, newQty)
-
- // 如果数量为0,删除该品牌
- if (newQty === 0) {
- delete item.brandQuantities[selectInfo.brandId]
- }
- }
-
- this.reduceItem = null
- },
-
- // 处理品牌选择器关闭事件
- onBrandSelectorClose() {
- // 如果用户取消品牌选择,重置状态
- this.pendingBrandIndex = null
- this.isWaitingForBrandSelection = false
- },
-
- // 获取已有的款式数量
- getExistingQuantities(brandId, callback) {
- if (this.pendingBrandIndex !== null) {
- const categoryId = this.categories[this.currentCategory]?.id
- const item = this.allProducts[categoryId]?.[this.pendingBrandIndex]
- if (item && item.brandStyleQuantities) {
- // 过滤出当前品牌的款式数量
- const existingQuantities = {}
- Object.entries(item.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
- if (uniqueKey.startsWith(`${brandId}_`)) {
- existingQuantities[uniqueKey] = quantity
- }
- })
- callback(existingQuantities)
- } else {
- callback({})
- }
- } else {
- callback({})
- }
- },
-
- // 打开商品明细弹窗
- openProductDetail(selectedItem) {
- if (!selectedItem.brandId || !selectedItem.styleId) {
- uni.showToast({
- title: '该商品无法查看明细',
- icon: 'none'
- })
- return
- }
-
- // 查找原始商品信息
- const originalItem = this.findOriginalItem(selectedItem.id)
- if (!originalItem) {
- uni.showToast({
- title: '商品信息不存在',
- icon: 'none'
- })
- return
- }
-
- // 构建商品信息
- const productInfo = {
- id: originalItem.id,
- name: originalItem.name,
- image: originalItem.image
- }
-
- // 构建品牌信息
- const brandInfo = {
- id: selectedItem.brandId,
- name: selectedItem.brandName,
- logo: selectedItem.brandImage
- }
-
- // 获取该品牌下的所有款式数量
- const existingQuantities = {}
- if (originalItem.brandStyleQuantities) {
- Object.entries(originalItem.brandStyleQuantities).forEach(([uniqueKey, quantity]) => {
- if (uniqueKey.startsWith(`${selectedItem.brandId}_`)) {
- existingQuantities[uniqueKey] = quantity
- }
- })
- }
-
- // 打开商品明细弹窗
- this.$refs.productDetailPopup.open(productInfo, brandInfo, existingQuantities, originalItem.styleCache || {})
- },
-
- // 处理商品明细确认修改事件
- onDetailConfirmChanges(data) {
- const { productInfo, brandInfo, updatedStyles } = data
-
- // 查找原始商品
- const originalItem = this.findOriginalItem(productInfo.id)
- if (!originalItem) return
-
- // 清理当前品牌的所有款式数据
- const brandPrefix = `${brandInfo.id}_`
- if (originalItem.brandStyleQuantities) {
- Object.keys(originalItem.brandStyleQuantities).forEach(key => {
- if (key.startsWith(brandPrefix)) {
- delete originalItem.brandStyleQuantities[key]
- if (originalItem.styleCache && originalItem.styleCache[key]) {
- delete originalItem.styleCache[key]
- }
- }
- })
- }
-
- // 重新设置款式数据
- if (!originalItem.brandStyleQuantities) {
- this.$set(originalItem, 'brandStyleQuantities', {})
- }
- if (!originalItem.styleCache) {
- this.$set(originalItem, 'styleCache', {})
- }
-
- updatedStyles.forEach(style => {
- if (style.quantity > 0) {
- const uniqueKey = `${brandInfo.id}_${style.id}`
- this.$set(originalItem.brandStyleQuantities, uniqueKey, style.quantity)
- this.$set(originalItem.styleCache, uniqueKey, {
- brandInfo: brandInfo,
- styleInfo: style
- })
- }
- })
-
- // uni.showToast({
- // title: '修改成功',
- // icon: 'success'
- // })
- },
-
- // 处理商品明细弹窗关闭事件
- onDetailPopupClose() {
- // 弹窗关闭时的处理逻辑
- },
-
- // 处理规则确认事件
- onRuleConfirm() {
- // 如果是在等待品牌选择的状态下关闭规则弹窗,则接着打开品牌选择
- if (this.isWaitingForBrandSelection) {
- this.isWaitingForBrandSelection = false; // 清除等待状态
- const categoryId = this.categories[this.currentCategory]?.id;
- const item = this.allProducts[categoryId]?.[this.pendingBrandIndex];
- // 记录该商品的规则已被查看
- this.viewedRuleItems.add(item.id);
- this.$refs.brandSelector.open(item.id); // 打开品牌索引弹窗
- } else if (this.pendingBrandIndex !== null) {
- // 无品牌商品,规则弹窗关闭后加数量
- const categoryId = this.categories[this.currentCategory]?.id;
- const item = this.allProducts[categoryId]?.[this.pendingBrandIndex];
- if (item) {
- let newQuantity = (item.quantity || 0) + 1
- this.$set(item, 'quantity', newQuantity)
- }
- this.pendingBrandIndex = null
- }
- },
- // 获取品牌信息
- getBrandInfo(brandId) {
- // 从所有商品的品牌缓存中查找品牌信息
- for (const productId in this.brandCache) {
- const brandInfo = this.brandCache[productId].find(brand => brand.id === brandId)
- if (brandInfo) {
- return brandInfo
- }
- }
- // 如果缓存中没有找到,也从当前brandList中查找(兼容性)
- return this.brandList.find(brand => brand.id === brandId)
- },
- // 获取商品的总数量(所有品牌款式)
- getItemTotalQuantity(item) {
- if (item.brandStyleQuantities && Object.keys(item.brandStyleQuantities).length > 0) {
- return Object.values(item.brandStyleQuantities).reduce((sum, qty) => sum + qty, 0)
- }
- if (item.brandQuantities && Object.keys(item.brandQuantities).length > 0) {
- return Object.values(item.brandQuantities).reduce((sum, qty) => sum + qty, 0)
- }
- return item.quantity || 0
- },
- // 显示回收规则
- showRules(item) {
- // 检查是否需要显示回收规则
- if (item.isRecycleRules !== 'Y') {
- // 不需要显示规则,直接添加数量
- if (item.isPin === 'Y') {
- // 品牌商品,直接打开品牌选择
- this.pendingBrandIndex = this.recycleList.findIndex(i => i.id === item.id)
- this.$refs.brandSelector.open(item.id)
- } else {
- // 非品牌商品,直接加数量
- let newQuantity = (item.quantity || 0) + 1
- this.$set(item, 'quantity', newQuantity)
- }
- return
- }
-
- // isPin=Y: 弹规则,读到底部后自动弹品牌;isPin=N: 只弹规则
- if (item.isPin === 'Y') {
- // 检查该商品是否已经查看过规则
- if (this.viewedRuleItems.has(item.id)) {
- // 如果已经查看过,直接跳过规则弹窗,进入品牌选择
- this.isWaitingForBrandSelection = false;
- this.$refs.brandSelector.open(item.id);
- return;
- }
- // 获取回收规则富文本
- this.$api('getGoodsRecycleRule', { goodsId: item.id }, res => {
- const ruleContent = (res.code === 200 && res.result) ? res.result : '<p>暂无回收规则</p>'
- this.$refs.rulePopup.openRulePopup(ruleContent)
- // 规则弹窗关闭后自动弹品牌弹窗逻辑在onRuleConfirm已实现
- })
- } else {
- // isPin=N 只弹规则
- this.$api('getGoodsRecycleRule', { goodsId: item.id }, res => {
- const ruleContent = (res.code === 200 && res.result) ? res.result : '<p>暂无回收规则</p>'
- this.$refs.rulePopup.openRulePopup(ruleContent)
- // 不弹品牌弹窗
- this.isWaitingForBrandSelection = false;
- })
- }
- },
- showMore() {
- uni.showToast({
- title: '更多规则请咨询客服',
- icon: 'none'
- })
- },
- submitOrder() {
- // 检查用户是否被拉入黑名单
- if (this.isUserBlacklisted) {
- uni.showModal({
- title: '提示',
- content: '您的账户已被限制使用回收服务,如有疑问请联系客服。',
- showCancel: false,
- confirmText: '我知道了'
- })
- return
- }
-
- if (this.totalCount < this.minMumber || Number(this.totalPrice) < this.minMoney) {
- uni.showToast({
- title: `各品类混合需要满${this.minMumber}${this.totalUnitText}并且各品类混合需要满${this.minMoney}元才能回收哦`,
- icon: 'none'
- })
- return
- }
-
- // 关闭商品明细弹窗
- this.showDetailPanel = false
-
- this.$refs.rulePopup.openConfirmPopup();
- },
- handlePickupCancel() {
- // 取消回收的处理逻辑
- },
- handlePickupAgree() {
- // 显示总的回收规则弹窗
- this.showGeneralRulesPopup()
- },
-
- // 显示总的回收规则弹窗
- showGeneralRulesPopup() {
- this.isFromPickupFlow = true // 标记是从预约流程触发
- this.showPriceInfoPopup = true
- },
-
- // 关闭价格说明弹窗的方法
- closePriceInfoPopup() {
- console.log('closePriceInfoPopup called');
- this.showPriceInfoPopup = false
- // 如果是从预约流程触发的,关闭弹窗后执行跳转逻辑
- if (this.isFromPickupFlow) {
- this.isFromPickupFlow = false // 重置标志
- this.executePickupFlow()
- }
- },
-
- // 执行预约流程
- executePickupFlow() {
- uni.showLoading({
- title: '提交中...'
- })
- setTimeout(() => {
- uni.hideLoading()
- uni.showToast({
- title: '预约成功',
- icon: 'success'
- })
- this.goToPickup()
- }, 1500)
- },
- goToPickup() {
- // 获取所有选中的衣物(所有分类)
- const selectedItems = this.selectedProducts.map(item => {
- let desc = '允许脏破烂,160码以上'
- if (item.brandName && item.styleName) {
- desc = `品牌:${item.brandName} | 款式:${item.styleName}`
- } else if (item.brandName) {
- desc = `品牌:${item.brandName}`
- } else if (item.styleName) {
- desc = `款式:${item.styleName}`
- }
-
- const baseItem = {
- id: item.id,
- name: item.name,
- icon: item.image,
- quantity: item.quantity,
- unitPrice: item.price,
- maxPrice: item.maxPrice,
- desc: desc
- }
-
- // 如果有品牌信息,添加品牌相关字段
- if (item.brandId) {
- baseItem.brandId = item.brandId
- baseItem.brandName = item.brandName
- baseItem.brandImage = item.brandImage
- }
-
- // 如果有款式信息,添加款式相关字段
- if (item.styleId) {
- baseItem.styleId = item.styleId
- baseItem.styleName = item.styleName
- baseItem.styleImage = item.styleImage
- }
-
- return baseItem
- })
- const itemsStr = encodeURIComponent(JSON.stringify(selectedItems))
- uni.navigateTo({
- url: `/pages/subcomponent/pickup?fromRecycle=true&items=${itemsStr}`
- })
- },
- checkBrand(index) {
- const categoryId = this.categories[this.currentCategory]?.id
- const item = this.allProducts[categoryId]?.[index]
- if (item?.id) {
- this.pendingBrandIndex = index
- this.$refs.brandSelector.open(item.id)
- }
- },
-
- // 添加下拉刷新方法
- async refreshData() {
- try {
- // 这里可以添加刷新数据的逻辑,比如重新获取商品列表等
- // 示例:重新初始化数据
- this.currentCategory = 0
- Object.values(this.allProducts).forEach(categoryItems => {
- categoryItems.forEach(item => {
- item.quantity = 0
- if (item.brandQuantities) {
- item.brandQuantities = {}
- }
- if (item.brandStyleQuantities) {
- item.brandStyleQuantities = {}
- }
- if (item.styleCache) {
- item.styleCache = {}
- }
- })
- })
- // 清空已查看规则的记录
- this.viewedRuleItems.clear()
-
- // 清空品牌缓存
- this.brandCache = {}
-
- // 模拟网络请求延迟
- await new Promise(resolve => setTimeout(resolve, 1000))
-
- uni.showToast({
- title: '刷新成功',
- icon: 'success'
- })
- } catch (error) {
- uni.showToast({
- title: '刷新失败',
- icon: 'none'
- })
- } finally {
- // 停止下拉刷新动画
- uni.stopPullDownRefresh()
- }
- },
- toggleDetailPanel() {
- this.showDetailPanel = !this.showDetailPanel
- },
-
- // 添加更多衣物
- addMoreItems() {
- this.showDetailPanel = false
- },
-
- // 检查新用户首次访问规则
- checkFirstTimeRules() {
- // 从本地存储检查是否已显示过首次规则
- const hasShown = uni.getStorageSync('hasShownFirstTimeRules')
- if (!hasShown && !this.hasShownFirstTimeRules) {
- this.showFirstTimeRulesPopup()
- }
- },
-
- // 显示新用户首次访问规则弹窗
- showFirstTimeRulesPopup() {
- // 显示价格说明弹窗
- this.showPriceInfoPopup = true
-
- // 标记已显示过首次规则
- this.hasShownFirstTimeRules = true
- uni.setStorageSync('hasShownFirstTimeRules', true)
- },
- fetchUserInfo() {
- if (uni.getStorageSync('token')) {
- this.login_status = getApp().globalData.login_status;
- this.$api("getUserByToken", {}, (res) => {
- if (res.code == 200) {
- this.userInfo = res.result
- // 检查用户是否被拉入黑名单
- this.isUserBlacklisted = res.result.isBlack === 'Y'
- // isTuiType 为0用户,1推广达人,2推广大使
- }
- })
- } else {
- this.login_status = false;
- }
- },
- updateQuantityByProduct(item, delta) {
- // 在明细弹窗中更新数量
- if (item.brandId && item.styleId) {
- // 有品牌和款式ID的商品(新的品牌款式逻辑)
- const originalItem = this.findOriginalItem(item.id)
- if (originalItem && originalItem.brandStyleQuantities) {
- const uniqueKey = `${item.brandId}_${item.styleId}`
- const currentQty = originalItem.brandStyleQuantities[uniqueKey] || 0
- const newQty = Math.max(0, currentQty + delta)
-
- if (newQty > 0) {
- this.$set(originalItem.brandStyleQuantities, uniqueKey, newQty)
- } else {
- // 如果数量为0,删除该品牌款式
- delete originalItem.brandStyleQuantities[uniqueKey]
- if (originalItem.styleCache && originalItem.styleCache[uniqueKey]) {
- delete originalItem.styleCache[uniqueKey]
- }
- }
-
- // 同步更新显示的数量
- item.quantity = newQty
- }
- } else if (item.brandId) {
- // 有品牌ID但没有款式ID的商品(兼容旧逻辑)
- const originalItem = this.findOriginalItem(item.id)
- if (originalItem && originalItem.brandQuantities) {
- const currentQty = originalItem.brandQuantities[item.brandId] || 0
- const newQty = Math.max(0, currentQty + delta)
-
- if (newQty > 0) {
- this.$set(originalItem.brandQuantities, item.brandId, newQty)
- } else {
- // 如果数量为0,删除该品牌
- delete originalItem.brandQuantities[item.brandId]
- }
-
- // 同步更新显示的数量
- item.quantity = newQty
- }
- } else {
- // 没有品牌的商品
- if (!item.quantity) item.quantity = 0
- item.quantity = Math.max(0, item.quantity + delta)
-
- // 同步到原商品
- const originalItem = this.findOriginalItem(item.id)
- if (originalItem) {
- this.$set(originalItem, 'quantity', item.quantity)
- }
- }
- },
-
- // 查找原始商品对象
- findOriginalItem(itemId) {
- for (const categoryItems of Object.values(this.allProducts)) {
- const item = categoryItems.find(i => i.id === itemId)
- if (item) return item
- }
- return null
- },
-
- loadMoreGoods() {
- const categoryId = this.categories[this.currentCategory]?.id
- const page = (this.allProductsPage[categoryId] || 1) + 1
- const total = this.allProductsTotal[categoryId] || 0
- const loaded = (this.allProducts[categoryId] || []).length
-
- if (this.loadingMore || this.finished) return
-
- if (loaded < total) {
- this.loadingMore = true
- this.fetchGoodsList(categoryId, page, () => {
- this.loadingMore = false
- // 判断是否加载完
- const newLoaded = (this.allProducts[categoryId] || []).length
- this.finished = newLoaded >= (this.allProductsTotal[categoryId] || 0)
- })
- } else {
- this.finished = true
- }
- },
-
- // 初始化页面数据的方法
- initializePageData() {
- const options = this.loadOptions || {}
-
- if (options && options.categoryId) {
- const idx = this.categories.findIndex(c => c.id == options.categoryId)
- if (idx !== -1) this.currentCategory = idx
- }
-
- if (this.categories.length > 0) {
- this.fetchGoodsList(this.categories[this.currentCategory].id, 1)
- }
-
- uni.$on('bannerListUpdated', () => {
- this.$forceUpdate && this.$forceUpdate()
- })
-
- if (getApp().globalData.bannerList && getApp().globalData.bannerList.length > 0) {
- this.$forceUpdate && this.$forceUpdate()
- }
-
- // 检查全局清空标志(兼容 reLaunch)
- if (getApp().globalData.shouldClearRecycle) {
- Object.values(this.allProducts).forEach(categoryItems => {
- categoryItems.forEach(item => {
- this.$set(item, 'quantity', 0)
- if (item.brandQuantities) {
- this.$set(item, 'brandQuantities', {})
- }
- if (item.brandStyleQuantities) {
- this.$set(item, 'brandStyleQuantities', {})
- }
- if (item.styleCache) {
- this.$set(item, 'styleCache', {})
- }
- })
- })
- // 清空已查看规则的记录
- this.viewedRuleItems.clear()
- this.showDetailPanel = false
- this.brandCache = {} // 清空品牌缓存
- this.$forceUpdate()
- getApp().globalData.shouldClearRecycle = false
- }
- },
-
- },
- created() {
- this.currentCategory = 0
- this.$nextTick(() => {
- if (this.categories.length > 0) {
- const firstCategoryId = this.categories[0]?.id
- if (firstCategoryId) {
- this.fetchGoodsList(firstCategoryId, 1)
- }
- }
- })
- },
- mounted() {
- this.$nextTick(() => {
- const query = uni.createSelectorQuery().in(this)
- query.select('.uv-tabbar').boundingClientRect(rect => {
- if (rect && rect.height) {
- this.tabbarHeight = rect.height
- } else {
- this.tabbarHeight = uni.upx2px ? uni.upx2px(95) : 45
- }
- // console.log(this.tabbarHeight,'tabbarHeight')
- }).exec()
- })
- },
- onLoad(options) {
- // 保存options参数
- this.loadOptions = options
-
- // 检查App数据是否已经准备好
- if (!getApp().globalData.isAppDataReady) {
- // 显示加载状态
- uni.showLoading({
- title: '加载中...',
- mask: true
- })
-
- // 监听App数据准备完成事件
- uni.$on('appDataReady', () => {
- uni.hideLoading()
- this.initializePageData()
- })
- } else {
- // App数据已经准备好,直接初始化页面数据
- this.initializePageData()
- }
- },
-
- onUnload() {
- uni.$off('bannerListUpdated')
- // 移除事件监听
- uni.$off('clearRecycleOrderData')
- },
- onShow() {
- // 获取用户信息,检查黑名单状态
- this.fetchUserInfo()
-
- // 检查是否为新用户首次访问,显示回收规则
- this.checkFirstTimeRules()
-
- const id = getApp().globalData.targetRecycleCategoryId
- if (id) {
- const trySwitch = () => {
- if (this.categories.length > 0) {
- const idx = this.categories.findIndex(c => String(c.id) === String(id))
- if (idx !== -1) {
- this.currentCategory = idx
- const categoryId = this.categories[idx]?.id
- if (categoryId && !this.allProducts[categoryId]) {
- this.loadingMore = false
- this.finished = false
- this.fetchGoodsList(categoryId, 1)
- }
- }
- getApp().globalData.targetRecycleCategoryId = null
- } else {
- setTimeout(trySwitch, 100)
- }
- }
- trySwitch()
- }
- // 检查全局清空标志
- if (getApp().globalData.shouldClearRecycle) {
- Object.values(this.allProducts).forEach(categoryItems => {
- categoryItems.forEach(item => {
- this.$set(item, 'quantity', 0)
- if (item.brandQuantities) {
- this.$set(item, 'brandQuantities', {})
- }
- if (item.brandStyleQuantities) {
- this.$set(item, 'brandStyleQuantities', {})
- }
- if (item.styleCache) {
- this.$set(item, 'styleCache', {})
- }
- })
- })
- // 清空已查看规则的记录
- this.viewedRuleItems.clear()
- this.showDetailPanel = false
- this.brandCache = {} // 清空品牌缓存
- this.$forceUpdate()
- getApp().globalData.shouldClearRecycle = false
- }
- // 监听清除订单数据的事件
- uni.$on('clearRecycleOrderData', () => {
- // 清除所有商品的选中数量,保证响应式
- Object.values(this.allProducts).forEach(categoryItems => {
- categoryItems.forEach(item => {
- this.$set(item, 'quantity', 0)
- if (item.brandQuantities) {
- this.$set(item, 'brandQuantities', {})
- }
- if (item.brandStyleQuantities) {
- this.$set(item, 'brandStyleQuantities', {})
- }
- if (item.styleCache) {
- this.$set(item, 'styleCache', {})
- }
- })
- })
- // 清空已查看规则的记录
- this.viewedRuleItems.clear()
- // 清空品牌缓存
- this.brandCache = {}
- // 重置其他相关数据
- this.showDetailPanel = false
- this.$forceUpdate()
- })
- },
- watch: {
- categories(newVal) {
- const id = getApp().globalData.targetRecycleCategoryId
- const idx = newVal.findIndex(c => String(c.id) === String(id))
- if (id && newVal.length > 0 && idx !== -1) {
- this.currentCategory = idx
- getApp().globalData.targetRecycleCategoryId = null
- // 自动加载右侧商品
- const categoryId = newVal[idx]?.id
- if (categoryId && !this.allProducts[categoryId]) {
- this.loadingMore = false
- this.finished = false
- this.fetchGoodsList(categoryId, 1)
- }
- }
- }
- },
- }
- </script>
-
- <style lang="scss" scoped>
- .container {
- display: flex;
- flex-direction: column;
- height: 100vh;
- background-color: #f5f5f5;
- overflow: hidden;
- }
-
-
-
- .goods-list {
- // flex: 1;
- display: flex;
- position: relative;
- height: calc(110vh - 320rpx - 160rpx - env(safe-area-inset-bottom));
- /* 减去banner、底部栏和绿色提示条的高度 */
- margin-top: -10rpx;
- z-index: 2;
- border-radius: 20rpx 20rpx 0 0;
- overflow: hidden;
- padding: 30rpx;
- box-shadow: 0 -4rpx 8rpx rgba(0, 0, 0, 0.05);
- background: linear-gradient(to bottom, #fff7e8, 20%, #ffffff);
-
- .category-nav {
- width: 20%;
- background: #ffffff;
- height: 100%;
- border-right: 1rpx solid rgba(255, 126, 14, 0.1);
- margin: 1rpx;
- border-radius: 20rpx 0 0 0;
- margin-right: 20rpx;
- overflow-y: auto;
- scrollbar-width: none;
- /* Firefox */
- -ms-overflow-style: none;
-
- /* IE and Edge */
- &::-webkit-scrollbar {
- width: 0 !important;
- display: none;
- /* Chrome, Safari, Opera */
- }
-
- .category-item {
- position: relative;
- padding: 28rpx 20rpx;
- text-align: center;
- font-family: PingFang SC;
- font-weight: 600;
- font-size: 15px;
- line-height: 100%;
- letter-spacing: 0px;
- color: #666;
-
- .category-dot {
- position: absolute;
- top: 15rpx;
- right: 15rpx;
- min-width: 32rpx;
- height: 32rpx;
- padding: 0 6rpx;
- background: #ff7a0e;
- border-radius: 16rpx;
- color: #fff;
- font-size: 20rpx;
- text-align: center;
- line-height: 32rpx;
- box-sizing: border-box;
- }
-
- &.active {
- color: #ff7a0e;
- font-weight: bold;
- background: #fff7e8;
- position: relative;
-
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: 50%;
- transform: translateY(-50%);
- width: 6rpx;
- height: 36rpx;
- background: #ff7a0e;
- border-radius: 3rpx;
- }
- }
- }
- }
-
- .goods-content {
- flex: 1;
- height: 100%;
- padding: 0 0 180rpx 0;
- /* 添加底部padding,为固定底部栏预留空间 */
- background: #ffffff;
- width: 70%;
- margin: 1rpx;
- margin-left: 0;
- border-radius: 0 20rpx 0 0;
- overflow-y: auto;
- box-sizing: border-box;
- scrollbar-width: none;
- /* Firefox */
- -ms-overflow-style: none;
-
- /* IE and Edge */
- &::-webkit-scrollbar {
- width: 0 !important;
- display: none;
- /* Chrome, Safari, Opera */
- }
- }
- }
-
- .goods-item {
- display: flex;
- align-items: flex-start;
- padding: 30rpx 0;
- border-bottom: 1rpx solid #f5f5f5;
-
- .goods-img-container {
- position: relative;
- width: 180rpx;
- height: 180rpx;
- margin-right: 28rpx;
- flex-shrink: 0;
- }
-
- .goods-item-img {
- width: 100%;
- height: 100%;
- border-radius: 24rpx;
- background: #f8f8f8;
- object-fit: contain;
- }
-
- .brand-tag {
- position: absolute;
- top: 0rpx;
- left: 0rpx;
- background: rgba(0, 0, 0, 0.8);
- color: #fff;
- font-size: 20rpx;
- padding: 4rpx 8rpx;
- border-radius: 8rpx;
- z-index: 2;
- }
-
- .goods-info-wrap {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- min-width: 0;
- }
-
- .goods-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10rpx;
- }
-
- .goods-name {
- font-family: PingFang SC;
- font-weight: 500;
- font-size: 14px;
- line-height: 140%;
- letter-spacing: 0%;
- vertical-align: middle;
- color: #333;
- font-weight: bold;
- flex-shrink: 1;
- flex-grow: 1;
- }
-
- .brand-check-placeholder {
- flex-shrink: 0;
- margin-left: 10rpx;
- }
-
- .brand-check {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- border: 1px solid #f8a01d;
- border-radius: 8rpx;
- color: #ff7a0e;
- font-family: PingFang SC;
- font-weight: 400;
- font-size: 12px;
- padding: 4rpx 10rpx;
- line-height: 1;
- white-space: nowrap;
-
- text {
- margin-right: 4rpx;
- }
- }
-
- .goods-desc {
- font-size: 20rpx;
- color: #999;
- display: block;
- // margin-bottom: 20rpx;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .goods-info {
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: nowrap;
- gap: 5rpx;
- margin-top: 10rpx;
- }
-
- .price-info {
- display: flex;
- align-items: baseline;
- white-space: nowrap;
- flex-shrink: 0;
-
- .price-symbol {
- font-size: 24rpx;
- color: #ff7a0e;
- }
-
- .price-value {
- font-size: 36rpx;
- color: #ff7a0e;
- font-weight: bold;
- margin: 0 0rpx;
- white-space: nowrap;
- }
-
- .price-unit {
- font-size: 24rpx;
- color: #999;
- white-space: nowrap;
- }
- }
-
- .quantity-control {
- display: flex;
- align-items: center;
- flex-shrink: 0;
- white-space: nowrap;
-
- button {
- width: 60rpx;
- height: 60rpx;
- padding: 0;
- margin: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 28rpx;
- color: #666;
- background: #ffffff;
- border: none;
- border-radius: 50%;
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.8;
- }
- }
-
- .quantity {
- width: 50rpx;
- text-align: center;
- font-size: 32rpx;
- color: #333;
- }
- }
-
- .rules-brand-row {
- display: flex;
- align-items: center;
- margin-top: 20rpx;
- gap: 16rpx;
-
- .rules-link {
- margin-top: 0;
-
- .rules {
- display: inline-flex;
- align-items: center;
- font-family: PingFang SC;
- font-weight: 400;
- font-size: 12px;
- color: #666;
- white-space: nowrap;
- }
- }
-
- .brand-check-placeholder {
- margin-left: 12rpx;
- }
- }
- }
-
- .other-unrecycle-card {
- display: flex;
- align-items: center;
- background: #fff;
- border-radius: 24rpx;
- box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
- padding: 30rpx 30rpx 30rpx 30rpx;
- margin: 30rpx 0 0 0;
- }
-
- .other-unrecycle-img {
- width: 120rpx;
- height: 120rpx;
- border-radius: 24rpx;
- background: #f8f8f8;
- margin-right: 28rpx;
- object-fit: contain;
- flex-shrink: 0;
- }
-
- .other-unrecycle-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- min-width: 0;
- overflow: hidden;
- }
-
- .other-unrecycle-title {
- font-size: 30rpx;
- color: #222;
- font-weight: bold;
- margin-bottom: 8rpx;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .other-unrecycle-desc {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 12rpx;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- }
-
- .other-unrecycle-price-row {
- display: flex;
- align-items: center;
- white-space: nowrap;
- }
-
- .other-unrecycle-price {
- font-size: 28rpx;
- color: #ff9c00;
- font-weight: bold;
- white-space: nowrap;
- }
-
- .other-unrecycle-btn {
- width: 60rpx;
- height: 60rpx;
- margin-left: 24rpx;
- border-radius: 50%;
- background: #fff;
- color: #666;
- font-size: 36rpx;
- border: none;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- .fixed-bottom-wrap {
- position: fixed;
- padding-bottom: 120rpx;
- left: 0;
- bottom: calc(env(safe-area-inset-bottom));
- // bottom: calc(v-bind('tabbarHeight + "rpx"') + env(safe-area-inset-bottom));
- width: 100vw;
- z-index: 100;
- background: transparent;
- box-sizing: border-box;
- pointer-events: auto;
- }
-
- .bottom-bar-divider {
- width: 100%;
- height: 1px;
- background: #f0f0f0;
- position: absolute;
- left: 0;
- bottom: 0;
- z-index: 1;
- }
-
- .green-tip-bar {
- width: 100%;
- background: #eaffea;
- color: #13ac47;
- font-size: 20rpx;
- padding: 8rpx 30rpx;
- box-sizing: border-box;
- text-align: center;
- display: flex;
- align-items: center;
- justify-content: center;
- line-height: 1.4;
- min-height: 40rpx;
-
- .tip-highlight {
- color: #ff9c00;
- font-weight: bold;
- font-size: 20rpx;
- }
- }
-
- .bottom-bar {
- width: 100%;
- background-color: #fff;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 30rpx;
- box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
- height: 120rpx;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- border-bottom-left-radius: env(safe-area-inset-bottom);
- border-bottom-right-radius: env(safe-area-inset-bottom);
-
- .bottom-left {
- // flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
-
- .summary-row {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- color: #333;
-
- .summary-label {
- color: #333;
- }
-
- .summary-count {
- color: #ff9c00;
- font-weight: bold;
- font-size: 28rpx;
- }
- }
-
- .amount-row {
- display: flex;
- align-items: center;
- margin-top: 4rpx;
-
- .amount {
- color: #ff9c00;
- font-size: 44rpx;
- font-weight: bold;
- vertical-align: middle;
- }
- }
- }
-
- .submit-btn {
- width: 300rpx;
- height: 88rpx;
- background: linear-gradient(to right, #ffd01e, #ff8917);
- border-radius: 44rpx;
- color: #fff;
- font-size: 32rpx;
- font-weight: bold;
- display: flex;
- align-items: center;
- justify-content: center;
- border: none;
- // margin-left: 0rpx;
- box-shadow: 0 4rpx 16rpx rgba(255, 156, 0, 0.08);
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.9;
- }
- }
- }
-
- .detail-popup-mask {
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- // padding-bottom: calc(env(safe-area-inset-bottom));
- // bottom: calc(120rpx + env(safe-area-inset-bottom));
- // bottom: calc(90rpx + env(safe-area-inset-bottom));
- /* tabbar高度+安全区 */
- background: rgba(0, 0, 0, 0.35);
- z-index: 9999;
- display: flex;
- align-items: flex-end;
- justify-content: center;
- }
-
- .detail-popup {
- width: 100vw;
- max-width: none;
- background: #fff;
- border-radius: 48rpx 48rpx 0 0;
- box-shadow: 0 8rpx 48rpx rgba(0, 0, 0, 0.18);
- display: flex;
- flex-direction: column;
- align-items: stretch;
- position: relative;
- padding: 0;
- padding-bottom: calc(env(safe-area-inset-bottom));
- overflow: hidden;
- min-height: 80vh;
- bottom: 0;
- }
-
- .detail-popup-close {
- position: absolute;
- right: 36rpx;
- top: 36rpx;
- font-size: 36rpx;
- color: #bbb;
- z-index: 2;
- }
-
- .popup-green-tip {
- border-radius: 48rpx 48rpx 0 0;
- font-size: 20rpx;
- padding: 24rpx 30rpx 0 30rpx;
- background: #eaffea;
- color: #13ac47;
- text-align: left;
- }
-
- .panel-header {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 32rpx;
- font-weight: bold;
- padding: 40rpx 36rpx 0 36rpx;
- background: #fff;
- position: relative;
- }
-
- .panel-title {
- font-size: 32rpx;
- color: #222;
- font-weight: bold;
- text-align: center;
- flex: 1;
- }
-
- .popup-panel-list {
- // flex: 1;
- width: 710rpx;
- overflow-y: auto;
- height: 70vh !important;
- padding: 0 24rpx;
- scrollbar-width: none;
- /* Firefox */
- -ms-overflow-style: none;
-
- /* IE and Edge */
- &::-webkit-scrollbar {
- width: 0 !important;
- display: none;
- /* Chrome, Safari, Opera */
- }
- }
-
- .panel-item {
- display: flex;
- align-items: center;
- justify-content: flex-start;
- padding: 24rpx 0;
- border-bottom: 1px solid #f0f0f0;
- cursor: pointer;
-
- &:active {
- // background: #f8f8f8;
- }
- }
-
- .panel-img-container {
- position: relative;
- width: 100rpx;
- height: 100rpx;
- margin-right: 20rpx;
- flex-shrink: 0;
- }
-
- .panel-item-img {
- width: 100%;
- height: 100%;
- border-radius: 16rpx;
- background: #f8f8f8;
- }
-
- .panel-brand-tag {
- position: absolute;
- top: 0rpx;
- left: 0rpx;
- background: rgba(0, 0, 0, 0.8);
- color: #fff;
- font-size: 18rpx;
- padding: 2rpx 6rpx;
- border-radius: 6rpx;
- z-index: 2;
- }
-
- .panel-item-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- min-width: 0;
-
- }
-
- .panel-item-name {
- font-size: 28rpx;
- color: #222;
- font-weight: bold;
- margin-bottom: 4rpx;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- }
-
- .panel-item-desc {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 4rpx;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- }
-
- .panel-item-price {
- font-size: 26rpx;
- color: #ff9c00;
- margin-top: 2rpx;
- }
-
- .panel-quantity-control {
- display: flex;
- align-items: center;
- margin-left: 20rpx;
- // margin-right: 30rpx;
- flex-shrink: 0;
- }
-
- .panel-quantity-control button {
- width: 48rpx;
- height: 48rpx;
- padding: 0;
- margin: 0 8rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 32rpx;
- color: #666;
- background: #ffffff;
- border: none;
- border-radius: 50%;
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.8;
- }
- }
-
- .panel-quantity-control .quantity {
- width: 30rpx;
- text-align: center;
- font-size: 28rpx;
- color: #333;
- }
-
- .popup-bottom-bar {
- width: 100%;
- background-color: #fff;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 30rpx;
- box-sizing: border-box;
- box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
- height: 120rpx;
- border-top: 1px solid #f0f0f0;
- border-bottom-left-radius: 48rpx;
- border-bottom-right-radius: 48rpx;
-
- // padding-bottom: env(safe-area-inset-bottom);
- .bottom-left {
- display: flex;
- flex-direction: column;
- justify-content: center;
-
- .summary-row {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- color: #333;
-
- .summary-label {
- color: #333;
- }
-
- .summary-count {
- color: #ff9c00;
- font-weight: bold;
- font-size: 28rpx;
- }
- }
-
- .amount-row {
- display: flex;
- align-items: center;
- margin-top: 4rpx;
-
- .amount {
- color: #ff9c00;
- font-size: 44rpx;
- font-weight: bold;
- vertical-align: middle;
- }
- }
- }
-
- .submit-btn {
- width: 300rpx;
- height: 88rpx;
- background: linear-gradient(to right, #ffd01e, #ff8917);
- border-radius: 44rpx;
- color: #fff;
- font-size: 32rpx;
- font-weight: bold;
- display: flex;
- align-items: center;
- justify-content: center;
- border: none;
- box-shadow: 0 4rpx 16rpx rgba(255, 156, 0, 0.08);
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.9;
- }
- }
- }
-
- /* 添加衣物浮窗按钮 */
- .floating-add-btn {
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- bottom: 210rpx;
- width: 160rpx;
- height: 80rpx;
- background: linear-gradient(to right, #ffd01e, #ff8917);
- border-radius: 40rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- box-shadow: 0 8rpx 24rpx rgba(255, 156, 0, 0.3);
- z-index: 10;
-
- &:active {
- opacity: 0.9;
- transform: translateX(-50%) scale(0.95);
- }
-
- .floating-btn-text {
- color: #fff;
- font-size: 28rpx;
- font-weight: bold;
- line-height: 1;
- text-align: center;
- }
- }
-
- .uv-tabbar {
- z-index: 1000;
- }
-
- .loading-more {
- text-align: center;
- color: #999;
- padding: 20rpx 0;
- font-size: 26rpx;
- }
-
-
- .price-info-popup-mask {
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.4);
- z-index: 996000;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- .price-info-popup {
- width: 85vw;
- max-width: 600rpx;
- background: #fff;
- border-radius: 24rpx;
- box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- padding: 40rpx 40rpx;
-
- .price-info-popup-title {
- font-size: 34rpx;
- color: #333;
- font-weight: bold;
- text-align: center;
- margin-bottom: 30rpx;
- }
-
- .price-info-popup-content {
- width: 100%;
- max-height: 50vh;
-
- .price-info-section {
- margin-bottom: 30rpx;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .price-info-heading {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- margin-bottom: 15rpx;
- }
-
- .price-info-text {
- font-size: 26rpx;
- color: #666;
- line-height: 1.6;
- }
- }
- }
-
- .price-info-popup-btn {
- width: 100%;
- height: 88rpx;
- background: linear-gradient(to right, #ffd01e, #ff8917);
- border-radius: 44rpx;
- color: #fff;
- font-size: 32rpx;
- font-weight: bold;
- display: flex;
- align-items: center;
- justify-content: center;
- border: none;
- margin-top: 40rpx;
- box-shadow: 0 4rpx 16rpx rgba(255, 156, 0, 0.08);
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.9;
- }
- }
- }
-
-
-
- .rules-link {
- min-width: 90rpx;
- padding: 0 12rpx;
-
- .rules {
- font-size: 15px;
- white-space: normal;
- overflow: visible;
- }
- }
-
- // ... existing code ...
- .rules-brand-row {
- display: flex;
- align-items: center;
- margin-top: 20rpx;
- gap: 24rpx; // 增大间距
-
- .rules-link {
- margin-top: 0;
- }
-
- .brand-check-placeholder {
- margin-left: 16rpx;
- }
- }
-
- // ... existing code ...
- .price-info {
- display: flex;
- align-items: baseline;
- white-space: nowrap;
- flex-shrink: 0;
- gap: 12rpx; // 增大间距
-
- .price-symbol {
- font-size: 32rpx; // 增大符号
- color: #ff7a0e;
- }
-
- .price-value {
- font-size: 44rpx; // 增大数字
- color: #ff7a0e;
- font-weight: bold;
- margin: 0 6rpx;
- white-space: nowrap;
- }
-
- .price-unit {
- font-size: 28rpx;
- color: #999;
- white-space: nowrap;
- }
- }
-
- .quantity-control {
- display: flex;
- align-items: center;
- flex-shrink: 0;
- white-space: nowrap;
- gap: 0rpx; // 增大间距
-
- button {
- width: 30rpx; // 增大按钮
- height: 72rpx;
- padding: 0;
- margin: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 36rpx; // 增大符号
- color: #666;
- background: #ffffff;
- border: none;
- border-radius: 50%;
-
- &::after {
- border: none;
- }
-
- &:active {
- opacity: 0.8;
- }
- }
-
- .quantity {
- width: 60rpx;
- text-align: center;
- font-size: 36rpx; // 增大数字
- color: #333;
- }
- }
- </style>
|