feat(news_reports): 事件支持多新闻源 sources + 页面底部访问计数器

- /api/news/events/ 事件行: sources 字段非空时显示多个新闻源, 为空回退 source 单源 (兼容数组/对象/JSON 字符串)
- footer 参考 index-2.php 深色样式, 增加 page_counter 访问计数
- 文档: AGENTS.md/CLAUDE.md 更新表数量 16->18 张, 补充 news_report/news_event 说明
This commit is contained in:
2026-08-12 15:08:00 +08:00
parent 10569bb828
commit 2855cb51ca
4 changed files with 40 additions and 8 deletions
+4 -3
View File
@@ -76,10 +76,10 @@ $_REQUEST['t'] = 'stockList';
## 数据库表名约定 ## 数据库表名约定
完整清单见 `DB_REFERENCE.md`(16 张表、在用/未用/已被 API 替代状态一目了然)。要点: 完整清单见 `DB_REFERENCE.md`(18 张表、在用/未用/已被 API 替代状态一目了然)。要点:
- **已被 API 替代、代码不再直接引用**:`index_hist_pro`(指数行情)、`stock_his_pro`(个股行情)、`stock_all_pro`(代码↔名称)——对应数据走 `api.doorcome.cn` 的 `indexDatas` / `stockbasic` / `stockinfo` 等端点。 - **已被 API 替代、代码不再直接引用**:`index_hist_pro`(指数行情)、`stock_his_pro`(个股行情)、`stock_all_pro`(代码↔名称)——对应数据走 `api.doorcome.cn` 的 `indexDatas` / `stockbasic` / `stockinfo` 等端点。
- **在用**:`moneyflow_hsgt_pro`(沪深港通原始值)、`moneyflow_hsgt_pro_ext`(累积值)、`estate_json` / `estate_json_ext` / `estate_listing`(房地产)、`trade_record` / `trade_record_cj`(方正/长江证券交易记录)、`mac_report`(宏观研究,quant/ 用)、`pv_log` / `pv_counter`(访问日志)。 - **在用**:`moneyflow_hsgt_pro`(沪深港通原始值)、`moneyflow_hsgt_pro_ext`(累积值)、`estate_json` / `estate_json_ext` / `estate_listing`(房地产)、`trade_record` / `trade_record_cj`(方正/长江证券交易记录)、`mac_report`(宏观研究,quant/ 用)、`pv_log` / `pv_counter`(访问日志)、`news_report` / `news_event`(投资资讯日报,由独立的 djapi 后端写入,本仓库前端 `charts/news_reports.php` 仅经 `/api/news/reports/`、`/api/news/events/` 只读消费)。
- **机构持仓在 `ih_by_ts_code_ext`**,但消费它的页面(`chartSix.php`、`chartThree.php`、`stock_ih.php`、`index_ih.php`)已全部移入 `deprecated/`,当前无活跃调用者;`getIhData()` / `getIhDataByStock()` 保留在 `inc/getData.inc.php`。 - **机构持仓在 `ih_by_ts_code_ext`**,但消费它的页面(`chartSix.php`、`chartThree.php`、`stock_ih.php`、`index_ih.php`)已全部移入 `deprecated/`,当前无活跃调用者;`getIhData()` / `getIhDataByStock()` 保留在 `inc/getData.inc.php`。
## 注意事项 ## 注意事项
@@ -88,7 +88,8 @@ $_REQUEST['t'] = 'stockList';
- **没有鉴权机制** —— 这是内网或个人使用的系统,不需要添加登录/权限功能。 - **没有鉴权机制** —— 这是内网或个人使用的系统,不需要添加登录/权限功能。
- **`deprecated/` 目录** —— 存放已废弃的旧版页面(`chartOne`~`chartSix`、`stock_ih`、`index_ih`、旧版 `stock_trend`/`index_trend` 等,部分仍用 `window.chartConfig` 模式),直接忽略,不要修改或引用。 - **`deprecated/` 目录** —— 存放已废弃的旧版页面(`chartOne`~`chartSix`、`stock_ih`、`index_ih`、旧版 `stock_trend`/`index_trend` 等,部分仍用 `window.chartConfig` 模式),直接忽略,不要修改或引用。
- **`class/basic_info.class.php`** —— 独立的小类,未被核心流程引用。 - **`class/basic_info.class.php`** —— 独立的小类,未被核心流程引用。
- **`news/` 和 `research/`** —— 独立的子模块,有自己的 JS/CSS 和设计文档,修改前先看对应的 `design.md` 和 `outline.md`。 - **`news/`** —— 独立子模块(新闻抓取/分析,面向 CCTV 新闻联播),有自己的 JS/CSS,修改前先看 `design.md` 和 `outline.md`。
- **`research/`** —— 股票/行业研究报告产物目录(HTML/PDF),修改前看 `intl_news_README.md`。
## Checkpoint ## Checkpoint
+1 -1
View File
@@ -36,7 +36,7 @@
- `upload.php` — 文件上传处理。 - `upload.php` — 文件上传处理。
- `plansetup.php` — 用于 Composer autoload 的快捷入口(`__DIR__."/../vendor/autoload.php"`)。 - `plansetup.php` — 用于 Composer autoload 的快捷入口(`__DIR__."/../vendor/autoload.php"`)。
> 数据库表全量清单(16 张表、在用/未用/已由 API 替代状态)见根目录 `DB_REFERENCE.md`。 > 数据库表全量清单(18 张表、在用/未用/已由 API 替代状态)见根目录 `DB_REFERENCE.md`。
### 页面结构 ### 页面结构
+15 -3
View File
@@ -1,3 +1,4 @@
<?php include_once __DIR__ . "/../inc/functions.inc.php"; ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
<head> <head>
@@ -222,10 +223,21 @@
</div> </div>
</main> </main>
<footer class="text-center text-gray-400 text-sm py-6"> <footer class="bg-dark text-white mt-16">
数据来源: api.doorcome.cn 日报接口 · 仅供个人研究参考 <div class="container mx-auto px-4 py-8">
<div class="text-center text-gray-400 text-sm">数据来源: api.doorcome.cn 日报接口 · 仅供个人研究参考</div>
<div class="border-t border-gray-800 mt-6 pt-6 text-center text-gray-500 text-sm">
<div>Powered by Simon Young <span style="font-family: Arial; font-size: x-small;"> &copy; </span>2019-<?=date('Y')?>
&nbsp;All Right Reserved <a href="mailto:simon.youngest@gmail.com" title='simon.youngest@gmail.com'>E-mail</a>.
</div>
<div>
<a href="https://beian.miit.gov.cn" target="_blank">浙ICP备18056264号-1</a>
<span class="ml-3"><?php page_counter(); ?></span>
</div>
</div>
</div>
</footer> </footer>
<script src="/js/newsReports.js?v=20260806"></script> <script src="/js/newsReports.js?v=20260812"></script>
</body> </body>
</html> </html>
+20 -1
View File
@@ -301,6 +301,17 @@ var NewsReports = {
'</div>'; '</div>';
}, },
// 解析事件新闻源: sources 字段(json 数组/对象/字符串), 归一化为字符串数组
parseSources: function (s) {
if (!s) return null;
if (typeof s === 'string') {
try { s = JSON.parse(s); } catch (err) { return null; }
}
if (Array.isArray(s)) return s.filter(function (x) { return x && String(x).trim(); });
if (typeof s === 'object') return Object.keys(s).filter(function (k) { return k && String(k).trim(); });
return null;
},
renderEventRow: function (e, idx, extraMeta) { renderEventRow: function (e, idx, extraMeta) {
var sen = this.SENTIMENT[e.sentiment] || this.SENTIMENT.neutral; var sen = this.SENTIMENT[e.sentiment] || this.SENTIMENT.neutral;
var impCls = e.importance >= 5 ? 'imp-5' : (e.importance >= 4 ? 'imp-4' : ''); var impCls = e.importance >= 5 ? 'imp-5' : (e.importance >= 4 ? 'imp-4' : '');
@@ -310,7 +321,15 @@ var NewsReports = {
var meta = []; var meta = [];
if (extraMeta) meta = meta.concat(extraMeta); if (extraMeta) meta = meta.concat(extraMeta);
if (e.event_type) meta.push('<span class="meta-item"><i class="fa-regular fa-tag mr-1"></i>' + selfEscape(e.event_type) + '</span>'); if (e.event_type) meta.push('<span class="meta-item"><i class="fa-regular fa-tag mr-1"></i>' + selfEscape(e.event_type) + '</span>');
if (e.source) meta.push('<span class="meta-item"><i class="fa-regular fa-newspaper mr-1"></i>' + selfEscape(e.source) + '</span>'); // 新闻源: 优先显示 sources(多源, json 数组/对象), 为空则回退 source(单源)
var srcs = this.parseSources(e.sources);
if (srcs && srcs.length) {
for (var i = 0; i < srcs.length; i++) {
meta.push('<span class="meta-item"><i class="fa-regular fa-newspaper mr-1"></i>' + selfEscape(srcs[i]) + '</span>');
}
} else if (e.source) {
meta.push('<span class="meta-item"><i class="fa-regular fa-newspaper mr-1"></i>' + selfEscape(e.source) + '</span>');
}
return '' + return '' +
'<div class="event-row">' + '<div class="event-row">' +
'<div class="event-left">' + '<div class="event-left">' +