fix:实现数据核对页面
This commit is contained in:
@@ -2,58 +2,63 @@
|
||||
|
||||
/* 全局字体 */
|
||||
body {
|
||||
font-family: "微软雅黑", "Microsoft YaHei", sans-serif;
|
||||
background-color: #f0f4f8;
|
||||
font-family: '微软雅黑', 'Microsoft YaHei', sans-serif;
|
||||
background-color: #f0f4f8;
|
||||
}
|
||||
|
||||
/* 标题栏 */
|
||||
.app-header {
|
||||
background-color: #2E8B57; /* SeaGreen */
|
||||
color: white;
|
||||
background-color: #2e8b57; /* SeaGreen */
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 卡片通用样式 */
|
||||
.func-card {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
background-color: white;
|
||||
border-radius: 0.5rem;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
background-color: white;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* 核心功能区顶部边框 */
|
||||
.card-core {
|
||||
border-top: 4px solid #16a34a; /* green-600 */
|
||||
border-top: 4px solid #16a34a; /* green-600 */
|
||||
}
|
||||
|
||||
/* 数据管理区顶部边框 */
|
||||
.card-data {
|
||||
border-top: 4px solid #3b82f6; /* blue-500 */
|
||||
border-top: 4px solid #3b82f6; /* blue-500 */
|
||||
}
|
||||
|
||||
/* 系统操作区顶部边框 */
|
||||
.card-system {
|
||||
border-top: 4px solid #ef4444; /* red-500 */
|
||||
border-top: 4px solid #ef4444; /* red-500 */
|
||||
}
|
||||
|
||||
.card-logging {
|
||||
border-top: 4px solid #9c1be0;
|
||||
border-top: 4px solid #9c1be0;
|
||||
}
|
||||
|
||||
/* 标题文字 */
|
||||
.section-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* 绿色标题 */
|
||||
.text-green { color: #166534; }
|
||||
.text-green {
|
||||
color: #166534;
|
||||
}
|
||||
/* 蓝色标题 */
|
||||
.text-blue { color: #1e40af; }
|
||||
.text-blue {
|
||||
color: #1e40af;
|
||||
}
|
||||
/* 红色标题 */
|
||||
.text-red { color: #991b1b; }
|
||||
|
||||
.text-red {
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
/* assets/style.css */
|
||||
|
||||
@@ -68,24 +73,24 @@ body {
|
||||
* 适用于 NiceGUI 默认的 Chromium 浏览器
|
||||
*/
|
||||
.hide-scrollbar::-webkit-scrollbar {
|
||||
/* 完全隐藏滚动条 */
|
||||
width: 0px;
|
||||
background: transparent; /* 使滚动条轨道透明 */
|
||||
/* 完全隐藏滚动条 */
|
||||
width: 0px;
|
||||
background: transparent; /* 使滚动条轨道透明 */
|
||||
}
|
||||
|
||||
/* 2. 隐藏 Firefox 浏览器的滚动条 */
|
||||
.hide-scrollbar {
|
||||
/* 设置滚动条宽度为 thin (细),比 auto (默认) 要窄 */
|
||||
scrollbar-width: none; /* 'none' 是最新且更彻底的隐藏方式 */
|
||||
|
||||
/* 确保容器内容溢出时可以滚动 */
|
||||
overflow: auto;
|
||||
/* 设置滚动条宽度为 thin (细),比 auto (默认) 要窄 */
|
||||
scrollbar-width: none; /* 'none' 是最新且更彻底的隐藏方式 */
|
||||
|
||||
/* 确保容器内容溢出时可以滚动 */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* 示例:如果你只想隐藏日志区的滚动条 */
|
||||
.card-logging .q-expansion-item__content .nicegui-log .q-scrollarea__content {
|
||||
/* 如果 nicegui-log 内部使用了 q-scrollarea,可能需要针对其内容应用样式 */
|
||||
scrollbar-width: none;
|
||||
/* 如果 nicegui-log 内部使用了 q-scrollarea,可能需要针对其内容应用样式 */
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* ---------------------------------- */
|
||||
@@ -93,38 +98,85 @@ body {
|
||||
/* 如果完全隐藏不好,可以试试这个更温和的方案 */
|
||||
/* ---------------------------------- */
|
||||
.thin-scrollbar::-webkit-scrollbar {
|
||||
width: 6px; /* 调整宽度 */
|
||||
height: 6px; /* 调整高度 */
|
||||
width: 6px; /* 调整宽度 */
|
||||
height: 6px; /* 调整高度 */
|
||||
}
|
||||
|
||||
.thin-scrollbar::-webkit-scrollbar-thumb {
|
||||
background-color: #a0a0a0; /* 拇指颜色 */
|
||||
border-radius: 3px;
|
||||
border: 1px solid #f0f4f8; /* 边框颜色 */
|
||||
background-color: #a0a0a0; /* 拇指颜色 */
|
||||
border-radius: 3px;
|
||||
border: 1px solid #f0f4f8; /* 边框颜色 */
|
||||
}
|
||||
|
||||
.thin-scrollbar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.thin-scrollbar {
|
||||
scrollbar-width: thin; /* Firefox 细滚动条 */
|
||||
scrollbar-color: #a0a0a0 transparent; /* Firefox 颜色设置 */
|
||||
scrollbar-width: thin; /* Firefox 细滚动条 */
|
||||
scrollbar-color: #a0a0a0 transparent; /* Firefox 颜色设置 */
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
/* 完全隐藏滚动条 */
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
background: transparent !important;
|
||||
/* 完全隐藏滚动条 */
|
||||
width: 0px !important;
|
||||
height: 0px !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
#nicegui-content,
|
||||
#q-app {
|
||||
/* 确保容器内容可以滚动,但滚动条被隐藏 */
|
||||
overflow: auto;
|
||||
|
||||
/* Firefox 隐藏滚动条 */
|
||||
scrollbar-width: none;
|
||||
|
||||
/* IE/Edge 隐藏滚动条 */
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
/* 档案卡片容器 */
|
||||
.profile-dialog {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
/* 档案条目样式 */
|
||||
.info-item {
|
||||
background: #ffffff;
|
||||
border: 1px solid #f1f5f9;
|
||||
border-radius: 12px;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 10px;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.info-item:hover {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.08);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
/* 标签与内容的对比度 */
|
||||
.info-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
color: #94a3b8; /* 浅灰色标签 */
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
width: 100px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.info-value {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: #1e293b; /* 深色内容 */
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
/* 自定义滚动条 */
|
||||
.custom-scroll::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.custom-scroll::-webkit-scrollbar-thumb {
|
||||
background: #e2e8f0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#nicegui-content, #q-app {
|
||||
/* 确保容器内容可以滚动,但滚动条被隐藏 */
|
||||
overflow: auto;
|
||||
|
||||
/* Firefox 隐藏滚动条 */
|
||||
scrollbar-width: none;
|
||||
|
||||
/* IE/Edge 隐藏滚动条 */
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
193
ui/views/data_page.py
Normal file
193
ui/views/data_page.py
Normal file
@@ -0,0 +1,193 @@
|
||||
import pandas as pd
|
||||
from nicegui import ui
|
||||
from config.config import load_config
|
||||
import os
|
||||
|
||||
|
||||
def data_page_header():
|
||||
# 头部样式保持不变,仅补充主体所需的 CSS 变量和类
|
||||
ui.add_head_html('<link href="/assets/style.css" rel="stylesheet" />')
|
||||
ui.add_head_html(
|
||||
"""
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: #f1f5f9;
|
||||
}
|
||||
/* 主体内容区:确保高度撑满并独立滚动 */
|
||||
.content-area {
|
||||
height: calc(100vh - 64px);
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
/* 详情弹窗增强 */
|
||||
.detail-row {
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
padding: 10px 4px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.detail-row:hover { background-color: #f8fafc; }
|
||||
.field-label { font-weight: 600; color: #64748b; width: 110px; flex-shrink: 0; font-size: 0.875rem; }
|
||||
.field-value { color: #1e293b; font-size: 0.935rem; line-height: 1.5; }
|
||||
|
||||
/* 数据卡片微调 */
|
||||
.data-card {
|
||||
border: none !important;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
)
|
||||
|
||||
with ui.header().classes("app-header items-center justify-between shadow-md px-6"):
|
||||
with ui.row().classes("items-center gap-2"):
|
||||
ui.image("/assets/icon.ico").classes("w-8 h-8").props("fit=contain")
|
||||
ui.label("尚城幼儿园成长报告助手").classes("text-xl font-bold")
|
||||
|
||||
with ui.row().classes("items-center gap-4"):
|
||||
ui.label("By 寒寒 | 这里的每一份评语都充满爱意").classes(
|
||||
"text-xs opacity-90"
|
||||
)
|
||||
ui.button(icon="home", on_click=lambda: ui.navigate.to("/")).props(
|
||||
"flat round color=white"
|
||||
).tooltip("回到首页")
|
||||
|
||||
|
||||
def load_data():
|
||||
conf_data = load_config("config.toml")
|
||||
excel_path = conf_data.get("excel_file")
|
||||
|
||||
# --- 1. 详情模态框 (UI 升级:档案感排版) ---
|
||||
with (
|
||||
ui.dialog() as detail_dialog,
|
||||
ui.card().classes(
|
||||
"w-[600px] p-0 profile-dialog rounded-3xl overflow-hidden shadow-2xl"
|
||||
),
|
||||
):
|
||||
# 【头部】渐变背景与动态图标
|
||||
with ui.row().classes(
|
||||
"w-full bg-gradient-to-r from-blue-50 to-indigo-50 items-center justify-between"
|
||||
):
|
||||
with ui.column().classes("gap-0"):
|
||||
ui.label("幼儿成长档案").classes(
|
||||
"text-xl p-4 font-black text-slate-800"
|
||||
)
|
||||
ui.button(icon="close", on_click=detail_dialog.close).props(
|
||||
"flat round color=primary"
|
||||
).classes("bg-white/50")
|
||||
|
||||
# 【中部】卡片流内容区
|
||||
with ui.column().classes("w-full p-6 h-[450px] overflow-auto gap-0"):
|
||||
content_container = ui.column().classes("w-full")
|
||||
|
||||
# 【底部】毛玻璃效果操作栏
|
||||
with ui.row().classes(
|
||||
"w-full p-5 bg-slate-50/80 backdrop-blur-md border-t justify-end gap-3"
|
||||
):
|
||||
ui.button("确认", on_click=detail_dialog.close).props(
|
||||
"unelevated color=blue-6"
|
||||
).classes("px-10 rounded-xl shadow-lg shadow-blue-200 font-bold")
|
||||
|
||||
def handle_cell_click(e):
|
||||
row_data = e.args["data"]
|
||||
content_container.clear()
|
||||
|
||||
# 尝试提取名字用于头部(假设你的列名里有“姓名”)
|
||||
student_name = row_data.get("姓名", "详细数据")
|
||||
|
||||
with content_container:
|
||||
# 顶部增加一个个人摘要卡片
|
||||
with ui.row().classes(
|
||||
"w-full items-center gap-4 p-4 bg-blue-600 rounded-2xl shadow-md shadow-blue-100"
|
||||
):
|
||||
ui.avatar("person", color="white", text_color="blue-6").props(
|
||||
"size=48px"
|
||||
)
|
||||
with ui.column().classes("gap-0 text-white"):
|
||||
ui.label(student_name).classes("text-lg font-bold")
|
||||
|
||||
# 遍历渲染每一条数据
|
||||
for key, value in row_data.items():
|
||||
if key == "姓名":
|
||||
continue # 名字已经显示在摘要里了
|
||||
with ui.element("div").classes("info-item"):
|
||||
ui.label(key).classes("info-label font-bold text-blue-800")
|
||||
ui.label(str(value)).classes("info-value flex-1")
|
||||
|
||||
detail_dialog.open()
|
||||
|
||||
# --- 2. 数据读取与展示 ---
|
||||
if not excel_path or not os.path.exists(excel_path):
|
||||
with ui.column().classes("w-full items-center p-12 text-slate-400"):
|
||||
ui.icon("folder_off", size="64px")
|
||||
ui.label("数据文件未找到,请检查配置路径").classes("mt-4")
|
||||
return
|
||||
|
||||
try:
|
||||
df = pd.read_excel(excel_path)
|
||||
for col in df.select_dtypes(include=["datetime"]):
|
||||
df[col] = df[col].dt.strftime("%Y-%m-%d")
|
||||
df = df.fillna("-")
|
||||
|
||||
# 表格上方信息条
|
||||
with ui.row().classes(
|
||||
"bg-blue-50 w-full p-3 px-6 items-center rounded-t-xl border-b border-blue-100"
|
||||
):
|
||||
ui.icon("fact_check", color="primary", size="20px")
|
||||
ui.label(f"班级:{conf_data.get('class_name', '未设定')}").classes(
|
||||
"text-sm font-bold text-blue-800"
|
||||
)
|
||||
ui.separator().props("vertical").classes("mx-2")
|
||||
ui.label(f"共加载 {len(df)} 条幼儿记录").classes("text-xs text-slate-500")
|
||||
ui.space()
|
||||
ui.label("💡 提示:点击行可展开完整评语详情").classes(
|
||||
"text-xs text-amber-600 bg-amber-50 px-2 py-1 rounded"
|
||||
)
|
||||
|
||||
# AgGrid (优化表格高度与交互)
|
||||
ui.aggrid(
|
||||
{
|
||||
"columnDefs": [
|
||||
{
|
||||
"headerName": col,
|
||||
"field": col,
|
||||
"sortable": True,
|
||||
"filter": True,
|
||||
"cellClass": "text-slate-600",
|
||||
"suppressMovable": True,
|
||||
}
|
||||
for col in df.columns
|
||||
],
|
||||
"rowData": df.to_dict("records"),
|
||||
"pagination": True,
|
||||
"paginationPageSize": 20,
|
||||
"theme": "balham",
|
||||
}
|
||||
).classes("w-full flex-grow h-[550px] border-none").on(
|
||||
"cellClicked", handle_cell_click
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
ui.notify(f"加载数据时发生错误: {e}", type="negative", position="top")
|
||||
|
||||
|
||||
def create_data_page():
|
||||
data_page_header()
|
||||
with ui.card().classes("w-full m-auto max-w-6xl gap-6"):
|
||||
# 主标题区域
|
||||
with ui.row().classes("items-end justify-between w-full px-2"):
|
||||
with ui.column().classes("gap-1"):
|
||||
ui.label("数据预览与核对").classes(
|
||||
"text-3xl font-bold text-slate-800 tracking-tight"
|
||||
)
|
||||
ui.button(
|
||||
"刷新表格", icon="sync", on_click=lambda: ui.navigate.to("/data")
|
||||
).props("outline color=primary").classes("rounded-lg bg-white shadow-sm")
|
||||
|
||||
# 数据卡片容器
|
||||
with ui.card().classes("w-full p-0 data-card rounded-xl overflow-hidden"):
|
||||
load_data()
|
||||
@@ -1,7 +1,7 @@
|
||||
from nicegui import ui
|
||||
from config.config import load_config
|
||||
from ui.core.state import app_state
|
||||
from ui.core.task_runner import run_task, select_folder
|
||||
from ui.core.task_runner import run_task
|
||||
|
||||
# 导入业务函数
|
||||
from utils.generate_utils import (
|
||||
@@ -12,7 +12,7 @@ from utils.generate_utils import (
|
||||
generate_zodiac,
|
||||
generate_signature,
|
||||
)
|
||||
from utils.file_utils import initialize_project, open_folder
|
||||
from utils.file_utils import open_folder
|
||||
|
||||
config = load_config("config.toml")
|
||||
|
||||
@@ -65,6 +65,7 @@ def create_home_page():
|
||||
ui.button(text, on_click=lambda: run_task(func)).props(
|
||||
f"outline"
|
||||
).classes("w-full")
|
||||
|
||||
# 特殊处理带参数的
|
||||
async def run_convert():
|
||||
await run_task(batch_convert_folder, config.get("output_folder"))
|
||||
@@ -72,7 +73,7 @@ def create_home_page():
|
||||
func_btn("📁 生成图片路径", generate_template)
|
||||
func_btn("🤖 生成评语 (AI)", generate_comment_all)
|
||||
func_btn("📊 生成报告 (PPT)", generate_report)
|
||||
func_btn("📑 格式转换 (PDF)", run_convert).props("outline")
|
||||
func_btn("📑 格式转换 (PDF)", run_convert)
|
||||
func_btn("🐂 生肖转化 (生日)", generate_zodiac)
|
||||
func_btn("💴 园长一键签名", generate_signature)
|
||||
|
||||
@@ -95,13 +96,17 @@ def create_home_page():
|
||||
"📤 打开数据文件夹",
|
||||
on_click=lambda: open_folder(config.get("data_folder")),
|
||||
).props(f"outline")
|
||||
ui.button(
|
||||
"🔍 查看数据",
|
||||
on_click=lambda: ui.navigate.to("/data"),
|
||||
).props(f"outline")
|
||||
ui.button("⛔ 停止", on_click=stop_now).props("color=negative").classes(
|
||||
"flex-1"
|
||||
)
|
||||
|
||||
# === 日志区 ===
|
||||
with ui.card().classes("func-card card-logging"):
|
||||
with ui.expansion("📝 系统实时日志", value=True).classes(
|
||||
with ui.expansion("📝 系统实时日志", value=False).classes(
|
||||
"w-full bg-white shadow-sm rounded"
|
||||
):
|
||||
app_state.log_element = ui.log(max_lines=200).classes(
|
||||
|
||||
Reference in New Issue
Block a user