|
|
@@ -24,26 +24,49 @@
|
|
|
`data-locate-point` 是可定位对象,`data-ledger-card` 是台账卡片,
|
|
|
`data-pie-*` 是状态分布饼图(票 14:扇区/图例行/选中态;面板不再自带筛选入口),
|
|
|
`data-panel-block` 是块类型,
|
|
|
- `data-panel-gap` 是契约缺口说明。
|
|
|
+ 票 56(二/三轮):顶部口径说明统一折叠进 `data-panel-summary-toggle` /
|
|
|
+ `data-panel-summary-details`,每条**保留自己原有的断言面**(折叠只是 `display:none`,
|
|
|
+ 文本仍在 DOM 里):`data-panel-gap` 契约缺口、`data-panel-note` 面板口径说明、
|
|
|
+ `data-panel-link-note` 联动出口、`data-panel-excluded-note` 口径剔除、
|
|
|
+ `data-panel-industry` / `data-panel-type-note` / `data-panel-event-note` /
|
|
|
+ `data-panel-range-note` / `data-panel-offline-note` / `data-panel-page-note` /
|
|
|
+ `data-locate-note`,另带 `data-summary="<键>"` 供按条目定位。
|
|
|
-->
|
|
|
<template>
|
|
|
<div ref="rootRef" class="panel-blocks" :data-panel-blocks="view.name" :data-panel-id="view.name">
|
|
|
- <!-- 面板级状态(色键与文案只来自 domain/sectionState.js) -->
|
|
|
- <header class="panel-blocks__head">
|
|
|
- <span v-if="view.industryNote" class="panel-blocks__note" data-panel-industry>{{ view.industryNote }}</span>
|
|
|
- <!-- 票 37:生效的设备类型(全局筛选条件之一)必须看得见,否则读者只看到"类型分布少了几行" -->
|
|
|
- <span v-if="view.typeNote" class="panel-blocks__note" data-panel-type-note>{{ view.typeNote }}</span>
|
|
|
- <span v-if="view.eventNote" class="panel-blocks__note" data-panel-event-note>{{ view.eventNote }}</span>
|
|
|
- <span v-if="view.rangeNote" class="panel-blocks__note" data-panel-range-note>{{ view.rangeNote }}</span>
|
|
|
+ <!-- 面板级状态(色键与文案只来自 domain/sectionState.js)。票 56 二轮:整条收成折叠入口。 -->
|
|
|
+ <header v-if="summaryItems.length" class="panel-blocks__head">
|
|
|
+ <!--
|
|
|
+ 票 56(第二轮,维护者 2026-10-17):**所有面板**的顶部摘要说明统一收成
|
|
|
+ 一个紧凑入口,且**只有点击**才展开/收起(撤销第一轮的 hover 自动展开——
|
|
|
+ 大屏上鼠标掠过就弹开,等于没有折叠)。键盘与触屏走原生 button:
|
|
|
+ Enter / Space / click 都会触发同一个 toggle,不必另写 keydown。
|
|
|
+ 每条摘要**保留自己原有的 `data-*` 断言面**(折叠时 `v-show` 只是隐藏,
|
|
|
+ 文本仍在 DOM 里),走查脚本读到的是同一句 domain 文案。
|
|
|
+ -->
|
|
|
+ <span class="panel-summary-disclosure">
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ class="panel-summary-disclosure__toggle"
|
|
|
+ :aria-expanded="summaryOpen"
|
|
|
+ :aria-controls="summaryDetailsId"
|
|
|
+ :aria-label="`${view.label || '面板'}摘要,${summaryOpen ? '收起' : '展开'}完整说明`"
|
|
|
+ data-panel-summary-toggle
|
|
|
+ @click="summaryOpen = !summaryOpen"
|
|
|
+ >
|
|
|
+ <span>{{ view.label || '面板' }}摘要</span><b>{{ summaryStatus }}</b><i aria-hidden="true">{{ summaryOpen ? '收起' : '展开' }}</i>
|
|
|
+ </button>
|
|
|
+ <span v-show="summaryOpen" :id="summaryDetailsId" class="panel-summary-disclosure__details" data-panel-summary-details>
|
|
|
+ <span
|
|
|
+ v-for="item in summaryItems"
|
|
|
+ :key="item.key"
|
|
|
+ :class="item.isGap ? 'panel-blocks__gap' : 'panel-blocks__note'"
|
|
|
+ v-bind="item.attrs"
|
|
|
+ >{{ item.text }}</span>
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
</header>
|
|
|
|
|
|
- <!-- 契约缺口:如实说明,不拿别的字段冒充(管理信息的「责任区域」、状态筛选不落图都是这一类) -->
|
|
|
- <p v-if="view.gap" class="panel-blocks__gap" data-panel-gap>{{ view.gap }}</p>
|
|
|
-
|
|
|
- <!-- 面板自己的附加说明(离线设备清单、分页口径),措辞来自 domain -->
|
|
|
- <p v-if="view.offlineNote" class="panel-blocks__note" data-panel-offline-note>{{ view.offlineNote }}</p>
|
|
|
- <p v-if="view.pageNote" class="panel-blocks__note" data-panel-page-note>{{ view.pageNote }}</p>
|
|
|
-
|
|
|
<!-- 还没取过数:说"正在取数",不说"没有数据"(那是在报告一件还没问过的事) -->
|
|
|
<p v-if="pending" class="panel-blocks__placeholder" data-panel-pending>{{ view.placeholder }}</p>
|
|
|
|
|
|
@@ -527,9 +550,6 @@
|
|
|
加载下一页监测点
|
|
|
</button>
|
|
|
|
|
|
- <!-- 可定位说明:有可定位对象才说,没有就说清为什么没有 -->
|
|
|
- <p v-if="view.locateNote" class="panel-blocks__note" data-locate-note>{{ view.locateNote }}</p>
|
|
|
-
|
|
|
<!-- 字段缺失:只说条数,路径进 tooltip(票 11 的立场) -->
|
|
|
<p
|
|
|
v-if="view.missing.count"
|
|
|
@@ -580,6 +600,59 @@ const emit = defineEmits(['locate', 'open-card', 'ledger-more', 'badge-needed',
|
|
|
/** 还没取过数(界面说"正在取数",不说"没有数据")。 */
|
|
|
const pending = computed(() => sectionPending(props.view.section))
|
|
|
|
|
|
+// 票 56(第二轮):所有面板顶部的摘要说明统一折叠,**只有点击**才展开/收起。
|
|
|
+// 只有一份状态(`summaryOpen`):hover / focus 都不碰它,所以鼠标掠过不会弹开、
|
|
|
+// 移开也不会把点击展开的内容收掉。展开态是纯展示状态,不进 store(面板私有、即挂即弃)。
|
|
|
+const summaryOpen = ref(false)
|
|
|
+const summaryDetailsId = computed(() => `panel-summary-details-${props.view.name || 'default'}`)
|
|
|
+
|
|
|
+/**
|
|
|
+ * 折叠进去的摘要条目。三条纪律:
|
|
|
+ * · **措辞与有无都由 domain 决定**,渲染层只按字段是否存在决定画不画,不重写、不合成;
|
|
|
+ * · 每条**保留原有的 `data-*` 断言面**(走查脚本 t17/t18/t20 读的还是同一个选择器与同一句话)。
|
|
|
+ * `v-show` 折叠时元素仍在 DOM 里,文本读得到 —— 折叠只改呈现,不改信息;
|
|
|
+ * · 本表是顶部口径说明的**唯一**消费点([t56 闸门](../../.scratch/cockpit-real-data-wayfinding/verify/t56-panel-summary-disclosure.mjs)
|
|
|
+ * E 组按 domain 声明双向锁定:domain 新增 `*Note`/`gap`/`note` 而不进这张表 → 判红;表内字段在 domain 已无声明 → 判红)。
|
|
|
+ *
|
|
|
+ * 后三条(`excludedNote` / `linkNote` / `note`)是第三轮补的:它们和前七条是同一件事,
|
|
|
+ * 但渲染层**从来没有消费点**——「故障口径」「两族口径」「联动出口」「口径剔除」这些必须
|
|
|
+ * 让值班人员看见的说明实际是隐形的。补法与票 49/50 的裁定一致:与其逐条发现,
|
|
|
+ * 不如把完备性做成机制。
|
|
|
+ */
|
|
|
+const SUMMARY_SOURCES = [
|
|
|
+ { key: 'industry', field: 'industryNote', hook: 'data-panel-industry' },
|
|
|
+ { key: 'type', field: 'typeNote', hook: 'data-panel-type-note' },
|
|
|
+ { key: 'event', field: 'eventNote', hook: 'data-panel-event-note' },
|
|
|
+ { key: 'range', field: 'rangeNote', hook: 'data-panel-range-note' },
|
|
|
+ { key: 'gap', field: 'gap', hook: 'data-panel-gap', isGap: true },
|
|
|
+ { key: 'offline', field: 'offlineNote', hook: 'data-panel-offline-note' },
|
|
|
+ { key: 'page', field: 'pageNote', hook: 'data-panel-page-note' },
|
|
|
+ { key: 'locate', field: 'locateNote', hook: 'data-locate-note' },
|
|
|
+ { key: 'excluded', field: 'excludedNote', hook: 'data-panel-excluded-note' },
|
|
|
+ { key: 'link', field: 'linkNote', hook: 'data-panel-link-note' },
|
|
|
+ { key: 'note', field: 'note', hook: 'data-panel-note' },
|
|
|
+]
|
|
|
+
|
|
|
+const summaryItems = computed(() =>
|
|
|
+ SUMMARY_SOURCES.flatMap(({ key, field, hook, isGap }) => {
|
|
|
+ const text = props.view[field]
|
|
|
+ if (!text) return []
|
|
|
+ return [{ key, text, isGap: Boolean(isGap), attrs: { [hook]: '', 'data-summary': key } }]
|
|
|
+ }),
|
|
|
+)
|
|
|
+
|
|
|
+/**
|
|
|
+ * 折叠态也要说得出「有没有要关注的东西」——只留标题会把口径缺口读成「一切正常」。
|
|
|
+ * 判据是 domain 的措辞本身(`'当前窗口没有离线设备'` 是 `monitoringPanels.js` 给的无离线句),
|
|
|
+ * 渲染层不自己算任何数。`note` / `gap` / `excludedNote` 同属口径说明一档。
|
|
|
+ */
|
|
|
+const summaryStatus = computed(() => {
|
|
|
+ const view = props.view
|
|
|
+ if (view.offlineNote && view.offlineNote !== '当前窗口没有离线设备') return '有离线设备'
|
|
|
+ if (view.gap || view.note || view.excludedNote) return '有口径提示'
|
|
|
+ return `${summaryItems.value.length} 条说明`
|
|
|
+})
|
|
|
+
|
|
|
/**
|
|
|
* 票 38:维度切换的**组件本地状态**(键=面板名 + 块标题,值=当前维度键)。
|
|
|
* 为什么放组件而不是 store:「换哪个维度看」不是全局条件(与 industry/district/deviceType
|
|
|
@@ -834,6 +907,52 @@ onBeforeUnmount(() => {
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
+.panel-summary-disclosure {
|
|
|
+ position: relative;
|
|
|
+ /* 头部是 flex-wrap 容器:折叠入口独占一行(`flex-basis: 100%`),长句才能在栏宽内换行,
|
|
|
+ 不被 max-content 顶出横向溢出(票 13 的「右侧被裁」是同一类缺陷)。 */
|
|
|
+ flex: 1 1 100%;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-summary-disclosure__toggle {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: calc(5 * var(--u, 1px));
|
|
|
+ min-height: calc(24 * var(--u, 1px));
|
|
|
+ padding: calc(2 * var(--u, 1px)) calc(7 * var(--u, 1px));
|
|
|
+ border: 1px solid rgba(1, 171, 234, 0.38);
|
|
|
+ border-radius: 3px;
|
|
|
+ background: rgba(0, 20, 72, 0.58);
|
|
|
+ color: var(--text-2, #88b7e8);
|
|
|
+ font: inherit;
|
|
|
+ font-size: var(--fs-caption, 10.5px);
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.panel-summary-disclosure__toggle:hover,
|
|
|
+.panel-summary-disclosure__toggle:focus-visible {
|
|
|
+ border-color: var(--cyan-hi, #00b8ff);
|
|
|
+ color: var(--text-strong, #fff);
|
|
|
+ outline: none;
|
|
|
+}
|
|
|
+.panel-summary-disclosure__toggle b { color: var(--text, #d7ecff); font-weight: 700; }
|
|
|
+.panel-summary-disclosure__toggle i { color: var(--muted, #5680b0); font-style: normal; }
|
|
|
+.panel-summary-disclosure__details {
|
|
|
+ display: grid;
|
|
|
+ gap: calc(3 * var(--u, 1px));
|
|
|
+ margin-top: calc(4 * var(--u, 1px));
|
|
|
+ padding: calc(4 * var(--u, 1px)) calc(7 * var(--u, 1px));
|
|
|
+ border-left: 2px solid var(--cyan, #01abea);
|
|
|
+ background: rgba(0, 20, 72, 0.42);
|
|
|
+}
|
|
|
+/* 展开区内每条摘要自己收口:等宽长串(统计窗口的 ISO 时间)按字符断行,不溢出面板。 */
|
|
|
+.panel-summary-disclosure__details > span {
|
|
|
+ min-width: 0;
|
|
|
+ overflow-wrap: anywhere;
|
|
|
+}
|
|
|
+.panel-summary-disclosure__details > .panel-blocks__gap {
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
.panel-blocks,
|
|
|
.panel-blocks *,
|
|
|
.panel-blocks *::before,
|