テーマの準備
This commit is contained in:
parent
25032d3b9b
commit
3e4af336f8
2 changed files with 92 additions and 81 deletions
|
|
@ -111,10 +111,13 @@ def build_invoice_items_edit_table(
|
|||
products: List[Product],
|
||||
on_product_select: Callable[[int], None] | None = None,
|
||||
row_refs: Optional[dict] = None,
|
||||
enable_reorder: bool = False,
|
||||
on_reorder: Optional[Callable[[int, int], None]] = None,
|
||||
) -> ft.Column:
|
||||
"""編集モードの明細テーブル。"""
|
||||
header_row = ft.Row(
|
||||
[
|
||||
ft.Container(width=28),
|
||||
ft.Text("商品", size=12, weight=ft.FontWeight.BOLD, width=180),
|
||||
ft.Text("数", size=12, weight=ft.FontWeight.BOLD, width=35),
|
||||
ft.Text("単価", size=12, weight=ft.FontWeight.BOLD, width=70),
|
||||
|
|
@ -190,20 +193,40 @@ def build_invoice_items_edit_table(
|
|||
"subtotal": subtotal_text,
|
||||
}
|
||||
|
||||
data_rows.append(
|
||||
ft.Row(
|
||||
[
|
||||
product_field,
|
||||
quantity_field,
|
||||
unit_price_field,
|
||||
subtotal_text,
|
||||
delete_button,
|
||||
],
|
||||
key=f"row-{i}-{item.description}",
|
||||
)
|
||||
handle = ft.Icon(
|
||||
ft.Icons.DRAG_HANDLE,
|
||||
size=18,
|
||||
color=ft.Colors.BLUE_GREY_400,
|
||||
visible=enable_reorder and not is_locked,
|
||||
)
|
||||
|
||||
list_control: ft.Control = ft.Column(data_rows, spacing=4)
|
||||
row_control = ft.Row(
|
||||
[
|
||||
handle,
|
||||
product_field,
|
||||
quantity_field,
|
||||
unit_price_field,
|
||||
subtotal_text,
|
||||
delete_button,
|
||||
],
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
key=f"row-{i}-{item.description}",
|
||||
)
|
||||
|
||||
data_rows.append(row_control)
|
||||
|
||||
if enable_reorder and on_reorder and not is_locked:
|
||||
reorder_items = [
|
||||
ft.ReorderableListViewItem(key=str(idx), content=row)
|
||||
for idx, row in enumerate(data_rows)
|
||||
]
|
||||
list_control = ft.ReorderableListView(
|
||||
controls=reorder_items,
|
||||
on_reorder=lambda e: on_reorder(e.old_index, e.new_index),
|
||||
shrink_wrap=True,
|
||||
)
|
||||
else:
|
||||
list_control = ft.Column(data_rows, spacing=4)
|
||||
|
||||
return ft.Column(
|
||||
[
|
||||
|
|
|
|||
126
main.py
126
main.py
|
|
@ -205,48 +205,9 @@ class FlutterStyleDashboard:
|
|||
|
||||
# 保存後遷移設定(True: 詳細に留まる, False: 一覧へ戻る)
|
||||
self.stay_on_detail_after_save = True
|
||||
self.invoice_card_theme = {
|
||||
"page_bg": "#F3F2FB",
|
||||
"card_bg": ft.Colors.WHITE,
|
||||
"card_radius": 18,
|
||||
"shadow": ft.BoxShadow(
|
||||
blur_radius=16,
|
||||
spread_radius=0,
|
||||
color="#D5D8F0",
|
||||
offset=ft.Offset(0, 6),
|
||||
),
|
||||
"icon_fg": ft.Colors.WHITE,
|
||||
"icon_default_bg": "#5C6BC0",
|
||||
"title_color": ft.Colors.BLUE_GREY_900,
|
||||
"subtitle_color": ft.Colors.BLUE_GREY_500,
|
||||
"amount_color": "#2F3C7E",
|
||||
"tag_text_color": "#4B4F67",
|
||||
"tag_bg": "#E7E9FB",
|
||||
"draft_card_bg": "#F5EEE4",
|
||||
"draft_border": "#D7C4AF",
|
||||
"draft_badge_bg": "#A7743A",
|
||||
"draft_shadow_highlight": ft.BoxShadow(
|
||||
blur_radius=8,
|
||||
spread_radius=0,
|
||||
color="#FFFFFF",
|
||||
offset=ft.Offset(-2, -2),
|
||||
),
|
||||
"draft_shadow_depth": ft.BoxShadow(
|
||||
blur_radius=14,
|
||||
spread_radius=2,
|
||||
color="#C3A88C",
|
||||
offset=ft.Offset(4, 6),
|
||||
),
|
||||
"badge_bg": "#35C46B",
|
||||
}
|
||||
self.doc_type_palette = {
|
||||
DocumentType.INVOICE.value: "#5C6BC0",
|
||||
DocumentType.ESTIMATE.value: "#7E57C2",
|
||||
DocumentType.DELIVERY.value: "#26A69A",
|
||||
DocumentType.RECEIPT.value: "#FF7043",
|
||||
DocumentType.SALES.value: "#42A5F5",
|
||||
DocumentType.DRAFT.value: "#90A4AE",
|
||||
}
|
||||
self.current_theme = "light"
|
||||
self.theme_presets = self._build_theme_presets()
|
||||
self.apply_theme(self.current_theme)
|
||||
|
||||
# ビジネスロジックサービス
|
||||
self.app_service = AppService()
|
||||
|
|
@ -254,6 +215,8 @@ class FlutterStyleDashboard:
|
|||
self.customers = []
|
||||
self._item_row_refs: Dict[int, Dict[str, ft.Control]] = {}
|
||||
self._total_amount_text: Optional[ft.Text] = None
|
||||
self._tax_amount_text: Optional[ft.Text] = None
|
||||
self._subtotal_text: Optional[ft.Text] = None
|
||||
|
||||
self.setup_page()
|
||||
self.setup_database()
|
||||
|
|
@ -1657,6 +1620,31 @@ class FlutterStyleDashboard:
|
|||
else:
|
||||
draft_control = ft.Container()
|
||||
|
||||
date_time_row = ft.Row(
|
||||
[
|
||||
date_button if date_button else ft.Text(
|
||||
self.editing_invoice.date.strftime("%Y/%m/%d"),
|
||||
size=12,
|
||||
color=ft.Colors.BLUE_GREY_600,
|
||||
),
|
||||
time_button if time_button else ft.Text(
|
||||
self.editing_invoice.date.strftime("%H:%M"),
|
||||
size=12,
|
||||
color=ft.Colors.BLUE_GREY_600,
|
||||
),
|
||||
],
|
||||
spacing=8,
|
||||
)
|
||||
|
||||
customer_block = ft.Column(
|
||||
[
|
||||
customer_control,
|
||||
date_time_row,
|
||||
],
|
||||
spacing=4,
|
||||
alignment=ft.MainAxisAlignment.START,
|
||||
)
|
||||
|
||||
summary_card = ft.Container(
|
||||
content=ft.Column(
|
||||
[
|
||||
|
|
@ -1690,25 +1678,11 @@ class FlutterStyleDashboard:
|
|||
),
|
||||
ft.Row(
|
||||
[
|
||||
customer_control,
|
||||
self._build_total_amount_text(),
|
||||
customer_block,
|
||||
self._build_totals_row(),
|
||||
],
|
||||
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
||||
),
|
||||
ft.Row(
|
||||
[
|
||||
date_button if date_button else ft.Text(
|
||||
self.editing_invoice.date.strftime("%Y/%m/%d"),
|
||||
size=12,
|
||||
color=ft.Colors.BLUE_GREY_600,
|
||||
),
|
||||
time_button if time_button else ft.Text(
|
||||
self.editing_invoice.date.strftime("%H:%M"),
|
||||
size=12,
|
||||
color=ft.Colors.BLUE_GREY_600,
|
||||
),
|
||||
],
|
||||
spacing=12,
|
||||
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||||
),
|
||||
summary_badges,
|
||||
],
|
||||
|
|
@ -1968,6 +1942,8 @@ class FlutterStyleDashboard:
|
|||
products=self.app_service.product.get_all_products(),
|
||||
on_product_select=self._open_product_picker_for_row,
|
||||
row_refs=self._ensure_item_row_refs(),
|
||||
enable_reorder=not is_locked,
|
||||
on_reorder=lambda old, new: self._reorder_item_row(old, new),
|
||||
)
|
||||
|
||||
def _open_product_picker_for_row(self, item_index: int):
|
||||
|
|
@ -2085,21 +2061,33 @@ class FlutterStyleDashboard:
|
|||
self._close_dialog()
|
||||
self.update_main_content()
|
||||
|
||||
def _build_total_amount_text(self) -> ft.Text:
|
||||
total = self.editing_invoice.total_amount if self.editing_invoice else 0
|
||||
def _build_totals_row(self) -> ft.Column:
|
||||
subtotal = self.editing_invoice.subtotal if self.editing_invoice else 0
|
||||
tax = self.editing_invoice.tax if self.editing_invoice else 0
|
||||
total = subtotal + tax
|
||||
|
||||
self._tax_amount_text = ft.Text(f"消費税 ¥{tax:,}", size=12, color=ft.Colors.BLUE_GREY_700)
|
||||
self._total_amount_text = ft.Text(
|
||||
f"¥{total:,} (税込)",
|
||||
size=15,
|
||||
weight=ft.FontWeight.BOLD,
|
||||
color=ft.Colors.BLUE_700,
|
||||
f"合計 ¥{total:,}", size=15, weight=ft.FontWeight.BOLD, color=ft.Colors.BLUE_700
|
||||
)
|
||||
|
||||
return ft.Column(
|
||||
[
|
||||
self._tax_amount_text,
|
||||
self._total_amount_text,
|
||||
],
|
||||
spacing=2,
|
||||
alignment=ft.MainAxisAlignment.END,
|
||||
)
|
||||
return self._total_amount_text
|
||||
|
||||
def _refresh_total_amount_display(self):
|
||||
if not self._total_amount_text:
|
||||
if not self.editing_invoice:
|
||||
return
|
||||
total = self.editing_invoice.total_amount if self.editing_invoice else 0
|
||||
self._total_amount_text.value = f"¥{total:,} (税込)"
|
||||
if self._tax_amount_text:
|
||||
self._tax_amount_text.value = f"消費税 ¥{self.editing_invoice.tax:,}"
|
||||
if self._total_amount_text:
|
||||
total = self.editing_invoice.total_amount
|
||||
self._total_amount_text.value = f"合計 ¥{total:,}"
|
||||
|
||||
def _ensure_item_row_refs(self) -> Dict[int, Dict[str, ft.Control]]:
|
||||
self._item_row_refs = {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue