# -*- coding: utf-8 -*- """ 由 YktVue/src/views/JcXx.vue 生成 JcXx.optimized.vue。 设计约束(与用户需求一一对应): 1. ') + len('')] 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, '
', '
', '根容器 class') s = rep(s, '', '', '顶部行 class') s = rep(s, '', '', '顶部左列 class') s = rep(s, '', '', '顶部中列 class') s = rep(s, '', '', '顶部右列 class') s = rep(s, '当前用户: {{ loginAccount }}', '当前用户: {{ loginAccount }}', '当前用户标签 class') # Element UI 派发的是 tab-click;原写法 tab_click 永远不会被触发(处理函数体为空,修正后行为不变) s = rep(s, '@tab_click=handleTabClick', '@tab-click=handleTabClick', 'tab 事件名拼写') # 状态列:仅加 class,文本与 v-if 链完全不变(行内底色已是状态语义色, # 这里只提升文字对比与字重,不把纯文字改成标签,保持原有信息呈现方式) old_state = """ """ new_state = """ """ s = rep(s, old_state, new_state, '主表状态列 class') old_dev = """ """ new_dev = """ """ s = rep(s, old_dev, new_dev, '设备状态列 class') old_hist = """ """ new_hist = """ """ 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']*?>', re.S) dialog_tags = dialog_re.findall(s) expected = s.count(' 逐字节未改; · 不引入新配色:所有色值取自本页原有样式 (#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, '', OPT_CSS + '', '追加优化层') # ============================================================ 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('') + len('')] assert script_before == script_after, '