自动检测/手动检测页面

This commit is contained in:
zhujiyan
2024-10-10 17:47:55 +08:00
parent 507ea137e4
commit e060939bc1
30 changed files with 3176 additions and 116 deletions

View File

@@ -0,0 +1,234 @@
<template>
{{ dataSource.length }}
<div
class="scrollContainer"
:key="currentTime"
:style="{ height: `${height}px` }"
>
<div
class="scrollHead"
:style="{
height: headerHeight + 'px',
}"
>
<div v-for="l in columns" :key="l.key" :style="{ width: `${l.width}px` }">
{{ l.title }}
</div>
</div>
<ul
class="scrollBody"
ref="wrapperDom"
:style="{ height: `${height - headerHeight}px` }"
>
<ul ref="childDom1" @mouseenter="handleEnter" @mouseleave="handleLeave">
<li
v-for="(l, i) in dataSource"
:data-key="rowKey ? l[rowKey] : `list${i}`"
:key="rowKey ? l[rowKey] : `list${i}`"
:style="{ height: `${rowHeight}px` }"
>
<div
v-for="(p, c) in columns"
:key="`p${c}`"
:style="getStyle(p, l)"
@click="
(e) => {
e.stopPropagation();
onCellClick(l, p);
onRowClick?.(l);
}
"
>
{{ p?.render?.(i, l, l[p.key]) || l[p.key] }}
</div>
</li>
</ul>
<ul ref="childDom2"></ul>
</ul>
</div>
</template>
<script lang="ts" setup>
import {
onMounted,
watch,
ref,
onBeforeUnmount,
computed,
nextTick,
defineProps,
} from "vue";
const props = defineProps([
"height",
"dataSource",
"columns",
"headerHeight",
"rowHeight",
"onRowClick",
"rowKey",
"scroll",
]);
export interface TableColumn {
key: string;
title: string;
width: number;
render?: (index: number, data: Record<string, any>, text: any) => any;
onClick?: (data: Record<string, any>) => void;
}
// const props = defineProps<ViewProps>()
const { height, columns, rowHeight = 27.5, headerHeight = 36, rowKey } = props;
const wrapperDom = ref<any>();
const childDom1 = ref<any>();
const childDom2 = ref<any>();
const currentTime = ref(new Date().getTime());
let count = 0;
let reqAnimation: number;
onMounted(() => {
nextTick(() => {
reqAnimation = window.requestAnimationFrame(taskStart);
});
});
onBeforeUnmount(() => {
handleEnter();
});
const dataSource = computed(() => {
console.log("dataSource", dataSource);
return props.dataSource;
});
watch(
() => props.dataSource,
() => {
currentTime.value = new Date().getTime();
}
);
const getStyle = (p, l) => {
let pStyle = { width: `${p.width}px` };
if (l.lineColor) {
pStyle["color"] = l.lineColor;
}
return pStyle;
};
//使用滚动表格,自动触发加载数据
const taskStart = () => {
// if (
// childDom1.value?.clientHeight >= wrapperDom.value?.clientHeight &&
// childDom2.value?.clientHeight < 10
// ) {
// childDom2.value.innerHTML = childDom1.value.innerHTML;
// }
// if (wrapperDom.value?.scrollTop >= childDom1.value?.scrollHeight) {
// // wrapperDom.value.scrollTop = 0;
// count = 0;
// }
// else {
count += 1;
wrapperDom.value.scrollTop = count;
// }
if (props.scroll) {
reqAnimation = window.requestAnimationFrame(taskStart);
}
};
const handleEnter = () => {
window.cancelAnimationFrame(reqAnimation);
};
const handleLeave = () => {
reqAnimation = window.requestAnimationFrame(taskStart);
};
const onCellClick = (l: Record<string, any>, p: TableColumn) => {
p?.onClick?.(l);
};
</script>
<style lang="scss" scoped>
.scrollContainer {
width: 100%;
div {
text-align: center;
display: inline-block;
margin: 0;
font-size: 14px;
font-weight: normal;
font-stretch: normal;
letter-spacing: 0;
opacity: 0.9;
}
.scrollHead {
display: flex;
align-items: center;
// background-color: rgba(33, 60, 93, 0.55);
background-color: #3F9EFF;
div {
font-size: 14px;
font-stretch: normal;
letter-spacing: 0;
font-family: MicrosoftYaHei, sans-serif;
font-weight: bold;
color: #ffffff;
opacity: 0.47;
flex:1;
border-left: 1px solid #fff;
}
}
.scrollBody {
overflow-y: scroll;
width: 100%;
scrollbar-width: none;
-ms-overflow-style: none;
ul {
height: auto;
padding: 0;
margin: 0;
}
li {
list-style: none;
position: relative;
cursor: pointer;
display: flex;
height: 36px;
color: #fff;
align-items: center;
}
li div {
line-height: 36px;
color: #24acef;
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 溢出部分隐藏 */
text-overflow: ellipsis; /* 溢出部分用"..."代替 */
flex:1;
border-left: 1px solid #eee;
}
li:hover {
background: rgba(43, 143, 171, 0.52);
> div {
color: #fff;
}
}
&::-webkit-scrollbar {
display: none;
}
li:nth-child(even) {
background-color: rgba(43, 143, 171, 0.13);
}
li:nth-child(even):hover {
background: rgba(43, 143, 171, 0.52);
color: #fff;
}
}
}
</style>

