列表自动滚动
This commit is contained in:
@ -55,6 +55,7 @@
|
|||||||
"vue-router": "4.4.5",
|
"vue-router": "4.4.5",
|
||||||
"vue-types": "5.1.3",
|
"vue-types": "5.1.3",
|
||||||
"vue3-print-nb": "^0.1.4",
|
"vue3-print-nb": "^0.1.4",
|
||||||
|
"vue3-scroll-seamless": "^1.0.6",
|
||||||
"vxe-table": "4.5.22"
|
"vxe-table": "4.5.22"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
58
src/api/gis/index.ts
Normal file
58
src/api/gis/index.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
import { QualityVO, Query, ConstructionUserVO, MachineryrVO, MaterialsVO } from './type';
|
||||||
|
/**
|
||||||
|
* 查询大屏质量信息
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getQualityList = (query?: Query): AxiosPromise<QualityVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/quality/qualityInspection/gis',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询施工人员大屏数据
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getConstructionUserList = (query?: Query): AxiosPromise<ConstructionUserVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/project/constructionUser/gis',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询大屏机械列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getMachineryrList = (query?: Query): AxiosPromise<MachineryrVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/machinery/machinery/list/gis',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询大屏材料信息
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getMaterialsList = (query?: Query): AxiosPromise<MaterialsVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/materials/materials/list/gis',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
43
src/api/gis/type.ts
Normal file
43
src/api/gis/type.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
export interface QualityVO {
|
||||||
|
count: number;
|
||||||
|
correctSituation: string;
|
||||||
|
list: Qualitylist[];
|
||||||
|
}
|
||||||
|
export interface Qualitylist {
|
||||||
|
id: number;
|
||||||
|
inspectionTypeLabel: string;
|
||||||
|
inspectionHeadline: string;
|
||||||
|
createTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Query {
|
||||||
|
projectId: string | number;
|
||||||
|
pageSize?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConstructionUserVO {
|
||||||
|
peopleCount: number;
|
||||||
|
attendanceCount: number;
|
||||||
|
attendanceRate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachineryrVO {
|
||||||
|
//机械名称
|
||||||
|
machineryName: string;
|
||||||
|
//机械数量
|
||||||
|
machineryCount: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MaterialsVO {
|
||||||
|
//材料名称
|
||||||
|
materialsName: string;
|
||||||
|
//计量单位
|
||||||
|
weightId: string;
|
||||||
|
//预计材料数量
|
||||||
|
quantityCount: string;
|
||||||
|
//入库数量
|
||||||
|
putCount: string;
|
||||||
|
//出库数量
|
||||||
|
outCount: string;
|
||||||
|
value: number;
|
||||||
|
}
|
@ -49,6 +49,8 @@ VXETable.config({
|
|||||||
// 修改 el-dialog 默认点击遮照为不关闭
|
// 修改 el-dialog 默认点击遮照为不关闭
|
||||||
/*import { ElDialog } from 'element-plus';
|
/*import { ElDialog } from 'element-plus';
|
||||||
ElDialog.props.closeOnClickModal.default = false;*/
|
ElDialog.props.closeOnClickModal.default = false;*/
|
||||||
|
// **main.js**
|
||||||
|
import { vue3ScrollSeamless } from 'vue3-scroll-seamless';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ app.use(print);
|
|||||||
app.use(i18n);
|
app.use(i18n);
|
||||||
app.use(VXETable);
|
app.use(VXETable);
|
||||||
app.use(plugins);
|
app.use(plugins);
|
||||||
|
app.component('vue3ScrollSeamless', vue3ScrollSeamless);
|
||||||
// 自定义指令
|
// 自定义指令
|
||||||
directive(app);
|
directive(app);
|
||||||
|
|
||||||
|
125
src/views/gisHome/component/autoScroller.vue
Normal file
125
src/views/gisHome/component/autoScroller.vue
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auto-scroll-container" @mouseenter="pauseScroll" @mouseleave="resumeScroll" ref="container">
|
||||||
|
<div class="auto-scroll-content" ref="content">
|
||||||
|
<div class="auto-scroll-item" v-for="(item, index) in duplicatedList" :key="index">
|
||||||
|
<slot :item="item">{{ item }}</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
|
||||||
|
// Props
|
||||||
|
const props = defineProps({
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
speed: {
|
||||||
|
type: Number,
|
||||||
|
default: 0.5 // px/frame
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 100 // px
|
||||||
|
},
|
||||||
|
minItems: {
|
||||||
|
type: Number,
|
||||||
|
default: 2 // 小于这个数量不滚动
|
||||||
|
},
|
||||||
|
autoScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true // 控制是否自动滚动
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Refs and Computed
|
||||||
|
const container = ref(null);
|
||||||
|
const content = ref(null);
|
||||||
|
const duplicatedList = computed(() => [...props.items, ...props.items]);
|
||||||
|
const shouldScroll = computed(() => props.items.length >= props.minItems);
|
||||||
|
|
||||||
|
let scrollY = 0;
|
||||||
|
let animationFrameId = null;
|
||||||
|
let manualPaused = false; // 记录是否因为滚轮手动停止
|
||||||
|
|
||||||
|
// 滚动核心逻辑
|
||||||
|
function normalizeScrollY(contentHeight) {
|
||||||
|
if (scrollY <= -contentHeight) scrollY += contentHeight;
|
||||||
|
if (scrollY >= 0) scrollY -= contentHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function step() {
|
||||||
|
const contentHeight = content.value.offsetHeight / 2;
|
||||||
|
scrollY -= props.speed;
|
||||||
|
normalizeScrollY(contentHeight);
|
||||||
|
content.value.style.transform = `translateY(${Math.round(scrollY)}px)`;
|
||||||
|
|
||||||
|
animationFrameId = requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startScroll() {
|
||||||
|
if (!animationFrameId) {
|
||||||
|
animationFrameId = requestAnimationFrame(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseScroll() {
|
||||||
|
cancelAnimationFrame(animationFrameId);
|
||||||
|
animationFrameId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鼠标滚轮事件:手动滚动并停止自动滚动
|
||||||
|
function onWheel(e) {
|
||||||
|
pauseScroll();
|
||||||
|
manualPaused = true; // 标记为手动停止
|
||||||
|
const contentHeight = content.value.offsetHeight / 2;
|
||||||
|
scrollY -= e.deltaY;
|
||||||
|
normalizeScrollY(contentHeight);
|
||||||
|
content.value.style.transform = `translateY(${Math.round(scrollY)}px)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鼠标移出时恢复自动滚动(如果不是手动暂停)
|
||||||
|
function resumeScroll() {
|
||||||
|
if (props.autoScroll && shouldScroll.value) {
|
||||||
|
manualPaused = false; // 重置手动暂停标志
|
||||||
|
startScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
if (shouldScroll.value && props.autoScroll) {
|
||||||
|
startScroll();
|
||||||
|
}
|
||||||
|
container.value.addEventListener('wheel', onWheel);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
pauseScroll();
|
||||||
|
container.value.removeEventListener('wheel', onWheel);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 响应 items 数量变化
|
||||||
|
watch(shouldScroll, (newVal) => {
|
||||||
|
if (!newVal) {
|
||||||
|
pauseScroll();
|
||||||
|
} else if (props.autoScroll && !manualPaused) {
|
||||||
|
startScroll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.auto-scroll-container {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.auto-scroll-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
</style>
|
@ -21,21 +21,30 @@
|
|||||||
<img src="@/assets/images/totalnumber.png" alt="" />
|
<img src="@/assets/images/totalnumber.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<p>总人数</p>
|
<p>总人数</p>
|
||||||
<div class="peopleNum"><span>259</span>人</div>
|
<div class="peopleNum">
|
||||||
|
<span>{{ constructionUserData?.peopleCount }}</span
|
||||||
|
>人
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="iconImg">
|
<div class="iconImg">
|
||||||
<img src="@/assets/images/attendanceperson.png" alt="" />
|
<img src="@/assets/images/attendanceperson.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<p>出勤人</p>
|
<p>出勤人</p>
|
||||||
<div class="peopleNum"><span>259</span>人</div>
|
<div class="peopleNum">
|
||||||
|
<span>{{ constructionUserData?.attendanceCount }}</span
|
||||||
|
>人
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="iconImg">
|
<div class="iconImg">
|
||||||
<img src="@/assets/images/Attendancerate.png" alt="" />
|
<img src="@/assets/images/Attendancerate.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<p>出勤率</p>
|
<p>出勤率</p>
|
||||||
<div class="peopleNum"><span>100</span>%</div>
|
<div class="peopleNum">
|
||||||
|
<span>{{ constructionUserData?.attendanceRate }}</span
|
||||||
|
>%
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
@ -75,20 +84,57 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { getConstructionUserList, getMachineryrList, getMaterialsList } from '@/api/gis';
|
||||||
|
import { ConstructionUserVO, MachineryrVO, MaterialsVO } from '@/api/gis/type';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
|
//echarts节点
|
||||||
|
const myMachineryChart = ref(null);
|
||||||
|
const myOrderChart = ref(null);
|
||||||
|
|
||||||
type EChartsOption = echarts.EChartsOption;
|
type EChartsOption = echarts.EChartsOption;
|
||||||
|
const constructionUserData = ref<ConstructionUserVO>(null);
|
||||||
|
const machineryOption = ref<MachineryrVO[]>([]); //机械
|
||||||
|
const orderOption = ref<MaterialsVO[]>([]); //材料
|
||||||
|
const machineryDataAxis = computed(() => machineryOption.value.map((item) => item.machineryName)); //x轴数据
|
||||||
|
const machineryData = computed(() => machineryOption.value.map((item) => item.machineryCount)); //柱状图数据
|
||||||
|
const orderDataAxis = computed(() => orderOption.value.map((item) => item.materialsName)); //材料x轴数据
|
||||||
|
const orderPutData = computed(() => orderOption.value.map((item) => item.putCount)); //柱状图领用量数据
|
||||||
|
const orderOutData = computed(() => orderOption.value.map((item) => item.outCount)); //柱状图出库量数据
|
||||||
|
const orderRankingData = computed(() => orderOption.value.map((item) => item.value)); //柱状图库存数据
|
||||||
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
|
//获取施工人员信息
|
||||||
|
const getConstructionUserData = async () => {
|
||||||
|
const res = await getConstructionUserList({ projectId: currentProject.value.id });
|
||||||
|
if (res.code !== 200) return;
|
||||||
|
constructionUserData.value = res.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
//查询大屏机械列表
|
||||||
|
const getMachineryData = async () => {
|
||||||
|
const res = await getMachineryrList({ projectId: currentProject.value.id });
|
||||||
|
if (res.code !== 200) return;
|
||||||
|
machineryOption.value = res.data;
|
||||||
|
initMachinerycharts();
|
||||||
|
};
|
||||||
|
|
||||||
|
//查询大屏材料信息
|
||||||
|
const getOrderData = async () => {
|
||||||
|
const res = await getMaterialsList({ projectId: currentProject.value.id });
|
||||||
|
if (res.code !== 200) return;
|
||||||
|
orderOption.value = res.data;
|
||||||
|
initOrderChart();
|
||||||
|
console.log(orderDataAxis);
|
||||||
|
};
|
||||||
|
|
||||||
const initMachinerycharts = () => {
|
const initMachinerycharts = () => {
|
||||||
let chartDom = document.getElementById('machineryMain');
|
let chartDom = document.getElementById('machineryMain');
|
||||||
let myMachineryChart = echarts.init(chartDom);
|
myMachineryChart.value = markRaw(echarts.init(chartDom));
|
||||||
let option: EChartsOption;
|
let option: EChartsOption;
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
let dataAxis = ['水泥机', '搅拌机', '拖拉机', '推土机', '推土机', '推土机','推土机', ];
|
|
||||||
// prettier-ignore
|
|
||||||
let data = [11, 23, 21, 20, 22, 24, 24];
|
|
||||||
|
|
||||||
option = {
|
option = {
|
||||||
title: {
|
title: {
|
||||||
subtext: '单位:台数'
|
subtext: '单位:台数'
|
||||||
@ -99,7 +145,7 @@ const initMachinerycharts = () => {
|
|||||||
bottom: '50vh'
|
bottom: '50vh'
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
data: dataAxis,
|
data: machineryDataAxis.value,
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
// inside: true,
|
// inside: true,
|
||||||
color: 'rgba(202, 218, 226, 1)'
|
color: 'rgba(202, 218, 226, 1)'
|
||||||
@ -163,7 +209,6 @@ const initMachinerycharts = () => {
|
|||||||
},
|
},
|
||||||
showDataShadow: false,
|
showDataShadow: false,
|
||||||
// 手柄大小
|
// 手柄大小
|
||||||
handleSize: 0,
|
|
||||||
showDetail: false, //即拖拽时候是否显示详细数值信息 默认true
|
showDetail: false, //即拖拽时候是否显示详细数值信息 默认true
|
||||||
moveHandleSize: 0, //移动手柄的大小
|
moveHandleSize: 0, //移动手柄的大小
|
||||||
// 滚动条高度
|
// 滚动条高度
|
||||||
@ -190,7 +235,7 @@ const initMachinerycharts = () => {
|
|||||||
},
|
},
|
||||||
start: 0,
|
start: 0,
|
||||||
// 计算初始结束百分比
|
// 计算初始结束百分比
|
||||||
end: (6 / data.length) * 100
|
end: (6 / machineryData.value.length) * 100
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
@ -205,21 +250,19 @@ const initMachinerycharts = () => {
|
|||||||
])
|
])
|
||||||
},
|
},
|
||||||
barWidth: '13vh',
|
barWidth: '13vh',
|
||||||
data: data
|
data: machineryData.value
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
option && myMachineryChart.setOption(option);
|
option && myMachineryChart.value.setOption(option);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initOrderChart = () => {
|
const initOrderChart = () => {
|
||||||
let chartDom = document.getElementById('orderMain');
|
let chartDom = document.getElementById('orderMain');
|
||||||
let myMachineryChart = echarts.init(chartDom);
|
|
||||||
let option: EChartsOption;
|
|
||||||
|
|
||||||
// prettier-ignore
|
myOrderChart.value = markRaw(echarts.init(chartDom));
|
||||||
let data = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
let option: EChartsOption;
|
||||||
|
|
||||||
option = {
|
option = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@ -244,20 +287,21 @@ const initOrderChart = () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
left: '5%', //距离dom间距
|
||||||
right: '4%',
|
right: '4%',
|
||||||
bottom: '0',
|
top: '20%',
|
||||||
containLabel: true,
|
bottom: '1%',
|
||||||
width: '90%'
|
height: '80%'
|
||||||
},
|
},
|
||||||
|
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
data,
|
data: orderDataAxis.value,
|
||||||
offset: 60,
|
offset: 0,
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
@ -266,13 +310,38 @@ const initOrderChart = () => {
|
|||||||
},
|
},
|
||||||
inverse: true,
|
inverse: true,
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
formatter: function (value, index) {
|
formatter: function (value) {
|
||||||
return `{${data[index]}|No.${index + 1}} {value|${value}}`;
|
let bgType = '';
|
||||||
|
let index = orderDataAxis.value.indexOf(value);
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
bgType = 'a';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bgType = 'b';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
bgType = 'c';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return `No.${index + 1} {value|${value}}`;
|
||||||
|
}
|
||||||
|
return `{${bgType}|No.${index + 1}} {value|${value}}`;
|
||||||
},
|
},
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
verticalAlign: 'bottom',
|
||||||
|
yAxisIndex: 0,
|
||||||
|
// 横坐标 分割线等取消显示
|
||||||
|
padding: [0, 10, 10, 6],
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
color: 'rgba(230, 247, 255, 1)',
|
color: 'rgba(230, 247, 255, 1)',
|
||||||
rich: {
|
rich: {
|
||||||
Mon: {
|
a: {
|
||||||
color: 'rgba(230, 247, 255, 1)',
|
color: 'rgba(230, 247, 255, 1)',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
@ -283,7 +352,7 @@ const initOrderChart = () => {
|
|||||||
{ offset: 1, color: 'rgba(255, 208, 59, 0)' }
|
{ offset: 1, color: 'rgba(255, 208, 59, 0)' }
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
Tue: {
|
b: {
|
||||||
color: 'rgba(230, 247, 255, 1)',
|
color: 'rgba(230, 247, 255, 1)',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
@ -294,7 +363,7 @@ const initOrderChart = () => {
|
|||||||
{ offset: 1, color: 'rgba(31, 189, 237, 0)' }
|
{ offset: 1, color: 'rgba(31, 189, 237, 0)' }
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
Wed: {
|
c: {
|
||||||
color: 'rgba(230, 247, 255, 1)',
|
color: 'rgba(230, 247, 255, 1)',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
@ -408,7 +477,7 @@ const initOrderChart = () => {
|
|||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
data: [320, 302, 301, 334, 345, 356, 367],
|
data: orderPutData.value,
|
||||||
barWidth: 3
|
barWidth: 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -421,7 +490,7 @@ const initOrderChart = () => {
|
|||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
data: [120, 132, 101, 134, 152, 103, 150],
|
data: orderOutData.value,
|
||||||
showBackground: true,
|
showBackground: true,
|
||||||
barWidth: 3,
|
barWidth: 3,
|
||||||
backgroundStyle: {
|
backgroundStyle: {
|
||||||
@ -430,12 +499,34 @@ const initOrderChart = () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
option && myMachineryChart.setOption(option);
|
option && myOrderChart.value.setOption(option);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
// 防抖函数
|
||||||
|
const debounce = <T,>(func: (this: T, ...args: any[]) => void, delay: number) => {
|
||||||
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
return function (this: T, ...args: any[]) {
|
||||||
|
const context = this;
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
func.apply(context, args);
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 窗口大小变化时触发的函数
|
||||||
|
const handleResize = () => {
|
||||||
|
myMachineryChart.value && myMachineryChart.value.dispose();
|
||||||
|
myOrderChart.value && myOrderChart.value.dispose();
|
||||||
initMachinerycharts();
|
initMachinerycharts();
|
||||||
initOrderChart();
|
initOrderChart();
|
||||||
|
};
|
||||||
|
const debouncedHandleResize = debounce(handleResize, 300);
|
||||||
|
onMounted(() => {
|
||||||
|
getOrderData();
|
||||||
|
getConstructionUserData();
|
||||||
|
getMachineryData();
|
||||||
|
window.addEventListener('resize', debouncedHandleResize); //监听窗口变化重新生成echarts
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -17,19 +17,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="events">
|
<div class="events">
|
||||||
<div class="content events-content event_s">
|
<div class="content events-content event_s">
|
||||||
<ul
|
<ul class="events-list">
|
||||||
class="events-list"
|
<!-- <li v-for="(item, index) in events" :key="index">
|
||||||
@mouseenter.native="autoScrollTable(true, 'projectRef')"
|
|
||||||
@mouseleave.native="autoScrollTable(false, 'projectRef')"
|
|
||||||
id="event_scroll"
|
|
||||||
ref="projectScroll"
|
|
||||||
>
|
|
||||||
<li v-for="(item, index) in events" :key="index">
|
|
||||||
<span class="text detail" style="display: inline"> {{ item.headline }}...</span>
|
<span class="text detail" style="display: inline"> {{ item.headline }}...</span>
|
||||||
<span class="more" v-if="!item.show" @click="onMore(item, true)">查看详情</span>
|
<span class="more" v-if="!item.show" @click="onMore(item, true)">查看详情</span>
|
||||||
<span class="more" style="color: #ffb100eb" v-else @click="onMore(item, false)">关闭详情</span>
|
<span class="more" style="color: #ffb100eb" v-else @click="onMore(item, false)">关闭详情</span>
|
||||||
</li>
|
</li> -->
|
||||||
</ul>
|
</ul>
|
||||||
|
<AutoScroller :items="events" class="events-list">
|
||||||
|
<template #default="{ item }">
|
||||||
|
<li>
|
||||||
|
<span class="text detail" style="display: inline"> {{ item.headline }}...</span>
|
||||||
|
<span class="more" v-if="!item.show" @click="onMore(item, true)">查看详情</span>
|
||||||
|
<span class="more" style="color: #ffb100eb" v-else @click="onMore(item, false)">关闭详情</span>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</AutoScroller>
|
||||||
<!-- <span v-else style="font-size: 20px; letter-spacing: 10px">暂无数据</span> -->
|
<!-- <span v-else style="font-size: 20px; letter-spacing: 10px">暂无数据</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -93,31 +96,28 @@
|
|||||||
<el-table-column prop="status" label="操作" />
|
<el-table-column prop="status" label="操作" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<AutoScroller :items="safetyData" class="tbody">
|
||||||
class="tbody"
|
<template #default="{ item }">
|
||||||
ref="tableScroll"
|
<el-table
|
||||||
@mouseenter.native="autoScrollTable(true, 'tableRef')"
|
:data="safetyData"
|
||||||
@mouseleave.native="autoScrollTable(false, 'tableRef')"
|
stripe
|
||||||
>
|
row-class-name="bg-transparent"
|
||||||
<el-table
|
cell-class-name="bg-transparent"
|
||||||
:data="safetyData"
|
header-row-class-name="header-row-bg-transparent"
|
||||||
stripe
|
header-cell-class-name="bg-transparent"
|
||||||
row-class-name="bg-transparent"
|
style="--el-table-border-color: none"
|
||||||
cell-class-name="bg-transparent"
|
>
|
||||||
header-row-class-name="header-row-bg-transparent"
|
<el-table-column prop="teamName" label="" class-name="teamNameWidth" />
|
||||||
header-cell-class-name="bg-transparent"
|
<el-table-column prop="name" label="" class-name="nameWidth" />
|
||||||
style="--el-table-border-color: none"
|
<el-table-column prop="meetingDate" label="" class-name="meetingDateWidth" />
|
||||||
>
|
<el-table-column prop="status" label="" class-name="statusWidth">
|
||||||
<el-table-column prop="teamName" label="" />
|
<template #default="scope">
|
||||||
<el-table-column prop="name" label="" />
|
<el-link :underline="false">查看</el-link>
|
||||||
<el-table-column prop="meetingDate" label="" />
|
</template>
|
||||||
<el-table-column prop="status" label="">
|
</el-table-column>
|
||||||
<template #default="scope">
|
</el-table>
|
||||||
<el-link type="primary" :underline="false">查看</el-link>
|
</template>
|
||||||
</template>
|
</AutoScroller>
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
@ -141,30 +141,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="qualityNum">
|
<div class="qualityNum">
|
||||||
<div>巡检记录 <b></b></div>
|
<div>巡检记录 <b></b></div>
|
||||||
<p>14<span>件</span></p>
|
<p>{{ qualityData?.count }}<span>件</span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="qualityNum ml-15">
|
<div class="qualityNum ml-15">
|
||||||
<div>整改情况 <b></b></div>
|
<div>整改情况 <b></b></div>
|
||||||
<p>20<span>%</span></p>
|
<p>{{ qualityData?.correctSituation }}<span>%</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<AutoScroller :items="qualityData?.list" class="qualityList">
|
||||||
class="qualityList"
|
<template #default="{ item }">
|
||||||
@mouseenter.native="autoScrollTable(true, 'qualityRef')"
|
<div class="qualityItem flex items-center">
|
||||||
@mouseleave.native="autoScrollTable(false, 'qualityRef')"
|
<div>
|
||||||
ref="qualityScroll"
|
<img src="@/assets/images/timeIcon.png" alt="" />
|
||||||
>
|
<span class="text-white">{{ item.createTime }}</span>
|
||||||
<div class="qualityItem flex items-center" v-for="item in 6">
|
</div>
|
||||||
<div>
|
<div class="text-#43E2CB record">{{ item.inspectionTypeLabel }}</div>
|
||||||
<img src="@/assets/images/timeIcon.png" alt="" />
|
<div class="text-#E6F7FF text-truncate">
|
||||||
<span class="text-white">2024-11-15</span>
|
<el-tooltip :content="item.inspectionHeadline" placement="top"> {{ item.inspectionHeadline }}</el-tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-#43E2CB record">巡检记录</div>
|
</template>
|
||||||
<div class="text-#E6F7FF text-truncate">
|
</AutoScroller>
|
||||||
<el-tooltip content="桩基钻孔深度、直径不足11111111" placement="top"> 桩基钻孔深度、直径不足</el-tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
@ -189,7 +186,12 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
//页面高度
|
|
||||||
|
import { QualityVO } from '@/api/gis/type';
|
||||||
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getQualityList } from '@/api/gis';
|
||||||
|
import AutoScroller from './autoScroller.vue';
|
||||||
|
const userStore = useUserStoreHook();
|
||||||
type EChartsOption = echarts.EChartsOption;
|
type EChartsOption = echarts.EChartsOption;
|
||||||
const option = ref<EChartsOption>(null);
|
const option = ref<EChartsOption>(null);
|
||||||
const myMachineryChart = ref(null);
|
const myMachineryChart = ref(null);
|
||||||
@ -210,13 +212,23 @@ const scrollList = reactive({
|
|||||||
intervalId: null
|
intervalId: null
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const autoScrollTable = (isAuto, ref) => {
|
|
||||||
if (isAuto) {
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
clearInterval(scrollList[ref].intervalId);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
} else {
|
const qualityData = ref<QualityVO>({ list: [], correctSituation: null, count: null });
|
||||||
startScroll(ref);
|
const classOptions = {
|
||||||
}
|
limitMoveNum: 3,
|
||||||
|
hoverStop: true,
|
||||||
|
step: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//获取质量信息
|
||||||
|
const getQualityData = async () => {
|
||||||
|
const res = await getQualityList({ projectId: currentProject.value.id });
|
||||||
|
if (res.code !== 200) return;
|
||||||
|
qualityData.value = res.data;
|
||||||
|
};
|
||||||
|
|
||||||
const events = ref([
|
const events = ref([
|
||||||
{
|
{
|
||||||
'id': 23,
|
'id': 23,
|
||||||
@ -390,23 +402,6 @@ const initUserChart = () => {
|
|||||||
option.value && myMachineryChart.value.setOption(option.value);
|
option.value && myMachineryChart.value.setOption(option.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
//开始滚动
|
|
||||||
const startScroll = (ref) => {
|
|
||||||
const { dom } = scrollList[ref];
|
|
||||||
const scrollContainer = dom.parentNode;
|
|
||||||
scrollList[ref].intervalId = setInterval(() => {
|
|
||||||
dom.scrollTop += 1;
|
|
||||||
|
|
||||||
if (dom.scrollHeight == dom.clientHeight + dom.scrollTop) {
|
|
||||||
dom.scrollTop = 0;
|
|
||||||
}
|
|
||||||
}, 50);
|
|
||||||
};
|
|
||||||
//停止滚动
|
|
||||||
const stopScroll = (intervalId) => {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
const debounce = <T,>(func: (this: T, ...args: any[]) => void, delay: number) => {
|
const debounce = <T,>(func: (this: T, ...args: any[]) => void, delay: number) => {
|
||||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||||
@ -429,19 +424,11 @@ const debouncedHandleResize = debounce(handleResize, 300);
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initUserChart();
|
initUserChart();
|
||||||
console.log(scrollList, 'scrollList');
|
getQualityData();
|
||||||
|
|
||||||
window.addEventListener('resize', debouncedHandleResize);
|
window.addEventListener('resize', debouncedHandleResize);
|
||||||
for (const key in scrollList) {
|
|
||||||
startScroll(key);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
for (const key in scrollList) {
|
|
||||||
stopScroll(scrollList[key].intervalId);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.removeEventListener('resize', debouncedHandleResize);
|
window.removeEventListener('resize', debouncedHandleResize);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -617,8 +604,9 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.qualityList {
|
.qualityList {
|
||||||
margin-left: vw(21);
|
margin-left: vw(21);
|
||||||
|
display: block;
|
||||||
height: vh(90);
|
height: vh(90);
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
margin-right: vw(10);
|
margin-right: vw(10);
|
||||||
font-size: vw(14);
|
font-size: vw(14);
|
||||||
.qualityItem {
|
.qualityItem {
|
||||||
@ -682,12 +670,12 @@ p {
|
|||||||
height: vh(82);
|
height: vh(82);
|
||||||
.events-list {
|
.events-list {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
padding-right: vw(10);
|
padding-right: vw(10);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
> li {
|
li {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-left: vw(20);
|
padding-left: vw(20);
|
||||||
background: url('@/assets/images/li.png') no-repeat 0 20%;
|
background: url('@/assets/images/li.png') no-repeat 0 20%;
|
||||||
@ -724,11 +712,11 @@ p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> li:last-child {
|
// li:last-child {
|
||||||
margin-bottom: 0;
|
// margin-bottom: 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
> li::after {
|
li::after {
|
||||||
content: '';
|
content: '';
|
||||||
border-left: vw(1) dashed rgba(0, 190, 247, 0.3);
|
border-left: vw(1) dashed rgba(0, 190, 247, 0.3);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -739,10 +727,10 @@ p {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
> li:last-child::after {
|
// li:last-child::after {
|
||||||
content: '';
|
// content: '';
|
||||||
border-left: none;
|
// border-left: none;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +751,7 @@ p {
|
|||||||
|
|
||||||
.tbody {
|
.tbody {
|
||||||
height: vh(94);
|
height: vh(94);
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
padding-right: vw(14);
|
padding-right: vw(14);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,10 +769,22 @@ p {
|
|||||||
border: none; //这是设置透明边框
|
border: none; //这是设置透明边框
|
||||||
color: rgba(255, 255, 255, 1); //这是设置字体颜色
|
color: rgba(255, 255, 255, 1); //这是设置字体颜色
|
||||||
font-size: vw(12);
|
font-size: vw(12);
|
||||||
text-align: center;
|
text-align: left;
|
||||||
padding: vh(4) 0;
|
padding: vh(4) 0;
|
||||||
height: vh(26) !important;
|
height: vh(26) !important;
|
||||||
}
|
}
|
||||||
|
.nameWidth {
|
||||||
|
width: vw(114);
|
||||||
|
}
|
||||||
|
.meetingDateWidth {
|
||||||
|
width: vw(114);
|
||||||
|
}
|
||||||
|
.statusWidth {
|
||||||
|
width: vw(44);
|
||||||
|
}
|
||||||
|
.teamNameWidth {
|
||||||
|
width: vw(114);
|
||||||
|
}
|
||||||
|
|
||||||
.el-table__row--striped {
|
.el-table__row--striped {
|
||||||
background: transparent !important; //这是设置透明背景色
|
background: transparent !important; //这是设置透明背景色
|
||||||
@ -815,6 +815,8 @@ p {
|
|||||||
/* 滚动条整体样式 */
|
/* 滚动条整体样式 */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: vw(6);
|
width: vw(6);
|
||||||
|
display: none;
|
||||||
|
|
||||||
/* 纵向滚动条宽度 */
|
/* 纵向滚动条宽度 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<AutoScroller :items="list2" :speed="0.7" class="h25" />
|
||||||
|
<!-- <AutoScroller :items="list2" :height="150" :speed="1.2" /> -->
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Index" lang="ts">
|
<script setup name="Index" lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import AutoScroller from './gisHome/component/autoScroller.vue';
|
||||||
|
|
||||||
|
const list1 = ['列表1 - 内容 A', '列表1 - 内容 B', '列表1 - 内容 C'];
|
||||||
|
|
||||||
|
const list2 = [
|
||||||
|
'列表2 - 第一条长内容测试',
|
||||||
|
'列表2 - 第二条长长长内容继续测试',
|
||||||
|
'列表2 - 第三条内容',
|
||||||
|
'列表2 - 第一条长内容测试',
|
||||||
|
'列表2 - 第二条长长长内容继续测试',
|
||||||
|
'列表2 - 第三条内容',
|
||||||
|
'列表2 - 第一条长内容测试',
|
||||||
|
'列表2 - 第二条长长长内容继续测试',
|
||||||
|
'列表2 - 第三条内容'
|
||||||
|
];
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// 模拟数据
|
// 模拟数据
|
||||||
|
Reference in New Issue
Block a user