|
|
@@ -6,7 +6,7 @@
|
|
|
* 本文件当前只含 `matrix` 子视图(默认),其余子视图(loop/units/events/cms)待迁。
|
|
|
*/
|
|
|
import { t } from '../i18n/zh'
|
|
|
-import { unitNo } from './render'
|
|
|
+import { unitNo, winName } from './render'
|
|
|
import { partName, sysName } from './render2'
|
|
|
import { VIBJARGON } from './vibjargon'
|
|
|
|
|
|
@@ -163,8 +163,6 @@ export const devBar = (ch: unknown, dev: number | null, vd: unknown, raw: unknow
|
|
|
export const winBar = (spans: any[] | undefined, raw: unknown): string => { if (!spans || !spans.length) return `<span class="small" title="${esc(raw || '')}">${t('fus.win_none')}</span>`; const T0 = Date.parse('2026-01-01'), T1 = Date.parse('2026-09-01'), W = 118, px = d => 3 + Math.max(0, Math.min(1, (Date.parse(d) - T0) / (T1 - T0))) * (W - 6);
|
|
|
return `<div title="${esc(raw || '')}"><svg class="dt" viewBox="0 0 ${W} 18" style="width:${W}px;height:18px"><rect x="3" y="4" width="${W - 6}" height="10" rx="2" fill="var(--line)" fill-opacity=".5"/>${spans.map(([a, b]) => { const x1 = px(a), x2 = px(b); return `<rect x="${x1.toFixed(1)}" y="4" width="${Math.max(x2 - x1, 2.5).toFixed(1)}" height="10" rx="2" fill="var(--accent)" fill-opacity=".8"/>`; }).join('')}</svg><div class="small muted">${t('fus.win_n', { n: spans.length })}</div></div>`; };
|
|
|
export const oilPill = (last: unknown, fresh: unknown, raw: unknown): string => `<div title="${esc(raw || '')}" style="display:flex;align-items:center;gap:6px"><i style="width:9px;height:9px;border-radius:50%;flex:none;background:${fresh ? 'var(--good)' : 'var(--unknown)'}"></i><span class="small num">${esc(last || t('fus.oil_none'))}</span></div><div class="small muted">${last ? (fresh ? t('fus.oil_fresh') : t('fus.oil_stale')) : '—'}</div>`;
|
|
|
- const evLadder = (x) => { const T = String(x || ''), n = /准定论|near[- ](?:conf|establish)/i.test(T) ? 3 : /确诊|onfirmed/.test(T) ? 4 : /定论|ettled|stablished/.test(T) ? 3 : /候选|andidate/.test(T) ? 2 : /参考|eference/.test(T) ? 1 : 0, col = n >= 4 ? 'var(--critical)' : n === 3 ? 'var(--warning)' : n === 2 ? 'var(--accent)' : n === 1 ? 'var(--muted)' : 'var(--unknown)';
|
|
|
- return `<div style="display:flex;align-items:center;gap:7px"><svg class="dt" viewBox="0 0 62 20" style="width:62px;height:20px;flex:none">${[0, 1, 2, 3].map(i => `<rect x="${2 + i * 15}" y="${12 - i * 3}" width="11" height="${6 + i * 3}" rx="1.5" fill="${i < n ? col : 'none'}" fill-opacity=".9" stroke="${col}" stroke-opacity="${i < n ? 1 : .4}" ${i >= n ? 'stroke-dasharray="2 1.5"' : ''}/>`).join('')}</svg><span class="small" style="color:${col}">${dv(T)}</span></div>`; };
|
|
|
|
|
|
/** 旧 `stateChip`(app.js:84) */
|
|
|
export const stateChip = (zh: unknown, cls?: string): string => {
|
|
|
@@ -204,4 +202,57 @@ export function unitsHtml(F: any, filter: string | null): string {
|
|
|
}
|
|
|
|
|
|
export const CHAIN7 = [['mbf', /主轴承[((]前|主轴承前|主轴承[++]|主轴承(?![((前后])/], ['mba', /主轴承[((]后|主轴承后/], ['ps', /行星|二级行星/], ['ims', /中间轴|中速/], ['hss', /高速轴|高速(?!.*发电)/], ['gde', /发电机DE|发电机[((]|发电机(?!NDE)/], ['gnde', /发电机NDE|NDE/]];
|
|
|
+export const gc = st => STC[stateKey(st)] || null;
|
|
|
+export const chainStates = (map) => `<span class="chain">${Object.entries(map).map(([k, col]) => `<i class="${col ? 'on' : ''}" style="${col ? `background:${col};border-color:${col}` : ''}" title="${t('chain.' + k)}"></i>`).join('')}</span>`;
|
|
|
+export const evLadder = (x) => { const T = String(x || ''), n = /准定论|near[- ](?:conf|establish)/i.test(T) ? 3 : /确诊|onfirmed/.test(T) ? 4 : /定论|ettled|stablished/.test(T) ? 3 : /候选|andidate/.test(T) ? 2 : /参考|eference/.test(T) ? 1 : 0, col = n >= 4 ? 'var(--critical)' : n === 3 ? 'var(--warning)' : n === 2 ? 'var(--accent)' : n === 1 ? 'var(--muted)' : 'var(--unknown)';
|
|
|
+ return `<div style="display:flex;align-items:center;gap:7px"><svg class="dt" viewBox="0 0 62 20" style="width:62px;height:20px;flex:none">${[0, 1, 2, 3].map(i => `<rect x="${2 + i * 15}" y="${12 - i * 3}" width="11" height="${6 + i * 3}" rx="1.5" fill="${i < n ? col : 'none'}" fill-opacity=".9" stroke="${col}" stroke-opacity="${i < n ? 1 : .4}" ${i >= n ? 'stroke-dasharray="2 1.5"' : ''}/>`).join('')}</svg><span class="small" style="color:${col}">${dv(T)}</span></div>` };
|
|
|
+
|
|
|
+/** 旧 `fusEvents(F, d)` —— 报警工单(逐字转写,app.js:946-958) */
|
|
|
+export function eventsHtml(F: any, d: any): string {
|
|
|
+ if (!F.事件) return `<div class="panel mb"><p class="small muted">${t('ui.empty')}</p></div>`
|
|
|
+ let h = `<div class="panel mb"><p class="small muted"><b>${t('fus.ev_win', { win: winName(d.win) })}</b></p></div>`
|
|
|
+ for (const [comp, E0] of Object.entries(F.事件 as Record<string, any>)) {
|
|
|
+ const E = E0 as any
|
|
|
+ const A = E.报警 || {}, W = E.工单 || {}
|
|
|
+ h += `<div class="panel mb"><h3>${t('fus.ev_head', { c: sysName(comp), an: A.总条数 || 0, au: A.台数 || 0, wn: W.总条数 || 0, wu: W.台数 || 0 })}</h3>`
|
|
|
+ if (A.总条数 > 0) {
|
|
|
+ h += `<div class="tblwrap"><table><tr><th>${t('fus.ev_code')}</th><th>${t('fus.ev_text')}</th><th class="r">${t('ui.count')}</th><th class="r">${t('fus.ev_units')}</th><th class="r">${t('fus.ev_dur')}</th></tr>${(A.码统计 || []).map((c: any) => `<tr><td>${esc(c.code)}</td><td class="small">${dv(vibPlain(c.text))}</td><td class="r">${c.条数}</td><td class="r">${c.台数}</td><td class="r">${c.时长h}</td></tr>`).join('')}</table></div>
|
|
|
+ <p class="small">${t('fus.ev_top')}${Object.entries(A.top台 || {}).map(([u, n]) => `<a href="/turbine/${u}">${unitNo(u)}</a>×${n}`).join(' · ')}</p>
|
|
|
+ <details><summary class="small">${t('fus.ev_recent', { n: (A.近况 || []).length })}</summary><div class="tblwrap"><table><tr><th>${t('ui.unit')}</th><th>${t('fus.ev_time')}</th><th>${t('fus.ev_code')}</th><th>${t('fus.ev_text')}</th><th class="r">${t('fus.ev_min')}</th></tr>${(A.近况 || []).map((x: any) => `<tr><td>${unitNo(x.t)}</td><td class="small">${esc(x.on)}</td><td>${esc(x.code)}</td><td class="small">${dv(vibPlain(x.text))}</td><td class="r">${x.dur_min ?? '—'}</td></tr>`).join('')}</table></div></details>`
|
|
|
+ } else h += `<p class="small">${t('fus.ev_no_alarm')}</p>`
|
|
|
+ if (W.总条数 > 0) h += `<div class="tblwrap"><table style="margin-top:8px"><tr><th>${t('ui.unit')}</th><th>${t('ui.date')}</th><th>${t('fus.ev_wo_name')}</th><th>${t('fus.ev_wo_act')}</th><th>${t('fus.ev_wo_cause')}</th></tr>${(W.明细 || []).map((x: any) => `<tr><td>${unitNo(x.t)}</td><td class="small">${esc(x.date)}</td><td class="small">${dv(x.name)}</td><td class="small">${dv(x.act)}</td><td class="small">${dv(x.cause)}</td></tr>`).join('')}</table></div>`
|
|
|
+ else h += `<p class="small">${t('fus.ev_no_wo')}</p>`
|
|
|
+ h += `</div>`
|
|
|
+ }
|
|
|
+ return h
|
|
|
+}
|
|
|
+
|
|
|
+/** 旧 `fusCms()`(app.js:960-976)—— 数据来自 `/api/vibcms`(按需异步取) */
|
|
|
+export function cmsHtml(V: any, err?: string | null): string {
|
|
|
+ if (err) return `<div class="panel mb"><p class="small" style="color:var(--critical)">${esc(err)}</p></div>`
|
|
|
+ if (!V) return `<div class="panel mb"><p class="small muted">${t('fus.cms_loading')}</p></div>`
|
|
|
+ if (V.error) return `<div class="panel mb"><p class="small" style="color:var(--critical)">${dv(V.error)}</p></div>`
|
|
|
+ const CK: Record<string, string> = {
|
|
|
+ '主轴承前': 'mbf', '主轴承后': 'mba', '齿轮箱': 'gb', '发电机': 'gen', '发电机DE': 'gde', '发电机NDE': 'gnde',
|
|
|
+ 'Main bearing, front': 'mbf', 'Main bearing, rear': 'mba', 'Gearbox': 'gb', 'Generator': 'gen',
|
|
|
+ 'Generator DE': 'gde', 'Generator NDE': 'gnde',
|
|
|
+ }
|
|
|
+ return `<div class="panel mb"><h3>${t('fus.cms_head', { d: esc(V.date || '') })}</h3>
|
|
|
+ ${V['时间范围'] ? `<p class="small" style="margin:2px 0 6px">${t('fus.cms_window', { r: esc(V['时间范围']) })}</p>` : ''}
|
|
|
+ <p class="small">${dv(V.overall || '')} ${t('fus.cms_note')}</p>
|
|
|
+ <h3 style="margin-top:10px">${t('fus.cms_action')}</h3><div class="tblwrap"><table><tr><th>${t('ui.unit')}</th><th>${t('fus.loop_state')}</th><th>${t('fus.cms_focus')} <span class="small muted" style="font-weight:400">${t('fus.cms_focus_note')}</span></th><th>${t('fus.cms_evidence')}</th><th>${t('fus.cms_act')}</th></tr>
|
|
|
+ ${(V.action || []).map((r: any) => {
|
|
|
+ const cm: Record<string, string | null> = {}
|
|
|
+ String(r[2]).split(/[;;]/).forEach((seg: string) => {
|
|
|
+ const m = seg.split(/[::]/)
|
|
|
+ if (m.length > 1) { const k = CK[m[0].trim()] || null; if (k) cm[k] = gc(m[1].trim()) }
|
|
|
+ })
|
|
|
+ return `<tr><td><b>${unitNo(r[0])}</b></td><td>${stateChip(r[1])}</td><td title="${esc(r[2])}">${chainStates(cm)} <span class="small muted">${dv(r[2])}</span></td><td style="min-width:150px">${evLadder(r[3])}</td><td>${/P0/.test(r[4]) ? `<b style="color:var(--critical)">${esc(r[4])}</b>` : esc(r[4])}</td></tr>`
|
|
|
+ }).join('')}</table></div>
|
|
|
+ <h3 style="margin-top:14px">${t('fus.cms_grades')}</h3><div class="tblwrap"><table><tr><th>${t('ui.unit')}</th><th>${t('fus.cms_chain')} <span class="small muted" style="font-weight:400">${t('fus.cms_chain_note')}</span></th><th>${t('fus.cms_overall')}</th><th>${t('fus.cms_act')}</th></tr>
|
|
|
+ ${(V.grades || []).map((g: any) => `<tr><td><b>${unitNo(g.t)}</b></td><td title="${t('chain.mbf')} ${stWord(g.主轴承前)} · ${t('chain.mba')} ${stWord(g.主轴承后)} · ${t('chain.gb')} ${stWord(g.齿轮箱)} · ${t('chain.gen')} ${stWord(g.发电机)}">${chainStates({ mbf: gc(g.主轴承前), mba: gc(g.主轴承后), gb: gc(g.齿轮箱), gen: gc(g.发电机) })}</td><td>${stateChip(g.综合)}</td><td class="small">${esc(g.行动)}</td></tr>`).join('')}</table></div>
|
|
|
+ <div class="small" style="margin-top:12px;padding:10px;border:1px solid var(--line);border-radius:8px"><b>${t('fus.cms_basis')}</b> ${t('fus.cms_basis_note', { a: ((V.diff || {}).only_cms || []).map(unitNo).join(', ') || t('fus.none_word'), b: (((V.diff || {}).only_vibration_package || (V.diff || {})['only_' + 'hand' + 'off']) || []).map(unitNo).join(', ') || t('fus.none_word') })}</div>
|
|
|
+ <p class="small muted" style="margin-top:10px">${t('fus.cms_link')} <a href="http://localhost:8030/index.html" target="_blank" rel="noopener">${t('fus.cms_open')}</a> <a href="/windcms/index.html" target="_blank" rel="noopener">${t('fus.cms_static')}</a></p></div>`
|
|
|
+}
|
|
|
+
|
|
|
export const FUS_SUBS = ['matrix', 'loop', 'units', 'events', 'cms'] as const
|