10.31
This commit is contained in:
parent
2e7013ffd6
commit
a4103b33d0
@ -184,6 +184,14 @@ export function channelList() {
|
||||
})
|
||||
}
|
||||
|
||||
// 根据渠道ID查询来源列表
|
||||
export function getSourcesByChannelId(channelId) {
|
||||
return request({
|
||||
url: `/rescue-channel-source/sources/${channelId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有来源
|
||||
export function sourceList() {
|
||||
return request({
|
||||
@ -192,3 +200,13 @@ export function sourceList() {
|
||||
})
|
||||
}
|
||||
|
||||
// 按角色编码拉员工
|
||||
export function getStaffByRoleCode(tenantId, roleCode) {
|
||||
return request({
|
||||
url: `/company/staff/staffListByRoleCode`,
|
||||
method: 'get',
|
||||
params: { tenantId, code: roleCode }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
50
src/api/rescue/passFee.js
Normal file
50
src/api/rescue/passFee.js
Normal file
@ -0,0 +1,50 @@
|
||||
// =============================================================
|
||||
// 文件:src/api/rescue/passFee.js
|
||||
// 说明:过关费管理接口封装
|
||||
// =============================================================
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 列表查询
|
||||
export function listPassFee(query) {
|
||||
return request({
|
||||
url: '/system/passFee/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 新增
|
||||
export function addPassFee(data) {
|
||||
return request({
|
||||
url: '/system/passFee',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改
|
||||
export function updatePassFee(data) {
|
||||
return request({
|
||||
url: '/system/passFee',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除(支持批量)
|
||||
export function delPassFee(ids) {
|
||||
return request({
|
||||
url: '/system/passFee/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出
|
||||
export function exportPassFee(params) {
|
||||
return request({
|
||||
url: '/system/passFee/export',
|
||||
method: 'get',
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,15 @@ export function listRefuelRecord(query) {
|
||||
})
|
||||
}
|
||||
|
||||
// 查询加油费用汇总
|
||||
export function listRefuelSummary(query) {
|
||||
return request({
|
||||
url: '/rescue/refuelRecord/summary',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询加油记录详细
|
||||
export function getRefuelRecord(id) {
|
||||
return request({
|
||||
|
||||
496
src/views/rescue/businessStatistics.vue
Normal file
496
src/views/rescue/businessStatistics.vue
Normal file
@ -0,0 +1,496 @@
|
||||
<template>
|
||||
<section class="statistics-pc">
|
||||
<!-- 顶部返回 + 标题 -->
|
||||
<el-page-header class="top-page-header" @back="goBack" content="业务管理统计" />
|
||||
|
||||
<!-- ========= 工单统计 ========= -->
|
||||
<el-card class="block-card" shadow="hover">
|
||||
<div class="card-head">
|
||||
工单统计
|
||||
<el-tabs v-model="orderTab" @tab-click="onOrderTabClick" class="inline-tabs" size="small">
|
||||
<el-tab-pane v-for="(t, i) in timeTabs" :key="i" :label="t" :name="tabMap[i]" />
|
||||
</el-tabs>
|
||||
</div>
|
||||
<!-- 自定义日期选择 -->
|
||||
<el-date-picker v-if="orderTab === 'more'" v-model="orderRange" type="daterange" range-separator="至"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="fetchOrderStats" class="full-width-picker" />
|
||||
|
||||
<el-row :gutter="20" class="summary-row">
|
||||
<el-col :span="6" v-for="box in orderBoxes" :key="box.key">
|
||||
<el-card class="summary-box">
|
||||
<div class="box-title">
|
||||
<span>{{ box.label }}</span>
|
||||
</div>
|
||||
<div class="box-value">{{ countNum[box.key] || 0 }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- ========= 业务渠道统计 ========= -->
|
||||
<el-card class="block-card" shadow="hover">
|
||||
<div class="card-head">
|
||||
业务渠道统计
|
||||
<el-tabs v-model="channelTab" @tab-click="onChannelTabClick" class="inline-tabs" size="small">
|
||||
<el-tab-pane v-for="(t, i) in timeTabs" :key="i" :label="t" :name="tabMap[i]" />
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<!-- 日期选择 -->
|
||||
<el-date-picker v-if="channelTab === 'more'" v-model="customRange" type="daterange" range-separator="至"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="fetchChannelStats" class="full-width-picker" />
|
||||
|
||||
<!-- ⇓ ❶ 给 el-table 加 row-key & type='expand' -->
|
||||
<el-table v-loading="channelLoading" :data="channelStats" border stripe row-key="__rowKey" :height="360" class="tight-table">
|
||||
|
||||
<!-- 展开列 -->
|
||||
<el-table-column type="expand">
|
||||
<!-- ❷ slot-scope 拿到 row.sources,再渲染内部小表格 -->
|
||||
<template #default="props">
|
||||
<el-table :data="props.row.sources" border size="mini" style="margin:6px 0 6px 40px">
|
||||
<el-table-column prop="source" label="来源名称" />
|
||||
<el-table-column prop="yjdNum" label="已接单" width="80" />
|
||||
<el-table-column prop="jyzNum" label="救援中" width="80" />
|
||||
<el-table-column prop="ywcNum" label="已完成" width="80" />
|
||||
<el-table-column prop="dqcNum" label="待取车" width="80" />
|
||||
<el-table-column prop="receivable" label="应收款(元)" width="110" />
|
||||
<el-table-column prop="receivedMoney" label="已收款(元)" width="110" />
|
||||
<el-table-column prop="dskNum" label="待收款(元)" width="110" />
|
||||
<el-table-column label="操作" width="100">
|
||||
<template #default="sc">
|
||||
<el-button type="text" size="mini"
|
||||
@click="viewOrderList({ channel: props.row.channel, source: sc.row.source }, channelTab, customRange)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 渠道汇总列 -->
|
||||
<el-table-column prop="channel" label="渠道名称" fixed />
|
||||
<el-table-column prop="yjdNum" label="已接单" width="90" />
|
||||
<el-table-column prop="jyzNum" label="救援中" width="90" />
|
||||
<el-table-column prop="ywcNum" label="已完成" width="90" />
|
||||
<el-table-column prop="dqcNum" label="待取车" width="90" />
|
||||
<el-table-column prop="receivable" label="应收款(元)" width="110" />
|
||||
<el-table-column prop="receivedMoney" label="已收款(元)" width="110" />
|
||||
<el-table-column prop="dskNum" label="待收款(元)" width="110" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="mini" @click="viewOrderList({ channel: scope.row.channel }, channelTab, customRange)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
|
||||
<!-- ========= 业务管理统计 ========= -->
|
||||
<el-card class="block-card" shadow="hover">
|
||||
<div class="card-head">
|
||||
业务管理统计
|
||||
<el-tabs v-model="bmTab" @tab-click="onBmTabClick" class="inline-tabs" size="small">
|
||||
<el-tab-pane v-for="(t, i) in timeTabs" :key="i" :label="t" :name="tabMap[i]" />
|
||||
</el-tabs>
|
||||
</div>
|
||||
<el-date-picker v-if="bmTab === 'more'" v-model="bmRange" type="daterange" range-separator="至"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="fetchBmStats" class="full-width-picker" />
|
||||
|
||||
<el-collapse v-model="bmActiveKeys" accordion>
|
||||
<el-collapse-item v-for="cat in bmCategories" :key="cat" :name="cat" :title="bmTitleMap[cat] || cat">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12" v-for="item in bmStats[cat]" :key="item.name">
|
||||
<div class="bm-item">
|
||||
<span class="bm-key">{{ item.name }}</span>
|
||||
<span class="bm-val">{{ item.count }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-card>
|
||||
|
||||
<!-- ========= 财务统计 ========= -->
|
||||
<el-card class="block-card" shadow="hover">
|
||||
<div class="card-head">
|
||||
财务统计
|
||||
<el-tabs v-model="financeTab" @tab-click="onFinanceTabClick" class="inline-tabs" size="small">
|
||||
<el-tab-pane v-for="(t, i) in timeTabs" :key="i" :label="t" :name="tabMap[i]" />
|
||||
</el-tabs>
|
||||
</div>
|
||||
<el-date-picker v-if="financeTab === 'more'" v-model="financeRange" type="daterange" range-separator="至"
|
||||
start-placeholder="开始日期" end-placeholder="结束日期" @change="fetchFinanceStats" class="full-width-picker" />
|
||||
|
||||
<el-row :gutter="20" class="summary-row">
|
||||
<el-col :span="8" v-for="card in financeCards" :key="card.key">
|
||||
<el-card class="finance-box" shadow="always">
|
||||
<div class="finance-title">{{ card.title }}</div>
|
||||
<p class="finance-money">¥{{ (financeStats[card.key].money / 100).toFixed(2) }}</p>
|
||||
<p class="finance-count">数量:{{ financeStats[card.key].count }}</p>
|
||||
<el-button type="text" size="mini" @click="viewOrderList(card.queryExtra, financeTab, financeRange)">查看明细</el-button>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request'
|
||||
import dayjs from 'dayjs'
|
||||
export default {
|
||||
name: 'businissStatistics',
|
||||
data() {
|
||||
return {
|
||||
// 公共时间 tab
|
||||
timeTabs: ['本日', '本月', '本年', '全部', '自定义'],
|
||||
tabMap: ['day', 'month', 'year', 'all', 'more'],
|
||||
|
||||
/* ========== 工单统计 ========== */
|
||||
orderTab: 'day',
|
||||
orderRange: [],
|
||||
countNum: { yjdNum: 0, jyzNum: 0, ywcNum: 0, dqcNum: 0 },
|
||||
orderBoxes: [
|
||||
{ key: 'yjdNum', label: '已接单', status: '' },
|
||||
{ key: 'jyzNum', label: '救援中', status: 1 },
|
||||
{ key: 'ywcNum', label: '已完成', status: 5 },
|
||||
{ key: 'dqcNum', label: '待取车', status: 3 },
|
||||
],
|
||||
|
||||
/* ========== 渠道统计 ========== */
|
||||
channelTab: 'day',
|
||||
customRange: [],
|
||||
channelStats: [],
|
||||
channelOptions: [],
|
||||
channelLoading: false,
|
||||
|
||||
/* ========== 业务管理统计 ========== */
|
||||
bmTab: 'day',
|
||||
bmRange: [],
|
||||
bmStats: {},
|
||||
bmCategories: [],
|
||||
bmActiveKeys: [],
|
||||
bmTitleMap: {
|
||||
rescueType: '救援类型统计',
|
||||
faultDistrict: '故障地点统计',
|
||||
carBrand: '车辆品牌统计',
|
||||
carType: '车辆类型统计',
|
||||
downDestination: '下车地统计',
|
||||
transferReason: '移交事由统计',
|
||||
newEnergy: '是否新能源统计',
|
||||
rescueNeeds: '救援需求统计',
|
||||
feeType: '收费类型统计',
|
||||
kouChe: '是否扣车统计',
|
||||
},
|
||||
|
||||
/* ========== 财务统计 ========== */
|
||||
financeTab: 'day',
|
||||
financeRange: [],
|
||||
financeStats: {
|
||||
receivable: { money: 0, count: 0 },
|
||||
received: { money: 0, count: 0 },
|
||||
pending: { money: 0, count: 0 },
|
||||
},
|
||||
financeCards: [
|
||||
{ key: 'receivable', title: '应收款统计', queryExtra: {} },
|
||||
{ key: 'received', title: '已收款统计', queryExtra: { ifConfirmPay: 1 } },
|
||||
{ key: 'pending', title: '待收款统计', queryExtra: { ifConfirmPay: 0 } },
|
||||
],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetchAll();
|
||||
this.fetchChannelOptions().then(() => this.fetchChannelStats())
|
||||
|
||||
},
|
||||
methods: {
|
||||
/* ====== 通用 ====== */
|
||||
goBack() {
|
||||
this.$router.back();
|
||||
},
|
||||
buildTimeParams(tab, range = []) {
|
||||
if (tab !== 'more') return { timeType: tab };
|
||||
if (range.length === 2) {
|
||||
const fmt = (d) => dayjs(d).format('YYYY-MM-DD')
|
||||
return {
|
||||
timeType: 'more',
|
||||
startTimeStr: `${fmt(range[0])} 00:00:01`,
|
||||
endTimeStr: `${fmt(range[1])} 23:59:59`,
|
||||
};
|
||||
}
|
||||
return { timeType: 'day' }; // fallback
|
||||
},
|
||||
/** 跳转到救援订单列表,并将筛选条件序列化到 query */
|
||||
/**
|
||||
* extra 其它查询字段
|
||||
* tab 当前模块的 timeType(day / month / year / all / more)
|
||||
* range 当前模块的日期区间数组([start, end]),only for tab==='more'
|
||||
*/
|
||||
viewOrderList(extra = {}, tab = 'day', range = []) {
|
||||
const base = this.buildTimeParams(tab, range);
|
||||
const query = { ...base, ...extra };
|
||||
this.$router.push({ path: '/rescue/rescue_finance/index', query });
|
||||
},
|
||||
|
||||
/* ====== 工单统计 ====== */
|
||||
onOrderTabClick() {
|
||||
if (this.orderTab !== 'more') this.orderRange = [];
|
||||
this.fetchOrderStats();
|
||||
},
|
||||
async fetchOrderStats() {
|
||||
const params = this.buildTimeParams(this.orderTab, this.orderRange);
|
||||
const { data } = await request.get('/app/rescueInfo/getRescueStatistics', { params });
|
||||
this.countNum = {
|
||||
yjdNum: data.yjdNum || 0,
|
||||
jyzNum: data.jyzNum || 0,
|
||||
ywcNum: data.ywcNum || 0,
|
||||
dqcNum: data.dqcNum || 0,
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
/* === 渠道 tab 点击 === */
|
||||
onChannelTabClick() {
|
||||
// 切到不是“自定义”时,把日期选择器清空
|
||||
if (this.channelTab !== 'more') {
|
||||
this.customRange = []
|
||||
}
|
||||
// 重新拉取统计
|
||||
this.fetchChannelStats()
|
||||
},
|
||||
/* ====== 渠道统计 ====== */
|
||||
async fetchChannelStats() {
|
||||
this.channelLoading = true;
|
||||
|
||||
try{
|
||||
if (!this.channelOptions.length) await this.fetchChannelOptions()
|
||||
|
||||
const base = this.buildTimeParams(this.channelTab, this.customRange)
|
||||
|
||||
// ① 并发请求每个渠道的汇总
|
||||
const channelTasks = this.channelOptions.map(c =>
|
||||
request.get('/app/rescueInfo/getRescueStatistics', {
|
||||
params: { ...base, channel: c.name }
|
||||
}).then(({ data }) => ({
|
||||
channel: c.name,
|
||||
channelId: c.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)
|
||||
}))
|
||||
)
|
||||
|
||||
// ② 并发请求每个渠道的来源列表 + 数据
|
||||
const sourceTasks = this.channelOptions.map(c =>
|
||||
request.get(`/rescue-channel-source/sources/${c.id}`)
|
||||
.then(res => res.data || [])
|
||||
.then(list => {
|
||||
if (!list.length) return []
|
||||
|
||||
const detailCalls = list.map(s =>
|
||||
request.get('/app/rescueInfo/getRescueStatistics', {
|
||||
params: { ...base, channel: c.name, source: s.name }
|
||||
}).then(({ data }) => ({
|
||||
source: s.name,
|
||||
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)
|
||||
}))
|
||||
)
|
||||
return Promise.all(detailCalls)
|
||||
})
|
||||
)
|
||||
|
||||
// ③ 合并结果
|
||||
const channels = await Promise.all(channelTasks)
|
||||
const allSources = await Promise.all(sourceTasks)
|
||||
|
||||
this.channelStats = channels.map((c, idx) => ({
|
||||
...c,
|
||||
sources: allSources[idx], // ← 给每行塞一个 sources 数组
|
||||
__rowKey: `c-${c.channelId}` // row-key 必须唯一
|
||||
}))
|
||||
|
||||
}finally {
|
||||
this.channelLoading = false; // 关闭 loading,无论成功失败
|
||||
}
|
||||
},
|
||||
|
||||
async fetchChannelOptions() {
|
||||
const res = await request.get('/rescue-channel-source/channelList');
|
||||
this.channelOptions = res.data || [];
|
||||
},
|
||||
|
||||
/* ====== 业务管理统计 ====== */
|
||||
onBmTabClick() {
|
||||
if (this.bmTab !== 'more') this.bmRange = [];
|
||||
this.fetchBmStats();
|
||||
},
|
||||
async fetchBmStats() {
|
||||
const params = this.buildTimeParams(this.bmTab, this.bmRange);
|
||||
const { data } = await request.get('/rescueBusiness/statistics/overview', { params });
|
||||
const filled = {};
|
||||
Object.keys(this.bmTitleMap).forEach((k) => {
|
||||
filled[k] = Array.isArray(data[k]) && data[k].length ? data[k] : [{ name: '—', count: 0 }];
|
||||
});
|
||||
this.bmStats = filled;
|
||||
this.bmCategories = Object.keys(filled);
|
||||
this.bmActiveKeys = this.bmCategories;
|
||||
},
|
||||
|
||||
/* ====== 财务统计 ====== */
|
||||
onFinanceTabClick() {
|
||||
if (this.financeTab !== 'more') this.financeRange = [];
|
||||
this.fetchFinanceStats();
|
||||
},
|
||||
async fetchFinanceStats() {
|
||||
const params = this.buildTimeParams(this.financeTab, this.financeRange);
|
||||
const { data } = await request.get('/app/rescueInfo/getRescueStatisticsInfoNum', { params });
|
||||
this.financeStats = {
|
||||
receivable: { money: data.yingskNum || 0, count: data.yjdNum || 0 },
|
||||
received: { money: data.yiskNum || 0, count: data.confirmPayNum || 0 },
|
||||
pending: {
|
||||
money: data.dskNum || 0,
|
||||
count: (data.yjdNum || 0) - (data.confirmPayNum || 0),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/* ====== 初始化 ====== */
|
||||
async fetchAll() {
|
||||
await Promise.all([
|
||||
this.fetchOrderStats(),
|
||||
this.fetchChannelOptions().then(this.fetchChannelStats),
|
||||
this.fetchBmStats(),
|
||||
this.fetchFinanceStats(),
|
||||
]);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$primary: #3a8dff;
|
||||
$bg: #f5f6fa;
|
||||
|
||||
.statistics-pc {
|
||||
padding: 16px 24px;
|
||||
background: $bg;
|
||||
|
||||
.top-page-header {
|
||||
background: transparent;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.block-card {
|
||||
margin-bottom: 24px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.inline-tabs {
|
||||
margin-left: 24px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width-picker {
|
||||
width: 100%;
|
||||
margin: 8px 0 16px;
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.summary-box {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
.box-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.box-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.box-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #001529;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.tight-table {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.bm-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 6px 0;
|
||||
|
||||
.bm-key {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.bm-val {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.finance-box {
|
||||
text-align: center;
|
||||
|
||||
.finance-title {
|
||||
font-size: 15px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.finance-money {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: $primary;
|
||||
margin: 8px 0 2px;
|
||||
}
|
||||
|
||||
.finance-count {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
216
src/views/rescue/checkpointMoney.vue
Normal file
216
src/views/rescue/checkpointMoney.vue
Normal file
@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryForm"
|
||||
size="small"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="日期" prop="dateRange">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
value-format="yyyy-MM-dd"
|
||||
unlink-panels
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="onDateChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="救援车车牌" prop="driverCarNum">
|
||||
<el-input
|
||||
v-model="queryParams.driverCarNum"
|
||||
placeholder="请输入救援车车牌"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="被施救车车牌" prop="licenseNum">
|
||||
<el-input
|
||||
v-model="queryParams.licenseNum"
|
||||
placeholder="请输入被施救车车牌"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<!-- <el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-download"
|
||||
:loading="exportLoading"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row> -->
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table v-loading="loading" :data="feeList" border fit style="width: 100%">
|
||||
<el-table-column label="序号" align="center" width="60">
|
||||
<template slot-scope="scope"
|
||||
>{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}</template
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="日期" align="center" min-width="120">
|
||||
<template slot-scope="scope">{{ formatDate(scope.row.rescueTime) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="救援车车牌" prop="driverCarNum" align="center" min-width="120" />
|
||||
<el-table-column label="被施救车车牌" prop="licenseNum" align="center" min-width="140" />
|
||||
<el-table-column label="金额(元)" align="center" min-width="100">
|
||||
<template slot-scope="scope">{{ (scope.row.setMoney / 100).toFixed(2) }}</template>
|
||||
</el-table-column>
|
||||
<!-- 取消固定列,避免右侧空白 -->
|
||||
<!-- <el-table-column label="操作" align="center" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="openEdit(scope.row)"
|
||||
>修改金额</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNo"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 修改金额弹窗 -->
|
||||
<el-dialog title="修改金额" :visible.sync="editOpen" width="400px" append-to-body>
|
||||
<el-form ref="editFormRef" :model="editForm" :rules="editRules" label-width="100px">
|
||||
<el-form-item label="金额(元)" prop="amount">
|
||||
<el-input-number v-model="editForm.amount" :min="0" :precision="2" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitEdit">确 定</el-button>
|
||||
<el-button @click="editOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listInfo, updateInfo, exportManagement } from '@/api/rescue/info'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
name: 'PassFeePage',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
exportLoading: false,
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
feeList: [],
|
||||
dateRange: [],
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
rescueStart: null,
|
||||
rescueEnd: null,
|
||||
driverCarNum: null,
|
||||
licenseNum: null
|
||||
},
|
||||
editOpen: false,
|
||||
editForm: {
|
||||
id: null,
|
||||
amount: 0
|
||||
},
|
||||
editRules: {
|
||||
amount: [{ required: true, message: '金额不能为空', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
formatDate(val) {
|
||||
return val ? dayjs(val).format('YYYY-MM-DD') : '-'
|
||||
},
|
||||
/* 查询 */
|
||||
onDateChange(val) {
|
||||
if (val && val.length === 2) {
|
||||
this.queryParams.rescueStart = val[0]
|
||||
this.queryParams.rescueEnd = val[1]
|
||||
} else {
|
||||
this.queryParams.rescueStart = null
|
||||
this.queryParams.rescueEnd = null
|
||||
}
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listInfo({ ...this.queryParams, listType: 2 }).then(res => {
|
||||
this.feeList = res.data.records || []
|
||||
this.total = res.data.total || 0
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.dateRange = []
|
||||
this.queryParams = {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
rescueStart: null,
|
||||
rescueEnd: null,
|
||||
driverCarNum: null,
|
||||
licenseNum: null
|
||||
}
|
||||
this.resetForm('queryForm')
|
||||
this.getList()
|
||||
},
|
||||
/* 编辑金额 */
|
||||
openEdit(row) {
|
||||
this.editForm.id = row.id
|
||||
this.editForm.amount = (row.setMoney || 0) / 100
|
||||
this.editOpen = true
|
||||
},
|
||||
submitEdit() {
|
||||
this.$refs['editFormRef'].validate(valid => {
|
||||
if (!valid) return
|
||||
updateInfo({ id: this.editForm.id, setMoney: Math.round(this.editForm.amount * 100) }).then(() => {
|
||||
this.$modal.msgSuccess('修改成功')
|
||||
this.editOpen = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
/* 导出 */
|
||||
async handleExport() {
|
||||
try {
|
||||
this.exportLoading = true
|
||||
const data = await exportManagement(this.queryParams)
|
||||
this.$download.excel(data, `过关费_${Date.now()}.xls`)
|
||||
} finally {
|
||||
this.exportLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,20 @@
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- 新增:记录时间段 -->
|
||||
<el-form-item label="记录时间" prop="recordTimeRange">
|
||||
<el-date-picker
|
||||
v-model="queryParams.recordTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
clearable
|
||||
@change="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
@ -28,6 +42,33 @@
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- ① 统计栏 -->
|
||||
<el-card class="mb8" shadow="never">
|
||||
<el-row :gutter="20" type="flex" justify="center">
|
||||
<el-col :span="6" class="stat-box">
|
||||
<div class="stat-label">行驶总公里数 (km)</div>
|
||||
<div class="stat-value">{{ summary.totalKm }}</div>
|
||||
</el-col>
|
||||
<el-col :span="6"> <!-- ★ 新增 -->
|
||||
<div class="stat-label">加油总花费 (元)</div>
|
||||
<div class="stat-value">{{ summary.totalRefuelMoney }}</div>
|
||||
</el-col>
|
||||
<el-col :span="6" class="stat-box">
|
||||
<div class="stat-label">平均油耗 (L/km)</div>
|
||||
<div class="stat-value">
|
||||
{{ summary.avgFuelEfficiencyLpkm }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6" class="stat-box">
|
||||
<div class="stat-label">平均成本 (元/km)</div>
|
||||
<div class="stat-value">
|
||||
{{ summary.avgCostPerKm }}
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
|
||||
<el-table v-loading="loading" :data="refuelRecordList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="序号" align="center">
|
||||
<template scope="scope">
|
||||
@ -113,12 +154,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listRefuelRecord, getRefuelRecord, delRefuelRecord, addRefuelRecord, updateRefuelRecord } from "./api/refuelRecord";
|
||||
import { listRefuelRecord, getRefuelRecord, delRefuelRecord, addRefuelRecord, updateRefuelRecord,listRefuelSummary } from "./api/refuelRecord";
|
||||
|
||||
export default {
|
||||
name: "RefuelRecord",
|
||||
data() {
|
||||
return {
|
||||
/* 统计栏三项 */
|
||||
summary: {
|
||||
totalKm: 0, // 行驶总公里数
|
||||
avgFuelEfficiencyLpkm: 0, // 平均油耗
|
||||
avgCostPerKm: 0, // 平均成本
|
||||
totalRefuelMoney: 0 // 加油总花费
|
||||
},
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
@ -146,6 +194,9 @@ export default {
|
||||
refuelNum: null,
|
||||
refuelMoney: null,
|
||||
recordTime: null,
|
||||
recordTimeRange: [], // 这里存 [开始日期, 结束日期]
|
||||
beginTime: null, // 发送给后端的开始日期
|
||||
endTime: null // 发送给后端的结束日期
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
@ -156,16 +207,65 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getSummary(); // 页面首次加载
|
||||
},
|
||||
methods: {
|
||||
/** 汇总接口:统计栏四项 */
|
||||
getSummary() {
|
||||
// ① 把 recordTimeRange 拆成 beginTime / endTime
|
||||
const { recordTimeRange, ...others } = this.queryParams;
|
||||
const [beginTime, endTime] = recordTimeRange || []; // 若为空数组则为 undefined
|
||||
|
||||
// ② 组装一个新对象发给后端,**不要带 recordTimeRange**
|
||||
const params = {
|
||||
...others, // pageNo、pageSize、realName...
|
||||
beginTime, // 2025-10-01
|
||||
endTime, // 2025-10-31
|
||||
timeType: 'more'
|
||||
};
|
||||
listRefuelSummary(params).then(res => {
|
||||
/* 后端已返回 totalKm / avgFuelEfficiencyLpkm / avgCostPerKm / totalRefuelMoney */
|
||||
this.summary = res.data || {
|
||||
totalKm: 0,
|
||||
avgFuelEfficiencyLpkm: 0,
|
||||
avgCostPerKm: 0,
|
||||
totalRefuelMoney: 0
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/** 查询加油记录列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listRefuelRecord(this.queryParams).then(response => {
|
||||
this.refuelRecordList = response.data.records;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
// ① 把 recordTimeRange 拆成 beginTime / endTime
|
||||
const { recordTimeRange, ...others } = this.queryParams;
|
||||
const [beginTime, endTime] = recordTimeRange || []; // 若为空数组则为 undefined
|
||||
|
||||
// ② 组装一个新对象发给后端,**不要带 recordTimeRange**
|
||||
const params = {
|
||||
...others, // pageNo、pageSize、realName...
|
||||
beginTime, // 2025-10-01
|
||||
endTime // 2025-10-31
|
||||
};
|
||||
|
||||
listRefuelRecord(params).then(res => {
|
||||
this.refuelRecordList = res.data.records;
|
||||
this.total = res.data.total;
|
||||
this.loading = false;
|
||||
|
||||
/* ★ 计算统计数字 ↓↓↓ */
|
||||
this.getSummary();
|
||||
});
|
||||
|
||||
// listRefuelRecord(this.queryParams).then(response => {
|
||||
// this.refuelRecordList = response.data.records;
|
||||
// this.total = response.data.total;
|
||||
// this.loading = false;
|
||||
// });
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
@ -205,6 +305,11 @@ export default {
|
||||
realName: null,
|
||||
recordTime: null,
|
||||
}
|
||||
// 拆出起止时间
|
||||
const [begin, end] = this.queryParams.recordTimeRange || [];
|
||||
this.queryParams.beginTime = begin || null;
|
||||
this.queryParams.endTime = end || null;
|
||||
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user