Files
renjianbo f2e65a8fbb feat: virtual company module, team projects, PWA dishes app, and startup scripts overhaul
- Add company module (3-tier org, CEO planning, parallel departments)
- Add company orchestrator, knowledge extractor, presets, scheduler
- Add company API endpoints, models, and frontend views
- Add 今天吃啥 PWA app (69 dishes, real images, offline support)
- Add team_projects output directory structure
- Add unified manage.ps1 for service lifecycle
- Add Windows startup guide v1.0
- Add TTS troubleshooting doc
- Update frontend (AgentChat UX overhaul, new views)
- Update backend (voice engine fix, multi-tenant, RBAC)
- Remove deprecated startup scripts and old docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-10 22:37:56 +08:00

218 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
家庭阅读激励工具 - 种子数据脚本
================================
提供演示/测试用种子数据,覆盖所有6张业务表。
数据设计符合典型家庭场景:2个孩子、5本书、打卡记录、积分流水、
3个奖品、兑换记录。
使用方式:
# 直接运行
python 06-seed_data.py
# 或在代码中调用
from seed_data import seed_all
seed_all()
"""
import sqlite3
import os
import sys
import logging
from datetime import date, timedelta
from typing import Optional
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
# 确保可以导入项目模块
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from db_config import init_db, get_db, transaction
# ============================================================
# 种子数据定义
# ============================================================
def seed_all(db_path: str = None) -> None:
"""
执行全部种子数据写入(幂等:使用INSERT OR IGNORE跳过重复数据)。
包含:2个孩子、5本书、若干打卡记录、积分流水、3个奖品、兑换记录。
"""
if db_path:
os.environ["READING_APP_DB_PATH"] = db_path
# 先确保Schema已初始化
init_db()
db = get_db()
try:
with transaction(db) as conn:
_seed_children(conn)
_seed_books(conn)
# 以上必须先于打卡记录(外键依赖)
_seed_reading_records(conn)
_seed_rewards(conn)
_seed_redemptions(conn)
_seed_app_settings(conn)
logger.info("✅ 种子数据写入完成")
except Exception as e:
logger.error("❌ 种子数据写入失败: %s", e)
raise
finally:
db.close()
def _seed_children(conn: sqlite3.Connection) -> None:
"""写入2个孩子"""
children = [
("小明", None, 8, 85, 1),
("小红", None, 6, 60, 1),
]
for name, avatar, age, points, active in children:
conn.execute(
"INSERT OR IGNORE INTO children (name, avatar_path, age, total_points, is_active) VALUES (?, ?, ?, ?, ?)",
(name, avatar, age, points, active),
)
logger.info(" 孩子: 2条")
def _seed_books(conn: sqlite3.Connection) -> None:
"""写入5本书"""
books = [
("小王子", "安托万·德·圣-埃克苏佩里", None, None, 120),
("夏洛的网", "E·B·怀特", None, None, 184),
("西游记(少儿版)", "吴承恩", None, None, 96),
("猜猜我有多爱你", "山姆·麦克布雷尼", None, None, 32),
("了不起的狐狸爸爸", "罗尔德·达尔", None, None, 96),
]
for title, author, cover, thumb, pages in books:
conn.execute(
"INSERT OR IGNORE INTO books (title, author, cover_image_path, thumbnail_path, page_count) VALUES (?, ?, ?, ?, ?)",
(title, author, cover, thumb, pages),
)
logger.info(" 书籍: 5条")
def _seed_reading_records(conn: sqlite3.Connection) -> None:
"""写入最近7天的打卡记录"""
today = date.today()
children_ids = [1, 2] # 小明、小红
book_ids = [1, 2, 3, 4, 5]
records = []
# 小明:最近7天,每天1-2本书
for days_ago in range(7):
d = (today - timedelta(days=days_ago)).isoformat()
for book_id in book_ids[:2 + (days_ago % 2)]: # 交替1-2本
records.append((children_ids[0], book_id, d, 20 + (days_ago % 3) * 5, 5 + days_ago * 2, "小明阅读笔记"))
# 小红:最近5天,每天1本书
for days_ago in range(5):
d = (today - timedelta(days=days_ago)).isoformat()
records.append((children_ids[1], book_ids[2 + (days_ago % 3)], d, 15 + days_ago * 2, 3 + days_ago, "小红阅读笔记"))
for child_id, book_id, read_date, duration, pages, notes in records:
try:
conn.execute(
"INSERT INTO reading_records (child_id, book_id, read_date, duration_minutes, pages_read, notes) VALUES (?, ?, ?, ?, ?, ?)",
(child_id, book_id, read_date, duration, pages, notes),
)
except sqlite3.IntegrityError:
pass # 已存在则跳过(UNIQUE约束)
logger.info(" 打卡记录: %d条", len(records))
# 更新孩子积分(每次打卡+10分,与ReadingRecordDAO一致)
for child_id in children_ids:
count = conn.execute(
"SELECT COUNT(*) as cnt FROM reading_records WHERE child_id=?", (child_id,)
).fetchone()["cnt"]
conn.execute(
"UPDATE children SET total_points = total_points + ?, updated_at = datetime('now','localtime') WHERE id=?",
(count * 10, child_id),
)
# 写入积分流水
for child_id, book_id, read_date, duration, pages, notes in records:
record_row = conn.execute(
"SELECT id FROM reading_records WHERE child_id=? AND book_id=? AND read_date=?",
(child_id, book_id, read_date),
).fetchone()
if record_row:
bal = conn.execute(
"SELECT total_points FROM children WHERE id=?", (child_id,)
).fetchone()["total_points"]
conn.execute(
"INSERT OR IGNORE INTO points (child_id, points_change, reason, reference_type, reference_id, balance_after) VALUES (?, 10, 'reading', 'reading_record', ?, ?)",
(child_id, record_row["id"], bal),
)
logger.info(" 积分流水: %d条", len(records))
def _seed_rewards(conn: sqlite3.Connection) -> None:
"""写入3个奖品"""
rewards = [
("多看30分钟动画片", "兑换后可多看30分钟动画片", None, 30, -1, 1),
("周末去游乐园", "本周六/日任选一天去游乐园", None, 80, -1, 1),
("新绘本一本", "可挑选一本新的绘本", None, 50, 10, 1),
]
for name, desc, img, points, stock, active in rewards:
conn.execute(
"INSERT OR IGNORE INTO rewards (name, description, image_path, points_required, stock, is_active) VALUES (?, ?, ?, ?, ?, ?)",
(name, desc, img, points, stock, active),
)
logger.info(" 奖品: 3条")
def _seed_redemptions(conn: sqlite3.Connection) -> None:
"""写入2条兑换记录(演示数据)"""
redemptions = [
(1, 1, 30, "fulfilled"), # 小明兑换了"多看30分钟动画片"
(2, 2, 80, "fulfilled"), # 小红兑换了"周末去游乐园"
]
for child_id, reward_id, points, status in redemptions:
conn.execute(
"INSERT OR IGNORE INTO redemption_records (child_id, reward_id, points_spent, status) VALUES (?, ?, ?, ?)",
(child_id, reward_id, points, status),
)
# 对应的积分扣减流水
bal = conn.execute(
"SELECT total_points FROM children WHERE id=?", (child_id,)
).fetchone()["total_points"]
conn.execute(
"INSERT OR IGNORE INTO points (child_id, points_change, reason, reference_type, reference_id, balance_after) VALUES (?, ?, 'redemption', 'redemption_record', ?, ?)",
(child_id, -points, child_id, bal),
)
logger.info(" 兑换记录: 2条")
def _seed_app_settings(conn: sqlite3.Connection) -> None:
"""写入默认应用配置"""
settings = {
"points_per_reading": "10",
"app_name": "家庭阅读激励工具",
"max_children": "5",
}
for key, value in settings.items():
conn.execute(
"INSERT OR IGNORE INTO app_settings (key, value) VALUES (?, ?)",
(key, value),
)
logger.info(" 应用配置: %d条", len(settings))
# ============================================================
# CLI入口
# ============================================================
if __name__ == "__main__":
print("=" * 50)
print("家庭阅读激励工具 - 种子数据写入")
print("=" * 50)
seed_all()
print("\n种子数据写入完成!")
print(" - 2个孩子: 小明(8岁), 小红(6岁)")
print(" - 5本书: 小王子, 夏洛的网, 西游记, 猜猜我有多爱你, 了不起的狐狸爸爸")
print(" - 最近7天打卡记录 + 积分流水")
print(" - 3个奖品: 动画片30分钟, 游乐园, 新绘本")
print(" - 2条兑换记录")