codeSearch/ui/fault_finder.py

431 lines
15 KiB
Python

import flet as ft
import sqlite3
from typing import List, Dict, Callable
from database.db_manager import DatabaseManager
class FaultFinderUI:
"""고장코드 검색 UI를 관리하는 클래스입니다."""
def __init__(self, page: ft.Page, db_manager: DatabaseManager):
"""
FaultFinderUI를 초기화합니다.
Args:
page (ft.Page): Flet 페이지 객체
db_manager (DatabaseManager): 데이터베이스 관리자 인스턴스
"""
self.page = page
self.db_manager = db_manager
# 전체 제작사 목록 가져오기
self.manufacturers = self._get_manufacturers()
# 상단: 제작사 필터
self.manufacturer_dropdown = ft.Dropdown(
label="제작사 선택",
options=[
ft.dropdown.Option(manufacturer) for manufacturer in self.manufacturers
],
on_change=self._on_manufacturer_change,
expand=True
)
# 전체 고장 타입 목록 가져오기
self.fault_types = self._get_fault_types()
# 상단: 고장 타입 필터
self.type_dropdown = ft.Dropdown(
label="장치분류 선택",
options=[
ft.dropdown.Option(type_) for type_ in self.fault_types
],
on_change=self._on_type_change,
expand=True
)
# 중앙: 고장 리스트
self.fault_list = ft.DataTable(
columns=[
ft.DataColumn(ft.Text("고장코드")),
ft.DataColumn(ft.Text("고장명")),
ft.DataColumn(ft.Text("고장타입"))
],
rows=[],
expand=True,
show_bottom_border=True,
column_spacing=10,
horizontal_lines=ft.border.BorderSide(1, "grey")
)
# 중앙 리스트 컨테이너 (스크롤 가능하도록)
self.fault_list_container = ft.Container(
content=ft.ListView(
controls=[self.fault_list],
expand=True,
spacing=10,
padding=10,
auto_scroll=True
),
expand=True,
border=ft.border.all(1, ft.colors.GREY_300),
border_radius=10
)
# 하단: 검색 필드
self.search_field = ft.TextField(
label="검색어 입력",
hint_text="고장코드나 고장명을 입력하세요",
expand=True,
on_change=self._on_search_change,
prefix_icon=ft.icons.SEARCH
)
# 메인 컨테이너
self.container = ft.Container(
content=ft.Column([
# 상단: 제작사 필터
ft.Container(
content=self.manufacturer_dropdown,
padding=10,
bgcolor=ft.colors.BLUE_GREY_50,
border_radius=10
),
# 상단: 고장 타입 필터
ft.Container(
content=self.type_dropdown,
padding=10,
bgcolor=ft.colors.BLUE_GREY_50,
border_radius=10
),
# 중앙: 고장 리스트
self.fault_list_container,
# 하단: 검색 필드
ft.Container(
content=self.search_field,
padding=10,
bgcolor=ft.colors.BLUE_GREY_50,
border_radius=10
)
], spacing=10),
expand=True,
padding=10
)
# 초기 로딩
self.load_all_codes()
def _get_manufacturers(self) -> List[str]:
"""
제작사 목록을 가져옵니다.
Returns:
List[str]: 제작사 목록
"""
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT manufacturers FROM woojin200 ORDER BY manufacturers")
manufacturers = [manufacturer[0] for manufacturer in cursor.fetchall()]
conn.close()
return manufacturers
def _get_fault_types(self) -> List[str]:
"""
고장 타입 목록을 가져옵니다.
Returns:
List[str]: 고장 타입 목록
"""
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT fault_type FROM woojin200 ORDER BY fault_type")
types = [type_[0] for type_ in cursor.fetchall()]
conn.close()
return types
def load_all_codes(self):
"""전체 고장 코드 목록을 로드합니다."""
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
ORDER BY fault_code
""")
results = cursor.fetchall()
conn.close()
self._update_fault_list(results)
def _on_manufacturer_change(self, e):
"""
제작사 선택 시 호출되는 콜백 함수입니다.
Args:
e: 드롭다운 변경 이벤트
"""
selected_manufacturer = self.manufacturer_dropdown.value
selected_type = self.type_dropdown.value
if selected_manufacturer:
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
# 제작사만 선택된 경우
if not selected_type:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE manufacturers = ?
ORDER BY fault_code
""", (selected_manufacturer,))
# 제작사와 고장 타입 모두 선택된 경우
else:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE manufacturers = ? AND fault_type = ?
ORDER BY fault_code
""", (selected_manufacturer, selected_type))
results = cursor.fetchall()
conn.close()
self._update_fault_list(results)
else:
# 제작사 선택 해제 시 현재 선택된 고장 타입으로 필터링
self._on_type_change(e)
def _on_type_change(self, e):
"""
고장 타입 선택 시 호출되는 콜백 함수입니다.
Args:
e: 드롭다운 변경 이벤트
"""
selected_type = self.type_dropdown.value
selected_manufacturer = self.manufacturer_dropdown.value
if selected_type:
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
# 고장 타입만 선택된 경우
if not selected_manufacturer:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE fault_type = ?
ORDER BY fault_code
""", (selected_type,))
# 제작사와 고장 타입 모두 선택된 경우
else:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE fault_type = ? AND manufacturers = ?
ORDER BY fault_code
""", (selected_type, selected_manufacturer))
results = cursor.fetchall()
conn.close()
self._update_fault_list(results)
else:
# 고장 타입 선택 해제 시 현재 선택된 제작사로 필터링
self._on_manufacturer_change(e)
def _on_search_change(self, e):
"""
검색어 변경 시 호출되는 콜백 함수입니다.
Args:
e: 검색 필드 변경 이벤트
"""
search_term = self.search_field.value
selected_type = self.type_dropdown.value
selected_manufacturer = self.manufacturer_dropdown.value
if search_term:
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
# 장치분류가 선택되지 않은 경우 전체 검색
if not selected_type:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE fault_code LIKE ? OR fault_name LIKE ?
ORDER BY fault_code
""", (f'%{search_term}%', f'%{search_term}%'))
# 장치분류가 선택된 경우 해당 분류 내에서 검색
else:
cursor.execute("""
SELECT fault_code, fault_name, fault_type
FROM woojin200
WHERE fault_type = ? AND (fault_code LIKE ? OR fault_name LIKE ?)
ORDER BY fault_code
""", (selected_type, f'%{search_term}%', f'%{search_term}%'))
results = cursor.fetchall()
conn.close()
self._update_fault_list(results)
else:
# 검색어가 없으면 현재 선택된 필터로 다시 로드
if selected_type:
self._on_type_change(e)
elif selected_manufacturer:
self._on_manufacturer_change(e)
else:
self.load_all_codes()
def _update_fault_list(self, results):
"""
고장 리스트를 업데이트합니다.
Args:
results (List[Tuple]): 고장 코드 결과 목록
"""
rows = []
for code, name, type_ in results:
row = ft.DataRow(
cells=[
ft.DataCell(ft.Text(str(code))),
ft.DataCell(ft.Text(name)),
ft.DataCell(ft.Text(type_))
],
on_select_changed=lambda e, code=code, name=name, type_=type_: self._show_fault_details(code, name, type_)
)
rows.append(row)
self.fault_list.rows = rows
self.page.update()
def _show_fault_details(self, code, name, type_):
"""
고장 상세 정보를 팝업으로 표시합니다.
Args:
code (str): 고장 코드
name (str): 고장명
type_ (str): 고장 타입
"""
conn = sqlite3.connect('fault_codes.db')
cursor = conn.cursor()
cursor.execute("""
SELECT fault_detail, reaction, detect_condition, clear_condition, action
FROM woojin200
WHERE fault_code = ?
""", (code,))
details = cursor.fetchone()
conn.close()
if details:
detail, reaction, detect, clear, action = details
# 상세 정보 다이얼로그 생성
dialog = ft.AlertDialog(
title=ft.Text(f"[{code}] {name}", weight=ft.FontWeight.BOLD),
content=ft.Column([
ft.Text("고장 타입: " + type_, color=ft.colors.BLUE_GREY_700),
ft.Divider(),
ft.Text("고장 상세:", weight=ft.FontWeight.BOLD),
ft.Text(detail, selectable=True),
ft.Divider(),
ft.Text("반응:", weight=ft.FontWeight.BOLD),
ft.Text(reaction, selectable=True),
ft.Divider(),
ft.Text("검지 조건:", weight=ft.FontWeight.BOLD),
ft.Text(detect, selectable=True),
ft.Divider(),
ft.Text("소거 조건:", weight=ft.FontWeight.BOLD),
ft.Text(clear, selectable=True),
ft.Divider(),
ft.Text("조치 방법:", weight=ft.FontWeight.BOLD),
ft.Text(action, selectable=True)
], width=500, height=500, scroll=ft.ScrollMode.AUTO),
actions=[
ft.TextButton("닫기", on_click=lambda e: self._close_dialog())
]
)
self.page.dialog = dialog
dialog.open = True
self.page.update()
def _close_dialog(self):
"""
다이얼로그를 닫는 메서드입니다.
"""
if self.page.dialog:
self.page.dialog.open = False
self.page.update()
def create_search_field(self, on_change: Callable) -> ft.TextField:
"""검색 필드를 생성합니다."""
self.search_field = ft.TextField(
label="검색",
hint_text="고장코드, 고장명, 분류 등을 입력하세요",
on_change=on_change,
expand=True
)
return self.search_field
def create_data_table(self, data: List) -> ft.DataTable:
"""검색 결과로 데이터 테이블을 생성합니다."""
columns = [
ft.DataColumn(ft.Text("고장코드")),
ft.DataColumn(ft.Text("고장명")),
ft.DataColumn(ft.Text("등급")),
ft.DataColumn(ft.Text("분류")),
ft.DataColumn(ft.Text("고장내용"), numeric=False),
ft.DataColumn(ft.Text("반응")),
ft.DataColumn(ft.Text("검지조건")),
ft.DataColumn(ft.Text("소거조건")),
ft.DataColumn(ft.Text("조치방법"))
]
rows = []
for row in data:
cells = [ft.DataCell(ft.Text(str(cell))) for cell in row]
rows.append(ft.DataRow(cells=cells))
self.data_table = ft.DataTable(
columns=columns,
rows=rows,
border=ft.border.all(1, "grey"),
border_radius=10,
vertical_lines=ft.border.BorderSide(1, "grey"),
horizontal_lines=ft.border.BorderSide(1, "grey"),
)
return self.data_table
def update_table(self, data: List):
"""테이블 데이터를 업데이트합니다."""
new_table = self.create_data_table(data)
self.data_table.columns = new_table.columns
self.data_table.rows = new_table.rows
def create_layout(self) -> ft.Column:
"""메인 레이아웃을 생성합니다."""
return ft.Column([
ft.Container(
content=self.search_field,
padding=10,
),
ft.Container(
content=ft.Column([
ft.Text("검색 결과", size=20, weight=ft.FontWeight.BOLD),
ft.Container(
content=self.data_table,
height=500,
)
]),
padding=10,
expand=True,
)
])