Skip to content

[Feat/birthboard] 生日灯牌功能正式PR - #996

Open
sparrowbot wants to merge 23 commits into
Yuanpei-Intelligence:developfrom
sparrowbot:feat/birthboard
Open

[Feat/birthboard] 生日灯牌功能正式PR#996
sparrowbot wants to merge 23 commits into
Yuanpei-Intelligence:developfrom
sparrowbot:feat/birthboard

Conversation

@sparrowbot

Copy link
Copy Markdown

feat: 新增生日板(birthboard)模块——YQPoint 付费生日祝福投放系统

本 PR 新增生日板模块,打通"发起、凑份子付款、寿星确认、审核、定时投放"全流程,并与 YQPoint 积分、企业微信通知、定时任务深度集成。

核心功能:

  1. 完整状态机:等待确认、等待寿星确认、等待审批、就绪、投放中、完成,及终止/驳回/撤销等终止态,每次变更都有审计日志(ChangeRecord)。
  2. 发起与凑份子:支持匿名发起、邀请送出人、按人扣减 YQPoint、寿星确认后进入审核。
  3. 两级审核:审核员一审、二审员二审;驳回需选择违规类型并填写原因;名单可通过 admin 配置。
  4. 定时投放:每晚 23:45 调度任务切换就绪/到期记录,并用 Playwright 自动化操作外部投放屏(shihannet)完成实机投放。
  5. 超时与退款:每日 12:00 对 D-3 未确认者提醒、D-1 未确认者自动拒绝并原子退款(悲观锁+事务),另有过期等待兜底任务。
  6. 企业微信通知:覆盖邀请、付款成功、等待提醒、审核提醒、投放开始/结束/即将结束、自动退款、撤销、退款等十余种场景。
  7. 审批定时提醒:为一审/二审分别调度提醒,审核完成后自动取消。
  8. 制作名单:组织名单配置化、弹窗视觉重构、字体去重、累计点赞、今日提醒服务端去重(跨设备)。
  9. 用户协议:投放前需签署;确认页各 tab 已读时间持久化到数据库,跨浏览器同步。

页面与路由(挂载于 /birthboard/):主页面、协议页、确认页(参与/寿星/完成三 tab)、审核页、驳回页,以及余额查询、点赞、确认计数、提醒已读等 JSON API;左侧导航栏新增入口。

基础设施改动:

  • generic.models.YQPointRecord.SourceType 新增 BIRTHBOARD=8,区分生日板消费/退款记录。
  • generic.utils.to_search_indices 返回值新增 pk 字段,供前端作为关联 id。
  • requirements.txt 新增 playwright、ddddocr。
  • config_template.json 新增 birthboard.contact_email、birthboard.contributor_orgs、shihannet(外部投放屏账号,仅占位符)。
  • 管理命令:backfill_birthboard_thumbnails、run_birthboard_waiting_checks、simulate_birthboard_nightly_update。
  • 大量前端资源与模板;birthboard 各阶段迁移已 squashed 合并,含 YQPointRecord source_type 调整及 generic 迁移分支合并。

测试:

birthboard/tests.py(718 行)覆盖发起、付款、审核、投放、退款主流程及超时、驳回、并发等边界场景。

部署与配置注意:

  1. 依赖:需安装 playwright 并执行 playwright install(Chromium);ddddocr 用于图片识别。
  2. 配置(config.json,不入库):birthboard.contact_email、contributor_orgs;shihannet 为外部投放屏真实账号(模板仅占位)。
  3. 迁移:python manage.py migrate(含 generic 迁移分支合并)。
  4. 初始化:通过 admin 录入审核员/二审员名单;历史缩略图可运行 backfill 命令。
  5. 定时任务:依赖 runscheduler 启动的调度器,三个定时任务自动注册。

生日祝福投放平台,包含投放记录、审核、确认、合约等功能,以及完整的模型、视图、定时任务、通知、管理命令与前端模板。

