本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:WWW/docs/星座运势插件开发方案_2026-10-18.md。
星座运势插件(horoscope)开发方案
日期:2026-10-18
状态:待拍板(4 个决策点见 §12,拍板后再动手)
依据:
docs/插件开发规范.mdv1.6(下称「规范」)、plugins/daily_checkin(每日一次型)、plugins/points_mall(A 派前台骨架)、plugins/quiz_duel(娱乐类)图标与 API 已实测,见 §10.1、§10.2
一、定位与边界
一句话:给登录用户一个「每天来看一眼」的理由——今日运势、未来 7 天、星座配对,全部本地算法生成,零外部依赖。
它不是什么:
- 不做真八字排盘(要农历/节气/干支历,工作量是本方案的 5 倍,且社区场景用不上)
- 不接外部运势 API(可用性、限流、隐私、付费都是坑,见 §3.2)
- 不做付费解锁(社区站没这个付费意愿,反而劝退打开)
和现有插件的关系(避免功能重叠):
| 已有插件 | 重叠点 | 本插件的差异 |
|---|---|---|
daily_checkin 每日签到 | 都是「每天来一次」 | 签到是得积分的确定收益;运势是看内容的软性留存。二者可互相导流,不冲突 |
dice 掷骰子 | 都是随机娱乐 | dice 是「玩一把就走」,无个人化;运势按用户+日期定种子,每人每天不一样 |
xiuxian 修仙 | 都是娱乐玩法 | 修仙是长线养成;运势是轻量日更 |
二、产品形态
2.1 三个页面 + 两个注入点
| 类型 | 路径 | 说明 |
|---|---|---|
| 主页面 | GET /horoscope | 今日运势(核心页) |
| 配对页 | GET /horoscope/pair | 星座配对(P1) |
| JSON 接口 | GET /horoscope/today?sign=aries | 切换星座时无刷新取数据 |
| 保存档案 | POST /horoscope/profile | 保存星座 / 生日(写操作) |
| 后台 | GET /admin/horoscope | 设置 + 统计(两 Tab) |
注入点:
| 钩子 | 位置 | 内容 |
|---|---|---|
nav_plugin_links | PC 左栏「应用」+ 顶栏「应用」下拉 | 「星座运势」入口(双触发,规范 §9.3) |
nav_user_menu_items | 用户下拉(PC + 移动) | 「我的星座」(双触发,按 placement 分渲染) |
right_sidebar_after | 右栏用户面板之后 | 今日运势小卡:星座 + 分数 + 一句话 + 「查看完整」 |
右栏卡只在登录后显示(与
daily_checkin一致:游客没有用户面板,卡片上下文不成立)。
2.2 主页面结构(对齐 A 派骨架)
规范 §6.4-2 要求前台插件页统一 .mn-section。本插件跟 points_mall / community_bank 同款:
┌ .mn-section .hs-wrap ──────────────────────────────┐
│ 🌙 星座运势 [切换星座 ▾] │ ← h1.mn-fs-20.mn-fw-600 + icon('moon',18)
│ 白羊座 · 3.21–4.19 · 10 月 18 日 周六 │ ← .hs-intro(13px / line-height 1.7)
│ │
│ ┌ 今日综合 ────────────────────────────────────┐ │
│ │ 88 分 ★★★★☆ │ │
│ │ 今天适合把拖了很久的事收个尾… │ │
│ └──────────────────────────────────────────────┘ │
│ ❤ 爱情 82 💼 事业 90 🪙 财运 74 🌱 健康 86 │ ← 5 维度(综合单独强调)
│ 🎨 幸运色 [■ 天空蓝] 🎯 幸运数字 7 ⭐ 贵人 天秤 │
│ 宜:整理房间 · 主动联系 忌:熬夜 · 冲动消费 │
└─────────────────────────────────────────────────────┘
┌ 🌙 未来 7 天 ───────────────────────────────────────┐
│ 7 根竖条(综合分),今天高亮 │
└─────────────────────────────────────────────────────┘
┌ ❤ 星座配对 ─────────────────────────────────────────┐
│ 白羊 × [下拉选择] → 82 分 · 火 + 风,互相点燃 │
└─────────────────────────────────────────────────────┘未设置星座时:主卡位置换成「选择你的星座」12 格选择器(点一下即保存),不做空页面。
三、核心设计:确定性运势引擎
这是整个插件的技术核心,也是它「不像随机数生成器」的关键。
3.1 为什么必须确定性
用户刷新页面结果变了 = 这东西是假的 = 明天不来了。所以:
同一用户 + 同一星座 + 同一天 → 结果永远一致;跨天自动变化。
实现:
// plugins/horoscope/Plugin.php
private static function seed(int $userId, string $sign, string $date): string
{
// 用 hash_hmac 而不是 mt_srand():不污染同请求内其他随机逻辑,
// 且跨进程/跨机器完全可复现(mt_* 是全局状态,PHP 版本间算法也变过)
return hash_hmac('sha256', $date . '|' . $userId . '|' . $sign, self::salt());
}为什么不用 mt_srand() + mt_rand():
mt_srand()是全局状态,会污染同请求内其他插件的随机逻辑(dice、quiz_duel、red_packet都在用随机)hash_hmac纯函数,给定输入必得同一输出,可以用夹具断言(这是能写测试的前提)
3.2 为什么不用外部 API
| 方案 | 问题 |
|---|---|
| 免费星座 API | 大多需 Key + 限流;中文内容质量差;服务挂了整页白 |
| 抓取星座屋等站点 | 侵权 + 反爬 + 页面结构一变就崩 |
| 付费 API | 站长成本,社区站无 ROI |
本地算法的额外好处:不产生任何出站请求 → 不需要 net:fetch 权限,也不受生产机 disable_functions 影响(规范 §1 红线)。
3.3 派生规则
从 64 位 hex 种子按固定偏移切片,每段独立派生一个值:
| 字段 | 派生方式 | 取值范围 |
|---|---|---|
| 综合分 | 55 + n % 45 | 55–99 |
| 爱情 / 事业 / 财运 / 健康 | 同上,各自独立偏移 | 55–99 |
| 幸运色 | 12 色池取模 | 12 选 1 |
| 幸运数字 | 1 + n % 9 | 1–9 |
| 贵人星座 | 12 星座中排除自己后取模 | 11 选 1 |
| 宜 / 忌 | 各 20 条池取模,取 1 条 | 20 选 1 |
分档:≥85 → high / ≥70 → mid / <70 → low,对应三套文案池。
盐:激活时随机生成 32 字节写入 settings(键 horoscope_seed_salt),只在不存在时写。
⚠️ 盐一旦丢失,全站用户运势全部重排。所以
activate()必须写成「读不到才写」,且uninstall()才删。
3.4 换日边界
MVP 用服务器时区 date('Y-m-d'),凌晨 0 点换日。
P2 可加「换日时间」配置(如 04:00 换日,照顾熬夜党),但要同步改
todayDate()单点函数,不能散落多处。
四、内容体系
4.1 维度与文案量
主流星座站(星座屋 / 今日运势等)的通行结构:综合 / 爱情 / 事业学业 / 财富 / 健康 + 指数 + 幸运色 / 幸运数字 / 贵人星座 / 宜忌。本方案取这套,减掉「商谈指数」「穿衣推荐」这类冷门项。
| 内容 | 条数(每语) | 说明 |
|---|---|---|
| 5 维度 × 3 档 × 5 条 | 75 | 核心文案池 |
| 12 星座名 + 日期区间 + 元素 | 12 | 白羊座 / 3.21–4.19 / 火 |
| 12 星座性格一句话 | 12 | 用于「选择星座」引导与配对页 |
| 12 幸运色(名 + hex) | 12 | hex 走内联 CSS 变量(规范 §7.3-4 合规) |
| 宜 / 忌 池 | 40 | 各 20 条 |
| 元素配对文案(10 组合 × 3 档) | 30 | 见 §4.2 |
| UI 文案(按钮/提示/后台表单) | ~70 | — |
| 合计 | ≈ 251 键/语 | 三语共 ≈ 753 条 |
工作量集中在文案,不在代码。建议 P0 每档先写 3 条(45 条),P1 补满到 5 条——键名不变,只加条目,不返工。
4.2 配对模型(不用 78 组硬编)
12×12 配对的朴素做法是写 78 组文案,不可维护。用四元素模型(占星学标准做法,有据可依):
| 元素 | 星座 |
|---|---|
| 火 | 白羊 / 狮子 / 射手 |
| 土 | 金牛 / 处女 / 摩羯 |
| 风 | 双子 / 天秤 / 水瓶 |
| 水 | 巨蟹 / 天蝎 / 双鱼 |
| 元素关系 | 分数区间 | 语义 |
|---|---|---|
| 同元素 | 85–98 | 天然同频 |
| 火+风 / 土+水 | 75–92 | 互相助燃 / 互相滋养 |
| 火+土 / 风+水 | 55–70 | 节奏不同,需磨合 |
| 火+水 / 土+风 | 40–60 | 差异最大,靠沟通 |
4×4 对称 → 10 种无序组合 × 3 档 = 30 条文案覆盖全部 78 组配对。具体分数由两星座索引做种子,落在区间内。
五、数据表
-- 用户星座档案
CREATE TABLE IF NOT EXISTS hs_profiles (
user_id INTEGER PRIMARY KEY,
sign TEXT NOT NULL, -- aries / taurus / ...
birthday_md TEXT NOT NULL DEFAULT '', -- 'MM-DD',只存月日,不存年份
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- 查看日志(仅登录用户,供后台统计)
CREATE TABLE IF NOT EXISTS hs_logs (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
sign TEXT NOT NULL,
log_date TEXT NOT NULL, -- Y-m-d
action TEXT NOT NULL, -- 'view' | 'pair'
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_hs_logs_date ON hs_logs (log_date);设计取舍:
- 不存每日运势结果。种子是
(日期, 用户, 星座)的纯函数 → 历史任意一天都能重算,存了反而是冗余 + 可能不一致。 - 不存生日年份。只需要月日推星座,存年份是没必要的隐私负担。
- 游客不写 log(
user_id无 0 值),避免被刷表;游客浏览量走核心访问统计。 - 表名前缀
hs_(horoscope),避免与其他插件撞名。
六、文件清单
plugins/horoscope/
├── plugin.json
├── Plugin.php # 常量/星座表/DDL/种子引擎/档案读写/统计
├── FrontController.php # index / pair / today(JSON) / saveProfile
├── AdminController.php # index(设置+统计) / save
├── hook/
│ ├── init_after.php # 惰性建表兜底
│ ├── route_register.php
│ ├── admin_route_register.php
│ ├── nav_plugin_links.php
│ ├── nav_user_menu_items.php
│ └── right_sidebar_after.php
├── views/
│ ├── index.php # 今日运势
│ ├── pair.php # 星座配对(P1)
│ ├── admin.php # 后台两 Tab
│ └── _sidebar.php # 右栏小卡
├── assets/
│ ├── style.css
│ └── script.js
├── lang/{zh,zh_tw,en}.php
└── data/ # 自动生成(含 .htaccess / web.config)plugin.json 草案:
{
"name": "星座运势",
"version": "1.0.0",
"min_core": "1.1.26",
"author": "FlintHub",
"description": "星座运势:按用户与日期确定性生成今日运势(综合/爱情/事业/财运/健康)、幸运色与宜忌,支持星座配对与 7 天趋势",
"activated": true,
"category": "entertainment",
"icon": "moon",
"admin_url": "/admin/horoscope",
"hooks": { ... },
"permissions": ["route:admin", "system:settings"]
}category: entertainment—— 与dice/quiz_duel/xiuxian同分类(10 类之一,规范 §3)min_core: 1.1.26—— 与当前核心同版本,避免老站装上后缺能力静默失效- 权限两项:
route:admin(后台路由)+system:settings(activate 写盐与开关)
七、后台功能
复用核心 .admin-tabs / .admin-tab-btn / .admin-table(规范 §11 后台 Tab 条),不自造 tab 类。
Tab 1 设置
| 项 | 类型 | 默认 | 说明 |
|---|---|---|---|
| 模块开关 | 开关 | 开 | 关闭后导航入口消失、路由 404、右栏卡不渲染 |
| 每日首次查看奖励 | 数字 | 0 | 0 = 不奖励;>0 时当天首次进入奖励积分 |
| 允许游客查看 | 开关 | 开 | 关 = 未登录跳登录 |
| 默认星座 | 下拉 | 白羊 | 未设置档案时的兜底展示 |
Tab 2 统计
- 今日查看 / 7 日查看 / 累计查看
- 12 星座分布(横条,纯 CSS 宽度)
- 最近 20 条记录(用户 / 星座 / 动作 / 时间)
八、i18n 方案
- 全部文案走
lang/{zh,zh_tw,en}.php,键名plugin.horoscope.* - 占位符用
{key}(I18n::get($key, ['sign' => ...]),实测app/Helpers/I18n.php:156) - 三语键集合与键序必须完全一致(验收标准,规范 §8)
- 星座名 / 维度名 / 档位文案统一走 i18n,不在 PHP 里硬编码中文
⚠️ 这决定了
Plugin.php里只能存「键名索引」,不能存成品文案。例:```php
private const TEXT_KEYS = [
'love' => ['high' => ['text.love_high_1', ...], 'mid' => [...], 'low' => [...]],
];
```
九、分期计划
P0 — MVP(可上线)
Plugin.php:星座表、DDL、种子引擎、档案读写、统计查询- 今日运势页(5 维度 + 幸运色/数字/贵人 + 宜忌)
- 星座档案(12 格选择器 / 填生日自动识别)
- 右栏小卡 + 导航入口 + 用户下拉入口
- 后台设置 + 统计
- 三语各 ~200 键
- 自检 + 审计
P1 — 增强
- 星座配对页(§4.2 模型)
- 未来 7 天趋势条
- 文案池补满(每档 3 → 5 条)
P2 — 可选
- 分享图(canvas 绘制 →
toDataURL;CSP 不含blob:,必须用 dataURL) - 塔罗 / 抽签(独立子模块,不影响主流程)
- 移动端 API(
mobile_api_routes) - 换日时间可配置
十、已核验的技术事实
10.1 图标(双重核验:$map 有名字 + 字体子集有字形)
| 用途 | 图标名 | 码点 | map | 字体 |
|---|---|---|---|---|
| 插件主图标 / 页面标题 | moon | U+F186 | ✅ | ✅ gid=214 |
| 综合运势 | star | U+F006 | ✅ | ✅ |
| 爱情 | heart | U+F004 | ✅ | ✅ |
| 事业 | user-tie | U+F508 | ✅ | ✅ |
| 财运 | coins | U+F53A | ✅ | ✅ |
| 健康 | seedling | U+F4D8 | ✅ | ✅ |
| 幸运色 | palette | U+F53F | ✅ | ✅ |
| 幸运数字 | bullseye | U+F140 | ✅ | ✅ |
| 配对 | hand-holding-heart | U+F4BE | ✅ | ✅ |
| 趋势 | chart-line | U+F201 | ✅ | ✅ |
不可用(已实测排除):briefcase(字体无字形)、circle-info / sparkles / hashtag / clover / cloud-sun($map 无此名)。
12 星座符号(♈♉♊…U+2648–U+2653)走系统字体,不依赖图标字体,可直接当文本输出。
10.2 API 签名(已读源码确认)
| API | 签名 | 备注 |
|---|---|---|
Auth::getCurrentUser() | ?array | 游客返回 null |
Csrf::verifyOrDie() | (string $token): void | 必须传参:$_POST['csrf'] ?? '';AJAX 走 HTTP_X_CSRF_TOKEN |
I18n::get() | (string $key, array $params = []): string | 占位符 {key};缺键返回 key 本身 |
Points::award() | (int $userId, int $points, string $reason, int $relatedId = 0, string $relatedType = '') | 若启用奖励则用 |
Plugin::ensureSchema() | (string $name, string $ddl) | 幂等建表 |
10.3 钩子约束(规范 §9.0 / §9.3)
- 渲染钩子禁
die()/exit()/header() nav_plugin_links/nav_user_menu_items一次渲染触发两次 → 钩子文件禁止声明顶层函数/类(否则降级include_once,第二处入口静默消失)nav_plugin_links图标 16px($view->icon('moon', 16),与 13 个既有实现一致)nav_user_menu_items图标 14px,按placement分pc/mobile渲染
十一、红线自查清单(写代码时逐条对照)
| # | 红线 | 本方案的处理 |
|---|---|---|
| 1 | 目录名含下划线 → 生命周期静默失效 | horoscope 无下划线,但仍加 class_alias 防御 |
| 2 | activate() 可能被跳过 → 无表 | init_after 惰性建表兜底 |
| 3 | 写操作顺序 | 先 requireLogin(),后 Csrf::verifyOrDie() |
| 4 | 渲染钩子中断页面 | 所有钩子只 echo,不 exit |
| 5 | 零内联 | 无 on*=、无静态 style=(幸运色用 CSS 变量注入,合规)、无内联 <script> |
| 6 | 图标问号 | 全部图标已双重核验(§10.1) |
| 7 | i18n 键漂移 | 三语键集合 + 键序一致性纳入验收 |
| 8 | SQL 注入 | 全部 prepare() + 绑定;无字符串拼接 |
| 9 | 前台链接硬编码 | 一律 $this->url() / 拼 BASE_PATH |
| 10 | 资源缓存 | ?v=filemtime() |
| 11 | 双主题可读性 | 只用 --mn-* 变量,不写死颜色 |
| 12 | 时区/换日 | 单点 todayDate() 函数,不散落 |
十二、待拍板的 4 个决策点
决策 1:积分怎么处理
| 选项 | 说明 | 代价 |
|---|---|---|
| A(推荐) 不涉及积分 | 纯内容模块,零耦合 | 无 |
| B 每日首次查看 +2 积分 | 拉活跃,但要防刷(一天一次幂等) | 多一张 hs_logs 唯一约束 + 奖励逻辑 |
| C 消耗积分看深度内容 | 商业化思路 | 社区站大概率劝退,不建议 |
推荐 A 起步。若选 B,实现上就是把
hs_logs的(user_id, log_date, action='view')做唯一索引,插入成功才发奖。
决策 2:内容边界
| 选项 | 内容 | 工作量 |
|---|---|---|
| A(推荐) 星座运势 + 配对 | 今日 + 7 天 + 配对 | 基准 |
| B 只做今日运势 | 最轻 | -30% |
| C + 塔罗 / 抽签 | 多一套 64 签文案 | +80% |
决策 3:游客可见范围
| 选项 | 说明 |
|---|---|
| A(推荐) 游客可看「默认星座」的今日运势,看不到个性化与 7 天趋势 | 保留 SEO 与转化入口 |
| B 全开(游客也能选星座) | 无法记档案,只能存 session |
| C 全关(未登录跳登录) | 少一个 SEO 入口 |
决策 4:文案由谁写
| 选项 | 说明 |
|---|---|
| A(推荐) 我按占星通行话术写,三语各 ~250 键,P0 先写 3 条/档 | 可控、可改、零依赖 |
| B 你提供文案,我留占位 | 质量最高,但要你先写 750 条 |
十三、验收标准
P0 交付时必须同时满足:
php -l全绿(8.0 + 8.2 双版本)- 三语键集合与键序完全一致(脚本比对,零差异)
- 确定性断言:同一
(用户, 星座, 日期)连算 1000 次结果完全一致;跨日期必变 - 分布断言:1000 个用户同一天同一星座,5 维度分数落在 55–99 且不是常数
- HTTP 冒烟:
/horoscope200、未登录跳转符合决策 3、右栏卡只在登录后出现、on*=为 0 - 审计工具(
plugin-audit/cli/audit.php):0 CRITICAL / 0 MAJOR - 双主题走查(浅色 + 暗夜星辰)
说明.md+plugin.json.changelog同步
附:与「网上参考」的差异说明
主流星座站(星座屋、今日运势等)普遍包含:综合 / 爱情 / 事业学业 / 财富 / 健康指数、幸运色、幸运数字、贵人星座、宜忌、穿衣推荐、商谈指数。
本方案取前 7 项,去掉后 3 项:
- 穿衣推荐 → 与「幸运色」重复
- 商谈指数 → 社区用户用不上
- 每日生肖 → 与星座体系混搭,显得杂
保留的判断依据:社区站要的是「一眼看完 + 明天还想来」,不是「专业占星报告」。