统计分析页面整改
This commit is contained in:
parent
2e423ffe85
commit
64d5b4812f
@ -157,8 +157,8 @@
|
|||||||
|
|
||||||
<el-table-column prop="orderNo" label="订单编号" min-width="180" sortable/>
|
<el-table-column prop="orderNo" label="订单编号" min-width="180" sortable/>
|
||||||
<el-table-column prop="customerName" label="客户名称" min-width="120"/>
|
<el-table-column prop="customerName" label="客户名称" min-width="120"/>
|
||||||
<el-table-column prop="pilotName" label="飞行员名称" min-width="120" />
|
<el-table-column prop="areaName" label="区域名称" min-width="120" />
|
||||||
<el-table-column prop="scenicName" label="景区名称" min-width="150" />
|
<el-table-column prop="scenicName" label="景区名称" min-width="150" />
|
||||||
<el-table-column prop="phone" label="联系电话" min-width="150"/>
|
<el-table-column prop="phone" label="联系电话" min-width="150"/>
|
||||||
<el-table-column prop="routeNames" label="配送路线" min-width="150" />
|
<el-table-column prop="routeNames" label="配送路线" min-width="150" />
|
||||||
<el-table-column prop="totalAmount" label="总金额(元)" min-width="140" sortable align="right">
|
<el-table-column prop="totalAmount" label="总金额(元)" min-width="140" sortable align="right">
|
||||||
@ -193,7 +193,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<!-- 分页 -->
|
<!-- 分页代码 -->
|
||||||
<div class="pagination-wrapper">
|
<div class="pagination-wrapper">
|
||||||
<div class="pagination-info">
|
<div class="pagination-info">
|
||||||
显示第 {{ (pagination.currentPage - 1) * pagination.pageSize + 1 }} 至
|
显示第 {{ (pagination.currentPage - 1) * pagination.pageSize + 1 }} 至
|
||||||
@ -201,25 +201,15 @@
|
|||||||
共 {{ pagination.total }} 条记录
|
共 {{ pagination.total }} 条记录
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pagination-jump">
|
<el-pagination
|
||||||
<span class="jump-text">跳至</span>
|
:current-page="pagination.currentPage"
|
||||||
<el-input
|
:page-size="pagination.pageSize"
|
||||||
v-model.number="jumpPage"
|
:total="Number(pagination.total)"
|
||||||
type="number"
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
:min="1"
|
layout="prev, pager, next, jumper"
|
||||||
:max="Math.ceil(pagination.total / pagination.pageSize)"
|
@current-change="handlePageChange"
|
||||||
@keyup.enter="handleJump"
|
@size-change="handleSizeChange"
|
||||||
class="jump-input"
|
/>
|
||||||
/>
|
|
||||||
<span class="jump-text">页</span>
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
@click="handleJump"
|
|
||||||
class="jump-button"
|
|
||||||
>
|
|
||||||
确定
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -231,32 +221,27 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import {
|
import {getDailyOrderAnalysis,getMonthlyOrderAnalysis,getYearlyOrderAnalysis} from '@/api/analysis/orderAnalysis';
|
||||||
getDailyOrderAnalysis,
|
|
||||||
getMonthlyOrderAnalysis,
|
|
||||||
getYearlyOrderAnalysis
|
|
||||||
} from '@/api/analysis/orderAnalysis';
|
|
||||||
import { allScenic } from "@/api/system/scenic";
|
import { allScenic } from "@/api/system/scenic";
|
||||||
import { allCustomer } from "@/api/system/customer";
|
import { allCustomer } from "@/api/system/customer";
|
||||||
import { getList } from "@/api/system/pilot";
|
import { getList } from "@/api/system/pilot";
|
||||||
import { getAllRoutes } from "@/api/system/route";
|
import { getAllRoutes } from "@/api/system/route";
|
||||||
|
import { allAreas } from "@/api/system/area";
|
||||||
import { getOrderStatusText, getSettlementStatusText, getOrderStatusClass, getSettlementStatusClass } from "@/utils/orderStatus";
|
import { getOrderStatusText, getSettlementStatusText, getOrderStatusClass, getSettlementStatusClass } from "@/utils/orderStatus";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'orderAnalysis',
|
name: 'orderAnalysis',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
customerMap: {},
|
customerMap: {},
|
||||||
pilotMap: {},
|
routeMap: {},
|
||||||
scenicMap: {},
|
orderTypeMap: {
|
||||||
routeMap: {},
|
1: '载物飞行',
|
||||||
orderTypeMap: {
|
2: '载人飞行'
|
||||||
1: '载物飞行',
|
},
|
||||||
2: '载人飞行'
|
areaOptions: [],
|
||||||
},
|
scenicOptions: [],
|
||||||
|
pilotOptions: [],
|
||||||
|
|
||||||
jumpPage: 1,
|
|
||||||
loading: false,
|
loading: false,
|
||||||
tableLoading: false,
|
tableLoading: false,
|
||||||
startPickerOptions: {
|
startPickerOptions: {
|
||||||
@ -305,31 +290,31 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
processedOrderList() {
|
processedOrderList() {
|
||||||
return this.orderList.map(order => {
|
return this.orderList.map(order => {
|
||||||
// 处理配送路线(兼容routeIds可能为空的情况)
|
// 处理配送路线
|
||||||
const routeNames = order.routeIds
|
const routeNames = order.routeIds
|
||||||
? order.routeIds.split(',').map(id => this.routeMap[id] || id).join('、')
|
? order.routeIds.split(',').map(id => this.routeMap[id] || id).join('、')
|
||||||
: '无路线';
|
: '无路线';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...order,
|
...order,
|
||||||
// 客户名称映射
|
// 客户名称映射
|
||||||
customerName: this.customerMap[order.customerId] || `客户${order.customerId}`,
|
customerName: this.customerMap[order.customerId] || `客户${order.customerId}`,
|
||||||
// 飞行员名称映射
|
// 区域名称(直接从order中获取)
|
||||||
pilotName: this.pilotMap[order.pilotId] || `飞行员${order.pilotId}`,
|
areaName: order.areaName,
|
||||||
// 景区名称映射
|
// 景区名称(直接从order中获取)
|
||||||
scenicName: this.scenicMap[order.scenicId] || `景区${order.scenicId}`,
|
scenicName: order.scenicName,
|
||||||
// 订单发起人映射
|
// 订单发起人(直接从order中获取)
|
||||||
orderInitiator: this.pilotMap[order.orderInitiatorId] || `发起人${order.orderInitiatorId}`,
|
orderInitiator: order.orderInitiator,
|
||||||
// 配送路线
|
// 配送路线
|
||||||
routeNames: routeNames,
|
routeNames: routeNames,
|
||||||
// 格式化金额
|
// 格式化金额
|
||||||
totalAmount: parseFloat(order.totalAmount || 0),
|
totalAmount: parseFloat(order.totalAmount || 0),
|
||||||
// 订单类型映射
|
// 订单类型映射
|
||||||
orderType: this.orderTypeMap[order.orderType] || '未知类型',
|
orderType: this.orderTypeMap[order.orderType] || '未知类型',
|
||||||
// 订单状态 - 使用工具函数
|
// 订单状态
|
||||||
statusText: this.getOrderStatusText(order.mainOrderStatus),
|
statusText: this.getOrderStatusText(order.mainOrderStatus),
|
||||||
statusClass: this.getOrderStatusClass(order.mainOrderStatus),
|
statusClass: this.getOrderStatusClass(order.mainOrderStatus),
|
||||||
// 结算状态 - 使用工具函数(非详情页面)
|
// 结算状态
|
||||||
settlementStatusText: this.getSettlementStatusText(order.settlementStatus),
|
settlementStatusText: this.getSettlementStatusText(order.settlementStatus),
|
||||||
settlementClass: this.getSettlementStatusClass(order.settlementStatus),
|
settlementClass: this.getSettlementStatusClass(order.settlementStatus),
|
||||||
// 保留原始值
|
// 保留原始值
|
||||||
@ -359,67 +344,47 @@ export default {
|
|||||||
this.filter.timeRange === 'month' ? '结束月份' : '结束日期';
|
this.filter.timeRange === 'month' ? '结束月份' : '结束日期';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.initCharts();
|
this.initCharts();
|
||||||
this.initMaps(); // 新增
|
await this.initMaps();
|
||||||
this.initDefaultDateRange();
|
this.initDefaultDateRange();
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
window.addEventListener('resize', this.handleResize);
|
window.addEventListener('resize', this.handleResize);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
if (this.trendChart) this.trendChart.dispose();
|
if (this.trendChart) this.trendChart.dispose();
|
||||||
if (this.modelChart) this.modelChart.dispose();
|
if (this.modelChart) this.modelChart.dispose();
|
||||||
if (this.routeChart) this.routeChart.dispose();
|
if (this.routeChart) this.routeChart.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getOrderStatusText,
|
getOrderStatusText,
|
||||||
getSettlementStatusText,
|
getSettlementStatusText,
|
||||||
getOrderStatusClass,
|
getOrderStatusClass,
|
||||||
getSettlementStatusClass,
|
getSettlementStatusClass,
|
||||||
getSettlementTagType(status) {
|
getSettlementTagType(status) {
|
||||||
const map = {
|
const map = {
|
||||||
0: 'info', // 未结算
|
0: 'info', // 未结算
|
||||||
1: 'warning', // 结算中
|
1: 'warning', // 结算中
|
||||||
2: 'success' // 已结算
|
2: 'success' // 已结算
|
||||||
};
|
};
|
||||||
return map[status] || 'info';
|
return map[status] || 'info';
|
||||||
},
|
},
|
||||||
getStatusTagType(status) {
|
getStatusTagType(status) {
|
||||||
const map = {
|
const map = {
|
||||||
0: 'info', // 未进行(灰色)
|
0: 'info', // 未进行(灰色)
|
||||||
1: 'primary', // 进行中(蓝色)
|
1: 'primary', // 进行中(蓝色)
|
||||||
2: 'success', // 已完成(绿色)
|
2: 'success', // 已完成(绿色)
|
||||||
3: 'danger', // 已取消(红色)
|
3: 'danger', // 已取消(红色)
|
||||||
4: 'warning' // 待确认(黄色)
|
4: 'warning' // 待确认(黄色)
|
||||||
};
|
};
|
||||||
return map[status] || 'info';
|
return map[status] || 'info';
|
||||||
},
|
|
||||||
// 修改后的类获取方法
|
|
||||||
getOrderStatusClass(status) {
|
|
||||||
const classObj = getOrderStatusClass(status);
|
|
||||||
return Object.keys(classObj).find(key => classObj[key]) || '';
|
|
||||||
},
|
|
||||||
|
|
||||||
getSettlementStatusClass(status) {
|
|
||||||
const classObj = getSettlementStatusClass(status);
|
|
||||||
return Object.keys(classObj).find(key => classObj[key]) || '';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 订单状态过滤
|
// 初始化映射数据
|
||||||
filterStatus(value, row) {
|
async initMaps() {
|
||||||
return row.mainOrderStatus === value;
|
try {
|
||||||
},
|
|
||||||
|
|
||||||
// 结算状态过滤
|
|
||||||
filterSettlementStatus(value, row) {
|
|
||||||
return row.settlementStatus === value;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 初始化映射数据
|
|
||||||
async initMaps() {
|
|
||||||
try {
|
|
||||||
// 获取客户映射
|
// 获取客户映射
|
||||||
const customers = await allCustomer();
|
const customers = await allCustomer();
|
||||||
this.customerMap = customers.reduce((map, customer) => {
|
this.customerMap = customers.reduce((map, customer) => {
|
||||||
@ -427,33 +392,59 @@ export default {
|
|||||||
return map;
|
return map;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
// 获取飞行员映射
|
// 获取区域映射
|
||||||
const pilotsResponse = await getList();
|
const areasResponse = await allAreas();
|
||||||
this.pilotMap = (pilotsResponse.content || pilotsResponse.data || []).reduce((map, pilot) => {
|
this.areaOptions = (areasResponse || []).map(area => ({
|
||||||
map[pilot.id] = pilot.name;
|
id: area.id,
|
||||||
return map;
|
name: area.name
|
||||||
}, {});
|
}));
|
||||||
|
|
||||||
// 获取景区映射
|
// 获取景区映射
|
||||||
const scenicsResponse = await allScenic();
|
const scenicsResponse = await allScenic();
|
||||||
this.scenicMap = (scenicsResponse.data || scenicsResponse || []).reduce((map, scenic) => {
|
this.scenicOptions = (scenicsResponse || []).map(scenic => ({
|
||||||
map[scenic.id] = scenic.name;
|
id: scenic.id,
|
||||||
return map;
|
name: scenic.name
|
||||||
}, {});
|
}));
|
||||||
|
|
||||||
// 获取路线映射 - 使用 getAllRoutes 方法
|
// 获取飞行员映射(用于订单发起人)
|
||||||
const routesResponse = await getAllRoutes(); // 修改这里
|
const pilotsResponse = await getList();
|
||||||
const routes = routesResponse.data || routesResponse; // 根据实际API响应结构调整
|
this.pilotOptions = (pilotsResponse.content || pilotsResponse.data || pilotsResponse || []).map(pilot => ({
|
||||||
|
id: pilot.id,
|
||||||
|
name: pilot.name
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 获取路线映射
|
||||||
|
const routesResponse = await getAllRoutes();
|
||||||
|
const routes = routesResponse.data || routesResponse;
|
||||||
this.routeMap = routes.reduce((map, route) => {
|
this.routeMap = routes.reduce((map, route) => {
|
||||||
map[route.id] = route.name;
|
map[route.id] = route.name;
|
||||||
return map;
|
return map;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
console.log('映射数据加载完成', {
|
||||||
|
areaOptions: this.areaOptions,
|
||||||
|
scenicOptions: this.scenicOptions,
|
||||||
|
pilotOptions: this.pilotOptions,
|
||||||
|
customerMap: this.customerMap,
|
||||||
|
routeMap: this.routeMap
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('初始化映射数据失败:', error);
|
console.error('初始化映射数据失败:', error);
|
||||||
this.$message.error('初始化数据失败,请刷新重试');
|
this.$message.error('初始化数据失败,请刷新重试');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 添加页面变化处理方法
|
||||||
|
handlePageChange(page) {
|
||||||
|
this.pagination.currentPage = page;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pagination.pageSize = size;
|
||||||
|
this.pagination.currentPage = 1; // 重置到第一页
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
initCharts() {
|
initCharts() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@ -583,15 +574,12 @@ export default {
|
|||||||
endDate: this.filter.endDate,
|
endDate: this.filter.endDate,
|
||||||
pageNum: this.pagination.currentPage,
|
pageNum: this.pagination.currentPage,
|
||||||
pageSize: this.pagination.pageSize,
|
pageSize: this.pagination.pageSize,
|
||||||
// 移除空的sortField
|
|
||||||
...(this.filter.sortField && {
|
...(this.filter.sortField && {
|
||||||
sortField: this.filter.sortField,
|
sortField: this.filter.sortField,
|
||||||
sortOrder: this.filter.sortOrder
|
sortOrder: this.filter.sortOrder
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('请求参数:', params);
|
|
||||||
console.log('正在请求接口:', this.filter.timeRange); // 调试
|
|
||||||
switch (this.filter.timeRange) {
|
switch (this.filter.timeRange) {
|
||||||
case 'day':
|
case 'day':
|
||||||
response = await getDailyOrderAnalysis(params);
|
response = await getDailyOrderAnalysis(params);
|
||||||
@ -607,7 +595,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('接口响应数据:', response);
|
console.log('接口响应数据:', response);
|
||||||
|
|
||||||
this.processResponseData(response);
|
this.processResponseData(response);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -642,34 +630,33 @@ export default {
|
|||||||
|
|
||||||
// 3. 设置orderList - 添加新字段映射
|
// 3. 设置orderList - 添加新字段映射
|
||||||
this.orderList = (data.orderList || []).map(item => {
|
this.orderList = (data.orderList || []).map(item => {
|
||||||
return {
|
// 查找匹配的区域和景区名称
|
||||||
...item,
|
const scenicIdValue = item.scenicId || item.attractionId || item.scenicID;
|
||||||
customerName: this.customerMap[item.customerId] || `客户${item.customerId}`,
|
const areaIdValue = item.areaId || item.regionId;
|
||||||
pilotName: this.pilotMap[item.pilotId] || `飞行员${item.pilotId}`,
|
const initiatorIdValue = item.orderInitiatorId || item.initiatorId;
|
||||||
scenicName: this.scenicMap[item.scenicId] || `景区${item.scenicId}`,
|
|
||||||
orderInitiator: this.pilotMap[item.orderInitiatorId] || `发起人${item.orderInitiatorId}`,
|
// 查找匹配
|
||||||
orderType: this.orderTypeMap[item.orderType] || '未知类型',
|
const matchedArea = this.areaOptions.find(area => area.id == areaIdValue);
|
||||||
routeNames: item.routeIds ? item.routeIds.split(',').map(id => this.routeMap[id] || id).join('、') : '无路线',
|
const matchedScenic = this.scenicOptions.find(scenic => scenic.id == scenicIdValue);
|
||||||
totalAmount: parseFloat(item.totalAmount || 0),
|
const matchedPilot = this.pilotOptions.find(pilot => pilot.id == initiatorIdValue);
|
||||||
statusText: this.getOrderStatusText(item.mainOrderStatus),
|
|
||||||
statusClass: this.getOrderStatusClass(item.mainOrderStatus),
|
return {
|
||||||
settlementStatusText: this.getSettlementStatusText(item.settlementStatus),
|
...item,
|
||||||
settlementClass: this.getSettlementStatusClass(item.settlementStatus),
|
areaName: matchedArea ? matchedArea.name : `区域${areaIdValue || '未知'}`,
|
||||||
mainOrderStatus: item.mainOrderStatus,
|
scenicName: matchedScenic ? matchedScenic.name : `景区${scenicIdValue || '未知'}`,
|
||||||
settlementStatus: item.settlementStatus
|
orderInitiator: matchedPilot ? matchedPilot.name : `发起人${initiatorIdValue || '未知'}`
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4. 设置分页数据
|
// 4. 设置分页数据
|
||||||
if (data.pageInfo) {
|
if (data.pageInfo) {
|
||||||
this.pagination.total = data.pageInfo.total || 0;
|
this.pagination.total = Number(data.pageInfo.total) || 0;
|
||||||
this.pagination.currentPage = data.pageInfo.pageNum || 1;
|
this.pagination.currentPage = Number(data.pageInfo.pageNum) || 1;
|
||||||
this.pagination.pageSize = data.pageInfo.pageSize || 10;
|
this.pagination.pageSize = Number(data.pageInfo.pageSize) || 10;
|
||||||
} else {
|
} else {
|
||||||
this.pagination.total = this.orderList.length;
|
this.pagination.total = Number(this.orderList.length);
|
||||||
this.pagination.currentPage = 1;
|
this.pagination.currentPage = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 更新图表
|
// 5. 更新图表
|
||||||
this.updateCharts({
|
this.updateCharts({
|
||||||
timeSeriesData: data.timeSeriesData || [],
|
timeSeriesData: data.timeSeriesData || [],
|
||||||
@ -723,7 +710,6 @@ export default {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 简单添加标题和最大值标注
|
|
||||||
const maxValue = Math.max(...seriesData);
|
const maxValue = Math.max(...seriesData);
|
||||||
const maxIndex = seriesData.indexOf(maxValue);
|
const maxIndex = seriesData.indexOf(maxValue);
|
||||||
|
|
||||||
@ -776,7 +762,7 @@ export default {
|
|||||||
},
|
},
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: true,
|
show: true,
|
||||||
inside: true, // 刻度在轴内
|
inside: true,
|
||||||
},
|
},
|
||||||
itemStyle: { color: '#4E80EE' },
|
itemStyle: { color: '#4E80EE' },
|
||||||
markPoint: {
|
markPoint: {
|
||||||
@ -894,7 +880,7 @@ export default {
|
|||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
left: '3%',
|
||||||
right: '12%', // 为右侧数值留更多空间
|
right: '12%',
|
||||||
bottom: '3%',
|
bottom: '3%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
@ -902,12 +888,12 @@ export default {
|
|||||||
type: 'value',
|
type: 'value',
|
||||||
name: '订单数量(件)',
|
name: '订单数量(件)',
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false // 移除背景竖线
|
show: false
|
||||||
},
|
},
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false // 隐藏刻度
|
show: false
|
||||||
},
|
},
|
||||||
max: Math.max(50, maxValue) // 动态调整最大值
|
max: Math.max(50, maxValue)
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
@ -918,12 +904,12 @@ export default {
|
|||||||
formatter: (name) => name.length > 8 ? `${name.substring(0, 8)}...` : name
|
formatter: (name) => name.length > 8 ? `${name.substring(0, 8)}...` : name
|
||||||
},
|
},
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false // 隐藏刻度
|
show: false
|
||||||
},
|
},
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false // 移除背景横线
|
show: false
|
||||||
},
|
},
|
||||||
inverse: true // 反转Y轴使最大值在上方
|
inverse: true
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: '订单量',
|
name: '订单量',
|
||||||
@ -939,25 +925,13 @@ export default {
|
|||||||
barWidth: '40%',
|
barWidth: '40%',
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
position: 'right', // 数值显示在右侧
|
position: 'right',
|
||||||
formatter: ({ data }) => data.displayValue || `${data.value}`,
|
formatter: ({ data }) => data.displayValue || `${data.value}`,
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}, true);
|
}, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleJump() {
|
|
||||||
const page = parseInt(this.jumpPage);
|
|
||||||
const maxPage = Math.ceil(this.pagination.total / this.pagination.pageSize);
|
|
||||||
|
|
||||||
if (page >= 1 && page <= maxPage) {
|
|
||||||
this.pagination.currentPage = page;
|
|
||||||
this.fetchData();
|
|
||||||
} else {
|
|
||||||
this.$message.warning(`请输入1-${maxPage}之间的页码`);
|
|
||||||
this.jumpPage = this.pagination.currentPage;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
refreshData() {
|
refreshData() {
|
||||||
this.pagination.currentPage = 1;
|
this.pagination.currentPage = 1;
|
||||||
@ -970,13 +944,6 @@ export default {
|
|||||||
this.refreshData();
|
this.refreshData();
|
||||||
},
|
},
|
||||||
|
|
||||||
handleViewDetail(row) {
|
|
||||||
this.$router.push({
|
|
||||||
path: '/order/detail',
|
|
||||||
query: { id: row.id }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleResize() {
|
handleResize() {
|
||||||
if (this.trendChart) this.trendChart.resize();
|
if (this.trendChart) this.trendChart.resize();
|
||||||
if (this.modelChart) this.modelChart.resize();
|
if (this.modelChart) this.modelChart.resize();
|
||||||
@ -1167,40 +1134,17 @@ export default {
|
|||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
border-top: 1px solid #ebeef5;
|
border-top: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-info {
|
.pagination-info {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
color: #606266;
|
||||||
.pagination-jump {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.jump-text {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.jump-input {
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
.jump-input .el-input__inner {
|
|
||||||
text-align: center;
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式布局 */
|
/* 响应式调整 */
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.card-grid { grid-template-columns: repeat(2, 1fr) }
|
|
||||||
.double-chart-section { grid-template-columns: 1fr }
|
|
||||||
}
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.card-grid { grid-template-columns: 1fr }
|
.pagination-wrapper {
|
||||||
.filter-section { flex-direction: column }
|
flex-direction: column;
|
||||||
.filter-group, .time-range-buttons, .date-range-picker { width: 100% }
|
gap: 12px;
|
||||||
.filter-item { flex-direction: column; align-items: flex-start }
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: 480px) {
|
|
||||||
.main-content { padding: 10px }
|
|
||||||
.content-box { padding: 16px }
|
|
||||||
.chart-wrapper { height: 280px }
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -80,34 +80,57 @@
|
|||||||
<div class="task-list-section">
|
<div class="task-list-section">
|
||||||
<h3 class="section-title">任务详情列表</h3>
|
<h3 class="section-title">任务详情列表</h3>
|
||||||
<el-table
|
<el-table
|
||||||
:data="orderDetailList"
|
:data="processedOrderDetailList"
|
||||||
:fit="true"
|
:fit="true"
|
||||||
|
:header-cell-style="{
|
||||||
|
'text-align': 'center',
|
||||||
|
'color': '#000000',
|
||||||
|
}"
|
||||||
:cell-style="{ textAlign: 'center' }"
|
:cell-style="{ textAlign: 'center' }"
|
||||||
border
|
border
|
||||||
stripe
|
stripe
|
||||||
class="task-detail-table"
|
class="task-detail-table"
|
||||||
:header-cell-style="{background:'#f5f7fa', color:'#333'}"
|
v-loading="loading"
|
||||||
>
|
>
|
||||||
<el-table-column prop="id" label="ID" min-width="150" />
|
<el-table-column prop="orderId" label="订单编号" min-width="150" />
|
||||||
<el-table-column prop="orderId" label="订单ID" min-width="150" />
|
<el-table-column prop="deviceId" label="设备名称" min-width="150" show-overflow-tooltip />
|
||||||
<el-table-column prop="deviceId" label="设备ID" min-width="150" show-overflow-tooltip />
|
<el-table-column prop="createTime" label="创建时间" min-width="160" />
|
||||||
<el-table-column prop="operatorId" label="操作员ID" min-width="80" />
|
<el-table-column prop="operatorName" label="操作员" min-width="150" />
|
||||||
<el-table-column prop="createTime" label="创建时间" min-width="160" />
|
<el-table-column
|
||||||
<el-table-column prop="orderItemStatus" label="状态" min-width="120" >
|
prop="orderItemStatus"
|
||||||
|
label="状态"
|
||||||
|
min-width="120"
|
||||||
|
:filters="statusFilters"
|
||||||
|
:filter-method="filterStatus"
|
||||||
|
filter-placement="bottom-end"
|
||||||
|
>
|
||||||
<template #default="{row}">
|
<template #default="{row}">
|
||||||
<el-tag :type="getStatusTagType(row.orderItemStatus)">
|
<el-tag :type="getStatusTagType(row.orderItemStatus)">
|
||||||
{{ getStatusText(row.orderItemStatus) }}
|
{{ getStatusText(row.orderItemStatus) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- <el-table-column prop="personCount" label="人数" min-width="100" /> -->
|
<el-table-column prop="cargoWeight" label="货物重量(kg)" min-width="100" />
|
||||||
<el-table-column prop="cargoWeight" label="货物重量(kg)" min-width="80" />
|
|
||||||
<!-- <el-table-column
|
|
||||||
label="操作"
|
|
||||||
min-width="120"
|
|
||||||
fixed="right"
|
|
||||||
/> -->
|
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页方案 -->
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<div class="pagination-info">
|
||||||
|
显示第 {{ (pagination.currentPage - 1) * pagination.pageSize + 1 }} 至
|
||||||
|
{{ Math.min(pagination.currentPage * pagination.pageSize, pagination.total) }} 条,
|
||||||
|
共 {{ pagination.total }} 条记录
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-pagination
|
||||||
|
:current-page="pagination.currentPage"
|
||||||
|
:page-size="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="sizes, prev, pager, next, jumper"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -117,12 +140,23 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { getDailyOrderAnalysis, getMonthlyOrderAnalysis, getYearlyOrderAnalysis } from '@/api/analysis/taskAnalysis'
|
import {
|
||||||
|
getDailyOrderAnalysis,
|
||||||
|
getMonthlyOrderAnalysis,
|
||||||
|
getYearlyOrderAnalysis
|
||||||
|
} from '@/api/analysis/taskAnalysis'
|
||||||
|
import { getAllPilots } from '@/api/system/pilot'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'taskAnalysis',
|
name: 'taskAnalysis',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
operatorsMap: {},
|
||||||
|
pagination: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
trendChart: null,
|
trendChart: null,
|
||||||
timeRanges: [
|
timeRanges: [
|
||||||
@ -168,6 +202,20 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
processedOrderDetailList() {
|
||||||
|
return this.orderDetailList.map(item => ({
|
||||||
|
...item,
|
||||||
|
operatorName: this.getOperatorName(item.operatorId)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
// 状态筛选器配置
|
||||||
|
statusFilters() {
|
||||||
|
return [
|
||||||
|
{ text: '未开始', value: 0 },
|
||||||
|
{ text: '已完成', value: 2 },
|
||||||
|
{ text: '已失败', value: 3 }
|
||||||
|
]
|
||||||
|
},
|
||||||
datePickerType() {
|
datePickerType() {
|
||||||
return this.filter.timeRange === 'year' ? 'year' :
|
return this.filter.timeRange === 'year' ? 'year' :
|
||||||
this.filter.timeRange === 'month' ? 'month' : 'date'
|
this.filter.timeRange === 'month' ? 'month' : 'date'
|
||||||
@ -189,7 +237,8 @@ export default {
|
|||||||
this.filter.timeRange === 'month' ? '结束月份' : '结束日期'
|
this.filter.timeRange === 'month' ? '结束月份' : '结束日期'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
|
await this.fetchOperators()
|
||||||
this.initDefaultDateRange()
|
this.initDefaultDateRange()
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
this.initChart()
|
this.initChart()
|
||||||
@ -200,6 +249,103 @@ export default {
|
|||||||
window.removeEventListener('resize', this.handleResize)
|
window.removeEventListener('resize', this.handleResize)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 添加页面变化处理方法
|
||||||
|
handlePageChange(page) {
|
||||||
|
this.pagination.currentPage = page;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pagination.pageSize = size;
|
||||||
|
this.pagination.currentPage = 1;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取操作员列表
|
||||||
|
async fetchOperators() {
|
||||||
|
try {
|
||||||
|
const response = await getAllPilots()
|
||||||
|
|
||||||
|
let operatorsArray = []
|
||||||
|
|
||||||
|
// 处理不同的响应格式
|
||||||
|
if (Array.isArray(response)) {
|
||||||
|
operatorsArray = response
|
||||||
|
}
|
||||||
|
else if (response.code === 200 && Array.isArray(response.data)) {
|
||||||
|
operatorsArray = response.data
|
||||||
|
}
|
||||||
|
else if (response.data && Array.isArray(response.data.records)) {
|
||||||
|
operatorsArray = response.data.records
|
||||||
|
}
|
||||||
|
else if (response.data && Array.isArray(response.data.list)) {
|
||||||
|
operatorsArray = response.data.list
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建操作员映射表
|
||||||
|
this.operatorsMap = {}
|
||||||
|
operatorsArray.forEach(operator => {
|
||||||
|
const operatorId = operator.id || operator.userId || operator.employeeId
|
||||||
|
if (operatorId) {
|
||||||
|
this.operatorsMap[operatorId] = {
|
||||||
|
name: operator.nickName || operator.realName || operator.name || operator.username || '未知操作员'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取操作员列表失败:', error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getOperatorName(operatorId) {
|
||||||
|
if (operatorId === null || operatorId === undefined || operatorId === '') {
|
||||||
|
return '未分配'
|
||||||
|
}
|
||||||
|
|
||||||
|
let operator = this.operatorsMap[operatorId]
|
||||||
|
|
||||||
|
if (!operator && operatorId) {
|
||||||
|
const stringId = operatorId.toString()
|
||||||
|
operator = this.operatorsMap[stringId]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!operator && operatorId) {
|
||||||
|
const numberId = Number(operatorId)
|
||||||
|
if (!isNaN(numberId)) {
|
||||||
|
operator = this.operatorsMap[numberId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return operator && operator.name ? operator.name : `操作员(${operatorId})`
|
||||||
|
},
|
||||||
|
|
||||||
|
// 状态筛选方法
|
||||||
|
filterStatus(value, row) {
|
||||||
|
return row.orderItemStatus === value
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusTagType(status) {
|
||||||
|
const typeMap = {
|
||||||
|
0: 'info',
|
||||||
|
2: 'success',
|
||||||
|
3: 'danger'
|
||||||
|
}
|
||||||
|
return typeMap[status] || 'info'
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusText(status) {
|
||||||
|
const textMap = {
|
||||||
|
0: '未开始',
|
||||||
|
2: '已完成',
|
||||||
|
3: '已失败'
|
||||||
|
}
|
||||||
|
return textMap[status] || '未知状态'
|
||||||
|
},
|
||||||
|
|
||||||
initDefaultDateRange() {
|
initDefaultDateRange() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const year = now.getFullYear()
|
const year = now.getFullYear()
|
||||||
@ -237,28 +383,29 @@ export default {
|
|||||||
async fetchData() {
|
async fetchData() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
const params = { startDate: this.filter.startDate, endDate: this.filter.endDate }
|
const analysisData = await this.getAnalysisData()
|
||||||
const apiMap = {
|
|
||||||
day: getDailyOrderAnalysis,
|
this.orderDetailList = analysisData.orderDetailList || []
|
||||||
month: getMonthlyOrderAnalysis,
|
|
||||||
year: getYearlyOrderAnalysis
|
// 确保分页数据是数字类型
|
||||||
|
this.pagination = {
|
||||||
|
currentPage: Number(analysisData.currentPage) || Number(analysisData.pageNum) || 1,
|
||||||
|
pageSize: Number(analysisData.pageSize) || Number(analysisData.size) || 10,
|
||||||
|
total: Number(analysisData.total) || this.orderDetailList.length
|
||||||
}
|
}
|
||||||
const res = await apiMap[this.filter.timeRange](params)
|
|
||||||
|
|
||||||
this.stats = {
|
this.stats = {
|
||||||
averageTaskCycle: res.averageTaskCycle || 0,
|
averageTaskCycle: analysisData.averageTaskCycle || 0,
|
||||||
completedTaskCount: res.completedTaskCount || 0,
|
completedTaskCount: analysisData.completedTaskCount || 0,
|
||||||
completionRate: res.completionRate || 0,
|
completionRate: analysisData.completionRate || 0,
|
||||||
droneUsageRate: res.droneUsageRate || 0,
|
droneUsageRate: analysisData.droneUsageRate || 0,
|
||||||
failedRate: res.failedRate || 0,
|
failedRate: analysisData.failedRate || 0,
|
||||||
failedTaskCount: res.failedTaskCount || 0,
|
failedTaskCount: analysisData.failedTaskCount || 0,
|
||||||
notStartedTaskCount: res.notStartedTaskCount || 0,
|
notStartedTaskCount: analysisData.notStartedTaskCount || 0,
|
||||||
processingTaskCount: res.processingTaskCount || 0,
|
processingTaskCount: analysisData.processingTaskCount || 0,
|
||||||
totalTaskCount: res.totalTaskCount || 0
|
totalTaskCount: analysisData.totalTaskCount || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
this.orderDetailList = res.orderDetailList || []
|
|
||||||
|
|
||||||
const keyMap = {
|
const keyMap = {
|
||||||
day: { time: 'date', completed: 'dailyCompletedCount', failed: 'dailyFailedCount' },
|
day: { time: 'date', completed: 'dailyCompletedCount', failed: 'dailyFailedCount' },
|
||||||
month: { time: 'month', completed: 'monthlyCompletedCount', failed: 'monthlyFailedCount' },
|
month: { time: 'month', completed: 'monthlyCompletedCount', failed: 'monthlyFailedCount' },
|
||||||
@ -266,20 +413,54 @@ export default {
|
|||||||
}
|
}
|
||||||
const keys = keyMap[this.filter.timeRange]
|
const keys = keyMap[this.filter.timeRange]
|
||||||
|
|
||||||
|
// 安全处理 timeSeriesData
|
||||||
|
const timeSeriesData = analysisData.timeSeriesData || []
|
||||||
this.chartData = {
|
this.chartData = {
|
||||||
dates: res.timeSeriesData.map(item => item[keys.time]),
|
dates: timeSeriesData.map(item => item[keys.time] || ''),
|
||||||
completed: res.timeSeriesData.map(item => item[keys.completed] || 0),
|
completed: timeSeriesData.map(item => item[keys.completed] || 0),
|
||||||
failed: res.timeSeriesData.map(item => item[keys.failed] || 0)
|
failed: timeSeriesData.map(item => item[keys.failed] || 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateChart()
|
this.updateChart()
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取数据失败:', error)
|
console.error('数据加载失败:', error)
|
||||||
this.$message.error('获取数据失败')
|
let errorMessage = '数据加载失败: '
|
||||||
|
if (error.response && error.response.data && error.response.data.message) {
|
||||||
|
errorMessage += error.response.data.message
|
||||||
|
} else if (error.message) {
|
||||||
|
errorMessage += error.message
|
||||||
|
} else {
|
||||||
|
errorMessage += '未知错误'
|
||||||
|
}
|
||||||
|
this.$message.error(errorMessage)
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getAnalysisData() {
|
||||||
|
const params = {
|
||||||
|
startDate: this.filter.startDate,
|
||||||
|
endDate: this.filter.endDate,
|
||||||
|
page: this.pagination.currentPage,
|
||||||
|
size: this.pagination.pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiMap = {
|
||||||
|
day: getDailyOrderAnalysis,
|
||||||
|
month: getMonthlyOrderAnalysis,
|
||||||
|
year: getYearlyOrderAnalysis
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await apiMap[this.filter.timeRange](params)
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
console.error('API调用失败:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initChart() {
|
initChart() {
|
||||||
this.trendChart = echarts.init(this.$refs.trendChartContainer)
|
this.trendChart = echarts.init(this.$refs.trendChartContainer)
|
||||||
@ -396,21 +577,12 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
refreshData() {
|
refreshData() {
|
||||||
|
this.pagination.currentPage = 1
|
||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
|
|
||||||
handleResize() {
|
handleResize() {
|
||||||
if (this.trendChart) this.trendChart.resize()
|
if (this.trendChart) this.trendChart.resize()
|
||||||
},
|
|
||||||
|
|
||||||
getStatusTagType(status) {
|
|
||||||
const types = ['info', 'primary', 'success']
|
|
||||||
return types[status] || 'info'
|
|
||||||
},
|
|
||||||
|
|
||||||
getStatusText(status) {
|
|
||||||
const texts = ['未开始', '进行中', '已完成']
|
|
||||||
return texts[status] || '未知状态'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,6 +790,21 @@ export default {
|
|||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 */
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.card-grid {
|
.card-grid {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
@ -641,5 +828,24 @@ export default {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.main-content {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-box {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue
Block a user