|
|
@@ -1,74 +1,37 @@
|
|
|
<template>
|
|
|
- <div class="main-page" @mousemove="onMouseMove" @mouseleave="onMouseLeave">
|
|
|
- <!-- 背景 -->
|
|
|
- <div class="bg"></div>
|
|
|
-
|
|
|
- <!-- 顶部 Header -->
|
|
|
- <div class="header">
|
|
|
- <!-- <div class="title">交通信号控制平台</div> -->
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 漂浮闪烁点 -->
|
|
|
- <div class="spark-layer" aria-hidden="true">
|
|
|
- <span
|
|
|
- v-for="d in dots"
|
|
|
- :key="d.id"
|
|
|
- class="spark"
|
|
|
- :style="dotStyle(d)"
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 中央功能区 -->
|
|
|
- <div class="center-wrap">
|
|
|
- <div class="nav-arrow left" @click="onPrev" title="上一页"></div>
|
|
|
+ <LoginLayout>
|
|
|
|
|
|
- <div class="dock">
|
|
|
- <div
|
|
|
- v-for="(item, idx) in items"
|
|
|
- :key="item.key"
|
|
|
- class="dock-item"
|
|
|
- :style="itemStyle(idx)"
|
|
|
- @click="go(item)"
|
|
|
- @mouseenter="handleHover(idx)"
|
|
|
- @mouseleave="currentHoverIndex = null"
|
|
|
- >
|
|
|
- <div class="icon" :style="iconStyle(idx, item)"></div>
|
|
|
- <div class="label">{{ item.label }}</div>
|
|
|
- </div>
|
|
|
+ <!-- 背景 -->
|
|
|
+ <template #background>
|
|
|
+ <div class="login-bg"></div>
|
|
|
+ <!-- 漂浮闪烁点 -->
|
|
|
+ <div class="spark-layer" aria-hidden="true">
|
|
|
+ <span v-for="d in dots" :key="d.id" class="spark" :style="dotStyle(d)" />
|
|
|
</div>
|
|
|
+ </template>
|
|
|
|
|
|
- <div class="nav-arrow right" @click="onNext" title="下一页"></div>
|
|
|
- </div>
|
|
|
+ <template #main>
|
|
|
+ <BottomDock :auto-hide="false" :custom-class="['dock-style']"></BottomDock>
|
|
|
+ </template>
|
|
|
|
|
|
- <div class="copyright">北京东土正创科技有限公司</div>
|
|
|
- </div>
|
|
|
+ </LoginLayout>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+import LoginLayout from "@/layouts/LoginLayout.vue";
|
|
|
+import BottomDock from "@/components/ui/BottomDock.vue";
|
|
|
+
|
|
|
export default {
|
|
|
- name: "Main",
|
|
|
+ name: "MainPage",
|
|
|
+ components: {
|
|
|
+ LoginLayout,
|
|
|
+ BottomDock
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+
|
|
|
+ },
|
|
|
data() {
|
|
|
return {
|
|
|
- // 以 1920x1080 为设计基准,用 scale 把“设计像素”映射到任意大屏
|
|
|
- baseW: 1920,
|
|
|
- baseH: 1080,
|
|
|
- scale: 1,
|
|
|
- currentHoverIndex: null,
|
|
|
-
|
|
|
- // mac dock 效果:鼠标点位
|
|
|
- mouseX: null,
|
|
|
- mouseY: null,
|
|
|
-
|
|
|
- // 6 个功能(route 先对齐到你当前路由:目前只有 /home 可落地,其它模块先通过 query 标记,避免 404)
|
|
|
- items: [
|
|
|
- { key: "home", label: "首页", img: "main-home", route: { path: "/home" } },
|
|
|
- { key: "surve", label: "状态监控", img: "main-surve", route: { path: "/surve", query: { panel: "surve" } } },
|
|
|
- { key: "security", label: "特勤安保", img: "main-security", route: { path: "/security", query: { panel: "security" } } },
|
|
|
- { key: "coor", label: "干线协调", img: "main-coor", route: { path: "/coor", query: { panel: "coor" } } },
|
|
|
- { key: "watch", label: "数据分析", img: "main-watch", route: { path: "/watch", query: { panel: "watch" } } },
|
|
|
- { key: "setting", label: "系统设置", img: "main-setting", route: { path: "/setting", query: { panel: "setting" } } },
|
|
|
- ],
|
|
|
-
|
|
|
// 亮点
|
|
|
dots: [],
|
|
|
};
|
|
|
@@ -90,73 +53,6 @@ export default {
|
|
|
// 写到 css 变量,方便 calc(var(--s) * xxxpx)
|
|
|
this.$el && this.$el.style.setProperty("--s", this.scale.toFixed(6));
|
|
|
},
|
|
|
-
|
|
|
- // ---------- Dock 缩放 ----------
|
|
|
- onMouseMove(e) {
|
|
|
- const rect = this.$el.getBoundingClientRect();
|
|
|
- this.mouseX = e.clientX - rect.left;
|
|
|
- this.mouseY = e.clientY - rect.top;
|
|
|
- },
|
|
|
- onMouseLeave() {
|
|
|
- this.mouseX = null;
|
|
|
- this.mouseY = null;
|
|
|
- },
|
|
|
- itemStyle(idx) {
|
|
|
- if (this.mouseX == null) return { transform: "translateZ(0) scale(1)" };
|
|
|
-
|
|
|
- const dock = this.$el.querySelector(".dock");
|
|
|
- const el = dock && dock.children && dock.children[idx];
|
|
|
- if (!el) return { transform: "translateZ(0) scale(1)" };
|
|
|
-
|
|
|
- const r = el.getBoundingClientRect();
|
|
|
- const root = this.$el.getBoundingClientRect();
|
|
|
- const cx = (r.left - root.left) + r.width / 2;
|
|
|
- const cy = (r.top - root.top) + r.height / 2;
|
|
|
-
|
|
|
- const dx = this.mouseX - cx;
|
|
|
- const dy = this.mouseY - cy;
|
|
|
- const dist = Math.sqrt(dx * dx + dy * dy);
|
|
|
-
|
|
|
- // 影响半径:约 220 设计像素(随 scale 变化)
|
|
|
- const R = 220 * this.scale;
|
|
|
- const t = Math.max(0, 1 - dist / R); // 0~1
|
|
|
- const s = 1 + 0.35 * (t * t); // 最大放大 1.35
|
|
|
-
|
|
|
- return { transform: `translateZ(0) scale(${s.toFixed(4)})` };
|
|
|
- },
|
|
|
-
|
|
|
- // ---------- 资源映射 ----------
|
|
|
- assetUrl(file) {
|
|
|
- try {
|
|
|
- return require("@/assets/main/" + file);
|
|
|
- } catch (e) {
|
|
|
- return "";
|
|
|
- }
|
|
|
- },
|
|
|
- iconStyle(index, item) {
|
|
|
- return {
|
|
|
- backgroundImage: this.currentHoverIndex === index ? `url(${this.assetUrl(item.img + '-hover.png')})` : `url(${this.assetUrl(item.img + '.png')})`
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- handleHover(index) {
|
|
|
- this.currentHoverIndex = index;
|
|
|
- },
|
|
|
-
|
|
|
- // ---------- 导航 ----------
|
|
|
- go(item) {
|
|
|
- // 路由对齐:你的路由表里目前只有 /home(其它页面后续再补路由)
|
|
|
- // 先用 query.panel 区分模块,保证点击不会 404
|
|
|
- if (this.$router && item.route) this.$router.push(item.route);
|
|
|
- }
|
|
|
- ,
|
|
|
- onPrev() {
|
|
|
- this.$emit("prev");
|
|
|
- },
|
|
|
- onNext() {
|
|
|
- this.$emit("next");
|
|
|
- },
|
|
|
-
|
|
|
// ---------- 闪烁点 ----------
|
|
|
initDots() {
|
|
|
const count = 28;
|
|
|
@@ -178,19 +74,36 @@ export default {
|
|
|
return {
|
|
|
left: d.x + "%",
|
|
|
top: d.y + "%",
|
|
|
- width: `calc(var(--s) * ${d.r * 4}px)`,
|
|
|
- height: `calc(var(--s) * ${d.r * 4}px)`,
|
|
|
+ width: `${d.r * 4}px`,
|
|
|
+ height: `${d.r * 4}px`,
|
|
|
opacity: d.a,
|
|
|
animationDelay: `${d.d}s`,
|
|
|
animationDuration: `${d.t}s`,
|
|
|
};
|
|
|
},
|
|
|
- },
|
|
|
-};
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.main-page{
|
|
|
+.dock-style {
|
|
|
+ left: 0;
|
|
|
+ bottom: unset !important;
|
|
|
+ height: 100%;
|
|
|
+ margin: auto 0;
|
|
|
+ border-radius: calc(var(--s) * 1.125rem);
|
|
|
+ background: linear-gradient(180deg, rgba(10, 35, 70, .18), rgba(0, 0, 0, .08));
|
|
|
+ box-shadow: 0 0 calc(var(--s) * 1.625rem) rgba(0, 140, 255, .08) inset;
|
|
|
+ backdrop-filter: blur(.125rem);
|
|
|
+}
|
|
|
+.dock-style ::v-deep .right-arrow {
|
|
|
+ margin-left: 100px;
|
|
|
+}
|
|
|
+.dock-style ::v-deep .left-arrow {
|
|
|
+ margin-right: 100px;
|
|
|
+}
|
|
|
+.main-page {
|
|
|
position: relative;
|
|
|
width: 100vw;
|
|
|
height: 100vh;
|
|
|
@@ -200,167 +113,46 @@ export default {
|
|
|
user-select: none;
|
|
|
}
|
|
|
|
|
|
-/* 背景图(图2) */
|
|
|
-.bg{
|
|
|
- position:absolute;
|
|
|
- inset:0;
|
|
|
- background: center/cover no-repeat;
|
|
|
- background-image: url("~@/assets/main/main-bg.png");
|
|
|
+.login-bg {
|
|
|
+ background: url('@/assets/images/main-background.png') no-repeat center/cover;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
filter: saturate(1.05) contrast(1.03);
|
|
|
}
|
|
|
|
|
|
-/* 顶部 header(高度 100 设计像素) */
|
|
|
-.header{
|
|
|
- position:absolute;
|
|
|
- left:0;
|
|
|
- top:0;
|
|
|
- width:100%;
|
|
|
- height: calc(var(--s) * 100px);
|
|
|
- background: center/100% 100% no-repeat;
|
|
|
- background-image: url("~@/assets/main/main-header.png");
|
|
|
- display:flex;
|
|
|
- align-items:center;
|
|
|
- justify-content:center;
|
|
|
- z-index: 5;
|
|
|
-}
|
|
|
-.title{
|
|
|
- font-size: calc(var(--s) * 34px);
|
|
|
- letter-spacing: calc(var(--s) * 2px);
|
|
|
- text-shadow: 0 0 calc(var(--s) * 10px) rgba(90, 200, 255, 0.35);
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-
|
|
|
-/* 中间区域:使用居中 + 轻微上移(避免写死 1920 的绝对 px) */
|
|
|
-.center-wrap{
|
|
|
- position:absolute;
|
|
|
- left:50%;
|
|
|
- top:46%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- width: min(92vw, calc(var(--s) * 1600px));
|
|
|
- display:flex;
|
|
|
- align-items:center;
|
|
|
- justify-content:center;
|
|
|
- gap: calc(var(--s) * 40px);
|
|
|
- z-index: 6;
|
|
|
-}
|
|
|
-
|
|
|
-/* 左右箭头(54*54) */
|
|
|
-.nav-arrow{
|
|
|
- width: calc(var(--s) * 54px);
|
|
|
- height: calc(var(--s) * 54px);
|
|
|
- background: center/contain no-repeat;
|
|
|
- opacity: .92;
|
|
|
- cursor: pointer;
|
|
|
- transition: transform .18s ease, opacity .18s ease, filter .18s ease;
|
|
|
- filter: drop-shadow(0 0 calc(var(--s) * 10px) rgba(60, 180, 255, .35));
|
|
|
-}
|
|
|
-.nav-arrow:hover{
|
|
|
- opacity: 1;
|
|
|
- transform: translateZ(0) scale(1.08);
|
|
|
- filter: drop-shadow(0 0 calc(var(--s) * 14px) rgba(90, 210, 255, .6));
|
|
|
-}
|
|
|
-.nav-arrow.left{ background-image: url("~@/assets/main/main-left.png"); }
|
|
|
-.nav-arrow.right{ background-image: url("~@/assets/main/main-right.png"); }
|
|
|
-
|
|
|
-/* 功能按钮 Dock */
|
|
|
-.dock{
|
|
|
- display:flex;
|
|
|
- align-items:flex-start;
|
|
|
- justify-content:center;
|
|
|
- gap: calc(var(--s) * 45px);
|
|
|
- padding: calc(var(--s) * 12px) calc(var(--s) * 16px);
|
|
|
- border-radius: calc(var(--s) * 18px);
|
|
|
- background: linear-gradient(180deg, rgba(10,35,70,.18), rgba(0,0,0,.08));
|
|
|
- box-shadow: 0 0 calc(var(--s) * 26px) rgba(0, 140, 255, .08) inset;
|
|
|
- backdrop-filter: blur(2px);
|
|
|
- margin: 0 6%;
|
|
|
-}
|
|
|
-
|
|
|
-.dock-item{
|
|
|
- width: calc(var(--s) * 98px);
|
|
|
- height: calc(var(--s) * 124px);
|
|
|
- display:flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items:center;
|
|
|
- justify-content:flex-start;
|
|
|
- cursor:pointer;
|
|
|
- transform-origin: 50% 80%;
|
|
|
- transition: transform .08s linear;
|
|
|
-}
|
|
|
-
|
|
|
-.icon{
|
|
|
- width: calc(var(--s) * 98px);
|
|
|
- height: calc(var(--s) * 86px);
|
|
|
- background: center/contain no-repeat;
|
|
|
- filter: drop-shadow(0 0 calc(var(--s) * 12px) rgba(70, 190, 255, .35));
|
|
|
-}
|
|
|
-
|
|
|
-.label{
|
|
|
- margin-top: calc(var(--s) * 10px);
|
|
|
- font-size: calc(var(--s) * 16px);
|
|
|
- line-height: 1;
|
|
|
- opacity: .92;
|
|
|
- text-shadow: 0 0 calc(var(--s) * 8px) rgba(0, 160, 255, .25);
|
|
|
-}
|
|
|
-
|
|
|
-/* hover 细节:轻微发光 + label 提亮 */
|
|
|
-.dock-item:hover .icon{
|
|
|
- filter: drop-shadow(0 0 calc(var(--s) * 18px) rgba(120, 230, 255, .65));
|
|
|
-}
|
|
|
-.dock-item:hover .label{
|
|
|
- opacity: 1;
|
|
|
-}
|
|
|
-
|
|
|
/* 闪烁亮点 */
|
|
|
-.spark-layer{
|
|
|
- position:absolute;
|
|
|
- inset:0;
|
|
|
+.spark-layer {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
z-index: 4;
|
|
|
pointer-events: none;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
-.spark{
|
|
|
- position:absolute;
|
|
|
+
|
|
|
+.spark {
|
|
|
+ position: absolute;
|
|
|
border-radius: 999px;
|
|
|
background: radial-gradient(circle, rgba(140, 235, 255, .95), rgba(140, 235, 255, 0) 70%);
|
|
|
animation-name: twinkle;
|
|
|
animation-timing-function: ease-in-out;
|
|
|
animation-iteration-count: infinite;
|
|
|
}
|
|
|
-@keyframes twinkle{
|
|
|
- 0%{ transform: translateZ(0) scale(.7); opacity: .22; }
|
|
|
- 50%{ transform: translateZ(0) scale(1.25); opacity: .9; }
|
|
|
- 100%{ transform: translateZ(0) scale(.7); opacity: .22; }
|
|
|
-}
|
|
|
-
|
|
|
-/* 版权信息 */
|
|
|
-.copyright {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- font-size: 14px;
|
|
|
- color: #FFF;
|
|
|
- line-height: 30px;
|
|
|
- text-align: center;
|
|
|
- position: absolute;
|
|
|
- bottom: 20px;
|
|
|
- left: calc(50% - 35px);
|
|
|
- display: none;
|
|
|
-}
|
|
|
|
|
|
-.copyright::before,
|
|
|
-.copyright::after {
|
|
|
- content: "";
|
|
|
- display: block;
|
|
|
- width: 4px;
|
|
|
- height: 4px;
|
|
|
- border-radius: 2px;
|
|
|
- background: #e7e7e7;
|
|
|
-}
|
|
|
+@keyframes twinkle {
|
|
|
+ 0% {
|
|
|
+ transform: translateZ(0) scale(.7);
|
|
|
+ opacity: .22;
|
|
|
+ }
|
|
|
|
|
|
-.copyright::before {
|
|
|
- margin-right: 10px;
|
|
|
-}
|
|
|
+ 50% {
|
|
|
+ transform: translateZ(0) scale(1.25);
|
|
|
+ opacity: .9;
|
|
|
+ }
|
|
|
|
|
|
-.copyright::after {
|
|
|
- margin-left: 10px;
|
|
|
+ 100% {
|
|
|
+ transform: translateZ(0) scale(.7);
|
|
|
+ opacity: .22;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|