wechat_yxcl/pages/everdayRenven/AnhuiServerpart.vue
ylj20011123 ca9d4fd6ff update
2025-10-13 15:03:34 +08:00

1915 lines
48 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view :class="'province-theme-' + currentProvinceCode" scroll-with-animation v-if="showPage">
<view class="page-body page-enter">
<div class="box-card card-enter" :style="'opacity:' + (1 - opacity) + ';'">
<div class="box-top-title">
<span class="box-center-title">{{ sMsg.serverpartname }}</span>
<picker mode="date" @change="bindDateChange" :value="theRequest && theRequest.time" :start="startTime"
:end="endTime" class="title-clock">
<view>{{ searchDate }} <text class="uni-icon uni-icon-arrowdown"></text></view>
</picker>
</div>
<view class="top-card data-card-enter">
<div class="box-center-box">
<div class="uni-flex ai-center jc-between" style="margin-bottom: 8rpx;">
<div class="main-amount-title">对客营收(元)</div>
<div class="tab-unit" @tap="showPop">
<span>上传门店:</span>
<span class="tab-unit-num" :class="{ 'priceRed': sMsg.uploadCount !== sMsg.totalUploadCount }">{{
sMsg.uploadCount
}}</span>
<span class="tab-unit-num " :class="{ 'more-btn': sMsg.uploadCount !== sMsg.totalUploadCount }">{{
sMsg.totalUploadCount }}</span>
</div>
</div>
<div class="uni-flex ai-base jc-between">
<span class="center-num">{{ sMsg.totalMoneyShow }}</span>
<span class="budgetamount">
<text class="budget-title">计划营收(元):</text>
<text :class="sMsg.budgetAmount < sMsg.cashPay ? 'up-text-title' : 'down-text-title'">
{{ sMsg.budgetamoutShow }}
<span style="font-size: 24rpx;margin-left: 12rpx;">{{ sMsg.diffBili }}%</span>
</text>
</span>
</div>
</div>
<div class="uni-flex jc-between box-center-box">
<div class="check-unit metric-enter">
<text>长款金额</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.diffMorePrice, 2) }} <text>元</text></div>
</div>
<div class="check-unit metric-enter">
<text>短款金额</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.diffLessPrice, 2) }} <text>元</text></div>
</div>
<div class="check-unit metric-enter">
<text>客单交易</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.ticketCount, 0) }} <text>笔</text></div>
</div>
<div class="check-unit metric-enter">
<text>客单均价</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.tickave, 2) }} <text>元</text></div>
</div>
</div>
<div class="uni-flex jc-between box-center-box mt8">
<div class="check-unit metric-enter">
<text>优惠金额</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.totalOffAmount, 2) }} <text>元</text></div>
</div>
<div class="check-unit metric-enter">
<text>移动支付</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.mobilePayment, 2) }} <text>元</text></div>
</div>
<div class="check-unit metric-enter">
<text>商品出售</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.totalCount, 0) }} <text>件</text></div>
</div>
<div class="check-unit metric-enter">
<text>商品均价</text>
<div class="check-price-color">{{ $util.fmoney(sMsg.countave, 2) }} <text>元</text></div>
</div>
</div>
</view>
</div>
<cover-view class="fixed-box page-title"
:style="'transform: translateY(' + fixedY + 'px);opacity:' + opacity + ';'">
<cover-view>{{ sMsg.serverpartname || '' }}</cover-view>
<cover-view class="price-text" style="width: 200rpx;text-align: right;">¥ {{ sMsg.totalMoneyShow }}
</cover-view>
</cover-view>
<template v-if="cateBrandList.length">
<template v-if="theRequest.ProvinceCode == '340000'">
<view class="uni-flex ai-center analysis-tabs tabs-enter">
<!-- <view @tap="changeTab(3)" class="tab" :class="{'active': nowTab==3}">经营模式</view> -->
<view @tap="changeTab(4)" class="tab tab-slide" :class="{ 'active': nowTab == 4 }">车流分析</view>
<view @tap="changeTab(1)" class="tab tab-slide" :class="{ 'active': nowTab == 1 }">经营分析</view>
<view @tap="changeTab(2)" class="tab tab-slide" :class="{ 'active': nowTab == 2 }">客群分析</view>
</view>
<!-- <view class="pie-content" v-show="nowTab==3">
<div class="pie-title">经营模式占比</div>
<view class="operation-model-content">
<canvas canvas-id="modelCount" v-if="operationModel.length>0" id="modelCount"
class="operation-model-content" @click="touchPie($event,'modelCount')" />
</view>
</view> -->
</template>
<!-- 经营分析内容 -->
<view v-show="nowTab == 1">
<!-- 安徽省 -->
<div class="pie-content">
<div class="model-busniess">经营业态占比</div>
<ServiceRevenuePie ref="serviceRevenuePie" v-show="ServiceRevenueData && ServiceRevenueData.length >= 2"
:data="ServiceRevenueData" @selectCate="selectCate" />
<!-- 其余省份 -->
<!-- <canvas v-else-if="sellData.length>0" canvas-id="sellCate" id="sellCate" class="operation-cate-content" @click="touchPie($event,'sellCate')"></canvas> -->
<div class="model-busniess progress-section-enter">
<div>经营模式占比</div>
<div class="progress-content">
<div class="progress-left" :style="'width: ' + operationModel[0].bili + '%;'"></div>
<div class="progress-right" :style="'width: ' + operationModel[1].bili + '%;'"></div>
</div>
<div class="uni-flex jc-between">
<div style="color: #667ED5;">{{ operationModel[0].name }}: <span style="font-size: 32rpx;">{{
operationModel[0].bili }}</span>%</div>
<div style="color: #F3AF50;" v-if="operationModel[1].name">{{ operationModel[1].name }}:
<span style="font-size: 32rpx;">{{ operationModel[1].bili }}</span>%
</div>
</div>
<div class="uni-flex jc-between">
<div style="margin-bottom: 0;"><span style="font-size: 32rpx;">{{ operationModel[0].data
}}</span>元
</div>
<div style="margin-bottom: 0;" v-if="operationModel[1].data"><span style="font-size: 32rpx;">{{
operationModel[1].data
}}</span>元
</div>
</div>
</div>
</div>
<!-- 品牌列表 -->
<div class="shop-box brand-list-enter">
<scroll-view scroll-x class="tab-shop tab-shop-slide" scroll-with-animation :scroll-left="scrollLeft">
<div v-for="(n, i) in cateBrandList" :key="i" :id="`tabNum${i}`" class="cate-name brand-tab-stagger"
:class="{ 'active': nowShop == i }" @click="selectCate(i)"
:style="'animation-delay: ' + (i * 0.05) + 's'">{{
n.Bussiness_Name }}</div>
</scroll-view>
<div class="tab-content brand-cards-container" v-if="cateBrandList.length">
<div class="shop-card brand-card-stagger" v-for="(m, i) in cateBrandList[nowShop].listBrandModel" :key="i"
@click="toBrandPage(m, i)" :style="'animation-delay: ' + (i * 0.08) + 's'">
<div class="brand-icon-wrapper">
<image v-if="m.Brand_ICO" :src="m.Brand_ICO" mode="aspectFit" class="brand-icon"></image>
<image v-else src="/static/images/revenue/home.png" mode="aspectFit" class="brand-icon"></image>
</div>
<div class="shop-name">{{ m.Brand_Name }}</div>
<div class="price-num">¥ {{ m.Revenue_Amount ? $util.fmoney(m.Revenue_Amount, 2) : '0.00' }}
</div>
</div>
</div>
</div>
</view>
<view class="tab-content-fade" v-show="nowTab == 2">
<CustomerAnalysis ref="customerAna" :show="nowTab == 2" />
</view>
<view class="tab-content-fade" v-show="nowTab == 4">
<CarAnalysis ref="carAna" :show="nowTab == 4" />
</view>
</template>
<view style="height: 350rpx;" v-else>
<noFound :nodata="'true'" :text="noDataText" />
</view>
<cover-view class="uni-mask" :style="showUnUpLoad ? ' display:block;' : 'opacity:0; display: none;'"
@click="closePop" :catchtouchmove="showUnUpLoad ? 'return' : ''"></cover-view>
<cover-view class="uni-popup uni-popup-middle" :style="showUnUpLoad ? 'display:flex;' : 'display: none;'"
:catchtouchmove="showUnUpLoad ? 'return' : ''">
<cover-view class="header-top" v-if="unUploadList.length > 0">{{ sMsg.serverpartname }}未上传门店</cover-view>
<cover-view class="pop-body">
<cover-view class="uni-flex pop-row" v-for="(c, i) in unUploadList" :key="i">
<cover-view class="uni-flex ai-center">
<cover-view class="pop-index">{{ i > 8 ? i + 1 : '0' + (i + 1) }}</cover-view>
<cover-view class="inline-item">{{ c.ServerpartShop_Name }}</cover-view>
</cover-view>
<cover-view class="pop-row-bottom"></cover-view>
</cover-view>
</cover-view>
</cover-view>
</view>
</view>
</template>
<script>
import uCharts from '@/components/u-charts.js';
import ServiceRevenuePie from './components/ServiceRevenuePie.vue'
import CustomerAnalysis from './components/CustomerAnalysis.vue'
import CarAnalysis from './components/CarAnalysis.vue'
import anhuiYestodayRevenueData from './components/anhuiYestodayRevenueData.js'
let rincanvas = {}
var _self;
export default {
data() {
const lastDay = this.$util.cutDate(new Date(), 'YYYY/MM/DD ', -1)
return {
lastDay: lastDay + '23:59:59', // 该页面的最近有效日期
noDataText: '抱歉,该服务区暂无品牌分析数据',
scrollLeft: 0,
theRequest: {},
showAll: false,
showHeight: uni.upx2px(484) + 'px',
searchDate: '',
sellData: [],
scrollTop: 0,
pageData: {},
cateBrandList: [],
// ringColor: ['#FFAC37', '#d8ece9', '#e0e3f7', '#f7f5f6', '#b2b7e3'],
nowShop: 0,
showPage: false,
fixedY: -68,
opacity: 0,
sMsg: null, // 头部数据
showUnUpLoad: false, //未上传门店弹出框
upcouts: null, // 上传门店数量
unUploadList: [], // 未上传门店列表
todayUpList: [], // 未上传门店列表
ServiceRevenueData: [],
nowTab: 1,
operationModel: [], // 安徽经营模式
startTime: '',//开始时间
endTime: '',//结束时间
currentProvinceCode: '' // 当前省份代码
}
},
computed: {
// 省份主题配色
provinceTheme() {
const themes = {
'330200': { // 宁波
primary: '#1890FF',
secondary: '#69C0FF',
background: '#E6F7FF',
accent: '#40A9FF'
},
'340000': { // 安徽
primary: '#748ED6',
secondary: '#91A7E3',
background: '#F0F4FF',
accent: '#A3B8E8'
},
'500000': { // 重庆
primary: '#FA541C',
secondary: '#FF7A45',
background: '#FFF2E8',
accent: '#FF8C73'
},
'510000': { // 四川
primary: '#FA8C16',
secondary: '#FFA940',
background: '#FFF7E6',
accent: '#FFAB65'
},
'520000': { // 贵州
primary: '#52C41A',
secondary: '#73D13D',
background: '#F6FFED',
accent: '#7CB342'
},
'530000': { // 云南(保持原色)
primary: '#27B25F',
secondary: '#4CCC7F',
background: '#F6FFED',
accent: '#5CDB87'
},
'630000': { // 青海
primary: '#13C2C2',
secondary: '#36CFC9',
background: '#E6FFFB',
accent: '#5CDBD3'
},
'734100': { // 海南
primary: '#E91E63',
secondary: '#F06292',
background: '#FCE4EC',
accent: '#F48FB1'
}
}
return themes[this.currentProvinceCode] || themes['530000'] // 如果找不到对应省份,使用云南配色
}
},
components: {
ServiceRevenuePie,
CustomerAnalysis,
CarAnalysis
},
onLoad(option) {
console.log(option)
_self = this
uni.showLoading({
title: '正在加载...'
})
if (option.ProvinceCode) {
// this.nowTab = option.ProvinceCode == 340000 ? 3 : 1
option.time = this.$util.cutDate(option.time, 'YYYY-MM-DD')
option.month = this.$util.cutDate(option.time, 'YYYYMM')
this.searchDate = this.$util.cutDate(option.time, 'MM月DD日')
this.theRequest = option
// 初始化省份主题
this.initProvinceCode()
this.initData(option)
this.getData(option)
}
let startTime // 开始时间
const date = new Date()
let y = date.getFullYear()
let m = date.getMonth() + 1
let d = date.getDate() - 1
if (d - 8 < 0) {
let num = 8 - d
let changeMonth = m - 1
if (changeMonth < 10) {
changeMonth = '0' + changeMonth
}
let thisMonthDay = this.$util.getThisMonthDay(`${y}-${changeMonth}`)
if (m < 10) {
m = '0' + m
}
startTime = `${y}-${m}-${thisMonthDay - num}`//真实的日期
} else {
if (m < 10) {
m = '0' + m
}
let day
day = d - 8
startTime = `${y}-${m}-${day}`
}
console.log('mmm', m);
this.startTime = startTime
this.endTime = `${y}-${m}-${d}`
console.log('this.startTimethis.startTime', this.startTime);
console.log('this.startTimethis.endTime', this.endTime);
},
methods: {
// 初始化省份代码
initProvinceCode() {
let provinceCode = ''
// 优先使用theRequest中的省份代码
if (this.theRequest && this.theRequest.ProvinceCode) {
provinceCode = this.theRequest.ProvinceCode
}
// 只有在确实找到省份代码时才设置和更新
if (provinceCode) {
this.currentProvinceCode = provinceCode
console.log('设置省份主题:', provinceCode)
// 强制更新以应用新主题
this.$forceUpdate()
}
},
// 获取主题颜色(小程序兼容版本)
getThemeColors() {
return this.provinceTheme
},
changeTab(value) {
this.nowTab = value
if (value == 2) {
let opt = this.theRequest
const params = {
serverpartId: opt.ServerpartIds,
pushprovinceCode: opt.ProvinceCode,
statisticsMonth: this.$util.cutDate(opt.time, 'YYYYMM', -30)
}
this.$refs['customerAna'].tabChange(1, params)
}
if (value == 4) {
let opt = this.theRequest
const params = {
serverpart_Id: opt.ServerpartIds,
pushprovinceCode: opt.ProvinceCode,
StatisticsDate: opt.time
}
this.$refs['carAna'].getTopData(params)
}
},
closePop() {
this.showUnUpLoad = false
},
bindDateChange(e) {
let values = e.detail.value
let selectT = new Date(e.detail.value)
this.unUploadList = []
if (selectT <= new Date(this.lastDay)) {
let opt = this.theRequest
opt.time = values
opt.month = this.$util.cutDate(opt.time, 'YYYYMM')
this.searchDate = this.$util.cutDate(values, 'MM月DD日')
this.changeTab(this.nowTab)
uni.showLoading({
title: '正在加载'
})
this.initData(opt)
this.getData(opt)
this.$forceUpdate()
} else {
uni.showToast({
title: '请选择有效日期',
icon: 'none',
})
}
},
showFixed(options) {
this.scrollTop = options.scrollTop
let selfHeight = uni.upx2px(396)
if (options.scrollTop > selfHeight) {
if (this.fixedY !== 0) {
// console.log( 0)
this.fixedY = 0
this.opacity = 1
this.$forceUpdate()
}
} else {
if (this.fixedY !== -selfHeight) {
this.fixedY = 0 - selfHeight
this.opacity = 0
this.$forceUpdate()
}
}
},
toBrandPage(item, index) {
let theRequest = this.theRequest
let nowShop = this.nowShop
let btid = this.cateBrandList[nowShop].Business_Trade
let pages = `/pages/everdayRenven/serviceDetail?bid=${item.Brand_Id}&shopid=${item.ServerpartShop_Id}&id=${theRequest.ServerpartIds}&time=${theRequest.time}&provinceId=${theRequest.ProvinceCode}&btid=${item.Business_Trade}`
this.$util.toNextRoute('navigateTo', pages)
},
async selectCate(index) {
if (index == this.nowShop) return
this.nowShop = index
this.showAll = false
let leftWidthSum = 0;
for (var i = 0; i <= index; i++) {
let nowElement = await this.getWidth('tabNum' + i)
leftWidthSum = leftWidthSum + nowElement.width
}
let winWidth = uni.getSystemInfoSync().windowWidth
winWidth = (winWidth - 60) / 1.5
this.scrollLeft = leftWidthSum > winWidth ? (leftWidthSum - winWidth) : 0
this.$forceUpdate()
},
getWidth(id) { //得到元素的宽高
return new Promise((res, rej) => {
uni.createSelectorQuery().select("#" + id).fields({
size: true,
scrollOffset: true
}, (data) => {
res(data)
// console.log(data)
}).exec()
})
},
operationFn() { //昨日营收占比
let _this = this;
// 业态营收占比
let colors1 = ['#FFAC37', '#d8ece9', '#e0e3f7', '#f7f5f6', '#b2b7e3'];
let list = []
let list2 = []
// 检查数据有效性
if (!_this.pageData || !_this.pageData.listBusinessModel) {
console.warn('pageData 或 listBusinessModel 无效')
return
}
_this.pageData.listBusinessModel.map((m, i) => {
if (m.Revenue_Amount && m.Revenue_Amount != 0) {
let n = {
name: m.Bussiness_Name,
data: m.Revenue_Amount
}
let n2 = {
name: m.Bussiness_Name,
value: m.Revenue_Amount
}
list2.push(n2)
n.textColor = '#D1D1D1'
n.textSize = uni.upx2px(26)
n.formatter = function (arg) {
if (typeof arg === 'number') {
return [n.name, (arg * 100).toFixed(2) + '%']
} else {
return [arg.name, (arg._proportion_ * 100).toFixed(2) + '%']
}
}
list.push(n)
}
})
// 构建完整的数据数组
let fullServiceRevenueData = []
// 添加第一层数据
if (list2.length > 0) {
fullServiceRevenueData.push(list2)
_this.sellData = list
console.log('第一层数据准备:', list2)
}
// 添加第二层数据
if (_this.pageData.listCurBusinessModel && _this.pageData.listCurBusinessModel.length > 0) {
let list3 = []
_this.pageData.listCurBusinessModel.map(m => {
if (m.Revenue_Amount && m.Revenue_Amount != 0) {
let n = {
name: m.Bussiness_Name,
value: m.Revenue_Amount
}
list3.push(n)
}
})
if (list3.length > 0) {
fullServiceRevenueData.push(list3)
console.log('第二层数据准备:', list3)
}
}
// 一次性设置完整数据,确保响应式更新
if (fullServiceRevenueData.length > 0) {
_this.$set(_this, 'ServiceRevenueData', fullServiceRevenueData)
console.log('operationFn设置完整数据:', fullServiceRevenueData)
}
console.log('最终 ServiceRevenueData:', _this.ServiceRevenueData)
if (list.length > 0) {
_this.showPie({
id: 'sellCate',
data: list,
colors: colors1,
});
}
},
operationBusniess(arr, data) { // 生成业态营收占比数据
var _data1 = [];
var _data2 = [];
let _this = this
arr.forEach((n, i) => {
if (data[n[0]] > 0) {
let num = Number(data[n[0]])
_data1.push({
name: n[1],
textColor: '#999',
data: data[n[0]], //+Number(data2[n[0]])
formatter: function (arg) {
if (typeof arg === 'number') {
return [n[1], (arg * 100).toFixed(2) + '%']
} else {
return [arg.name, (arg._proportion_ * 100).toFixed(2) + '%']
}
// return [n[1], (arg * 100).toFixed(2) + '%']
}
});
}
});
_data1.sort(function (a, b) {
return b.data - a.data
})
return _data1;
},
showPie(obj) {
let data = {
series: []
}
const ctx = uni.createCanvasContext(obj.id, this);
data.series = data.series.concat(obj.data)
rincanvas[obj.id] = new uCharts({
// $this: _self,
// canvasId: obj.id,
context: ctx,
color: obj.colors,
type: 'ring',
padding: obj.id != 'modelCount' ? [15, 15, 25, 0] : '',
legend: {
show: false,
},
title: {
name: data.series[0].name,
fontSize: uni.upx2px(26),
color: '#666666',
// offsetY: uni.upx2px(-16),
},
animation: false,
subtitle: {
name: '¥' + this.$util.fmoney(data.series[0].data, 2),
color: '#666666',
fontSize: uni.upx2px(30),
offsetX: uni.upx2px(16),
},
fontSize: 12,
background: '#FFFFFF',
pixelRatio: 1,
series: data.series,
animation: true,
width: obj.id != 'modelCount' ? uni.upx2px(720) : uni.upx2px(666),
height: obj.id != 'modelCount' ? uni.upx2px(586) : uni.upx2px(480),
dataLabel: true,
disablePieStroke: true,
dataPointShape: false,
extra: {
ring: {
ringWidth: obj.id != 'modelCount' ? uni.upx2px(90) : 40,
labelWidth: uni.upx2px(40),
activeOpacity: 1,
activeRadius: 10
},
tooltip: {
showBox: false,
bgColor: '#000',
bgOpacity: 0.4,
}
},
});
},
touchPie(e, id, opt) {
let touches = null
if (id == "modelCount" && e.currentTarget.offsetTop < 100) {
e.currentTarget.offsetTop = e.currentTarget.offsetTop + uni.upx2px(620)
}
let index = rincanvas[id].getCurrentDataIndex(e)
if (index == -1) return
let item = id != "modelCount" ? this.sellData[index] : this.operationModel[index]
if (id != "modelCount") {
this.sellData.map(n => {
n.textColor = "#d1d1d1"
})
item.textColor = "#999"
this.nowShop = index + 1
}
let showData = {
title: {
name: item.name,
fontSize: uni.upx2px(26),
color: '#666666',
offsetY: uni.upx2px(-16),
},
series: id != "modelCount" ? this.sellData : this.operationModel,
animation: false,
subtitle: {
name: '¥' + this.$util.fmoney(item.data, 2),
color: '#666666',
fontSize: uni.upx2px(30),
offsetY: uni.upx2px(-16),
},
}
rincanvas[id].updateData(showData);
rincanvas[id].showToolTip(e);
},
showPop() {
let list = this.unUploadList
if (list.length || this.todayUpList.length) {
this.showUnUpLoad = true
this.$forceUpdate()
}
},
getData(theRequest) {
let _this = this
this.$request.$webGet('CommercialApi/Revenue/GetServerpartBrand', {
Serverpart_Id: theRequest.ServerpartIds,
statictics_Time: theRequest.time,
pushProvinceCode: theRequest.ProvinceCode
}).then(res => {
if (res.Result_Code != 100) return
_this.pageData = res.Result_Data
if (res.Result_Data.listBusinessModel) {
let list = JSON.parse(JSON.stringify(res.Result_Data.listBusinessModel))
console.log('获取到业务数据:', list)
if (list.length > 0) {
let all = {
Bussiness_Name: '全部',
listBrandModel: []
}
list.map(n => {
all.listBrandModel.push(...n.listBrandModel)
})
all.listBrandModel.sort((a, b) => {
if (a.Revenue_Amount < b.Revenue_Amount) {
return 1
} else {
return -1
}
})
_this.cateBrandList = [all, ...list]
// 确保在数据设置后调用 operationFn
_this.$nextTick(() => {
_this.operationFn()
})
return
}
return
}
// 没有数据时清空相关数据
_this.cateBrandList = []
_this.$set(_this, 'ServiceRevenueData', [])
})
},
// 获取头部卡片 展示信息
async initData(theRequest) {
let _this = this
const [totalData, busniessTypePie, busniessTradePie, busniessTradeFathPie] =
await anhuiYestodayRevenueData.getData(theRequest, true)
totalData.tickave = totalData.ticketCount > 0 ? this.$util.fmoney(totalData.cashPay / totalData
.ticketCount, 2) : 0
totalData.countave = totalData.totalCount > 0 ? this.$util.fmoney(totalData.cashPay / totalData
.totalCount, 2) : 0
totalData.totalMoneyShow = this.$util.fmoney(totalData.cashPay)
// totalData.dayOfShow = this.$util.cutDate(theRequest.time, 'MM月DD日')
totalData.budgetamoutShow = totalData.budgetAmount ? _this.$util.fmoney(totalData.budgetAmount) : 0.00
totalData.diffBudgetTotal = Math.abs(totalData.budgetAmount - totalData.cashPay)
totalData.diffBili = totalData.budgetAmount > 0 ? this.$util.fmoney((totalData.diffBudgetTotal /
totalData.budgetAmount) * 100, 2) : '100'
this.sMsg = totalData
// 饼图分析及数据条形分析
const [progressList, pieList] = this.getProgressData(busniessTypePie, totalData.cashPay)
this.operationModel = progressList
// 经营类型分析
var colors1 = ['#FFAC37', '#6B75B8'];
this.showPie({
id: 'modelCount',
data: pieList,
colors: colors1,
});
// 经营业态
if (busniessTradeFathPie && busniessTradeFathPie.length > 0 && busniessTradePie && busniessTradePie.length > 0) {
this.$set(this, 'ServiceRevenueData', [busniessTradeFathPie, busniessTradePie])
} else {
this.$set(this, 'ServiceRevenueData', [])
}
if (totalData.uploadCount !== totalData.totalUploadCount) {
this.getUnUpLoadShops(theRequest)
}
this.showPage = true
uni.hideLoading()
},
getProgressData(data, total) {
var _data1 = [];
var _data2 = [];
let _this = this
data.forEach((n, i) => {
_data1.push({
...n,
textColor: '#999',
formatter: function (arg) {
if (typeof arg === 'number') {
return [n.name, (arg * 100).toFixed(2) + '%']
} else {
return [arg.name, (arg._proportion_ * 100).toFixed(2) + '%']
}
}
});
_data2.push({
name: n.name,
num: n.data,
data: _this.$util.fmoney(n.data, 2), //+Number(data2[n[0]])
bili: _this.$util.fmoney((n.data / total) * 100, 2)
});
});
_data1.sort(function (a, b) {
return b.data - a.data
})
_data2.sort(function (a, b) {
return b.num - a.num
})
return [_data2, _data1];
},
getUnUpLoadShops(theRequest) {
let _this = this
_this.$request.$webGet('CommercialApi/Revenue/GetUnUpLoadShops', {
Statistics_Date: theRequest.time,
pushProvinceCode: theRequest.ProvinceCode,
Serverpart_ID: theRequest.ServerpartIds
}).then(res => {
//
if (res.Result_Code != 100) {
return false
}
let _data = res.Result_Data
_this.unUploadList = _data.List
})
},
},
onPageScroll(e) {
this.showFixed(e)
}
}
</script>
<style lang="scss" scoped>
// 省份主题定义 - 创建mixin以便复用
@mixin theme-colors($primary, $secondary) {
// 主要操作按钮和强调元素 - 使用主题色
.box-center-title {
background: linear-gradient(90deg, $primary, $secondary);
}
.tab.active {
background: linear-gradient(135deg, $primary, $secondary);
}
.fixed-box {
background: linear-gradient(135deg, $primary, $secondary);
}
.top-card {
background: linear-gradient(135deg, $primary 0%, $secondary 100%);
}
// 装饰性元素 - 使用主题色
.box-card::before {
background: linear-gradient(90deg, $primary, $secondary);
}
.pie-content::before {
background: linear-gradient(90deg, $primary, $secondary);
}
.header-top::after {
background: linear-gradient(90deg, $primary, $secondary);
}
// 关键数据和金额 - 使用主题色突出显示
.center-num {
color: #fff; // 保持白色在渐变背景上
}
.price-num {
color: #fff; // 门店卡片价格保持白色
}
// 进度条和状态指示器
.progress-left {
background: linear-gradient(90deg, $primary, $secondary);
}
.pop-index {
background: linear-gradient(135deg, $primary, $secondary);
}
// 特殊状态元素
.shop-card:nth-child(6n) {
background: linear-gradient(135deg, $primary, $secondary);
}
}
// 宁波 330200
.province-theme-330200 {
@include theme-colors(#1890FF, #69C0FF);
}
// 安徽 340000
.province-theme-340000 {
@include theme-colors(#748ED6, #91A7E3);
}
// 重庆 500000
.province-theme-500000 {
@include theme-colors(#FA541C, #FF7A45);
}
// 四川 510000
.province-theme-510000 {
@include theme-colors(#FA8C16, #FFA940);
}
// 贵州 520000
.province-theme-520000 {
@include theme-colors(#52C41A, #73D13D);
}
// 云南 530000
.province-theme-530000 {
@include theme-colors(#27B25F, #4CCC7F);
}
// 青海 630000
.province-theme-630000 {
@include theme-colors(#13C2C2, #36CFC9);
}
// 海南 734100
.province-theme-734100 {
@include theme-colors(#E91E63, #F06292);
}
.page-body {
background-color: #f8f9fa;
padding: 0 32rpx 32rpx;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
min-height: 100vh;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.mt8 {
margin-top: 20rpx;
}
cover-view.page-title {
color: #fff;
}
.page-title {
background-color: #fcfcfc;
display: flex;
align-items: center;
height: 110rpx;
padding: 0 24rpx;
justify-content: space-between;
color: #000;
font-size: 30rpx;
}
.page-title text:last-child {
color: #383838;
}
.fixed-box {
transition: all .3s ease;
position: fixed;
top: 0;
left: 32rpx;
width: calc(100% - 64rpx);
z-index: 999;
box-sizing: border-box;
color: #fff;
box-shadow: 0 4rpx 20rpx rgba(39, 178, 95, 0.3);
backdrop-filter: blur(10rpx);
border-radius: 0 0 16rpx 16rpx;
}
/* 业态 */
.operation-cate-content {
height: 585rpx;
width: 690rpx;
margin: 0 auto;
}
.operation-model-content {
height: 480rpx;
width: 690rpx;
margin: 0 auto;
}
/* 门店 */
.shop-box {
margin: 24rpx 0;
border-radius: 16rpx;
background-color: #fff;
padding: 32rpx 24rpx;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
border: 1rpx solid #f0f0f0;
}
.tab-shop {
color: #999999;
white-space: nowrap;
}
.tab-shop .cate-name {
padding-right: 16rpx;
font-size: 26rpx;
display: inline-block;
vertical-align: middle;
}
.tab-shop .cate-name+.cate-name::before {
content: '|';
color: #eeeeee;
padding-right: 16rpx;
}
.tab-shop .cate-name.active {
color: #000;
font-size: 28rpx;
font-weight: 600;
}
.tab-content {
display: flex;
flex-wrap: wrap;
// margin-top: 24rpx;
transition: all 0.5s cubic-bezier(0, 1, 0.5, 1);
margin: 0 auto 0 auto;
overflow: hidden;
height: inherit;
width: inherit;
}
.pie-content {
margin: 24rpx 0 32rpx;
border-radius: 16rpx;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
background-color: #fff;
position: relative;
padding: 32rpx 24rpx;
border: 1rpx solid #f0f0f0;
overflow: hidden;
// 主题色边框由 mixin 处理
}
.pie-title {
padding: 0;
line-height: 1.5;
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
/* 门店卡片 */
.shop-card {
width: 192rpx;
height: 240rpx;
border-radius: 16rpx;
color: #fff;
text-align: center;
padding: 24rpx 16rpx;
box-sizing: border-box;
margin-top: 20rpx;
margin-right: 16rpx;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
&:active {
transform: scale(0.98);
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%);
pointer-events: none;
}
}
.shop-card:nth-child(6n-5) {
background: linear-gradient(135deg, #ff6b6b, #ee5a52);
}
.shop-card:nth-child(6n-4) {
background: linear-gradient(135deg, #feca57, #ff9ff3);
}
.shop-card:nth-child(6n-3) {
background: linear-gradient(135deg, #a8e6cf, #7fcdcd);
}
.shop-card:nth-child(6n-2) {
background: linear-gradient(135deg, #74b9ff, #0984e3);
}
.shop-card:nth-child(6n-1) {
background: linear-gradient(135deg, #fd79a8, #e84393);
}
.shop-card:nth-child(6n) {
// 主题色由 mixin 处理,无需额外间距
}
// 每行第3个卡片移除右边距实现3列对齐
.shop-card:nth-child(3n) {
margin-right: 0;
}
.shop-card .shop-name {
height: 60rpx;
font-size: 26rpx;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
line-height: 30rpx;
// max-height: 50rpx;
overflow: hidden;
font-weight: 500;
margin: 4rpx 0;
}
.shop-card image {
border-radius: 50%;
border: 3rpx solid rgba(255, 255, 255, 0.9);
background-color: #FFFFFF;
width: 64rpx;
height: 64rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.2);
}
.shop-card .price-num {
font-size: 28rpx;
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
font-weight: 700;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
margin-top: auto;
white-space: nowrap;
}
.box-card {
padding: 32rpx 24rpx 16rpx;
background-color: #fff;
width: 100%;
box-sizing: border-box;
transition: all .3s ease;
margin: 0 0 24rpx;
border-radius: 16rpx;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
// 主题色边框由 mixin 处理
}
.top-card {
margin-top: 32rpx;
padding: 24rpx 0;
border-radius: 16rpx;
position: relative;
box-shadow: 0 8rpx 24rpx rgba(39, 178, 95, 0.2);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="90" cy="10" r="2" fill="white" opacity="0.3"/><circle cx="80" cy="20" r="1" fill="white" opacity="0.2"/><circle cx="70" cy="5" r="1.5" fill="white" opacity="0.4"/></svg>') repeat;
pointer-events: none;
}
}
.budgetamount {
margin-left: 16rpx;
color: rgba(255, 255, 255, 0.9);
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
font-weight: 500;
display: flex;
align-items: center;
}
.budget-title {
color: rgba(255, 255, 255, 0.8);
padding: 6rpx 12rpx;
border-radius: 12rpx;
margin-right: 8rpx;
background: rgba(255, 255, 255, 0.1);
font-size: 22rpx;
}
.up-text-title,
.down-text-title {
font-size: 32rpx;
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
font-weight: 600;
line-height: 1.3;
}
.up-text-title:after {
content: "";
margin-left: 6rpx;
width: 16rpx;
height: 18rpx;
display: inline-block;
background: url('/static/images/revenue/up-arrow.png') no-repeat center;
background-size: contain;
}
.down-text-title:after {
content: "";
margin-left: 6rpx;
width: 16rpx;
height: 18rpx;
display: inline-block;
background: url('/static/images/revenue/down-arrow.png') no-repeat center;
background-size: contain;
}
.box-top-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8rpx;
}
.title-clock {
color: #666;
font-size: 26rpx;
text-align: right;
padding: 8rpx 16rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 20rpx;
border: 1rpx solid #e5e5e5;
}
/*
.more-btn,.weisc-ico {
display: flex;
align-items: center;
margin-left: 8upx;
color: #dd7575;
font-size: 30upx;
} */
.more-btn:after {
content: '';
display: inline-block;
margin-left: 8upx;
width: 10upx;
height: 20upx;
background: url(../../static/images/effective/sj.png) no-repeat center;
background-size: contain;
}
.box-center-title {
font-size: 28rpx;
color: #fff;
border-radius: 24rpx;
padding: 8rpx 20rpx;
text-align: center;
font-weight: 400;
box-shadow: 0 4rpx 12rpx rgba(39, 178, 95, 0.3);
}
.uni-icon-arrowdown {
font-size: 24rpx;
}
.box-center-box {
/* margin-bottom: 16rpx; */
padding: 0 24rpx;
}
.center-title {
color: #DEDEDE;
font-size: 24rpx;
}
.center-num {
font-size: 32rpx;
color: #fff;
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
font-weight: 700;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
letter-spacing: 2rpx;
}
.check-unit,
.budgetamount {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.9);
text-align: center;
line-height: 1.4;
}
.main-amount-title {
color: rgba(255, 255, 255, 0.9);
font-size: 26rpx;
font-weight: 500;
}
.tab-unit {
background: rgba(255, 255, 255, 0.2);
border-radius: 20rpx;
color: #fff;
font-size: 26rpx;
padding: 2rpx 16rpx;
font-weight: 500;
backdrop-filter: blur(10rpx);
border: 1rpx solid rgba(255, 255, 255, 0.3);
}
.check-price-color {
color: #fff;
font-size: 28rpx;
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
line-height: 1.3;
font-weight: 600;
margin-top: 8rpx;
}
.check-price-color text {
font-size: 24rpx;
}
.tab-icon2 {
font-size: 26rpx;
color: #DEDEDE;
flex: 1;
}
.tab-unit-num {
font-size: 24rpx;
color: #fff;
}
.tab-unit-num+.tab-unit-num:before {
content: '/';
margin: 0 4rpx;
color: #fff;
}
.priceGreen,
.priceGreen.tab-unit-num {
color: #7CB9A5;
/* font-size: 28rpx; */
}
.priceRed,
.tab-unit-num.priceRed {
color: #DD7575;
/* font-size: 28rpx; */
}
/* 弹出内容 */
.uni-mask {
position: absolute;
z-index: 998;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #000;
height: calc(100vh);
width: 750rpx;
opacity: 0.6;
}
.uni-popup {
position: fixed;
z-index: 999;
background: #ffffff;
box-shadow: 0 0 30upx rgba(0, 0, 0, .1);
}
.uni-popup-middle {
display: flex;
flex-direction: column;
align-items: center;
min-width: 500rpx;
min-height: 400rpx;
border-radius: 20rpx;
top: 30%;
left: 50%;
transform: translate(-50%, -20%);
justify-content: flex-start;
padding: 0 32rpx 32rpx;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
border: 1rpx solid rgba(255, 255, 255, 0.2);
}
.header-top {
font-size: 32rpx;
font-weight: 700;
color: #333;
text-align: left;
width: 100%;
padding: 32rpx 0 24rpx;
background-color: #fff;
position: relative;
// 主题色下划线由 mixin 处理
}
.pop-body {
width: 100%;
max-height: 500rpx;
overflow-y: auto;
background-color: #fff;
padding-bottom: 16rpx;
border-radius: 8rpx;
}
.pop-row {
padding: 20rpx 0;
font-size: 26rpx;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
position: relative;
color: #333;
}
.pop-row .pop-row-bottom {
position: absolute;
height: 1rpx;
width: 100%;
background: linear-gradient(90deg, transparent 0%, #e5e5e5 50%, transparent 100%);
bottom: 0;
left: 0;
}
.pop-index {
color: #fff;
border-radius: 12rpx;
padding: 4rpx 12rpx;
margin-right: 16rpx;
font-size: 22rpx;
font-weight: 600;
min-width: 48rpx;
text-align: center;
box-shadow: 0 2rpx 8rpx rgba(39, 178, 95, 0.3);
}
/* .customer-title {
color: #525280;
font-size: 32rpx;
font-weight: 600;
background: url(../../static/images/revenue/customer-bg.png) no-repeat center;
background-size: contain;
border-radius: 12rpx;
margin-top: 24rpx;
height: 104rpx;
line-height: 104rpx;
padding: 0 32rpx;
font-family: 'FZZhengHeiS-DB-GB Regular', 'FZZhengHeiS-DB-GB Regular-Regular';
display: flex;
align-items: center;
justify-content: space-between;
} */
.uni-icon-arrowright {
border: 1rpx solid #606060;
border-radius: 50%;
color: #606060;
font-size: 32rpx;
}
.analysis-tabs {
margin: 24rpx 0;
overflow: hidden;
background-color: #fff;
border-radius: 12rpx;
display: flex;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
border: 1rpx solid #f0f0f0;
}
.tab {
text-align: center;
flex: 1;
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
color: #666;
transition: all 0.3s ease;
font-weight: 500;
position: relative;
}
.tab.active {
color: #fff;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(39, 178, 95, 0.3);
border-radius: 8rpx;
margin: 4rpx;
height: 72rpx;
line-height: 72rpx;
}
// 经营模式占比
.model-busniess {
font-family: 'DIN Alternate', 'Bahnschrift', sans-serif;
padding: 8rpx 24rpx;
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
border-radius: 12rpx;
border: 1rpx solid #f0f0f0;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}
.model-busniess view {
font-size: 28rpx;
font-weight: 600;
color: #333;
// margin-bottom: 16rpx;
}
.model-busniess .progress-content {
width: 100%;
height: 12rpx;
border-radius: 6rpx;
display: flex;
justify-content: space-between;
margin: 8rpx 0 8rpx;
overflow: hidden;
box-shadow: inset 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.model-busniess .progress-left {
border-radius: 6rpx 0 0 6rpx;
}
.model-busniess .progress-right {
background: linear-gradient(90deg, #ff9f43, #ffb84d);
border-radius: 0 6rpx 6rpx 0;
}
/* 动画效果 - UniApp微信小程序兼容版本 */
/* 页面入场动画 */
@keyframes pageEnter {
0% {
opacity: 0;
transform: translateY(50rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.page-enter {
animation: pageEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
}
/* 卡片入场动画 */
@keyframes cardEnter {
0% {
opacity: 0;
transform: translateY(30rpx) scale(0.95);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.card-enter {
animation: cardEnter 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.1s forwards;
opacity: 0;
}
/* 数据卡片动画 */
@keyframes dataCardEnter {
0% {
opacity: 0;
transform: translateY(20rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.data-card-enter {
animation: dataCardEnter 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.2s forwards;
opacity: 0;
}
/* 指标动画 */
@keyframes metricEnter {
0% {
opacity: 0;
transform: translateY(15rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.metric-enter:nth-child(1) {
animation: metricEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.3s forwards;
opacity: 0;
}
.metric-enter:nth-child(2) {
animation: metricEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.4s forwards;
opacity: 0;
}
.metric-enter:nth-child(3) {
animation: metricEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s forwards;
opacity: 0;
}
.metric-enter:nth-child(4) {
animation: metricEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.6s forwards;
opacity: 0;
}
/* Tab标签页动画 */
@keyframes tabsEnter {
0% {
opacity: 0;
transform: translateY(20rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.tabs-enter {
animation: tabsEnter 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.4s forwards;
opacity: 0;
}
@keyframes tabSlide {
0% {
opacity: 0;
transform: translateX(-20rpx);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.tab-slide:nth-child(1) {
animation: tabSlide 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s forwards;
opacity: 0;
}
.tab-slide:nth-child(2) {
animation: tabSlide 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.6s forwards;
opacity: 0;
}
.tab-slide:nth-child(3) {
animation: tabSlide 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.7s forwards;
opacity: 0;
}
/* Tab内容淡入动画 */
@keyframes tabContentFade {
0% {
opacity: 0;
transform: translateY(10rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.tab-content-fade {
animation: tabContentFade 0.4s ease-out forwards;
}
/* 图表容器动画 */
@keyframes chartContainerEnter {
0% {
opacity: 0;
transform: translateY(30rpx) scale(0.98);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.chart-container-enter {
animation: chartContainerEnter 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.6s forwards;
opacity: 0;
}
/* 标题滑入动画 */
@keyframes titleSlideIn {
0% {
opacity: 0;
transform: translateX(-30rpx);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.title-slide-in {
animation: titleSlideIn 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.7s forwards;
opacity: 0;
}
/* 进度条区域动画 */
@keyframes progressSectionEnter {
0% {
opacity: 0;
transform: translateY(20rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.progress-section-enter {
animation: progressSectionEnter 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.8s forwards;
opacity: 0;
}
/* 品牌列表动画 */
@keyframes brandListEnter {
0% {
opacity: 0;
transform: translateY(25rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.brand-list-enter {
animation: brandListEnter 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.9s forwards;
opacity: 0;
}
/* 品牌卡片错列动画 */
@keyframes brandCardStagger {
0% {
opacity: 0;
transform: translateY(20rpx) scale(0.95);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.brand-card-stagger {
animation: brandCardStagger 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1s forwards;
opacity: 0;
}
/* 交互反馈动画 */
.tab-slide:active,
.brand-card-stagger:active {
transform: scale(0.98);
transition: transform 0.1s ease-out;
}
/* 图表加载状态 */
.chart-loading {
display: flex;
justify-content: center;
align-items: center;
height: 300rpx;
color: #999;
font-size: 28rpx;
}
/* 品牌标签页动画 */
@keyframes tabShopSlide {
0% {
opacity: 0;
transform: translateY(15rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.tab-shop-slide {
animation: tabShopSlide 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1.1s forwards;
opacity: 0;
}
/* 品牌标签错列动画 */
@keyframes brandTabStagger {
0% {
opacity: 0;
transform: translateX(-15rpx);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.brand-tab-stagger {
animation: brandTabStagger 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1.2s forwards;
opacity: 0;
}
/* 品牌卡片容器动画 */
@keyframes brandCardsContainer {
0% {
opacity: 0;
transform: translateY(20rpx);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.brand-cards-container {
animation: brandCardsContainer 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1.3s forwards;
opacity: 0;
}
/* 品牌图标包装器动画 */
@keyframes brandIconWrapper {
0% {
opacity: 0;
transform: scale(0.8) rotate(-5deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
.brand-icon-wrapper {
animation: brandIconWrapper 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
animation-delay: inherit;
}
.brand-icon {
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
/* 品牌卡片悬浮效果增强 */
.brand-card-stagger:active .brand-icon-wrapper {
transform: scale(0.9) rotate(2deg);
}
.brand-card-stagger:active .shop-name {
transform: translateY(2rpx);
}
.brand-card-stagger:active .price-num {
transform: scale(1.05);
}
/* 品牌标签活跃状态动画 */
.brand-tab-stagger.active {
animation: brandTabStagger 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards,
tabActivePulse 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.2s forwards;
}
@keyframes tabActivePulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
</style>