初步完善

This commit is contained in:
shi
2025-08-21 20:38:44 +08:00
parent 37e01eda4b
commit 479291d857
17 changed files with 1023 additions and 0 deletions

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="440" height="1" viewBox="0 0 440 1" fill="none">
<path fill="url(#linear_border_216_180_0)" d="M440 0L439 0L439 1L440 1L440 0ZM437 0L435 0L435 1L437 1L437 0ZM433 0L431 0L431 1L433 1L433 0ZM429 0L427 0L427 1L429 1L429 0ZM425 0L423 0L423 1L425 1L425 0ZM421 0L419 0L419 1L421 1L421 0ZM417 0L415 0L415 1L417 1L417 0ZM413 0L411 0L411 1L413 1L413 0ZM409 0L407 0L407 1L409 1L409 0ZM405 0L403 0L403 1L405 1L405 0ZM401 0L399 0L399 1L401 1L401 0ZM397 0L395 0L395 1L397 1L397 0ZM393 0L391 0L391 1L393 1L393 0ZM389 0L387 0L387 1L389 1L389 0ZM385 0L383 0L383 1L385 1L385 0ZM381 0L379 0L379 1L381 1L381 0ZM377 0L375 0L375 1L377 1L377 0ZM373 0L371 0L371 1L373 1L373 0ZM369 0L367 0L367 1L369 1L369 0ZM365 0L363 0L363 1L365 1L365 0ZM361 0L359 0L359 1L361 1L361 0ZM357 0L355 0L355 1L357 1L357 0ZM353 0L351 0L351 1L353 1L353 0ZM349 0L347 0L347 1L349 1L349 0ZM345 0L343 0L343 1L345 1L345 0ZM341 0L339 0L339 1L341 1L341 0ZM337 0L335 0L335 1L337 1L337 0ZM333 0L331 0L331 1L333 1L333 0ZM329 0L327 0L327 1L329 1L329 0ZM325 0L323 0L323 1L325 1L325 0ZM321 0L319 0L319 1L321 1L321 0ZM317 0L315 0L315 1L317 1L317 0ZM313 0L311 0L311 1L313 1L313 0ZM309 0L307 0L307 1L309 1L309 0ZM305 0L303 0L303 1L305 1L305 0ZM301 0L299 0L299 1L301 1L301 0ZM297 0L295 0L295 1L297 1L297 0ZM293 0L291 0L291 1L293 1L293 0ZM289 0L287 0L287 1L289 1L289 0ZM285 0L283 0L283 1L285 1L285 0ZM281 0L279 0L279 1L281 1L281 0ZM277 0L275 0L275 1L277 1L277 0ZM273 0L271 0L271 1L273 1L273 0ZM269 0L267 0L267 1L269 1L269 0ZM265 0L263 0L263 1L265 1L265 0ZM261 0L259 0L259 1L261 1L261 0ZM257 0L255 0L255 1L257 1L257 0ZM253 0L251 0L251 1L253 1L253 0ZM249 0L247 0L247 1L249 1L249 0ZM245 0L243 0L243 1L245 1L245 0ZM241 0L239 0L239 1L241 1L241 0ZM237 0L235 0L235 1L237 1L237 0ZM233 0L231 0L231 1L233 1L233 0ZM229 0L227 0L227 1L229 1L229 0ZM225 0L223 0L223 1L225 1L225 0ZM221 0L219 0L219 1L221 1L221 0ZM217 0L215 0L215 1L217 1L217 0ZM213 0L211 0L211 1L213 1L213 0ZM209 0L207 0L207 1L209 1L209 0ZM205 0L203 0L203 1L205 1L205 0ZM201 0L199 0L199 1L201 1L201 0ZM197 0L195 0L195 1L197 1L197 0ZM193 0L191 0L191 1L193 1L193 0ZM189 0L187 0L187 1L189 1L189 0ZM185 0L183 0L183 1L185 1L185 0ZM181 0L179 0L179 1L181 1L181 0ZM177 0L175 0L175 1L177 1L177 0ZM173 0L171 0L171 1L173 1L173 0ZM169 0L167 0L167 1L169 1L169 0ZM165 0L163 0L163 1L165 1L165 0ZM161 0L159 0L159 1L161 1L161 0ZM157 0L155 0L155 1L157 1L157 0ZM153 0L151 0L151 1L153 1L153 0ZM149 0L147 0L147 1L149 1L149 0ZM145 0L143 0L143 1L145 1L145 0ZM141 0L139 0L139 1L141 1L141 0ZM137 0L135 0L135 1L137 1L137 0ZM133 0L131 0L131 1L133 1L133 0ZM129 0L127 0L127 1L129 1L129 0ZM125 0L123 0L123 1L125 1L125 0ZM121 0L119 0L119 1L121 1L121 0ZM117 0L115 0L115 1L117 1L117 0ZM113 0L111 0L111 1L113 1L113 0ZM109 0L107 0L107 1L109 1L109 0ZM105 0L103 0L103 1L105 1L105 0ZM101 0L99 0L99 1L101 1L101 0ZM97 0L95 0L95 1L97 1L97 0ZM93 0L91 0L91 1L93 1L93 0ZM89 0L87 0L87 1L89 1L89 0ZM85 0L83 0L83 1L85 1L85 0ZM81 0L79 0L79 1L81 1L81 0ZM77 0L75 0L75 1L77 1L77 0ZM73 0L71 0L71 1L73 1L73 0ZM69 0L67 0L67 1L69 1L69 0ZM65 0L63 0L63 1L65 1L65 0ZM61 0L59 0L59 1L61 1L61 0ZM57 0L55 0L55 1L57 1L57 0ZM53 0L51 0L51 1L53 1L53 0ZM49 0L47 0L47 1L49 1L49 0ZM45 0L43 0L43 1L45 1L45 0ZM41 0L39 0L39 1L41 1L41 0ZM37 0L35 0L35 1L37 1L37 0ZM33 0L31 0L31 1L33 1L33 0ZM29 0L27 0L27 1L29 1L29 0ZM25 0L23 0L23 1L25 1L25 0ZM21 0L19 0L19 1L21 1L21 0ZM17 0L15 0L15 1L17 1L17 0ZM13 0L11 0L11 1L13 1L13 0ZM9 0L7 0L7 1L9 1L9 0ZM5 0L3 0L3 1L5 1L5 0ZM1 0L0 0L0 1L1 1L1 0Z">
</path>
<defs>
<linearGradient id="linear_border_216_180_0" x1="440" y1="0.5" x2="0" y2="0.5" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1DD6FF" stop-opacity="0" />
<stop offset="1" stop-color="#1DD6FF" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 370 KiB

