Compare commits

...
38 Commits
Author SHA1 Message Date
simon 10569bb828 docs: 更新 README/CLAUDE/AGENTS/DB_REFERENCE
- README: 新增投资资讯日报功能、日报 API 数据源、三种数据流模式、sync-echart 部署与 gitea 仓库说明
- CLAUDE.md: 页面目录表补 charts/news_reports.php,模式B 代表页面补充
- AGENTS.md: 模式B 页面清单与 API 端点补充
- DB_REFERENCE.md: 补 news_report/news_event 两张日报表(共 18 张)
2026-08-06 09:33:53 +08:00
simon 11f31762ad feat: 页首开始/结束日期输入框写入默认值(近30天) 2026-08-06 09:29:26 +08:00
simon 7785de7d1f fix: newsReports.js 加版本号参数, 规避浏览器缓存导致的重要事件Tab无反应 2026-08-06 09:28:14 +08:00
simon 4da1fc9301 feat: 重要事件聚合视图 + stats 英文键格式加固
- normalizeKV 显式识别 intl 英文键格式(importance/count、event_type/count、source/count),不再依赖键顺序
- 新增"重要事件"视图 Tab:跨日报聚合(/api/news/events/),支持 天数/重要度/类型 筛选,复用事件行渲染
- 兼容文档 v1.1:intl sentiment 对象格式、finance news.event_types 对象格式
2026-08-06 09:25:16 +08:00
simon f8bca284a8 merge: 合并 gitea 初始提交(LICENSE/README) 2026-08-05 20:29:14 +08:00
simon 8ea9b48a9a feat: 投资资讯日报查询页 + 文档更新 + 拉取服务器最新内容
- 新增 charts/news_reports.php 报告查询导航页(列表+详情一体,fetch API 渲染)
- 新增 js/newsReports.js:AI 摘要/新闻联播/财经新闻/公告调研/数据总览固定模块,stats 归一化兼容多种格式
- index-2.php 研究报告卡片改为导航链接,移除 PHP 目录下拉框
- 更新 AGENTS.md/CLAUDE.md(路径、页面清单、数据模式等核实修正)
- 同步服务器拉取的文档:quant 使用手册、podcast-docs
- 生成 continuation.md 会话检查点
2026-08-05 20:28:57 +08:00
simonandClaude 60fb1b95e1 fix: 修复 getBasic.inc.php 多余括号 & 重构研究报告卡片
- 删除 index-2.php 中 PDF 报告卡片(6 个硬编码链接)
- 研究报告卡片改为动态加载:扫描 research/yyyymmdd/ 子目录生成下拉框
- 选中日期后显示该目录下所有 HTML 文件(提取 <title> 作为链接名)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-17 20:46:33 +08:00
simonandClaude Opus 4.7 742bed2644 fix: 修复 getBasic.inc.php 多余括号 & 重构研究报告卡片
- 删除 getBasic.inc.php 中残留的多余 `}` 导致部署后解析错误
- index-2.php: 删除 PDF报告卡片;研究报告卡片改为按日期子目录动态加载

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-15 09:54:48 +08:00
simonandClaude Opus 4.7 080d6da44c refactor: 前端库清理、页面废弃、DB→API 数据源替换
- 删除重复库文件:lib/DataTables-2/、lib/echarts/、libai/、css/fontawesome/ 等 179 个冗余文件
- 下载外部 CDN 到本地:Mermaid、AOS、Google Fonts(Inter/Noto Serif SC/Noto Sans SC)
- 所有第三方库统一到 lib/,按库名-版本号命名
- 更新 8 个 research HTML 文件引用路径

- stock_his_pro → /api/stockbasic/(getStockHist、recentPrice)
- stock_all_pro → /api/stockinfo/(tscodeToName)
- index_hist_pro → /api/indexDatas/(getIndexData)
- 新增 callDoorcomeApi() 共享函数
- 被替换表的 DB 查询代码完全删除,无回退

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 15:50:39 +08:00
simonandClaude Opus 4.7 ef123c697f refactor: 废弃机构持仓图表页面,整理数据库表引用文档
- 将 chartSix.php、chartThree.php、stock_ih.php、index_ih.php 移至 deprecated/
- 从 index.php、index-2.php 移除对应导航链接
- 新增 DB_REFERENCE.md,完整记录 16 张数据库表的使用状态
- 更新 continuation.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 08:30:15 +08:00
simonandClaude Opus 4.7 eedead0d41 feat: 全面代码更新 - ECharts 5.4.2 重构、新增量化分析模块、前端库升级
- 升级 ECharts 到 5.4.2,重构 lib/ 目录结构
- 新增 DataTables 2.x 和 FixedColumns 插件
- 新增 quant/ 宏观研究报告模块
- 重构图表页面:stock_trend、hkholdbycode 等采用 JS fetch API.doorcome.cn 模式
- 新增 CLAUDE.md 补充页面文档和新数据流说明
- 更新 inc/config.php TuShare API 配置
- 更新新闻联播分析模块 news/ 和相关研究报告 research/
- 新增 api_document/ 参考文档
- 清理 .gitignore,排除 uploads/xls/.mcp.json/ source maps 等非代码文件
- 所有 PHP 文件通过 php -l 语法检查

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 18:01:55 +08:00
simonandClaude Code f3f9d19da7 refactor: 前端库整理与图表标准化
库文件整理:
- 所有JS/CSS/字体库统一到lib/js/、lib/css/、lib/webfonts/
- 按名称-版本格式重命名(jquery-3.6.0.min.js等)
- 删除约80个重复/废弃的库文件副本
- 更新17个文件中的引用路径

图表模式标准化:
- moneyflow/realestate/estate3个页面从$.ajax/PHP注入转为fetch+loading overlay模式
- 新增moneyflowData/estateData两个AJAX端点
- chartmoneyflow.js、estate.js移至deprecated

README.md更新为完整功能介绍

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-05-26 14:34:28 +08:00
simonandClaude Code 7e57cae242 refactor: 全面代码重构与项目结构整理
安全性:
- 所有SQL查询改用参数化查询(db_query),防止SQL注入
- TUSHARE_API_TOKEN集中到config.php常量,移除硬编码和多份拷贝
- getBasic.inc.php中$_REQUEST输出到JS时添加htmlspecialchars转义

代码组织:
- 21个页面文件移至charts/子目录,根目录仅保留入口文件
- ajax.inc.php拆分:esfTradeDaily/esfListDaily迁至getEstate.inc.php
- getBasic.inc.php拆分:HTML组件函数迁至新建的widgets.inc.php
- 前端依赖去重:移除lib/echarts.min.js、libai/3.4.16.js、research/js/3.4.16.js