View File

@@ -0,0 +1,141 @@
<template>
<div class="time">
<!-- 自定义预检测图表页面 -->
<div class="time_device" v-for="(item, index) in data" :key="index">
<p>
{{ item.name }}
</p>
<!-- 按顺序执行 -->
<div class="device_children" v-for="(vv, vvs) in item.children">
<div class="item_children" :key="vvs">
<p>正在进行 {{ vv.name }}</p>
</div>
</div>
<!-- 分割线 -->
<div class="time_split_line"></div>
<div class="time_end" v-if="item.children.length == 4">预校验完毕</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineExpose } from "vue";
import { MoreFilled } from "@element-plus/icons-vue";
const activities = [
{
content: "Custom icon",
timestamp: "2018-04-12 20:46",
size: "large",
type: "primary",
icon: MoreFilled,
},
{
content: "Custom color",
timestamp: "2018-04-03 20:46",
color: "#0bbd87",
},
{
content: "Custom size",
timestamp: "2018-04-03 20:46",
size: "large",
},
{
content: "Custom hollow",
timestamp: "2018-04-03 20:46",
type: "primary",
hollow: true,
},
{
content: "Default node",
timestamp: "2018-04-03 20:46",
},
];
const data = ref([]);
const open = (list: any) => {
data.value = list;
console.log(data.value, "99999999");
};
onMounted(() => {
console.log();
});
defineExpose({ open });
</script>
<style lang="scss" scoped>
.time {
width: 100%;
height: 100%;
height: calc(100vh - 260px);
display: flex;
justify-content: space-around;
//设备层
.time_device {
flex: none;
width: 200px;
min-height: 40px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
margin: 0 20px;
position: relative;
background: #fff;
//分割线
.time_split_line {
width: 2px;
// min-height: 50px;
height: 100%;
background-color: #0a47a1;
position: absolute;
left: 49%;
top: 0;
z-index: 0;
}
> p {
text-align: center;
flex: none;
width: 100px;
line-height: 30px;
border: 2px solid blue;
z-index: 999;
background: #fff;
}
//具体执行情况(按顺序执行)
.device_children {
width: 100%;
height: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: #fff;
z-index: 999;
.item_children {
width: 200px;
min-height: 120px;
background: #fff;
display: flex;
justify-content: space-between;
border: 1px solid green;
border-radius: 6px;
z-index: 999;
p {
flex: none;
width: 200px;
text-align: left;
z-index: 999;
}
}
}
.time_end {
width: 100px;
line-height: 30px;
border: 2px solid blue;
z-index: 999;
background: #fff;
}
}
}
</style>

View File

