You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
7.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 企业新闻舆情部署与维护
后台页面 `/companyNews/index` 支持新闻采集、公司和发布日期筛选、人工正文编辑、留存审核及批次记录。当前没有对外展示接口。所有新闻默认 `is_visible=false`,保存与审核也不会开启展示。
## 业务规则
- 点击“获取更新”创建一个全量候选和已占额企业快照,不受新闻列表筛选和分页影响;仅 `company_qcc_accounts.status` 为 `selected` 或 `occupied` 的企业进入批次,按公司 ID 顺序执行。
- 执行前再次检查企业是否仍为候选或已占额;不符合的任务记录失败/跳过,不调用元禾。
- 单次请求使用元禾 `enterprise/packInfo`,连接超时 10 秒、总超时 60 秒;只有外层 `code=200` 且 `data.news` 是数组或 null 才进行处理。null/空数组记成功、0 新增;缺字段、非数组记失败。
- 本功能直接调用 Repository,不调用 QccCallService;成功、失败、超时均不更新企业户状态。原来的 `qcc:verify-pack-info` 诊断命令仍有状态流转,不能用它代替本功能。
- 按企业、数据提供方及去重键建立唯一约束。去重键按 NewsId、Id、原文 URL 的优先级生成 SHA-256;来源标识必须跨次稳定。同一新闻关联不同公司分别保存。
- 重复采集只更新来源字段、原始 JSON 与最近采集信息,不覆盖标题、人工正文、审核结论或展示状态。不留存是逻辑状态,不删除记录。
- 原文 HTML 使用现有 TinyMCE 组件编辑,并通过服务端 HTMLPurifier 清理。来源 Content 独立保存,接口正文为空时不会伪造原文。
- 原文抓取仅预留字段,本期不自动访问来源链接抓取正文。
- 新闻列表日期筛选依据原文 PublishTime,按应用时区保存与筛选,结束日期包含当天全部时间。
- 单条新闻字段错误会记录序号与错误,其余正常条目继续保存;该企业任务记失败,以便核查和重试。成功/失败按企业计数,新增加总实际插入行数。
## 企业下拉查询
公司筛选仅返回企业户中 selected、occupied 的企业,不返回 unknown 或未纳入的企业。接口按企业名称、ID 排序,每页 30 家;前端滚动触底加载下一页,输入关键词时从第一页重新搜索。“获取更新”采集全部候选和已占额企业,不受当前公司筛选或下拉分页影响。
## 元禾接口配置
后端 `.env` 必须设置 YUANHE_BASE_URL、YUANHE_CUSTOMERID、YUANHE_AUTHKEY,值使用当前授权的元禾配置。密钥不得提交到版本控制。项目通过 config/yuanhe.php 读取,因此使用配置缓存的环境更新后需重新生成配置缓存,并重启采集进程。
创建批次和启动消费者前会校验配置,缺少配置时直接说明缺少的键名,不会创建一批注定失败的任务;页面顶部也会显示配置错误。
## 上线步骤
部署本次 PHP 源码后,在项目根目录执行这两条迁移(不包含工作区其他功能的迁移):
```bash
php artisan migrate --path=database/migrations/2026_10_09_100000_create_company_news_tables.php --force
php artisan migrate --path=database/migrations/2026_10_09_100001_add_company_news_menu.php --force
```
新增五张表:company_news、company_news_logs、company_news_batches、company_news_tasks、company_news_control。
菜单迁移创建“企业新闻舆情”,页面地址 `/companyNews/index`,API 权限前缀 `api/admin/company-news/`。继承现有 `/qccEnterpriseAccount/index` 菜单的角色及直接授权;若旧菜单不存在或未给用户分配权限,请在角色管理中分配新菜单。新接口同时经过管理员登录与 RBAC 权限检查。重新登录加载新菜单。
在前端项目构建并将产物部署到站点 `public/admin`:
```bash
npm run build:prod -- --dest dist
```
后端要使用与现有项目一致的 PHP CLI 和 composer.lock 依赖(HTMLPurifier 已包含在当前锁定的生产依赖中)。更新了路由缓存的环境需重新生成或清理路由缓存。
## 调度执行
本地使用 `php artisan serve` 启动 HTTP 服务并不会启动后台调度。`company-news/latest` 只读查询进度,轮询它不会执行企业请求。需在另一个终端保持以下专用消费者运行:
```bash
php artisan qcc:collect-news --watch
```
此模式每 5 秒检查是否有新建批次,只运行新闻采集,不触发其他短信、邮件等调度任务。重启电脑、停止终端或更改元禾配置后需重启该进程。生产环境可使用宝塔守护进程/Supervisor 管理该命令,或使用下面已有的 Laravel scheduler 方式。
复用服务器已有 Laravel scheduler,每分钟执行 `php artisan schedule:run`。无需新增 Redis 或修改全站 QUEUE_CONNECTION;任务和锁存储在数据库中。
本次 Kernel 增加 `qcc:collect-news`,每分钟在后台启动消费者。它仅处理管理员已经创建的批次,不会每分钟重新创建采集批次。页面点击后通常在下一分钟开始;关闭页面不影响执行。
如果服务器尚未设置 Laravel scheduler,可在宝塔计划任务配置每分钟执行,PHP 路径使用服务器实际安装的 CLI 路径:
```bash
cd /www/wwwroot/wx.sstbc.com && php artisan schedule:run
```
也可以手工消费已经创建的批次:
```bash
php artisan qcc:collect-news
```
限制本次消费者处理量:
```bash
php artisan qcc:collect-news --limit=20
```
命令不创建批次、不改企业户状态;没有任务时立即退出。1000 家为顺序执行,实际耗时取决于元禾响应时间,页面持续展示进度,不承诺 10 分钟完成。
## 重复执行和故障恢复
- 创建批次和领取任务都锁定 company_news_control 的唯一控制行。同一时间仅允许一个活动批次,一个企业请求在执行;多实例 scheduler 可重复启动消费者,但不会重复领取活跃任务。
- 领取时生成 worker_token 和 5 分钟租约。外部请求在数据库事务外执行,结果提交时核验 token;过期 worker 不允许写入后续 worker 的任务结果。
- 进程崩溃后,下次消费者在租约到期时把中断任务记为失败,继续后续企业,不会自动重复外部请求。
- 网络超时不能证明元禾未收到请求。对方没有提供幂等协议时,无法保证外部调用严格只发生一次;“仅重试失败企业”由管理员明确启动新批次,并重新检查候选或已占额状态。
- 某个任务保存失败,其事务回滚后独立记失败;数据库整体不可用时命令退出,调度恢复后按租约继续。
- 页面显示“等待后台调度”长时间无进展:检查宝塔 scheduler、PHP CLI 版本、任务日志和 active_batch_id。不要通过删除控制行或随意清锁恢复,这可能破坏防重入机制。
- 不留存记录必须保留,否则后续采集又会变成新的待审核记录。
## 验证命令
```bash
php vendor/bin/phpunit tests/Feature/CompanyNewsWorkflowTest.php tests/Unit/Services/QccCallServiceTest.php
```
前端项目:
```bash
npx vue-cli-service test:unit tests/unit/components/CompanyNews.spec.js --runInBand
```
后端测试使用 SQLite 内存数据库、模拟元禾响应,不访问业务数据库、不调用收费接口。上线人工验收:创建包含候选和已占额企业的小规模批次,查看进度、历史与失败明细;重复采集验证新闻不重复,编辑/留存后再采集验证人工数据保持。