feat: 트렌드 워크스페이스(ECharts) 추가 + 이벤트히스토리 sub_area 정렬
트렌드 P1 (Tab 17 "트렌드"): - 단일 ECharts 차트 슬롯구조(trState/TR_LAYERS/trRender) — P2/P3 무중단 증분 기반 - 기능: 그룹빌더(realtime 아날로그 클릭선택)/멀티시리즈·이중축/dataZoom(좌우날짜)/ 범례표(색변경·행클릭 강조·보이는구간 통계)/보이는범위 minmax 마커/라이브 현재값/ 트립·이벤트 오버레이(/api/event-history 재사용)/100%환산/Y줌 - 백엔드: trend_group 테이블 + v_analog_points 뷰(숫자 livevalue=아날로그) + TrendService/TrendController(/api/trend: analog-points·groups CRUD·live) + DI - echarts 5.5.1 로컬 번들, DTO는 [JsonPropertyName]로 camelCase 고정 이벤트히스토리 sub_area 정렬(컬럼 일치): - event_history_table section → sub_area (DDL/인덱스/엔티티/DTO/서비스/컨트롤러/evt UI/MCP/프롬프트) - 이력 조회 PIVOT 재작성(MAX/CASE), ft.category '계기' → 'instrument' Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1622,7 +1622,7 @@ async def query_events(
|
||||
|
||||
sql = f"""
|
||||
SELECT id, tagname, prev_value, curr_value, event_type, event_time,
|
||||
area, section, duration_seconds, metadata
|
||||
area, sub_area, duration_seconds, metadata
|
||||
FROM event_history_table
|
||||
WHERE {' AND '.join(where)}
|
||||
ORDER BY event_time DESC
|
||||
@@ -1638,7 +1638,7 @@ async def query_events(
|
||||
events = [
|
||||
{"id": r[0], "tag_name": r[1], "prev_value": r[2], "curr_value": r[3],
|
||||
"event_type": r[4], "event_time": r[5].isoformat() if r[5] else None,
|
||||
"area": r[6], "section": r[7], "prev_state_duration_s": r[8], "metadata": r[9]}
|
||||
"area": r[6], "sub_area": r[7], "prev_state_duration_s": r[8], "metadata": r[9]}
|
||||
for r in rows
|
||||
]
|
||||
return json.dumps({
|
||||
@@ -1678,13 +1678,13 @@ async def active_alarms(area: str | None = None, limit: int = 100) -> str:
|
||||
WITH latest AS (
|
||||
SELECT DISTINCT ON (tagname)
|
||||
id, tagname, curr_value, event_type, event_time,
|
||||
area, section, duration_seconds, metadata
|
||||
area, sub_area, duration_seconds, metadata
|
||||
FROM event_history_table
|
||||
WHERE event_time >= NOW() - INTERVAL '30 days'
|
||||
ORDER BY tagname, event_time DESC
|
||||
)
|
||||
SELECT id, tagname, curr_value, event_type, event_time,
|
||||
area, section, duration_seconds, metadata,
|
||||
area, sub_area, duration_seconds, metadata,
|
||||
EXTRACT(EPOCH FROM (NOW() - event_time))::bigint AS age_seconds
|
||||
FROM latest
|
||||
WHERE event_type IN ('ALARM', 'TRIP')
|
||||
@@ -1700,7 +1700,7 @@ async def active_alarms(area: str | None = None, limit: int = 100) -> str:
|
||||
alarms = [
|
||||
{"id": r[0], "tag_name": r[1], "curr_value": r[2], "event_type": r[3],
|
||||
"since": r[4].isoformat() if r[4] else None,
|
||||
"area": r[5], "section": r[6], "prev_state_duration_s": r[7], "metadata": r[8],
|
||||
"area": r[5], "sub_area": r[6], "prev_state_duration_s": r[7], "metadata": r[8],
|
||||
"age_seconds": r[9]}
|
||||
for r in rows
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user