lanan-app/pages/rescue/businessManage写好.vue
2025-10-23 13:04:29 +08:00

2970 lines
83 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="statistics-container">
<view class="top—1"></view>
<!-- 顶部导航栏 -->
<view class="nav-bar">
<uni-icons class="back-icon" @click="goBack" size="24" type="left" color="#fff"></uni-icons>
<view class="title-tabs">
<text :class="['tab-item', activeTab === 'order' ? 'active' : '']" @click="switchTab('order')">
业务渠道统计
</text>
<text :class="['tab-item', activeTab === 'category' ? 'active' : '']" @click="switchTab('category')">
业绩统计
</text>
<text :class="['tab-item', activeTab === '' ? 'active' : '']" @click="switchTab('')">
财务统计
</text>
</view>
<view class="filter-btn" ></view>
</view>
<!-- 工单统计 -->
<view v-if="activeTab === 'order'">
<view class="dil" >
<!-- 四个选项 -->
<!-- #ifdef APP-PLUS || H5 -->
<view class="tab-choose-class">
<view class="tab-content" @click="tabChoose(item, index)"
v-for='(item, index) in ["当日", "当月","当年", "全部", "自定义"]' :key='index'>
<!-- tab 名称信息 -->
<view class='tab-name-class'
:style='{ color: index + 1 == tabValue ? "#101A3E" : "#8D90A6", fontWeight: index + 1 == tabValue ? "bold" : "normal" }'>
{{ item }}
<view class="icon-tab" v-if='index == 4'>
<image src="@/static/icons/homeOrderCard/xialajiantou.svg" mode="scaleToFill"></image>
</view>
</view>
<!-- 名称下 icon -->
<view class="tab-icon"
:style='{ background: index + 1 == tabValue ? "linear-gradient( 180deg, #054DF3 0%, #55A3FF 100%)" : "" }'>
</view>
</view>
</view>
<view class="example-body" v-show="tabValue==5" style="margin-bottom: 16rpx;">
<uni-datetime-picker v-model="range" type="daterange" @maskClick="maskClick" />
</view>
<view class="four-box-header">
<view class="blue-line"></view>
<text class="four-box-header-title">业务</text>
</view>
<!-- <view class="tab-choose-class tab-choose-multi tab-choose-equal">
<view class="tab-content" @click="channelTabChoose(item, index)"
v-for='(item, index) in ["泸渝高速", "泸贵高速","交警二大队", "泸州人才保险", "泸州中华保险","泸州中华保险","泸州平安保险","蓝安修理厂","其他修理场","其他修理场"]' :key='index'>
<view class='tab-name-class'
:style='{ color: index + 1 == channelTabValue ? "#101A3E" : "#8D90A6", fontWeight: index + 1 == channelTabValue ? "bold" : "normal" }'>
{{ item }}
</view>
</view>
</view> -->
<!-- 快捷统计卡 -->
<view class="four-box">
<view class="boxf" @click="goToOrder('null')">
<view class="zi1">
<image class="zi1-icon" src="@/static/icons/homeOrderCard/receivedOrder_new.png" mode="aspectFit" />
<text>已接单</text>
</view>
<view class="zi2" style="margin-top: 10rpx;">{{countNum.yjdNum ? countNum.yjdNum : '0'}}</view>
</view>
<view class="boxf" @click="goToOrder(1)">
<view class="zi1">
<image class="zi1-icon" src="@/static/icons/homeOrderCard/jyz_new.png" mode="aspectFit" />
<text>救援中</text>
</view>
<view class="zi2" style="margin-top: 10rpx;">{{countNum.jyzNum ? countNum.jyzNum : '0'}}</view>
</view>
<view class="boxf" @click="goToOrder(5)">
<view class="zi1">
<image class="zi1-icon" src="@/static/icons/homeOrderCard/ywc_new.png" mode="aspectFit" />
<text>已完成</text>
</view>
<view class="zi2" style="margin-top: 10rpx;">{{countNum.ywcNum ? countNum.ywcNum : '0'}}</view>
</view>
</view>
<!-- 金额/待取车卡 -->
<view class="two-box-container">
<view class="two-box">
<view class="boxf2" style="background: linear-gradient(135deg, #E0F0FF 40%, #BBD9FF 100%);">
<view style="display: flex; justify-content: space-between; align-items: center;">
<view class="zi1_1">
<image class="zi1_1-icon" src="@/static/icons/homeOrderCard/ysk_solid.png" mode="aspectFit" />
<text style="color: #3d6ba0; font-weight: bold; font-size: 30rpx;">应收款</text>
</view>
<uni-icons class="eye-icon" type="eye" />
</view>
<view class="zi2_2" style="margin-top: 10rpx;">{{ countNum.yingskNum ? countNum.yingskNum : '0' }}</view>
</view>
<view class="boxf2" style="background: linear-gradient(135deg, #FFF7E0 40%, #FFE7B8 100%);" @click="goToOrder(3)">
<view style="display: flex; justify-content: space-between; align-items: center;">
<view class="zi1_1">
<image class="zi1_1-icon" src="@/static/icons/homeOrderCard/qucar.png" mode="aspectFit" />
<text style="color: #a97747; font-size: 30rpx; font-weight: bold;">待取车</text>
</view>
<uni-icons class="eye-icon" type="eye" />
</view>
<view class="zi2_2" style="margin-top: 10rpx;">{{ countNum.dqcNum ? countNum.dqcNum : '0' }}</view>
</view>
</view>
<view class="two-box">
<view class="boxf2" style="background: linear-gradient(135deg, #E6F8ED 40%, #C8F0D8 100%);">
<view style="display: flex; justify-content: space-between; align-items: center;">
<view class="zi1_1">
<image class="zi1_1-icon" src="@/static/icons/homeOrderCard/yisk_solid.png" mode="aspectFit" />
<text style="color: #169948; font-size: 30rpx; font-weight: bold;">已收款</text>
</view>
<uni-icons class="eye-icon" type="eye" />
</view>
<view class="zi2_2" style="margin-top: 10rpx;">{{ countNum.yiskNum ? countNum.yiskNum : '0' }}</view>
</view>
<view class="boxf2" style="background: linear-gradient(135deg, #F0E9FF 40%, #D9CEFF 100%);">
<view style="display: flex; justify-content: space-between; align-items: center;">
<view class="zi1_1">
<image class="zi1_1-icon" src="@/static/icons/homeOrderCard/dsk_solid.png" mode="aspectFit" />
<text style="color: #6657da; font-weight: bold; font-size: 30rpx;">待收款</text>
</view>
<uni-icons class="eye-icon" type="eye" />
</view>
<view class="zi2_2" style="margin-top: 10rpx;">{{ countNum.dskNum ? countNum.dskNum : '0' }}</view>
</view>
</view>
</view>
<!-- #endif -->
<!-- ===== 业务渠道统计 标题栏 ===== -->
<view class="bc-header">
<view class="blue-line"></view>
<text class="section-title">业务渠道统计</text>
<!-- 右侧时间 Tab -->
<!-- <view class="time-tabs">
<text class="time-item active">本日</text>
<text class="time-item">本月</text>
<text class="time-item">本年</text>
<text class="time-item">全部</text>
<text class="time-item">自定义</text>
</view> -->
<!-- 右侧时间 Tab ✅ 改成循环 -->
<view class="time-tabs">
<text
v-for="(t,i) in ['本日','本月','本年','全部','自定义']"
:key="i"
:class="['time-item', cTab===i ? 'active' : '']"
@click.stop="switchCTab(i)"
>
{{ t }}
</text>
</view>
</view>
<!-- 仅当点了「自定义」才出现 -->
<uni-datetime-picker
class="full-width-picker"
v-if="cTab===4"
v-model="customRange"
type="daterange"
rangeSeparator="至"
@change="onCustomRangeChange"
/>
<view v-for="stat in channelStats" :key="stat.channel" class="channel-card" @click="goSource(stat)">
<view class="c-header">
<text class="c-name">{{ stat.channel }}</text>
<view class="pk-btn" @click="toChannelPk(stat.channelId)">PK 去对比</view>
</view>
<view class="c-row four">
<view class="c-cell"><text class="c-num">{{ stat.yjdNum }}</text><text class="c-lab">已接单</text></view>
<view class="c-cell"><text class="c-num">{{ stat.jyzNum }}</text><text class="c-lab">救援中</text></view>
<view class="c-cell"><text class="c-num">{{ stat.ywcNum }}</text><text class="c-lab">已完成</text></view>
<view class="c-cell wait-car"><text class="c-num">{{ stat.dqcNum }}</text><text class="c-lab">待取车</text></view>
</view>
<view class="c-row three">
<view class="c-cell"><text class="c-num">{{ stat.receivable }}</text><text class="c-lab">应收款</text></view>
<view class="c-cell"><text class="c-num">{{ stat.receivedMoney }}</text><text class="c-lab">已收款</text></view>
<view class="c-cell"><text class="c-num">{{ stat.dskNum }}</text><text class="c-lab">待收款</text></view>
</view>
</view>
<!-- ===== 渠道卡 1泸渝高速 ===== -->
<view class="channel-card">
<view class="c-header">
<text class="c-name">泸渝高速</text>
<view class="pk-btn">PK 去对比</view>
</view>
<!-- 第一行 4 格 -->
<view class="c-row four">
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已接单</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">救援中</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已完成</text>
</view>
<!-- 待取车:浅灰描边 + 倾斜数字示例 -->
<view class="c-cell wait-car">
<text class="c-num">0</text><text class="c-lab">待取车</text>
</view>
</view>
<!-- 第二行 3 格 -->
<view class="c-row three">
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">应收款</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已收款</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">待收款</text>
</view>
</view>
</view>
<!-- ===== 渠道卡 1泸渝高速 ===== -->
<view class="channel-card">
<view class="c-header">
<text class="c-name">泸渝高速</text>
<view class="pk-btn">PK 去对比</view>
</view>
<!-- 第一行 4 格 -->
<view class="c-row four">
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已接单</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">救援中</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已完成</text>
</view>
<!-- 待取车:浅灰描边 + 倾斜数字示例 -->
<view class="c-cell wait-car">
<text class="c-num">0</text><text class="c-lab">待取车</text>
</view>
</view>
<!-- 第二行 3 格 -->
<view class="c-row three">
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">应收款</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">已收款</text>
</view>
<view class="c-cell">
<text class="c-num">0</text><text class="c-lab">待收款</text>
</view>
</view>
</view>
<!-- ===== 再复制一份改名即可:泸贵高速 / 交警二大队 … ===== -->
<!-- ===== 业务管理统计 标题栏 ===== -->
<view class="bm-header">
<view class="blue-line"></view>
<text class="section-title">业务管理统计</text>
<!-- <view class="time-tabs">
<text class="time-item active">本日</text>
<text class="time-item">本月</text>
<text class="time-item">本年</text>
<text class="time-item">全部</text>
<text class="time-item">自定义</text>
</view> -->
<!-- 放在业务管理统计标题栏右侧 -->
<view class="time-tabs">
<text v-for="(t,i) in ['本日','本月','本年','全部','自定义']"
:key="i"
:class="['time-item', bmTimeTab===i ? 'active' : '']"
@click.stop="changeBmTime(i)">
{{ t }}
</text>
</view>
<!-- 新:外面套一层 -->
<view class="bm-picker" v-if="bmTimeTab===4">
<uni-datetime-picker class="full-width-picker" v-model="bmRange"
type="daterange"
@change="changeBmTime(4,true)" />
</view>
</view>
<!-- ===== 业务管理统计标题栏保持不变 ===== -->
<!-- ===== 业务管理卡:统一 v-for 渲染 ===== -->
<view v-for="cat in bmCategories" :key="cat" class="manage-card">
<view class="m-header">
<text class="m-title">{{ bmTitleMap[cat] || cat }}</text>
<view class="pk-btn" @click="toPk(cat)">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item" v-for="item in bmStats[cat]" :key="item.name">
<text class="m-key">{{ item.name }}</text>
<text class="m-val">{{ item.count }}</text>
</view>
</view>
</view>
<!-- ===== 统计卡 1救援类型统计 ===== -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">救援类型统计</text>
<view class="pk-btn">PK 去对比</view>
</view> -->
<!-- 数据区域:任意偶数个条目均可,自动两列排版 -->
<!-- <view class="m-grid">
<view class="m-item">
<text class="m-key">道路救援</text>
<text class="m-val">46</text>
</view>
<view class="m-item">
<text class="m-key">事故救援</text>
<text class="m-val">29</text>
</view>
</view>
</view> -->
<!-- ===== 统计卡 2故障地点统计示例 4 项) ===== -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">故障地点统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">新旧转换区</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">莱芜区</text><text class="m-val">29</text></view>
<view class="m-item"><text class="m-key">历城区</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">章丘区</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 车辆类型统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">车辆类型统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">小型车</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">中型车</text><text class="m-val">29</text></view>
<view class="m-item"><text class="m-key">大型车</text><text class="m-val">46</text></view>
</view>
</view> -->
<!-- 车辆品牌统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">车辆品牌统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">奔驰</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">沃尔玛</text><text class="m-val">29</text></view>
<view class="m-item"><text class="m-key">大众</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">宝马</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">五菱宏光</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">小米汽车</text><text class="m-val">29</text></view>
<view class="m-item"><text class="m-key">凯迪拉克</text><text class="m-val">46</text></view>
</view>
</view> -->
<!-- 下车地统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">下车地统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">新旧转换区</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">莱芜区</text><text class="m-val">29</text></view>
<view class="m-item"><text class="m-key">历城区</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">章丘区</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 移交易由统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">移交易由统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">请假</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">技术问题</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 是否新能源统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">是否新能源统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">新能源统计</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">非新能源统计</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 救援需求统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">救援需求统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">轮胎问题</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">汽车故障</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 收费类型统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">收费类型统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item"><text class="m-key">线上支付</text><text class="m-val">46</text></view>
<view class="m-item"><text class="m-key">线下支付</text><text class="m-val">29</text></view>
</view>
</view> -->
<!-- 是否扣车统计 -->
<!-- <view class="manage-card">
<view class="m-header">
<text class="m-title">是否扣车统计</text>
<view class="pk-btn">PK 去对比</view>
</view>
<view class="m-grid">
<view class="m-item">
<text class="m-key">待取车数量</text>
<text class="m-val">46</text>
</view>
<view class="m-item">
<text class="m-key">车辆信息</text>
<text class="m-val">29</text>
</view>
</view>
</view> -->
<!-- =========== 财务统计 BEGIN =========== -->
<!-- ========= 财务统计 ========= -->
<view class="sec-bar">
<view class="blue-line"></view>
<text class="sec-title">财务统计</text>
<!-- 时间切换 -->
<view class="time-tabs">
<text v-for="t in ['本日','本月','本年','全部','自定义']"
:key="t"
:class="['t-item', t==='本日' ? 'active' : '']">
{{ t }}
</text>
</view>
</view>
<view class="list-wrap">
<!-- ===== 应收款统计 ===== -->
<view class="uni-card">
<view class="card-hd">
<text class="card-title">应收款统计</text>
<button class="pk-btn">PK 去对比</button>
</view>
<view class="row-g">
<view class="row"><text class="lbl">金额</text><text class="val">1414.70</text><text class="lbl">数量</text><text class="val">208</text></view>
<view class="row"><text class="lbl">相对应的渠道</text><text class="val">489</text><text class="lbl">来源</text><text class="val">512</text></view>
<view class="row"><text class="lbl">救援类型</text><text class="val">216</text><text class="lbl">故障地点</text><text class="val">390</text></view>
<view class="row"><text class="lbl">车辆品牌</text><text class="val">968</text><text class="lbl">车辆类型</text><text class="val">776</text></view>
<view class="row"><text class="lbl">是否新能源</text><text class="val">994</text><text class="lbl">救援需求</text><text class="val">468</text></view>
<view class="row"><text class="lbl">收费类型</text><text class="val">965</text><text class="lbl">待取车数量</text><text class="val">684</text></view>
</view>
</view>
<!-- ===== 已收款统计 ===== -->
<view class="uni-card">
<view class="card-hd">
<text class="card-title">已收款统计</text>
<button class="pk-btn">PK 去对比</button>
</view>
<view class="row-g">
<view class="row"><text class="lbl">金额</text><text class="val">6629.45</text><text class="lbl">数量</text><text class="val">646</text></view>
<view class="row"><text class="lbl">相对应的渠道</text><text class="val">466</text><text class="lbl">来源</text><text class="val">271</text></view>
<view class="row"><text class="lbl">救援类型</text><text class="val">268</text><text class="lbl">故障地点</text><text class="val">573</text></view>
<view class="row"><text class="lbl">车辆品牌</text><text class="val">828</text><text class="lbl">车辆类型</text><text class="val">242</text></view>
<view class="row"><text class="lbl">是否新能源</text><text class="val">240</text><text class="lbl">救援需求</text><text class="val">432</text></view>
<view class="row"><text class="lbl">收费类型</text><text class="val">752</text><text class="lbl">待取车数量</text><text class="val">627</text></view>
</view>
</view>
<!-- ===== 待收款统计 ===== -->
<view class="uni-card">
<view class="card-hd">
<text class="card-title">待收款统计</text>
<button class="pk-btn">PK 去对比</button>
</view>
<view class="row-g">
<view class="row"><text class="lbl">金额</text><text class="val">7774.92</text><text class="lbl">数量</text><text class="val">504</text></view>
<view class="row"><text class="lbl">相对应的渠道</text><text class="val">240</text><text class="lbl">来源</text><text class="val">365</text></view>
<view class="row"><text class="lbl">救援类型</text><text class="val">608</text><text class="lbl">故障地点</text><text class="val">936</text></view>
<view class="row"><text class="lbl">车辆品牌</text><text class="val">347</text><text class="lbl">车辆类型</text><text class="val">841</text></view>
<view class="row"><text class="lbl">是否新能源</text><text class="val">765</text><text class="lbl">救援需求</text><text class="val">219</text></view>
<view class="row"><text class="lbl">收费类型</text><text class="val">630</text><text class="lbl">待取车数量</text><text class="val">637</text></view>
</view>
</view>
</view>
<!-- =========== 财务统计 END =========== -->
<view class="four-box-header_2">
<view class="four-box-header">
<view class="blue-line"></view>
<text class="four-box-header-title">救援列表</text>
</view>
</view>
<view class="tap-box">
<view class="ques" v-if="loading && orderList.length == 0">
<view class="loading-container">
<view class="loading-spinner"></view>
<text class="loading-text">加载中,请稍候...</text>
</view>
</view>
<view class="ques" v-else-if="!loading && orderList.length == 0">
<image src="../../static/quesheng.png" mode="aspectFit"></image>
</view>
<!-- <view style="display: flex;flex-direction: column;row-gap: 10px;" v-else>
<order-card-new :status="1" @revokeOk="revokeOrderHandle"
@refresh="getlist" v-for="(item, index) in orderList" :key="index" :orderData="item"
:activeTab="activeTab" @update:activeTab="activeTab = $event"></order-card-new>
</view> -->
</view>
</view>
<view class="stat-cards-container">
<view class="stat-cards">
<view class="stat-card">
<text class="stat-num">{{ countNum.yjdNum }}</text>
<text class="stat-label">已接单</text>
</view>
<view class="stat-card">
<text class="stat-num">{{ countNum.jyzNum }}</text>
<text class="stat-label">救援中</text>
</view>
<view class="stat-card">
<text class="stat-num">{{ countNum.ywcNum }}</text>
<text class="stat-label">已完成</text>
</view>
</view>
</view>
<!-- 展开后的额外统计块 -->
<view class="expanded-cards">
<view class="stat-cards" style="margin-bottom: 20rpx;">
<view class="stat-card">
<text class="stat-num">{{ countNum.yingskNum }}</text>
<text class="stat-label">应收款(元)</text>
</view>
<view class="stat-card">
<text class="stat-num">{{ countNum.yiskNum }}</text>
<text class="stat-label">已收款(元)</text>
</view>
</view>
<view class="stat-cards">
<view class="stat-card">
<text class="stat-num">{{ countNum.dskNum }}</text>
<text class="stat-label">待收款(元)</text>
</view>
<view class="stat-card">
<text class="stat-num">{{ countNum.dqcNum }}</text>
<text class="stat-label">待取车</text>
</view>
</view>
</view>
<!-- 搜索和时间筛选区域 -->
<view class="search-filter-area">
<!-- 全部、筛选选项卡 -->
<view class="tab-choose-class">
<view class="tab-content" @click="tabChoose(item, index)" v-for='(item, index) in tabTwoList'
:key='index'>
<view class='tab-name-class' :style='{ color: index + 1 == tabValue ? "#101A3E" : "#8D90A6" }'>
{{ item }}
<view class="icon-tab" v-if='index >= 1'>
<image src="@/static/icons/homeOrderCard/xialajiantou.svg" mode="scaleToFill"></image>
</view>
</view>
<view class="tab-icon"
:style='{ background: index + 1 == tabValue ? "linear-gradient( 180deg, #054DF3 0%, #55A3FF 100%)" : "" }'>
</view>
</view>
</view>
<!-- 筛选弹窗 -->
<u-popup :show="isShowPop" ref="popup" round="55" @close="closePop" @open="openPop">
<view class="popup-content" :style="{'height':windowsHeight + 'px'}">
<view class="popup-header">
<text>选择筛选项</text>
<view style="display: flex;justify-content: space-between" @click="clearSelection">
<u-icon name="close-circle" size="18" color="#327DFB"></u-icon>
<text style="color:#327DFB;">清除筛选项</text>
</view>
</view>
<scroll-view scroll-y="true" class="scroll_view_style" style="height: 80%">
<view class="popup-body">
<view style="">
<view class="filter-section" style="padding: 0 10rpx;">
<text>时间范围</text>
<view style="margin-top: 10rpx">
<uni-datetime-picker v-model="queryParams.rangeTime" type="daterange"
rangeSeparator="至" />
</view>
</view>
<!-- 其余筛选项省略, 保持原有逻辑 -->
</view>
</view>
</scroll-view>
<view class="popup-footer">
<u-button @click="closePop" style="background: #F7F8FC;color: black">取消</u-button>
<u-button @click="submitPop">确定</u-button>
</view>
</view>
</u-popup>
</view>
<!-- 订单列表 -->
<view class="dil">
<!-- 初始加载状态 -->
<view class="ques" v-if="initialLoading">
<view class="loading-container">
<view class="loading-spinner"></view>
<text class="loading-text">加载中,请稍候...</text>
</view>
</view>
<!-- 无数据状态 -->
<view class="ques" v-else-if="!initialLoading && orderList.length == 0">
<image src="@/static/quesheng.png" mode=""></image>
</view>
<view v-else>
<order-card-vue @refresh="getlist" :status="gindex" v-for="(item,index) in orderList" :key="index"
:orderData="item" :brandList="brandList" :staffList="staffList"
:activeTab="activeInfoTab"></order-card-vue>
<!-- 底部加载更多状态 -->
<view v-if="loadingMore" class="loading-more">
<view class="loading-spinner mini"></view>
<text>正在加载更多...</text>
</view>
<view v-if="!hasMore" class="no-more-data">
<text>没有更多数据了</text>
</view>
</view>
<view style="width: 100%; height: 60px;"></view>
</view>
</view>
<!-- 分类统计 -->
<view v-else>
<view class="sub-tabs">
<text v-for="(tab, index) in filteredSubTabs" :key="index"
:class="['sub-tab-item', activeSubTab === tab.value ? 'active' : '']"
@click="switchSubTab(tab.value)">
{{ tab.label }}
</text>
</view>
<!-- 列表部分 -->
<category-list :type="activeSubTab" :list="currentList" />
</view>
<!-- 各种 picker 组件 -->
<lzc-picker ref="lzcPickerRescueStatus" :pickerList="jyStatusOptions" pickerTittle="选择救援状态"
@change="onPickerConfirm('rescueStatus', $event)" />
<lzc-picker ref="lzcPickerChannel" :pickerList="channelOptions" pickerTittle="选择渠道"
@change="onPickerConfirm('channel', $event)" />
<lzc-picker ref="lzcPickerSource" :pickerList="sourceOptions" pickerTittle="选择来源"
@change="onPickerConfirm('source', $event)" />
<lzc-picker ref="lzcPickerDispatcher" :pickerList="dispatcherOptions" pickerTittle="选择调度"
@change="onPickerConfirm('secondDispatchId', $event)" />
<lzc-picker ref="lzcPickerRescueType" :pickerList="jyTypeOptions" pickerTittle="选择救援类型"
@change="onPickerConfirm('rescueType', $event)" />
<lzc-picker ref="lzcPickerFaultType" :pickerList="faultTypeOptions" pickerTittle="选择故障类型"
@change="onPickerConfirm('faultType', $event)" />
<lzc-picker ref="lzcPickerPhenomenon" :pickerList="phenomenonOptions" pickerTittle="选择故障现象"
@change="onPickerConfirm('phenomenon', $event)" />
<lzc-picker ref="lzcPickerRescueDriver" :pickerList="rescueDriverOptions" pickerTittle="选择救援司机"
@change="onPickerConfirm('rescueDriver', $event)" />
<lzc-picker ref="lzcPickerRescueCar" :pickerList="rescueCarOptions" pickerTittle="选择救援车牌号"
@change="onPickerConfirm('rescueCar', $event)" />
</view>
</template>
<!-- 省略 script 与 style 块,其内容保持用户提供版本 -->
<script>
// import OrderCardVue from '../../components/orderCard/StatisticsInfoOrderCard.vue';
import OrderCardNew from '@/components/orderCard/OrderCardNew.vue'
import request from '../../utils/request';
import CategoryList from '../../components/categoryList/CategoryList.vue';
import lzcPicker from '@/components/lzc-picker/lzc-picker.vue';
import BusinessPanel from '@/components/BusinessPanel.vue'
import {
hasRole,
hasRoleNew
} from "@/utils/auth";
export default {
name: "StatisticsInfo",
data() {
return {
customRange: [], // ← 加这一行,保证是响应式数组
// ↓ 渠道 Tab 当前索引
channelTabIdx: 0,
// ↓ 你已有 — 改默认值为空数组,供模板 v-for
channelOptions: [],
// 时间 Tab0~4 对应 本日、本月…)
cTab: 0,
timeTypeMap: ['day', 'month', 'year', 'all', 'more'],
/* ↓↓↓ 新增 ↓↓↓ */
// bmCatKeys: [
// 'rescueType', // 救援类型统计
// 'faultDistrict', // 故障地点统计
// 'carBrand', // 车辆品牌统计
// 'carType', // 车辆类型统计
// 'downDestination', // 下车地统计
// 'transferReason', // 移交易由统计
// 'newEnergy', // 是否新能源统计
// 'rescueNeeds', // 救援需求统计
// 'feeType', // 收费类型统计
// 'kouChe' // 是否扣车统计
// ],
bmTimeTab: 0, // 0 本日 1 本月 2 本年 3 全部 4 自定义
bmRange: [], // 自定义时间
bmStats: {}, // 后端返回的整个 data
bmTitleMap:{ // key ➜ 卡片标题
rescueType:'救援类型统计',
faultDistrict:'故障地点统计',
carBrand:'车辆品牌统计',
carType:'车辆类型统计',
downDestination:'下车地统计',
transferReason:'移交易由统计',
newEnergy:'是否新能源统计',
rescueNeeds:'救援需求统计',
feeType:'收费类型统计',
kouChe:'是否扣车统计'
},
financeTimeTab:0, // 0~4 对应 本日…自定义
financeData:{
/* 应收款 y 前缀 */
yAmount:0,yQty:0,yChannel:0,ySource:0,
yRescueType:0,yFault:0,yBrand:0,yCarType:0,
yNewEnergy:0,yNeed:0,yFeeType:0,yDqc:0,
/* 已收款 r 前缀 */
rAmount:0,rQty:0,rChannel:0,rSource:0,
rRescueType:0,rFault:0,rBrand:0,rCarType:0,
rNewEnergy:0,rNeed:0,rFeeType:0,rDqc:0,
},
cTab: 0, // 0:本日 1:本月 ...
channelStats: [], // 渠道统计列表
activeTab: "order", // 默认进入工单统计
activeSubTab: "driver", // 默认进入救援司机
// 工单统计相关数据
tabValue: 1,
channelTabValue: 1,
timeType: "all",
range: [],
startTimeStr: null,
endTimeStr: null,
searchText: '',
searchKeyword: null,
gindex: 1,
brandList: [],
staffList: [],
orderList: [],
total: 0,
pageNum: 1,
pageSize: 10,
totalPages: 0,
activeInfoTab: 4, // 信息选项卡
initialLoading: true,
loadingMore: false,
hasMore: true,
scrollTop: 0,
totalNum: null,
// 筛选相关数据
isShowPop: false,
windowsHeight: 700,
tabTwoList: ["全部", "筛选"],
queryParams: {
pageNum: 1,
pageSize: 10,
timeType: null,
rescueStatus: null,
rescueType: null,
licenseNum: null,
rangeTime: [],
startTimeStr: null,
endTimeStr: null,
connectionName: null,
connectionPhone: null,
rescuePosition: null,
secondDispatchId: null,
driverId: null,
rescueDriver: null,
rescueCar: null,
driverCarNum: null,
faultType: null,
phenomenon: null,
channel: null,
channelId: null,
source: null
},
rescueStatusList: [{
text: "已接单",
value: "1"
},
{
text: "救援中",
value: "2"
},
{
text: "已完成",
value: "3"
}
],
sortList: [{
text: "正序",
value: "asc"
},
{
text: "倒序",
value: "desc"
}
],
// 分类统计相关数据
subTabs: [{
label: "救援司机",
value: "driver"
},
{
label: "救援车辆",
value: "vehicle"
},
{
label: "调度",
value: "dispatch"
},
],
driverList: [],
vehicleList: [],
dispatchList: [],
orderStats: {
received: 235,
rescuing: 152,
completed: 39,
},
// 调度人员信息
dispatcherColumns: [],
userinfo: {},
jyStatusOptions: [],
jyTypeOptions: [],
faultTypeOptions: [],
phenomenonOptions: [],
currentPickerType: '', // 当前选择器类型
dispatcherOptions: [], // 调度选项
rescueDriverOptions: [],
rescueCarOptions: [],
channelOptions: [],
sourceOptions: [],
countNum: {
jyzNum: 0,
dzfNum: 0,
dqcNum: 0,
ywcNum: 0,
zwxNum: 0,
yjdNum: 0,
yingskNum: 0,
yiskNum: 0,
dskNum: 0,
},
};
},
components: {
// OrderCardVue,
OrderCardNew,
CategoryList,
lzcPicker,
BusinessPanel
},
onLoad(option) {
this.gindex = option.id || 1
this.getOptions()
this.getlist()
this.getBrandList()
this.getStaffList()
uni.getSystemInfo({
success: function(res) {
this.windowsHeight = res.windowHeight - 100;
console.log('屏幕高度:', res.windowHeight);
}
});
this.fetchBmStats();
// 只需一次,后面所有刷新都在 fetchChannelStats 内部做
this.loadChannelOptions();
},
created() {
// this.fetchChannelStats('day');
},
onReachBottom() {
console.log('触底加载');
if (this.pageNum >= this.totalPages) {
this.hasMore = false;
} else if (!this.loadingMore) {
this.loadingMore = true;
this.pageNum++;
this.getlist();
}
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
watch: {
range(newval) {
if (newval && newval.length === 2) {
this.startTimeStr = newval[0];
this.endTimeStr = newval[1];
this.pageNum = 1;
this.orderList = [];
this.hasMore = true;
this.initialLoading = true;
this.getlist();
}
},
'queryParams.rangeTime': {
handler(newval) {
if (newval && newval.length === 2) {
this.queryParams.startTimeStr = newval[0];
this.queryParams.endTimeStr = newval[1];
this.queryParams.timeType = 'more';
} else {
this.queryParams.startTimeStr = null;
this.queryParams.endTimeStr = null;
}
},
deep: true
}
},
computed: {
/* 过滤掉 null 或空数组的分类,只渲染有数据的 */
bmCategories(){
// return Object.keys(this.bmStats)
// .filter(k=>Array.isArray(this.bmStats[k]) && this.bmStats[k].length);
if (!this.bmStats || typeof this.bmStats !== 'object') {
return [];
}
return Object.keys(this.bmStats).filter(k => {
const value = this.bmStats[k];
return Array.isArray(value) && value.length > 0;
});
},
currentList() {
switch (this.activeSubTab) {
case "driver":
return this.driverList;
case "vehicle":
return this.vehicleList;
case "dispatch":
return this.dispatchList;
default:
return [];
}
},
filteredSubTabs() {
const tabs = [{
label: "救援司机",
value: "driver"
},
{
label: "救援车辆",
value: "vehicle"
}
];
if (this.hasRole('ddzx')) {
tabs.push({
label: "调度",
value: "dispatch"
});
}
return tabs;
},
},
methods: {
/* 进入来源页 */
async goSource(stat){
const map = ['day','month','year','all','more']
const dateType = map[this.cTab]
// 共用的查询串
const baseQuery = [
`channelId=${stat.channelId}`,
`channel=${encodeURIComponent(stat.channel)}`,
`dateType=${dateType}`
].join('&')
try{
const { data:list=[] } = await request({
url:`/rescue-channel-source/sources/${stat.channelId}`,
method:'get'
})
// 没有来源 ⇒ 直接查订单
if(!list.length){
uni.navigateTo({
url:`/pages/rescue/businessManageOrder?${baseQuery}&sourceName=`
})
}else{
// 有来源 ⇒ 去来源页
uni.navigateTo({
url:`/pages/rescue/businessManageSource?${baseQuery}`
})
}
}catch(e){
uni.showToast({ title:'获取来源失败', icon:'none' })
}
},
switchCTab(i){ // 顶部时间 Tab 点击
this.cTab = i;
// this.fetchChannelStats();
if(i!==4) this.fetchChannelStats()
},
/* 选完日期再打接口 */
onCustomRangeChange(val){
// val 形如 ['2024-01-01','2024-01-31']
if(Array.isArray(val) && val.length===2){
this.customRange = val
this.fetchChannelStats()
}
},
// ③ 真正调用 /app/rescueInfo/getRescueStatistics
async fetchChannelStats(){
const timeType = ['day','month','year','all','more'][this.cTab]
/* ---- 参数拼装 ---- */
const baseParams = { timeType }
if(timeType==='more'){
if(!this.customRange.length){
return uni.showToast({title:'请选择时间区间',icon:'none'})
}
baseParams.startTimeStr = this.customRange[0] + ' 00:00:01'
baseParams.endTimeStr = this.customRange[1] + ' 23:59:59'
}
/* ---- 并发请求各渠道 ---- */
const list = this.channelOptions.filter(c=>c.id!=='all')
const tasks = list.map(c=>{
return request({
url:'/app/rescueInfo/getRescueStatistics',
params:{ ...baseParams, channel:c.nickname }
}).then(r=>({
channel : c.nickname,
channelId : c.id,
yjdNum : r.data.yjdNum,
jyzNum : r.data.jyzNum,
ywcNum : r.data.ywcNum,
dqcNum : r.data.dqcNum,
receivable : (r.data.yingskNum/100).toFixed(1),
receivedMoney : (r.data.yiskNum/100).toFixed(1),
dskNum : (r.data.dskNum/100).toFixed(1),
}))
})
this.channelStats = await Promise.all(tasks)
// const timeType = this.timeTypeMap[this.cTab]
// // 过滤掉“全部”那条,只查真正的渠道
// const list = this.channelOptions.filter(c => c.id !== 'all')
// console.log('list',list)
// // 并发请求每个渠道的数据
// const tasks = list.map(c =>
// request({
// url : '/app/rescueInfo/getRescueStatistics',
// params: { timeType, channel: c.nickname }
// }).then(r => ({
// channel : c.nickname, // 前端取中文名
// channelId : c.id,
// yjdNum : r.data.yjdNum,
// jyzNum : r.data.jyzNum,
// ywcNum : r.data.ywcNum,
// dqcNum : r.data.dqcNum,
// receivable : (r.data.yingskNum / 100).toFixed(1),
// receivedMoney : (r.data.yiskNum / 100).toFixed(1),
// dskNum : (r.data.dskNum / 100).toFixed(1)
// }))
// )
// this.channelStats = await Promise.all(tasks)
/* 接口字段 → 页面字段 */
// this.channelStats = [{
// channel: chn.nickname,
// channelId: chn.id,
// // 已接单、救援中…接口字段一一对应
// yjdNum: data.yjdNum,
// jyzNum: data.jyzNum,
// ywcNum: data.ywcNum,
// dqcNum: data.dqcNum,
// receivable: (data.yingskNum/100).toFixed(1),
// receivedMoney: (data.yiskNum/100).toFixed(1),
// dskNum: (data.dskNum/100).toFixed(1)
// }];
},
changeBmTime(i,rangePicked=false){
this.bmTimeTab=i;
/* 自定义必须选完区间再请接口 */
if(i===4 && !rangePicked) return;
const map=['day','month','year','all','more'];
const params={timeType:map[i]};
if(i===4){params.startTime=this.bmRange[0];params.endTime=this.bmRange[1];}
this.fetchBmStats(params);
},
/* 真正请求接口 */
fetchBmStats(params={timeType:'day'}){
request({
url:'/rescueBusiness/statistics/overview',
method:'get',
params
}).then(res=>{
const raw = res.data || {};
const filled = {};
/* 给 10 个分类都补一份数据,没数据就放一条 count=0 */
this.bmCatKeys.forEach(k=>{
if(Array.isArray(raw[k]) && raw[k].length){
filled[k] = raw[k];
}else{
filled[k] = [{ name:'—', count:0 }]; // 占位
}
});
this.bmStats = filled;
});
},
// PK 跳转
toChannelPk(channelId) {
uni.navigateTo({
url: `/pages/rescue/channelPk?channelId=${channelId}`
});
},
hasRole,
hasRoleNew,
switchTab(tab) {
this.activeTab = tab;
if (tab == 'category') {
this.switchSubTab('driver')
}
},
switchSubTab(tab) {
this.activeSubTab = tab;
let data = {}
if (tab == 'driver') {
data.queryType = 'driver'
this.getStatisticsList(data)
} else if (tab == 'vehicle') {
data.queryType = 'car'
this.getStatisticsList(data)
} else if (tab == 'dispatch') {
data.queryType = 'dispatch'
this.getStatisticsList(data)
}
console.log('切换到tab:', tab);
},
switchInfoTab(index) {
this.activeInfoTab = index;
console.log('切换到信息选项卡:', index);
},
toggleExpand() {
this.isExpanded = !this.isExpanded;
},
goBack() {
uni.navigateBack();
},
Fourhammers() {
request({
url: '/app/rescueInfo/getRescueStatistics',
method: 'get',
params: {
timeType: this.timeType,
startTimeStr: this.startTimeStr,
endTimeStr: this.endTimeStr,
}
}).then((res) => {
console.log('四个', res);
this.countNum.dqcNum = res.data.dqcNum
this.countNum.dzfNum = res.data.dzfNum
this.countNum.jyzNum = res.data.jyzNum
this.countNum.ywcNum = res.data.ywcNum
this.countNum.yjdNum = res.data.yjdNum
this.countNum.yingskNum = res.data.yingskNum ? res.data.yingskNum / 100 : 0
this.countNum.yiskNum = res.data.yiskNum ? res.data.yiskNum / 100 : 0
this.countNum.dskNum = res.data.dskNum ? res.data.dskNum / 100 : 0
})
},
getRescueList(item){
return new Promise((resolve, reject) => {
this.loading = true;
let data = {
rescueStatus: 1,
pageSize: this.pageSize,
pageNum: this.pageNum,
channel: item
}
request({
url: '/app/rescueInfo/getRescueList',
method: 'get',
params: data
}).then((res) => {
console.log('首页', res);
if (res.code == 200) {
if (this.pageNum != 1) {
this.orderList = this.orderList.concat(res.rows)
} else {
this.orderList = res.rows
}
let total = res.total
this.totalPages = Math.ceil(total / this.pageSize);
}
resolve(); // 请求完成
}).catch(error => {
console.error('获取列表失败', error);
reject(error);
}).finally(() => {
this.loading = false;
})
});
},
showPicker(type) {
this.currentPickerType = type;
// 根据类型选择对应的选择器引用
let pickerRef = '';
switch (type) {
case 'channel':
pickerRef = 'lzcPickerChannel';
break;
case 'source':
pickerRef = 'lzcPickerSource';
break;
case 'rescueStatus':
pickerRef = 'lzcPickerRescueStatus';
break;
case 'secondDispatchId':
pickerRef = 'lzcPickerDispatcher';
break;
case 'rescueType':
pickerRef = 'lzcPickerRescueType';
break;
case 'faultType':
pickerRef = 'lzcPickerFaultType';
break;
case 'phenomenon':
pickerRef = 'lzcPickerPhenomenon';
break;
case 'rescueCar':
pickerRef = 'lzcPickerRescueCar';
break;
case 'rescueDriver':
pickerRef = 'lzcPickerRescueDriver';
break;
default:
console.error('未知的选择器类型:', type);
return;
}
// 确保选择器引用存在
if (!this.$refs[pickerRef]) {
console.error(`选择器引用 ${pickerRef} 未找到`);
return;
}
// 如果选项为空,先加载数据
this.loadPickerOptions(type).then(() => {
this.$refs[pickerRef].handleShow();
}).catch(error => {
console.error('加载选项失败:', error);
});
},
async loadPickerOptions(type) {
switch (type) {
case 'channel':
if (this.channelOptions.length === 0) {
await this.loadChannelOptions();
}
break;
case 'source':
if (this.sourceOptions.length === 0) {
await this.loadSourceOptions();
}
break;
case 'rescueStatus':
if (this.jyStatusOptions.length === 0) {
await this.loadjyStatusOptions();
}
break;
case 'secondDispatchId':
if (this.dispatcherOptions.length === 0) {
await this.loadDispatcherOptions();
}
break;
case 'rescueType':
if (this.jyTypeOptions.length === 0) {
await this.loadjyTypeOptions();
}
break;
case 'faultType':
if (this.faultTypeOptions.length === 0) {
await this.loadFaultTypeOptions();
}
break;
case 'phenomenon':
if (this.phenomenonOptions.length === 0) {
await this.loadPhenomenonOptions();
}
break;
case 'rescueDriver':
if (this.rescueDriverOptions.length === 0) {
await this.loadRescueDriverOptions();
}
break;
case 'rescueCar':
if (this.rescueCarOptions.length === 0) {
await this.loadRescueCarOptions();
}
break;
}
},
// 选择器确认回调
onPickerConfirm(field, selectedItem) {
if (selectedItem && selectedItem.value) {
if (field == 'rescueDriver') {
this.queryParams.driverId = selectedItem.id
} else if (field == 'rescueCar') {
this.queryParams.driverCarNum = selectedItem.value
}else if(field == 'channel') {
this.queryParams.channelId = selectedItem.id
}
// 根据字段名设置对应的值
this.queryParams[field] = selectedItem.value;
// 强制更新视图
this.$forceUpdate();
console.log(`选择了 ${field}:`, selectedItem);
}
},
// 获取选中项的显示文本
getSelectedLabel(type, value) {
let options = [];
switch (type) {
case 'channel':
options = this.channelOptions;
break;
case 'source':
options = this.sourceOptions;
break;
case 'rescueStatus':
options = this.jyStatusOptions;
break;
case 'secondDispatchId':
options = this.dispatcherOptions;
break;
case 'rescueType':
options = this.jyTypeOptions;
break;
case 'faultType':
options = this.faultTypeOptions;
break;
case 'phenomenon':
options = this.phenomenonOptions;
break;
case 'rescueDriver':
options = this.rescueDriverOptions;
break;
case 'rescueCar':
options = this.rescueCarOptions;
break;
default:
options = [];
}
const selected = options.find(item => item.value === value);
return selected ? selected.nickname : '请选择';
},
openFilter() {
uni.showToast({
title: "筛选功能待实现",
icon: "none",
});
},
// 选项卡选择
tabChoose(item, index) {
this.tabValue = index + 1
if (1 == this.tabValue) {
this.timeType = "day"
} else if (2 == this.tabValue) {
this.timeType = "month"
} else if (3 == this.tabValue) {
this.timeType = "year"
}else if (4 == this.tabValue) {
this.timeType = "all"
}else if (5 == this.tabValue) {
this.timeType = "more"
this.range = []
}
if (5 == this.tabValue) {
if (this.range.length > 0) {
this.startTimeStr = this.range[0]
this.endTimeStr = this.range[1]
this.Fourhammers()
}
} else {
this.Fourhammers()
}
// this.tabValue = index + 1;
// if (1 == this.tabValue) {
// // 全部 - 清除筛选条件
// this.clearSelection();
// this.refreshList();
// } else if (2 == this.tabValue) {
// // 筛选 - 打开弹窗
// this.isShowPop = true;
// }
},
maskClick(e) {
console.log('maskClick事件:', e);
},
// 处理搜索
handleSearch() {
this.searchKeyword = this.searchText.trim();
this.pageNum = 1;
this.orderList = [];
this.getlist();
},
getBrandList() {
let data = {
pageSize: 1000,
pageNum: 1,
}
request({
url: '/base/carBrand/page',
method: 'get',
params: data
}).then((res) => {
console.log('list', res);
if (res.code == 200) {
this.brandList = res.data.records
}
})
},
getStaffList() {
let data = {
pageSize: 1000,
pageNum: 1,
}
request({
url: '/company/staff/list',
method: 'get',
params: data
}).then((res) => {
console.log('list', res);
if (res.code == 200) {
this.staffList = res.data
}
})
},
getlist() {
console.log('queryParams', this.queryParams)
request({
url: '/app/rescueInfo/getRescueStatisticsInfoList',
method: 'get',
params: this.queryParams
}).then((res) => {
console.log('list', res);
if (res.code == 200) {
this.getCountNum()
if (this.pageNum != 1) {
const currentScrollTop = this.scrollTop;
this.orderList = this.orderList.concat(res.rows)
this.$nextTick(() => {
uni.pageScrollTo({
scrollTop: currentScrollTop,
duration: 0
});
});
} else {
this.orderList = res.rows
}
this.totalNum = res.total
let total = res.total
this.totalPages = Math.ceil(total / this.pageSize);
this.hasMore = this.pageNum < this.totalPages;
}
}).catch((error) => {
console.error('获取数据失败', error);
uni.showToast({
title: '数据加载失败',
icon: 'none'
});
}).finally(() => {
this.initialLoading = false;
this.loadingMore = false;
});
},
// 刷新列表
refreshList() {
this.pageNum = 1;
this.orderList = [];
this.hasMore = true;
this.initialLoading = true;
this.getlist();
},
// 关闭弹窗
closePop() {
this.isShowPop = false;
document.body.style.overflow = ''
uni.pageScrollTo({
scrollTop: 0,
duration: 0
});
},
// 提交筛选
submitPop() {
this.refreshList();
this.isShowPop = false;
document.body.style.overflow = '';
// 对于uni-app可能需要使用uni API
uni.pageScrollTo({
scrollTop: 0,
duration: 0
});
},
// 打开弹窗
openPop() {
this.isShowPop = true;
document.body.style.overflow = 'hidden'
},
// 清除筛选条件
clearSelection() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
timeType: null,
rescueStatus: null,
rescueType: null,
licenseNum: null,
rangeTime: [],
startTimeStr: null,
endTimeStr: null,
connectionName: null,
connectionPhone: null,
rescuePosition: null,
secondDispatchId: null,
rescueCar: null,
rescueDriver: null,
driverId: null,
driverCarNum: null,
faultType: null,
phenomenon: null,
channel: null,
source: null
};
this.searchText = '';
this.searchKeyword = null;
this.$forceUpdate();
},
getStatisticsList(data) {
let url = '';
if (this.hasRole('ddzx')) {
url = '/app/rescueInfo/statisticsAll';
} else if (this.hasRole('second_dispatcher')) {
url = '/app/rescueInfo/statisticsAllSecond';
} else {
this.driverList = [];
this.vehicleList = [];
return;
}
request({
url: url,
method: 'get',
params: data
}).then((res) => {
console.log('list', res);
if (res.code == 200) {
const processedData = res.data.map(item => {
if (item.money !== undefined && item.money !== null) {
return {
...item,
money: Math.trunc(item.money / 100),
mileage: Math.trunc(item.mileage)
};
}
return item;
});
switch (data.queryType) {
case 'driver':
this.driverList = processedData;
break;
case 'car':
this.vehicleList = processedData;
break;
case 'dispatch':
this.dispatchList = processedData;
break;
}
}
})
},
// 获取所有渠道信息
// async loadChannelOptions () {
// const { data } = await request({ url:'/rescue-channel-source/channelList' })
// this.channelOptions = [
// { id:'all', nickname:'全部' },
// ...data.map(v => ({ id:v.id, nickname:v.name }))
// ]
// /* ① 默认高亮第一项 */
// this.channelTabIdx = 0
// /* ② 直接取一次统计,否则初次进入页面看不到数据 */
// this.fetchChannelStats()
// },
async loadChannelOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue-channel-source/channelList',
method: 'get',
}).then((res) => {
this.channelOptions = res.data.map(item => ({
nickname: item.name, // 显示文本
value: item.name, // 实际值
id: item.id, // ID
label: item.name // 保留原字段
}));
resolve();
}).catch(reject);
});
},
// 获取所有来源信息
async loadSourceOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue-channel-source/sourceList',
method: 'get',
}).then((res) => {
this.sourceOptions = res.data.map(item => ({
nickname: item.name, // 显示文本
value: item.name, // 实际值
id: item.id, // ID
label: item.name // 保留原字段
}));
resolve();
}).catch(reject);
});
},
// 获取调度人员信息
loadDispatcherOptions() {
return new Promise((resolve, reject) => {
this.dispatcherColumns = [];
const tenantId = this.userinfo.tenantId + '';
const request1 = request({
url: `/company/staff/staffListByRoleCode?tenantId=${tenantId}&code=second_dispatcher`,
method: 'get',
});
const request2 = request({
url: `/company/staff/staffListByRoleCode?tenantId=${tenantId}&code=ddzx`,
method: 'get',
});
Promise.all([request1, request2])
.then(([res1, res2]) => {
const combinedData = [...(res1.data || []), ...(res2.data || [])];
const uniqueMap = new Map();
combinedData.forEach(item => {
if (item && item.id) {
uniqueMap.set(item.id, item);
}
});
const uniqueData = Array.from(uniqueMap.values());
this.dispatcherColumns.push(uniqueData);
this.dispatcherOptions = this.dispatcherColumns[0].map(item => ({
nickname: item.name || item.nickname,
value: item.id,
id: item.id,
name: item.id // 存储实际值
}));
console.log('this.dispatcherColumns', this.dispatcherColumns)
console.log('this.dispatcherOptions', this.dispatcherOptions)
resolve(uniqueData);
})
.catch(error => {
console.error('获取调度人员数据失败:', error);
reject(error);
});
});
},
// 获取救援状态 字典
async loadjyStatusOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue/dict/data/type/jy_status',
method: 'get',
}).then((res) => {
this.jyStatusOptions = res.data.map(item => ({
nickname: item.label,
value: item.value,
id: item.id,
name: item.value // 存储实际值
}));
resolve();
}).catch(reject);
});
},
// 获取救援类型 字典
async loadjyTypeOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue/dict/data/type/dljy_type',
method: 'get',
}).then((res) => {
this.jyTypeOptions = res.data.map(item => ({
nickname: item.label, // 显示文本
value: item.value, // 实际值
id: item.id, // ID
label: item.label // 保留原字段
}));
resolve();
}).catch(reject);
});
},
// 加载故障类型选项
async loadFaultTypeOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue-type-phenomenon/typeList',
method: 'get',
}).then((res) => {
this.faultTypeOptions = res.data.map(item => ({
nickname: item.name, // 显示文本
value: item.name, // 实际值
id: item.id, // ID
label: item.name // 保留原字段
}));
resolve();
}).catch(reject);
});
},
// 加载故障现象选项方法
async loadPhenomenonOptions() {
return new Promise((resolve, reject) => {
request({
url: '/rescue-type-phenomenon/listPhenomenonByPid',
method: 'get',
}).then((res) => {
this.phenomenonOptions = res.data.map(item => ({
nickname: item.name, // 显示文本
value: item.name, // 实际值
id: item.id, // ID
label: item.name // 保留原字段
}));
resolve();
}).catch(reject);
});
},
// 加载司机选项方法
async loadRescueDriverOptions() {
return new Promise((resolve, reject) => {
let url = '';
if (this.hasRole('ddzx')) {
url = '/system/DriverInfo/listDriverInfo';
} else if (this.hasRole('second_dispatcher')) {
url = '/system/DriverInfo/listDriverInfoSecond';
} else {
this.rescueDriverOptions = [];
resolve();
return;
}
request({
url: url,
method: 'get',
}).then((res) => {
this.rescueDriverOptions = res.data.map(item => ({
nickname: item.nickName,
value: item.userId,
id: item.id,
label: item.nickName
}));
resolve();
}).catch(reject);
});
},
// 加载救援车辆选项方法
async loadRescueCarOptions() {
return new Promise((resolve, reject) => {
let url = '';
if (this.hasRole('ddzx')) {
url = '/system/DriverInfo/listCarInfo';
} else if (this.hasRole('second_dispatcher')) {
url = '/system/DriverInfo/listCarInfoSecond';
} else {
this.rescueCarOptions = [];
resolve();
return;
}
request({
url: url,
method: 'get',
}).then((res) => {
this.rescueCarOptions = res.data.map(item => ({
nickname: item.rescueCarNum, // 显示文本
value: item.rescueCarNum,
id: item.id,
label: item.rescueCarNum
}));
resolve();
}).catch(reject);
});
},
async getOptions() {
this.userinfo = uni.getStorageSync('userInfo')
// await this.getDispatcher()
await this.loadDispatcherOptions() // 新增
await this.loadjyStatusOptions()
await this.loadjyTypeOptions()
await this.loadFaultTypeOptions()
await this.loadPhenomenonOptions()
await this.loadRescueDriverOptions()
await this.loadRescueCarOptions()
await this.loadChannelOptions()
},
getCountNum() {
request({
url: '/app/rescueInfo/getRescueStatisticsInfoNum',
method: 'get',
params: this.queryParams
}).then((res) => {
console.log('四个', res);
this.countNum.dqcNum = res.data.dqcNum
this.countNum.dzfNum = res.data.dzfNum
this.countNum.jyzNum = res.data.jyzNum
this.countNum.ywcNum = res.data.ywcNum
this.countNum.yjdNum = res.data.yjdNum
this.countNum.zwxNum = res.data.zwxNum
this.countNum.yingskNum = res.data.yingskNum ? res.data.yingskNum / 100 : 0
this.countNum.yiskNum = res.data.yiskNum ? res.data.yiskNum / 100 : 0
this.countNum.dskNum = res.data.dskNum ? res.data.dskNum / 100 : 0
})
},
}
};
</script>
<style scoped lang="scss">
/* ========== 财务统计 (最终) ========== */
/* 标题条与上面所有二级标题保持一致 */
.sec-bar{
display:flex;align-items:center;
margin:16rpx 0 6rpx; /* 与上一块距离缩窄 */
line-height:1;
.blue-line{width:8rpx;height:32rpx;border-radius:4rpx;background:#054df3;margin-right:16rpx;}
.sec-title{font-size:30rpx;font-weight:bold;color:#101A3E;margin-right:20rpx;}
}
/* 时间切换本日/本月保持一行间隔统一 */
.time-tabs{
display:flex;column-gap:28rpx;align-items:center;font-size:26rpx;color:#8d90a6;
.t-item{position:relative;}
.t-item.active{font-weight:bold;color:#101A3E;}
.t-item.active::after{
content:'';position:absolute;left:50%;bottom:-12rpx;transform:translateX(-50%);
width:22rpx;height:6rpx;border-radius:3rpx;background:linear-gradient(180deg,#054df3 0%,#55a3ff 100%);
}
}
/* 卡片外观保持同一浅蓝渐变卡片间距16rpx */
.uni-card{
background:linear-gradient(180deg,rgba(166,188,255,.24) 0%,#ffffff 100%);
border-radius:16rpx;
padding:26rpx 24rpx;
margin-bottom:16rpx;
}
/* 头部标题在左PK按钮贴最右 */
.card-hd{
display:flex;align-items:center;
.card-title{font-size:30rpx;font-weight:bold;color:#101A3E;margin-right:auto;}
.pk-btn{
margin-left:auto; /* 让按钮永远贴右 */
padding:10rpx 38rpx;
font-size:24rpx;
color:#327DFB;
background:#fff;
border:2rpx solid #327DFB;
border-radius:34rpx;
line-height:1;
}
}
/* 数据行是否扣车统计间距一致整体再左移一些 */
.row-g{display:flex;flex-direction:column;row-gap:12rpx;}
.row{
display:grid;
grid-template-columns:max-content 96rpx max-content 96rpx; /* 标签-数值 | 标签-数值 */
column-gap:16rpx; /* 间隔统一 */
font-size:26rpx;color:#666;
.lbl{white-space:nowrap;}
.val{font-weight:bold;color:#32373d;}
}
/* ------- 财务统计 · 间距微调 ------- */
/* 整体行距比原来略大看起来更舒展 */
.row-g{
display:flex;
flex-direction:column;
row-gap:20rpx; /* 原来 12rpx 20rpx */
}
/* 单行两列组之间的左右留白做大待取车数量 / 车辆信息那行保持一致 */
.row{
display:grid;
/* 标签 标签 */
grid-template-columns:max-content 120rpx max-content 120rpx;
column-gap:40rpx; /* 横向间距原来 16rpx 40rpx */
font-size:26rpx;color:#666;
.lbl{white-space:nowrap;}
.val{font-weight:bold;color:#32373d;}
}
/* ========== 业务管理统计样式 开始 ========= */
/* ========== 业务管理统计标题 · 最终微调 ========== */
.bm-header{
/* 去掉背景圆角阴影 */
background:transparent; /* 删掉原来那条 linear-gradient */
border-radius:0;
box-shadow:none;
padding:0 0 10rpx 0; /* 保留一点下内边距即可 */
margin:32rpx 0 16rpx; /* 与上下模块留距离 */
display:flex;align-items:center;flex-wrap:wrap;
}
.bm-header .blue-line{ /* 竖线保持不变可略缩左右空隙 */
margin-right:12rpx;
}
.bm-header .section-title{
font-size:30rpx;font-weight:bold;color:#101A3E;
margin-right:20rpx; /* 这里把多余的 margin-left 删除 */
}
/* 自定义日期选择器与标题栏之间留距离 */
.bm-header + uni-datetime-picker{
margin-top:16rpx; /* 上下间隔 */
}
/* 业务管理统计 时间 Tab 选中态 */
.bm-header .time-item{
position:relative;
font-size:26rpx;
color:#8D90A6;
}
.bm-header .time-item.active{
font-weight:600;
color:#101A3E;
}
.bm-header{
padding:0 20rpx 10rpx;
display:flex;align-items:center;
.time-tabs{ // 新增 / 保留里头只留这一句
margin-left:40rpx; // 想再右一点就调大左一点就调小
}
}
.bm-picker{ // 刚刚包的那层
margin-top:16rpx;
}
.time-item.active::after{
width:220rpx; // 想宽就调大
}
/* 日期选择器外层容器example-body 已存在*/
.example-body{
display:flex; /* 让里面元素可用 flex:1 撑满 */
padding:0 20rpx; /* 如果想去掉左右留白可设为 0 */
}
/* picker 占满整行 */
.full-width-picker{
flex:1; /* 关键横向拉伸 */
width:100%;
}
/* 深度选择把内部输入框也拉满HBuilderX 3.8 ::v-deep */
.full-width-picker::v-deep .uni-date__content,
.full-width-picker::v-deep .uni-date__input{
width:100% !important;
}
/* ========== 业务管理统计卡 ========= */
.manage-card{
margin-bottom:10rpx;
padding:24rpx;
border-radius:12rpx;
background:linear-gradient(180deg,#e4ecff 0%,#ffffff 100%);
box-shadow:0 4rpx 12rpx rgba(0,0,0,.06);
}
/* 头部标题 + PK */
.m-header{display:flex;justify-content:space-between;align-items:center;}
.m-title{font-size:28rpx;font-weight:600;}
/* PK 按钮沿用之前的 pk-btn 样式无需重复 */
/* 数据区自动两列网格条目多少都可 */
/* 统计卡内部表格 调整对齐 */
/* ===== 故障地点统计 列表排版优化 ===== */
/* flex grid一行 2 */
.m-grid{
display:grid;
grid-template-columns:repeat(2,1fr); /* 两列等宽 */
column-gap:20rpx; /* 左右留白 */
row-gap:12rpx; /* 行距 */
padding:18rpx 0;
}
/* 每项左右各占一边 */
.m-item{
display:flex;
justify-content:space-between; /* 关键数字贴右 */
align-items:center;
}
/* 左侧地点名 */
.m-key{
flex:1; /* 自动占剩余 */
font-size:26rpx;
color:#646b79;
overflow:hidden; /* 超长省略 */
text-overflow:ellipsis;
white-space:nowrap;
}
/* 右侧数量 */
.m-val{
flex:none;
font-size:32rpx;
font-weight:600;
color:#101A3E;
margin-left:12rpx; /* 与文字拉开一点 */
}
/* ========== 业务管理统计样式 结束 ========= */
/* ========== 业务渠道统计样式 开始 ========== */
/* -------- 业务渠道统计标题 -------- */
.bc-header{
display:flex;align-items:center;justify-content:space-between;
margin:32rpx 0 16rpx 0;
.blue-line{width:8rpx;height:32rpx;border-radius:4rpx;background:#054df3;}
.section-title{font-size:30rpx;font-weight:600;margin-left:20rpx;white-space:nowrap;}
.time-tabs{margin-left:auto;display:flex;align-items:center;}
.time-item{font-size:26rpx;color:#666;margin-left:28rpx;position:relative;}
.time-item.active{color:#101a3e;font-weight:600;}
.time-item.active::after{
content:'';position:absolute;left:50%;bottom:-14rpx;transform:translateX(-50%);
border-left:10rpx solid transparent;border-right:10rpx solid transparent;border-top:10rpx solid #054df3;
}
}
/* 底部小箭头 */
.time-item.active::after{
content:"";
position:absolute;left:50%;transform:translateX(-50%);
bottom:-14rpx;width:0;height:0;
border-left:10rpx solid transparent;
border-right:10rpx solid transparent;
border-top:10rpx solid #054df3;
}
/* ========== 渠道卡加深渐变 ========== */
.channel-card{
margin-bottom:24rpx;padding:24rpx;border-radius:12rpx;
/* 深一点的浅蓝到白渐变 */
background:linear-gradient(180deg,#d9e6ff 0%,#ffffff 100%);
box-shadow:0 4rpx 12rpx rgba(0,0,0,.06);
}
/* 待取车无描边 */
.wait-car{border:none;padding:0;} /* 如果之前还保留可留着覆盖 */
/* 顶部渠道名 + PK */
.c-header{display:flex;justify-content:space-between;align-items:center;}
.c-name{font-size:28rpx;font-weight:600;}
.pk-btn{
font-size:22rpx;color:#327dfb;border:1rpx solid #327dfb;
border-radius:20rpx;padding:4rpx 20rpx;
}
/* 行容器四格或三格 */
.c-row{display:grid;column-gap:0;row-gap:24rpx;margin-top:24rpx;}
.c-row.four{grid-template-columns:repeat(4,1fr);} /* 第一行 4 */
.c-row.three{grid-template-columns:repeat(3,1fr);} /* 第二行 3 */
.c-cell{text-align:center;}
.c-num{font-size:30rpx;font-weight:600;color:#101a3e;}
.c-lab{display:block;margin-top:6rpx;font-size:22rpx;color:#666;}
/* ========== 业务渠道统计样式 结束 ========== */
.dil {
// background-color: #F7F8FC;
background-color: #f3f5fc;
box-sizing: border-box;
padding: 0 30rpx;
}
.four-box-header {
display: flex;
justify-content: start;
align-items: center;
padding: 20rpx 0 10rpx 0;
}
.blue-line {
width: 8rpx;
height: 32rpx;
background: #054DF3;
border-radius: 4rpx;
margin-right: 20rpx;
}
.four-box-header-title {
font-weight: bold;
}
.tab-choose-class {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4rpx 20rpx 16rpx 20rpx;
border-top: 1rpx solid #F5F5F5;
.tab-content {
font-size: 28rpx;
display: flex;
flex-direction: column;
align-items: center;
.tab-name-class {
display: flex;
align-items: center;
.icon-tab {
display: flex;
align-items: center;
justify-content: center;
width: 32rpx;
height: 32rpx;
image {
width: 100%;
height: 100%;
}
}
}
}
.tab-icon {
width: 66rpx;
height: 8rpx;
margin-top: 8rpx;
}
}
.four-box {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 24rpx;
// margin-top: 15px;
width: 100%;
margin-bottom: 20rpx;
}
.boxf {
height: 130rpx;
overflow: hidden;
box-sizing: border-box;
border-radius: 6px;
padding: 12px;
// background-image: url('~@/static/images/homeOrderCard/dzf.png');
// background: rgba(218, 218, 218, 0.2);
background-color: #fdfeff;
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: center;
// 边框
border: 1px solid #badeff;
// 阴影
box-shadow: inset 0 2px 8px rgba(186, 222, 255, 0.3);
}
.zi1 {
font-size: 24rpx;
color: #333;
display: flex;
align-items: center;
column-gap: 10rpx;
.zi1-icon {
width: 38rpx;
height: 38rpx;
}
}
.zi2 {
width: 100%;
font-size: 40rpx;
font-weight: bold;
color: #000;
}
.two-box-container {
display: flex;
flex-direction: column;
gap: 20rpx;
width: 100%;
}
.two-box {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18rpx;
width: 100%;
}
.boxf2 {
height: 120rpx;
overflow: hidden;
box-sizing: border-box;
border-radius: 6px;
padding: 2px 12px 2px 12px;
background: rgba(218, 218, 218, 0.2);
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.zi1_1 {
font-size: 24rpx;
color: #333;
display: flex;
align-items: center;
column-gap: 10rpx;
.zi1_1-icon {
width: 38rpx;
height: 38rpx;
}
}
.zi2_2 {
width: 100%;
font-size: 30rpx;
font-weight: bold;
color: #000;
}
/* 三列自动换行专用 */
.tab-choose-multi {
display: flex;
flex-wrap: wrap; // 允许换行
}
/* 每个选项占 1/3 宽度 */
.tab-choose-multi .tab-content {
flex: 0 0 33.333%;
box-sizing: border-box;
text-align: center;
margin-bottom: 12rpx; // 行间距可按需调整
}
/* 三列对齐 + 文字居中专用 */
.tab-choose-equal {
/* 用网格替代 flex列宽完全一致 */
display: grid;
grid-template-columns: repeat(3, 1fr); // 3 列等宽
row-gap: 5rpx; // 行间距可按需调整
column-gap: 0; // 列间距如需分隔可自行设置
}
/* 每个格子内部再居中一下文字 */
.tab-choose-equal .tab-content {
display: flex; // 保留原来的竖直布局
flex-direction: column;
align-items: center; // 水平居中
justify-content: center; // 垂直居中可选
text-align: center;
}
/* 原有样式保持不变只添加弹窗相关样式 */
.popup-content {
padding: 20rpx 20rpx 20rpx 20rpx;
overflow-y: scroll;
background: white;
border-radius: 20rpx;
}
.popup-header {
font-size: 32rpx;
color: #101A3E;
margin-bottom: 40rpx;
display: flex;
justify-content: space-between;
}
.popup-body {
font-size: 28rpx;
color: #101A3E;
}
.filter-section {
margin-top: 30rpx;
}
.filter-section text {
display: block;
margin-bottom: 10rpx;
}
.options {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.popup-footer {
display: flex;
justify-content: space-between;
margin-top: 60rpx;
margin-bottom: 30rpx;
}
.popup-footer button {
padding: 10rpx 20rpx;
margin: 0 10rpx;
border-radius: 5px;
background-color: #327DFB;
color: #fff;
border: none;
}
/* 搜索和时间筛选区域 */
/* .search-filter-area {
width: 100%;
background: #fff;
margin: 0 20rpx;
border-radius: 16rpx;
padding: 6rpx 0 10rpx 0;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
} */
.tab-icon {
width: 66rpx;
height: 8rpx;
margin-top: 8rpx;
}
.statistics-container {
background: #f6f8fc;
min-height: 100vh;
}
.top1 {
width: 100%;
height: 100rpx;
background: #3a8dff;
}
/* 顶部导航 */
.nav-bar {
position:relative; // 关键让子元素能绝对定位
display: flex;
align-items: center;
background: linear-gradient(180deg, #3a8dff, #579dff);
color: #fff;
padding: 10px 16px;
height: 100rpx;
box-sizing: border-box;
}
/* 给箭头固定宽度 */
.nav-bar uni-icons {
flex:0 0 60rpx; // 60rpx 左右自己调够摆下箭头就行
}
/* 左侧返回箭头占 60rpx */
.back-icon { width:60rpx; flex-shrink:0; }
.title-tabs {
position:absolute; /* 关键 */
left:50%;
top:0;
transform:translateX(-50%); /* 真正水平居中 */
height:100%;
display:flex;
align-items:center;
}
.tab-item {
padding:0 24rpx;
font-size:15px;
line-height:100rpx;
white-space:nowrap; /* 不允许自动换行 */
flex:none; /* 别再撑满父元素 */
}
.tab-item.active {
font-weight: bold;
border-bottom: 3px solid #fff;
opacity: 1;
}
.filter-btn {
width:60rpx; flex-shrink:0;
font-size: 14px;
}
/* 统计卡片 */
/* .stat-cards {
display: flex;
justify-content: space-around;
margin: 14rpx 0;
} */
.stat-card {
background: #fff;
border-radius: 12rpx;
padding: 4rpx;
flex: 1;
margin: 0 16rpx;
text-align: center;
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.05);
}
.stat-num {
font-size: 20px;
font-weight: bold;
color: #333;
}
.stat-label {
display: block;
margin-top: 6px;
color: #666;
font-size: 14px;
}
/* 搜索和时间筛选区域 */
.search-filter-area {
background: #fff;
margin: 0 20rpx;
border-radius: 16rpx;
/* padding: 6rpx 0 10rpx 0; */
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
}
.top-icon {
box-sizing: border-box;
width: 100%;
padding: 5px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.h-text {
width: 124rpx;
height: 56rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 28rpx;
font-size: 28rpx;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
background: #327DFB;
}
.s-input {
width: 78%;
height: 56rpx;
background: #f5f5f5;
border-radius: 50px;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 0px 10px;
input {
margin-left: 5px;
flex: 1;
width: 0;
font-size: 14px;
color: #999999;
}
}
/* 时间筛选选项卡样式 */
.tab-choose-class {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0 16rpx 0;
background-color: #fff;
/* border-bottom: 1rpx solid #F5F5F5; */
width: 100%;
/* 新增让容器占满宽度 */
}
.tab-content {
font-size: 28rpx;
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
text-align: center;
}
.tab-name-class {
display: flex;
align-items: center;
}
.icon-tab {
display: flex;
align-items: center;
justify-content: center;
width: 32rpx;
height: 32rpx;
}
.icon-tab image {
width: 100%;
height: 100%;
}
.example-body {
display:flex;
background-color: #fff;
padding: 0 20rpx;
}
/* 信息选项卡样式 */
.four-box-header_2 {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
}
.four-box-header_2_right {
width: 60%;
display: flex;
justify-content: space-around;
align-items: center;
}
.four-box-header_2_right .tab-item {
font-size: 28rpx;
font-weight: normal;
color: #a1a6aa;
position: relative;
padding: 0rpx 20rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.four-box-header_2_right .tab-item.active {
font-weight: bold;
color: #000000;
}
.four-box-header_2_right .tab-item.active::after {
content: '';
position: absolute;
bottom: -10rpx;
left: 50%;
transform: translateX(-50%);
width: 33.33%;
height: 6rpx;
background: linear-gradient(90deg, #054DF3 0%, #55A3FF 100%);
border-radius: 3rpx 3rpx 0 0;
}
/* 订单列表区域 */
.dil {
background-color: #F7F8FC;
box-sizing: border-box;
padding: 8px 12px 15px 12px;
display: flex;
flex-direction: column;
row-gap: 10px;
}
.loading-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-spinner {
position: relative;
width: 60px;
height: 60px;
border: 4px solid #f3f3f3;
border-top: 4px solid #327DFB;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 15px;
display: flex;
justify-content: center;
align-items: center;
}
.loading-text {
font-size: 16px;
color: #666;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.ques {
margin: 0px auto;
margin-top: 40px;
width: 80%;
}
.ques image {
width: 100%;
}
.loading-more {
display: flex;
justify-content: center;
align-items: center;
padding: 20rpx;
color: #999;
font-size: 26rpx;
}
.loading-more .mini {
width: 30px;
height: 30px;
border-width: 2px;
margin-right: 10rpx;
}
.no-more-data {
text-align: center;
padding: 20rpx;
color: #999;
font-size: 26rpx;
}
/* 分类统计样式 */
.sub-tabs {
display: flex;
background: #fff;
padding: 10px 0;
justify-content: space-around;
border-bottom: 1px solid #eee;
}
.sub-tab-item {
font-size: 15px;
color: #666;
padding: 4px 10px;
}
.sub-tab-item.active {
font-weight: bold;
color: #3a8dff;
border-bottom: 2px solid #3a8dff;
}
.list-container {
margin: 10px;
}
.table-header,
.table-row {
display: flex;
align-items: center;
background: #fff;
border-radius: 8px;
padding: 10px;
margin-bottom: 6px;
}
.table-header {
font-weight: bold;
background: #f0f3f8;
}
.col-rank {
width: 40px;
text-align: center;
}
.col-driver {
flex: 1;
display: flex;
align-items: center;
}
.avatar {
width: 28px;
height: 28px;
border-radius: 50%;
margin-right: 6px;
}
.col-num,
.col-distance,
.col-money {
width: 80px;
text-align: center;
}
.scroll_view_style {
flex: 1;
}
/* 新增选择字段样式 */
.select-field {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
background: #fff;
border-radius: 8rpx;
border: 1rpx solid #e9ecef;
min-height: 80rpx;
box-sizing: border-box;
}
.select-text {
font-size: 28rpx;
color: #333;
flex: 1;
}
.select-field:active {
background: #e9ecef;
}
.stat-cards-container {
position: relative;
display: flex;
align-items: center;
margin: 14rpx 0;
}
.stat-cards {
display: flex;
justify-content: space-around;
flex: 1;
}
.expand-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 60rpx;
height: 80rpx;
margin-right: 20rpx;
background: #fff;
border-radius: 12rpx;
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.05);
}
.expand-text {
font-size: 20rpx;
color: #327DFB;
margin-top: 4rpx;
}
.expanded-cards {
margin-top: 10rpx;
margin-bottom: 20rpx;
}
</style>