431 lines
15 KiB
Python
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,
|
|
)
|
|
])
|