import '@material/web/button/elevated-button.js' // import '@material/web/select/outlined-select.js' import '@material/web/textfield/outlined-text-field.js' import '@material/web/icon/icon.js' import { PageView } from '@operato/shell' import { css, html, LitElement } from 'lit' import { customElement, property } from 'lit/decorators.js' import { client } from '@operato/graphql' import { i18next, localize } from '@operato/i18n' import { notify } from '@operato/layout' import { OxPopup } from '@operato/popup' import gql from 'graphql-tag' import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles' const VIZ_TYPES = [ { value: 'CARD', label: '카드', icon: 'dashboard' }, { value: 'GAUGE', label: '게이지', icon: 'speed' }, { value: 'PROGRESS', label: '진행률', icon: 'linear_scale' }, { value: 'BAR', label: '막대 차트', icon: 'bar_chart' }, { value: 'LINE', label: '선 차트', icon: 'show_chart' }, { value: 'PIE', label: '파이 차트', icon: 'pie_chart' }, { value: 'DONUT', label: '도넛 차트', icon: 'donut_large' }, { value: 'RADAR', label: '레이더 차트', icon: 'radar' }, { value: 'BULLET', label: '불릿 차트', icon: 'track_changes' }, { value: 'THERMOMETER', label: '온도계', icon: 'thermostat' }, { value: 'SPEEDOMETER', label: '속도계', icon: 'speed' }, { value: 'ICON', label: '아이콘', icon: 'emoji_events' }, { value: 'BADGE', label: '배지', icon: 'badge' }, { value: 'TEXT', label: '텍스트', icon: 'text_fields' }, { value: 'TABLE', label: '테이블', icon: 'table_chart' } ] @customElement('kpi-viz-editor') export class KpiVizEditor extends localize(i18next)(LitElement) { static styles = [ CommonHeaderStyles, ScrollbarStyles, css` :host { display: flex; flex-direction: column; background-color: var(--md-sys-color-surface, #f4f6fa); } .viz-editor { flex: 1; display: flex; flex-direction: column; overflow-y: auto; background: white; padding: 24px; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 8px; font-weight: 500; color: #555; } .form-options { flex: 1; display: flex; flex-direction: row; } .viz-type-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; margin-bottom: 20px; } .viz-type-option { display: flex; flex-direction: column; align-items: center; padding: 16px 12px; border: 2px solid #e0e0e0; border-radius: 8px; cursor: pointer; transition: all 0.2s; text-align: center; } .viz-type-option:hover { border-color: #2196f3; background: #f5f9ff; } .viz-type-option.selected { border-color: #2196f3; background: #e3f2fd; } .viz-type-option md-icon { font-size: 24px; margin-bottom: 8px; color: #666; } .viz-type-option.selected md-icon { color: #2196f3; } .viz-type-option .label { font-size: 0.9rem; font-weight: 500; color: #333; } .viz-meta-section { margin-top: 24px; padding-top: 20px; border-top: 1px solid #eee; } .color-picker { display: flex; gap: 12px; align-items: center; margin-bottom: 16px; } .color-input { width: 60px; height: 40px; border: none; border-radius: 6px; cursor: pointer; } .buttons { display: flex; gap: 12px; justify-content: flex-end; margin-top: 24px; padding-top: 20px; border-top: 1px solid #eee; } .preview { flex: 1; margin: 30px 16px 16px 16px; padding: 16px; background: #f8f9fa; border-radius: 8px; border: 1px solid #e9ecef; } .preview h4 { margin: 0 0 12px 0; color: #495057; font-size: 0.95rem; } .footer span { font-size: 0.8em; color: var(--md-sys-color-on-surface); line-height: 1.5; padding: 10px; } ` ] @property({ type: Object }) kpi: any = null @property({ type: String }) selectedVizType: string = 'CARD' @property({ type: Object }) vizMeta: any = {} @property({ type: Object }) onSave: Function = () => {} @property({ type: Object }) onCancel: Function = () => {} connectedCallback() { super.connectedCallback() if (this.kpi) { this.selectedVizType = this.kpi.vizType || 'CARD' this.vizMeta = this.kpi.vizMeta || {} } } _selectVizType(type: string) { this.selectedVizType = type this.requestUpdate() } _updateVizMeta(key: string, value: any) { this.vizMeta = { ...this.vizMeta, [key]: value } this.requestUpdate() } _renderPreview() { const kpiValue = this.kpi?.value?.value ?? 75 const targetValue = this.kpi?.targetValue ?? 100 const unit = this.kpi?.unit ?? '' const color = this.vizMeta.color || '#2196f3' const icon = this.vizMeta.icon || 'trending_up' const min = this.vizMeta.minValue ?? 0 const max = this.vizMeta.maxValue ?? 100 switch (this.selectedVizType) { case 'CARD': return html`