规范化:
- AJAX响应格式统一为jsonResponse()标准封装
- 前端全局变量统一为window.chartConfig对象模式
- 修复PHP 8.4 Deprecated警告(getEstateData、getStockHistoryDataByTS参数顺序)
- html/head.php中jQuery/CSS路径改为绝对路径,修复charts/子目录加载问题

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-05-26 08:20:33 +08:00
杨水淼 07da6a2ad4 update before cc involved 2026-05-25 11:01:06 +08:00
杨水淼 2f600aed0f feat: 使用 get_mysqli_connection() 函数重构数据库连接 2025-11-12 16:02:19 +08:00
杨水淼 4c348e379d feat: Refactor database connection handling to use centralized configuration 2025-11-12 16:00:32 +08:00
杨水淼 8303ae39f1 Refactor code structure for improved readability and maintainability 2025-11-03 12:01:37 +08:00
杨水淼 4990e2068c Add Font Awesome v4 compatibility WOFF2 file 2025-10-29 08:07:49 +08:00
杨水淼 cb98c1649c Add summary statistics and macroeconomic data files for 2025
- Created summary_statistics.csv with total news articles and key metrics from January 1 to October 13, 2025.
- Added 一号文件十四五十五五规划情况.csv detailing keyword occurrences related to planning documents.
- Introduced 主要宏观经济数据.csv capturing mentions of key economic indicators.
- Included 国外交流随行企业与企业家名单.csv listing leaders and their engagements with foreign enterprises.
- Added 国家领导人考察行程清单.csv documenting leaders' inspection itineraries.
- Created 国际合作与外交动态.csv summarizing international cooperation and diplomatic activities.
- Added 高频行业关键词统计.csv with statistics on frequently mentioned industry keywords.
2025-10-23 14:58:21 +08:00
杨水淼 4a56455151 feat: Update database connection and error display settings
- Changed database connection credentials in footer.php for improved security.
- Disabled error display in ajax.inc.php to prevent sensitive information exposure.
- Added comprehensive design documentation for the news flow application.
- Implemented a modernized index.php layout with responsive design and enhanced user experience.
- Developed main.js for dynamic news loading, including infinite scroll and date filtering functionalities.
- Structured interaction.md to detail core interactive features of the application.
- Organized outline.md to clarify project structure and core functionalities.
- Populated mock-data.json with realistic news data for testing and development purposes.
2025-10-13 16:16:46 +08:00
杨水淼 521e0687a4 Add stock dividend trend analysis page with chart rendering and data fetching 2025-09-02 12:41:09 +08:00
杨水淼 4b3a51083b 更新:增加html研究报告页面,增加新的导航页 2025-07-28 12:44:46 +08:00
杨水淼 bd82783ddb 更新:js容错算法改善,增加2份Ai报表 2025-07-22 16:16:59 +08:00
杨水淼 bd4f92d465 更新:ajax 载入动图更新 2025-07-19 10:01:53 +08:00
杨水淼 de11c31f0b 更新:重构多个页面代码,简化代码。实现无刷新更新数据。 2025-07-14 12:46:48 +08:00
杨水淼 daeae185dd 更新:重构股票和指数趋势页面,增加流通市值图表,优化数据获取逻辑,修复代码中的小错误 2025-07-10 17:24:15 +08:00
杨水淼 5152b3ee2f 更新:重构和迁移多个PHP文件到deprecated目录,删除不再使用的文件,更新pubfunc.js版本;index_trend,stock_trend 数据源以及代码重构简化 2025-07-09 15:21:52 +08:00
杨水淼 43a202c789 更新:添加每日和每月数据选项,修改相关URL参数,更新JavaScript文件,增加股票指数历史数据获取功能 2025-07-09 07:36:50 +08:00
yangshuimiao 5d135b24f1 update: minor update 2025-01-10 07:48:24 +08:00
yangshuimiao e33cb8e93a fix: 标题错误 2023-11-13 10:01:00 +08:00
yangshuimiao d367cfc2e9 融资余额Y坐标auto scale 2023-10-26 10:24:47 +08:00
yangshuimiao fdbbe445bb update: PV Counter 2023-10-24 09:03:37 +08:00
yangshuimiao e3f65c200d Merge branch 'main' of https://github.com/Simon2046/echarts 2023-10-16 14:05:06 +08:00
yangshuimiao b6b0d93b37 Minor update 2023-10-16 13:38:42 +08:00
Simon2046andGitHub 3a8e5ef82d Delete .vscode directory 2023-10-16 13:35:44 +08:00
Simon2046andGitHub eded42c881 Update README.md 2023-10-16 13:15:27 +08:00
Simon2046andGitHub 0b876e8807 Create README.md 2023-10-16 13:15:11 +08:00
yangshuimiao 3a09f3ca67 first commit 2023-10-16 12:58:41 +08:00
1527 changed files with 479254 additions and 2 deletions
+8
View File
@@ -0,0 +1,8 @@
.vscode/
.files/
uploads/
xls/
.serena/
.mcp.json
*.xls
*.map
+103
View File
@@ -0,0 +1,103 @@
# AGENTS.md
本文件为 AI 编码助手提供在本仓库中工作的指引与约定。
## 项目背景
这是一个 A 股基本面数据可视化和宁波房地产数据分析平台,面向个人投资者使用。项目没有框架,是原生 PHP 写的传统 Web 应用。
## 技术约束
- **不要引入框架或构建工具** —— 项目是纯 PHP + jQuery + ECharts,没有 webpack、vite、composer autoload 之外的依赖管理。新增功能沿用现有模式即可。
- **不要动 `inc/config.php`** —— 该文件含**明文**数据库凭据和 `TUSHARE_API_TOKEN`,是敏感文件;手工修改可能破坏连接逻辑。也**不要提交到公开仓库**。
- **PHP 版本** —— 代码兼容 PHP 7.x/8.x(本地为 PHP 8.4),使用了 `mysqli`、cURL、Composer autoload。不要使用 PHP 8.1+ 独有的特性(如枚举、readonly 等)。
- **所有用户输入走 `$_REQUEST`** —— GET 和 POST 统一处理,不需要区分。
- **图表数据传递** —— 当前活跃页面有三种模式(见下),新页面优先复用现有模式,不要自创第四种。
### 三种数据传递模式(实测现状)
1. **模式 Bfetch 外部 API**:页面 JS 用 `fetch()``https://api.doorcome.cn/api/*`(如 `stockparam``indexDatas``stockinfo``getdiv``stockep``stockmargin``stockbasic``news/reports``news/events`)。代表页面:`stock_trend.php``stockdiv.php``stockep.php``stockmargin.php``hkholdbycode.php``index_trend.php``index_mv_all.php``index_margin.php``news_reports.php`(日报 + 重要事件聚合)。
2. **模式 CAJAX → `inc/ajax.inc.php`**:页面 JS 用 `$.ajax``../inc/ajax.inc.php`,通过 `$_REQUEST['t']` 路由(if 链,不是 switch/case)。`t` 取值:`stockList``financeData``esfTBD``esfListDaily``newTBD``moneyflowData``estateData`。代表页面:`moneyflow.php``realestate.php``estateTradeDaily.php``estateListDaily.php``estateNewTradeDaily.php``stockkeydata.php``stockTradeRecord.php`
3. **模式 A(服务端注入)**PHP 查询后 `json_encode()` 注入 `<script>` 标签中的 JS 变量。`window.chartConfig` 全局变量**仅剩 `deprecated/` 在用**;活跃页面 `charts/chartStDetail.php` 是变体(注入命名变量 `data1``data5``legend` 等)。
## 代码风格约定
- 缩进:使用 Tab 缩进(现有代码风格)。
- SQL 查询:使用 heredoc 语法,保持可读性。
- PHP 标签:使用 `<?=``<?php` 短标签。
- 注释:中文注释,简洁为主,解释业务逻辑而非代码本身(如指数的 ts_code 映射、机构类型 LX 含义等)。
- 不需要加 docblock —— 现有代码基本没有,新代码也不加。
## 新增页面流程
如果要新增一个数据可视化页面,按以下步骤:
1.`inc/` 中写数据获取函数(如果数据源有复用价值),或在页面内直接写查询
2.`charts/` 创建 `newpage.php`include 需要的 `inc/*.php`
3. 通过 `$_REQUEST` 接收参数(如 `ts_code``t_start``t_end`
4. 数据获取:优先走模式 B(fetch `api.doorcome.cn`)或模式 C`ajax.inc.php` 加一个 `t=` 分支)
5. 图表 JS 放 `js/` 目录,新式页面复用 `js/renderCharts.js``doubleLineChart()` 等)和 `js/pubfunc.js``getRows()``hideSwitch()` 等)
6. 公共库统一从 `/lib/js/` 引用:`jquery-3.6.0.min.js``echarts-5.4.2.js``tailwindcss-3.4.17.js`(注意是连字符、在 `lib/js/` 下,不是 `js/`
7. 对于样式较新的页面,使用 `/lib/js/tailwindcss-3.4.17.js` 并参考 `index-2.php` 的布局风格
8.`index-2.php` 中添加导航入口
## 常用代码片段
### 获取数据库连接
```php
include_once __DIR__."/inc/config.php";
$mysqli = get_mysqli_connection();
```
### 标准查询返回 echarts 数据格式
```php
$tDate = $idx = $data = array();
while ($row = $result->fetch_assoc()) {
array_push($tDate, $row['trade_date']);
array_push($idx, $row['close']);
array_push($data, array("value" => array($row['trade_date'], round($row['close'], 2))));
}
$result->free();
$mysqli->close();
return array('tDate' => $tDate, 'idx' => $idx, 'data' => $data);
```
### 调用 TuShare API
```php
include_once __DIR__."/inc/functions.inc.php";
$data = callTushareApi('daily_basic', $params);
```
### 前端 AJAX 调用模式
```php
// 请求参数中必须包含 t 字段,用于 ajax.inc.php 路由
$_REQUEST['t'] = 'stockList';
```
## 数据库表名约定
完整清单见 `DB_REFERENCE.md`(16 张表、在用/未用/已被 API 替代状态一目了然)。要点:
- **已被 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`(访问日志)。
- **机构持仓在 `ih_by_ts_code_ext`**,但消费它的页面(`chartSix.php``chartThree.php``stock_ih.php``index_ih.php`)已全部移入 `deprecated/`,当前无活跃调用者;`getIhData()` / `getIhDataByStock()` 保留在 `inc/getData.inc.php`
## 注意事项
- **TuShare API token 硬编码在 `inc/config.php` 中** —— 不要提交到公开仓库。
- **没有鉴权机制** —— 这是内网或个人使用的系统,不需要添加登录/权限功能。
- **`deprecated/` 目录** —— 存放已废弃的旧版页面(`chartOne`~`chartSix``stock_ih``index_ih`、旧版 `stock_trend`/`index_trend` 等,部分仍用 `window.chartConfig` 模式),直接忽略,不要修改或引用。
- **`class/basic_info.class.php`** —— 独立的小类,未被核心流程引用。
- **`news/``research/`** —— 独立的子模块,有自己的 JS/CSS 和设计文档,修改前先看对应的 `design.md``outline.md`
## Checkpoint
当用户说 "checkpoint" 时,在项目根目录生成 `continuation.md`,包含:
- **当前状态**:刚刚完成了什么、改了哪些文件、结果如何
- **后续步骤**:具体的、有序的下一步行动
- **待解决问题**:未解决的疑问、已知限制或需要决策的事项
## Notes
(待补充:部署 `sync-echart` 命令细节见 CLAUDE.mdPHP 语法检查 `php -l` 修改后必做。)
+190
View File
@@ -0,0 +1,190 @@
# CLAUDE.md
本文件为 Claude Codeclaude.ai/code)在本仓库中工作提供指引。
## 项目概览
基于 PHP 的 A 股金融数据可视化和宁波房地产数据分析平台。使用 ECharts 生成交互式图表,后端为 MySQL 数据库和 TuShare API。
## 技术栈
- **后端**: PHP(无框架),Composer 管理依赖(`phpoffice/phpspreadsheet``monolog/monolog`
- **前端**: ECharts 4.x、jQuery、Tailwind CSS 3.4CDN 引入)、DataTables、Font Awesome
- **数据库**: MySQL,通过 `mysqli` 连接——统一使用 `inc/config.php` 中的 `get_mysqli_connection()` 获取连接
- **外部 API**: TuShare`api.tushare.pro``api.waditu.com`),用于获取财务数据
- **调试**: XDebug,端口 9000(配置见 `.vscode/launch.json`
## 无构建步骤
传统 PHP 应用,没有构建/检查/测试流水线。文件直接部署到 Web 服务器。运行于 `echart.doorcome.cn`。每个 `.php` 文件是独立的入口点,没有路由机制。Composer autoload 在部分文件中使用(引入 `vendor/autoload.php`)。
## 架构
### 核心 includes`inc/`
- `config.php` — 数据库连接工厂(`get_mysqli_connection()`),所有 DB 操作统一走此函数。另含 `db_query()` 参数化查询函数和 `jsonResponse()` 统一 JSON 响应函数。
- `getData.inc.php` — 指数数据、机构持仓(IH)、资金流向(沪深港通南北向)、个股历史查询。
- `getBasic.inc.php` — PE/PB/PS 历史、股价历史、市值数据、TuShare API 封装、日期工具、数据查询函数。HTML 渲染函数已拆分至 `widgets.inc.php`
- `widgets.inc.php` — HTML 组件函数:`tradeStocksList()``vendorList()``yearList()``yearToname()`
- `functions.inc.php` — 共享表单组件(districtList、indexList、seList、byDM)和 `callTushareApi()` 辅助函数。
- `ajax.inc.php` — 所有 AJAX 端点,通过 `$_REQUEST['t']` 分发:股票列表、财务数据(调用 `getFinanceData.class.php`)、房地产成交/挂牌查询。业务函数(`esfTradeDaily``esfListDaily`)已迁移至 `getEstate.inc.php`
- `getFinanceData.class.php``getFinance` 类,调用 TuShare API 获取财务报表数据。
- `tradeRec.inc.php` — 交易记录查询(`trade_record` / `trade_record_cj` 表)。
- `excelOperate.inc.php` — 通过 PhpSpreadsheet 读取 Excel/CSV 文件。
- `postJson.inc.php` — 使用 cURL 发送 JSON HTTP POST 请求。
- `getEstate.inc.php` — 房地产相关数据查询(`estate_json``estate_json_ext``estate_listing` 表)及二手房成交/挂牌数据函数(`esfTradeDaily``esfListDaily`)。
- `upload.php` — 文件上传处理。
- `plansetup.php` — 用于 Composer autoload 的快捷入口(`__DIR__."/../vendor/autoload.php"`)。
> 数据库表全量清单(16 张表、在用/未用/已由 API 替代状态)见根目录 `DB_REFERENCE.md`。
### 页面结构
根目录及 `charts/` 下的每个 `.php` 文件渲染一个独立的数据视图,存在三种数据获取模式:
**模式 A(服务端注入):**
1. 引入所需的 `inc/*.php`,通过 `$_REQUEST` 接收查询参数
2. PHP 查询数据库,将结果通过 `json_encode()` 注入 `<script>` 标签内的 JS 变量
3. 引入对应的 `js/*.js` 渲染
4. 注意:`window.chartConfig` 全局变量**仅剩 `deprecated/` 在用**;活跃页面中 `charts/chartStDetail.php` 是变体(注入命名变量 `data1``data5`
**模式 B(较新——JS fetch 调用外部 API):**
1. 页面直接加载 JS,不注入数据
2. JS 在 `$(document).ready` 中通过 `fetch()` 调用 `https://api.doorcome.cn/api/*`(如 `stockparam``indexDatas``stockinfo``getdiv``stockep``stockmargin``stockbasic`)获取数据
3. 代表页面:`stock_trend.php``stockdiv.php``stockep.php``stockmargin.php``hkholdbycode.php``index_trend.php``index_mv_all.php``index_margin.php``news_reports.php`(含重要事件聚合,调 `/api/news/events/`
**模式 CAJAX → `inc/ajax.inc.php`):**
1. 页面 JS 用 `$.ajax``../inc/ajax.inc.php`,通过 `$_REQUEST['t']` 路由(if 链):`stockList``financeData``esfTBD``esfListDaily``newTBD``moneyflowData``estateData`
2. 代表页面:`moneyflow.php``realestate.php``estateTradeDaily.php``estateListDaily.php``estateNewTradeDaily.php``stockkeydata.php``stockTradeRecord.php`
### 页面目录
根目录保留入口文件(`index.php``index-2.php``phpinfo.php`),其余页面文件均位于 `charts/` 子目录。
| 文件 | 用途 |
|------|------|
| `index.php` | 原导航页,重定向至 `index-2.php` |
| `index-2.php` | 主导航门户(Tailwind 风格) |
| `charts/stock_trend.php` | 股价 VS PE/PB/PS 趋势 |
| `charts/stockep.php` | 股价 VS 盈利能力 |
| `charts/stockdiv.php` | 股价 VS 股息率 |
| `charts/stockmargin.php` | 股价 VS 融资融券余额 |
| `charts/hkholdbycode.php` | 股价 VS 北向资金持股 |
| `charts/stockkeydata.php` | 个股基本面数据 |
| `charts/index_trend.php` | 指数 VS PE/PB/PS/市值 |
| `charts/index_mv_all.php` | 指数 VS 两市总市值 |
| `charts/index_margin.php` | 指数 VS 融资余额 |
| `charts/moneyflow.php` | 指数 VS 沪深港通资金流向 |
| `charts/realestate.php` | 房地产挂牌数量趋势(宁波) |
| `charts/estateNewTradeDaily.php` | 新房每日成交量(宁波) |
| `charts/estateTradeDaily.php` | 二手房每日成交量(宁波) |
| `charts/estateListDaily.php` | 二手房每日挂牌量(宁波) |
| `charts/stockTradeRecord.php` | 个人股票交易记录 |
| `charts/myexcel.php` | 交易记录 Excel/CSV 导入处理(配合上传流程) |
| `charts/chartStDetail.php` | 个股详细图表(服务端注入命名变量 data1…data5 |
| `charts/news_reports.php` | 投资资讯日报导航页(国内/国际日报列表+详情+重要事件聚合,fetch api.doorcome.cn |
> 注:`stock_ih.php`、`index_ih.php`、`chartSix.php`、`chartThree.php` 及旧版 `stock_trend.php`/`index_trend.php`/`index_mv_all.php` 已移入 `deprecated/`,勿引用。
### JavaScript 约定
每个页面加载 `js/` 中对应的 JS 文件(如 `chartStDetail.js``renderCharts.js``pubfunc.js``adj.ajax.js`)。新式图表页面复用 `js/renderCharts.js``doubleLineChart()` 等)和 `js/pubfunc.js``getRows()``hideSwitch()` 等)。ECharts 库统一从 `/lib/js/echarts-5.4.2.js`v5)引用。`window.chartConfig` 传递模式仅存于 `deprecated/`
### 子模块
- `news/` — 独立的新闻抓取/分析模块,面向 CCTV 新闻联播。包含自己的 PHP、JS 和设计文档。
- `research/` — 股票研究报告(HTML 和 PDF)、行业分析,含 AI 生成的研究内容。
- `quant/` — 宏观研究报告模块,基于 PHP + Tailwind CSS,数据存储在 `mac_report` 表中。
- `api_document/` — Hailo 平台 API 参考文档(TXT 格式,非本项目核心内容)。
- `deprecated/` — 已废弃的旧版页面和脚本,仅供参考。
### 前端库位置
- `lib/js/` — jQuery 3.6.0、DataTables 1.13.4、ECharts 5.4.2`echarts-5.4.2.js`)、ECharts GL、ecStat、Tailwind CSS 3.4.17`tailwindcss-3.4.17.js`)、Chart.js、anime.js、marked、mermaid 等第三方库
- `lib/css/``lib/webfonts/` — 第三方 CSS 与字体
- `libai/` — shader-park-coreAI/研究页面使用)
- `js/` — 页面专属图表逻辑(不含第三方库)
- `css/` — 自定义样式(`style.css``css2.css`)、Font Awesome
## 常用命令
```bash
# PHP 语法检查(修改文件后必做)
php -l inc/ajax.inc.php
php -l charts/stock_trend.php
# Composer 依赖管理
composer update # 更新依赖
composer dump-autoload # 更新 autoload
# 部署到远程服务器(脚本位于 ~/bin/sync-echartrsync 单向推送本地 → 服务器)
sync-echart -n # 预览(dry-run
sync-echart # 执行部署到 simon@www.doorcome.cn:/var/www/html/echart/
# 排除项: .git/.vscode/.claude/.serena/.mcp.json/reasonix.toml
# 以及数据/产物目录 uploads/xls/files/research/podcast/podcast-docs(服务器为权威,不覆盖)
# 批量 PHP 语法检查(修改多个文件后)
for f in charts/*.php; do php -l "$f"; done
for f in inc/*.php; do php -l "$f"; done
```
## 代码风格约定(来自 AGENTS.md)
- 缩进使用 Tab
- SQL 查询使用 heredoc 语法
- PHP 标签使用 `<?=``<?php` 短标签
- 中文注释,简洁为主,解释业务逻辑而非代码本身
- 不加 docblock
- 避免使用 PHP 8.1+ 特有特性(enum、readonly 等),需兼容 PHP 7.x
## 服务器与部署
应用运行于 `echart.doorcome.cn`。所有用户输入通过 `$_REQUEST` 读取——GET 和 POST 统一处理。无认证或 CSRF 防护。数据库凭据在 `inc/config.php` 中。
TuShare API Token 统一定义在 `inc/config.php``TUSHARE_API_TOKEN` 常量中。
部署到远程服务器使用 `sync-echart` 命令(定义在 `~/.bashrc` 中),自动排除 `.git``.vscode``.claude``.files`
```bash
sync-echart -n # 先预览
sync-echart # 执行部署
```
服务器路径:`simon@www.doorcome.cn:/var/www/html/echart/`
## 多文件修改规范
修改多个文件前,先输出:
- **涉及文件** — 列出所有将被修改的文件
- **修改原因** — 每个文件为什么需要改
- **潜在影响** — 可能破坏什么,哪些消费者会受影响
修改完成后,输出:
- **已完成列表** — 每个文件的具体变更内容
- **验证步骤** — 确认正确性的步骤(语法检查、页面访问测试等)
## 风险意识
- 本项目**没有自动化测试**,所有变更需手动验证。
- 跨层修改(如 AJAX 响应格式、JS 全局变量、PHP 引入路径)属于**高风险操作**——修改前必须追踪所有消费者,并明确说明风险后再动手。
- 修改 AJAX 响应格式时,需同时检查 PHP 端消费者(服务端数据组装)和 JS 端消费者(`$.ajax` success 回调、`getRows()` 调用、DataTables 配置)。
- 修改 JS 全局变量名时,需检查所有引用这些变量的 `.js` 文件,而非仅检查注入变量的 PHP 页面。
- `deprecated/` 目录的文件可更新路径以保持一致性,除此之外不要改动。
## 批量脚本注意事项
用 Python/sed 对大量文件做机械性修改(路径前缀替换、变量重命名)可以接受,但需:
- 运行脚本前先列出将要影响的文件清单
- 脚本运行后,用 grep 搜索旧模式确认无遗漏
- 对每个修改过的 PHP 文件执行 `php -l` 语法检查
## Checkpoint
当用户说 "checkpoint" 时,在项目根目录生成 `continuation.md`,包含:
- **当前状态**:刚刚完成了什么、改了哪些文件、结果如何
- **后续步骤**:具体有序的下一步行动
- **待解决问题**:未解决的疑问、已知限制或需要决策的事项
+66
View File
@@ -0,0 +1,66 @@
# 数据库表引用清单
数据库:`myquant`(配置在 `inc/config.php`
共 18 张表,其中 12 张在使用,3 张未使用,3 张已由 API 替代。
## 全表清单
### 股票交易记录(2 张,均在用)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `trade_record` | ✅ 在用 | 方正证券交易记录 | `inc/ajax.inc.php``inc/tradeRec.inc.php``inc/widgets.inc.php``inc/excelOperate.inc.php` |
| `trade_record_cj` | ✅ 在用 | 长江证券交易记录 | `inc/ajax.inc.php``inc/tradeRec.inc.php``inc/widgets.inc.php``inc/excelOperate.inc.php` |
### 股票行情与基本面(4 张,2 张未使用,2 张已由 API 替代)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `stock_his_pro` | 🔄 已替换 | 股票历史日线行情(复权价) | 已由 API `/api/stockbasic/` 替代,代码中不再引用 |
| `stock_all_pro` | 🔄 已替换 | 股票代码↔名称对照 | 已由 API `/api/stockinfo/` 替代,代码中不再引用 |
| `stock_his_basic_pro` | ❌ 未使用 | 历史基本面(PE/PB/PS) | 被 `getBasicData()` 查询,该函数唯一调用在 `deprecated/chartStDetail.php:14` 且已注释 |
| `stock_basic_ext` | ❌ 未使用 | 总市值/流通市值/股本等 | 被 `getBasicExtData()` 查询,该函数全项目无调用者 |
### 指数与资金流向(4 张,2 张在用,1 张未使用,1 张已由 API 替代)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `index_hist_pro` | 🔄 已替换 | 指数历史日线行情 | 已由 API `/api/indexDatas/` 替代,代码中不再引用 |
| `moneyflow_hsgt_pro` | ✅ 在用 | 沪深港通资金流向(原始值) | `inc/getData.inc.php` |
| `moneyflow_hsgt_pro_ext` | ✅ 在用 | 沪深港通资金流向(累积值) | `inc/getData.inc.php` |
| `ih_by_ts_code_ext` | ❌ 未使用 | 机构持仓(基金/QFII/社保/券商/保险/信托) | 被 `getIhData()` / `getIhDataByStock()` 查询,原调用 `chartSix.php` / `chartThree.php` 已移至 `deprecated/`,当前无活跃调用者 |
### 房地产数据(3 张,均在用)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `estate_json` | ✅ 在用 | 新房/二手房成交挂牌主表 | `inc/getEstate.inc.php``inc/ajax.inc.php` |
| `estate_json_ext` | ✅ 在用 | 房地产扩展属性(区域/面积/价格) | `inc/getEstate.inc.php``inc/ajax.inc.php` |
| `estate_listing` | ✅ 在用 | 二手房每日挂牌套数 | `inc/getEstate.inc.php` |
### 宏观研究(1 张,在用)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `mac_report` | ✅ 在用 | 宏观研究报告 | `quant/index.php``quant/report.php` |
### 系统日志(2 张,均在用)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `pv_log` | ✅ 在用 | 页面访问日志 | `inc/functions.inc.php` |
| `pv_counter` | ✅ 在用 | 页面访问计数器 | `inc/functions.inc.php` |
### 日报 API2 张,djapi 后端管理)
| 表名 | 状态 | 用途 | 引用文件 |
|------|------|------|---------|
| `news_report` | ✅ 在用 | 投资资讯日报主表(国内 finance / 国际 intl,每天每类型一份) | djapi `api/report/` 写入;前端 `charts/news_reports.php``api.doorcome.cn/api/news/reports/` 只读消费 |
| `news_event` | ✅ 在用 | 日报事件明细(xwlb/news/cninfo/intl 板块,含重要度/情感/来源/链接) | 同上,`/api/news/events/` 跨日报聚合 |
## 说明
- 所有 SQL 查询均通过 `db_query()` 参数化查询(prepare/execute),`excelOperate.inc.php` 中 insert 操作用字符串拼接
- 部分较新页面(`stock_trend.php``stockdiv.php` 等)通过 JS fetch 调用 `https://api.doorcome.cn/api/*`,不直接查询数据库
- `deprecated/` 目录中的文件已排除,不纳入统计
+105 -2
View File
@@ -1,3 +1,106 @@
# echart
# echarts — 金融数据可视化平台
https://echart.doorcome.cn/
A 股基本面分析和宁波房地产数据可视化平台,基于 PHP + ECharts + MySQL + TuShare API。
## 主要功能
### 个股分析
| 页面 | 功能 |
|------|------|
| 股价 VS PE/PB/PS 趋势 | 股票收盘价与估值指标(市盈率/市净率/市销率)的历史对比 |
| 股价 VS EP | 股价与盈利能力(Earnings Power)趋势分析 |
| 股价 VS 股息率 | 股票价格与股息率的历史走势对比 |
| 股价 VS 融资融券余额 | 个股价格与融资融券余额的关系分析 |
| 股价 VS 北向资金持股 | 股票价格与沪深港通北向资金持股变化 |
| 股价 VS 机构持仓趋势 | 基金、QFII、社保、券商、保险、信托六类机构的持仓变化 |
| 个股基本面数据 | 财务报表数据表格展示(资产负债表、利润表、现金流量表关键指标) |
| 个股交易记录 | 个人交易记录导入、查询、分析(支持方正证券/长江证券),含做T收益计算 |
### 指数分析
| 页面 | 功能 |
|------|------|
| 指数 VS PE/PB/PS/市值 | 上证/深证/中小板/创业板/上证50/沪深300/中证500/北证50的估值与市值趋势 |
| 指数 VS 机构持仓趋势 | 各指数对应成分股的机构持仓汇总变化 |
| 指数 VS 两市总市值 | 指数点位与沪深两市总市值对比 |
| 指数 VS 融资余额 | 指数走势与全市场融资余额的关系 |
| 指数 VS 沪深港通资金流向 | 指数与北向/南向资金、港股通资金流向的对比分析 |
### 房地产(宁波)
| 页面 | 功能 |
|------|------|
| 房地产挂牌数量趋势 | 宁波各区县二手房挂牌数量变化趋势 |
| 新房每日成交量 | 宁波各区县新房每日成交面积和套数(日/月维度) |
| 二手房每日成交量 | 宁波各区县二手房成交面积和套数(日/月维度) |
| 二手房每日挂牌量 | 宁波各区县二手房每日新增挂牌套数和均价 |
### 投资资讯日报
| 页面 | 功能 |
|------|------|
| 日报查询导航页(`charts/news_reports.php`) | 国内 / 国际 AI 深度研究日报,按日期分模块查看(AI 摘要、新闻联播要闻、财经新闻、公告调研、数据总览) |
| 重要事件聚合 | 跨日报检索重要事件(近 N 天 / 重要度 / 类型筛选),数据来自 `api.doorcome.cn/api/news/events/` |
### 其他模块
- **新闻联播分析**`news/`):CCTV 新闻联播内容抓取与关键词分析
- **研究报告**`research/`):AI 产业链、锂矿、新能源等行业深度研究报告(含 PDF 和 HTML 版本)
- **宏观研究**`quant/`):宏观量化分析报告,数据存储在 `mac_report`
## 技术栈
- **后端**PHP 8.4,无框架
- **前端**ECharts 5.4、jQuery 3.6、Tailwind CSS 3.4、DataTables 1.13、Font Awesome 6.4
- **数据库**MySQL,通过 `mysqli` 连接
- **外部 API**TuShare`api.tushare.pro` / `api.waditu.com`)、日报接口(`api.doorcome.cn/api/news/reports/``/api/news/events/`,由 djapi 后端提供,表 `news_report`/`news_event`
- **数据来源**:宁波市房产交易服务信息网(`cnnbfdc.com`
## 项目结构
```
├── index.php / index-2.php # 入口导航页
├── charts/ # 数据可视化页面(含 charts/news_reports.php 日报导航页)
├── inc/ # PHP 核心代码
│ ├── config.php # DB连接、db_query()、jsonResponse()
│ ├── getData.inc.php # 数据查询(指数、持仓、资金流向)
│ ├── getBasic.inc.php # PE/PB/PS/市值查询、TuShare API
│ ├── getEstate.inc.php # 房地产数据查询
│ ├── getFinanceData.class.php # 财务报表 API 调用
│ ├── functions.inc.php # 共享组件、callTushareApi()
│ ├── widgets.inc.php # HTML 组件(下拉列表等)
│ ├── tradeRec.inc.php # 交易记录查询与分析
│ ├── ajax.inc.php # AJAX 端点
│ ├── excelOperate.inc.php # Excel/CSV 读取
│ └── postJson.inc.php # JSON HTTP POST
├── lib/ # 第三方库
│ ├── js/ # JS 库(jQuery、ECharts、DataTables 等)
│ ├── css/ # CSS 库(Font Awesome、DataTables
│ └── webfonts/ # 字体文件
├── js/ # 页面专属图表/渲染 JSnewsReports.js 为日报页逻辑)
├── css/ # 自定义样式
├── html/ # 公共 HTML 头部/底部
├── news/ # 新闻联播分析模块
├── research/ # 研究报告模块
├── podcast-docs/ # 播客相关文档
└── deprecated/ # 已废弃的旧页面
```
## 数据流
```
用户请求 → .php 页面(charts/
→ 模式A: inc/*.php 查询 MySQL → json_encode() 注入 <script> 变量 → js/*.js 渲染
→ 模式B: js 直接 fetch api.doorcome.cn/api/* (日报、指数、个股行情等新页面)
→ 模式C: js 通过 $.ajax 调 inc/ajax.inc.php 的 t= 路由(房地产、资金流向等)
→ ECharts / HTML 渲染交互式图表
```
## 开发环境
- **本地 PHP**`d:\software\php8.4\`(本机 Mac 无 PHP`php -l` 语法检查走服务器)
- **部署**`~/bin/sync-echart`rsync 单向推送本地 → `simon@www.doorcome.cn:/var/www/html/echart/``-n` 预览;排除本地环境文件与数据目录 uploads/xls/files/research
- **代码仓库**gitea `ssh://git@gitea/simon/echart.git``~/.ssh/config` 别名 gitea,端口 2222
- **调试**XDebug 端口 9000VS Code 配置 `.vscode/launch.json`
- **代码指引**:见 `CLAUDE.md``AGENTS.md`
@@ -0,0 +1,313 @@
HailoRT Python API Reference
hailo_platform.pyhailort.hw_object
Hailo hardware API
class hailo_platform.pyhailort.hw_object.InferenceTargets[source]
Bases: object
Enum-like class with all inference targets supported by the HailoRT.
UNINITIALIZED = 'uninitialized'
UDP_CONTROLLER = 'udp'
PCIE_CONTROLLER = 'pcie'
exception hailo_platform.pyhailort.hw_object.HailoHWObjectException[source]
Bases: Exception
Raised in any error related to Hailo hardware.
class hailo_platform.pyhailort.hw_object.HailoHWObject[source]
Bases: object
Abstract Hailo hardware device representation (deprecated)
NAME = 'uninitialized'
IS_HARDWARE = True
__init__()[source]
Create the Hailo hardware object.
property name
The name of this target. Valid values are defined by InferenceTargets (deprecated)
Type
str
property is_hardware
Indicates this target runs on a physical hardware device. (deprecated)
Type
bool
property device_id
Getter for the device_id. :returns: A string ID of the device. BDF for PCIe devices, IP address for Ethernet devices, “Core” for core devices. :rtype: str
property sorted_output_layer_names
Getter for the property sorted_output_names (deprecated). :returns: Sorted list of the output layer names. :rtype: list of str
use_device(*args, **kwargs)[source]
A context manager that wraps the usage of the device. (deprecated)
get_output_device_layer_to_original_layer_map()[source]
Get a mapping between the device outputs to the layers names they represent (deprecated).
Returns
Keys are device output names and values are lists of layers names.
Return type
dict
get_original_layer_to_device_layer_map()[source]
Get a mapping between the layer names and the device outputs that contain them (deprecated).
Returns
Keys are the names of the layers and values are device outputs names.
Return type
dict
property device_input_layers
Get a list of the names of the devices inputs. (deprecated)
property device_output_layers
Get a list of the names of the devices outputs. (deprecated)
hef_loaded()[source]
Return True if this object has loaded the model HEF to the hardware device. (deprecated)
outputs_count()[source]
Return the amount of output tensors that are returned from the hardware device for every input image (deprecated).
property model_name
Get the name of the current model (deprecated).
Returns
Model name.
Return type
str
get_output_shapes()[source]
Get the model output shapes, as returned to the user (without any hardware padding) (deprecated).
Returns
Tuple of output shapes, sorted by the output names.
class hailo_platform.pyhailort.hw_object.HailoChipObject[source]
Bases: hailo_platform.pyhailort.hw_object.HailoHWObject
Hailo hardware device representation (deprecated)
__init__()[source]
Create the Hailo Chip hardware object.
property control
Returns the control object of this device, which implements the control API of the Hailo device. .. attention:: Use the low level control API with care.
Type
HailoControl
get_all_input_layers_dtype()[source]
Get the model inputs dtype (deprecated).
Returns
obj:numpy.dtype: where the key is model input_layer name, and the value is dtype as the device expect to get for this input.
Return type
dict of
get_input_vstream_infos(network_name=None)[source]
Get input vstreams information of a specific network group (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.VStreamInfo: with all the information objects of all input vstreams
get_output_vstream_infos(network_name=None)[source]
Get output vstreams information of a specific network group (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.VStreamInfo: with all the information objects of all output vstreams
get_all_vstream_infos(network_name=None)[source]
Get input and output vstreams information (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.VStreamInfo: with all the information objects of all input and output vstreams
get_input_stream_infos(network_name=None)[source]
Get the input low-level streams information of a specific network group (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.VStreamInfo: with information objects of all input low-level streams.
get_output_stream_infos(network_name=None)[source]
Get the output low-level streams information of a specific network group (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.VStreamInfo: with information objects of all output low-level streams.
get_all_stream_infos(network_name=None)[source]
Get input and output streams information of a specific network group (deprecated).
Parameters
network_name (str, optional) The name of the network to access. In case not given, all the networks in the network group will be addressed.
Returns
If there is exactly one configured network group, returns a list of hailo_platform.pyhailort._pyhailort.StreamInfo: with all the information objects of all input and output streams
property loaded_network_groups
Getter for the property _loaded_network_groups. :returns: List of the the configured network groups loaded on the device. :rtype: list of ConfiguredNetwork
get_input_shape(name=None)[source]
Get the input shape (not padded) of a network (deprecated).
Parameters
name (str, optional) The name of the desired input. If a name is not provided, return the first input_dataflow shape.
Returns
Tuple of integers representing the input_shape.
get_index_from_name(name)[source]
Get the index in the output list from the name (deprecated).
Parameters
name (str) The name of the output.
Returns
The index of the layer name in the output list.
Return type
int
release()[source]
Release the allocated resources of the device. This function should be called when working with the device not as context-manager. Note: After calling this function, the device will not be usable.
class hailo_platform.pyhailort.hw_object.EthernetDevice(remote_ip, remote_control_port=22401)[source]
Bases: hailo_platform.pyhailort.hw_object.HailoChipObject
Represents any Hailo hardware device that supports UDP control and dataflow (deprecated)
NAME = 'udp'
__init__(remote_ip, remote_control_port=22401)[source]
Create the Hailo UDP hardware object.
Parameters
remote_ip (str) Device IP address.
remote_control_port (int, optional) UDP port to which the device listens for control. Defaults to 22401.
static scan_devices(interface_name, timeout_seconds=3)[source]
Scans for all eth devices on a specific network interface.
Parameters
interface_name (str) Interface to scan.
timeout_seconds (int, optional) timeout for scan operation. Defaults to 3.
Returns
IPs of scanned devices.
Return type
list of str
property remote_ip
Return the IP of the remote device (deprecated).
class hailo_platform.pyhailort.hw_object.PcieDevice(device_info=None)[source]
Bases: hailo_platform.pyhailort.hw_object.HailoChipObject
Hailo PCIe production device representation (deprecated)
NAME = 'pcie'
__init__(device_info=None)[source]
Create the Hailo PCIe hardware object.
Parameters
device_info (hailo_platform.pyhailort.pyhailort.PcieDeviceInfo, optional) Device info to create, call PcieDevice.scan_devices() to get list of all available devices.
static scan_devices()[source]
Scans for all pcie devices on the system (deprecated).
Returns
list of hailo_platform.pyhailort.pyhailort.PcieDeviceInfo
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,332 @@
hailo_platform.pyhailort.control_object
Control operations for the Hailo hardware device.
exception hailo_platform.pyhailort.control_object.ControlObjectException[source]
Bases: Exception
Raised on illegal ContolObject operation.
exception hailo_platform.pyhailort.control_object.FirmwareUpdateException[source]
Bases: Exception
class hailo_platform.pyhailort.control_object.HailoControl(device: hailo_platform.pyhailort._pyhailort.Device)[source]
Bases: hailo_platform.pyhailort.pyhailort.Control
Control object that sends control operations to a Hailo hardware device.
class hailo_platform.pyhailort.control_object.HcpControl(device: hailo_platform.pyhailort._pyhailort.Device)[source]
Bases: hailo_platform.pyhailort.control_object.HailoControl
Control object that uses the HCP protocol for controlling the device.
class hailo_platform.pyhailort.control_object.UdpHcpControl(remote_ip, device=None, remote_control_port=22401, retries=2, response_timeout_seconds=10.0, ignore_socket_errors=False)[source]
Bases: hailo_platform.pyhailort.control_object.HcpControl
Control object that uses a HCP over UDP controller interface.
__init__(remote_ip, device=None, remote_control_port=22401, retries=2, response_timeout_seconds=10.0, ignore_socket_errors=False)[source]
Initializes a new UdpControllerControl object.
Parameters
remote_ip (str) The IPv4 address of the remote Hailo device (X.X.X.X).
remote_control_port (int, optional) The port that the remote Hailo device listens on.
response_timeout_seconds (float, optional) Number of seconds to wait until a response is received.
ignore_socket_errors (bool, optional) Ignore socket error (might be usefull for debugging).
class hailo_platform.pyhailort.control_object.PcieHcpControl(device=None, device_info=None)[source]
Bases: hailo_platform.pyhailort.control_object.HcpControl
Control object that uses a HCP over PCIe controller interface.
__init__(device=None, device_info=None)[source]
Initializes a new HailoPcieController object.
hailo_platform.pyhailort.hailo_controller.i2c_slaves
hailo_platform.pyhailort.i2c_slaves.NO_I2C_SWITCH = 5
Variable which defines that the I2C slave is not behind a switch.
exception hailo_platform.pyhailort.i2c_slaves.I2CSlavesException[source]
Bases: Exception
class hailo_platform.pyhailort.i2c_slaves.I2CSlave(name, bus_index, slave_address, switch_number=5, register_address_size=1, endianness=<Endianness.LITTLE_ENDIAN: 1>, should_hold_bus=False)[source]
Bases: object
__init__(name, bus_index, slave_address, switch_number=5, register_address_size=1, endianness=<Endianness.LITTLE_ENDIAN: 1>, should_hold_bus=False)[source]
Initialize a class which describes an I2C slave.
Parameters
name (str) The name of the I2C slave.
bus_index (int) The bus number the I2C slave is connected to.
slave_address (int) The address of the I2C slave.
switch_number (int) The number of the switch the i2c salve is connected to.
register_address_size (int) Slave register address length (in bytes).
endianness (Endianness) The endianness of the slave.
should_hold_bus (bool) Should hold the bus during the read.
property name
Get the name of the I2C slave.
Returns
Name of the I2C slave.
Return type
str
property bus_index
Get bus index the I2C slave is connected to.
Returns
Index of the bus the I2C slave is connected to.
Return type
int
property slave_address
Get the address of the salve.
Returns
The address of the I2C slave.
Return type
int
property register_address_size
Get the slave register address length (in bytes). This number represents how many bytes are in the register address the slave can access.
Returns
Slave register address length.
Return type
int
Note
Pay attention to the slave endianness (Endianness).
property switch_number
Get the switch number the slave is connected to.
Returns
The number of the switch the I2C is behind.
Return type
int
Note
If NO_I2C_SWITCH is returned, it means the slave is not behind a switch.
property endianness
Get the slave endianness.
Returns
The slave endianness.
Return type
Endianness
property should_hold_bus
Returns a Boolean indicating if the bus will be held while reading from the slave.
Returns
True if the bus would be held, otherwise False.
Return type
bool
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_MIPI_AVDD
Class which represents the MIPI AVDD I2C slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_USB_AVDD_IO
Class which represents the USB AVDD IO slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_VDD_CORE
Class which represents the V_CORE slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_VDD_TOP
Class which represents the VDD TOP slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_MIPI_AVDD_H
Class which represents the MIPI AVDD_H I2C slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_USB_AVDD_IO_HV
Class which represents the DVM USB AVDD IO HV slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_VDD_IO
Class which represents the DVM_VDDIO slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_AVDD_H
Class which represents the DVM_AVDD_H slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_SDIO_VDD_IO
Class which represents the DVM_SDIO_VDDIO slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_M_DOT_2_OVERCURREN_PROTECTION
Class which represents the DVM_SDIO_VDDIO slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_I2S_CODEC
Class which represents the I2S codec I2C slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_I2C_TO_GPIO
Class which represents the I2C to gpio I2C slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_SWITCH
Class which represents the I2C switch slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_TEMP_SENSOR_0
Class which represents the I2C TEMP_sensor_0 slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_TEMP_SENSOR_1
Class which represents the I2S TEMP_sensor_1 slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_EEPROM
Class which represents the EEPROM I2C slave.
hailo_platform.pyhailort.i2c_slaves.I2C_SLAVE_RASPICAM
Class which represents the raspicam I2C slave.
hailo_platform.pyhailort.i2c_slaves.set_i2c_switch(control_object, slave, slave_switch=None)[source]
Set the I2C switch in order to perform actions from the I2C slave.
Parameters
control_object (HcpControl) Control object which communicates with the Hailo chip.
slave (I2CSlave) Slave which the switch is set for.
slave_switch (I2CSlave) The I2C slave for the switch it self. Defaults to I2C_SLAVE_SWITCH.
hailo_platform.tools.udp_rate_limiter
Tool for limiting the packet sending rate via UDP. Needed to ensure the board will not get more traffic than it can handle, which would cause packet loss.
exception hailo_platform.tools.udp_rate_limiter.RateLimiterException[source]
Bases: Exception
A problem has occurred during the rate setting.
exception hailo_platform.tools.udp_rate_limiter.BadTCParamError[source]
Bases: Exception
One of shells tc command params is wrong.
exception hailo_platform.tools.udp_rate_limiter.BadTCCallError[source]
Bases: Exception
Shells tc command has failed.
class hailo_platform.tools.udp_rate_limiter.RateLimiterWrapper(configured_network_group, fps=1, fps_factor=1.0, remote_ip=None)[source]
Bases: object
UDPRateLimiter wrapper enabling with statements.
__init__(configured_network_group, fps=1, fps_factor=1.0, remote_ip=None)[source]
RateLimiterWrapper constructor.
Parameters
configured_network_group (ConfiguredNetwork) The target network_group.
fps (int) Frame rate.
fps_factor (float) Safety factor by which to multiply the calculated UDP rate.
remote_ip (str) Device IP address.
class hailo_platform.tools.udp_rate_limiter.UDPRateLimiter(remote_ip, port, rate_kbits_per_sec=0)[source]
Bases: object
Enables limiting or removing limits on UDP communication rate to a board.
__init__(remote_ip, port, rate_kbits_per_sec=0)[source]
set_rate_limit()[source]
reset_rate_limit()[source]
static calc_udp_rate(hef, network_group_name, fps, fps_factor=1, max_supported_kbps_rate=850000.0)[source]
Calculates the proper UDP rate according to an HEF.
Parameters
hef (str) Path to an HEF file containing the network_group.
network_group_name (str) Name of the network_group to configure rates for.
fps (int) Frame rate.
fps_factor (float, optional) Safety factor by which to multiply the calculated UDP rate.
max_supported_kbps_rate (int, optional) Max supported Kbits per second. Defaults to 850 Mbit/s (850,000 Kbit/s).
Returns
Maps between each input default dport to its calculated Rate in Kbits/sec.
Return type
dict
+58
View File
@@ -0,0 +1,58 @@
<?php
include_once "../inc/config.php";
$mysqli = get_mysqli_connection();
include_once dirname(__FILE__) . "/../inc/getBasic.inc.php";
include_once dirname(__FILE__) . "/../inc/getData.inc.php";
include_once dirname(__FILE__) . "/../inc/tradeRec.inc.php";
include_once __DIR__ . "/../html/headChart.php";
$ts_code= ts_code_conv($_REQUEST['ts_code']);
$day_st = ($_REQUEST['s']=='')?'20180101':reformDate($_REQUEST['s']);
$day_end= ($_REQUEST['e']=='')?date('Ymd'):reformDate($_REQUEST['e']);
$unit = '股'; # Without a unit on PE
$data = getStockHist($ts_code,date("Ymd",strtotime($day_st)),date("Ymd",strtotime($day_end)));
//$data2 = getBasicData($ts_code,$day_st,$day_end,$item);
if($_REQUEST['t_vendor']=='方正证券') {$flg3 = '买入'; $flg4 = '卖出';}
elseif($_REQUEST['t_vendor']=='长江证券') {$flg3 = '证券买入'; $flg4 = '证券卖出';}
$trdData = trade_rec($ts_code, $day_st, $day_end,'');
$data3 = recDataSort($trdData,$flg3);
$data4 = recDataSort($trdData,$flg4);
$data3Avg = avePrice($data3['tvol'],$data3['tprice']);
$data4Avg = avePrice($data4['tvol'],$data4['tprice']);
$subtext_ext = " {$flg3}均价: {$data3Avg['avePrice']}, 量{$data3Avg['ttlVol']}";
$subtext_ext .= "-- {$flg4}均价: {$data4Avg['avePrice']}, 量{$data4Avg['ttlVol']}";
$ts_name = tscodeToName($ts_code);
$legend = array('不复权股价','交易买入','交易卖出','买入量','卖出量');
if($_REQUEST['adj']) $legend[0]='复权股价';
?>
<form name="form1" id="form1" method="post">
<input type="hidden" name="adj" id="adj" value="<?=$_REQUEST['adj'] ?>">
<input type="hidden" name="ts_code" id="ts_code" value="<?=$ts_code ?>">
<input type="hidden" name="s" id="s" value="<?=$day_st ?>">
<input type="hidden" name="e" id="e" value="<?=$day_end ?>">
</form>
<script type="text/javascript">
var legend = <?php echo json_encode($legend);?>;
var unit ='<?=$unit ?>';
var headtxt = '<?php echo $ts_name.'('.$ts_code.')'; ?>';
var subtxt = '<?=$subtext_ext ?>';
var data1 = <?php echo json_encode($data['data']); ?>;
var data2 = <?php echo json_encode($data3['data']); ?>;
var data3 = <?php echo json_encode($data4['data']); ?>;
var data4 = <?php echo json_encode($data3['data2']); ?>;
var data5 = <?php echo json_encode($data4['data2']); ?>;
console.log(data1[0]['value'][0]);
console.log(data1[0]['value'][1]);
</script>
<script type="text/javascript" src="../js/adj.ajax.js?verion=3.14"></script>
<script>
console.log(data1[0]['value'][0]);
console.log(data1[0]['value'][1]);
</script>
<script type="text/javascript" src="../js/chartStDetail.js?version=3.16"></script>
</body>
</html>
+86
View File
@@ -0,0 +1,86 @@
<?php
require_once "../inc/functions.inc.php";
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2023-08-15';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$_REQUEST['district']=$_REQUEST['district']?$_REQUEST['district']:'合计';
$subTitle=($_REQUEST['district']=='合计')?'宁波地区':$_REQUEST['district'];
$title="二手房每日新增挂牌量({$subTitle})";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
区域:
<?php districtList(); ?>&nbsp;&nbsp;
开始时间: <input type='date' name='t_start' id='t_start' width='30px' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' >
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div >&nbsp;</div>
<div style="margin:0 auto;width: 1000px ">
<span style="color:grey">
* 数据来源:<a href='https://www.cnnbfdc.com/' target='_blank'>宁波市房产交易服务信息网</a><br />
* 更新时间: 每天下午5:30</span></div>
<script>
var dataSel1 = ['td','price'];
var dataSel2 = ['td','qty'];
var legend = ['挂牌均价','挂牌数量'];
$(document).ready(function() {
$("#district").val('<?=$_REQUEST['district']?>');
$("#t_start").val('<?=$_REQUEST['t_start']?>');
$("#t_end").val('<?=$_REQUEST['t_end']?>');
loadChartData();
$('#submitBtn').click(function(e) { e.preventDefault(); loadChartData(); });
});
function loadChartData() {
$('#loadingOverlay').addClass('active');
var district = $('#district').val();
var t_start = $('#t_start').val();
var t_end = $('#t_end').val();
var url = "../inc/ajax.inc.php?t=esfListDaily&district="+district+"&t_start="+t_start+"&t_end="+t_end+"&dm=Daily";
fetch(url)
.then(function(r) { return r.json(); })
.then(function(resp) {
var d = resp.data;
var data1 = getRows(d.datas, dataSel1);
var data2 = getRows(d.datas, dataSel2);
var dom = document.getElementById("container");
var myChart = echarts.init(dom, 'dark');
var option = {
title: { text: '<?=$title?>', textAlign:'center', left:'50%' },
tooltip: { trigger: 'axis' },
legend: { data: legend, right:'20' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
toolbox: { feature: { saveAsImage: {} } },
xAxis: { type: 'time', boundaryGap: false },
yAxis: [
{ type: 'value', name: legend[0], show: true },
{ type: 'value', name: legend[1], show: true, boundaryGap: false, splitLine: { show: false } }
],
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ start: 0, end: 100, handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 } }
],
series: [
{ name: legend[0], type: 'line', yAxisIndex: 0, symbol: 'none', data: data1, itemStyle: { normal: { label: { show: true } } } },
{ name: legend[1], type: 'bar', yAxisIndex: 1, symbol: 'none', data: data2, itemStyle: { normal: { label: { show: true } } } }
]
};
myChart.setOption(option, true);
})
.catch(function(error) { console.error('数据加载失败:', error); })
.finally(function() { $('#loadingOverlay').removeClass('active'); });
}
</script>
<?php include_once "../html/footer.php"; ?>
+151
View File
@@ -0,0 +1,151 @@
<?php
require_once "../inc/functions.inc.php";
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2023-08-15';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$_REQUEST['mst']=$_REQUEST['mst']?$_REQUEST['mst']:'2023-08';
$_REQUEST['med']=$_REQUEST['med']?$_REQUEST['med']:date('Y-m');
$_REQUEST['dm']=$_REQUEST['dm']?$_REQUEST['dm']:'Daily';
$_REQUEST['district']=$_REQUEST['district']?$_REQUEST['district']:'合计';
$subTitle=($_REQUEST['district']=='合计')?'宁波地区':$_REQUEST['district'];
$title1="新房每日成交量({$subTitle})";
$title2="二手房每日成交量({$subTitle})";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
区域:
<?php districtList(); ?>&nbsp;&nbsp;
Daily/Monthly:
<?php byDM('dm','dblock','mblock'); ?> &nbsp;&nbsp;
<span style="display:inline;" id='dblock'>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' >
</span>
<span style="display:None;" id='mblock'>
开始月份: <input type="month" name='mst' id='mst' >&nbsp;&nbsp;
结束月份: <input type="month" name='med' id='med' >
</span>
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay1">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div >&nbsp;</div>
<div id="container2" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay2">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div >&nbsp;</div>
<div style="margin:0 auto;width: 1000px ">
<span style="color:grey">
* 数据来源:<a href='https://www.cnnbfdc.com/' target='_blank'>宁波市房产交易服务信息网</a><br />
* 更新时间: 每天下午5:30</span></div>
<script>
var dataSel1 = ['td','area'];
var dataSel2 = ['td','qty'];
var legend = ['成交面积','成交套数','可售套数'];
var legend2 = ['成交面积','成交套数'];
$(document).ready(function() {
$("#district").val('<?=$_REQUEST['district']?>');
$("#t_start").val('<?=$_REQUEST['t_start']?>');
$("#t_end").val('<?=$_REQUEST['t_end']?>');
$("#mst").val('<?=$_REQUEST['mst']?>');
$("#med").val('<?=$_REQUEST['med']?>');
$("#dm").val('<?=$_REQUEST['dm']?>');
var vdm = $('#dm').val();
if(vdm=='Monthly'){ $('#dblock').css('display','none'); $('#mblock').css('display','inline'); }
if(vdm=='Daily'){ $('#dblock').css('display','inline'); $('#mblock').css('display','none'); }
loadChartData();
$('#submitBtn').click(function(e) { e.preventDefault(); loadChartData(); });
});
function loadChartData() {
$('#loadingOverlay1').addClass('active');
$('#loadingOverlay2').addClass('active');
var district = $('#district').val();
var dm = $('#dm').val();
var url1 = "../inc/ajax.inc.php?t=newTBD&district="+district+"&dm="+dm;
var url2 = "../inc/ajax.inc.php?t=esfTBD&district="+district+"&dm="+dm;
if(dm=='Daily') {
url1 += "&t_start="+$('#t_start').val()+"&t_end="+$('#t_end').val();
url2 += "&t_start="+$('#t_start').val()+"&t_end="+$('#t_end').val();
}
if(dm=='Monthly') {
url1 += "&t_start="+$('#mst').val()+"&t_end="+$('#med').val();
url2 += "&t_start="+$('#mst').val()+"&t_end="+$('#med').val();
}
Promise.all([fetch(url1), fetch(url2)])
.then(function(responses) { return Promise.all(responses.map(function(r) { return r.json(); })); })
.then(function(results) {
// Chart 1: 新房
var d1 = results[0].data;
var data1 = getRows(d1.datas, dataSel1);
var data2 = getRows(d1.datas, dataSel2);
var data3 = getRows(d1.dataExt, dataSel2);
var dom1 = document.getElementById("container");
var chart1 = echarts.init(dom1, 'dark');
chart1.setOption({
title: { text: '<?=$title1?>', textAlign:'center', left:'50%' },
tooltip: { trigger: 'axis' },
legend: { data: legend, right:'20' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
toolbox: { feature: { saveAsImage: {} } },
xAxis: { type: 'time', boundaryGap: false },
yAxis: [
{ type: 'value', name: legend[2], show: true },
{ type: 'value', name: legend[1], show: true, boundaryGap: false, splitLine: { show: false } }
],
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ start: 0, end: 100, handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 } }
],
series: [
{ name: legend[2], type: 'line', yAxisIndex: 0, symbol: 'none', data: data3, label: { show: true, position: 'top' } },
{ name: legend[1], type: 'bar', yAxisIndex: 1, symbol: 'none', data: data2, label: { show: true } }
]
}, true);
$('#loadingOverlay1').removeClass('active');
// Chart 2: 二手房
var d2 = results[1].data;
var data4 = getRows(d2.dataTrade, dataSel1);
var data5 = getRows(d2.dataTrade, dataSel2);
var dom2 = document.getElementById("container2");
var chart2 = echarts.init(dom2, 'dark');
chart2.setOption({
title: { text: '<?=$title2?>', textAlign:'center', left:'50%' },
tooltip: { trigger: 'axis' },
legend: { data: legend2, right:'20' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
toolbox: { feature: { saveAsImage: {} } },
xAxis: { type: 'time', boundaryGap: false },
yAxis: [
{ type: 'value', name: legend2[0], show: true },
{ type: 'value', name: legend2[1], show: true, boundaryGap: false, splitLine: { show: false } }
],
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ start: 0, end: 100, handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 } }
],
series: [
{ name: legend2[0], type: 'line', yAxisIndex: 0, symbol: 'none', data: data4, itemStyle: { normal: { label: { show: true } } } },
{ name: legend2[1], type: 'bar', yAxisIndex: 1, symbol: 'none', data: data5, itemStyle: { normal: { label: { show: true } } } }
]
}, true);
$('#loadingOverlay2').removeClass('active');
})
.catch(function(error) { console.error('数据加载失败:', error); $('#loadingOverlay1').removeClass('active'); $('#loadingOverlay2').removeClass('active'); });
}
</script>
<?php include_once "../html/footer.php"; ?>
+107
View File
@@ -0,0 +1,107 @@
<?php
require_once "../inc/functions.inc.php";
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2023-08-15';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$_REQUEST['mst']=$_REQUEST['mst']?$_REQUEST['mst']:'2023-08';
$_REQUEST['med']=$_REQUEST['med']?$_REQUEST['med']:date('Y-m');
$_REQUEST['dm']=$_REQUEST['dm']?$_REQUEST['dm']:'Daily';
$_REQUEST['district']=$_REQUEST['district']?$_REQUEST['district']:'合计';
$subTitle=($_REQUEST['district']=='合计')?'宁波地区':$_REQUEST['district'];
$title="二手房每日成交量({$subTitle})";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
区域:
<?php districtList(); ?>&nbsp;&nbsp;
Daily/Monthly:
<?php byDM('dm','dblock','mblock'); ?> &nbsp;&nbsp;
<span style="display:inline;" id='dblock'>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' >
</span>
<span style="display:None;" id='mblock'>
开始月份: <input type="month" name='mst' id='mst' >&nbsp;&nbsp;
结束月份: <input type="month" name='med' id='med' >
</span>
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div >&nbsp;</div>
<div style="margin:0 auto;width: 1000px ">
<span style="color:grey">
* 数据来源:<a href='https://www.cnnbfdc.com/' target='_blank'>宁波市房产交易服务信息网</a><br />
* 更新时间: 每天下午5:30</span></div>
<script>
var dataSel1 = ['td','qty'];
var dataSel2 = ['td','area'];
var legend = ['成交套数','成交面积','挂牌套数'];
$(document).ready(function() {
$("#district").val('<?=$_REQUEST['district']?>');
$("#t_start").val('<?=$_REQUEST['t_start']?>');
$("#t_end").val('<?=$_REQUEST['t_end']?>');
$("#mst").val('<?=$_REQUEST['mst']?>');
$("#med").val('<?=$_REQUEST['med']?>');
$("#dm").val('<?=$_REQUEST['dm']?>');
var vdm = $('#dm').val();
if(vdm=='Monthly'){ $('#dblock').css('display','none'); $('#mblock').css('display','inline'); }
if(vdm=='Daily'){ $('#dblock').css('display','inline'); $('#mblock').css('display','none'); }
loadChartData();
$('#submitBtn').click(function(e) { e.preventDefault(); loadChartData(); });
});
function loadChartData() {
$('#loadingOverlay').addClass('active');
var district = $('#district').val();
var dm = $('#dm').val();
var url = "../inc/ajax.inc.php?t=esfTBD&district="+district+"&dm="+dm;
if(dm=='Daily') url += "&t_start="+$('#t_start').val()+"&t_end="+$('#t_end').val();
if(dm=='Monthly') url += "&t_start="+$('#mst').val()+"&t_end="+$('#med').val();
fetch(url)
.then(function(r) { return r.json(); })
.then(function(resp) {
var d = resp.data;
var data1 = getRows(d.dataList, dataSel1);
var data2 = getRows(d.dataTrade, dataSel2);
var data3 = getRows(d.dataTrade, dataSel1);
var dom = document.getElementById("container");
var myChart = echarts.init(dom, 'dark');
var option = {
title: { text: '<?=$title?>', textAlign:'center', left:'50%' },
tooltip: { trigger: 'axis' },
legend: { data: legend, right:'20' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
toolbox: { feature: { saveAsImage: {} } },
xAxis: { type: 'time', boundaryGap: false },
yAxis: [
{ type: 'value', name: legend[2], show: true },
{ type: 'value', name: legend[0], show: true },
{ type: 'value', name: legend[1], show: true, boundaryGap: false, splitLine: { show: false } }
],
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ start: 0, end: 100, handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 } }
],
series: [
{ name: legend[2], type: 'bar', yAxisIndex: 0, symbol: 'none', data: data1, itemStyle: { normal: { label: { show: true } } } },
{ name: legend[0], type: 'bar', yAxisIndex: 0, symbol: 'none', data: data3, itemStyle: { normal: { label: { show: true } } } },
{ name: legend[1], type: 'line', yAxisIndex: 1, symbol: 'none', data: data2, itemStyle: { normal: { label: { show: true } } } }
]
};
myChart.setOption(option, true);
})
.catch(function(error) { console.error('数据加载失败:', error); })
.finally(function() { $('#loadingOverlay').removeClass('active'); });
}
</script>
<?php include_once "../html/footer.php"; ?>
+103
View File
@@ -0,0 +1,103 @@
<?php
include_once "../inc/getBasic.inc.php";
include_once "../inc/getData.inc.php";
include_once "../inc/postJson.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['tp']=$_REQUEST['tp']?$_REQUEST['tp']:'ratio';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-06-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS北向资金持股:".$ts_name.'('.$_REQUEST['ts_code'].')';
$unit = '';
$data = getStockHist(ts_code_conv($_REQUEST['ts_code']),$_REQUEST['t_start'],$_REQUEST['t_end']);
$getData = getHKHoldByCode();
$data2 = hkHoldReform($getData,$_REQUEST['tp']);
#var_dump($data2['data']);
$subtext_ext = "Max: ".$data2['data_max'];
$subtext_ext .= ", Min: ".$data2['data_min'];
$subtext_ext .= ", Average: ".$data2['data_avg'];
$subtext_ext .= ", Recent: ".$data2['data_last'];
$legend=array('不复权股价',hkholdConv($_REQUEST['tp']));
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get">
<div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
数据选择:
<select name="tp" id="tp">
<option value="ratio">持股比例(%)</option>
<option value="vol">持股数(万)</option>
</select>
<script>
$("#tp").val('<?=$_REQUEST['tp']?>');
</script>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="margin:0 auto;height: 400px;width: 1000px"></div>
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
<script type="text/javascript">
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let ts_code = $("#ts_code").val();
url = "https://api.doorcome.cn/api/stockbasic/?tscode="+ts_code;
url += "&start_date="+t_start+"&end_date="+t_end;
url1 = "https://api.doorcome.cn/api/stockmargin/?tscode="+ts_code;
url1 += "&start_date="+t_start+"&end_date="+t_end;
url2 = "https://api.doorcome.cn/api/stockinfo/?tscode="+ts_code;
Promise.all([
fetch(url),
fetch(url1),
fetch(url2)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([dailyData,hkData,stockInfo]) => {
// 图表配置:pe_ttm
let codeName = stockInfo[0].name;
var params = {};
params.chartid='container';
params.legend = ['不复权股价','北向资金(%)'];
params.text = codeName+'('+ts_code+')';
params.data1 = pickData(dailyData, 'trade_date', 'close');
params.data2 = pickData(margindData, 'trade_date', 'rzrqye');
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 /10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "TTM PE Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
}
);
}
</script>
<script type="text/javascript" src="../js/hkhold.js?version=3.14"></script>
<?php include_once "../html/footer.php"; ?>
+101
View File
@@ -0,0 +1,101 @@
<?php
include_once("../inc/functions.inc.php");
$_REQUEST['code']=$_REQUEST['code']?$_REQUEST['code']:'000001.SH';
$_REQUEST['se']=$_REQUEST['se']?$_REQUEST['se']:'SSE';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2020-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$title="指数VS融资融券余额";
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指数代码: <?php indexList('code'); ?>&nbsp;
融资融券交易所: <?php seList('se'); ?>&nbsp;
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
</div> </form>
<div >&nbsp;</div>
<!-- 图表容器 -->
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 设置默认值
$('#code').val('<?= $_REQUEST['code'] ?>');
$('#se').val('<?= $_REQUEST['se'] ?>');
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
e.preventDefault(); // 阻止表单提交刷新页面
loadChartData();
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let code = $("#code").val();
let se = $("#se").val();
let codeName=convertIndexCode(code);
url = "https://api.doorcome.cn/api/indexDatas/?tscode="+code;
url += "&start_date="+t_start+"&end_date="+t_end;
url1 = "https://api.doorcome.cn/api/dailymargin/?exchange_id="+se;
url1 += "&start_date="+t_start+"&end_date="+t_end;
Promise.all([
fetch(url),
fetch(url1)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([indexData,seData]) => {
let dataMain=pickData(indexData, 'trade_date', 'close');
let marginData=pickData(seData, 'trade_date', 'rzrqye');
// 图表配置:total_mv
params = {};
params.chartid='container';
params.legend = [codeName,'融资融券余额-亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = dataMain;
params.data2 = marginData;
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 / 10000 ).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "融资融券余额 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
</script>
<?php include_once("../html/footer.php"); ?>
+155
View File
@@ -0,0 +1,155 @@
<?php
include_once("../inc/functions.inc.php");
$_REQUEST['code']=$_REQUEST['code']?$_REQUEST['code']:'000001.SH';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$title="指数VS两市总市值趋势";
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指数代码: <?php indexList('code'); ?>
&nbsp;
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
<input type='checkbox' id='cb_total_mv' onclick="hideSwitch(this.id,'total_mv')" checked > 两市总市值
<input type='checkbox' id='cb_circ_mv' onclick="hideSwitch(this.id,'circ_mv')" checked> 两市流通市值
</div> </form>
<div >&nbsp;</div>
<!-- 图表容器 -->
<div id="container" style="width: 1000px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
<div id="total_mv" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="float_mv" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 设置默认值
$('#code').val('<?= $_REQUEST['code'] ?>');
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
e.preventDefault(); // 阻止表单提交刷新页面
loadChartData();
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let code = $("#code").val();
let codeName=convertIndexCode(code);
url = "https://api.doorcome.cn/api/indexDatas/?tscode="+code;
url += "&start_date="+t_start+"&end_date="+t_end;
url1 = "https://api.doorcome.cn/api/indexDatas/?tscode=000001.SH";
url1 += "&start_date="+t_start+"&end_date="+t_end;
url2 = "https://api.doorcome.cn/api/indexDatas/?tscode=399001.SZ";
url2 += "&start_date="+t_start+"&end_date="+t_end;
Promise.all([
fetch(url),
fetch(url1),
fetch(url2)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([searchData,SHData,SZData]) => {
let dataMain=pickData(searchData, 'trade_date', 'close');
let totalMVSH=pickData(SHData, 'trade_date', 'total_mv');
let floatMVSH=pickData(SHData, 'trade_date', 'float_mv');
let totalMVSZ=pickData(SZData, 'trade_date', 'total_mv');
let floatMVSZ=pickData(SZData, 'trade_date', 'float_mv');
let data_TotalMV=mergeAndSumArrays(totalMVSH,totalMVSZ);
let data_folatMV=mergeAndSumArrays(floatMVSH,floatMVSZ);
// 图表配置:total_mv
params = {};
params.chartid='total_mv';
params.legend = [codeName,'总市值-万亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = dataMain;
params.data2 = data_TotalMV;
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 / 10000 / 10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "总市值 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:float_mv
params = {};
params.chartid='float_mv';
params.legend = [codeName,'流通市值-万亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = dataMain;
params.data2 = data_folatMV;
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 / 10000 / 10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "流通市值 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
// 函数:合并两个数组,日期相同则数字相加
function mergeAndSumArrays(arr1, arr2) {
// 创建一个 Map 来存储日期和对应的数字总和
const resultMap = new Map();
// 处理第一个数组
arr1.forEach(item => {
const [date, value] = item.value;
resultMap.set(date, (resultMap.get(date) || 0) + parseFloat(value));
});
// 处理第二个数组
arr2.forEach(item => {
const [date, value] = item.value;
resultMap.set(date, (resultMap.get(date) || 0) + parseFloat(value));
});
// 将 Map 转换为数组格式
const resultArray = Array.from(resultMap, ([date, totalValue]) => ({
value: [date, totalValue]
}));
return resultArray;
}
</script>
<?php include_once("../html/footer.php"); ?>
+156
View File
@@ -0,0 +1,156 @@
<?php
/*
* @Author: 杨水淼 yangshuimiao@jsjd.cc
* @Date: 2025-07-08 08:16:01
* @LastEditors: Simon failsafe@163.com
* @LastEditTime: 2025-07-13 11:02:35
* @FilePath: \echarts\index_trend.php
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
include_once("../inc/functions.inc.php");
$title="指数VS PE/PB/PS/市值 趋势";
include_once "../html/head.php";
$_REQUEST['code'] = $_REQUEST['code']?$_REQUEST['code']:'000001.SH';
$_REQUEST['t_start']= $_REQUEST['t_start']?$_REQUEST['t_start']:'2020-01-01';
$_REQUEST['t_end'] = $_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$ts_code = $_REQUEST['code'];
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指数代码:
<?php indexList('code'); ?>&nbsp;
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
<input type='checkbox' id='cb_pe' onclick="hideSwitch(this.id,'pe_ttm')" checked> PE_TTM 市盈率
<input type='checkbox' id='cb_pb' onclick="hideSwitch(this.id,'pb')" checked> PB 市净率
<input type='checkbox' id='cb_total_mv' onclick="hideSwitch(this.id,'total_mv')" checked> 总市值
<input type='checkbox' id='cb_float_mv' onclick="hideSwitch(this.id,'float_mv')" checked> 流通市值
</div> </form>
<div >&nbsp;</div>
<!-- 图表容器 -->
<div id="container" style="width: 1000px; margin: 0 auto 20px;">
<div style="position: relative; height: 10px;"></div>
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div id="pe_ttm" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="pb" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="total_mv" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="float_mv" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 设置默认值
$('#code').val('<?= $_REQUEST['code'] ?>');
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
e.preventDefault(); // 阻止表单提交刷新页面
loadChartData();
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let code = $("#code").val();
let codeName=convertIndexCode(code);
url = "https://api.doorcome.cn/api/indexDatas/?tscode="+code;
url += "&start_date="+t_start+"&end_date="+t_end;
fetch(url)
.then(httpresponse => httpresponse.json())
.then(parsedData => {
// 图表配置:pe_ttm
var params = {};
params.chartid='pe_ttm';
params.legend = [codeName,'pe_ttm'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'pe_ttm');
dataCal = calculateStats(params.data2);
params.sub_text = "TTM PE Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:pb
params = {};
params.chartid='pb';
params.legend = [codeName,'pb'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'pb');
dataCal = calculateStats(params.data2);
params.sub_text = "PB Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:total_mv
params = {};
params.chartid='total_mv';
params.legend = [codeName,'总市值-万亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'total_mv');
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 / 10000 / 10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "总市值 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:float_mv
params = {};
params.chartid='float_mv';
params.legend = [codeName,'流通市值-万亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'float_mv');
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 / 10000 / 10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "流通市值 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
</script>
<?php include_once "../html/footer.php"; ?>
+97
View File
@@ -0,0 +1,97 @@
<?php
include_once "../inc/functions.inc.php";
$_REQUEST['code']=$_REQUEST['code']?$_REQUEST['code']:'sh';
$_REQUEST['hsgt']=$_REQUEST['hsgt']?$_REQUEST['hsgt']:'north_money';
$_REQUEST['stacked']=$_REQUEST['stacked']?$_REQUEST['stacked']:'1';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-06-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$title="股指VS沪深港通资金流向";
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指数代码:
<select name='code' id='code'>
<option value='sh'>上证指数</option>
<option value='sz'>深圳成指</option>
<option value='zx'>中小板指</option>
<option value='cy'>创业板指</option>
</select>&nbsp;
资金选择:
<select name="hsgt" id="hsgt">
<option value="ggt_ss">港股通(上海)</option>
<option value="ggt_sz">港股通(深圳)</option>
<option value="hgt">沪股通</option>
<option value="sgt">深股通</option>
<option value="north_money">北向资金</option>
<option value="south_money">南向资金</option>
</select>&nbsp;
数据累积:
<select name="stacked" id="stacked">
<option value="-1">每日值</option>
<option value="1">累积值</option>
</select>&nbsp;
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<script>
$(document).ready(function() {
$('#code').val('<?= $_REQUEST['code'] ?>');
$('#hsgt').val('<?= $_REQUEST['hsgt'] ?>');
$('#stacked').val('<?= $_REQUEST['stacked'] ?>');
loadChartData();
$('#submitBtn').click(function(e) {
e.preventDefault();
loadChartData();
});
});
function loadChartData() {
$('#loadingOverlay').addClass('active');
var t_start = $('#t_start').val();
var t_end = $('#t_end').val();
var code = $('#code').val();
var hsgt = $('#hsgt').val();
var stacked = $('#stacked').val();
var codeName = $('#code option:selected').text();
var hsgtName = $('#hsgt option:selected').text();
var url = "../inc/ajax.inc.php?t=moneyflowData&code="+code+"&hsgt="+hsgt+"&stacked="+stacked+"&t_start="+t_start+"&t_end="+t_end;
fetch(url)
.then(function(r) { return r.json(); })
.then(function(resp) {
var d = resp.data;
var indexData = d.indexData;
var flowData = d.flowData;
var params = {};
params.chartid = 'container';
params.legend = [codeName, hsgtName+'-亿元'];
params.text = params.legend[0] + ' V.S ' + params.legend[1];
params.data1 = indexData;
params.data2 = flowData;
var dataCal = calculateStats(flowData);
params.sub_text = hsgtName + " Max:" + dataCal.max;
params.sub_text += ", Min:" + dataCal.min;
params.sub_text += ", Average:" + dataCal.avg;
params.sub_text += ", Recent:" + dataCal.last;
doubleLineChart(params);
})
.catch(function(error) { console.error('数据加载失败:', error); })
.finally(function() {
$('#loadingOverlay').removeClass('active');
});
}
</script>
<?php include_once "../html/footer.php"; ?>
+32
View File
@@ -0,0 +1,32 @@
<?php
ini_set("display_errors","1");
include_once "../inc/config.php";
//ini_set('error_reporting', 'E_ALL'); //wrong way to open error_reporting
//ini_set("error_reporting","32759"); //Right way to set error_reporting
$mysqli = get_mysqli_connection();
include_once __DIR__ . "/../inc/excelOperate.inc.php";
include_once __DIR__ . "/../inc/tradeRec.inc.php";
$file = $_REQUEST['fpath'];
$company = $_REQUEST['up_vendor'];
$msg = array();
/*
echo json_encode(array(
"status" => "2",
"fpath"=> $file,
'company'=> $_REQUEST['up_vendor'],
"msg" => "upload sucessful!",
));
*/
$data = readMyExcel($file);
$msg[] = addslashes("Finished excel read! <br />");
$msg_op = dbOp($data, $company);
if($msg_op == false) exit(); //if return false, function dbOp() will echo massage to ajax
$msg = array_merge($msg,$msg_op);
echo json_encode(array(
"status" => "1",
"fpath"=> $file,
'company'=> $_REQUEST['up_vendor'],
"msg" => $msg,
));
?>
+231
View File
@@ -0,0 +1,231 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>投资资讯日报</title>
<script src="/lib/js/tailwindcss-3.4.17.js"></script>
<script type="text/javascript" src="/lib/js/jquery-3.6.0.min.js"></script>
<link href="/lib/css/fontawesome-6.4.all.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36D399',
neutral: '#F8FAFC',
dark: '#1E293B'
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer components {
.badge {
@apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold whitespace-nowrap;
}
.badge-finance { @apply bg-blue-100 text-blue-700; }
.badge-intl { @apply bg-violet-100 text-violet-700; }
.badge-pos { @apply bg-emerald-100 text-emerald-700; }
.badge-neg { @apply bg-red-100 text-red-700; }
.badge-neu { @apply bg-gray-200 text-gray-600; }
.type-tab, .view-tab {
@apply px-4 py-2 rounded-lg text-sm font-medium text-gray-500 hover:text-primary hover:bg-primary/5 transition-colors cursor-pointer;
}
.tab-active { @apply bg-primary text-white hover:text-white hover:bg-primary shadow-sm; }
.btn-view {
@apply inline-flex items-center px-3 py-1.5 rounded-lg text-xs font-semibold text-primary bg-primary/10 hover:bg-primary hover:text-white transition-colors whitespace-nowrap;
}
.report-card {
@apply bg-white rounded-xl shadow-sm border border-gray-100 p-5 hover:shadow-md hover:border-primary/30 transition-all cursor-pointer;
}
.stat-bit {
@apply inline-flex items-center gap-1 px-2 py-1 rounded-md bg-gray-50 border border-gray-100 text-xs text-gray-500;
}
.module-card {
@apply bg-white rounded-xl shadow-sm border border-gray-100 p-5 md:p-6 mb-6;
}
.module-title {
@apply flex items-center gap-2 text-xl font-bold text-dark mb-4;
}
.module-sub { @apply ml-2 text-sm font-normal text-gray-400; }
.ai-summary-list {
@apply space-y-2.5 text-base leading-relaxed text-gray-700;
}
.ai-summary-list li {
@apply pl-4 relative;
}
.ai-summary-list li::before {
content: "";
@apply absolute left-0 text-primary;
}
.event-row { @apply flex gap-3 py-3.5 px-2 hover:bg-gray-50 transition-colors rounded-lg; }
.event-left { @apply flex flex-col items-center gap-1 pt-0.5 shrink-0 w-9; }
.event-rank { @apply text-sm text-gray-400 font-mono; }
.event-body { @apply flex-1 min-w-0; }
.event-title-line { @apply flex items-start gap-2.5; }
.imp-badge { @apply shrink-0 mt-0.5 inline-flex items-center justify-center w-7 h-7 rounded-md text-sm font-bold bg-gray-100 text-gray-500; }
.imp-5 { @apply bg-red-100 text-red-700; }
.imp-4 { @apply bg-orange-100 text-orange-600; }
.event-title { @apply text-base font-medium text-gray-800 leading-snug; }
.event-link { @apply text-gray-800 hover:text-primary transition-colors; }
.event-summary { @apply mt-1.5 text-sm text-gray-500 leading-relaxed line-clamp-3; }
.event-meta { @apply mt-2.5 flex flex-wrap gap-x-4 gap-y-1 text-sm text-gray-400; }
.meta-item { @apply inline-flex items-center; }
.stats-grid { @apply grid grid-cols-3 md:grid-cols-6 gap-3 mb-4; }
.stat-card {
@apply bg-gray-50 border border-gray-100 rounded-xl p-3 text-center;
}
.stat-num { @apply text-2xl font-bold text-dark; }
.stat-label { @apply mt-1.5 text-sm text-gray-500; }
.stats-sub { @apply grid grid-cols-2 md:grid-cols-5 gap-3 mb-3; }
.stats-sub-title { @apply text-base font-semibold text-gray-600 mt-2 mb-2; }
.kv-table-wrap { @apply mb-4; }
.kv-title { @apply text-base font-semibold text-gray-600 mb-1.5; }
.kv-table { @apply w-full text-base border-collapse; }
.kv-table th { @apply text-left text-sm font-semibold text-gray-500 bg-gray-50 px-3 py-2 border border-gray-100; }
.kv-table td { @apply px-3 py-2 border border-gray-100 text-gray-700; }
.sentiment-wrap { @apply mb-4; }
.sentiment-bar { @apply flex h-4 rounded-full overflow-hidden mb-2; }
.s-pos { @apply bg-emerald-500; }
.s-neg { @apply bg-red-500; }
.s-neu { @apply bg-gray-400; }
.sentiment-legend { @apply flex flex-wrap gap-4 text-xs text-gray-500; }
.s-dot { @apply inline-block w-2.5 h-2.5 rounded-full mr-1; }
.s-dot.s-pos { @apply bg-emerald-500; }
.s-dot.s-neg { @apply bg-red-500; }
.s-dot.s-neu { @apply bg-gray-400; }
.source-grid { @apply grid grid-cols-3 md:grid-cols-6 gap-3; }
.source-item { @apply bg-gray-50 border border-gray-100 rounded-lg p-2.5 text-center; }
.s-count { @apply text-xl font-bold text-dark; }
.s-name { @apply mt-1 text-sm text-gray-500 truncate; }
.empty-box {
@apply bg-white rounded-xl shadow-sm border border-gray-100 py-16 text-center text-gray-400;
}
.empty-box i { @apply text-4xl mb-3 block; }
.empty-box p { @apply text-sm; }
.filter-input {
@apply px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary/50;
}
.btn-primary {
@apply inline-flex items-center px-4 py-2 bg-primary text-white rounded-lg hover:bg-blue-600 transition-colors text-sm font-medium;
}
}
</style>
</head>
<body class="bg-gray-50 font-inter text-dark min-h-screen">
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa-solid fa-newspaper text-primary text-2xl"></i>
<h1 class="text-xl font-bold">投资资讯日报</h1>
<span class="text-xs text-gray-400 hidden md:inline ml-1">国内 / 国际 · AI 深度研究日报</span>
</div>
<a href="/index-2.php" class="inline-flex items-center text-sm text-gray-500 hover:text-primary transition-colors">
<i class="fa-solid fa-house mr-1"></i>返回门户
</a>
</div>
</header>
<main class="container mx-auto px-4 py-6 max-w-5xl">
<!-- 筛选栏 -->
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-4 mb-6">
<div class="flex flex-wrap items-center gap-3">
<div class="flex bg-gray-100 rounded-lg p-1">
<span class="view-tab tab-active" data-view="list">日报列表</span>
<span class="view-tab" data-view="events">重要事件</span>
</div>
<div class="flex bg-gray-100 rounded-lg p-1">
<span class="type-tab tab-active" data-type="">全部</span>
<span class="type-tab" data-type="finance">国内</span>
<span class="type-tab" data-type="intl">国际</span>
</div>
<div class="flex items-center gap-2 ml-auto flex-wrap">
<label class="text-sm text-gray-500">开始</label>
<input type="date" id="startDate" class="filter-input">
<label class="text-sm text-gray-500">结束</label>
<input type="date" id="endDate" class="filter-input">
<button id="btnQuery" class="btn-primary"><i class="fa-solid fa-magnifying-glass mr-1"></i>查询</button>
</div>
</div>
<div class="mt-3 text-sm text-gray-400" id="rangeInfo"></div>
</div>
<!-- 列表视图 -->
<div id="listView">
<div id="reportList" class="space-y-4"></div>
</div>
<!-- 重要事件聚合视图 -->
<div id="eventsView" class="hidden">
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-4 mb-4">
<div class="flex flex-wrap items-center gap-3">
<span class="text-sm text-gray-500"></span>
<select id="evDays" class="filter-input">
<option value="7" selected>7</option>
<option value="14">14</option>
<option value="30">30</option>
</select>
<span class="text-sm text-gray-500"> · 重要度 </span>
<select id="evImportance" class="filter-input">
<option value="4" selected>4</option>
<option value="5">5</option>
<option value="3">3</option>
</select>
<span class="text-sm text-gray-500">类型</span>
<select id="evType" class="filter-input">
<option value="">全部</option>
<option value="finance">国内</option>
<option value="intl">国际</option>
</select>
<button id="btnEvQuery" class="btn-primary"><i class="fa-solid fa-magnifying-glass mr-1"></i>查询</button>
</div>
<div class="mt-3 text-sm text-gray-400" id="eventsInfo"></div>
</div>
<div id="eventsList"></div>
</div>
<!-- 详情视图 -->
<div id="detailView" class="hidden">
<div class="flex items-center justify-between mb-4 flex-wrap gap-2">
<button id="btnBack" class="inline-flex items-center text-sm text-gray-500 hover:text-primary transition-colors">
<i class="fa-solid fa-arrow-left mr-1"></i>返回列表
</button>
<div id="detailHeader" class="flex items-center gap-3 flex-wrap"></div>
</div>
<div id="detailContent"></div>
</div>
<!-- 加载遮罩 -->
<div id="loadingOverlay" class="hidden fixed inset-0 bg-white/70 backdrop-blur-sm z-40 flex items-center justify-center">
<div class="text-center">
<div class="inline-block w-10 h-10 border-4 border-primary border-t-transparent rounded-full animate-spin"></div>
<p class="mt-3 text-sm text-gray-500" id="loadingMsg">加载中...</p>
</div>
</div>
</main>
<footer class="text-center text-gray-400 text-sm py-6">
数据来源: api.doorcome.cn 日报接口 · 仅供个人研究参考
</footer>
<script src="/js/newsReports.js?v=20260806"></script>
</body>
</html>
+76
View File
@@ -0,0 +1,76 @@
<?php
include_once "../inc/functions.inc.php";
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2023-06-20';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$title="房地产挂牌数量趋势(宁波)";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
&nbsp;&nbsp;
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="width: 1000px; height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
<div >&nbsp;</div>
<div style="margin:0 auto;width: 1000px ">
<span style="color:grey">
* 数据来源:<a href='https://www.cnnbfdc.com/' target='_blank'>宁波市房产交易服务信息网</a><br />
* 更新时间:每天上午9:00</span></div>
<script>
$(document).ready(function() {
loadChartData();
$('#submitBtn').click(function(e) {
e.preventDefault();
loadChartData();
});
});
function loadChartData() {
$('#loadingOverlay').addClass('active');
var t_start = $('#t_start').val();
var t_end = $('#t_end').val();
var url = "../inc/ajax.inc.php?t=estateData&t_start="+t_start+"&t_end="+t_end;
fetch(url)
.then(function(r) { return r.json(); })
.then(function(resp) {
var data = resp.data;
var dom = document.getElementById("container");
var myChart = echarts.init(dom, 'dark');
var option = {
title: { text: '<?=$title?>', textAlign: 'center', left: '50%' },
tooltip: { trigger: 'axis' },
legend: { data: ['挂牌数(套)'], right: '20' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
toolbox: { feature: { saveAsImage: {} } },
xAxis: { type: 'time', boundaryGap: false },
yAxis: { type: 'value', name: '挂牌数(套)', show: true, scale: true },
dataZoom: [
{ type: 'inside', start: 0, end: 100 },
{ start: 0, end: 100, handleSize: '80%', handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 } }
],
series: [{
name: '挂牌数(套)', type: 'line', symbol: 'none',
data: data,
itemStyle: { normal: { label: { show: true } } }
}]
};
myChart.setOption(option, true);
})
.catch(function(error) { console.error('数据加载失败:', error); })
.finally(function() {
$('#loadingOverlay').removeClass('active');
});
}
</script>
<?php include_once "../html/footer.php"; ?>
+208
View File
@@ -0,0 +1,208 @@
<?php
ini_set("display_errors","0");
include_once "../inc/config.php";
include_once dirname(__FILE__) . "/../inc/getBasic.inc.php";
include_once dirname(__FILE__) . "/../inc/tradeRec.inc.php";
include_once __DIR__ . "/../inc/postJson.inc.php";
//include_once dirname(__FILE__) . "/class/basic_info.class.php";
$mysqli = get_mysqli_connection();
$_REQUEST['t_vendor']=($_REQUEST['t_vendor'])?$_REQUEST['t_vendor']:'方正证券';
if($_REQUEST['ts_code']) {
$_REQUEST['t_start'] = $_REQUEST['t_start'] ? $_REQUEST['t_start'] : '2020-01-01';
$_REQUEST['t_end'] = $_REQUEST['t_end'] ? $_REQUEST['t_end'] : '';
//$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'002273';
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$_REQUEST['fitDays'] = $_REQUEST['fitDays'] ? $_REQUEST['fitDays'] : '0';
if($_REQUEST['t_vendor']=='方正证券') {$flg3 = " and flg='买入'"; $flg4 = " and flg='卖出'";}
elseif($_REQUEST['t_vendor']=='长江证券') {$flg3 = " and flg in ('证券买入','新股申购确认缴款')"; $flg4 = " and flg='证券卖出'";}
//复权操作
$trdData = trade_rec(ts_code_conv($_REQUEST['ts_code']), $_REQUEST['t_start'], $_REQUEST['t_end'], '');
if($trdData){
$data3 = trade_rec(ts_code_conv($_REQUEST['ts_code']), $_REQUEST['t_start'], $_REQUEST['t_end'], $flg3);
$data4 = trade_rec(ts_code_conv($_REQUEST['ts_code']), $_REQUEST['t_start'], $_REQUEST['t_end'], $flg4);
//复权操作
if($_REQUEST['adj']) {
$adjArr = getAdj();
$trdData = adjData($adjArr, $trdData);
$data3 = adjData($adjArr, $data3);
$data4 = adjData($adjArr, $data4);
//var_dump($trdData);
}
$lastKey = count($trdData) - 1;
$tradeSummary = tradeSummary($data3, $data4,$trdData);
if ($_REQUEST['fitDays'] == '1') {
$_REQUEST['t_start'] = dateGap($trdData[0]['tdate'], -5);
//$_REQUEST['t_end'] = dateGap($trdData[$lastKey]['tdate'], +5);
}
}
}
$title="个股交易记录:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
证券公司: <?php vendorList('t_vendor'); ?>
股票代码:<?php tradeStocksList(); ?>
复权:<select id="adj" name="adj">
<option value="0">不复权</option>
<option value="1">前复权</option>
</select>
<script>
$("#adj").val(<?=$_REQUEST['adj']?>);
</script>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<input type='submit' value=" 给我查! ">
<input type="button" id="fitBtn" value=" 匹配交易时间 " onclick="fitBtnClick();">
<input type="hidden" name='fitDays' id="fitDays" value="0">
<div >&nbsp;</div>
</div> </form>
<?php
if($_REQUEST['ts_code'] and $trdData) {
echo "<div class='div_parent'>";
$i=0;
foreach ($tradeSummary as $key=>$val){
if(fmod($i,5)==0) echo "<div class='div_cell' style='clear: both;'>".$key." : ".$val." </div>\n";
else echo "<div class='div_cell' >".$key." : ".$val." </div>\n";
$i++;
if(fmod($i,5)==0) print("<br />\n");
}
$url="https://echart.doorcome.cn/charts/chartStDetail.php?";
$url.="ts_code={$_REQUEST['ts_code']}";
$url.="&s={$_REQUEST['t_start']}&e={$_REQUEST['t_end']}";
$url.="&t_vendor={$_REQUEST['t_vendor']}";
$url.="&adj={$_REQUEST['adj']}";
echo <<<EOF
</div>
<div style="width:100%; text-align:center;margin:0 auto;">
<iframe src="{$url}
height="400px" width="1000px"></iframe>
</div>
EOF;
}
?>
<div>&nbsp;</div>
<form id="form1" name="form1" method="post" enctype="multipart/form-data">
<div style="width:100%; text-align:center;margin:0 auto;">
<input type="file" id="file" name="file">
证券公司: <?php vendorList('up_vendor'); ?>
<input type="hidden" id="fpath" name="fpath" value="">
<input type="button" id="btnUpload" value=" 上传并导入 ">
<input type="button" id="btnClearMsg" value="清除导入信息">
</div>
<div style="width:100%; text-align:center;margin:0 auto; display: none;" id="ftxt">
</div>
</form>
<script>
//if($("#fitDays").val()=="1") $("#fitBtn").val("取消交易时间匹配");
//else if($("#fitDays").val()=="0") $("#fitBtn").val("时间交易匹配");
function fitBtnClick(){
if($("#fitDays").val()=="0") $("#fitDays").val("1");
$(document).ready(function(){
$("#main").submit();
});
}
$(function (){
$("#btnClearMsg").click(function (){
console.log("clear massage button clicked");
$("#ftxt").html("");
$("#ftxt").css("display","none");
});
});
// ajax process file upload
$(function () {
$("#btnUpload").click(function () {
console.log("Upload button clicked!");
var formData = new FormData($('#form1')[0]);
$.ajax({
type: 'post',
url: "https://echart.doorcome.cn/inc/upload.php", //上传文件的请求路径必须是绝对路劲
data: formData,
cache: false,
processData: false,
contentType: false,
success:function (data) {
afterUpload(data);
},
error: function () {
alert("上传失败");
}
});
});
});
//process after file upload
function afterUpload(data){
var arr = $.parseJSON(data);
if(arr['status']!=1) {
//alert(data);
alert(arr.msg);
return false;
}
console.log("Clear file area");
$("#file").val(''); //set input(file) to null
$("#ftxt").css("display","block");
$("#ftxt").html("文件上传成功!点击下面按钮开始执行<br />"+arr['fpath']+"<br />");
$("#fpath").val(arr['fpath']);
var tmp = $("#fpath").val();
console.log("fpath value:"+tmp);
console.log("Start import data!");
// Handle excel data import; ajax
var formData = new FormData($('#form1')[0]);
$.ajax({
type: 'post',
url: "https://echart.doorcome.cn/charts/myexcel.php", //上传文件的请求路径必须是绝对路劲
data: formData,
cache: false,
processData: false,
contentType: false,
success: function (data) {
console.log("get in excel ajax!");
$("#ftxt").css("display","block");
console.log(data);
var farr = $.parseJSON(data);
//alert(data);
$("#ftxt").html(farr.msg);
},
error:function () {
alert("数据解析失败!");
}
});
}
$(function(){
$("#t_vendor").change(function (){
console.log("Trade vendor changed!");
var t_vendor=$("#t_vendor").val();
console.log("Get vendor value: "+t_vendor);
var formData = new FormData($('#main')[0]);
$.ajax({
type: 'post',
url: "https://echart.doorcome.cn/inc/ajax.inc.php?t=stockList&t_vendor="+t_vendor, //上传文件的请求路径必须是绝对路劲
data: formData,
cache: false,
processData: false,
contentType: false,
success: function (data) {
console.log("get in ajax!");
var farr = $.parseJSON(data);
$("#codeList").empty();
for(let i=0;i<farr.data.stocks.length;i++)
$("#codeList").append("<option label='"+farr.data.stocks[i]['ts_name']+"' value='"+farr.data.stocks[i]['ts_code']+"'></option>");
},
error:function () {
alert("数据解析失败!");
}
});
});
});
</script>
</div>
<?php include_once "../html/footer.php"; ?>
+145
View File
@@ -0,0 +1,145 @@
<?php
ini_set("display_errors","0");
include_once "../inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:'';
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS PE/PB/PS 趋势:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
<input type='checkbox' id='cb_pe' onclick="hideSwitch(this.id,'pe_ttm')" checked> PE_TTM 市盈率
<input type='checkbox' id='cb_pb' onclick="hideSwitch(this.id,'pb')" checked> PB 市净率
<input type='checkbox' id='cb_ps' onclick="hideSwitch(this.id,'ps')" checked> PS 市销率
<input type='checkbox' id='cb_ttmv' onclick="hideSwitch(this.id,'total_mv')" checked> 总市值
</div> </form>
<!-- 图表容器 -->
<div id="container" style="width: 1000px; margin: 0 auto 20px;">
<div style="position: relative; height: 10px;"></div>
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
<div id="pe_ttm" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="pb" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="ps" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
<div id="total_mv" style="width: 1000px; height:400px; margin: 0 auto 20px;"></div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
e.preventDefault(); // 阻止表单提交刷新页面
loadChartData();
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let ts_code = $("#ts_code").val();
url = "https://api.doorcome.cn/api/stockparam/?tscode="+ts_code;
url += "&start_date="+t_start+"&end_date="+t_end;
url2 = "https://api.doorcome.cn/api/stockinfo/?tscode="+ts_code;
Promise.all([
fetch(url),
fetch(url2)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([parsedData,stockInfo]) => {
// 图表配置:pe_ttm
let codeName = stockInfo[0].name;
var params = {};
params.chartid='pe_ttm';
params.legend = [codeName,'pe_ttm'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'pe_ttm')
dataCal = calculateStats(params.data2);
params.sub_text = "TTM PE Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:pb
params = {};
params.chartid='pb';
params.legend = [codeName,'市净率'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'pb')
dataCal = calculateStats(params.data2);
params.sub_text = "PB Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:ps
params = {};
params.chartid='ps';
params.legend = [codeName,'市销率'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'ps')
dataCal = calculateStats(params.data2);
params.sub_text = "PS Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
// 图表配置:total_mv
params = {};
params.chartid='total_mv';
params.legend = [codeName,'总市值-亿'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'total_mv')
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "总市值 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
</script>
</div>
<?php include_once "../html/footer.php"; ?>
+123
View File
@@ -0,0 +1,123 @@
<?php
include_once "../inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2020-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股息率趋势:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js?version=1.0"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
</div> </form>
<div style="margin:0 auto;clear:both;left:100px;width:1000px;height:30px;text-align:left"><span style="color:grey">股息率=100*TTM每股派息/股价。如:股息率=3表示每股派息3%</span></div>
<!-- 图表容器 -->
<div id="container" style="width: 1000px;height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
//e.preventDefault(); // 阻止表单提交刷新页面
$('#loadingOverlay').addClass('active');
loadChartData();
$('#loadingOverlay').removeClass('active');
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let ts_code = $("#ts_code").val();
url = "https://api.doorcome.cn/api/getdiv/?tscode="+ts_code;
url += "&start_date="+t_start+"&end_date="+t_end;
Promise.all([
fetch(url)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([parsedData]) => {
var params = {};
params.chartid='container';
params.legend = [ts_code,'股息率','每股股息'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'div_yield');
params.data3 = pickData(parsedData, 'trade_date', 'cash_div_tax',fixed=3);
params.data3 = params.data3.map(item => {
let value = item.value[1];
// 将字符串转为数字,并判断是否等于 0
if (parseFloat(value) === 0) {
return [item[0], null];
} else {
return item; // 非零值保持不变
}
});
console.log(params.data3);
dataCal = calculateStats(params.data2);
params.sub_text = "TTM 股息 Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
var myChart = doubleLineChart(params);
// 👇 动态添加第三条线,使用副Y轴(yAxisIndex: 1
myChart.setOption({
yAxis: [
{ // 主Y轴配置
type: 'value'
},
{ // 副Y轴配置
type: 'value',
name: '股息率/股息',
position: 'right'
}
],
series: [
// 前两个 series 保持不变(ECharts 会合并)
{}, // 占位:对应第一个 series
{}, // 占位:对应第二个 series
{
name: '每股股息',
type: 'scatter',
yAxisIndex:1,
symbolSize: 10,
smooth:false,
data:params.data3
}
]
});
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
</script>
</div>
<?php include_once "../html/footer.php"; ?>
+91
View File
@@ -0,0 +1,91 @@
<?php
include_once "../inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2020-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS EP趋势:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
</div> </form>
<div style="margin:0 auto;clear:both;left:100px;width:1000px;height:30px;text-align:left"><span style="color:grey">EP=100*TTM每股收益/股价。如:EP=5表示每股收益率5%</span></div>
<!-- 图表容器 -->
<div id="container" style="width: 1000px;height:400px; margin: 0 auto 20px;">
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
</div>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
//e.preventDefault(); // 阻止表单提交刷新页面
$('#loadingOverlay').addClass('active');
loadChartData();
$('#loadingOverlay').removeClass('active');
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let ts_code = $("#ts_code").val();
url = "https://api.doorcome.cn/api/stockep/?tscode="+ts_code;
url += "&start_date="+t_start+"&end_date="+t_end;
url2 = "https://api.doorcome.cn/api/stockinfo/?tscode="+ts_code;
Promise.all([
fetch(url),
fetch(url2)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([parsedData,stockInfo]) => {
// 图表配置:pe_ttm
let codeName = stockInfo[0].name;
var params = {};
params.chartid='container';
params.legend = [codeName,'EP'];
params.text = params.legend[0]+' V.S '+params.legend[1];
params.data1 = pickData(parsedData, 'trade_date', 'close');
params.data2 = pickData(parsedData, 'trade_date', 'basic_ep_ttm');
dataCal = calculateStats(params.data2);
params.sub_text = "TTM EP Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
});
}
</script>
</div>
<?php include_once "../html/footer.php"; ?>
+84
View File
@@ -0,0 +1,84 @@
<?php
include_once "../inc/getBasic.inc.php";
include_once "../inc/getData.inc.php";
include_once "../inc/postJson.inc.php";
include_once "../inc/getFinanceData.class.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000002';
$_REQUEST['yst']=$_REQUEST['yst']?$_REQUEST['yst']:'2015';
$_REQUEST['yed']=$_REQUEST['yed']?$_REQUEST['yed']:date('Y');
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="六段式表格:".$ts_name.'('.$_REQUEST['ts_code'].')';
$years=yearList($_REQUEST['yst'],$_REQUEST['yed']);
$thWidth = round(1/(count($years)+1)*100,1);
$thWidth .='%';
$urlAppend="ts_code={$_REQUEST['ts_code']}&yst={$_REQUEST['yst']}&yed={$_REQUEST['yed']}";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='input' name='yst' id='yst' width='20px' list='yearlist' autocomplete="off" >
<datalist id="yearlist">
<option value="2022"></option>
<option value="2021"></option>
<option value="2020"></option>
<option value="2019"></option>
<option value="2018"></option>
<option value="2017"></option>
<option value="2016"></option>
<option value="2015"></option>
</datalist>
结束时间: <input type='input' name='yed' id='yed' width='20px'list='yearlist' autocomplete="off" >
<script>
$("#yst").val('<?=$_REQUEST['yst']?>');
$("#yed").val('<?=$_REQUEST['yed']?>');
</script>
<input type='submit' value="给我查!">
<div >&nbsp;</div>
</div> </form>
<div id="container" style="margin:0 auto;height:auto;width: 90%">
<table id="fina" class="display" style="width: 100%">
<thead>
<tr>
<th> </th>
<?php
for($i=0;$i<count($years);$i++) echo "<th style='width:{$thWidth};text-align: left;'> ".yearToname($years[$i])."</th>\n";
?>
</tr>
</thead>
<tfoot>
<tr>
<th> </th>
<?php
for($i=0;$i<count($years);$i++) echo "<th style='width:{$thWidth};text-align: left;'> ".yearToname($years[$i])."</th>\n";
?>
</tr>
</tfoot>
</table>
</div>
<?php include_once "../html/footer.php"; ?>
<script>
$(document).ready(function() {
$('#fina').DataTable( {
paging:false,
scrollY:950,
ordering:false,
"ajax": 'https://echart.doorcome.cn/inc/ajax.inc.php?t=financeData&<?=$urlAppend?>'
} );
} );
</script>
+93
View File
@@ -0,0 +1,93 @@
<?php
include_once "../inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:date('Y-m-d');
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS融资融券余额:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<script src="../js/renderCharts.js"></script>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
<div >&nbsp;</div>
</div> </form>
<div >&nbsp;</div>
<div id="container" style="margin:0 auto;height: 400px;width: 1000px"></div>
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<p style="font-size:18px; color:#2c3e50;">正在加载数据,请稍候...</p>
</div>
<script>
// 页面加载时初始化图表
$(document).ready(function() {
// 加载初始数据
loadChartData();
// 绑定按钮点击事件
$('#submitBtn').click(function(e) {
e.preventDefault(); // 阻止表单提交刷新页面
loadChartData();
});
});
// 加载图表数据的函数
function loadChartData() {
// 显示加载动画
$('#loadingOverlay').addClass('active');
let t_start = $('#t_start').val();
let t_end = $('#t_end').val();
let ts_code = $("#ts_code").val();
url = "https://api.doorcome.cn/api/stockmargin/?tscode="+ts_code;
url += "&start_date="+t_start+"&end_date="+t_end;
url1 = "https://api.doorcome.cn/api/stockbasic/?tscode="+ts_code;
url1 += "&start_date="+t_start+"&end_date="+t_end;
url2 = "https://api.doorcome.cn/api/stockinfo/?tscode="+ts_code;
Promise.all([
fetch(url),
fetch(url1),
fetch(url2)
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([margindData,dailyData,stockInfo]) => {
// 图表配置:pe_ttm
let codeName = stockInfo[0].name;
var params = {};
params.chartid='container';
params.legend = ['不复权股价','融资融券余额(亿元)'];
params.text = codeName+'('+ts_code+')';
params.data1 = pickData(dailyData, 'trade_date', 'close');
params.data2 = pickData(margindData, 'trade_date', 'rzrqye');
params.data2 = params.data2.map(item => {
return {
value: [
item.value[0],
parseFloat((parseFloat(item.value[1]) / 10000 /10000).toFixed(2))
]
};
});
dataCal = calculateStats(params.data2);
params.sub_text = "TTM PE Max:"+dataCal['max'];
params.sub_text += ", Min:"+dataCal['min'];
params.sub_text += ", Average:"+dataCal['avg'];
params.sub_text += ", Recent:"+dataCal['last'];
doubleLineChart(params);
})
.catch(error => console.error('数据加载失败:', error))
.finally(() => {
// 隐藏加载动画
$('#loadingOverlay').removeClass('active');
}
);
}
</script>
<?php include_once "../html/footer.php"; ?>
+72
View File
@@ -0,0 +1,72 @@
<?php
/**
* Basic Information Display
*
* Basic Information and Display as Format HTML Tables.
* @package Display
* @author Simon <simon.youngest@gmail.com>
* @date 2011-3-28
* @version 0.1
*/
class basic_info{
public $columns; //Number of Column
public $rows; //Number of rows
public $content; //Content to display,2-D
/* Array with items<$itemNum; If need add No at 0, use function: array_unshift*/
public $titles;
/* Main title of Basic Information as: lot information */
public $main_title;
public $num_flag; //Is first column is No? Set 1 if yes.
public $aligns; //Align method for each column;
public $width;
public $display;
//Get Formated Display of Content
function get_Content_Display(){
global $tableTop,$interval;
if($this->content[0]==NULL) {
$this->display="<p align='center'><font size='3' color='red'><i><b>Query result is null</b></i></font></p>";
return;
}
/* Get number of rows if not defined */
if($this->rows == NULL) $this->rows=count($this->content[0]);
$this->display="<table width='".$this->width."' align='center' >\n";
/* Main title display */
if(strlen($this->main_title)>0) {
$this->display.="<tr><td colspan='5' align='center' style='font-size:14px;padding:5px;'><h3>";
$this->display.=$this->main_title;
$this->display.="</h3></td></tr>\n";
}
/* Get Row number of HTML */
$html_row=ceil(count($this->content[0])/2);
//display data
for($i=0;$i<$html_row;$i++){
$j=$i+1;
$this->display.="<tr >\n";
$this->display.="<td bgcolor='".$tableTop."' width='18%' style='font-size:14px;padding:5px;'>\n";
$this->display.=$this->content[0][2*$i];
$this->display.="</td><td bgcolor='".$interval."' width='31%' style='font-size:14px;padding:5px;'>\n";
$this->display.=$this->content[1][2*$i];
$this->display.="</td>\n";
$this->display.="<td >&nbsp;</td>\n";
$this->display.="<td bgcolor='".$tableTop."' width='18%' style='font-size:14px;padding:5px;'>\n";
$this->display.=$this->content[0][2*$i+1];
$this->display.="</td><td bgcolor='".$interval."' width='31%' style='font-size:14px;padding:5px;'>\n";
$this->display.=$this->content[1][2*$i+1];
$this->display.="</td>\n";
$this->display.="</tr>\n";
}
$this->display.="</table>";
}
function display(){
echo $this->display;
}
}
?>
+9
View File
@@ -0,0 +1,9 @@
{
"require": {
"monolog/monolog": "2.0.*",
"phpoffice/phpspreadsheet": "^1.18",
"ext-json": "*",
"ext-mysqli": "*",
"ext-curl": "*"
}
}
Generated
+981
View File
@@ -0,0 +1,981 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d292afeef339b8706e16baf682993aa0",
"packages": [
{
"name": "ezyang/htmlpurifier",
"version": "v4.13.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
"reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
],
"exclude-from-classmap": [
"/library/HTMLPurifier/Language/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
},
"time": "2020-06-29T00:56:53+00:00"
},
{
"name": "maennchen/zipstream-php",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/maennchen/ZipStream-PHP.git",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"myclabs/php-enum": "^1.5",
"php": ">= 7.1",
"psr/http-message": "^1.0",
"symfony/polyfill-mbstring": "^1.0"
},
"require-dev": {
"ext-zip": "*",
"guzzlehttp/guzzle": ">= 6.3",
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": ">= 7.5"
},
"type": "library",
"autoload": {
"psr-4": {
"ZipStream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paul Duncan",
"email": "pabs@pablotron.org"
},
{
"name": "Jonatan Männchen",
"email": "jonatan@maennchen.ch"
},
{
"name": "Jesse Donat",
"email": "donatj@gmail.com"
},
{
"name": "András Kolesár",
"email": "kolesar@kolesar.hu"
}
],
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
"keywords": [
"stream",
"zip"
],
"support": {
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
"source": "https://github.com/maennchen/ZipStream-PHP/tree/master"
},
"funding": [
{
"url": "https://opencollective.com/zipstream",
"type": "open_collective"
}
],
"time": "2020-05-30T13:11:16+00:00"
},
{
"name": "markbaker/complex",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "6f724d7e04606fd8adaa4e3bb381c3e9db09c946"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/6f724d7e04606fd8adaa4e3bb381c3e9db09c946",
"reference": "6f724d7e04606fd8adaa4e3bb381c3e9db09c946",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"phpcompatibility/php-compatibility": "^9.0",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
"squizlabs/php_codesniffer": "^3.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/2.0.3"
},
"time": "2021-06-02T09:44:11+00:00"
},
{
"name": "markbaker/matrix",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "174395a901b5ba0925f1d790fa91bab531074b61"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/174395a901b5ba0925f1d790fa91bab531074b61",
"reference": "174395a901b5ba0925f1d790fa91bab531074b61",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"phpcompatibility/php-compatibility": "^9.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Matrix\\": "classes/src/"
},
"files": [
"classes/src/Functions/adjoint.php",
"classes/src/Functions/antidiagonal.php",
"classes/src/Functions/cofactors.php",
"classes/src/Functions/determinant.php",
"classes/src/Functions/diagonal.php",
"classes/src/Functions/identity.php",
"classes/src/Functions/inverse.php",
"classes/src/Functions/minors.php",
"classes/src/Functions/trace.php",
"classes/src/Functions/transpose.php",
"classes/src/Operations/add.php",
"classes/src/Operations/directsum.php",
"classes/src/Operations/subtract.php",
"classes/src/Operations/multiply.php",
"classes/src/Operations/divideby.php",
"classes/src/Operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@demon-angel.eu"
}
],
"description": "PHP Class for working with matrices",
"homepage": "https://github.com/MarkBaker/PHPMatrix",
"keywords": [
"mathematics",
"matrix",
"vector"
],
"support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.3"
},
"time": "2021-05-25T15:42:17+00:00"
},
{
"name": "monolog/monolog",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/c861fcba2ca29404dc9e617eedd9eff4616986b8",
"reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": "^7.2",
"psr/log": "^1.0.1"
},
"provide": {
"psr/log-implementation": "1.0.0"
},
"require-dev": {
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
"doctrine/couchdb": "~1.0@dev",
"elasticsearch/elasticsearch": "^6.0",
"graylog2/gelf-php": "^1.4.2",
"jakub-onderka/php-parallel-lint": "^0.9",
"php-amqplib/php-amqplib": "~2.4",
"php-console/php-console": "^3.1.3",
"phpspec/prophecy": "^1.6.1",
"phpunit/phpunit": "^8.3",
"predis/predis": "^1.1",
"rollbar/rollbar": "^1.3",
"ruflin/elastica": ">=0.90 <3.0",
"swiftmailer/swiftmailer": "^5.3|^6.0"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mbstring": "Allow to work properly with unicode symbols",
"ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"php-console/php-console": "Allow sending log messages to Google Chrome",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Monolog\\": "src/Monolog"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
"homepage": "http://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging",
"psr-3"
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/2.0.2"
},
"time": "2019-12-20T14:22:59+00:00"
},
{
"name": "myclabs/php-enum",
"version": "1.8.3",
"source": {
"type": "git",
"url": "https://github.com/myclabs/php-enum.git",
"reference": "b942d263c641ddb5190929ff840c68f78713e937"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937",
"reference": "b942d263c641ddb5190929ff840c68f78713e937",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*",
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^4.6.2"
},
"type": "library",
"autoload": {
"psr-4": {
"MyCLabs\\Enum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP Enum contributors",
"homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
}
],
"description": "PHP Enum implementation",
"homepage": "http://github.com/myclabs/php-enum",
"keywords": [
"enum"
],
"support": {
"issues": "https://github.com/myclabs/php-enum/issues",
"source": "https://github.com/myclabs/php-enum/tree/1.8.3"
},
"funding": [
{
"url": "https://github.com/mnapoli",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
"type": "tidelift"
}
],
"time": "2021-07-05T08:18:36+00:00"
},
{
"name": "phpoffice/phpspreadsheet",
"version": "1.18.0",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
"reference": "418cd304e8e6b417ea79c3b29126a25dc4b1170c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/418cd304e8e6b417ea79c3b29126a25dc4b1170c",
"reference": "418cd304e8e6b417ea79c3b29126a25dc4b1170c",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-ctype": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"ezyang/htmlpurifier": "^4.13",
"maennchen/zipstream-php": "^2.1",
"markbaker/complex": "^2.0",
"markbaker/matrix": "^2.0",
"php": "^7.2 || ^8.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/simple-cache": "^1.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
"dompdf/dompdf": "^1.0",
"friendsofphp/php-cs-fixer": "^2.18",
"jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^8.0",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^0.12.82",
"phpstan/phpstan-phpunit": "^0.12.18",
"phpunit/phpunit": "^8.5",
"squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "^6.3"
},
"suggest": {
"dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)",
"jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)"
},
"type": "library",
"autoload": {
"psr-4": {
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maarten Balliauw",
"homepage": "https://blog.maartenballiauw.be"
},
{
"name": "Mark Baker",
"homepage": "https://markbakeruk.net"
},
{
"name": "Franck Lefevre",
"homepage": "https://rootslabs.net"
},
{
"name": "Erik Tilt"
},
{
"name": "Adrien Crivelli"
}
],
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
"keywords": [
"OpenXML",
"excel",
"gnumeric",
"ods",
"php",
"spreadsheet",
"xls",
"xlsx"
],
"support": {
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.18.0"
},
"time": "2021-05-31T18:21:15+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
},
"time": "2020-06-29T06:28:15+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.0.0",
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/master"
},
"time": "2019-04-30T12:38:16+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "psr/simple-cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/simple-cache.git",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\SimpleCache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interfaces for simple caching",
"keywords": [
"cache",
"caching",
"psr",
"psr-16",
"simple-cache"
],
"support": {
"source": "https://github.com/php-fig/simple-cache/tree/master"
},
"time": "2017-10-23T01:57:42+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-05-27T12:26:48+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
}
+44
View File
@@ -0,0 +1,44 @@
# continuation.md — 会话检查点
> 生成时间:2026-08-04(本会话)
> 工作区:/Users/summer/Downloads/py/wwwechart 平台,PHP + jQuery + ECharts,无框架)
## 当前状态
本会话完成四件事,均已部署上线:
### 1. 项目文档刷新(init
- 重写 `AGENTS.md`,外科手术式修正 `CLAUDE.md`Tailwind/ECharts 真实路径(`/lib/js/tailwindcss-3.4.17.js``/lib/js/echarts-5.4.2.js`)、已移入 `deprecated/` 的页面清单、三种数据模式(fetch api.doorcome.cn / ajax.inc.php t= 路由 / 服务端注入)、表名约定(index_hist_pro 等已由 API 替代)、config.php 明文凭据说明。
### 2. 服务器 → 本地全量拉取
- rsync(不带 `--delete`)从 `simon@www.doorcome.cn:/var/www/html/echart/` 拉取 148M、405 文件。新增 `podcast-docs/`deploy.md、usage.html)、`quant/intlnews_usage.html``quant/user_guide.html``research/` 每日报告目录(2026060820260804)。`podcast/` 服务器上为空目录。
- 文档按用户选择恢复为本地新版(备份在 `/tmp/echart-doc-backup/`)。
### 3. 投资资讯日报前端(核心交付)
- 新建 `charts/news_reports.php`:报告查询导航页(类型 Tabs + 日期筛选 + 列表 + 详情一体,Tailwind 本地库,零外部链接)。
- 新建 `js/newsReports.js`fetch `https://api.doorcome.cn/api/news/reports/` 渲染。详情固定模块:AI 摘要 → 事件(finance: xwlb→news→cninfointl: intl)→ 数据总览。
- 修改 `index-2.php`:研究报告下拉框卡片 → 链接 `/charts/news_reports.php`,删除 `showReportGroup`
- **关键坑**:真实 API `stats` 结构与文档示例差异大且随日期变化(8/1 前后两套:新版 `pipeline(raw_total)+news/cninfo/xwlb`,旧版 `pipeline(M1中文键)+sources/sentiment/importance/event_types`intl 的 sentiment 是字符串数组、importance 值是字符串、还有合并格式 `{"重要度":"数量","等级 N":"..."}`)。已实现 `normalizeKV()` 归一化,59 份日报全部渲染通过。
- **Bug 修复**:点击卡片"无法弹出"——根因 `openDetail` 未隐藏 `listView`(详情渲染在列表下方,滚动回顶部后用户看不到)。新增 `showDetail()` 隐藏列表,已部署并用 CDP 真实点击验证(`listView class: hidden` ✓)。
### 4. 部署工具 sync-echart
- 创建 `~/bin/sync-echart`rsync 单向推送本地 → `simon@www.doorcome.cn:/var/www/html/echart/`,排除本地环境文件 + 数据目录 `uploads/xls/files/research/podcast/podcast-docs`)。`-n` 预览。
- PATH 已配:`~/.bash_profile``~/.zshrc`(原注释行改为启用)。
- 部署方式已记录:`CLAUDE.md` 常用命令节 + 项目记忆 `project/sync-echart-deploy.md`
- 已执行 3 次部署(页面+JS+index-2 → CLAUDE.md → JS 修复),服务器 md5 全部验证一致。
## 后续步骤
1. 让用户在浏览器**硬刷新**Cmd+Shift+R)验证 `https://echart.doorcome.cn/charts/news_reports.php`:列表 → 点击卡片 → 详情各模块。
2. (建议)把 `charts/news_reports.php` 补进 `CLAUDE.md` 的页面目录表,`sync-echart` 部署。
3. (可选)导航页加"重要事件聚合"视图:`/api/news/events/`days/importance/report_type/section/limit 参数,已预留 API_EVENTS 常量未用)。
4. (可选)数据总览改 ECharts 图表版(当前是数字卡 + 表格)。
5. (可选)`research/` 静态日报 HTML 与 API 页面并存,旧文件仍可直接访问;确认是否需要归档清理。
## 待解决问题
- **本机无 PHP**`php -l` 语法检查需 scp 到服务器执行(已建立流程)。
- **数据目录不同步**`sync-echart` 排除 uploads/xls/files/research/podcast;服务器 ↔ 本地数据同步需手动 rsync(不带 `--delete`)。
- **API stats 结构不稳定**:随生成日期变化,前端依赖 `normalizeKV()` 防御性兼容;若 API 侧统一格式可简化前端(需与 djapi 后端协调)。
- **API 文档滞后**`/Users/summer/Downloads/cc-cursor/docs/news_report_api.md` 中 finance stats 的 `sources` key 实测不存在(新版为 `pipeline.raw_by_source`),文档与实测不一致。
- **记忆**:曾有一次 `remember` 被拒(后来明确要求后成功保存);如后续会话需重新保存,注意用户偏好。
+6496
View File
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
.div_parent{
min-height: 200px;
background: #ffffff;
width: 900px;
position:relative;
text-align:center;
margin:0 auto;
}
.div_cell{
background: #fff;
width:180px;
height:30px;
margin: 0 auto;
text-align: left;
float: left;
position: relative;
left:50px;
}
.div_block{
background: #fff;
width:280px;
height:30px;
text-align: left;
margin: 0 auto;
left:50px;
}
A:link {
FONT-SIZE: 16px;
COLOR: #333333;
TEXT-DECORATION: none
}
A:visited {
FONT-SIZE: 16px;
COLOR: #333333;
TEXT-DECORATION: none
}
A:hover {
FONT-SIZE: 16px;
COLOR: #043B9C;
TEXT-DECORATION: underline
}
.btn-submit {
background-color: var(--primary-color);
color: #0c0c0c;
border: none;
padding: 2px 2px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: background-color 0.3s;
display: flex;
align-items: center;
gap: 8px;
margin-top: 15px; /* ADDED 上边距 */
display: inline-flex; /* MODIFIED from flex */
}
.btn-submit:hover {
background-color: #2980b9;
}
.btn-submit:disabled {
background-color: #95a5a6;
cursor: not-allowed;
}
#chartCanvas {
width: 100%;
height: 10px;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.85);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
z-index: 10;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.loading-overlay.active {
opacity: 1;
pointer-events: auto;
}
/* 加载文字样式 */
.loading-overlay p {
font-size: 18px;
color: var(--secondary-color);
margin-top: 10px;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(52, 152, 219, 0.2);
border-top: 5px solid var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.chart-container {
width: 1000px;
height: 400px;
margin-top: 20px;
}
.chart-container:last-child {
margin-bottom: 20px;
}
+198
View File
@@ -0,0 +1,198 @@
// 日期选择
// By Ziyue(http://www.web-v.com/)
var months = new Array("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月");
var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var days = new Array("日","一", "二", "三", "四", "五", "六");
var today;
document.writeln("<div id='Calendar' style='position:absolute; z-index:1; visibility: hidden; filter:\"progid:DXImageTransform.Microsoft.Shadow(direction=135,color=#999999,strength=3)\"'></div>");
function getDays(month, year)
{
//下面的这段代码是判断当前是否是闰年的
if (1 == month)
return ((0 == year % 4) && (0 != (year % 100))) || (0 == year % 400) ? 29 : 28;
else
return daysInMonth[month];
}
function getToday()
{
//得到今天的年,月,日
this.now = new Date();
this.year = this.now.getFullYear();
this.month = this.now.getMonth();
this.day = this.now.getDate();
}
function getStringDay(str)
{
//得到输入框的年,月,日
var str=str.split("-")
this.now = new Date(parseFloat(str[0]),parseFloat(str[1])-1,parseFloat(str[2]));
this.year = this.now.getFullYear();
this.month = this.now.getMonth();
this.day = this.now.getDate();
}
function newCalendar() {
//var parseYear = parseInt(document.all.Year.options[document.all.Year.selectedIndex].value);
var parseYear = parseInt(document.getElementById('Year').options[document.getElementById('Year').selectedIndex].value);
//var newCal = new Date(parseYear, document.all.Month.selectedIndex, 1);
var newCal = new Date(parseYear, document.getElementById('Month').selectedIndex, 1);
var day = -1;
var startDay = newCal.getDay();
var daily = 0;
if ((today.year == newCal.getFullYear()) &&(today.month == newCal.getMonth()))
day = today.day;
var tableCal = document.getElementById('calendar');
var intDaysInMonth =getDays(newCal.getMonth(), newCal.getFullYear());
for (var intWeek = 1; intWeek < tableCal.rows.length;intWeek++)
for (var intDay = 0;intDay < tableCal.rows[intWeek].cells.length;intDay++)
{
var cell = tableCal.rows[intWeek].cells[intDay];
if ((intDay == startDay) && (0 == daily))
daily = 1;
if(day==daily) //今天,调用今天的Class
{
cell.style.background='#6699CC';
cell.style.color='#FFFFFF';
//cell.style.fontWeight='bold';
}
else if(intDay==6) //周六
cell.style.color='green';
else if (intDay==0) //周日
cell.style.color='red';
if ((daily > 0) && (daily <= intDaysInMonth))
{
cell.innerText = daily;
daily++;
}
else
cell.innerText = "";
}
}
function GetDate(InputBox)
{
var sDate;
//这段代码处理鼠标点击的情况
if (event.srcElement.tagName == "TD")
if (event.srcElement.innerText != "")
{
sDate = document.getElementById('Year').value + "-" + document.getElementById('Month').value + "-" + event.srcElement.innerText;
//eval("document.all."+InputBox).value=sDate;
document.getElementById(InputBox).value=sDate;
HiddenCalendar();
}
}
function HiddenCalendar()
{
//关闭选择窗口
document.getElementById('Calendar').style.visibility='hidden';
}
function ShowCalendar(InputBox)
{
var x,y,intLoop,intWeeks,intDays;
var DivContent;
var year,month,day;
//var o=eval("document.getElementById("+InputBox+")");
o=document.getElementById(InputBox);
var thisyear; //真正的今年年份
thisyear=new getToday();
thisyear=thisyear.year;
today = o.value;
if(isDate(today))
today = new getStringDay(today);
else
today = new getToday();
//显示的位置
x=o.offsetLeft;
y=o.offsetTop;
while(o=o.offsetParent)
{
x+=o.offsetLeft;
y+=o.offsetTop;
}
//document.all.Calendar.style.left=x+2;
//document.all.Calendar.style.top=y+20;
//document.all.Calendar.style.visibility="visible";
document.getElementById('Calendar').style.left=x+2;
document.getElementById('Calendar').style.top=y+20;
document.getElementById('Calendar').style.visibility="visible";
//下面开始输出日历表格(border-color:#9DBAF7)
DivContent="<table border='0' cellspacing='0' style='border:1px solid #0066FF; background-color:#EDF2FC'>";
DivContent+="<tr>";
DivContent+="<td style='border-bottom:1px solid #0066FF; background-color:#C7D8FA'>";
//年
DivContent+="<select name='Year' id='Year' onChange='newCalendar()' style='font-family:Verdana; font-size:12px'>";
for (intLoop = thisyear - 10; intLoop < (thisyear + 3); intLoop++)
DivContent+="<option value= " + intLoop + " " + (today.year == intLoop ? "Selected" : "") + ">" + intLoop + "</option>";
DivContent+="</select>";
//月
DivContent+="<select name='Month' id='Month' onChange='newCalendar()' style='font-family:Verdana; font-size:12px'>";
for (intLoop = 0; intLoop < months.length; intLoop++)
DivContent+="<option value= " + (intLoop + 1) + " " + (today.month == intLoop ? "Selected" : "") + ">" + months[intLoop] + "</option>";
DivContent+="</select>";
DivContent+="</td>";
DivContent+="<td style='border-bottom:1px solid #0066FF; background-color:#C7D8FA; font-weight:bold; font-family:Wingdings 2,Wingdings,Webdings; font-size:16px; padding-top:2px; color:#4477FF; cursor:hand' align='center' title='关闭' onClick='javascript:HiddenCalendar()'>S</td>";
DivContent+="</tr>";
DivContent+="<tr><td align='center' colspan='2'>";
DivContent+="<table id='calendar' border='0' width='100%'>";
//星期
DivContent+="<tr>";
for (intLoop = 0; intLoop < days.length; intLoop++)
DivContent+="<td align='center' style='font-size:12px'>" + days[intLoop] + "</td>";
DivContent+="</tr>";
//天
for (intWeeks = 0; intWeeks < 6; intWeeks++)
{
DivContent+="<tr>";
for (intDays = 0; intDays < days.length; intDays++)
DivContent+="<td onClick='GetDate(\"" + InputBox + "\")' style='cursor:hand; border-right:1px solid #BBBBBB; border-bottom:1px solid #BBBBBB; color:#215DC6; font-family:Verdana; font-size:12px' align='center'></td>";
DivContent+="</tr>";
}
DivContent+="</table></td></tr></table>";
//document.all.Calendar.innerHTML=DivContent;
document.getElementById('Calendar').innerHTML=DivContent;
newCalendar();
}
function isDate(dateStr)
{
var datePat = /^(\d{4})(\-)(\d{1,2})(\-)(\d{1,2})$/;
var matchArray = dateStr.match(datePat);
if (matchArray == null) return false;
var month = matchArray[3];
var day = matchArray[5];
var year = matchArray[1];
if (month < 1 || month > 12) return false;
if (day < 1 || day > 31) return false;
if ((month==4 || month==6 || month==9 || month==11) && day==31) return false;
if (month == 2)
{
var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
if (day > 29 || (day==29 && !isleap)) return false;
}
return true;
}
+124
View File
@@ -0,0 +1,124 @@
<?php
include_once "inc/getBasic.inc.php";
include_once "inc/getData.inc.php";
include_once "html/headChart.php"; //required after $ts_code and $ts_name,maybe doesn't matter
$ts_code=$_REQUEST['code'];
#echo $ts_code;
$item=$_REQUEST['item'];
$day_st=($_REQUEST['s']=='')?'20120101':$_REQUEST['s'];
$day_end=($_REQUEST['e']=='')?date('Ymd'):$_REQUEST['e'];
if($item == 'total_mv' or $item=='circ_mv') $unit='-万亿';
else $unit = ''; # Without a unit on PE
#var_dump($lx);
$data=getIndexData(codetocode($ts_code),$day_st,$day_end);
$data2 = getBasicExtData($ts_code,$item,$day_st,$day_end);
#var_dump($data2);
$ts_name = codeToName($ts_code);
if($item=='total_mv_all') $item_name = '总市值';
elseif($item=='circ_mv_all') $item_name = '流通市值';
else $item_name=$item;
$legend=array($ts_name,'深证成指',$item_name);
#$value=json_encode($data['data']);
$subtext_ext = "Max: ".$data2['data_max'];
$subtext_ext .= ", Min: ".$data2['data_min'];
$subtext_ext .= ", Average: ".$data2['data_avg'];
$subtext_ext .= ", Recent: ".$data2['data_last'];
$unit='-万亿';
?>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
legend = <?php echo json_encode($legend);?>;
unit ='<?php echo $unit; ?>';
var subtxt = '<?php echo $subtext_ext; ?>';
option = {
title: {
text: legend[0]+' V.S '+legend[2],
subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true
},
{
type:'value',
name:legend[2]+unit, //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:<?php echo json_encode($data['data']); ?>
},
{
name:legend[2],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data:<?php echo json_encode($data2['data']); ?>
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
</body>
</html>
+45
View File
@@ -0,0 +1,45 @@
<?php
/*
* @Author: Yangshuimiao
* @Date: 2023-06-25 12:26:16
* @LastEditTime: 2025-02-13 17:04:36
* @FilePath: \chartFore.php
* @Description:
* Copyright 2025 Yangshuimiao, All Rights Reserved.
*/
#查询个股价格对应PE_TTM, PB, PS的长期趋势数据
include_once "inc/getBasic.inc.php" ;
include_once "inc/getData.inc.php";
include_once "html/headChart.php"; //required after $ts_code and $ts_name,maybe doesn't matter
$ts_code=ts_code_conv($_REQUEST['ts_code']);
$day_st=($_REQUEST['s']=='')?'20120101':$_REQUEST['s'];
$day_end=($_REQUEST['e']=='')?date('Ymd'):$_REQUEST['e'];
$item = ($_REQUEST['item']=='')?'pe_ttm':$_REQUEST['item'];
$unit = ''; # Without a unit on PE
$data = getStockHist($ts_code,$day_st,$day_end);
#$data = getIndexHistoryDataByTS($ts_code, $day_st, $day_end);
$data2 = getBasicData($ts_code,$day_st,$day_end,$item);
#$data2 = getStockHistoryDataByTS($ts_code, $day_st, $day_end, $item);
//print_r($data2);
//print_r($data);
$subtext_ext = "Max: ".$data2['data_max'];
$subtext_ext .= ", Min: ".$data2['data_min'];
$subtext_ext .= ", Average: ".$data2['data_avg'];
$subtext_ext .= ", Recent: ".$data2['data_last'];
$ts_name = tscodeToName($ts_code);
$legend=array('不复权股价','深证成指',strtoupper($item));
#$value=json_encode($data['data']);
?>
<script type="text/javascript">
var data1 = <?php echo json_encode($data['data']); ?>;
var data2 =<?php echo json_encode($data2['data']); ?>;
var legend = <?php echo json_encode($legend);?>;
var unit ='<?php echo $unit; ?>';
var headtxt = '<?php echo $ts_name.'('.$ts_code.')'; ?>';
var subtxt = '<?php echo $subtext_ext; ?>';
</script>
<script type="text/javascript" src="js/chartFore.js?ver=3.14"></script>
</body>
</html>
+119
View File
@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<?php
ini_set('error_reporting', E_ALL);
$mysqli = new mysqli('localhost','root','nancysimon','myquant');
$ts_code = '000001.SH';
$day_st = '20190101';
$day_end = '20190701';
$where = " and trade_date>'".$day_st."'";
if($day_end) $where .= " and trade_date <'".$day_end."'";
$date_range = "and trade_date";
$sql= <<<EOF
select trade_date, close from index_hist_pro where ts_code = '$ts_code' $where order by trade_date asc
EOF;
#echo $sql;
$result = $mysqli->query($sql);
$tDate=array('交易日');
$idx=array('上证指数');
if($result && $result->num_rows>0) {
#$data = $result->fetch_all();
while($row=$result->fetch_assoc()){
array_push($tDate,$row['trade_date']);
array_push($idx,$row['close']);
}
}
#Free result and close connection.
$result->free();
$mysqli->close();
?>
<body style="height: 100%; margin: 0">
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="container" style="height: 400px;width: 600px"></div>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/echarts.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts-gl/echarts-gl.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts-stat/ecStat.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/extension/dataTool.min.js"></script>
<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/simplex.js"></script>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
option = null;
option = {
title: {
text: '折线图堆叠'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:['邮件营销','联盟广告','视频广告','直接访问','搜索引擎']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一','周二','周三','周四','周五','周六','周日']
},
yAxis: {
type: 'value'
},
series: [
{
name:'邮件营销',
type:'line',
stack: '总量',
data:[120, 132, 101, 134, 90, 230, 210]
},
{
name:'联盟广告',
type:'line',
stack: '总量',
data:[220, 182, 191, 234, 290, 330, 310]
},
{
name:'视频广告',
type:'line',
stack: '总量',
data:[150, 232, 201, 154, 190, 330, 410]
},
{
name:'直接访问',
type:'line',
stack: '总量',
data:[320, 332, 301, 334, 390, 330, 320]
},
{
name:'搜索引擎',
type:'line',
stack: '总量',
data:[820, 932, 901, 934, 1290, 1330, 1320]
}
]
};
;
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
</body>
</html>
+66
View File
@@ -0,0 +1,66 @@
<?php
#查询个股价格对应机构持仓的数量
include_once "../inc/getBasic.inc.php";
include_once "../inc/getData.inc.php";
$ts_code=ts_code_conv($_REQUEST['ts_code']);
$ts_name = tscodeToName($ts_code);
include_once "../html/headChart.php"; //required after $ts_code and $ts_name
$day_st=($_REQUEST['s']=='')?'2012-01-01':$_REQUEST['s'];
$day_end=($_REQUEST['e']=='')?date('Y-m-d'):$_REQUEST['e'];
#item: f9:持股数 f10:持股额 f11:占总股本比例 f12:占流通股比例
$item = ($_REQUEST['item']=='')?'f9':$_REQUEST['item'];
switch($item){
case 'f9':
case 'F9':
$unit = ' - 万股';
$item_name = "持股数";
break;
case 'f10':
case 'F10':
$unit = ' - 万元';
$item_name = "持股金额";
break;
case 'f11':
case 'F11':
$unit = ' - %';
$item_name = "总股本股比例";
break;
case 'f12':
case 'F12':
$unit = ' - %';
$item_name = "流通股比例";
break;
default:
$unit = '';
}
$data = getStockHist($ts_code,$day_st,$day_end);
$lx = ''; //define null var avoid error
$data2 = getIhDataByStock($ts_code,$item,$lx,$day_st,$day_end);
#var_dump($data2['data']);
$subtext_ext = "Max: ".$data2['data_max'];
$subtext_ext .= ", Min: ".$data2['data_min'];
$subtext_ext .= ", Average: ".$data2['data_avg'];
$subtext_ext .= ", Recent: ".$data2['data_last'];
$legend=array('不复权股价','深证成指',$item_name);
#$value=json_encode($data['data']);
?>
<script type="text/javascript">
window.chartConfig = {
data: <?php echo json_encode($data['data']); ?>,
data2: <?php echo json_encode($data2['data']); ?>,
legend: <?php echo json_encode($legend);?>,
unit: '<?php echo $unit; ?>',
title: '<?php echo $ts_name.'('.$ts_code.')'; ?>',
subtitle: '<?php echo $subtext_ext; ?>'
};
</script>
<script type="text/javascript" src="../js/chartSix.js?ver=3.141"></script>
</body>
</html>
+119
View File
@@ -0,0 +1,119 @@
<?php
include_once "../inc/getData.inc.php";
include_once "../html/headChart.php"; //required after $ts_code and $ts_name,maybe doesn't matter
$day_st=$_REQUEST['s']?$_REQUEST['s']:'2006-01-01';
$day_end=$_REQUEST['e']?$_REQUEST['e']:date('Y-m-d');
#$day_st_='2006-01-01';
#$day_end_=date('Y-m-d');
$lx=isset($lx)?$lx:$_REQUEST['lx'];
$share =$_REQUEST['share'];
$share = ($share)?$share:'ShareHDNum';
if($share=='ShareHDNum') $unit = '(亿股)';
elseif($share=='vPosition') $unit = '(亿元)';
elseif($share=='VSRatio') $unit = '(元)';
#var_dump($lx);
$data=getIndexData('000001.SH',$day_st,$day_end);
#$data1=getIndexData('399001.SZ',$day_st,$day_end);
$data2=getIhData($lx,$share,$day_st,$day_end);
$legend=array('上证综指','深证成指',lxDefine($lx));
#$value=json_encode($data['data']);
?>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
window.chartConfig = {
legend: <?php echo json_encode($legend); ?>,
unit: '<?php echo $unit; ?>'
};
var cfg = window.chartConfig;
option = {
title: {
text: cfg.legend[0]+" V.S "+cfg.legend[2],
//subtext:"双轴显示",
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true
},
{
type:'value',
name: cfg.legend[2]+cfg.unit, //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'slider', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:<?php echo json_encode($data['data']); ?>
},
{
name:legend[2],
type:'line',
yAxisIndex:1,
//symbol:'none',
smooth:false,
data:<?php echo json_encode($data2['data']); ?>
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
</body>
</html>
+93
View File
@@ -0,0 +1,93 @@
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="utf-8">
</head>
<?php
ini_set('error_reporting', E_ALL);
include_once "inc/getData.inc.php";
$day_st='20180101';
$day_end=date('Ymd');
$data=getIndexData('000001.SH',$day_st,$day_end);
$data1=getIndexData('399001.SZ',$day_st,$day_end);
$legend=array('上证综指','深证成指');
?>
<body style="height: 100%; margin: 0">
<div id="container" style="height: 400px;width: 1000px"></div>
<script type="text/javascript" src="../js/echarts.min.js"></script>
<script type="text/javascript" src="../js/echarts-gl.min.js"></script>
<script type="text/javascript" src="../js/ecStat.min.js"></script>
<script type="text/javascript" src="../js/dataTool.min.js"></script>
<script type="text/javascript" src="../js/simplex.js"></script>
<script type="text/javascript" src="../js/grey.js"></script>
<script type="text/javascript">
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'grey');
var app = {};
option = null;
legend = <?php echo json_encode($legend);?>;
option = {
title: {
text: '历史数据折线图',
subtext:"双轴显示",
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
//type: 'time',
boundaryGap: false,
data: <?php echo json_encode($data['tDate']); ?>
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true
},
{
type:'value',
name:legend[1], //图例
//scale:true, //true 不强制包含0刻度
boundaryGap:false,
show:true
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
data:<?php echo json_encode($data['idx']); ?>
},
{
name:legend[1],
type:'line',
yAxisIndex:1,
data:<?php echo json_encode($data1['idx']); ?>
}
]
};
;
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
</script>
</body>
</html>
+93
View File
@@ -0,0 +1,93 @@
var cfg = window.chartConfig;
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: legend[0]+' V.S '+legend[2],
text: cfg.title,
subtext: cfg.subtitle,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true,
scale:true,
},
{
type:'value',
name:legend[1]+'-'+unit, //图例
scale:true, //auto sacle
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data: cfg.data,
},
{
name:legend[1],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data: cfg.data2,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+16
View File
@@ -0,0 +1,16 @@
<?php
/**
* Created by Simon
* For stock index compare and draw in echart
* Date: 2019/5/26
*
**/
#set dispay_errors to adjust when coding
ini_set('display_errors',1);
?>
<form name ="myform" id="myform" method="post">
<input type="hidden" name="x" id= "x" value='<?php //echo json_encode=($l_x)?>' />
</form>
<script src='../js/echarts.min.js'></script>
<script src='js/itrend.basic.js'
+16
View File
@@ -0,0 +1,16 @@
<?php
ini_set("display_errors","On");
ini_set('error_reporting', 'E_ALL & ~E_NOTICE');
include_once("getBasic.inc.php");
$link = mysqli_connect('localhost', 'root', 'nancysimon', 'myquant');
if (!$link) {
die('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
echo 'Success... ' . mysqli_get_host_info($link) . "\n";
mysqli_close($link);
log_pv();
?>
+77
View File
@@ -0,0 +1,77 @@
var cfg = window.chartConfig;
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: cfg.legend[0]+' V.S '+cfg.legend[2],
text: cfg.title,
//subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:cfg.legend[0], //图列
show:true,
scale:true,
//min:190000,
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:cfg.legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:cfg.data,
itemStyle:{normal:{label:{show:true}}}, //显示数字
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+62
View File
@@ -0,0 +1,62 @@
<?php
include_once "../inc/getBasic.inc.php";
$_REQUEST['code']=$_REQUEST['code']?$_REQUEST['code']:'ShareHDNum'; #code:sh sz zx cy
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2006-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:'';
$title="指数VS机构持仓";
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指标代码:
<select name='code' id='code'>
<option value='ShareHDNum'>持股数-亿股</option>
<option value='vPosition'>持股金额-亿元</option>
<option value='VSRatio'>每股单价-元</option>
</select>&nbsp;
<script>
document.getElementById('code').value='<?=$_REQUEST['code']?>';
</script>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>'>
<input type='submit' value="给我查!">
<div >&nbsp;</div>
<input type='checkbox' id='cb_01' onclick="hideSwitch(this.id,'1')" > 基金
<input type='checkbox' id='cb_02' onclick="hideSwitch(this.id,'2')" checked> QFII
<input type='checkbox' id='cb_03' onclick="hideSwitch(this.id,'3')" > 社保
<input type='checkbox' id='cb_04' onclick="hideSwitch(this.id,'4')" > 券商
<input type='checkbox' id='cb_05' onclick="hideSwitch(this.id,'5')" > 保险
<input type='checkbox' id='cb_06' onclick="hideSwitch(this.id,'6')" > 信托
</div> </form>
<div >&nbsp;</div>
<!-- https://echart.doorcome.cn/charts/chartThree.php?lx=1&share=vPosition&s=2010-01-01 -->
<div style="width:100%; text-align:center;display:None" id='1'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=1&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
<div >&nbsp;</div>
</div>
<div style="width:100%; text-align:center; display:block;" id='2'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=2&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
<div >&nbsp;</div>
</div>
<div style="width:100%; text-align:center; display:None;" id='3'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=3&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='4'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=4&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='5'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=5&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='6'>
<iframe src="https://echart.doorcome.cn/charts/chartThree.php?s=<?=$_REQUEST['t_start']?>&lx=6&share=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<?php include_once "../html/footer.php"; ?>
View File
+56
View File
@@ -0,0 +1,56 @@
<?php
$_REQUEST['code']=$_REQUEST['code']?$_REQUEST['code']:'sh'; #code:sh sz zx cy
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:'';
$title="指数VS PE/PB/PS/市值 趋势";
include_once "html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
指数代码:
<select name='code' id='code'>
<option value='sh'>上证指数</option>
<option value='sz'>深圳成指</option>
<option value='zx'>中小板指</option>
<option value='cy'>创业板指</option>
</select>&nbsp;
<script>
document.getElementById('code').value='<?=$_REQUEST['code']?>';
</script>
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<input type='submit' value="给我查!">
<div >&nbsp;</div>
<input type='checkbox' id='cb_pe' onclick="hideSwitch(this.id,'pe_ttm')" checked> PE_TTM 市盈率
<input type='checkbox' id='cb_pb' onclick="hideSwitch(this.id,'pb')" > PB 市净率
<input type='checkbox' id='cb_ps' onclick="hideSwitch(this.id,'ps')" > PS 市销率
<input type='checkbox' id='cb_total_mv' onclick="hideSwitch(this.id,'total_mv')" > 总市值
<input type='checkbox' id='cb_circ_mv' onclick="hideSwitch(this.id,'circ_mv')" > 流通市值
</div> </form>
<div >&nbsp;</div>
<!--https://echart.doorcome.cn/chartFive.php?s=20071001&code=sz&item=total_mv-->
<div style="width:100%; text-align:center" id='pe_ttm'>
<iframe src="https://echart.doorcome.cn/chartFive.php?s=<?=$_REQUEST['t_start']?>&item=pe_ttm&code=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='pb'>
<iframe src="https://echart.doorcome.cn/chartFive.php?s=<?=$_REQUEST['t_start']?>&item=pb&code=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='ps'>
<iframe src="https://echart.doorcome.cn/chartFive.php?s=<?=$_REQUEST['t_start']?>&item=ps&code=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='total_mv'>
<iframe src="https://echart.doorcome.cn/chartFive.php?s=<?=$_REQUEST['t_start']?>&item=total_mv&code=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='circ_mv'>
<iframe src="https://echart.doorcome.cn/chartFive.php?s=<?=$_REQUEST['t_start']?>&item=circ_mv&code=<?=$_REQUEST['code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<?php include_once "html/footer.php"; ?>
+107
View File
@@ -0,0 +1,107 @@
<div class="layui-form-item">
<label class="layui-form-label">股票代码:</label>
<div class="layui-input-block" id="ccc">
<input type="text" name="stockcode" value="{$data.stockcode}" autocomplete="off" class="layui-input" id="kw" onKeyup="getContent(this);">
<div id="append"></div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">股票名称:</label>
<div class="layui-input-block">
<input type="text" name="stockname" value="{$data.stockname}" autocomplete="off" class="layui-input" id="codename">
<input type="hidden" name="" value="" class="layui-input" id="hiddenname">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$(document).keydown(function(e){
e = e || window.event;
var keycode = e.which ? e.which : e.keyCode;
if(keycode == 38){
if(jQuery.trim($("#append").html())==""){
return;
}
movePrev();
}else if(keycode == 40){
if(jQuery.trim($("#append").html())==""){
return;
}
$("#kw").blur();
if($(".item").hasClass("addbg")){
moveNext();
}else{
$(".item").removeClass('addbg').eq(0).addClass('addbg');
}
}else if(keycode == 13){
dojob();
}
});
var movePrev = function(){
$("#kw").blur();
var index = $(".addbg").prevAll().length;
if(index == 0){
$(".item").removeClass('addbg').eq($(".item").length-1).addClass('addbg');
}else{
$(".item").removeClass('addbg').eq(index-1).addClass('addbg');
}
}
var moveNext = function(){
var index = $(".addbg").prevAll().length;
if(index == $(".item").length-1){
$(".item").removeClass('addbg').eq(0).addClass('addbg');
}else{
$(".item").removeClass('addbg').eq(index+1).addClass('addbg');
}
}
var dojob = function(){
$("#kw").blur();
var value = $(".addbg").text();
$("#kw").val(value);
$("#append").hide().html("");
}
});
function getContent(obj){
var kw = jQuery.trim($(obj).val());
if(kw == ""){
$("#append").hide().html("");
return false;
}
$.ajax({
url:"{:U('question/stock')}",
data:{"key":kw},
dataType:"json",
type:"POST",
success:function(data){
var html = "";
for (var i = 0; i < data.length; i++) {
if (data[i][0].indexOf(kw) >= 0) {
html = html + "<div namelist="+data[i][4]+" codelist="+data[i][0]+" class='item' onmouseenter='getFocus(this)' onClick='getCon(this);'>"+data[i][0]+"--"+data[i][4]+"</div>"
}
}
if(html != ""){
$("#append").show().html(html);
}else{
$("#append").hide().html("");
}
}
});
}
function getFocus(obj){
$(".item").removeClass("addbg");
$(obj).addClass("addbg");
}
function getCon(obj){
var value = $(obj).attr('codelist')
var name = $(obj).attr('namelist');
console.log(name)
$("#kw").val(value);
$("#codename").val(name);
$("#append").hide().html("");
}
</script>
+45
View File
@@ -0,0 +1,45 @@
<?php
include_once "../inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:'';
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS机构持仓趋势:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "../html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>'>
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<input type='submit' value="给我查!">
<div >&nbsp;</div>
<input type='checkbox' id='cb_f9' onclick="hideSwitch(this.id,'F9')" checked> 持股数
<input type='checkbox' id='cb_f10' onclick="hideSwitch(this.id,'F10')" checked> 持股金额
<input type='checkbox' id='cb_f11' onclick="hideSwitch(this.id,'F11')" checked> 占流通股比例
<input type='checkbox' id='cb_f12' onclick="hideSwitch(this.id,'F12')" checked> 占总股本比例
</div> </form>
<div >&nbsp;</div>
<div style="width:100%; text-align:center" id='F9'>
<iframe src="https://echart.doorcome.cn/charts/chartSix.php?s=<?=$_REQUEST['t_start']?>&item=F9&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; " id='F10'>
<iframe src="https://echart.doorcome.cn/charts/chartSix.php?s=<?=$_REQUEST['t_start']?>&item=F10&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; " id='F11'>
<iframe src="https://echart.doorcome.cn/charts/chartSix.php?s=<?=$_REQUEST['t_start']?>&item=F11&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div style="width:100%; text-align:center; " id='F12'>
<iframe src="https://echart.doorcome.cn/charts/chartSix.php?s=<?=$_REQUEST['t_start']?>&item=F12&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<?php include_once "../html/footer.php"; ?>
+36
View File
@@ -0,0 +1,36 @@
<?php
include_once "inc/getBasic.inc.php";
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'000001';
$_REQUEST['t_start']=$_REQUEST['t_start']?$_REQUEST['t_start']:'2015-01-01';
$_REQUEST['t_end']=$_REQUEST['t_end']?$_REQUEST['t_end']:'';
$ts_name = tscodeToName(ts_code_conv($_REQUEST['ts_code']));
$title="股价VS PE/PB/PS 趋势:".$ts_name.'('.$_REQUEST['ts_code'].')';
include_once "html/head.php";
?>
<form name="main" id="main" method="get"> <div style="width:100%;text-align:center">
股票代码: <input type='text' name='ts_code' id='ts_code' width="30px" value='<?=$_REQUEST['ts_code']?>' >
开始时间: <input type='date' name='t_start' id='t_start' width='30px' value='<?=$_REQUEST['t_start']?>' >
结束时间: <input type='date' name='t_end' id='t_end' width='30px' value='<?=$_REQUEST['t_end']?>' >
<input type='submit' value="给我查!">
<div >&nbsp;</div>
<input type='checkbox' id='cb_pe' onclick="hideSwitch(this.id,'pe_ttm')" checked> PE_TTM 市盈率
<input type='checkbox' id='cb_pb' onclick="hideSwitch(this.id,'pb')" > PB 市净率
<input type='checkbox' id='cb_ps' onclick="hideSwitch(this.id,'ps')" > PS 市销率
</div> </form>
<div >&nbsp;</div>
<div style="width:100%; text-align:center" id='pe_ttm'>
<iframe src="https://echart.doorcome.cn/chartFore.php?s=<?=$_REQUEST['t_start']?>&item=pe_ttm&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='pb'>
<iframe src="https://echart.doorcome.cn/chartFore.php?s=<?=$_REQUEST['t_start']?>&item=pb&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<div >&nbsp;</div>
<div style="width:100%; text-align:center; display:None;" id='ps'>
<iframe src="https://echart.doorcome.cn/chartFore.php?s=<?=$_REQUEST['t_start']?>&item=ps&ts_code=<?=$_REQUEST['ts_code']?>&e=<?=$_REQUEST['t_end']?>"
height="400px" width="1000px"></iframe>
</div>
<?php include_once "html/footer.php"; ?>
+25
View File
@@ -0,0 +1,25 @@
<div id='footer'>
<p>&nbsp;</p>
<hr style='text-align: center;width: 980px;border-width: 0;background-color: gray;height: 1px;' id='foot_hr' >
<div style='text-align: center'>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 style='text-align: center'>
<span style="color: grey; font-size: x-small; ">
<a href="https://beian.miit.gov.cn" target="_blank">浙ICP备18056264号-1</a>
</span>
<span style='color:grey;font-size:small;'>
<?php
include_once __DIR__ . "/../inc/functions.inc.php";
page_counter();
?>
</span>
</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
</div>
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html >
<html>
<?php global $title; ?>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="/lib/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="/lib/js/echarts-5.4.2.js"></script>
<script type="text/javascript" src="/lib/js/datatables-1.13.4.min.js"></script>
<script type="text/javascript" src="/js/pubfunc.js?version=0.14"></script>
<link href="/css/style.css?version=0.7" rel="stylesheet" type="text/css">
<link href="/lib/css/datatables-1.13.4.min.css" rel="stylesheet" type="text/css">
<title><?=$title?></title>
</head>
<body>
<div >&nbsp;</div>
<div style="text-align: center"><h2> <?=$title?> </h2></div>
+11
View File
@@ -0,0 +1,11 @@
<?php ini_set("display_errors","1"); ?>
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
<html style="height: 100%">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<script type="text/javascript" src="/lib/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="/lib/js/echarts-5.4.2.js"></script>
</head>
<body style="height: 100%; margin: 0">
<div id="container" style="height: 400px;width: 1000px"></div>
+188
View File
@@ -0,0 +1,188 @@
<?php
ini_set("display_errors","0");
include_once __DIR__."/config.php";
include_once __DIR__."/getEstate.inc.php";
$mysqli = get_mysqli_connection();
//ajax: get stock list for select
if($_REQUEST['t']=='stockList'){
if($_REQUEST['t_vendor']=='方正证券'){
$sql= <<< EOF
select distinct(ts_code) ts_code,ts_name from trade_record
where tprice>0 and (ts_code not like '7%' and ts_code not like '1%') and length(trade_id)=5 order by ts_code
EOF;
}elseif($_REQUEST['t_vendor']=='长江证券'){
//length(0+ts_name)!=length(ts_name) 判断ts_name 不能为纯数字
$sql= <<< EOF
select distinct(ts_code) ts_code,ts_name from trade_record_cj
where tprice>0 and ts_code not like '7%' and length(0+ts_name)!=length(ts_name) order by ts_code
EOF;
}
$result = db_query($mysqli, $sql);
$data = $result->fetch_all(MYSQLI_ASSOC);
jsonResponse(['stocks' => $data, 'company' => $_REQUEST['t_vendor']]);
}
/**
* AJAX get finance Data from getFianceData class
*/
if($_REQUEST['t']=='financeData'){
include_once __DIR__."/getFinanceData.class.php";
include_once __DIR__."/getBasic.inc.php";
$years=yearList($_REQUEST['yst'],$_REQUEST['yed']);
$fina = new getFinance();
$fina->ts_code=$_REQUEST['ts_code'];
$dataAll=array();
foreach($years as $year){
$fina->finDate=$year;
$dataAll[] =$fina->getFinanceData();
}
for($i=0;$i<count($dataAll);$i++){
$n=0;
foreach ($dataAll[$i] as $key=>$val){
$n++;
if(strlen($n)<2) $n='0'.$n;
if($key=='ts_code') {
$key=$n.'.股票代码';
$val=tscodeToName($val);
$n--;
continue; //不显示股票代码
}elseif($key=='period') {
$key=$n.'.报告期';
$val=yearToname($val);
$n--;
continue; //不显示报告期
}else $key=$n.'.'.$key;
if($i==0) $data[$n][]=$key; //首列加
$data[$n][]=$val;
}
}
//strip key from array $data
//dataTable must NOT have any key of json
$data=array_values($data);
jsonResponse($data);
}
/*
*esfTBD: 二手房Trade By Day
*/
if($_REQUEST['t']=='esfTBD'){
$dataTrade=esfTradeDaily();
$dataList=esfListDaily();
jsonResponse(['dataTrade' => $dataTrade, 'dataList' => $dataList]);
}
/*
*esfListDaily: 二手房每日挂牌数量
*/
if($_REQUEST['t']=='esfListDaily'){
$data=esfListDaily();
jsonResponse(['datas' => $data]);
}
/*
*newTBD: 新房Trade By Day
*/
if($_REQUEST['t']=='newTBD'){
$district = $_REQUEST['district'];
$t_start = $_REQUEST['t_start'];
$t_end = $_REQUEST['t_end'];
if($_REQUEST['dm']=='Daily'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m-%d') td, eje.val district, eje1.val qty, eje2.val area
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='1' and ej.tdate >= ? and ej.tdate <= ?
order by date_format(tdate,'%Y-%m-%d') asc";
$params = [$district, $t_start, $t_end];
}
if($_REQUEST['dm']=='Monthly'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m') td, eje.val district, sum(eje1.val) qty, sum(eje2.val) area
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='1'";
$params = [$district];
if($t_start) { $sql .= " and ej.tdate >= ?"; $params[] = $t_start . '-01'; }
if($t_end) {
$endDate = new DateTime($t_end);
$endDate->modify('last day of this month');
$sql .= " and ej.tdate <= ?";
$params[] = $endDate->format('Y-m-d');
}
$sql .= " group by date_format(tdate,'%Y-%m') order by date_format(tdate,'%Y-%m') asc";
}
$result = db_query($mysqli, $sql, $params);
$data = $result->fetch_all(MYSQLI_ASSOC);
if($_REQUEST['dm']=='Daily'){
$sql2 = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m-%d') td, eje.val district, eje1.val area, eje2.val qty
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='4' and ej.tdate >= ? and ej.tdate <= ?
order by date_format(tdate,'%Y-%m-%d') asc";
$params2 = [$district, $t_start, $t_end];
}
if($_REQUEST['dm']=='Monthly'){
$sql2 = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m-%d') td, eje.val district, max(eje1.val) area, max(eje2.val) qty
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='4'";
$params2 = [$district];
if($t_start) { $sql2 .= " and ej.tdate >= ?"; $params2[] = $t_start . '-01'; }
if($t_end) {
$endDate = new DateTime($t_end);
$endDate->modify('last day of this month');
$sql2 .= " and ej.tdate <= ?";
$params2[] = $endDate->format('Y-m-d');
}
$sql2 .= " group by date_format(tdate,'%Y-%m') order by date_format(tdate,'%Y-%m') asc";
}
$result = db_query($mysqli, $sql2, $params2);
$data2 = $result->fetch_all(MYSQLI_ASSOC);
jsonResponse(['datas' => $data, 'dataExt' => $data2]);
}
/*
* moneyflowData: 资金流向数据
*/
if($_REQUEST['t']=='moneyflowData'){
include_once __DIR__."/getData.inc.php";
include_once __DIR__."/getBasic.inc.php";
$code = $_REQUEST['code'] ?? 'sh';
$hsgt = $_REQUEST['hsgt'] ?? 'north_money';
$stacked = $_REQUEST['stacked'] ?? '1';
$t_start = $_REQUEST['t_start'] ?? '2015-06-01';
$t_end = $_REQUEST['t_end'] ?? date('Y-m-d');
$indexData = getIndexData(codetocode($code), date('Ymd',strtotime($t_start)), date('Ymd',strtotime($t_end)));
$flowData = getMoneyFlowData($hsgt, date('Ymd',strtotime($t_start)), date('Ymd',strtotime($t_end)), $stacked);
jsonResponse([
'indexData' => $indexData['data'],
'flowData' => $flowData['data'],
'data_max' => $flowData['data_max'],
'data_min' => $flowData['data_min'],
'data_avg' => $flowData['data_avg'],
'data_last' => $flowData['data_last'],
]);
}
/*
* estateData: 房地产挂牌数据
*/
if($_REQUEST['t']=='estateData'){
include_once __DIR__."/getEstate.inc.php";
$city = $_REQUEST['city'] ?? '宁波';
$t_start = $_REQUEST['t_start'] ?? '2023-06-20';
$t_end = $_REQUEST['t_end'] ?? date('Y-m-d');
$data = getEstateData($city, $t_start, $t_end);
jsonResponse($data);
}
+63
View File
@@ -0,0 +1,63 @@
<?php
define('TUSHARE_API_TOKEN', '1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea');
function get_db_config() {
return [
'host' => 'localhost',
'username' => 'myquant',
'password' => '_H(lU1_fF*9baRTp',
'database' => 'myquant',
'charset' => 'utf8mb4'
];
}
function get_mysqli_connection() {
$db_config = get_db_config();
$mysqli = new mysqli(
$db_config['host'],
$db_config['username'],
$db_config['password'],
$db_config['database']
);
if ($mysqli->connect_error) {
die("Connection failed: " . $mysqli->connect_error);
}
$mysqli->set_charset($db_config['charset']);
return $mysqli;
}
/**
* 参数化查询,防止SQL注入。返回mysqli_result或false。
* @param mysqli $mysqli
* @param string $sql 带 ? 占位符的SQL
* @param array $params 参数值数组
* @return \mysqli_result|false
*/
function db_query($mysqli, $sql, $params = []) {
$stmt = $mysqli->prepare($sql);
if (!$stmt) return false;
if ($params) {
$types = str_repeat('s', count($params));
$stmt->bind_param($types, ...$params);
}
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
return $result;
}
/**
* 统一JSON响应格式
* @param mixed $data 响应数据
* @param string $status ok|error
* @param string $message 错误信息
*/
function jsonResponse($data = null, $status = 'ok', $message = '') {
$response = ['status' => $status];
if ($data !== null) $response['data'] = $data;
if ($message) $response['message'] = $message;
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit();
}
+151
View File
@@ -0,0 +1,151 @@
<?php
require_once "vendor/autoload.php";
include_once __DIR__."/config.php";
use PhpOffice\PhpSpreadsheet\Reader\Csv;
/**
* Read an excel file and return an array of excel cell data.
* @param $file: excel file to read.
* @return array
*/
function readMyExcel($file): array
{
//$inputFileName = dirname(__FILE__) . '/xls/fz20180501-20190101.xls';
//$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file);
$reader = new Csv();
$reader->setInputEncoding("CP936");
//$reader->setCodepage("CP936");
$excel = $reader->load($file);
return $excel->getActiveSheet()->toArray(null,true,true,false);
}
/**
* Upload excel data to mysql table trade_record
* @param $data: array which get from excel file.
* @param $company: 证券公司名
* @return array: msg
*/
function dbOp($data,$company)
{
$mysqli = get_mysqli_connection();
$maxrow = count($data);
$maxcol = count($data[0]);
$msg = array();
for ($row = 0; $row < $maxrow; $row++) {
if ($row == 0) {
//检查文件与证券公司是否匹配
if(($data[$row][4]=='买卖标志' and $company=='方正证券') or ($data[$row][4]=='操作' and $company=='长江证券'))
continue; //skip 1st row;
else{
echo json_encode(array(
"status" => "-1",
"row1"=> $data[$row],
'company'=> $company,
"msg" => "文件格式不正确或与证券公司不匹配,请重试!",
));
return false;
}
}
//处理时间字段, 方正证券格式: hhmmss需要特别处理, 长江证券时间格式正常: hh:mm:ss
$tm = $data[$row][1]; //format $time
if ($tm == 0) $data[$row][1] = '00:00:00';
elseif($company=='方正证券') $data[$row][1] = substr($tm, 0, -4) . ':' . substr($tm, -4, 2) . ':' . substr($tm, -2);
//处理长江证券的改动:去掉item 9,15,重置键名
if($company=='长江证券'){
unset($data[$row][9]);
unset($data[$row][15]);
$data[$row]=array_values($data[$row]);
$maxcol = count($data[$row]); //重置 maxcol
}
/**
* addslashes处理
* 方正证券14 其他费用,15:备注(需要处理)
* 长江证券14备注(需要处理),15:交易市场
*/
$data[$row][14] = addslashes($data[$row][14]); // add slash avoid sql clash
$data[$row][15] = addslashes($data[$row][15]); // add slash avoid sql clash
// duplicate check for each row
if (recordDupCheck($data[$row], $mysqli,$company)) {
$msg[] = addslashes("Row <span style='color:#ff0000'> $row </span> exist. Skip!<br />");
continue;
}
//else var_dump($data[$row]);
$values = ''; //initial $values;
for ($col = 0; $col < $maxcol; $col++) {
$values .= "'" . $data[$row][$col] . "',";
}
$values = rtrim($values, ','); //如果需要,此行去除末尾逗号(,)
if($company=='方正证券') {
$sql = <<<EOF
insert into
trade_record(
`tdate`,`ttime`, `ts_code`, `ts_name`, `flg`, `tprice`, `tvol`,
`trade_id`, `entrust_id`, `holder_code`, `tamount`, `commission`,
`tax1`, `tax2`, `tax3`, `note`, `t_vendor`)
values(
$values,
'$company'
)
EOF;
}elseif($company=='长江证券'){
$sql = <<< EOF
insert into
trade_record_cj(
`tdate`, `ttime`, `ts_code`, `ts_name`, `flg`, `tvol`, `tprice`,
`tamount`, `entrust_id`, `trade_id`, `tax1`, `tax2`, `tax3`,
`ttl_amount`, `note`, `trade_mkt`, `uaccount`, `t_vendor`)
values(
$values,
'$company'
)
EOF;
}
$mysqli->query($sql) or die("Data upload failure: " . $sql);
unset($values); //release $values;
$msg[] = addslashes("Row <span style='color:#ff0000'> $row </span> uploaded.<br />");
}
$msg[] = addslashes("All data uploaded!<p />");
$mysqli->close();
return $msg;
}
/**
* Duplicate check of each row by given $row
* @param $row: data of 1 row
* @param $mysqli: mysqli handle
* @return bool return true if record exist
*/
function recordDupCheck($row,$mysqli,$company): bool
{
if($company=='方正证券') {
$sql = <<< EOF
select *
from trade_record
where
tdate = '$row[0]'
and ttime = '$row[1]'
and ts_code = '$row[2]'
and note = '$row[15]'
EOF;
}elseif($company=='长江证券') {
$sql = <<< EOF
select *
from trade_record_cj
where
tdate = '$row[0]'
and ttime = '$row[1]'
and ts_code = '$row[2]'
and note = '$row[14]'
EOF;
}
$result=$mysqli->query($sql) or die($sql."<br />\n");
$r = $result->num_rows;
$result->free();
if($r > 0) return true;
else return false;
}
+203
View File
@@ -0,0 +1,203 @@
<?php
include_once __DIR__ . "/config.php";
/**
* 宁波各区县List
*/
function districtList(){
?>
<select name='district' id='district'>
<option value='北仑区'>北仑区</option>
<option value='余姚市'>余姚市</option>
<option value='海曙区'>海曙区</option>
<option value='江北区'>江北区</option>
<option value='镇海区'>镇海区</option>
<option value='鄞州区'>鄞州区</option>
<option value='奉化区'>奉化区</option>
<option value='慈溪市'>慈溪市</option>
<option value='宁海县'>宁海县</option>
<option value='象山县'>象山县</option>
<option value='合计'>合计</option>
</select>
<?php
}
function indexList($id='code'): void{
?>
<select name='<?=$id?>' id='<?=$id?>'>
<option value='000001.SH'>上证指数</option>
<option value='399001.SZ'>深圳成指</option>
<option value='399005.SZ'>中小板指</option>
<option value='399006.SZ'>创业板指</option>
<option value='000016.SH'>上证50</option>
<option value='399300.SZ'>沪深300</option>
<option value='399905.SZ'>中证500</option>
<option value='899050.BJ'>北证50</option>
</select>
<?php
}
/* 证券交易所list */
function seList($id='se'): void{
?>
<select name='<?=$id?>' id='<?=$id?>'>
<option value='SSE'>上交所</option>
<option value='SZSE'>深交所</option>
<option value='BSE'>北交所</option>
</select>
<?php
}
/* select list by Day month */
function byDM($id,$oid,$nid){
$str=<<<EOF
<select name='{$id}' id='{$id}' onchange="dmChange('{$id}','{$oid}','{$nid}');">
<option value='Daily'>Daily</option>
<option value='Monthly'>Monthly</option>
</select>
EOF;
echo $str;
}
// 辅助函数:调用TuShare API
function callTushareApi($method, $params){
$token = TUSHARE_API_TOKEN;
// 将参数编码为JSON格式
$postData = json_encode([
"api_name" => $method,
"token" => $token,
"params" => $params,
"fields" => "" // 其他字段需要根据具体API调整
]);
// 初始化cURL会话
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://api.tushare.pro');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Content-Length: ' . strlen($postData)
]);
// 执行cURL请求
$response = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
// 调试输出:打印请求和响应信息
if (debug_enabled()) { // 假设这是一个函数,用于检查是否启用了调试模式
error_log("TuShare API Request: " . $postData);
error_log("TuShare API Response: " . $response);
}
// 错误处理
if ($err) {
error_log("cURL error: " . $err);
return "cURL error: " . $err;
}
$responseData = json_decode($response, true);
// 检查API调用是否成功
if (isset($responseData['code']) && $responseData['code'] != 200) {
error_log("TuShare API Error: " . $responseData['msg']);
return "TuShare API Error: " . $responseData['msg'];
}
if (isset($responseData['data']) && isset($responseData['data']['items'])) {
return $responseData['data']['items'];
} else {
return [];
}
}
/**
* 调用 api.doorcome.cn 获取实时数据
*/
function callDoorcomeApi($endpoint, $params = []) {
$url = 'https://api.doorcome.cn/api/' . $endpoint;
if ($params) {
$url .= '?' . http_build_query($params);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
if ($err) {
error_log("Doorcome API error [$endpoint]: " . $err);
return null;
}
return json_decode($resp, true);
}
// 假设的调试模式开关函数
function debug_enabled()
{
return true;
}
/**
* 记录页面访问日志
*/
function log_pv(){
$mysqli = get_mysqli_connection();
$vpage = $_SERVER['PHP_SELF'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$ip = $_SERVER['REMOTE_ADDR'];
$qs = $_SERVER['QUERY_STRING'];
$vtime = date("Y-m-d H:i:s");
$sql = "insert into pv_log(vpage,querystring,remoteip,ua,vtime) values (?,?,?,?,?)";
db_query($mysqli, $sql, [$vpage, $qs, $ip, $ua, $vtime]);
$mysqli->close();
}
/**
* 页面访问计数器,输出命中数
*/
function pv_counter($user=''){
$mysqli = get_mysqli_connection();
$page = $_SERVER['PHP_SELF'];
$lmtime = date("Y-m-d H:i:s");
$ip = $_SERVER['REMOTE_ADDR'];
$result = db_query($mysqli, "select hits from pv_counter where page_name = ?", [$page]);
$rt = $result->fetch_all(MYSQLI_ASSOC);
$n = count($rt);
if($n < 1){
db_query($mysqli,
"insert into pv_counter(page_id,Page_name,hits,lm_date,lm_ip,lm_user) values (null,?,1,?,?,?)",
[$page, $lmtime, $ip, $user]);
$hits = 1;
} elseif($n == 1){
$hits = $rt[0]['hits'] + 1;
db_query($mysqli,
"update pv_counter set hits = ?, lm_date = ?, lm_ip = ?, lm_user = ? where page_name = ?",
[$hits, $lmtime, $ip, $user, $page]);
} else {
$mysqli->close();
return "<p align='center'>There is error on pv_counter</p>";
}
$result = db_query($mysqli, "select sum(hits) hits_all from pv_counter");
$hits_all = $result->fetch_all(MYSQLI_ASSOC);
$mysqli->close();
echo "Page hits: " . $hits . " Total: " . $hits_all[0]['hits_all'];
}
/**
* 页面访问统计(日志+计数器)
*/
function page_counter(){
log_pv();
pv_counter();
}
?>
+257
View File
@@ -0,0 +1,257 @@
<?php
include_once __DIR__."/config.php";
include_once __DIR__."/functions.inc.php";
include_once __DIR__."/widgets.inc.php";
/**
* 获取PE_TTM,PB,PS等历史数据
* @param $ts_code ts code
* @param $day_st start date
* @param $day_end end date
* @param $item: PE_TTM, PB,PS
* @return array
*/
function getBasicData($ts_code,$day_st,$day_end,$item){
$allowed_items = ['PE_TTM', 'PB', 'PS', 'pe_ttm', 'pb', 'ps'];
if(!in_array($item, $allowed_items)) return array('tDate'=>[],'idx'=>[],'data'=>[],'data_max'=>0,'data_min'=>0,'data_avg'=>0,'data_last'=>0);
$day_st=date('Ymd',strtotime($day_st));
$mysqli = get_mysqli_connection();
$sql = "select DATE_FORMAT(trade_date,'%Y-%m-%d') as trade_date, $item as pe_ttm from stock_his_basic_pro where ts_code = ? and trade_date > ?";
$params = [$ts_code, $day_st];
if($day_end) {
$day_end=date('Ymd',strtotime($day_end));
$sql .= " and trade_date < ?";
$params[] = $day_end;
}
$sql .= " order by trade_date asc";
$result = db_query($mysqli, $sql, $params);
$tDate=$idx=$data=$data_clean=array(); # $data_clean is an array without null
if($result && $result->num_rows>0) {
#$data = $result->fetch_all();
while($row=$result->fetch_assoc()){
$trade_date=$row['trade_date'];
#$trade_date=substr($row['trade_date'],0,4).'-'.substr($row['trade_date'],4,2).'-'.substr($row['trade_date'],6,2);
#$trade_date1=strtotime($row['trade_date']);
array_push($tDate,$trade_date);
array_push($idx,$row['pe_ttm']);
$data_tmp = array("value"=>array($trade_date,$row['pe_ttm']));
array_push($data,$data_tmp);
if($data_tmp['value'][1]>0) array_push($data_clean,$data_tmp['value'][1]);
}
}
$data_last= round($data_clean[count($data_clean)-1],2);
$data_max= round(max($data_clean),2);
$data_min= round(min($data_clean),2);
if(count($data_clean)>0) $data_avg= round(array_sum($data_clean)/count($data_clean),2);
else $data_avg=null;
#Free result and close connection.
$result->free();
$mysqli->close();
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
function ts_code_conv($ts_code){
$tmp = explode('.',$ts_code);
switch($tmp[1]){
case 'SZ':
return $ts_code;
case 'SH':
return $ts_code;
case 'sz':
return strtoupper($ts_code);
case 'sh':
return strtoupper($ts_code);
default:
if(substr($tmp[0],0,2)=='60') return $tmp[0].'.SH';
elseif(substr($tmp[0],0,2)=='30') return $tmp[0].'.SZ';
elseif(substr($tmp[0],0,2)=='00') return $tmp[0].'.SZ';
else return $ts_code;
}
}
function getStockHist($ts_code,$day_st,$day_end){
$tDate=$idx=$data=array();
$ds = preg_replace('/\D/', '', $day_st);
$de = $day_end ? preg_replace('/\D/', '', $day_end) : date('Ymd');
$resp = callDoorcomeApi('stockbasic', ['tscode' => $ts_code, 'start_date' => $ds, 'end_date' => $de]);
if ($resp && is_array($resp)) {
foreach ($resp as $row) {
$d = $row['trade_date'];
array_push($tDate, $d);
array_push($idx, $row['close']);
array_push($data, ["value" => [$d, $row['close']]]);
}
}
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data);
}
function tscodeToName($ts_code){
$resp = callDoorcomeApi('stockinfo', ['tscode' => $ts_code]);
if ($resp && isset($resp[0]['name'])) {
return $resp[0]['name'];
}
return $ts_code;
}
function getBasicExtData($ts_code,$item,$day_st,$day_end){
$mysqli = get_mysqli_connection();
$allowed_items = ['total_mv','circ_mv','total_mv_all','circ_mv_all','pe_ttm','pb','ps','total_share','float_share','free_share'];
if(!in_array($item, $allowed_items)) return array('tDate'=>[],'idx'=>[],'data'=>[],'data_max'=>0,'data_min'=>0,'data_avg'=>0,'data_last'=>0);
$extra_where = "";
if($item=='total_mv_all' or $item=='circ_mv_all') {
$extra_where = " and vol/10000/10000 > 1";
$ts_code='all';
$item=substr($item,0,-4);
}
$sql = "select * from stock_basic_ext where code = ? and item = ? and trade_date > ?";
$params = [$ts_code, $item, $day_st];
if($day_end) {
$sql .= " and trade_date < ?";
$params[] = $day_end;
}
$sql .= $extra_where . " order by trade_date asc";
$result = db_query($mysqli, $sql, $params);
$tDate=$idx=$data=array();
if($result && $result->num_rows>0) {
#$data = $result->fetch_all();
while($row=$result->fetch_assoc()){
if($item=='total_mv' or $item=='circ_mv') {
$row['vol']=$row['vol']/10000/10000; #单位:亿
}
$trade_date=substr($row['trade_date'],0,4).'-'.substr($row['trade_date'],4,2).'-'.substr($row['trade_date'],6,2);
#$trade_date=substr($row['trade_date'],0,4).'-'.substr($row['trade_date'],4,2).'-'.substr($row['trade_date'],6,2);
$trade_date=substr($row['trade_date'],0,10);
array_push($tDate,$trade_date);
array_push($idx,$row['vol']);
array_push($data,array("value"=>array($trade_date,round($row['vol'],2))));
}
}
#Free result and close connection.
$result->free();
$mysqli->close();
$data_last= round($idx[count($idx)-1],2);
$data_max= round(max($idx),2);
$data_min= round(min($idx),2);
if(count($idx)>0) $data_avg= round(array_sum($idx)/count($idx),2);
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
/**
* @param $date : given a date (yyyy-mm-dd)
* @param $gap : days +/- n(int)
* @return false|string
*/
function dateGap($date,$gap){
$str="$date $gap day";
return date('Y-m-d',strtotime($str));//日期天数相加函数
}
// 函数一:获取股票代码ts_code对应的历史pe_ttm、pb或ps
function getStockHistoryDataByTS($ts_code, $day_st, $item, $day_end = null){
//global $token;
// 参数校验
if (empty($ts_code) || empty($day_st) || !in_array(strtolower($item), ['pe_ttm', 'pb', 'ps'])) {
return "参数错误:股票代码、起始日期不能为空,查询项目必须为pe_ttm、pb或ps。";
}
// 处理日期参数
$params = [
"ts_code" => $ts_code,
"start_date" => $day_st,
"end_date" => $day_end ?? date("Y-m-d") // 如果为空,默认为今天
];
// 调用TuShare API获取数据
$data = callTushareApi('daily_basic', $params);
return true ;
if (empty($data)) {
return "未获取到数据,请检查参数或网络连接。";
}
// 提取指定项目的数据
$result = [];
$tDate = [];
$itemValues = [];
foreach ($data as $row) {
$tDate[] = $row['trade_date'];
$itemValues[] = $row[$item];
}
// 按日期排序(从远到近,默认已经是按日期排序的)
$tDate = array_reverse($tDate); // 默认TuShare按日期顺序是近到远,所以反转得到远到近
$itemValues = array_reverse($itemValues);
// 计算统计值
$dataMax = max($itemValues);
$dataMin = min($itemValues);
$dataAvg = array_sum($itemValues) / count($itemValues);
$dataLast = end($itemValues);
// 返回结果
return [
'tDate' => $tDate,
'data' => $itemValues,
'data_max' => $dataMax,
'data_min' => $dataMin,
'data_avg' => $dataAvg,
'data_last' => $dataLast
];
}
// 函数二:获取指数趋势历史数据
function getIndexHistoryDataByTS($ts_code, $day_st, $day_end = null)
{
global $token;
// 参数校验
if (empty($ts_code) || empty($day_st)) {
return "参数错误:股票代码和起始日期不能为空。";
}
// 处理日期参数
$params = [
"ts_code" => $ts_code,
"start_date" => $day_st,
"end_date" => $day_end ?? date("Y-m-d") // 如果为空,默认为今天
];
// 调用TuShare API获取数据
$data = callTushareApi('index_dailybasic', $params);
return true ;
if (empty($data)) {
return "未获取到数据,请检查参数或网络连接。";
}
// 提取指数点数值
$tDate = [];
$closeValues = [];
foreach ($data as $row) {
$tDate[] = $row['trade_date'];
$closeValues[] = $row['close']; // 假设close字段是指数点数值
}
// 按日期排序
$tDate = array_reverse($tDate);
$closeValues = array_reverse($closeValues);
// 返回结果
return [
'tDate' => $tDate,
'data' => $closeValues
];
}
?>
+239
View File
@@ -0,0 +1,239 @@
<?php
include_once __DIR__."/config.php";
include_once __DIR__."/functions.inc.php";
/*
上证指数:000001.SH
深证成指:399001.SZ
中小板指: 399005.SZ
创业板指:399006.SZ
*/
function getIndexData($ts_code,$day_st,$day_end){
$tDate=$idx=$data=array();
$ds = preg_replace('/\D/', '', $day_st);
$de = $day_end ? preg_replace('/\D/', '', $day_end) : date('Ymd');
$resp = callDoorcomeApi('indexDatas', ['tscode' => $ts_code, 'start_date' => $ds, 'end_date' => $de]);
if ($resp && is_array($resp)) {
foreach ($resp as $row) {
$d = substr($row['trade_date'],0,4).'-'.substr($row['trade_date'],4,2).'-'.substr($row['trade_date'],6,2);
array_push($tDate, $d);
array_push($idx, $row['close']);
array_push($data, ["value" => [$d, round($row['close'], 2)]]);
}
}
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data);
}
/*
#LX: 序号 1-6,分别代表基金,QFII, 社保,券商,保险,信托
#share: vposition 市值 f10, sahreHDnum 股数 f9
*/
function getIhData($lx,$share,$day_st,$day_end){
$mysqli = get_mysqli_connection();
if($share=='ShareHDNum' ) $shareSel="sum(f9)/100000000"; //持股数
elseif($share=='vPosition') $shareSel="sum(f10)/100000000"; //持股额
elseif($share=='VSRatio') $shareSel='f10/f9'; //每股价格
$sql = "select ih_date,$shareSel as ttl from ih_by_ts_code_ext where tp = ? and ih_date >= ?";
$params = [$lx, $day_st];
if($day_end) {
$sql .= " and ih_date <= ?";
$params[] = $day_end;
}
$sql .= " group by ih_date order by ih_date";
$result = db_query($mysqli, $sql, $params);
//echo $sql;
$tDate=$idx=$data=array();
if($result && $result->num_rows>0) {
#$data = $result->fetch_all();
while($row=$result->fetch_assoc()){
array_push($tDate,$row['ih_date']);
array_push($idx,$row['ttl']);
array_push($data,array("value"=>array($row['ih_date'],$row['ttl'])));
}
}
#Free result and close connection.
$result->free();
$mysqli->close();
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data);
}
function lxDefine($lx){
switch($lx){
case 1: return "公募基金";
case 2: return "QFII";
case 3: return "社保基金";
case 4: return "券商持仓";
case 5: return "保险持仓";
case 6: return "信托持仓";
}
}
/*
上证指数:000001.SH
深证成指:399001.SZ
中小板指: 399005.SZ
创业板指:399006.SZ
*/
function codetocode($code){
switch($code){
case 'sh':
return '000001.SH';
case 'sz':
return '399001.SZ';
case 'zx':
return '399005.SZ';
case 'cy':
return '399006.SZ';
case 'all':
return '000002.SH';
}
}
/**
* @param $code
* @return string|void
*/
function codeToName($code){
switch($code){
case 'sh':
return '上证';
case 'sz':
return '深证';
case 'zx':
return '中小板';
case 'cy':
return '创业板';
case 'all':
return 'A股';
}
}
/**
* 名称 类型 描述
trade_date str 交易日期
ggt_ss float 港股通(上海)
ggt_sz float 港股通(深圳)
hgt float 沪股通(百万元)
sgt float 深股通(百万元)
north_money float 北向资金(百万元)
south_money float 南向资金(百万元)
* @param $code
* @return false|string
*/
function hsgtConv($code){
switch ($code){
case 'ggt_ss':
return '港股通(上海)';
case 'ggt_sz':
return '港股通(深圳)';
case 'hgt':
return '沪股通';
case 'sgt':
return '深股通';
case 'north_money':
return '北向资金';
case 'south_money':
return '南向资金';
default:
return false;
}
}
function hkholdConv($code){
switch ($code){
case 'ratio':
return '持股比例(%)';
case 'vol':
return '持股数(万)';
default:
return false;
}
}
/*
#item: f9:持股数 f10:持股额 f11:占总股本比例 f12:占流通股比例
#LX: tp字段: 序号 1-6,分别代表基金,QFII, 社保,券商,保险,信托
*/
function getIhDataByStock($ts_code,$item,$lx,$day_st,$day_end){
$mysqli = get_mysqli_connection();
switch(strtoupper($item)){
case 'F9':
$item_sel = 'sum(f9)/10000';
break;
case 'F10':
$item_sel = 'sum(f10)/10000';
break;
case 'F11':
case 'F12':
$item_sel = "sum($item)";
break;
}
$sql = "select ts_code,ih_date,$item_sel as ttl from ih_by_ts_code_ext where ts_code = ? and ih_date > ?";
$params = [$ts_code, $day_st];
if($day_end) {
$sql .= " and ih_date < ?";
$params[] = $day_end;
}
if($lx) {
$sql .= " and tp = ?";
$params[] = $lx;
}
$sql .= " group by ih_date order by ih_date asc";
$result = db_query($mysqli, $sql, $params);
#echo $sql;
$tDate=$idx=$data=array();
if($result && $result->num_rows>0) {
#$data = $result->fetch_all();
while($row=$result->fetch_assoc()){
array_push($tDate,$row['ih_date']);
array_push($idx,$row['ttl']);
array_push($data,array("value"=>array($row['ih_date'],$row['ttl'])));
}
}
$data_last= round($idx[count($idx)-1],1);
$data_max= round(max($idx),1);
$data_min= round(min($idx),1);
if(count($idx)>0) $data_avg= round(array_sum($idx)/count($idx),1);
else $data_avg=null;
#Free result and close connection.
$result->free();
$mysqli->close();
return array('tDate'=>$tDate,'idx'=>$idx,'data'=>$data,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
function getMoneyFlowData($itm, $day_st,$day_end, $stacked){
$mysqli = get_mysqli_connection();
$allowed_cols = ['ggt_ss','ggt_sz','hgt','sgt','north_money','south_money'];
if(!in_array($itm, $allowed_cols)) return array('tDate'=>[],'data'=>[],'data_max'=>0,'data_min'=>0,'data_avg'=>0,'data_last'=>0);
if($stacked==1) $tb = 'moneyflow_hsgt_pro_ext';
else $tb = 'moneyflow_hsgt_pro';
$sql = "select trade_date, $itm as itm from $tb where trade_date >= ?";
$params = [$day_st];
if($day_end) {
$sql .= " and trade_date <= ?";
$params[] = $day_end;
}
$sql .= " order by trade_date asc";
$result = db_query($mysqli, $sql, $params);
$tDate=$data=array();
if($result && $result->num_rows>0) {
while($row=$result->fetch_assoc()){
$trade_date=date('Y-m-d',strtotime($row['trade_date']));
array_push($tDate,$row['itm']/100);
array_push($data,array("value"=>array($trade_date,round($row['itm']/100,2))));
}
}
#Free result and close connection.
$result->free();
$mysqli->close();
$data_last= round($tDate[count($tDate)-1],2);
$data_max= round(max($tDate),2);
$data_min= round(min($tDate),2);
if(count($tDate)>0) $data_avg= round(array_sum($tDate)/count($tDate),2);
return array('tDate'=>$tDate,'data'=>$data,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
?>
+96
View File
@@ -0,0 +1,96 @@
<?php
include_once __DIR__."/config.php";
function getEstateData($city, $fDate, $toDate){
$mysqli = get_mysqli_connection();
$sql = "SELECT city, listdate, sum(nums) as num FROM estate_listing where listdate >= ? and listdate <= ? and city = ? group by listdate";
$result = db_query($mysqli, $sql, [$fDate, $toDate, $city]);
$data=array();
if($result && $result->num_rows>0) {
while($row = $result->fetch_assoc()){
array_push($data,array("value"=>array($row['listdate'],$row['num'])));
}
}
return $data;
}
function esfTradeDaily(){
global $mysqli;
$district = $_REQUEST['district'];
$t_start = $_REQUEST['t_start'];
$t_end = $_REQUEST['t_end'];
if($_REQUEST['dm']=='Daily'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m-%d') td, eje.val district, eje1.val qty, eje2.val area
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='5' and ej.tdate >= ? and ej.tdate <= ?
order by ej.tdate asc";
$params = [$district, $t_start, $t_end];
}
if($_REQUEST['dm']=='Monthly'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m') td, eje.val district, sum(eje1.val) qty, sum(eje2.val) area
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+4
where ej.data_type='5'";
$params = [$district];
if($t_start) {
$sql .= " and ej.tdate >= ?";
$params[] = $t_start . '-01';
}
if($t_end) {
$endDate = new DateTime($t_end);
$endDate->modify('last day of this month');
$sql .= " and ej.tdate <= ?";
$params[] = $endDate->format('Y-m-d');
}
$sql .= " group by date_format(tdate,'%Y-%m') order by date_format(tdate,'%Y-%m') asc";
}
$result = db_query($mysqli, $sql, $params);
$data = $result->fetch_all(MYSQLI_ASSOC);
return $data;
}
function esfListDaily(){
global $mysqli;
$district = $_REQUEST['district'];
$t_start = $_REQUEST['t_start'];
$t_end = $_REQUEST['t_end'];
if($_REQUEST['dm']=='Daily'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m-%d') td, eje.val district, eje1.val qty, eje2.val price
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+5
where ej.data_type='8' and ej.tdate >= ? and ej.tdate <= ?
order by ej.tdate asc";
$params = [$district, $t_start, $t_end];
}
if($_REQUEST['dm']=='Monthly'){
$sql = "SELECT distinct(ej.uuid) uid, date_format(tdate,'%Y-%m') td, eje.val district, sum(eje1.val) qty, sum(eje2.val) price
FROM estate_json ej
left join estate_json_ext eje on ej.uuid=eje.uuid and eje.val = ?
left join estate_json_ext eje1 on eje1.id=eje.id+3
left join estate_json_ext eje2 on eje2.id=eje.id+5
where ej.data_type='8'";
$params = [$district];
if($t_start) {
$sql .= " and ej.tdate >= ?";
$params[] = $t_start . '-01';
}
if($t_end) {
$endDate = new DateTime($t_end);
$endDate->modify('last day of this month');
$sql .= " and ej.tdate <= ?";
$params[] = $endDate->format('Y-m-d');
}
$sql .= " group by date_format(tdate,'%Y-%m') order by date_format(tdate,'%Y-%m') asc";
}
$result = db_query($mysqli, $sql, $params);
$data = $result->fetch_all(MYSQLI_ASSOC);
return $data;
}
?>
+324
View File
@@ -0,0 +1,324 @@
<?php
include_once __DIR__."/getData.inc.php"; //类外调用方法
include_once __DIR__."/getBasic.inc.php"; //类外调用方法
class getFinance
{
private $url = "http://api.waditu.com";
private $token;
public $ts_code = '002273.SZ';
public $httpjsonStr;
public $finDate;
public $preFinDate;
public $param = array();
private $unitFactor = 100000000;
function __construct()
{
$this->token = TUSHARE_API_TOKEN;
$this->param['token'] = $this->token;
}
/**
* PHP发送Json对象数据
*
* @param $url 请求url
* @param $jsonStr 发送的json字符串,来自$param转换
* @return array
*/
function http_post_json()
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->httpjsonStr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($this->httpjsonStr)
)
);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array($httpCode, $response);
}
/**
* @param $ts_code
* @param $finDate 财报日期 如一季报日期:20220331
*/
function getFinanceData()
{
$this->ts_code = ts_code_conv($this->ts_code);
$balance = $this->getBalance();
$pre_balance = $this->getPreBalance();
$income = $this->getIncome();
$cash = $this->getCashflow();
$data = array();
$data['ts_code'] = $this->ts_code;
$data['period'] = $this->finDate;
$data['--运营数据--'] = ''; //空行
$data['现金额-亿'] = $cash['c_cash_equ_end_period'][0] / $this->unitFactor;
$data['现金占比率'] = $cash['c_cash_equ_end_period'][0] / $balance['total_assets'][0];
$data['存货-亿'] = $balance['inventories'][0] / $this->unitFactor;
$data['存货占比率'] = $balance['inventories'][0] / $balance['total_assets'][0];
#应收账票
$tmp = 0;
if ($balance['accounts_receiv'][0]) $tmp += $balance['accounts_receiv'][0];
if ($balance['notes_receiv'][0]) $tmp += $balance['notes_receiv'][0];
$data['应收账票-亿'] = $tmp / $this->unitFactor;
$data['应收账票占比率'] = $tmp / $balance['total_assets'][0];
#预付款
$tmp = 0;
if ($balance['prepayment'][0]) $tmp += $balance['prepayment'][0];
$data['预付款-亿'] = $tmp / $this->unitFactor;
#预付占比
$data['预付款占比率'] = $tmp / $balance['total_assets'][0];
#运营占比
$tmp = 0;
if ($cash['c_cash_equ_end_period'][0]) $tmp += $cash['c_cash_equ_end_period'][0];
if ($balance['inventories'][0]) $tmp += $balance['inventories'][0];
if ($balance['accounts_receiv'][0]) $tmp += $balance['accounts_receiv'][0];
if ($balance['notes_receiv'][0]) $tmp += $balance['notes_receiv'][0];
if ($balance['prepayment'][0]) $tmp += $balance['prepayment'][0];
$data['运营占比率'] = $tmp / $balance['total_assets'][0];
$data['--资产分布--'] = ''; //空行
if ($balance['fix_assets'][0]) $tmp = $balance['fix_assets'][0] / $this->unitFactor;
else $tmp = "";
$data['固定资产-亿'] = $tmp;
if ($balance['fix_assets'][0]) $tmp = $balance['fix_assets'][0] / $balance['total_assets'][0];
else $tmp = "";
$data['固定资产占比率'] = $tmp;
$data['无形资产-亿'] = $balance['intan_assets'][0] / $this->unitFactor;
$data['无形资产占率'] = $balance['intan_assets'][0] / $balance['total_assets'][0];
$tmp = 0;
if ($balance['lt_eqt_invest'][0]) $tmp = $balance['lt_eqt_invest'][0];
$data['股权投资-亿'] = $tmp / $this->unitFactor;
$data['股权投资占比率'] = $tmp / $balance['total_assets'][0];
$tmp = 0;
if ($balance['fix_assets'][0]) $tmp += $balance['fix_assets'][0];
if ($balance['intan_assets'][0]) $tmp += $balance['intan_assets'][0];
if ($balance['lt_eqt_invest'][0]) $tmp += $balance['lt_eqt_invest'][0];
$data['投资占比率'] = $tmp / $balance['total_assets'][0];
$data['--负债分布--'] = ''; //空行
$tmp = 0;
if ($balance['acct_payable'][0]) $tmp += $balance['acct_payable'][0];
if ($balance['notes_payable'][0]) $tmp += $balance['notes_payable'][0];
if ($balance['adv_receipts'][0]) $tmp += $balance['adv_receipts'][0];
#tmp = balance['acct_payable'][0]+balance['notes_payable'][0]+balance['adv_receipts'][0]
$data['经营负债-亿'] = $tmp / $this->unitFactor;
$data['经营负债占比率'] = $tmp / $balance['total_assets'][0];
$tmp = 0;
if ($balance['st_borr'][0]) $tmp += $balance['st_borr'][0];
if ($balance['lt_borr'][0]) $tmp += $balance['lt_borr'][0];
if ($balance['bond_payable'][0]) $tmp += $balance['bond_payable'][0];
$data['金融负债-亿'] = $tmp / $this->unitFactor;
$data['金融负债占比率'] = $tmp / $balance['total_assets'][0];
$zcfz = ($balance['total_cur_liab'][0] + $balance['total_ncl'][0]) / $balance['total_assets'][0];
$data['资产负债率'] = $zcfz;
$data['--运营能力--'] = ''; //空行
$totalDays=$this->getTotalDays();
@$days_1 = $totalDays / ($income['oper_cost'][0] / (($pre_balance['inventories'][0] + $balance['inventories'][0]) / 2));
if(is_nan($days_1)) $days_1=0; //solve division by zero warning
//echo "\$days_1:".$days_1;
$data['存货周转天数'] = $days_1;
if(!$pre_balance['accounts_receiv'][0]) $days_2 = 0;
elseif(!$balance['accounts_receiv'][0]) $days_2 = 0;
else $days_2 = $totalDays/($income['revenue'][0]/(($pre_balance['accounts_receiv'][0]+$balance['accounts_receiv'][0])/2));
$data['应收周转天数'] = $days_2;
$data['营业周期'] = $days_1+$days_2;
$data['--管理费分布--'] = ''; //空行
$tmp = ($income['revenue'][0]-$income['oper_cost'][0])/$income['revenue'][0];
$data['毛利额'] = ($income['revenue'][0]-$income['oper_cost'][0])/$this->unitFactor;;
$data['毛利率'] = $tmp;
$data['营业税金率'] = $income['biz_tax_surchg'][0]/$income['revenue'][0];
$data['销售费用率'] = $income['sell_exp'][0]/$income['revenue'][0];
$data['研发费用率'] = $income['rd_exp'][0]/$income['revenue'][0];
$data['管理费用率'] = $income['admin_exp'][0]/$income['revenue'][0];
$data['净利润'] = $income['n_income'][0]/$this->unitFactor;
$data['净利润率'] = $income['n_income'][0]/$income['revenue'][0];
$data['--权益及回报率--'] = ''; //空行
$data['总资产-亿'] = $balance['total_assets'][0]/$this->unitFactor;
$data['销售收入-亿'] =$income['revenue'][0]/$this->unitFactor;
$data['总资产周转率'] = $income['revenue'][0]/$balance['total_assets'][0];
$zchb = $income['n_income'][0]/$balance['total_assets'][0];
$data['总资产回报率']=$zchb;
$data['权益乘数']=1/(1-$zcfz);
$data['净资产回报率']=$zchb*(1/(1-$zcfz));
foreach ($data as $key=>$val){
if(is_numeric($val)) {
if(mb_substr($key,-1,1)=='率') $rt[$key]= round($val*100,2).'%'; //最后一个字为率,则去百分比%
else $rt[$key]= round($val,2);
}
else $rt[$key]=$val;
}
return $rt;
}
function getFinanceJson()
{
$d = $this->getFinanceData();
return json_encode($d);
}
function getBalance()
{
$this->param['api_name']='balancesheet';
## 资产负债表
$fields = 'ts_code';
$fields .= ',end_date'; #=$finDate
$fields .= ',total_assets'; #总资产
$fields .= ',fix_assets'; #固定资产
$fields .= ',intan_assets'; #无形资产
$fields .= ',lt_eqt_invest'; #长期股权投资
$fields .= ',inventories'; #存货
$fields .= ',accounts_receiv'; #应收账款
$fields .= ',notes_receiv'; #应收票据
$fields .= ',prepayment'; #预付款
$fields .= ',acct_payable'; #应付账款
$fields .= ',notes_payable'; #应付票据
$fields .= ',adv_receipts'; #预收款
$fields .= ',st_borr'; #短期借款
$fields .= ',lt_borr'; #长期借款
$fields .= ',bond_payable'; #应付债券
$fields .= ',total_cur_liab'; #流动负债合计
$fields .= ',total_ncl'; #非流动负债合计
$this->param['params'] = array('ts_code' => ts_code_conv($this->ts_code),
'period'=>$this->finDate);
$this->param['fields']=$fields;
$this->httpjsonStr=json_encode($this->param);
list($returnCode, $returnContent) = $this->http_post_json();
$arr = json_decode($returnContent,true);
return $this->mergeArr($arr['data']);
}
/**
* #期初的日期: 上一年的年底的数据
* @return mixed
*/
function getPreBalance()
{
$this->param['api_name']='balancesheet';
$this->preFinDate=(substr($this->finDate,0,4)-1).'1231'; //上一年的年底日期;
## 资产负债表
$fields = 'ts_code';
$fields .= ',end_date'; #=$finDate
$fields .= ',inventories'; #存货
$fields .= ',accounts_receiv'; #应收账款
$fields .= ',notes_receiv'; #应收票据
$this->param['params'] = array('ts_code' => ts_code_conv($this->ts_code),
'period'=>$this->preFinDate);
$this->param['fields']=$fields;
$this->httpjsonStr=json_encode($this->param);
list($returnCode, $returnContent) = $this->http_post_json();
$arr = json_decode($returnContent,true);
return $this->mergeArr($arr['data']);
}
function getIncome()
{
$this->param['api_name']='income';
#利润表
#销售毛利率=(营业收入-营业成本)/营业收入 注意非总收入和总成本
$fields = 'ts_code';
$fields .= ',end_date'; #=period
$fields .= ',revenue'; #营业收入
$fields .= ',oper_cost'; #营业成本
$fields .= ',biz_tax_surchg'; #营业税金及附加
$fields .= ',sell_exp'; #销售费用
$fields .= ',fin_exp'; #财务费用
$fields .= ',admin_exp'; #管理费用
$fields .= ',n_income'; #净利润
$fields .= ',rd_exp'; #研发费用
$this->param['params'] = array('ts_code' => ts_code_conv($this->ts_code),
'period'=>$this->finDate);
$this->param['fields']=$fields;
$this->httpjsonStr=json_encode($this->param);
list($returnCode, $returnContent) = $this->http_post_json();
$arr = json_decode($returnContent,true);
return $this->mergeArr($arr['data']);
}
function getCashflow()
{
$this->param['api_name']='cashflow';
#现金流量表
$fields = 'ts_code';
$fields .= ',end_date'; #=period
$fields .= ',c_cash_equ_end_period';#期末现金及现金等价物余额
$fields .= ',end_bal_cash'; #现金的期末余额
$this->param['params'] = array('ts_code' => ts_code_conv($this->ts_code),
'period'=>$this->finDate);
$this->param['fields']=$fields;
$this->httpjsonStr=json_encode($this->param);
list($returnCode, $returnContent) = $this->http_post_json();
//echo $returnContent;
$arr = json_decode($returnContent,true);
return $this->mergeArr($arr['data']);
}
/**
* Array ( [fields] => Array ( [0] => ts_code [1] => end_date [2] => notes_receiv [3] => accounts_receiv [4] => inventories )
* [items] => Array ( [0] => Array ( [0] => 002223.SZ [1] => 20201231 [2] => [3] => 546811497.99 [4] => 968427866.64 )
* [1] => Array ( [0] => 002223.SZ [1] => 20201231 [2] => [3] => 546811497.99 [4] => 968427866.64 ) )
* transfor to:
* Array (ts_code=>array([0]=>002273.SZ [1]=>002273.SZ) notes_receiv=>array([0]=>546811497.99 [1]=>546811497.99)... )
* @param $data
*/
function mergeArr($data)
{
$rt = array();
for($i=0;$i<count($data['fields']);$i++){
for($j=0;$j<count($data['items']);$j++)
$rt[$data['fields'][$i]][]=$data['items'][$j][$i];
}
return $rt;
}
/**
* 根据当前财报日期,获取营业周期的基本天数
* 天数按会计算法?90/180/270/360
*/
function getTotalDays(){
if($this->finDate) $dateCut=substr($this->finDate,4,4);
switch ($dateCut){
case '0331':
return 90;
case '0630':
return 180;
case '0930':
return 270;
case '1231':
return 360;
}
}
}
?>
+111
View File
@@ -0,0 +1,111 @@
<?php
ob_start();
include_once "../include/config.inc.php"; //Include config file;
$db = new ora();
$title="计划设置";
include_once "head.php"; //include head file
echo $hr;
$t = 1; //initial type to 1;
if($_REQUEST['doSubmit']) bom_op($_REQUEST['t']); //operate when submit
if($_REQUEST['bomid'] and !$_REQUEST['doSubmit']) {
$bom = bom_data_by_id();
$_REQUEST["bom"] = $bom['BOMNAME'];
$_REQUEST["bomid"] = $bom['BOMID'];
$_REQUEST["bomnote"] = $bom['FNOTE'];
$_REQUEST["flowid"] = $bom['FLOWID'];
$_REQUEST["ver"] = $bom['VER'];
$t = 0;
}
?>
<link rel="stylesheet" href="../lib/layui/css/layui.min.css">
<div id="mainContent">
<h2><?php echo $title; ?></h2>
<form name="formhead" id="formhead" method="post" enctype="multipart/form-data" >
<div class="layui-inline">
<input type="file" id="file" name="file" class="layui-btn">
</div>
<div class="layui-inline">
<button type="button" class="layui-btn" id="btnUpload">
<i class="layui-icon">&#xe67c;</i>EXCEL上传验证
</button>
</div>
</form>
<form name="form2" id="form2" method="post" >
<div class="stay_center" id="fblock" style="display: none">
<div style="margin-top:10px;" id="ftext" class="layui-col-md12"></div>
<input type="hidden" name="fpath" id="fpath" value="">
<div class="layui-inline">
<input type="button" id="btnExcel" value="处理上传文件" class="layui-btn">
</div>
</div>
</form>
<script type="text/javascript">
$(function () {
$("#btnUpload").click(function () {
console.log("Upload button clicked!");
var formData = new FormData($('#formhead')[0]);
$.ajax({
type: 'post',
url: "http://192.168.10.21/cimv2/cim/bom/upload.php", //上传文件的请求路径必须是绝对路劲
data: formData,
cache: false,
processData: false,
contentType: false,
}).success(function (data) {
afterUpload(data);
}).error(function () {
alert("上传失败");
});
});
});
function afterUpload(data){
var arr = $.parseJSON(data);
if(arr['status']!=1) {
alert(arr.msg);
return false;
}
$("#file").val(''); //set input(file) to null
$("#fblock").css("display","block");
$("#ftext").html("文件上传成功!点击下面按钮开始执行<br />"+arr['fpath']+"<br />");
$("#fpath").val(arr['fpath']);
}
$(function () {
$("#btnExcel").click(function () {
console.log("Process excel button clicked!");
$("#btnExcel").attr("disabled",true);
console.log("Button disabled!");
var formData = new FormData($('#form2')[0]);
$.ajax({
type: 'post',
url: "http://192.168.10.21/cimv2/cim/bom/excel.php", //上传文件的请求路径必须是绝对路劲
data: formData,
cache: false,
processData: false,
contentType: false,
}).success(function (data) {
excelProcess(data);
$("#btnExcel").attr("disabled",false);
console.log("Button enabled!");
console.log("Done everything!");
}).error(function () {
alert("处理失败");
});
});
});
function excelProcess(data){
console.log("Excel data upload successful!");
console.log(data);
var arr = $.parseJSON(data);
var htmlmsg;
for(i = 0;i < arr.msg.length;i++) htmlmsg += arr['msg'][i];
console.log("htmlmsg proceed!");
$("#ftext").html(htmlmsg);
}
</script>
</div>
<?php
include_once "foot.php";
?>
+265
View File
@@ -0,0 +1,265 @@
<?php
/**
* PHP发送Json对象数据
*
* @param $url 请求url
* @param $jsonStr 发送的json字符串
* @return array
*/
function http_post_json($url, $jsonStr)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($jsonStr)
)
);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array($httpCode, $response);
}
/**
* 获取复权因子
* @return array
*/
function getAdj(){
$url = "http://api.waditu.com";
$param['api_name']='adj_factor';
$param['token']='1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea';
$param['params'] = array('ts_code' => ts_code_conv($_REQUEST['ts_code']),
'start_date'=>str_replace('-','',$_REQUEST['t_start']),
'end_date'=>str_replace('-','',$_REQUEST['t_end'])
);
$param['fields'] ="";
$jsonStr=json_encode($param);
list($returnCode, $returnContent) = http_post_json($url, $jsonStr);
$arr = json_decode($returnContent,true);
$items = $arr['data']['items'];
$lastAdj=$items[0][2];
foreach ($items as $t){
list($ts_code,$date,$adj)=$t;
$rt[$date]=$adj/$lastAdj;
}
return $rt;
}
/**
* 获取个股融资融券余额信息
* @return mixed
*/
function getMarginByCode(){
$url = "http://api.waditu.com";
$param['api_name']='margin_detail';
$param['token']='1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea';
$param['params'] = array('ts_code' => ts_code_conv($_REQUEST['ts_code']),
'start_date'=>str_replace('-','',$_REQUEST['t_start']),
'end_date'=>str_replace('-','',$_REQUEST['t_end'])
);
$param['fields'] ="";
$jsonStr=json_encode($param);
list($returnCode, $returnContent) = http_post_json($url, $jsonStr);
$arr = json_decode($returnContent,true);
return $arr['data'];
}
/**
* @param $exchange SSE OR SZSE, set null for all
* @return mixed
*/
function getMarginAll($exchange){
$url = "http://api.waditu.com";
$param['api_name']='margin_detail';
$param['token']='1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea';
$param['params'] = array(
'start_date'=>str_replace('-','',$_REQUEST['t_start']),
'end_date'=>str_replace('-','',$_REQUEST['t_end']),
'exchange_id'=>$exchange
);
$param['fields'] ="";
$jsonStr=json_encode($param);
list($returnCode, $returnContent) = http_post_json($url, $jsonStr);
$arr = json_decode($returnContent,true);
return $arr['data'];
}
/**
* 沪深港通资金流向
* @return mixed
*/
function getMoneyFlowHSGT(){
$url = "http://api.waditu.com";
$param['api_name']='moneyflow_hsgt';
$param['token']='1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea';
$param['params'] = array(
'start_date'=>'20200601',
'end_date'=>date('Ymd')
);
$param['fields'] ="";
$jsonStr=json_encode($param);
list($returnCode, $returnContent) = http_post_json($url, $jsonStr);
$arr = json_decode($returnContent,true);
return $arr['data'];
}
/**
* 获取A股个股香港资金持股每日数据
* @return mixed
*/
function getHKHoldByCode(){
$url = "http://api.waditu.com";
$param['api_name']='hk_hold';
$param['token']='1bc28452ba375da19320cda845ae6307578964cb3ae473d0dc702aea';
$param['params'] = array(
'ts_code' => ts_code_conv($_REQUEST['ts_code']),
'start_date'=>str_replace('-','',$_REQUEST['t_start']),
'end_date'=>str_replace('-','',$_REQUEST['t_end'])
);
$param['fields'] ="";
$jsonStr=json_encode($param);
list($returnCode, $returnContent) = http_post_json($url, $jsonStr);
$arr = json_decode($returnContent,true);
return $arr['data'];
}
/**
* 使用复权因子对股价和成交股数进行复权
* @param $adj
* @param $data
* @return mixed
*/
function adjData($adj,$data){
$num = count($data);
for($i=0;$i<$num;$i++){
$t = str_replace('-','',$data[$i]['tdate']);
$data[$i]['tprice']=round($data[$i]['tprice']*$adj[$t],3);
$data[$i]['tvol']=round($data[$i]['tvol']/$adj[$t],0);
}
return $data;
}
/**
*
0] => trade_date
[1] => ts_code
[2] => rzye
[3] => rqye
[4] => rzmre
[5] => rqyl
[6] => rzche
[7] => rqchl
[8] => rqmcl
[9] => rzrqye
https://tushare.pro/document/2?doc_id=58
*/
function marginByCodeReform($data){
$data['items']=array_reverse($data['items']);
foreach($data['items'] as $rec){
$dataRT[]=array('value'=>array(date('Y-m-d',strtotime($rec[0])),$rec[9]/10000/10000));
$val[]=$rec[9]/10000/10000;
}
$data_last= round($val[count($val)-1],2);
$data_max= round(max($val),2);
$data_min= round(min($val),2);
if(count($val)>0) $data_avg= round(array_sum($val)/count($val),2);
else $data_avg=null;
return array('data'=>$dataRT,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
/**
* 计算累积值
* @param $data
* @return array
*/
function moneyFlowStacked($data){
$keys=array_keys($data['fields']);
$num = count($data['items']);
foreach ($keys as $key) {
$tmp = 0;
for($i=0; $i<$num; $i++){
//keep trade_date field NOT changed.
if($key > 0)$tmp += $data['items'][$i][$key];
else $tmp = $data['items'][$i][$key];
$items[$i][$key]=$tmp;
}
}
return array('fields'=>$data['fields'],'items'=>$items);
}
/**
* 根据日期截取数据
* @param $data
* @param $s start date yyyymmdd
* @param $e end date yyyymmdd
* @return array|false
*/
function moneyFlowDateFilter($data,$s,$e){
if($s>$e) return false;
$num = count($data['items']);
$items = array();
for($i=0;$i<$num;$i++){
if($data['items'][$i][0]>= $s and $data['items'][$i][0]<= $e)
$items[]=$data['items'][$i];
}
return array('fields'=>$data['fields'],'items'=>$items);
}
/**
*$hsgt :
[0] => trade_date
[1] => ggt_ss
[2] => ggt_sz
[3] => hgt
[4] => sgt
[5] => north_money
[6] => south_money
*/
function moneyFlowReform($data,$hsgt){
$data['items']=array_reverse($data['items']);
$key = array_search($hsgt,$data['fields']);
foreach($data['items'] as $rec){
$dataRT[]=array('value'=>array(date('Y-m-d',strtotime($rec[0])),$rec[$key]/100));
$val[]=$rec[$key]/100; //单位:亿元
}
$data_last= round($val[count($val)-1],2);
$data_max= round(max($val),2);
$data_min= round(min($val),2);
if(count($val)>0) $data_avg= round(array_sum($val)/count($val),2);
else $data_avg=null;
return array('data'=>$dataRT,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
/**
* $hkhold:
* 0 code
* 1 trade_date
* 2 ts_code
* 3 name
* 4 vol
* 5 ratio
* 6 exchange
*
*/
function hkHoldReform($data,$hkhold){
//print_r($data);
$data['items']=array_reverse($data['items']);
$key = array_search($hkhold,$data['fields']);
foreach($data['items'] as $rec){
if($hkhold=='vol') $rec[$key] = $rec[$key]/10000; //万股
$dataRT[]=array('value'=>array(date('Y-m-d',strtotime($rec[1])),$rec[$key]));
$val[]=$rec[$key];
}
$data_last= round($val[count($val)-1],2);
$data_max= round(max($val),2);
$data_min= round(min($val),2);
if(count($val)>0) $data_avg= round(array_sum($val)/count($val),2);
else $data_avg=null;
return array('data'=>$dataRT,'data_max'=>$data_max,'data_min'=>$data_min,'data_avg'=>$data_avg,'data_last'=>$data_last);
}
+150
View File
@@ -0,0 +1,150 @@
<?php
/**
* @param $ts_code: stock code
* @param $where: add select condition you need.
* @return array: return stock trade recode history data;
*/
function trade_rec($ts_code, $day_st, $day_end, $extra_where = ''): array
{
global $mysqli;
$tmp=explode('.',$ts_code);
$ts_code = $tmp[0];
$day_end = ($day_end)?$day_end:date('Y-m-d');
$vendor = $_REQUEST['t_vendor'] ?? '方正证券';
if($vendor == '方正证券') {
$sql = "select * from trade_record where ts_code = ? and tdate >= ? and tdate <= ? and tprice>0 $extra_where and length(trade_id)=5 order by tdate asc,ttime asc";
} elseif($vendor == '长江证券') {
$sql = "select * from trade_record_cj where ts_code = ? and tdate >= ? and tdate <= ? and tprice>0 $extra_where order by tdate asc,ttime asc";
}
$result = db_query($mysqli, $sql, [$ts_code, $day_st, $day_end]);
return $result->fetch_all(MYSQLI_ASSOC);
}
/**
* @param $data : data get from db
* @param $flgType : 2 of flg type: 买入,卖出,
* @return array
*/
function recDataSort($data,$flgType):array {
$dataNum=count($data);
$rtData=$note=$rtVol=$rtPrice=array();
for($i=0;$i<$dataNum;$i++){
if($flgType !='' and $data[$i]['flg']!=$flgType) continue; //$flgType is null means all data matches
$rtData[] = array("value"=>array($data[$i]['tdate'],$data[$i]['tprice']));
$rtDataVol[] = array("value"=>array($data[$i]['tdate'],abs($data[$i]['tvol'])));
$rtVol[] = $data[$i]['tvol'];
$rtPrice[] = $data[$i]['tprice'];
$note[] = "{$data[$i]['tprice']} {$data[$i]['flg']} {$data[$i]['ts_name']} {$data[$i]['tvol']} 股,成交金额 {$data[$i]['tamount']}";
}
return array('data'=>$rtData, 'data2'=>$rtDataVol,'note'=>$note, 'tvol'=>$rtVol, 'tprice'=>$rtPrice);
}
/**
* @param $vol : trade volume array
* @param $price : trade price array
* @return array|false
*/
function avePrice($vol,$price){
$numVol = count($vol);
$numPrice = count($price);
if($numPrice!=$numVol or $numVol==0) return false;
$ttlVol=array_sum($vol);
$ttlAmt=0; //total amount
for($i=0;$i<$numVol;$i++){
$ttlAmt += $vol[$i]*$price[$i];
}
$aveprice=round($ttlAmt/$ttlVol,2);
return array('avePrice'=>$aveprice,'ttlVol'=>$ttlVol,);
}
function tradeSummary($dataBuy,$dataSell,$dataAll):array{
$buyNum = count($dataBuy);
$sellNum = count($dataSell);
$allNum = count($dataAll);
$dataBuyReverse = array_reverse($dataBuy,false); //反向重排数组,key值不保留
$sellVol = $sellAmt = $sellTaxAll =0;
$buyVol = $buyAmt = $buyTaxAll = 0;
$buyVolRev = $buyAmtRev = $buyAmtRevFix = $buyPriceRevFix = 0;
for($i=0;$i<$sellNum;$i++){
$sellVol += $dataSell[$i]['tvol'];
$sellAmt += $dataSell[$i]['tamount'];
if($_REQUEST['t_vendor']=='方正证券')
$sellTaxAll += $dataSell[$i]['commission'];
$sellTaxAll += $dataSell[$i]['tax1'];
$sellTaxAll += $dataSell[$i]['tax2'];
$sellTaxAll += $dataSell[$i]['tax3'];
}
for($i=0;$i<$buyNum;$i++){
$buyVol += $dataBuy[$i]['tvol'];
$buyAmt += $dataBuy[$i]['tamount'];
if($_REQUEST['t_vendor']=='方正证券')
$buyTaxAll += $dataSell[$i]['commission'];
$buyTaxAll += $dataBuy[$i]['tax2'];
$buyTaxAll += $dataBuy[$i]['tax3'];
$buyTaxAll += $dataBuy[$i]['tax1'];
if($buyVolRev<abs($sellVol)) {
$buyVolRev += $dataBuyReverse[$i]['tvol'];
$buyAmtRev += $dataBuyReverse[$i]['tamount'];
}
}
if($buyVolRev >= $sellVol) {
$buyAmtRevFix = $buyAmtRev;
$netTAmt = $sellAmt - $buyAmtRevFix;
//按价格验算净收入
if($buyVolRev) $buyPriceRevFix = $buyAmtRev/$buyVolRev;
else $buyPriceRevFix = 0;
$netTAmtCal = $sellAmt-abs($buyPriceRevFix*min(abs($sellVol),$buyVolRev));
$buyPriceRevFix = round($buyPriceRevFix,2);
$netTAmtCal = round($netTAmtCal,0);
//差价>100表示$buyVolRev 与$sellVol差异较大
if(abs($netTAmtCal-$netTAmt)>100)
$netTAmtArr = array("T买成本" => $buyPriceRevFix, "T买股数" => $buyVolRev,"T近似收益" => $netTAmtCal);
else
$netTAmtArr = array("T买成本" => $buyPriceRevFix, "T买股数" => $buyVolRev,"做T收益" => round($netTAmt,0));
}
$buyAvePrice = round($buyAmt/$buyVol,2);
if($sellVol) $sellAvePrice = abs(round($sellAmt/$sellVol,2));
else $sellAvePrice = 0;
$netBuyVol = $buyVol + $sellVol;
$netBuyAmt = $buyAmt - $sellAmt;
$recentPrice = recentPrice($_REQUEST['ts_code']); //最新价格,前一天收盘价
$stockCost =($netBuyVol>0)?round(($netBuyAmt+$sellTaxAll+$buyTaxAll)/$netBuyVol,2):'--'; //持股成本
$currentProfit =($netBuyVol>0)?round(($recentPrice['close'] - $stockCost) * $netBuyVol,2):'--'; //当前浮动盈亏;
$netTAmtArr = array_merge($netTAmtArr, array("最新价格"=>$recentPrice['close'],"浮动盈亏" => $currentProfit));
$rtArr =array("买入次数"=>$buyNum,"买入股数"=>$buyVol,"买入金额"=>$buyAmt,"买入均价"=>$buyAvePrice,"买入税费"=>$buyTaxAll,
"卖出次数"=>$sellNum,"卖出股数"=>abs($sellVol),"卖出金额"=>$sellAmt,"卖出均价"=>$sellAvePrice,"卖出税费"=>$sellTaxAll,
"当前股数"=>$netBuyVol,"持股金额"=>$netBuyAmt, "持股成本"=>$stockCost);
return array_merge($rtArr,$netTAmtArr);
}
function recentPrice($ts_code){
$today = date('Ymd');
$start = date('Ymd', strtotime('-20 days'));
$resp = callDoorcomeApi('stockparam', ['tscode' => ts_code_conv($ts_code), 'start_date' => $start, 'end_date' => $today]);
if ($resp && is_array($resp) && count($resp) > 0) {
$last = end($resp);
return ['close' => $last['close']];
}
return ['close' => 0];
}
/**
* reform date to yyyymmdd
* @param $date
* @return false|string
*/
function reformDate($date){
return date('Ymd',strtotime($date));
}
+71
View File
@@ -0,0 +1,71 @@
<?php
ini_set("display_errors","1");
header("content-type:text/html;charset=utf-8");
//设置时区
date_default_timezone_set('PRC');
//获取文件名
$filename = $_FILES['file']['name'];
//获取文件临时路径
$temp_name = $_FILES['file']['tmp_name'];
//获取大小
$size = $_FILES['file']['size'];
//获取文件上传码,0代表文件上传成功
$error = $_FILES['file']['error'];
//判断文件大小是否超过设置的最大上传限制
if ($size > 20*1024*1024){
//
//echo "<script>alert('文件大小超过20M大小');window.history.go(-1);</script>";
echo json_encode(array(
"status" => "-2",
"data"=> $_FILES['file'],
"msg" => "文件大小超过20MB!",
));
exit();
}
//phpinfo函数会以数组的形式返回关于文件路径的信息
//[dirname]:目录路径[basename]:文件名[extension]:文件后缀名[filename]:不包含后缀的文件名
$arr = pathinfo($filename);
//获取文件的后缀名
$ext_suffix = $arr['extension'];
//设置允许上传文件的后缀
$allow_suffix = array('xls');
//判断上传的文件是否在允许的范围内(后缀)==>白名单判断
if(!in_array($ext_suffix, $allow_suffix)){
//window.history.go(-1)表示返回上一页并刷新页面
//echo "<script>alert('上传的文件类型只能是jpg,gif,jpeg,png,xls');window.history.go(-1);</script>";
echo json_encode(array(
"status" => "-1",
"rows"=>$arr,
"msg" => "仅支持上传文件类型: xls!",
));
exit();
}
//检测存放上传文件的路径是否存在,如果不存在则新建目录
$uploadDir = __DIR__ . '/../uploads/';
if (!file_exists($uploadDir)){
mkdir($uploadDir);
}
//为上传的文件新起一个名字,保证更加安全
$new_filename = date('YmdHis',time()).rand(100,1000).'.'.$ext_suffix;
//将文件从临时路径移动到磁盘
if (move_uploaded_file($temp_name, $uploadDir.$new_filename)){
//echo "<script>alert('文件上传成功!');window.history.go(-1);</script>";
echo json_encode(array(
"status" => "1",
"data"=>$arr,
"fpath"=>$uploadDir.$new_filename,
"msg" => "File upload success!",
));
}else{
//echo "<script>alert('文件上传失败,错误码:$error');</script>";
echo json_encode(array(
"status" => "-1",
"data"=>$ext_suffix,
"fpath"=>$uploadDir,
"file"=>$_FILES['file'],
"msg" => "文件上传失败,错误码:$error",
"e"=>"error",
));
}
+117
View File
@@ -0,0 +1,117 @@
<?php
include_once __DIR__."/config.php";
/**
* 显示股票代码选择列表 (datalist widget)
* @param string $email: default null
* @return bool true
*/
function tradeStocksList($email=null){
$mysqli = get_mysqli_connection();
if($_REQUEST['t_vendor']=='方正证券'){
$sql= <<< EOF
select distinct(ts_code) ts_code,ts_name from trade_record
where tprice>0 and (ts_code not like '7%' and ts_code not like '1%') and length(trade_id)=5 order by ts_code
EOF;
}elseif($_REQUEST['t_vendor']=='长江证券'){
//length(0+ts_name)!=length(ts_name) 判断ts_name 不能为纯数字
$sql= <<< EOF
select distinct(ts_code) ts_code,ts_name from trade_record_cj
where tprice>0 and ts_code not like '7%' and length(0+ts_name)!=length(ts_name) order by ts_code
EOF;
}
$result = $mysqli->query($sql);
$data = $result->fetch_all(MYSQLI_ASSOC);
$option='';
foreach ( $data as $item){
$option .= "<option label='{$item['ts_name']}' value='{$item['ts_code']}'></option>\n";
}
$ts_code_val = htmlspecialchars($_REQUEST['ts_code'] ?? '', ENT_QUOTES);
$html = <<< EOF
<input id="ts_code" name= "ts_code" list="codeList" autocomplete="off"/>
<datalist id="codeList">
$option
</datalist>
<script>
$("#ts_code").val('$ts_code_val');
</script>
EOF;
echo $html;
return true;
}
function vendorList($id='t_vendor'){
$val = htmlspecialchars($_REQUEST[$id] ?? '', ENT_QUOTES);
$html = <<<EOF
<select id="{$id}" name= "{$id}" autocomplete="off" >
<option value="方正证券">方正证券</option>
<option value="长江证券">长江证券</option>
</select>
<script>
$("#{$id}").val('{$val}');
</script>
EOF;
echo $html;
return true;
}
/**
* 根据年份区间,获取财报日期清单
* @param $yst
* @param $yed
*/
function yearList($yst,$yed){
$n = $yed-$yst+1;
$thisYear=date('Y'); //yyyy,eg.2022
$thisMonDay=date('md'); //mmdd,eg.0331
$years=array();
for($i=0;$i<$n;$i++){
if(($yst+$i)<($thisYear-1) ) $years[]=($yst+$i)."1231"; //前年及以前
//去年
if(($yst+$i)==($thisYear-1)and $thisMonDay<='0430') $years[]=($yst+$i)."0930";
if(($yst+$i)==($thisYear-1)and $thisMonDay >'0430') $years[]=($yst+$i)."1231";
//今年
if(($yst+$i)==$thisYear){
switch ($thisMonDay){
case $thisMonDay<='0430':
//一季报未公布do nothing
break;
case $thisMonDay>'0430' && $thisMonDay<= '0831':
//公布一季报
$years[]=($yst+$i)."0331";
break;
case $thisMonDay>'0831' && $thisMonDay<= '1031':
//公布一季报
$years[]=($yst+$i)."0630";
break;
case $thisMonDay>'1031':
//公布一季报
$years[]=($yst+$i)."0930";
break;
default: break;
}
}
}
return $years;
}
/**
* $year 20201231 转为2020年报
* @param $year
*/
function yearToname($year){
switch (substr($year,4,4)){
case '1231':
return substr($year,0,4).'年报';
case '0930':
return substr($year,0,4).'三季';
case '0630':
return substr($year,0,4).'半年';
case '0331':
return substr($year,0,4).'一季';
default:
return substr($year,4,4);
}
}
+280
View File
@@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>金融数据可视化门户</title>
<script src="/lib/js/tailwindcss-3.4.17.js"></script>
<script type="text/javascript" src="/lib/js/jquery-3.6.0.min.js"></script>
<link href="/lib/css/fontawesome-6.4.all.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36D399',
neutral: '#F8FAFC',
dark: '#1E293B'
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-hover {
@apply transition-all duration-300 hover:shadow-lg hover:scale-[1.02] hover:-translate-y-1;
}
.card-active {
@apply bg-primary/10 border-primary;
}
}
</style>
</head>
<body class="bg-gray-50 font-inter text-dark min-h-screen">
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa-solid fa-line-chart text-primary text-2xl"></i>
<h1 class="text-xl font-bold text-dark">金融数据可视化平台</h1>
</div>
<div class="flex items-center space-x-4">
</div>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<div class="mb-8">
<h2 class="text-[clamp(1.5rem,3vw,2rem)] font-bold mb-4 flex items-center">
<i class="fa-solid fa-database text-primary mr-2"></i>数据概览
</h2>
<p class="text-gray-600 max-w-3xl">探索金融市场的各类数据可视化图表,包括股票、指数和房地产市场的趋势分析,帮助您做出更明智的投资决策。</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- 股票数据卡片 -->
<div class="bg-white rounded-xl shadow-md p-6 card-hover">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa-solid fa-chart-line text-primary"></i>
</div>
<h3 class="text-lg font-semibold">股票数据分析</h3>
</div>
<div class="mb-4">
<div class="flex items-center">
<span class="text-gray-600 mr-2">个股:</span>
<div class="relative flex-1">
<input type="text" name="ts_code" id="ts_code" placeholder="输入股票代码"
class="w-full pl-3 pr-10 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/50">
<button id="search-stock" class="absolute right-2 top-1/2 -translate-y-1/2 text-primary">
<i class="fa-solid fa-search"></i>
</button>
</div>
</div>
</div>
<div class="space-y-3">
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stock_trend.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-arrow-trend-up text-primary w-6"></i>
<span>股价VS PE/PB/PS 趋势</span>
</a>
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockep.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-balance-scale text-secondary w-6"></i>
<span>股价VS EP</span>
</a>
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockmargin.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-money-bill-wave text-green-500 w-6"></i>
<span>股价VS 融资融券余额</span>
</a>
<!--<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/hkholdbycode.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-globe-asia text-blue-500 w-6"></i>
<span>股价VS 北向资金持股</span>-->
</a>
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockkeydata.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-table text-yellow-500 w-6"></i>
<span>个股基本面数据</span>
</a>
</div>
<div class="mt-6 pt-6 border-t border-gray-200">
<h4 class="font-medium mb-3">指数分析</h4>
<div class="space-y-3">
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_trend.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-chart-area text-indigo-500 w-6"></i>
<span>指数VS PE/PB/PS/市值 趋势</span>
</a>
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_mv_all.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-chart-pie text-orange-500 w-6"></i>
<span>指数VS 两市总市值</span>
</a>
<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_margin.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-bank text-red-500 w-6"></i>
<span>指数VS 融资余额</span>
</a>
<!--<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/moneyflow.php');"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-exchange text-pink-500 w-6"></i>
<span>指数VS 沪深港通资金流向</span>
</a>-->
</div>
</div>
</div>
<!-- 研究报告数据卡片 -->
<div class="bg-white rounded-xl shadow-md p-6 card-hover">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
<i class="fa-solid fa-file-text text-indigo-600"></i>
</div>
<h3 class="text-lg font-semibold">研究报告</h3>
</div>
<p class="text-gray-600 text-sm mb-4">国内 / 国际投资资讯日报,按日期分模块查看,含 AI 摘要、新闻联播要闻、重要事件与数据总览。</p>
<a href="/charts/news_reports.php" class="inline-flex items-center px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors text-sm font-medium">
查看报告 <i class="fa-solid fa-arrow-right ml-2"></i>
</a>
</div>
<!-- 宏观研究数据卡片 -->
<div class="bg-white rounded-xl shadow-md p-6 card-hover">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
<i class="fa-solid fa-chart-bar text-indigo-600"></i>
</div>
<h3 class="text-lg font-semibold">宏观研究</h3>
</div>
<p class="text-gray-600 text-sm mb-4">宏观量化分析报告,包含量化日报等研究内容。</p>
<a href="/quant/" class="inline-flex items-center px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors text-sm font-medium">
查看报告 <i class="fa-solid fa-arrow-right ml-2"></i>
</a>
</div>
<!-- 房地产数据卡片 -->
<div class="bg-white rounded-xl shadow-md p-6 card-hover">
<div class="flex items-center mb-6">
<div class="w-10 h-10 rounded-full bg-secondary/10 flex items-center justify-center mr-3">
<i class="fa-solid fa-home text-secondary"></i>
</div>
<h3 class="text-lg font-semibold">房地产数据分析</h3>
</div>
<div class="mb-4 text-gray-600">
<p>以下数据主要聚焦于宁波地区房地产市场动态,包括挂牌数量、成交量等趋势分析。</p>
</div>
<div class="space-y-3">
<a href="https://echart.doorcome.cn/charts/realestate.php" target="_blank"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-building text-blue-500 w-6"></i>
<span>房地产挂牌数量趋势(宁波)</span>
</a>
<a href="https://echart.doorcome.cn/charts/estateNewTradeDaily.php" target="_blank"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-key text-green-500 w-6"></i>
<span>新房每日成交量(宁波)</span>
</a>
<a href="https://echart.doorcome.cn/charts/estateTradeDaily.php" target="_blank"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-exchange-alt text-yellow-500 w-6"></i>
<span>二手房每日成交量(宁波)</span>
</a>
<a href="https://echart.doorcome.cn/charts/estateListDaily.php" target="_blank"
class="flex items-center p-3 border border-gray-200 rounded-lg hover:bg-gray-50 transition-all">
<i class="fa-solid fa-list-alt text-purple-500 w-6"></i>
<span>二手房每日挂牌量(宁波)</span>
</a>
</div>
<div class="mt-8 bg-blue-50 p-4 rounded-lg border border-blue-100">
<div class="flex items-start">
<i class="fa-solid fa-info-circle text-blue-500 mt-1 mr-3"></i>
<div>
<h4 class="font-medium text-blue-800 mb-1">数据更新说明</h4>
<p class="text-blue-700 text-sm">所有房地产数据每日凌晨自动更新,股票和指数数据在交易日收盘后2小时内更新。</p>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</main>
<footer class="bg-dark text-white mt-16">
<div class="container mx-auto px-4 py-12">
<div class="border-t border-gray-800 mt-8 pt-8 text-center text-gray-500 text-sm">
<div style='text-align: center'>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 style='text-align: center'>
<span style="color: grey; font-size: small; ">
<a href="https://beian.miit.gov.cn" target="_blank">浙ICP备18056264号-1</a>
</span>
</div>
</div>
</footer>
<script>
// 模拟打开链接的函数
function openurl(url) {
let ts_code = $("#ts_code").val();
url = url + '?ts_code='+ ts_code;
console.log(url);
window.open(url);
}
// 股票搜索功能
document.getElementById('search-stock').addEventListener('click', function() {
const stockCode = document.getElementById('ts_code').value.trim();
if (stockCode) {
alert(`搜索股票代码: ${stockCode}`);
// 这里可以添加实际的搜索逻辑
} else {
alert('请输入股票代码');
}
});
// 为链接添加点击效果
document.querySelectorAll('a').forEach(link => {
link.addEventListener('click', function(e) {
if (this.getAttribute('href') === '#') {
e.preventDefault();
}
// 添加点击效果
this.classList.add('card-active');
setTimeout(() => {
this.classList.remove('card-active');
}, 300);
});
});
// 模拟数据加载动画
document.addEventListener('DOMContentLoaded', function() {
setTimeout(() => {
document.querySelectorAll('.card-hover').forEach(card => {
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
});
}, 300);
});
</script>
</body>
</html>
+55
View File
@@ -0,0 +1,55 @@
<?php
header("Location: index-2.php");
exit();
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="/lib/js/jquery-3.6.0.min.js"></script>
<link href="css/style.css?version=22000" rel="stylesheet" type="text/css">
<link href="/lib/css/fontawesome-6.4.all.min.css" rel="stylesheet" type="text/css">
<title>Stock Reference Data</title>
</head>
<?php
$_REQUEST['ts_code']=$_REQUEST['ts_code']?$_REQUEST['ts_code']:'600000';
?>
<body>
<div >&nbsp;</div>
<div style="text-align: center"><h2>Stock Reference Data</h2></div>
<div >&nbsp;</div>
<div style="text-align: center; margin:0 auto; width: 840px;">
<div style="clear:both;position: relative; float:left; text-align:center; margin: 0 auto;width:400px;height: 400px; ">
<div class="div_block">个股:股票代码: <input type='text' name='ts_code' id='ts_code' size="12" value='<?=$_REQUEST['ts_code']?>' ></div>
<div class="div_block">个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stock_trend.php');">股价VS PE/PB/PS 趋势</a></div>
<div class="div_block">个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockep.php');">股价VS EP</a></div>
<div class="div_block">个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockdiv.php');">股价VS 股息率</a></div>
<div class="div_block">个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockmargin.php');">股价VS 融资融券余额</a></div>
<!--<div class="div_block">个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/hkholdbycode.php');">股价VS 北向资金持股</a></div>-->
<div class='div_block'>个股:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/stockkeydata.php');">个股基本面数据</a></div>
<div class='div_block'>指数:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_trend.php');">指数VS PE/PB/PS/市值 趋势</a>
</div>
<div class='div_block'>指数:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_mv_all.php');">指数VS 两市总市值</a></div>
<div class='div_block'>指数:<a href="#" onclick="openurl('https://echart.doorcome.cn/charts/index_margin.php');">指数VS 融资余额</a></div>
<!--<div class='div_block'>指数:<a href="#" onclick="openurl('https://echart.doorcome.cn/moneyflow.php');">指数VS 沪深港通资金流向</a></div> -->
</div>
<div style="text-align:center; margin: 0 auto;float: left;position: relative;width:400px; ">
<div class='div_block'>房产:<a href="https://echart.doorcome.cn/charts/realestate.php" target='_blank'>房地产挂牌数量趋势(宁波)</a></div>
<div class='div_block'>房产:<a href="https://echart.doorcome.cn/charts/estateNewTradeDaily.php" target='_blank'>新房每日成交量(宁波)</a></div>
<div class='div_block'>房产:<a href="https://echart.doorcome.cn/charts/estateTradeDaily.php" target='_blank'>二手房每日成交量(宁波)</a></div>
<div class='div_block'>房产:<a href="https://echart.doorcome.cn/charts/estateListDaily.php" target='_blank'>二手房每日挂牌量(宁波)</a></div>
</div>
</div>
<div style="clear: both;text-align: center; margin:0 auto; width: 840px;"><a href="index-2.php">首页导航进阶版</a></div>
<?php include_once "html/footer.php"; ?>
<script>
function openurl(url){
let ts_code = $("#ts_code").val();
url = url + '?ts_code='+ ts_code;
console.log(url);
window.open(url);
}
</script>
+69
View File
@@ -0,0 +1,69 @@
var cfg = window.chartConfig;
// ajax with adj set 1
$(function () {
jQuery.support.cors = true;
if($("#adj").val()=='1') {
console.log("Got adj set 1");
var pyurl= "https://py.doorcome.cn/ts/adj?";
pyurl += "ts_code="+$("#ts_code").val();
pyurl += "&s="+$("#s").val();
pyurl += "&e="+$("#e").val();
console.log(pyurl);
//var formData = new FormData($('#form1')[0]);
$.ajax({
crossDomain:true,
//type: 'post',
url: pyurl, //上传文件的请求路径必须是绝对路劲
//data: formData,
cache: false,
processData: false,
contentType: false,
success:function (data) {
console.log("Get data sucessfully");
var adj = getAdj(data);
//console.log(adj);
console.log(cfg.data[0]['value'][0]);
console.log(cfg.data[0]['value'][1]);
cfg.data = adjData(adj,cfg.data,'price');
cfg.data2 = adjData(adj,cfg.data2,'price');
cfg.data3 = adjData(adj,cfg.data3,'price');
cfg.data4 = adjData(adj,cfg.data4,'volum');
cfg.data5 = adjData(adj,cfg.data5,'volum');
console.log(cfg.data[0]['value'][0]);
console.log(cfg.data[0]['value'][1]);
//重新执行画图
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
},
error: function () {
alert("获取数据失败!");
}
});
};
});
function getAdj(data){
var arr = $.parseJSON(data);
var rtArr = {};
var key = '';
//console.log(arr);
var lastAdj= arr[0]['adj_factor'] //last adj number
for(var i = 0; i <arr.length;i++){
key=arr[i]['trade_date'];
rtArr[key] = arr[i]['adj_factor']/lastAdj;
}
return rtArr;
}
function adjData(adj,data,tp){
var k = '';
if(data == null) return 0;
for(var i=0; i<data.length; i++){
k = data[i]['value'][0]; //get date as key
k = k.replace(/-/g,''); //formate key formate from yyyy-mm-dd to yyyymmdd
if(tp=='price')data[i]['value'][1]=Math.round(data[i]['value'][1]*adj[k]*100)/100; //价格保留两位小数
if(tp=='volum')data[i]['value'][1]=Math.round(data[i]['value'][1]/adj[k]); //数量取整数
}
return data;
}
+91
View File
@@ -0,0 +1,91 @@
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: legend[0]+' V.S '+legend[2],
text: headtxt,
subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true
},
{
type:'value',
name:legend[2]+unit, //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:data1,
},
{
name:legend[2],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data:data2,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+93
View File
@@ -0,0 +1,93 @@
var cfg = window.chartConfig;
$(function (){
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
var option = null;
option = {
title: {
//text: cfg.legend[0]+' V.S '+cfg.legend[2],
text: cfg.title,
subtext: cfg.subtitle,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name: cfg.legend[0], //图列
show:true
},
{
type:'value',
name: cfg.legend[2]+cfg.unit, //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name: cfg.legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data: cfg.data
},
{
name: cfg.legend[2],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data: cfg.data2
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
});
+136
View File
@@ -0,0 +1,136 @@
var cfg = window.chartConfig;
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark'); //内置主题:dark, grey,bright,light
var app = {};
option = null;
console.log(cfg.data[0]['value'][0]);
console.log(cfg.data[0]['value'][1]);
option = {
//backgroundColor: '',
title: {
//text: cfg.legend[0]+' V.S '+cfg.legend[2],
text: cfg.title,
subtext: cfg.subtitle,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: [
{
data: [cfg.legend[0],cfg.legend[1],cfg.legend[2]],
right:'50',
},
{
data: [cfg.legend[3],cfg.legend[4]],
right:'100',
top:'30',
},
],
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:cfg.legend[0], //图列
show:true,
scale:true,
},
{
type:'value',
name: cfg.unit, //图例
scale:true, //自动缩放
boundaryGap:false,
show:true,
axisLine:{
show:true, //Y2 坐标轴
},
axisTick: {
show:true, //Y2 坐标刻度
},
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:cfg.legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
smooth:false,
data: cfg.data,
},
{
name:cfg.legend[1],
type:'scatter', //散点图
yAxisIndex:0,
symbolSize: 10,
smooth:false,
data: cfg.data2,
},
{
name:cfg.legend[2],
type:'scatter', //散点图
yAxisIndex:0,
symbolSize: 10,
smooth:false,
data: cfg.data3
},
{
name:cfg.legend[3],
type:'bar',
yAxisIndex:1,
symbolSize: 0,
barWidth: 1,
smooth:false,
data: cfg.data4,
},
{
name:cfg.legend[4],
type:'bar',
yAxisIndex:1,
symbolSize: 0,
barWidth: 1,
smooth:false,
data: cfg.data5,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+92
View File
@@ -0,0 +1,92 @@
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: legend[0]+' V.S '+legend[2],
text: headtxt,
subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true,
scale:true,
},
{
type:'value',
name:legend[1]+'-'+unit, //图例
scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:data1,
},
{
name:legend[1],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data:data2,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+93
View File
@@ -0,0 +1,93 @@
var cfg = window.chartConfig;
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: legend[0]+' V.S '+legend[2],
text: cfg.title,
subtext: cfg.subtitle,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true,
scale:true,
},
{
type:'value',
name:legend[1]+'-'+unit, //图例
scale:true, //auto sacle
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data: cfg.data,
},
{
name:legend[1],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data: cfg.data2,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+77
View File
@@ -0,0 +1,77 @@
var cfg = window.chartConfig;
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: cfg.legend[0]+' V.S '+cfg.legend[2],
text: cfg.title,
//subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:cfg.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:cfg.legend[0], //图列
show:true,
scale:true,
//min:190000,
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:cfg.legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:cfg.data,
itemStyle:{normal:{label:{show:true}}}, //显示数字
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+517
View File
@@ -0,0 +1,517 @@
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports', 'echarts'], factory);
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('echarts'));
} else {
// Browser globals
factory({}, root.echarts);
}
}(this, function (exports, echarts) {
var log = function (msg) {
if (typeof console !== 'undefined') {
console && console.error && console.error(msg);
}
};
if (!echarts) {
log('ECharts is not Loaded');
return;
}
echarts.registerTheme('grey', {
"color": [
"#9b8bba",
"#e098c7",
"#8fd3e8",
"#71669e",
"#cc70af",
"#7cb4cc"
],
"backgroundColor": "rgba(91,92,110,1)",
"textStyle": {},
"title": {
"textStyle": {
"color": "#ffffff"
},
"subtextStyle": {
"color": "#cccccc"
}
},
"line": {
"itemStyle": {
"normal": {
"borderWidth": "2"
}
},
"lineStyle": {
"normal": {
"width": "3"
}
},
"symbolSize": "7",
"symbol": "circle",
"smooth": true
},
"radar": {
"itemStyle": {
"normal": {
"borderWidth": "2"
}
},
"lineStyle": {
"normal": {
"width": "3"
}
},
"symbolSize": "7",
"symbol": "circle",
"smooth": true
},
"bar": {
"itemStyle": {
"normal": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
},
"emphasis": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
}
}
},
"pie": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"scatter": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"boxplot": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"parallel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"sankey": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"funnel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"gauge": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"candlestick": {
"itemStyle": {
"normal": {
"color": "#e098c7",
"color0": "transparent",
"borderColor": "#e098c7",
"borderColor0": "#8fd3e8",
"borderWidth": "2"
}
}
},
"graph": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"lineStyle": {
"normal": {
"width": 1,
"color": "#aaaaaa"
}
},
"symbolSize": "7",
"symbol": "circle",
"smooth": true,
"color": [
"#9b8bba",
"#e098c7",
"#8fd3e8",
"#71669e",
"#cc70af",
"#7cb4cc"
],
"label": {
"normal": {
"textStyle": {
"color": "#eeeeee"
}
}
}
},
"map": {
"itemStyle": {
"normal": {
"areaColor": "#eeeeee",
"borderColor": "#444444",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(224,152,199,1)",
"borderColor": "#444444",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#000000"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(255,255,255)"
}
}
}
},
"geo": {
"itemStyle": {
"normal": {
"areaColor": "#eeeeee",
"borderColor": "#444444",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(224,152,199,1)",
"borderColor": "#444444",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#000000"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(255,255,255)"
}
}
}
},
"categoryAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#cccccc"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee",
"#333333"
]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"valueAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#cccccc"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee",
"#333333"
]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"logAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#cccccc"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee",
"#333333"
]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"timeAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#cccccc"
}
},
"splitLine": {
"show": false,
"lineStyle": {
"color": [
"#eeeeee",
"#333333"
]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"toolbox": {
"iconStyle": {
"normal": {
"borderColor": "#999999"
},
"emphasis": {
"borderColor": "#666666"
}
}
},
"legend": {
"textStyle": {
"color": "#cccccc"
}
},
"tooltip": {
"axisPointer": {
"lineStyle": {
"color": "#cccccc",
"width": 1
},
"crossStyle": {
"color": "#cccccc",
"width": 1
}
}
},
"timeline": {
"lineStyle": {
"color": "#8fd3e8",
"width": 1
},
"itemStyle": {
"normal": {
"color": "#8fd3e8",
"borderWidth": 1
},
"emphasis": {
"color": "#8fd3e8"
}
},
"controlStyle": {
"normal": {
"color": "#8fd3e8",
"borderColor": "#8fd3e8",
"borderWidth": 0.5
},
"emphasis": {
"color": "#8fd3e8",
"borderColor": "#8fd3e8",
"borderWidth": 0.5
}
},
"checkpointStyle": {
"color": "#8fd3e8",
"borderColor": "rgba(138,124,168,0.37)"
},
"label": {
"normal": {
"textStyle": {
"color": "#8fd3e8"
}
},
"emphasis": {
"textStyle": {
"color": "#8fd3e8"
}
}
}
},
"visualMap": {
"color": [
"#8a7ca8",
"#e098c7",
"#cceffa"
]
},
"dataZoom": {
"backgroundColor": "rgba(0,0,0,0)",
"dataBackgroundColor": "rgba(255,255,255,0.3)",
"fillerColor": "rgba(167,183,204,0.4)",
"handleColor": "#a7b7cc",
"handleSize": "100%",
"textStyle": {
"color": "#333333"
}
},
"markPoint": {
"label": {
"normal": {
"textStyle": {
"color": "#eeeeee"
}
},
"emphasis": {
"textStyle": {
"color": "#eeeeee"
}
}
}
}
});
}));
+93
View File
@@ -0,0 +1,93 @@
var dom = document.getElementById("container");
var myChart = echarts.init(dom,'dark');
var app = {};
option = null;
option = {
title: {
//text: legend[0]+' V.S '+legend[2],
text: headtxt,
subtext: subtxt,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
//type: 'category',
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:legend[0], //图列
show:true,
scale:true,
},
{
type:'value',
name:legend[1]+unit, //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
smooth: false,
data:data1,
},
{
name:legend[1],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data:data2,
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
+554
View File
@@ -0,0 +1,554 @@
/**
* 投资资讯日报 前端逻辑
* 数据源: https://api.doorcome.cn/api/news/reports/ (日报列表/详情)
* https://api.doorcome.cn/api/news/events/ (重要事件聚合, 预留)
* 模式 B: 页面加载后由 JS fetch 获取数据并渲染, 无服务端注入
*/
var NewsReports = {
API_REPORTS: 'https://api.doorcome.cn/api/news/reports/',
API_EVENTS: 'https://api.doorcome.cn/api/news/events/',
// 类型/section 中文映射
TYPE_NAMES: { finance: '国内投资资讯', intl: '国际投资资讯' },
SECTION_NAMES: { xwlb: '新闻联播要闻', news: '重要事件 · 财经新闻', cninfo: '重要事件 · 公告/调研/互动', intl: '国际要闻' },
SECTION_ICONS: { xwlb: 'fa-tower-broadcast', news: 'fa-fire', cninfo: 'fa-clipboard-list', intl: 'fa-earth-asia' },
SENTIMENT: { positive: { icon: '🟢', cls: 'badge-pos', txt: '利好' }, negative: { icon: '🔴', cls: 'badge-neg', txt: '利空' }, neutral: { icon: '⚪', cls: 'badge-neu', txt: '中性' } },
state: { reportType: '', startDate: '', endDate: '', currentId: null, eventsLoaded: false },
init: function () {
var now = new Date();
var start = new Date(now.getTime() - 30 * 86400000);
this.state.startDate = this.fmtDate(start);
this.state.endDate = this.fmtDate(now);
// 默认值写入日期输入框 (开始=30天前, 结束=今天)
$('#startDate').val(this.state.startDate);
$('#endDate').val(this.state.endDate);
this.bindEvents();
this.loadReports();
},
fmtDate: function (d) {
return d.getFullYear() + '-' + this.pad2(d.getMonth() + 1) + '-' + this.pad2(d.getDate());
},
pad2: function (n) { return n < 10 ? '0' + n : '' + n; },
// 时间显示: 2026-08-03T07:00:00 -> 2026-08-03 07:00
fmtTime: function (iso) {
if (!iso) return '';
return iso.replace('T', ' ').substring(0, 16);
},
bindEvents: function () {
var self = this;
// 视图切换 (日报列表 / 重要事件)
$('.view-tab').on('click', function () {
$('.view-tab').removeClass('tab-active');
$(this).addClass('tab-active');
self.switchView($(this).data('view'));
});
// 类型 Tabs
$('.type-tab').on('click', function () {
$('.type-tab').removeClass('tab-active');
$(this).addClass('tab-active');
self.state.reportType = $(this).data('type');
self.loadReports();
});
// 查询按钮
$('#btnQuery').on('click', function () {
self.state.startDate = $('#startDate').val() || self.state.startDate;
self.state.endDate = $('#endDate').val() || self.state.endDate;
self.loadReports();
});
// 重要事件查询
$('#btnEvQuery').on('click', function () {
self.loadEvents();
});
// 返回列表
$('#btnBack').on('click', function () {
self.showList();
});
},
// ==================== 重要事件聚合 ====================
switchView: function (view) {
if (view === 'events') {
$('#listView').addClass('hidden');
$('#detailView').addClass('hidden');
$('#eventsView').removeClass('hidden');
if (!this.state.eventsLoaded) this.loadEvents();
} else {
$('#eventsView').addClass('hidden');
$('#listView').removeClass('hidden');
}
},
loadEvents: function () {
var self = this;
this.showLoading('正在加载重要事件...');
var days = $('#evDays').val() || 7;
var imp = $('#evImportance').val() || 4;
var type = $('#evType').val() || '';
var url = this.API_EVENTS + '?days=' + days + '&importance=' + imp + '&limit=300';
if (type) url += '&report_type=' + type;
$.getJSON(url)
.done(function (data) {
self.renderEvents(data);
self.state.eventsLoaded = true;
self.hideLoading();
})
.fail(function (xhr) {
self.renderEventsError(xhr);
self.hideLoading();
});
},
renderEvents: function (list) {
var self = this;
if (!Array.isArray(list) || list.length === 0) {
$('#eventsList').html('<div class="empty-box"><i class="fa-solid fa-inbox"></i><p>该条件下暂无重要事件</p></div>');
$('#eventsInfo').text('');
return;
}
$('#eventsInfo').text('共 ' + list.length + ' 条重要事件(按重要度、日期降序)');
var rows = list.map(function (e, i) {
var typeName = self.TYPE_NAMES[e.report_type] || e.report_type;
var secName = self.SECTION_NAMES[e.section] || e.section;
var extra = ['<span class="meta-item"><i class="fa-regular fa-calendar mr-1"></i>' + selfEscape(e.report_date) + ' · ' + selfEscape(typeName) + ' · ' + selfEscape(secName) + '</span>'];
return self.renderEventRow(e, i + 1, extra);
}).join('');
$('#eventsList').html('<div class="module-card"><div class="module-title"><i class="fa-solid fa-fire text-indigo-600"></i>重要事件聚合<span class="module-sub">跨日报检索 · 重要度 ≥ ' + $('#evImportance').val() + '</span></div><div class="divide-y divide-gray-100">' + rows + '</div></div>');
},
renderEventsError: function (xhr) {
var detail = '';
if (xhr && xhr.responseJSON && xhr.responseJSON.error) detail = xhr.responseJSON.error;
$('#eventsList').html('<div class="empty-box"><i class="fa-solid fa-triangle-exclamation text-red-500"></i><p>重要事件加载失败</p>' + (detail ? '<p class="text-sm text-gray-400">' + selfEscape(detail) + '</p>' : '') + '</div>');
$('#eventsInfo').text('');
},
// ==================== 列表 ====================
loadReports: function () {
var self = this;
this.showLoading('正在加载日报列表...');
var url = this.API_REPORTS + '?start_date=' + this.state.startDate + '&end_date=' + this.state.endDate;
if (this.state.reportType) url += '&report_type=' + this.state.reportType;
$.getJSON(url)
.done(function (data) {
if (!Array.isArray(data) || data.length === 0) {
self.renderEmpty();
return;
}
self.state.reports = data;
self.renderList(data);
})
.fail(function (xhr) {
self.renderError('列表加载失败', xhr);
});
},
renderList: function (reports) {
var self = this;
var html = '';
reports.forEach(function (r) {
var typeName = self.TYPE_NAMES[r.report_type] || r.report_type;
var typeCls = r.report_type === 'finance' ? 'badge-finance' : 'badge-intl';
var summary = self.truncate(r.ai_summary || '', 140);
var statBits = self.listStatBits(r);
html += '' +
'<div class="report-card aos-init" data-id="' + r.id + '" onclick="NewsReports.openDetail(' + r.id + ')">' +
'<div class="flex items-start justify-between gap-3">' +
'<div class="flex items-center gap-2 flex-wrap">' +
'<span class="badge ' + typeCls + '">' + typeName + '</span>' +
'<span class="text-lg font-bold text-dark">' + r.report_date + '</span>' +
'<span class="text-sm text-gray-400"><i class="fa-regular fa-clock mr-1"></i>' + self.fmtTime(r.generated_at) + ' 生成</span>' +
'</div>' +
'<button class="btn-view"><i class="fa-solid fa-book-open mr-1"></i>查看</button>' +
'</div>' +
'<p class="mt-2.5 text-base text-gray-600 leading-relaxed line-clamp-3">' + summary + '</p>' +
(statBits ? '<div class="mt-3 flex flex-wrap gap-2">' + statBits + '</div>' : '') +
'</div>';
});
$('#reportList').html(html);
this.hideLoading();
this.updateRangeInfo(reports);
},
// 列表卡片上的统计数据小徽章 (防御性读取)
listStatBits: function (r) {
var bits = [];
var s = r.stats || {};
if (s.xwlb && s.xwlb.total) bits.push('<span class="stat-bit"><i class="fa-solid fa-tower-broadcast text-sky-600"></i>新闻联播 ' + s.xwlb.total + '</span>');
if (s.news && s.news.total) bits.push('<span class="stat-bit"><i class="fa-solid fa-newspaper text-indigo-600"></i>财经新闻 ' + s.news.total + '</span>');
if (s.cninfo && s.cninfo.total) bits.push('<span class="stat-bit"><i class="fa-solid fa-clipboard-list text-emerald-600"></i>公告调研 ' + s.cninfo.total + '</span>');
if (s.source_dist && s.source_dist.length) bits.push('<span class="stat-bit"><i class="fa-solid fa-globe text-teal-600"></i>来源 ' + s.source_dist.length + '</span>');
if (s.sources) bits.push('<span class="stat-bit"><i class="fa-solid fa-globe text-teal-600"></i>来源 ' + Object.keys(s.sources).length + '</span>');
if (s.pipeline) {
var p = s.pipeline;
var pKeys = Object.keys(p);
for (var i = pKeys.length - 1; i >= 0; i--) {
var pv = p[pKeys[i]];
if (pv == null || typeof pv === 'object') continue;
bits.push('<span class="stat-bit"><i class="fa-solid fa-database text-slate-600"></i>' + pKeys[i] + ' ' + pv + '</span>');
break;
}
}
return bits.join('');
},
truncate: function (txt, n) {
txt = (txt || '').replace(/\s+/g, ' ').trim();
if (!txt) return '(无摘要)';
return txt.length > n ? txt.substring(0, n) + '…' : txt;
},
updateRangeInfo: function (reports) {
var dates = reports.map(function (r) { return r.report_date; });
$('#rangeInfo').text('共 ' + reports.length + ' 份日报' + (dates.length ? ' · ' + dates[0] + ' ~ ' + dates[dates.length - 1] : ''));
},
renderEmpty: function () {
$('#reportList').html('<div class="empty-box"><i class="fa-solid fa-inbox"></i><p>该时间段暂无日报</p></div>');
$('#rangeInfo').text('');
this.hideLoading();
},
renderError: function (msg, xhr) {
var detail = '';
if (xhr && xhr.responseJSON && xhr.responseJSON.error) detail = xhr.responseJSON.error;
$('#reportList').html('<div class="empty-box"><i class="fa-solid fa-triangle-exclamation text-red-500"></i><p>' + msg + '</p>' + (detail ? '<p class="text-sm text-gray-400">' + detail + '</p>' : '') + '</div>');
this.hideLoading();
},
// ==================== 详情 ====================
openDetail: function (id) {
var self = this;
this.state.currentId = id;
this.showDetail();
this.showLoading('正在加载日报详情...');
$('#detailContent').html('');
$.getJSON(this.API_REPORTS + '?id=' + id)
.done(function (r) {
self.renderDetail(r);
self.hideLoading();
window.scrollTo({ top: 0, behavior: 'smooth' });
})
.fail(function (xhr) {
self.renderError('日报详情加载失败', xhr);
self.hideLoading();
});
},
renderDetail: function (r) {
var self = this;
var typeName = this.TYPE_NAMES[r.report_type] || r.report_type;
var typeCls = r.report_type === 'finance' ? 'badge-finance' : 'badge-intl';
// 头部
$('#detailHeader').html(
'<span class="badge ' + typeCls + '">' + typeName + '</span>' +
'<span class="text-xl font-bold text-dark">' + r.report_date + ' 日报</span>' +
'<span class="text-sm text-gray-400"><i class="fa-regular fa-clock mr-1"></i>' + this.fmtTime(r.generated_at) + ' 生成</span>'
);
var html = '';
// ① AI 摘要
html += this.renderSummary(r.ai_summary);
// ② 事件模块 (固定顺序: 国内 xwlb→news→cninfo, 国际 intl)
var sections = r.report_type === 'finance' ? ['xwlb', 'news', 'cninfo'] : ['intl'];
var events = r.events || [];
sections.forEach(function (sec) {
var secEvents = events.filter(function (e) { return e.section === sec; });
if (secEvents.length === 0) return;
html += self.renderEventModule(sec, secEvents);
});
// ③ 数据总览
html += this.renderStats(r.stats);
$('#detailContent').html(html);
this.bindEventHover();
},
// AI 摘要: 按条目分行渲染
renderSummary: function (summary) {
if (!summary) return '';
var items = summary.split('\n').map(function (s) { return s.replace(/^[-*\s]+/, '').trim(); }).filter(Boolean);
if (items.length === 0) return '';
var lis = items.map(function (s) { return '<li>' + selfEscape(s) + '</li>'; }).join('');
return '' +
'<div class="module-card">' +
'<div class="module-title"><i class="fa-solid fa-wand-magic-sparkles text-indigo-600"></i>AI 摘要</div>' +
'<ul class="ai-summary-list">' + lis + '</ul>' +
'</div>';
},
// 事件模块
renderEventModule: function (sec, events) {
var self = this;
var name = this.SECTION_NAMES[sec] || sec;
var icon = this.SECTION_ICONS[sec] || 'fa-list';
var imp = events.filter(function (e) { return e.importance >= 4; }).length;
var rows = events.map(function (e, i) { return self.renderEventRow(e, i + 1); }).join('');
return '' +
'<div class="module-card">' +
'<div class="module-title"><i class="fa-solid ' + icon + ' text-indigo-600"></i>' + name +
'<span class="module-sub">共 ' + events.length + ' 条' + (imp ? ' · 重要(≥4) ' + imp + ' 条' : '') + '</span>' +
'</div>' +
'<div class="divide-y divide-gray-100">' + rows + '</div>' +
'</div>';
},
renderEventRow: function (e, idx, extraMeta) {
var sen = this.SENTIMENT[e.sentiment] || this.SENTIMENT.neutral;
var impCls = e.importance >= 5 ? 'imp-5' : (e.importance >= 4 ? 'imp-4' : '');
var title = selfEscape(e.title || '');
if (e.url) title = '<a href="' + selfEscape(e.url) + '" target="_blank" rel="noopener" class="event-link">' + title + '<i class="fa-solid fa-up-right-from-square ml-1 text-xs"></i></a>';
var summary = e.summary ? '<p class="event-summary">' + selfEscape(e.summary) + '</p>' : '';
var meta = [];
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.source) meta.push('<span class="meta-item"><i class="fa-regular fa-newspaper mr-1"></i>' + selfEscape(e.source) + '</span>');
return '' +
'<div class="event-row">' +
'<div class="event-left">' +
'<span class="event-rank">' + idx + '</span>' +
'<span class="badge ' + sen.cls + '" title="' + sen.txt + '">' + sen.icon + '</span>' +
'</div>' +
'<div class="event-body">' +
'<div class="event-title-line">' +
'<span class="imp-badge ' + impCls + '">' + (e.importance != null ? e.importance : '-') + '</span>' +
'<div class="event-title">' + title + '</div>' +
'</div>' +
summary +
(meta.length ? '<div class="event-meta">' + meta.join('') + '</div>' : '') +
'</div>' +
'</div>';
},
// ==================== 数据总览 ====================
// stats 格式随生成日期变化(2026-08 前后两套结构), 统一归一化后渲染:
// A. 字符串数组 ["🟢 利好 5 (11%)", ...] (intl / finance旧版 sentiment)
// B. 对象 {"1": 81, "2": 265} / {"东方财富": 16} (importances / sources)
// C. 对象数组 [{"重要度":"等级 2","数量":"4"}] 或合并格式 [{"重要度":"数量","等级 1":"46"}]
normalizeKV: function (data) {
var out = [];
if (!data) return out;
if (Array.isArray(data)) {
data.forEach(function (item) {
if (item == null) return;
if (typeof item === 'string' || typeof item === 'number') {
out.push({ label: String(item), value: '' });
} else if (typeof item === 'object') {
if (item['重要度'] === '数量') {
// 合并格式: {"重要度":"数量","等级 1":"46",...} → 展开各等级键
Object.keys(item).forEach(function (k) {
if (k === '重要度') return;
out.push({ label: k, value: item[k] });
});
return;
}
if ('数量' in item) {
if (item['数量'] === '数量') {
// 合并格式: {"重要度":"数量","等级 1":"46",...} → 展开各等级键
Object.keys(item).forEach(function (k) {
if (k === '重要度') return;
out.push({ label: k, value: item[k] });
});
} else {
var lk = Object.keys(item).filter(function (k) { return k !== '数量'; })[0];
out.push({ label: lk ? item[lk] : '—', value: item['数量'] });
}
return;
}
if ('count' in item) {
// intl 英文键格式: {"importance":2,"count":2} / {"event_type":"宏观","count":15} / {"source":"X","count":30}
var lk2 = Object.keys(item).filter(function (k) { return k !== 'count'; })[0];
out.push({ label: lk2 ? item[lk2] : '—', value: item['count'] });
return;
}
var keys = Object.keys(item);
if (keys.length >= 2) out.push({ label: item[keys[0]], value: item[keys[1]] });
else if (keys.length === 1) out.push({ label: keys[0], value: item[keys[0]] });
}
});
} else if (typeof data === 'object') {
Object.keys(data).forEach(function (k) {
var v = data[k];
if (v == null || typeof v === 'object') return; // 嵌套对象跳过, 单独处理
out.push({ label: k, value: v });
});
}
return out;
},
renderStats: function (s) {
if (!s) return '';
var html = '<div class="module-card">' +
'<div class="module-title"><i class="fa-solid fa-chart-simple text-indigo-600"></i>数据总览</div>';
// pipeline 管道 (M1→M6 / raw_total 两种键名, 嵌套对象为来源明细)
if (s.pipeline) {
var keys = Object.keys(s.pipeline);
var nums = keys.filter(function (k) { return typeof s.pipeline[k] !== 'object'; });
if (nums.length) {
html += '<div class="stats-grid">';
nums.forEach(function (k) {
var v = s.pipeline[k];
if (v == null) return;
html += '<div class="stat-card"><div class="stat-num">' + v + '</div><div class="stat-label">' + selfEscape(String(k).replace(/^M\d+\s*/, 'M')) + '</div></div>';
});
html += '</div>';
}
keys.forEach(function (k) {
var v = s.pipeline[k];
if (v == null || typeof v !== 'object') return;
var label = String(k).replace(/^M\d+\s*/, '');
html += '<div class="stats-sub-title">' + selfEscape(label) + '</div><div class="source-grid">';
Object.keys(v).forEach(function (sk) {
html += '<div class="source-item"><div class="s-count">' + v[sk] + '</div><div class="s-name">' + selfEscape(sk) + '</div></div>';
});
html += '</div>';
});
}
// finance: news / cninfo / xwlb 统计
if (s.news) html += this.renderFinanceNewsStats(s.news);
if (s.cninfo) html += this.renderCninfoStats(s.cninfo);
if (s.xwlb) html += this.renderXwlbStats(s.xwlb);
// 顶层: sentiment / importance / event_types / source_dist / sources (intl & finance旧版)
if (s.sentiment && s.sentiment.length) html += this.renderSentiment(s.sentiment);
if (s.importance && s.importance.length) html += this.renderKVTable('重要度分布', s.importance);
if (s.event_types && s.event_types.length) html += this.renderKVTable('事件类型分布', s.event_types);
if (s.source_dist && s.source_dist.length) html += this.renderKVTable('来源分布', s.source_dist);
if (s.sources) html += this.renderSources(s.sources);
html += '</div>';
return html;
},
renderFinanceNewsStats: function (news) {
var html = '<div class="stats-sub">';
if (news.total != null) html += '<div class="stat-card"><div class="stat-num">' + news.total + '</div><div class="stat-label">新闻总量</div></div>';
if (news.hi_threshold != null) html += '<div class="stat-card"><div class="stat-num">' + news.hi_threshold + '</div><div class="stat-label">重要(≥阈值)</div></div>';
html += '</div>';
if (news.sentiments) html += this.renderSentimentBar(news.sentiments);
if (news.importances) html += this.renderKVTable('新闻重要度', news.importances);
if (news.event_types && news.event_types.length) html += this.renderKVTable('新闻事件类型', news.event_types);
return html;
},
// sentiment: 字符串数组(已含emoji/百分比, intl & finance旧版) 或 对象(finance新版 news.sentiments)
renderSentiment: function (data) {
if (data.length && typeof data[0] === 'string') {
var items = data.map(function (s) { return '<span class="badge badge-neu">' + selfEscape(s) + '</span>'; }).join('');
return '<div class="stats-sub-title">情感分布</div><div class="flex flex-wrap gap-2 mb-3">' + items + '</div>';
}
return this.renderSentimentBar(data);
},
renderCninfoStats: function (cn) {
var html = '<div class="stats-sub">';
if (cn.total != null) html += '<div class="stat-card"><div class="stat-num">' + cn.total + '</div><div class="stat-label">公告调研总量</div></div>';
if (cn.hi_threshold != null) html += '<div class="stat-card"><div class="stat-num">' + cn.hi_threshold + '</div><div class="stat-label">重要(≥阈值)</div></div>';
if (cn.announcement != null) html += '<div class="stat-card"><div class="stat-num">' + cn.announcement + '</div><div class="stat-label">公司公告</div></div>';
if (cn.research != null) html += '<div class="stat-card"><div class="stat-num">' + cn.research + '</div><div class="stat-label">调研报告</div></div>';
if (cn.irm != null) html += '<div class="stat-card"><div class="stat-num">' + cn.irm + '</div><div class="stat-label">互动易</div></div>';
html += '</div>';
if (cn.by_day) {
var days = Object.keys(cn.by_day).sort();
if (days.length) {
html += '<div class="kv-table-wrap"><table class="kv-table"><thead><tr><th>日期</th><th>数量</th></tr></thead><tbody>';
days.forEach(function (d) { html += '<tr><td>' + selfEscape(d) + '</td><td>' + cn.by_day[d] + '</td></tr>'; });
html += '</tbody></table></div>';
}
}
return html;
},
renderXwlbStats: function (xw) {
var html = '<div class="stats-sub">';
if (xw.total != null) html += '<div class="stat-card"><div class="stat-num">' + xw.total + '</div><div class="stat-label">新闻联播条数</div></div>';
if (xw.date) html += '<div class="stat-card"><div class="stat-num text-sm">' + selfEscape(xw.date) + '</div><div class="stat-label">联播日期</div></div>';
html += '</div>';
return html;
},
renderKVTable: function (title, data) {
var items = this.normalizeKV(data);
if (!items.length) return '';
var rows = items.map(function (it) {
return '<tr><td>' + selfEscape(it.label) + '</td><td>' + (it.value === '' ? '' : selfEscape(it.value)) + '</td></tr>';
}).join('');
return '<div class="kv-table-wrap"><div class="kv-title">' + selfEscape(title) + '</div>' +
'<table class="kv-table"><thead><tr><th>类别</th><th>数量</th></tr></thead><tbody>' + rows + '</tbody></table></div>';
},
renderSentimentBar: function (sent) {
var pos = sent.positive || sent.pos || 0;
var neg = sent.negative || sent.neg || 0;
var neu = sent.neutral || sent.neu || 0;
var total = pos + neg + neu;
if (!total) return '';
var pct = function (v) { return (v / total * 100).toFixed(1) + '%'; };
return '' +
'<div class="sentiment-wrap">' +
'<div class="sentiment-bar"><div class="s-pos" style="width:' + pct(pos) + '"></div><div class="s-neg" style="width:' + pct(neg) + '"></div><div class="s-neu" style="width:' + pct(neu) + '"></div></div>' +
'<div class="sentiment-legend">' +
'<span><i class="s-dot s-pos"></i>利好 ' + pos + ' (' + pct(pos) + ')</span>' +
'<span><i class="s-dot s-neg"></i>利空 ' + neg + ' (' + pct(neg) + ')</span>' +
'<span><i class="s-dot s-neu"></i>中性 ' + neu + ' (' + pct(neu) + ')</span>' +
'</div>' +
'</div>';
},
renderSources: function (sources) {
var self = this;
var keys = Object.keys(sources);
if (!keys.length) return '';
var items = keys.map(function (k) {
return '<div class="source-item"><div class="s-count">' + sources[k] + '</div><div class="s-name">' + selfEscape(k) + '</div></div>';
}).join('');
return '<div class="stats-sub-title">各源数据</div><div class="source-grid">' + items + '</div>';
},
// ==================== UI 控制 ====================
showList: function () {
$('#listView').removeClass('hidden');
$('#detailView').addClass('hidden');
$('#detailHeader').html('');
$('#detailContent').html('');
},
// 打开详情: 隐藏列表, 独占视口
showDetail: function () {
$('#listView').addClass('hidden');
$('#detailView').removeClass('hidden');
},
showLoading: function (msg) {
$('#loadingOverlay').removeClass('hidden');
$('#loadingMsg').text(msg || '加载中...');
},
hideLoading: function () {
$('#loadingOverlay').addClass('hidden');
},
bindEventHover: function () {
// 事件行悬停样式已由 CSS 处理, 无需额外逻辑 (保留钩子)
}
};
// HTML 转义 (防 XSS, 数据来自外部 API)
function selfEscape(str) {
return String(str == null ? '' : str)
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}
$(function () {
NewsReports.init();
});
+141
View File
@@ -0,0 +1,141 @@
/*
* @Author: 杨水淼 yangshuimiao@jsjd.cc
* @Date: 2025-03-21 11:58:51
* @LastEditors: 杨水淼 yangshuimiao@jsjd.cc
* @LastEditTime: 2025-07-16 16:15:16
* @FilePath: \echarts\js\pubfunc.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
/**
* hide switch the iframe
* @param cbid:checkbox id
* @param iframeid: iframe id
*/
function hideSwitch(cbid,iframeid){
if($("#"+cbid).prop("checked")) {
$("#"+iframeid).css('display','block');
}
else {
$("#"+iframeid).css('display','none');
}
}
/**
*
* @param {*} jsonData : from ajax, e.g: https://echart.doorcome.cn/inc/ajax.inc.php?t=esfTBD&t_start=2023-06-20&t_end=2023-08-23&district=合计'
* @param {*} array :e.g: dataSel=['td','area'];
* @returns
*/
function getRows(jsonData,array){
var listSplit = [];
var tmp;
for (let i = 0; i < jsonData.length; i++) {
var arr = [];
for (let j = 0; j < array.length; j++) {
tmp=(jsonData[i][array[j]])?jsonData[i][array[j]]:'';
arr[j]=tmp;
}
listSplit[i]={"value":arr};
}
return listSplit;
}
function dmChange(parid,dayblock,monblock){
var v= $('#'+parid).val();
if(v=='Monthly'){
$('#'+dayblock).css('display','none');
$('#'+monblock).css('display','inline');
}
if(v=='Daily'){
$('#'+dayblock).css('display','inline');
$('#'+monblock).css('display','none');
}
}
/*
<option value='000001.SH'>上证指数</option>
<option value='399001.SZ'>深圳成指</option>
<option value='399005.SZ'>中小板指</option>
<option value='399006.SZ'>创业板指</option>
<option value='000016.SZ'>上证50</option>
<option value='399300.SZ'>沪深300</option>
<option value='399905.SZ'>中证500</option>
*/
function convertIndexCode(tscode){
switch(tscode){
case '000001.SH':
return '上证指数';
case '399001.SZ':
return '深圳成指';
case '399005.SZ':
return '中小板指';
case '399006.SZ':
return '创业板指';
case '000016.SH':
return '上证50';
case '399300.SZ':
return '沪深300';
case '399905.SZ':
return '中证500';
default:
return '';
}
}
function formatDateToYYYYMMDD(dateStr) {
return dateStr.replace(/-/g, '');
}
function pickData(data, dateKey, valueKey,fixed=2) {
data.sort((a, b) => a[dateKey] - b[dateKey]);
return data.map(item => ({
value: [
item[dateKey].slice(0, 4) + '-' + item[dateKey].slice(4, 6) + '-' + item[dateKey].slice(6, 8), // 格式化日期 yyyymmdd 转为 yyyy-mm-dd
item[valueKey] === null || item[valueKey] === undefined || item[valueKey] === '' ? '' : parseFloat(item[valueKey]).toFixed(fixed)
]
}));
}
/* 将上述pickData函数返回的结果,value计算返回最大值,最小值,均值,以及最后一个值 */
function calculateStats(data,fixed=2) {
if (data.length === 0) {
return {
max: null,
min: null,
avg: null,
last: null
};
}
let max = -Infinity;
let min = Infinity;
let sum = 0;
let last = null;
let count = 0;
for (const item of data) {
const valueStr = item.value[1];
if (valueStr === '' || valueStr === null || valueStr === undefined) continue;
const value = parseFloat(valueStr);
if (isNaN(value)) continue;
if (value > max) {
max = value;
}
if (value < min) {
min = value;
}
sum += value;
last = value;
count++;
}
const avg = count > 0 ? sum / count : null;
return {
max: max !== -Infinity ? max.toFixed(fixed) : null,
min: min !== Infinity ? min.toFixed(fixed) : null,
avg: avg !== null ? avg.toFixed(fixed) : null,
last: last !== null ? last.toFixed(fixed) : null
};
}
+106
View File
@@ -0,0 +1,106 @@
/*
* @Author: 杨水淼 yangshuimiao@jsjd.cc
* @Date: 2025-07-08 10:40:52
* @LastEditors: 杨水淼 yangshuimiao@jsjd.cc
* @LastEditTime: 2025-07-09 07:38:46
* @FilePath: \echarts\js\renderCharts.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
function doubleLineChart(params){
/*
需要外部提供:
chartid: div container id
legend: array
unit: str
sub_text: str
data:data1,data2, array
*/
var dom = document.getElementById(params.chartid);
var myChart = echarts.init(dom,'dark');
option = null;
option = {
title: {
text: params.text,
subtext: params.sub_text,
textAlign:'center',
left:'50%'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:params.legend,
right:'20'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'time',
boundaryGap: false
},
yAxis: [{
type: 'value',
name:params.legend[0], //图列
show:true
},
{
type:'value',
name:params.legend[1], //图例
//scale:true,
boundaryGap:false,
show:true,
splitLine:{
show:false, //Y2 坐标刻度横线
},
}
],
dataZoom: [{
type: 'inside', //or slider
start: 0,
end: 100
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: [
{
name:params.legend[0],
type:'line',
yAxisIndex:0,
symbol:'none',
data:params.data1
},
{
name:params.legend[1],
type:'line',
yAxisIndex:1,
symbol:'none', //数据圆点
smooth:false,
data:params.data2
}
]
};
if (option && typeof option === "object") {
myChart.setOption(option, true);
}
return myChart;
}
+416
View File
@@ -0,0 +1,416 @@
/*
* A fast javascript implementation of simplex noise by Jonas Wagner
*
* Based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java.
* Which is based on example code by Stefan Gustavson (stegu@itn.liu.se).
* With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu).
* Better rank ordering method by Stefan Gustavson in 2012.
*
*
* Copyright (C) 2016 Jonas Wagner
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
(function() {
'use strict';
var F2 = 0.5 * (Math.sqrt(3.0) - 1.0);
var G2 = (3.0 - Math.sqrt(3.0)) / 6.0;
var F3 = 1.0 / 3.0;
var G3 = 1.0 / 6.0;
var F4 = (Math.sqrt(5.0) - 1.0) / 4.0;
var G4 = (5.0 - Math.sqrt(5.0)) / 20.0;
function SimplexNoise(random) {
if (!random) random = Math.random;
this.p = buildPermutationTable(random);
this.perm = new Uint8Array(512);
this.permMod12 = new Uint8Array(512);
for (var i = 0; i < 512; i++) {
this.perm[i] = this.p[i & 255];
this.permMod12[i] = this.perm[i] % 12;
}
}
SimplexNoise.prototype = {
grad3: new Float32Array([1, 1, 0,
-1, 1, 0,
1, -1, 0,
-1, -1, 0,
1, 0, 1,
-1, 0, 1,
1, 0, -1,
-1, 0, -1,
0, 1, 1,
0, -1, 1,
0, 1, -1,
0, -1, -1]),
grad4: new Float32Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1,
0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1,
1, 0, 1, 1, 1, 0, 1, -1, 1, 0, -1, 1, 1, 0, -1, -1,
-1, 0, 1, 1, -1, 0, 1, -1, -1, 0, -1, 1, -1, 0, -1, -1,
1, 1, 0, 1, 1, 1, 0, -1, 1, -1, 0, 1, 1, -1, 0, -1,
-1, 1, 0, 1, -1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, -1,
1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0,
-1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 0]),
noise2D: function(xin, yin) {
var permMod12 = this.permMod12;
var perm = this.perm;
var grad3 = this.grad3;
var n0 = 0; // Noise contributions from the three corners
var n1 = 0;
var n2 = 0;
// Skew the input space to determine which simplex cell we're in
var s = (xin + yin) * F2; // Hairy factor for 2D
var i = Math.floor(xin + s);
var j = Math.floor(yin + s);
var t = (i + j) * G2;
var X0 = i - t; // Unskew the cell origin back to (x,y) space
var Y0 = j - t;
var x0 = xin - X0; // The x,y distances from the cell origin
var y0 = yin - Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if (x0 > y0) {
i1 = 1;
j1 = 0;
} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else {
i1 = 0;
j1 = 1;
} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
var y1 = y0 - j1 + G2;
var x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
var y2 = y0 - 1.0 + 2.0 * G2;
// Work out the hashed gradient indices of the three simplex corners
var ii = i & 255;
var jj = j & 255;
// Calculate the contribution from the three corners
var t0 = 0.5 - x0 * x0 - y0 * y0;
if (t0 >= 0) {
var gi0 = permMod12[ii + perm[jj]] * 3;
t0 *= t0;
n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0); // (x,y) of grad3 used for 2D gradient
}
var t1 = 0.5 - x1 * x1 - y1 * y1;
if (t1 >= 0) {
var gi1 = permMod12[ii + i1 + perm[jj + j1]] * 3;
t1 *= t1;
n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1);
}
var t2 = 0.5 - x2 * x2 - y2 * y2;
if (t2 >= 0) {
var gi2 = permMod12[ii + 1 + perm[jj + 1]] * 3;
t2 *= t2;
n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
return 70.0 * (n0 + n1 + n2);
},
// 3D simplex noise
noise3D: function(xin, yin, zin) {
var permMod12 = this.permMod12;
var perm = this.perm;
var grad3 = this.grad3;
var n0, n1, n2, n3; // Noise contributions from the four corners
// Skew the input space to determine which simplex cell we're in
var s = (xin + yin + zin) * F3; // Very nice and simple skew factor for 3D
var i = Math.floor(xin + s);
var j = Math.floor(yin + s);
var k = Math.floor(zin + s);
var t = (i + j + k) * G3;
var X0 = i - t; // Unskew the cell origin back to (x,y,z) space
var Y0 = j - t;
var Z0 = k - t;
var x0 = xin - X0; // The x,y,z distances from the cell origin
var y0 = yin - Y0;
var z0 = zin - Z0;
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in.
var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
if (x0 >= y0) {
if (y0 >= z0) {
i1 = 1;
j1 = 0;
k1 = 0;
i2 = 1;
j2 = 1;
k2 = 0;
} // X Y Z order
else if (x0 >= z0) {
i1 = 1;
j1 = 0;
k1 = 0;
i2 = 1;
j2 = 0;
k2 = 1;
} // X Z Y order
else {
i1 = 0;
j1 = 0;
k1 = 1;
i2 = 1;
j2 = 0;
k2 = 1;
} // Z X Y order
}
else { // x0<y0
if (y0 < z0) {
i1 = 0;
j1 = 0;
k1 = 1;
i2 = 0;
j2 = 1;
k2 = 1;
} // Z Y X order
else if (x0 < z0) {
i1 = 0;
j1 = 1;
k1 = 0;
i2 = 0;
j2 = 1;
k2 = 1;
} // Y Z X order
else {
i1 = 0;
j1 = 1;
k1 = 0;
i2 = 1;
j2 = 1;
k2 = 0;
} // Y X Z order
}
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6.
var x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
var y1 = y0 - j1 + G3;
var z1 = z0 - k1 + G3;
var x2 = x0 - i2 + 2.0 * G3; // Offsets for third corner in (x,y,z) coords
var y2 = y0 - j2 + 2.0 * G3;
var z2 = z0 - k2 + 2.0 * G3;
var x3 = x0 - 1.0 + 3.0 * G3; // Offsets for last corner in (x,y,z) coords
var y3 = y0 - 1.0 + 3.0 * G3;
var z3 = z0 - 1.0 + 3.0 * G3;
// Work out the hashed gradient indices of the four simplex corners
var ii = i & 255;
var jj = j & 255;
var kk = k & 255;
// Calculate the contribution from the four corners
var t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
if (t0 < 0) n0 = 0.0;
else {
var gi0 = permMod12[ii + perm[jj + perm[kk]]] * 3;
t0 *= t0;
n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0 + grad3[gi0 + 2] * z0);
}
var t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
if (t1 < 0) n1 = 0.0;
else {
var gi1 = permMod12[ii + i1 + perm[jj + j1 + perm[kk + k1]]] * 3;
t1 *= t1;
n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1 + grad3[gi1 + 2] * z1);
}
var t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
if (t2 < 0) n2 = 0.0;
else {
var gi2 = permMod12[ii + i2 + perm[jj + j2 + perm[kk + k2]]] * 3;
t2 *= t2;
n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2 + grad3[gi2 + 2] * z2);
}
var t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
if (t3 < 0) n3 = 0.0;
else {
var gi3 = permMod12[ii + 1 + perm[jj + 1 + perm[kk + 1]]] * 3;
t3 *= t3;
n3 = t3 * t3 * (grad3[gi3] * x3 + grad3[gi3 + 1] * y3 + grad3[gi3 + 2] * z3);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to stay just inside [-1,1]
return 32.0 * (n0 + n1 + n2 + n3);
},
// 4D simplex noise, better simplex rank ordering method 2012-03-09
noise4D: function(x, y, z, w) {
var permMod12 = this.permMod12;
var perm = this.perm;
var grad4 = this.grad4;
var n0, n1, n2, n3, n4; // Noise contributions from the five corners
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
var s = (x + y + z + w) * F4; // Factor for 4D skewing
var i = Math.floor(x + s);
var j = Math.floor(y + s);
var k = Math.floor(z + s);
var l = Math.floor(w + s);
var t = (i + j + k + l) * G4; // Factor for 4D unskewing
var X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
var Y0 = j - t;
var Z0 = k - t;
var W0 = l - t;
var x0 = x - X0; // The x,y,z,w distances from the cell origin
var y0 = y - Y0;
var z0 = z - Z0;
var w0 = w - W0;
// For the 4D case, the simplex is a 4D shape I won't even try to describe.
// To find out which of the 24 possible simplices we're in, we need to
// determine the magnitude ordering of x0, y0, z0 and w0.
// Six pair-wise comparisons are performed between each possible pair
// of the four coordinates, and the results are used to rank the numbers.
var rankx = 0;
var ranky = 0;
var rankz = 0;
var rankw = 0;
if (x0 > y0) rankx++;
else ranky++;
if (x0 > z0) rankx++;
else rankz++;
if (x0 > w0) rankx++;
else rankw++;
if (y0 > z0) ranky++;
else rankz++;
if (y0 > w0) ranky++;
else rankw++;
if (z0 > w0) rankz++;
else rankw++;
var i1, j1, k1, l1; // The integer offsets for the second simplex corner
var i2, j2, k2, l2; // The integer offsets for the third simplex corner
var i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
// simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
// Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
// impossible. Only the 24 indices which have non-zero entries make any sense.
// We use a thresholding to set the coordinates in turn from the largest magnitude.
// Rank 3 denotes the largest coordinate.
i1 = rankx >= 3 ? 1 : 0;
j1 = ranky >= 3 ? 1 : 0;
k1 = rankz >= 3 ? 1 : 0;
l1 = rankw >= 3 ? 1 : 0;
// Rank 2 denotes the second largest coordinate.
i2 = rankx >= 2 ? 1 : 0;
j2 = ranky >= 2 ? 1 : 0;
k2 = rankz >= 2 ? 1 : 0;
l2 = rankw >= 2 ? 1 : 0;
// Rank 1 denotes the second smallest coordinate.
i3 = rankx >= 1 ? 1 : 0;
j3 = ranky >= 1 ? 1 : 0;
k3 = rankz >= 1 ? 1 : 0;
l3 = rankw >= 1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to compute that.
var x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
var y1 = y0 - j1 + G4;
var z1 = z0 - k1 + G4;
var w1 = w0 - l1 + G4;
var x2 = x0 - i2 + 2.0 * G4; // Offsets for third corner in (x,y,z,w) coords
var y2 = y0 - j2 + 2.0 * G4;
var z2 = z0 - k2 + 2.0 * G4;
var w2 = w0 - l2 + 2.0 * G4;
var x3 = x0 - i3 + 3.0 * G4; // Offsets for fourth corner in (x,y,z,w) coords
var y3 = y0 - j3 + 3.0 * G4;
var z3 = z0 - k3 + 3.0 * G4;
var w3 = w0 - l3 + 3.0 * G4;
var x4 = x0 - 1.0 + 4.0 * G4; // Offsets for last corner in (x,y,z,w) coords
var y4 = y0 - 1.0 + 4.0 * G4;
var z4 = z0 - 1.0 + 4.0 * G4;
var w4 = w0 - 1.0 + 4.0 * G4;
// Work out the hashed gradient indices of the five simplex corners
var ii = i & 255;
var jj = j & 255;
var kk = k & 255;
var ll = l & 255;
// Calculate the contribution from the five corners
var t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
if (t0 < 0) n0 = 0.0;
else {
var gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]]]] % 32) * 4;
t0 *= t0;
n0 = t0 * t0 * (grad4[gi0] * x0 + grad4[gi0 + 1] * y0 + grad4[gi0 + 2] * z0 + grad4[gi0 + 3] * w0);
}
var t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
if (t1 < 0) n1 = 0.0;
else {
var gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]] % 32) * 4;
t1 *= t1;
n1 = t1 * t1 * (grad4[gi1] * x1 + grad4[gi1 + 1] * y1 + grad4[gi1 + 2] * z1 + grad4[gi1 + 3] * w1);
}
var t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
if (t2 < 0) n2 = 0.0;
else {
var gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]] % 32) * 4;
t2 *= t2;
n2 = t2 * t2 * (grad4[gi2] * x2 + grad4[gi2 + 1] * y2 + grad4[gi2 + 2] * z2 + grad4[gi2 + 3] * w2);
}
var t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
if (t3 < 0) n3 = 0.0;
else {
var gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]] % 32) * 4;
t3 *= t3;
n3 = t3 * t3 * (grad4[gi3] * x3 + grad4[gi3 + 1] * y3 + grad4[gi3 + 2] * z3 + grad4[gi3 + 3] * w3);
}
var t4 = 0.6 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
if (t4 < 0) n4 = 0.0;
else {
var gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]] % 32) * 4;
t4 *= t4;
n4 = t4 * t4 * (grad4[gi4] * x4 + grad4[gi4 + 1] * y4 + grad4[gi4 + 2] * z4 + grad4[gi4 + 3] * w4);
}
// Sum up and scale the result to cover the range [-1,1]
return 27.0 * (n0 + n1 + n2 + n3 + n4);
}
};
function buildPermutationTable(random) {
var i;
var p = new Uint8Array(256);
for (i = 0; i < 256; i++) {
p[i] = i;
}
for (i = 0; i < 255; i++) {
var r = i + ~~(random() * (256 - i));
var aux = p[i];
p[i] = p[r];
p[r] = aux;
}
return p;
}
SimplexNoise._buildPermutationTable = buildPermutationTable;
// amd
if (typeof define !== 'undefined' && define.amd) define(function() {return SimplexNoise;});
// common js
if (typeof exports !== 'undefined') exports.SimplexNoise = SimplexNoise;
// browser
else if (typeof window !== 'undefined') window.SimplexNoise = SimplexNoise;
// nodejs
if (typeof module !== 'undefined') {
module.exports = SimplexNoise;
}
})();
+80
View File
@@ -0,0 +1,80 @@
/**
* Created by Simon on 2017-6-14.
*/
(function(){
$("#btn-search").on("click",function(){
if(check_form("myform")){
$("#myform").submit();
}
});
drawGraph();
function drawGraph(){
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
var x = $.parseJSON($("#x").val());
var legend = $.parseJSON($("#legend").val());
var total = $.parseJSON($("#total").val());
var l_yield = $.parseJSON($("#yield").val());
var option = {
title: {
text: '经营报表趋势图',
top: "top",
left: "center"
},
tooltip: {
trigger: 'axis',
axisPointer: {
animation: false
}
},
grid: {x: '7%', y: '7%', width: '85%', height: '70%',top: "15%"},
xAxis: {
type : 'category',
data : x
},
yAxis: [{
type: 'value',
name: legend[0],
},{
type: 'value',
name: legend[1],
/* axisLabel: {
formatter:'{value} %'
}, */
scale: true,
boundaryGap: ['20%','20%']
}],
series: [{
name: legend[0],
type: "bar",
yAxisIndex: 0,
data: total,
itemStyle:{
normal:{
color: "#00BB00"
}
}
},{
name: legend[1],
type: "line",
yAxisIndex: 1,
data: l_yield,
label:{
normal:{
show: true
}
},
lineStyle:{
normal:{
color: "#D26900"
}
}
}]
};
//console.info(option);
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+59
View File
@@ -0,0 +1,59 @@
/* Noto Serif SC - downloaded from Google Fonts */
@font-face {
font-family: 'Noto Serif SC';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(../webfonts/google/NotoSerifSC-400.ttf) format('truetype');
}
@font-face {
font-family: 'Noto Serif SC';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../webfonts/google/NotoSerifSC-600.ttf) format('truetype');
}
@font-face {
font-family: 'Noto Serif SC';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../webfonts/google/NotoSerifSC-700.ttf) format('truetype');
}
/* Inter - downloaded from Google Fonts */
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(../webfonts/google/Inter-300.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(../webfonts/google/Inter-400.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../webfonts/google/Inter-500.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../webfonts/google/Inter-600.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../webfonts/google/Inter-700.ttf) format('truetype');
}
File diff suppressed because it is too large Load Diff
+8
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+31
View File
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+69
View File
File diff suppressed because one or more lines are too long
+1646
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More