feat: 完成布局优化 - 操作列固定、批量按钮自适应、分类标签带数量

优化内容:
1. 表格布局:
   - 使用 calc(100vw - 160px) 确保表格不超出视口
   - 操作列 fixed='right' 固定在右侧,宽度 300px
   - 按钮 3 个后自动换行 (max-width: 200px)
   - 恢复合理列宽,不再过度压缩

2. 批量操作区域:
   - 容器改为 inline-block,宽度自适应按钮内容
   - 背景宽度与按钮总宽度匹配

3. 分类标签:
   - 显示数量 (如 '待处理 (20)')
   - 点击切换筛选,去掉误导的 'X' 图标

4. 删除功能:
   - 操作列增加删除按钮
   - 删除前弹出确认对话框

5. 系统日志:
   - 修复后端日志路径 (parents[4])
   - 404 时显示友好提示

6. 其他:
   - 左侧菜单宽度 160px
   - 所有功能保留 (登录、用户管理、批量操作等)
This commit is contained in:
lt
2026-04-27 11:32:17 +08:00
parent 59d2a76df4
commit 277b13eaae
137 changed files with 8615 additions and 1213 deletions
+66 -34
View File
@@ -3,53 +3,85 @@ import os
from datetime import datetime
from pathlib import Path
from .database import SessionLocal, init_db
from .models import Topic
from .models import Topic, User
import bcrypt
# 计算项目根目录(backend/app/initial_data.py -> 上升3层到 yu-zhi-ran
PROJECT_ROOT = Path(__file__).resolve().parents[3]
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if os.getenv('PROJECT_ROOT'):
PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT'))
TOPICS_FILE = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json"
def import_topics_from_json():
# 从环境变量读取管理员配置
DEFAULT_ADMIN_USERNAME = os.getenv('DEFAULT_ADMIN_USERNAME', 'admin')
DEFAULT_ADMIN_PASSWORD = os.getenv('DEFAULT_ADMIN_PASSWORD', 'admin123')
def import_initial_data():
db = SessionLocal()
try:
if db.query(Topic).count() > 0:
print("数据库已有数据,跳过导入")
return
if not __import__('os').path.exists(TOPICS_FILE):
print(f"选题文件不存在: {TOPICS_FILE}")
return
topics = json.loads(open(TOPICS_FILE, encoding='utf-8').read())
for t in topics:
topic = Topic(
id=t['id'],
title=t['title'],
field=t['field'],
format=t.get('format'),
core_concept=t.get('core_concept'),
audience_pain=t.get('audience_pain'),
unique_angle=t.get('unique_angle'),
priority=t.get('priority'),
priority_score=t.get('priority_score', 0),
total_score=t.get('total_score'),
status=t.get('status', 'pending'),
cases=t.get('cases', []),
source_file=t.get('source_file'),
ready_at=datetime.strptime(t['ready_at'], '%Y-%m-%d').date() if t.get('ready_at') else None,
published_at=datetime.strptime(t['published_at'], '%Y-%m-%d').date() if t.get('published_at') else None,
compliance_score=t.get('compliance_score'),
platform_urls=t.get('platform_urls', {})
# 1. 导入选题数据
if db.query(Topic).count() == 0:
if __import__('os').path.exists(TOPICS_FILE):
topics = json.loads(open(TOPICS_FILE, encoding='utf-8').read())
# 去重:保留每个 ID 最后出现的记录
seen = {}
for t in topics:
seen[t['id']] = t
unique_topics = list(seen.values())
for t in unique_topics:
topic = Topic(
id=t['id'],
title=t['title'],
field=t['field'],
format=t.get('format'),
core_concept=t.get('core_concept'),
audience_pain=t.get('audience_pain'),
unique_angle=t.get('unique_angle'),
priority=t.get('priority'),
priority_score=t.get('priority_score', 0),
total_score=t.get('total_score'),
status=t.get('status', 'pending'),
cases=t.get('cases', []),
source_file=t.get('source_file'),
ready_at=datetime.strptime(t['ready_at'], '%Y-%m-%d').date() if t.get('ready_at') else None,
published_at=datetime.strptime(t['published_at'], '%Y-%m-%d').date() if t.get('published_at') else None,
compliance_score=t.get('compliance_score'),
platform_urls=t.get('platform_urls', {})
)
db.add(topic)
db.commit()
print(f"✅ 导入 {len(unique_topics)} 个选题到数据库(去重后)")
else:
print(f"⚠️ 选题文件不存在: {TOPICS_FILE}")
else:
print("数据库已有选题数据,跳过导入")
# 2. 创建默认管理员用户(bcrypt 哈希)
admin_exists = db.query(User).filter(User.username == DEFAULT_ADMIN_USERNAME).first()
if not admin_exists:
hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
admin = User(
username=DEFAULT_ADMIN_USERNAME,
password_hash=hashed.decode('utf-8'),
role="admin"
)
db.add(topic)
db.commit()
print(f"导入 {len(topics)} 个选题到数据库")
db.add(admin)
db.commit()
print(f"创建默认管理员: {DEFAULT_ADMIN_USERNAME}")
else:
# 如果管理员已存在但密码为空,更新为默认密码的哈希
if not admin_exists.password_hash:
hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
admin_exists.password_hash = hashed.decode('utf-8')
db.commit()
print(f"✅ 更新管理员密码")
print(f"管理员已存在: {DEFAULT_ADMIN_USERNAME}")
except Exception as e:
print(f"导入失败: {e}")
print(f"初始化失败: {e}")
db.rollback()
finally:
db.close()
if __name__ == "__main__":
init_db()
import_topics_from_json()
import_initial_data()