🎯 Mục tiêu bài dạy & Kế hoạch 60 phút
⏱️ 10' Tổng kết mục tiêu Mini-CRM phục vụ thực tế
⏱️ 25' Live Code: st.tabs(["Báo Giá", "Tiến Độ", "Thêm Khách"])
⏱️ 20' Học viên chạy thử Mini-CRM toàn diện
⏱️ 5' Nghiệm thu mốc Hoàn Thiện Tháng 3
Mục tiêu: Học viên làm chủ cấu trúc chia tab st.tabs(), tích hợp toàn bộ logic tính báo giá và luồng SQLite vào một file duy nhất mini_crm_app.py chạy mượt mà.
💡 Bẫy lỗi thường gặp & Mẹo sư phạm
- Kiểm thử trên di động qua mạng nội bộ: Hướng dẫn học viên lấy địa chỉ
Network URL: http://192.168.x.x:8501 và mở trực tiếp trên điện thoại cùng mạng Wifi để thấy ngay thành quả!
🛠️ Đồ án tốt nghiệp Giai đoạn 3 tại lớp
Yêu cầu đồ án: Hoàn thiện file mini_crm_app.py gồm 3 Tab: (1) Tính toán báo giá sàn có giảm giá và phí dọn rác, (2) Bảng tiến độ và biểu đồ cột công trình, (3) Form thêm khách hàng lưu trực tiếp vào SQLite.
# BUỔI 24: ĐỒ ÁN GIAI ĐOẠN 3 - MINI-CRM HOÀN CHỈNH CHO CÔNG TRƯỜNG
import streamlit as st
import sqlite3
import pandas as pd
st.set_page_config(page_title="Mini-CRM Công Trường", page_icon="🏗️", layout="wide")
st.title("🏗️ MINI-CRM GIÁM SÁT CÔNG TRƯỜNG")
# Điều hướng bằng 3 Tab chức năng
tab_bao_gia, tab_tien_do, tab_them_khach = st.tabs([
"💰 Báo Giá Lát Sàn",
"📊 Theo Dõi Tiến Độ",
"➕ Thêm Khách Hàng"
])
# --- TAB 1: BÁO GIÁ NHANH ---
with tab_bao_gia:
st.subheader("Công Cụ Báo Giá Nhanh")
c1, c2 = st.columns(2)
with c1:
dai = st.number_input("Chiều dài phòng (ft):", value=20.0, min_value=0.0)
rong = st.number_input("Chiều rộng phòng (ft):", value=15.0, min_value=0.0)
with c2:
gia = st.number_input("Đơn giá thi công (USD/sqft):", value=5.0, min_value=0.0)
nha_cu = st.checkbox("Nhà cũ (+10% phí dọn xà bần)")
sqft = dai * rong
giam = 0.05 if sqft >= 1000 else 0.0
tien_goc = sqft * gia
tong = (tien_goc * (1 - giam)) + ((tien_goc * 0.1) if nha_cu else 0.0)
st.metric("TỔNG DỰ TOÁN BÁO GIÁ", f"${tong:,.2f} USD", delta=f"{sqft:,.0f} sqft")
# --- TAB 2: TIẾN ĐỘ DỰ ÁN ---
with tab_tien_do:
st.subheader("Tiến Độ Thi Công Các Công Trình")
with sqlite3.connect("cong_trinh.db") as conn:
df_khach = pd.read_sql_query("SELECT * FROM KhachHang", conn)
col_chart, col_data = st.columns([1, 2])
with col_chart:
st.write("**Phân bố theo Zip Code:**")
if not df_khach.empty and "zip_code" in df_khach.columns:
st.bar_chart(df_khach["zip_code"].value_counts())
with col_data:
st.write("**Danh sách hồ sơ:**")
st.dataframe(df_khach, use_container_width=True, hide_index=True)
# --- TAB 3: THÊM KHÁCH HÀNG MỚI ---
with tab_them_khach:
st.subheader("Nhập Hồ Sơ Khách Hàng Mới")
with st.form("form_crm"):
ten = st.text_input("Tên chủ nhà:")
sdt = st.text_input("Số điện thoại:")
zip_cd = st.text_input("Zip Code:", value="77001")
if st.form_submit_button("LƯU HỒ SƠ"):
if ten.strip():
with sqlite3.connect("cong_trinh.db") as conn:
conn.execute("INSERT INTO KhachHang (ho_ten, sdt, zip_code) VALUES (?, ?, ?)", (ten, sdt, zip_cd))
conn.commit()
st.success(f"✅ Đã thêm hồ sơ khách hàng: {ten}")
else:
st.error("Vui lòng điền tên khách hàng!")
# Ứng dụng Mini-CRM sẵn sàng đứng lớp:
Chạy lệnh: streamlit run mini_crm_app.py
Đầy đủ chức năng Báo giá + Thống kê + Lưu trữ SQLite!