View File

@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="42.20001220703125" height="44.0025634765625" viewBox="0 0 42.20001220703125 44.0025634765625" fill="none">
<g opacity="0.8">
<ellipse transform="matrix(0.9915240406990051, -0.12992359697818756, 0.13317112624645233, 0.9910931587219238, 0, 4.8818359375)" cx="18.787446539492898" cy="18.56099636814998" rx="18.787446539492898" ry="18.56099636814998" fill="url(#linear_fill_216_484)" >
</ellipse>
</g>
<g clip-path="url(#clip-path-216_485)">
<g filter="url(#filter_216_487)">
<path d="M18.4577 26.933C16.6094 26.933 14.8691 26.2223 13.5609 24.9334C12.2528 23.6445 11.5316 21.9297 11.5316 20.1085C11.5316 18.2873 12.2528 16.5755 13.5609 15.2866C14.8691 13.9976 16.6094 13.287 18.4577 13.287C20.306 13.287 22.0463 13.9976 23.3545 15.2866C24.6626 16.5755 25.3839 18.2902 25.3839 20.1114C25.3839 21.9326 24.6626 23.6473 23.3545 24.9363C22.0463 26.2252 20.306 26.933 18.4577 26.933ZM18.4577 15.5886C15.9261 15.5886 13.8675 17.617 13.8675 20.1114C13.8675 22.6058 15.9261 24.6342 18.4577 24.6342C20.9893 24.6342 23.0479 22.6058 23.0479 20.1114C23.0479 17.617 20.9893 15.5886 18.4577 15.5886ZM29.2353 42.6332C28.59 42.6332 28.0673 42.1182 28.0673 41.4823L28.0673 35.5326C28.0673 33.1129 26.1606 31.122 23.7487 30.9436L21.0185 32.8597C19.4972 33.9271 17.4532 33.93 15.929 32.8684L13.1667 30.9436C10.7549 31.122 8.84812 33.1129 8.84812 35.5326L8.84812 41.4823C8.84812 42.1182 8.32544 42.6332 7.68013 42.6332C7.03482 42.6332 6.51215 42.1182 6.51215 41.4823L6.51215 35.5326C6.51215 33.6883 7.24214 31.9535 8.56488 30.6502C9.88762 29.3468 11.6484 28.6276 13.5201 28.6276C13.7624 28.6276 13.996 28.7024 14.1946 28.8376L17.278 30.9868C17.9934 31.4845 18.9512 31.4816 19.6637 30.9839L22.7179 28.8405C22.9165 28.7024 23.153 28.6276 23.3954 28.6276C25.2671 28.6276 27.0278 29.3468 28.3505 30.6502C29.6733 31.9535 30.4033 33.6883 30.4033 35.5326L30.4033 41.4823C30.4033 42.1182 29.8806 42.6332 29.2353 42.6332Z" fill="#FFFFFF" >
</path>
</g>
<path d="M11.7564 42.6332C11.1111 42.6332 10.5884 42.1182 10.5884 41.4824L10.5884 38.7204C10.5884 38.0845 11.1111 37.5695 11.7564 37.5695C12.4017 37.5695 12.9244 38.0845 12.9244 38.7204L12.9244 41.4824C12.9244 42.1182 12.4017 42.6332 11.7564 42.6332ZM25.159 42.6332C24.5137 42.6332 23.991 42.1182 23.991 41.4824L23.991 38.7204C23.991 38.0845 24.5137 37.5695 25.159 37.5695C25.8043 37.5695 26.327 38.0845 26.327 38.7204L26.327 41.4824C26.327 42.1182 25.8043 42.6332 25.159 42.6332ZM23.7283 20.2093L8.39845 20.2093C7.75314 20.2093 7.23047 19.6943 7.23047 19.0584C7.23047 18.4226 7.75314 17.9076 8.39845 17.9076L23.7283 17.9076C24.3736 17.9076 24.8962 18.4226 24.8962 19.0584C24.8962 19.6943 24.3736 20.2093 23.7283 20.2093Z" fill="#FFFFFF" >
</path>
</g>
<defs>
<radialGradient id="linear_fill_216_484" cx="0" cy="0" r="1" gradientTransform="translate(31.006426019848288 5.783235248388171) rotate(-151.06468116612422) scale(28.374047672813088, 28.374047672813088)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1DD6FF" stop-opacity="0.78" />
<stop offset="0.9861" stop-color="#1DD6FF" stop-opacity="0" />
</radialGradient>
<clipPath id="clip-path-216_485">
<path d="M2.54681 44.0025L34.2695 44.0025L34.2695 12.2961L2.54681 12.2961L2.54681 44.0025Z" fill="white"/>
</clipPath>
<filter id="filter_216_487" x="4.51214599609375" y="11.2869873046875" width="27.89111328125" height="33.34619140625" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="feFloodId_216_487"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha_216_487"/>
<feOffset dx="0" dy="0"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha_216_487" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.7450980392156863 0 0 0 0 0.9686274509803922 0 0 0 0.8 0"/>
<feBlend mode="normal" in2="feFloodId_216_487" result="dropShadow_1_216_487"/>
<feBlend mode="normal" in="SourceGraphic" in2="dropShadow_1_216_487" result="shape_216_487"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.4189453125" height="12" viewBox="0 0 12.4189453125 12" fill="none">
<ellipse cx="6.20947265625" cy="6" rx="6.20947265625" ry="6" fill="#1DD6FF" fill-opacity="0.2">
</ellipse>
<ellipse cx="6.209228515625" cy="6" rx="3.104736328125" ry="3" fill="#1DD6FF" >
</ellipse>
</svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15" height="35" viewBox="0 0 15 35" fill="none">
<rect x="1" y="0" width="14" height="35" fill="url(#linear_fill_216_187)" fill-opacity="1">
</rect>
<rect x="0" y="0" width="4" height="35" fill="#1DD6FF" >
</rect>
<defs>
<linearGradient id="linear_fill_216_187" x1="1" y1="17.5" x2="13.62772" y2="17.5" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#43E2CB" stop-opacity="0.4" />
<stop offset="1" stop-color="#43E2CB" stop-opacity="0" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -75,6 +75,11 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/error/401.vue'), component: () => import('@/views/error/401.vue'),
hidden: true hidden: true
}, },
{
path: '/ProjectScreen',
component: () => import('@/views/ProjectScreen/index.vue'),
hidden: true
},
{ {
path: '/user', path: '/user',
component: Layout, component: Layout,

View File

@ -0,0 +1,174 @@
<template>
<div class="centerPage">
<div class="topPage">
<!-- 暂无 -->
</div>
<div class="endPage">
<Title title="AI安全巡检" :prefix="true" />
<div class="swiper">
<div class="arrow" :class="{ 'canUse': canLeft }" @click="swiperClick('left')">
<el-icon size="16" color="skyblue">
<ArrowLeft />
</el-icon>
</div>
<div class="swiper_content" ref="swiperContent">
<div class="swiper_item" v-for="(item, index) in swiperList" :key="index">
<img src="@/assets/projectLarge/swiper.png" alt="" class="swiper_img">
<div class="swiper_date">{{ item.date }}</div>
<div class="swiper_tip">{{ item.tip }}</div>
</div>
</div>
<div class="arrow" :class="{ 'canUse': canRight }" @click="swiperClick('right')">
<el-icon size="16">
<ArrowRight />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import Title from './title.vue'
const swiperList = ref([
{ date: '03-18 15:00', tip: '未佩戴安全帽1' },
{ date: '03-18 15:00', tip: '未佩戴安全帽2' },
{ date: '03-18 15:00', tip: '未佩戴安全帽3' },
{ date: '03-18 15:00', tip: '未佩戴安全帽4' },
{ date: '03-18 15:00', tip: '未佩戴安全帽5' },
{ date: '03-18 15:00', tip: '未佩戴安全帽6' },
{ date: '03-18 15:00', tip: '未佩戴安全帽7' },
{ date: '03-18 15:00', tip: '未佩戴安全帽8' },
{ date: '03-18 15:00', tip: '未佩戴安全帽9' },
{ date: '03-18 15:00', tip: '未佩戴安全帽10' },
{ date: '03-18 15:00', tip: '未佩戴安全帽11' },
{ date: '03-18 15:00', tip: '未佩戴安全帽12' },
])
const swiperContent = ref<HTMLDivElement>()
const swiperItemWidth = ref(100)
const canLeft = ref(false)
const canRight = ref(true)
const swiperClick = (direction: 'left' | 'right') => {
if (direction === 'right') {
if (swiperContent.value.scrollLeft >= swiperContent.value.scrollWidth - swiperContent.value.clientWidth) {
canRight.value = false
canLeft.value = true
return
}
swiperContent.value.scrollLeft += swiperItemWidth.value
} else {
if (swiperContent.value.scrollLeft <= 0) {
canLeft.value = false
canRight.value = true
return
}
swiperContent.value.scrollLeft -= swiperItemWidth.value
}
}
onMounted(() => {
swiperItemWidth.value = swiperContent.value.children[0].clientWidth + 20
})
</script>
<style scoped lang="scss">
.centerPage {
display: flex;
flex-direction: column;
width: 50vw;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.topPage {
flex: 1;
margin-bottom: 23px;
}
}
.swiper {
width: 100%;
display: flex;
align-items: center;
gap: 20px;
padding: 20px 20px 10px 20px;
.swiper_content {
width: 100%;
display: flex;
gap: 20px;
transition: all 0.3s ease-in-out;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
}
.swiper_item {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 133px;
height: 84px;
.swiper_img {
width: 133px;
height: 84px;
object-fit: cover;
}
.swiper_date {
position: absolute;
top: 4px;
right: 4px;
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
}
.swiper_tip {
position: absolute;
bottom: 0;
width: 100%;
padding: 5px 0;
text-align: center;
font-size: 12px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
background-color: rgba(0, 0, 0, 0.5);
}
}
}
.arrow {
display: grid;
place-items: center;
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid skyblue;
color: skyblue;
&:canUse {
color: #000 !important;
}
}
</style>

View File

@ -0,0 +1,198 @@
<template>
<div class="header">
<div class="header_left">
<div class="header_left_img">
<img src="@/assets/large/secure.png" style="width: 100%; height: 100%" />
</div>
<div style="font-size: 12px; padding-left: 10px">安全生产天数</div>
<div class="header_left_text">
1,235
<span style="font-size: 12px"></span>
</div>
</div>
<div class="title">
<div>XXX智慧工地管理平台</div>
<div>XXX Smart Construction Stic Management Dashboard</div>
</div>
<div class="right">
<div class="top-bar">
<!-- 左侧天气图标 + 日期文字 -->
<div class="left-section">
<img src="@/assets/large/weather.png" alt="天气图标" />
<span>
<span>多云 9°/18°</span>
<span style="padding-left: 20px"> {{ week[date.week] }} ({{ date.ymd }})</span>
</span>
</div>
<!-- 分割线 -->
<div class="divider">
<div class="top-block"></div>
<div class="bottom-block"></div>
</div>
<!-- 右侧管理系统图标 + 文字 -->
<div class="right-section">
<img src="@/assets/large/setting.png" alt="设置图标" />
<span>管理系统</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const date = ref({
ymd: '',
hms: '',
week: 0
});
const setTime = () => {
let date1 = new Date();
let year: any = date1.getFullYear();
let month: any = date1.getMonth() + 1;
let day: any = date1.getDate();
let hours: any = date1.getHours();
if (hours < 10) {
hours = '0' + hours;
}
let minutes: any = date1.getMinutes();
if (minutes < 10) {
minutes = '0' + minutes;
}
let seconds: any = date1.getSeconds();
if (seconds < 10) {
seconds = '0' + seconds;
}
date.value.ymd = year + '-' + month + '-' + day;
date.value.hms = hours + ':' + minutes + ':' + seconds;
date.value.week = date1.getDay();
};
// 添加定时器,每秒更新一次时间
const timer = setInterval(setTime, 1000);
// 组件卸载时清除定时器
onUnmounted(() => {
clearInterval(timer);
});
</script>
<style scoped lang="scss">
.header {
width: 100%;
height: 80px;
box-sizing: border-box;
padding: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
color: #fff;
}
.header_left {
display: flex;
align-items: center;
.header_left_img {
width: 48px;
height: 48px;
box-sizing: border-box;
// padding-right: 10px;
}
.header_left_text {
font-weight: 500;
text-shadow: 0px 1.24px 6.21px rgba(25, 179, 250, 1);
}
}
.title {
color: #fff;
font-family: 'AlimamaShuHeiTi', sans-serif;
text-align: center;
}
.title>div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
letter-spacing: 0.1em;
}
.title>div:last-child {
/* 最后一个子元素的样式 */
font-size: 14px;
}
.right {
width: 100%;
height: 100%;
display: flex;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
.top-bar {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
// background-color: #1e2128;
color: #fff;
padding: 8px 16px;
font-size: 14px;
}
/* 左侧区域(天气 + 日期):自身也用 Flex 水平排列,确保元素在一行 */
.left-section {
display: flex;
align-items: center;
// margin-right: auto; /* 让右侧元素(管理系统)居右 */
}
.left-section img {
width: 32px;
height: 32px;
margin-right: 8px;
/* 图标与文字间距 */
}
/* 分割线(视觉分隔,可根据需求调整样式) */
.divider {
display: grid;
grid-template-rows: 1fr 1fr;
height: 100%;
/* 根据需要调整高度 */
padding: 14px 10px;
}
.divider .top-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: start;
}
.divider .bottom-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: end;
}
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
display: flex;
align-items: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
cursor: pointer;
}
.right-section img {
width: 20px;
height: 20px;
margin-right: 6px;
/* 图标与文字间距 */
}
</style>

