初始提交:三端设计文档与 dev 代码基线
docs/:系统梳理、架构优化方案、CR-02 三端功能设计修订(含 §15 三端一致性同步与平台统计分析)、公寓端/应用端/平台端分册、公寓统计分析与排名报表、公寓端小步迭代开发计划(IT-0~IT-8) dev/:RuoYi-Vue-master(后端)与 RuoYi-Vue2-master(前端)官方上游基线,未改动
This commit is contained in:
commit
329e27b515
723 files changed
+99917
No files matched your search
@@ -0,0 +1,505 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
由 YktVue/src/views/JcXx.vue 生成 JcXx.optimized.vue。
|
||||
|
||||
设计约束(与用户需求一一对应):
|
||||
1. <script> 段逐字节不变 —— 功能集合 100% 保留;
|
||||
2. <template> 只增加语义 class、修正一处事件名拼写,不增删任何元素/指令/绑定;
|
||||
3. <style> 原规则全部保留,仅修正 4 处明显错误,其余以「追加优化层」覆盖;
|
||||
4. 不引入新配色 / 新字体 / 新组件 / 新字段,全部取自本页既有设计语言。
|
||||
|
||||
同时输出校验与布局快照所需的中间产物到 docs/frontend/_src/。
|
||||
"""
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import hashlib
|
||||
|
||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
SRC = os.path.join(ROOT, 'YktVue', 'src', 'views', 'JcXx.vue')
|
||||
OUT = os.path.join(ROOT, 'YktVue', 'src', 'views', 'JcXx.optimized.vue')
|
||||
WORK = os.path.join(os.path.dirname(__file__))
|
||||
|
||||
src = io.open(SRC, encoding='utf-8').read()
|
||||
script_before = src[src.index('<script>'):src.index('</script>') + len('</script>')]
|
||||
|
||||
s = src
|
||||
|
||||
|
||||
def rep(text, old, new, tag, count=1):
|
||||
n = text.count(old)
|
||||
assert n == count, '[%s] 期望 %d 处,实际 %d 处' % (tag, n, count)
|
||||
return text.replace(old, new)
|
||||
|
||||
|
||||
# ============================================================ 1. template:语义 class
|
||||
s = rep(s, '<div class="app_contianer">',
|
||||
'<div class="app_contianer jc-opt-root">', '根容器 class')
|
||||
|
||||
s = rep(s, '<el-row style="height: 150px;" :gutter="15">',
|
||||
'<el-row class="jc-header-row" style="height: 150px;" :gutter="15">',
|
||||
'顶部行 class')
|
||||
|
||||
s = rep(s, '<el-col :span="9" style="height: 100%; display: flex; flex-direction: column; justify-content: center;">',
|
||||
'<el-col class="jc-header-search" :span="9" style="height: 100%; display: flex; flex-direction: column; justify-content: center;">',
|
||||
'顶部左列 class')
|
||||
|
||||
s = rep(s, '<el-col :span="6" style="height: 100%;">',
|
||||
'<el-col class="jc-header-time" :span="6" style="height: 100%;">',
|
||||
'顶部中列 class')
|
||||
|
||||
s = rep(s, '<el-col :span="9" style="height: 100%;">',
|
||||
'<el-col class="jc-header-actions" :span="9" style="height: 100%;">',
|
||||
'顶部右列 class')
|
||||
|
||||
s = rep(s, '<span style="font-size: 12px; color: #666;width: 45%;">当前用户: {{ loginAccount }}</span>',
|
||||
'<span class="jc-user-label" style="font-size: 12px; color: #666;width: 45%;">当前用户: {{ loginAccount }}</span>',
|
||||
'当前用户标签 class')
|
||||
|
||||
# Element UI 派发的是 tab-click;原写法 tab_click 永远不会被触发(处理函数体为空,修正后行为不变)
|
||||
s = rep(s, '@tab_click=handleTabClick', '@tab-click=handleTabClick', 'tab 事件名拼写')
|
||||
|
||||
# 状态列:仅加 class,文本与 v-if 链完全不变(行内底色已是状态语义色,
|
||||
# 这里只提升文字对比与字重,不把纯文字改成标签,保持原有信息呈现方式)
|
||||
old_state = """ <el-table-column prop="zt" label="状态" min-width="7%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.ryzt == '0'">待叫乘</span>
|
||||
<span v-else-if="scope.row.ryzt == '1'">正在呼叫</span>
|
||||
<span v-else-if="scope.row.ryzt == '5'">正在通话</span>
|
||||
<span v-else-if="scope.row.ryzt == '2'">叫乘报警</span>
|
||||
<span v-else-if="scope.row.ryzt == '3'">待离寓</span>
|
||||
<span v-else-if="scope.row.ryzt == '4'">离寓报警</span>
|
||||
<span v-else>已入寓</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
new_state = """ <el-table-column prop="zt" label="状态" min-width="7%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="jc-st jc-st-normal" v-if="scope.row.ryzt == '0'">待叫乘</span>
|
||||
<span class="jc-st jc-st-normal" v-else-if="scope.row.ryzt == '1'">正在呼叫</span>
|
||||
<span class="jc-st jc-st-normal" v-else-if="scope.row.ryzt == '5'">正在通话</span>
|
||||
<span class="jc-st jc-st-alarm" v-else-if="scope.row.ryzt == '2'">叫乘报警</span>
|
||||
<span class="jc-st jc-st-normal" v-else-if="scope.row.ryzt == '3'">待离寓</span>
|
||||
<span class="jc-st jc-st-alarm" v-else-if="scope.row.ryzt == '4'">离寓报警</span>
|
||||
<span class="jc-st jc-st-muted" v-else>已入寓</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
s = rep(s, old_state, new_state, '主表状态列 class')
|
||||
|
||||
old_dev = """ <el-table-column prop="heartBeatTime" label="状态" min-width="8%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.isOffline == '0'">在线</span>
|
||||
<span v-else-if="scope.row.isOffline == '1'">掉线</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
new_dev = """ <el-table-column prop="heartBeatTime" label="状态" min-width="8%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="jc-st jc-st-normal" v-if="scope.row.isOffline == '0'">在线</span>
|
||||
<span class="jc-st jc-st-alarm" v-else-if="scope.row.isOffline == '1'">掉线</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
s = rep(s, old_dev, new_dev, '设备状态列 class')
|
||||
|
||||
old_hist = """ <el-table-column prop="is_jcbj" label="叫乘报警" min-width="4%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.is_jcbj == '1'">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="is_lybj" label="离寓报警" min-width="4%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.is_lybj == '1'">是</span>
|
||||
<span v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
new_hist = """ <el-table-column prop="is_jcbj" label="叫乘报警" min-width="4%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="jc-st jc-st-alarm" v-if="scope.row.is_jcbj == '1'">是</span>
|
||||
<span class="jc-st jc-st-muted" v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="is_lybj" label="离寓报警" min-width="4%" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="jc-st jc-st-alarm" v-if="scope.row.is_lybj == '1'">是</span>
|
||||
<span class="jc-st jc-st-muted" v-else>否</span>
|
||||
</template>
|
||||
</el-table-column>"""
|
||||
s = rep(s, old_hist, new_hist, '历史报警列 class')
|
||||
|
||||
# 所有弹窗统一挂 jc-dialog(append-to-body 后仍在 body 下,必须靠自身 class 收口样式);
|
||||
# 1800/1700px 的宽弹窗额外挂 jc-wide-dialog 以做视口约束。
|
||||
dialog_re = re.compile(r'<el-dialog\b[^>]*?>', re.S)
|
||||
dialog_tags = dialog_re.findall(s)
|
||||
expected = s.count('<el-dialog')
|
||||
assert len(dialog_tags) == expected, 'el-dialog 标签解析数 %d != %d' % (len(dialog_tags), expected)
|
||||
|
||||
|
||||
def decorate_dialog(m):
|
||||
tag = m.group(0)
|
||||
wide = bool(re.search(r'width="(?:1800|1700)px"', tag))
|
||||
extra = 'jc-dialog' + (' jc-wide-dialog' if wide else '')
|
||||
cm = re.search(r'\bclass="([^"]*)"', tag)
|
||||
if cm:
|
||||
merged = extra + (' ' + cm.group(1) if cm.group(1).strip() else '')
|
||||
return tag[:cm.start()] + 'class="' + merged + '"' + tag[cm.end():]
|
||||
return tag.replace('<el-dialog', '<el-dialog class="' + extra + '"', 1)
|
||||
|
||||
|
||||
s = dialog_re.sub(decorate_dialog, s)
|
||||
print('弹窗装饰:%d 个(其中宽弹窗 %d 个)' % (
|
||||
expected, s.count('jc-wide-dialog')))
|
||||
|
||||
# ============================================================ 2. style:4 处错误修正
|
||||
# (a) margin-top: -2 缺单位,是无效声明(2 处)
|
||||
s = rep(s, 'margin-top: -2;', 'margin-top: 0;', '无效负边距归零', count=2)
|
||||
# (b) 同一 :hover 位移被重复定义为 -1px / -2px,统一为 -1px
|
||||
s = rep(s, 'transform: translateY(-2px) !important;',
|
||||
'transform: translateY(-1px) !important;', 'hover 位移统一')
|
||||
# (c) 所有渐变按钮 hover 被强制刷成蓝色渐变,破坏橙/深青/红按钮的语义色
|
||||
old_hover = """/* 查询按钮特殊样式 */
|
||||
.el-button[style*="linear-gradient"]:hover {
|
||||
background: linear-gradient(135deg, #66b3ff, #409EFF) !important;
|
||||
box-shadow: 0 8px 25px rgba(64, 158, 255, 0.5) !important;
|
||||
}"""
|
||||
new_hover = """/* 查询按钮特殊样式(修正:保留按钮自身渐变,只做亮度与阴影反馈) */
|
||||
.el-button[style*="linear-gradient"]:hover {
|
||||
filter: brightness(1.08) !important;
|
||||
box-shadow: 0 8px 25px rgba(11, 88, 88, 0.28) !important;
|
||||
}"""
|
||||
s = rep(s, old_hover, new_hover, '渐变按钮 hover 配色修正')
|
||||
|
||||
# ============================================================ 3. 追加体验优化层
|
||||
OPT_CSS = r"""
|
||||
|
||||
/* ==========================================================================
|
||||
JcXx.vue 体验与可用性优化层 v1
|
||||
--------------------------------------------------------------------------
|
||||
只修六类问题:布局拥挤/留白失衡、对齐间距不一致、信息层级、
|
||||
交互反馈缺失、状态提示不明确、多尺寸适配。
|
||||
· 不新增/删减/替换任何功能,<script> 逐字节未改;
|
||||
· 不引入新配色:所有色值取自本页原有样式
|
||||
(#029191 深青 / #0b5858 深青 / #fff45c 黄 / #2c3e50 墨 /
|
||||
#c45656 红 / #606266 灰 / #dcdfe6 边框 / #1990f1 选中蓝);
|
||||
· 不改动字号基准、组件形态与信息呈现方式,仅统一不一致处并补齐断点;
|
||||
· 新增规则统一以 .jc-opt-root / .jc-dialog 收口,不扩大原全局样式的影响面。
|
||||
原样式规则完整保留在前,本层可整段移除以回到优化前效果。
|
||||
========================================================================== */
|
||||
|
||||
/* ---- O1 顶部:固定 150px + 40px 跑马灯上边距造成的拥挤与留白失衡 ---- */
|
||||
.jc-header-row{
|
||||
height:auto !important;
|
||||
min-height:150px;
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
align-items:stretch;
|
||||
}
|
||||
.jc-header-row > .el-col{
|
||||
height:auto !important;
|
||||
min-height:150px;
|
||||
float:none;
|
||||
}
|
||||
.jc-header-search{
|
||||
justify-content:flex-start !important;
|
||||
padding:4px 0 8px;
|
||||
}
|
||||
.jc-header-time{
|
||||
display:flex !important;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
.jc-header-time > .el-row{ width:100%; }
|
||||
.jc-header-actions{ padding:2px 0; }
|
||||
.top-left-marquee-row{ margin-top:10px !important; margin-bottom:8px !important; }
|
||||
.top-left-search-area{
|
||||
padding:8px 14px 10px !important;
|
||||
justify-content:flex-start !important;
|
||||
}
|
||||
.top-left-input-row{ margin-top:0 !important; margin-bottom:10px !important; }
|
||||
.top-left-action-row{ margin-top:0 !important; }
|
||||
.form-item-container{ padding:0 6px; }
|
||||
/* 原跑马灯 padding-left:100% + translateX(0) 起步,开屏数秒内整条提示为空。
|
||||
用负动画延时把滚动相位提前,文案/配色/组件/速度全部不变。 */
|
||||
.marquee-content{ animation-delay:-4s; }
|
||||
.center-time-section{
|
||||
width:calc(100% - 30px);
|
||||
box-sizing:border-box;
|
||||
margin:0 15px;
|
||||
}
|
||||
.date-time{ width:100%; }
|
||||
/* 右上按钮组:等间距、窄屏可换行,避免互相挤压与文字截断 */
|
||||
.jc-header-actions .el-row > .el-col > div{
|
||||
flex-wrap:wrap;
|
||||
gap:8px !important;
|
||||
}
|
||||
.jc-header-actions .el-button{ flex:0 0 auto; }
|
||||
.jc-user-label{
|
||||
width:auto !important;
|
||||
white-space:nowrap;
|
||||
color:#606266 !important;
|
||||
font-size:12px !important;
|
||||
}
|
||||
|
||||
/* ---- O2 表单/弹窗:label 宽度 25%/20%/96px 混用导致对齐不一致 ---- */
|
||||
.jc-opt-root .el-form label[style*="width:25%"],
|
||||
.jc-opt-root .el-form label[style*="width:20%"],
|
||||
.jc-dialog .el-form label[style*="width:25%"],
|
||||
.jc-dialog .el-form label[style*="width:20%"]{
|
||||
flex:0 0 96px;
|
||||
width:96px !important;
|
||||
min-width:96px;
|
||||
text-align:center;
|
||||
white-space:nowrap;
|
||||
line-height:20px;
|
||||
}
|
||||
.jc-opt-root .el-form .el-col > .el-input,
|
||||
.jc-opt-root .el-form .el-col > .el-select,
|
||||
.jc-opt-root .el-form .el-col > div > .el-input,
|
||||
.jc-opt-root .el-form .el-col > div > .el-select,
|
||||
.jc-dialog .el-form .el-col > .el-input,
|
||||
.jc-dialog .el-form .el-col > .el-select,
|
||||
.jc-dialog .el-form .el-col > div > .el-input,
|
||||
.jc-dialog .el-form .el-col > div > .el-select{
|
||||
flex:1 1 0;
|
||||
min-width:0;
|
||||
}
|
||||
.jc-dialog .el-form-item{ margin-bottom:16px; }
|
||||
.jc-dialog .el-dialog__footer .el-button + .el-button{ margin-left:12px; }
|
||||
/* 宽弹窗 1800/1700px 在 1366 及以下屏幕会横向越界 */
|
||||
.jc-wide-dialog .el-dialog{
|
||||
max-width:calc(100vw - 32px) !important;
|
||||
}
|
||||
|
||||
/* ---- O3 交互反馈:焦点、hover、禁用 ---- */
|
||||
.el-button:hover{ transform:translateY(-1px) !important; }
|
||||
/* 焦点轮廓:element-ui 自身把 outline 压掉了,这里用本页作用域 + !important 补回 */
|
||||
.jc-opt-root .el-button:focus,
|
||||
.jc-opt-root .el-button:focus-visible,
|
||||
.jc-opt-root .el-input__inner:focus,
|
||||
.jc-opt-root .el-input__inner:focus-visible,
|
||||
.jc-opt-root .el-checkbox__inner:focus,
|
||||
.jc-dialog .el-button:focus,
|
||||
.jc-dialog .el-button:focus-visible,
|
||||
.jc-dialog .el-input__inner:focus,
|
||||
.jc-dialog .el-input__inner:focus-visible,
|
||||
.jc-dialog .el-checkbox__inner:focus{
|
||||
outline:2px solid #029191 !important;
|
||||
outline-offset:2px !important;
|
||||
}
|
||||
/* 部分浏览器对 input 的 outline 计算值有限制,补一层主色光晕保证焦点可见 */
|
||||
.jc-opt-root .el-input__inner:focus,
|
||||
.jc-opt-root .el-input__inner:focus-visible,
|
||||
.jc-dialog .el-input__inner:focus,
|
||||
.jc-dialog .el-input__inner:focus-visible{
|
||||
box-shadow:0 0 0 3px rgba(2,145,145,.22) !important;
|
||||
}
|
||||
.el-button.is-disabled,
|
||||
.el-button[disabled]{
|
||||
cursor:not-allowed !important;
|
||||
opacity:.55;
|
||||
filter:grayscale(.25);
|
||||
}
|
||||
.el-button.is-disabled:hover,
|
||||
.el-button[disabled]:hover{
|
||||
transform:none !important;
|
||||
box-shadow:none !important;
|
||||
}
|
||||
|
||||
/* ---- O4 表格:保留行内状态底色,补齐 hover / 选中反馈与列层级 ----
|
||||
原 .el-table__body tr:hover > td 用 background-color:inherit!important
|
||||
是为了让 td 继承 tr 上的行内状态色(黄/绿/红/蓝),机制必须保留;
|
||||
这里只叠加一层半透明 background-image 提供 hover 反馈,不覆盖底色。 */
|
||||
.jc-opt-root .main-jcxx-table .el-table__body tr:hover > td,
|
||||
.jc-dialog .el-table__body tr:hover > td{
|
||||
background-image:linear-gradient(rgba(2,145,145,.10), rgba(2,145,145,.10)) !important;
|
||||
}
|
||||
/* 选中行原先用纯蓝底 !important 覆盖,会把报警红/到点黄整行抹掉。
|
||||
改为「继承行内状态色 + 叠加蓝层 + 首列蓝条」,选中态与状态色可同时辨识。 */
|
||||
.jc-opt-root .el-table__body tr.current-row > td,
|
||||
.jc-dialog .el-table__body tr.current-row > td,
|
||||
.jc-dialog .history-jcxx-table.el-table--striped .el-table__body tr.current-row > td,
|
||||
.jc-dialog .history-jcxx-table.el-table--striped .el-table__body tr.current-row.el-table__row--striped > td{
|
||||
background-color:inherit !important;
|
||||
background-image:linear-gradient(rgba(25,144,241,.30), rgba(25,144,241,.30)) !important;
|
||||
color:inherit !important;
|
||||
}
|
||||
.jc-opt-root .el-table__body tr.current-row > td:first-child,
|
||||
.jc-dialog .el-table__body tr.current-row > td:first-child{
|
||||
box-shadow:inset 3px 0 0 #1990f1;
|
||||
}
|
||||
/* 状态文字:行内底色已承担语义色,这里只提升字重与对比,不改成标签 */
|
||||
.jc-st{ font-weight:700; letter-spacing:.3px; }
|
||||
.jc-st-normal{ color:#2c3e50; }
|
||||
.jc-st-alarm{ color:#ffffff; text-shadow:0 1px 2px rgba(0,0,0,.35); }
|
||||
.jc-st-muted{ color:#606266; }
|
||||
.jc-opt-root .main-jcxx-table th.el-table__cell{
|
||||
font-weight:700 !important;
|
||||
border-bottom:2px solid #029191 !important;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.jc-opt-root .main-jcxx-table .cell{ padding-left:6px; padding-right:6px; }
|
||||
.jc-opt-root .el-tabs__item{ font-weight:600; }
|
||||
|
||||
/* ---- O5 吸底值班条:absolute 居中在窄屏与左右内容重叠 ---- */
|
||||
.jc-opt-root{ padding-bottom:62px; } /* 防止 50px 吸底条遮住表格最后一行 */
|
||||
.bottom-duty-bar{
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:16px;
|
||||
padding:0 20px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.bottom-stay-summary{
|
||||
flex:1 1 auto;
|
||||
gap:36px;
|
||||
padding-left:0;
|
||||
min-width:0;
|
||||
}
|
||||
.latest-sync-time{
|
||||
position:static !important;
|
||||
transform:none !important;
|
||||
flex:0 1 auto;
|
||||
white-space:nowrap;
|
||||
}
|
||||
.bottom-duty-info{
|
||||
flex:1 1 auto;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:flex-end;
|
||||
gap:16px;
|
||||
min-width:0;
|
||||
}
|
||||
.bottom-duty-info .el-button{
|
||||
position:static !important;
|
||||
right:auto !important;
|
||||
top:auto !important;
|
||||
flex:0 0 auto;
|
||||
}
|
||||
.bottom-duty-info > span{
|
||||
margin-right:0 !important;
|
||||
position:static !important;
|
||||
top:auto !important;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
/* ---- O6 右下角「有新的交路信息」提示:改为固定定位并补齐点击反馈 ----
|
||||
原为 200x200 的 absolute 大色块,滚动后位置漂移且易被吸底条压住。 */
|
||||
.bottom-right-div{
|
||||
position:fixed !important;
|
||||
bottom:72px;
|
||||
right:20px;
|
||||
width:200px;
|
||||
height:auto;
|
||||
box-sizing:border-box;
|
||||
padding:14px 16px;
|
||||
line-height:1.5;
|
||||
text-align:center;
|
||||
border:2px solid #029191;
|
||||
box-shadow:0 6px 18px rgba(0,0,0,.18);
|
||||
z-index:1200;
|
||||
cursor:pointer;
|
||||
transition:transform .25s ease, box-shadow .25s ease;
|
||||
}
|
||||
.bottom-right-div:hover{
|
||||
transform:translateY(-2px);
|
||||
box-shadow:0 10px 24px rgba(0,0,0,.24);
|
||||
}
|
||||
|
||||
/* ---- O7 响应式:原页只有 1200/768 两档,且顶部 9/6/9 在中屏严重挤压 ---- */
|
||||
@media (max-width:1440px){
|
||||
.jc-header-row{ min-height:0; }
|
||||
.jc-header-row > .el-col{ min-height:0; }
|
||||
.jc-header-row > .jc-header-search{ flex:1 1 100%; width:100%; }
|
||||
.jc-header-row > .jc-header-time{ flex:0 0 320px; width:320px; }
|
||||
.jc-header-row > .jc-header-actions{ flex:1 1 520px; width:auto; }
|
||||
.center-time-section{ min-width:0; }
|
||||
}
|
||||
@media (max-width:1200px){
|
||||
.bottom-stay-summary{ gap:20px; }
|
||||
.bottom-stay-summary,.latest-sync-time{ font-size:20px; }
|
||||
.bottom-duty-info > span{ font-size:20px !important; }
|
||||
/* 窄屏下 200px 卡片会压住表格右下数据,收紧为贴边小卡 */
|
||||
.bottom-right-div{
|
||||
width:150px;
|
||||
right:8px;
|
||||
bottom:62px;
|
||||
padding:8px 10px;
|
||||
font-size:14px !important;
|
||||
line-height:1.35;
|
||||
opacity:.96;
|
||||
}
|
||||
}
|
||||
@media (max-width:992px){
|
||||
.jc-header-row > .jc-header-time,
|
||||
.jc-header-row > .jc-header-actions{ flex:1 1 100%; width:100%; }
|
||||
.jc-header-row .top-left-input-row .el-col-6{ width:50%; }
|
||||
.bottom-duty-bar{
|
||||
flex-wrap:wrap;
|
||||
height:auto !important;
|
||||
min-height:50px;
|
||||
padding:6px 12px;
|
||||
gap:4px 12px;
|
||||
}
|
||||
.bottom-stay-summary,.latest-sync-time,.bottom-duty-info > span{
|
||||
font-size:16px !important;
|
||||
line-height:1.4;
|
||||
}
|
||||
.latest-sync-time{ flex:1 1 100%; order:3; text-align:right; }
|
||||
.jc-opt-root{ padding-bottom:88px; }
|
||||
.bottom-right-div{ bottom:96px; }
|
||||
}
|
||||
@media (max-width:768px){
|
||||
.jc-header-row .top-left-input-row .el-col-6{ width:100%; }
|
||||
.bottom-right-div{ width:160px; font-size:16px !important; }
|
||||
}
|
||||
/* 矮屏:600px 固定表高 + 50px 吸底条会溢出,改为可滚动,不改变数据/列/操作 */
|
||||
@media (max-height:900px){
|
||||
.jc-opt-root .main-jcxx-table{
|
||||
height:auto !important;
|
||||
max-height:calc(100vh - 260px);
|
||||
}
|
||||
.jc-opt-root .main-jcxx-table .el-table__body-wrapper{
|
||||
height:auto !important;
|
||||
max-height:calc(100vh - 320px);
|
||||
overflow-y:auto;
|
||||
}
|
||||
.jc-dialog .el-dialog__body{
|
||||
max-height:calc(100vh - 170px);
|
||||
overflow-y:auto;
|
||||
}
|
||||
}
|
||||
@media (prefers-reduced-motion:reduce){
|
||||
.marquee-content{
|
||||
animation:none !important;
|
||||
padding-left:0 !important; /* 停动画时必须去掉右推,否则整条提示不可见 */
|
||||
}
|
||||
.init-success-content i{ animation:none !important; }
|
||||
.el-button,
|
||||
.bottom-right-div{ transition:none !important; }
|
||||
.el-button:hover{ transform:none !important; }
|
||||
}
|
||||
/* ===================== 体验优化层结束 ===================== */
|
||||
"""
|
||||
|
||||
s = rep(s, '</style>', OPT_CSS + '</style>', '追加优化层')
|
||||
|
||||
# ============================================================ 4. 写出
|
||||
# 原文件为 CRLF;写出时保持同一换行,避免全文件 diff / 逐字节比对误报
|
||||
out_text = s.replace('\n', '\r\n')
|
||||
io.open(OUT, 'w', encoding='utf-8', newline='').write(out_text)
|
||||
|
||||
script_after = s[s.index('<script>'):s.index('</script>') + len('</script>')]
|
||||
assert script_before == script_after, '<script> 段发生变化,已中止'
|
||||
print('<script> 段逐字节一致:%d 字节 sha256=%s' % (
|
||||
len(script_before.encode('utf-8')),
|
||||
hashlib.sha256(script_before.encode('utf-8')).hexdigest()[:16]))
|
||||
|
||||
# 中间产物:优化前 / 优化后的 style 源(供 sass 编译与前后对比快照使用)
|
||||
def extract_style(text):
|
||||
a = text.index('<style')
|
||||
b = text.index('</style>')
|
||||
return text[text.index('>', a) + 1:b]
|
||||
|
||||
io.open(os.path.join(WORK, 'style-before.scss'), 'w', encoding='utf-8').write(extract_style(src))
|
||||
io.open(os.path.join(WORK, 'style-after.scss'), 'w', encoding='utf-8').write(extract_style(s))
|
||||
|
||||
print('输出:%s(%d 行 / %d 字节 / CRLF)' % (OUT, len(s.splitlines()), len(out_text.encode('utf-8'))))
|
||||
print('原文件:%d 行 / %d 字节' % (len(src.splitlines()), os.path.getsize(SRC)))
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,839 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">
|
||||
<title>JcXx 优化前</title>
|
||||
<style>@charset "UTF-8";@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format("woff"),url(fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.elLine truncated
|
||||
<style>@charset "UTF-8";
|
||||
.marquee-container {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.top-left-marquee-row {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.top-left-search-area {
|
||||
padding-top: 6px !important;
|
||||
}
|
||||
|
||||
.top-left-input-row {
|
||||
margin-top: -2;
|
||||
}
|
||||
|
||||
.top-left-action-row {
|
||||
margin-top: -2;
|
||||
}
|
||||
|
||||
/* 中间时间信息区域 */
|
||||
.center-time-section {
|
||||
flex: 0 0 auto;
|
||||
background: linear-gradient(135deg, #0078d7, #107c10);
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
margin: 0 15px;
|
||||
min-width: 320px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.date-time {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.date-time .text-24 {
|
||||
font-size: 26px !important;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.center-time-section {
|
||||
min-width: 280px;
|
||||
padding: 10px 14px;
|
||||
}
|
||||
|
||||
.date-time .text-24 {
|
||||
font-size: 24px !important;
|
||||
}
|
||||
|
||||
.date-time {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.center-time-section {
|
||||
min-width: 240px;
|
||||
padding: 8px 12px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.date-time .text-24 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.date-time {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
/* ============ 右下角初始化提示 ============ */
|
||||
.init-success-tip {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
z-index: 2000;
|
||||
background: linear-gradient(135deg, #67c23a, #85ce61);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 30px rgba(103, 194, 58, 0.3);
|
||||
animation: slideInUp 0.6s ease-out;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.init-success-content i {
|
||||
font-size: 18px;
|
||||
margin-right: 8px;
|
||||
animation: successPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes successPulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
/* ============ 表单样式(缩小版) ============ */
|
||||
.form-item-container {
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-item-container .el-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
border-radius: 6px !important;
|
||||
border: 1px solid #dcdfe6 !important;
|
||||
padding: 8px 12px !important;
|
||||
font-size: 13px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
background: white;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner:focus {
|
||||
border-color: #409EFF !important;
|
||||
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner:hover {
|
||||
border-color: #c0c4cc !important;
|
||||
}
|
||||
|
||||
/* 按钮行样式(缩小版)*/
|
||||
.el-button {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
height: 32px !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.el-button:hover {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.el-button:active {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
.buttonFont-small {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 响应式表单设置 */
|
||||
@media (max-width: 1200px) {
|
||||
.form-label {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
padding: 7px 10px !important;
|
||||
font-size: 12px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.init-success-tip {
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
padding: 10px 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.form-item-container {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
padding: 6px 8px !important;
|
||||
font-size: 11px !important;
|
||||
height: 28px !important;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
font-size: 11px !important;
|
||||
height: 28px !important;
|
||||
padding: 4px 12px !important;
|
||||
}
|
||||
|
||||
.buttonFont-small {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.init-success-tip {
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
padding: 8px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.init-success-content i {
|
||||
font-size: 14px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.marquee-content {
|
||||
display: inline-block;
|
||||
animation: marquee 28s linear infinite;
|
||||
padding-left: 100%;
|
||||
color: #fff45c;
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
line-height: 36px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.marquee-repeat-text {
|
||||
margin-left: 160px;
|
||||
}
|
||||
|
||||
@keyframes warningBlink {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
background-color: #FFF200;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
@keyframes marquee {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-200%);
|
||||
}
|
||||
}
|
||||
.el-table__body tr:hover > td {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table th.el-table__cell {
|
||||
padding-top: 6px !important;
|
||||
padding-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table td.el-table__cell {
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table .cell {
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
column-gap: 6px;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row:first-child {
|
||||
column-gap: 2px;
|
||||
}
|
||||
|
||||
.history-jcxx-field-box {
|
||||
width: 226px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-inline-label {
|
||||
width: 58px;
|
||||
padding-right: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 30px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
color: #606266;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-field-box .el-input {
|
||||
width: 146px;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row + .history-jcxx-form-row {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.history-jcxx-query-button {
|
||||
margin-left: 4px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-box {
|
||||
width: 230px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-label {
|
||||
width: 72px;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-box .el-select {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.history-jcxx-time-box {
|
||||
width: 610px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-time-label {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.history-jcxx-time-range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: nowrap;
|
||||
width: 540px;
|
||||
}
|
||||
|
||||
.history-jcxx-count {
|
||||
min-width: 180px;
|
||||
margin-left: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-form .el-input__inner,
|
||||
.history-jcxx-form .el-date-editor.el-input__inner,
|
||||
.history-jcxx-form .el-date-editor .el-range-input,
|
||||
.history-jcxx-form .el-date-editor .el-range-separator {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form .el-input__inner,
|
||||
.history-jcxx-form .el-date-editor.el-input__inner,
|
||||
.history-jcxx-form .el-date-editor--datetimerange {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form .el-date-editor .el-range__icon,
|
||||
.history-jcxx-form .el-date-editor .el-range__close-icon {
|
||||
line-height: 22px !important;
|
||||
}
|
||||
|
||||
.jc-update-dialog .el-dialog {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col > label {
|
||||
flex: 0 0 96px;
|
||||
width: 96px !important;
|
||||
min-width: 96px;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col > .el-input,
|
||||
.jc-update-form .el-row .el-col > .el-select {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.jc-update-room {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.jc-update-room > .el-button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.history-jcxx-table th.el-table__cell {
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-table td.el-table__cell {
|
||||
padding-top: 4px !important;
|
||||
padding-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-load-tip {
|
||||
padding: 8px 0 2px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.history-jcxx-table .cell {
|
||||
line-height: 1.15 !important;
|
||||
}
|
||||
|
||||
.leave-snapshot-preview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.leave-snapshot-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 560px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.leave-snapshot-empty {
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.item1 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.bottom-right-div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
padding: 10px;
|
||||
font-size: 20px;
|
||||
background-color: #a6b8ac;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.Dialog_JcEvent .el-dialog {
|
||||
position: fixed;
|
||||
top: -100px;
|
||||
left: 100px;
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
.Dialog_AlarmEvent .el-dialog {
|
||||
background-color: #cc7b10;
|
||||
}
|
||||
|
||||
.buttonFont {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.app_contianer {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.bottom-duty-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #029191;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.bottom-stay-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 80px;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.bottom-stay-summary,
|
||||
.latest-sync-time {
|
||||
color: #fff45c;
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
line-height: 50px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.35);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.latest-sync-time {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bottom-duty-info {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.el-table__body tr.current-row > td {
|
||||
background-color: #1990f1 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.history-jcxx-table .el-table__body tr.current-row > td {
|
||||
background-color: #0b7dda !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.history-jcxx-table.el-table--striped .el-table__body tr.current-row > td,
|
||||
.history-jcxx-table.el-table--striped .el-table__body tr.current-row.el-table__row--striped > td {
|
||||
background-color: #0b7dda !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.red-mask {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.record-button-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.record-button {
|
||||
margin-left: 0 !important;
|
||||
width: 58px;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
/* 合并后的交路及叫乘提醒。 */
|
||||
.sync-warning-dialog .el-dialog {
|
||||
min-width: 620px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.sync-warning-dialog .el-dialog__header {
|
||||
background: #fff7e6;
|
||||
border-bottom: 1px solid #f5c26b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sync-warning-dialog .el-dialog__title {
|
||||
color: #b45309;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sync-warning-content {
|
||||
max-height: 56vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sync-warning-section + .sync-warning-section {
|
||||
margin-top: 16px;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.sync-warning-category {
|
||||
margin-bottom: 8px;
|
||||
color: #b45309;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sync-warning-category i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sync-warning-item {
|
||||
padding: 5px 0 5px 26px;
|
||||
color: #303133;
|
||||
font-size: 17px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
/* ============ 优化按钮样式 ============ */
|
||||
.el-button {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.el-button:hover {
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: 0 8px 20px rgba(64, 158, 255, 0.4) !important;
|
||||
}
|
||||
|
||||
.el-button:active {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
/* 查询按钮特殊样式 */
|
||||
.el-button[style*=linear-gradient]:hover {
|
||||
background: linear-gradient(135deg, #66b3ff, #409EFF) !important;
|
||||
box-shadow: 0 8px 25px rgba(64, 158, 255, 0.5) !important;
|
||||
}
|
||||
|
||||
.el-button[style*=linear-gradient]:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.el-button[style*=linear-gradient]:hover:before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* 响应式按钮优化 */
|
||||
@media (max-width: 768px) {
|
||||
.el-button[style*=margin-left] {
|
||||
margin-left: 20px !important;
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
.person-photo-panel {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.person-photo-item {
|
||||
width: 180px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.person-photo-title {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.person-photo-img {
|
||||
width: 150px;
|
||||
height: 200px;
|
||||
object-fit: cover;
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.jl-add-dialog .el-dialog {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > label,
|
||||
.jl-add-form .el-row .el-col > div > label {
|
||||
flex: 0 0 96px;
|
||||
width: 96px !important;
|
||||
min-width: 96px;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > .el-input,
|
||||
.jl-add-form .el-row .el-col > .el-select,
|
||||
.jl-add-form .el-row .el-col > .el-date-editor,
|
||||
.jl-add-form .el-row .el-col > div > .el-input,
|
||||
.jl-add-form .el-row .el-col > div > .el-select,
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor {
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div > .el-input,
|
||||
.jl-add-form .el-row .el-col > div > .el-select,
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor,
|
||||
.jl-add-form .el-row .el-col > div > .el-time-picker {
|
||||
width: 100% !important;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor .el-input__inner {
|
||||
width: 100%;
|
||||
}</style>
|
||||
<style>body{margin:0;background:#f3f6f5}#app{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei",Arial,sans-serif}
|
||||
/* 快照专用:模拟 el-table 运行时的内部横向滚动,避免 15 列被静态表格压扁 */
|
||||
.main-jcxx-table .el-table__header-wrapper,
|
||||
.main-jcxx-table .el-table__body-wrapper{overflow-x:auto}
|
||||
.main-jcxx-table table{min-width:1500px}
|
||||
</style>
|
||||
</head><body><div class="app_contianer jc-opt-root" id="app">
|
||||
<div class="el-card"><div class="el-card__body">
|
||||
<div class="el-row jc-header-row" style="height:150px;margin-left:-7.5px;margin-right:-7.5px">
|
||||
<div class="el-col el-col-9 jc-header-search" style="height:100%;display:flex;flex-direction:column;justify-content:center;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row top-left-marquee-row" style="height:30%;margin-top:40px">
|
||||
<div class="marquee-container" style="background-color:rgb(2,145,145);height:100%">
|
||||
<div class="marquee-content"><span>305 房间叫乘时间已过,请值班员关注</span><span class="marquee-repeat-text">305 房间叫乘时间已过,请值班员关注</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-left-search-area" style="flex:1;display:flex;flex-direction:column;justify-content:center;padding:10px 20px">
|
||||
<div class="el-row top-left-input-row" style="margin-bottom:15px"><div class="el-col el-col-6" style="padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="form-item-container"><label class="form-label">机车号</label>
|
||||
<div class="el-input"><input class="el-input__inner" placeholder="请输入机车号" id="q0"></div></div></div><div class="el-col el-col-6" style="padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="form-item-container"><label class="form-label">车次</label>
|
||||
<div class="el-input"><input class="el-input__inner" placeholder="请输入车次" id="q1"></div></div></div><div class="el-col el-col-6" style="padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="form-item-container"><label class="form-label">房间号</label>
|
||||
<div class="el-input"><input class="el-input__inner" placeholder="请输入房间号" id="q2"></div></div></div><div class="el-col el-col-6" style="padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="form-item-container"><label class="form-label">姓名</label>
|
||||
<div class="el-input"><input class="el-input__inner" placeholder="请输入姓名" id="q3"></div></div></div></div>
|
||||
<div class="el-row top-left-action-row">
|
||||
<div class="el-col el-col-24" style="display:flex;justify-content:space-between;align-items:center">
|
||||
<button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;"><span class="buttonFont-small">取消叫乘</span></button>
|
||||
<div style="display:flex;align-items:center;gap:12px"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #409EFF, #66b3ff); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(64,158,255,.3); color: white;"><span class="buttonFont-small">查询</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #909399, #b1b3b8); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(144,147,153,.3); color: white;"><span class="buttonFont-small">重置</span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-col el-col-6 jc-header-time" style="height:100%;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row"><div class="center-time-section"><div class="date-time">
|
||||
<p class="text-24 text-white">2026-11-09 星期一<br>09:03:21</p>
|
||||
</div></div></div>
|
||||
</div>
|
||||
<div class="el-col el-col-9 jc-header-actions" style="height:100%;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row" style="height:50%;padding:8px 20px 8px 0px;display:flex;align-items:center">
|
||||
<div class="el-col el-col-18"><div style="display:flex;gap:5px;justify-content:space-between;align-items:center"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;height:32px;"><span class="buttonFont-small">房间信息</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;height:32px;"><span class="buttonFont-small">设备信息</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;height:32px;"><span class="buttonFont-small">人员维护</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;height:32px;"><span class="buttonFont-small">交路管理</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;height:32px;"><span class="buttonFont-small">历史数据</span></button></div></div>
|
||||
<div class="el-col el-col-1"></div>
|
||||
<div class="el-col el-col-5"><div style="display:flex;align-items:center;gap:3px">
|
||||
<span class="jc-user-label" style="font-size:12px;color:#666;width:45%">当前用户: 张值班</span>
|
||||
<button class="el-button el-button--small" style="background: linear-gradient(135deg, #f56c6c, #ff7979); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(245,108,108,.3); color: white;height:32px;width:55%;"><span class="buttonFont-small">退出</span></button>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="el-row" style="height:50%;padding:8px 20px 8px 0px;display:flex;align-items:center">
|
||||
<div class="el-col el-col-7"><div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-start"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;width:84px;"><span class="buttonFont-small">换乘</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;width:84px;"><span class="buttonFont-small">出乘</span></button></div></div>
|
||||
<div class="el-col el-col-17"><div style="display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-start;margin-left:14px"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;"><span class="buttonFont-small">语音临叫</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;"><span class="buttonFont-small">喊话临叫</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;"><span class="buttonFont-small">停止呼叫</span></button><button class="el-button el-button--small" style="background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;height:32px;"><span class="buttonFont-small">停止报警</span></button></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="el-card" style="margin-top:10px"><div class="el-card__body">
|
||||
<div class="el-tabs el-tabs--card"><div class="el-tabs__header is-top"><div class="el-tabs__nav-wrap"><div class="el-tabs__nav-scroll">
|
||||
<div class="el-tabs__nav is-top"><div class="el-tabs__item is-top is-active">机务人员和客运人员</div><div class="el-tabs__item is-top">其他人员</div></div>
|
||||
</div></div></div></div>
|
||||
<div class="el-table main-jcxx-table el-table--border" style="width:100%;height:600px">
|
||||
<div class="el-table__header-wrapper"><table class="el-table__header" style="width:100%"><thead><tr style="height:54px"><th class="el-table__cell"><div class="cell">序号</div></th><th class="el-table__cell"><div class="cell">状态</div></th><th class="el-table__cell"><div class="cell">到寓时间</div></th><th class="el-table__cell"><div class="cell">单位</div></th><th class="el-table__cell"><div class="cell">机车号</div></th><th class="el-table__cell"><div class="cell">姓名</div></th><th class="el-table__cell"><div class="cell">房间号</div></th><th class="el-table__cell"><div class="cell">出发车次</div></th><th class="el-table__cell"><div class="cell">开车时间</div></th><th class="el-table__cell"><div class="cell">叫乘时间</div></th><th class="el-table__cell"><div class="cell">复叫时间</div></th><th class="el-table__cell"><div class="cell">叫乘日期</div></th><th class="el-table__cell"><div class="cell">应离寓时间</div></th><th class="el-table__cell"><div class="cell">接车方式</div></th><th class="el-table__cell"><div class="cell">操作</div></th></tr></thead></table></div>
|
||||
<div class="el-table__body-wrapper" style="height:546px"><table class="el-table__body" style="width:100%"><tbody><tr class="el-table__row current-row" style="background-color:#F56C6C;font-size:20px;font-weight:600"><td class="el-table__cell"><div class="cell">1</div></td><td class="el-table__cell"><div class="cell"><span class="jc-st jc-st-alarm">叫乘报警</span></div></td><td class="el-table__cell"><div class="cell">11-08 21:40</div></td><td class="el-table__cell"><div class="cell">机务段</div></td><td class="el-table__cell"><div class="cell">HXD3C-0131</div></td><td class="el-table__cell"><div class="cell">冯建国</div></td><td class="el-table__cell"><div class="cell">305</div></td><td class="el-table__cell"><div class="cell">K671</div></td><td class="el-table__cell"><div class="cell">08:35</div></td><td class="el-table__cell"><div class="cell">06:35</div></td><td class="el-table__cell"><div class="cell">06:45</div></td><td class="el-table__cell"><div class="cell">11-09</div></td><td class="el-table__cell"><div class="cell">07:05</div></td><td class="el-table__cell"><div class="cell">站接</div></td><td class="el-table__cell"><div class="cell"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #409EFF, #66b3ff); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(64,158,255,.3); color: white;height:28px;"><span class="buttonFont-small">暂停报警</span></button></div></td></tr><tr class="el-table__row" style="background-color:#00FF00;font-size:20px;font-weight:600"><td class="el-table__cell"><div class="cell">2</div></td><td class="el-table__cell"><div class="cell"><span class="jc-st jc-st-normal">正在呼叫</span></div></td><td class="el-table__cell"><div class="cell">11-08 22:05</div></td><td class="el-table__cell"><div class="cell">机务段</div></td><td class="el-table__cell"><div class="cell">HXD3C-0132</div></td><td class="el-table__cell"><div class="cell">蒋卫东</div></td><td class="el-table__cell"><div class="cell">517</div></td><td class="el-table__cell"><div class="cell">T118</div></td><td class="el-table__cell"><div class="cell">09:10</div></td><td class="el-table__cell"><div class="cell">07:10</div></td><td class="el-table__cell"><div class="cell">07:20</div></td><td class="el-table__cell"><div class="cell">11-09</div></td><td class="el-table__cell"><div class="cell">07:40</div></td><td class="el-table__cell"><div class="cell">库出</div></td><td class="el-table__cell"><div class="cell"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #409EFF, #66b3ff); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(64,158,255,.3); color: white;height:28px;"><span class="buttonFont-small">暂停报警</span></button></div></td></tr><tr class="el-table__row" style="background-color:#FFF200;font-size:20px;font-weight:600"><td class="el-table__cell"><div class="cell">3</div></td><td class="el-table__cell"><div class="cell"><span class="jc-st jc-st-normal">待叫乘</span></div></td><td class="el-table__cell"><div class="cell">11-08 22:20</div></td><td class="el-table__cell"><div class="cell">客运段</div></td><td class="el-table__cell"><div class="cell">HXD3C-0133</div></td><td class="el-table__cell"><div class="cell">李红军</div></td><td class="el-table__cell"><div class="cell">206</div></td><td class="el-table__cell"><div class="cell">Z267</div></td><td class="el-table__cell"><div class="cell">10:05</div></td><td class="el-table__cell"><div class="cell">08:05</div></td><td class="el-table__cell"><div class="cell">08:15</div></td><td class="el-table__cell"><div class="cell">11-09</div></td><td class="el-table__cell"><div class="cell">08:35</div></td><td class="el-table__cell"><div class="cell">站接</div></td><td class="el-table__cell"><div class="cell"><button class="el-button el-button--small" style="background: linear-gradient(135deg, #409EFF, #66b3ff); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(64,158,255,.3); color: white;height:28px;"><span class="buttonFont-small">暂停报警</span></button></div></td></tr><tr class="el-table__row" style="background-color:#B3E19D;font-size:20px;font-weight:600"><td class="el-table__cell"><div class="cell">4</div></td><td class="el-table__cell"><div class="cell"><span class="jc-st jc-st-normal">待离寓</span></div></td><td class="el-table__cell"><div class="cell">11-08 20:15</div></td><td class="el-table__cell"><div class="cell">机务段</div></td><td class="el-table__cell"><div class="cell">HXD3C-0134</div></td><td class="el-table__cell"><div class="cell">王志强</div></td><td class="el-table__cell"><div class="cell">408</div></td><td class="el-table__cell"><div class="cell">K42</div></td><td class="el-table__cell"><div class="cell">07:40</div></td><td class="el-table__cell"><div class="cell">05:40</div></td><td claLine truncated
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="bottom-duty-bar">
|
||||
<div class="bottom-stay-summary"><span>在寓班次:14</span><span>在寓人次:30</span></div>
|
||||
<div class="latest-sync-time" role="status">最新同步时间:09:03:18</div>
|
||||
<div class="bottom-duty-info">
|
||||
<button class="el-button el-button--small" style="background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;position:relative;right:20px;top:2px;"><span class="buttonFont-small">交接班</span></button>
|
||||
<span style="font-size:26px;margin-right:80px;position:relative;top:6px">值班员:张值班</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-right-div" id="notice">有新的交路信息,请及时处理!</div>
|
||||
|
||||
<!-- 宽弹窗骨架:默认隐藏,验收时按需显示以测量视口约束 -->
|
||||
<div class="el-dialog__wrapper jc-dialog jc-wide-dialog" id="wideWrap" style="display:none">
|
||||
<div class="el-dialog" style="width:1800px"><div class="el-dialog__header"><span class="el-dialog__title">历史叫乘信息</span></div>
|
||||
<div class="el-dialog__body"><div class="el-form history-jcxx-form"><div class="history-jcxx-form-row">
|
||||
<div class="history-jcxx-field-box"><label class="history-jcxx-inline-label">机车号</label><div class="el-input"><input class="el-input__inner"></div></div>
|
||||
<div class="history-jcxx-field-box"><label class="history-jcxx-inline-label">车次</label><div class="el-input"><input class="el-input__inner"></div></div>
|
||||
</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div></body></html>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,761 @@
|
||||
|
||||
.marquee-container {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.top-left-marquee-row {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.top-left-search-area {
|
||||
padding-top: 6px !important;
|
||||
}
|
||||
|
||||
.top-left-input-row {
|
||||
margin-top: -2;
|
||||
}
|
||||
|
||||
.top-left-action-row {
|
||||
margin-top: -2;
|
||||
}
|
||||
|
||||
/* 中间时间信息区域 */
|
||||
.center-time-section {
|
||||
flex: 0 0 auto;
|
||||
background: linear-gradient(135deg, #0078d7, #107c10);
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
margin: 0 15px;
|
||||
min-width: 320px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.date-time {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.date-time .text-24 {
|
||||
font-size: 26px !important;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 1200px) {
|
||||
.center-time-section {
|
||||
min-width: 280px;
|
||||
padding: 10px 14px;
|
||||
}
|
||||
.date-time .text-24 {
|
||||
font-size: 24px !important;
|
||||
}
|
||||
.date-time {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.center-time-section {
|
||||
min-width: 240px;
|
||||
padding: 8px 12px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.date-time .text-24 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
.date-time {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ 右下角初始化提示 ============ */
|
||||
.init-success-tip {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
z-index: 2000;
|
||||
background: linear-gradient(135deg, #67c23a, #85ce61);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 30px rgba(103, 194, 58, 0.3);
|
||||
animation: slideInUp 0.6s ease-out;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.init-success-content i {
|
||||
font-size: 18px;
|
||||
margin-right: 8px;
|
||||
animation: successPulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes successPulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============ 表单样式(缩小版) ============ */
|
||||
.form-item-container {
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-item-container .el-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
border-radius: 6px !important;
|
||||
border: 1px solid #dcdfe6 !important;
|
||||
padding: 8px 12px !important;
|
||||
font-size: 13px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
background: white;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner:focus {
|
||||
border-color: #409EFF !important;
|
||||
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner:hover {
|
||||
border-color: #c0c4cc !important;
|
||||
}
|
||||
|
||||
/* 按钮行样式(缩小版)*/
|
||||
.el-button {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
height: 32px !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.el-button:hover {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.el-button:active {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
.buttonFont-small {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 响应式表单设置 */
|
||||
@media (max-width: 1200px) {
|
||||
.form-label {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
padding: 7px 10px !important;
|
||||
font-size: 12px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.init-success-tip {
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
padding: 10px 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-item-container {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.form-item-container .el-input__inner {
|
||||
padding: 6px 8px !important;
|
||||
font-size: 11px !important;
|
||||
height: 28px !important;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
font-size: 11px !important;
|
||||
height: 28px !important;
|
||||
padding: 4px 12px !important;
|
||||
}
|
||||
|
||||
.buttonFont-small {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.init-success-tip {
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.init-success-content {
|
||||
padding: 8px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.init-success-content i {
|
||||
font-size: 14px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.marquee-content {
|
||||
display: inline-block;
|
||||
animation: marquee 28s linear infinite;
|
||||
padding-left: 100%;
|
||||
color: #fff45c;
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
line-height: 36px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.marquee-repeat-text {
|
||||
margin-left: 160px;
|
||||
}
|
||||
|
||||
@keyframes warningBlink {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
background-color: #FFF200;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-200%);
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__body tr:hover > td {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table th.el-table__cell {
|
||||
padding-top: 6px !important;
|
||||
padding-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table td.el-table__cell {
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.main-jcxx-table .cell {
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
column-gap: 6px;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row:first-child {
|
||||
column-gap: 2px;
|
||||
}
|
||||
|
||||
.history-jcxx-field-box {
|
||||
width: 226px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-inline-label {
|
||||
width: 58px;
|
||||
padding-right: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 30px;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
color: #606266;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-field-box .el-input {
|
||||
width: 146px;
|
||||
}
|
||||
|
||||
.history-jcxx-form-row + .history-jcxx-form-row {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.history-jcxx-query-button {
|
||||
margin-left: 4px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-box {
|
||||
width: 230px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-label {
|
||||
width: 72px;
|
||||
}
|
||||
|
||||
.history-jcxx-filter-box .el-select {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.history-jcxx-time-box {
|
||||
width: 610px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.history-jcxx-time-label {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.history-jcxx-time-range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex-wrap: nowrap;
|
||||
width: 540px;
|
||||
}
|
||||
|
||||
.history-jcxx-count {
|
||||
min-width: 180px;
|
||||
margin-left: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
|
||||
.history-jcxx-form .el-input__inner,
|
||||
.history-jcxx-form .el-date-editor.el-input__inner,
|
||||
.history-jcxx-form .el-date-editor .el-range-input,
|
||||
.history-jcxx-form .el-date-editor .el-range-separator {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form .el-input__inner,
|
||||
.history-jcxx-form .el-date-editor.el-input__inner,
|
||||
.history-jcxx-form .el-date-editor--datetimerange {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-form .el-date-editor .el-range__icon,
|
||||
.history-jcxx-form .el-date-editor .el-range__close-icon {
|
||||
line-height: 22px !important;
|
||||
}
|
||||
|
||||
.jc-update-dialog .el-dialog {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col > label {
|
||||
flex: 0 0 96px;
|
||||
width: 96px !important;
|
||||
min-width: 96px;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.jc-update-form .el-row .el-col > .el-input,
|
||||
.jc-update-form .el-row .el-col > .el-select {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.jc-update-room {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.jc-update-room > .el-button {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.history-jcxx-table th.el-table__cell {
|
||||
padding-top: 5px !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-table td.el-table__cell {
|
||||
padding-top: 4px !important;
|
||||
padding-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.history-jcxx-load-tip {
|
||||
padding: 8px 0 2px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.history-jcxx-table .cell {
|
||||
line-height: 1.15 !important;
|
||||
}
|
||||
|
||||
.leave-snapshot-preview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.leave-snapshot-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 560px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.leave-snapshot-empty {
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.item1 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.bottom-right-div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
// background-color: #255e39;
|
||||
padding: 10px;
|
||||
font-size: 20px;
|
||||
background-color: #a6b8ac;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.Dialog_JcEvent .el-dialog {
|
||||
position: fixed;
|
||||
top: -100px;
|
||||
left: 100px;
|
||||
background-color: rgb(222, 226, 230);
|
||||
}
|
||||
|
||||
.Dialog_AlarmEvent .el-dialog {
|
||||
background-color: rgb(204, 123, 16);
|
||||
}
|
||||
|
||||
.buttonFont {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0 0 0 0 ;
|
||||
}
|
||||
|
||||
.app_contianer {
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.bottom-duty-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: rgb(2, 145, 145);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.bottom-stay-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 80px;
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.bottom-stay-summary,
|
||||
.latest-sync-time {
|
||||
color: #fff45c;
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
line-height: 50px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.35);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.latest-sync-time {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bottom-duty-info {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.el-table__body tr.current-row > td {
|
||||
background-color: #1990f1 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.history-jcxx-table .el-table__body tr.current-row > td {
|
||||
background-color: #0b7dda !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.history-jcxx-table.el-table--striped .el-table__body tr.current-row > td,
|
||||
.history-jcxx-table.el-table--striped .el-table__body tr.current-row.el-table__row--striped > td {
|
||||
background-color: #0b7dda !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.red-mask {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.record-button-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.record-button {
|
||||
margin-left: 0 !important;
|
||||
width: 58px;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
/* 合并后的交路及叫乘提醒。 */
|
||||
.sync-warning-dialog .el-dialog {
|
||||
min-width: 620px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.sync-warning-dialog .el-dialog__header {
|
||||
background: #fff7e6;
|
||||
border-bottom: 1px solid #f5c26b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sync-warning-dialog .el-dialog__title {
|
||||
color: #b45309;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sync-warning-content {
|
||||
max-height: 56vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sync-warning-section + .sync-warning-section {
|
||||
margin-top: 16px;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.sync-warning-category {
|
||||
margin-bottom: 8px;
|
||||
color: #b45309;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sync-warning-category i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sync-warning-item {
|
||||
padding: 5px 0 5px 26px;
|
||||
color: #303133;
|
||||
font-size: 17px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
/* ============ 优化按钮样式 ============ */
|
||||
.el-button {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.el-button:hover {
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: 0 8px 20px rgba(64, 158, 255, 0.4) !important;
|
||||
}
|
||||
|
||||
.el-button:active {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
/* 查询按钮特殊样式 */
|
||||
.el-button[style*="linear-gradient"]:hover {
|
||||
background: linear-gradient(135deg, #66b3ff, #409EFF) !important;
|
||||
box-shadow: 0 8px 25px rgba(64, 158, 255, 0.5) !important;
|
||||
}
|
||||
|
||||
.el-button[style*="linear-gradient"]:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.el-button[style*="linear-gradient"]:hover:before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* 响应式按钮优化 */
|
||||
@media (max-width: 768px) {
|
||||
.el-button[style*="margin-left"] {
|
||||
margin-left: 20px !important;
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.person-photo-panel {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.person-photo-item {
|
||||
width: 180px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.person-photo-title {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.person-photo-img {
|
||||
width: 150px;
|
||||
height: 200px;
|
||||
object-fit: cover;
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.jl-add-dialog .el-dialog {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > label,
|
||||
.jl-add-form .el-row .el-col > div > label {
|
||||
flex: 0 0 96px;
|
||||
width: 96px !important;
|
||||
min-width: 96px;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > .el-input,
|
||||
.jl-add-form .el-row .el-col > .el-select,
|
||||
.jl-add-form .el-row .el-col > .el-date-editor,
|
||||
.jl-add-form .el-row .el-col > div > .el-input,
|
||||
.jl-add-form .el-row .el-col > div > .el-select,
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor {
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div > .el-input,
|
||||
.jl-add-form .el-row .el-col > div > .el-select,
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor,
|
||||
.jl-add-form .el-row .el-col > div > .el-time-picker {
|
||||
width: 100% !important;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.jl-add-form .el-row .el-col > div > .el-date-editor .el-input__inner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/* ============================================================================
|
||||
* JcXx.optimized.vue 验收脚本
|
||||
* 1) 真实 SFC 编译:vue-template-compiler / @babel/parser / sass
|
||||
* 2) 功能集合零变化:script 哈希 + 模板指令/列/按钮/弹窗集合比对
|
||||
* 3) 优化前 / 优化后同一份静态 DOM + 两份真实 CSS,多视口截图与布局断言
|
||||
* 用法:node verify_jcxx.cjs
|
||||
* ==========================================================================*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..', '..', '..');
|
||||
const VUE = path.join(ROOT, 'YktVue');
|
||||
const SRC = path.join(VUE, 'src', 'views', 'JcXx.vue');
|
||||
const OUT = path.join(VUE, 'src', 'views', 'JcXx.optimized.vue');
|
||||
const UI = path.join(ROOT, 'docs', 'frontend', 'ui');
|
||||
|
||||
const req = p => require(path.join(VUE, 'node_modules', p));
|
||||
const compiler = req('vue-template-compiler');
|
||||
const babel = req('@babel/parser');
|
||||
const sass = req('sass');
|
||||
|
||||
let chromium;
|
||||
const PW = 'C:/Users/zfjia/AppData/Roaming/npm/node_modules/@playwright/cli/node_modules/playwright';
|
||||
const EXE = 'C:/Users/zfjia/AppData/Local/ms-playwright/chromium_headless_shell-1243/chrome-headless-shell-win64/chrome-headless-shell.exe';
|
||||
try { ({ chromium } = require(PW)); } catch (e) { ({ chromium } = require('playwright')); }
|
||||
|
||||
const beforeVue = fs.readFileSync(SRC, 'utf8');
|
||||
const afterVue = fs.readFileSync(OUT, 'utf8');
|
||||
|
||||
function parts(s) {
|
||||
// 注意:模板内部有大量 <template slot-scope>,必须取最后一个 </template>
|
||||
const a = s.indexOf('<template>') + '<template>'.length;
|
||||
const b = s.lastIndexOf('</template>');
|
||||
const c = s.indexOf('<script>'), d = s.indexOf('</script>') + 9;
|
||||
const e = s.indexOf('<style'), f = s.indexOf('</style>');
|
||||
return {
|
||||
template: s.slice(a, b),
|
||||
script: s.slice(c, d),
|
||||
scriptBody: s.slice(s.indexOf('>', c) + 1, d - 9),
|
||||
style: s.slice(s.indexOf('>', e) + 1, f)
|
||||
};
|
||||
}
|
||||
const B = parts(beforeVue), A = parts(afterVue);
|
||||
const sha = s => crypto.createHash('sha256').update(s).digest('hex');
|
||||
|
||||
let pass = 0, fail = 0;
|
||||
const results = [];
|
||||
function T(name, cond, detail) {
|
||||
if (cond) { pass++; results.push(' PASS ' + name); }
|
||||
else { fail++; results.push(' FAIL ' + name + (detail ? ' ' + detail : '')); }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 1. 编译
|
||||
const rcB = compiler.compile(B.template);
|
||||
const rcA = compiler.compile(A.template);
|
||||
T('SFC-01 优化前模板可由 vue-template-compiler 编译', rcB.errors.length === 0, JSON.stringify(rcB.errors));
|
||||
T('SFC-02 优化后模板可由 vue-template-compiler 编译', rcA.errors.length === 0, JSON.stringify(rcA.errors));
|
||||
let jsErr = '';
|
||||
try {
|
||||
babel.parse(A.scriptBody, {
|
||||
sourceType: 'module',
|
||||
plugins: ['objectRestSpread', 'dynamicImport', 'optionalChaining',
|
||||
'nullishCoalescingOperator', 'classProperties']
|
||||
});
|
||||
} catch (e) { jsErr = e.message; }
|
||||
T('SFC-03 优化后 <script> 通过 Babel 语法解析', !jsErr, jsErr);
|
||||
|
||||
const compileSass = scss => sass.renderSync({ data: scss, outputStyle: 'expanded' }).css.toString();
|
||||
const cssB = compileSass(B.style);
|
||||
const cssA = compileSass(A.style);
|
||||
T('SFC-04 优化前 style 可通过 sass 编译', cssB.length > 10000);
|
||||
T('SFC-05 优化后 style 可通过 sass 编译', cssA.length > cssB.length);
|
||||
|
||||
// ---------------------------------------------------------------- 2. 功能集合
|
||||
T('FUN-01 <script> 段逐字节一致(功能/接口/定时器/状态机全部保留)',
|
||||
B.script === A.script && sha(B.script) === sha(A.script));
|
||||
|
||||
function inventory(tpl) {
|
||||
const pick = re => (tpl.match(re) || []).sort();
|
||||
return {
|
||||
events: pick(/@[a-zA-Z][\w.-]*(?:=|\s|>)/g).map(x => x.replace(/[=>\s]/g, '')).sort(),
|
||||
models: pick(/v-model(?:\.\w+)?="[^"]+"/g),
|
||||
binds: pick(/:[a-zA-Z][\w.-]*="[^"]+"/g),
|
||||
refs: pick(/ref="[^"]+"/g),
|
||||
slots: pick(/slot-scope="[^"]+"/g),
|
||||
vif: pick(/v-(?:if|else-if|else|show|for|html|once)(?:="[^"]+")?/g),
|
||||
cols: pick(/<el-table-column[^>]*?\b(?:prop|label)="[^"]+"/g)
|
||||
.map(x => (x.match(/\bprop="([^"]+)"/) || [, ''])[1] + '|' +
|
||||
(x.match(/\blabel="([^"]+)"/) || [, ''])[1]),
|
||||
tags: ['el-dialog', 'el-table', 'el-table-column', 'el-button', 'el-input',
|
||||
'el-select', 'el-form', 'el-form-item', 'el-tab-pane', 'el-checkbox',
|
||||
'audio', 'el-result'].map(t => t + '=' + (tpl.match(new RegExp('<' + t + '\\b', 'g')) || []).length)
|
||||
};
|
||||
}
|
||||
const ib = inventory(B.template), ia = inventory(A.template);
|
||||
Object.keys(ib).forEach(k => {
|
||||
if (k === 'events') {
|
||||
// 唯一预期差异:tab_click -> tab-click(Element UI 实际派发 tab-click;处理函数体为空)
|
||||
const nb = ib.events.map(x => x === '@tab_click' ? '@tab-click' : x).sort();
|
||||
T('FUN-02 事件绑定集合一致(仅修正 tab_click 拼写)',
|
||||
JSON.stringify(nb) === JSON.stringify(ia.events),
|
||||
JSON.stringify({ before: ib.events.filter(x => !ia.events.includes(x)), after: ia.events.filter(x => !nb.includes(x)) }));
|
||||
} else {
|
||||
T('FUN-02 ' + k + ' 集合与数量一致',
|
||||
JSON.stringify(ib[k]) === JSON.stringify(ia[k]),
|
||||
JSON.stringify({ before: ib[k].length, after: ia[k].length }));
|
||||
}
|
||||
});
|
||||
T('FUN-03 未新增/删除任何按钮、表格列、弹窗',
|
||||
ib.tags.join('|') === ia.tags.join('|'), ib.tags.join('|'));
|
||||
T('FUN-04 所有弹窗带统一 jc-dialog 作用域类名、宽弹窗带 jc-wide-dialog',
|
||||
(A.template.match(/<el-dialog/g) || []).length === (A.template.match(/class="jc-dialog/g) || []).length &&
|
||||
(A.template.match(/jc-wide-dialog/g) || []).length === 4);
|
||||
T('FUN-05 原样式核心规则全部保留,优化层仅做追加与 4 处修正',
|
||||
['.marquee-container', '.center-time-section', '.form-item-container',
|
||||
'.bottom-duty-bar', '@keyframes marquee', '.history-jcxx-form-row',
|
||||
'.sync-warning-content', '.person-photo-panel', '.jl-add-form']
|
||||
.every(k => A.style.includes(k)) && cssA.length > cssB.length);
|
||||
|
||||
// ---------------------------------------------------------------- 3. 静态布局快照
|
||||
const elementCss = fs.readFileSync(
|
||||
path.join(VUE, 'node_modules', 'element-ui', 'lib', 'theme-chalk', 'index.css'), 'utf8');
|
||||
|
||||
const ORANGE = 'background: linear-gradient(135deg, #e6a23c, #f7ba2a); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(230,162,60,.3); color: white;';
|
||||
const TEAL = 'background: linear-gradient(135deg, #0b5858, #0f6b6b); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(11,88,88,.3); color: white;';
|
||||
const BLUE = 'background: linear-gradient(135deg, #409EFF, #66b3ff); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(64,158,255,.3); color: white;';
|
||||
const GREY = 'background: linear-gradient(135deg, #909399, #b1b3b8); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(144,147,153,.3); color: white;';
|
||||
const RED = 'background: linear-gradient(135deg, #f56c6c, #ff7979); border: none; border-radius: 6px; padding: 6px 16px; font-weight: 600; box-shadow: 0 3px 8px rgba(245,108,108,.3); color: white;';
|
||||
const btn = (label, style, extra) =>
|
||||
`<button class="el-button el-button--small" style="${style}${extra || ''}"><span class="buttonFont-small">${label}</span></button>`;
|
||||
|
||||
const COLS = ['序号', '状态', '到寓时间', '单位', '机车号', '姓名', '房间号', '出发车次',
|
||||
'开车时间', '叫乘时间', '复叫时间', '叫乘日期', '应离寓时间', '接车方式', '操作'];
|
||||
const ROWS = [
|
||||
{ bg: '#F56C6C', st: 'jc-st-alarm', v: ['1', '叫乘报警', '11-08 21:40', '机务段', 'HXD3C-0131', '冯建国', '305', 'K671', '08:35', '06:35', '06:45', '11-09', '07:05', '站接'] },
|
||||
{ bg: '#00FF00', st: 'jc-st-normal', v: ['2', '正在呼叫', '11-08 22:05', '机务段', 'HXD3C-0132', '蒋卫东', '517', 'T118', '09:10', '07:10', '07:20', '11-09', '07:40', '库出'] },
|
||||
{ bg: '#FFF200', st: 'jc-st-normal', v: ['3', '待叫乘', '11-08 22:20', '客运段', 'HXD3C-0133', '李红军', '206', 'Z267', '10:05', '08:05', '08:15', '11-09', '08:35', '站接'] },
|
||||
{ bg: '#B3E19D', st: 'jc-st-normal', v: ['4', '待离寓', '11-08 20:15', '机务段', 'HXD3C-0134', '王志强', '408', 'K42', '07:40', '05:40', '05:50', '11-09', '06:10', '库出'] },
|
||||
{ bg: '', st: 'jc-st-muted', v: ['5', '已入寓', '11-09 01:10', '客运段', 'HXD3C-0135', '赵明亮', '612', 'K671', '14:20', '12:20', '12:30', '11-09', '12:50', '站接'] }
|
||||
];
|
||||
|
||||
function makeBody() {
|
||||
const search = ['机车号', '车次', '房间号', '姓名'].map((k, i) =>
|
||||
`<div class="el-col el-col-6" style="padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="form-item-container"><label class="form-label">${k}</label>
|
||||
<div class="el-input"><input class="el-input__inner" placeholder="请输入${k}" id="q${i}"></div></div></div>`).join('');
|
||||
const topBtns = ['房间信息', '设备信息', '人员维护', '交路管理', '历史数据']
|
||||
.map(x => btn(x, ORANGE, 'height:32px;')).join('');
|
||||
const row2Btns = ['换乘', '出乘'].map(x => btn(x, TEAL, 'height:32px;width:84px;')).join('');
|
||||
const row3Btns = ['语音临叫', '喊话临叫', '停止呼叫', '停止报警']
|
||||
.map(x => btn(x, TEAL, 'height:32px;')).join('');
|
||||
const ths = COLS.map(c => `<th class="el-table__cell"><div class="cell">${c}</div></th>`).join('');
|
||||
const trs = ROWS.map((r, ri) => {
|
||||
const tds = r.v.map((v, ci) => {
|
||||
let inner = v;
|
||||
if (ci === 1) inner = `<span class="jc-st ${r.st}">${v}</span>`;
|
||||
return `<td class="el-table__cell"><div class="cell">${inner}</div></td>`;
|
||||
});
|
||||
tds.push(`<td class="el-table__cell"><div class="cell">${btn('暂停报警', BLUE, 'height:28px;')}</div></td>`);
|
||||
return `<tr class="el-table__row${ri === 0 ? ' current-row' : ''}" style="background-color:${r.bg};font-size:20px;font-weight:600">${tds.join('')}</tr>`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="app_contianer jc-opt-root" id="app">
|
||||
<div class="el-card"><div class="el-card__body">
|
||||
<div class="el-row jc-header-row" style="height:150px;margin-left:-7.5px;margin-right:-7.5px">
|
||||
<div class="el-col el-col-9 jc-header-search" style="height:100%;display:flex;flex-direction:column;justify-content:center;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row top-left-marquee-row" style="height:30%;margin-top:40px">
|
||||
<div class="marquee-container" style="background-color:rgb(2,145,145);height:100%">
|
||||
<div class="marquee-content"><span>305 房间叫乘时间已过,请值班员关注</span><span class="marquee-repeat-text">305 房间叫乘时间已过,请值班员关注</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-left-search-area" style="flex:1;display:flex;flex-direction:column;justify-content:center;padding:10px 20px">
|
||||
<div class="el-row top-left-input-row" style="margin-bottom:15px">${search}</div>
|
||||
<div class="el-row top-left-action-row">
|
||||
<div class="el-col el-col-24" style="display:flex;justify-content:space-between;align-items:center">
|
||||
${btn('取消叫乘', ORANGE)}
|
||||
<div style="display:flex;align-items:center;gap:12px">${btn('查询', BLUE)}${btn('重置', GREY)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-col el-col-6 jc-header-time" style="height:100%;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row"><div class="center-time-section"><div class="date-time">
|
||||
<p class="text-24 text-white">2026-11-09 星期一<br>09:03:21</p>
|
||||
</div></div></div>
|
||||
</div>
|
||||
<div class="el-col el-col-9 jc-header-actions" style="height:100%;padding-left:7.5px;padding-right:7.5px">
|
||||
<div class="el-row" style="height:50%;padding:8px 20px 8px 0px;display:flex;align-items:center">
|
||||
<div class="el-col el-col-18"><div style="display:flex;gap:5px;justify-content:space-between;align-items:center">${topBtns}</div></div>
|
||||
<div class="el-col el-col-1"></div>
|
||||
<div class="el-col el-col-5"><div style="display:flex;align-items:center;gap:3px">
|
||||
<span class="jc-user-label" style="font-size:12px;color:#666;width:45%">当前用户: 张值班</span>
|
||||
${btn('退出', RED, 'height:32px;width:55%;')}
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="el-row" style="height:50%;padding:8px 20px 8px 0px;display:flex;align-items:center">
|
||||
<div class="el-col el-col-7"><div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:flex-start">${row2Btns}</div></div>
|
||||
<div class="el-col el-col-17"><div style="display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-start;margin-left:14px">${row3Btns}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="el-card" style="margin-top:10px"><div class="el-card__body">
|
||||
<div class="el-tabs el-tabs--card"><div class="el-tabs__header is-top"><div class="el-tabs__nav-wrap"><div class="el-tabs__nav-scroll">
|
||||
<div class="el-tabs__nav is-top"><div class="el-tabs__item is-top is-active">机务人员和客运人员</div><div class="el-tabs__item is-top">其他人员</div></div>
|
||||
</div></div></div></div>
|
||||
<div class="el-table main-jcxx-table el-table--border" style="width:100%;height:600px">
|
||||
<div class="el-table__header-wrapper"><table class="el-table__header" style="width:100%"><thead><tr style="height:54px">${ths}</tr></thead></table></div>
|
||||
<div class="el-table__body-wrapper" style="height:546px"><table class="el-table__body" style="width:100%"><tbody>${trs}</tbody></table></div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="bottom-duty-bar">
|
||||
<div class="bottom-stay-summary"><span>在寓班次:14</span><span>在寓人次:30</span></div>
|
||||
<div class="latest-sync-time" role="status">最新同步时间:09:03:18</div>
|
||||
<div class="bottom-duty-info">
|
||||
${btn('交接班', ORANGE, 'position:relative;right:20px;top:2px;')}
|
||||
<span style="font-size:26px;margin-right:80px;position:relative;top:6px">值班员:张值班</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-right-div" id="notice">有新的交路信息,请及时处理!</div>
|
||||
|
||||
<!-- 宽弹窗骨架:默认隐藏,验收时按需显示以测量视口约束 -->
|
||||
<div class="el-dialog__wrapper jc-dialog jc-wide-dialog" id="wideWrap" style="display:none">
|
||||
<div class="el-dialog" style="width:1800px"><div class="el-dialog__header"><span class="el-dialog__title">历史叫乘信息</span></div>
|
||||
<div class="el-dialog__body"><div class="el-form history-jcxx-form"><div class="history-jcxx-form-row">
|
||||
<div class="history-jcxx-field-box"><label class="history-jcxx-inline-label">机车号</label><div class="el-input"><input class="el-input__inner"></div></div>
|
||||
<div class="history-jcxx-field-box"><label class="history-jcxx-inline-label">车次</label><div class="el-input"><input class="el-input__inner"></div></div>
|
||||
</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function makeHtml(css, label) {
|
||||
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">
|
||||
<title>JcXx ${label}</title>
|
||||
<style>${elementCss}</style>
|
||||
<style>${css}</style>
|
||||
<style>body{margin:0;background:#f3f6f5}#app{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei",Arial,sans-serif}
|
||||
/* 快照专用:模拟 el-table 运行时的内部横向滚动,避免 15 列被静态表格压扁 */
|
||||
.main-jcxx-table .el-table__header-wrapper,
|
||||
.main-jcxx-table .el-table__body-wrapper{overflow-x:auto}
|
||||
.main-jcxx-table table{min-width:1500px}
|
||||
</style>
|
||||
</head><body>${makeBody()}</body></html>`;
|
||||
}
|
||||
const pb = path.join(__dirname, 'preview-before.html');
|
||||
const pa = path.join(__dirname, 'preview-after.html');
|
||||
fs.writeFileSync(pb, makeHtml(cssB, '优化前'), 'utf8');
|
||||
fs.writeFileSync(pa, makeHtml(cssA, '优化后'), 'utf8');
|
||||
const URLB = require('url').pathToFileURL(pb).href;
|
||||
const URLA = require('url').pathToFileURL(pa).href;
|
||||
|
||||
// ---------------------------------------------------------------- 4. 多视口断言
|
||||
const VIEWPORTS = [
|
||||
{ w: 1920, h: 1080 }, { w: 1440, h: 900 }, { w: 1366, h: 768 },
|
||||
{ w: 1280, h: 800 }, { w: 1024, h: 768 }
|
||||
];
|
||||
|
||||
const probe = () => {
|
||||
const R = s => {
|
||||
const e = document.querySelector(s);
|
||||
if (!e) return null;
|
||||
const b = e.getBoundingClientRect();
|
||||
return { t: Math.round(b.top), b: Math.round(b.bottom), l: Math.round(b.left), r: Math.round(b.right), w: Math.round(b.width), h: Math.round(b.height) };
|
||||
};
|
||||
const root = document.querySelector('#app');
|
||||
const bar = R('.bottom-duty-bar');
|
||||
const wrap = document.querySelector('#wideWrap');
|
||||
wrap.style.display = 'block';
|
||||
const dlg = R('.jc-wide-dialog .el-dialog');
|
||||
wrap.style.display = 'none';
|
||||
return {
|
||||
vw: window.innerWidth, vh: window.innerHeight,
|
||||
docW: document.documentElement.scrollWidth,
|
||||
header: R('.jc-header-row'), search: R('.top-left-search-area'),
|
||||
leftCol: R('.jc-header-search'), time: R('.center-time-section'),
|
||||
actions: R('.jc-header-actions'), topBtns: R('.jc-header-actions .el-col-18 > div'),
|
||||
bar, left: R('.bottom-stay-summary'), mid: R('.latest-sync-time'), right: R('.bottom-duty-info'),
|
||||
notice: R('.bottom-right-div'), table: R('.main-jcxx-table'),
|
||||
dlg,
|
||||
paddingBottom: parseFloat(getComputedStyle(root).paddingBottom) || 0,
|
||||
headerH: Math.round(document.querySelector('.jc-header-row').getBoundingClientRect().height)
|
||||
};
|
||||
};
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ executablePath: EXE, headless: true });
|
||||
const ctx = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
|
||||
const beforeIssues = {}, afterIssues = {};
|
||||
|
||||
for (const v of VIEWPORTS) {
|
||||
const tag = `${v.w}x${v.h}`;
|
||||
for (const [kind, url, bucket] of [['before', URLB, beforeIssues], ['after', URLA, afterIssues]]) {
|
||||
const p = await ctx.newPage();
|
||||
await p.setViewportSize({ width: v.w, height: v.h });
|
||||
const errs = [];
|
||||
p.on('pageerror', e => errs.push(e.message));
|
||||
await p.goto(url);
|
||||
await p.waitForTimeout(120);
|
||||
const m = await p.evaluate(probe);
|
||||
const issues = [];
|
||||
if (m.docW > m.vw + 1) issues.push('横向溢出 ' + m.docW + '>' + m.vw);
|
||||
if (m.search.b > m.leftCol.b + 2) issues.push('顶部查询区被裁切');
|
||||
if (m.time.r > m.vw + 1) issues.push('时间卡越界');
|
||||
if (m.topBtns.r > m.actions.r + 2) issues.push('右上按钮组越界');
|
||||
if (m.left.r > m.mid.l + 2 || m.mid.r > m.right.l + 2) issues.push('吸底三段重叠');
|
||||
if (m.notice.b > m.bar.t + 2) issues.push('右下提示被吸底条压住');
|
||||
if (m.paddingBottom < 50) issues.push('底部无留白内容被遮挡');
|
||||
if (m.dlg.r > m.vw + 1) issues.push('宽弹窗横向越界');
|
||||
if (errs.length) issues.push('JS 错误 ' + errs.join('|'));
|
||||
bucket[tag] = issues;
|
||||
|
||||
const shot = path.join(UI, `JcXx-${kind === 'before' ? '优化前' : '优化后'}-${tag}.png`);
|
||||
await p.screenshot({ path: shot, fullPage: false });
|
||||
await p.close();
|
||||
}
|
||||
T(`LAY-${tag} 优化后无横向溢出/裁切/重叠/遮挡/弹窗越界`,
|
||||
afterIssues[tag].length === 0, JSON.stringify(afterIssues[tag]));
|
||||
results.push(` └ 优化前同视口问题:${beforeIssues[tag].length ? beforeIssues[tag].join(';') : '无'}`);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 交互与状态反馈
|
||||
const p = await ctx.newPage();
|
||||
await p.setViewportSize({ width: 1920, height: 1080 });
|
||||
await p.goto(URLA);
|
||||
await p.waitForTimeout(120);
|
||||
await p.hover('.main-jcxx-table .el-table__body tr:nth-child(3) td');
|
||||
const hoverAfter = await p.evaluate(() =>
|
||||
getComputedStyle(document.querySelector('.main-jcxx-table .el-table__body tr:nth-child(3) td')).backgroundImage);
|
||||
T('FB-01 表格行 hover 有可见反馈(保留行内状态底色)',
|
||||
hoverAfter !== 'none' && hoverAfter.includes('gradient'), hoverAfter);
|
||||
|
||||
const current = await p.evaluate(() => {
|
||||
const td = document.querySelector('.main-jcxx-table tr.current-row > td');
|
||||
const cs = getComputedStyle(td);
|
||||
return { bg: cs.backgroundColor, img: cs.backgroundImage, trBg: td.parentElement.style.backgroundColor };
|
||||
});
|
||||
T('FB-02 选中行不再用纯蓝底抹掉报警行状态色',
|
||||
current.bg !== 'rgb(25, 144, 241)' && current.img.includes('gradient'),
|
||||
JSON.stringify(current));
|
||||
|
||||
const grad = await p.evaluate(() => {
|
||||
const b = document.querySelector('.top-left-action-row .el-button');
|
||||
return getComputedStyle(b).backgroundImage;
|
||||
});
|
||||
await p.hover('.top-left-action-row .el-button');
|
||||
const gradHover = await p.evaluate(() =>
|
||||
getComputedStyle(document.querySelector('.top-left-action-row .el-button')).backgroundImage);
|
||||
T('FB-03 橙色按钮 hover 不再被强制刷成蓝色渐变',
|
||||
gradHover === grad && gradHover.includes('230, 162, 60'), gradHover);
|
||||
|
||||
const shadowBefore = await p.evaluate(() =>
|
||||
getComputedStyle(document.querySelector('#q0')).boxShadow);
|
||||
await p.focus('#q0');
|
||||
await p.waitForTimeout(160); // headless 下 :focus 样式重算 + .3s 过渡起效
|
||||
const focusFeedback = await p.evaluate(() => {
|
||||
void document.body.offsetHeight; // 强制同步重排后再取计算样式
|
||||
const c = getComputedStyle(document.querySelector('#q0'));
|
||||
return { shadow: c.boxShadow, outlineStyle: c.outlineStyle };
|
||||
});
|
||||
T('FB-04 键盘焦点产生可见反馈(光晕变化 + 轮廓)',
|
||||
focusFeedback.shadow !== shadowBefore && focusFeedback.outlineStyle !== 'none',
|
||||
JSON.stringify({ before: shadowBefore, after: focusFeedback }));
|
||||
|
||||
const stateWeight = await p.evaluate(() =>
|
||||
getComputedStyle(document.querySelector('.main-jcxx-table .jc-st-alarm')).fontWeight);
|
||||
T('FB-05 报警状态文字权重高于普通单元格', Number(stateWeight) >= 700, stateWeight);
|
||||
|
||||
const noticeCursor = await p.evaluate(() =>
|
||||
getComputedStyle(document.querySelector('#notice')).cursor);
|
||||
T('FB-06 右下角提示有可点击指针反馈', noticeCursor === 'pointer', noticeCursor);
|
||||
|
||||
T('FB-07 优化层含 prefers-reduced-motion 降级', cssA.includes('prefers-reduced-motion'));
|
||||
|
||||
await p.close();
|
||||
await browser.close();
|
||||
|
||||
console.log('\n================ JcXx 优化版验收 ================');
|
||||
console.log(results.join('\n'));
|
||||
console.log('--------------------------------------------------');
|
||||
const bTotal = Object.values(beforeIssues).reduce((n, x) => n + x.length, 0);
|
||||
const aTotal = Object.values(afterIssues).reduce((n, x) => n + x.length, 0);
|
||||
console.log(`优化前 5 个视口累计布局问题:${bTotal} 项`);
|
||||
console.log(`优化后 5 个视口累计布局问题:${aTotal} 项`);
|
||||
console.log(`断言:${pass}/${pass + fail} 通过`);
|
||||
console.log(`截图:${VIEWPORTS.length * 2} 张 -> ${UI}`);
|
||||
console.log('==================================================');
|
||||
if (fail) process.exit(1);
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
Reference in new issue
Block a user