refactor: restructure api module and implement articles pagination with dynamic routing

This commit is contained in:
Flook
2026-05-06 05:58:38 +07:00
parent b4725b184b
commit 2d9cbb3376
12 changed files with 195 additions and 12 deletions
View File
View File
+38
View File
@@ -0,0 +1,38 @@
import requests
API_BASE_URL = 'http://localhost:8000/api'
def list_articles(page=1, search=None, token=None):
params = {'page' : page}
if search:
params['search'] = search
headers = {}
if token:
headers['Authorization'] = f"Bearer {token}"
r = requests.get(
f"{API_BASE_URL}/articles",
params=params,
headers=headers,
timeout=10
)
r.raise_for_status()
return r.json()
def get_article(article_id, token=None):
headers={}
if token:
headers['Authorization'] = f"Bearer {token}"
r = requests.get(
f"{API_BASE_URL}/articles/{article_id}",
headers = headers,
timeout = 10
)
r.raise_for_status()
return r.json()
View File
+35
View File
@@ -0,0 +1,35 @@
import asyncio
import flet as ft
from app.api.articles import get_article
from app.state import state
def article_detail_page(page: ft.Page, article_id: int):
content = ft.Column(expand=True)
async def load_article():
content.controls.clear()
content.controls.append(ft.ProgressRing())
page.update()
article = await asyncio.to_thread(
get_article,
article_id,
state.access_token
)
content.controls.clear()
content.controls.extend([
ft.Text(article['title'], size=16, weight=ft.FontWeight.BOLD),
ft.Text(article['body']),
ft.FilledButton(
'ย้อนกลับ',
on_click=lambda e: asyncio.create_task(page.push_route('/articles'))
)
])
page.update()
asyncio.create_task(load_article())
return content
+105 -5
View File
@@ -1,7 +1,107 @@
import asyncio
import flet as ft
def articles_page():
return ft.Column([
ft.Text("บทความ", size=22),
ft.Text("รายการบทความจะมาอยู่ตรงนี้"),
])
from app.api.articles import list_articles
from app.state import state
def article_card(page, article):
async def go_detail(e):
await page.push_route(f"/articles/{article['id']}")
return ft.Card(
content=ft.Container(
padding=15,
content=ft.Column(
controls=[
ft.Text(article['title'], size=18, weight=ft.FontWeight.BOLD),
ft.Text(article.get('body', ''), max_lines=2),
ft.TextButton(
'อ่านต่อ',
on_click=go_detail,
)
]
)
)
)
def articles_page(page: ft.Page):
articles_column = ft.Column(expand=True, spacing=10)
search_field = ft.TextField(
hint_text="ค้นหาบทความ",
prefix_icon=ft.Icons.SEARCH,
)
current_page = {'value':1}
page_text = ft.Text(value=f"หน้า {current_page['value']}")
# สร้างปุ่ม
btn_prev = ft.OutlinedButton('ก่อนหน้า', disabled=True)
btn_next = ft.OutlinedButton('ถัดไป', disabled=True)
async def load_articles():
articles_column.controls.clear()
articles_column.controls.append(ft.ProgressRing())
btn_prev.disabled = True
btn_next.disabled = True
page.update()
try:
data = await asyncio.to_thread(
list_articles,
page=current_page['value'],
search=search_field.value,
token=state.access_token,
)
# อัปเดตสถานะปุ่มจากข้อมูล Backend
btn_prev.disabled = data.get('previous') is None
btn_next.disabled = data.get('next') is None
page_text.value = f"หน้า {current_page['value']}"
articles_column.controls.clear()
for item in data.get('results', []):
articles_column.controls.append(article_card(page, item))
if not data.get('results'):
articles_column.controls.append(ft.Text("ไม่พบบทความ"))
except Exception as e:
articles_column.controls.clear()
articles_column.controls.append(ft.Text(f"เกิดข้อผิดพลาด: {e}", color=ft.Colors.RED))
btn_prev.disabled = current_page['value'] <= 1
btn_next.disabled = True
page.update()
# Logic การเปลี่ยนหน้า
async def change_page(delta):
current_page['value'] += delta
await load_articles()
btn_prev.on_click = lambda e: asyncio.create_task(change_page(-1))
btn_next.on_click = lambda e: asyncio.create_task(change_page(1))
def on_search(e):
current_page['value'] = 1
asyncio.create_task(load_articles())
search_field.on_submit = on_search
controls = ft.Column(
controls=[
ft.Text('บทความ', size=24),
ft.Row([search_field]),
articles_column,
ft.Row(
controls=[btn_prev, page_text, btn_next],
alignment=ft.MainAxisAlignment.CENTER
)
],
expand=True,
)
asyncio.create_task(load_articles())
return controls
+1 -1
View File
@@ -1,6 +1,6 @@
import flet as ft
def courses_page():
def courses_page(page: ft.Page):
return ft.Column([
ft.Text("หลักสูตร", size=22),
ft.Text("รายการหลักสูตร")
+1 -1
View File
@@ -1,7 +1,7 @@
import flet as ft
import asyncio
from app.api import login, get_me
from app.api.auth import login, get_me
from app.state import state
def login_page(page: ft.Page, on_login_success):
+1 -1
View File
@@ -1,6 +1,6 @@
import flet as ft
def my_courses_page():
def my_courses_page(page: ft.Page):
return ft.Column([
ft.Text('หลักสูตรของฉัน', size=22),
ft.Text('ข้อมูลหลักสูตรที่ลงทะเบียน')
+1 -1
View File
@@ -1,6 +1,6 @@
import flet as ft
def profile_page():
def profile_page(page: ft.Page):
return ft.Column([
ft.Text("ข้อมูลผู้ใช้งาน", size=22),
ft.Text("รายละเอียดข้อมูลผู้ใช้งานจะมาอยู่ตรงนี้"),
+1 -1
View File
@@ -1,6 +1,6 @@
import flet as ft
def progress_page():
def progress_page(page: ft.Page):
return ft.Column([
ft.Text('ความก้าวหน้าของฉัน', size=22),
ft.Text('รายละเอียดความก้าวหน้าของฉัน')