View File

@ -0,0 +1,204 @@
<template>
<div class="leftPage">
<div class="topPage">
<Title title="项目公告" />
<div class="content">
<div class="content_item" v-for="item in 6" :key="item">
<div class="round">
<div class="sub_round"></div>
</div>
<div class="ellipsis">2025年6月23日 重庆市两江新区广场前期准备与审批完毕区广场前期准备与审批完毕前期准备与审批完毕区广场前期准备与审批完毕</div>
</div>
</div>
</div>
<div class="endPage">
<Title title="人员情况" />
<div class="map">
<img src="@/assets/projectLarge/map.svg" alt="">
</div>
<div class="attendance_tag">
<div class="tag_item" v-for="(item, index) in tagList" :key="index">
<img src="@/assets/projectLarge/people.svg" alt="">
<div class="tag_title">{{ item.title }}</div>
<div class="tag_info">
{{ item.number }}
<span style="font-size: 14px;">{{ index === 2 ? '%' : '人' }}</span>
</div>
</div>
</div>
<div class="attendance_list">
<div class="attendance_item subfont">
<div class="attendance_item_title"></div>
<div class="attendance_item_title">在岗人数</div>
<div class="attendance_item_title">出勤率</div>
<div class="attendance_item_title">出勤时间</div>
</div>
<div v-for="item in list" :key="item.title" class="attendance_item">
<div class="attendance_item_title">{{ item.title }}</div>
<div class="attendance_item_number">{{ item.number }} <span class="subfont">/{{ item.number }}</span></div>
<div class="attendance_item_rate">{{ item.attendanceRate }} %</div>
<div class="attendance_item_date subfont">{{ item.date }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import Title from './title.vue'
const list = ref([
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
{ title: '智慧系统运维', number: 30, attendanceRate: 100, date: '2025-08-05 08:10' },
])
const tagList = ref([
{ title: '出勤人数', number: 259 },
{ title: '在岗人数', number: 100 },
{ title: '出勤率', number: 100 },
])
</script>
<style scoped lang="scss">
.leftPage {
display: flex;
flex-direction: column;
width: calc(25vw - 30px);
margin: 0 15px;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.endPage {
flex: 1;
margin-top: 23px;
}
}
.content {
max-height: 100px;
margin: 0 15px;
padding: 0 10px;
margin-top: 15px;
box-sizing: border-box;
overflow-y: auto;
&::-webkit-scrollbar-track {
background: rgba(204, 204, 204, 0.1);
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: rgba(29, 214, 255, 0.78);
border-radius: 10px;
}
.content_item {
display: flex;
align-items: flex-start;
gap: 10px;
// position: relative;
margin-bottom: 20px;
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
.ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.5;
}
&:last-child {
margin-bottom: 0;
}
.round {
display: grid;
place-items: center;
margin-top: 3px;
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(29, 214, 255, 0.3);
.sub_round {
width: 6px;
height: 6px;
border-radius: 50%;
background: #1DD6FF;
}
}
}
}
.map {
margin-top: 15px;
}
.attendance_tag {
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 30px;
margin-top: 15px;
.tag_item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
border: 1px dashed rgba(29, 214, 255, 0.3);
padding: 10px 25px;
.tag_info {
font-size: 20px;
font-weight: 700;
color: rgba(230, 247, 255, 1);
text-shadow: 0px 1.24px 6.21px rgba(0, 190, 247, 1);
}
.tag_title {
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
}
}
}
.attendance_list {
padding: 0px 30px;
font-size: 14px;
.attendance_item {
display: grid;
grid-template-columns: 3fr 2fr 2fr 3fr;
margin-top: 20px;
}
}
.subfont {
color: rgba(138, 149, 165, 1);
}
</style>

