feat:添加现场大屏整体框架,完成现场大屏承包商项目信息、AI报警情况以及特殊作业情况的静态页面绘画

This commit is contained in:
Vce 2024-06-12 22:11:48 +08:00
parent 809e3a1f34
commit c908c79e55
16 changed files with 1094 additions and 5 deletions

31
package-lock.json generated
View File

@ -56,6 +56,7 @@
"devDependencies": {
"@commitlint/cli": "^17.0.1",
"@commitlint/config-conventional": "^17.0.0",
"@types/echarts": "^4.9.22",
"@types/node": "^17.0.31",
"@types/sortablejs": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^5.22.0",
@ -3186,6 +3187,15 @@
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz",
"integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ=="
},
"node_modules/@types/echarts": {
"version": "4.9.22",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@types/echarts/-/echarts-4.9.22.tgz",
"integrity": "sha512-7Fo6XdWpoi8jxkwP7BARUOM7riq8bMhmsCtSG8gzUcJmFhLo387tihoBYS/y5j7jl3PENT5RxeWZdN9RiwO7HQ==",
"dev": true,
"dependencies": {
"@types/zrender": "*"
}
},
"node_modules/@types/eslint": {
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.0.tgz",
@ -3287,6 +3297,12 @@
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"node_modules/@types/zrender": {
"version": "4.0.6",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@types/zrender/-/zrender-4.0.6.tgz",
"integrity": "sha512-1jZ9bJn2BsfmYFPBHtl5o3uV+ILejAtGrDcYSpT4qaVKEI/0YY+arw3XHU04Ebd8Nca3SQ7uNcLaqiL+tTFVMg==",
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.7.tgz",
@ -18822,6 +18838,15 @@
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz",
"integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ=="
},
"@types/echarts": {
"version": "4.9.22",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@types/echarts/-/echarts-4.9.22.tgz",
"integrity": "sha512-7Fo6XdWpoi8jxkwP7BARUOM7riq8bMhmsCtSG8gzUcJmFhLo387tihoBYS/y5j7jl3PENT5RxeWZdN9RiwO7HQ==",
"dev": true,
"requires": {
"@types/zrender": "*"
}
},
"@types/eslint": {
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.0.tgz",
@ -18923,6 +18948,12 @@
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"@types/zrender": {
"version": "4.0.6",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@types/zrender/-/zrender-4.0.6.tgz",
"integrity": "sha512-1jZ9bJn2BsfmYFPBHtl5o3uV+ILejAtGrDcYSpT4qaVKEI/0YY+arw3XHU04Ebd8Nca3SQ7uNcLaqiL+tTFVMg==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.59.7",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.7.tgz",

View File

@ -68,6 +68,7 @@
"devDependencies": {
"@commitlint/cli": "^17.0.1",
"@commitlint/config-conventional": "^17.0.0",
"@types/echarts": "^4.9.22",
"@types/node": "^17.0.31",
"@types/sortablejs": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^5.22.0",

View File

@ -28,6 +28,7 @@ export const BASE_IMAGE_URL = import.meta.env.VITE_BASE_IMAGE_URL;
// export const COMPANY: string = "zsbf"; //中水北方
// export const COMPANY: string = "as"; //鞍山项目
// export const COMPANY: string = "agjt"; //鞍钢集团
export const COMPANY: string = "agjtLive"; //鞍钢集团现场大屏
// export const COMPANY: string = "agjtCommand"; //鞍钢集团指挥部大屏
// export const COMPANY: string = "slx"; //苏立信项目
// export const COMPANY: string = "hfqc"; //合肥启程项目
@ -37,4 +38,4 @@ export const BASE_IMAGE_URL = import.meta.env.VITE_BASE_IMAGE_URL;
// export const COMPANY: string = "phmw"; //鄱湖美湾医疗、医美产业集群项目 (需要去src\routers\modules\staticRouter.ts更换首页)
// export const COMPANY: string = "xjnb"; // 新建宁波项目
// export const COMPANY: string = "ahsa"; // 安徽水安项目
export const COMPANY: string = "zkax"; // 中科安信项目
// export const COMPANY: string = "zkax"; // 中科安信项目

View File

@ -1321,7 +1321,7 @@ export const ZHZRFMenu: Array<any> = [
},
]; //中海·臻如府
// 中科安信大屏
export const ZKAXMenu: Array<any> = [
{
moduleName: "首页概览",
@ -1343,4 +1343,4 @@ export const ZKAXMenu: Array<any> = [
moduleName: "进度计划",
modulePath: "/schedulePlan"
}
];
]; //中科安信大屏

View File

@ -24,8 +24,8 @@ export const staticRouter: RouteRecordRaw[] = [
{
path: "/large",
name: "大屏",
component: () => import("@/views/sevenLargeScreen/indexL.vue"), //七参数标准版
// component: () => import("@/views/commandScreen/indexCommand.vue"), //指挥部大屏
// component: () => import("@/views/sevenLargeScreen/indexL.vue"), //七参数标准版
component: () => import("@/views/commandScreen/indexCommand.vue"), //指挥部大屏
// component: () => import("@/views/sevenLargeScreen/indexL_syhy.vue"), // 只有一级路由(盘锦、嘉兴、鄱湖美湾医疗项目需切换至该首页)
children: [
{
@ -269,6 +269,11 @@ export const staticRouter: RouteRecordRaw[] = [
path: "/commandScreen",
name: "指挥部大屏",
component: () => import("@/views/commandScreen/commandCenter/index.vue")
},
{
path: "/liveScreen",
name: "现场大屏",
component: () => import("@/views/commandScreen/liveScreen/index.vue")
}
],
meta: {

View File

@ -5,6 +5,7 @@
<div class="header">
<span class="projectTitle">
<p v-if="COMPANY === 'agjtCommand'">指挥部大屏</p>
<p v-if="COMPANY === 'agjtLive'">现场大屏</p>
</span>
<div class="leftIcon">
<div class="info">数字化项目监管平台</div>
@ -69,6 +70,13 @@ let agjtCommandList = ref([
modulePath: "/commandScreen"
}
]);
//
let agjtLiveList = ref([
{
moduleName: "现场大屏",
modulePath: "/liveScreen"
}
]);
const itemList = ref([]);
const activeTab = ref(0);
@ -100,6 +108,10 @@ onMounted(async () => {
// menuList.value = AGJTCommandMenu;
menuList.value = agjtCommandList.value;
}
if (COMPANY === "agjtLive") {
// menuList.value = AGJTCommandMenu;
menuList.value = agjtLiveList.value;
}
//token
//
if (window.location.href.indexOf("token") != -1) {
@ -194,6 +206,9 @@ function jumpBgd() {
if(COMPANY === "agjtCommand"){
window.location.replace("http://47.93.215.234:9809" + "/#/login?token=" + store.token);
}
if(COMPANY === "agjtLive"){
window.location.replace("http://47.93.215.234:9809" + "/#/login?token=" + store.token);
}
}
</script>

View File

@ -0,0 +1,40 @@
<template>
<div class="centerBottomLeft">
<Card title="劳务实名制">
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { ref, watch, onMounted } from "vue";
import { getStageOption } from "@/api/modules/projectOverview";
import { GlobalStore } from "@/stores";
</script>
<style lang="scss" scoped>
.centerBottomLeft {
width: 100%;
height: 100%;
}
::v-deep .h-card .content {
height: 80%;
margin-top: 4%;
}
.notoDta {
bottom: 10%;
width: 20%;
left: 35%;
text-align: center;
position: absolute;
img {
width: 40%;
}
div {
color: #fff;
font-size: 14px;
}
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<div class="centerBottomRight">
<Card title="质量待办">
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { ref, watch, onMounted } from "vue";
import { getStageOption } from "@/api/modules/projectOverview";
import { GlobalStore } from "@/stores";
</script>
<style lang="scss" scoped>
.centerBottomRight {
width: 100%;
height: 100%;
}
::v-deep .h-card .content {
height: 80%;
margin-top: 4%;
}
.notoDta {
bottom: 10%;
width: 20%;
left: 35%;
text-align: center;
position: absolute;
img {
width: 40%;
}
div {
color: #fff;
font-size: 14px;
}
}
</style>

View File

@ -0,0 +1,374 @@
<template>
<div class="centerTop">
<Card title="安全教育">
<div class="top-tab" v-if="COMPANY === 'agjt'">
<div
class="tab-box"
:style="boxStyle(item)"
v-for="(item, index) in topText2"
:key="item.id"
@click="activeBtn(item, index)"
>
{{ item.title }}
</div>
</div>
<div class="top-tab" v-else>
<div
class="tab-box"
:style="boxStyle(item)"
v-for="(item, index) in topText"
:key="item.id"
@click="activeBtn(item, index)"
>
{{ item.title }}
</div>
</div>
<div class="href-content" v-if="showVideo == 1">
<el-carousel indicator-position="none" height="450px" style="width: 76%;">
<el-carousel-item v-for="(item, index) in videoList" :key="item.id">
<ckplayerComp
:name="index"
:poster="''"
:deviceIp="`http://${item.account}:${item.password}`"
:videoUrls="item.serialNumber"
:autoPlay="true"
></ckplayerComp>
</el-carousel-item>
</el-carousel>
</div>
<div class="videoBox" v-if="showVideo == 2" @mouseenter="showChangeVideo = true" @mouseleave="showChangeVideo = false">
<el-upload
:action="BASEURL + '/upload/image'"
:on-success="file => handleSuccessTwo(file, 1)"
:on-error="file => handleError(file, 1)"
:beforeUpload="file => handleBeforeUploadVideo(file, 1)"
name="files"
:show-file-list="false"
>
<!-- 更换视频 -->
<span class="change-video" v-if="showChangeVideo">更换视频</span>
</el-upload>
<video :src="BASEURL + '/image/' + projectData.videoUrl" class="videos" autoplay controls loop></video>
</div>
<div class="imgBox" v-if="showVideo == 3">
<div class="imgs" @mouseenter="showChangeImg = true" @mouseleave="showChangeImg = false">
<el-upload
:action="BASEURL + '/upload/image'"
:on-success="file => handleSuccess(file, 1)"
:on-error="file => handleError(file, 1)"
:beforeUpload="file => handleBeforeUploadPic(file, 1)"
name="files"
:show-file-list="false"
>
<!-- 更换图片 -->
<span class="change-video" v-if="showChangeImg">更换图片</span>
</el-upload>
<img :src="BASEURL + '/image/' + picUrl" alt="" />
</div>
</div>
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { ref, onMounted, watch } from "vue";
import { GlobalStore } from "@/stores";
import { ElMessage } from "element-plus";
import { editProjectInfo, eidtProjectShowConfig, queryBySnData } from "@/api/modules/projectOverview";
import { selectLiveVideoListApi } from "@/api/modules/video";
import ckplayerComp from "./ckplayerComp.vue";
import { COMPANY } from "@/config/config";
const store = GlobalStore();
const videoList = ref([] as any);
// ts
type Props = {
projectData?: any; //
};
// withDefaults ()
const props = withDefaults(defineProps<Props>(), {
projectData: {}
});
//
const projectData = ref({} as any);
watch(
() => props.projectData,
newVal => {
if (newVal) {
// props.xData = newVal;
projectData.value = newVal;
}
}
);
//
const picUrl = ref("" as any);
const BASEURL = import.meta.env.VITE_API_URL;
//
const showVideo = ref(1 as any);
//
const showChangeImg = ref(false as any);
//
const showChangeVideo = ref(false as any);
let topText2 = ref([
{ id: 1, title: "现场视频", isActive: true },
{ id: 2, title: "宣传视频", isActive: false },
{ id: 3, title: "效果图", isActive: false }
]);
let topText = ref([
// { id: 1, title: "", isActive: true },
{ id: 2, title: "宣传视频", isActive: true },
{ id: 3, title: "效果图", isActive: false }
]);
const getVideoList = async (showLoading: boolean) => {
let res: any = await selectLiveVideoListApi({
projectSn: store.sn
},showLoading);
if(res.result && res.result.extend1){
videoList.value = JSON.parse(res.result.extend1).result.videoList;
// 使
setTimeout(() => {
// video
var videos = document.querySelectorAll(".href-content video")
// var videos = document.getElementsByTagName("video");
// video
for (var i = 0; i < videos.length; i++) {
//
videos[i].style.width = "99.9%";
videos[i].style.height = "99.9%";
}
}, 2000);
}
};
function boxStyle(item: any) {
if (item.isActive) {
let choiseStyle = {
color: "#fff"
};
return choiseStyle;
}
return {};
}
let tabIndex = ref(1 as any);
function activeBtn(item: any) {
let currentState = item.isActive;
if (!currentState) {
topText.value.forEach(el => {
el.isActive = false;
});
item.isActive = !currentState;
tabIndex.value = item.id;
}
showVideo.value = item.id;
}
const uploadFail = () => {
ElMessage({
showClose: true,
message: "上传失败,请重试",
type: "warning"
});
};
const fileTypeFail = (text: any) => {
ElMessage({
showClose: true,
message: text,
type: "warning"
});
};
const uploadSuccess = () => {
ElMessage({
showClose: true,
message: "上传成功",
type: "success"
});
};
//
function handleBeforeUploadVideo(file: any) {
let fileType = file.type.split("/")[0];
if (fileType == "video") {
return true;
} else {
fileTypeFail("请选择正确的视频文件"); //""
return false;
}
}
//
function handleBeforeUploadPic(file: any) {
let fileType = file.type.split("/")[0];
if (fileType == "image") {
return true;
} else {
fileTypeFail("请选择正确的图片文件"); //""
return false;
}
}
//
function handleError(file: any) {
uploadFail(); //""
}
//
function handleSuccess(file: any) {
if (file.code == 200 || file.status == "SUCCESS") {
let url = file.data[0].imageUrl;
saveEffectData(url);
}
}
//
function handleSuccessTwo(file: any) {
if (file.code == 200 || file.status == "SUCCESS") {
let url = file.data[0].imageUrl;
// this.imgUrl = url;
saveOrDeleteVideo(url);
}
}
//
function saveEffectData(url: any) {
// let configValue = JSON.stringify(url);
let data = {
projectSn: store.sn,
showType: 3,
showTitle: "效果图", //''
configValue: url
};
eidtProjectShowConfig(data).then((res: any) => {
if (res.code == 200) {
getQueryBySnData();
}
});
}
//
function getQueryBySnData() {
queryBySnData({
projectSn: store.sn,
showType: 3
}).then((res: any) => {
if (res.result) {
picUrl.value = res.result.configValue;
}
});
}
// //
function saveOrDeleteVideo(url) {
editProjectInfo({
projectSn: store.sn,
videoUrl: url
}).then(res => {
uploadSuccess(); //""
projectData.value.videoUrl = url;
});
}
//
defineExpose({
getQueryBySnData
})
onMounted(async () => {
if(COMPANY !== 'agjt') showVideo.value = 2
await getVideoList();
getQueryBySnData();
if(COMPANY != 'agjt'){
showVideo.value = 2;
}
});
</script>
<style lang="scss" scoped>
.centerTop {
width: 100%;
height: 100%;
position: relative;
.videoBox {
width: 100%;
height: 92%;
margin-top: 8%;
background: url("@/assets/images/comprehensiveManage/project10.png") no-repeat;
background-size: 100% 100%;
.videos {
width: 78%;
height: 90%;
margin-left: 11%;
margin-top: 1%;
}
}
.imgBox {
width: 100%;
height: 92%;
margin-top: 8%;
background: url("@/assets/images/comprehensiveManage/project10.png") no-repeat;
background-size: 100% 100%;
.imgs {
width: 78%;
height: 82%;
margin: 3% 11%;
img {
width: 100%;
height: 100%;
margin-top: 5%;
}
}
}
.href-content {
width: 100%;
height: 92%;
margin-top: 8%;
background: url("@/assets/images/comprehensiveManage/project10.png") no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
// .href-content {
// width: 95%;
// height: 92%;
// margin: 0 auto;
// margin-top: 8%;
// }
.change-video {
position: absolute;
background: url("@/assets/images/cardImg.png") no-repeat;
background-size: 100% 100%;
color: #fff;
padding: 1% 2%;
font-size: 16px;
left: 45%;
top: 55%;
z-index: 10;
}
.top-tab {
position: absolute;
top: 12%;
width: 100%;
box-sizing: border-box;
padding: 0 30%;
display: flex;
justify-content: space-around;
.tab-box {
font-size: 16px;
color: rgba(255, 255, 255, 0.3);
cursor: pointer;
}
}
::v-deep .h-card .content {
background: none;
}
</style>

View File

@ -0,0 +1,41 @@
<!--ckplayer 视频播放-->
<template>
<div style="width: 100%;height: 100%">
<video :id="'videoItem' + name" muted controls autoplay style="width: 100%;height: 100%;object-fit: fill;" />
</div>
</template>
<script>
import Srs from "@/assets/js/srs.sdk";
export default {
props: ["videoUrls", "autoPlay", "poster", "deviceIp", "name"],
data() {
return {
player: "",
rtcPlayer: null
};
},
mounted: function () {
this.player = document.getElementById("videoItem" + this.name);
//使srs.sdk.js
this.rtcPlayer = new Srs.SrsRtcWhipWhepAsync();
this.rtcPlayer.play(this.videoUrls);
// video
this.player.srcObject = this.rtcPlayer.stream;
// 使jswebrtc.min.js
// new JSWebrtc.Player(this.url, { video: player, autoplay: true, });
},
beforeDestroy: function () {
this.rtcPlayer.close();
},
watch: {
// watch
videoUrls(newVal,oldVal) {
this.rtcPlayer = new Srs.SrsRtcWhipWhepAsync();
this.rtcPlayer.play(newVal);
this.player.srcObject = this.rtcPlayer.stream;
}
},
methods: {}
};
</script>

View File

@ -0,0 +1,146 @@
<template>
<div class="projectContent">
<div class="left">
<leftTop :projectData="projectData" class="leftTop" ref="leftTopRef"></leftTop>
<leftCenter :statisticsCount="statisticsCount" class="leftCenter"></leftCenter>
<leftBottom :statisticsCount="statisticsCount" class="leftBottom"></leftBottom>
</div>
<div class="center">
<centerTop :projectData="projectData" class="centerTop" ref="centerTopRef"></centerTop>
<div class="centerBottom">
<centerBottomLeft :projectData="projectData" class="centerBottomLeft" ref="centerBottomLeftRef"></centerBottomLeft>
<centerBottomRight :projectData="projectData" class="centerBottomRight" ref="centerBottomRightRef"></centerBottomRight>
</div>
</div>
<div class="right">
<rightTop class="rightTop" ref="rightTopRef"></rightTop>
<rightBottom class="rightBottom" ref="rightBottomRef"></rightBottom>
</div>
</div>
</template>
<script setup lang="ts">
import leftTop from "@/views/commandScreen/liveScreen/leftTop.vue";
import leftCenter from "@/views/commandScreen/liveScreen/leftCenter.vue";
import leftBottom from "@/views/commandScreen/liveScreen/leftBottom.vue";
import centerTop from "@/views/commandScreen/liveScreen/centerTop.vue";
import centerBottomLeft from "@/views/commandScreen/liveScreen/centerBottomLeft.vue";
import centerBottomRight from "@/views/commandScreen/liveScreen/centerBottomRight.vue";
import rightTop from "@/views/commandScreen/liveScreen/rightTop.vue";
import rightBottom from "@/views/commandScreen/liveScreen/rightBottom.vue";
import { GlobalStore } from "@/stores";
const store = GlobalStore();
import { getWorkerStatisticsCountApi, getProjectDetail } from "@/api/modules/projectOverview";
import { ref, onMounted, onBeforeUnmount,nextTick } from "vue";
const statisticsCount = ref(null as any);
const projectData = ref(null as any);
//
const getProjectInfo = async (showLoading: boolean) => {
const res = await getProjectDetail({ projectSn: store.sn },showLoading);
projectData.value = res.result;
};
//
const getPersonDetail = async () => {
const res = await getWorkerStatisticsCountApi({ sn: store.sn });
statisticsCount.value = res.result;
};
const leftTopRef = ref();
const centerTopRef = ref();
const centerBottomLeftRef = ref();
const rightTopRef = ref();
const rightBottomRef = ref();
const callChildFn = async () => {
nextTick( async ()=>{
leftTopRef.value.projectTypeEnum()
centerTopRef.value.getQueryBySnData()
centerBottomLeftRef.value.getProgressOption()
rightTopRef.value.getSafeInfo()
rightBottomRef.value.getList()
})
}
//
const interval = ref(null as any);
//
const startInterval = async () => {
interval.value= setInterval(() => {
getPersonDetail();
getProjectInfo();
callChildFn();
}, 30 * 1000);
}
// interval
const destroyInterval = () => {
if (interval.value) {
clearInterval(interval.value);
}
}
// destroyInterval interval
onBeforeUnmount(() => {
destroyInterval();
})
window.onbeforeunload = (e) => {
destroyInterval();
}
onMounted( async () => {
getPersonDetail();
getProjectInfo();
startInterval();
});
</script>
<style lang="scss" scoped>
.projectContent {
width: 100%;
height: 100%;
display: flex;
.left {
width: 26%;
.leftTop {
height: 32%;
}
.leftCenter {
height: 33%;
margin: 3% 0 3% 0;
}
.leftBottom {
height: 35.25%;
}
}
.center {
width: 46%;
margin: 0 1%;
.centerTop {
height: 66%;
margin-bottom: 2.1%;
}
.centerBottom{
height: 100%;
width: 100%;
display: flex;
justify-content: space-between;
.centerBottomLeft {
width: 49%;
height: 35.23%;
}
.centerBottomRight {
width: 49%;
height: 35.23%;
}
}
}
.right {
width: 26%;
.rightTop {
height: 32%;
}
.rightBottom {
height: 78.636%;
margin: 3% 0 0 0;
}
}
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<div class="leftBottom">
<Card title="特殊作业情况">
<div class="mainContainer">
<div id="pieEchart" style="width:100%;height:100%"></div>
</div>
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { ref, onMounted, watch } from "vue";
import * as echarts from 'echarts';
function drawPie(){
type EChartsOption = echarts.EChartsOption;
var chartDom = document.getElementById('pieEchart')!;
var myChart = echarts.init(chartDom);
var option: EChartsOption;
option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
data: [ 'Direct', 'Marketing', 'Search Engine', 'Email', 'Union Ads', 'Video Ads', 'Baidu', 'Google', 'Bing', 'Others' ]
},
series: [
{
grid:{
left: '5%',
right: '5%',
bottom: '5%',
containLabel:true
},
name: 'Access From',
type: 'pie',
selectedMode: 'single',
radius: [0, '30%'],
label: {
position: 'inner',
fontSize: 14
},
labelLine: {
show: false
},
data: [
{ value: 1548, name: 'Search Engine' },
{ value: 775, name: 'Direct' },
{ value: 679, name: 'Marketing', selected: true }
]
},
{
name: 'Access From',
type: 'pie',
radius: ['45%', '60%'],
labelLine: {
length: 1
},
label: {
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}}{c} {per|{d}%} ',
backgroundColor: '#F6F8FC',
borderColor: '#8C8D8E',
borderWidth: 1,
borderRadius: 3,
rich: {
a: {
color: '#6E7079',
lineHeight: 10,
align: 'center'
},
hr: {
borderColor: '#8C8D8E',
width: '100%',
borderWidth: 1,
height: 0
},
b: {
color: '#4C5058',
fontSize: 10,
fontWeight: 'bold',
lineHeight: 12
},
per: {
color: '#fff',
backgroundColor: '#4C5058',
padding: [1, 1],
borderRadius: 1
}
}
},
data: [
{ value: 1048, name: 'Baidu' },
{ value: 335, name: 'Direct' },
{ value: 310, name: 'Email' },
{ value: 251, name: 'Google' },
{ value: 234, name: 'Union Ads' },
{ value: 147, name: 'Bing' },
{ value: 135, name: 'Video Ads' },
{ value: 102, name: 'Others' }
]
}
]
};
option && myChart.setOption(option);
}
onMounted( async () => {
drawPie()
});
</script>
<style lang="scss" scoped>
.leftBottom {
width: 100%;
height: 100%;
.mainContainer{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
::v-deep .h-card .content {
height: 80%;
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<div class="leftCenter">
<Card title="AI报警情况">
<div class="mainContainer">
<div class="imgBox"><img src="@\assets\images\vehicleManagement\goCar.png"/></div>
<div class="textBox">
<div>报警位置东南口</div>
<div>报警事件2024-03-01 12:00:00</div>
</div>
</div>
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { GlobalStore } from "@/stores";
import { COMPANY } from "@/config/config";
import { ref, onMounted, watch } from "vue";
import { getPersonTypeAndEduStatisticsApi } from "@/api/modules/labor";
const store = GlobalStore();
// ts
onMounted( async () => {
});
</script>
<style lang="scss" scoped>
.leftCenter {
width: 100%;
height: 100%;
.mainContainer{
width: calc(100% - 20px);
height: calc(100% - 20px);
color: #fff;
padding: 10px;
.imgBox{
width: 100%;
height: 85%;
img{
width: 100%;
height:100%;
background-size: 100% 100%;
}
}
.textBox{
height: 15%;
display: flex;
justify-content: space-between;
align-items: center;
line-height: 22px;
}
}
}
::v-deep .h-card .content {
height: 80%;
}
</style>

View File

@ -0,0 +1,140 @@
<template>
<div class="leftTop">
<Card title="承包商项目信息">
<!-- <div class="projectInfo">
<div><span>项目名称</span> {{ projectData.projectName || "" }}</div>
<div :title="projectLocal"><span>项目地址</span> {{ projectLocal }}</div>
<div><span>项目经理</span> {{ projectData.projectManage || "" }}</div>
<div><span>联系电话</span> {{ projectData.projectTel || "" }}</div>
<div><span>建筑面积</span> {{ projectData.projectAcreage || "" }} </div>
<div><span>开工日期</span> {{ projectData.startWorkDate || "" }}</div>
<div><span>项目编号</span> {{ projectData.projectNumber || "" }}</div>
<div><span>工程类别</span> {{ projectData.projectType && projectTypeEnumList.length > 0 ? projectTypeEnumList[projectData.projectType - 1].name : "" }}</div>
</div> -->
<div class="mainContainer">
<div>承包商名称辽宁五瞏</div>
<div class="lineBox"><div class="boxInner1">施工区域东北角一区</div> <div class="boxInner2">项目编号002</div></div>
<div class="lineBox"><div class="boxInner1">项目经理王海龙</div> <div class="boxInner2">项目类型epc总承包</div></div>
<div class="lineBox"><div class="boxInner1">联系电话13312545623</div> <div class="boxInner2">竣工日期2024-03-01</div></div>
<div class="lineBox"><div class="boxInner1">建筑面积12457</div> <div class="boxInner2">合同总额230万元</div></div>
<div class="lineBox"><div class="boxInner1">投资总额12457万元</div> <div class="boxInner2">工程类别矿山</div></div>
<div class="lineBox"><div class="boxInner1">开工日期2024-03-01</div> <div class="boxInner2">结构类型混合结构</div></div>
<div class="lineBox"><div class="boxInner1">项目编号鞍高开项备[2021]23)</div> <div class="boxInner2">施工阶段主体施工</div></div>
<div class="lineBox"><div class="boxInner1">工程类别矿山</div> <div class="boxInner2">工程状态</div></div>
</div>
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { GlobalStore } from "@/stores";
import { ref, onMounted, watch } from "vue";
import { getStageOption } from "@/api/modules/projectOverview";
// ts
type Props = {
projectData?: any; //
};
// withDefaults ()
const props = withDefaults(defineProps<Props>(), {
projectData: {}
});
//
const projectData = ref({} as any);
const projectLocal = ref("" as any);
const store = GlobalStore();
const projectTypeEnumList:any = ref([]); //
//
const projectTypeEnum = async () => {
const res: any = await getStageOption({ dictionaryEncoding: "project_type", projectSn: store.sn });
if (res.result.length > 0) {
let newArray = res.result.map((item: any) => {
return {
name: item.name,
id: Number(item.data)
};
});
projectTypeEnumList.value = newArray
} else {
projectTypeEnumList.value = []
}
};
//
defineExpose({
projectTypeEnum
})
onMounted( async () => {
await projectTypeEnum();
})
watch(
() => props.projectData,
newVal => {
if (newVal) {
// props.xData = newVal;
projectData.value = newVal;
projectLocal.value =
projectData.value.provinceName +
projectData.value.cityName +
projectData.value.areaName +
projectData.value.projectAddress;
}
}
);
</script>
<style lang="scss" scoped>
.leftTop {
width: 100%;
height: 100%;
.mainContainer{
color: #fff;
padding: 10px;
.lineBox{
// background-color: #fff;
line-height: 18px;
height: 18px;
display: flex;
.boxInner1{
// width: 60%;
width: 50%;
}
.boxInner2{
// width: 40%;
width: 50%;
}
}
}
// .projectInfo {
// width: 100%;
// height: 100%;
// color: #fff;
// padding: 2% 0 0 4%;
// div {
// width: 95%;
// height: 12%;
// font-size: 15px;
// white-space: nowrap; //
// overflow: hidden;
// text-overflow: ellipsis;
// span {
// margin-right: 3%;
// color: #ccc;
// }
// }
// }
}
::v-deep .h-card .content {
height: 80%;
}
::v-deep .h-card {
position: relative;
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<div class="rightBottom">
<Card title="安全待办">
</Card>
</div>
</template>
<script lang="ts" setup>
import { GlobalStore } from "@/stores";
import { getCurrentDayAirQualityApi } from "@/api/modules/projectOverview";
import { ref, onMounted, reactive } from "vue";
// import * as echarts from "echarts";
import Card from "@/components/card.vue";
const store = GlobalStore();
onMounted( async () => {
});
</script>
<style lang="scss" scoped>
.rightBottom {
width: 100%;
height: 100%;
}
::v-deep .h-card .content {
height: 80%;
}
</style>

View File

@ -0,0 +1,31 @@
<template>
<div class="rightTop">
<Card title="应急记录">
</Card>
</div>
</template>
<script setup lang="ts">
import Card from "@/components/card.vue";
import { onMounted, ref } from "vue";
import { GlobalStore } from "@/stores";
const store = GlobalStore();
import * as echarts from "echarts";
onMounted(async () => {
});
</script>
<style scoped>
.rightTop {
width: 100%;
height: 100%;
}
::v-deep .h-card .content {
height: 80%;
}
::v-deep .h-card {
position: relative;
}
</style>