# 昼夜主题与配色配置 ## 功能概述 - **顶栏固定样式**:最上方标题条(背景图、中英文标题、数据同步、界面开关、主题配置、立即同步按钮)**始终为黑夜科技风配色**,不随「白天 / 黑夜」切换或主题 Token 变化;昼夜仅影响其下方的搜索区、侧栏卡片、图例、底图切换条、地图弹窗与 ECharts 等。 - **默认「黑夜」**:与历史大屏一致的深色半透明面板、浅色文字,适合暗色政务底图。 - **「白天」**:高对比浅底深字,适合「标准版政务底图」等浅色底图,减轻文字与弹窗看不清的问题。 - **昼夜与底图联动**:**不单独提供**顶栏昼夜开关。左下角切换底图时自动切换主题——**「暗蓝色政务底图」**(`shmap_blue_web`)对应 **黑夜**,**「标准版政务底图」**、**「卫星影像」** 对应 **白天**。常量见 `src/utils/uiTheme.js` 的 `BASE_MAP_KEY_NIGHT`、`getUiModeForBaseMap`。 - **右上角**:仅保留 **主题配置** 按钮(颜色 Token),不再保留独立的昼夜开关。 - **持久化**:当前模式(`night` / `day`)与 **按昼夜分别存储** 的覆盖项 `overridesByMode` 写入 **`localStorage`**,键名常量:`industry_map_ui_theme_v1`(定义于 `src/utils/uiTheme.js` 的 `UI_THEME_STORAGE_KEY`)。在白天下调主题只写入 `overridesByMode.day`,黑夜写入 `overridesByMode.night`,互不覆盖。 ## 配置流程(面向使用者) 1. 打开页面后,主题在 **`main.js` 启动时** 从缓存读出并应用到 `document.documentElement`(`data-ui-theme` + 内联 CSS 变量)。 2. 切换 **底图**:在 `qpjyj.vue` 的 `changeMapService` 中更新 `activeMap` 后调用 `syncThemeWithBaseMap()` → `persistTheme(getUiModeForBaseMap(activeMap), overridesByMode, sidebarWidthPx)`,写入缓存并刷新 CSS 变量;ECharts 通过计算属性 `isDayTheme`(由 `activeMap` 推导)同步 `chart-theme`。 3. 点击 **主题配置**: - **统一表面背景(`--ui-surface-bg`)**:侧栏卡片、搜索框容器、左下角底图切换条、右下角图例、地图详情弹窗主区域与弹窗内信息条等共用同一背景色;支持 **透明度**(`show-alpha` + `rgb` 格式输出 `rgba(...)`)。 - **文字分级**:标题、一级~三级、描述、占位;除占位外默认 **十六进制**;占位支持透明度。 - **强调色(`--ui-main`)**:十六进制;应用后由 `resolveThemeTokens` 同步描边、链接色、搜索高亮、弹窗强调色等。 - **拖动或修改颜色即生效**:立刻更新页面 CSS,并在约 120ms 防抖后写入 `localStorage`;仅当与当前模式**内置默认值**在语义上同色(支持 `#hex` 与 `rgb()` 对照)时,不写入该项覆盖。清空某项表示恢复默认。每次合并 `overrides` 时会移除一批**已废弃的单独背景/文字覆盖键**(见下文)。 4. **恢复默认**:清空 **当前模式** 在 `overridesByMode` 中的颜色覆盖(另一模式保留);同时将 **侧栏宽度** 恢复为内置默认值 **`DEFAULT_SIDEBAR_WIDTH_PX`**(当前为 `432`,定义于 `src/utils/uiTheme.js`),并写入缓存。 ## 缓存 JSON 结构 ```json { "mode": "day", "overridesByMode": { "night": {}, "day": { "--ui-surface-bg": "rgba(255,255,255,0.26)", "--ui-text-title": "#0d7ea0", "--ui-main": "#0d7ea0" } }, "sidebarWidthPx": 432 } ``` - `mode`:仅允许 `"night"` 或 `"day"`(非法值按 `night` 处理),表示**当前**界面模式(与底图一致)。 - `overridesByMode.day` / `overridesByMode.night`:各自模式下的覆盖表;键为 CSS 自定义属性名(必须以 `--` 开头)。 - `sidebarWidthPx`:左右侧悬浮栏宽度(像素),昼夜共用;**默认**与 **`DEFAULT_SIDEBAR_WIDTH_PX`**(432)一致;合法范围见 `SIDEBAR_WIDTH_MIN_PX` / `SIDEBAR_WIDTH_MAX_PX`;运行时写入 `:root` 的 `--ui-sidebar-width`。 - **旧版缓存**仅含 `overrides` 时,加载时会当作 **当时 `mode` 对应那一份** 使用,另一模式为空,避免历史数据把昼夜绑死成同一套颜色。 ## 核心 Token(主题对话框可编辑) | Token | 含义 | |--------|------| | `--ui-surface-bg` | 统一表面背景(面板、搜索、图例容器、弹窗主区与弹窗内卡片条等) | | `--ui-text-title` | 标题 | | `--ui-text-1` | 一级文字(面板正文、弹窗主文、搜索主色等) | | `--ui-text-2` | 二级文字(小节标题、图层控制标题、弹窗标签行等) | | `--ui-text-3` | 三级文字(搜索结果的地址/信用代码等辅文) | | `--ui-text-desc` | 描述/弱说明(弹窗长段落、muted) | | `--ui-text-placeholder` | 输入框占位符 | | `--ui-main` | 强调色 / 主描边 / 链接 / 搜索命中高亮 | `resolveThemeTokens()` 会把上述项**派生**到旧变量(如 `--ui-panel-bg`、`--ui-search-bg`、`--ui-popup-inner-bg`、`--ui-panel-text`、`--ui-title-section` 等),便于逐步迁移样式而无需一次改全库。 **合并 overrides 时清理的废弃覆盖键**(若本地仍存有历史配置会被删掉):`--ui-panel-bg`、`--ui-search-bg`、`--ui-popup-inner-bg`、`--ui-popup-card-bg`、`--ui-panel-text`、`--ui-card-title-text`、`--ui-border-accent`、`--ui-popup-accent`、`--ui-link`、`--ui-search-result-active`、`--ui-title-section`、`--ui-title2`、`--ui-popup-text`、`--ui-popup-muted`、`--ui-search-text`、`--ui-search-secondary`。 ## 开发者:代码入口 | 环节 | 说明 | |------|------| | 内置表 | `src/utils/uiTheme.js` 中 `NIGHT`、`DAY` 对象 | | 派生合并 | `resolveThemeTokens`、`getBaseTokens`、`getMergedTokens`、`applyUiTheme`、`persistTheme` | | 可编辑键列表 | `THEME_CONFIG_PICKER_KEYS` | | 启动应用 | `src/main.js` 在挂载 Vue 根实例前 `loadStoredTheme()` + `applyUiTheme` | | 页面交互 | `src/views/qpjyj.vue`:`isDayTheme`、`themeOverridesByMode`、`syncThemeWithBaseMap`、`openThemeConfig`、`applyThemeFormLive`(取色拖动即时生效)、`resetThemeDefaults` | | 全局样式 | `src/assets/global.css`:Leaflet 弹窗、下拉、地图标注等 | | 卡片 | `src/components/card/index.vue` | | 图表 | `pieView.vue` / `barView.vue`:`chart-theme` prop(`day` / `night`) | | 地图容器底色 | `appMap.vue`:`background: var(--ui-map-bg)` | 完整变量名列表见 `uiTheme.js` 中的 `UI_THEME_VAR_KEYS`。 ## 扩展主题配置 UI 1. 在 `uiTheme.js` 的 `NIGHT` / `DAY` 中增加默认值,并在 `resolveThemeTokens` 中如需则派生到旧键。 2. 将新键加入 `UI_THEME_VAR_KEYS`;若需出现在对话框,加入 `THEME_CONFIG_PICKER_KEYS` 与 `qpjyj.vue` 表单项。 3. 在样式中优先使用 `var(--ui-text-*)` / `var(--ui-surface-bg)`,并保留 `var(--旧键, 回退)` 以兼容。 ## 与底图的关系 主题只负责 **UI 叠层**(头、搜索、侧栏、图例、弹窗、ECharts),**不自动切换** Leaflet 底图。浅色底图对应白天模式;微调颜色请用 **主题配置** 或编辑 `overrides`。 ## 白天模式专项视觉优化(实现说明) 以下项在 **`data-ui-theme="day"`** 下单独加强可读性,**不写入**主题 Token(避免与 ColorPicker 配置纠缠);若需改版可改对应源码。 | 区域 | 问题 | 实现位置 | |------|------|----------| | **青浦园产业分布** 三枚图标 | 静态 PNG 偏暗,浅底卡片上发灰 | `qpjyj.vue`:`.industrial-dist-icon` + `.container.theme-day` 下对 `img` / `.el-image__inner` 使用 `filter` | | **核心企业集聚程度** 柱状图 | 浅色画布上阴影/柱渐变过重 | `barView.vue`:白天 `axisPointer`、柱渐变、`itemStyle.opacity` | | **园区详情弹窗** pup1 / pup2 | 小图与浅色弹窗底对比不足 | `appMap.vue`:`map-popup-stat-icon`;`global.css`:`html[data-ui-theme="day"]` 下衬底与滤镜 | 黑夜模式保持原有观感;弹窗图标在黑夜下不强制套白天衬底(选择器仅 `day`)。 --- *变更时请同步更新本节与 `ARCHITECTURE.md` 中主题相关条目。*