Compare commits
33 Commits
5e8d1e4895
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fb2ba4dcf | |||
| cbca6217d6 | |||
| 04be883e4d | |||
| cbdc5199f4 | |||
| 8d9161eb1a | |||
| c3e430a24b | |||
| 8c8dec620e | |||
| af15aef37d | |||
| 84f0d60817 | |||
| 0c2d410642 | |||
| 26d20dbd7c | |||
| ae6dcc228b | |||
| 6df33a663c | |||
| 28415a1d4d | |||
| 78e7233bc0 | |||
| 008d4b3e19 | |||
| 9881f75e59 | |||
| efdef3798e | |||
| f4c67bd102 | |||
| 54dd2fe5ad | |||
| bf469e33ee | |||
| 61e748e020 | |||
| bd881f239e | |||
| 79f1a1dc80 | |||
| 074aa4d677 | |||
| 6e2e4cdc98 | |||
| 29e364f74a | |||
| 0b3f7210e0 | |||
| 8ed4837992 | |||
| f36410dcc6 | |||
| 7e4b6a3443 | |||
| 616239392a | |||
| f2b432a9f4 |
+121
-3
@@ -6,7 +6,16 @@
|
||||
|
||||
## Phases
|
||||
|
||||
- [ ] **Phase 1: 遗漏号码分析** - 在 history 页面添加"遗漏号码"按钮,弹窗支持输入期数查询并展示遗漏号码、遗漏期数及波色球
|
||||
- [x] **Phase 1: 遗漏号码分析** - 在 history 页面添加"遗漏号码"按钮,弹窗支持输入期数查询并展示遗漏号码、遗漏期数及波色球
|
||||
- [ ] **Phase 2: 走势图分析** - 可视化展示号码在连续期次中的出现趋势
|
||||
- [ ] **Phase 3: 冷热号码分析** - 统计某段时间内出现频率最高和最少的号码
|
||||
- [ ] **Phase 4: 波色分析** - 统计红蓝绿波的出现比例和趋势
|
||||
- [ ] **Phase 5: 生肖分析** - 统计各生肖出现频率和遗漏情况
|
||||
- [ ] **Phase 6: 奇偶分析** - 统计每期奇数/偶数的比例
|
||||
- [ ] **Phase 7: 大小分析** - 按号码大小(1-24为小,25-49为大)统计
|
||||
- [ ] **Phase 8: 和值分析** - 每期号码之和的趋势
|
||||
- [ ] **Phase 9: 连号分析** - 连续出现的号码对/三连号统计
|
||||
- [ ] **Phase 10: 尾数分析** - 按尾数(0-9)分组统计
|
||||
|
||||
## Phase Details
|
||||
|
||||
@@ -27,11 +36,120 @@ Plans:
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 2: 走势图分析
|
||||
**Goal**: 以折线图或网格形式可视化展示各号码在最近期次中的出现情况,辅助发现规律
|
||||
**Depends on**: 1 (使用已有的 history.js 和 History 模型)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 用户可通过新按钮打开走势图弹窗
|
||||
2. 可选择期数范围(默认 30 期)
|
||||
3. 图表展示 1-49 号码在各期的出现/未出现状态
|
||||
4. 支持 num1~num7 全部号码或仅特码筛选
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 3: 冷热号码分析
|
||||
**Goal**: 统计某段时间内出现频率最高(热)和最少(冷)的号码
|
||||
**Depends on**: 1 (复用数据查询逻辑)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 用户可选择统计期数范围
|
||||
2. 展示热号(高频)和冷号(低频)列表
|
||||
3. 显示每个号码的出现次数和百分比
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 4: 波色分析
|
||||
**Goal**: 统计红、蓝、绿波的出现比例和趋势
|
||||
**Depends on**: 1 (复用 Num 模型和颜色映射)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示三种波色的出现次数和占比
|
||||
2. 可视化展示波色在最近期次中的分布
|
||||
3. 支持特码波色单独统计
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 5: 生肖分析
|
||||
**Goal**: 统计各生肖出现频率和遗漏情况
|
||||
**Depends on**: 1 (复用 getAnimalMap 接口)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示 12 生肖的出现次数排名
|
||||
2. 显示各生肖遗漏期数
|
||||
3. 支持特码生肖单独统计
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 6: 奇偶分析
|
||||
**Goal**: 统计每期奇数/偶数的比例
|
||||
**Depends on**: 1 (复用 history 数据)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示总体奇偶比例
|
||||
2. 展示每期奇偶数量
|
||||
3. 支持特码奇偶单独统计
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 7: 大小分析
|
||||
**Goal**: 按号码大小(1-24为小,25-49为大)统计
|
||||
**Depends on**: 1 (复用 history 数据)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示总体大小比例
|
||||
2. 展示每期大小数量
|
||||
3. 支持特码大小单独统计
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 8: 和值分析
|
||||
**Goal**: 每期号码之和的趋势
|
||||
**Depends on**: 1 (复用 history 数据)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示每期和值折线图
|
||||
2. 显示和值的平均值和极值
|
||||
3. 可过滤特码和值
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 9: 连号分析
|
||||
**Goal**: 连续出现的号码对/三连号统计
|
||||
**Depends on**: 1 (复用 history 数据)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示历史中出现过的连号组合
|
||||
2. 按出现频率排序
|
||||
3. 支持查询特定连号的历史
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 10: 尾数分析
|
||||
**Goal**: 按尾数(0-9)分组统计
|
||||
**Depends on**: 1 (复用 history 数据)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. 展示 0-9 尾数的出现频率
|
||||
2. 展示每期尾数分布
|
||||
3. 支持特码尾数单独统计
|
||||
**Plans**: TBD
|
||||
|
||||
**UI hint**: yes
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1
|
||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. 遗漏号码分析 | 0/3 | Not started | - |
|
||||
| 1. 遗漏号码分析 | 3/3 | Complete | 2026-04-21 |
|
||||
| 2. 走势图分析 | 0/0 | Not planned | - |
|
||||
| 3. 冷热号码分析 | 0/0 | Not planned | - |
|
||||
| 4. 波色分析 | 0/0 | Not planned | - |
|
||||
| 5. 生肖分析 | 0/0 | Not planned | - |
|
||||
| 6. 奇偶分析 | 0/0 | Not planned | - |
|
||||
| 7. 大小分析 | 0/0 | Not planned | - |
|
||||
| 8. 和值分析 | 0/0 | Not planned | - |
|
||||
| 9. 连号分析 | 0/0 | Not planned | - |
|
||||
| 10. 尾数分析 | 0/0 | Not planned | - |
|
||||
|
||||
+27
-14
@@ -2,16 +2,16 @@
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: executing
|
||||
stopped_at: ROADMAP.md created, Phase 1 ready to plan
|
||||
last_updated: "2026-04-21T13:05:05.724Z"
|
||||
last_activity: 2026-04-21 -- Phase 01 execution started
|
||||
status: complete
|
||||
stopped_at: Phase 1 complete, 9 new analysis phases added to roadmap
|
||||
last_updated: "2026-04-21T14:00:00.000Z"
|
||||
last_activity: 2026-04-21 -- Phase 01 complete, Phases 2-10 added
|
||||
progress:
|
||||
total_phases: 1
|
||||
completed_phases: 0
|
||||
total_phases: 10
|
||||
completed_phases: 1
|
||||
total_plans: 3
|
||||
completed_plans: 0
|
||||
percent: 0
|
||||
completed_plans: 3
|
||||
percent: 10
|
||||
---
|
||||
|
||||
# Project State
|
||||
@@ -25,12 +25,12 @@ See: .planning/PROJECT.md (updated 2026-04-21)
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 01 (omitted-number-analysis) — EXECUTING
|
||||
Plan: 1 of 3
|
||||
Status: Executing Phase 01
|
||||
Last activity: 2026-04-21 -- Phase 01 execution started
|
||||
Phase: 01 (omitted-number-analysis) — COMPLETE
|
||||
Plan: 3 of 3
|
||||
Status: Phase 1 complete, ready to plan next phase
|
||||
Last activity: 2026-04-24 -- Completed quick task 260424-roj: 在history页面新增特码冷热查询功能
|
||||
|
||||
Progress: [░░░░░░░░░░] 0%
|
||||
Progress: [████░░░░░░] 10%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
@@ -69,6 +69,14 @@ None yet.
|
||||
|
||||
None yet.
|
||||
|
||||
### Quick Tasks Completed
|
||||
|
||||
| # | Description | Date | Commit | Directory |
|
||||
|---|-------------|------|--------|-----------|
|
||||
| 260422-vep | 在控制台增加特码热力图功能 | 2026-04-22 | 73e7403 | [260422-vep](./quick/260422-vep/) |
|
||||
| 260424-roj | 在history页面新增特码冷热查询功能 | 2026-04-24 | 2513bbb | [260424-roj](./quick/260424-roj-history-y/) |
|
||||
| 260425-w2i | 在控制台页面新增区域转移概率统计功能 | 2026-04-25 | 28415a1 | [260425-w2i](./quick/260425-w2i-5-10/) |
|
||||
|
||||
## Deferred Items
|
||||
|
||||
| Category | Item | Status | Deferred At |
|
||||
@@ -78,5 +86,10 @@ None yet.
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-21
|
||||
Stopped at: ROADMAP.md created, Phase 1 ready to plan
|
||||
Stopped at: Phase 1 complete, 9 new analysis phases added to roadmap
|
||||
Resume file: None
|
||||
|
||||
### Roadmap Evolution
|
||||
|
||||
- Phase 1: 遗漏号码分析 — complete (2026-04-21)
|
||||
- Phase 2-10 added: 走势图、冷热号码、波色、生肖、奇偶、大小、和值、连号、尾数分析
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
quick_id: 260422-vep
|
||||
description: 在控制台增加特码热力图功能
|
||||
mode: quick
|
||||
date: 2026-04-22
|
||||
---
|
||||
|
||||
# Quick Task Plan: 特码热力图功能
|
||||
|
||||
## Goal
|
||||
在控制台(Dashboard)增加特码热力图功能,直观展示特码号码在近 N 期内的出现分布情况。
|
||||
|
||||
## Implementation Design
|
||||
|
||||
### 热力图数据结构
|
||||
- X轴:期号(最近30期)
|
||||
- Y轴:号码 1-49
|
||||
- 颜色:基于号码的波色(红/蓝/绿),出现时显示颜色,未出现时显示浅灰
|
||||
|
||||
### Files to Modify
|
||||
1. `application/admin/model/History.php` - 添加 `getSpecialHeatmap()` 方法
|
||||
2. `application/admin/controller/History.php` - 添加 `specialHeatmap` API 接口和权限声明
|
||||
3. `public/assets/js/backend/dashboard.js` - 添加热力图渲染逻辑
|
||||
4. `application/admin/view/dashboard/index.html` - 无需修改(热力图容器由 JS 动态生成)
|
||||
|
||||
## Tasks
|
||||
|
||||
### Task 1: 后端数据模型
|
||||
**File:** `application/admin/model/History.php`
|
||||
**Action:** 添加 `getSpecialHeatmap()` 方法
|
||||
**Verify:** 方法返回热力图数据(expects, heatmap_data, colorMap)
|
||||
**Done:** 方法可被正确调用并返回结构化数据
|
||||
|
||||
### Task 2: API 接口
|
||||
**File:** `application/admin/controller/History.php`
|
||||
**Action:**
|
||||
1. 在 `$noNeedRight` 数组添加 `specialHeatmap`
|
||||
2. 添加 `specialHeatmap()` 方法
|
||||
**Verify:** API 可通过 AJAX 访问并返回正确数据
|
||||
**Done:** 接口可被前端调用
|
||||
|
||||
### Task 3: 前端渲染
|
||||
**File:** `public/assets/js/backend/dashboard.js`
|
||||
**Action:**
|
||||
1. 在 AJAX 请求中添加热力图数据获取
|
||||
2. 在 render 函数中添加热力图 HTML 和 ECharts 渲染
|
||||
**Verify:** 热力图正确显示在 Dashboard 页面
|
||||
**Done:** 热力图可视化完成
|
||||
@@ -0,0 +1,34 @@
|
||||
# Quick Task 260422-vep: 特码热力图功能 - Summary
|
||||
|
||||
**Status:** Completed
|
||||
**Date:** 2026-04-22
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
在控制台(Dashboard)增加了特码热力图功能,直观展示特码号码在近 N 期内的出现分布情况。
|
||||
|
||||
### Changes Made
|
||||
|
||||
**1. Backend Model (`application/admin/model/History.php`)**
|
||||
- 新增 `getSpecialHeatmap($periods)` 方法
|
||||
- 返回热力图数据结构:expects(期号列表)、heatmap(出现数据)、colors(号码波色)、nums(号码列表)
|
||||
|
||||
**2. Backend Controller (`application/admin/controller/History.php`)**
|
||||
- 在 `$noNeedRight` 数组添加 `specialHeatmap` 权限声明
|
||||
- 新增 `specialHeatmap()` API 接口方法
|
||||
- `getDashboardData()` 方法已自动包含热力图数据
|
||||
|
||||
**3. Frontend JS (`public/assets/js/backend/dashboard.js`)**
|
||||
- 在 `render()` 函数中添加热力图 HTML 部分
|
||||
- 新增 ECharts 热力图渲染逻辑,使用号码波色作为单元格颜色
|
||||
|
||||
### Features
|
||||
- X轴:期号(从左往右,从远到近)
|
||||
- Y轴:号码 1-49
|
||||
- 颜色:号码对应波色(红/蓝/绿),未开出显示浅灰
|
||||
- Tooltip:显示期号、号码、状态
|
||||
|
||||
### Files Modified
|
||||
1. `application/admin/model/History.php` - 添加热力图数据方法
|
||||
2. `application/admin/controller/History.php` - 添加 API 接口
|
||||
3. `public/assets/js/backend/dashboard.js` - 添加前端渲染逻辑
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
description: 在history页面新增特码冷热号查询功能 — 选定某一期,向前推算y期,判断该期特码属于冷号还是热号
|
||||
tasks: 3
|
||||
must_haves:
|
||||
- 后端接口接收 expect(期号) 和 lookback(向前期数) 参数
|
||||
- 计算逻辑: 从指定期号往前lookback期, 统计该期特码在lookback范围内的出现频率, 判定冷热
|
||||
- 前端弹窗: 选择期号 + 输入向前期数 + 展示冷热判定结果
|
||||
plan_model: quick
|
||||
---
|
||||
|
||||
# Quick Plan: 在history页面新增特码冷热号查询功能
|
||||
|
||||
## Task 1: 后端 Model — 添加 getSpecialHotColdByExpect 方法
|
||||
|
||||
**Files:** `application/admin/model/History.php`
|
||||
|
||||
**Action:** 新增方法 `getSpecialHotColdByExpect($expect, $lookback)`
|
||||
|
||||
- 根据指定期号 `expect` 查询到该期数据,获取该期特码 `num7`
|
||||
- 从该期往前数 `lookback` 期(不包含该期本身),统计这期间每个号码的出现次数
|
||||
- 计算该特码在 lookback 范围内的出现次数和频率
|
||||
- 根据频率分布判定冷热:将该号码的出现次数与所有号码的平均值比较
|
||||
- 高于平均值 1.5 倍以上 → 热号
|
||||
- 低于平均值 0.5 倍以下 → 冷号
|
||||
- 介于之间 → 温号
|
||||
- 返回结构化数据:`{expect, specialNum, lookback, count, avgCount, status, rank, totalPeriods}`
|
||||
|
||||
## Task 2: 后端 Controller — 添加 specialHotColdAction 方法
|
||||
|
||||
**Files:** `application/admin/controller/History.php`
|
||||
|
||||
**Action:** 新增 `specialHotColdAction()` 方法
|
||||
|
||||
- 接收 AJAX GET 参数:`expect`(期号,必填), `lookback`(向前期数,默认30,范围10-100)
|
||||
- 参数校验后调用 Model 方法
|
||||
- 返回 JSON 响应
|
||||
|
||||
## Task 3: 前端 JS — 添加按钮、弹窗和渲染
|
||||
|
||||
**Files:** `application/admin/view/history/index.html`, `public/assets/js/backend/history.js`
|
||||
|
||||
**Action:**
|
||||
- 在 `index.html` 的 toolbar 添加一个「特码冷热」按钮
|
||||
- 在 `history.js` 的 `index` 方法中绑定点击事件
|
||||
- 在 `api` 对象中添加:
|
||||
- `showSpecialHotColdDialog()` — 展示弹窗,包含:当前最新期号显示、期号选择下拉框、向前期数输入框、查询按钮、结果展示区
|
||||
- `querySpecialHotCold(expect, lookback, layero)` — AJAX 请求后端接口
|
||||
- `renderSpecialHotCold(data, layero)` — 渲染冷热判定结果,用颜色区分冷/温/热
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
description: 在history页面新增特码冷热列表功能 — 每期特码相对于它前面N期的冷热状态
|
||||
status: complete
|
||||
date: 2026-04-24
|
||||
---
|
||||
|
||||
# Quick Task Summary: 特码冷热列表
|
||||
|
||||
## What was built
|
||||
|
||||
新增「特码冷热列表」功能,以弹窗表格形式展示每一期特码相对于它前面 N 期的冷热状态。
|
||||
|
||||
### 核心逻辑
|
||||
- 对每一期,取它**前面** N 期(不包含自身)的历史数据
|
||||
- 统计这 N 期内 49 个号码各自作为特码的出现次数
|
||||
- 计算平均值(N / 49),对比该期特码的出现次数:
|
||||
- **热号**:出现次数 > 平均值 × 1.5
|
||||
- **冷号**:出现次数 < 平均值 × 0.5
|
||||
- **温号**:介于两者之间
|
||||
|
||||
## Changes made
|
||||
|
||||
### Model (`application/admin/model/History.php`)
|
||||
- `getSpecialHotColdList($lookback, $limit)` — 批量查询,返回每期的冷热状态数组
|
||||
|
||||
### Controller (`application/admin/controller/History.php`)
|
||||
- `specialHotColdAction()` — AJAX 接口,接收 `lookback`(默认30)和 `limit`(默认100)
|
||||
|
||||
### Frontend (`history.js`)
|
||||
- `showSpecialHotColdDialog()` — 弹窗,包含向前期数输入框 + 查询按钮
|
||||
- `querySpecialHotCold()` — AJAX 请求
|
||||
- `renderSpecialHotCold()` — 表格渲染:期号、特码球(带波色)、冷热标签、出现次数、平均次数、频率排名;热号行淡红背景、冷号行淡蓝背景
|
||||
|
||||
## Commit
|
||||
`d4a5c30`
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
description: "在控制台页面新增区域转移概率统计:1-49分5区,统计特码所在区下一期特码出现在各区的概率"
|
||||
status: in-progress
|
||||
---
|
||||
# Quick Task 260425-w2i: 区域转移概率统计
|
||||
|
||||
## Plan
|
||||
|
||||
1. **Model** — Add `getZoneTransition($periods)` method to `app\admin\model\History`
|
||||
- Query latest `$periods` periods ordered by openTime ASC
|
||||
- Divide numbers 1-49 into 5 zones: 1-10, 11-20, 21-30, 31-40, 41-49
|
||||
- For each consecutive pair of periods, record (current_zone → next_zone)
|
||||
- Return: `{zones: ['1-10','11-20','21-30','31-40','41-49'], matrix: [[count...]], probabilities: [[prob...]], total_transitions: N}`
|
||||
|
||||
2. **Controller** — Add `zoneTransition()` method to `app\admin\controller\History`
|
||||
- Accept `periods` param (default 100, range 10-500)
|
||||
- Add to `$noNeedRight` list
|
||||
- Call model method, return JSON response
|
||||
|
||||
3. **Dashboard** — Include `zoneTransition` in `getDashboardData()` response
|
||||
|
||||
4. **Frontend JS** — Add zone transition heatmap/table in `public/assets/js/backend/dashboard.js`
|
||||
- Render as a 5×5 matrix table with color-coded cells showing count and percentage
|
||||
- Append below existing heatmap section
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
status: complete
|
||||
---
|
||||
# Quick Task 260425-w2i Summary
|
||||
|
||||
## Description
|
||||
在控制台页面新增区域转移概率统计功能:将1-49数字分为5个区域(每10个数一个区域),统计每一区域出现特码后下一期出现特码的区域概率。
|
||||
|
||||
## Changes
|
||||
- `application/admin/model/History.php` — 新增 `getZoneTransition($periods)` 方法,返回5×5转移矩阵和概率
|
||||
- `application/admin/controller/History.php` — 新增 `zoneTransition()` AJAX接口,加入 `$noNeedRight`
|
||||
- `application/admin/model/History.php` — `getDashboardData()` 增加 `zonetransition` 字段
|
||||
- `public/assets/js/backend/dashboard.js` — 渲染区域转移概率彩色表格
|
||||
|
||||
## Commits
|
||||
- `28415a1` feat(dashboard): 添加区域转移概率统计功能
|
||||
- `6df33a6` docs(state): 记录区域转移概率统计 quick task 完成
|
||||
@@ -7,9 +7,9 @@
|
||||
</style>
|
||||
<meta charset="UTF-8">
|
||||
<html>
|
||||
<head><title>404 Not Found</title></head>
|
||||
<head><title>404 Not Found </title></head>
|
||||
<body>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<center><h1>404 Not Found </h1></center>
|
||||
<hr>
|
||||
<div style="text-align: center;font-size: 15px" >Power by <a class="btlink" href="https://www.bt.cn/?from=404" target="_blank">堡塔 (免费,高效和安全的托管控制面板)</a></div>
|
||||
</body>
|
||||
|
||||
@@ -2,83 +2,18 @@
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\Admin;
|
||||
use app\admin\model\User;
|
||||
use app\common\controller\Backend;
|
||||
use app\common\model\Attachment;
|
||||
use fast\Date;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 控制台
|
||||
* 控制台 - 六合彩数据分析
|
||||
*
|
||||
* @icon fa fa-dashboard
|
||||
* @remark 用于展示当前系统中的统计数据、统计报表及重要实时数据
|
||||
*/
|
||||
class Dashboard extends Backend
|
||||
{
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
\think\Db::execute("SET @@sql_mode='';");
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
$column = [];
|
||||
$starttime = Date::unixtime('day', -6);
|
||||
$endtime = Date::unixtime('day', 0, 'end');
|
||||
$joinlist = Db("user")->where('jointime', 'between time', [$starttime, $endtime])
|
||||
->field('jointime, status, COUNT(*) AS nums, DATE_FORMAT(FROM_UNIXTIME(jointime), "%Y-%m-%d") AS join_date')
|
||||
->group('join_date')
|
||||
->select();
|
||||
for ($time = $starttime; $time <= $endtime;) {
|
||||
$column[] = date("Y-m-d", $time);
|
||||
$time += 86400;
|
||||
}
|
||||
$userlist = array_fill_keys($column, 0);
|
||||
foreach ($joinlist as $k => $v) {
|
||||
$userlist[$v['join_date']] = $v['nums'];
|
||||
}
|
||||
|
||||
$dbTableList = Db::query("SHOW TABLE STATUS");
|
||||
$addonList = get_addon_list();
|
||||
$totalworkingaddon = 0;
|
||||
$totaladdon = count($addonList);
|
||||
foreach ($addonList as $index => $item) {
|
||||
if ($item['state']) {
|
||||
$totalworkingaddon += 1;
|
||||
}
|
||||
}
|
||||
$this->view->assign([
|
||||
'totaluser' => User::count(),
|
||||
'totaladdon' => $totaladdon,
|
||||
'totaladmin' => Admin::count(),
|
||||
'totalcategory' => \app\common\model\Category::count(),
|
||||
'todayusersignup' => User::whereTime('jointime', 'today')->count(),
|
||||
'todayuserlogin' => User::whereTime('logintime', 'today')->count(),
|
||||
'sevendau' => User::whereTime('jointime|logintime|prevtime', '-7 days')->count(),
|
||||
'thirtydau' => User::whereTime('jointime|logintime|prevtime', '-30 days')->count(),
|
||||
'threednu' => User::whereTime('jointime', '-3 days')->count(),
|
||||
'sevendnu' => User::whereTime('jointime', '-7 days')->count(),
|
||||
'dbtablenums' => count($dbTableList),
|
||||
'dbsize' => array_sum(array_map(function ($item) {
|
||||
return $item['Data_length'] + $item['Index_length'];
|
||||
}, $dbTableList)),
|
||||
'totalworkingaddon' => $totalworkingaddon,
|
||||
'attachmentnums' => Attachment::count(),
|
||||
'attachmentsize' => Attachment::sum('filesize'),
|
||||
'picturenums' => Attachment::where('mimetype', 'like', 'image/%')->count(),
|
||||
'picturesize' => Attachment::where('mimetype', 'like', 'image/%')->sum('filesize'),
|
||||
]);
|
||||
|
||||
$this->assignconfig('column', array_keys($userlist));
|
||||
$this->assignconfig('userdata', array_values($userlist));
|
||||
|
||||
$this->assign('periods', 100);
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class History extends Backend
|
||||
* 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录)
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedRight = ['missingNum'];
|
||||
protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction', 'zoneTransition', 'colorWaveTransition', 'zoneToColorTransition', 'zodiacTransition'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
@@ -31,6 +31,49 @@ class History extends Backend
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看开奖记录(支持按每月日号筛选)
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->request->filter(['strip_tags', 'trim']);
|
||||
if (false === $this->request->isAjax()) {
|
||||
return $this->view->fetch();
|
||||
}
|
||||
if ($this->request->request('keyField')) {
|
||||
return $this->selectpage();
|
||||
}
|
||||
// search_day 在 filter JSON 里,先提取出来再移除
|
||||
$filterStr = $this->request->get('filter', '[]', 'trim');
|
||||
$opStr = $this->request->get('op', '[]', 'trim');
|
||||
$filter = json_decode($filterStr, true) ?: [];
|
||||
$op = json_decode($opStr, true) ?: [];
|
||||
$searchDay = isset($filter['search_day']) ? $filter['search_day'] : '';
|
||||
unset($filter['search_day'], $op['search_day']);
|
||||
// 写回 Request 对象
|
||||
$ref = new \ReflectionProperty($this->request, 'get');
|
||||
$ref->setAccessible(true);
|
||||
$getData = $ref->getValue($this->request);
|
||||
if (is_array($getData)) {
|
||||
$getData['filter'] = json_encode($filter);
|
||||
$getData['op'] = json_encode($op);
|
||||
$ref->setValue($this->request, $getData);
|
||||
}
|
||||
|
||||
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
|
||||
$list = $this->model->where($where);
|
||||
// 按每月日号筛选
|
||||
if ($searchDay !== '' && is_numeric($searchDay)) {
|
||||
$day = intval($searchDay);
|
||||
if ($day >= 1 && $day <= 31) {
|
||||
$list = $list->whereRaw('DAY(openTime) = ?', [$day]);
|
||||
}
|
||||
}
|
||||
$query = $list->order($sort, $order)->paginate($limit);
|
||||
$result = ['total' => $query->total(), 'rows' => $query->items()];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询遗漏号码
|
||||
@@ -52,5 +95,268 @@ class History extends Backend
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取走势图数据
|
||||
* @return void
|
||||
*/
|
||||
public function trendData()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getTrendData($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取冷热号码
|
||||
* @return void
|
||||
*/
|
||||
public function hotColdNumbers()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getHotColdNumbers($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 波色分析
|
||||
*/
|
||||
public function colorWaveAnalysis()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getColorWaveAnalysis($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生肖分析
|
||||
*/
|
||||
public function zodiacAnalysis()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getZodiacAnalysis($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 奇偶分析
|
||||
*/
|
||||
public function oddEvenAnalysis()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getOddEvenAnalysis($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 大小分析
|
||||
*/
|
||||
public function bigSmallAnalysis()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getBigSmallAnalysis($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 特码走势
|
||||
*/
|
||||
public function specialTrend()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$result = $this->model->getSpecialTrend($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连号分析
|
||||
*/
|
||||
public function consecutiveNumbers()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$result = $this->model->getConsecutiveNumbers($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尾数分析
|
||||
*/
|
||||
public function tailNumbers()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getTailNumbers($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 综合统计面板
|
||||
*/
|
||||
public function dashboard()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$type = $this->request->get('type', 'all');
|
||||
if (!in_array($type, ['all', 'special'])) {
|
||||
$this->error('查询类型不正确');
|
||||
}
|
||||
$result = $this->model->getDashboardData($periods, $type);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 特码冷热列表(每期相对于前N期的冷热状态)
|
||||
*/
|
||||
public function specialHotColdAction()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$lookback = $this->request->get('lookback', 30, 'intval');
|
||||
if ($lookback < 10 || $lookback > 100) {
|
||||
$this->error('向前期数范围必须在 10-100 之间');
|
||||
}
|
||||
$limit = $this->request->get('limit', 100, 'intval');
|
||||
if ($limit < 10 || $limit > 200) {
|
||||
$this->error('查询期数范围必须在 10-200 之间');
|
||||
}
|
||||
$result = $this->model->getSpecialHotColdList($lookback, $limit);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 特码热力图
|
||||
*/
|
||||
public function specialHeatmap()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 30, 'intval');
|
||||
if ($periods < 10 || $periods > 100) {
|
||||
$this->error('期数范围必须在 10-100 之间');
|
||||
}
|
||||
$result = $this->model->getSpecialHeatmap($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 区域转移概率统计
|
||||
*/
|
||||
public function zoneTransition()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 100, 'intval');
|
||||
if ($periods < 10 || $periods > 500) {
|
||||
$this->error('期数范围必须在 10-500 之间');
|
||||
}
|
||||
$result = $this->model->getZoneTransition($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 波色转移概率统计
|
||||
*/
|
||||
public function colorWaveTransition()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 100, 'intval');
|
||||
if ($periods < 10 || $periods > 500) {
|
||||
$this->error('期数范围必须在 10-500 之间');
|
||||
}
|
||||
$result = $this->model->getColorWaveTransition($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生肖转移概率统计
|
||||
*/
|
||||
public function zodiacTransition()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
$periods = $this->request->get('periods', 100, 'intval');
|
||||
if ($periods < 10 || $periods > 500) {
|
||||
$this->error('期数范围必须在 10-500 之间');
|
||||
}
|
||||
$result = $this->model->getZodiacTransition($periods);
|
||||
$this->success('查询成功', null, $result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 表格完整示例
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark 在使用Bootstrap-table中的常用方式,更多使用方式可查看:http://bootstrap-table.wenzhixin.net.cn/zh-cn/
|
||||
*/
|
||||
class Bootstraptable extends Backend
|
||||
{
|
||||
/**
|
||||
* @var \app\admin\model\AdminLog
|
||||
*/
|
||||
protected $model = null;
|
||||
/**
|
||||
* 无需鉴权的方法(需登录)
|
||||
* @var array
|
||||
*/
|
||||
protected $noNeedRight = ['start', 'pause', 'change', 'detail', 'cxselect', 'searchlist', 'selectpage'];
|
||||
|
||||
/**
|
||||
* 快捷搜索的字段
|
||||
* @var string
|
||||
*/
|
||||
protected $searchFields = 'id,title,url';
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams(null);
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->paginate($limit);
|
||||
$result = array("total" => $list->total(), "rows" => $list->items(), "extend" => ['money' => mt_rand(100000, 999999), 'price' => 200]);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
public function detail($ids)
|
||||
{
|
||||
$row = $this->model->get(['id' => $ids]);
|
||||
if (!$row) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
if ($this->request->isAjax()) {
|
||||
$this->success("Ajax请求成功", null, ['id' => $ids]);
|
||||
}
|
||||
$this->view->assign("row", $row->toArray());
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用
|
||||
*/
|
||||
public function start($ids = '')
|
||||
{
|
||||
$this->success("模拟启动成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停
|
||||
*/
|
||||
public function pause($ids = '')
|
||||
{
|
||||
$this->success("模拟暂停成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换
|
||||
*/
|
||||
public function change($ids = '')
|
||||
{
|
||||
//你需要在此做具体的操作逻辑
|
||||
|
||||
$this->success("模拟切换成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 联动搜索
|
||||
*/
|
||||
public function cxselect()
|
||||
{
|
||||
$type = $this->request->get('type');
|
||||
$group_id = $this->request->get('group_id');
|
||||
$list = null;
|
||||
if ($group_id !== '') {
|
||||
if ($type == 'group') {
|
||||
$groupIds = $this->auth->getChildrenGroupIds(true);
|
||||
$list = \app\admin\model\AuthGroup::where('id', 'in', $groupIds)->field('id as value, name')->select();
|
||||
} else {
|
||||
$adminIds = \app\admin\model\AuthGroupAccess::where('group_id', 'in', $group_id)->column('uid');
|
||||
$list = \app\admin\model\Admin::where('id', 'in', $adminIds)->field('id as value, username AS name')->select();
|
||||
}
|
||||
}
|
||||
$this->success('', null, $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索下拉列表
|
||||
*/
|
||||
public function searchlist()
|
||||
{
|
||||
$result = $this->model->limit(10)->select();
|
||||
$searchlist = [];
|
||||
foreach ($result as $key => $value) {
|
||||
$searchlist[] = ['id' => $value['url'], 'name' => $value['url']];
|
||||
}
|
||||
$data = ['searchlist' => $searchlist];
|
||||
$this->success('', null, $data);
|
||||
}
|
||||
|
||||
public function selectpage()
|
||||
{
|
||||
$this->model = new \app\admin\model\AdminLog;
|
||||
return parent::selectpage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 彩色角标
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark 在JS端控制角标的显示与隐藏,请注意左侧菜单栏角标的数值变化
|
||||
*/
|
||||
class Colorbadge extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 控制器间跳转
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark FastAdmin支持在控制器间跳转,点击后将切换到另外一个TAB中,无需刷新当前页面
|
||||
*/
|
||||
class Controllerjump extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\admin\model\AdminLog;
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 自定义表单示例
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark FastAdmin支持在控制器间跳转,点击后将切换到另外一个TAB中,无需刷新当前页面
|
||||
*/
|
||||
class Customform extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$this->success("提交成功", null, ['data' => json_encode($this->request->post("row/a"), JSON_UNESCAPED_UNICODE)]);
|
||||
}
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
public function get_title_list()
|
||||
{
|
||||
$query = $this->request->get("query");
|
||||
$suggestions = AdminLog::where('title', 'like', '%' . $query . '%')->limit(10)->column("title");
|
||||
$result = [
|
||||
'query' => $query,
|
||||
'suggestions' => $suggestions
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 自定义搜索
|
||||
*
|
||||
* @icon fa fa-search
|
||||
* @remark 自定义列表的搜索
|
||||
*/
|
||||
class Customsearch extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
$ipList = $this->model->whereTime('createtime', '-37 days')->group("ip")->column("ip,ip as aa");
|
||||
$this->view->assign("ipList", $ipList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 多级联动
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark FastAdmin使用了jQuery-cxselect实现多级联动,更多文档请参考https://github.com/karsonzhang/cxSelect
|
||||
*/
|
||||
class Cxselect extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 统计图表示例
|
||||
*
|
||||
* @icon fa fa-charts
|
||||
* @remark 展示在FastAdmin中使用Echarts展示丰富多彩的统计图表
|
||||
*/
|
||||
class Echarts extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
public function detail($ids)
|
||||
{
|
||||
$row = $this->model->get(['id' => $ids]);
|
||||
if (!$row) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
$this->view->assign("row", $row->toArray());
|
||||
return $this->view->fetch();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 多表格示例
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark 当一个页面上存在多个Bootstrap-table时该如何控制按钮和表格
|
||||
*/
|
||||
class Multitable extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
protected $noNeedRight = ['table1', 'table2'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->loadlang('general/attachment');
|
||||
$this->loadlang('general/crontab');
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
public function table1()
|
||||
{
|
||||
$this->model = model('Attachment');
|
||||
//设置过滤方法
|
||||
$this->request->filter(['strip_tags']);
|
||||
if ($this->request->isAjax()) {
|
||||
//如果发送的来源是Selectpage,则转发到Selectpage
|
||||
if ($this->request->request('keyField')) {
|
||||
return $this->selectpage();
|
||||
}
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
$total = $this->model
|
||||
->where($where)
|
||||
->field('id,filename,filesize,imagewidth,imageheight,mimetype')
|
||||
->order($sort, $order)
|
||||
->count();
|
||||
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->field('id,filename,filesize,imagewidth,imageheight,mimetype')
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->select();
|
||||
|
||||
$result = array("total" => $total, "rows" => $list);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch('index');
|
||||
}
|
||||
|
||||
public function table2()
|
||||
{
|
||||
$this->model = model('AdminLog');
|
||||
//设置过滤方法
|
||||
$this->request->filter(['strip_tags']);
|
||||
if ($this->request->isAjax()) {
|
||||
//如果发送的来源是Selectpage,则转发到Selectpage
|
||||
if ($this->request->request('keyField')) {
|
||||
return $this->selectpage();
|
||||
}
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
$total = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->count();
|
||||
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->select();
|
||||
|
||||
$result = array("total" => $total, "rows" => $list);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch('index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 关联模型
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark 当使用到关联模型时需要重载index方法
|
||||
*/
|
||||
class Relationmodel extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->relationSearch = true;
|
||||
$this->searchFields = "admin.username,id";
|
||||
if ($this->request->isAjax()) {
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
$list = $this->model
|
||||
->with("admin")
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->paginate($limit);
|
||||
|
||||
$result = array("total" => $list->total(), "rows" => $list->items());
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 表格联动
|
||||
* 点击左侧日志列表,右侧的表格数据会显示指定管理员的日志列表
|
||||
* @icon fa fa-table
|
||||
*/
|
||||
class Tablelink extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
protected $noNeedRight = ['table1', 'table2'];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
|
||||
public function table1()
|
||||
{
|
||||
$this->model = model('Admin');
|
||||
//设置过滤方法
|
||||
$this->request->filter(['strip_tags']);
|
||||
if ($this->request->isAjax()) {
|
||||
//如果发送的来源是Selectpage,则转发到Selectpage
|
||||
if ($this->request->request('keyField')) {
|
||||
return $this->selectpage();
|
||||
}
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
$total = $this->model
|
||||
->where($where)
|
||||
->field('id,username')
|
||||
->order($sort, $order)
|
||||
->count();
|
||||
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->field('id,username')
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->select();
|
||||
|
||||
$result = array("total" => $total, "rows" => $list);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch('index');
|
||||
}
|
||||
|
||||
public function table2()
|
||||
{
|
||||
$this->model = model('AdminLog');
|
||||
//设置过滤方法
|
||||
$this->request->filter(['strip_tags']);
|
||||
if ($this->request->isAjax()) {
|
||||
//如果发送的来源是Selectpage,则转发到Selectpage
|
||||
if ($this->request->request('keyField')) {
|
||||
return $this->selectpage();
|
||||
}
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
|
||||
$total = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->count();
|
||||
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->select();
|
||||
|
||||
$result = array("total" => $total, "rows" => $list);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch('index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\example;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
|
||||
/**
|
||||
* 表格模板示例
|
||||
*
|
||||
* @icon fa fa-table
|
||||
* @remark 可以通过使用表格模板将表格中的行渲染成一样的展现方式,基于此功能可以任意定制自己想要的展示列表
|
||||
*/
|
||||
class Tabletemplate extends Backend
|
||||
{
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
$this->model = model('AdminLog');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
list($where, $sort, $order, $offset, $limit) = $this->buildparams(null);
|
||||
$total = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->count();
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->order($sort, $order)
|
||||
->limit($offset, $limit)
|
||||
->select();
|
||||
$result = array("total" => $total, "rows" => $list);
|
||||
|
||||
return json($result);
|
||||
}
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*/
|
||||
public function detail($ids)
|
||||
{
|
||||
$row = $this->model->get(['id' => $ids]);
|
||||
if (!$row) {
|
||||
$this->error(__('No Results were found'));
|
||||
}
|
||||
$this->view->assign("row", $row->toArray());
|
||||
return $this->view->fetch();
|
||||
}
|
||||
}
|
||||
@@ -15,4 +15,16 @@ return [
|
||||
'Query Type' => '查询类型',
|
||||
'All Numbers' => '全部号码',
|
||||
'Special Only' => '仅特码',
|
||||
'Trend Chart' => '走势图',
|
||||
'No data available' => '暂无数据',
|
||||
'Hot/Cold Analysis' => '冷热分析',
|
||||
'Color Wave' => '波色分析',
|
||||
'Zodiac' => '生肖分析',
|
||||
'Odd/Even' => '奇偶分析',
|
||||
'Big/Small' => '大小分析',
|
||||
'Sum Chart' => '和值分析',
|
||||
'Consecutive' => '连号分析',
|
||||
'Tail Numbers' => '尾数分析',
|
||||
'Dashboard' => '综合统计面板',
|
||||
'Refresh' => '刷新',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Area extends Model
|
||||
{
|
||||
|
||||
// 开启自动写入时间戳字段
|
||||
protected $autoWriteTimestamp = false;
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = false;
|
||||
protected $updateTime = false;
|
||||
}
|
||||
@@ -30,6 +30,117 @@ class History extends Model
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取走势图数据
|
||||
* @param int $periods 查询最近多少期
|
||||
* @param string $type 查询类型 all=全部号码 special=仅特码
|
||||
* @return array {expects: [], data: [[num1,...], ...], colorMap: []}
|
||||
*/
|
||||
public function getTrendData($periods = 30, $type = 'all')
|
||||
{
|
||||
// 查询波色映射
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
$history = $this
|
||||
->field('expect,num1,num2,num3,num4,num5,num6,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history)) {
|
||||
return ['expects' => [], 'data' => [], 'colorMap' => []];
|
||||
}
|
||||
|
||||
$expects = [];
|
||||
$data = [];
|
||||
foreach ($history as $row) {
|
||||
$expects[] = (string)$row['expect'];
|
||||
if ($type === 'special') {
|
||||
$data[] = ['num7' => (int)$row['num7']];
|
||||
} else {
|
||||
$row_data = [];
|
||||
for ($i = 1; $i <= 7; $i++) {
|
||||
$row_data['num' . $i] = (int)$row['num' . $i];
|
||||
}
|
||||
$data[] = $row_data;
|
||||
}
|
||||
}
|
||||
|
||||
// 反转数组,使最远的数据在左边,最近的数据在右边(从左往右,从远到近)
|
||||
$expects = array_reverse($expects);
|
||||
$data = array_reverse($data);
|
||||
|
||||
return [
|
||||
'expects' => $expects,
|
||||
'data' => $data,
|
||||
'colorMap' => $colorMap
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取冷热号码
|
||||
* @param int $periods 查询最近多少期
|
||||
* @param string $type 查询类型 all=全部号码 special=仅特码
|
||||
* @return array {hot: [], cold: [], all: []}
|
||||
*/
|
||||
public function getHotColdNumbers($periods = 30, $type = 'all')
|
||||
{
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
$animalMap = $num_model->column('animal', 'num');
|
||||
|
||||
$history = $this
|
||||
->field('expect,num1,num2,num3,num4,num5,num6,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history)) {
|
||||
return ['hot' => [], 'cold' => [], 'all' => []];
|
||||
}
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7'];
|
||||
|
||||
// 统计每个号码的出现次数
|
||||
$count = array_fill(1, 49, 0);
|
||||
$totalAppearances = 0;
|
||||
foreach ($history as $row) {
|
||||
foreach ($fields as $field) {
|
||||
$num = (int)$row[$field];
|
||||
if ($num >= 1 && $num <= 49) {
|
||||
$count[$num]++;
|
||||
$totalAppearances++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$all = [];
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$percent = $totalAppearances > 0 ? round($count[$num] / $totalAppearances * 100, 1) : 0;
|
||||
$all[] = [
|
||||
'num' => $num,
|
||||
'count' => $count[$num],
|
||||
'percent' => $percent,
|
||||
'color' => $colorMap[$num] ?? '—',
|
||||
'animal' => $animalMap[$num] ?? '—'
|
||||
];
|
||||
}
|
||||
|
||||
// 按出现次数降序排序
|
||||
$sorted = $all;
|
||||
usort($sorted, function ($a, $b) {
|
||||
return $b['count'] - $a['count'];
|
||||
});
|
||||
|
||||
// 热号: top 10, 冷号: bottom 10
|
||||
$hot = array_slice($sorted, 0, 10);
|
||||
$cold = array_slice($sorted, -10);
|
||||
$cold = array_reverse($cold);
|
||||
|
||||
return ['hot' => $hot, 'cold' => $cold, 'all' => $all];
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算遗漏号码
|
||||
* @param int $periods 查询最近多少期
|
||||
@@ -139,5 +250,752 @@ class History extends Model
|
||||
return count($allHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 波色分析
|
||||
*/
|
||||
public function getColorWaveAnalysis($periods = 30, $type = 'all')
|
||||
{
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['red' => 0, 'blue' => 0, 'green' => 0, 'red_pct' => 0, 'blue_pct' => 0, 'green_pct' => 0, 'details' => []];
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7'];
|
||||
$colors = ['红' => 0, '蓝' => 0, '绿' => 0];
|
||||
$total = 0;
|
||||
foreach ($history as $row) {
|
||||
foreach ($fields as $f) {
|
||||
$num = (int)$row[$f];
|
||||
$color = $colorMap[$num] ?? '';
|
||||
if (strpos($color, '红') !== false) { $colors['红']++; $total++; }
|
||||
elseif (strpos($color, '蓝') !== false) { $colors['蓝']++; $total++; }
|
||||
elseif (strpos($color, '绿') !== false) { $colors['绿']++; $total++; }
|
||||
}
|
||||
}
|
||||
return [
|
||||
'red' => $colors['红'], 'blue' => $colors['蓝'], 'green' => $colors['绿'],
|
||||
'red_pct' => $total ? round($colors['红']/$total*100,1) : 0,
|
||||
'blue_pct' => $total ? round($colors['蓝']/$total*100,1) : 0,
|
||||
'green_pct' => $total ? round($colors['绿']/$total*100,1) : 0,
|
||||
'total' => $total
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 生肖分析
|
||||
*/
|
||||
public function getZodiacAnalysis($periods = 30, $type = 'all')
|
||||
{
|
||||
$num_model = new Num();
|
||||
$animalMap = $num_model->column('animal', 'num');
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['list' => []];
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7'];
|
||||
$counts = [];
|
||||
foreach ($history as $row) {
|
||||
foreach ($fields as $f) {
|
||||
$num = (int)$row[$f];
|
||||
$animal = $animalMap[$num] ?? '未知';
|
||||
if (!isset($counts[$animal])) $counts[$animal] = ['animal' => $animal, 'count' => 0, 'color' => $colorMap[$num] ?? '—'];
|
||||
$counts[$animal]['count']++;
|
||||
}
|
||||
}
|
||||
$list = array_values($counts);
|
||||
usort($list, function ($a, $b) { return $b['count'] - $a['count']; });
|
||||
$total = array_sum(array_column($list, 'count'));
|
||||
foreach ($list as &$item) { $item['percent'] = $total ? round($item['count']/$total*100, 1) : 0; }
|
||||
return ['list' => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* 奇偶分析
|
||||
*/
|
||||
public function getOddEvenAnalysis($periods = 30, $type = 'all')
|
||||
{
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['odd' => 0, 'even' => 0, 'odd_pct' => 0, 'even_pct' => 0, 'per_period' => []];
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7'];
|
||||
$odd = 0; $even = 0; $perPeriod = [];
|
||||
foreach ($history as $row) {
|
||||
$p_odd = 0; $p_even = 0;
|
||||
foreach ($fields as $f) {
|
||||
$num = (int)$row[$f];
|
||||
if ($num % 2 == 0) { $even++; $p_even++; } else { $odd++; $p_odd++; }
|
||||
}
|
||||
$perPeriod[] = ['expect' => $row['expect'], 'odd' => $p_odd, 'even' => $p_even];
|
||||
}
|
||||
$total = $odd + $even;
|
||||
return [
|
||||
'odd' => $odd, 'even' => $even,
|
||||
'odd_pct' => $total ? round($odd/$total*100, 1) : 0,
|
||||
'even_pct' => $total ? round($even/$total*100, 1) : 0,
|
||||
'per_period' => $perPeriod
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 大小分析(1-24为小,25-49为大)
|
||||
*/
|
||||
public function getBigSmallAnalysis($periods = 30, $type = 'all')
|
||||
{
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['big' => 0, 'small' => 0, 'big_pct' => 0, 'small_pct' => 0, 'per_period' => []];
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7'];
|
||||
$big = 0; $small = 0; $perPeriod = [];
|
||||
foreach ($history as $row) {
|
||||
$p_big = 0; $p_small = 0;
|
||||
foreach ($fields as $f) {
|
||||
$num = (int)$row[$f];
|
||||
if ($num >= 25) { $big++; $p_big++; } else { $small++; $p_small++; }
|
||||
}
|
||||
$perPeriod[] = ['expect' => $row['expect'], 'big' => $p_big, 'small' => $p_small];
|
||||
}
|
||||
$total = $big + $small;
|
||||
return [
|
||||
'big' => $big, 'small' => $small,
|
||||
'big_pct' => $total ? round($big/$total*100, 1) : 0,
|
||||
'small_pct' => $total ? round($small/$total*100, 1) : 0,
|
||||
'per_period' => $perPeriod
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 特码走势
|
||||
*/
|
||||
public function getSpecialTrend($periods = 30)
|
||||
{
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
// 先取最近 $periods 条数据
|
||||
$history = $this->field('expect,num7,openTime')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['expects' => [], 'specials' => [], 'colors' => []];
|
||||
|
||||
// 反转,使数据从左到右为从远到近
|
||||
$history = array_reverse($history);
|
||||
$expects = []; $specials = []; $colors = [];
|
||||
foreach ($history as $row) {
|
||||
$expects[] = (string)$row['expect'];
|
||||
$num = (int)$row['num7'];
|
||||
$specials[] = $num;
|
||||
$colors[] = $colorMap[$num] ?? '';
|
||||
}
|
||||
return ['expects' => $expects, 'specials' => $specials, 'colors' => $colors];
|
||||
}
|
||||
|
||||
/**
|
||||
* 连号分析
|
||||
*/
|
||||
public function getConsecutiveNumbers($periods = 30)
|
||||
{
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['pairs' => [], 'triples' => []];
|
||||
|
||||
$pairCount = []; $tripleCount = [];
|
||||
foreach ($history as $row) {
|
||||
$nums = [];
|
||||
for ($i = 1; $i <= 7; $i++) $nums[] = (int)$row['num' . $i];
|
||||
sort($nums);
|
||||
// 找连号对
|
||||
for ($i = 0; $i < count($nums) - 1; $i++) {
|
||||
if ($nums[$i + 1] - $nums[$i] === 1) {
|
||||
$pair = $nums[$i] . '-' . $nums[$i + 1];
|
||||
$pairCount[$pair] = isset($pairCount[$pair]) ? $pairCount[$pair] + 1 : 1;
|
||||
}
|
||||
}
|
||||
// 找连号三连
|
||||
for ($i = 0; $i < count($nums) - 2; $i++) {
|
||||
if ($nums[$i + 1] - $nums[$i] === 1 && $nums[$i + 2] - $nums[$i + 1] === 1) {
|
||||
$triple = $nums[$i] . '-' . $nums[$i + 1] . '-' . $nums[$i + 2];
|
||||
$tripleCount[$triple] = isset($tripleCount[$triple]) ? $tripleCount[$triple] + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
arsort($pairCount); arsort($tripleCount);
|
||||
return ['pairs' => $pairCount, 'triples' => $tripleCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* 尾数分析
|
||||
*/
|
||||
public function getTailNumbers($periods = 30, $type = 'all')
|
||||
{
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
$animalMap = $num_model->column('animal', 'num');
|
||||
|
||||
$history = $this->field('expect,num1,num2,num3,num4,num5,num6,num7')->order('openTime', 'desc')->limit($periods)->select();
|
||||
if (empty($history)) return ['tails' => [], 'all' => []];
|
||||
|
||||
$fields = ($type === 'special') ? ['num7'] : ['num1','num2','num3','num4','num5','num6','num7'];
|
||||
$tailCount = array_fill(0, 10, 0);
|
||||
$all = [];
|
||||
foreach ($history as $row) {
|
||||
foreach ($fields as $f) {
|
||||
$num = (int)$row[$f];
|
||||
$tail = $num % 10;
|
||||
$tailCount[$tail]++;
|
||||
}
|
||||
}
|
||||
$total = array_sum($tailCount);
|
||||
for ($t = 0; $t <= 9; $t++) {
|
||||
$all[] = ['tail' => $t, 'count' => $tailCount[$t], 'percent' => $total ? round($tailCount[$t]/$total*100, 1) : 0];
|
||||
}
|
||||
usort($all, function ($a, $b) { return $b['count'] - $a['count']; });
|
||||
return ['all' => $all];
|
||||
}
|
||||
|
||||
/**
|
||||
* 综合统计面板
|
||||
*/
|
||||
public function getDashboardData($periods = 30, $type = 'all')
|
||||
{
|
||||
return [
|
||||
'hotcold' => $this->getHotColdNumbers($periods, 'special'),
|
||||
'colorwave' => $this->getColorWaveAnalysis($periods, 'special'),
|
||||
'zodiac' => $this->getZodiacAnalysis($periods, 'special'),
|
||||
'oddeven' => $this->getOddEvenAnalysis($periods, 'special'),
|
||||
'bigsmall' => $this->getBigSmallAnalysis($periods, 'special'),
|
||||
'special' => $this->getSpecialTrend($periods),
|
||||
'tailnumbers' => $this->getTailNumbers($periods, 'special'),
|
||||
'heatmap' => $this->getSpecialHeatmap($periods),
|
||||
'zonetransition' => $this->getZoneTransition($periods),
|
||||
'colorwavetransition' => $this->getColorWaveTransition($periods),
|
||||
'zonetocolortransition' => $this->getZoneToZoneColor($periods),
|
||||
'zodiactransition' => $this->getZodiacTransition($periods)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询所有期号特码相对于前N期的冷热状态
|
||||
* @param int $lookback 向前推算期数
|
||||
* @param int $limit 查询总期数(从最新往前取)
|
||||
* @return array [{expect, specialNum, count, avgCount, status, rank, totalPeriods}, ...]
|
||||
*/
|
||||
public function getSpecialHotColdList($lookback = 30, $limit = 100)
|
||||
{
|
||||
// 查询最近 $limit 期数据,按时间倒序(最新在前)
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($limit)
|
||||
->select();
|
||||
|
||||
if (empty($history)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 查询更多历史数据用于统计
|
||||
$allHistory = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($limit + 200)
|
||||
->select();
|
||||
|
||||
// 按openTime排序(确保顺序)
|
||||
$historySorted = [];
|
||||
foreach ($history as $row) {
|
||||
$historySorted[] = $row;
|
||||
}
|
||||
$allHistorySorted = [];
|
||||
foreach ($allHistory as $row) {
|
||||
$allHistorySorted[] = $row;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
// 对每一期,计算它前面lookback期的冷热状态
|
||||
for ($i = 0; $i < count($historySorted); $i++) {
|
||||
$row = $historySorted[$i];
|
||||
$specialNum = (int)$row['num7'];
|
||||
|
||||
// 找到该期在全量数据中的位置
|
||||
$targetTime = $row['openTime'];
|
||||
$count = array_fill(1, 49, 0);
|
||||
$periodCount = 0;
|
||||
|
||||
// 往前统计lookback期(跳过该期本身)
|
||||
for ($j = 0; $j < count($allHistorySorted); $j++) {
|
||||
$checkRow = $allHistorySorted[$j];
|
||||
$checkTime = $checkRow['openTime'];
|
||||
|
||||
// 只统计比该期更早的数据
|
||||
if ($checkTime >= $targetTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($periodCount >= $lookback) {
|
||||
break;
|
||||
}
|
||||
|
||||
$num = (int)$checkRow['num7'];
|
||||
if ($num >= 1 && $num <= 49) {
|
||||
$count[$num]++;
|
||||
}
|
||||
$periodCount++;
|
||||
}
|
||||
|
||||
if ($periodCount === 0) {
|
||||
$result[] = [
|
||||
'expect' => (string)$row['expect'],
|
||||
'specialNum' => $specialNum,
|
||||
'count' => 0,
|
||||
'avgCount' => 0,
|
||||
'status' => 'unknown',
|
||||
'rank' => 0
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$targetCount = $count[$specialNum];
|
||||
$avgCount = $periodCount / 49;
|
||||
|
||||
$status = 'normal';
|
||||
if ($avgCount > 0) {
|
||||
if ($targetCount > $avgCount * 1.5) {
|
||||
$status = 'hot';
|
||||
} elseif ($targetCount < $avgCount * 0.5) {
|
||||
$status = 'cold';
|
||||
}
|
||||
}
|
||||
|
||||
// 计算排名
|
||||
$sorted = [];
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$sorted[] = ['num' => $num, 'count' => $count[$num]];
|
||||
}
|
||||
usort($sorted, function ($a, $b) {
|
||||
return $b['count'] - $a['count'];
|
||||
});
|
||||
|
||||
$rank = 0;
|
||||
foreach ($sorted as $idx => $item) {
|
||||
if ($item['num'] === $specialNum) {
|
||||
$rank = $idx + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'expect' => (string)$row['expect'],
|
||||
'specialNum' => $specialNum,
|
||||
'count' => $targetCount,
|
||||
'avgCount' => round($avgCount, 2),
|
||||
'status' => $status,
|
||||
'rank' => $rank
|
||||
];
|
||||
}
|
||||
|
||||
// 基于最新一期(result[0])的lookback窗口,计算当前所有49个号码的冷热状态
|
||||
$current = $this->_computeCurrentHotCold($allHistorySorted, $historySorted[0], $lookback);
|
||||
|
||||
return [
|
||||
'list' => $result,
|
||||
'current' => $current
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于指定期的lookback窗口,计算所有49个号码的冷热状态
|
||||
* @param array $allHistorySorted 全量历史数据
|
||||
* @param mixed $targetRow 目标期数据
|
||||
* @param int $lookback 向前期数
|
||||
* @return array {hot: [{num, count}], cold: [{num, count}], warm: [{num, count}]}
|
||||
*/
|
||||
private function _computeCurrentHotCold($allHistorySorted, $targetRow, $lookback)
|
||||
{
|
||||
$targetTime = $targetRow['openTime'];
|
||||
$count = array_fill(1, 49, 0);
|
||||
$periodCount = 0;
|
||||
|
||||
for ($j = 0; $j < count($allHistorySorted); $j++) {
|
||||
$checkRow = $allHistorySorted[$j];
|
||||
$checkTime = $checkRow['openTime'];
|
||||
|
||||
if ($checkTime >= $targetTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($periodCount >= $lookback) {
|
||||
break;
|
||||
}
|
||||
|
||||
$num = (int)$checkRow['num7'];
|
||||
if ($num >= 1 && $num <= 49) {
|
||||
$count[$num]++;
|
||||
}
|
||||
$periodCount++;
|
||||
}
|
||||
|
||||
$avgCount = $periodCount > 0 ? $periodCount / 49 : 0;
|
||||
$hot = [];
|
||||
$cold = [];
|
||||
$warm = [];
|
||||
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$status = 'warm';
|
||||
if ($avgCount > 0) {
|
||||
if ($count[$num] > $avgCount * 1.5) {
|
||||
$status = 'hot';
|
||||
} elseif ($count[$num] < $avgCount * 0.5) {
|
||||
$status = 'cold';
|
||||
}
|
||||
}
|
||||
|
||||
$item = ['num' => $num, 'count' => $count[$num]];
|
||||
if ($status === 'hot') {
|
||||
$hot[] = $item;
|
||||
} elseif ($status === 'cold') {
|
||||
$cold[] = $item;
|
||||
} else {
|
||||
$warm[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
// 热号按次数降序,冷号按次数升序
|
||||
usort($hot, function ($a, $b) { return $b['count'] - $a['count']; });
|
||||
usort($cold, function ($a, $b) { return $a['count'] - $b['count']; });
|
||||
usort($warm, function ($a, $b) { return $b['count'] - $a['count']; });
|
||||
|
||||
return ['hot' => $hot, 'cold' => $cold, 'warm' => $warm];
|
||||
}
|
||||
|
||||
/**
|
||||
* 区域转移概率统计
|
||||
* 将1-49分为5个区域,统计特码从一个区域转移到另一个区域的概率
|
||||
* 区域1: 1-10, 区域2: 11-20, 区域3: 21-30, 区域4: 31-40, 区域5: 41-49
|
||||
* @param int $periods 查询最近多少期
|
||||
* @return array {zones: [], matrix: [], probabilities: [], total_transitions: int}
|
||||
*/
|
||||
public function getZoneTransition($periods = 100)
|
||||
{
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history) || count($history) < 2) {
|
||||
return ['zones' => ['1-10','11-20','21-30','31-40','41-49'], 'matrix' => [], 'probabilities' => [], 'total_transitions' => 0];
|
||||
}
|
||||
|
||||
// 反转为升序,从旧到新
|
||||
$history = array_reverse($history);
|
||||
|
||||
$zoneLabels = ['1-10', '11-20', '21-30', '31-40', '41-49'];
|
||||
$matrix = array_fill(0, 5, array_fill(0, 5, 0));
|
||||
$rowTotals = array_fill(0, 5, 0);
|
||||
|
||||
$getZone = function ($num) {
|
||||
if ($num <= 10) return 0;
|
||||
if ($num <= 20) return 1;
|
||||
if ($num <= 30) return 2;
|
||||
if ($num <= 40) return 3;
|
||||
return 4;
|
||||
};
|
||||
|
||||
$totalTransitions = 0;
|
||||
for ($i = 0; $i < count($history) - 1; $i++) {
|
||||
$currentNum = (int)$history[$i]['num7'];
|
||||
$nextNum = (int)$history[$i + 1]['num7'];
|
||||
if ($currentNum < 1 || $currentNum > 49 || $nextNum < 1 || $nextNum > 49) continue;
|
||||
|
||||
$from = $getZone($currentNum);
|
||||
$to = $getZone($nextNum);
|
||||
$matrix[$from][$to]++;
|
||||
$rowTotals[$from]++;
|
||||
$totalTransitions++;
|
||||
}
|
||||
|
||||
// 计算概率矩阵
|
||||
$probabilities = array_fill(0, 5, array_fill(0, 5, 0));
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
if ($rowTotals[$i] > 0) {
|
||||
for ($j = 0; $j < 5; $j++) {
|
||||
$probabilities[$i][$j] = round($matrix[$i][$j] / $rowTotals[$i] * 100, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'zones' => $zoneLabels,
|
||||
'matrix' => $matrix,
|
||||
'probabilities' => $probabilities,
|
||||
'row_totals' => $rowTotals,
|
||||
'total_transitions' => $totalTransitions
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 波色转移概率统计
|
||||
* 统计特码从一种波色转移到另一种波色的概率(红/蓝/绿)
|
||||
* @param int $periods 查询最近多少期
|
||||
* @return array {colors: [], matrix: [], probabilities: [], row_totals: [], total_transitions: int}
|
||||
*/
|
||||
public function getColorWaveTransition($periods = 100)
|
||||
{
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history) || count($history) < 2) {
|
||||
return ['colors' => ['红波','蓝波','绿波'], 'matrix' => [], 'probabilities' => [], 'row_totals' => [], 'total_transitions' => 0];
|
||||
}
|
||||
|
||||
$history = array_reverse($history);
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
$colorLabels = ['红波', '蓝波', '绿波'];
|
||||
$matrix = array_fill(0, 3, array_fill(0, 3, 0));
|
||||
$rowTotals = array_fill(0, 3, 0);
|
||||
|
||||
$getColorIdx = function ($num) use ($colorMap) {
|
||||
$color = $colorMap[$num] ?? '';
|
||||
if (strpos($color, '红') !== false) return 0;
|
||||
if (strpos($color, '蓝') !== false) return 1;
|
||||
if (strpos($color, '绿') !== false) return 2;
|
||||
return -1;
|
||||
};
|
||||
|
||||
$totalTransitions = 0;
|
||||
for ($i = 0; $i < count($history) - 1; $i++) {
|
||||
$currentNum = (int)$history[$i]['num7'];
|
||||
$nextNum = (int)$history[$i + 1]['num7'];
|
||||
$from = $getColorIdx($currentNum);
|
||||
$to = $getColorIdx($nextNum);
|
||||
if ($from < 0 || $to < 0) continue;
|
||||
|
||||
$matrix[$from][$to]++;
|
||||
$rowTotals[$from]++;
|
||||
$totalTransitions++;
|
||||
}
|
||||
|
||||
$probabilities = array_fill(0, 3, array_fill(0, 3, 0));
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
if ($rowTotals[$i] > 0) {
|
||||
for ($j = 0; $j < 3; $j++) {
|
||||
$probabilities[$i][$j] = round($matrix[$i][$j] / $rowTotals[$i] * 100, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'colors' => $colorLabels,
|
||||
'matrix' => $matrix,
|
||||
'probabilities' => $probabilities,
|
||||
'row_totals' => $rowTotals,
|
||||
'total_transitions' => $totalTransitions
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 生肖转移概率统计
|
||||
* 统计特码从一种生肖转移到另一种生肖的概率(12生肖)
|
||||
* @param int $periods 查询最近多少期
|
||||
* @return array {animals: [], matrix: [], probabilities: [], row_totals: [], total_transitions: int}
|
||||
*/
|
||||
public function getZodiacTransition($periods = 100)
|
||||
{
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history) || count($history) < 2) {
|
||||
return ['animals' => ['鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪'], 'matrix' => [], 'probabilities' => [], 'row_totals' => [], 'total_transitions' => 0];
|
||||
}
|
||||
|
||||
$history = array_reverse($history);
|
||||
$num_model = new Num();
|
||||
$animalMap = $num_model->column('animal', 'num');
|
||||
|
||||
$animalLabels = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];
|
||||
$numAnimals = 12;
|
||||
$matrix = array_fill(0, $numAnimals, array_fill(0, $numAnimals, 0));
|
||||
$rowTotals = array_fill(0, $numAnimals, 0);
|
||||
|
||||
$getAnimalIdx = function ($num) use ($animalMap, $animalLabels) {
|
||||
$animal = $animalMap[$num] ?? '';
|
||||
$idx = array_search($animal, $animalLabels);
|
||||
return $idx === false ? -1 : $idx;
|
||||
};
|
||||
|
||||
$totalTransitions = 0;
|
||||
for ($i = 0; $i < count($history) - 1; $i++) {
|
||||
$currentNum = (int)$history[$i]['num7'];
|
||||
$nextNum = (int)$history[$i + 1]['num7'];
|
||||
$from = $getAnimalIdx($currentNum);
|
||||
$to = $getAnimalIdx($nextNum);
|
||||
if ($from < 0 || $to < 0) continue;
|
||||
|
||||
$matrix[$from][$to]++;
|
||||
$rowTotals[$from]++;
|
||||
$totalTransitions++;
|
||||
}
|
||||
|
||||
$probabilities = array_fill(0, $numAnimals, array_fill(0, $numAnimals, 0));
|
||||
for ($i = 0; $i < $numAnimals; $i++) {
|
||||
if ($rowTotals[$i] > 0) {
|
||||
for ($j = 0; $j < $numAnimals; $j++) {
|
||||
$probabilities[$i][$j] = round($matrix[$i][$j] / $rowTotals[$i] * 100, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'animals' => $animalLabels,
|
||||
'matrix' => $matrix,
|
||||
'probabilities' => $probabilities,
|
||||
'row_totals' => $rowTotals,
|
||||
'total_transitions' => $totalTransitions
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 区域→区域转移矩阵,单元格内显示波色概率
|
||||
* 统计上一期特码所在区域后,下一期特码在各区域的分布,以及每个区域内的波色占比
|
||||
* @param int $periods 查询最近多少期
|
||||
* @return array {zones: [], matrix: [[zone_count]], color_probs: [[{red, blue, green}]]}
|
||||
*/
|
||||
public function getZoneToZoneColor($periods = 100)
|
||||
{
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history) || count($history) < 2) {
|
||||
return ['zones' => ['1-10','11-20','21-30','31-40','41-49'], 'matrix' => [], 'color_probs' => []];
|
||||
}
|
||||
|
||||
$history = array_reverse($history);
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
$zoneLabels = ['1-10', '11-20', '21-30', '31-40', '41-49'];
|
||||
$matrix = array_fill(0, 5, array_fill(0, 5, 0));
|
||||
$colorCounts = [];
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
for ($j = 0; $j < 5; $j++) {
|
||||
$colorCounts[$i][$j] = ['red' => 0, 'blue' => 0, 'green' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
$getZone = function ($num) {
|
||||
if ($num <= 10) return 0;
|
||||
if ($num <= 20) return 1;
|
||||
if ($num <= 30) return 2;
|
||||
if ($num <= 40) return 3;
|
||||
return 4;
|
||||
};
|
||||
|
||||
for ($i = 0; $i < count($history) - 1; $i++) {
|
||||
$currentNum = (int)$history[$i]['num7'];
|
||||
$nextNum = (int)$history[$i + 1]['num7'];
|
||||
$from = $getZone($currentNum);
|
||||
$to = $getZone($nextNum);
|
||||
$color = $colorMap[$nextNum] ?? '';
|
||||
|
||||
$matrix[$from][$to]++;
|
||||
if (strpos($color, '红') !== false) $colorCounts[$from][$to]['red']++;
|
||||
elseif (strpos($color, '蓝') !== false) $colorCounts[$from][$to]['blue']++;
|
||||
elseif (strpos($color, '绿') !== false) $colorCounts[$from][$to]['green']++;
|
||||
}
|
||||
|
||||
// 计算每个单元格波色概率
|
||||
$colorProbs = array_fill(0, 5, array_fill(0, 5, ['red' => 0, 'blue' => 0, 'green' => 0]));
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
for ($j = 0; $j < 5; $j++) {
|
||||
$total = $matrix[$i][$j];
|
||||
if ($total > 0) {
|
||||
$colorProbs[$i][$j] = [
|
||||
'red' => round($colorCounts[$i][$j]['red'] / $total * 100, 1),
|
||||
'blue' => round($colorCounts[$i][$j]['blue'] / $total * 100, 1),
|
||||
'green' => round($colorCounts[$i][$j]['green'] / $total * 100, 1),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'zones' => $zoneLabels,
|
||||
'matrix' => $matrix,
|
||||
'color_probs' => $colorProbs
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 特码热力图数据
|
||||
* @param int $periods 查询最近多少期
|
||||
* @return array {expects: [], heatmap: [[x, y, value]], colors: [号码对应颜色]}
|
||||
*/
|
||||
public function getSpecialHeatmap($periods = 30)
|
||||
{
|
||||
$num_model = new Num();
|
||||
$colorMap = $num_model->column('color', 'num');
|
||||
|
||||
// 查询最近 N 期特码数据
|
||||
$history = $this
|
||||
->field('expect,num7,openTime')
|
||||
->order('openTime', 'desc')
|
||||
->limit($periods)
|
||||
->select();
|
||||
|
||||
if (empty($history)) {
|
||||
return ['expects' => [], 'heatmap' => [], 'colors' => []];
|
||||
}
|
||||
|
||||
// 反转数组,使数据从左到右为从远到近
|
||||
$history = array_reverse($history);
|
||||
$expects = [];
|
||||
$heatmap = [];
|
||||
|
||||
// 构建热力图数据:[x_index, y_index, value]
|
||||
// x_index = 期号索引(0到periods-1)
|
||||
// y_index = 号码-1(0到48,号码1-49)
|
||||
// value = 1(出现)或 0(未出现)
|
||||
foreach ($history as $idx => $row) {
|
||||
$expects[] = (string)$row['expect'];
|
||||
$specialNum = (int)$row['num7'];
|
||||
// 标记该期特码号码出现
|
||||
if ($specialNum >= 1 && $specialNum <= 49) {
|
||||
$heatmap[] = [$idx, $specialNum - 1, 1];
|
||||
}
|
||||
}
|
||||
|
||||
// 补充号码颜色映射(索引0对应号码1)
|
||||
$colors = [];
|
||||
for ($num = 1; $num <= 49; $num++) {
|
||||
$color = $colorMap[$num] ?? '';
|
||||
if (strpos($color, '红') !== false) {
|
||||
$colors[] = '#e74c3c';
|
||||
} elseif (strpos($color, '蓝') !== false) {
|
||||
$colors[] = '#3498db';
|
||||
} elseif (strpos($color, '绿') !== false) {
|
||||
$colors[] = '#2ecc71';
|
||||
} else {
|
||||
$colors[] = '#95a5a6';
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'expects' => $expects,
|
||||
'heatmap' => $heatmap,
|
||||
'colors' => $colors,
|
||||
'nums' => range(1, 49) // 号码列表
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,403 +1,32 @@
|
||||
<style type="text/css">
|
||||
.sm-st {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sm-st-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: inline-block;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
font-size: 30px;
|
||||
background: #eee;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sm-st-info {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.sm-st-info span {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.orange {
|
||||
background: #fa8564 !important;
|
||||
}
|
||||
|
||||
.tar {
|
||||
background: #45cf95 !important;
|
||||
}
|
||||
|
||||
.sm-st .green {
|
||||
background: #86ba41 !important;
|
||||
}
|
||||
|
||||
.pink {
|
||||
background: #AC75F0 !important;
|
||||
}
|
||||
|
||||
.yellow-b {
|
||||
background: #fdd752 !important;
|
||||
}
|
||||
|
||||
.stat-elem {
|
||||
|
||||
background-color: #fff;
|
||||
padding: 18px;
|
||||
border-radius: 40px;
|
||||
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
margin-top: -5px;
|
||||
padding: 8px;
|
||||
-webkit-box-shadow: 0 1px 0px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.05);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.st-red {
|
||||
background-color: #F05050;
|
||||
}
|
||||
|
||||
.st-green {
|
||||
background-color: #27C24C;
|
||||
}
|
||||
|
||||
.st-violet {
|
||||
background-color: #7266ba;
|
||||
}
|
||||
|
||||
.st-blue {
|
||||
background-color: #23b7e5;
|
||||
}
|
||||
|
||||
.stats .stat-icon {
|
||||
color: #28bb9c;
|
||||
display: inline-block;
|
||||
font-size: 26px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 50px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.stat {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.stat .value {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat .name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.stat.lg .value {
|
||||
font-size: 26px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.stat-col {
|
||||
margin:0 0 10px 0;
|
||||
}
|
||||
.stat.lg .name {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.stat-col .progress {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.stat-col .progress-bar {
|
||||
line-height: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 30px 0;
|
||||
}
|
||||
|
||||
|
||||
#statistics .panel {
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
#statistics .panel h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
.dash-section { margin-bottom: 20px; }
|
||||
.dash-section h4 { border-bottom: 1px solid #eee; padding-bottom: 8px; margin-bottom: 12px; font-size: 15px; color: #333; }
|
||||
.dash-card { background: #f9f9f9; border-radius: 6px; padding: 12px; text-align: center; }
|
||||
.dash-card .big-num { font-size: 28px; font-weight: bold; color: #333; }
|
||||
.dash-card .label-text { font-size: 12px; color: #999; margin-top: 4px; }
|
||||
.num-ball-sm { display: inline-block; width: 32px; height: 32px; line-height: 32px; text-align: center; border-radius: 50%; color: #fff; font-weight: bold; font-size: 13px; }
|
||||
.mini-card { text-align: center; background: #f5f5f5; padding: 8px 12px; border-radius: 5px; display: inline-block; margin: 3px; min-width: 65px; }
|
||||
.mini-card .name { font-size: 14px; font-weight: bold; color: #333; }
|
||||
.mini-card .val { font-size: 11px; color: #666; }
|
||||
#dash-chart { width: 100%; height: 280px; }
|
||||
</style>
|
||||
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-heading">
|
||||
{:build_heading(null, false)}
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#one" data-toggle="tab">{:__('Dashboard')}</a></li>
|
||||
<li><a href="#two" data-toggle="tab">{:__('Custom')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-xs-6">
|
||||
<div class="sm-st clearfix">
|
||||
<span class="sm-st-icon st-red"><i class="fa fa-users"></i></span>
|
||||
<div class="sm-st-info">
|
||||
<span>{$totaluser|htmlentities}</span>
|
||||
{:__('Total user')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-6">
|
||||
<div class="sm-st clearfix">
|
||||
<span class="sm-st-icon st-violet"><i class="fa fa-magic"></i></span>
|
||||
<div class="sm-st-info">
|
||||
<span>{$totaladdon|htmlentities}</span>
|
||||
{:__('Total addon')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-6">
|
||||
<div class="sm-st clearfix">
|
||||
<span class="sm-st-icon st-blue"><i class="fa fa-leaf"></i></span>
|
||||
<div class="sm-st-info">
|
||||
<span>{$attachmentnums|htmlentities}</span>
|
||||
{:__('Total attachment')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3 col-xs-6">
|
||||
<div class="sm-st clearfix">
|
||||
<span class="sm-st-icon st-green"><i class="fa fa-user"></i></span>
|
||||
<div class="sm-st-info">
|
||||
<span>{$totaladmin|htmlentities}</span>
|
||||
{:__('Total admin')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div id="echart" class="btn-refresh" style="height:300px;width:100%;"></div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card sameheight-item stats">
|
||||
<div class="card-block">
|
||||
<div class="row row-sm stats-container">
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-rocket"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$todayusersignup|htmlentities}</div>
|
||||
<div class="name"> {:__('Today user signup')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-vcard"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$todayuserlogin|htmlentities}</div>
|
||||
<div class="name"> {:__('Today user login')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-calendar"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$threednu|htmlentities}</div>
|
||||
<div class="name"> {:__('Three dnu')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-calendar-plus-o"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$sevendnu|htmlentities}</div>
|
||||
<div class="name"> {:__('Seven dnu')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-user-circle"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$sevendau|htmlentities}</div>
|
||||
<div class="name"> {:__('Seven dau')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 stat-col">
|
||||
<div class="stat-icon"><i class="fa fa-user-circle-o"></i></div>
|
||||
<div class="stat">
|
||||
<div class="value"> {$thirtydau|htmlentities}</div>
|
||||
<div class="name"> {:__('Thirty dau')}</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success" style="width: 20%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top:15px;" id="statistics">
|
||||
|
||||
<div class="col-lg-12">
|
||||
</div>
|
||||
<div class="col-xs-6 col-md-3">
|
||||
<div class="panel bg-blue-gradient no-border">
|
||||
<div class="panel-body">
|
||||
<div class="panel-title">
|
||||
<span class="label label-primary pull-right">{:__('Real time')}</span>
|
||||
<h5>{:__('Working addon count')}</h5>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1 class="no-margins">{$totalworkingaddon|htmlentities}</h1>
|
||||
<div class="font-bold"><i class="fa fa-magic"></i>
|
||||
<small>{:__('Working addon count tips')}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 col-md-3">
|
||||
<div class="panel bg-teal-gradient no-border">
|
||||
<div class="panel-body">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary pull-right">{:__('Real time')}</span>
|
||||
<h5>{:__('Database count')}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$dbtablenums|htmlentities}</h1>
|
||||
<div class="font-bold"><i class="fa fa-database"></i>
|
||||
<small>{:__('Database table nums')}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$dbsize|format_bytes=###,'',0}</h1>
|
||||
<div class="font-bold"><i class="fa fa-filter"></i>
|
||||
<small>{:__('Database size')}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-md-3">
|
||||
<div class="panel bg-purple-gradient no-border">
|
||||
<div class="panel-body">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary pull-right">{:__('Real time')}</span>
|
||||
<h5>{:__('Attachment count')}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$attachmentnums|htmlentities}</h1>
|
||||
<div class="font-bold"><i class="fa fa-files-o"></i>
|
||||
<small>{:__('Attachment nums')}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$attachmentsize|format_bytes=###,'',0}</h1>
|
||||
<div class="font-bold"><i class="fa fa-filter"></i>
|
||||
<small>{:__('Attachment size')}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6 col-md-3">
|
||||
<div class="panel bg-green-gradient no-border">
|
||||
<div class="panel-body">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary pull-right">{:__('Real time')}</span>
|
||||
<h5>{:__('Picture count')}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$picturenums|htmlentities}</h1>
|
||||
<div class="font-bold"><i class="fa fa-picture-o"></i>
|
||||
<small>{:__('Picture nums')}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h1 class="no-margins">{$picturesize|format_bytes=###,'',0}</h1>
|
||||
<div class="font-bold"><i class="fa fa-filter"></i>
|
||||
<small>{:__('Picture size')}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="two">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{:__('Custom zone')}
|
||||
</div>
|
||||
</div>
|
||||
<div style="float:right;">
|
||||
<div class="form-inline">
|
||||
<label>{:__('Query Periods')}:</label>
|
||||
<input type="number" id="dash-periods" class="form-control input-sm" value="{$periods|htmlentities}" min="10" max="100" style="width:80px;display:inline-block;">
|
||||
<button class="btn btn-sm btn-primary" id="btn-dash-refresh"><i class="fa fa-refresh"></i> {:__('Refresh')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="dash-content">
|
||||
<div class="text-center" style="padding:60px;"><i class="fa fa-spinner fa-spin fa-2x"></i><br><span class="text-muted">{:__('Loading')}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{:__('Title')}</th>
|
||||
<th>{:__('Content')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="row" id="vo" }
|
||||
<tr>
|
||||
<td>{$key}</td>
|
||||
<td style="word-break: break-all;">{$vo|htmlentities}</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
{if $Think.get.dialog}
|
||||
<tr>
|
||||
<td>回传数据</td>
|
||||
<td>
|
||||
<div class="input-group">
|
||||
<input name="callback" class="form-control" value="test" />
|
||||
<span class="input-group-btn"><a href="javascript:;" class="btn btn-success btn-callback" >回传数据</a></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="hide layer-footer">
|
||||
<label class="control-label col-xs-12 col-sm-2"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr><td>这里是编辑窗口</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="hide layer-footer">
|
||||
<label class="control-label col-xs-12 col-sm-2"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
|
||||
<div class="panel-heading">
|
||||
{:build_heading(null,FALSE)}
|
||||
<ul class="nav nav-tabs nav-custom-condition">
|
||||
<li class="active"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
|
||||
<li class=""><a href="#t-1" data-value='1' data-toggle="tab">自定义搜索条件1</a></li>
|
||||
<li class=""><a href="#t-2" data-value='2' data-toggle="tab">自定义搜索条件2</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,delete')}
|
||||
<a class="btn btn-info btn-disabled disabled btn-selected" href="javascript:;"><i class="fa fa-leaf"></i> 获取选中项</a>
|
||||
<div class="dropdown btn-group">
|
||||
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> <?= __('More') ?></a>
|
||||
<ul class="dropdown-menu text-left" role="menu">
|
||||
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
|
||||
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-success btn-singlesearch" href="javascript:;"><i class="fa fa-user"></i> 自定义搜索</a>
|
||||
<a class="btn btn-success btn-change btn-start" data-params="action=start" data-url="example/bootstraptable/start" href="javascript:;"><i class="fa fa-play"></i> 启动</a>
|
||||
<a class="btn btn-danger btn-change btn-pause" data-params="action=pause" data-url="example/bootstraptable/pause" href="javascript:;"><i class="fa fa-pause"></i> 暂停</a>
|
||||
<a href="javascript:;" class="btn btn-default" style="font-size:14px;color:dodgerblue;">
|
||||
<span class="extend">
|
||||
金额:<span id="money">0</span>
|
||||
单价:<span id="price">0</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover table-nowrap" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script id="categorytpl" type="text/html">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="group,admin">
|
||||
<select class="group form-control" name="group" data-url="example/bootstraptable/cxselect?type=group"></select>
|
||||
<select class="admin form-control" name="admin_id" data-url="example/bootstraptable/cxselect?type=admin" data-query-name="group_id"></select>
|
||||
<input type="hidden" class="operate" data-name="admin_id" value="=" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,delete')}
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,delete')}
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,350 @@
|
||||
<style>
|
||||
.upload-image {
|
||||
background: url('__CDN__/assets/addons/example/img/plus.png') no-repeat center center;
|
||||
background-size: 30px 30px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
textarea.form-control {
|
||||
background: #eee;
|
||||
}
|
||||
</style>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-success">
|
||||
<div class="panel-heading">
|
||||
{:__('自定义图片描述')}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-success-light">
|
||||
<b>温馨提示</b><br>
|
||||
默认我们的多图是没有图片描述的,如果我们需要自定义描述,可以使用以下的自定义功能<br>
|
||||
特别注意的是图片的url和描述是分开储存的,也就是说图片一个字段,描述一个字段,你在前台使用时需要自己匹配映射关系<br>
|
||||
<b>下面的演示textarea为了便于调试,设置为可见的,实际使用中应该添加个hidden的class进行隐藏</b>
|
||||
</div>
|
||||
<form id="first-form" role="form" data-toggle="validator" method="POST" action="">
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">{:__('一维数组示例')}:</label>
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-files" data-rule="required" class="form-control" size="50" name="row[files]" type="text" value="__CDN__/assets/addons/example/img/1.png,__CDN__/assets/addons/example/img/2.png,__CDN__/assets/addons/example/img/3.png">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="plupload-files" class="btn btn-danger plupload" data-input-id="c-files" data-mimetype="*" data-multiple="true" data-preview-id="p-files"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
<span><button type="button" id="fachoose-files" class="btn btn-primary fachoose" data-input-id="c-files" data-mimetype="*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-files"></span>
|
||||
</div>
|
||||
|
||||
<!--ul需要添加 data-template和data-name属性,并一一对应且唯一 -->
|
||||
<ul class="row list-inline plupload-preview" id="p-files" data-template="introtpl" data-name="row[intro]"></ul>
|
||||
|
||||
<!--请注意 ul和textarea间不能存在其它任何元素,实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[intro]" class="form-control" style="margin-top:5px;">["简洁响应式博客","CMS内容管理系统","在线投票系统"]</textarea>
|
||||
|
||||
<!--这里自定义图片预览的模板 开始-->
|
||||
<script type="text/html" id="introtpl">
|
||||
<li class="col-xs-3">
|
||||
<a href="<%=fullurl%>" data-url="<%=url%>" target="_blank" class="thumbnail">
|
||||
<img src="<%=fullurl%>" class="img-responsive">
|
||||
</a>
|
||||
<input type="text" name="row[intro][<%=index%>]" class="form-control mb-1" placeholder="请输入文件描述" value="<%=value?value:''%>"/>
|
||||
<a href="javascript:;" class="btn btn-danger btn-xs btn-trash"><i class="fa fa-trash"></i></a>
|
||||
</li>
|
||||
</script>
|
||||
<!--这里自定义图片预览的模板 结束-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">{:__('二维数组示例')}:</label>
|
||||
<div class="col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-images" data-rule="required" class="form-control" size="50" name="row[images]" type="text" value="__CDN__/assets/addons/example/img/1.png,__CDN__/assets/addons/example/img/2.png,__CDN__/assets/addons/example/img/3.png">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="plupload-images" class="btn btn-danger plupload" data-input-id="c-images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
<span><button type="button" id="fachoose-images" class="btn btn-primary fachoose" data-input-id="c-images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-images"></span>
|
||||
</div>
|
||||
|
||||
<!--ul需要添加 data-template和data-name属性,并一一对应且唯一 -->
|
||||
<ul class="row list-inline plupload-preview" id="p-images" data-template="desctpl" data-name="row[desc]"></ul>
|
||||
|
||||
<!--请注意 ul和textarea间不能存在其它任何元素,实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[desc]" class="form-control" style="margin-top:5px;">[{"info":"简洁响应式博客","size":"1M"},{"info":"CMS内容管理系统","size":"2M"},{"info":"在线投票系统","size":"1M"}]</textarea>
|
||||
|
||||
<!--这里自定义图片预览的模板 开始-->
|
||||
<script type="text/html" id="desctpl">
|
||||
<li class="col-xs-3">
|
||||
<a href="<%=fullurl%>" data-url="<%=url%>" target="_blank" class="thumbnail">
|
||||
<img src="<%=fullurl%>" class="img-responsive">
|
||||
</a>
|
||||
<input type="text" name="row[desc][<%=index%>][info]" class="form-control mb-1" placeholder="请输入插件描述" value="<%=value?value['info']:''%>"/>
|
||||
<input type="text" name="row[desc][<%=index%>][size]" class="form-control mb-1" placeholder="请输入插件大小" value="<%=value?value['size']:''%>"/>
|
||||
<a href="javascript:;" class="btn btn-danger btn-xs btn-trash"><i class="fa fa-trash"></i></a>
|
||||
</li>
|
||||
</script>
|
||||
<!--这里自定义图片预览的模板 结束-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12"></label>
|
||||
<div class="col-xs-12">
|
||||
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
|
||||
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box box-info">
|
||||
<div class="panel-heading">
|
||||
{:__('自定义Fieldlist示例')}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-danger-light">
|
||||
<b>温馨提示</b><br>
|
||||
默认的fieldlist为键值形式,如果需要一维数组或二维数组,可使用下面的自定义模板来实现<br>
|
||||
默认追加的元素是没有进行事件绑定的,我们需要监听btn-append这个按钮的fa.event.appendfieldlist事件<br>
|
||||
<b>下面的演示textarea为了便于调试,设置为可见的,实际使用中应该添加个hidden的class进行隐藏</b>
|
||||
</div>
|
||||
<form id="second-form" role="form" data-toggle="validator" method="POST" action="">
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">
|
||||
{:__('Fieldlist一维示例')}:
|
||||
<span style="font-weight: normal"><font color="red">只支持FastAdmin1.5.0+</font> {if version_compare($Think.config.fastadmin.version, '1.5.0')<0}<span class="label label-danger">你当前FastAdmin版本不支持</span>{/if}</span>
|
||||
</label>
|
||||
<div class="col-xs-12">
|
||||
<dl class="list-unstyled fieldlist" data-template="singletpl" data-name="row[single]" id="single-table">
|
||||
<dd>
|
||||
<ins>{:__('标题')}</ins>
|
||||
</dd>
|
||||
<dd>
|
||||
<ins><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></ins>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[single]" class="form-control" cols="30" rows="5">["你好","世界"]</textarea>
|
||||
<script id="singletpl" type="text/html">
|
||||
<dd class="form-inline">
|
||||
<ins><input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" size="15" value="<%=row%>" placeholder="标题"/></ins>
|
||||
<ins>
|
||||
<!--下面的两个按钮务必保留-->
|
||||
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
|
||||
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
|
||||
</ins>
|
||||
</dd>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">{:__('Fieldlist一维键值示例')}:</label>
|
||||
<div class="col-xs-12">
|
||||
<dl class="list-unstyled fieldlist" data-name="row[keyvalue]" id="keyvalue-table">
|
||||
<dd>
|
||||
<ins>{:__('标题')}</ins>
|
||||
</dd>
|
||||
<dd>
|
||||
<ins><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></ins>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[keyvalue]" class="form-control" cols="30" rows="5">{"2":"Hello", "1":"World"}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">{:__('Fieldlist二维数组示例')}:</label>
|
||||
<div class="col-xs-12">
|
||||
<table class="table fieldlist" data-template="basictpl" data-name="row[basic]" id="first-table">
|
||||
<tr>
|
||||
<td>{:__('标题')}</td>
|
||||
<td>{:__('介绍')}</td>
|
||||
<td>{:__('大小')}</td>
|
||||
<td>{:__('状态')}</td>
|
||||
<td width="100"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5"><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[basic]" class="form-control" cols="30" rows="5">[{"title":"开发者示例插件","intro":"开发者必备","size":"1M","state":1},{"title":"又拍云储存整合","intro":"一款云储存插件","size":"2M","state":0},{"title":"阿里OSS云储存","intro":"一款云储存插件","size":"1M","state":1}]</textarea>
|
||||
<script id="basictpl" type="text/html">
|
||||
<tr class="form-inline">
|
||||
<td><input type="text" name="<%=name%>[<%=index%>][title]" class="form-control" size="15" value="<%=row.title||'fast'%>" placeholder="标题"/></td>
|
||||
<td><input type="text" name="<%=name%>[<%=index%>][intro]" class="form-control" size="15" value="<%=row.intro%>" placeholder="介绍"/></td>
|
||||
<td><input type="text" name="<%=name%>[<%=index%>][size]" class="form-control" style="width:50px" value="<%=row.size%>" placeholder="大小"/></td>
|
||||
<td>
|
||||
<input type="hidden" name="<%=name%>[<%=index%>][state]" id="c-state-<%=index%>" class="form-control" style="width:50px" value="<%=row.state%>" placeholder="状态"/>
|
||||
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-state-<%=index%>" data-yes="1" data-no="0">
|
||||
<i class="fa fa-toggle-on text-success <%if(row.state!=1){%>fa-flip-horizontal text-gray<%}%> fa-2x"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<!--下面的两个按钮务必保留-->
|
||||
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
|
||||
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">{:__('Fieldlist绑定事件示例')}:</label>
|
||||
<div class="col-xs-12">
|
||||
<table class="table fieldlist" data-template="eventtpl" data-name="row[event]" id="second-table">
|
||||
<tr>
|
||||
<td>{:__('管理员')}</td>
|
||||
<td>{:__('图片')}</td>
|
||||
<td>{:__('登录时间')}</td>
|
||||
<td width="100"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--请注意实际开发中textarea应该添加个hidden进行隐藏-->
|
||||
<textarea name="row[event]" class="form-control" cols="30" rows="5">[{"id":"1","image":"/assets/addons/example/img/200x200.png","time":"2019-06-28 12:05:03"}]</textarea>
|
||||
<script id="eventtpl" type="text/html">
|
||||
<tr class="form-inline">
|
||||
<td><input type="text" name="<%=name%>[<%=index%>][id]" class="form-control selectpage" data-source="auth/admin/selectpage" data-field="username" value="<%=row.id%>" placeholder="管理员"/></td>
|
||||
<td>
|
||||
<input type="hidden" name="<%=name%>[<%=index%>][image]" id="c-image-<%=index%>" value="<%=row.image%>">
|
||||
<!--@formatter:off-->
|
||||
<button type="button" id="faupload-image" class="btn btn-danger faupload upload-image" data-input-id="c-image-<%=index%>" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="false" <%if(row.image){%>style="background-image: url('<%=Fast.api.cdnurl(row.image)%>')"<%}%>></button>
|
||||
<!--@formatter:on-->
|
||||
</td>
|
||||
<td><input type="text" name="<%=name%>[<%=index%>][time]" class="form-control datetimepicker" style="width:120px" value="<%=row.time%>" placeholder="时间"/></td>
|
||||
<td>
|
||||
<!--下面的两个按钮务必保留-->
|
||||
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
|
||||
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12"></label>
|
||||
<div class="col-xs-12">
|
||||
<button type="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
|
||||
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="panel-heading">
|
||||
自动完成+标签输入示例,<font color="red">只支持FastAdmin1.3.0+</font> {if version_compare($Think.config.fastadmin.version, '1.3.0')<0}<span class="label label-danger">你当前FastAdmin版本不支持</span>{/if}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="alert alert-danger-light">
|
||||
<b>温馨提示</b><br>
|
||||
</div>
|
||||
<form id="third-form" role="form" data-toggle="validator" method="POST" action="">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">自动完成</label>
|
||||
<div class="col-xs-12">
|
||||
<input type="text" class="form-control" data-role="autocomplete" data-autocomplete-options='{"url":"example/customform/get_title_list", "minChars":1}'/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">标签输入 <span class="text-muted small">输入后<code>回车</code>或<code>,</code>确认</span></label>
|
||||
<div class="col-xs-12">
|
||||
<input type="text" class="form-control" data-role="tagsinput"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">自动完成+标签输入</label>
|
||||
<div class="col-xs-12">
|
||||
<input type="text" class="form-control" data-role="tagsinput" data-tagsinput-options='{"minChars":1, "autocomplete":{"url":"example/customform/get_title_list"}}'/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box box-danger">
|
||||
<div class="panel-heading">
|
||||
动态显示,<font color="red">只支持FastAdmin1.3.3+</font> {if version_compare($Think.config.fastadmin.version, '1.3.3')<0}<span class="label label-danger">你当前FastAdmin版本不支持</span>{/if}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form id="fourth-form" role="form" data-toggle="validator" method="POST" action="">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">常规使用</label>
|
||||
<div class="col-xs-12">
|
||||
<input type="radio" name="row[type]" value="value1" checked/> 类型1
|
||||
<input type="radio" name="row[type]" value="value2"/> 类型2
|
||||
<div data-favisible="type=value1" class="p-3">显示内容1</div>
|
||||
<div data-favisible="type=value2" class="p-3">显示内容2</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">使用开关组件</label>
|
||||
<div class="col-xs-12">
|
||||
|
||||
<input id="c-switch" name="row[switch]" type="hidden" value="0">
|
||||
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-switch" data-yes="1" data-no="0">
|
||||
<i class="fa fa-toggle-on text-success fa-flip-horizontal text-gray fa-2x"></i>
|
||||
</a>
|
||||
|
||||
<div data-favisible="switch=1" class="p-3">显示内容隐藏的内容</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">组件嵌套</label>
|
||||
<div class="col-xs-12">
|
||||
<input type="radio" name="row[mode]" value="value1"/> 模式1
|
||||
<input type="radio" name="row[mode]" value="value2"/> 模式2
|
||||
<div data-favisible="mode=value1" class="p-3">
|
||||
<h4>显示内容1</h4>
|
||||
<input id="c-switch1" name="row[switch1]" type="hidden" value="0">
|
||||
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-switch1" data-yes="1" data-no="0">
|
||||
<i class="fa fa-toggle-on text-success fa-flip-horizontal text-gray fa-2x"></i>
|
||||
</a>
|
||||
|
||||
<div data-favisible="switch1=1" class="p-3">显示内容隐藏的内容1</div>
|
||||
</div>
|
||||
<div data-favisible="mode=value2" class="p-3">
|
||||
<h4>显示内容2</h4>
|
||||
<input id="c-switch2" name="row[switch2]" type="hidden" value="0">
|
||||
<a href="javascript:;" data-toggle="switcher" class="btn-switcher" data-input-id="c-switch2" data-yes="1" data-no="0">
|
||||
<i class="fa fa-toggle-on text-success fa-flip-horizontal text-gray fa-2x"></i>
|
||||
</a>
|
||||
|
||||
<div data-favisible="switch2=1" class="p-3">显示内容隐藏的内容2</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
<label class="control-label col-xs-12">使用内容判断 <span class="text-muted small">只有输入指定的内容才显示</span></label>
|
||||
<div class="col-xs-12">
|
||||
<input type="text" class="form-control" name="row[title]" placeholder="请输入abc三个字母">
|
||||
<div data-favisible="title=abc" class="p-3">显示内容隐藏的内容</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,126 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh')}
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script id="customformtpl" type="text/html">
|
||||
<!--form表单必须添加form-commsearch这个类-->
|
||||
<form action="" class="form-commonsearch">
|
||||
<div style="border-radius:2px;margin-bottom:10px;background:#f5f5f5;padding:15px 20px;">
|
||||
<h4>自定义搜索表单</h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label">ID</label>
|
||||
<!--显式的operate操作符-->
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<select class="form-control operate" data-name="id" style="width:60px;">
|
||||
<option value="=" selected>等于</option>
|
||||
<option value=">">大于</option>
|
||||
<option value="<">小于</option>
|
||||
</select>
|
||||
</div>
|
||||
<input class="form-control" type="text" name="id" placeholder="" value=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label">标题</label>
|
||||
<!--隐式的operate操作符,必须携带一个class为operate隐藏的文本框,且它的data-name="字段",值为操作符-->
|
||||
<input class="operate" type="hidden" data-name="title" value="="/>
|
||||
<div>
|
||||
<input class="form-control" type="text" name="title" placeholder="请输入查找的标题" value=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label">管理员ID</label>
|
||||
<div class="row" data-toggle="cxselect" data-selects="group,admin">
|
||||
<div class="col-xs-6">
|
||||
<select class="group form-control" name="group"
|
||||
data-url="example/bootstraptable/cxselect?type=group"></select>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<select class="admin form-control" name="admin_id"
|
||||
data-url="example/bootstraptable/cxselect?type=admin"
|
||||
data-query-name="group_id"></select>
|
||||
</div>
|
||||
<input type="hidden" class="operate" data-name="admin_id" value="="/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label">用户名</label>
|
||||
<input type="hidden" class="operate" data-name="username" value="="/>
|
||||
<div>
|
||||
<input id="c-category_id" data-source="auth/admin/index" data-primary-key="username"
|
||||
data-field="username" class="form-control selectpage" name="username" type="text"
|
||||
value="" style="display:block;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-6 col-md-3" style="min-height:68px;">
|
||||
<!--这里添加68px是为了避免刷新时出现元素错位闪屏-->
|
||||
<div class="form-group">
|
||||
<label class="control-label">IP</label>
|
||||
<input type="hidden" class="operate" data-name="ip" value="in"/>
|
||||
<div>
|
||||
<!--给select一个固定的高度-->
|
||||
<!--@formatter:off-->
|
||||
<select id="c-flag" class="form-control selectpicker" multiple name="ip" style="height:31px;">
|
||||
{foreach name="ipList" item="vo"}
|
||||
<option value="{$key}" {in name="key" value="" }selected{/in}>{$vo}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
<!--@formatter:on-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label">创建时间</label>
|
||||
<input type="hidden" class="operate" data-name="createtime" value="RANGE"/>
|
||||
<div>
|
||||
<input type="text" class="form-control datetimerange" name="createtime" value=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-3">
|
||||
<div class="form-group">
|
||||
<label class="control-label"></label>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<input type="submit" class="btn btn-success btn-block" value="提交"/>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<input type="reset" class="btn btn-primary btn-block" value="重置"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
@@ -0,0 +1,160 @@
|
||||
<style>#cxselect-example textarea{margin:10px 0;}</style>
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding" id="cxselect-example">
|
||||
<form id="cxselectform" action="">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><b>省市区联动</b>(通过AJAX读取数据)</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select class="province form-control" name="province" data-url="ajax/area"></select>
|
||||
<select class="city form-control" name="city" data-url="ajax/area"></select>
|
||||
<select class="area form-control" name="area" data-url="ajax/area"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-primary"><i class="fa fa-pencil"></i> 增加</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="province,city,area">
|
||||
<select class="province form-control" name="province" data-url="ajax/area">
|
||||
<option value="1964" selected>广东省</option>
|
||||
</select>
|
||||
<select class="city form-control" name="city" data-url="ajax/area">
|
||||
<option value="1988" selected>深圳市</option>
|
||||
</select>
|
||||
<select class="area form-control" name="area" data-url="ajax/area">
|
||||
<option value="1991" selected>南山区</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-success"><i class="fa fa-edit"></i> 修改</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><b>类别联动</b>(Ajax读取数据)</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="first,second">
|
||||
<select class="first form-control" name="first" data-url="ajax/category?type=page&pid=5"></select>
|
||||
<select class="second form-control" name="second" data-url="ajax/category" data-query-name="pid"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-primary"><i class="fa fa-pencil"></i> 增加</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<div class="form-inline" data-toggle="cxselect" data-selects="first,second">
|
||||
<select class="first form-control" name="first" data-url="ajax/category?type=page&pid=5">
|
||||
<option value="6" selected>网站建站</option>
|
||||
</select>
|
||||
<select class="second form-control" name="second" data-url="ajax/category" data-query-name="pid">
|
||||
<option value="9" selected>移动端</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-success"><i class="fa fa-edit"></i> 修改</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><b>省市区联动</b>(通过JSON渲染数据)</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<!--由于在初始化中修改了默认值,所以这里需要修改-jsonSpace/jsonValue/jsonName的值-->
|
||||
<div class="form-inline" data-toggle="cxselect" data-url="__CDN__/assets/libs/fastadmin-cxselect/js/cityData.min.json"
|
||||
data-selects="province,city,area" data-json-space="" data-json-name="n" data-json-value="">
|
||||
<select class="province form-control" name="province"></select>
|
||||
<select class="city form-control" name="city"></select>
|
||||
<select class="area form-control" name="area"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-primary"><i class="fa fa-pencil"></i> 增加</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-9">
|
||||
<!--由于在初始化中修改了默认值,所以这里需要修改-jsonSpace/jsonValue/jsonName的值-->
|
||||
<div class="form-inline" data-toggle="cxselect" data-url="__CDN__/assets/libs/fastadmin-cxselect/js/cityData.min.json"
|
||||
data-selects="province,city,area" data-json-space="" data-json-name="n" data-json-value="">
|
||||
<select class="province form-control" data-first-title="选择省">
|
||||
<option value="">请选择</option>
|
||||
<option value="浙江省" selected>浙江省</option>
|
||||
</select>
|
||||
<select class="city form-control" data-first-title="选择市">
|
||||
<option value="">请选择</option>
|
||||
<option value="杭州市" selected>杭州市</option>
|
||||
</select>
|
||||
<select class="area form-control" data-first-title="选择地区">
|
||||
<option value="">请选择</option>
|
||||
<option value="西湖区" selected>西湖区</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h6><label class="label label-success"><i class="fa fa-edit"></i> 修改</label></h6>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<textarea class="form-control" rows="8">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,165 @@
|
||||
<style>
|
||||
.tab-content > .chart {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-aqua">
|
||||
<div class="inner">
|
||||
<h3>150</h3>
|
||||
|
||||
<p>今日订单</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-shopping-cart"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">更多 <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-lg-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-green">
|
||||
<div class="inner">
|
||||
<h3>53<sup style="font-size: 20px">%</sup></h3>
|
||||
|
||||
<p>同比增长率</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-area-chart"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">更多 <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-lg-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner">
|
||||
<h3>44</h3>
|
||||
|
||||
<p>今日注册用户数</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-users"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">更多 <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-lg-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-red">
|
||||
<div class="inner">
|
||||
<h3>65</h3>
|
||||
|
||||
<p>唯一访客用户</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-user"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">更多 <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<!-- Main row -->
|
||||
<div class="row" style="margin-bottom:5px;">
|
||||
<!-- Left col -->
|
||||
<section class="col-lg-7 connectedSortable">
|
||||
<!-- Custom tabs (Charts with tabs)-->
|
||||
<div class="nav-tabs-custom charts-custom">
|
||||
<!-- Tabs within a box -->
|
||||
<ul class="nav nav-tabs pull-right">
|
||||
<li class="active"><a href="#line-chart" data-toggle="tab">折线图</a></li>
|
||||
<li><a href="#area-chart" data-toggle="tab">区域图</a></li>
|
||||
<li class="pull-left header"><i class="fa fa-inbox"></i> 销售趋势</li>
|
||||
</ul>
|
||||
<div class="tab-content no-padding">
|
||||
<!-- Morris chart - Sales -->
|
||||
<div class="chart tab-pane active" id="line-chart" style="position: relative; height: 300px;"></div>
|
||||
<div class="chart tab-pane" id="area-chart" style="position: relative; height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-tabs-custom charts-custom">
|
||||
<!-- Tabs within a box -->
|
||||
<ul class="nav nav-tabs pull-right">
|
||||
<li class="active"><a href="#pie-chart" data-toggle="tab">饼图</a></li>
|
||||
<li><a href="#bar-chart" data-toggle="tab">柱状图</a></li>
|
||||
<li class="pull-left header"><i class="fa fa-inbox"></i> 访问记录</li>
|
||||
</ul>
|
||||
<div class="tab-content no-padding">
|
||||
<!-- Morris chart - Sales -->
|
||||
<div class="chart tab-pane active" id="pie-chart" style="position: relative; height: 300px;"></div>
|
||||
<div class="chart tab-pane" id="bar-chart" style="position: relative; height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.nav-tabs-custom -->
|
||||
|
||||
</section>
|
||||
<!-- /.Left col -->
|
||||
<section class="col-lg-5 connectedSortable">
|
||||
|
||||
<!-- Map box -->
|
||||
<div class="box box-solid bg-light-blue-gradient">
|
||||
<div class="box-header">
|
||||
<!-- tools box -->
|
||||
<div class="pull-right box-tools">
|
||||
</div>
|
||||
<!-- /. tools -->
|
||||
|
||||
<i class="fa fa-map-marker"></i>
|
||||
|
||||
<h3 class="box-title">
|
||||
访客分布
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div id="simplebar-chart" style="height: 250px; width: 100%;"></div>
|
||||
</div>
|
||||
<!-- /.box-body-->
|
||||
<div class="box-footer no-border">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-center">
|
||||
<div class="knob-label">统计最近一周访客的记录</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
|
||||
<!-- solid sales graph -->
|
||||
<div class="box box-solid bg-teal-gradient">
|
||||
<div class="box-header">
|
||||
<i class="fa fa-th"></i>
|
||||
|
||||
<h3 class="box-title">订单趋势</h3>
|
||||
|
||||
<div class="box-tools pull-right">
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body border-radius-none">
|
||||
<div class="chart" id="smoothline-chart" style="height: 250px;"></div>
|
||||
</div>
|
||||
<!-- /.box-body-->
|
||||
<div class="box-footer no-border">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-center">
|
||||
<div class="knob-label">统计最近一周订单的趋势</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
|
||||
</section>
|
||||
<!-- right col -->
|
||||
</div>
|
||||
<!-- /.row (main row) -->
|
||||
@@ -0,0 +1,27 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-heading">
|
||||
<div class="panel-lead"><em>多表格(Multitable)</em>用于展示在一个页面展示多个表格数据,并且每次切换时刷新</div>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#first" data-toggle="tab">表格1</a></li>
|
||||
<li><a href="#second" data-toggle="tab">表格2</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="first">
|
||||
<div id="toolbar1" class="toolbar">
|
||||
{:build_toolbar('refresh')}
|
||||
</div>
|
||||
<table id="table1" class="table table-striped table-bordered table-hover" width="100%">
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="second">
|
||||
<div id="toolbar2" class="toolbar">
|
||||
{:build_toolbar('refresh')}
|
||||
</div>
|
||||
<table id="table2" class="table table-striped table-bordered table-hover" width="100%">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,delete')}
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-5 col-lg-4">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
<div id="1" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar1" class="toolbar">
|
||||
{:build_toolbar('refresh')}
|
||||
</div>
|
||||
<table id="table1" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-7 col-lg-8">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent2" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="two">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar2" class="toolbar">
|
||||
{:build_toolbar('refresh')}
|
||||
</div>
|
||||
<table id="table2" class="table table-striped table-bordered table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,67 @@
|
||||
<div class="panel panel-default panel-intro">
|
||||
{:build_heading()}
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
<div class="tab-pane fade active in" id="one">
|
||||
<div class="widget-body no-padding">
|
||||
<div id="toolbar" class="toolbar">
|
||||
{:build_toolbar('refresh,delete')}
|
||||
<a class="btn btn-info btn-disabled disabled btn-selected" href="javascript:;"><i class="fa fa-leaf"></i> 获取选中项</a>
|
||||
<a class="btn btn-success btn-toggle-view" href="javascript:;"><i class="fa fa-leaf"></i> 切换视图</a>
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-hover" width="100%">
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style type="text/css">
|
||||
.example {
|
||||
height:100%;position: relative;
|
||||
}
|
||||
.example > span {
|
||||
position:absolute;left:15px;top:15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script id="itemtpl" type="text/html">
|
||||
<!--
|
||||
如果启用了templateView,默认调用的是itemtpl这个模板,可以通过设置templateFormatter来修改
|
||||
在当前模板中可以使用三个变量(item:行数据,i:当前第几行,data:所有的行数据)
|
||||
此模板引擎使用的是art-template的native,可参考官方文档
|
||||
-->
|
||||
|
||||
<div class="col-sm-4 col-md-3">
|
||||
<!--下面四行是为了展示随机图片和标签,可移除-->
|
||||
<% var imagearr = ['__CDN__/assets/addons/example/img/1.png', '__CDN__/assets/addons/example/img/2.png', '__CDN__/assets/addons/example/img/3.png']; %>
|
||||
<% var image = imagearr[item.id % 3]; %>
|
||||
<% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %>
|
||||
<% var label = labelarr[item.id % 3]; %>
|
||||
<div class="thumbnail example">
|
||||
<span class="btn btn-<%=label%>">ID:<%=item.id%></span>
|
||||
<img src="<%=image%>" style="width:100%;" alt="<%=item.title%>">
|
||||
<div class="caption">
|
||||
<h4><%=item.title?item.title:'无'%></h4>
|
||||
<p class="text-muted">操作者IP:<%=item.ip%></p>
|
||||
<p class="text-muted">操作时间:<%=Moment(item.createtime*1000).format("YYYY-MM-DD HH:mm:ss")%></p>
|
||||
<p>
|
||||
<!--详情的事件需要在JS中手动绑定-->
|
||||
<a href="#" class="btn btn-primary btn-success btn-detail" data-id="<%=item.id%>"><i class="fa fa-camera"></i> 详情</a>
|
||||
|
||||
<!--如果需要响应编辑或删除事件,可以给元素添加 btn-edit或btn-del的类和data-id这个属性值-->
|
||||
<a href="#" class="btn btn-primary btn-edit" data-id="<%=item.id%>"><i class="fa fa-pencil"></i> 编辑</a>
|
||||
<a href="#" class="btn btn-danger btn-del" data-id="<%=item.id%>"><i class="fa fa-times"></i> 删除</a>
|
||||
<span class="pull-right" style="margin-top:10px;">
|
||||
<!--如果需要多选操作,请确保有下面的checkbox元素存在,可移除-->
|
||||
<input name="checkbox" data-id="<%=item.id%>" type="checkbox" />
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
@@ -8,6 +8,17 @@
|
||||
<div id="toolbar" class="toolbar">
|
||||
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
|
||||
<a href="javascript:;" class="btn btn-warning btn-missingnum" title="{:__('Missing Number Analysis')}"><i class="fa fa-search"></i> {:__('Missing Number Analysis')}</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-trend" title="{:__('Trend Chart')}"><i class="fa fa-area-chart"></i> {:__('Trend Chart')}</a>
|
||||
<a href="javascript:;" class="btn btn-danger btn-hotcold" title="{:__('Hot/Cold Analysis')}"><i class="fa fa-fire"></i> {:__('Hot/Cold Analysis')}</a>
|
||||
<a href="javascript:;" class="btn btn-success btn-colorwave" title="{:__('Color Wave')}"><i class="fa fa-paint-brush"></i> {:__('Color Wave')}</a>
|
||||
<a href="javascript:;" class="btn btn-primary btn-zodiac" title="{:__('Zodiac')}"><i class="fa fa-star"></i> {:__('Zodiac')}</a>
|
||||
<a href="javascript:;" class="btn btn-warning btn-oddeven" title="{:__('Odd/Even')}"><i class="fa fa-balance-scale"></i> {:__('Odd/Even')}</a>
|
||||
<a href="javascript:;" class="btn btn-info btn-bigsmall" title="{:__('Big/Small')}"><i class="fa fa-arrows-h"></i> {:__('Big/Small')}</a>
|
||||
<a href="javascript:;" class="btn btn-success btn-sumchart" title="{:__('Sum Chart')}"><i class="fa fa-line-chart"></i> {:__('Sum Chart')}</a>
|
||||
<a href="javascript:;" class="btn btn-warning btn-consecutive" title="{:__('Consecutive')}"><i class="fa fa-link"></i> {:__('Consecutive')}</a>
|
||||
<a href="javascript:;" class="btn btn-default btn-tailnums" title="{:__('Tail Numbers')}"><i class="fa fa-list-ol"></i> {:__('Tail Numbers')}</a>
|
||||
<a href="javascript:;" class="btn btn-danger btn-specialhotcold" title="{:__('Special Hot/Cold')}"><i class="fa fa-fire"></i> 特码冷热</a>
|
||||
<!-- <a href="javascript:;" class="btn btn-success btn-dashboard" title="{:__('Dashboard')}"><i class="fa fa-tachometer"></i> {:__('Dashboard')}</a>-->
|
||||
<!-- <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('history/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
|
||||
</div>
|
||||
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
|
||||
@@ -21,3 +32,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ECharts CDN for trend chart -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
||||
|
||||
@@ -270,7 +270,7 @@ return [
|
||||
//FastAdmin配置
|
||||
'fastadmin' => [
|
||||
//是否开启前台会员中心
|
||||
'usercenter' => true,
|
||||
'usercenter' => false,
|
||||
//会员注册验证码类型email/mobile/wechat/text/false
|
||||
'user_register_captcha' => 'text',
|
||||
//登录验证码
|
||||
|
||||
@@ -7,6 +7,10 @@ return array (
|
||||
),
|
||||
'route' =>
|
||||
array (
|
||||
'/example$' => 'example/index/index',
|
||||
'/example/d/[:name]' => 'example/demo/index',
|
||||
'/example/d1/[:name]' => 'example/demo/demo1',
|
||||
'/example/d2/[:name]' => 'example/demo/demo2',
|
||||
),
|
||||
'priority' =>
|
||||
array (
|
||||
|
||||
@@ -37,12 +37,13 @@ class Index extends Api
|
||||
Db::name('history')->where('expect', $item['expect'])->update($insert_data);
|
||||
}
|
||||
}
|
||||
$this->success('获取成功');
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
$this->success('获取成功');
|
||||
|
||||
} else {
|
||||
$this->error('获取失败');
|
||||
}
|
||||
|
||||
@@ -1,78 +1,386 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echarts-theme', 'template'], function ($, undefined, Backend, Datatable, Table, Echarts, undefined, Template) {
|
||||
|
||||
define(['jquery'], function ($) {
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
var myChart = Echarts.init(document.getElementById('echart'), 'walden');
|
||||
|
||||
// 指定图表的配置项和数据
|
||||
var option = {
|
||||
title: {
|
||||
text: '',
|
||||
subtext: ''
|
||||
},
|
||||
color: [
|
||||
"#18d1b1",
|
||||
"#3fb1e3",
|
||||
"#626c91",
|
||||
"#a0a7e6",
|
||||
"#c4ebad",
|
||||
"#96dee8"
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: [__('Register user')]
|
||||
},
|
||||
toolbox: {
|
||||
show: false,
|
||||
feature: {
|
||||
magicType: {show: true, type: ['stack', 'tiled']},
|
||||
saveAsImage: {show: true}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: Config.column
|
||||
},
|
||||
yAxis: {},
|
||||
grid: [{
|
||||
left: 'left',
|
||||
top: 'top',
|
||||
right: '10',
|
||||
bottom: 30
|
||||
}],
|
||||
series: [{
|
||||
name: __('Register user'),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
normal: {}
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 1.5
|
||||
}
|
||||
},
|
||||
data: Config.userdata
|
||||
}]
|
||||
var getColor = function (color) {
|
||||
if (!color || color === '—') return '#95a5a6';
|
||||
if (color.indexOf('红') !== -1) return '#e74c3c';
|
||||
if (color.indexOf('蓝') !== -1) return '#3498db';
|
||||
if (color.indexOf('绿') !== -1) return '#2ecc71';
|
||||
return '#95a5a6';
|
||||
};
|
||||
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
myChart.setOption(option);
|
||||
var ball = function (num, color) {
|
||||
return '<span class="num-ball-sm" style="background-color:' + getColor(color) + ';">' + num + '</span>';
|
||||
};
|
||||
|
||||
$(window).resize(function () {
|
||||
myChart.resize();
|
||||
});
|
||||
function loadData() {
|
||||
var periods = parseInt($('#dash-periods').val()) || 30;
|
||||
if (periods < 10) periods = 10;
|
||||
if (periods > 100) periods = 100;
|
||||
$('#dash-content').html('<div class="text-center" style="padding:60px;"><i class="fa fa-spinner fa-spin fa-2x"></i><br><span class="text-muted">' + __('Loading') + '</span></div>');
|
||||
|
||||
$(document).on("click", ".btn-refresh", function () {
|
||||
setTimeout(function () {
|
||||
myChart.resize();
|
||||
}, 0);
|
||||
});
|
||||
$.ajax({
|
||||
url: 'history/dashboard',
|
||||
type: 'GET',
|
||||
data: {periods: periods},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code != 1) {
|
||||
$('#dash-content').html('<div class="alert alert-danger">' + (ret.msg || '加载失败') + '</div>');
|
||||
return;
|
||||
}
|
||||
render(ret.data);
|
||||
},
|
||||
error: function () {
|
||||
$('#dash-content').html('<div class="alert alert-danger">请求失败,请重试</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function render(data) {
|
||||
var hc = data.hotcold, cw = data.colorwave, zo = data.zodiac;
|
||||
var oe = data.oddeven, bs = data.bigsmall, sp = data.special, tn = data.tailnumbers;
|
||||
var zt = data.zonetransition;
|
||||
|
||||
var html = '';
|
||||
|
||||
// 热号:按次数降序取前5名
|
||||
var hotAll = hc.all.slice().sort(function (a, b) { return b.count - a.count; });
|
||||
var hotTop5 = hotAll.slice(0, 5);
|
||||
// 冷号:按次数升序取前5名,第5名有并列则全部包含
|
||||
var coldAll = hc.all.slice().sort(function (a, b) { return a.count - b.count; });
|
||||
var coldList = coldAll.slice(0, 5);
|
||||
if (coldList.length >= 5) {
|
||||
var threshold = coldList[4].count;
|
||||
var rest = coldAll.slice(5);
|
||||
for (var k = 0; k < rest.length; k++) {
|
||||
if (rest[k].count === threshold) coldList.push(rest[k]);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
html += '<div class="dash-section"><h4>🔥❄️ 冷热号码</h4><div class="row">';
|
||||
html += '<div class="col-sm-6"><div class="dash-card" style="border-left:3px solid #e74c3c;"><div style="color:#e74c3c;font-weight:bold;margin-bottom:8px;">热号 Top 5</div>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;">';
|
||||
for (var i = 0; i < hotTop5.length; i++) {
|
||||
html += '<span style="flex:0 0 20%;text-align:center;margin-bottom:4px;">' + ball(hotTop5[i].num, hotTop5[i].color) + '<br><span style="font-size:11px;color:#999;">' + hotTop5[i].count + '次</span></span>';
|
||||
}
|
||||
html += '</div></div></div>';
|
||||
html += '<div class="col-sm-6"><div class="dash-card" style="border-left:3px solid #3498db;"><div style="color:#3498db;font-weight:bold;margin-bottom:8px;">冷号</div>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;">';
|
||||
for (var i = 0; i < coldList.length; i++) {
|
||||
html += '<span style="flex:0 0 20%;text-align:center;margin-bottom:4px;">' + ball(coldList[i].num, coldList[i].color) + '<br><span style="font-size:11px;color:#999;">' + coldList[i].count + '次</span></span>';
|
||||
}
|
||||
html += '</div></div></div></div></div>';
|
||||
|
||||
html += '<div class="dash-section"><h4>📊 比例分析</h4><div class="row">';
|
||||
html += '<div class="col-sm-4"><div class="dash-card"><div id="colorwave-chart" style="width:100%;height:200px;"></div></div></div>';
|
||||
html += '<div class="col-sm-4"><div class="dash-card"><div id="oddeven-chart" style="width:100%;height:200px;"></div></div></div>';
|
||||
html += '<div class="col-sm-4"><div class="dash-card"><div id="bigsmall-chart" style="width:100%;height:200px;"></div></div></div>';
|
||||
html += '</div></div>';
|
||||
|
||||
html += '<div class="dash-section"><h4>⭐ 生肖排名</h4><div id="zodiac-chart" style="width:100%;height:250px;"></div></div>';
|
||||
|
||||
html += '<div class="dash-section"><h4>📈 特码走势</h4><div id="special-chart" style="width:100%;height:280px;"></div></div>';
|
||||
|
||||
html += '<div class="dash-section"><h4>🔢 尾数频率</h4><div id="tail-chart" style="width:100%;height:220px;"></div></div>';
|
||||
|
||||
// 区域转移概率 + 波色转移概率
|
||||
if (zt && zt.matrix && zt.matrix.length > 0) {
|
||||
var cwt = data.colorwavetransition;
|
||||
var zt2 = data.zodiactransition;
|
||||
html += '<div class="dash-section"><h4>🔄 转移概率</h4><div class="row">';
|
||||
// 左侧:区域转移
|
||||
html += '<div class="col-sm-7"><div style="font-size:12px;color:#999;margin-bottom:8px;">区域转移(共 ' + zt.total_transitions + ' 次)</div>';
|
||||
html += '<table class="table table-bordered table-condensed text-center" style="margin:0 auto;"><thead><tr><th style="width:80px;position:relative;"><div style="width:100%;height:35px;border-bottom:1px solid #e5e5e5;position:relative;"><span style="position:absolute;top:2px;right:5px;font-size:12px;">区域</span><span style="position:absolute;bottom:2px;left:5px;font-size:12px;">特码</span></div></th>';
|
||||
for (var z = 0; z < zt.zones.length; z++) {
|
||||
html += '<th>' + zt.zones[z] + '</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
for (var r = 0; r < 5; r++) {
|
||||
html += '<tr><td style="font-weight:bold;">' + zt.zones[r] + '</td>';
|
||||
for (var c = 0; c < 5; c++) {
|
||||
var pct = zt.probabilities[r][c];
|
||||
var cnt = zt.matrix[r][c];
|
||||
var bg = pct > 30 ? '#e74c3c' : pct > 20 ? '#f39c12' : pct > 10 ? '#3498db' : pct > 0 ? '#95a5a6' : '#f5f5f5';
|
||||
var txt = pct > 10 ? '#fff' : '#333';
|
||||
html += '<td style="background-color:' + bg + ';color:' + txt + ';">' + cnt + '次<br>' + pct + '%</td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table></div>';
|
||||
// 右侧:波色转移
|
||||
if (cwt && cwt.matrix && cwt.matrix.length > 0) {
|
||||
html += '<div class="col-sm-5"><div style="font-size:12px;color:#999;margin-bottom:8px;">波色转移(共 ' + cwt.total_transitions + ' 次)</div>';
|
||||
html += '<table class="table table-bordered table-condensed text-center" style="margin:0 auto;"><thead><tr><th style="width:70px;position:relative;"><div style="width:100%;height:35px;border-bottom:1px solid #e5e5e5;position:relative;"><span style="position:absolute;top:2px;right:5px;font-size:12px;">区域</span><span style="position:absolute;bottom:2px;left:5px;font-size:12px;">特码</span></div></th>';
|
||||
for (var z = 0; z < cwt.colors.length; z++) {
|
||||
html += '<th>' + cwt.colors[z] + '</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
var cwColors = ['#e74c3c', '#3498db', '#2ecc71'];
|
||||
for (var r = 0; r < 3; r++) {
|
||||
html += '<tr><td style="font-weight:bold;color:' + cwColors[r] + ';">' + cwt.colors[r] + '</td>';
|
||||
for (var c = 0; c < 3; c++) {
|
||||
var pct = cwt.probabilities[r][c];
|
||||
var cnt = cwt.matrix[r][c];
|
||||
var bg = pct > 40 ? cwColors[r] : pct > 20 ? cwColors[c] : pct > 0 ? '#95a5a6' : '#f5f5f5';
|
||||
var txt = pct > 20 ? '#fff' : '#333';
|
||||
html += '<td style="background-color:' + bg + ';color:' + txt + ';">' + cnt + '次<br>' + pct + '%</td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
// 下方:区域→区域转移矩阵,单元格内显示波色概率
|
||||
var ztc = data.zonetocolortransition;
|
||||
if (ztc && ztc.matrix && ztc.matrix.length > 0) {
|
||||
html += '<div style="margin-top:20px;font-size:12px;color:#999;margin-bottom:8px;">区域→区域转移矩阵(单元格内为波色概率)</div>';
|
||||
html += '<table class="table table-bordered table-condensed text-center" style="max-width:600px;margin:0 auto;"><thead><tr><th style="width:80px;position:relative;"><div style="width:100%;height:35px;border-bottom:1px solid #e5e5e5;position:relative;"><span style="position:absolute;top:2px;right:5px;font-size:12px;">区域</span><span style="position:absolute;bottom:2px;left:5px;font-size:12px;">特码</span></div></th>';
|
||||
for (var z = 0; z < ztc.zones.length; z++) {
|
||||
html += '<th>' + ztc.zones[z] + '</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
for (var r = 0; r < 5; r++) {
|
||||
html += '<tr><td style="font-weight:bold;">' + ztc.zones[r] + '</td>';
|
||||
for (var c = 0; c < 5; c++) {
|
||||
var cnt = ztc.matrix[r][c];
|
||||
var cp = ztc.color_probs[r][c];
|
||||
var bg = cnt > 0 ? '#fafafa' : '#fff';
|
||||
var txt = (cp.red > 40 || cp.blue > 40 || cp.green > 40) ? '#fff' : '#333';
|
||||
html += '<td style="background-color:' + bg + ';color:' + txt + ';"><span style="color:#e74c3c;">红' + cp.red + '%</span><br><span style="color:#3498db;">蓝' + cp.blue + '%</span><br><span style="color:#2ecc71;">绿' + cp.green + '%</span><br><span style="font-size:11px;color:#000;">(' + cnt + '次)</span></td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
}
|
||||
// 下方:生肖转移矩阵
|
||||
if (zt2 && zt2.matrix && zt2.matrix.length > 0) {
|
||||
html += '<div style="margin-top:20px;font-size:12px;color:#999;margin-bottom:8px;">生肖转移(共 ' + zt2.total_transitions + ' 次)</div>';
|
||||
html += '<table class="table table-bordered table-condensed text-center" style="max-width:720px;margin:0 auto;"><thead><tr><th style="width:50px;">特码</th>';
|
||||
for (var z = 0; z < zt2.animals.length; z++) {
|
||||
html += '<th>' + zt2.animals[z] + '</th>';
|
||||
}
|
||||
html += '</tr></thead><tbody>';
|
||||
var animalColors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22', '#34495e', '#e74c3c', '#3498db', '#2ecc71', '#f39c12'];
|
||||
for (var r = 0; r < zt2.animals.length; r++) {
|
||||
html += '<tr><td style="font-weight:bold;color:' + animalColors[r] + ';">' + zt2.animals[r] + '</td>';
|
||||
for (var c = 0; c < zt2.animals.length; c++) {
|
||||
var pct = zt2.probabilities[r][c];
|
||||
var cnt = zt2.matrix[r][c];
|
||||
var bg = pct > 30 ? '#e74c3c' : pct > 20 ? '#f39c12' : pct > 10 ? '#3498db' : pct > 0 ? '#95a5a6' : '#f5f5f5';
|
||||
var txt = pct > 10 ? '#fff' : '#333';
|
||||
html += '<td style="background-color:' + bg + ';color:' + txt + ';">' + cnt + '次<br>' + pct + '%</td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// 热力图部分
|
||||
var hm = data.heatmap;
|
||||
html += '<div class="dash-section"><h4>🎨 特码热力图</h4><div style="font-size:12px;color:#999;margin-bottom:8px;">X轴:期号(从左往右,从远到近) | Y轴:号码1-49 | 颜色:号码波色</div><div id="heatmap-chart" style="width:100%;height:500px;"></div></div>';
|
||||
|
||||
$('#dash-content').html(html);
|
||||
|
||||
// 波色饼图
|
||||
if (typeof echarts !== 'undefined') {
|
||||
var cwDom = document.getElementById('colorwave-chart');
|
||||
if (cwDom) {
|
||||
var cwChart = echarts.init(cwDom);
|
||||
cwChart.setOption({
|
||||
tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'},
|
||||
series: [{
|
||||
type: 'pie', radius: '60%',
|
||||
data: [
|
||||
{value: cw.red, name: '红波', itemStyle: {color: '#e74c3c'}},
|
||||
{value: cw.blue, name: '蓝波', itemStyle: {color: '#3498db'}},
|
||||
{value: cw.green, name: '绿波', itemStyle: {color: '#2ecc71'}}
|
||||
],
|
||||
label: {show: true, formatter: '{b}\n{d}%'},
|
||||
emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}}
|
||||
}],
|
||||
grid: {top: 0, bottom: 0}
|
||||
});
|
||||
$(window).on('resize', function(){ cwChart.resize(); });
|
||||
}
|
||||
|
||||
// 奇偶饼图
|
||||
var oeDom = document.getElementById('oddeven-chart');
|
||||
if (oeDom) {
|
||||
var oeChart = echarts.init(oeDom);
|
||||
oeChart.setOption({
|
||||
tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'},
|
||||
series: [{
|
||||
type: 'pie', radius: '60%',
|
||||
data: [
|
||||
{value: oe.odd, name: '奇数', itemStyle: {color: '#e74c3c'}},
|
||||
{value: oe.even, name: '偶数', itemStyle: {color: '#3498db'}}
|
||||
],
|
||||
label: {show: true, formatter: '{b}\n{d}%'},
|
||||
emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}}
|
||||
}],
|
||||
grid: {top: 0, bottom: 0}
|
||||
});
|
||||
$(window).on('resize', function(){ oeChart.resize(); });
|
||||
}
|
||||
|
||||
// 大小饼图
|
||||
var bsDom = document.getElementById('bigsmall-chart');
|
||||
if (bsDom) {
|
||||
var bsChart = echarts.init(bsDom);
|
||||
bsChart.setOption({
|
||||
tooltip: {trigger: 'item', formatter: '{b}: {c} ({d}%)'},
|
||||
series: [{
|
||||
type: 'pie', radius: '60%',
|
||||
data: [
|
||||
{value: bs.big, name: '大数', itemStyle: {color: '#f39c12'}},
|
||||
{value: bs.small, name: '小数', itemStyle: {color: '#2ecc71'}}
|
||||
],
|
||||
label: {show: true, formatter: '{b}\n{d}%'},
|
||||
emphasis: {itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)'}}
|
||||
}],
|
||||
grid: {top: 0, bottom: 0}
|
||||
});
|
||||
$(window).on('resize', function(){ bsChart.resize(); });
|
||||
}
|
||||
}
|
||||
|
||||
// 生肖柱状图
|
||||
if (typeof echarts !== 'undefined' && zo.list && zo.list.length > 0) {
|
||||
var zDom = document.getElementById('zodiac-chart');
|
||||
if (zDom) {
|
||||
var zChart = echarts.init(zDom);
|
||||
zChart.setOption({
|
||||
tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}},
|
||||
grid: {left: 50, right: 20, bottom: 30, top: 10},
|
||||
xAxis: {type: 'category', data: zo.list.map(function(z){return z.animal;})},
|
||||
yAxis: {type: 'value', splitNumber: 3},
|
||||
series: [{type: 'bar', data: zo.list.map(function(z){return z.count;}), itemStyle: {color: '#626c91'}, label: {show: true, position: 'top', fontSize: 12, color: '#333'}}]
|
||||
});
|
||||
$(window).on('resize', function(){ zChart.resize(); });
|
||||
}
|
||||
}
|
||||
|
||||
// 特码走势
|
||||
if (typeof echarts !== 'undefined' && sp.expects && sp.expects.length > 0) {
|
||||
var chartDom = document.getElementById('special-chart');
|
||||
if (chartDom) {
|
||||
var chart = echarts.init(chartDom);
|
||||
var colorMap = {'红': '#e74c3c', '蓝': '#3498db', '绿': '#2ecc71'};
|
||||
var itemColors = sp.colors.map(function(c) {
|
||||
if (c.indexOf('红') !== -1) return colorMap['红'];
|
||||
if (c.indexOf('蓝') !== -1) return colorMap['蓝'];
|
||||
if (c.indexOf('绿') !== -1) return colorMap['绿'];
|
||||
return '#95a5a6';
|
||||
});
|
||||
chart.setOption({
|
||||
tooltip: {trigger: 'axis', formatter: function(p) {
|
||||
return '期号: ' + p[0].axisValue + '<br/>特码: <b style="color:' + itemColors[p[0].dataIndex] + '">' + p[0].data + '</b>';
|
||||
}},
|
||||
xAxis: {type: 'category', data: sp.expects, axisLabel: {rotate: 45, fontSize: 10}},
|
||||
yAxis: {type: 'value', min: 0, max: 50},
|
||||
series: [{type: 'line', data: sp.specials, smooth: true, symbolSize: 8, itemStyle: {color: function(p) { return itemColors[p.dataIndex]; }}, areaStyle: {color: 'rgba(52,152,219,0.05)'}}],
|
||||
grid: {left: 50, right: 20, bottom: 50, top: 20}
|
||||
});
|
||||
$(window).on('resize', function () { chart.resize(); });
|
||||
}
|
||||
}
|
||||
|
||||
// 尾数柱状图
|
||||
if (typeof echarts !== 'undefined' && tn.all && tn.all.length > 0) {
|
||||
var tDom = document.getElementById('tail-chart');
|
||||
if (tDom) {
|
||||
var tChart = echarts.init(tDom);
|
||||
var sorted = tn.all.slice().sort(function(a,b){return a.tail - b.tail;});
|
||||
tChart.setOption({
|
||||
tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}},
|
||||
grid: {left: 50, right: 20, bottom: 30, top: 10},
|
||||
xAxis: {type: 'category', data: sorted.map(function(t){return t.tail;})},
|
||||
yAxis: {type: 'value', splitNumber: 3},
|
||||
series: [{type: 'bar', data: sorted.map(function(t){return t.count;}), itemStyle: {color: '#23b7e5'}, label: {show: true, position: 'top', fontSize: 12, color: '#333'}}]
|
||||
});
|
||||
$(window).on('resize', function(){ tChart.resize(); });
|
||||
}
|
||||
}
|
||||
|
||||
// 特码热力图
|
||||
if (typeof echarts !== 'undefined' && hm && hm.expects && hm.expects.length > 0) {
|
||||
var hmDom = document.getElementById('heatmap-chart');
|
||||
if (hmDom) {
|
||||
var hmChart = echarts.init(hmDom);
|
||||
// 构建完整的热力图数据矩阵(每期每号码)
|
||||
var hmData = [];
|
||||
for (var x = 0; x < hm.expects.length; x++) {
|
||||
for (var y = 0; y < 49; y++) {
|
||||
// 检查该期是否有该号码作为特码
|
||||
var found = false;
|
||||
for (var i = 0; i < hm.heatmap.length; i++) {
|
||||
if (hm.heatmap[i][0] === x && hm.heatmap[i][1] === y) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hmData.push([x, y, found ? 1 : 0]);
|
||||
}
|
||||
}
|
||||
hmChart.setOption({
|
||||
tooltip: {
|
||||
position: 'top',
|
||||
formatter: function(p) {
|
||||
var periodIdx = p.data[0];
|
||||
var num = p.data[1] + 1;
|
||||
var val = p.data[2];
|
||||
return '期号: ' + hm.expects[periodIdx] + '<br/>号码: ' + num + '<br/>状态: ' + (val === 1 ? '已开出' : '未开出');
|
||||
}
|
||||
},
|
||||
grid: {left: 80, right: 30, bottom: 60, top: 30},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: hm.expects,
|
||||
axisLabel: {rotate: 45, fontSize: 10, interval: 0},
|
||||
splitArea: {show: true}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: hm.nums,
|
||||
axisLabel: {fontSize: 10},
|
||||
splitArea: {show: true}
|
||||
},
|
||||
visualMap: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
show: false,
|
||||
inRange: {
|
||||
color: ['#f0f0f0', '#e74c3c']
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
type: 'heatmap',
|
||||
data: hmData,
|
||||
label: {show: false},
|
||||
itemStyle: {
|
||||
color: function(p) {
|
||||
// 未开出显示浅灰,开出显示该号码的波色
|
||||
if (p.data[2] === 0) return '#f5f5f5';
|
||||
var numIdx = p.data[1];
|
||||
return hm.colors[numIdx] || '#95a5a6';
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.5)'}
|
||||
}
|
||||
}]
|
||||
});
|
||||
$(window).on('resize', function(){ hmChart.resize(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#btn-dash-refresh').on('click', loadData);
|
||||
loadData();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/bootstraptable/index',
|
||||
add_url: '',
|
||||
edit_url: 'example/bootstraptable/edit',
|
||||
del_url: 'example/bootstraptable/del',
|
||||
multi_url: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
//在普通搜索提交搜索前
|
||||
table.on('common-search.bs.table', function (event, table, query) {
|
||||
//这里可以获取到普通搜索表单中字段的查询条件
|
||||
console.log(query);
|
||||
});
|
||||
|
||||
//在普通搜索渲染后
|
||||
table.on('post-common-search.bs.table', function (event, table) {
|
||||
var form = $("form", table.$commonsearch);
|
||||
$("input[name='title']", form).addClass("selectpage").data("source", "example/bootstraptable/selectpage").data("primaryKey", "title").data("field", "title").data("orderBy", "id desc");
|
||||
$("input[name='username']", form).addClass("selectpage").data("source", "auth/admin/index").data("primaryKey", "username").data("field", "username").data("orderBy", "id desc");
|
||||
Form.events.cxselect(form);
|
||||
Form.events.selectpage(form);
|
||||
});
|
||||
|
||||
//在表格内容渲染完成后回调的事件
|
||||
table.on('post-body.bs.table', function (e, settings, json, xhr) {
|
||||
console.log(e, settings, json, xhr);
|
||||
});
|
||||
|
||||
//当表格数据加载完成时
|
||||
table.on('load-success.bs.table', function (e, data) {
|
||||
//这里可以获取从服务端获取的JSON数据
|
||||
console.log(data);
|
||||
//这里我们手动设置底部的值
|
||||
$("#money").text(data.extend.money);
|
||||
$("#price").text(data.extend.price);
|
||||
});
|
||||
|
||||
// 初始化表格
|
||||
// 这里使用的是Bootstrap-table插件渲染表格
|
||||
// 相关文档:https://doc.fastadmin.net/doc/table.html
|
||||
table.bootstrapTable({
|
||||
//表格参数可以参考:https://doc.fastadmin.net/doc/190.html
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
columns: [
|
||||
[
|
||||
//更多列参数可以参考:https://doc.fastadmin.net/doc/191.html
|
||||
//该列为复选框字段,如果后台的返回state值将会默认选中
|
||||
{field: 'state', checkbox: true,},
|
||||
//sortable为是否排序,operate为搜索时的操作符,visible表示是否可见
|
||||
{field: 'id', title: 'ID', sortable: true, operate: false},
|
||||
//直接响应搜索
|
||||
{field: 'username', title: __('管理员'), formatter: Table.api.formatter.search},
|
||||
//模糊搜索
|
||||
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '模糊搜索,*表示任意字符', width: '280px'},
|
||||
//通过Ajax渲染searchList,也可以使用JSON数据
|
||||
{
|
||||
field: 'url',
|
||||
title: __('Url'),
|
||||
align: 'left',
|
||||
searchList: $.getJSON('example/bootstraptable/searchlist?search=a&field=row[user_id]'),
|
||||
formatter: Controller.api.formatter.url,
|
||||
addClass: "selectpicker"
|
||||
},
|
||||
//点击IP时同时执行搜索此IP
|
||||
{
|
||||
field: 'ip',
|
||||
title: __('IP'),
|
||||
events: Controller.api.events.ip,
|
||||
formatter: Controller.api.formatter.ip
|
||||
},
|
||||
//自定义栏位,custom是不存在的字段
|
||||
{field: 'custom', title: __('切换'), operate: false, formatter: Controller.api.formatter.custom},
|
||||
{
|
||||
field: 'admin_id', title: __('联动搜索'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
//启用时间段搜索
|
||||
{
|
||||
field: 'createtime',
|
||||
title: __('Update time'),
|
||||
sortable: true,
|
||||
formatter: Table.api.formatter.datetime,
|
||||
operate: 'RANGE',
|
||||
addclass: 'datetimerange'
|
||||
},
|
||||
//操作栏,默认有编辑、删除或排序按钮,可自定义配置buttons来扩展按钮
|
||||
{
|
||||
field: 'operate',
|
||||
width: "150px",
|
||||
title: __('Operate'),
|
||||
table: table,
|
||||
events: Table.api.events.operate,
|
||||
buttons: [
|
||||
{
|
||||
name: 'click',
|
||||
title: __('点击执行事件'),
|
||||
classname: 'btn btn-xs btn-info btn-click',
|
||||
icon: 'fa fa-leaf',
|
||||
// dropdown: '更多',//如果包含dropdown,将会以下拉列表的形式展示
|
||||
click: function (data) {
|
||||
Layer.alert("点击按钮执行的事件");
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'detail',
|
||||
title: __('弹出窗口打开'),
|
||||
classname: 'btn btn-xs btn-primary btn-dialog',
|
||||
icon: 'fa fa-list',
|
||||
url: 'example/bootstraptable/detail',
|
||||
callback: function (data) {
|
||||
Layer.alert("接收到回传数据:" + JSON.stringify(data), {title: "回传数据"});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ajax',
|
||||
title: __('发送Ajax'),
|
||||
classname: 'btn btn-xs btn-success btn-magic btn-ajax',
|
||||
icon: 'fa fa-magic',
|
||||
confirm: '确认发送Ajax请求?',
|
||||
url: 'example/bootstraptable/detail',
|
||||
success: function (data, ret) {
|
||||
Layer.alert(ret.msg + ",返回数据:" + JSON.stringify(data));
|
||||
//如果需要阻止成功提示,则必须使用return false;
|
||||
//return false;
|
||||
},
|
||||
error: function (data, ret) {
|
||||
console.log(data, ret);
|
||||
Layer.alert(ret.msg);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'addtabs',
|
||||
title: __('新选项卡中打开'),
|
||||
classname: 'btn btn-xs btn-warning btn-addtabs',
|
||||
icon: 'fa fa-folder-o',
|
||||
url: 'example/bootstraptable/detail'
|
||||
}
|
||||
],
|
||||
formatter: Table.api.formatter.operate
|
||||
},
|
||||
],
|
||||
],
|
||||
//更多配置参数可参考:https://doc.fastadmin.net/doc/190.html
|
||||
//亦可以参考require-table.js中defaults的配置
|
||||
//快捷搜索,这里可在控制器定义快捷搜索的字段
|
||||
search: true,
|
||||
//启用普通表单搜索
|
||||
commonSearch: true,
|
||||
//显示导出按钮
|
||||
showExport: true,
|
||||
//启用跨页选择
|
||||
maintainSelected: true,
|
||||
//启用固定列
|
||||
fixedColumns: true,
|
||||
//固定左侧列数
|
||||
fixedNumber: 3,
|
||||
//固定右侧列数
|
||||
fixedRightNumber: 1,
|
||||
//导出类型
|
||||
exportDataType: "all", //共有basic, all, selected三种值 basic当前页 all全部 selected仅选中
|
||||
//导出下拉列表选项
|
||||
exportTypes: ['json', 'xml', 'csv', 'txt', 'doc', 'excel'],
|
||||
//可以控制是否默认显示搜索单表,false则隐藏,默认为false
|
||||
searchFormVisible: true,
|
||||
queryParams: function (params) {
|
||||
//这里可以追加搜索条件
|
||||
var filter = JSON.parse(params.filter);
|
||||
var op = JSON.parse(params.op);
|
||||
//这里可以动态赋值,比如从URL中获取admin_id的值,filter.admin_id=Fast.api.query('admin_id');
|
||||
filter.admin_id = 1;
|
||||
op.admin_id = "=";
|
||||
params.filter = JSON.stringify(filter);
|
||||
params.op = JSON.stringify(op);
|
||||
return params;
|
||||
},
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
|
||||
// 监听下拉列表改变的事件
|
||||
$(document).on('change', 'select[name=admin]', function () {
|
||||
$("input[name='admin_id']").val($(this).val());
|
||||
});
|
||||
|
||||
//自定义Tab筛选条件
|
||||
$('.panel-heading .nav-custom-condition a[data-toggle="tab"]', table.closest(".panel-intro")).on('shown.bs.tab', function (e) {
|
||||
var value = $(this).data("value");
|
||||
var options = table.bootstrapTable('getOptions');
|
||||
var queryParams = options.queryParams;
|
||||
options.pageNumber = 1;
|
||||
options.queryParams = function (params) {
|
||||
//这一行必须要存在,否则在点击下一页时会丢失搜索栏数据
|
||||
params = queryParams(params);
|
||||
|
||||
//如果希望追加搜索条件,可使用
|
||||
var filter = params.filter ? JSON.parse(params.filter) : {};
|
||||
var op = params.op ? JSON.parse(params.op) : {};
|
||||
if (value) {
|
||||
//这里可以自定义多个筛选条件
|
||||
filter.admin_id = value;
|
||||
op.admin_id = '=';
|
||||
} else {
|
||||
//选全部时要移除相应的条件
|
||||
delete filter.admin_id;
|
||||
delete op.admin_id;
|
||||
}
|
||||
|
||||
params.filter = JSON.stringify(filter);
|
||||
params.op = JSON.stringify(op);
|
||||
|
||||
//如果希望忽略搜索栏搜索条件,可使用
|
||||
//params.filter = JSON.stringify(value?{admin_id: value}:{});
|
||||
//params.op = JSON.stringify(value?{admin_id: '='}:{});
|
||||
return params;
|
||||
};
|
||||
|
||||
table.trigger("uncheckbox");
|
||||
table.bootstrapTable('refresh', {pageNumber: 1});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 指定搜索条件
|
||||
$(document).on("click", ".btn-singlesearch", function () {
|
||||
var options = table.bootstrapTable('getOptions');
|
||||
var queryParams = options.queryParams;
|
||||
options.pageNumber = 1;
|
||||
options.queryParams = function (params) {
|
||||
//这一行必须要存在,否则在点击下一页时会丢失搜索栏数据
|
||||
params = queryParams(params);
|
||||
|
||||
//如果希望追加搜索条件,可使用
|
||||
var filter = params.filter ? JSON.parse(params.filter) : {};
|
||||
var op = params.op ? JSON.parse(params.op) : {};
|
||||
filter.url = 'login';
|
||||
op.url = 'like';
|
||||
|
||||
params.filter = JSON.stringify(filter);
|
||||
params.op = JSON.stringify(op);
|
||||
|
||||
//如果希望忽略搜索栏搜索条件,可使用
|
||||
//params.filter = JSON.stringify({url: 'login'});
|
||||
//params.op = JSON.stringify({url: 'like'});
|
||||
return params;
|
||||
};
|
||||
table.bootstrapTable('refresh', {});
|
||||
Toastr.info("当前执行的是自定义搜索,搜索URL中包含login的数据");
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取选中项
|
||||
$(document).on("click", ".btn-selected", function () {
|
||||
Layer.alert(JSON.stringify(Table.api.selecteddata(table)));
|
||||
});
|
||||
|
||||
// 启动和暂停按钮
|
||||
$(document).on("click", ".btn-start,.btn-pause", function () {
|
||||
//在table外不可以使用添加.btn-change的方法
|
||||
//只能自己调用Table.api.multi实现
|
||||
//如果操作全部则ids可以置为空
|
||||
var ids = Table.api.selectedids(table);
|
||||
Table.api.multi("changestatus", ids.join(","), table, this);
|
||||
});
|
||||
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
edit: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
detail: function () {
|
||||
$(document).on('click', '.btn-callback', function () {
|
||||
Fast.api.close($("input[name=callback]").val());
|
||||
});
|
||||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
formatter: {//渲染的方法
|
||||
url: function (value, row, index) {
|
||||
return '<div class="input-group input-group-sm" style="width:250px;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
|
||||
},
|
||||
ip: function (value, row, index) {
|
||||
return '<a class="btn btn-xs btn-ip bg-success"><i class="fa fa-map-marker"></i> ' + value + '</a>';
|
||||
},
|
||||
custom: function (value, row, index) {
|
||||
//添加上btn-change可以自定义请求的URL进行数据处理
|
||||
return '<a class="btn-change text-success" data-url="example/bootstraptable/change" data-confirm="确认切换状态?" data-id="' + row.id + '"><i class="fa ' + (row.title == '' ? 'fa-toggle-on fa-flip-horizontal text-gray' : 'fa-toggle-on') + ' fa-2x"></i></a>';
|
||||
},
|
||||
},
|
||||
events: {//绑定事件的方法
|
||||
ip: {
|
||||
//格式为:方法名+空格+DOM元素
|
||||
'click .btn-ip': function (e, value, row, index) {
|
||||
e.stopPropagation();
|
||||
var container = $("#table").data("bootstrap.table").$container;
|
||||
var options = $("#table").bootstrapTable('getOptions');
|
||||
//这里我们手动将数据填充到表单然后提交
|
||||
$("form.form-commonsearch [name='ip']", container).val(value);
|
||||
$("form.form-commonsearch", container).trigger('submit');
|
||||
Toastr.info("执行了自定义搜索操作");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/colorbadge/index',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: 'example/colorbadge/del',
|
||||
multi_url: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
// 初始化表格
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true, },
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'title', title: __('Title')},
|
||||
{field: 'ip', title: __('IP')},
|
||||
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
]
|
||||
],
|
||||
onLoadSuccess: function (data) {
|
||||
// 在表格第次加载成功后,刷新左侧菜单栏彩色小角标,支持一次渲染多个
|
||||
// 如果需要在进入后台即显示左侧的彩色小角标,请使用服务端渲染方式,详情修改application/admin/controller/Index.php
|
||||
Backend.api.sidebar({
|
||||
'example/colorbadge': data.total
|
||||
});
|
||||
Toastr.info("左侧角标已经刷新成功");
|
||||
}
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
},
|
||||
add: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
edit: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/controllerjump/index',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: 'example/controllerjump/del',
|
||||
multi_url: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
// 初始化表格
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true, },
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'admin_id', title: __('Admin_id')},
|
||||
{field: 'title', title: __('Title')},
|
||||
{field: 'ip', title: __('IP'),formatter: Controller.api.formatter.ip},
|
||||
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
},
|
||||
add: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
edit: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
api: {
|
||||
formatter: {
|
||||
ip: function (value, row, index) {
|
||||
//这里手动构造URL
|
||||
url = "example/bootstraptable?" + this.field + "=" + value;
|
||||
|
||||
//方式一,直接返回class带有addtabsit的链接,这可以方便自定义显示内容
|
||||
//return '<a href="' + url + '" class="label label-success addtabsit" title="' + __("Search %s", value) + '">' + __('Search %s', value) + '</a>';
|
||||
|
||||
//方式二,直接调用Table.api.formatter.addtabs
|
||||
this.url = url;
|
||||
return Table.api.formatter.addtabs.call(this, value, row, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
Template.helper("Fast", Fast);
|
||||
|
||||
//因为日期选择框不会触发change事件,导致无法刷新textarea,所以加上判断
|
||||
$(document).on("dp.change", "#second-form .datetimepicker", function () {
|
||||
$(this).parent().prev().find("input").trigger("change");
|
||||
});
|
||||
$(document).on("fa.event.appendfieldlist", "#first-table .btn-append", function (e, obj) {
|
||||
|
||||
});
|
||||
$(document).on("fa.event.appendfieldlist", "#second-table .btn-append", function (e, obj) {
|
||||
//绑定动态下拉组件
|
||||
Form.events.selectpage(obj);
|
||||
//绑定日期组件
|
||||
Form.events.datetimepicker(obj);
|
||||
//绑定上传组件
|
||||
Form.events.faupload(obj);
|
||||
|
||||
//上传成功回调事件,变更按钮的背景
|
||||
$(".upload-image", obj).data("upload-success", function (data) {
|
||||
$(this).css("background-image", "url('" + Fast.api.cdnurl(data.url) + "')");
|
||||
})
|
||||
});
|
||||
Form.api.bindevent($("form[role=form]"), function (data, ret) {
|
||||
Layer.alert(data.data);
|
||||
});
|
||||
},
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
var Controller = {
|
||||
index: function () {
|
||||
//
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/customsearch/index',
|
||||
add_url: 'example/customsearch/add',
|
||||
edit_url: '',
|
||||
del_url: 'example/customsearch/del',
|
||||
multi_url: 'example/customsearch/multi',
|
||||
table: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
// 初始化表格
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
pk: 'id',
|
||||
sortName: 'id',
|
||||
searchFormVisible: true,
|
||||
searchFormTemplate: 'customformtpl',
|
||||
columns: [
|
||||
[
|
||||
{checkbox: true},
|
||||
{field: 'id', title: 'ID', operate: false},
|
||||
{field: 'admin_id', title: __('Admin_id'), visible: false, operate: false},
|
||||
{field: 'username', title: __('Username'), formatter: Table.api.formatter.search},
|
||||
{field: 'title', title: __('Title')},
|
||||
{field: 'url', title: __('Url'), align: 'left'},
|
||||
{field: 'ip', title: __('IP')},
|
||||
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{
|
||||
field: 'operate',
|
||||
title: __('Operate'),
|
||||
table: table,
|
||||
events: Table.api.events.operate,
|
||||
formatter: Table.api.formatter.operate
|
||||
}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
edit: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
}
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
$("#cxselect-example .col-xs-12").each(function () {
|
||||
$("textarea", this).val($(this).prev().prev().html().replace(/[ ]{2}/g, ''));
|
||||
});
|
||||
|
||||
//这里需要手动为Form绑定上元素事件
|
||||
Form.api.bindevent($("form#cxselectform"));
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,206 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'echarts', 'echarts-theme'], function ($, undefined, Backend, Table, Form, Template, Echarts) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
//这句话在多选项卡统计表时必须存在,否则会导致影响的图表宽度不正确
|
||||
$(document).on("click", ".charts-custom a[data-toggle=\"tab\"]", function () {
|
||||
var that = this;
|
||||
setTimeout(function () {
|
||||
var id = $(that).attr("href");
|
||||
var chart = Echarts.getInstanceByDom($(id)[0]);
|
||||
chart.resize();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
var lineChart = Echarts.init(document.getElementById('line-chart'), 'walden');
|
||||
|
||||
// 指定图表的配置项和数据
|
||||
var option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [{
|
||||
data: [49, 92, 61, 134, 90, 130, 120],
|
||||
type: 'line'
|
||||
}]
|
||||
};
|
||||
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
lineChart.setOption(option);
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
var areaChart = Echarts.init(document.getElementById('area-chart'), 'walden');
|
||||
|
||||
// 指定图表的配置项和数据
|
||||
var option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [{
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
type: 'line',
|
||||
areaStyle: {}
|
||||
}]
|
||||
};
|
||||
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
areaChart.setOption(option);
|
||||
|
||||
var pieChart = Echarts.init(document.getElementById('pie-chart'), 'walden');
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 10,
|
||||
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
fontSize: '30',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
normal: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{value: 335, name: '直接访问'},
|
||||
{value: 310, name: '邮件营销'},
|
||||
{value: 234, name: '联盟广告'},
|
||||
{value: 135, name: '视频广告'},
|
||||
{value: 1548, name: '搜索引擎'}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
pieChart.setOption(option);
|
||||
|
||||
var barChart = Echarts.init(document.getElementById('bar-chart'), 'walden');
|
||||
option = {
|
||||
legend: {},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: [
|
||||
['产品销售', '2015', '2016', '2017'],
|
||||
['风扇', 43.3, 85.8, 93.7],
|
||||
['电视机', 83.1, 73.4, 55.1],
|
||||
['空调', 86.4, 65.2, 82.5],
|
||||
['冰箱', 72.4, 53.9, 39.1]
|
||||
]
|
||||
},
|
||||
xAxis: {type: 'category'},
|
||||
yAxis: {},
|
||||
// Declare several bar series, each will be mapped
|
||||
// to a column of dataset.source by default.
|
||||
series: [
|
||||
{type: 'bar'},
|
||||
{type: 'bar'},
|
||||
{type: 'bar'}
|
||||
]
|
||||
};
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
barChart.setOption(option);
|
||||
|
||||
|
||||
var barChart = Echarts.init(document.getElementById('simplebar-chart'));
|
||||
option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: [120, 200, 150, 80, 70, 110, 130],
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: "#fff",
|
||||
opacity: 0.6
|
||||
}
|
||||
}]
|
||||
};
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
barChart.setOption(option);
|
||||
|
||||
var barChart = Echarts.init(document.getElementById('smoothline-chart'));
|
||||
option = {
|
||||
textStyle: {
|
||||
color: "#fff"
|
||||
},
|
||||
color: ['#fff'],
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
opacity: 0.4
|
||||
}
|
||||
|
||||
}]
|
||||
};
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
barChart.setOption(option);
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init();
|
||||
|
||||
//绑定事件
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var panel = $($(this).attr("href"));
|
||||
if (panel.length > 0) {
|
||||
Controller.table[panel.attr("id")].call(this);
|
||||
$(this).on('click', function (e) {
|
||||
$($(this).attr("href")).find(".btn-refresh").trigger("click");
|
||||
});
|
||||
}
|
||||
//移除绑定的事件
|
||||
$(this).unbind('shown.bs.tab');
|
||||
});
|
||||
|
||||
//必须默认触发shown.bs.tab事件
|
||||
$('ul.nav-tabs li.active a[data-toggle="tab"]').trigger("shown.bs.tab");
|
||||
},
|
||||
table: {
|
||||
first: function () {
|
||||
// 表格1
|
||||
var table1 = $("#table1");
|
||||
table1.bootstrapTable({
|
||||
url: 'example/multitable/table1',
|
||||
toolbar: '#toolbar1',
|
||||
sortName: 'id',
|
||||
search: false,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true, },
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'filename', title: __('Name')},
|
||||
{field: 'imagewidth', title: __('Imagewidth')},
|
||||
{field: 'imageheight', title: __('Imageheight')},
|
||||
{field: 'mimetype', title: __('Mimetype')},
|
||||
{field: 'operate', title: __('Operate'), table: table1, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格1绑定事件
|
||||
Table.api.bindevent(table1);
|
||||
},
|
||||
second: function () {
|
||||
// 表格2
|
||||
var table2 = $("#table2");
|
||||
table2.bootstrapTable({
|
||||
url: 'example/multitable/table2',
|
||||
extend: {
|
||||
index_url: '',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: '',
|
||||
multi_url: '',
|
||||
table: '',
|
||||
},
|
||||
toolbar: '#toolbar2',
|
||||
sortName: 'id',
|
||||
search: false,
|
||||
columns: [
|
||||
[
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'title', title: __('Title')},
|
||||
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
|
||||
{field: 'ip', title: __('ip')},
|
||||
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格2绑定事件
|
||||
Table.api.bindevent(table2);
|
||||
}
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
edit: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/relationmodel/index',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: 'example/relationmodel/del',
|
||||
multi_url: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
// 初始化表格
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true, },
|
||||
{field: 'id', title: 'ID', operate: '='},
|
||||
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '关键字,模糊搜索'},
|
||||
{field: 'admin.avatar', title: __('Avatar'), operate: false, formatter: Table.api.formatter.image},
|
||||
{field: 'admin.username', title: __('Username'), operate: 'FIND_IN_SET'},
|
||||
{field: 'admin.nickname', title: __('Nickname'), operate: 'LIKE %...%', placeholder: '关键字,模糊搜索'},
|
||||
{field: 'ip', title: __('IP'), operate: '='},
|
||||
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{field: 'admin.createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
]
|
||||
],
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
},
|
||||
add: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
edit: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init();
|
||||
this.table.first();
|
||||
this.table.second();
|
||||
},
|
||||
table: {
|
||||
first: function () {
|
||||
// 表格1
|
||||
var table1 = $("#table1");
|
||||
table1.bootstrapTable({
|
||||
url: 'example/tablelink/table1',
|
||||
toolbar: '#toolbar1',
|
||||
sortName: 'id',
|
||||
search: false,
|
||||
columns: [
|
||||
[
|
||||
// {field: 'state', checkbox: true,},
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'username', title: __('Nickname')},
|
||||
{
|
||||
field: 'operate', title: __('Operate'), table: table1, events: Table.api.events.operate, buttons: [
|
||||
{
|
||||
name: 'log',
|
||||
title: '日志列表',
|
||||
text: '日志列表',
|
||||
icon: 'fa fa-list',
|
||||
classname: 'btn btn-primary btn-xs btn-click',
|
||||
click: function (e, data) {
|
||||
$("#myTabContent2 .form-commonsearch input[name='username']").val(data.username);
|
||||
$("#myTabContent2 .btn-refresh").trigger("click");
|
||||
}
|
||||
}
|
||||
], formatter: Table.api.formatter.operate
|
||||
}
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格1绑定事件
|
||||
Table.api.bindevent(table1);
|
||||
},
|
||||
second: function () {
|
||||
// 表格2
|
||||
var table2 = $("#table2");
|
||||
table2.bootstrapTable({
|
||||
url: 'example/tablelink/table2',
|
||||
extend: {
|
||||
index_url: '',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: '',
|
||||
multi_url: '',
|
||||
table: '',
|
||||
},
|
||||
toolbar: '#toolbar2',
|
||||
sortName: 'id',
|
||||
search: false,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true,},
|
||||
{field: 'id', title: 'ID'},
|
||||
{field: 'username', title: __('Nickname')},
|
||||
{field: 'title', title: __('Title')},
|
||||
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
|
||||
{field: 'ip', title: __('ip')},
|
||||
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
]
|
||||
]
|
||||
});
|
||||
|
||||
// 为表格2绑定事件
|
||||
Table.api.bindevent(table2);
|
||||
}
|
||||
},
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -0,0 +1,115 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) {
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
// 初始化表格参数配置
|
||||
Table.api.init({
|
||||
extend: {
|
||||
index_url: 'example/tabletemplate/index',
|
||||
add_url: '',
|
||||
edit_url: '',
|
||||
del_url: 'example/tabletemplate/del',
|
||||
multi_url: '',
|
||||
}
|
||||
});
|
||||
|
||||
var table = $("#table");
|
||||
|
||||
Template.helper("Moment", Moment);
|
||||
|
||||
// 初始化表格
|
||||
table.bootstrapTable({
|
||||
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||
templateView: true,
|
||||
columns: [
|
||||
[
|
||||
{field: 'state', checkbox: true, },
|
||||
{field: 'id', title: 'ID', operate: false},
|
||||
//直接响应搜索
|
||||
{field: 'username', title: __('Username'), formatter: Table.api.formatter.search},
|
||||
//模糊搜索
|
||||
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '模糊搜索,*表示任意字符', style: 'width:200px'},
|
||||
//通过Ajax渲染searchList
|
||||
{field: 'url', title: __('Url'), align: 'left', formatter: Controller.api.formatter.url},
|
||||
//点击IP时同时执行搜索此IP,同时普通搜索使用下拉列表的形式
|
||||
{field: 'ip', title: __('IP'), searchList: ['127.0.0.1', '127.0.0.2'], events: Controller.api.events.ip, formatter: Controller.api.formatter.ip},
|
||||
//browser是一个不存在的字段
|
||||
//通过formatter来渲染数据,同时为它添加上事件
|
||||
{field: 'browser', title: __('Browser'), operate: false, events: Controller.api.events.browser, formatter: Controller.api.formatter.browser},
|
||||
//启用时间段搜索
|
||||
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
],
|
||||
],
|
||||
//禁用默认搜索
|
||||
search: false,
|
||||
//启用普通表单搜索
|
||||
commonSearch: false,
|
||||
//可以控制是否默认显示搜索单表,false则隐藏,默认为false
|
||||
searchFormVisible: false,
|
||||
//分页大小
|
||||
pageSize: 12
|
||||
});
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
|
||||
//指定搜索条件
|
||||
$(document).on("click", ".btn-toggle-view", function () {
|
||||
var options = table.bootstrapTable('getOptions');
|
||||
table.bootstrapTable('refreshOptions', {templateView: !options.templateView});
|
||||
});
|
||||
|
||||
//点击详情
|
||||
$(document).on("click", ".btn-detail[data-id]", function () {
|
||||
Backend.api.open('example/bootstraptable/detail/ids/' + $(this).data('id'), __('Detail'));
|
||||
});
|
||||
|
||||
//获取选中项
|
||||
$(document).on("click", ".btn-selected", function () {
|
||||
//在templateView的模式下不能调用table.bootstrapTable('getSelections')来获取选中的ID,只能通过下面的Table.api.selectedids来获取
|
||||
Layer.alert(JSON.stringify(Table.api.selectedids(table)));
|
||||
});
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
edit: function () {
|
||||
Controller.api.bindevent();
|
||||
},
|
||||
api: {
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
formatter: {
|
||||
url: function (value, row, index) {
|
||||
return '<div class="input-group input-group-sm" style="width:250px;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
|
||||
},
|
||||
ip: function (value, row, index) {
|
||||
return '<a class="btn btn-xs btn-ip bg-success"><i class="fa fa-map-marker"></i> ' + value + '</a>';
|
||||
},
|
||||
browser: function (value, row, index) {
|
||||
//这里我们直接使用row的数据
|
||||
return '<a class="btn btn-xs btn-browser">' + row.useragent.split(" ")[0] + '</a>';
|
||||
}
|
||||
},
|
||||
events: {
|
||||
ip: {
|
||||
'click .btn-ip': function (e, value, row, index) {
|
||||
var options = $("#table").bootstrapTable('getOptions');
|
||||
//这里我们手动将数据填充到表单然后提交
|
||||
$("#commonSearchContent_" + options.idTable + " form [name='ip']").val(value);
|
||||
$("#commonSearchContent_" + options.idTable + " form").trigger('submit');
|
||||
Toastr.info("执行了自定义搜索操作");
|
||||
}
|
||||
},
|
||||
browser: {
|
||||
'click .btn-browser': function (e, value, row, index) {
|
||||
Layer.alert("该行数据为: <code>" + JSON.stringify(row) + "</code>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
@@ -35,6 +35,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
{field: 'num6', title: __('Num6'), formatter: Controller.api.formatter.numBall},
|
||||
{field: 'num7', title: __('Num7'), formatter: Controller.api.formatter.numBall},
|
||||
{field: 'openTime', title: __('OpenTime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
|
||||
{field: 'search_day', title: '每月日号', visible: false, searchable: true, operate: '=', style: 'width:80px;', extend: 'min="1" max="31" placeholder="1-31"'}
|
||||
]
|
||||
]
|
||||
});
|
||||
@@ -47,6 +48,55 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
$(document).off('click', '.btn-missingnum').on('click', '.btn-missingnum', function () {
|
||||
Controller.api.showMissingNumDialog();
|
||||
});
|
||||
|
||||
// 走势图按钮事件
|
||||
$(document).off('click', '.btn-trend').on('click', '.btn-trend', function () {
|
||||
Controller.api.showTrendDialog();
|
||||
});
|
||||
|
||||
// 冷热分析按钮事件
|
||||
$(document).off('click', '.btn-hotcold').on('click', '.btn-hotcold', function () {
|
||||
Controller.api.showHotColdDialog();
|
||||
});
|
||||
|
||||
// 波色分析按钮事件
|
||||
$(document).off('click', '.btn-colorwave').on('click', '.btn-colorwave', function () {
|
||||
Controller.api.showAnalysisDialog('colorWave');
|
||||
});
|
||||
// 生肖分析按钮事件
|
||||
$(document).off('click', '.btn-zodiac').on('click', '.btn-zodiac', function () {
|
||||
Controller.api.showAnalysisDialog('zodiac');
|
||||
});
|
||||
// 奇偶分析按钮事件
|
||||
$(document).off('click', '.btn-oddeven').on('click', '.btn-oddeven', function () {
|
||||
Controller.api.showAnalysisDialog('oddEven');
|
||||
});
|
||||
// 大小分析按钮事件
|
||||
$(document).off('click', '.btn-bigsmall').on('click', '.btn-bigsmall', function () {
|
||||
Controller.api.showAnalysisDialog('bigSmall');
|
||||
});
|
||||
// 和值分析按钮事件
|
||||
$(document).off('click', '.btn-sumchart').on('click', '.btn-sumchart', function () {
|
||||
Controller.api.showSumDialog();
|
||||
});
|
||||
// 连号分析按钮事件
|
||||
$(document).off('click', '.btn-consecutive').on('click', '.btn-consecutive', function () {
|
||||
Controller.api.showConsecutiveDialog();
|
||||
});
|
||||
// 尾数分析按钮事件
|
||||
$(document).off('click', '.btn-tailnums').on('click', '.btn-tailnums', function () {
|
||||
Controller.api.showAnalysisDialog('tailNumbers');
|
||||
});
|
||||
|
||||
// 特码冷热按钮事件
|
||||
$(document).off('click', '.btn-specialhotcold').on('click', '.btn-specialhotcold', function () {
|
||||
Controller.api.showSpecialHotColdDialog();
|
||||
});
|
||||
|
||||
// 综合统计面板按钮事件
|
||||
$(document).off('click', '.btn-dashboard').on('click', '.btn-dashboard', function () {
|
||||
Controller.api.showDashboard();
|
||||
});
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
@@ -140,6 +190,282 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示冷热分析弹窗
|
||||
*/
|
||||
showHotColdDialog: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
|
||||
' <label style="margin-right:15px;">' + __('Query Type') + ':</label>' +
|
||||
' <label class="radio-inline" style="margin-right:15px;">' +
|
||||
' <input type="radio" name="hc-type" value="all" checked> ' + __('All Numbers') +
|
||||
' </label>' +
|
||||
' <label class="radio-inline">' +
|
||||
' <input type="radio" name="hc-type" value="special"> ' + __('Special Only') +
|
||||
' </label>' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="hc-periods" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-hc-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="hc-result" style="margin-top:15px;overflow-x:auto;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: __('Hot/Cold Analysis'),
|
||||
area: ['700px', '600px'],
|
||||
content: html,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-hc-query', layero).on('click', function () {
|
||||
var periods = parseInt($('#hc-periods', layero).val()) || 30;
|
||||
var type = $('input[name="hc-type"]:checked', layero).val();
|
||||
Controller.api.queryHotCold(periods, type, layero);
|
||||
});
|
||||
$('input[name="hc-type"]', layero).on('change', function () {
|
||||
var periods = parseInt($('#hc-periods', layero).val()) || 30;
|
||||
Controller.api.queryHotCold(periods, $(this).val(), layero);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
queryHotCold: function (periods, type, layero) {
|
||||
var $btn = $('#btn-hc-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#hc-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/hotColdNumbers',
|
||||
type: 'GET',
|
||||
data: {periods: periods, type: type},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderHotCold(ret.data, layero);
|
||||
} else {
|
||||
$('#hc-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#hc-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderHotCold: function (data, layero) {
|
||||
var getColor = function (num) {
|
||||
var color = data.all.find(function (item) { return item.num === num; });
|
||||
if (!color || !color.color) return '#95a5a6';
|
||||
if (color.color.indexOf('红') !== -1) return '#e74c3c';
|
||||
if (color.color.indexOf('蓝') !== -1) return '#3498db';
|
||||
if (color.color.indexOf('绿') !== -1) return '#2ecc71';
|
||||
return '#95a5a6';
|
||||
};
|
||||
|
||||
var getAnimal = function (num) {
|
||||
var item = data.all.find(function (item) { return item.num === num; });
|
||||
return item ? (item.animal || '') : '';
|
||||
};
|
||||
|
||||
var renderSection = function (title, items, icon) {
|
||||
var html = '<div style="margin-bottom:15px;"><h4 style="margin:0 0 8px 0;border-bottom:1px solid #eee;padding-bottom:5px;">' + icon + ' ' + title + '</h4>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:8px;">';
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
var color = getColor(item.num);
|
||||
var animal = getAnimal(item.num);
|
||||
html += '<div style="text-align:center;background:#f9f9f9;padding:8px;border-radius:6px;min-width:70px;">' +
|
||||
'<span style="display:inline-block;width:36px;height:36px;line-height:36px;text-align:center;border-radius:50%;color:#fff;background-color:' + color + ';font-weight:bold;">' + item.num + '</span>' +
|
||||
'<div style="margin-top:4px;font-size:10px;color:#666;">' + (animal ? animal + '<br>' : '') + '<b>' + item.count + '</b> (' + item.percent + '%)</div>' +
|
||||
'</div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
return html;
|
||||
};
|
||||
|
||||
var html = '<div style="padding:10px;">' +
|
||||
renderSection('热号 Top 10', data.hot, '<span style="color:#e74c3c;">🔥</span>') +
|
||||
renderSection('冷号 Top 10', data.cold, '<span style="color:#3498db;">❄</span>') +
|
||||
'</div>';
|
||||
|
||||
$('#hc-result', layero).html(html);
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示走势图弹窗
|
||||
*/
|
||||
showTrendDialog: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
|
||||
' <label style="margin-right:15px;">' + __('Query Type') + ':</label>' +
|
||||
' <label class="radio-inline" style="margin-right:15px;">' +
|
||||
' <input type="radio" name="trend-type" value="all" checked> ' + __('All Numbers') +
|
||||
' </label>' +
|
||||
' <label class="radio-inline">' +
|
||||
' <input type="radio" name="trend-type" value="special"> ' + __('Special Only') +
|
||||
' </label>' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="trend-periods" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-trend-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="trend-result" style="margin-top:15px;overflow-x:auto;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: __('Trend Chart'),
|
||||
area: ['90%', '80%'],
|
||||
content: html,
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-trend-query', layero).on('click', function () {
|
||||
var periods = parseInt($('#trend-periods', layero).val()) || 30;
|
||||
var type = $('input[name="trend-type"]:checked', layero).val();
|
||||
Controller.api.queryTrend(periods, type, layero);
|
||||
});
|
||||
$('input[name="trend-type"]', layero).on('change', function () {
|
||||
var periods = parseInt($('#trend-periods', layero).val()) || 30;
|
||||
Controller.api.queryTrend(periods, $(this).val(), layero);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询走势图
|
||||
*/
|
||||
queryTrend: function (periods, type, layero) {
|
||||
var $btn = $('#btn-trend-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#trend-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/trendData',
|
||||
type: 'GET',
|
||||
data: {periods: periods, type: type},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderTrend(ret.data, type, layero);
|
||||
} else {
|
||||
$('#trend-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#trend-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 渲染走势图(ECharts 折线图)
|
||||
*/
|
||||
renderTrend: function (data, type, layero) {
|
||||
var expects = data.expects;
|
||||
var rows = data.data;
|
||||
var colorMap = data.colorMap;
|
||||
|
||||
if (!expects || expects.length === 0) {
|
||||
$('#trend-result', layero).html('<div class="alert alert-info">' + __('No data available') + '</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
var getColor = function (num) {
|
||||
var color = colorMap[num];
|
||||
if (!color) return '#95a5a6';
|
||||
if (color.indexOf('红') !== -1) return '#e74c3c';
|
||||
if (color.indexOf('蓝') !== -1) return '#3498db';
|
||||
if (color.indexOf('绿') !== -1) return '#2ecc71';
|
||||
return '#95a5a6';
|
||||
};
|
||||
|
||||
$('#trend-result', layero).html('<div id="trend-chart" style="width:100%;height:500px;"></div>');
|
||||
|
||||
var chartDom = document.getElementById('trend-chart');
|
||||
var myChart = echarts.init(chartDom);
|
||||
|
||||
var series = [];
|
||||
if (type === 'special') {
|
||||
series = [{
|
||||
name: '特码',
|
||||
type: 'line',
|
||||
data: rows.map(function (r) { return r.num7; }),
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
lineStyle: { width: 2 },
|
||||
itemStyle: {
|
||||
color: function (params) {
|
||||
var num = params.data;
|
||||
return getColor(num);
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
fontSize: 11,
|
||||
color: '#333'
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
var numFields = [];
|
||||
for (var c = 1; c <= 7; c++) {
|
||||
numFields.push('num' + c);
|
||||
}
|
||||
var colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#e67e22'];
|
||||
for (var f = 0; f < numFields.length; f++) {
|
||||
(function (idx) {
|
||||
series.push({
|
||||
name: '第' + (idx + 1) + '码',
|
||||
type: 'line',
|
||||
data: rows.map(function (r) { return r[numFields[idx]]; }),
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: { width: 2 },
|
||||
itemStyle: { color: colors[idx] },
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
fontSize: 10,
|
||||
color: '#333'
|
||||
}
|
||||
});
|
||||
})(f);
|
||||
}
|
||||
}
|
||||
|
||||
var option = {
|
||||
title: { text: type === 'special' ? '特码走势' : '全部号码走势', left: 'center', textStyle: { fontSize: 14 } },
|
||||
tooltip: { trigger: 'axis', formatter: function (params) {
|
||||
var tip = '期号: ' + params[0].axisValueLabel + '<br/>';
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
tip += params[i].seriesName + ': <b>' + params[i].data + '</b><br/>';
|
||||
}
|
||||
return tip;
|
||||
}},
|
||||
legend: { bottom: 10, data: series.map(function (s) { return s.name; }) },
|
||||
grid: { left: 40, right: 20, bottom: 50, top: 40 },
|
||||
xAxis: { type: 'category', data: expects, axisLabel: { rotate: 45, fontSize: 10 } },
|
||||
yAxis: { type: 'value', min: 0, max: 50, splitLine: { show: true, lineStyle: { type: 'dashed' } } },
|
||||
dataZoom: [{ type: 'slider', bottom: 30, height: 20, start: 0, end: 100 }],
|
||||
series: series
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
window.addEventListener('resize', function () { myChart.resize(); });
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示遗漏号码分析弹窗
|
||||
*/
|
||||
@@ -264,8 +590,613 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
$('#missing-result', layero).html('').append(container);
|
||||
},
|
||||
|
||||
/**
|
||||
* 特码冷热列表(每期相对于前N期的冷热状态)
|
||||
*/
|
||||
showSpecialHotColdDialog: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
|
||||
' <label>向前期数:</label>' +
|
||||
' <input type="number" id="shc-lookback" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-shc-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="shc-result" style="margin-top:10px;max-height:500px;overflow-y:auto;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: '特码冷热列表',
|
||||
area: ['650px', '600px'],
|
||||
content: html,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-shc-query', layero).on('click', function () {
|
||||
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
|
||||
Controller.api.querySpecialHotCold(lookback, layero);
|
||||
});
|
||||
// 打开时自动查询
|
||||
var lookback = parseInt($('#shc-lookback', layero).val()) || 30;
|
||||
Controller.api.querySpecialHotCold(lookback, layero);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
querySpecialHotCold: function (lookback, layero) {
|
||||
var $btn = $('#btn-shc-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#shc-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/specialHotColdAction',
|
||||
type: 'GET',
|
||||
data: {lookback: lookback},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderSpecialHotCold(ret.data, lookback, layero);
|
||||
} else {
|
||||
$('#shc-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#shc-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderSpecialHotCold: function (data, lookback, layero) {
|
||||
var getColor = function (num) {
|
||||
return Controller.api.getColorByNum(num);
|
||||
};
|
||||
|
||||
var statusTag = function (status) {
|
||||
var map = {
|
||||
'hot': '<span style="color:#e74c3c;font-weight:bold;">🔥 热号</span>',
|
||||
'cold': '<span style="color:#3498db;font-weight:bold;">❄ 冷号</span>',
|
||||
'normal': '<span style="color:#f39c12;font-weight:bold;">➜ 温号</span>',
|
||||
'unknown': '<span style="color:#999;">数据不足</span>'
|
||||
};
|
||||
return map[status] || '';
|
||||
};
|
||||
|
||||
// 新接口返回 {list: [...], current: {hot: [], cold: [], warm: []}}
|
||||
var listData = data.list || data;
|
||||
var current = data.current || null;
|
||||
|
||||
if (!listData || listData.length === 0) {
|
||||
$('#shc-result', layero).html('<div class="alert alert-info">暂无数据</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '<div style="padding:0 5px;">';
|
||||
|
||||
// 当前冷热号汇总区域
|
||||
if (current && (current.hot.length > 0 || current.cold.length > 0)) {
|
||||
var renderNumBall = function (item) {
|
||||
var color = getColor(item.num);
|
||||
return '<span style="display:inline-block;width:30px;height:30px;line-height:30px;text-align:center;border-radius:50%;color:#fff;background-color:' + color + ';font-weight:bold;font-size:14px;" title="' + item.num + ' ×' + item.count + '">' + item.num + '</span>';
|
||||
};
|
||||
|
||||
html += '<div style="background:#fafafa;border:1px solid #e0e0e0;border-radius:6px;padding:12px;margin-bottom:12px;">';
|
||||
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;color:#333;"><i class="fa fa-bullseye"></i> 当前热号</div>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;">';
|
||||
for (var h = 0; h < current.hot.length; h++) {
|
||||
html += renderNumBall(current.hot[h]);
|
||||
}
|
||||
if (current.hot.length === 0) {
|
||||
html += '<span style="color:#999;font-size:12px;">暂无热号</span>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div style="height:8px;"></div>';
|
||||
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;color:#333;"><i class="fa fa-snowflake-o"></i> 当前冷号</div>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;">';
|
||||
for (var c = 0; c < current.cold.length; c++) {
|
||||
html += renderNumBall(current.cold[c]);
|
||||
}
|
||||
if (current.cold.length === 0) {
|
||||
html += '<span style="color:#999;font-size:12px;">暂无冷号</span>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
// 历史记录表格
|
||||
html += '<table class="table table-striped table-bordered table-hover" style="font-size:13px;">' +
|
||||
'<thead><tr>' +
|
||||
'<th style="text-align:center;width:120px;">期号</th>' +
|
||||
'<th style="text-align:center;width:60px;">特码</th>' +
|
||||
'<th style="text-align:center;width:80px;">冷热</th>' +
|
||||
'<th style="text-align:center;width:60px;">次数</th>' +
|
||||
'<th style="text-align:center;width:60px;">平均</th>' +
|
||||
'<th style="text-align:center;width:60px;">排名</th>' +
|
||||
'</tr></thead><tbody>';
|
||||
|
||||
for (var i = 0; i < listData.length; i++) {
|
||||
var item = listData[i];
|
||||
var rowClass = '';
|
||||
if (item.status === 'hot') rowClass = 'style="background:#fff5f5;"';
|
||||
else if (item.status === 'cold') rowClass = 'style="background:#f5f8ff;"';
|
||||
|
||||
html += '<tr ' + rowClass + '>' +
|
||||
'<td style="text-align:center;">' + item.expect + '</td>' +
|
||||
'<td style="text-align:center;">' +
|
||||
'<span style="display:inline-block;width:30px;height:30px;line-height:30px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(item.specialNum) + ';font-weight:bold;font-size:14px;">' + item.specialNum + '</span>' +
|
||||
'</td>' +
|
||||
'<td style="text-align:center;">' + statusTag(item.status) + '</td>' +
|
||||
'<td style="text-align:center;">' + item.count + '</td>' +
|
||||
'<td style="text-align:center;">' + item.avgCount + '</td>' +
|
||||
'<td style="text-align:center;">' + item.rank + '</td>' +
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
html += '</tbody></table></div>';
|
||||
$('#shc-result', layero).html(html);
|
||||
},
|
||||
|
||||
bindevent: function () {
|
||||
Form.api.bindevent($("form[role=form]"));
|
||||
},
|
||||
|
||||
/**
|
||||
* 通用分析弹窗(波色、生肖、奇偶、大小、尾数)
|
||||
*/
|
||||
showAnalysisDialog: function (type) {
|
||||
var titles = {
|
||||
colorWave: __('Color Wave'),
|
||||
zodiac: __('Zodiac'),
|
||||
oddEven: __('Odd/Even'),
|
||||
bigSmall: __('Big/Small'),
|
||||
tailNumbers: __('Tail Numbers')
|
||||
};
|
||||
var endpoints = {
|
||||
colorWave: 'history/colorWaveAnalysis',
|
||||
zodiac: 'history/zodiacAnalysis',
|
||||
oddEven: 'history/oddEvenAnalysis',
|
||||
bigSmall: 'history/bigSmallAnalysis',
|
||||
tailNumbers: 'history/tailNumbers'
|
||||
};
|
||||
var hasType = ['colorWave', 'zodiac', 'oddEven', 'bigSmall', 'tailNumbers'].indexOf(type) !== -1;
|
||||
|
||||
var html = '<div style="padding:20px;">';
|
||||
if (hasType) {
|
||||
html += '<div class="form-group" style="border-bottom:1px solid #eee;padding-bottom:10px;margin-bottom:10px;">' +
|
||||
' <label style="margin-right:15px;">' + __('Query Type') + ':</label>' +
|
||||
' <label class="radio-inline" style="margin-right:15px;">' +
|
||||
' <input type="radio" name="analysis-type-' + type + '" value="all" checked> ' + __('All Numbers') +
|
||||
' </label>' +
|
||||
' <label class="radio-inline">' +
|
||||
' <input type="radio" name="analysis-type-' + type + '" value="special"> ' + __('Special Only') +
|
||||
' </label>' +
|
||||
'</div>';
|
||||
}
|
||||
html += '<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="analysis-periods-' + type + '" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-analysis-' + type + '" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="analysis-result-' + type + '" style="margin-top:15px;overflow-x:auto;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: titles[type] || type,
|
||||
area: ['650px', '550px'],
|
||||
content: html,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-analysis-' + type, layero).on('click', function () {
|
||||
var periods = parseInt($('#analysis-periods-' + type, layero).val()) || 30;
|
||||
var tp = hasType ? $('input[name="analysis-type-' + type + '"]:checked', layero).val() : 'all';
|
||||
Controller.api.queryAnalysis(periods, tp, type, endpoints[type], layero);
|
||||
});
|
||||
if (hasType) {
|
||||
$('input[name="analysis-type-' + type + '"]', layero).on('change', function () {
|
||||
var periods = parseInt($('#analysis-periods-' + type, layero).val()) || 30;
|
||||
Controller.api.queryAnalysis(periods, $(this).val(), type, endpoints[type], layero);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
queryAnalysis: function (periods, type, analysisType, endpoint, layero) {
|
||||
var $btn = $('#btn-analysis-' + analysisType, layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#analysis-result-' + analysisType, layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: endpoint,
|
||||
type: 'GET',
|
||||
data: {periods: periods, type: type},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
var renderMap = {
|
||||
colorWave: 'renderColorWaveAnalysis',
|
||||
zodiac: 'renderZodiacAnalysis',
|
||||
oddEven: 'renderOddEvenAnalysis',
|
||||
bigSmall: 'renderBigSmallAnalysis',
|
||||
tailNumbers: 'renderTailNumbers'
|
||||
};
|
||||
var renderFn = renderMap[analysisType];
|
||||
if (renderFn && typeof Controller.api[renderFn] === 'function') {
|
||||
Controller.api[renderFn](ret.data, layero);
|
||||
} else {
|
||||
$('#analysis-result-' + analysisType, layero).html('<div class="alert alert-danger">渲染方法不存在: ' + renderFn + '</div>');
|
||||
}
|
||||
} else {
|
||||
$('#analysis-result-' + analysisType, layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#analysis-result-' + analysisType, layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderColorWaveAnalysis: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;justify-content:space-around;">';
|
||||
var items = [
|
||||
{label: '红波', value: data.red, pct: data.red_pct, color: '#e74c3c'},
|
||||
{label: '蓝波', value: data.blue, pct: data.blue_pct, color: '#3498db'},
|
||||
{label: '绿波', value: data.green, pct: data.green_pct, color: '#2ecc71'}
|
||||
];
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
html += '<div style="text-align:center;padding:20px;border-radius:8px;background:#f5f5f5;min-width:120px;">' +
|
||||
'<div style="width:60px;height:60px;line-height:60px;border-radius:50%;background-color:' + item.color + ';color:#fff;font-size:24px;font-weight:bold;margin:0 auto;">' + item.value + '</div>' +
|
||||
'<div style="margin-top:10px;font-size:14px;color:#333;">' + item.label + '</div>' +
|
||||
'<div style="font-size:12px;color:#999;">' + item.pct + '%</div>' +
|
||||
'</div>';
|
||||
}
|
||||
html += '</div><div style="margin-top:15px;color:#999;font-size:12px;text-align:center;">总计: ' + data.total + ' 个号码</div></div>';
|
||||
$('#analysis-result-colorWave', layero).html(html);
|
||||
},
|
||||
|
||||
renderZodiacAnalysis: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;flex-wrap:wrap;gap:8px;">';
|
||||
for (var i = 0; i < data.list.length; i++) {
|
||||
var item = data.list[i];
|
||||
html += '<div style="text-align:center;background:#f9f9f9;padding:10px 15px;border-radius:6px;min-width:90px;">' +
|
||||
'<div style="font-size:18px;font-weight:bold;color:#333;">' + item.animal + '</div>' +
|
||||
'<div style="font-size:12px;color:#666;">' + item.count + ' (' + item.percent + '%)</div>' +
|
||||
'</div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
$('#analysis-result-zodiac', layero).html(html);
|
||||
},
|
||||
|
||||
renderOddEvenAnalysis: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;justify-content:space-around;margin-bottom:15px;">';
|
||||
html += '<div style="text-align:center;padding:15px;border-radius:8px;background:#f5f5f5;min-width:140px;">' +
|
||||
'<div style="font-size:28px;font-weight:bold;color:#e74c3c;">' + data.odd + '</div>' +
|
||||
'<div style="font-size:14px;color:#333;">奇数</div>' +
|
||||
'<div style="font-size:12px;color:#999;">' + data.odd_pct + '%</div></div>';
|
||||
html += '<div style="text-align:center;padding:15px;border-radius:8px;background:#f5f5f5;min-width:140px;">' +
|
||||
'<div style="font-size:28px;font-weight:bold;color:#3498db;">' + data.even + '</div>' +
|
||||
'<div style="font-size:14px;color:#333;">偶数</div>' +
|
||||
'<div style="font-size:12px;color:#999;">' + data.even_pct + '%</div></div>';
|
||||
html += '</div></div>';
|
||||
$('#analysis-result-oddEven', layero).html(html);
|
||||
},
|
||||
|
||||
renderBigSmallAnalysis: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;justify-content:space-around;margin-bottom:15px;">';
|
||||
html += '<div style="text-align:center;padding:15px;border-radius:8px;background:#f5f5f5;min-width:140px;">' +
|
||||
'<div style="font-size:28px;font-weight:bold;color:#f39c12;">' + data.big + '</div>' +
|
||||
'<div style="font-size:14px;color:#333;">大数(25-49)</div>' +
|
||||
'<div style="font-size:12px;color:#999;">' + data.big_pct + '%</div></div>';
|
||||
html += '<div style="text-align:center;padding:15px;border-radius:8px;background:#f5f5f5;min-width:140px;">' +
|
||||
'<div style="font-size:28px;font-weight:bold;color:#2ecc71;">' + data.small + '</div>' +
|
||||
'<div style="font-size:14px;color:#333;">小数(1-24)</div>' +
|
||||
'<div style="font-size:12px;color:#999;">' + data.small_pct + '%</div></div>';
|
||||
html += '</div></div>';
|
||||
$('#analysis-result-bigSmall', layero).html(html);
|
||||
},
|
||||
|
||||
renderTailNumbers: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;flex-wrap:wrap;gap:8px;">';
|
||||
for (var i = 0; i < data.all.length; i++) {
|
||||
var item = data.all[i];
|
||||
html += '<div style="text-align:center;background:#f9f9f9;padding:10px 15px;border-radius:6px;min-width:70px;">' +
|
||||
'<div style="font-size:22px;font-weight:bold;color:#333;">' + item.tail + '</div>' +
|
||||
'<div style="font-size:12px;color:#666;">' + item.count + ' (' + item.percent + '%)</div></div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
$('#analysis-result-tailNumbers', layero).html(html);
|
||||
},
|
||||
|
||||
/**
|
||||
* 和值分析弹窗
|
||||
*/
|
||||
showSumDialog: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="sum-periods" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-sum-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="sum-result" style="margin-top:15px;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: __('Sum Chart'),
|
||||
area: ['750px', '400px'],
|
||||
content: html,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-sum-query', layero).on('click', function () {
|
||||
var periods = parseInt($('#sum-periods', layero).val()) || 30;
|
||||
Controller.api.querySum(periods, layero);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
querySum: function (periods, layero) {
|
||||
var $btn = $('#btn-sum-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#sum-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/sumAnalysis',
|
||||
type: 'GET',
|
||||
data: {periods: periods},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderSum(ret.data, layero);
|
||||
} else {
|
||||
$('#sum-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#sum-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderSum: function (data, layero) {
|
||||
var html = '<div style="padding:15px;"><div style="display:flex;justify-content:space-around;margin-bottom:15px;">';
|
||||
html += '<div style="text-align:center;padding:10px;"><div style="font-size:20px;font-weight:bold;color:#333;">' + data.avg + '</div><div style="font-size:12px;color:#999;">平均和值</div></div>';
|
||||
html += '<div style="text-align:center;padding:10px;"><div style="font-size:20px;font-weight:bold;color:#e74c3c;">' + data.max + '</div><div style="font-size:12px;color:#999;">最大和值</div></div>';
|
||||
html += '<div style="text-align:center;padding:10px;"><div style="font-size:20px;font-weight:bold;color:#3498db;">' + data.min + '</div><div style="font-size:12px;color:#999;">最小和值</div></div>';
|
||||
html += '</div><div id="sum-chart" style="width:100%;height:250px;"></div></div>';
|
||||
$('#sum-result', layero).html(html);
|
||||
|
||||
var chartDom = document.getElementById('sum-chart');
|
||||
if (chartDom && typeof echarts !== 'undefined') {
|
||||
var myChart = echarts.init(chartDom);
|
||||
myChart.setOption({
|
||||
xAxis: {type: 'category', data: data.expects, axisLabel: {rotate: 45, fontSize: 10}},
|
||||
yAxis: {type: 'value'},
|
||||
series: [{type: 'line', data: data.sums, smooth: true, itemStyle: {color: '#3498db'}, areaStyle: {color: 'rgba(52,152,219,0.1)'}}],
|
||||
grid: {left: 40, right: 20, bottom: 40, top: 20}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 连号分析弹窗
|
||||
*/
|
||||
showConsecutiveDialog: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="consecutive-periods" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-consecutive-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="consecutive-result" style="margin-top:15px;overflow-x:auto;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: __('Consecutive'),
|
||||
area: ['600px', '500px'],
|
||||
content: html,
|
||||
shadeClose: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-consecutive-query', layero).on('click', function () {
|
||||
var periods = parseInt($('#consecutive-periods', layero).val()) || 30;
|
||||
Controller.api.queryConsecutive(periods, layero);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
queryConsecutive: function (periods, layero) {
|
||||
var $btn = $('#btn-consecutive-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#consecutive-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/consecutiveNumbers',
|
||||
type: 'GET',
|
||||
data: {periods: periods},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderConsecutive(ret.data, layero);
|
||||
} else {
|
||||
$('#consecutive-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#consecutive-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderConsecutive: function (data, layero) {
|
||||
var html = '<div style="padding:15px;">';
|
||||
html += '<h4 style="margin:0 0 10px 0;border-bottom:1px solid #eee;padding-bottom:5px;">连号对</h4>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:15px;">';
|
||||
var pairs = data.pairs;
|
||||
if (pairs && Object.keys(pairs).length > 0) {
|
||||
for (var pair in pairs) {
|
||||
html += '<div style="background:#f5f5f5;padding:6px 12px;border-radius:4px;font-size:13px;">' + pair + ' <b>×' + pairs[pair] + '</b></div>';
|
||||
}
|
||||
} else {
|
||||
html += '<div style="color:#999;font-size:13px;">暂无连号数据</div>';
|
||||
}
|
||||
html += '</div><h4 style="margin:0 0 10px 0;border-bottom:1px solid #eee;padding-bottom:5px;">三连号</h4>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;">';
|
||||
var triples = data.triples;
|
||||
if (triples && Object.keys(triples).length > 0) {
|
||||
for (var triple in triples) {
|
||||
html += '<div style="background:#f5f5f5;padding:6px 12px;border-radius:4px;font-size:13px;">' + triple + ' <b>×' + triples[triple] + '</b></div>';
|
||||
}
|
||||
} else {
|
||||
html += '<div style="color:#999;font-size:13px;">暂无三连号数据</div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
$('#consecutive-result', layero).html(html);
|
||||
},
|
||||
|
||||
/**
|
||||
* 综合统计面板
|
||||
*/
|
||||
showDashboard: function () {
|
||||
var html = '<div style="padding:20px;">' +
|
||||
'<div class="form-group">' +
|
||||
' <label>' + __('Query Periods') + ':</label>' +
|
||||
' <input type="number" id="dash-periods" class="form-control" value="30" min="10" max="100" style="width:120px;display:inline-block;">' +
|
||||
' <button class="btn btn-primary" id="btn-dash-query" style="margin-left:10px;"><i class="fa fa-search"></i> ' + __('Query') + '</button>' +
|
||||
'</div>' +
|
||||
'<div id="dash-result" style="margin-top:15px;"></div>' +
|
||||
'</div>';
|
||||
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: __('Dashboard'),
|
||||
area: ['90%', '90%'],
|
||||
content: html,
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
success: function (layero, index) {
|
||||
$('#btn-dash-query', layero).on('click', function () {
|
||||
var periods = parseInt($('#dash-periods', layero).val()) || 30;
|
||||
Controller.api.queryDashboard(periods, layero);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
queryDashboard: function (periods, layero) {
|
||||
var $btn = $('#btn-dash-query', layero);
|
||||
$btn.prop('disabled', true);
|
||||
$('#dash-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> ' + __('Loading') + '</div>');
|
||||
$.ajax({
|
||||
url: 'history/dashboard',
|
||||
type: 'GET',
|
||||
data: {periods: periods},
|
||||
dataType: 'json',
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
Controller.api.renderDashboard(ret.data, layero);
|
||||
} else {
|
||||
$('#dash-result', layero).html('<div class="alert alert-danger">' + (ret.msg || __('Query failed')) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
$('#dash-result', layero).html('<div class="alert alert-danger">' + __('Query failed') + '</div>');
|
||||
},
|
||||
complete: function () {
|
||||
$btn.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderDashboard: function (data, layero) {
|
||||
var getColor = function (color) {
|
||||
if (!color) return '#95a5a6';
|
||||
if (color.indexOf('红') !== -1) return '#e74c3c';
|
||||
if (color.indexOf('蓝') !== -1) return '#3498db';
|
||||
if (color.indexOf('绿') !== -1) return '#2ecc71';
|
||||
return '#95a5a6';
|
||||
};
|
||||
|
||||
var hc = data.hotcold;
|
||||
var cw = data.colorwave;
|
||||
var zo = data.zodiac;
|
||||
var oe = data.oddeven;
|
||||
var bs = data.bigsmall;
|
||||
var sm = data.sum;
|
||||
var tn = data.tailnumbers;
|
||||
|
||||
var ballHtml = function (item) {
|
||||
return '<div style="text-align:center;display:inline-block;margin:3px;"><span style="display:inline-block;width:28px;height:28px;line-height:28px;text-align:center;border-radius:50%;color:#fff;background-color:' + getColor(item.color) + ';font-weight:bold;font-size:12px;">' + item.num + '</span><div style="font-size:9px;color:#666;">' + item.count + '</div></div>';
|
||||
};
|
||||
|
||||
var html = '<div style="padding:10px;max-height:75vh;overflow-y:auto;">';
|
||||
|
||||
// 冷热号码
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">🔥❄️ 冷热号码</h4>';
|
||||
html += '<div style="display:flex;"><div style="flex:1;padding:5px;"><b style="color:#e74c3c;">热号 Top5</b><div>';
|
||||
for (var i = 0; i < 5; i++) html += ballHtml(hc.hot[i]);
|
||||
html += '</div></div><div style="flex:1;padding:5px;"><b style="color:#3498db;">冷号 Top5</b><div>';
|
||||
for (var i = 0; i < 5; i++) html += ballHtml(hc.cold[i]);
|
||||
html += '</div></div></div>';
|
||||
|
||||
// 波色分析
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">🎨 波色比例</h4>';
|
||||
html += '<div style="display:flex;gap:15px;">';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#fce4ec;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#e74c3c;">' + cw.red + '</div><div>红波 ' + cw.red_pct + '%</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#e3f2fd;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#3498db;">' + cw.blue + '</div><div>蓝波 ' + cw.blue_pct + '%</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#e8f5e9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#2ecc71;">' + cw.green + '</div><div>绿波 ' + cw.green_pct + '%</div></div>';
|
||||
html += '</div>';
|
||||
|
||||
// 生肖分析
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">⭐ 生肖排名</h4>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:5px;">';
|
||||
for (var i = 0; i < Math.min(zo.list.length, 12); i++) {
|
||||
var z = zo.list[i];
|
||||
html += '<div style="text-align:center;background:#f5f5f5;padding:5px 10px;border-radius:4px;"><div style="font-size:14px;font-weight:bold;">' + z.animal + '</div><div style="font-size:10px;color:#666;">' + z.count + ' (' + z.percent + '%)</div></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
// 奇偶分析
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">⚖️ 奇偶分析</h4>';
|
||||
html += '<div style="display:flex;gap:15px;">';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#e74c3c;">' + oe.odd + ' (' + oe.odd_pct + '%)</div><div>奇数</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#3498db;">' + oe.even + ' (' + oe.even_pct + '%)</div><div>偶数</div></div>';
|
||||
html += '</div>';
|
||||
|
||||
// 大小分析
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">📊 大小分析</h4>';
|
||||
html += '<div style="display:flex;gap:15px;">';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#f39c12;">' + bs.big + ' (' + bs.big_pct + '%)</div><div>大数(25-49)</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#2ecc71;">' + bs.small + ' (' + bs.small_pct + '%)</div><div>小数(1-24)</div></div>';
|
||||
html += '</div>';
|
||||
|
||||
// 和值
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">📈 和值统计</h4>';
|
||||
html += '<div style="display:flex;gap:15px;">';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;">' + sm.avg + '</div><div>平均</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#e74c3c;">' + sm.max + '</div><div>最大</div></div>';
|
||||
html += '<div style="flex:1;text-align:center;padding:8px;background:#f9f9f9;border-radius:6px;"><div style="font-size:20px;font-weight:bold;color:#3498db;">' + sm.min + '</div><div>最小</div></div>';
|
||||
html += '</div>';
|
||||
|
||||
// 尾数
|
||||
html += '<h4 style="border-bottom:1px solid #eee;padding-bottom:5px;">🔢 尾数频率</h4>';
|
||||
html += '<div style="display:flex;flex-wrap:wrap;gap:5px;">';
|
||||
for (var i = 0; i < tn.all.length; i++) {
|
||||
var t = tn.all[i];
|
||||
html += '<div style="text-align:center;background:#f5f5f5;padding:5px 10px;border-radius:4px;"><div style="font-size:16px;font-weight:bold;">' + t.tail + '</div><div style="font-size:10px;color:#666;">' + t.count + ' (' + t.percent + '%)</div></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
$('#dash-result', layero).html(html);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user