从 fork 的 develop 分支重建:丢弃了误操作的 merge 提交与对上游小程序 API (Yuanpei-Intelligence#966) 的 revert,并移除了误提交的测试凭证文件与调试输出文件。

Files changed:
- birthboard/: 新增生日板应用(模型、视图、定时任务、通知、迁移等)
- boot/config.py: 新增 shihannet 配置
- boot/settings.py: 注册 birthboard 应用
- boot/urls.py: 挂载 /birthboard/ 路由
- requirements.txt: 新增 playwright 与 ddddocr 依赖
- static/birthboard/: 新增字体资源
- templates/birthboard/: 新增页面模板
fix:消息函数已经改为notification_create
fix:解决一系列并发问题,加入一系列悲观锁。
feat:完善协议文件。
feat:在welcome页面加入入口。
- 新增 BirthboardLike 累计点赞模型与 like_count/like_add 接口,制作名单弹窗支持点赞并随机切换 14 种按钮图标
- 新增 BirthboardReminderSeen 模型与 reminder_seen 接口,今日提醒(happy/bless)改为服务端跨设备去重
- 制作名单弹窗视觉:hpbtd 风格背景、三列名单排版、按钮位置/描边、淡入 3s 淡出 1s 动画
- 页脚手机版缩小字号/宽度;新增 downbtn/textN/lddq、页脚提示卡片与遮罩样式
- 将 shihannet 配置从 boot/config.py 迁移到 birthboard/config.py,新增 birthboard contact_email 配置
- 协议页标题改用 h1;左侧导航加入"生日灯牌"入口
- 新增迁移 0012/0013 及对应测试(37 项全通过)

Files changed:
- birthboard/models.py: 新增 BirthboardLike、BirthboardReminderSeen 模型
- birthboard/views.py: 新增 like_count/like_add/reminder_seen 接口,提醒 seen 去重
- birthboard/urls.py: 注册三个新接口路由
- birthboard/tests.py: 新增点赞与提醒去重测试
- birthboard/jobs.py: shihannet 改为从 birthboard.config 导入
- birthboard/web_controller.py: shihannet 改为从 birthboard.config 导入
- birthboard/config.py: 新增 BirthboardConfig(contact_email) 与 shihannet 配置
- birthboard/migrations/0012_birthboardlike.py: BirthboardLike 迁移
- birthboard/migrations/0013_birthboardreminderseen.py: BirthboardReminderSeen 迁移
- boot/config.py: 移除 shihannet 配置
- config_template.json: 新增 birthboard.contact_email 占位
- static/birthboard/birthboard.css: 页脚/点赞弹窗/淡入淡出/提示卡片样式
- templates/birthboard/birthboard.html: 制作名单弹窗、点赞、提醒去重前端
- templates/birthboard/contract.html: 协议标题改用 h1
- templates/user_left_navbar.html: 左侧导航加入生日灯牌入口
- 制作名单弹窗改为相对视口固定居中,缩放不漂移、内容不换行;点赞按钮
  固定尺寸,数字/横线/间距等改由 CSS 变量控制(桌面 :root 默认、
  initPhoneLayers() 手机覆盖)。
- 制作名单的组织名称与姓名从模板硬编码迁入配置系统
  (birthboard.contributor_orgs),由视图传入模板循环渲染,便于运营维护。
- 字体去重:思源黑体等 @font-face 统一收敛到 birthboard_fonts.css 并加
  local() 本地优先;confirm/approve 页改为引用共享字体文件,避免重复下载。

Files changed:
- birthboard/config.py: 新增 contributor_orgs 配置项(制作名单组织与姓名)。
- birthboard/views.py: 各渲染分支向模板传入 contributor_orgs。
- birthboard/tests.py: 新增 ContributorOrgsConfigTests 校验配置结构。
- config_template.json: birthboard 段新增 contributor_orgs 默认名单。
- static/birthboard/birthboard.css: 移除 @font-face,新增 --bb-clist-* 变量。
- static/birthboard/birthboard_approve.css: 移除 @font-face,引用共享字体文件。
- static/birthboard/birthboard_confirm.css: 移除 @font-face,引用共享字体文件。
- static/birthboard/birthboard_fonts.css: 新增共享字体声明(本地优先)。
- templates/birthboard/birthboard.html: likeModal 视觉重构 + 名单循环渲染。
- templates/birthboard/birthboard_approve.html: 引入共享字体样式。
- templates/birthboard/birthboard_confirm.html: 引入共享字体样式。
- templates/birthboard/contract.html: 引入共享字体样式。
Rebase 到 upstream/develop 后,generic 出现两个迁移分支叶子
(本分支 0005_alter_yqpointrecord_source_type 与 upstream 的
0007_merge_pending_auth_credentials)。新增 0008 merge 迁移统一迁移图。

Files changed:
- generic/migrations/0008_merge_20260831_0208.py: 合并两个迁移分支叶子。
- birthboard_sign_contract / birthboard_like_add / 主视图 POST 补 @csrf_protect
  (项目禁用全局 CsrfViewMiddleware,所有登录态变更操作需显式 CSRF);
  like_add 前端 fetch POST 补 X-CSRFToken。
- 移除 views.py 的 from app.views_dependency import *,显式导入 login_required / render。
- BirthboardConfirmSeen.mark_seen 改用 save(update_fields=...)。
- birthboard.html 删除重复定义的 toggleAnon。
- forms.py 修正 mode=2 的投放模式文案(1000 -> 10000 元气值/1年)。
- api_yqpoint.py 装饰器顺序改为 login_required 在外层,符合规范。

Files changed:
- birthboard/views.py: 补 csrf_protect;移除通配符导入;显式导入。
- birthboard/models.py: mark_seen 使用 update_fields。
- birthboard/forms.py: 修正 10000 元气值文案。
- birthboard/api_yqpoint.py: 调整装饰器顺序。
- templates/birthboard/birthboard.html: like_add 补 X-CSRFToken;删除重复 toggleAnon。
Copilot AI lite review requested due to automatic review settings August 31, 2026 04:31

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 660f39a0f5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread birthboard/views.py
Comment thread birthboard/views.py
Comment thread birthboard/web_controller.py
Comment thread birthboard/views.py
Comment thread birthboard/views.py
Comment thread birthboard/views.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

本 PR 为 YPPF 引入新的「生日灯牌(birthboard)」子系统:以 Django 模板页 + 后台任务为核心,打通生日祝福投放的用户流程,并与元气值(YQPoint)、通知、定时任务等模块对接,同时补充配置、依赖与迁移。

Changes:

  • 新增 birthboard Django app:路由、模型、任务(scheduler jobs)、通知、管理命令与测试用例。
  • 扩展通用能力:YQPointRecord SourceType 增加 BIRTHBOARD;用户搜索索引返回值增加 pk 字段。
  • 增加前端模板与静态资源,并在左右侧导航栏加入入口;补充配置模板与依赖。

Reviewed changes

Copilot reviewed 40 out of 49 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
templates/user_left_navbar.html 用户侧导航栏增加 birthboard 入口链接
templates/org_left_navbar.html 组织侧导航栏增加 birthboard 入口链接
templates/birthboard/contract.html 新增 birthboard 用户协议页面
templates/birthboard/birthboard_approve.html 新增 birthboard 审核台页面与筛选/弹窗交互
templates/birthboard/birthboard_approve_denied.html 新增无审核权限提示页
static/birthboard/contract.css 新增协议页样式
static/birthboard/birthboard.css 新增 birthboard 主页面样式(含大量定位/弹窗样式)
static/birthboard/birthboard_fonts.css 新增 birthboard 共享字体声明样式
static/birthboard/birthboard_confirm.css 新增/调整确认页样式
static/birthboard/birthboard_approve.css 新增审核页样式
static/birthboard/birthboard_approve_denied.css 新增无权限页样式
requirements.txt 增加 birthboard 相关依赖(playwright、ddddocr)
generic/utils.py to_search_indices 返回值增加 pk 字段以支持前端关联
generic/models.py YQPointRecord.SourceType 增加 BIRTHBOARD=8
generic/migrations/0005_alter_yqpointrecord_source_type.py 迁移:更新 YQPointRecord.source_type choices
generic/migrations/0008_merge_20260831_0208.py 迁移:合并 generic 的迁移分支
config_template.json 增加 birthboard 配置段(contact_email、contributor_orgs)
boot/urls.py 注册 /birthboard/ 路由到 birthboard.urls
boot/settings.py 将 birthboard 加入应用配置列表
birthboard/utils.py 增加每人扣费计算与缩略图生成工具函数
birthboard/urls.py 新增 birthboard 页面与 JSON API 路由
birthboard/tests.py 新增较完整的单测覆盖(流程/任务/并发/提醒等)
birthboard/reminder.py 新增审核提醒定时任务的排期/撤回逻辑
birthboard/notify.py 新增站内信 + 企业微信通知封装函数
birthboard/models.py 新增 birthboard 核心模型(记录、参与者、审核员、协议、已读、点赞、提醒去重等)
birthboard/migrations/0001_initial.py birthboard 初始迁移
birthboard/migrations/0002_alter_birthboardrecord_status_squashed_0011_add_thumbnail_field.py squashed 迁移:扩展状态机/审核员/日志/协议/缩略图等
birthboard/migrations/0012_birthboardlike.py 增加点赞量模型迁移
birthboard/migrations/0013_birthboardreminderseen.py 增加提醒已读去重模型迁移
birthboard/migrations/init.py 迁移包初始化文件
birthboard/management/init.py management 包初始化
birthboard/management/commands/init.py commands 包初始化
birthboard/management/commands/backfill_birthboard_thumbnails.py 管理命令:历史记录缩略图回填
birthboard/management/commands/run_birthboard_waiting_checks.py 管理命令:手动触发等待提醒/超时处理
birthboard/management/commands/simulate_birthboard_nightly_update.py 管理命令:模拟 23:45 夜间更新任务
birthboard/jobs.py 定时任务:提醒/超时自动拒绝退款/夜间投放同步(Playwright)/过期兜底
birthboard/forms.py 新增表单:投放记录提交字段
birthboard/config.py 新增 birthboard + shihannet 配置封装
birthboard/apps.py 新增 Django AppConfig
birthboard/api_yqpoint.py 新增 YQPoint 校验 API(按 senders/record 计算是否足够)
birthboard/admin.py 新增审核员/二审员 admin 配置
birthboard/init.py app 包初始化文件
Suppressed comments (2)

birthboard/jobs.py:83

  • 同一函数中字符串分支也把年档 cost 写成了 1000;应与年档 10000 保持一致,否则 mode 以字符串形式存储时同样会被错误推断为 1 天。
        if isinstance(mode, str) and mode.isdigit():
            m = int(mode)
            cost_map = {35: 1, 60: 3, 1000: 365}
            return cost_map.get(m, 1)

static/birthboard/birthboard_fonts.css:43

  • 同文件后续两个 @font-face 也使用了 display: swap;(无效)。应统一改为 font-display: swap;,避免只有部分字体族按预期加载。

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread birthboard/api_yqpoint.py Outdated
Comment thread birthboard/api_yqpoint.py
Comment thread birthboard/api_yqpoint.py Outdated
Comment thread birthboard/jobs.py
Comment thread templates/birthboard/birthboard_approve.html Outdated
Comment thread static/birthboard/birthboard_fonts.css
Comment thread static/birthboard/contract.css Outdated
Comment thread birthboard/models.py Outdated
Comment thread config_template.json
Comment thread birthboard/models.py Outdated
sparrowbot and others added 2 commits August 31, 2026 13:32
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
修复 Codex/Copilot PR review 建议及后续自查发现的问题:

- 撤销增加发起人/寿星所有权校验(行锁内),越权返回 forbidden
- 审核/驳回全部移入锁定事务,避免并发一审/二审互相覆盖
- 外部投放屏更新失败时返回失败结果并回退夜间推进的状态
- birthboard_confirm/approve 补 CSRF 保护与 profile 门禁
- 修复年档成本 1000→10000(jobs 与审核页文案)
- check_yqpoint 改为只查本人余额,补 logger 与通用错误消息
- 扣款成功通知移入 transaction.on_commit
- 统一 datetime.now() 替代 timezone.now()
- 补 __all__、models 显式时间常量、confirm 表单 CSRF token、文案统一

Files changed:
- birthboard/views.py: 撤销所有权校验、锁事务范围、CSRF/门禁、on_commit、datetime、__all__
- birthboard/jobs.py: 年档、失败回退、datetime、__all__
- birthboard/api_yqpoint.py: 只查本人余额、logger、通用错误、CSRF
- birthboard/models.py: 默认值显式常量、docstring
- birthboard/notify.py: __all__
- birthboard/utils.py: __all__
- birthboard/forms.py: __all__
- birthboard/tests.py: 回归测试与适配
- boot/settings.py: 启用 csrf context processor
- config_template.json: 补齐 shihannet 占位配置
- static/birthboard/*.css: font-display 修正、嵌套注释修复
- templates/birthboard/*.html: CSRF token、10000 文案、需要修改、forbidden 提示
@sparrowbot

Copy link
Copy Markdown
Author

完成修改,并按学院要求修改了部分措辞

@sparrowbot

Copy link
Copy Markdown
Author

增加了手机版的审核视图

小程序内嵌 webview 完整适配:登录跳板放行同源绝对 URL、会话过期登录页兜底、
退出/返回出口在小程序内回小程序、移动版审核入口与返回按钮;图片上传区新增
配置驱动的"模版下载"链接并与错误提示同槽位互斥。

Files changed:
- utils/http/utils.py: safe_local_redirect_target 放行同源绝对 URL(P0-1)
- generic/views.py: Index.visitor_get 对 miniProgram UA 渲染登录兜底页(P0-2)
- generic/tests.py: 新增同源放行、webview 跳转与登录兜底测试
- birthboard/config.py: 新增 template_download_url 配置
- birthboard/views.py: birthboard 视图各 render 传入 template_download_url
- config_template.json: birthboard 段新增 template_download_url
- static/birthboard/birthboard_webview.js: 新增,小程序 UA 门控退出脚本
- templates/webview_expired.html: 新增,登录兜底页
- templates/birthboard/birthboard.html: 退出按钮 data-bb-exit、模版下载链接与联动、手机版审核入口
- templates/birthboard/birthboard_approve_mobile.html: 顶栏新增"返回投放板"
- templates/birthboard/contract.html: 底部"返回首页" data-bb-exit
@sparrowbot

Copy link
Copy Markdown
Author

增加了微信小程序的适配,应该是最后一次改动了

- 完善发布、付款、确认、中止、撤销、审核及退款状态校验
- 强制一审二审分离,并禁止活动关联人员参与审核
- 增加违规限制、待下架持久化及投屏失败重试机制
- 加固海报访问、余额查询、POST/CSRF 与并发锁控制
- 修复夜间同步竞态、失败回退和补偿任务
- 补全数据库迁移与 birthboard 缺省配置兼容
- 升级开发容器至 Debian 12,支持 Playwright Chromium
- 增加安全、审核、并发及投屏工作流回归测试
@Morgen-Kornblume

Copy link
Copy Markdown
Collaborator

已根据 AGENTS.md 对 PR #996 进行二次审阅和修改,重点检查了发布、付款、确认、审核、退款、违规处理及投屏同步中的权限与状态漏洞。

本次主要调整:

  • 发布时在服务端校验发起人必须属于送出者并完成付款,同时限制人数和图片大小。
  • 余额接口只返回当前用户信息;海报改为通过有权限校验的端点访问。
  • 发布前允许发起人中止并按参与记录实际费用退款;审核通过后仅允许无退款撤销。
  • 一审和二审必须由不同账号完成,且送出者、寿星等关联人员不得参与审核。
  • 驳回原因使用服务端表单校验,避免绕过前端提交任意内容。
  • 对投放中或已完成内容的违规处理不退款,并限制发起人 30 天内再次参与。
  • 投屏下架失败时持久化 display_takedown_pending,定时重试;未完成下架前阻断新上传。
  • 调整夜间同步顺序和数据库锁复查,增加 00:05 补偿任务及外部同步失败后的状态回退。
  • 修复 Playwright 重试无界、默认非 headless、N+1 查询及本地配置缺少 birthboard 段时无法启动的问题。
  • 补全 0014_harden_review_and_takedown 迁移,并升级开发容器至 Debian 12,以兼容 Playwright 1.62 Chromium。

Docker 开发容器验证结果:

  • python manage.py check:通过
  • python manage.py makemigrations --check --dry-runNo changes detected
  • python manage.py migrate:通过
  • 定向安全及工作流测试:44/44 通过
  • birthboardgeneric.tests:74/74 通过
  • 项目全量测试:507/507 通过
  • compilealltabnanny、JSON 校验及 git diff --check:通过
  • 容器内 Chromium 151.0.7922.34 headless 启动与关闭:通过

受现场条件限制,本次没有实际执行电子屏登录、素材上传、播单更新或下架。相关投屏流程通过 mock、失败回退、下架优先和定时重试测试验证,测试过程中未连接或操作真实投屏系统。

- 提交页:服务端表单错误回填到 #senders-error / #image-error 槽位;
  前端对送出者人数上限做校验;人均费用计算与后端 calculate_per_cost 对齐。
- 驳回:限制发起人由自动改为弹窗勾选(restrict,默认不勾),并注册
  BirthboardContract 到 admin,提供"解除限制参与"批量动作。
- 模板:修复确认页 tab 徽标定位与审核页移动端 onclick 嵌套引号语法。

Files changed:
- birthboard/views.py: json_context 注入 max_senders;_reject_record_by_admin
  增加 restrict 参数,仅勾选时设限。
- birthboard/forms.py: BirthboardRejectForm 增加 restrict 字段。
- birthboard/admin.py: 注册 BirthboardContract 及解除限制 action。
- birthboard/tests.py: 更新驳回限制测试并新增默认不设限回归测试。
- templates/birthboard/birthboard.html: 错误槽位渲染、前端人数上限校验、
  人均费用计算对齐后端。
- templates/birthboard/birthboard_approve.html: 驳回弹窗增加限制勾选框。
- templates/birthboard/birthboard_approve_mobile.html: 驳回弹窗勾选框 +
  onclick 嵌套引号语法修复。
- templates/birthboard/birthboard_confirm.html: 修复 tab 徽标定位。
@sparrowbot

Copy link
Copy Markdown
Author

根据修改完善了部分逻辑和视图

- 通知发件人改由 config.birthboard.sender_username/sender_name 控制,
  notify.py 统一改用 record.log logger,避免发件人缺失时静默失败;
  新增 ensure_birthboard_sender 幂等创建官方组织账号的命令。
- 一审/二审员新增 reminder_enabled 开关:关闭后仍可审核,但不再接收
  自动重复审核提醒(notify_approval_reminder 只发给开启者)。
- 投放记录接入 admin:只读流程字段 + 参与者/变更记录只读内联,可改 date;
  审核员/二审员管理页提供内联开关。
- 四个模型补充中文 verbose_name 并用序号前缀控制 admin 显示顺序。
- config_template.json:birthboard 段新增 sender_username/sender_name。

Files changed:
- birthboard/config.py: 新增 sender_username/sender_name 配置项。
- birthboard/notify.py: 发件人读取 config(_sender_user),logger 换统一 logger;审核提醒按 reminder_enabled 过滤。
- birthboard/management/commands/ensure_birthboard_sender.py: 新增幂等创建发件人命令。
- birthboard/models.py: approver/second approver 新增 reminder_enabled;四个模型加中文 verbose_name。
- birthboard/admin.py: 审核员内联开关;投放记录只读 admin 与参与者/变更记录只读内联。
- birthboard/migrations/0015_*: 新增 reminder_enabled 字段。
- birthboard/migrations/0016_*: 模型 Meta 选项(verbose_name)变更。
- birthboard/tests.py: 通知发件人与提醒开关回归测试。
- config_template.json: birthboard 段新增发件人配置(sender_username/sender_name)。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants