Compare commits
38
Commits
cb72ffdf03
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10569bb828 | ||
|
|
11f31762ad | ||
|
|
7785de7d1f | ||
|
|
4da1fc9301 | ||
|
|
f8bca284a8 | ||
|
|
8ea9b48a9a | ||
|
|
60fb1b95e1 | ||
|
|
742bed2644 | ||
|
|
080d6da44c | ||
|
|
ef123c697f | ||
|
|
eedead0d41 | ||
|
|
f3f9d19da7 | ||
|
|
7e57cae242 | ||
|
|
07da6a2ad4 | ||
|
|
2f600aed0f | ||
|
|
4c348e379d | ||
|
|
8303ae39f1 | ||
|
|
4990e2068c | ||
|
|
cb98c1649c | ||
|
|
4a56455151 | ||
|
|
521e0687a4 | ||
|
|
4b3a51083b | ||
|
|
bd82783ddb | ||
|
|
bd4f92d465 | ||
|
|
de11c31f0b | ||
|
|
daeae185dd | ||
|
|
5152b3ee2f | ||
|
|
43a202c789 | ||
|
|
5d135b24f1 | ||
|
|
e33cb8e93a | ||
|
|
d367cfc2e9 | ||
|
|
fdbbe445bb | ||
|
|
e3f65c200d | ||
|
|
b6b0d93b37 | ||
|
|
3a8e5ef82d | ||
|
|
eded42c881 | ||
|
|
0b876e8807 | ||
|
|
3a09f3ca67 |
@@ -0,0 +1,8 @@
|
||||
.vscode/
|
||||
.files/
|
||||
uploads/
|
||||
xls/
|
||||
.serena/
|
||||
.mcp.json
|
||||
*.xls
|
||||
*.map
|
||||
@@ -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. **模式 B(fetch 外部 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. **模式 C(AJAX → `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.md;PHP 语法检查 `php -l` 修改后必做。)
|
||||
@@ -0,0 +1,190 @@
|
||||
# CLAUDE.md
|
||||
|
||||
本文件为 Claude Code(claude.ai/code)在本仓库中工作提供指引。
|
||||
|
||||
## 项目概览
|
||||
|
||||
基于 PHP 的 A 股金融数据可视化和宁波房地产数据分析平台。使用 ECharts 生成交互式图表,后端为 MySQL 数据库和 TuShare API。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **后端**: PHP(无框架),Composer 管理依赖(`phpoffice/phpspreadsheet`、`monolog/monolog`)
|
||||
- **前端**: ECharts 4.x、jQuery、Tailwind CSS 3.4(CDN 引入)、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/`)
|
||||
|
||||
**模式 C(AJAX → `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-core(AI/研究页面使用)
|
||||
- `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-echart,rsync 单向推送本地 → 服务器)
|
||||
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`,包含:
|
||||
|
||||
- **当前状态**:刚刚完成了什么、改了哪些文件、结果如何
|
||||
- **后续步骤**:具体有序的下一步行动
|
||||
- **待解决问题**:未解决的疑问、已知限制或需要决策的事项
|
||||
@@ -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` |
|
||||
|
||||
### 日报 API(2 张,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/` 目录中的文件已排除,不纳入统计
|
||||
@@ -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/ # 页面专属图表/渲染 JS(newsReports.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 端口 9000(VS 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 device’s inputs. (deprecated)
|
||||
|
||||
property device_output_layers
|
||||
|
||||
Get a list of the names of the device’s 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 shell’s tc command params is wrong.
|
||||
|
||||
exception hailo_platform.tools.udp_rate_limiter.BadTCCallError[source]
|
||||
|
||||
Bases: Exception
|
||||
|
||||
Shell’s 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
|
||||
|
||||
@@ -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>
|
||||
@@ -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(); ?>
|
||||
开始时间: <input type='date' name='t_start' id='t_start' width='30px' >
|
||||
结束时间: <input type='date' name='t_end' id='t_end' width='30px' >
|
||||
|
||||
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
|
||||
</div> </form>
|
||||
<div > </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 > </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"; ?>
|
||||
@@ -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(); ?>
|
||||
Daily/Monthly:
|
||||
<?php byDM('dm','dblock','mblock'); ?>
|
||||
<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' >
|
||||
结束月份: <input type="month" name='med' id='med' >
|
||||
</span>
|
||||
|
||||
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
|
||||
</div> </form>
|
||||
<div > </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 > </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 > </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"; ?>
|
||||
@@ -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(); ?>
|
||||
Daily/Monthly:
|
||||
<?php byDM('dm','dblock','mblock'); ?>
|
||||
<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' >
|
||||
结束月份: <input type="month" name='med' id='med' >
|
||||
</span>
|
||||
|
||||
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
|
||||
</div> </form>
|
||||
<div > </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 > </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"; ?>
|
||||
@@ -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 > </div>
|
||||
|
||||
</div> </form>
|
||||
<div > </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"; ?>
|
||||
|
||||
@@ -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'); ?>
|
||||
融资融券交易所: <?php seList('se'); ?>
|
||||
|
||||
开始时间: <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 > </div>
|
||||
|
||||
</div> </form>
|
||||
<div > </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"); ?>
|
||||
|
||||
@@ -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'); ?>
|
||||
|
||||
|
||||
开始时间: <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 > </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 > </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"); ?>
|
||||
|
||||
@@ -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'); ?>
|
||||
|
||||
开始时间: <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 > </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 > </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"; ?>
|
||||
@@ -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>
|
||||
资金选择:
|
||||
<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>
|
||||
数据累积:
|
||||
<select name="stacked" id="stacked">
|
||||
<option value="-1">每日值</option>
|
||||
<option value="1">累积值</option>
|
||||
</select>
|
||||
开始时间: <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> </form>
|
||||
<div > </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"; ?>
|
||||
@@ -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,
|
||||
));
|
||||
?>
|
||||
@@ -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>
|
||||
@@ -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']?>' >
|
||||
|
||||
<button id="submitBtn" class="btn-submit"><span>查询数据</span></button>
|
||||
</div> </form>
|
||||
<div > </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 > </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"; ?>
|
||||
@@ -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 > </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> </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"; ?>
|
||||
@@ -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 > </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"; ?>
|
||||
|
||||
@@ -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 > </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"; ?>
|
||||
|
||||
@@ -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 > </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"; ?>
|
||||
|
||||
@@ -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 > </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>
|
||||
|
||||
@@ -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 > </div>
|
||||
|
||||
</div> </form>
|
||||
<div > </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"; ?>
|
||||
|
||||
@@ -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 > </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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"require": {
|
||||
"monolog/monolog": "2.0.*",
|
||||
"phpoffice/phpspreadsheet": "^1.18",
|
||||
"ext-json": "*",
|
||||
"ext-mysqli": "*",
|
||||
"ext-curl": "*"
|
||||
}
|
||||
}
|
||||
Generated
+981
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# continuation.md — 会话检查点
|
||||
|
||||
> 生成时间:2026-08-04(本会话)
|
||||
> 工作区:/Users/summer/Downloads/py/www(echart 平台,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/` 每日报告目录(20260608–20260804)。`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→cninfo;intl: 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
File diff suppressed because it is too large
Load Diff
+129
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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();
|
||||
?>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
<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 > </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 > </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 > </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 > </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 > </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 > </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 > </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"; ?>
|
||||
|
||||
@@ -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>
|
||||
<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 > </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 > </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 > </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 > </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 > </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 > </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"; ?>
|
||||
|
||||
@@ -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>
|
||||
@@ -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 > </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 > </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 > </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 > </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 > </div>
|
||||
<?php include_once "../html/footer.php"; ?>
|
||||
|
||||
@@ -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 > </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 > </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 > </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 > </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"; ?>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<div id='footer'>
|
||||
<p> </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; "> © </span>2019-<?=date('Y')?>
|
||||
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> </div>
|
||||
<div> </div>
|
||||
<div> </div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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 > </div>
|
||||
<div style="text-align: center"><h2> <?=$title?> </h2></div>
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
?>
|
||||
@@ -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
|
||||
];
|
||||
}
|
||||
?>
|
||||
@@ -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);
|
||||
}
|
||||
?>
|
||||
@@ -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;
|
||||
}
|
||||
?>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -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"></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";
|
||||
?>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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; "> © </span>2019-<?=date('Y')?>
|
||||
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>
|
||||
|
||||
@@ -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 > </div>
|
||||
<div style="text-align: center"><h2>Stock Reference Data</h2></div>
|
||||
|
||||
<div > </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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/"/g, '"').replace(/'/g, ''');
|
||||
}
|
||||
|
||||
$(function () {
|
||||
NewsReports.init();
|
||||
});
|
||||
+141
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -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
Vendored
+18
File diff suppressed because one or more lines are too long
Vendored
+9
File diff suppressed because one or more lines are too long
@@ -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
Vendored
+8
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
Vendored
+31
File diff suppressed because one or more lines are too long
+95739
File diff suppressed because it is too large
Load Diff
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+2
File diff suppressed because one or more lines are too long
Vendored
+69
File diff suppressed because one or more lines are too long
Vendored
+1646
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
Reference in New Issue
Block a user