1640 lines
44 KiB
Vue
1640 lines
44 KiB
Vue
<template>
|
||
<view class="share-page">
|
||
<page-meta :page-style="pageStyle"/>
|
||
<view class="share-hero">
|
||
<AppNavbar title="药分享">
|
||
</AppNavbar>
|
||
<view class="stats-card">
|
||
<view class="flex justify-between items-center w-100p">
|
||
<!-- <view class="stat-item" @click="jumpWithAuth('/pages/share/mine')">-->
|
||
<!-- <view class="stat-value">-->
|
||
<!-- <text class="stat-number">{{-->
|
||
<!-- data.income-->
|
||
<!-- }}-->
|
||
<!-- </text>-->
|
||
<!-- <text class="stat-unit">元</text>-->
|
||
<!-- </view>-->
|
||
<!-- <text class="stat-label">我的晒单收益</text>-->
|
||
<!-- </view>-->
|
||
<view class="stat-item" @click="jumpWithAuth('/pages/share/mine')">
|
||
<view class="stat-value">
|
||
<text class="stat-number">{{ data.num }}</text>
|
||
<text class="stat-unit">个</text>
|
||
</view>
|
||
<text class="stat-label">我的晒单数量</text>
|
||
</view>
|
||
<!-- <view class="stat-action" @click="jumpWithAuth('/pages/bonus/withdraw')">去提现</view>-->
|
||
</view>
|
||
<view class="flex justify-center items-center w-100p pt-20 border-top" v-if="isLoggedIn && user.canAuth === 1">
|
||
<!-- <view class="stat-item flex-1 justify-center items-center">-->
|
||
<!-- <view class="stat-value">-->
|
||
<!-- <text class="stat-number text-main">{{-->
|
||
<!-- data.totalIncome-->
|
||
<!-- }}-->
|
||
<!-- </text>-->
|
||
<!-- <text class="stat-unit">元</text>-->
|
||
<!-- </view>-->
|
||
<!-- <text class="stat-label">合计晒单收益</text>-->
|
||
<!-- </view>-->
|
||
<view class="stat-item flex-1 justify-center items-center">
|
||
<view class="stat-value">
|
||
<text class="stat-number text-main">{{ data.totalNum }}</text>
|
||
<text class="stat-unit">个</text>
|
||
</view>
|
||
<text class="stat-label">合计晒单数量</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 今日晒单 -->
|
||
<view class="today-head">
|
||
<view class="city" @tap="openAreaPicker">
|
||
<u-icon name="map" size="26" color="#27c7a4"/>
|
||
<text>{{ currentCity }}</text>
|
||
</view>
|
||
<view class="head-center">
|
||
<image class="head-icon"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/a215c967f5d89626826da5bc3bec9130.png"
|
||
mode="heightFix"/>
|
||
</view>
|
||
<view v-if="canShowTodayMore" class="today-more" @tap="showAllTodayEntries">更多</view>
|
||
</view>
|
||
<view class="filter-chips">
|
||
<view class="filter-chip" @tap="openMerchantPicker">{{ merchantLabel }}</view>
|
||
</view>
|
||
|
||
<view class="today-list">
|
||
<template v-if="displayedTodayEntries.length">
|
||
<view class="today-card" v-for="(item, index) in displayedTodayEntries" :key="index" @click="showDetail(item)">
|
||
<view class="today-row">
|
||
<text class="today-label">匹配门店:</text>
|
||
<text class="today-value">{{ item.merchantName }}</text>
|
||
</view>
|
||
<view class="today-row">
|
||
<text class="today-label">订单号:</text>
|
||
<text class="today-value">{{ item.orderNo }}</text>
|
||
</view>
|
||
<view class="today-row today-row-space">
|
||
<text class="today-time">分享时间:{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}</text>
|
||
<view class="today-distance">
|
||
<u-icon name="map" size="24" color="#ff9f43"/>
|
||
<text>距离{{ item.distance || '100米' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<u-empty v-else
|
||
icon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/ddcc1bbd561d97128ed19407b07e299b.png"
|
||
text="暂无数据"/>
|
||
</view>
|
||
|
||
<!-- 分享产品清单 -->
|
||
<view class="product-section">
|
||
<view class="section-head">
|
||
<view class="section-left" style="width: calc(100% - 100rpx)">
|
||
<image class="head-icon"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/17b2063b8acca65f86370593849e607d.png"
|
||
mode="heightFix"/>
|
||
</view>
|
||
<view
|
||
v-if="canShowProductMore"
|
||
class="section-more product-more"
|
||
@tap="showAllProductEntries"
|
||
>更多>>
|
||
</view>
|
||
</view>
|
||
<view class="product-search">
|
||
<view class="search-box">
|
||
<u-icon name="search" size="28" color="#9ca3af"/>
|
||
<input class="search-input" placeholder="请输入关键字搜索" v-model="productKeyword"/>
|
||
</view>
|
||
<view class="search-btn" @click="searchProduct">搜索</view>
|
||
</view>
|
||
<view class="product-grid">
|
||
<template v-if="displayedShareProducts.length">
|
||
<view class="product-card" v-for="(item, index) in displayedShareProducts" :key="index">
|
||
<view class="flex justify-center items-center">
|
||
<u-image
|
||
:src="item.product && item.product.cover ? item.product.cover : 'https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/35fa0fb100376d9925f872fdb752b5f1.jpeg'"
|
||
width="180rpx"
|
||
height="180rpx"
|
||
radius="12rpx"
|
||
mode="aspectFill"
|
||
@click="preview(item.product && item.product.cover ? item.product.cover : 'https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/35fa0fb100376d9925f872fdb752b5f1.jpeg')"
|
||
/>
|
||
</view>
|
||
<view class="product-info">
|
||
<view class="product-name text-center">{{ item.goodsName }}</view>
|
||
<u-line dashed/>
|
||
<view class="product-meta text-center">{{ item.product ? item.product.spec : item.spec }}</view>
|
||
<u-line dashed/>
|
||
<view class="product-meta text-center">{{ item.product ? item.product.makerAbb : '' }}</view>
|
||
<u-line dashed/>
|
||
</view>
|
||
<!-- <view class="product-bonus">-->
|
||
<!-- <text>赚¥{{ item.income || 0 }}</text>-->
|
||
<!-- <image class="bonus-tag"-->
|
||
<!-- src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/2dedec3908af49f55012691f7e22b408.png"-->
|
||
<!-- mode="aspectFit"/>-->
|
||
<!-- </view>-->
|
||
<u-line dashed/>
|
||
<view class="product-bonus">
|
||
<text>共分享{{ item.totalNum ? item.totalNum : 0 }}次</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="rank-section">
|
||
<view class="section-head rank-head">
|
||
<view class="section-left" style="width: calc(100% - 100rpx)">
|
||
<image class="head-icon"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/fe741abe2e0dd7e39a60cb4deba45c4e.png"
|
||
mode="heightFix"/>
|
||
<!-- <text class="section-title">门店晒单排名</text>-->
|
||
</view>
|
||
</view>
|
||
<view class="rank-list">
|
||
<template v-if="brandRanks.length">
|
||
<view class="rank-item" v-for="(item, idx) in brandRanks" :key="idx">
|
||
<view class="rank-left">
|
||
<view class="rank-badge">
|
||
<image v-if="idx === 0" class="rank-medal"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/99b7a70575473d52e38c765a8635428c.png"
|
||
mode="aspectFit"/>
|
||
<image v-else-if="idx === 1" class="rank-medal"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/3a984885c03dbd31f1bd998f98c41493.png"
|
||
mode="aspectFit"/>
|
||
<image v-else-if="idx === 2" class="rank-medal"
|
||
src="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/722383e4ed2ba2e98cd04ce3ee5c4b8f.png"
|
||
mode="aspectFit"/>
|
||
<text v-else class="rank-num">{{ idx + 1 }}</text>
|
||
</view>
|
||
<text class="rank-name">{{ item.merchantName || item.merchant_name || '门店' }}</text>
|
||
</view>
|
||
<view class="rank-right">
|
||
<!-- <text class="rank-reward">奖励¥{{ item.amount || 0 }}</text>-->
|
||
<text class="rank-count">晒单 {{ item.shareList.length || 0 }}</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<u-empty v-else
|
||
icon="https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/ddcc1bbd561d97128ed19407b07e299b.png"
|
||
text="暂无数据"/>
|
||
</view>
|
||
<!-- <view class="rank-rule" @click="openRulePopup">红包奖励规则</view>-->
|
||
</view>
|
||
|
||
<view class="footer">
|
||
<view class="share-action" @click="handleShare">我要分享</view>
|
||
</view>
|
||
|
||
<view v-if="showDetailPopup" class="share-popup-mask" @tap="closeDetailPopup" @touchmove.stop.prevent></view>
|
||
<view v-if="showDetailPopup" class="share-popup card" @tap.stop>
|
||
<view class="popup-head">
|
||
<view class="section-title">晒单详情</view>
|
||
<view class="close-btn" @tap="closeDetailPopup">关闭</view>
|
||
</view>
|
||
<view class="record-meta">门店:{{ detailEntry.merchantName || detailEntry.merchant_name || '-' }}</view>
|
||
<!-- <view class="record-meta text-red">-->
|
||
<!-- 红包:¥{{ formatPrice(detailEntry.income || 0) }}-->
|
||
<!-- <text v-if="hasExtraIncome(detailEntry)">(含额外加提:{{ formatPrice(resolveExtraIncome(detailEntry)) }}元)</text>-->
|
||
<!-- </view>-->
|
||
<view class="record-meta">
|
||
提交人:{{ detailEntry.owner || '-' }} · {{ detailEntry.date || detailEntry.shareDate || detailEntry.activityDateText || '-' }}
|
||
</view>
|
||
<view class="record-meta">留言:{{ detailEntry.remark || '-' }}</view>
|
||
<view class="detail-title">商品明细</view>
|
||
<view v-if="detailEntry.detailList.length === 0" class="detail-empty">暂无明细</view>
|
||
<view v-else class="detail-list">
|
||
<view class="detail-item" v-for="(detail, idx) in detailEntry.detailList" :key="idx">
|
||
<view class="detail-head">
|
||
<view class="detail-name">{{ detail.goodsName || detail.goods_name || detail.name || detail.title || '商品' }}</view>
|
||
</view>
|
||
<view class="detail-grid">
|
||
<view class="detail-kv">
|
||
<text class="detail-label">数量</text>
|
||
<text class="detail-value">x {{ detail.num || detail.qty || 0 }}</text>
|
||
</view>
|
||
<view class="detail-kv">
|
||
<text class="detail-label">厂家</text>
|
||
<text class="detail-value">{{ resolveManufacturer(detail) }}</text>
|
||
</view>
|
||
<view class="detail-kv">
|
||
<text class="detail-label">编号</text>
|
||
<text class="detail-value">{{ resolveCode(detail) }}</text>
|
||
</view>
|
||
<view class="detail-kv">
|
||
<text class="detail-label">规格</text>
|
||
<text class="detail-value">{{ resolveSpec(detail) }}</text>
|
||
</view>
|
||
<view class="detail-kv">
|
||
<text class="detail-label">金额</text>
|
||
<text class="detail-value text-red">{{ formatMoney(resolveAmount(detail)) }}</text>
|
||
</view>
|
||
<!-- <view class="detail-kv">-->
|
||
<!-- <text class="detail-label">额外加提</text>-->
|
||
<!-- <text class="detail-value text-red">{{ formatMoney(resolveExtraAmount(detail)) }}</text>-->
|
||
<!-- </view>-->
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="showRulePopup" class="share-popup-mask" @tap="closeRulePopup" @touchmove.stop.prevent></view>
|
||
<view v-if="showRulePopup" class="share-popup card rule-popup" @tap.stop>
|
||
<view class="popup-head">
|
||
<view class="section-title">规则</view>
|
||
<view class="close-btn" @tap="closeRulePopup">关闭</view>
|
||
</view>
|
||
<view class="rule-content">{{ rewardRules || '暂无规则' }}</view>
|
||
</view>
|
||
<AreaPicker
|
||
:show="showAreaPicker"
|
||
:default-province="currentProvince"
|
||
:default-city="currentCity"
|
||
@close="showAreaPicker = false"
|
||
@confirm="onAreaConfirm"
|
||
/>
|
||
<u-popup :show="showMerchantPicker" mode="bottom" round="24rpx" @close="closeMerchantPicker">
|
||
<view class="merchant-picker">
|
||
<view class="merchant-picker-head">
|
||
<view class="picker-action" @tap="closeMerchantPicker">取消</view>
|
||
<text class="picker-title">选择连锁和门店</text>
|
||
<view class="picker-action primary" @tap="confirmMerchantPicker">确定</view>
|
||
</view>
|
||
<view class="merchant-picker-search">
|
||
<input
|
||
v-model="merchantSearchKeyword"
|
||
class="merchant-search-input"
|
||
placeholder="搜索连锁/门店"
|
||
placeholder-class="merchant-search-placeholder"
|
||
/>
|
||
</view>
|
||
<view v-if="merchantLoading" class="merchant-picker-loading">
|
||
<u-loading-icon mode="circle"></u-loading-icon>
|
||
</view>
|
||
<picker-view
|
||
v-else
|
||
class="merchant-picker-view"
|
||
:value="merchantPickerValue"
|
||
:indicator-style="merchantIndicatorStyle"
|
||
@change="onMerchantPickerChange"
|
||
>
|
||
<picker-view-column>
|
||
<view v-for="(item, idx) in merchantChainOptions" :key="idx" class="merchant-picker-item">{{
|
||
item.text
|
||
}}
|
||
</view>
|
||
</picker-view-column>
|
||
<picker-view-column>
|
||
<view v-for="(item, idx) in merchantStoreOptions" :key="idx" class="merchant-picker-item">{{
|
||
item.text
|
||
}}
|
||
</view>
|
||
</picker-view-column>
|
||
</picker-view>
|
||
</view>
|
||
</u-popup>
|
||
<Login ref="Login" @done="getUserData"/>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {calcDistanceMeters, formatDistance, getLocationAction} from "@/util";
|
||
import {dictDataInfoReq} from "@/api/common";
|
||
import {
|
||
shareDataReq,
|
||
shareDetailPageReq,
|
||
shareListReq,
|
||
shareUserDataReq
|
||
} from "@/api/share";
|
||
import dayjs from 'dayjs'
|
||
import Login from "@/components/Login.vue";
|
||
import AppNavbar from "@/components/AppNavbar.vue";
|
||
import AreaPicker from "@/components/AreaPicker.vue";
|
||
import {userInfoReq} from "@/api/user";
|
||
import {getUserInfo} from "@/util/user";
|
||
import {merchantGroupByChainReq} from "@/api/shop";
|
||
|
||
export default {
|
||
components: {Login, AppNavbar, AreaPicker},
|
||
data() {
|
||
return {
|
||
todayEntries: [],
|
||
brandRanks: [],
|
||
shareProducts: [],
|
||
rewardRules: '',
|
||
showDetailPopup: false,
|
||
showRulePopup: false,
|
||
detailEntry: {
|
||
detailList: []
|
||
},
|
||
isLoggedIn: false,
|
||
data: {
|
||
income: 0,
|
||
num: 0,
|
||
totalNum: 0,
|
||
totalIncome: 0,
|
||
},
|
||
lat: null,
|
||
lng: null,
|
||
currentCity: '定位中',
|
||
currentProvince: '',
|
||
showAreaPicker: false,
|
||
showMerchantPicker: false,
|
||
merchantLoading: false,
|
||
merchantChainList: [],
|
||
merchantSearchKeyword: '',
|
||
merchantPickerValue: [0, 0],
|
||
merchantChainId: '',
|
||
merchantId: '',
|
||
merchantText: '门店筛选',
|
||
showAllToday: false,
|
||
showAllProducts: false,
|
||
productKeyword: '',
|
||
productKeywordApplied: '',
|
||
user: {
|
||
canAuth: 0
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
isPopupOpen() {
|
||
return this.showDetailPopup || this.showRulePopup
|
||
},
|
||
pageStyle() {
|
||
return this.isPopupOpen ? 'overflow: hidden;' : ''
|
||
},
|
||
displayedTodayEntries() {
|
||
const list = Array.isArray(this.todayEntries) ? this.todayEntries : []
|
||
return this.showAllToday ? list : list.slice(0, 5)
|
||
},
|
||
canShowTodayMore() {
|
||
return !this.showAllToday && this.todayEntries.length > 5
|
||
},
|
||
merchantLabel() {
|
||
return this.merchantText || '门店筛选'
|
||
},
|
||
merchantChainOptions() {
|
||
const list = Array.isArray(this.merchantChainList) ? this.merchantChainList : []
|
||
const keyword = (this.merchantSearchKeyword || '').trim()
|
||
if (!keyword) return list.length ? list : [{id: '', text: '暂无连锁', merchants: []}]
|
||
const filtered = list
|
||
.map(chain => {
|
||
const merchants = Array.isArray(chain.merchants) ? chain.merchants : []
|
||
const chainMatch = (chain.text || '').includes(keyword)
|
||
if (chainMatch) return {...chain}
|
||
const matchedMerchants = merchants.filter(merchant => (merchant.text || '').includes(keyword))
|
||
if (!matchedMerchants.length) return null
|
||
return {
|
||
...chain,
|
||
merchants: matchedMerchants
|
||
}
|
||
})
|
||
.filter(Boolean)
|
||
return filtered.length ? filtered : [{id: '', text: '无匹配连锁', merchants: []}]
|
||
},
|
||
merchantStoreOptions() {
|
||
const chainIndex = Number(this.merchantPickerValue[0] || 0)
|
||
const currentChain = this.merchantChainOptions[chainIndex] || this.merchantChainOptions[0] || {}
|
||
const merchants = Array.isArray(currentChain.merchants) ? currentChain.merchants : []
|
||
return merchants.length ? merchants : [{id: '', text: '无门店'}]
|
||
},
|
||
merchantPickerIndexes() {
|
||
const chainList = Array.isArray(this.merchantChainList) ? this.merchantChainList : []
|
||
if (!chainList.length) return [0, 0]
|
||
let chainIndex = chainList.findIndex(item => item.id === this.merchantChainId)
|
||
if (chainIndex < 0 && this.merchantId) {
|
||
chainIndex = chainList.findIndex(item => {
|
||
const merchants = Array.isArray(item.merchants) ? item.merchants : []
|
||
return merchants.some(merchant => merchant.id === this.merchantId)
|
||
})
|
||
}
|
||
if (chainIndex < 0) chainIndex = 0
|
||
const merchants = Array.isArray(chainList[chainIndex].merchants) ? chainList[chainIndex].merchants : []
|
||
let merchantIndex = merchants.findIndex(item => item.id === this.merchantId)
|
||
if (merchantIndex < 0) merchantIndex = 0
|
||
return [chainIndex, merchantIndex]
|
||
},
|
||
merchantIndicatorStyle() {
|
||
return 'height: 44px;'
|
||
},
|
||
displayedShareProducts() {
|
||
const list = this.filteredShareProducts
|
||
return this.showAllProducts ? list.slice(0, 48) : list.slice(0, 12)
|
||
},
|
||
canShowProductMore() {
|
||
return !this.showAllProducts && this.filteredShareProducts.length > 12
|
||
},
|
||
filteredShareProducts() {
|
||
const list = Array.isArray(this.shareProducts) ? this.shareProducts : []
|
||
const keyword = (this.productKeywordApplied || '').trim()
|
||
if (!keyword) return list
|
||
const normalized = keyword.toLowerCase()
|
||
return list.filter(item => {
|
||
const name = (item.goodsName || item.productName || '').toString().toLowerCase()
|
||
const spec = (item.product ? item.product.spec : item.spec || '').toString().toLowerCase()
|
||
const maker = (item.product ? item.product.makerAbb : '').toString().toLowerCase()
|
||
return name.includes(normalized) || spec.includes(normalized) || maker.includes(normalized)
|
||
})
|
||
}
|
||
},
|
||
watch: {
|
||
merchantSearchKeyword() {
|
||
this.merchantPickerValue = [0, 0]
|
||
}
|
||
},
|
||
async onShow() {
|
||
await this.refreshPageData()
|
||
},
|
||
async onPullDownRefresh() {
|
||
try {
|
||
await this.refreshPageData()
|
||
} finally {
|
||
uni.stopPullDownRefresh()
|
||
}
|
||
},
|
||
methods: {
|
||
dayjs,
|
||
async refreshPageData() {
|
||
if (getUserInfo().token) {
|
||
await this.getUserData()
|
||
}
|
||
const res = await getLocationAction().catch(() => {
|
||
uni.showToast({
|
||
title: '请允许位置授权',
|
||
icon: 'none'
|
||
})
|
||
})
|
||
if (res) {
|
||
this.lat = res.latitude
|
||
this.lng = res.longitude
|
||
this.currentCity = res.city_str
|
||
this.currentProvince = res.province_str || ''
|
||
}
|
||
await this.getShareUserData()
|
||
await this.getShareData()
|
||
await this.getTodayShare()
|
||
await this.getProductList()
|
||
await this.getRule()
|
||
},
|
||
openAreaPicker() {
|
||
this.showAreaPicker = true
|
||
},
|
||
onAreaConfirm({provinceName, cityName}) {
|
||
this.currentProvince = provinceName
|
||
this.currentCity = cityName
|
||
this.showAreaPicker = false
|
||
this.getShareData()
|
||
this.getTodayShare()
|
||
this.getProductList()
|
||
},
|
||
normalizeMerchantChain(item, index) {
|
||
const chainName = this.pickFirstText(item, ['chainName', 'chain', 'chainAbb', 'name', 'title']) || `连锁${index + 1}`
|
||
const rawChainId = item.chainId ?? item.chain_id ?? item.id ?? item.chainCode ?? item.chain_code ?? chainName
|
||
const chainId = rawChainId === undefined || rawChainId === null || String(rawChainId).trim() === ''
|
||
? `chain_${index}`
|
||
: rawChainId
|
||
const childCandidates = ['children', 'merchantList', 'merchants', 'shopList', 'list', 'records']
|
||
let rawChildren = []
|
||
for (let i = 0; i < childCandidates.length; i++) {
|
||
const list = item[childCandidates[i]]
|
||
if (Array.isArray(list) && list.length) {
|
||
rawChildren = list
|
||
break
|
||
}
|
||
}
|
||
let merchants = rawChildren
|
||
.map(child => this.normalizeMerchant(child))
|
||
.filter(merchant => merchant.id !== undefined && merchant.id !== null && String(merchant.id).trim() !== '')
|
||
if (!merchants.length) {
|
||
const selfMerchant = this.normalizeMerchant(item)
|
||
if (selfMerchant.id !== undefined && selfMerchant.id !== null && String(selfMerchant.id).trim() !== '') {
|
||
merchants = [selfMerchant]
|
||
}
|
||
}
|
||
return {
|
||
id: chainId,
|
||
text: chainName,
|
||
merchants
|
||
}
|
||
},
|
||
normalizeMerchant(item) {
|
||
const id = item.id ?? item.merchantId ?? item.merchant_id
|
||
const text = item.name || item.merchantName || item.merchant_name || item.title || '未命名门店'
|
||
return {
|
||
id,
|
||
text
|
||
}
|
||
},
|
||
pickFirstText(source, keys = []) {
|
||
if (!source || typeof source !== 'object') return ''
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const value = source[keys[i]]
|
||
if (value !== undefined && value !== null && String(value).trim()) {
|
||
return String(value).trim()
|
||
}
|
||
}
|
||
return ''
|
||
},
|
||
unwrapList(data) {
|
||
if (Array.isArray(data)) return data
|
||
if (!data || typeof data !== 'object') return []
|
||
const keys = ['list', 'records', 'rows', 'items', 'data', 'result', 'chainList']
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const value = data[keys[i]]
|
||
if (Array.isArray(value)) return value
|
||
if (value && typeof value === 'object') {
|
||
const nested = this.unwrapList(value)
|
||
if (nested.length) return nested
|
||
}
|
||
}
|
||
return [data]
|
||
},
|
||
async getMerchantList() {
|
||
this.merchantLoading = true
|
||
try {
|
||
const {data} = await merchantGroupByChainReq({})
|
||
const list = this.unwrapList(data)
|
||
const chainList = list
|
||
.map((item, index) => this.normalizeMerchantChain(item, index))
|
||
.filter(item => Array.isArray(item.merchants) && item.merchants.length)
|
||
this.merchantChainList = [{
|
||
id: '',
|
||
text: '全部连锁',
|
||
merchants: [{id: '', text: '全部门店'}]
|
||
}].concat(chainList)
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: '门店列表获取失败',
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
this.merchantLoading = false
|
||
}
|
||
},
|
||
async openMerchantPicker() {
|
||
if (!this.merchantChainList || this.merchantChainList.length <= 1) {
|
||
await this.getMerchantList()
|
||
}
|
||
this.merchantSearchKeyword = ''
|
||
this.merchantPickerValue = [...this.merchantPickerIndexes]
|
||
this.showMerchantPicker = true
|
||
},
|
||
closeMerchantPicker() {
|
||
this.showMerchantPicker = false
|
||
},
|
||
onMerchantPickerChange(e) {
|
||
const value = e.detail && e.detail.value !== undefined ? e.detail.value : e.detail
|
||
const currentChainIndex = Number(this.merchantPickerValue[0] || 0)
|
||
let chainIndex = Array.isArray(value) ? Number(value[0] || 0) : Number(value || 0)
|
||
let merchantIndex = Array.isArray(value) ? Number(value[1] || 0) : 0
|
||
if (!Number.isFinite(chainIndex) || chainIndex < 0) chainIndex = 0
|
||
if (!Number.isFinite(merchantIndex) || merchantIndex < 0) merchantIndex = 0
|
||
const chain = this.merchantChainOptions[chainIndex] || this.merchantChainOptions[0] || {}
|
||
const merchants = Array.isArray(chain.merchants) ? chain.merchants : []
|
||
if (!merchants.length) {
|
||
merchantIndex = 0
|
||
} else if (chainIndex !== currentChainIndex || merchantIndex > merchants.length - 1) {
|
||
merchantIndex = 0
|
||
}
|
||
this.merchantPickerValue = [chainIndex, merchantIndex]
|
||
},
|
||
confirmMerchantPicker() {
|
||
const chainIndex = Number(this.merchantPickerValue[0] || 0)
|
||
const merchantIndex = Number(this.merchantPickerValue[1] || 0)
|
||
const chain = this.merchantChainOptions[chainIndex] || null
|
||
const merchants = chain && Array.isArray(chain.merchants) ? chain.merchants : []
|
||
const selected = merchants[merchantIndex] || null
|
||
if (!selected) return
|
||
this.merchantChainId = chain ? (chain.id ?? '') : ''
|
||
this.merchantId = selected.id ?? ''
|
||
if (!this.merchantId) {
|
||
this.merchantText = '门店筛选'
|
||
} else {
|
||
this.merchantText = `${(chain && chain.text) || '连锁'}/${selected.text || '门店'}`
|
||
}
|
||
this.showMerchantPicker = false
|
||
this.getShareData()
|
||
this.getTodayShare()
|
||
this.getProductList()
|
||
},
|
||
async getRule() {
|
||
const {data} = await dictDataInfoReq(576)
|
||
this.rewardRules = data.dictDataCode
|
||
},
|
||
async getShareData() {
|
||
const params = {
|
||
province: this.currentProvince,
|
||
city: this.currentCity
|
||
}
|
||
if (this.merchantId) {
|
||
params.merchantId = this.merchantId
|
||
}
|
||
const {data} = await shareDataReq(params)
|
||
const list = Array.isArray(data) ? data : (data && data.list ? data.list : [])
|
||
this.brandRanks = list.sort((a, b) => parseFloat(b.amount) - parseFloat(a.amount))
|
||
},
|
||
async getShareUserData() {
|
||
const {data} = await shareUserDataReq()
|
||
this.data = data
|
||
},
|
||
async getUserData() {
|
||
const {data} = await userInfoReq()
|
||
this.isLoggedIn = true
|
||
this.user = data
|
||
},
|
||
async getTodayShare() {
|
||
const params = {
|
||
createTimeStart: dayjs().format('YYYY-MM-DD'),
|
||
createTimeEnd: dayjs().format('YYYY-MM-DD 23:59:59'),
|
||
province: this.currentProvince,
|
||
city: this.currentCity
|
||
}
|
||
if (this.merchantId) {
|
||
params.merchantId = this.merchantId
|
||
}
|
||
const {data} = await shareListReq(params)
|
||
this.todayEntries = data
|
||
this.showAllToday = false
|
||
this.updateTodayDistances()
|
||
},
|
||
async getProductList() {
|
||
const params = {
|
||
page: 1,
|
||
limit: 48,
|
||
province: this.currentProvince,
|
||
city: this.currentCity,
|
||
groupByProduct: true
|
||
}
|
||
if (this.merchantId) {
|
||
params.merchantId = this.merchantId
|
||
}
|
||
const {data} = await shareDetailPageReq(params)
|
||
this.shareProducts = data.list
|
||
this.shareProducts = this.shareProducts.filter(item => !!item.product).filter((item, index) => index < 48)
|
||
this.showAllProducts = false
|
||
this.productKeyword = ''
|
||
this.productKeywordApplied = ''
|
||
},
|
||
showDetail(item) {
|
||
this.detailEntry = this.normalizeDetailEntry(item || {})
|
||
this.showDetailPopup = true
|
||
},
|
||
closeDetailPopup() {
|
||
this.showDetailPopup = false
|
||
this.detailEntry = {detailList: []}
|
||
},
|
||
openRulePopup() {
|
||
this.showRulePopup = true
|
||
},
|
||
closeRulePopup() {
|
||
this.showRulePopup = false
|
||
},
|
||
showAllTodayEntries() {
|
||
this.showAllToday = true
|
||
},
|
||
showAllProductEntries() {
|
||
this.showAllProducts = true
|
||
},
|
||
searchProduct() {
|
||
this.productKeywordApplied = (this.productKeyword || '').trim()
|
||
this.showAllProducts = false
|
||
},
|
||
updateTodayDistances() {
|
||
if (!Number.isFinite(this.lat) || !Number.isFinite(this.lng)) return
|
||
const list = Array.isArray(this.todayEntries) ? this.todayEntries : []
|
||
this.todayEntries = list.map(item => {
|
||
const merchant = item.merchant || {}
|
||
const lat = Number(merchant.lat || merchant.latitude || item.merchantLat || item.merchantLatitude || item.lat || item.latitude)
|
||
const lng = Number(merchant.lng || merchant.longitude || item.merchantLng || item.merchantLongitude || item.lng || item.longitude)
|
||
if (!Number.isFinite(lat) || !Number.isFinite(lng)) return item
|
||
const meters = calcDistanceMeters(this.lat, this.lng, lat, lng)
|
||
return Object.assign({}, item, {
|
||
distance: formatDistance(meters)
|
||
})
|
||
})
|
||
},
|
||
handleShare() {
|
||
if (!this.isLoggedIn) {
|
||
this.$refs.Login.open()
|
||
return
|
||
}
|
||
const lat = Number.isFinite(this.lat) ? this.lat : ''
|
||
const lng = Number.isFinite(this.lng) ? this.lng : ''
|
||
const province = encodeURIComponent(this.currentProvince || '')
|
||
const city = encodeURIComponent(this.currentCity || '')
|
||
uni.navigateTo({
|
||
url: `/pages/share/create?lat=${lat}&lng=${lng}&province=${province}&city=${city}`
|
||
})
|
||
},
|
||
normalizeDetailEntry(item) {
|
||
const rawList = item.detailList || item.list || item.detail_list || []
|
||
const detailList = this.parseJsonMaybe(rawList)
|
||
return {
|
||
...item,
|
||
owner: item.owner || (item.user && (item.user.realName || item.user.nickname)) || '-',
|
||
activityDateText: item.date || item.shareDate || item.createTime || item.createdAt || item.create_time || '-',
|
||
detailList: Array.isArray(detailList) ? detailList : []
|
||
}
|
||
},
|
||
formatPrice(value) {
|
||
const num = Number(value || 0)
|
||
return num.toFixed(2)
|
||
},
|
||
resolveExtraIncome(source = {}) {
|
||
const candidates = [
|
||
source.extraIncome,
|
||
source.extra_income,
|
||
source.extraBonus,
|
||
source.extra_bonus,
|
||
source.otherIncome,
|
||
source.other_income
|
||
]
|
||
for (let i = 0; i < candidates.length; i++) {
|
||
const raw = candidates[i]
|
||
if (raw === '' || raw === null || raw === undefined) continue
|
||
const num = Number(raw)
|
||
if (Number.isFinite(num)) return num
|
||
}
|
||
return 0
|
||
},
|
||
hasExtraIncome(source = {}) {
|
||
return this.resolveExtraIncome(source) !== 0
|
||
},
|
||
resolveManufacturer(detail) {
|
||
if (!detail) return '-'
|
||
const product = detail.product || {}
|
||
const value = detail.makerAbb
|
||
|| detail.manufacturer
|
||
|| detail.vendor
|
||
|| detail.factory
|
||
|| detail.brand
|
||
|| product.makerAbb
|
||
|| product.manufacturer
|
||
|| product.vendor
|
||
|| product.factory
|
||
|| product.brand
|
||
return this.normalizeText(value)
|
||
},
|
||
resolveCode(detail) {
|
||
if (!detail) return '-'
|
||
const value = detail.goodsCode
|
||
|| detail.code
|
||
|| detail.productCode
|
||
|| detail.skuCode
|
||
|| detail.barcode
|
||
return this.normalizeText(value)
|
||
},
|
||
resolveSpec(detail) {
|
||
if (!detail) return '-'
|
||
const product = detail.product || {}
|
||
const value = detail.spec
|
||
|| detail.specification
|
||
|| detail.standard
|
||
|| product.spec
|
||
|| product.specification
|
||
|| product.standard
|
||
return this.normalizeText(value)
|
||
},
|
||
resolveAmount(detail) {
|
||
if (!detail) return ''
|
||
if (detail.income !== undefined && detail.income !== null && detail.income !== '') return detail.income
|
||
if (detail.product && detail.product.income !== undefined && detail.product.income !== null && detail.product.income !== '') {
|
||
return detail.product.income
|
||
}
|
||
return ''
|
||
},
|
||
resolveExtraAmount(detail) {
|
||
if (!detail) return ''
|
||
if (detail.extraIncome !== undefined && detail.extraIncome !== null && detail.extraIncome !== '') return detail.extraIncome
|
||
if (detail.product && detail.product.extraIncome !== undefined && detail.product.extraIncome !== null && detail.product.extraIncome !== '') {
|
||
return detail.product.extraIncome
|
||
}
|
||
return ''
|
||
},
|
||
normalizeText(value) {
|
||
if (value === 0) return '0'
|
||
if (value === null || value === undefined || value === '') return '-'
|
||
return String(value)
|
||
},
|
||
formatMoney(value) {
|
||
if (value === null || value === undefined || value === '') return '-'
|
||
const num = Number(value)
|
||
if (Number.isFinite(num)) return `¥${num.toFixed(2)}`
|
||
return String(value)
|
||
},
|
||
parseJsonMaybe(value) {
|
||
if (value === null || value === undefined || value === '') return null
|
||
if (typeof value === 'string') {
|
||
try {
|
||
return JSON.parse(value)
|
||
} catch (err) {
|
||
return value
|
||
}
|
||
}
|
||
return value
|
||
},
|
||
preview(cover) {
|
||
uni.previewImage({
|
||
urls: [cover]
|
||
})
|
||
},
|
||
jumpWithAuth(url) {
|
||
if (!this.isLoggedIn) {
|
||
this.$refs.Login.open()
|
||
return
|
||
}
|
||
uni.navigateTo({
|
||
url
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.share-page {
|
||
min-height: 100vh;
|
||
//padding: 0 20rpx 50rpx;
|
||
background: #e9fbf6 url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/7b74d64d385c371f718cad4a275a5082.png') no-repeat top center / 100% auto;
|
||
}
|
||
|
||
.share-hero {
|
||
padding: 0 6rpx 0;
|
||
}
|
||
|
||
.hero-icon {
|
||
width: 34rpx;
|
||
height: 34rpx;
|
||
border-radius: 10rpx;
|
||
background: rgba(39, 199, 164, 0.18);
|
||
border: 1rpx solid rgba(39, 199, 164, 0.35);
|
||
}
|
||
|
||
.stats-card {
|
||
margin: 20rpx;
|
||
padding: 18rpx 20rpx;
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
justify-content: flex-start;
|
||
box-shadow: 0 12rpx 24rpx rgba(0, 0, 0, 0.08);
|
||
border: 1px solid #2fc6a7;
|
||
border-top: 20px solid #2fc6a7;
|
||
}
|
||
|
||
.stat-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6rpx;
|
||
}
|
||
|
||
.stat-value {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 4rpx;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 32rpx;
|
||
font-weight: 800;
|
||
color: #ff3b30;
|
||
}
|
||
|
||
.stat-unit {
|
||
font-size: 22rpx;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 22rpx;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.stat-action {
|
||
padding: 10rpx 18rpx;
|
||
background: #2fc6a7;
|
||
color: #ffffff;
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
border-radius: 999rpx;
|
||
}
|
||
|
||
.today-head {
|
||
margin-top: 18rpx;
|
||
padding: 0 6rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
.filter-chips {
|
||
margin: 8rpx 20rpx 0;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.filter-chip {
|
||
padding: 6rpx 14rpx;
|
||
border-radius: 999rpx;
|
||
border: 1rpx solid #2fc6a7;
|
||
color: #2fc6a7;
|
||
font-size: 22rpx;
|
||
}
|
||
|
||
.city {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6rpx;
|
||
color: #2fc6a7;
|
||
font-weight: 700;
|
||
font-size: 24rpx;
|
||
position: absolute;
|
||
top: 10rpx;
|
||
left: 20rpx;
|
||
}
|
||
|
||
.today-more {
|
||
position: absolute;
|
||
top: 10rpx;
|
||
right: 20rpx;
|
||
font-size: 22rpx;
|
||
color: #2fc6a7;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.head-center {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8rpx;
|
||
color: #2fc6a7;
|
||
flex: 1;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 26rpx;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.head-center .section-title,
|
||
.section-left .section-title {
|
||
color: #2fc6a7;
|
||
}
|
||
|
||
.section-more {
|
||
font-size: 22rpx;
|
||
color: #2fc6a7;
|
||
}
|
||
|
||
.product-more {
|
||
color: #ffffff;
|
||
}
|
||
|
||
.head-icon {
|
||
//width: 30rpx;
|
||
height: 60rpx;
|
||
}
|
||
|
||
.today-list {
|
||
margin-top: 12rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14rpx;
|
||
}
|
||
|
||
.today-card {
|
||
background: #ffffff;
|
||
border-radius: 18rpx;
|
||
padding: 14rpx 16rpx;
|
||
border: 1rpx solid #a7f3d0;
|
||
box-shadow: 0 8rpx 16rpx rgba(39, 199, 164, 0.12);
|
||
margin: 0 20rpx 0;
|
||
}
|
||
|
||
.today-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6rpx;
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
margin-top: 6rpx;
|
||
}
|
||
|
||
.today-row:first-child {
|
||
margin-top: 0;
|
||
}
|
||
|
||
.today-row-space {
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.today-label {
|
||
color: #6b7280;
|
||
}
|
||
|
||
.today-time {
|
||
color: #6b7280;
|
||
font-size: 22rpx;
|
||
}
|
||
|
||
.today-distance {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4rpx;
|
||
font-size: 22rpx;
|
||
color: #ff8a00;
|
||
}
|
||
|
||
.product-section {
|
||
margin-top: 20rpx;
|
||
padding: 22rpx 18rpx 26rpx;
|
||
border-radius: 24rpx;
|
||
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/09dd8e6519b44d71410fc82a7e255540.jpg') no-repeat top / cover;
|
||
}
|
||
|
||
.section-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.section-left {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.product-search {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.search-box {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
background: #ffffff;
|
||
border-radius: 999rpx;
|
||
padding: 10rpx 16rpx;
|
||
box-shadow: 0 8rpx 14rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.search-input {
|
||
flex: 1;
|
||
font-size: 24rpx;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.search-btn {
|
||
padding: 10rpx 16rpx;
|
||
background: #2fc6a7;
|
||
color: #ffffff;
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
border-radius: 999rpx;
|
||
}
|
||
|
||
.product-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.product-card {
|
||
background: #ffffff;
|
||
border-radius: 16rpx;
|
||
padding: 12rpx;
|
||
box-shadow: 0 8rpx 14rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.product-card .product-name {
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.product-card .product-meta {
|
||
font-size: 20rpx;
|
||
color: #6b7280;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.product-info {
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.product-bonus {
|
||
margin-top: 6rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6rpx;
|
||
font-size: 22rpx;
|
||
font-weight: 700;
|
||
color: #ff6b00;
|
||
}
|
||
|
||
.bonus-tag {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.rank-section {
|
||
margin: 20rpx;
|
||
background: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 22rpx 18rpx 80rpx;
|
||
position: relative;
|
||
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.rank-head {
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.rank-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.rank-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 14rpx 0;
|
||
border-bottom: 1rpx dashed #dbe5f0;
|
||
}
|
||
|
||
.rank-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.rank-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.rank-badge {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.rank-medal {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
}
|
||
|
||
.rank-num {
|
||
color: #2fc6a7;
|
||
font-weight: 700;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.rank-name {
|
||
color: #1f2937;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.rank-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
font-size: 22rpx;
|
||
color: #ef4444;
|
||
}
|
||
|
||
.rank-reward {
|
||
color: #ef4444;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.rank-count {
|
||
color: #ef4444;
|
||
}
|
||
|
||
.rank-rule {
|
||
position: absolute;
|
||
right: 18rpx;
|
||
bottom: 18rpx;
|
||
padding: 10rpx 22rpx;
|
||
background: linear-gradient(135deg, #ffb020, #ff7a00);
|
||
color: #ffffff;
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
border-radius: 999rpx;
|
||
}
|
||
|
||
.share-action {
|
||
margin: 20rpx;
|
||
padding: 20rpx 0;
|
||
background: linear-gradient(135deg, #33d0b3, #22c3a1);
|
||
color: #ffffff;
|
||
text-align: center;
|
||
font-size: 30rpx;
|
||
font-weight: 700;
|
||
border-radius: 999rpx;
|
||
box-shadow: 0 10rpx 18rpx rgba(34, 195, 161, 0.3);
|
||
}
|
||
|
||
.product {
|
||
padding: 16rpx 0;
|
||
border-bottom: 1rpx solid #edf1f7;
|
||
}
|
||
|
||
.product:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.product-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 30rpx;
|
||
color: var(--text-main);
|
||
}
|
||
|
||
.product-meta {
|
||
color: var(--text-sub);
|
||
font-size: 24rpx;
|
||
margin-top: 6rpx;
|
||
}
|
||
|
||
.product-amount {
|
||
color: #FE6869;
|
||
font-size: 24rpx;
|
||
margin-top: 6rpx;
|
||
}
|
||
|
||
.product-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12rpx;
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.rule {
|
||
color: var(--text-sub);
|
||
margin-bottom: 8rpx;
|
||
line-height: 1.5;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.review {
|
||
padding: 12rpx 0;
|
||
border-bottom: 1rpx dashed #e3eaf4;
|
||
}
|
||
|
||
.review:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.review-name {
|
||
color: var(--text-main);
|
||
}
|
||
|
||
.review-meta {
|
||
color: var(--text-sub);
|
||
font-size: 24rpx;
|
||
margin: 4rpx 0;
|
||
}
|
||
|
||
.review-actions {
|
||
display: flex;
|
||
gap: 10rpx;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.share-popup-mask {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.45);
|
||
z-index: 30;
|
||
}
|
||
|
||
.share-popup {
|
||
position: fixed;
|
||
left: 50%;
|
||
bottom: 40rpx;
|
||
transform: translateX(-50%);
|
||
width: 88%;
|
||
max-height: 70vh;
|
||
overflow: auto;
|
||
z-index: 40;
|
||
}
|
||
|
||
.popup-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.close-btn {
|
||
color: var(--text-sub);
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.form-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12rpx 0;
|
||
border-bottom: 1rpx solid #edf1f7;
|
||
}
|
||
|
||
.form-row:last-of-type {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.label {
|
||
color: var(--text-main);
|
||
font-size: 26rpx;
|
||
min-width: 140rpx;
|
||
}
|
||
|
||
.input {
|
||
flex: 1;
|
||
text-align: right;
|
||
font-size: 26rpx;
|
||
color: var(--text-main);
|
||
}
|
||
|
||
.picker-input {
|
||
flex: 1;
|
||
}
|
||
|
||
.picker-input-inner {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 8rpx;
|
||
min-height: 40rpx;
|
||
}
|
||
|
||
.picker-text {
|
||
color: var(--text-main);
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.picker-placeholder {
|
||
color: #9ca3af;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.merchant-picker {
|
||
padding: 20rpx 24rpx 30rpx;
|
||
}
|
||
|
||
.merchant-picker-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.picker-action {
|
||
font-size: 26rpx;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.picker-action.primary {
|
||
color: #2fc6a7;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.picker-title {
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.merchant-picker-search {
|
||
margin: 6rpx 0 12rpx;
|
||
}
|
||
|
||
.merchant-search-input {
|
||
width: 100%;
|
||
background: #f3f4f6;
|
||
border-radius: 12rpx;
|
||
padding: 12rpx 16rpx;
|
||
font-size: 26rpx;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.merchant-search-placeholder {
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.merchant-picker-loading {
|
||
padding: 20rpx 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.merchant-picker-view {
|
||
height: 360rpx;
|
||
}
|
||
|
||
.merchant-picker-item {
|
||
height: 44px;
|
||
line-height: 44px;
|
||
text-align: center;
|
||
font-size: 26rpx;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.form-value {
|
||
flex: 1;
|
||
text-align: right;
|
||
font-size: 26rpx;
|
||
color: var(--text-main);
|
||
}
|
||
|
||
.detail-title {
|
||
margin-top: 12rpx;
|
||
font-weight: 700;
|
||
color: var(--text-main);
|
||
}
|
||
|
||
.detail-actions {
|
||
margin-top: 8rpx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.ghost-btn {
|
||
color: var(--brand-primary);
|
||
border: 1rpx solid var(--brand-primary);
|
||
padding: 6rpx 16rpx;
|
||
border-radius: 999rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.detail-empty {
|
||
color: var(--text-sub);
|
||
text-align: center;
|
||
padding: 12rpx 0;
|
||
}
|
||
|
||
.detail-list {
|
||
margin-top: 8rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.detail-item {
|
||
border: 1rpx dashed #dfe8f5;
|
||
border-radius: 12rpx;
|
||
padding: 12rpx;
|
||
}
|
||
|
||
.detail-name {
|
||
color: var(--text-main);
|
||
font-weight: 600;
|
||
flex: 1;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.detail-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8rpx 16rpx;
|
||
}
|
||
|
||
.detail-kv {
|
||
display: flex;
|
||
gap: 6rpx;
|
||
min-width: 45%;
|
||
}
|
||
|
||
.detail-label {
|
||
color: var(--text-sub);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.detail-value {
|
||
color: var(--text-main);
|
||
flex: 1;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.detail-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 6rpx;
|
||
}
|
||
|
||
.detail-index {
|
||
color: var(--text-sub);
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.detail-remove {
|
||
color: #ff3b30;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.submit {
|
||
margin-top: 16rpx;
|
||
padding: 14rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.popup-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
margin-top: 16rpx;
|
||
}
|
||
|
||
.popup-actions .ghost-action,
|
||
.popup-actions .submit {
|
||
flex: 1;
|
||
margin-top: 0;
|
||
margin-left: 0;
|
||
margin-right: 0;
|
||
width: auto;
|
||
}
|
||
|
||
.textarea {
|
||
flex: 1;
|
||
text-align: right;
|
||
font-size: 26rpx;
|
||
color: var(--text-main);
|
||
background: transparent;
|
||
min-height: 40rpx;
|
||
line-height: 40rpx;
|
||
}
|
||
|
||
.ghost-action {
|
||
text-align: center;
|
||
padding: 10rpx 16rpx;
|
||
border-radius: 999rpx;
|
||
font-weight: 800;
|
||
font-size: 26rpx;
|
||
flex: 1;
|
||
background: #F0F6FF;
|
||
color: #2563eb;
|
||
border: 1rpx solid #F0F6FF;
|
||
margin: 10rpx;
|
||
width: calc(100% - 60rpx);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.rule-popup {
|
||
max-height: 70vh;
|
||
}
|
||
|
||
.rule-content {
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
line-height: 1.6;
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.record-meta {
|
||
color: var(--text-sub);
|
||
font-size: 24rpx;
|
||
margin-top: 6rpx;
|
||
}
|
||
|
||
.text-red {
|
||
color: #ef4444;
|
||
}
|
||
|
||
</style>
|