View File

@ -0,0 +1,274 @@
<template>
<div class="leftPage">
<div class="topPage">
<Title title="项目概况" />
<div class="content">
<div class="content_item">项目名称智慧生态工地社区开发项目</div>
<div class="content_item">项目位置贵州省贵阳市乌当区具体地块编号01-123-11</div>
<div class="content_item">占地面积约10000亩</div>
<div class="content_item"> 土地性质城镇住宅用地兼容商业用地容积率2.5</div>
</div>
</div>
<div class="endPage">
<!-- 饼图容器 -->
<Title title="形象进度" />
<div ref="pieChartRef" class="echart" />
<!-- 折线图容器 -->
<div ref="lineChartRef" class="echart" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick } from "vue"
import Title from './title.vue'
import * as echarts from 'echarts';
// 饼图相关
const pieChartRef = ref<HTMLDivElement | null>(null);
let pieChart: any = null;
// 折线图相关
const lineChartRef = ref<HTMLDivElement | null>(null);
let lineChart: any = null;
// 饼图数据
const pieData = [
{ name: '桩点浇筑', value: 13 },
{ name: '水泥灌注', value: 7 },
{ name: '箱变安装', value: 40 },
{ name: '支架安装', value: 20 },
{ name: '组件安装', value: 20 },
]
// 折线图数据
const barData = {
xAxis: ['地块1', '地块2', '地块3', '地块4', '地块5', '地块6'],
series: [
{
name: '计划流转面积',
data: [70, 25, 45, 115, 70, 85]
},
{
name: '已流转面积',
data: [105, 30, 150, 65, 80, 200]
}
]
}
// 饼图配置
const pieOption = {
series: {
type: 'pie',
data: pieData,
radius: [50, 80],
itemStyle: {
borderColor: '#fff',
borderWidth: 1
},
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{percent|{c} %}',
minMargin: 10,
edgeDistance: 20,
lineHeight: 15,
rich: {
name: {
fontSize: 12,
color: '#fff'
},
percent: {
fontSize: 12,
color: '#fff'
}
}
},
legend: {
top: 'bottom'
},
}
};
// 柱状图配置
const barOption = {
legend: {
data: ['计划流转面积', '已流转面积'],
top: 0
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: barData.xAxis
},
yAxis: {
name: '单位m²',
type: 'value',
axisLabel: {
formatter: '{value}'
}
},
series: [
{
type: 'bar',
data: [], // 空数据仅用于承载markArea
markArea: {
silent: true, // 背景不响应交互
data: (() => {
const groupCount = 3; // 共3组6个月 ÷ 2
const groupWidth = 1.8; // 每组背景宽度覆盖2根柱子
const bgData = [];
for (let i = 0; i < groupCount; i++) {
const startX = i * 2 - 0.9; // 每组起始位置
const endX = startX + groupWidth; // 每组结束位置
bgData.push([
{ xAxis: startX, yAxis: 0 },
{ xAxis: endX, yAxis: 100 }
]);
}
return bgData;
})(),
itemStyle: {
color: 'rgba(255, 255, 255, 0.05)',
borderRadius: 4
}
}
},
{
name: '计划流转面积',
type: 'bar',
data: barData.series[0].data,
barWidth: 15, // 柱形宽度
itemStyle: {
color: 'rgb(29, 253, 253)'
},
},
{
name: '已流转面积',
type: 'bar',
data: barData.series[1].data,
barWidth: 15,
itemStyle: {
color: '#rgb(25, 181, 251)'
},
}
]
};
// 初始化饼图
const initPieChart = () => {
if (!pieChartRef.value) {
console.error('未找到饼图容器元素');
return;
}
pieChart = echarts.init(pieChartRef.value, null, {
renderer: 'canvas',
useDirtyRect: false
});
pieChart.setOption(pieOption);
}
// 初始化折线图
const initLineChart = () => {
if (!lineChartRef.value) {
console.error('未找到折线图容器元素');
return;
}
lineChart = echarts.init(lineChartRef.value, null, {
renderer: 'canvas',
useDirtyRect: false
});
lineChart.setOption(barOption);
}
// 响应窗口大小变化
const handleResize = () => {
if (pieChart) pieChart.resize();
if (lineChart) lineChart.resize();
};
// 组件挂载时初始化图表
onMounted(() => {
nextTick(() => {
initPieChart();
initLineChart();
window.addEventListener('resize', handleResize);
});
});
// 组件卸载时清理
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
if (pieChart) {
pieChart.dispose();
pieChart = null;
}
if (lineChart) {
lineChart.dispose();
lineChart = null;
}
});
</script>
<style scoped lang="scss">
.leftPage {
display: flex;
flex-direction: column;
width: calc(25vw - 30px);
margin: 0 15px;
height: 100%;
.topPage,
.endPage {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
padding: 15px 0;
border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box;
}
.endPage {
flex: 1;
margin-top: 23px;
.echart {
width: 100%;
height: 100%;
}
}
}
.content {
margin: 10px 35px;
.content_item {
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
}
.ellipse {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.subfont {
color: rgba(138, 149, 165, 1);
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<div class="title">
<div class="title_icon">
<img src="@/assets/projectLarge/section.svg" alt="">
<img src="@/assets/projectLarge/border.svg" alt="">
</div>
<div v-if="prefix">
<img src="@/assets/projectLarge/robot.svg" alt="" style="width: 20px; height: 20px;margin-right: 5px;">
</div>
<div>{{ title }}</div>
</div>
</template>
<script setup lang="ts">
defineProps({
title: {
type: String,
default: '标题'
},
prefix: {
type: Boolean,
default: false
}
})
</script>
<style scoped lang="scss">
.title {
width: 100%;
display: flex;
align-items: center;
gap: 3px;
font-family: 'AlimamaShuHeiTi', sans-serif;
.title_icon {
position: relative;
&>img:last-child {
position: absolute;
bottom: 4px;
left: 0;
}
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="large-screen">
<Header />
<div class="nav">
<leftPage />
<centerPage />
<rightPage />
</div>
</div>
</template>
<script setup lang="ts">
import Header from './components/header.vue';
import leftPage from './components/leftPage.vue';
import centerPage from './components/centerPage.vue';
import rightPage from './components/rightPage.vue';
</script>
<style lang="scss" scoped>
.large-screen {
width: 100vw;
height: 100vh;
background: url('@/assets/large/bg.png') no-repeat;
background-size: 100% 100%;
background-color: rgba(4, 7, 17, 1);
}
.nav {
display: flex;
gap: 15rpx;
width: 100%;
height: calc(100vh - 100px);
box-sizing: border-box;
color: #fff;
}
.nav_left,
.nav_right {
margin: 0 15px 15px 15px;
}
.nav_center {
margin-bottom: 15px;
}
</style>