feat(api): v1.0.10 免费发布条数(周期 每日/每月/累计)+ 计费顺序(套餐额度 → 免费条数 → 单条付费)

需求:免费发布不能是「要么全免费、要么一开付费就是硬付费墙」,需要可配「前 N 条免费」,
超出的按付费发布标准计费。

- 后台「发布与费用配置」新增「免费发布条数 + 统计周期」:post.freeQuota / post.freeQuotaCycle
  (day 每日 / month 每月 / total 累计;0 = 不限制,免费发布模式下「免费到底」)
  Publish::save 校验周期枚举与条数非负;页面补说明(计费顺序:套餐额度 → 免费发布条数 → 单条付费)
- FcInstall::upgradePublish 与内置种子各补两枚配置(幂等,不覆盖运营已改的值;老库缺失时
  API 回落 fee.freePostPerDay 按日计,行为与升级前一致)
- POST /post/create 计费重构为三级顺序:
  ① 套餐额度(fc_user_ext.post_quota_left)→ ② 免费发布条数(按周期统计本人已发布条数,不含软删)
  → ③ 单条付费(post.singlePrice,即「付费发布」标准)
  免费发布模式下免费条数用完时明确提示「免费额度已用完,请按 X.XX 元/条付费发布」
  (服务端不主动扣款,需客户端切到 plan=single 并选支付方式后重新提交)
- GET /post/publish-config 字段调整:freePerDay/freeUsedToday/freeLeftToday
  → freeQuota / freeQuotaCycle / freeQuotaUsed / freeQuotaLeft / freeUnlimited(-1 = 不限制)
- tools/verify-api.mjs P9 同步断言新字段与「能否免费发布」判定;后台语言包补齐中文映射
- application/config.php:site.version 1.6.6.20261016 → 1.6.7.20261016(后台视图/JS 变更后强制刷新静态资源缓存)

自检:node tools/check-admin-i18n.mjs(错误 0/警告 0)、node tools/check-theme.mjs(错误 0/警告 0)、
5 个 PHP 文件 php -n -l 无语法错误。
这个提交包含在:
linda
2026-10-17 11:45:36 +08:00
父节点 d278c9a758
当前提交 d452be1d60
共有 7 个文件被更改,包括 201 次插入 和 73 次删除

查看文件

@@ -141,12 +141,13 @@ class FcInstall extends Command
*
* 背景:v1.0.7 新增「免费发布 / 付费发布」开关与付费发布的三档定价
* · 单条价格 post.singlePrice
* · 免费发布条数 post.freeQuota / post.freeQuotaCycle(v1.0.10:达到条数后按单条价格计费)
* · 按月(价格 + 含条数)post.monthPrice / post.monthQuota
* · 按年(价格 + 含条数)post.yearPrice / post.yearQuota
* 老库缺列/缺配置时补齐,**不覆盖运营已改过的值**:
* ① fc_user_ext 补 post_quota_left / post_quota_expire(剩余发布条数 + 有效期)
* ② fc_plan 补 post_quota(套餐含发布条数,月/年卡赠送额度)
* ③ fc_config 补 post.* 六项(已存在则跳过)
* ③ fc_config 补 post.* 八项(已存在则跳过)
* ④ 月卡/年卡的价格与条数以配置为准做一次同步(配置缺失时反向用套餐值填配置)
*/
private function upgradePublish(Output $output)
@@ -181,7 +182,9 @@ class FcInstall extends Command
// ③ 配置项(只补缺失的,不覆盖运营已改的值)
$defaults = [
['post.mode', 'free', 'post', '发布模式:free 免费发布 / paid 付费发布'],
['post.singlePrice', '5', 'post', '单条发布价格(元)'],
['post.singlePrice', '5', 'post', '单条发布价格(元)=付费发布标准价'],
['post.freeQuota', '0', 'post', '免费发布条数(0 = 不限制/免费到底;达到条数后按单条发布价格计费)'],
['post.freeQuotaCycle', 'day', 'post', '免费条数统计周期:day 每日 / month 每月 / total 累计'],
['post.monthPrice', '19.9', 'post', '按月发布价格(元)'],
['post.monthQuota', '30', 'post', '按月含发布条数'],
['post.yearPrice', '168', 'post', '按年发布价格(元)'],
@@ -689,7 +692,9 @@ class FcInstall extends Command
['fee.memberYear', '168', 'fee', '年卡价格'],
// 发布模式与发布套餐(后台「发布与费用配置」页维护;真源=配置,保存时同步 fc_plan)
['post.mode', 'free', 'post', '发布模式:free 免费发布 / paid 付费发布(默认免费,避免上线即撞付费墙)'],
['post.singlePrice', '5', 'post', '单条发布价格(元)'],
['post.singlePrice', '5', 'post', '单条发布价格(元)=付费发布标准价'],
['post.freeQuota', '0', 'post', '免费发布条数(0 = 不限制/免费到底;达到条数后按单条发布价格计费)'],
['post.freeQuotaCycle', 'day', 'post', '免费条数统计周期:day 每日 / month 每月 / total 累计'],
['post.monthPrice', '19.9', 'post', '按月发布价格(元)'],
['post.monthQuota', '30', 'post', '按月含发布条数'],
['post.yearPrice', '168', 'post', '按年发布价格(元)'],