@@ -0,0 +1,272 @@
<!-- 计划管理-预检测页面 -->
<template>
<div class="test">
<!-- 顶部筛选条件&返回按钮 -->
<!-- {{ printText }} -->
<div class="test_top">
<el-checkbox
v-for="(item, index) in detectionOptions"
:model-value="item.id"
:true-value="item.id"
:key="index"
style="pointer-events: none"
>{{ item.name }}</el-checkbox
>
<el-button type="primary" @click="handlePreTest">启动预检测</el-button>
<el-button type="primary" @click="handleBackDeviceList"
>返回设备列表</el-button
>
<el-button type="primary" @click="handleAutoTest">进入检测流程</el-button>
</div>
<div class="test_bot">
<div class="bot_left">
<p v-for="(item, index) in leftDeviceData" :key="index">
{{ item.name }}{{ item.status === 0 ? "异常" : "通过" }}
</p>
</div>
<div class="bot_right">
<div class="right_top">
<p>校验信息</p>
</div>
<div class="right_container">
<div
v-for="(item, index) in leftDeviceData"
:key="index"
class="text_item"
>
<el-divider content-position="left">{{ item.name }}</el-divider>
<Text :text="item.name"></Text>
</div>
</div>
<div class="right_bot"><p>预检测结束</p></div>
<!-- <el-card style="height: 100%">
<template #header>
<div class="card-header">
<span>校验信息</span>
</div>
</template>
<div>
</div>
<template #footer></template>
</el-card> -->
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, nextTick } from "vue";
import { useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import Text from "./text.vue";
const router = useRouter();
const printText = ref(""); // 要显示的文字
const speed = 100; // 打字速度,单位:毫秒
let index = 0;
const str = "这是一段文字这是一段文字这是一段\n文字这是一段文字这是一段文字...";
const typeWriter = () => {
if (index < str.length) {
printText.value += str.charAt(index);
index++;
setTimeout(typeWriter, speed);
}
if (index == str.length) {
printText.value = "";
index = 0;
}
};
const handlePrintText = (text: any, val: any) => {
if (index < text.length) {
leftDeviceData.value[val].name = text.charAt(index);
index++;
setTimeout(typeWriter, speed);
}
// if (index == text.length) {
// printText.value = "";
// index = 0;
// }
};
const leftDeviceData = ref<any>([
// {
// id: 0,
// name: "设备1-预检测",
// status: 0,
// },
// {
// id: 1,
// name: "设备2-预检测",
// status: 1,
// },
// {
// id: 2,
// name: "设备3-预检测",
// status: 1,
// },
// {
// id: 3,
// name: "设备4-预检测",
// status: 0,
// },
// {
// id: 4,
// name: "设备5-预检测",
// status: 1,
// },
// {
// id: 5,
// name: "设备6-预检测",
// status: 0,
// },
]);
const initLeftDeviceData = () => {
leftDeviceData.value.map((item, index) => {
// handlePrintText(item.name, index);
});
};
//定义与预检测配置数组
const detectionOptions = [
{
id: 0,
name: "标准源通讯检测",
},
{
id: 1,
name: "设备通讯检测",
},
{
id: 2,
name: "协议校验",
},
{
id: 3,
name: "数据校对",
},
];
//启动预检测
let timer: any = null;
const handlePreTest = () => {
ElMessage.success("启动预检测");
let count = 0;
if (timer) {
clearInterval(timer);
count = 0;
leftDeviceData.value = [];
}
if (count == 5) {
count = 0;
} else {
timer = setInterval(async () => {
count++;
if (count > 5) return;
await nextTick(() => {
leftDeviceData.value.push({
id: count,
name: "设备" + count + "预检测",
status: count % 2 == 0 ? 0 : 1,
});
});
}, 2000);
}
};
//进入检测流程
const handleAutoTest = () => {
router.push({
path: "/plan/autoTest",
});
};
//返回设备列表
const handleBackDeviceList = () => {
router.push({
path: "/plan/singlePlanList",
});
};
//左侧数据
leftDeviceData.value.map((item: any) => {});
onMounted(() => {
handlePreTest();
typeWriter();
initLeftDeviceData();
});
</script>
<style lang="scss" scoped>
.test {
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
.test_top {
width: 100%;
height: 50px;
display: flex;
background-color: #fff;
justify-content: flex-start;
align-items: center;
border-radius: 4px;
padding: 0 10px;
box-sizing: border-box;
.el-button {
margin-left: 20px;
}
}
.test_bot {
flex: 1;
margin-top: 10px;
display: flex;
.bot_left {
width: 200px;
height: 100%;
background-color: #fff;
border-radius: 6px;
padding: 10px;
box-sizing: border-box;
p {
cursor: pointer;
}
}
.bot_right {
flex: 1;
background-color: #fff;
margin-left: 10px;
max-height: calc(100vh - 240px);
display: flex;
flex-direction: column;
justify-content: space-between;
.right_top {
width: 100%;
height: 50px;
padding: 0 20px;
box-sizing: border-box;
}
.right_container {
flex: 1;
border: 2px solid #eee;
border-left: 0;
border-right: 0;
padding: 0 20px;
box-sizing: border-box;
overflow: auto;
}
.right_bot {
width: 100%;
height: 50px;
padding: 0 20px;
box-sizing: border-box;
}
// .el-card {
// width: 100%;
// height: 100%;
// display: flex;
// flex-direction: column;
// cursor: pointer;
// div {
// width: 100%;
// height: 100px;
// border: 2px solid red;
// }
// }
}
}
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<div>
<p>{{ typedText }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
text: String,
delay: {
type: Number,
default: 1000,
},
});
const typedText = ref("");
let timerId;
function typeText() {
if (props.text.length > typedText.value.length) {
typedText.value = props.text.substring(0, typedText.value.length + 1);
timerId = setTimeout(typeText, props.delay);
}
}
onMounted(() => {
typeText();
});
onUnmounted(() => {
clearTimeout(timerId);
});
</script>