Files
delivery_manage_front/src/views/index.vue
2026-02-04 08:47:21 +08:00

660 lines
18 KiB
Vue

<template>
<div class="app-container home">
<!-- <el-divider /> -->
<el-row :gutter="20">
<el-col :span="11">
<el-card class="update-log" >
<template v-slot:header>
<div class="titleBox">
<div class="line"></div>
<div class="name">
<div>配送订单总览</div>
<el-date-picker
v-model="dateInventoryTypeObj"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
style="margin: 0 20px;"
/>
<el-button type="primary" size="small" @click="getTotalOverview">搜索</el-button>
</div>
</div>
</template>
<div class="body" id="orderOverview">
</div>
</el-card>
</el-col>
<el-col :span="13">
<el-card class="update-log" >
<template v-slot:header>
<div class="titleBox">
<div class="line"></div>
<div class="name">
<div>配送费统计</div>
<el-date-picker
v-model="twoTimeArr"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
style="margin: 0 20px;"
/>
<el-button type="primary" size="small" @click="getFee">搜索</el-button>
</div>
</div>
</template>
<div class="body" id="orderFee">
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px;">
<el-col :span="13">
<el-card class="update-log" >
<template v-slot:header>
<div class="titleBox">
<div class="line"></div>
<div class="name">
<div>每日订单统计</div>
<!-- <el-date-picker
v-model="dateInventoryTypeObj"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
style="margin: 0 20px;"
/> -->
<el-select v-model="monthValue" placeholder="选择月份" style="width: 200px;margin: 0 20px;">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary" size="small" @click="getDayOrder('search')">搜索</el-button>
</div>
</div>
</template>
<div class="body" id="everyDayCount">
</div>
</el-card>
</el-col>
<el-col :span="11" >
<el-card class="update-log" >
<template v-slot:header>
<div class="titleBox">
<div class="line"></div>
<div class="name">
<div>各类车型配送统计</div>
<el-date-picker
v-model="threeTimeArr"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD"
style="margin: 0 20px;"
/>
<el-button type="primary" size="small" @click="getOrderCarType">搜索</el-button>
</div>
</div>
</template>
<div class="body" id="orderCarType">
</div>
</el-card>
</el-col>
</el-row>
<!-- @click="goAi" -->
<div class="imgBox" ref="iconRef" @mousedown="startDrag" :style="{
left: position.x ? position.x + 'px' :'',
top: position.y + 'px'
}" >
<img src="@/assets/images/rgzn.png" style="width: 100%;height: 100%;" @click="goAi" />
</div>
</div>
</template>
<script setup name="Index">
import * as echarts from 'echarts';
import {getOrderStatus,getDeliveryFee,getOrderCar,everyDayOrder} from "@/api/index/index";
const version = ref('3.9.0')
import { parseTime } from '@/utils/ruoyi'
// import { getTime } from '@/utils/index'
import { get } from '@vueuse/core';
// let statDate = parseTime(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), '{y}-{m}-{d}') // 14天前
// let endDate = parseTime(new Date(), '{y}-{m}-{d}') // 当前时间
let currentDate = new Date();
let currentYear = currentDate.getFullYear();
let monthVal = currentDate.getMonth() + 1;
let statDate = parseTime(new Date(currentYear,monthVal-1,1), '{y}-{m}-{d}')
let endDate = parseTime(new Date(currentYear,monthVal,0), '{y}-{m}-{d}')
// let statDate = parseTime(getTime('start'))
// let endDate = parseTime(getTime(''))
const dateInventoryTypeObj = ref([statDate,endDate]) //第一个接口时间参数
const twoTimeArr = ref([statDate,endDate]) //第二个接口时间参数
const threeTimeArr = ref([statDate,endDate]) //第三个接口、各类车型 时间参数
const fourTimeArr = ref([statDate,endDate]) //第四个接口、每日订单时间参数
const { proxy } = getCurrentInstance()
const options = [
{ value: '01', label: '1月' },
{ value: '02', label: '2月' },
{ value: '03', label: '3月' },
{ value: '04', label: '4月' },
{ value: '05', label: '5月' },
{ value: '06', label: '6月' },
{ value: '07', label: '7月' },
{ value: '08', label: '8月' },
{ value: '09', label: '9月' },
{ value: '10', label: '10月' },
{ value: '11', label: '11月' },
{ value: '12', label: '12月' }
]
const monthValue = ref('')
onMounted(() => {
getTotalOverview()
getFee()
getOrderCarType()
getDayOrder('') //每日订单统计
});
//第一个接口,订单总览
function getTotalOverview(){
const dataArr = {
statDate: dateInventoryTypeObj.value[0],
endDate: dateInventoryTypeObj.value[1]
}
getOrderStatus(dataArr).then(Response => {
const dataInfo = Response.data
const data = [
{name:'已完成',value:dataInfo.signedCount},
{name:'配送中',value:dataInfo.deliveringCount},
{name:'待配送',value:dataInfo.waitCount},
]
getChart(data)
// console.log(Response)
})
}
//第二个接口,各月配送费用
function getFee(){
const dataArr = {
statDate: twoTimeArr.value[0],
endDate: twoTimeArr.value[1]
}
getDeliveryFee(dataArr).then(Response => {
// console.log(Response)
getFeeChart(Response.data)
})
}
//第三个接口,各类车型订单数
function getOrderCarType(){
const dataArr = {
statDate: threeTimeArr.value[0],
endDate: threeTimeArr.value[1]
}
getOrderCar(dataArr).then(Response => {
const dataInfo = Response.data
getCarTypeChart(dataInfo)
// const data = [
// {name:'小车',value:dataInfo.smallCarCount},
// {name:'中车',value:dataInfo.middleCarCount},
// ]
})
}
//第四个接口,每日订单数
function getDayOrder(isSearch){
// monthValue.value = monthVal+'' //下拉框显示
if(isSearch == 'search'){
if(monthValue.value == ''){
proxy.$modal.msgError("请选择月份");
return
}
// console.log(currentYear)
fourTimeArr.value[0] = parseTime(new Date(currentYear,monthValue.value-1,1), '{y}-{m}-{d}')
fourTimeArr.value[1] = parseTime(new Date(currentYear,monthValue.value,0), '{y}-{m}-{d}')
}
else{
monthValue.value = monthVal+''
}
// console.log(11111)
// console.log(dateInventoryTypeObj.vlaue[0])
const dataArr = {
statDate: fourTimeArr.value[0],
endDate: fourTimeArr.value[1]
}
// console.log(dataArr)
everyDayOrder(dataArr).then(Response => {
const dataInfo = Response.data
getEveryDayChart(dataInfo)
})
}
//第一个图表
function getChart(data) {
let chartDom = document.getElementById('orderOverview');
let myChart = echarts.init(chartDom, null, {
// width: 600, // 宽度
height: 300 // 高度
});
// console.log(data)
myChart.setOption({
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '',
type: 'pie',
radius: '50%',
data: data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
});
}
//第二个图表,各月配送费用
function getFeeChart(dataInfo){
// dataInfo = [
// {statMonth:'2025-01',totalActualFee:1000},
// {statMonth:'2025-02',totalActualFee:1221},
// {statMonth:'2025-03',totalActualFee:1543},
// {statMonth:'2025-04',totalActualFee:2000},
// {statMonth:'2025-05',totalActualFee:699},
// {statMonth:'2025-06',totalActualFee:4000},
// {statMonth:'2025-07',totalActualFee:6000},
// {statMonth:'2025-08',totalActualFee:5000},
// {statMonth:'2025-09',totalActualFee:3000},
// {statMonth:'2025-10',totalActualFee:2000},
// {statMonth:'2025-11',totalActualFee:1288},
// {statMonth:'2025-12',totalActualFee:1000},
// ]
var chartDom = document.getElementById('orderFee');
var myChart = echarts.init(chartDom, null, {
// width: 600, // 宽度
height: 300 // 高度
});
var option;
let xAxisData = []
let seriesData = []
if(dataInfo.length > 0){
dataInfo.forEach(item => {
xAxisData.push(item.statMonth)
seriesData.push(item.totalActualFee)
})
}
option = {
xAxis: {
type: 'category',
data: xAxisData,
axisLabel: {
rotate: 30,
},
},
yAxis: {
type: 'value'
},
series: [
{
data: seriesData,
type: 'line',
label: {
show: true, // 显示数值
position: 'top', // 数值显示的位置,可以是'top', 'bottom', 'left', 'right'等
formatter: '{c}',
}
}
]
};
option && myChart.setOption(option);
}
//第三个图表,各类车型订单数
function getCarTypeChart(dataInfo){
let xAxisData = [] //车型
let totalOrder = [] //订单数
let totalActualFee = [] //总费用
let totalKm = [] //总里程
if(dataInfo.length > 0){
dataInfo.forEach(item => {
xAxisData.push(item.vehicleTypeName)
totalOrder.push(item.orderCount)
totalActualFee.push(item.totalActualFee)
totalKm.push(item.totalKm)
})
}
var chartDom = document.getElementById('orderCarType');
var myChart = echarts.init(chartDom, null, {
// width: 600, // 宽度
height: 300 // 高度
});
myChart.setOption({
// title: {
// text: 'World Population'
// },
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
// bottom: '8%',
},
legend: {},
yAxis: {
type: 'value',
boundaryGap: [0, 0.01]
},
xAxis: {
type: 'category',
data: xAxisData,
axisLabel: {
rotate: 30,
},
},
series: [
{
name: '订单数',
type: 'bar',
data: totalOrder
},
{
name: '总费用',
type: 'bar',
data: totalActualFee
},
{
name: '公里数',
type: 'bar',
data: totalKm
}
]
});
}
//第四个图表,每日订单数
function getEveryDayChart(dataInfo){
// let xAxisData = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31] //日期
// let totalOrder = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10] //订单数
// let totalActualFee = [20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20] //总费用
// let totalKm = [30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30] //总里程
let xAxisData = [] //日期
let totalOrder = [] //订单数
let totalActualFee = [] //总费用
let totalKm = [] //总里程
if(dataInfo.length > 0){
dataInfo.forEach(item => {
xAxisData.push(item.statDate)
totalOrder.push(item.orderCount)
totalActualFee.push(item.totalActualFee)
totalKm.push(item.totalKm)
})
}
var chartDom = document.getElementById('everyDayCount');
var myChart = echarts.init(chartDom, null, {
// width: 600, // 宽度
height: 300 // 高度
});
myChart.setOption({
// title: {
// text: 'World Population'
// },
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
// bottom: '8%',
},
legend: {},
yAxis: {
type: 'value',
boundaryGap: [0, 0.01]
},
xAxis: {
type: 'category',
data: xAxisData,
axisLabel: {
// rotate: 50,
},
},
series: [
{
name: '订单数',
type: 'bar',
data: totalOrder
},
{
name: '总费用',
type: 'bar',
data: totalActualFee
},
{
name: '公里数',
type: 'bar',
data: totalKm
}
]
});
}
function goTarget(url) {
window.open(url, '__blank')
}
// 图标元素引用
const iconRef = ref(null)
// 图标当前位置
const position = reactive({ x: 0, y: 300 })
// 拖拽状态
let isDragging = false
let offsetX = 0
let offsetY = 0
let isMove
// 获取边界限制
function getBoundaries() {
if (!iconRef.value) return { minX: 0, maxX: 0, minY: 0, maxY: 0 }
const rect = iconRef.value.getBoundingClientRect()
const width = rect.width
const height = rect.height
// 浏览器视口尺寸
const viewportWidth = window.innerWidth
const viewportHeight = window.innerHeight
return {
minX: 0,
maxX: viewportWidth - width, // 最大 left 值
minY: 0,
maxY: viewportHeight - height // 最大 top 值
}
}
// 开始拖拽
function startDrag(e) {
// console.log(1111)
if (!iconRef.value) return
isDragging = true
isMove = false
const rect = iconRef.value.getBoundingClientRect()
offsetX = e.clientX - rect.left
offsetY = e.clientY - rect.top
e.preventDefault()
}
// 全局鼠标移动监听
function handleMouseMove(e) {
if (!isDragging || !iconRef.value) return
isMove = true
const boundaries = getBoundaries()
let newX = e.clientX - offsetX
let newY = e.clientY - offsetY
// 限制在视口内
// console.log(boundaries.minX+'--'+)
newX = Math.max(boundaries.minX, Math.min(newX, boundaries.maxX))
newY = Math.max(boundaries.minY, Math.min(newY, boundaries.maxY))
position.x = newX
position.y = newY
}
// 停止拖拽
function handleMouseUp() {
// console.log(2222)
// if(!isMove && iconRef.value){
// window.open('http://192.168.1.28:8000/#/chat/index', '_blank')
// }
isDragging = false
}
// 绑定全局事件(组件挂载时)
window.addEventListener('mousemove', handleMouseMove)
window.addEventListener('mouseup', handleMouseUp)
// 可选:组件卸载时清理(防止内存泄漏)
// 在 Vue 3 中,如果使用 <script setup>,可以用 onBeforeUnmount
import { onBeforeUnmount } from 'vue'
onBeforeUnmount(() => {
window.removeEventListener('mousemove', handleMouseMove)
window.removeEventListener('mouseup', handleMouseUp)
})
function goAi(){
// console.log(33333)
// setTimeout(() => {
if(!isMove){
window.open('http://192.168.1.28:8000/#/chat/index', '_blank')
}
// }, 200);
// window.open('http://192.168.1.28:8000/#/chat/index', '_blank')
}
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
ul {
list-style-type: none;
}
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
}
}
.titleBox{
display: flex;
align-items: center;
.line {
width: 6px;
height: 15px;
background: #199793;
border-radius: 12px 12px 12px 12px;
transform: rotateX(360deg);
}
.name{
margin-left: 8px;
display: flex;
align-items: center;
height: 28px;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 20px;
color: #333333;
line-height: 23px;
text-align: left;
font-style: normal;
text-transform: none;
}
}
.imgBox{
width: 40px;
height: 40px;
position:fixed;
right: 0;
// top: 50%;
cursor: pointer;
}
}
</style>