Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07313f5c73 | |||
| 10dbb93efa | |||
| 93b73cabc8 | |||
| 59131f1d5b | |||
| f62de54f3d |
822
(红头)后台文档.md
Normal file
822
(红头)后台文档.md
Normal file
@@ -0,0 +1,822 @@
|
||||
# 后台管理系统文档
|
||||
|
||||
**项目名称:** 瑞莱医疗后台管理系统
|
||||
**技术架构:** ThinkPHP 5.0 + Layui + jQuery
|
||||
**数据库:** MySQL
|
||||
**文档版本:** v2.0
|
||||
**创建日期:** 2025年1月28日
|
||||
**最后更新:** 2025年1月29日(已完成逻辑彻底分离)
|
||||
|
||||
> **✅ 分离状态:** 两个后台模块已实现**逻辑彻底分离**(方案一),可独立维护,互不影响。
|
||||
> - **admin 模块**:早熟预测后台,完全独立实现
|
||||
> - **adminghd 模块**:GHD预测后台,完全独立实现
|
||||
> - 两个模块不再依赖 `common` 模块的业务基类
|
||||
|
||||
---
|
||||
|
||||
## 一、系统概述
|
||||
|
||||
### 1.1 系统简介
|
||||
|
||||
本系统为两个医疗小程序提供统一的后台管理服务:
|
||||
|
||||
1. **女童成长发育早熟预测模型后台** (`admin` 模块)
|
||||
- 对应小程序:瑞莱医疗小程序
|
||||
- 小程序AppID: `wx0847525a15342a46`
|
||||
- 访问路径:`/admin/`
|
||||
|
||||
2. **生长激素缺乏预测模型后台** (`adminghd` 模块)
|
||||
- 对应小程序:生长激素缺乏(GHD)预测模型小程序
|
||||
- 小程序AppID: `wxa75a76964ae7ce73`
|
||||
- 访问路径:`/adminghd/`
|
||||
|
||||
### 1.2 系统架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 后台管理系统 │
|
||||
├─────────────────────────────────────────┤
|
||||
│ admin模块 adminghd模块 │
|
||||
│ (早熟预测) (GHD预测) │
|
||||
├─────────────────────────────────────────┤
|
||||
│ 共同功能: │
|
||||
│ - 登录认证 │
|
||||
│ - 菜单管理 │
|
||||
│ - 资讯管理 │
|
||||
│ - 用户管理 │
|
||||
│ - 计算记录管理 │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、系统架构
|
||||
|
||||
### 2.1 目录结构
|
||||
|
||||
```
|
||||
/www/wwwroot/code/
|
||||
├── application/ # 应用目录
|
||||
│ ├── admin/ # 早熟预测后台模块
|
||||
│ │ ├── controller/ # 控制器
|
||||
│ │ │ ├── Login.php # 登录控制器
|
||||
│ │ │ ├── Menu.php # 菜单管理
|
||||
│ │ │ ├── Wechatset.php # 资讯管理
|
||||
│ │ │ ├── Wechatinfro.php # 用户和记录管理
|
||||
│ │ │ └── Dashboard.php # 仪表盘
|
||||
│ │ ├── common/ # 公共类
|
||||
│ │ │ └── Base.php # 基础控制器(登录验证)
|
||||
│ │ └── view/ # 视图模板
|
||||
│ │ ├── login/ # 登录相关视图
|
||||
│ │ │ ├── login.html # 登录页
|
||||
│ │ │ └── nav.html # 主框架页
|
||||
│ │ ├── wechatset/ # 资讯管理视图
|
||||
│ │ └── wechatinfro/ # 用户和记录视图
|
||||
│ ├── adminghd/ # GHD预测后台模块
|
||||
│ │ ├── controller/ # 控制器(结构同admin)
|
||||
│ │ ├── common/ # 公共类
|
||||
│ │ └── view/ # 视图模板
|
||||
│ ├── app/ # 小程序API模块
|
||||
│ │ └── controller/
|
||||
│ │ ├── Ruilaiwechat.php # 瑞莱小程序API
|
||||
│ │ └── Ghdwechat.php # GHD小程序API
|
||||
│ └── common/ # 公共模块
|
||||
│ ├── config/ # 配置类
|
||||
│ │ └── BusinessConfig.php # 业务配置
|
||||
│ └── controller/ # 公共控制器
|
||||
│ ├── WechatsetBase.php # 资讯管理基类
|
||||
│ ├── WechatinfroBase.php # 用户管理基类
|
||||
│ └── DashboardBase.php # 仪表盘基类
|
||||
├── public/ # 公共访问目录
|
||||
│ ├── static/ # 静态资源
|
||||
│ │ ├── admin/ # admin模块静态资源
|
||||
│ │ │ ├── css/ # 样式文件
|
||||
│ │ │ ├── js/ # JavaScript文件
|
||||
│ │ │ └── layui/ # Layui框架
|
||||
│ │ └── adminghd/ # adminghd模块静态资源
|
||||
│ └── index.php # 入口文件
|
||||
└── thinkphp/ # ThinkPHP框架核心
|
||||
```
|
||||
|
||||
### 2.2 技术栈
|
||||
|
||||
- **后端框架:** ThinkPHP 5.0
|
||||
- **前端框架:** Layui 2.x
|
||||
- **JavaScript库:** jQuery
|
||||
- **数据库:** MySQL
|
||||
- **会话管理:** ThinkPHP Session
|
||||
|
||||
---
|
||||
|
||||
## 三、模块说明
|
||||
|
||||
### 3.1 admin 模块(早熟预测后台)
|
||||
|
||||
#### 3.1.1 访问路径
|
||||
- 登录页:`/admin/login`
|
||||
- 主框架:`/admin/login/index`(登录后自动跳转)
|
||||
|
||||
#### 3.1.2 Session配置
|
||||
- 用户ID键名:`admin_user_id`
|
||||
- 登录时间键名:`admin_user_login_time`
|
||||
- 超时时间:3600秒(1小时)
|
||||
|
||||
#### 3.1.3 数据表映射
|
||||
| 业务表 | 数据库表名 |
|
||||
|--------|-----------|
|
||||
| 用户表 | `wechat_user` |
|
||||
| 资讯表 | `wechat_real_time_info` |
|
||||
| 计算记录表 | `wechat_calculate_record` |
|
||||
| 菜单表 | `menu` |
|
||||
| 管理员表 | `user` |
|
||||
|
||||
#### 3.1.4 静态资源路径
|
||||
- CSS:`/static/admin/css/`
|
||||
- JS:`/static/admin/js/`
|
||||
- Layui:`/static/admin/layui/`
|
||||
|
||||
### 3.2 adminghd 模块(GHD预测后台)
|
||||
|
||||
#### 3.2.1 访问路径
|
||||
- 登录页:`/adminghd/login`
|
||||
- 主框架:`/adminghd/login/index`(登录后自动跳转)
|
||||
|
||||
#### 3.2.2 Session配置
|
||||
- 用户ID键名:`adminghd_user_id`
|
||||
- 登录时间键名:`adminghd_user_login_time`
|
||||
- 超时时间:3600秒(1小时)
|
||||
|
||||
#### 3.2.3 数据表映射
|
||||
| 业务表 | 数据库表名 |
|
||||
|--------|-----------|
|
||||
| 用户表 | `ghd_wechat_user` |
|
||||
| 资讯表 | `wechat_real_time_info` |
|
||||
| 计算记录表 | `wechat_calculate_record` |
|
||||
| 菜单表 | `menu` |
|
||||
| 管理员表 | `user` |
|
||||
|
||||
#### 3.2.4 静态资源路径
|
||||
- CSS:`/static/adminghd/css/`
|
||||
- JS:`/static/adminghd/js/`
|
||||
- Layui:`/static/adminghd/layui/`
|
||||
|
||||
---
|
||||
|
||||
## 四、功能模块
|
||||
|
||||
### 4.1 登录认证模块
|
||||
|
||||
#### 4.1.1 登录功能
|
||||
|
||||
**控制器:** `Login.php`
|
||||
|
||||
**登录流程:**
|
||||
1. 用户访问登录页 `/admin/login` 或 `/adminghd/login`
|
||||
2. 输入用户名(手机号)和密码
|
||||
3. 系统验证用户信息:
|
||||
- 查询 `user` 表
|
||||
- 验证条件:`phone` = 用户名,`password` = MD5(密码),`status` = 1,`type` = 1
|
||||
4. 登录成功:
|
||||
- 设置Session:`admin_user_id` 或 `adminghd_user_id`
|
||||
- 设置登录时间:`admin_user_login_time` 或 `adminghd_user_login_time`(当前时间 + 3600秒)
|
||||
- 返回JSON:`{'status':1, 'msg':'登录成功', 'token':1}`
|
||||
5. 跳转到主框架页面
|
||||
|
||||
**登录验证:**
|
||||
- 所有需要登录的页面继承 `Base` 类
|
||||
- `Base::_initialize()` 方法自动检查Session
|
||||
- 未登录或超时:跳转到登录页
|
||||
|
||||
#### 4.1.2 退出功能
|
||||
|
||||
**接口:** `/admin/Login/logout` 或 `/adminghd/Login/logout`
|
||||
|
||||
**功能:**
|
||||
- 清除所有Session数据
|
||||
- 返回JSON:`{'status':1, 'msg':'退出成功'}`
|
||||
- 前端跳转到登录页
|
||||
|
||||
### 4.2 菜单管理模块
|
||||
|
||||
#### 4.2.1 菜单结构
|
||||
|
||||
**数据表:** `menu`
|
||||
|
||||
**表结构:**
|
||||
- `id`:菜单ID(主键)
|
||||
- `pid`:父菜单ID(空或0表示一级菜单)
|
||||
- `menu_name`:菜单名称
|
||||
- `url`:菜单链接
|
||||
- `seq_on`:排序序号
|
||||
- `menu_icon`:菜单图标
|
||||
- `create_time`:创建时间
|
||||
|
||||
**菜单层级:**
|
||||
- 一级菜单:`pid` 为空或0
|
||||
- 二级菜单:`pid` 指向一级菜单的 `id`
|
||||
|
||||
#### 4.2.2 获取菜单列表
|
||||
|
||||
**接口:** `/admin/Menu/getMenuList` 或 `/adminghd/Menu/getMenuList`
|
||||
|
||||
**返回格式:**
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"msg": "获取数据成功!!",
|
||||
"data": [
|
||||
{
|
||||
"id": "xxx",
|
||||
"pid": "",
|
||||
"menu_name": "小程序设置",
|
||||
"url": "",
|
||||
"seq_on": 1,
|
||||
"type": 1,
|
||||
"children": [
|
||||
{
|
||||
"id": "yyy",
|
||||
"pid": "xxx",
|
||||
"menu_name": "首页资讯列表",
|
||||
"url": "/admin/Wechatset/wechatRealTimeInfo",
|
||||
"type": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.3 菜单管理功能
|
||||
|
||||
- **添加菜单:** `/admin/Menu/doaddMenu`
|
||||
- **修改菜单:** `/admin/Menu/doupdMenu`
|
||||
- **删除菜单:** `/admin/Menu/delMenu`
|
||||
- **获取菜单详情:** `/admin/Menu/updMenu`
|
||||
|
||||
### 4.3 用户信息模块
|
||||
|
||||
#### 4.3.1 获取当前用户信息
|
||||
|
||||
**接口:** `/admin/Menu/getUserInfor` 或 `/adminghd/Menu/getUserInfor`
|
||||
|
||||
**返回格式:**
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"msg": "查询成功",
|
||||
"infro": {
|
||||
"user_name": "管理员",
|
||||
"user_head": "/static/admin/img/upload.png"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3.2 小程序注册用户管理
|
||||
|
||||
**控制器:** `Wechatinfro.php`
|
||||
|
||||
**功能列表:**
|
||||
- **用户列表:** `/admin/Wechatinfro/wechatUserList`
|
||||
- **获取用户列表:** `/admin/Wechatinfro/getWechatUserList`
|
||||
|
||||
**数据表:**
|
||||
- admin模块:`wechat_user`
|
||||
- adminghd模块:`ghd_wechat_user`
|
||||
|
||||
**用户列表字段:**
|
||||
- `uid`:用户ID
|
||||
- `nickname`:用户昵称
|
||||
- `headimg`:头像
|
||||
- `create_time`:注册时间
|
||||
|
||||
**搜索功能:**
|
||||
- 支持按昵称模糊搜索
|
||||
|
||||
### 4.4 资讯管理模块
|
||||
|
||||
#### 4.4.1 资讯列表
|
||||
|
||||
**控制器:** `Wechatset.php`
|
||||
|
||||
**功能列表:**
|
||||
- **资讯列表页:** `/admin/Wechatset/wechatRealTimeInfo`
|
||||
- **获取资讯列表:** `/admin/Wechatset/getWechatRealTimeInfoList`
|
||||
- **添加资讯页:** `/admin/Wechatset/wechatRealTimeInfoAdd`
|
||||
- **编辑资讯页:** `/admin/Wechatset/wechatRealTimeInfoUpdate`
|
||||
- **保存资讯:** `/admin/Wechatset/saveWechatRealTimeInfo`
|
||||
- **删除资讯:** `/admin/Wechatset/delWechatRealTimeInfo`
|
||||
- **获取资讯详情:** `/admin/Wechatset/getRealTimeInfoDetail`
|
||||
|
||||
**数据表:** `wechat_real_time_info`(两个模块共用)
|
||||
|
||||
**资讯字段:**
|
||||
- `id`:资讯ID
|
||||
- `title_plain`:标题
|
||||
- `thumbnail`:缩略图
|
||||
- `excerpt_plain`:简介
|
||||
- `url`:跳转链接
|
||||
- `create_time`:创建时间
|
||||
|
||||
**搜索功能:**
|
||||
- 支持按标题模糊搜索
|
||||
|
||||
#### 4.4.2 资讯管理流程
|
||||
|
||||
1. **添加资讯:**
|
||||
- 填写标题、上传图片、填写简介、填写跳转链接
|
||||
- 系统自动生成ID(MD5(时间戳+随机数))
|
||||
- 保存到数据库
|
||||
|
||||
2. **编辑资讯:**
|
||||
- 根据ID获取资讯详情
|
||||
- 修改后保存
|
||||
|
||||
3. **删除资讯:**
|
||||
- 根据ID删除记录
|
||||
|
||||
### 4.5 计算记录管理模块
|
||||
|
||||
#### 4.5.1 计算记录列表
|
||||
|
||||
**控制器:** `Wechatinfro.php`
|
||||
|
||||
**功能列表:**
|
||||
- **记录列表页:** `/admin/Wechatinfro/wechatRecordList`
|
||||
- **获取记录列表:** `/admin/Wechatinfro/getWechatRecordList`
|
||||
|
||||
**数据表:** `wechat_calculate_record`(两个模块共用)
|
||||
|
||||
**记录字段:**
|
||||
- `id`:记录ID
|
||||
- `name`:姓名
|
||||
- `age`:年龄
|
||||
- `height`:身高
|
||||
- `bone_age`:骨龄
|
||||
- `father_height`:父亲身高
|
||||
- `mother_height`:母亲身高
|
||||
- `IGF`:IGF-1值(GHD)或IGFBP-3值(早熟)
|
||||
- `LH`:LH值(早熟)
|
||||
- `uterus_thickness`:子宫厚度(早熟)
|
||||
- `calculate_resutlt`:计算结果
|
||||
- `create_time`:创建时间
|
||||
|
||||
**搜索功能:**
|
||||
- 支持按姓名模糊搜索
|
||||
|
||||
### 4.6 仪表盘模块(Dashboard)
|
||||
|
||||
#### 4.6.1 统计概览
|
||||
|
||||
**控制器:** `Dashboard.php`
|
||||
|
||||
**功能列表:**
|
||||
- **仪表盘页面:** `/admin/Dashboard/index`
|
||||
- **获取统计数据:** `/admin/Dashboard/getStatistics`
|
||||
|
||||
**统计数据:**
|
||||
- 注册用户数
|
||||
- 首页资讯数量
|
||||
- 最近一次计算时间
|
||||
- 今日新增用户数
|
||||
- 总计算次数
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库设计
|
||||
|
||||
### 5.1 核心数据表
|
||||
|
||||
#### 5.1.1 管理员表(user)
|
||||
|
||||
**说明:** 后台管理员账户表,两个模块共用
|
||||
|
||||
**字段:**
|
||||
- `id`:管理员ID(主键)
|
||||
- `user_name`:管理员姓名
|
||||
- `phone`:手机号(登录用户名)
|
||||
- `password`:密码(MD5加密)
|
||||
- `user_head`:头像
|
||||
- `status`:状态(1=启用,0=禁用)
|
||||
- `type`:类型(1=管理员)
|
||||
|
||||
#### 5.1.2 菜单表(menu)
|
||||
|
||||
**说明:** 后台菜单配置表,两个模块共用
|
||||
|
||||
**字段:**
|
||||
- `id`:菜单ID(主键,MD5生成)
|
||||
- `pid`:父菜单ID(空或0=一级菜单)
|
||||
- `menu_name`:菜单名称
|
||||
- `url`:菜单链接
|
||||
- `seq_on`:排序序号
|
||||
- `menu_icon`:菜单图标
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 5.1.3 小程序用户表
|
||||
|
||||
**说明:** 小程序注册用户表,两个模块使用不同的表
|
||||
|
||||
**admin模块:** `wechat_user`
|
||||
**adminghd模块:** `ghd_wechat_user`
|
||||
|
||||
**字段:**
|
||||
- `uid`:用户ID(主键)
|
||||
- `openid`:微信OpenID
|
||||
- `nickname`:用户昵称
|
||||
- `headimg`:头像
|
||||
- `create_time`:注册时间
|
||||
|
||||
#### 5.1.4 资讯表(wechat_real_time_info)
|
||||
|
||||
**说明:** 首页资讯表,两个模块共用
|
||||
|
||||
**字段:**
|
||||
- `id`:资讯ID(主键,MD5生成)
|
||||
- `title_plain`:标题
|
||||
- `thumbnail`:缩略图URL
|
||||
- `excerpt_plain`:简介
|
||||
- `url`:跳转链接
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 5.1.5 计算记录表(wechat_calculate_record)
|
||||
|
||||
**说明:** 预测计算记录表,两个模块共用
|
||||
|
||||
**字段:**
|
||||
- `id`:记录ID(主键,MD5生成)
|
||||
- `uid`:用户ID
|
||||
- `name`:姓名
|
||||
- `age`:年龄
|
||||
- `height`:身高(cm)
|
||||
- `bone_age`:骨龄(年)
|
||||
- `father_height`:父亲身高(cm)
|
||||
- `mother_height`:母亲身高(cm)
|
||||
- `IGF`:IGF-1值(GHD)或IGFBP-3值(早熟)
|
||||
- `LH`:LH值(早熟预测)
|
||||
- `uterus_thickness`:子宫厚度(早熟预测)
|
||||
- `calculate_resutlt`:计算结果(JSON格式)
|
||||
- `create_time`:创建时间
|
||||
|
||||
---
|
||||
|
||||
## 六、前端架构
|
||||
|
||||
### 6.1 主框架结构
|
||||
|
||||
**文件:** `application/admin/view/login/nav.html` 或 `application/adminghd/view/login/nav.html`
|
||||
|
||||
**布局:**
|
||||
- 左侧导航栏:菜单列表
|
||||
- 顶部栏:面包屑导航 + 用户信息 + 退出按钮
|
||||
- 主内容区:iframe加载功能页面
|
||||
|
||||
### 6.2 导航菜单渲染
|
||||
|
||||
**文件:** `public/static/admin/js/nav.js` 或 `public/static/adminghd/js/nav.js`
|
||||
|
||||
**功能:**
|
||||
1. 页面加载时调用 `/admin/Menu/getMenuList` 获取菜单数据
|
||||
2. 将菜单数据渲染为左侧导航栏
|
||||
3. 支持一级和二级菜单结构
|
||||
4. 点击菜单项,在iframe中加载对应页面
|
||||
|
||||
### 6.3 样式框架
|
||||
|
||||
**CSS框架:** Layui 2.x
|
||||
|
||||
**主要样式文件:**
|
||||
- `nav.css`:主框架样式
|
||||
- `login.css`:登录页样式
|
||||
- `index.css`:列表页样式
|
||||
|
||||
---
|
||||
|
||||
## 七、API接口
|
||||
|
||||
### 7.1 登录相关
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Login/index` | GET | 登录页 |
|
||||
| `/admin/Login/login` | POST | 登录验证 |
|
||||
| `/admin/Login/logout` | POST | 退出登录 |
|
||||
| `/admin/Login/logoutJump` | GET | 超时跳转页 |
|
||||
|
||||
### 7.2 菜单相关
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Menu/getMenuList` | POST | 获取菜单列表 |
|
||||
| `/admin/Menu/getUserInfor` | POST | 获取当前用户信息 |
|
||||
| `/admin/Menu/doaddMenu` | POST | 添加菜单 |
|
||||
| `/admin/Menu/doupdMenu` | POST | 修改菜单 |
|
||||
| `/admin/Menu/delMenu` | POST | 删除菜单 |
|
||||
|
||||
### 7.3 用户管理
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Wechatinfro/wechatUserList` | GET | 用户列表页 |
|
||||
| `/admin/Wechatinfro/getWechatUserList` | POST | 获取用户列表 |
|
||||
|
||||
### 7.4 资讯管理
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Wechatset/wechatRealTimeInfo` | GET | 资讯列表页 |
|
||||
| `/admin/Wechatset/getWechatRealTimeInfoList` | POST | 获取资讯列表 |
|
||||
| `/admin/Wechatset/wechatRealTimeInfoAdd` | GET | 添加资讯页 |
|
||||
| `/admin/Wechatset/wechatRealTimeInfoUpdate` | GET | 编辑资讯页 |
|
||||
| `/admin/Wechatset/saveWechatRealTimeInfo` | POST | 保存资讯 |
|
||||
| `/admin/Wechatset/delWechatRealTimeInfo` | POST | 删除资讯 |
|
||||
| `/admin/Wechatset/getRealTimeInfoDetail` | POST | 获取资讯详情 |
|
||||
|
||||
### 7.5 计算记录
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Wechatinfro/wechatRecordList` | GET | 记录列表页 |
|
||||
| `/admin/Wechatinfro/getWechatRecordList` | POST | 获取记录列表 |
|
||||
|
||||
### 7.6 仪表盘
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/Dashboard/index` | GET | 仪表盘页面 |
|
||||
| `/admin/Dashboard/getStatistics` | POST | 获取统计数据 |
|
||||
|
||||
---
|
||||
|
||||
## 八、安全机制
|
||||
|
||||
### 8.1 登录验证
|
||||
|
||||
- 所有需要登录的控制器继承 `Base` 类
|
||||
- `Base::_initialize()` 自动检查Session
|
||||
- 未登录或超时自动跳转到登录页
|
||||
|
||||
### 8.2 密码加密
|
||||
|
||||
- 密码使用MD5加密存储
|
||||
- 登录时对输入密码进行MD5加密后比对
|
||||
|
||||
### 8.3 Session管理
|
||||
|
||||
- 登录成功设置Session,有效期1小时
|
||||
- 每次请求检查Session是否过期
|
||||
- 退出登录清除所有Session
|
||||
|
||||
### 8.4 权限控制
|
||||
|
||||
- 当前版本未实现细粒度权限控制
|
||||
- 所有登录用户拥有相同权限
|
||||
- 预留权限控制接口(代码中已注释)
|
||||
|
||||
---
|
||||
|
||||
## 九、部署说明
|
||||
|
||||
### 9.1 环境要求
|
||||
|
||||
- PHP >= 5.6
|
||||
- MySQL >= 5.6
|
||||
- Apache/Nginx Web服务器
|
||||
- ThinkPHP 5.0框架
|
||||
|
||||
### 9.2 配置说明
|
||||
|
||||
#### 9.2.1 数据库配置
|
||||
|
||||
**文件:** `application/database.php`
|
||||
|
||||
```php
|
||||
return [
|
||||
'type' => 'mysql',
|
||||
'hostname' => '127.0.0.1',
|
||||
'database' => 'ruilai',
|
||||
'username' => 'rootrui',
|
||||
'password' => 'X2)jB+k%YH.p',
|
||||
'charset' => 'utf8',
|
||||
'prefix' => 't_sys_',
|
||||
];
|
||||
```
|
||||
|
||||
#### 9.2.2 路由配置
|
||||
|
||||
**文件:** `application/route.php`
|
||||
|
||||
默认使用ThinkPHP的路由规则,URL格式:
|
||||
- `/模块/控制器/方法`
|
||||
|
||||
例如:
|
||||
- `/admin/Login/index` → `application/admin/controller/Login.php::index()`
|
||||
|
||||
### 9.3 静态资源
|
||||
|
||||
静态资源存放在 `public/static/` 目录下,通过Web服务器直接访问。
|
||||
|
||||
**访问路径:**
|
||||
- `/static/admin/css/nav.css`
|
||||
- `/static/adminghd/js/nav.js`
|
||||
|
||||
---
|
||||
|
||||
## 十、常见问题
|
||||
|
||||
### 10.1 登录问题
|
||||
|
||||
**问题:** 登录后立即跳转到登录页
|
||||
|
||||
**原因:** Session未正确设置或Base类验证失败
|
||||
|
||||
**解决:**
|
||||
1. 检查Session配置
|
||||
2. 检查Base类的Session键名是否正确
|
||||
3. 检查数据库用户表数据
|
||||
|
||||
### 10.2 菜单不显示
|
||||
|
||||
**问题:** 左侧导航栏菜单不显示
|
||||
|
||||
**原因:**
|
||||
1. 菜单数据未正确返回
|
||||
2. JavaScript渲染错误
|
||||
3. 菜单表数据为空
|
||||
|
||||
**解决:**
|
||||
1. 检查浏览器控制台错误
|
||||
2. 检查 `/admin/Menu/getMenuList` 接口返回
|
||||
3. 检查 `menu` 表是否有数据
|
||||
|
||||
### 10.3 数据表不存在
|
||||
|
||||
**问题:** 提示数据表不存在
|
||||
|
||||
**原因:** 数据库表前缀配置错误
|
||||
|
||||
**解决:**
|
||||
1. 检查 `application/database.php` 中的 `prefix` 配置
|
||||
2. 确认数据库表名是否正确(包含前缀)
|
||||
|
||||
---
|
||||
|
||||
## 十一、开发规范
|
||||
|
||||
### 11.1 代码规范
|
||||
|
||||
- 遵循PSR-2编码规范
|
||||
- 控制器类名首字母大写
|
||||
- 方法名使用驼峰命名
|
||||
- 注释使用PHPDoc格式
|
||||
|
||||
### 11.2 命名规范
|
||||
|
||||
- **控制器:** 大驼峰,如 `Wechatset.php`
|
||||
- **方法:** 小驼峰,如 `getWechatUserList()`
|
||||
- **数据表:** 小写下划线,如 `wechat_user`
|
||||
- **Session键:** 小写下划线,如 `admin_user_id`
|
||||
|
||||
### 11.3 文件组织
|
||||
|
||||
- 控制器放在 `controller/` 目录
|
||||
- 视图放在 `view/` 目录
|
||||
- 静态资源放在 `public/static/` 目录
|
||||
- 公共类放在 `common/` 目录
|
||||
|
||||
---
|
||||
|
||||
## 十二、后续优化建议
|
||||
|
||||
### 12.1 代码优化
|
||||
|
||||
1. **统一公共逻辑:** 将两个模块的公共代码提取到 `common` 模块
|
||||
2. **配置统一管理:** 使用配置文件管理业务类型和表映射
|
||||
3. **错误处理:** 统一异常处理和错误返回格式
|
||||
|
||||
### 12.2 功能增强
|
||||
|
||||
1. **权限管理:** 实现基于角色的权限控制(RBAC)
|
||||
2. **操作日志:** 记录管理员操作日志
|
||||
3. **数据统计:** 增加更详细的数据统计和报表功能
|
||||
4. **批量操作:** 支持批量删除、批量导出等功能
|
||||
|
||||
### 12.3 性能优化
|
||||
|
||||
1. **缓存机制:** 菜单数据、统计数据使用缓存
|
||||
2. **数据库优化:** 添加索引,优化查询语句
|
||||
3. **前端优化:** 压缩静态资源,使用CDN
|
||||
|
||||
---
|
||||
|
||||
## 十三、后台模块彻底分离维护方案
|
||||
|
||||
两个后台(admin 早熟预测、adminghd GHD 预测)可以做到**彻底分离维护**,互不影响。根据目标不同,有两种做法。
|
||||
|
||||
### 13.1 分离状态
|
||||
|
||||
**✅ 已完成逻辑彻底分离(方案一)**
|
||||
|
||||
| 模块 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| **admin 模块** | ✅ 已独立 | 所有控制器继承 `app\admin\common\Base`,不再依赖 common 模块 |
|
||||
| **adminghd 模块** | ✅ 已独立 | 所有控制器继承 `app\adminghd\common\Base`,不再依赖 common 模块 |
|
||||
| **Dashboard** | ✅ 已独立 | 两个模块的 `Dashboard` 控制器各自实现 `getStatistics` 方法,使用固定的表名 |
|
||||
| **数据库** | 共用 | 同一库 `ruilai`,同一前缀 `t_sys_`;部分表共用(menu、wechat_real_time_info、wechat_calculate_record),用户表不同(wechat_user / ghd_wechat_user) |
|
||||
| **入口与框架** | 共用 | 同一 `public/index.php`、同一 ThinkPHP 应用目录 |
|
||||
|
||||
**已解除的耦合:**
|
||||
- ✅ `Dashboard` 不再继承 `DashboardBase`
|
||||
- ✅ 表名和 Session 键已硬编码到各自控制器中
|
||||
- ✅ 两个模块可独立修改,互不影响
|
||||
|
||||
---
|
||||
|
||||
### 13.2 方案一:同仓库内逻辑彻底分离(✅ 已采用)
|
||||
|
||||
**目标**:同一套代码、同一部署,但 admin 与 adminghd 在代码上**完全独立**,改一个模块不会牵动另一个,也不依赖 common 里的业务基类。
|
||||
|
||||
**实施状态:** ✅ **已完成**
|
||||
|
||||
**已完成的修改:**
|
||||
|
||||
1. **✅ 解除 Dashboard 对 common 的依赖**
|
||||
- `application/admin/controller/Dashboard.php` 已改为继承 `\app\admin\common\Base`,不再继承 `DashboardBase`。
|
||||
- `getStatistics` 方法已独立实现,使用固定的表名 `wechat_user`、`wechat_real_time_info`、`wechat_calculate_record`。
|
||||
- `application/adminghd/controller/Dashboard.php` 已改为继承 `\app\adminghd\common\Base`,使用固定的表名 `ghd_wechat_user`、`wechat_real_time_info`、`wechat_calculate_record`。
|
||||
|
||||
2. **✅ 代码独立性验证**
|
||||
- 两个模块的控制器已完全独立,不再依赖 `app\common\controller\*Base` 和 `BusinessConfig`。
|
||||
- 表名和 Session 键已硬编码到各自控制器中。
|
||||
|
||||
3. **✅ common 模块保留**
|
||||
- `common` 模块中的基类(`DashboardBase`、`WechatinfroBase`、`WechatsetBase`)已保留,但不再被使用。
|
||||
- 可作为参考或未来新后台的模板,但不影响现有两个模块的独立性。
|
||||
|
||||
**优点**:✅ 部署不变、数据库不变,只改一处不影响另一处,适合继续同仓库、同服务器维护。
|
||||
**维护约定**:两个模块独立维护,如需同步功能,需分别在两个模块中实现。建议在代码注释中标注需要同步的功能点。
|
||||
|
||||
---
|
||||
|
||||
### 13.3 方案二:拆成两个独立项目(物理分离)
|
||||
|
||||
**目标**:两套独立代码库、可独立部署、独立发版,甚至不同服务器、不同数据库。
|
||||
|
||||
**思路**:
|
||||
- 以当前代码为基准,复制出两份项目:一份只保留 admin 相关(及 app、index 等必要模块),一份只保留 adminghd 相关。
|
||||
- 每份项目有独立 `application`、独立入口(可共用同一 `public` 或各建各的)、独立配置与依赖。
|
||||
|
||||
**具体步骤**:
|
||||
|
||||
1. **项目 A(早熟预测后台)**
|
||||
- 新建目录如 `code-admin`,保留 ThinkPHP 框架、`public`、`application/database.php` 等。
|
||||
- 只保留 `application/admin`、`application/app`(瑞莱小程序 API)、`application/index` 等与早熟业务相关的模块;删除 `application/adminghd` 和 `application/common` 中业务相关部分。
|
||||
- 将原 admin 内对表名、Session 的写法固定为早熟业务(wechat_user、admin_user_id 等)。
|
||||
- 配置独立入口(如 `code-admin/public/index.php`)和独立域名或路径。
|
||||
|
||||
2. **项目 B(GHD 预测后台)**
|
||||
- 新建目录如 `code-adminghd`,同样保留框架与必要目录。
|
||||
- 只保留 `application/adminghd`、`application/app`(GHD 小程序 API)等;删除 `application/admin` 和 common 业务基类。
|
||||
- 表名、Session 固定为 GHD(ghd_wechat_user、adminghd_user_id 等)。
|
||||
- 配置独立入口与访问方式。
|
||||
|
||||
3. **数据库**
|
||||
- **选项甲**:仍用同一库,两项目连同一 `database.php`,仅模块不同、访问表不同。
|
||||
- **选项乙**:分库(如 `ruilai` 与 `ruilai_ghd`),各项目独立 `database.php`,表结构可复制或迁移脚本分表。
|
||||
|
||||
4. **静态资源**
|
||||
- 各项目 `public/static` 下只保留本后台所需(如项目 A 只保留 `admin`,项目 B 只保留 `adminghd`),避免混用。
|
||||
|
||||
**优点**:版本、上线、回滚完全独立,技术栈升级可分批进行。
|
||||
**缺点**:两套代码、两套部署与运维;公共 bug 或需求要改两处,需通过复制或少量共享库(如 composer 私有包)来收敛。
|
||||
|
||||
---
|
||||
|
||||
### 13.4 选择建议
|
||||
|
||||
| 场景 | 建议 |
|
||||
|------|------|
|
||||
| 希望**少动部署、少动库**,只希望开发时互不干扰 | 采用 **方案一**(同仓库逻辑分离) |
|
||||
| 需要**独立域名、独立服务器、独立发版节奏** | 采用 **方案二**(拆成两个项目) |
|
||||
| 未来可能新增更多“类似后台”且希望复用一套基类 | 可保留 common 基类,仅把 admin、adminghd 改为不继承它们,实现“可选复用、默认分离” |
|
||||
|
||||
**实施完成日期:** 2025年1月29日
|
||||
**采用的方案:** 方案一(同仓库内逻辑彻底分离)
|
||||
**状态:** ✅ 已完成,两个模块已完全独立,可独立维护
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### A. 相关文档
|
||||
|
||||
- [数据库配置文档](./数据库配置.md)
|
||||
- [生长激素缺乏预测模型项目需求文档](./生长激素缺乏预测模型项目需求文档.md)
|
||||
|
||||
### B. 联系方式
|
||||
|
||||
如有问题,请联系开发团队。
|
||||
|
||||
---
|
||||
|
||||
**文档生成时间:** 2025年1月28日
|
||||
**最后更新:** 2025年1月28日
|
||||
133
(红头)数据库配置.md
Normal file
133
(红头)数据库配置.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 数据库配置文档
|
||||
|
||||
**项目路径:** `/www/wwwroot/code`
|
||||
**配置文件:** `application/database.php`
|
||||
**框架版本:** ThinkPHP 5.0
|
||||
|
||||
---
|
||||
|
||||
## 数据库连接信息
|
||||
|
||||
| 配置项 | 值 | 说明 |
|
||||
|--------|-----|------|
|
||||
| **数据库类型** | `mysql` | MySQL数据库 |
|
||||
| **服务器地址** | `127.0.0.1` | 本地MySQL服务器 |
|
||||
| **数据库名** | `ruilai` | 数据库名称 |
|
||||
| **用户名** | `rootrui` | 数据库用户名 |
|
||||
| **密码** | `X2)jB+k%YH.p` | 数据库密码 |
|
||||
| **端口** | `` | 默认3306端口 |
|
||||
| **字符集** | `utf8` | 数据库编码 |
|
||||
|
||||
---
|
||||
|
||||
## 数据库高级配置
|
||||
|
||||
| 配置项 | 值 | 说明 |
|
||||
|--------|-----|------|
|
||||
| **表前缀** | `t_sys_` | 数据库表前缀 |
|
||||
| **调试模式** | `true` | 已开启数据库调试 |
|
||||
| **部署方式** | `0` | 集中式(单一服务器) |
|
||||
| **读写分离** | `false` | 未启用读写分离 |
|
||||
| **主服务器数量** | `1` | 主服务器数量 |
|
||||
| **字段严格检查** | `true` | 严格检查字段是否存在 |
|
||||
| **数据集返回类型** | `array` | 返回数组格式 |
|
||||
| **自动时间戳** | `false` | 未启用自动时间戳 |
|
||||
| **时间格式** | `Y-m-d H:i:s` | 默认时间格式 |
|
||||
| **SQL性能分析** | `false` | 未启用SQL性能分析 |
|
||||
|
||||
---
|
||||
|
||||
## 完整配置文件内容
|
||||
|
||||
```php
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 数据库类型
|
||||
'type' => 'mysql',
|
||||
// 服务器地址
|
||||
'hostname' => '127.0.0.1',
|
||||
// 数据库名
|
||||
'database' => 'ruilai',
|
||||
// 用户名
|
||||
'username' => 'rootrui',
|
||||
// 密码
|
||||
'password' => 'X2)jB+k%YH.p',
|
||||
// 端口
|
||||
'hostport' => '',
|
||||
// 连接dsn
|
||||
'dsn' => '',
|
||||
// 数据库连接参数
|
||||
'params' => [],
|
||||
// 数据库编码默认采用utf8
|
||||
'charset' => 'utf8',
|
||||
// 数据库表前缀
|
||||
'prefix' => 't_sys_',
|
||||
// 数据库调试模式
|
||||
'debug' => true,
|
||||
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
|
||||
'deploy' => 0,
|
||||
// 数据库读写是否分离 主从式有效
|
||||
'rw_separate' => false,
|
||||
// 读写分离后 主服务器数量
|
||||
'master_num' => 1,
|
||||
// 指定从服务器序号
|
||||
'slave_no' => '',
|
||||
// 是否严格检查字段是否存在
|
||||
'fields_strict' => true,
|
||||
// 数据集返回类型
|
||||
'resultset_type' => 'array',
|
||||
// 自动写入时间戳字段
|
||||
'auto_timestamp' => false,
|
||||
// 时间字段取出后的默认时间格式
|
||||
'datetime_format' => 'Y-m-d H:i:s',
|
||||
// 是否需要进行SQL性能分析
|
||||
'sql_explain' => false,
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 连接字符串示例
|
||||
|
||||
### MySQL命令行连接
|
||||
```bash
|
||||
mysql -h 127.0.0.1 -u rootrui -p'X2)jB+k%YH.p' ruilai
|
||||
```
|
||||
|
||||
### PDO连接字符串
|
||||
```
|
||||
mysql:host=127.0.0.1;dbname=ruilai;charset=utf8
|
||||
```
|
||||
|
||||
### 连接信息摘要
|
||||
- **Host:** 127.0.0.1
|
||||
- **Database:** ruilai
|
||||
- **User:** rootrui
|
||||
- **Password:** X2)jB+k%YH.p
|
||||
- **Charset:** utf8
|
||||
- **Table Prefix:** t_sys_
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. ⚠️ **数据库调试模式已开启** (`debug => true`),生产环境建议关闭
|
||||
2. 📝 **表前缀为** `t_sys_`,查询时需注意表名格式
|
||||
3. 🔒 **密码包含特殊字符**,使用命令行连接时需用引号包裹
|
||||
4. 🌐 **字符集为utf8**,支持中文存储
|
||||
5. 📊 **未启用读写分离**,适合单服务器部署
|
||||
|
||||
---
|
||||
|
||||
**生成时间:** 2025年1月26日
|
||||
**配置文件位置:** `/www/wwwroot/code/application/database.php`
|
||||
99
(红头)服务器重启.md
Normal file
99
(红头)服务器重启.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# 服务器重启记录(nginx / php-fpm)
|
||||
|
||||
## 执行时间
|
||||
|
||||
2026-04-02
|
||||
|
||||
## 目标
|
||||
|
||||
修复后台接口返回 `502 Bad Gateway`(`/admin/login` 与 `/adminghd/login`)。
|
||||
|
||||
## 处置过程与关键命令
|
||||
|
||||
### 1. 校验并重启 nginx
|
||||
|
||||
1) 校验配置:
|
||||
|
||||
```bash
|
||||
/www/server/nginx/sbin/nginx -t
|
||||
```
|
||||
|
||||
2) 平滑停/启(按命令执行顺序):
|
||||
|
||||
```bash
|
||||
/www/server/nginx/sbin/nginx -s stop
|
||||
sleep 1
|
||||
/www/server/nginx/sbin/nginx
|
||||
sleep 1
|
||||
```
|
||||
|
||||
3) 重启后快速探测(当时仍为 502):
|
||||
|
||||
```bash
|
||||
curl -k -sS -o /dev/null -w '%{http_code}\n' -H "Host: www.ruilaizipj.com" https://127.0.0.1/admin/login
|
||||
curl -k -sS -o /dev/null -w '%{http_code}\n' -H "Host: www.ruilaizipj.com" https://127.0.0.1/adminghd/login
|
||||
```
|
||||
|
||||
当时输出:`502` / `502`。
|
||||
|
||||
### 2. 进一步定位:nginx fastcgi 指向的 php-fpm socket 丢失
|
||||
|
||||
从 nginx vhost 错误日志中观察到典型报错:
|
||||
`connect() to unix:/tmp/php-cgi-56.sock failed (2: No such file or directory) while connecting to upstream`
|
||||
|
||||
并且在故障窗口期内,直接探测 socket 路径存在性出现不一致(最终以“socket 不在”导致 nginx 502 为主因)。
|
||||
|
||||
### 3. 重启 php-fpm(先 USR2 方式)
|
||||
|
||||
先对 php-fpm 两套版本做了重载(USR2):
|
||||
|
||||
```bash
|
||||
kill -USR2 12760 # php-fpm 56 master process
|
||||
kill -USR2 12747 # php-fpm 73 master process
|
||||
sleep 2
|
||||
```
|
||||
|
||||
重载后 `ss` 可见 socket 监听,但 `/admin/login` 仍返回 `502`,socket 仍存在“文件不可直接访问/表现不稳定”的情况。
|
||||
|
||||
### 4. 强制彻底重启 php-fpm 56(重新创建 socket)
|
||||
|
||||
为了强制重新绑定并确保 socket 文件落地,执行了 php-fpm 56 停-起:
|
||||
|
||||
```bash
|
||||
# 停止 php-fpm 56 master(先查到 pid 为 14010)
|
||||
kill -TERM 14010
|
||||
|
||||
# 启动
|
||||
/www/server/php/56/sbin/php-fpm --daemonize \
|
||||
--fpm-config /www/server/php/56/etc/php-fpm.conf \
|
||||
--pid /www/server/php/56/var/run/php-fpm.pid
|
||||
sleep 1
|
||||
```
|
||||
|
||||
启动后检查结果:
|
||||
|
||||
```bash
|
||||
ls -la /tmp/php-cgi-56.sock
|
||||
# socket 文件已存在
|
||||
```
|
||||
|
||||
并且本机对 socket 做了直接连通性检查,`connect ok`。
|
||||
|
||||
## 验证结果
|
||||
|
||||
重启 php-fpm 56 完成后,后台入口已恢复:
|
||||
|
||||
```bash
|
||||
curl -k -sS -o /dev/null -w '%{http_code}\n' -H "Host: www.ruilaizipj.com" https://127.0.0.1/admin/login
|
||||
curl -k -sS -o /dev/null -w '%{http_code}\n' -H "Host: www.ruilaizipj.com" https://127.0.0.1/adminghd/login
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
- `/admin/login` => `200`
|
||||
- `/adminghd/login` => `200`
|
||||
|
||||
## 结论
|
||||
|
||||
此次 `502` 的根因主要为 nginx fastcgi 上游(php-fpm socket)异常/缺失,导致 `connect() to unix:/tmp/php-cgi-56.sock ... No such file or directory`,通过强制重启 php-fpm 56 后 socket 重新正常创建,服务恢复。
|
||||
|
||||
926
(红头)生长激素缺乏预测模型项目需求文档.md
Normal file
926
(红头)生长激素缺乏预测模型项目需求文档.md
Normal file
@@ -0,0 +1,926 @@
|
||||
# 生长激素缺乏预测模型项目需求文档
|
||||
|
||||
**项目名称:** 生长激素缺乏(GHD)预测模型系统
|
||||
**项目类型:** 医疗健康小程序 + 后台管理系统
|
||||
**技术架构:** 微信小程序(前端)+ ThinkPHP 5.0(后端)
|
||||
**数据库:** MySQL
|
||||
**文档版本:** v1.0
|
||||
**创建日期:** 2025年1月28日
|
||||
|
||||
---
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
生长激素缺乏(Growth Hormone Deficiency, GHD)是儿童内分泌疾病中的常见问题,早期诊断和预测对患者的治疗和预后具有重要意义。本项目旨在开发一个基于多因素分析的GHD预测模型系统,通过微信小程序为医生和患者提供便捷的预测工具,并通过后台管理系统进行数据管理和内容维护。
|
||||
|
||||
### 1.2 项目目标
|
||||
|
||||
1. **提供GHD预测功能**:基于骨龄、实际年龄、IGF-1、IGFBP-3等指标,计算GHD患病概率
|
||||
2. **数据管理**:记录用户计算历史,便于医生和患者追踪
|
||||
3. **资讯管理**:提供相关医疗资讯的发布和管理功能
|
||||
4. **用户管理**:管理小程序注册用户信息
|
||||
|
||||
### 1.3 用户群体
|
||||
|
||||
- **主要用户**:医生、患者及其家属
|
||||
- **管理员**:医疗机构的系统管理员
|
||||
|
||||
---
|
||||
|
||||
## 二、系统架构
|
||||
|
||||
### 2.1 技术架构
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 微信小程序前端 │
|
||||
│ (WeChat Mini │
|
||||
│ Program) │
|
||||
└────────┬────────┘
|
||||
│ HTTP/HTTPS
|
||||
│ API调用
|
||||
┌────────▼────────┐
|
||||
│ ThinkPHP 5.0 │
|
||||
│ 后端服务 │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ MySQL数据库 │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 目录结构
|
||||
|
||||
```
|
||||
/www/wwwroot/code/
|
||||
├── application/ # 应用目录
|
||||
│ ├── adminghd/ # 后台管理模块
|
||||
│ │ ├── controller/ # 控制器
|
||||
│ │ │ ├── Login.php # 登录控制器
|
||||
│ │ │ ├── Menu.php # 菜单管理
|
||||
│ │ │ ├── Wechatinfro.php # 微信用户信息管理
|
||||
│ │ │ └── Wechatset.php # 微信设置管理
|
||||
│ │ ├── model/ # 模型
|
||||
│ │ └── view/ # 视图
|
||||
│ ├── app/ # 小程序API模块
|
||||
│ │ └── controller/
|
||||
│ │ ├── Ghdwechat.php # GHD相关API
|
||||
│ │ └── Ruilaiwechat.php # 瑞来相关API
|
||||
│ └── database.php # 数据库配置
|
||||
├── public/ # 公共访问目录
|
||||
│ ├── index.php # 入口文件
|
||||
│ └── static/ # 静态资源
|
||||
├── szjs/ # 微信小程序源码
|
||||
│ ├── pages/ # 小程序页面
|
||||
│ │ ├── ghdCalculator/ # GHD计算器页面
|
||||
│ │ ├── home/ # 首页
|
||||
│ │ ├── my/ # 个人中心
|
||||
│ │ └── ...
|
||||
│ ├── app.js # 小程序入口
|
||||
│ └── app.json # 小程序配置
|
||||
└── thinkphp/ # ThinkPHP框架核心
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、功能需求
|
||||
|
||||
### 3.1 微信小程序功能
|
||||
|
||||
#### 3.1.1 GHD预测计算器
|
||||
|
||||
**功能描述:** 用户输入相关指标,系统自动计算GHD患病概率
|
||||
|
||||
**前端计算器输入参数:**
|
||||
- **骨龄(BA)**:单位:年,支持小数
|
||||
- **实际年龄(CA)**:单位:年,支持小数
|
||||
- **IGF-1值**:单位:ng/ml,支持小数
|
||||
- **IGFBP-3值**:单位:mg/L,支持小数
|
||||
|
||||
**后端API计算输入参数:**
|
||||
- **用户ID(uid)**:必填
|
||||
- **患者姓名(name)**:必填
|
||||
- **年龄(age)**:必填,数字
|
||||
- **身高(height)**:必填,数字
|
||||
- **骨龄(bone_age)**:必填,数字
|
||||
- **父亲身高(father_height)**:必填,数字
|
||||
- **母亲身高(mother_height)**:必填,数字
|
||||
- **IGF-1值(IGF)**:必填,数字,单位:ng/ml
|
||||
- **LH值(LH)**:必填,数字,单位:mIU/ml
|
||||
- **子宫厚度(uterus_thickness)**:必填,数字,单位:mm
|
||||
|
||||
**前端计算公式:**
|
||||
```
|
||||
Y = 3.726 - 0.876×(BA-CA) - 0.058×(IGF-1) + 0.229×(IGFBP-3)
|
||||
P = e^Y / (1 + e^Y)
|
||||
```
|
||||
|
||||
其中:
|
||||
- Y:中间变量
|
||||
- P:GHD预测概率(0-1之间)
|
||||
- BA-CA:骨龄与实际年龄的差值
|
||||
|
||||
**后端API计算公式:**
|
||||
```
|
||||
P = exp(-5.908 + 0.008×IGF-1 + 2.146×LH + 0.286×子宫厚度) /
|
||||
(1 + exp(-5.908 + 0.008×IGF-1 + 2.146×LH + 0.286×子宫厚度))
|
||||
```
|
||||
|
||||
其中:
|
||||
- P:GHD预测概率(0-1之间),保留3位小数
|
||||
|
||||
**输出结果:**
|
||||
- GHD预测概率(百分比形式)
|
||||
- 计算过程详情(分步骤展示)
|
||||
- 结果解释和建议
|
||||
|
||||
**结果分级:**
|
||||
- **P ≥ 0.8**:GHD可能性较大,建议进一步进行相关检查
|
||||
- **0.5 ≤ P < 0.8**:存在GHD可能,建议进行相关检查
|
||||
- **P < 0.5**:GHD可能性较小,但仍需结合临床表现进行综合判断
|
||||
|
||||
**参考范围:**
|
||||
系统内置IGF-1和IGFBP-3的参考范围(按性别和年龄段):
|
||||
- IGF-1参考范围(男性/女性,0-17岁,分9个年龄段)
|
||||
- IGFBP-3参考范围(男性/女性,0-17岁,分9个年龄段)
|
||||
|
||||
#### 3.1.2 其他工具页面
|
||||
|
||||
根据小程序配置,还包含以下页面:
|
||||
- **首页(home)**:展示资讯和功能入口
|
||||
- **个人中心(my)**:用户信息、历史记录
|
||||
- **IGF参考值(igfrefer)**:IGF-1和IGFBP-3参考范围查询
|
||||
- **身高SDS计算器(heightSdsCalculator)**:身高标准差评分计算
|
||||
- **工具集合(tool)**:其他医疗工具
|
||||
- **性发育图表(sexChart)**:性发育相关图表
|
||||
- **关于(guanyu)**:关于小程序的信息
|
||||
|
||||
#### 3.1.3 用户功能
|
||||
|
||||
- **微信授权登录**:
|
||||
- 通过微信授权获取用户信息
|
||||
- 接口:`/app/Ghdwechat/wechatLogin` 或 `/app/Ruilaiwechat/wechatLogin`
|
||||
- 参数:`code`(微信登录code)、`encryptedData`(加密数据)、`iv`(初始向量)
|
||||
- 返回:用户ID(uid)和登录状态
|
||||
|
||||
- **计算历史记录**:
|
||||
- 查看历史计算记录:`/app/Ghdwechat/selectRecordList` 或 `/app/Ruilaiwechat/selectRecordList`
|
||||
- 删除历史记录:`/app/Ghdwechat/deleteRecord` 或 `/app/Ruilaiwechat/deleteRecord`
|
||||
- 支持分页查询(默认每页30条)
|
||||
|
||||
- **资讯浏览**:
|
||||
- 获取资讯列表:`/app/Ghdwechat/selectRealtimeInfoList` 或 `/app/Ruilaiwechat/selectRealtimeInfoList`
|
||||
- 支持分页查询(默认每页20条)
|
||||
|
||||
### 3.2 后台管理系统功能
|
||||
|
||||
#### 3.2.1 用户登录
|
||||
|
||||
**功能描述:** 管理员登录后台管理系统
|
||||
|
||||
**登录方式:**
|
||||
- 用户名/手机号 + 密码登录
|
||||
- Session会话管理(1小时有效期)
|
||||
|
||||
**权限控制:**
|
||||
- 基于Session的用户身份验证
|
||||
- 不同用户类型可能有不同权限(当前代码中部分权限检查被注释)
|
||||
|
||||
#### 3.2.2 微信用户管理
|
||||
|
||||
**功能描述:** 查看和管理小程序注册用户
|
||||
|
||||
**功能列表:**
|
||||
- **用户列表查询**:
|
||||
- 支持按昵称搜索
|
||||
- 分页显示(默认每页30条)
|
||||
- 显示字段:用户ID、昵称、头像、注册时间
|
||||
- **用户信息查看**:查看用户详细信息
|
||||
|
||||
**数据表:** `ghd_wechat_user`
|
||||
- `uid`:用户ID
|
||||
- `nickname`:昵称
|
||||
- `headimg`:头像
|
||||
- `create_time`:注册时间
|
||||
|
||||
#### 3.2.3 计算记录管理
|
||||
|
||||
**功能描述:** 查看和管理用户的GHD预测计算记录
|
||||
|
||||
**功能列表:**
|
||||
- **记录列表查询**:
|
||||
- 支持按姓名搜索
|
||||
- 分页显示(默认每页30条)
|
||||
- 显示字段:序号、姓名、年龄、身高、骨龄、父亲身高、母亲身高、IGF、LH、子宫厚度、计算结果、创建时间
|
||||
- **记录详情查看**:查看完整的计算记录详情
|
||||
|
||||
**数据表:** `wechat_calculate_record`
|
||||
- `id`:记录ID
|
||||
- `name`:姓名
|
||||
- `age`:年龄
|
||||
- `height`:身高
|
||||
- `bone_age`:骨龄
|
||||
- `father_height`:父亲身高
|
||||
- `mother_height`:母亲身高
|
||||
- `IGF`:IGF-1值
|
||||
- `LH`:LH值
|
||||
- `uterus_thickness`:子宫厚度
|
||||
- `calculate_resutlt`:计算结果
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 3.2.4 资讯管理
|
||||
|
||||
**功能描述:** 管理小程序中展示的医疗资讯
|
||||
|
||||
**功能列表:**
|
||||
- **资讯列表**:
|
||||
- 支持按标题搜索
|
||||
- 分页显示(默认每页30条)
|
||||
- 显示字段:标题、缩略图、简介、跳转链接、创建时间
|
||||
- **添加资讯**:
|
||||
- 标题(必填)
|
||||
- 缩略图(必填)
|
||||
- 简介(必填)
|
||||
- 跳转链接(必填)
|
||||
- **编辑资讯**:修改已有资讯信息
|
||||
- **删除资讯**:删除不需要的资讯
|
||||
|
||||
**数据表:** `wechat_real_time_info`
|
||||
- `id`:资讯ID
|
||||
- `title_plain`:标题
|
||||
- `thumbnail`:缩略图
|
||||
- `excerpt_plain`:简介
|
||||
- `url`:跳转链接
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 3.2.5 菜单管理
|
||||
|
||||
**功能描述:** 管理系统菜单(当前部分功能被注释)
|
||||
|
||||
**功能列表:**
|
||||
- 获取菜单列表
|
||||
- 添加菜单
|
||||
- 修改菜单
|
||||
- 删除菜单
|
||||
|
||||
---
|
||||
|
||||
## 四、数据库设计
|
||||
|
||||
### 4.1 核心数据表
|
||||
|
||||
#### 4.1.1 用户表(t_sys_user)
|
||||
|
||||
**用途:** 存储后台管理员用户信息
|
||||
|
||||
**主要字段:**
|
||||
- `id`:用户ID(主键)
|
||||
- `user_name`:用户名
|
||||
- `phone`:手机号(登录账号)
|
||||
- `password`:密码(MD5加密)
|
||||
- `user_head`:头像
|
||||
- `status`:状态(1:启用,0:禁用)
|
||||
- `type`:用户类型(1:管理员)
|
||||
|
||||
#### 4.1.2 微信用户表(ghd_wechat_user / wechat_user)
|
||||
|
||||
**用途:** 存储小程序注册用户信息
|
||||
|
||||
**主要字段:**
|
||||
- `uid`:用户ID(主键,自增)
|
||||
- `openid`:微信OpenID(唯一标识)
|
||||
- `nickname`:昵称
|
||||
- `headimg`:头像URL
|
||||
- `create_time`:注册时间
|
||||
|
||||
**注意:** 代码中同时使用了 `ghd_wechat_user` 和 `wechat_user` 两个表名,需要确认实际使用的表名
|
||||
|
||||
#### 4.1.3 计算记录表(wechat_calculate_record)
|
||||
|
||||
**用途:** 存储用户的GHD预测计算记录
|
||||
|
||||
**主要字段:**
|
||||
- `id`:记录ID(主键)
|
||||
- `name`:姓名
|
||||
- `age`:年龄
|
||||
- `height`:身高
|
||||
- `bone_age`:骨龄
|
||||
- `father_height`:父亲身高
|
||||
- `mother_height`:母亲身高
|
||||
- `IGF`:IGF-1值
|
||||
- `uid`:用户ID(关联微信用户)
|
||||
- `LH`:LH值(促黄体生成素),单位:mIU/ml
|
||||
- `uterus_thickness`:子宫厚度,单位:mm
|
||||
- `calculate_resutlt`:计算结果(GHD概率,0-1之间,保留3位小数)
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 4.1.4 资讯表(wechat_real_time_info)
|
||||
|
||||
**用途:** 存储小程序展示的医疗资讯
|
||||
|
||||
**主要字段:**
|
||||
- `id`:资讯ID(主键,MD5生成)
|
||||
- `title_plain`:标题
|
||||
- `thumbnail`:缩略图URL
|
||||
- `excerpt_plain`:简介
|
||||
- `url`:跳转链接
|
||||
- `create_time`:创建时间
|
||||
|
||||
#### 4.1.5 菜单表(t_sys_menu)
|
||||
|
||||
**用途:** 存储后台管理系统菜单
|
||||
|
||||
**主要字段:**
|
||||
- `id`:菜单ID(主键)
|
||||
- `pid`:父菜单ID
|
||||
- `menu_name`:菜单名称
|
||||
- `url`:菜单链接
|
||||
- `menu_icon`:菜单图标
|
||||
- `seq_on`:排序序号
|
||||
- `create_time`:创建时间
|
||||
|
||||
---
|
||||
|
||||
## 五、API接口设计
|
||||
|
||||
### 5.1 小程序API接口
|
||||
|
||||
#### 5.1.1 用户相关接口
|
||||
|
||||
**接口路径:** `/app/Ghdwechat/xxx` 或 `/app/Ruilaiwechat/xxx`
|
||||
|
||||
**主要接口:**
|
||||
- 用户登录/注册
|
||||
- 获取用户信息
|
||||
- 更新用户信息
|
||||
|
||||
#### 5.1.2 计算相关接口
|
||||
|
||||
**计算接口:**
|
||||
- **接口路径:** `/app/Ghdwechat/calculate` 或 `/app/Ruilaiwechat/calculate`
|
||||
- **请求方式:** POST
|
||||
- **功能:** 提交计算参数,返回计算结果并保存记录
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"uid": "用户ID",
|
||||
"name": "患者姓名",
|
||||
"age": 10.5,
|
||||
"height": 140,
|
||||
"bone_age": 9.5,
|
||||
"father_height": 175,
|
||||
"mother_height": 160,
|
||||
"IGF": 250,
|
||||
"LH": 0.8,
|
||||
"uterus_thickness": 10
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "计算成功",
|
||||
"calculate_resutlt": 0.661
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"erro": -1,
|
||||
"msg": "错误信息(如:未传入用户id、未传入姓名等)"
|
||||
}
|
||||
```
|
||||
|
||||
**历史记录查询接口:**
|
||||
- **接口路径:** `/app/Ghdwechat/selectRecordList` 或 `/app/Ruilaiwechat/selectRecordList`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"uid": "用户ID",
|
||||
"page": 1,
|
||||
"page_size": 30
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "查询成功",
|
||||
"lists": [
|
||||
{
|
||||
"id": "记录ID",
|
||||
"name": "患者姓名",
|
||||
"age": 10.5,
|
||||
"height": 140,
|
||||
"bone_age": 9.5,
|
||||
"father_height": 175,
|
||||
"mother_height": 160,
|
||||
"IGF": 250,
|
||||
"LH": 0.8,
|
||||
"uterus_thickness": 10,
|
||||
"calculate_resutlt": 0.661,
|
||||
"create_time": "2024-05-19 17:47:17"
|
||||
}
|
||||
],
|
||||
"lastPage": 10,
|
||||
"currentPage": 1
|
||||
}
|
||||
```
|
||||
|
||||
**删除记录接口:**
|
||||
- **接口路径:** `/app/Ghdwechat/deleteRecord` 或 `/app/Ruilaiwechat/deleteRecord`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"uid": "用户ID",
|
||||
"id": "记录ID"
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.3 资讯相关接口
|
||||
|
||||
**获取资讯列表:**
|
||||
- **接口路径:** `/app/Ghdwechat/selectRealtimeInfoList` 或 `/app/Ruilaiwechat/selectRealtimeInfoList`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "查询成功",
|
||||
"lists": [
|
||||
{
|
||||
"title_plain": "资讯标题",
|
||||
"thumbnail": "图片URL",
|
||||
"excerpt_plain": "简介",
|
||||
"url": "跳转链接"
|
||||
}
|
||||
],
|
||||
"lastPage": 10,
|
||||
"currentPage": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.1.4 用户登录接口
|
||||
|
||||
**微信授权登录:**
|
||||
- **接口路径:** `/app/Ghdwechat/wechatLogin` 或 `/app/Ruilaiwechat/wechatLogin`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"code": "微信登录code",
|
||||
"encryptedData": "加密的用户数据",
|
||||
"iv": "初始向量"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "登录成功",
|
||||
"uid": "用户ID"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"erro": -1,
|
||||
"msg": "错误信息(如:未传入code、解析数据失败等)"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 后台管理API接口
|
||||
|
||||
#### 5.2.1 登录接口
|
||||
|
||||
**接口路径:** `/adminghd/Login/login`
|
||||
|
||||
**请求方式:** POST
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"username": "13212345678",
|
||||
"password": "123456",
|
||||
"loginsubmit": "true"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"msg": "登录成功",
|
||||
"token": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.2.2 用户信息接口
|
||||
|
||||
**接口路径:** `/adminghd/Menu/getUserInfor`
|
||||
|
||||
**请求方式:** GET/POST
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"msg": "查询成功",
|
||||
"infro": {
|
||||
"user_name": "管理员",
|
||||
"user_head": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.2.3 微信用户列表接口
|
||||
|
||||
**接口路径:** `/adminghd/Wechatinfro/getWechatUserList`
|
||||
|
||||
**请求方式:** POST
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"page_size": 30,
|
||||
"title": "搜索关键词(可选)"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "查询成功",
|
||||
"lists": [
|
||||
{
|
||||
"uid": "xxx",
|
||||
"nickname": "用户昵称",
|
||||
"headimg": "头像URL",
|
||||
"create_time": "2024-05-19 17:47:17",
|
||||
"no_id": 1
|
||||
}
|
||||
],
|
||||
"lastPage": 10,
|
||||
"currentPage": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.2.4 计算记录列表接口
|
||||
|
||||
**接口路径:** `/adminghd/Wechatinfro/getWechatRecordList`
|
||||
|
||||
**请求方式:** POST
|
||||
|
||||
**请求参数:**
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"page_size": 30,
|
||||
"title": "搜索关键词(可选)"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据:**
|
||||
```json
|
||||
{
|
||||
"erro": 0,
|
||||
"msg": "查询成功",
|
||||
"lists": [
|
||||
{
|
||||
"id": "xxx",
|
||||
"name": "患者姓名",
|
||||
"age": 10.5,
|
||||
"height": 140,
|
||||
"bone_age": 9.5,
|
||||
"father_height": 175,
|
||||
"mother_height": 160,
|
||||
"IGF": 250,
|
||||
"LH": 0.8,
|
||||
"uterus_thickness": 10,
|
||||
"calculate_resutlt": 0.661,
|
||||
"create_time": "2024-05-19 17:47:17",
|
||||
"no_id": 1
|
||||
}
|
||||
],
|
||||
"lastPage": 10,
|
||||
"currentPage": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.2.5 资讯管理接口
|
||||
|
||||
**获取资讯列表:**
|
||||
- **接口路径:** `/adminghd/Wechatset/getWechatRealTimeInfoList`
|
||||
- **请求方式:** POST
|
||||
|
||||
**添加/更新资讯:**
|
||||
- **接口路径:** `/adminghd/Wechatset/saveWechatRealTimeInfo`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"id": "资讯ID(更新时必填)",
|
||||
"title_plain": "标题",
|
||||
"thumbnail": "缩略图URL",
|
||||
"excerpt_plain": "简介",
|
||||
"url": "跳转链接"
|
||||
}
|
||||
```
|
||||
|
||||
**删除资讯:**
|
||||
- **接口路径:** `/adminghd/Wechatset/delWechatRealTimeInfo`
|
||||
- **请求方式:** POST
|
||||
- **请求参数:**
|
||||
```json
|
||||
{
|
||||
"id": "资讯ID"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、预测模型算法
|
||||
|
||||
### 6.1 GHD预测模型(小程序前端模型 - 基于骨龄和IGF指标)
|
||||
|
||||
**模型公式:**
|
||||
```
|
||||
Y = 3.726 - 0.876×(BA-CA) - 0.058×(IGF-1) + 0.229×(IGFBP-3)
|
||||
P = e^Y / (1 + e^Y)
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
- **BA**:骨龄(Bone Age),单位:年
|
||||
- **CA**:实际年龄(Chronological Age),单位:年
|
||||
- **IGF-1**:胰岛素样生长因子-1,单位:ng/ml
|
||||
- **IGFBP-3**:胰岛素样生长因子结合蛋白-3,单位:mg/L
|
||||
- **Y**:中间变量(对数几率)
|
||||
- **P**:GHD预测概率(0-1之间)
|
||||
|
||||
**计算步骤:**
|
||||
1. 计算骨龄差值:BA-CA
|
||||
2. 代入公式计算Y值
|
||||
3. 通过Logistic函数计算概率P
|
||||
4. 将P转换为百分比形式
|
||||
|
||||
**使用场景:** 小程序前端计算器页面(`ghdCalculator`),用于前端实时计算展示
|
||||
|
||||
### 6.2 GHD预测模型(后端API模型 - 基于IGF、LH和子宫厚度)
|
||||
|
||||
**模型公式:**
|
||||
```
|
||||
P = exp(-5.908 + 0.008×IGF-1 + 2.146×LH + 0.286×子宫厚度) /
|
||||
(1 + exp(-5.908 + 0.008×IGF-1 + 2.146×LH + 0.286×子宫厚度))
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
- **IGF-1**:胰岛素样生长因子-1,单位:ng/ml
|
||||
- **LH**:促黄体生成素(Luteinizing Hormone),单位:mIU/ml
|
||||
- **子宫厚度**:单位:mm
|
||||
- **P**:预测概率(0-1之间),保留3位小数
|
||||
|
||||
**计算步骤:**
|
||||
1. 计算指数部分:exp(-5.908 + 0.008×IGF-1 + 2.146×LH + 0.286×子宫厚度)
|
||||
2. 通过Logistic函数计算概率P
|
||||
3. 将P四舍五入保留3位小数
|
||||
|
||||
**使用场景:** 后端API接口(`/app/Ghdwechat/calculate` 和 `/app/Ruilaiwechat/calculate`),用于服务器端计算并保存记录
|
||||
|
||||
**输入参数(后端API):**
|
||||
- `uid`:用户ID(必填)
|
||||
- `name`:患者姓名(必填)
|
||||
- `age`:年龄(必填,数字)
|
||||
- `height`:身高(必填,数字)
|
||||
- `bone_age`:骨龄(必填,数字)
|
||||
- `father_height`:父亲身高(必填,数字)
|
||||
- `mother_height`:母亲身高(必填,数字)
|
||||
- `IGF`:IGF-1值(必填,数字)
|
||||
- `LH`:LH值(必填,数字)
|
||||
- `uterus_thickness`:子宫厚度(必填,数字)
|
||||
|
||||
**输出结果:**
|
||||
- `calculate_resutlt`:计算结果(概率值,0-1之间)
|
||||
- 计算结果自动保存到数据库表 `wechat_calculate_record`
|
||||
|
||||
**注意:**
|
||||
- 小程序前端和后端API使用不同的预测模型公式
|
||||
- 前端模型基于骨龄和IGF指标,后端模型基于IGF、LH和子宫厚度
|
||||
- 两个模型可能适用于不同的预测场景或患者群体
|
||||
- 建议统一模型或明确说明两个模型的适用场景
|
||||
|
||||
---
|
||||
|
||||
## 七、非功能性需求
|
||||
|
||||
### 7.1 性能需求
|
||||
|
||||
- **响应时间**:API接口响应时间 < 500ms
|
||||
- **并发支持**:支持至少100个并发用户
|
||||
- **数据库查询**:优化查询性能,使用索引
|
||||
|
||||
### 7.2 安全需求
|
||||
|
||||
- **数据加密**:用户密码使用MD5加密存储
|
||||
- **Session管理**:使用Session进行用户身份验证
|
||||
- **HTTPS支持**:生产环境使用HTTPS协议
|
||||
- **SQL注入防护**:使用ThinkPHP的ORM防止SQL注入
|
||||
- **XSS防护**:对用户输入进行过滤和转义
|
||||
|
||||
### 7.3 可用性需求
|
||||
|
||||
- **系统可用性**:99%以上
|
||||
- **数据备份**:定期备份数据库
|
||||
- **错误处理**:友好的错误提示信息
|
||||
|
||||
### 7.4 兼容性需求
|
||||
|
||||
- **微信小程序**:支持微信小程序最新版本
|
||||
- **浏览器**:后台管理系统支持主流浏览器(Chrome、Firefox、Safari、Edge)
|
||||
- **移动端**:后台管理系统支持移动端访问
|
||||
|
||||
---
|
||||
|
||||
## 八、部署要求
|
||||
|
||||
### 8.1 服务器环境
|
||||
|
||||
- **操作系统**:Linux(CentOS 7+)
|
||||
- **Web服务器**:Nginx 1.20+
|
||||
- **PHP版本**:PHP 5.6+(推荐PHP 7.3+)
|
||||
- **数据库**:MySQL 5.7+
|
||||
- **PHP扩展**:mysqli、pdo_mysql、mbstring、openssl
|
||||
|
||||
### 8.2 目录权限
|
||||
|
||||
- `runtime/`:可写权限(日志、缓存)
|
||||
- `public/uploads/`:可写权限(文件上传)
|
||||
- `public/static/`:可读权限(静态资源)
|
||||
|
||||
### 8.3 配置文件
|
||||
|
||||
- **数据库配置**:`/www/wwwroot/code/application/database.php`
|
||||
- **应用配置**:`/www/wwwroot/code/application/config.php`
|
||||
- **Nginx配置**:`/etc/nginx/conf.d/default.conf` 或宝塔面板配置
|
||||
|
||||
---
|
||||
|
||||
## 九、项目现状
|
||||
|
||||
### 9.1 已完成功能
|
||||
|
||||
✅ **后台管理系统:**
|
||||
- 用户登录功能
|
||||
- 微信用户管理
|
||||
- 计算记录管理
|
||||
- 资讯管理
|
||||
- 菜单管理(部分功能)
|
||||
|
||||
✅ **小程序前端:**
|
||||
- GHD计算器页面
|
||||
- 首页、个人中心等基础页面
|
||||
- 计算逻辑实现
|
||||
|
||||
✅ **后端API:**
|
||||
- 用户相关接口
|
||||
- 计算记录接口
|
||||
- 资讯接口
|
||||
|
||||
### 9.2 待完善功能
|
||||
|
||||
⏳ **数据验证:**
|
||||
- 输入参数的范围验证
|
||||
- 计算结果合理性检查
|
||||
|
||||
⏳ **用户体验:**
|
||||
- 错误提示优化
|
||||
- 加载状态提示
|
||||
- 结果可视化展示
|
||||
|
||||
⏳ **功能扩展:**
|
||||
- 计算历史记录查看(小程序端)
|
||||
- 数据导出功能
|
||||
- 统计分析功能
|
||||
|
||||
⏳ **文档完善:**
|
||||
- API接口文档
|
||||
- 用户使用手册
|
||||
- 管理员操作手册
|
||||
|
||||
---
|
||||
|
||||
## 十、风险评估
|
||||
|
||||
### 10.1 技术风险
|
||||
|
||||
- **PHP版本兼容性**:当前使用PHP 5.6,建议升级到PHP 7.3+
|
||||
- **数据库连接**:需要确保MySQL服务稳定运行
|
||||
- **Session管理**:需要确保Session配置正确
|
||||
|
||||
### 10.2 业务风险
|
||||
|
||||
- **数据准确性**:预测模型需要定期验证和优化
|
||||
- **医疗责任**:系统仅作为辅助工具,不能替代专业医疗诊断
|
||||
- **数据隐私**:需要保护患者隐私信息
|
||||
|
||||
### 10.3 运维风险
|
||||
|
||||
- **数据备份**:需要建立定期备份机制
|
||||
- **系统监控**:需要监控系统运行状态
|
||||
- **安全更新**:需要及时更新安全补丁
|
||||
|
||||
---
|
||||
|
||||
## 十一、后续规划
|
||||
|
||||
### 11.1 短期规划(1-3个月)
|
||||
|
||||
1. **功能优化**:
|
||||
- 完善输入验证
|
||||
- 优化用户界面
|
||||
- 添加计算历史功能
|
||||
|
||||
2. **性能优化**:
|
||||
- 数据库查询优化
|
||||
- 缓存机制引入
|
||||
- 接口响应时间优化
|
||||
|
||||
3. **文档完善**:
|
||||
- 编写API文档
|
||||
- 编写用户手册
|
||||
|
||||
### 11.2 中期规划(3-6个月)
|
||||
|
||||
1. **功能扩展**:
|
||||
- 多模型支持
|
||||
- 数据统计分析
|
||||
- 报告生成功能
|
||||
|
||||
2. **技术升级**:
|
||||
- PHP版本升级
|
||||
- 框架版本升级
|
||||
- 前端框架优化
|
||||
|
||||
### 11.3 长期规划(6-12个月)
|
||||
|
||||
1. **智能化**:
|
||||
- 机器学习模型集成
|
||||
- 个性化推荐
|
||||
- 智能诊断辅助
|
||||
|
||||
2. **平台化**:
|
||||
- 多租户支持
|
||||
- 开放API平台
|
||||
- 第三方集成
|
||||
|
||||
---
|
||||
|
||||
## 十二、附录
|
||||
|
||||
### 12.1 术语表
|
||||
|
||||
- **GHD**:Growth Hormone Deficiency,生长激素缺乏
|
||||
- **IGF-1**:Insulin-like Growth Factor-1,胰岛素样生长因子-1
|
||||
- **IGFBP-3**:Insulin-like Growth Factor Binding Protein-3,胰岛素样生长因子结合蛋白-3
|
||||
- **BA**:Bone Age,骨龄
|
||||
- **CA**:Chronological Age,实际年龄
|
||||
- **LH**:Luteinizing Hormone,促黄体生成素
|
||||
|
||||
### 12.2 参考文档
|
||||
|
||||
- ThinkPHP 5.0 官方文档:http://www.kancloud.cn/manual/thinkphp5
|
||||
- 微信小程序开发文档:https://developers.weixin.qq.com/miniprogram/dev/framework/
|
||||
- MySQL官方文档:https://dev.mysql.com/doc/
|
||||
|
||||
### 12.3 联系方式
|
||||
|
||||
- **项目地址**:`/www/wwwroot/code`
|
||||
- **后台管理地址**:`https://www.ruilaizipj.com/adminghd/login`
|
||||
- **数据库**:MySQL (`ruilai`)
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
|
||||
**创建时间:** 2025年1月28日
|
||||
**最后更新:** 2025年1月28日
|
||||
**文档版本:** v1.0
|
||||
BIN
admin_pic.png
Normal file
BIN
admin_pic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
77
application/admin/controller/Dashboard.php
Normal file
77
application/admin/controller/Dashboard.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\common\Base;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 系统概览控制器
|
||||
* 早熟预测后台独立实现,不再依赖common模块
|
||||
*/
|
||||
class Dashboard extends Base
|
||||
{
|
||||
/**
|
||||
* 后台首页概览
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->view->fetch('dashboard/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* admin模块独立实现,使用wechat_user表
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
// admin模块使用的表名(固定)
|
||||
$userTable = 'wechat_user';
|
||||
$infoTable = 'wechat_real_time_info';
|
||||
$recordTable = 'wechat_calculate_record';
|
||||
|
||||
// 小程序注册用户数量
|
||||
$userCount = Db::name($userTable)->count();
|
||||
|
||||
// 首页资讯数量
|
||||
$infoCount = Db::name($infoTable)->count();
|
||||
|
||||
// 最近一次计算时间
|
||||
$lastCalculate = Db::name($recordTable)
|
||||
->order('create_time desc')
|
||||
->value('create_time');
|
||||
|
||||
// 今日新增用户
|
||||
$todayUserCount = Db::name($userTable)
|
||||
->whereTime('create_time', 'today')
|
||||
->count();
|
||||
|
||||
// 总计算次数
|
||||
$totalCalculateCount = Db::name($recordTable)->count();
|
||||
|
||||
return json([
|
||||
'status' => 1,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'user_count' => $userCount,
|
||||
'info_count' => $infoCount,
|
||||
'last_calculate_time' => $lastCalculate ?: '暂无',
|
||||
'today_user_count' => $todayUserCount,
|
||||
'total_calculate_count' => $totalCalculateCount
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'status' => 0,
|
||||
'msg' => '获取失败:' . $e->getMessage(),
|
||||
'data' => [
|
||||
'user_count' => 0,
|
||||
'info_count' => 0,
|
||||
'last_calculate_time' => '暂无',
|
||||
'today_user_count' => 0,
|
||||
'total_calculate_count' => 0
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
138
application/admin/view/dashboard/index.html
Normal file
138
application/admin/view/dashboard/index.html
Normal file
@@ -0,0 +1,138 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>系统概览</title>
|
||||
<link rel="stylesheet" href="/static/admin/layui/css/layui.css">
|
||||
<style>
|
||||
body{
|
||||
background:#f5f7fb;
|
||||
padding:24px 24px 40px;
|
||||
box-sizing:border-box;
|
||||
font-family:"Microsoft YaHei",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
|
||||
}
|
||||
.dash-card{
|
||||
background:#fff;
|
||||
border-radius:10px;
|
||||
box-shadow:0 10px 30px rgba(15,35,52,0.06);
|
||||
padding:20px 24px;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.dash-title{
|
||||
font-size:18px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.dash-sub{
|
||||
font-size:12px;
|
||||
color:#9aa4b1;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
.dash-grid{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:16px;
|
||||
}
|
||||
.dash-item{
|
||||
flex:1 1 200px;
|
||||
min-width:200px;
|
||||
background:#f8fafc;
|
||||
border-radius:8px;
|
||||
padding:14px 16px;
|
||||
cursor:pointer;
|
||||
transition:all 0.3s;
|
||||
}
|
||||
.dash-item:hover{
|
||||
background:#f0f4f8;
|
||||
transform:translateY(-2px);
|
||||
box-shadow:0 4px 12px rgba(15,35,52,0.1);
|
||||
}
|
||||
.dash-item-label{
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.dash-item-value{
|
||||
margin-top:6px;
|
||||
font-size:22px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
}
|
||||
.dash-item-desc{
|
||||
margin-top:4px;
|
||||
font-size:12px;
|
||||
color:#b0b7c3;
|
||||
}
|
||||
.dash-empty{
|
||||
margin-top:10px;
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.loading{
|
||||
text-align:center;
|
||||
padding:40px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="dash-card">
|
||||
<div class="dash-title">欢迎使用后台管理系统</div>
|
||||
<div class="dash-sub">这里是系统概览,实时展示系统统计数据。</div>
|
||||
<div class="dash-grid" id="dashGrid">
|
||||
<div class="loading">数据加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/admin/js/jquery.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
// 加载统计数据
|
||||
loadStatistics();
|
||||
|
||||
function loadStatistics(){
|
||||
$.ajax({
|
||||
url: '/admin/Dashboard/getStatistics',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status == 1){
|
||||
renderStatistics(res.data);
|
||||
} else {
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败:' + res.msg + '</div>');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败,请稍后重试</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatistics(data){
|
||||
var html = `
|
||||
<div class="dash-item" onclick="parent.location.href='/admin/wechatinfro/wechatUserList'">
|
||||
<div class="dash-item-label">小程序注册用户</div>
|
||||
<div class="dash-item-value">${data.user_count}</div>
|
||||
<div class="dash-item-desc">今日新增:${data.today_user_count} 人</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/admin/wechatset/wechatRealTimeInfo'">
|
||||
<div class="dash-item-label">首页资讯数量</div>
|
||||
<div class="dash-item-value">${data.info_count}</div>
|
||||
<div class="dash-item-desc">可在「咨询管理」菜单中维护展示内容</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/admin/wechatinfro/wechatRecordList'">
|
||||
<div class="dash-item-label">总计算次数</div>
|
||||
<div class="dash-item-value">${data.total_calculate_count}</div>
|
||||
<div class="dash-item-desc">最近一次:${data.last_calculate_time}</div>
|
||||
</div>
|
||||
`;
|
||||
$('#dashGrid').html(html);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,143 +1,106 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>用户登录</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>登录 - 女童成长发育早熟预测模型后台</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/admin/css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/admin/css/login.css" />
|
||||
<style>
|
||||
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); padding: 20px; box-sizing: border-box; }
|
||||
.login-card { width: 100%; max-width: 400px; background: #fff; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.2); overflow: hidden; }
|
||||
.login-card .login-header { padding: 36px 24px 24px; text-align: center; border-bottom: 1px solid #f0f0f0; }
|
||||
.login-card .login-title { font-size: 18px; font-weight: 600; color: #1f2d3d; line-height: 1.5; margin: 0; }
|
||||
.login-card .login-body { padding: 32px 28px 40px; }
|
||||
.login-card .form-item { margin-bottom: 22px; }
|
||||
.login-card .form-item input { width: 100%; height: 48px; padding: 0 16px; border: 1px solid #e0e0e0; border-radius: 8px; font-size: 15px; color: #333; background: #fafafa; box-sizing: border-box; transition: border-color .2s, background .2s; }
|
||||
.login-card .form-item input::placeholder { color: #aaa; }
|
||||
.login-card .form-item input:focus { outline: none; border-color: #667eea; background: #fff; }
|
||||
.login-card .form-item .warning { display: block; margin-top: 6px; font-size: 12px; color: #e4393c; min-height: 18px; }
|
||||
.login-card .btn-login { width: 100%; height: 48px; border: none; border-radius: 8px; font-size: 16px; font-weight: 500; color: #fff; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); cursor: pointer; transition: opacity .2s, transform .05s; }
|
||||
.login-card .btn-login:hover { opacity: 0.95; }
|
||||
.login-card .btn-login:active { transform: scale(0.99); }
|
||||
#cover.modal { display: none !important; line-height: 100vh; text-align: center; position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0,0,0,0.6); z-index: 9999; color: #fff; font-size: 18px; }
|
||||
#cover.modal.show { display: flex !important; align-items: center; justify-content: center; }
|
||||
</style>
|
||||
</head>
|
||||
<style>
|
||||
.login-top .tbb{ font-size:18px; font-weight:bold; position:absolute; bottom:0; left:195px; color:#FFD200;}
|
||||
</style>
|
||||
<body style='min-width:1235px'>
|
||||
<div style='height:100px;'></div>
|
||||
<div style='background:#e3e3e3;height:450px;width:100%;position:relative;'>
|
||||
<div style='width:350px;height:400px;background:#EDF1F5;float:right;margin-right:20%;margin-top:1.5%;box-shadow:#666 0px 0px 20px;'>
|
||||
<div class="login-top" style="padding-bottom:0;">
|
||||
<div style='color:#453A3E;margin:30px auto 10px auto;width:150px;font-size:18px;font-weight:bold;text-align:center;'>瑞莱医疗</div>
|
||||
</div>
|
||||
<div style='height:1px;width:100%;background:#DEDCDD;'>
|
||||
<div style='background:#e3e3e3;height:3px;width:80%;margin:0px auto 0 auto;'></div>
|
||||
</div>
|
||||
<form method="post" id="agent_login" name="login">
|
||||
<div class="login-content">
|
||||
<ul class="user-logn">
|
||||
<li class="user-jobnum" style='width:100%;margin-bottom:0px;'>
|
||||
<div class="li-bg error" style='width:100%;'>
|
||||
<label></label>
|
||||
<input type="text" id="username" name="username" placeholder="请输入账号" value="" validate="" validatename="工号" class="phonecode" style='width:83%;padding-right:0px;background:#EDF1F5;height:40px;border:2px solid balck;border-radius:4px;'/>
|
||||
<span id="checkusername" class="warning"></span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="pwd" style='width:100%;margin-bottom:0px;'>
|
||||
<div class="li-bg " style='width:100%;'>
|
||||
<label></label>
|
||||
<input type="password" style="width: 0;height: 0;border: none;" name="">
|
||||
<input type="password" autocomplete="off" id="admin_password" name="password" class="pwd" placeholder="请输入密码" validate="" validatename="密码" style='border:2px solid balck;width:83%;padding-right:0px;background:#EDF1F5;height:40px;border-radius:4px;'>
|
||||
<span id="checkpassword" class="warning"></span>
|
||||
</div>
|
||||
</li>
|
||||
<li style="margin-top:40px;width:100%;">
|
||||
<button type="submit" name="dologinbtn" style='background:#afaeb2;border-radius:4px;height:35px;width:100%;' class="actLogin" onclick="return checklogin(this.form);">立即登录</button>
|
||||
<input type="hidden" name="loginsubmit" value="true" />
|
||||
</li>
|
||||
</ul>
|
||||
<body>
|
||||
<div class="login-wrap">
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<h1 class="login-title">女童成长发育早熟预测模型后台</h1>
|
||||
</div>
|
||||
</form>
|
||||
<div class="login-body">
|
||||
<form method="post" id="agent_login" name="login">
|
||||
<div class="form-item">
|
||||
<input type="text" id="username" name="username" placeholder="请输入账号" value="" autocomplete="username" />
|
||||
<span id="checkusername" class="warning"></span>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<input type="password" style="width:0;height:0;border:none;position:absolute;opacity:0;" name="" tabindex="-1" />
|
||||
<input type="password" autocomplete="off" id="admin_password" name="password" placeholder="请输入密码" />
|
||||
<span id="checkpassword" class="warning"></span>
|
||||
</div>
|
||||
<div class="form-item" style="margin-bottom:0;margin-top:28px;">
|
||||
<button type="submit" name="dologinbtn" class="btn-login" onclick="return checklogin(this.form);">立即登录</button>
|
||||
<input type="hidden" name="loginsubmit" value="true" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="cover" class="modal">身份获取中。。。</div>
|
||||
</div>
|
||||
|
||||
<div id="cover" class="modal" style="display:none !important;">身份获取中...</div>
|
||||
|
||||
<script type="text/javascript" src="/static/admin/js/jquery.js"></script>
|
||||
<script>
|
||||
var _login_time = -1;
|
||||
var _user_type = '';
|
||||
function checklogin(form){
|
||||
var phonenumFlg = true;
|
||||
var pwdFlg = true;
|
||||
if(!form.username.value || form.username.value.trim() === ''){
|
||||
$('#checkusername').text('账号不能为空').addClass("warning");
|
||||
phonenumFlg = false;
|
||||
} else {
|
||||
$('#checkusername').empty();
|
||||
}
|
||||
if(!form.password.value || form.password.value === ''){
|
||||
$('#checkpassword').text('密码不能为空').addClass("warning");
|
||||
pwdFlg = false;
|
||||
} else {
|
||||
$('#checkpassword').empty();
|
||||
}
|
||||
if(phonenumFlg && pwdFlg){
|
||||
$("#agent_login").off('submit').on("submit", function(event) {
|
||||
event.preventDefault();
|
||||
var $cover = $('#cover');
|
||||
$cover.addClass('show').css('display','flex');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/admin/Login/login",
|
||||
data: $(this).serialize(),
|
||||
success: function(data) {
|
||||
$cover.removeClass('show').hide();
|
||||
if(data.status){
|
||||
location.replace("/admin/login");
|
||||
} else {
|
||||
alert(data.msg);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
$cover.removeClass('show').hide();
|
||||
console.error("Error: " + textStatus);
|
||||
alert('登录请求失败,请稍后重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#agent_login").submit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<script type="text/javascript" src="/static/admin/js/jquery.js"></script>
|
||||
<script>
|
||||
var _login_time = -1;
|
||||
var _user_type = '';
|
||||
|
||||
function checklogin(form){
|
||||
var username = $('username').value;
|
||||
var pwd = $('password').value;
|
||||
var phonenumFlg = true;
|
||||
var pwdFlg = true;
|
||||
//var codeFlg = true;
|
||||
if(form.username.value == null || form.username.value == ""){
|
||||
$('#checkusername').empty();
|
||||
$('#checkusername').append(' 账号不能为空!');
|
||||
$('#checkusername').addClass("warning");
|
||||
phonenumFlg = false;
|
||||
return phonenumFlg;
|
||||
}else{
|
||||
$('#checkusername').empty();
|
||||
// $('#checkusername').append('<img src="/images/base/check_right.gif" width="13" height="13">');
|
||||
$('#checkusername').addClass("warning");
|
||||
}
|
||||
if(form.password.value == null || form.password.value == ""){
|
||||
$('#checkpassword').empty();
|
||||
$('#checkpassword').append(' 密码不能为空!');
|
||||
$('#checkpassword').addClass("warning");
|
||||
pwdFlg = false;
|
||||
return pwdFlg;
|
||||
}else{
|
||||
$('#checkpassword').empty();
|
||||
// $('#checkpassword').append('<img src="/images/base/check_right.gif" width="13" height="13">');
|
||||
$('#checkpassword').addClass("warning");
|
||||
}
|
||||
if(phonenumFlg == true && pwdFlg == true){
|
||||
// alert(11);
|
||||
$("#agent_login").submit(function(event) {
|
||||
event.preventDefault(); // 阻止表单默认提交行为
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/admin/Login/login", // 服务器端脚本的 URL
|
||||
data: $(this).serialize(), // 自动序列化表单元素为字符串
|
||||
success: function(data) {
|
||||
if(data.status){
|
||||
//alert(data.msg);
|
||||
location.replace("/admin/login");
|
||||
// location.reload();
|
||||
} else {
|
||||
alert(data.msg);
|
||||
return ;
|
||||
}
|
||||
console.log(response); // 处理服务器响应
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error("Error submitting form: " + textStatus);
|
||||
}
|
||||
});
|
||||
});
|
||||
// $('#agent_login').submit();
|
||||
// ajaxpost('registerform', 'register');
|
||||
// $('#agent_login').ajaxSubmit({
|
||||
/* $.ajax({
|
||||
url:'/admin/Login/login',
|
||||
dataType:'json',
|
||||
type:'post',
|
||||
data:{
|
||||
"username":username,
|
||||
"password":pwd
|
||||
},
|
||||
success:function(data){
|
||||
alert(222);
|
||||
alert(data.msg);
|
||||
return false;
|
||||
if(data.status){
|
||||
alert(data.msg);
|
||||
// $(form).resetForm();
|
||||
} else {
|
||||
alert(data.msg);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}) */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>瑞莱医疗后台</title>
|
||||
<title>女童成长发育早熟预测模型后台</title>
|
||||
|
||||
<link rel="stylesheet" href="/static/admin/layui/css/layui.css?t=1554901097999" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="/static/admin/css/nav.css" />
|
||||
@@ -33,17 +33,9 @@
|
||||
</div>
|
||||
<!--顶部-->
|
||||
<div class="top_right">
|
||||
<a href="javascript:void(0)" class="logo">
|
||||
<!-- <img id="packBtn" src="{S_URL}/templates/adminfactory/img/logo.png">-->
|
||||
</a>
|
||||
<b></b>
|
||||
<div class="header_title">女童成长发育早熟预测模型后台</div>
|
||||
<div class="user_right">
|
||||
<a href="javascript:;" id="user" style="position: absolute;left: 100px;top: 4px;font-size: 16px;"></a>
|
||||
<span id="inform">
|
||||
<!-- 您好!工厂
|
||||
<img id="u_headimg" src="{S_URL}/templates/adminfactory/img/logo.png" alt="">
|
||||
<i>荣麟</i> -->
|
||||
</span>
|
||||
<span id="inform"></span>
|
||||
<b class="out" id="sign_out">退出</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
1
application/admincpp/common.php
Normal file
1
application/admincpp/common.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
109
application/admincpp/common/Base.php
Normal file
109
application/admincpp/common/Base.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace app\admincpp\common;
|
||||
use think\Controller;
|
||||
use think\Session;
|
||||
// use think\Request;
|
||||
// use think\Db;
|
||||
use think\Response;
|
||||
|
||||
class Base extends Controller
|
||||
{
|
||||
protected function _initialize()
|
||||
{
|
||||
if(!session('admincpp_user_id')){//没有登录信息
|
||||
// $this->redirect('login/index');
|
||||
return $this->error('您还未登录',url('Login/logoutJump'));
|
||||
//Response::create(['status' => '0','msg'=> '还未登录,验证失败'], 'json')->send();
|
||||
exit;
|
||||
}else{
|
||||
//登录信息超时
|
||||
$log_time=session('admincpp_user_login_time')-time();
|
||||
if($log_time < 0){
|
||||
Session::clear();
|
||||
//Response::create(['status' => '0','msg'=> '登录超时,需重新登陆'], 'json')->send();
|
||||
return $this->error('登录超时',url('Login/logoutJump'));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
//简单的token生成函数
|
||||
/* protected function create_token()
|
||||
{
|
||||
$str = md5(uniqid(md5(microtime(true)), true)); //生成一个不会重复的字符串
|
||||
$str = sha1($str); //加密
|
||||
return $str;
|
||||
}
|
||||
//验证Token
|
||||
public function checkToken($token)
|
||||
{
|
||||
$user = Db::name('user')->where('token', $token)->find();
|
||||
if (empty($user)) {
|
||||
return ['status'=>0,'msg'=>'token错误,验证失败'];
|
||||
}else{
|
||||
if (time() - $user['time_out'] > 0) {
|
||||
return ['status'=>0,'msg'=>'token长时间未使用而过期,需重新登陆'];
|
||||
}
|
||||
return ['status'=>1,'msg'=>'成功!','data'=>$user];
|
||||
}
|
||||
}
|
||||
//通过分组id获取分组名称
|
||||
public function getGroupName($id){
|
||||
$res = Db::name('group')->field('group_name')->where('group_id',$id)->find();
|
||||
if($res){
|
||||
return $res['group_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'分组匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
//通过城市id获取城市名称
|
||||
public function getCityName($id){
|
||||
$res = Db::name('city')->field('city_name')->where('city_id',$id)->find();
|
||||
if($res){
|
||||
return $res['city_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'城市匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
//通过工厂id获取工厂名称
|
||||
public function getFirmName($id){
|
||||
$res = Db::name('firm')->field('firm_name')->where('firm_id',$id)->find();
|
||||
if($res){
|
||||
return $res['firm_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'工厂匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
//通过品牌id获取品牌名称
|
||||
public function getBrandName($id){
|
||||
$res = Db::name('brand')->field('brand_name')->where('brand_id',$id)->find();
|
||||
if($res){
|
||||
return $res['brand_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'品牌匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
//通过代理商id获取代理商名称
|
||||
public function getVenderName($id){
|
||||
$res = Db::name('vender')->field('vender_name')->where('vender_id',$id)->find();
|
||||
if($res){
|
||||
return $res['vender_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'代理商匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
//通过角色id获取角色名称
|
||||
public function getRoleName($id){
|
||||
$res = Db::name('role')->field('role_name')->where('role_id',$id)->find();
|
||||
if($res){
|
||||
return $res['role_name'];
|
||||
}else{
|
||||
// return json_encode(['status'=>0,'msg'=>'角色匹配不到']);
|
||||
return '';
|
||||
}
|
||||
}*/
|
||||
}
|
||||
5
application/admincpp/config.php
Normal file
5
application/admincpp/config.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
//配置文件
|
||||
return [
|
||||
|
||||
];
|
||||
40
application/admincpp/controller/Dashboard.php
Normal file
40
application/admincpp/controller/Dashboard.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Db;
|
||||
|
||||
class Dashboard extends Base
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return $this->view->fetch("dashboard/index");
|
||||
}
|
||||
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
$userCount = Db::name("wechat_user")->count();
|
||||
$todayUserCount = Db::name("wechat_user")
|
||||
->where("create_time", ">=", date("Y-m-d") . " 00:00:00")
|
||||
->count();
|
||||
$recordCount = Db::name("cpp_calculate_record")->count();
|
||||
$infoCount = Db::name("wechat_real_time_info")->count();
|
||||
$lastCalculate = Db::name("cpp_calculate_record")
|
||||
->order("create_time desc")->value("create_time");
|
||||
|
||||
return json([
|
||||
"status" => 1,
|
||||
"data" => [
|
||||
"user_count" => $userCount,
|
||||
"today_user_count" => $todayUserCount,
|
||||
"total_calculate_count" => $recordCount,
|
||||
"info_count" => $infoCount,
|
||||
"last_calculate_time" => $lastCalculate ?: "暂无",
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json(["status" => 0, "msg" => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
118
application/admincpp/controller/Files.php
Normal file
118
application/admincpp/controller/Files.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
//use think\Db;
|
||||
//use think\Log;
|
||||
//use think\Image;
|
||||
use think\Response;
|
||||
/**
|
||||
*上传文件
|
||||
*/
|
||||
class Files extends Base
|
||||
{
|
||||
/**
|
||||
*上传图片
|
||||
*@param
|
||||
*/
|
||||
public function uploadImg(Request $request)
|
||||
{
|
||||
$typeArr = array("jpg","png",'jpeg');//图片类型
|
||||
$path = "uploads/" . date('Y/m/d/');//上传路径
|
||||
if(!file_exists($path)){
|
||||
//创建文件
|
||||
mkdir($path,0777,true);
|
||||
}
|
||||
if ($_FILES) {
|
||||
$name = $_FILES['file']['name'];
|
||||
$size = $_FILES['file']['size'];
|
||||
$name_tmp = $_FILES['file']['tmp_name'];
|
||||
if (empty($name)) {
|
||||
return json(array("status"=>"-1","error"=>"图片不能为空"));
|
||||
exit;
|
||||
}
|
||||
$type = strtolower(substr(strrchr($name, '.'), 1)); //获取文件类型
|
||||
|
||||
if (!in_array($type, $typeArr)) {
|
||||
return json(array("status"=>"-1","error"=>"请上传jpg,png,或jpeg类型的文件!"));//mov,webm
|
||||
exit;
|
||||
}
|
||||
if ($size > (2 * 1024 * 1024)) {
|
||||
return json(array("status"=>"-1","error"=>"文件大小已超过2MB!"));
|
||||
exit;
|
||||
}
|
||||
|
||||
/* if($_GET['type'] == 'cx'){
|
||||
$imageType = 'cx';
|
||||
}*/
|
||||
$imageType='';
|
||||
$pic_name = $imageType.time() . rand(10000, 99999) . "." . $type;//图片名称
|
||||
$pic_url =$path . $pic_name;//上传后图片路径+名称
|
||||
|
||||
if (move_uploaded_file($name_tmp, $pic_url)) { //临时文件转移到目标文件夹
|
||||
/* $_POST['name'] = $pic_name;
|
||||
$_POST['topic'] = $imageType;
|
||||
$_POST['albumPath'] = $pic_url;*/
|
||||
return json(array("status"=>"0","file_name"=>$pic_name,"file_path"=>$request->domain().'/'.$pic_url));
|
||||
die();
|
||||
} else {
|
||||
return json(array("status"=>"-1","error"=>"上传有误,请检查服务器配置!"));
|
||||
die();
|
||||
}
|
||||
}else{
|
||||
return json(array("status"=>"-1","error"=>"系统错误!"));
|
||||
die();
|
||||
}
|
||||
}
|
||||
/**
|
||||
*上传视频
|
||||
*/
|
||||
public function uploadVideo(Request $request){
|
||||
$typeArr = array("mp4","wkv");//官方推荐 mp4
|
||||
$path = "uploadnv/" . date('Y/m/d/');//上传路径
|
||||
if(!file_exists($path)){
|
||||
//创建文件
|
||||
mkdir($path,0777,true);
|
||||
}
|
||||
// if ($_FILES) {
|
||||
$name = $_FILES['file']['name'];
|
||||
$size = $_FILES['file']['size'];
|
||||
$name_tmp = $_FILES['file']['tmp_name'];
|
||||
if (empty($name)) {
|
||||
// return json_encode(['status'=>0,'msg'=>'查询失败']);
|
||||
echo json_encode(array("error"=>"您还未选择文件"));
|
||||
exit;
|
||||
}
|
||||
$type = strtolower(substr(strrchr($name, '.'), 1)); //获取文件类型
|
||||
|
||||
if (!in_array($type, $typeArr)) {
|
||||
echo json_encode(array("error"=>"请上传mp4,wkv类型的文件!"));//mov,webm
|
||||
exit;
|
||||
}
|
||||
if ($size > (15 * 1024 * 1024)) {
|
||||
echo json_encode(array("error"=>"文件大小已超过30MB!"));
|
||||
exit;
|
||||
}
|
||||
|
||||
/* if($_GET['type'] == 'cx'){
|
||||
$imageType = 'cx';
|
||||
}*/
|
||||
$imageType='';
|
||||
$pic_name = $imageType.time() . rand(10000, 99999) . "." . $type;//图片名称
|
||||
$pic_url =$path . $pic_name;//上传后图片路径+名称
|
||||
|
||||
if (move_uploaded_file($name_tmp, $pic_url)) { //临时文件转移到目标文件夹
|
||||
/* $_POST['name'] = $pic_name;
|
||||
$_POST['topic'] = $imageType;
|
||||
$_POST['albumPath'] = $pic_url;*/
|
||||
echo json_encode(array("status"=>"0","file_name"=>$pic_name,"file_path"=>$request->domain().'/'.$pic_url));
|
||||
die();
|
||||
} else {
|
||||
echo json_encode(array("error"=>"上传有误,请检查服务器配置!"));
|
||||
die();
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
196
application/admincpp/controller/Index.php
Normal file
196
application/admincpp/controller/Index.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
//use think\Log;
|
||||
class Menu extends Base
|
||||
{
|
||||
/**
|
||||
*初始化
|
||||
*/
|
||||
protected function _initialize(){
|
||||
parent::_initialize();
|
||||
if(session('admin_user_type') != 1){
|
||||
$result['erro']=-1;
|
||||
$result['msg']='权限不足';
|
||||
Response::create($result,'json')->send();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取菜单列表
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getMenuList(Request $request){
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result = Db::name('menu')
|
||||
->field('id,pid,menu_name,url,seq_on,menu_icon')
|
||||
->order('seq_on')
|
||||
->select();
|
||||
//找二级菜单
|
||||
$second=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != ''){
|
||||
//二级
|
||||
$second[]=$value;
|
||||
unset($result[$key]);
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
$result=array_values($result);
|
||||
foreach ($result as $key => $value) {
|
||||
$result[$key]['type']=1;
|
||||
$result[$key]['No']=$key+1;
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['menu_id']==$v['pid']){
|
||||
$v['type']=2;
|
||||
$result[$key]['children'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($result){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg,'data'=>$result]);
|
||||
}
|
||||
/**
|
||||
* 权限菜单列表
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getPermissionMenu(Request $request){
|
||||
$data=$request->param();
|
||||
//$this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result=Db::name('menu')->field('id,pid,menu_name,url,seq_on,menu_icon')->order('seq_on')->select();
|
||||
//找二级三级菜单
|
||||
$second=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != ''){
|
||||
$second[]=$value;
|
||||
unset($result[$key]);
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
foreach ($result as $key => $value) {
|
||||
$result[$key]['type']=1;
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['menu_id']==$v['pid']){
|
||||
$v['type']=2;
|
||||
$result[$key]['second'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($result){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg,'data'=>$result]);
|
||||
}
|
||||
|
||||
public function getMenuOption(Request $request){
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result = Db::name('menu')
|
||||
->field('id,pid,menu_name')
|
||||
//->where('status',0)
|
||||
->order('seq_on')
|
||||
->select();
|
||||
//找二级三级菜单
|
||||
$second=[];
|
||||
// $third=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != ''){
|
||||
//二级
|
||||
$second[$key]['value']=$value['id'];
|
||||
$second[$key]['label']=$value['menu_name'];
|
||||
$second[$key]['pid']=$value['pid'];
|
||||
unset($result[$key]);
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
$first=[];
|
||||
foreach ($result as $key => $value) {
|
||||
$first[$key]['value']=$value['id'];
|
||||
$first[$key]['label']=$value['menu_name'];
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['menu_id']==$v['pid']){
|
||||
unset($v['pid']);
|
||||
$first[$key]['children'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($first){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg,'data'=>$first]);
|
||||
}
|
||||
//获取当前菜单最大序号
|
||||
public function getMaxSeq($map){
|
||||
$result=Db::name('menu')->field('seq_on')->where($map)->order('seq_on','desc')->find();
|
||||
if($result){
|
||||
return $result['seq_on']+1;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
//添加菜单
|
||||
public function doaddMenu(Request $request){
|
||||
//获取一下表单提交的数据,并保存在变量中
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
unset($data['Token']);
|
||||
$menu_id=md5(uniqid(''));//一级菜单id
|
||||
$create_time=date('Y-m-d H:i:s');//插入时间
|
||||
$data1=[];
|
||||
//添加一级菜单
|
||||
if(empty($data['father'])){
|
||||
$map['pid']='';
|
||||
}else{
|
||||
$map['pid']=$data['father'];
|
||||
}
|
||||
//获取一级菜单最大序号
|
||||
$seq_on=$this->getMaxSeq($map);
|
||||
$data1=$map;
|
||||
if(!empty($data['urs'])){
|
||||
$data1['url']=$data['url'];
|
||||
}
|
||||
if(!empty($data['menu_icon'])){
|
||||
$data1['menu_icon']=$data['menu_icon'];
|
||||
}
|
||||
$data1['id']=$menu_id;
|
||||
$data1['menu_name']=$data['title'];
|
||||
$data1['seq_on']=$seq_on;
|
||||
$data1['create_time']=$create_time;
|
||||
$res=Db::name('menu')->insert($data1);
|
||||
if($res){
|
||||
$status=1;
|
||||
$msg='添加菜单成功!!';
|
||||
}else{
|
||||
$status=0;
|
||||
$msg='添加菜单失败!!';
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg]);
|
||||
}
|
||||
}
|
||||
92
application/admincpp/controller/Login.php
Normal file
92
application/admincpp/controller/Login.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
// use app\admin\model\Admin;
|
||||
use think\Session;
|
||||
use think\Db;
|
||||
use think\Controller;
|
||||
|
||||
class Login extends Controller{
|
||||
/**
|
||||
* 渲染登陆界面
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if(!session('admincpp_user_id')){//没有登录信息
|
||||
return $this->view->fetch('login');
|
||||
}else{
|
||||
//登录信息超时
|
||||
$log_time=session('admincpp_user_login_time')-time();
|
||||
if($log_time < 0){
|
||||
return $this->view->fetch('login');
|
||||
}
|
||||
}
|
||||
return $this->view->fetch('nav');
|
||||
}
|
||||
/**
|
||||
* 验证用户身份.
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
//判断是否是post方法发送的数据:如果是则开始登陆
|
||||
if(Request::instance()->isPost()){
|
||||
$user_name=Request::instance()->param("username");
|
||||
$password=Request::instance()->param('password');
|
||||
if(empty($user_name) || empty($password)){
|
||||
$result=['status'=>0,'msg'=>'用户名或密码为空'];
|
||||
return json($result);
|
||||
}
|
||||
//数据查询
|
||||
$infor=Db::name("user")
|
||||
->field('id,user_name,user_head')
|
||||
->where('phone',$user_name)
|
||||
->where('password',md5($password))
|
||||
->where("status",1)
|
||||
->where('type',1)
|
||||
->find();
|
||||
if(empty($infor)){
|
||||
$result=['status'=>0,'msg'=>'用户不存在或密码不正确'];
|
||||
}else{
|
||||
//Session::set('admin_user_type',$infor['role_id']);
|
||||
Session::set('admincpp_user_id',$infor['id']);
|
||||
//Session::set('admin_mechanism_id',$infor['mechanism_id']);
|
||||
$time_out=time()+3600;
|
||||
Session::set('admincpp_user_login_time',$time_out);
|
||||
$result=['status'=>1,'msg'=>'登录成功','token'=>1];
|
||||
}
|
||||
return json($result);
|
||||
}
|
||||
//如果不是post,则返回登陆界面
|
||||
else{
|
||||
$result=['status'=>0,'msg'=>'未获取到参数'];
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 退出登录
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
Session::clear();
|
||||
return json(['status'=>1,'msg'=>'退出成功']);
|
||||
}
|
||||
/**
|
||||
* 超时登录推出跳转页面
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function logoutJump(Request $request)
|
||||
{
|
||||
return $this->view->fetch('logoutJump');
|
||||
}
|
||||
}
|
||||
326
application/admincpp/controller/Menu.php
Normal file
326
application/admincpp/controller/Menu.php
Normal file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
//use think\Log;
|
||||
|
||||
class Menu extends Base
|
||||
{
|
||||
/**
|
||||
*初始化
|
||||
*/
|
||||
protected function _initialize(){
|
||||
/* parent::_initialize();
|
||||
if(session('admin_user_type') != 1){
|
||||
$result['erro']=-1;
|
||||
$result['msg']='权限不足';
|
||||
Response::create($result,'json')->send();
|
||||
exit;
|
||||
}*/
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
// $this->alreadyLogin();
|
||||
return $this->view->fetch('index');
|
||||
}
|
||||
public function nav()
|
||||
{
|
||||
// $this->alreadyLogin();
|
||||
return $this->view->fetch('nav');
|
||||
}
|
||||
public function getUserInfor(){
|
||||
$data=Db::name("user")
|
||||
->field('user_name,user_head')
|
||||
// admincpp 模块登录写入的是 admincpp_user_id(否则这里会变成 id IS NULL)
|
||||
->where('id',session('admincpp_user_id'))
|
||||
->find();
|
||||
$result=['status'=>1,'msg'=>'查询成功','infro'=>$data];
|
||||
return json($result);
|
||||
}
|
||||
/**
|
||||
* 获取菜单列表
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getMenuList(Request $request){
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result = Db::name('menu')
|
||||
->field('id,pid,menu_name,url,seq_on,menu_icon')
|
||||
->order('seq_on')
|
||||
->select();
|
||||
//找二级菜单
|
||||
$second=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != '' && $value['pid'] != 0){
|
||||
//二级
|
||||
$value['grade']="二级菜单";
|
||||
$second[]=$value;
|
||||
unset($result[$key]);
|
||||
}else{
|
||||
$result[$key]['grade']="一级菜单";
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
$result=array_values($result);
|
||||
foreach ($result as $key => $value) {
|
||||
$result[$key]['type']=1;
|
||||
$result[$key]['No']=$key+1;
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['id']==$v['pid']){
|
||||
$v['type']=2;
|
||||
$result[$key]['children'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($result){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json(['status'=>$status,'msg'=>$msg,'data'=>$result]);
|
||||
}
|
||||
/**
|
||||
* 权限菜单列表
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getPermissionMenu(Request $request){
|
||||
$data=$request->param();
|
||||
//$this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result=Db::name('menu')->field('id,pid,menu_name,url,seq_on,menu_icon')->order('seq_on')->select();
|
||||
//找二级三级菜单
|
||||
$second=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != ''){
|
||||
$second[]=$value;
|
||||
unset($result[$key]);
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
foreach ($result as $key => $value) {
|
||||
$result[$key]['type']=1;
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['menu_id']==$v['pid']){
|
||||
$v['type']=2;
|
||||
$result[$key]['second'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($result){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json(['status'=>$status,'msg'=>$msg,'data'=>$result]);
|
||||
}
|
||||
|
||||
public function getMenuOption(Request $request){
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
//升序获取菜单列表
|
||||
$result = Db::name('menu')
|
||||
->field('id,pid,menu_name')
|
||||
//->where('status',0)
|
||||
->order('seq_on')
|
||||
->select();
|
||||
//找二级三级菜单
|
||||
$second=[];
|
||||
// $third=[];
|
||||
foreach ($result as $key => $value) {
|
||||
if($value['pid'] != ''){
|
||||
//二级
|
||||
$second[$key]['value']=$value['id'];
|
||||
$second[$key]['label']=$value['menu_name'];
|
||||
$second[$key]['pid']=$value['pid'];
|
||||
unset($result[$key]);
|
||||
}
|
||||
}
|
||||
//二级组装到一级
|
||||
$first=[];
|
||||
foreach ($result as $key => $value) {
|
||||
$first[$key]['value']=$value['id'];
|
||||
$first[$key]['label']=$value['menu_name'];
|
||||
foreach ($second as $k => $v) {
|
||||
if($value['menu_id']==$v['pid']){
|
||||
unset($v['pid']);
|
||||
$first[$key]['children'][]=$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($first){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}
|
||||
else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json(['status'=>$status,'msg'=>$msg,'data'=>$first]);
|
||||
}
|
||||
//获取当前菜单最大序号
|
||||
public function getMaxSeq($map){
|
||||
$result=Db::name('menu')->field('seq_on')->where($map)->order('seq_on','desc')->find();
|
||||
if($result){
|
||||
return $result['seq_on']+1;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
//添加菜单
|
||||
public function doaddMenu(Request $request){
|
||||
//获取一下表单提交的数据,并保存在变量中
|
||||
$data=$request->param();
|
||||
// $this->checkToken($data['Token']);
|
||||
unset($data['Token']);
|
||||
$menu_id=md5(uniqid(''));//一级菜单id
|
||||
$create_time=date('Y-m-d H:i:s');//插入时间
|
||||
$data1=[];
|
||||
//添加一级菜单
|
||||
if(empty($data['father'])){
|
||||
$map['pid']='';
|
||||
}else{
|
||||
$map['pid']=$data['father'];
|
||||
}
|
||||
//获取一级菜单最大序号
|
||||
$seq_on=$this->getMaxSeq($map);
|
||||
$data1=$map;
|
||||
if(!empty($data['urs'])){
|
||||
$data1['url']=$data['url'];
|
||||
}
|
||||
if(!empty($data['menu_icon'])){
|
||||
$data1['menu_icon']=$data['menu_icon'];
|
||||
}
|
||||
$data1['id']=$menu_id;
|
||||
$data1['menu_name']=$data['title'];
|
||||
$data1['seq_on']=$seq_on;
|
||||
$data1['create_time']=$create_time;
|
||||
$res=Db::name('menu')->insert($data1);
|
||||
if($res){
|
||||
$status=1;
|
||||
$msg='添加菜单成功!!';
|
||||
}else{
|
||||
$status=0;
|
||||
$msg='添加菜单失败!!';
|
||||
}
|
||||
return json(['status'=>$status,'msg'=>$msg]);
|
||||
}
|
||||
/**
|
||||
* 修改菜单详情
|
||||
* @param $data 菜单id(一级菜单、二级菜单)
|
||||
* @param $data 菜单详情
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function updMenu(Request $request){
|
||||
$data=$request->param();
|
||||
$result=Db::name('menu')->field('id,pid,menu_name,url,menu_icon')->where('menu_id',$data['menu_id'])->find();
|
||||
$result['type']=1;
|
||||
if(!empty($result['pid'])){
|
||||
$result['type']=2;
|
||||
$result['father']=$result['pid'];
|
||||
}
|
||||
unset($result['pid']);
|
||||
if($result){
|
||||
$status=1;
|
||||
$msg="获取数据成功!!";
|
||||
}else{
|
||||
$status=0;
|
||||
$msg="获取数据失败!!";
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg,'data'=>$result]);
|
||||
}
|
||||
public function doupdMenu(Request $request){
|
||||
$data=$request->param();
|
||||
$data1=[];
|
||||
//添加一级菜单
|
||||
if(empty($data['father'])){
|
||||
$data1['pid']='';
|
||||
if(!empty($data['menu_icon'])){
|
||||
$data1['menu_icon']=$data['menu_icon'];
|
||||
}
|
||||
}else{
|
||||
$data1['pid']=$data['father'];
|
||||
//获取一级菜单最大序号
|
||||
if(!empty($data['url'])){
|
||||
$data1['url']=$data['url'];
|
||||
}
|
||||
}
|
||||
$data1['menu_name']=$data['menu_name'];
|
||||
$res=Db::name('menu')->where('id',$data['id'])->update($data1);
|
||||
if($res){
|
||||
$status=1;
|
||||
$msg='修改菜单成功!!';
|
||||
}else{
|
||||
$status=0;
|
||||
$msg='修改菜单失败!!';
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg]);
|
||||
}
|
||||
/**
|
||||
* 设置菜单状态
|
||||
* @param $data 一级菜单id、二级菜单id
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function setMenuStatus(Request $request){
|
||||
$data=$request->param();
|
||||
$this->checkToken($data['Token']);
|
||||
$res=Db::name('menu')->where('id',$data['id'])->update(['status'=>$data['status']]);
|
||||
if($res){
|
||||
$status=1;
|
||||
$msg='设置成功!!';
|
||||
}else{
|
||||
$status=0;
|
||||
$msg='设置失败!!';
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg]);
|
||||
}
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param $data 一级菜单id、二级菜单id
|
||||
*@author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function delMenu(Request $request){
|
||||
$data=$request->param();
|
||||
$res=Db::name('menu')->where('id',$data['id'])->find();
|
||||
//一级菜单
|
||||
if($res['pid']==''){
|
||||
$map1['id|pid']=$data['id'];
|
||||
$map2['id']=['in',[$data['id'],$res['pid']]];
|
||||
}else{
|
||||
$map1['id']=$data['id'];
|
||||
$map2['id']=$data['id'];
|
||||
}
|
||||
// 启动事务
|
||||
Db::startTrans();
|
||||
try{
|
||||
//删除二级菜单
|
||||
Db::name('menu')->where($map1)->delete();
|
||||
// Db::table('t_nv_role_menu')->where($map2)->delete();
|
||||
// 提交事务
|
||||
Db::commit();
|
||||
$status=1;
|
||||
$msg='删除菜单成功!!';
|
||||
} catch (\Exception $e) {
|
||||
Log::record($e->getMessage(),'error');
|
||||
// 回滚事务
|
||||
Db::rollback();
|
||||
$status=0;
|
||||
$msg='删除菜单失败!!';
|
||||
}
|
||||
return json_encode(['status'=>$status,'msg'=>$msg]);
|
||||
}
|
||||
}
|
||||
106
application/admincpp/controller/Wechatinfro.php
Normal file
106
application/admincpp/controller/Wechatinfro.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
|
||||
class Wechatinfro extends Base
|
||||
{
|
||||
protected function _initialize(){
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
public function wechatUserList()
|
||||
{
|
||||
return $this->view->fetch('userList');
|
||||
}
|
||||
|
||||
public function getWechatUserList(Request $request){
|
||||
$post=$request->param();
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30;
|
||||
$where=[];
|
||||
if(isset($post['title']) && !empty($post['title'])){
|
||||
$where['nickname']=['like','%'.$post['title'].'%'];
|
||||
}
|
||||
$res = Db::name('wechat_user')
|
||||
->field('uid,nickname,headimg,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size,false,['page'=>$page]);
|
||||
$lists=$res->items();
|
||||
$start=($page-1)*$page_size;
|
||||
foreach($lists as $k=>$v){
|
||||
$start+=1;
|
||||
$lists[$k]['no_id']=$start;
|
||||
}
|
||||
$result['lists'] =$lists;
|
||||
$result['lastPage'] = $res->lastPage();
|
||||
$result['currentPage'] = $res->currentPage();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
public function wechatRecordList()
|
||||
{
|
||||
return $this->view->fetch('wechatRecordList');
|
||||
}
|
||||
|
||||
public function getWechatRecordList(Request $request){
|
||||
$post=$request->param();
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30;
|
||||
$where=[];
|
||||
if(isset($post['title']) && !empty($post['title'])){
|
||||
$where['name']=['like','%'.$post['title'].'%'];
|
||||
}
|
||||
$res = Db::name('cpp_calculate_record')
|
||||
->field('id,name,bone_age,uterus_length,uterus_width,lh_peak,fsh_peak,fsh_3m,igf1,calculate_result,risk_level,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size,false,['page'=>$page]);
|
||||
$lists=$res->items();
|
||||
$start=($page-1)*$page_size;
|
||||
foreach($lists as $k=>$v){
|
||||
$start+=1;
|
||||
$lists[$k]['no_id']=$start;
|
||||
}
|
||||
$result = array();
|
||||
$result['lists'] =$lists;
|
||||
$result['lastPage'] = $res->lastPage();
|
||||
$result['currentPage'] = $res->currentPage();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
public function feedbackList()
|
||||
{
|
||||
return $this->view->fetch('feedbackList');
|
||||
}
|
||||
|
||||
public function getFeedbackList(Request $request){
|
||||
$post=$request->param();
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30;
|
||||
$res = Db::name('cpp_feedback')
|
||||
->field('id,uid,content,create_time')
|
||||
->order('create_time desc')
|
||||
->paginate($page_size,false,['page'=>$page]);
|
||||
$lists=$res->items();
|
||||
$start=($page-1)*$page_size;
|
||||
foreach($lists as $k=>$v){
|
||||
$start+=1;
|
||||
$lists[$k]['no_id']=$start;
|
||||
}
|
||||
$result = array();
|
||||
$result['lists'] =$lists;
|
||||
$result['lastPage'] = $res->lastPage();
|
||||
$result['currentPage'] = $res->currentPage();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
182
application/admincpp/controller/Wechatset.php
Normal file
182
application/admincpp/controller/Wechatset.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\controller;
|
||||
|
||||
use app\admincpp\common\Base;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
//use think\Log;
|
||||
|
||||
|
||||
class Wechatset extends Base
|
||||
{
|
||||
/**
|
||||
*初始化
|
||||
*/
|
||||
protected function _initialize(){
|
||||
parent::_initialize();
|
||||
/*if(session('admin_user_type') != 1){
|
||||
$result['erro']=-1;
|
||||
$result['msg']='权限不足';
|
||||
Response::create($result,'json')->send();
|
||||
exit;
|
||||
}*/
|
||||
}
|
||||
/**
|
||||
* 小程序资讯信息页面
|
||||
*/
|
||||
public function wechatRealTimeInfo()
|
||||
{
|
||||
return $this->view->fetch('realTimeInfo');
|
||||
}
|
||||
/**
|
||||
* 小程序添加资讯信息页面
|
||||
*/
|
||||
public function wechatRealTimeInfoAdd()
|
||||
{
|
||||
return $this->view->fetch('realTimeInfoAdd');
|
||||
}
|
||||
/**
|
||||
* 小程序添加资讯信息页面
|
||||
*/
|
||||
public function wechatRealTimeInfoUpdate(Request $request)
|
||||
{
|
||||
$id=$request->get('id');
|
||||
$this->assign('id',$id);
|
||||
return $this->view->fetch('realTimeInfoUpdate');
|
||||
}
|
||||
/**
|
||||
* 查询小程序资讯信息
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getWechatRealTimeInfoList(Request $request){
|
||||
$post=$request->param();
|
||||
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;//页数
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30;//每页条数
|
||||
//搜索
|
||||
$where=[];
|
||||
if(isset($post['title']) && !empty($post['title'])){
|
||||
$where['title_plain']=['like','%'.$post['title'].'%'];
|
||||
}
|
||||
//升序获取菜单列表
|
||||
$res = Db::name('wechat_real_time_info')
|
||||
->field('id,title_plain,thumbnail,excerpt_plain,url,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size,false,['page'=>$page]);
|
||||
$lists=$res->items();
|
||||
$start=($page-1)*$page_size;
|
||||
foreach($lists as $k=>$v){
|
||||
$start+=1;
|
||||
$lists[$k]['no_id']=$start;
|
||||
}
|
||||
$result['lists'] =$lists;
|
||||
$result['lastPage'] = $res->lastPage();//总页数
|
||||
$result['currentPage'] = $res->currentPage();//当前页
|
||||
// $result['total'] = $res->total();//数据总条数
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
public function wechatRecordList()
|
||||
{
|
||||
return $this->view->fetch('wechatRecordList');
|
||||
}
|
||||
/**
|
||||
* 删除小程序资讯信息
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function delWechatRealTimeInfo(Request $request){
|
||||
$post=$request->param();
|
||||
if(!isset($post['id']) || empty($post['id']) ){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "请选择要删除的记录";
|
||||
return json($result);
|
||||
}
|
||||
$id=Db::name('wechat_real_time_info')->where('id',$post['id'])->value('id');
|
||||
if(empty($id)){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "该记录异常,无法删除";
|
||||
return json($result);
|
||||
}
|
||||
$res=Db::name('wechat_real_time_info')->where('id',$id)->delete();
|
||||
if($res > 0){
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '删除成功';
|
||||
}else{
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '删除失败';
|
||||
}
|
||||
return json($result);
|
||||
}
|
||||
/***
|
||||
*保存小程序资讯信息
|
||||
**/
|
||||
public function saveWechatRealTimeInfo(Request $request){
|
||||
$post=$request->param();
|
||||
|
||||
if(!isset($post['title_plain']) || empty($post['title_plain']) ){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入标题";
|
||||
return json($result);
|
||||
}
|
||||
if(!isset($post['thumbnail']) || empty($post['thumbnail']) ){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入图片";
|
||||
return json($result);
|
||||
}
|
||||
if(!isset($post['excerpt_plain']) || empty($post['excerpt_plain']) ){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入简介";
|
||||
return json($result);
|
||||
}
|
||||
if(!isset($post['url']) || empty($post['url'])){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入资讯跳转链接";
|
||||
return json($result);
|
||||
}
|
||||
//提交数据
|
||||
$data=[];
|
||||
$data['title_plain']=$post['title_plain'];//标题
|
||||
$data['thumbnail']=$post['thumbnail'];//图片
|
||||
$data['excerpt_plain']=$post['excerpt_plain'];//介绍
|
||||
$data['url']=$post['url'];//跳转连接
|
||||
if(isset($post['id']) && !empty($post['id'])){
|
||||
//修改数据
|
||||
$res=Db::name('wechat_real_time_info')->where('id',$post['id'])->update($data);
|
||||
}else{
|
||||
//保存记录数据
|
||||
$data['id']=md5(time().rand(100000,999999));
|
||||
$data['create_time']=date('Y-m-d H:i:s');
|
||||
$res=Db::name('wechat_real_time_info')->insert($data);
|
||||
}
|
||||
if($res===false){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "添加失败";
|
||||
return json($result);
|
||||
}else{
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = "添加成功";
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*查询资讯信息详情
|
||||
*/
|
||||
public function getRealTimeInfoDetail(Request $request){
|
||||
$post=$request->param();
|
||||
if(!isset($post['id']) || empty($post['id'])){
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入资讯id";
|
||||
return json($result);
|
||||
}
|
||||
//修改数据
|
||||
$result['infro']=Db::name('wechat_real_time_info')->where('id',$post['id'])->find();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = "查询成功";
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
11
application/admincpp/model/Permission.php
Normal file
11
application/admincpp/model/Permission.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Permission extends Model
|
||||
{
|
||||
// 设置完整的数据表(包含前缀)
|
||||
protected $table = 't_sys_menu';
|
||||
}
|
||||
11
application/admincpp/model/Role.php
Normal file
11
application/admincpp/model/Role.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace app\admincpp\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class Role extends Model
|
||||
{
|
||||
// 设置完整的数据表(包含前缀)
|
||||
protected $table = 't_sys_role';
|
||||
}
|
||||
138
application/admincpp/view/dashboard/index.html
Normal file
138
application/admincpp/view/dashboard/index.html
Normal file
@@ -0,0 +1,138 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>系统概览</title>
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<style>
|
||||
body{
|
||||
background:#f5f7fb;
|
||||
padding:24px 24px 40px;
|
||||
box-sizing:border-box;
|
||||
font-family:"Microsoft YaHei",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
|
||||
}
|
||||
.dash-card{
|
||||
background:#fff;
|
||||
border-radius:10px;
|
||||
box-shadow:0 10px 30px rgba(15,35,52,0.06);
|
||||
padding:20px 24px;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.dash-title{
|
||||
font-size:18px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.dash-sub{
|
||||
font-size:12px;
|
||||
color:#9aa4b1;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
.dash-grid{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:16px;
|
||||
}
|
||||
.dash-item{
|
||||
flex:1 1 200px;
|
||||
min-width:200px;
|
||||
background:#f8fafc;
|
||||
border-radius:8px;
|
||||
padding:14px 16px;
|
||||
cursor:pointer;
|
||||
transition:all 0.3s;
|
||||
}
|
||||
.dash-item:hover{
|
||||
background:#f0f4f8;
|
||||
transform:translateY(-2px);
|
||||
box-shadow:0 4px 12px rgba(15,35,52,0.1);
|
||||
}
|
||||
.dash-item-label{
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.dash-item-value{
|
||||
margin-top:6px;
|
||||
font-size:22px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
}
|
||||
.dash-item-desc{
|
||||
margin-top:4px;
|
||||
font-size:12px;
|
||||
color:#b0b7c3;
|
||||
}
|
||||
.dash-empty{
|
||||
margin-top:10px;
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.loading{
|
||||
text-align:center;
|
||||
padding:40px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="dash-card">
|
||||
<div class="dash-title">欢迎使用后台管理系统</div>
|
||||
<div class="dash-sub">这里是系统概览,实时展示系统统计数据。</div>
|
||||
<div class="dash-grid" id="dashGrid">
|
||||
<div class="loading">数据加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/admincpp/js/jquery.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
// 加载统计数据
|
||||
loadStatistics();
|
||||
|
||||
function loadStatistics(){
|
||||
$.ajax({
|
||||
url: '/admincpp/Dashboard/getStatistics',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status == 1){
|
||||
renderStatistics(res.data);
|
||||
} else {
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败:' + res.msg + '</div>');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败,请稍后重试</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatistics(data){
|
||||
var html = `
|
||||
<div class="dash-item" onclick="parent.location.href='/admincpp/wechatinfro/wechatUserList'">
|
||||
<div class="dash-item-label">小程序注册用户</div>
|
||||
<div class="dash-item-value">${data.user_count}</div>
|
||||
<div class="dash-item-desc">今日新增:${data.today_user_count} 人</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/admincpp/wechatset/wechatRealTimeInfo'">
|
||||
<div class="dash-item-label">首页资讯数量</div>
|
||||
<div class="dash-item-value">${data.info_count}</div>
|
||||
<div class="dash-item-desc">可在「咨询管理」菜单中维护展示内容</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/admincpp/wechatinfro/wechatRecordList'">
|
||||
<div class="dash-item-label">总计算次数</div>
|
||||
<div class="dash-item-value">${data.total_calculate_count}</div>
|
||||
<div class="dash-item-desc">最近一次:${data.last_calculate_time}</div>
|
||||
</div>
|
||||
`;
|
||||
$('#dashGrid').html(html);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
91
application/admincpp/view/login/login.html
Normal file
91
application/admincpp/view/login/login.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>登录 - CPP生长减速预测模型后台</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/admincpp/css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/admincpp/css/login.css" />
|
||||
<style>
|
||||
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #27C2A7 0%, #1abc9c 100%); padding: 20px; box-sizing: border-box; }
|
||||
.login-card { width: 100%; max-width: 400px; background: #fff; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.2); overflow: hidden; }
|
||||
.login-card .login-header { padding: 36px 24px 24px; text-align: center; border-bottom: 1px solid #f0f0f0; }
|
||||
.login-card .login-title { font-size: 18px; font-weight: 600; color: #1f2d3d; line-height: 1.5; margin: 0; }
|
||||
.login-card .login-body { padding: 32px 28px 40px; }
|
||||
.login-card .form-item { margin-bottom: 22px; }
|
||||
.login-card .form-item input { width: 100%; height: 48px; padding: 0 16px; border: 1px solid #e0e0e0; border-radius: 8px; font-size: 15px; color: #333; background: #fafafa; box-sizing: border-box; transition: border-color .2s, background .2s; }
|
||||
.login-card .form-item input::placeholder { color: #aaa; }
|
||||
.login-card .form-item input:focus { outline: none; border-color: #27C2A7; background: #fff; }
|
||||
.login-card .form-item .warning { display: block; margin-top: 6px; font-size: 12px; color: #e4393c; min-height: 18px; }
|
||||
.login-card .btn-login { width: 100%; height: 48px; border: none; border-radius: 8px; font-size: 16px; font-weight: 500; color: #fff; background: #27C2A7; cursor: pointer; transition: background .2s; }
|
||||
.login-card .btn-login:hover { background: #1fa891; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-wrap">
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<h1 class="login-title">CPP生长减速预测模型后台</h1>
|
||||
</div>
|
||||
<div class="login-body">
|
||||
<form id="loginForm" method="post">
|
||||
<div class="form-item">
|
||||
<input type="text" id="username" name="username" placeholder="请输入账号" value="" autocomplete="username" />
|
||||
<span id="checkusername" class="warning"></span>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<input type="password" autocomplete="off" id="admin_password" name="password" placeholder="请输入密码" />
|
||||
<span id="checkpassword" class="warning"></span>
|
||||
</div>
|
||||
<button type="button" class="btn-login" id="loginBtn">立即登录</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
$("#loginBtn").on("click", function(){
|
||||
var username = $("#username").val().trim();
|
||||
var password = $("#admin_password").val().trim();
|
||||
var hasError = false;
|
||||
if(username === ""){
|
||||
$("#checkusername").text("账号不能为空").addClass("warning");
|
||||
hasError = true;
|
||||
}else{
|
||||
$("#checkusername").text("").removeClass("warning");
|
||||
}
|
||||
if(password === ""){
|
||||
$("#checkpassword").text("密码不能为空").addClass("warning");
|
||||
hasError = true;
|
||||
}else{
|
||||
$("#checkpassword").text("").removeClass("warning");
|
||||
}
|
||||
if(hasError) return;
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/admincpp/Login/login",
|
||||
data: { username: username, password: password },
|
||||
dataType: "json",
|
||||
success: function(res){
|
||||
if(res.status == 1){
|
||||
window.location.href = "/admincpp/Login/index";
|
||||
}else{
|
||||
alert(res.msg || "登录失败");
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
alert("登录请求失败,请稍后再试");
|
||||
}
|
||||
});
|
||||
});
|
||||
$(document).keydown(function(e){
|
||||
if(e.keyCode == 13){ $("#loginBtn").click(); }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
application/admincpp/view/login/logoutJump.html
Normal file
28
application/admincpp/view/login/logoutJump.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title></title>
|
||||
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css?t=1554901097999" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="/static/admincpp/css/nav.css" />
|
||||
|
||||
|
||||
</head>
|
||||
<body class="parent_color">
|
||||
|
||||
|
||||
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
top.location.href = '/admincpp/login';
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
41
application/admincpp/view/login/nav.html
Normal file
41
application/admincpp/view/login/nav.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>CPP生长减速预测模型后台</title>
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css?t=1554901097999" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="/static/admincpp/css/nav.css" />
|
||||
<style>
|
||||
iframe{
|
||||
/*border: 1px solid red;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-id="0" class="parent_color">
|
||||
<!--左侧导航-->
|
||||
<div class="layui-side layui-bg-black">
|
||||
<div class="layui-side-scroll">
|
||||
<ul id="nav" class="layui-nav layui-nav-tree site-demo-nav" lay-filter="demo" style="margin-right: 10px;">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!--顶部-->
|
||||
<div class="top_right">
|
||||
<div class="header_title">CPP生长减速预测模型后台</div>
|
||||
<div class="user_right">
|
||||
<span id="inform"></span>
|
||||
<b class="out" id="sign_out">退出</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main_content">
|
||||
<iframe id="iframeId" src="/admincpp/Dashboard/index" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/nav.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
25
application/admincpp/view/wechatinfro/feedbackList.html
Normal file
25
application/admincpp/view/wechatinfro/feedbackList.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<title>CPP反馈列表</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<li class="layui-nav-item layui-this"><a href="#">反馈列表</a></li>
|
||||
</ul>
|
||||
<div class="content">
|
||||
<table class="layui-hide" id="test" lay-filter="test"></table>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/wechatinfro/feedbackList.js" type="text/javascript" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
64
application/admincpp/view/wechatinfro/userList.html
Normal file
64
application/admincpp/view/wechatinfro/userList.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<style type="text/css">
|
||||
.layui-table-cell{
|
||||
height:auto!important;
|
||||
white-space:normal;
|
||||
}
|
||||
</style>
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/common.js" type="text/javascript" charset="utf-8"></script>
|
||||
<title>用户管理</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<li class="layui-nav-item layui-this"><a href="#">用户注册列表</a></li>
|
||||
</ul>
|
||||
<div class="main_top">
|
||||
<div class="head">
|
||||
<form class="layui-form" action="">
|
||||
<div class="layui-form-item">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">搜索:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="searchBox" name="title" lay-verify="title" autocomplete="off" placeholder="请输入用户昵称" class="layui-input">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<button id="search" type="button" class="layui-btn layui-btn-normal">查询</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="layui-hide" id="test" lay-filter="test"></table>
|
||||
<script type="text/html" id="imgTpl">
|
||||
<!--图片设置 -->
|
||||
<img src="{{ d.headimg }}" width="50px" height="50px">
|
||||
</script>
|
||||
<!-- <div class="table_page" id="page"></div> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<script src="/static/admincpp/js/wechatinfro/userList.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
48
application/admincpp/view/wechatinfro/wechatRecordList.html
Normal file
48
application/admincpp/view/wechatinfro/wechatRecordList.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<style type="text/css">
|
||||
.layui-table-cell{
|
||||
height:auto!important;
|
||||
white-space:normal;
|
||||
}
|
||||
</style>
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/common.js" type="text/javascript" charset="utf-8"></script>
|
||||
<title>CPP计算记录</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<li class="layui-nav-item layui-this"><a href="#">计算记录列表</a></li>
|
||||
</ul>
|
||||
<div class="main_top">
|
||||
<div class="head">
|
||||
<form class="layui-form" action="">
|
||||
<div class="layui-form-item">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">姓名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="searchBox" name="title" lay-verify="title" autocomplete="off" placeholder="请输入姓名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<button id="search" type="button" class="layui-btn layui-btn-normal">查询</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="layui-hide" id="test" lay-filter="test"></table>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/wechatinfro/wechatRecordList.js" type="text/javascript" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
69
application/admincpp/view/wechatset/realTimeInfo.html
Normal file
69
application/admincpp/view/wechatset/realTimeInfo.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<style type="text/css">
|
||||
.layui-table-cell{
|
||||
height:auto!important;
|
||||
white-space:normal;
|
||||
}
|
||||
</style>
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/common.js" type="text/javascript" charset="utf-8"></script>
|
||||
<title>用户管理</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<li class="layui-nav-item layui-this"><a href="#">首页资讯列表</a></li>
|
||||
</ul>
|
||||
<div class="main_top">
|
||||
<div class="head">
|
||||
<form class="layui-form" action="">
|
||||
<div class="layui-form-item">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">搜索:</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" id="searchBox" name="title" lay-verify="title" autocomplete="off" placeholder="请输入标题" class="layui-input">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<button id="search" type="button" class="layui-btn layui-btn-normal">查询</button>
|
||||
<div class="head_right">
|
||||
<i class="layui-btn" id="add" onclick="skip()">+ 新增</i>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content">
|
||||
<table class="layui-hide" id="test" lay-filter="test"></table>
|
||||
<script type="text/html" id="barDemo">
|
||||
<a class="layui-btn layui-btn-xs tab_edit" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs tab_delete" lay-event="del">删除</a>
|
||||
</script>
|
||||
<script type="text/html" id="imgTpl">
|
||||
<!--图片设置 -->
|
||||
<img src="{{ d.thumbnail }}" width="50px" height="50px">
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<script src="/static/admincpp/js/wechatset/wechatRealTimeInfoList.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
319
application/admincpp/view/wechatset/realTimeInfoAdd.html
Normal file
319
application/admincpp/view/wechatset/realTimeInfoAdd.html
Normal file
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>新建编辑</title>
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<style>
|
||||
.upload_pic_left .poster{
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
position: relative;
|
||||
}
|
||||
.popup >div{
|
||||
display: none;
|
||||
width: 400px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 50%;
|
||||
transform:translate(-50%,-50%);
|
||||
-ms-transform:translate(-50%,-50%); /* IE 9 */
|
||||
-webkit-transform:translate(-50%,-50%); /* Safari and Chrome */
|
||||
text-align: center;
|
||||
}
|
||||
.popup >div h3{
|
||||
padding: 7px 0;
|
||||
border-bottom: 1px solid #A4A4A4;
|
||||
}
|
||||
.popup >div input{
|
||||
padding-left: 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #bfbfbf;
|
||||
width: 210px;
|
||||
height: 34px;
|
||||
margin: 8px 0 ;
|
||||
}
|
||||
.activity_time {
|
||||
padding: 0px;
|
||||
}
|
||||
.popup .btn{
|
||||
margin: 15px 0 25px 0;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
display: -webkit-flex; /* Safari */
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
justify-content: space-around;
|
||||
-webkit-justify-content: space-around;
|
||||
-moz-justify-content: space-around;
|
||||
-ms-justify-content: space-around;
|
||||
}
|
||||
.popup .btn a {
|
||||
float: left;
|
||||
width: 130px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #333333;
|
||||
background: #fff;
|
||||
border: #f8c619 solid 1px;
|
||||
}
|
||||
.popup p .curr{
|
||||
background: #f8c619;
|
||||
}
|
||||
.upload_pic_left{
|
||||
width: 815px;
|
||||
}
|
||||
.title_content .title {
|
||||
padding-left: 13px;
|
||||
font-size: 14px;
|
||||
margin: 10px;
|
||||
}
|
||||
.upload_pic_left .title_content input {
|
||||
width: 700px;
|
||||
border: 1px solid #bfbfbf;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
margin-left: 27px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.upload_pic_left .title_content {
|
||||
position: relative;
|
||||
height: 70px;
|
||||
}
|
||||
.upload_pic_left .title_content span {
|
||||
left: 713px;
|
||||
bottom: 10px;
|
||||
position: absolute;
|
||||
right: 43px;
|
||||
bottom: 0;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.upload_pic_left .upload_pic{
|
||||
margin-left: 27px;
|
||||
}
|
||||
.product_table {
|
||||
min-width: 1570px;
|
||||
}
|
||||
.upload_pic{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
background: none;
|
||||
}
|
||||
.upload_pic_left{
|
||||
height: auto;
|
||||
}
|
||||
.activity_list_add{
|
||||
overflow: visible;
|
||||
}
|
||||
.poster {
|
||||
width: 347px;
|
||||
height: 180px;
|
||||
position: relative;
|
||||
}
|
||||
.upload_pic {
|
||||
width: 284px;
|
||||
height: 176px;
|
||||
border: 1px solid #bfbfbf;
|
||||
position: relative;
|
||||
font-size: 80px;
|
||||
color: #bfbfbf;
|
||||
background: url(/admincpp/img/upload.png) no-repeat;
|
||||
background-size: 60px;
|
||||
background-position: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 30px;
|
||||
margin-left: 27px;
|
||||
display: inline-block;
|
||||
}
|
||||
.poster img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.layout {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.6);
|
||||
z-index: 999;
|
||||
display: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.popup >div {
|
||||
display: none;
|
||||
width: 400px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
-ms-transform: translate(-50%,-50%);
|
||||
-webkit-transform: translate(-50%,-50%);
|
||||
text-align: center;
|
||||
}
|
||||
.popup {
|
||||
width: 544px;
|
||||
}
|
||||
.popup >div h3 {
|
||||
padding: 7px 0;
|
||||
border-bottom: 1px solid #A4A4A4;
|
||||
}
|
||||
.popup .btn {
|
||||
margin: 15px 0 25px 0;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
justify-content: space-around;
|
||||
-webkit-justify-content: space-around;
|
||||
-moz-justify-content: space-around;
|
||||
-ms-justify-content: space-around;
|
||||
}
|
||||
.popup .btn a {
|
||||
float: left;
|
||||
width: 130px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #333333;
|
||||
background: #fff;
|
||||
border: #f8c619 solid 1px;
|
||||
}
|
||||
.popup p .curr {
|
||||
background: #f8c619;
|
||||
}
|
||||
.popup .activity_product {
|
||||
width: 1239px;
|
||||
height: 640px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<span onclick="lists()">< 返回</span>
|
||||
<li class="layui-nav-item layui-this"><a href="#">新建活动</a></li>
|
||||
</ul>
|
||||
<div class="main_top">
|
||||
<div class="head">
|
||||
|
||||
<div class="head_right">
|
||||
<i id="save" class="layui-btn yellow" >保存</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="product_table activity_list_add" >
|
||||
<!-- 左侧上传图片-->
|
||||
<div class="upload_pic_left">
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入标题:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="title" name="title" placeholder="建议标题字数在45个字以内"/>
|
||||
<span>
|
||||
<i class="i_leng">0</i>/
|
||||
<em>30</em>
|
||||
</span>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入介绍:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="excerpt_plain" name="title" placeholder="请输入资讯介绍"/>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入资讯跳转链接:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="url" name="title" placeholder="请输入资讯跳转链接"/>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>请上传资讯图片:
|
||||
<span></span>
|
||||
</p>
|
||||
<div class="img_cont" id="img_cont">
|
||||
<div class="upload_pic poster" id="poster">
|
||||
<img src="" alt="" id="Upload_img2"/>
|
||||
<input id="goodsUpload" hidden type="file" name="file2" />
|
||||
<!-- <i>①</i> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout popup" >
|
||||
<!-- 特价商品 -->
|
||||
<div id="specials" class="activity_product">
|
||||
<p class="btn">
|
||||
<a href="#" id="special_cancel" class="btncancel">取消</a>
|
||||
<a href="#" id="special_deter" class="curr" >确定</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/common.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/wechatset/wechatRealTimeInfoAdd.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
layui.use('upload', function(){
|
||||
var upload = layui.upload;
|
||||
|
||||
//图片上传接口
|
||||
upload.render({
|
||||
elem: '#Upload_img2'
|
||||
,url: '/admincpp/Files/uploadImg' //改成你的图片上传接口
|
||||
,multiple: true
|
||||
,before: function(obj){
|
||||
//do something
|
||||
}
|
||||
,done: function(res){
|
||||
//上传完毕回调
|
||||
if(res.status == 0){ //假设成功返回的code为0
|
||||
$('#Upload_img2').attr("src",res.file_path);
|
||||
//do something
|
||||
}
|
||||
}
|
||||
,error: function(){
|
||||
//请求出错处理
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
320
application/admincpp/view/wechatset/realTimeInfoUpdate.html
Normal file
320
application/admincpp/view/wechatset/realTimeInfoUpdate.html
Normal file
@@ -0,0 +1,320 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>新建编辑</title>
|
||||
<link rel="stylesheet" href="/static/admincpp/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="/static/admincpp/css/index.css"/>
|
||||
<link rel="stylesheet" href="/static/admincpp/css/activity.css"/>
|
||||
<style>
|
||||
|
||||
.upload_pic_left .poster{
|
||||
width: 112px;
|
||||
height: 112px;
|
||||
position: relative;
|
||||
}
|
||||
.popup >div{
|
||||
display: none;
|
||||
width: 400px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 50%;
|
||||
transform:translate(-50%,-50%);
|
||||
-ms-transform:translate(-50%,-50%); /* IE 9 */
|
||||
-webkit-transform:translate(-50%,-50%); /* Safari and Chrome */
|
||||
text-align: center;
|
||||
}
|
||||
.popup >div h3{
|
||||
padding: 7px 0;
|
||||
border-bottom: 1px solid #A4A4A4;
|
||||
}
|
||||
.popup >div input{
|
||||
padding-left: 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #bfbfbf;
|
||||
width: 210px;
|
||||
height: 34px;
|
||||
margin: 8px 0 ;
|
||||
}
|
||||
.activity_time {
|
||||
padding: 0px;
|
||||
}
|
||||
.popup .btn{
|
||||
margin: 15px 0 25px 0;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
display: -webkit-flex; /* Safari */
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
justify-content: space-around;
|
||||
-webkit-justify-content: space-around;
|
||||
-moz-justify-content: space-around;
|
||||
-ms-justify-content: space-around;
|
||||
}
|
||||
.popup .btn a {
|
||||
float: left;
|
||||
width: 130px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #333333;
|
||||
background: #fff;
|
||||
border: #f8c619 solid 1px;
|
||||
}
|
||||
.popup p .curr{
|
||||
background: #f8c619;
|
||||
}
|
||||
.upload_pic_left{
|
||||
width: 815px;
|
||||
}
|
||||
.title_content .title {
|
||||
padding-left: 13px;
|
||||
font-size: 14px;
|
||||
margin: 10px;
|
||||
}
|
||||
.upload_pic_left .title_content input {
|
||||
width: 700px;
|
||||
border: 1px solid #bfbfbf;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
margin-left: 27px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.upload_pic_left .title_content {
|
||||
position: relative;
|
||||
height: 70px;
|
||||
}
|
||||
.upload_pic_left .title_content span {
|
||||
left: 713px;
|
||||
bottom: 10px;
|
||||
position: absolute;
|
||||
right: 43px;
|
||||
bottom: 0;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.upload_pic_left .upload_pic{
|
||||
margin-left: 27px;
|
||||
}
|
||||
.product_table {
|
||||
min-width: 1570px;
|
||||
}
|
||||
.upload_pic{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
background: none;
|
||||
}
|
||||
.upload_pic_left{
|
||||
height: auto;
|
||||
}
|
||||
.activity_list_add{
|
||||
overflow: visible;
|
||||
}
|
||||
.poster {
|
||||
width: 347px;
|
||||
height: 180px;
|
||||
position: relative;
|
||||
}
|
||||
.upload_pic {
|
||||
width: 284px;
|
||||
height: 176px;
|
||||
border: 1px solid #bfbfbf;
|
||||
position: relative;
|
||||
font-size: 80px;
|
||||
color: #bfbfbf;
|
||||
background: url(/admincpp/img/upload.png) no-repeat;
|
||||
background-size: 60px;
|
||||
background-position: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 30px;
|
||||
margin-left: 27px;
|
||||
display: inline-block;
|
||||
}
|
||||
.poster img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.layout {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.6);
|
||||
z-index: 999;
|
||||
display: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.popup >div {
|
||||
display: none;
|
||||
width: 400px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
top: 46%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
-ms-transform: translate(-50%,-50%);
|
||||
-webkit-transform: translate(-50%,-50%);
|
||||
text-align: center;
|
||||
}
|
||||
.popup {
|
||||
width: 544px;
|
||||
}
|
||||
.popup >div h3 {
|
||||
padding: 7px 0;
|
||||
border-bottom: 1px solid #A4A4A4;
|
||||
}
|
||||
.popup .btn {
|
||||
margin: 15px 0 25px 0;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
justify-content: space-around;
|
||||
-webkit-justify-content: space-around;
|
||||
-moz-justify-content: space-around;
|
||||
-ms-justify-content: space-around;
|
||||
}
|
||||
.popup .btn a {
|
||||
float: left;
|
||||
width: 130px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
color: #333333;
|
||||
background: #fff;
|
||||
border: #f8c619 solid 1px;
|
||||
}
|
||||
.popup p .curr {
|
||||
background: #f8c619;
|
||||
}
|
||||
.popup .activity_product {
|
||||
width: 1239px;
|
||||
height: 640px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body data-idd="71">
|
||||
<div class="main">
|
||||
<ul class="layui-nav" lay-filter="">
|
||||
<span onclick="lists()">< 返回</span>
|
||||
<li class="layui-nav-item layui-this"><a href="#">新建活动</a></li>
|
||||
</ul>
|
||||
<div class="main_top">
|
||||
<div class="head">
|
||||
<div class="head_right">
|
||||
<i id="save" class="layui-btn yellow" >保存</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="product_table activity_list_add" >
|
||||
<input type="hidden" id="id" name="title" value="{$id}"/>
|
||||
<!-- 左侧上传图片-->
|
||||
<div class="upload_pic_left">
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入标题:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="title" name="title" placeholder="建议标题字数在45个字以内"/>
|
||||
<span>
|
||||
<i class="i_leng">0</i>/
|
||||
<em>30</em>
|
||||
</span>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入介绍:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="excerpt_plain" name="title" placeholder="请输入资讯介绍"/>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>
|
||||
请输入资讯跳转链接:
|
||||
</p>
|
||||
<div class="title_content">
|
||||
<input type="text" id="url" name="title" placeholder="请输入资讯跳转链接"/>
|
||||
</div>
|
||||
<p class="title">
|
||||
<i>*</i>请上传资讯图片:
|
||||
<span></span>
|
||||
</p>
|
||||
<div class="img_cont" id="img_cont">
|
||||
<div class="upload_pic poster" id="poster">
|
||||
<img src="" alt="" id="Upload_img2"/>
|
||||
<input id="goodsUpload" hidden type="file" name="file2" />
|
||||
<!-- <i>①</i> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout popup" >
|
||||
<!-- 特价商品 -->
|
||||
<div id="specials" class="activity_product">
|
||||
<p class="btn">
|
||||
<a href="#" id="special_cancel" class="btncancel">取消</a>
|
||||
<a href="#" id="special_deter" class="curr" >确定</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script src="/static/admincpp/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/layui/layui.all.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/common.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/admincpp/js/wechatset/wechatRealTimeInfoUpdate.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
layui.use('upload', function(){
|
||||
var upload = layui.upload;
|
||||
|
||||
//图片上传接口
|
||||
upload.render({
|
||||
elem: '#Upload_img2'
|
||||
,url: '/admincpp/Files/uploadImg' //改成你的图片上传接口
|
||||
,multiple: true
|
||||
,before: function(obj){
|
||||
//do something
|
||||
}
|
||||
,done: function(res){
|
||||
//上传完毕回调
|
||||
if(res.status == 0){ //假设成功返回的code为0
|
||||
$('#Upload_img2').attr("src",res.file_path);
|
||||
//do something
|
||||
}
|
||||
}
|
||||
,error: function(){
|
||||
//请求出错处理
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,10 +9,9 @@ use think\Response;
|
||||
class Base extends Controller
|
||||
{
|
||||
protected function _initialize()
|
||||
{var_dump(1111);exit;
|
||||
{
|
||||
if(!session('adminghd_user_id')){//没有登录信息
|
||||
// $this->redirect('login/index');
|
||||
var_dump(url('Login/logoutJump'));exit;
|
||||
return $this->error('您还未登录',url('Login/logoutJump'));
|
||||
//Response::create(['status' => '0','msg'=> '还未登录,验证失败'], 'json')->send();
|
||||
exit;
|
||||
|
||||
77
application/adminghd/controller/Dashboard.php
Normal file
77
application/adminghd/controller/Dashboard.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace app\adminghd\controller;
|
||||
|
||||
use app\adminghd\common\Base;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 系统概览控制器
|
||||
* GHD预测后台独立实现,不再依赖common模块
|
||||
*/
|
||||
class Dashboard extends Base
|
||||
{
|
||||
/**
|
||||
* 后台首页概览
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return $this->view->fetch('dashboard/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* adminghd模块独立实现,使用ghd_wechat_user表
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
// adminghd模块使用的表名(固定)
|
||||
$userTable = 'ghd_wechat_user';
|
||||
$infoTable = 'wechat_real_time_info';
|
||||
$recordTable = 'wechat_calculate_record';
|
||||
|
||||
// 小程序注册用户数量
|
||||
$userCount = Db::name($userTable)->count();
|
||||
|
||||
// 首页资讯数量
|
||||
$infoCount = Db::name($infoTable)->count();
|
||||
|
||||
// 最近一次计算时间
|
||||
$lastCalculate = Db::name($recordTable)
|
||||
->order('create_time desc')
|
||||
->value('create_time');
|
||||
|
||||
// 今日新增用户
|
||||
$todayUserCount = Db::name($userTable)
|
||||
->whereTime('create_time', 'today')
|
||||
->count();
|
||||
|
||||
// 总计算次数
|
||||
$totalCalculateCount = Db::name($recordTable)->count();
|
||||
|
||||
return json([
|
||||
'status' => 1,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'user_count' => $userCount,
|
||||
'info_count' => $infoCount,
|
||||
'last_calculate_time' => $lastCalculate ?: '暂无',
|
||||
'today_user_count' => $todayUserCount,
|
||||
'total_calculate_count' => $totalCalculateCount
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'status' => 0,
|
||||
'msg' => '获取失败:' . $e->getMessage(),
|
||||
'data' => [
|
||||
'user_count' => 0,
|
||||
'info_count' => 0,
|
||||
'last_calculate_time' => '暂无',
|
||||
'today_user_count' => 0,
|
||||
'total_calculate_count' => 0
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
138
application/adminghd/view/dashboard/index.html
Normal file
138
application/adminghd/view/dashboard/index.html
Normal file
@@ -0,0 +1,138 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>系统概览</title>
|
||||
<link rel="stylesheet" href="/static/adminghd/layui/css/layui.css">
|
||||
<style>
|
||||
body{
|
||||
background:#f5f7fb;
|
||||
padding:24px 24px 40px;
|
||||
box-sizing:border-box;
|
||||
font-family:"Microsoft YaHei",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
|
||||
}
|
||||
.dash-card{
|
||||
background:#fff;
|
||||
border-radius:10px;
|
||||
box-shadow:0 10px 30px rgba(15,35,52,0.06);
|
||||
padding:20px 24px;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.dash-title{
|
||||
font-size:18px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
margin-bottom:4px;
|
||||
}
|
||||
.dash-sub{
|
||||
font-size:12px;
|
||||
color:#9aa4b1;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
.dash-grid{
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:16px;
|
||||
}
|
||||
.dash-item{
|
||||
flex:1 1 200px;
|
||||
min-width:200px;
|
||||
background:#f8fafc;
|
||||
border-radius:8px;
|
||||
padding:14px 16px;
|
||||
cursor:pointer;
|
||||
transition:all 0.3s;
|
||||
}
|
||||
.dash-item:hover{
|
||||
background:#f0f4f8;
|
||||
transform:translateY(-2px);
|
||||
box-shadow:0 4px 12px rgba(15,35,52,0.1);
|
||||
}
|
||||
.dash-item-label{
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.dash-item-value{
|
||||
margin-top:6px;
|
||||
font-size:22px;
|
||||
font-weight:600;
|
||||
color:#1f2d3d;
|
||||
}
|
||||
.dash-item-desc{
|
||||
margin-top:4px;
|
||||
font-size:12px;
|
||||
color:#b0b7c3;
|
||||
}
|
||||
.dash-empty{
|
||||
margin-top:10px;
|
||||
font-size:13px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
.loading{
|
||||
text-align:center;
|
||||
padding:40px;
|
||||
color:#9aa4b1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="dash-card">
|
||||
<div class="dash-title">欢迎使用后台管理系统</div>
|
||||
<div class="dash-sub">这里是系统概览,实时展示系统统计数据。</div>
|
||||
<div class="dash-grid" id="dashGrid">
|
||||
<div class="loading">数据加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/adminghd/js/jquery.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
// 加载统计数据
|
||||
loadStatistics();
|
||||
|
||||
function loadStatistics(){
|
||||
$.ajax({
|
||||
url: '/adminghd/Dashboard/getStatistics',
|
||||
type: 'post',
|
||||
dataType: 'json',
|
||||
success: function(res){
|
||||
if(res.status == 1){
|
||||
renderStatistics(res.data);
|
||||
} else {
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败:' + res.msg + '</div>');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
$('#dashGrid').html('<div class="loading">数据加载失败,请稍后重试</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderStatistics(data){
|
||||
var html = `
|
||||
<div class="dash-item" onclick="parent.location.href='/adminghd/wechatinfro/wechatUserList'">
|
||||
<div class="dash-item-label">小程序注册用户</div>
|
||||
<div class="dash-item-value">${data.user_count}</div>
|
||||
<div class="dash-item-desc">今日新增:${data.today_user_count} 人</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/adminghd/wechatset/wechatRealTimeInfo'">
|
||||
<div class="dash-item-label">首页资讯数量</div>
|
||||
<div class="dash-item-value">${data.info_count}</div>
|
||||
<div class="dash-item-desc">可在「咨询管理」菜单中维护展示内容</div>
|
||||
</div>
|
||||
<div class="dash-item" onclick="parent.location.href='/adminghd/wechatinfro/wechatRecordList'">
|
||||
<div class="dash-item-label">总计算次数</div>
|
||||
<div class="dash-item-value">${data.total_calculate_count}</div>
|
||||
<div class="dash-item-desc">最近一次:${data.last_calculate_time}</div>
|
||||
</div>
|
||||
`;
|
||||
$('#dashGrid').html(html);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,143 +1,106 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>用户登录</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>登录 - 生长激素缺乏预测模型后台</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/adminghd/css/style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/adminghd/css/login.css" />
|
||||
<style>
|
||||
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #11998e 0%, #38ef7d 50%, #06beb6 100%); padding: 20px; box-sizing: border-box; }
|
||||
.login-card { width: 100%; max-width: 400px; background: #fff; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.2); overflow: hidden; }
|
||||
.login-card .login-header { padding: 36px 24px 24px; text-align: center; border-bottom: 1px solid #f0f0f0; }
|
||||
.login-card .login-title { font-size: 18px; font-weight: 600; color: #1f2d3d; line-height: 1.5; margin: 0; }
|
||||
.login-card .login-body { padding: 32px 28px 40px; }
|
||||
.login-card .form-item { margin-bottom: 22px; }
|
||||
.login-card .form-item input { width: 100%; height: 48px; padding: 0 16px; border: 1px solid #e0e0e0; border-radius: 8px; font-size: 15px; color: #333; background: #fafafa; box-sizing: border-box; transition: border-color .2s, background .2s; }
|
||||
.login-card .form-item input::placeholder { color: #aaa; }
|
||||
.login-card .form-item input:focus { outline: none; border-color: #11998e; background: #fff; }
|
||||
.login-card .form-item .warning { display: block; margin-top: 6px; font-size: 12px; color: #e4393c; min-height: 18px; }
|
||||
.login-card .btn-login { width: 100%; height: 48px; border: none; border-radius: 8px; font-size: 16px; font-weight: 500; color: #fff; background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); cursor: pointer; transition: opacity .2s, transform .05s; }
|
||||
.login-card .btn-login:hover { opacity: 0.95; }
|
||||
.login-card .btn-login:active { transform: scale(0.99); }
|
||||
#cover.modal { display: none !important; line-height: 100vh; text-align: center; position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0,0,0,0.6); z-index: 9999; color: #fff; font-size: 18px; }
|
||||
#cover.modal.show { display: flex !important; align-items: center; justify-content: center; }
|
||||
</style>
|
||||
</head>
|
||||
<style>
|
||||
.login-top .tbb{ font-size:18px; font-weight:bold; position:absolute; bottom:0; left:195px; color:#FFD200;}
|
||||
</style>
|
||||
<body style='min-width:1235px'>
|
||||
<div style='height:100px;'></div>
|
||||
<div style='background:#e3e3e3;height:450px;width:100%;position:relative;'>
|
||||
<div style='width:350px;height:400px;background:#EDF1F5;float:right;margin-right:20%;margin-top:1.5%;box-shadow:#666 0px 0px 20px;'>
|
||||
<div class="login-top" style="padding-bottom:0;">
|
||||
<div style='color:#453A3E;margin:30px auto 10px auto;width:150px;font-size:18px;font-weight:bold;text-align:center;'>瑞莱医疗</div>
|
||||
</div>
|
||||
<div style='height:1px;width:100%;background:#DEDCDD;'>
|
||||
<div style='background:#e3e3e3;height:3px;width:80%;margin:0px auto 0 auto;'></div>
|
||||
</div>
|
||||
<form method="post" id="agent_login" name="login">
|
||||
<div class="login-content">
|
||||
<ul class="user-logn">
|
||||
<li class="user-jobnum" style='width:100%;margin-bottom:0px;'>
|
||||
<div class="li-bg error" style='width:100%;'>
|
||||
<label></label>
|
||||
<input type="text" id="username" name="username" placeholder="请输入账号" value="" validate="" validatename="工号" class="phonecode" style='width:83%;padding-right:0px;background:#EDF1F5;height:40px;border:2px solid balck;border-radius:4px;'/>
|
||||
<span id="checkusername" class="warning"></span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="pwd" style='width:100%;margin-bottom:0px;'>
|
||||
<div class="li-bg " style='width:100%;'>
|
||||
<label></label>
|
||||
<input type="password" style="width: 0;height: 0;border: none;" name="">
|
||||
<input type="password" autocomplete="off" id="admin_password" name="password" class="pwd" placeholder="请输入密码" validate="" validatename="密码" style='border:2px solid balck;width:83%;padding-right:0px;background:#EDF1F5;height:40px;border-radius:4px;'>
|
||||
<span id="checkpassword" class="warning"></span>
|
||||
</div>
|
||||
</li>
|
||||
<li style="margin-top:40px;width:100%;">
|
||||
<button type="submit" name="dologinbtn" style='background:#afaeb2;border-radius:4px;height:35px;width:100%;' class="actLogin" onclick="return checklogin(this.form);">立即登录</button>
|
||||
<input type="hidden" name="loginsubmit" value="true" />
|
||||
</li>
|
||||
</ul>
|
||||
<body>
|
||||
<div class="login-wrap">
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<h1 class="login-title">生长激素缺乏预测模型后台</h1>
|
||||
</div>
|
||||
</form>
|
||||
<div class="login-body">
|
||||
<form method="post" id="agent_login" name="login">
|
||||
<div class="form-item">
|
||||
<input type="text" id="username" name="username" placeholder="请输入账号" value="" autocomplete="username" />
|
||||
<span id="checkusername" class="warning"></span>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<input type="password" style="width:0;height:0;border:none;position:absolute;opacity:0;" name="" tabindex="-1" />
|
||||
<input type="password" autocomplete="off" id="admin_password" name="password" placeholder="请输入密码" />
|
||||
<span id="checkpassword" class="warning"></span>
|
||||
</div>
|
||||
<div class="form-item" style="margin-bottom:0;margin-top:28px;">
|
||||
<button type="submit" name="dologinbtn" class="btn-login" onclick="return checklogin(this.form);">立即登录</button>
|
||||
<input type="hidden" name="loginsubmit" value="true" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="cover" class="modal">身份获取中。。。</div>
|
||||
</div>
|
||||
|
||||
<div id="cover" class="modal" style="display:none !important;">身份获取中...</div>
|
||||
|
||||
<script type="text/javascript" src="/static/adminghd/js/jquery.js"></script>
|
||||
<script>
|
||||
var _login_time = -1;
|
||||
var _user_type = '';
|
||||
function checklogin(form){
|
||||
var phonenumFlg = true;
|
||||
var pwdFlg = true;
|
||||
if(!form.username.value || form.username.value.trim() === ''){
|
||||
$('#checkusername').text('账号不能为空').addClass("warning");
|
||||
phonenumFlg = false;
|
||||
} else {
|
||||
$('#checkusername').empty();
|
||||
}
|
||||
if(!form.password.value || form.password.value === ''){
|
||||
$('#checkpassword').text('密码不能为空').addClass("warning");
|
||||
pwdFlg = false;
|
||||
} else {
|
||||
$('#checkpassword').empty();
|
||||
}
|
||||
if(phonenumFlg && pwdFlg){
|
||||
$("#agent_login").off('submit').on("submit", function(event) {
|
||||
event.preventDefault();
|
||||
var $cover = $('#cover');
|
||||
$cover.addClass('show').css('display','flex');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/adminghd/Login/login",
|
||||
data: $(this).serialize(),
|
||||
success: function(data) {
|
||||
$cover.removeClass('show').hide();
|
||||
if(data.status){
|
||||
location.replace("/adminghd/login");
|
||||
} else {
|
||||
alert(data.msg);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
$cover.removeClass('show').hide();
|
||||
console.error("Error: " + textStatus);
|
||||
alert('登录请求失败,请稍后重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
$("#agent_login").submit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<script type="text/javascript" src="/static/adminghd/js/jquery.js"></script>
|
||||
<script>
|
||||
var _login_time = -1;
|
||||
var _user_type = '';
|
||||
|
||||
function checklogin(form){
|
||||
var username = $('username').value;
|
||||
var pwd = $('password').value;
|
||||
var phonenumFlg = true;
|
||||
var pwdFlg = true;
|
||||
//var codeFlg = true;
|
||||
if(form.username.value == null || form.username.value == ""){
|
||||
$('#checkusername').empty();
|
||||
$('#checkusername').append(' 账号不能为空!');
|
||||
$('#checkusername').addClass("warning");
|
||||
phonenumFlg = false;
|
||||
return phonenumFlg;
|
||||
}else{
|
||||
$('#checkusername').empty();
|
||||
// $('#checkusername').append('<img src="/images/base/check_right.gif" width="13" height="13">');
|
||||
$('#checkusername').addClass("warning");
|
||||
}
|
||||
if(form.password.value == null || form.password.value == ""){
|
||||
$('#checkpassword').empty();
|
||||
$('#checkpassword').append(' 密码不能为空!');
|
||||
$('#checkpassword').addClass("warning");
|
||||
pwdFlg = false;
|
||||
return pwdFlg;
|
||||
}else{
|
||||
$('#checkpassword').empty();
|
||||
// $('#checkpassword').append('<img src="/images/base/check_right.gif" width="13" height="13">');
|
||||
$('#checkpassword').addClass("warning");
|
||||
}
|
||||
if(phonenumFlg == true && pwdFlg == true){
|
||||
// alert(11);
|
||||
$("#agent_login").submit(function(event) {
|
||||
event.preventDefault(); // 阻止表单默认提交行为
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/adminghd/Login/login", // 服务器端脚本的 URL
|
||||
data: $(this).serialize(), // 自动序列化表单元素为字符串
|
||||
success: function(data) {
|
||||
if(data.status){
|
||||
//alert(data.msg);
|
||||
location.replace("/adminghd/login");
|
||||
// location.reload();
|
||||
} else {
|
||||
alert(data.msg);
|
||||
return ;
|
||||
}
|
||||
console.log(response); // 处理服务器响应
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error("Error submitting form: " + textStatus);
|
||||
}
|
||||
});
|
||||
});
|
||||
// $('#agent_login').submit();
|
||||
// ajaxpost('registerform', 'register');
|
||||
// $('#agent_login').ajaxSubmit({
|
||||
/* $.ajax({
|
||||
url:'/admin/Login/login',
|
||||
dataType:'json',
|
||||
type:'post',
|
||||
data:{
|
||||
"username":username,
|
||||
"password":pwd
|
||||
},
|
||||
success:function(data){
|
||||
alert(222);
|
||||
alert(data.msg);
|
||||
return false;
|
||||
if(data.status){
|
||||
alert(data.msg);
|
||||
// $(form).resetForm();
|
||||
} else {
|
||||
alert(data.msg);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}) */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp">
|
||||
<title>瑞莱医疗后台</title>
|
||||
<title>生长激素缺乏预测模型后台</title>
|
||||
|
||||
<link rel="stylesheet" href="/static/adminghd/layui/css/layui.css?t=1554901097999" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="/static/adminghd/css/nav.css" />
|
||||
@@ -33,22 +33,14 @@
|
||||
</div>
|
||||
<!--顶部-->
|
||||
<div class="top_right">
|
||||
<a href="javascript:void(0)" class="logo">
|
||||
<!-- <img id="packBtn" src="{S_URL}/templates/adminfactory/img/logo.png">-->
|
||||
</a>
|
||||
<b></b>
|
||||
<div class="header_title">生长激素缺乏预测模型后台</div>
|
||||
<div class="user_right">
|
||||
<a href="javascript:;" id="user" style="position: absolute;left: 100px;top: 4px;font-size: 16px;"></a>
|
||||
<span id="inform">
|
||||
<!-- 您好!工厂
|
||||
<img id="u_headimg" src="{S_URL}/templates/adminfactory/img/logo.png" alt="">
|
||||
<i>荣麟</i> -->
|
||||
</span>
|
||||
<span id="inform"></span>
|
||||
<b class="out" id="sign_out">退出</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main_content">
|
||||
<iframe id="iframeId" src="" frameborder="0"></iframe>
|
||||
<iframe id="iframeId" src="/adminghd/Dashboard/index" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<script src="/static/adminghd/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
401
application/app/controller/Cppwechat.php
Normal file
401
application/app/controller/Cppwechat.php
Normal file
@@ -0,0 +1,401 @@
|
||||
<?php
|
||||
namespace app\app\controller;
|
||||
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* CPP生长减速预测模型 小程序API
|
||||
*/
|
||||
class Cppwechat extends Base
|
||||
{
|
||||
private $Appid;
|
||||
private $Appsecret;
|
||||
private $TokenKey;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->Appid = 'wx2deff82b6c422615';
|
||||
$this->Appsecret = '447c3e46ce640ad772534c8f9161e1fd';
|
||||
$this->TokenKey = 'ruilai340u20k4';
|
||||
}
|
||||
|
||||
/********************************* 首页 *********************************/
|
||||
public function selectRealtimeInfoList(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 20;
|
||||
|
||||
$res = Db::name('wechat_real_time_info')
|
||||
->field('title_plain,thumbnail,excerpt_plain,url')
|
||||
->order('create_time desc')
|
||||
->paginate($page_size, false, ['page' => $page]);
|
||||
|
||||
$result = array();
|
||||
$result['lists'] = $res->items();
|
||||
$result['lastPage'] = $res->lastPage();
|
||||
$result['currentPage'] = $res->currentPage();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/********************************* 计算 *********************************/
|
||||
public function calculate(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入用户id";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['name']) || empty($post['name'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入姓名";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['bone_age']) || empty($post['bone_age']) || !is_numeric($post['bone_age'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入初诊骨龄或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['uterus_length']) || empty($post['uterus_length']) || !is_numeric($post['uterus_length'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入初诊子宫长或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['uterus_width']) || empty($post['uterus_width']) || !is_numeric($post['uterus_width'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入初诊子宫宽或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['lh_peak']) || empty($post['lh_peak']) || !is_numeric($post['lh_peak'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入LH峰值或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['fsh_peak']) || empty($post['fsh_peak']) || !is_numeric($post['fsh_peak'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入FSH峰值或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['fsh_3m']) || empty($post['fsh_3m']) || !is_numeric($post['fsh_3m'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入治疗3月FSH或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['igf1']) || empty($post['igf1']) || !is_numeric($post['igf1'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入基础IGF-1或数据格式不对";
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
// 参数取值
|
||||
$bone_age = floatval($post['bone_age']);
|
||||
$uterus_length = floatval($post['uterus_length']);
|
||||
$uterus_width = floatval($post['uterus_width']);
|
||||
$lh_peak = floatval($post['lh_peak']);
|
||||
$fsh_peak = floatval($post['fsh_peak']);
|
||||
$fsh_3m = floatval($post['fsh_3m']);
|
||||
$igf1 = floatval($post['igf1']);
|
||||
|
||||
// 交互项: 骨龄 x 子宫长
|
||||
$interaction_ba_ul = $bone_age * $uterus_length;
|
||||
// 比值项: LH峰值 / FSH峰值
|
||||
$lh_fsh_ratio = $lh_peak / $fsh_peak;
|
||||
// log(FSH峰值)
|
||||
$log_fsh_peak = log($fsh_peak);
|
||||
|
||||
// 预测模型
|
||||
$logit = -2.8457
|
||||
+ 0.1198 * $interaction_ba_ul
|
||||
+ 1.0411 * $log_fsh_peak
|
||||
- 0.4832 * $fsh_3m
|
||||
- 0.0044 * $igf1
|
||||
+ 0.4207 * $lh_fsh_ratio
|
||||
- 0.8303 * $uterus_width;
|
||||
|
||||
// sigmoid
|
||||
$exp_val = exp($logit);
|
||||
$probability = $exp_val / (1 + $exp_val);
|
||||
|
||||
// 风险分级
|
||||
if ($probability < 0.430) {
|
||||
$risk_level = '低风险';
|
||||
$suggestion = '继续目前GnRHa治疗方案,按常规6个月随访即可,关注身高增长趋势。';
|
||||
} elseif ($probability <= 0.572) {
|
||||
$risk_level = '中风险';
|
||||
$suggestion = '建议缩短随访间隔至3个月,关注GV下降趋势,必要时联合rhGH。';
|
||||
} else {
|
||||
$risk_level = '高风险';
|
||||
$suggestion = '建议每2-3个月密切随访,积极监测生长速率变化,尽早考虑rhGH联合干预。';
|
||||
}
|
||||
|
||||
// 保存记录
|
||||
$data = [];
|
||||
$data['id'] = md5(time() . rand(100000, 999999));
|
||||
$data['uid'] = $post['uid'];
|
||||
$data['name'] = $post['name'];
|
||||
$data['bone_age'] = $bone_age;
|
||||
$data['uterus_length'] = $uterus_length;
|
||||
$data['uterus_width'] = $uterus_width;
|
||||
$data['lh_peak'] = $lh_peak;
|
||||
$data['fsh_peak'] = $fsh_peak;
|
||||
$data['fsh_3m'] = $fsh_3m;
|
||||
$data['igf1'] = $igf1;
|
||||
$data['calculate_result'] = round($probability, 4);
|
||||
$data['risk_level'] = $risk_level;
|
||||
$data['create_time'] = date('Y-m-d H:i:s');
|
||||
|
||||
$res = Db::name('cpp_calculate_record')->insert($data);
|
||||
if ($res === false) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '计算失败,请重试';
|
||||
return json_encode($result);
|
||||
} else {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '计算成功';
|
||||
$result['calculate_result'] = round($probability, 4);
|
||||
$result['risk_level'] = $risk_level;
|
||||
$result['suggestion'] = $suggestion;
|
||||
return json_encode($result);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************* 记录 *********************************/
|
||||
public function selectRecordList(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入用户id";
|
||||
return json_encode($result);
|
||||
}
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1;
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30;
|
||||
|
||||
$res = Db::name('cpp_calculate_record')
|
||||
->field('id,name,bone_age,uterus_length,uterus_width,lh_peak,fsh_peak,fsh_3m,igf1,calculate_result,risk_level,create_time')
|
||||
->where('uid', $post['uid'])
|
||||
->order('create_time desc')
|
||||
->paginate($page_size, false, ['page' => $page]);
|
||||
|
||||
$result = array();
|
||||
$result['lists'] = $res->items();
|
||||
$result['lastPage'] = $res->lastPage();
|
||||
$result['currentPage'] = $res->currentPage();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
public function deleteRecord(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入用户id";
|
||||
return json($result);
|
||||
}
|
||||
if (!isset($post['id']) || empty($post['id'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "请选择要删除的记录";
|
||||
return json($result);
|
||||
}
|
||||
$id = Db::name('cpp_calculate_record')
|
||||
->where('id', $post['id'])
|
||||
->where('uid', $post['uid'])
|
||||
->value('id');
|
||||
if (empty($id)) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '该记录异常,无法删除';
|
||||
return json($result);
|
||||
}
|
||||
$res = Db::name('cpp_calculate_record')->where('id', $id)->delete();
|
||||
if ($res > 0) {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '删除成功';
|
||||
} else {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '删除失败';
|
||||
}
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/********************************* 反馈 *********************************/
|
||||
public function submitFeedback(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "请先登录";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['content']) || empty(trim($post['content']))) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "请输入反馈内容";
|
||||
return json_encode($result);
|
||||
}
|
||||
$data = [];
|
||||
$data['uid'] = $post['uid'];
|
||||
$data['content'] = trim($post['content']);
|
||||
$data['create_time'] = date('Y-m-d H:i:s');
|
||||
$res = Db::name('cpp_feedback')->insert($data);
|
||||
if ($res) {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '感谢您的反馈';
|
||||
} else {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '提交失败,请重试';
|
||||
}
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
/********************************* 登录 *********************************/
|
||||
public function wechatLogin(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['code']) || empty($post['code'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入code";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['encryptedData']) || empty($post['encryptedData'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入encryptedData";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['iv']) || empty($post['iv'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入iv";
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
$encryptedData = $post['encryptedData'];
|
||||
$iv = $post['iv'];
|
||||
$code = $post['code'];
|
||||
$URL = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $this->Appid . "&secret=" . $this->Appsecret . "&js_code=$code&grant_type=authorization_code";
|
||||
$apiData = json_decode($this->httpGet($URL), true);
|
||||
|
||||
if (!isset($apiData['errcode'])) {
|
||||
$sessionKey = $apiData['session_key'];
|
||||
$openid = $apiData['openid'];
|
||||
$errCode = $this->decryptData($sessionKey, $this->Appid, $encryptedData, $iv, $data);
|
||||
if ($errCode == 0) {
|
||||
$record = json_decode($data, true);
|
||||
$record['openid'] = $openid;
|
||||
$res = $this->saveUseInfor($record);
|
||||
return json_encode($res);
|
||||
} else {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '解析接口返回数据失败,请重试!';
|
||||
return json_encode($result);
|
||||
}
|
||||
} else {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = $apiData['errmsg'];
|
||||
return json_encode($result);
|
||||
}
|
||||
}
|
||||
|
||||
private function saveUseInfor($record)
|
||||
{
|
||||
$data = array();
|
||||
$data['nickname'] = isset($record['nickName']) ? $record['nickName'] : 'WeChat User';
|
||||
$data['headimg'] = isset($record['avatarUrl']) ? $record['avatarUrl'] : '';
|
||||
|
||||
$rec = Db::name('wechat_user')->field('uid')->where('openid', $record['openid'])->find();
|
||||
|
||||
if (empty($rec)) {
|
||||
$data['openid'] = $record['openid'];
|
||||
$data['create_time'] = date('Y-m-d H:i:s');
|
||||
$res = Db::name('wechat_user')->insertGetId($data);
|
||||
$uid = $res;
|
||||
} else {
|
||||
$res = Db::name('wechat_user')->where('uid', $rec['uid'])->update($data);
|
||||
$uid = $rec['uid'];
|
||||
}
|
||||
if ($res === false) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '保存信息失败';
|
||||
return $result;
|
||||
} else {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '登录成功';
|
||||
$result['uid'] = $uid;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
public function getToken(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传登录用户id";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['phone']) || empty($post['phone'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传登录用户账号";
|
||||
return json_encode($result);
|
||||
}
|
||||
$arr = array();
|
||||
$arr['phone'] = $post['phone'];
|
||||
$arr['status'] = 1;
|
||||
$res = Db::name('accounthosting')->where($arr)->value('id');
|
||||
if ($res != $post['uid']) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '账号异常';
|
||||
return json_encode($result);
|
||||
}
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '登录成功';
|
||||
$result['token'] = $this->authcode($post['uid'] . '_' . time(), 'ENCODE', $this->TokenKey, 60 * 60 * 3);
|
||||
return json_encode($result);
|
||||
}
|
||||
|
||||
private function checkToken($token, $uid)
|
||||
{
|
||||
$res = $this->authcode($token, 'DECODE', $this->TokenKey, 60 * 60 * 3);
|
||||
if (empty($res)) {
|
||||
return false;
|
||||
} else {
|
||||
$data = explode('_', $res);
|
||||
if ($data[0] == $uid) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserBaseInfo(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['uid']) || empty($post['uid'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入登录人id";
|
||||
return json_encode($result);
|
||||
}
|
||||
if (!isset($post['token']) || empty($post['token'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入token";
|
||||
return json_encode($result);
|
||||
}
|
||||
if ($this->checkToken($post['token'], $post['uid']) === false) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = 'token异常';
|
||||
return json_encode($result);
|
||||
}
|
||||
$result['infor'] = Db::name('accounthosting')
|
||||
->field('name,headimg,balance')
|
||||
->where('id', $post['uid'])
|
||||
->find();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '获取数据成功';
|
||||
return json_encode($result);
|
||||
}
|
||||
}
|
||||
71
application/common/common/BaseController.php
Normal file
71
application/common/common/BaseController.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* 公共基础控制器
|
||||
* 统一处理登录验证和业务类型识别
|
||||
*/
|
||||
namespace app\common\common;
|
||||
|
||||
use think\Controller;
|
||||
use think\Session;
|
||||
use app\common\config\BusinessConfig;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* 当前业务类型
|
||||
* @var string
|
||||
*/
|
||||
protected $businessType;
|
||||
|
||||
/**
|
||||
* 数据表映射
|
||||
* @var array
|
||||
*/
|
||||
protected $tableMap;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function _initialize()
|
||||
{
|
||||
// 获取业务类型
|
||||
$this->businessType = BusinessConfig::getBusinessTypeByModule();
|
||||
$this->tableMap = BusinessConfig::getTableMap($this->businessType);
|
||||
|
||||
// 验证登录
|
||||
$this->checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查登录状态
|
||||
*/
|
||||
protected function checkLogin()
|
||||
{
|
||||
$sessionKey = BusinessConfig::getSessionKey($this->businessType);
|
||||
$loginTimeKey = BusinessConfig::getLoginTimeKey($this->businessType);
|
||||
|
||||
if (!session($sessionKey)) {
|
||||
// 没有登录信息
|
||||
return $this->error('您还未登录', url('Login/logoutJump'));
|
||||
exit;
|
||||
} else {
|
||||
// 登录信息超时
|
||||
$logTime = session($loginTimeKey) - time();
|
||||
if ($logTime < 0) {
|
||||
Session::clear();
|
||||
return $this->error('登录超时', url('Login/logoutJump'));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据表名
|
||||
* @param string $tableKey 表键名
|
||||
* @return string
|
||||
*/
|
||||
protected function getTableName($tableKey)
|
||||
{
|
||||
return isset($this->tableMap[$tableKey]) ? $this->tableMap[$tableKey] : $tableKey;
|
||||
}
|
||||
}
|
||||
69
application/common/config/BusinessConfig.php
Normal file
69
application/common/config/BusinessConfig.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace app\common\config;
|
||||
|
||||
class BusinessConfig
|
||||
{
|
||||
const BUSINESS_ADMIN = 'admin';
|
||||
const BUSINESS_ADMINGHD = 'adminghd';
|
||||
const BUSINESS_ADMINCPP = 'admincpp';
|
||||
|
||||
public static function getTableMap($businessType)
|
||||
{
|
||||
$maps = [
|
||||
self::BUSINESS_ADMIN => [
|
||||
'user' => 'wechat_user',
|
||||
'real_time_info' => 'wechat_real_time_info',
|
||||
'calculate_record' => 'wechat_calculate_record',
|
||||
],
|
||||
self::BUSINESS_ADMINGHD => [
|
||||
'user' => 'ghd_wechat_user',
|
||||
'real_time_info' => 'wechat_real_time_info',
|
||||
'calculate_record' => 'wechat_calculate_record',
|
||||
],
|
||||
self::BUSINESS_ADMINCPP => [
|
||||
'user' => 'wechat_user',
|
||||
'real_time_info' => 'wechat_real_time_info',
|
||||
'calculate_record' => 'cpp_calculate_record',
|
||||
'feedback' => 'cpp_feedback',
|
||||
],
|
||||
];
|
||||
return isset($maps[$businessType]) ? $maps[$businessType] : $maps[self::BUSINESS_ADMIN];
|
||||
}
|
||||
|
||||
public static function getSessionKey($businessType)
|
||||
{
|
||||
$keys = [
|
||||
self::BUSINESS_ADMIN => 'admin_user_id',
|
||||
self::BUSINESS_ADMINGHD => 'adminghd_user_id',
|
||||
self::BUSINESS_ADMINCPP => 'admincpp_user_id',
|
||||
];
|
||||
return isset($keys[$businessType]) ? $keys[$businessType] : 'admin_user_id';
|
||||
}
|
||||
|
||||
public static function getLoginTimeKey($businessType)
|
||||
{
|
||||
$keys = [
|
||||
self::BUSINESS_ADMIN => 'admin_user_login_time',
|
||||
self::BUSINESS_ADMINGHD => 'adminghd_user_login_time',
|
||||
self::BUSINESS_ADMINCPP => 'admincpp_user_login_time',
|
||||
];
|
||||
return isset($keys[$businessType]) ? $keys[$businessType] : 'admin_user_login_time';
|
||||
}
|
||||
|
||||
public static function getBusinessTypeByModule()
|
||||
{
|
||||
$module = request()->module();
|
||||
if ($module === 'adminghd') return self::BUSINESS_ADMINGHD;
|
||||
if ($module === 'admincpp') return self::BUSINESS_ADMINCPP;
|
||||
return self::BUSINESS_ADMIN;
|
||||
}
|
||||
|
||||
public static function getTableName($tableKey, $businessType = null)
|
||||
{
|
||||
if ($businessType === null) {
|
||||
$businessType = self::getBusinessTypeByModule();
|
||||
}
|
||||
$map = self::getTableMap($businessType);
|
||||
return isset($map[$tableKey]) ? $map[$tableKey] : $tableKey;
|
||||
}
|
||||
}
|
||||
68
application/common/controller/DashboardBase.php
Normal file
68
application/common/controller/DashboardBase.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* 系统概览公共控制器
|
||||
* 提供统一的业务逻辑,供admin和adminghd模块继承使用
|
||||
*/
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\common\BaseController;
|
||||
use think\Db;
|
||||
|
||||
class DashboardBase extends BaseController
|
||||
{
|
||||
/**
|
||||
* 获取统计数据
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
// 获取表名
|
||||
$userTable = $this->getTableName('user');
|
||||
$infoTable = $this->getTableName('real_time_info');
|
||||
$recordTable = $this->getTableName('calculate_record');
|
||||
|
||||
// 小程序注册用户数量
|
||||
$userCount = Db::name($userTable)->count();
|
||||
|
||||
// 首页资讯数量
|
||||
$infoCount = Db::name($infoTable)->count();
|
||||
|
||||
// 最近一次计算时间
|
||||
$lastCalculate = Db::name($recordTable)
|
||||
->order('create_time desc')
|
||||
->value('create_time');
|
||||
|
||||
// 今日新增用户
|
||||
$todayUserCount = Db::name($userTable)
|
||||
->whereTime('create_time', 'today')
|
||||
->count();
|
||||
|
||||
// 总计算次数
|
||||
$totalCalculateCount = Db::name($recordTable)->count();
|
||||
|
||||
return json([
|
||||
'status' => 1,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'user_count' => $userCount,
|
||||
'info_count' => $infoCount,
|
||||
'last_calculate_time' => $lastCalculate ?: '暂无',
|
||||
'today_user_count' => $todayUserCount,
|
||||
'total_calculate_count' => $totalCalculateCount
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'status' => 0,
|
||||
'msg' => '获取失败:' . $e->getMessage(),
|
||||
'data' => [
|
||||
'user_count' => 0,
|
||||
'info_count' => 0,
|
||||
'last_calculate_time' => '暂无',
|
||||
'today_user_count' => 0,
|
||||
'total_calculate_count' => 0
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
application/common/controller/WechatinfroBase.php
Normal file
100
application/common/controller/WechatinfroBase.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* 微信用户信息管理公共控制器
|
||||
* 提供统一的业务逻辑,供admin和adminghd模块继承使用
|
||||
*/
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\common\BaseController;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
|
||||
class WechatinfroBase extends BaseController
|
||||
{
|
||||
/**
|
||||
* 查看小程序注册用户信息
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getWechatUserList(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1; // 页数
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30; // 每页条数
|
||||
|
||||
// 搜索
|
||||
$where = [];
|
||||
if (isset($post['title']) && !empty($post['title'])) {
|
||||
$where['nickname'] = ['like', '%' . $post['title'] . '%'];
|
||||
}
|
||||
|
||||
// 获取用户表名
|
||||
$tableName = $this->getTableName('user');
|
||||
|
||||
// 升序获取菜单列表
|
||||
$res = Db::name($tableName)
|
||||
->field('uid,nickname,headimg,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size, false, ['page' => $page]);
|
||||
|
||||
$lists = $res->items();
|
||||
$start = ($page - 1) * $page_size;
|
||||
foreach ($lists as $k => $v) {
|
||||
$start += 1;
|
||||
$lists[$k]['no_id'] = $start;
|
||||
}
|
||||
|
||||
$result['lists'] = $lists;
|
||||
$result['lastPage'] = $res->lastPage(); // 总页数
|
||||
$result['currentPage'] = $res->currentPage(); // 当前页
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看小程序记录
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getWechatRecordList(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1; // 页数
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30; // 每页条数
|
||||
|
||||
// 搜索
|
||||
$where = [];
|
||||
if (isset($post['title']) && !empty($post['title'])) {
|
||||
$where['name'] = ['like', '%' . $post['title'] . '%'];
|
||||
}
|
||||
|
||||
// 获取计算记录表名
|
||||
$tableName = $this->getTableName('calculate_record');
|
||||
|
||||
// 查询列表
|
||||
$res = Db::name($tableName)
|
||||
->field('id,name,age,height,bone_age,father_height,mother_height,IGF,LH,uterus_thickness,calculate_resutlt,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size, false, ['page' => $page]);
|
||||
|
||||
$lists = $res->items();
|
||||
$start = ($page - 1) * $page_size;
|
||||
foreach ($lists as $k => $v) {
|
||||
$start += 1;
|
||||
$lists[$k]['no_id'] = $start;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$result['lists'] = $lists;
|
||||
$result['lastPage'] = $res->lastPage(); // 总页数
|
||||
$result['currentPage'] = $res->currentPage(); // 当前页
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
169
application/common/controller/WechatsetBase.php
Normal file
169
application/common/controller/WechatsetBase.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* 微信设置管理公共控制器
|
||||
* 提供统一的业务逻辑,供admin和adminghd模块继承使用
|
||||
*/
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\common\BaseController;
|
||||
use think\Request;
|
||||
use think\Db;
|
||||
|
||||
class WechatsetBase extends BaseController
|
||||
{
|
||||
/**
|
||||
* 查询小程序资讯信息
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function getWechatRealTimeInfoList(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
|
||||
$page = isset($post['page']) && !empty($post['page']) ? $post['page'] : 1; // 页数
|
||||
$page_size = isset($post['page_size']) && !empty($post['page_size']) ? $post['page_size'] : 30; // 每页条数
|
||||
|
||||
// 搜索
|
||||
$where = [];
|
||||
if (isset($post['title']) && !empty($post['title'])) {
|
||||
$where['title_plain'] = ['like', '%' . $post['title'] . '%'];
|
||||
}
|
||||
|
||||
// 获取资讯表名
|
||||
$tableName = $this->getTableName('real_time_info');
|
||||
|
||||
// 升序获取菜单列表
|
||||
$res = Db::name($tableName)
|
||||
->field('id,title_plain,thumbnail,excerpt_plain,url,create_time')
|
||||
->where($where)
|
||||
->order('create_time desc')
|
||||
->paginate($page_size, false, ['page' => $page]);
|
||||
|
||||
$lists = $res->items();
|
||||
$start = ($page - 1) * $page_size;
|
||||
foreach ($lists as $k => $v) {
|
||||
$start += 1;
|
||||
$lists[$k]['no_id'] = $start;
|
||||
}
|
||||
|
||||
$result['lists'] = $lists;
|
||||
$result['lastPage'] = $res->lastPage(); // 总页数
|
||||
$result['currentPage'] = $res->currentPage(); // 当前页
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '查询成功';
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除小程序资讯信息
|
||||
* @author hjc
|
||||
* @date 2024-05-14
|
||||
*/
|
||||
public function delWechatRealTimeInfo(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['id']) || empty($post['id'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "请选择要删除的记录";
|
||||
return json($result);
|
||||
}
|
||||
|
||||
$tableName = $this->getTableName('real_time_info');
|
||||
$id = Db::name($tableName)->where('id', $post['id'])->value('id');
|
||||
|
||||
if (empty($id)) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "该记录异常,无法删除";
|
||||
return json($result);
|
||||
}
|
||||
|
||||
$res = Db::name($tableName)->where('id', $id)->delete();
|
||||
if ($res > 0) {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = '删除成功';
|
||||
} else {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = '删除失败';
|
||||
}
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存小程序资讯信息
|
||||
* @author hjc
|
||||
*/
|
||||
public function saveWechatRealTimeInfo(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
|
||||
if (!isset($post['title_plain']) || empty($post['title_plain'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入标题";
|
||||
return json($result);
|
||||
}
|
||||
if (!isset($post['thumbnail']) || empty($post['thumbnail'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入图片";
|
||||
return json($result);
|
||||
}
|
||||
if (!isset($post['excerpt_plain']) || empty($post['excerpt_plain'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入简介";
|
||||
return json($result);
|
||||
}
|
||||
if (!isset($post['url']) || empty($post['url'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入资讯跳转链接";
|
||||
return json($result);
|
||||
}
|
||||
|
||||
// 提交数据
|
||||
$data = [];
|
||||
$data['title_plain'] = $post['title_plain']; // 标题
|
||||
$data['thumbnail'] = $post['thumbnail']; // 图片
|
||||
$data['excerpt_plain'] = $post['excerpt_plain']; // 介绍
|
||||
$data['url'] = $post['url']; // 跳转连接
|
||||
|
||||
$tableName = $this->getTableName('real_time_info');
|
||||
|
||||
if (isset($post['id']) && !empty($post['id'])) {
|
||||
// 修改数据
|
||||
$res = Db::name($tableName)->where('id', $post['id'])->update($data);
|
||||
} else {
|
||||
// 保存记录数据
|
||||
$data['id'] = md5(time() . rand(100000, 999999));
|
||||
$data['create_time'] = date('Y-m-d H:i:s');
|
||||
$res = Db::name($tableName)->insert($data);
|
||||
}
|
||||
|
||||
if ($res === false) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "添加失败";
|
||||
return json($result);
|
||||
} else {
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = "添加成功";
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询资讯信息详情
|
||||
* @author hjc
|
||||
*/
|
||||
public function getRealTimeInfoDetail(Request $request)
|
||||
{
|
||||
$post = $request->param();
|
||||
if (!isset($post['id']) || empty($post['id'])) {
|
||||
$result['erro'] = -1;
|
||||
$result['msg'] = "未传入资讯id";
|
||||
return json($result);
|
||||
}
|
||||
|
||||
$tableName = $this->getTableName('real_time_info');
|
||||
$result['infro'] = Db::name($tableName)->where('id', $post['id'])->find();
|
||||
$result['erro'] = 0;
|
||||
$result['msg'] = "查询成功";
|
||||
return json($result);
|
||||
}
|
||||
}
|
||||
105
合并优化说明.md
Normal file
105
合并优化说明.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 两套后台合并优化说明
|
||||
|
||||
## 优化目标
|
||||
将 `admin` 和 `adminghd` 两套后台的重复代码进行合并,通过统一的架构减少代码冗余,提高可维护性。
|
||||
|
||||
## 优化成果
|
||||
|
||||
### 1. 创建公共配置类
|
||||
**文件**: `application/common/config/BusinessConfig.php`
|
||||
|
||||
- 统一管理业务类型配置
|
||||
- 提供数据表映射(`wechat_user` vs `ghd_wechat_user`)
|
||||
- 提供Session标识映射(`admin_user_id` vs `adminghd_user_id`)
|
||||
- 自动根据模块名识别业务类型
|
||||
|
||||
### 2. 创建公共基础控制器
|
||||
**文件**: `application/common/common/BaseController.php`
|
||||
|
||||
- 统一处理登录验证逻辑
|
||||
- 自动识别业务类型并加载对应的数据表映射
|
||||
- 提供 `getTableName()` 方法,自动获取正确的数据表名
|
||||
|
||||
### 3. 创建公共业务控制器
|
||||
**文件**:
|
||||
- `application/common/controller/WechatinfroBase.php` - 微信用户信息管理
|
||||
- `application/common/controller/WechatsetBase.php` - 微信设置管理
|
||||
- `application/common/controller/DashboardBase.php` - 系统概览
|
||||
|
||||
**功能**:
|
||||
- 统一的业务逻辑实现
|
||||
- 自动使用正确的数据表(通过 `getTableName()` 方法)
|
||||
- 减少重复代码约 **70%**
|
||||
|
||||
### 4. 重构模块控制器
|
||||
**修改文件**:
|
||||
- `application/admin/controller/Wechatinfro.php`
|
||||
- `application/admin/controller/Wechatset.php`
|
||||
- `application/admin/controller/Dashboard.php`
|
||||
- `application/adminghd/controller/Wechatinfro.php`
|
||||
- `application/adminghd/controller/Wechatset.php`
|
||||
- `application/adminghd/controller/Dashboard.php`
|
||||
|
||||
**改进**:
|
||||
- 继承公共控制器,代码量减少 **80%**
|
||||
- 只保留视图渲染方法,业务逻辑全部复用
|
||||
|
||||
### 5. 统一Base类
|
||||
**修改文件**:
|
||||
- `application/admin/common/Base.php`
|
||||
- `application/adminghd/common/Base.php`
|
||||
|
||||
**改进**:
|
||||
- 继承公共 `BaseController`
|
||||
- 自动处理业务类型识别和登录验证
|
||||
- 修复了 `adminghd` 模块中的调试代码问题
|
||||
|
||||
## 代码减少统计
|
||||
|
||||
### 控制器代码减少
|
||||
- **Wechatinfro**: 从 ~105 行减少到 ~25 行(减少 76%)
|
||||
- **Wechatset**: 从 ~183 行减少到 ~30 行(减少 84%)
|
||||
- **Dashboard**: 从 ~68 行减少到 ~12 行(减少 82%)
|
||||
|
||||
### 总体效果
|
||||
- **总代码行数减少**: 约 **600+ 行**
|
||||
- **重复代码消除**: 约 **90%**
|
||||
- **维护成本降低**: 修改业务逻辑只需在一个地方进行
|
||||
|
||||
## 架构优势
|
||||
|
||||
1. **单一职责**: 公共控制器只负责业务逻辑,模块控制器只负责视图渲染
|
||||
2. **易于扩展**: 新增业务类型只需在 `BusinessConfig` 中添加配置
|
||||
3. **向后兼容**: 保持两套后台的访问路径不变(`/admin/` 和 `/adminghd/`)
|
||||
4. **数据隔离**: 通过配置自动使用不同的数据表,保证数据隔离
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 添加新的业务类型
|
||||
1. 在 `BusinessConfig.php` 中添加新的业务类型常量
|
||||
2. 在 `getTableMap()` 方法中添加数据表映射
|
||||
3. 在 `getSessionKey()` 方法中添加Session标识映射
|
||||
|
||||
### 添加新的公共业务逻辑
|
||||
1. 在 `application/common/controller/` 下创建新的公共控制器
|
||||
2. 继承 `BaseController`,使用 `getTableName()` 获取数据表名
|
||||
3. 在模块控制器中继承公共控制器
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **静态资源**: CSS和JS文件保持独立,因为路径不同(`/admin/` vs `/adminghd/`)
|
||||
2. **视图文件**: 视图文件保持独立,因为可能有个性化需求
|
||||
3. **登录控制器**: 登录逻辑保持独立,因为Session标识不同
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **统一静态资源**: 可以考虑通过动态变量统一CSS/JS路径
|
||||
2. **统一视图模板**: 如果视图完全一致,可以考虑使用公共视图
|
||||
3. **API统一**: 可以考虑将API接口也进行统一管理
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. 测试 `admin` 模块的所有功能是否正常
|
||||
2. 测试 `adminghd` 模块的所有功能是否正常
|
||||
3. 验证数据表是否正确使用(`wechat_user` vs `ghd_wechat_user`)
|
||||
4. 验证Session是否正确隔离
|
||||
457
后台架构文档.md
Normal file
457
后台架构文档.md
Normal file
@@ -0,0 +1,457 @@
|
||||
# CPP 生长减速预测模型 — 后台架构文档
|
||||
|
||||
## 一、系统总览
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ 客户端 (微信小程序) │
|
||||
│ ├── szjs (生长激素缺乏 GHD) → 微信AppID: wx... │
|
||||
│ ├── cppszjs (CPP 生长减速) → 微信AppID: wx0847525a15342a46 │
|
||||
│ └── rlgz (瑞来工作) → 微信AppID: wx... │
|
||||
└──────────────────────────────┬───────────────────────────────────────┘
|
||||
│ HTTPS POST
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ ThinkPHP 5.0 后端 (ruilaizipj.com) — 腾讯云 101.43.95.130 │
|
||||
│ │
|
||||
│ app 模块 (小程序API) │
|
||||
│ ├── Cppwechat.php ← cppszjs 小程序 API │
|
||||
│ ├── Ruilaiwechat.php ← szjs 小程序 API │
|
||||
│ └── ... │
|
||||
│ │
|
||||
│ 后台管理模块 (三套独立入口) │
|
||||
│ ├── admincpp/ → /admincpp CPP 生长减速预测模型后台 │
|
||||
│ ├── adminghd/ → /adminghd 生长激素缺乏预测模型后台 │
|
||||
│ └── admin/ → /admin 通用后台 │
|
||||
└──────────────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ MySQL 数据库 (127.0.0.1:3306, 库名: ruilai) │
|
||||
│ 表前缀: t_sys_ │
|
||||
│ 用户名: rootrui 密码: X2)jB+k%YH.p │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、URL 路由与模块隔离
|
||||
|
||||
### 2.1 模块自动识别
|
||||
|
||||
ThinkPHP 通过 URL 第一段自动识别模块名,由 `BusinessConfig.php` 实现:
|
||||
|
||||
```php
|
||||
// /application/common/config/BusinessConfig.php
|
||||
public static function getBusinessTypeByModule() {
|
||||
$module = request()->module();
|
||||
if ($module === 'adminghd') return self::BUSINESS_ADMINGHD;
|
||||
if ($module === 'admincpp') return self::BUSINESS_ADMINCPP;
|
||||
return self::BUSINESS_ADMIN;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 三个后台入口
|
||||
|
||||
| 模块 | URL | Session Key | 对应项目 |
|
||||
|------|-----|-------------|----------|
|
||||
| admin | /admin/login | admin_user_id | 通用 |
|
||||
| adminghd | /adminghd/login | adminghd_user_id | 生长激素缺乏 GHD |
|
||||
| admincpp | /admincpp/login | admincpp_user_id | CPP 生长减速 |
|
||||
|
||||
### 2.3 表名映射
|
||||
|
||||
不同模块访问同一逻辑表名时,自动路由到不同的物理表:
|
||||
|
||||
| 逻辑表名 | admin | adminghd | admincpp |
|
||||
|----------|-------|----------|----------|
|
||||
| user | wechat_user | ghd_wechat_user | wechat_user |
|
||||
| calculate_record | wechat_calculate_record | wechat_calculate_record | cpp_calculate_record |
|
||||
| feedback | — | — | cpp_feedback |
|
||||
| real_time_info | wechat_real_time_info | wechat_real_time_info | wechat_real_time_info |
|
||||
|
||||
> 注:ThinkPHP `Db::name('xxx')` 会自动添加 `t_sys_` 前缀,例如 `Db::name('wechat_user')` → `t_sys_wechat_user`
|
||||
|
||||
---
|
||||
|
||||
## 三、admincpp 模块 — 目录结构
|
||||
|
||||
```
|
||||
application/admincpp/
|
||||
├── common/
|
||||
│ └── Base.php # 基类 (session 登录校验)
|
||||
├── common.php # 模块公共函数
|
||||
├── config.php # 模块配置
|
||||
├── controller/
|
||||
│ ├── Dashboard.php # 仪表盘 / 统计
|
||||
│ ├── Files.php # 文件上传
|
||||
│ ├── Index.php # 首页 / 菜单管理 API
|
||||
│ ├── Login.php # 登录 / 退出 / 超时跳转
|
||||
│ ├── Menu.php # 菜单管理 (CRUD)
|
||||
│ ├── Wechatinfro.php # 用户列表 / 计算记录 / 反馈列表
|
||||
│ └── Wechatset.php # 首页资讯管理
|
||||
├── model/
|
||||
│ ├── Permission.php # 权限模型
|
||||
│ └── Role.php # 角色模型
|
||||
└── view/
|
||||
├── dashboard/
|
||||
│ └── index.html # 系统概览页 (统计卡片)
|
||||
├── login/
|
||||
│ ├── login.html # 登录页
|
||||
│ ├── logoutJump.html # 超时跳转页
|
||||
│ └── nav.html # 主框架 (侧边栏+顶栏+iframe)
|
||||
├── wechatinfro/
|
||||
│ ├── feedbackList.html # 反馈列表
|
||||
│ ├── userList.html # 用户列表
|
||||
│ └── wechatRecordList.html# CPP 计算记录列表
|
||||
└── wechatset/
|
||||
├── realTimeInfo.html # 资讯列表
|
||||
├── realTimeInfoAdd.html # 添加资讯
|
||||
└── realTimeInfoUpdate.html # 编辑资讯
|
||||
|
||||
public/static/admincpp/
|
||||
├── css/
|
||||
│ ├── activity.css # 活动页样式
|
||||
│ ├── index.css # 内容页样式 (table, main, head)
|
||||
│ ├── login.css # 登录页样式
|
||||
│ ├── nav.css # 主框架样式 (侧边栏+顶栏)
|
||||
│ └── style.css # 全局基础样式 (reset)
|
||||
├── js/
|
||||
│ ├── common.js # 公共函数 (超时检测)
|
||||
│ ├── jquery.js # jQuery
|
||||
│ ├── menu.js # (废弃) 早期菜单组件
|
||||
│ ├── nav.js # 主框架JS (菜单渲染、用户信息、退出)
|
||||
│ ├── wechatinfro/
|
||||
│ │ ├── feedbackList.js # 反馈列表 DataTable
|
||||
│ │ ├── userList.js # 用户列表 DataTable
|
||||
│ │ └── wechatRecordList.js # 计算记录 DataTable
|
||||
│ └── wechatset/
|
||||
│ ├── wechatRealTimeInfoAdd.js # 添加资讯
|
||||
│ ├── wechatRealTimeInfoList.js # 资讯列表
|
||||
│ └── wechatRealTimeInfoUpdate.js # 编辑资讯
|
||||
├── img/
|
||||
│ └── upload.png # 默认头像
|
||||
└── layui/ # layUI 框架 (v2.x)
|
||||
├── css/
|
||||
├── font/
|
||||
├── images/
|
||||
├── lay/
|
||||
└── layui.all.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、控制器详解
|
||||
|
||||
### 4.1 Login.php — 登录控制器
|
||||
|
||||
| 方法 | URL | Method | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| index() | /admincpp/Login/index | GET | 渲染登录页 (未登录) 或导航框架 (已登录) |
|
||||
| login() | /admincpp/Login/login | POST | 验证手机号+MD5密码,写入 session |
|
||||
| logout() | /admincpp/Login/logout | POST | 清除 session,退出登录 |
|
||||
| logoutJump() | /admincpp/Login/logoutJump | GET | 超时跳转提示页 |
|
||||
|
||||
**登录验证流程**:
|
||||
1. 查询 `t_sys_user` 表:`phone=$username AND password=MD5($password) AND status=1 AND type=1`
|
||||
2. 验证通过后设置 session:
|
||||
- `admincpp_user_id` → 用户ID
|
||||
- `admincpp_user_login_time` → `time() + 3600`
|
||||
|
||||
### 4.2 Dashboard.php — 仪表盘
|
||||
|
||||
| 方法 | URL | Method | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| index() | /admincpp/Dashboard/index | GET | 渲染系统概览页 |
|
||||
| getStatistics() | /admincpp/Dashboard/getStatistics | POST | 返回 JSON 统计数据 |
|
||||
|
||||
**统计返回字段**:
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"data": {
|
||||
"user_count": 87, // 微信用户总数
|
||||
"today_user_count": 0, // 今日新增
|
||||
"total_calculate_count": 19, // 累计计算次数
|
||||
"info_count": 2, // 首页资讯数量
|
||||
"last_calculate_time": "2026-07-18 15:37:53"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Wechatinfro.php — 数据管理
|
||||
|
||||
| 方法 | URL | Method | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| wechatUserList() | /admincpp/Wechatinfro/wechatUserList | GET | 用户列表页 |
|
||||
| getWechatUserList() | /admincpp/Wechatinfro/getWechatUserList | POST | 用户列表 JSON |
|
||||
| wechatRecordList() | /admincpp/Wechatinfro/wechatRecordList | GET | 计算记录页 |
|
||||
| getWechatRecordList() | /admincpp/Wechatinfro/getWechatRecordList | POST | 计算记录 JSON |
|
||||
| feedbackList() | /admincpp/Wechatinfro/feedbackList | GET | 反馈列表页 |
|
||||
| getFeedbackList() | /admincpp/Wechatinfro/getFeedbackList | POST | 反馈列表 JSON |
|
||||
|
||||
**计算记录列表字段** (对应 `t_sys_cpp_calculate_record`):
|
||||
`id, name, bone_age, uterus_length, uterus_width, lh_peak, fsh_peak, fsh_3m, igf1, calculate_result, risk_level, create_time`
|
||||
|
||||
### 4.4 Wechatset.php — 资讯管理
|
||||
|
||||
| 方法 | URL | Method | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| wechatRealTimeInfo() | /admincpp/Wechatset/wechatRealTimeInfo | GET | 资讯列表页 |
|
||||
| wechatRealTimeInfoAdd() | /admincpp/Wechatset/wechatRealTimeInfoAdd | GET | 添加资讯页 |
|
||||
| wechatRealTimeInfoUpdate() | /admincpp/Wechatset/wechatRealTimeInfoUpdate | GET | 编辑资讯页 |
|
||||
| getWechatRealTimeInfoList() | /admincpp/Wechatset/getWechatRealTimeInfoList | POST | 资讯列表 JSON |
|
||||
| saveWechatRealTimeInfo() | /admincpp/Wechatset/saveWechatRealTimeInfo | POST | 保存/更新资讯 |
|
||||
| delWechatRealTimeInfo() | /admincpp/Wechatset/delWechatRealTimeInfo | POST | 删除资讯 |
|
||||
| getRealTimeInfoDetail() | /admincpp/Wechatset/getRealTimeInfoDetail | POST | 获取单条资讯详情 |
|
||||
|
||||
### 4.5 Menu.php — 菜单管理
|
||||
|
||||
| 方法 | URL | 说明 |
|
||||
|------|-----|------|
|
||||
| getMenuList() | /admincpp/Menu/getMenuList | 获取菜单树 (一级+二级) |
|
||||
| getUserInfor() | /admincpp/Menu/getUserInfor | 获取当前登录用户信息 |
|
||||
| doaddMenu() | /admincpp/Menu/doaddMenu | 添加菜单项 |
|
||||
| doupdMenu() | /admincpp/Menu/doupdMenu | 更新菜单项 |
|
||||
| delMenu() | /admincpp/Menu/delMenu | 删除菜单项 |
|
||||
|
||||
### 4.6 Base.php — 登录校验基类
|
||||
|
||||
```php
|
||||
class Base extends Controller {
|
||||
protected function _initialize() {
|
||||
if (!session('admincpp_user_id')) {
|
||||
// 未登录 → 跳转超时页
|
||||
return $this->error('您还未登录', url('Login/logoutJump'));
|
||||
}
|
||||
$log_time = session('admincpp_user_login_time') - time();
|
||||
if ($log_time < 0) {
|
||||
// 超时 → 清除 session → 跳转
|
||||
Session::clear();
|
||||
return $this->error('登录超时', url('Login/logoutJump'));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Dashboard、Wechatinfro、Wechatset、Menu 均继承 Base,需登录后才能访问。
|
||||
|
||||
---
|
||||
|
||||
## 五、前端框架 (nav.js) 工作流程
|
||||
|
||||
### 5.1 页面加载流程
|
||||
|
||||
```
|
||||
Login 成功 → 设置 session → 跳转 /admincpp/Login/index
|
||||
→ Login::index() 检测 session → 返回 nav.html
|
||||
→ nav.html 加载 nav.css + nav.js
|
||||
→ nav.js 初始化:
|
||||
1. 设置默认 iframe 页面: /admincpp/Dashboard/index
|
||||
2. AJAX 调用 /admincpp/Menu/getMenuList 获取菜单数据
|
||||
3. AJAX 调用 /admincpp/Menu/getUserInfor 获取用户信息
|
||||
4. MenuHtml() 渲染侧边栏菜单
|
||||
5. 点击菜单 → 更新 iframe src
|
||||
```
|
||||
|
||||
### 5.2 菜单 URL 转换
|
||||
|
||||
数据库共享 `t_sys_menu` 表,菜单 URL 默认为 `/admin/...`。nav.js 在渲染时自动转换:
|
||||
|
||||
```javascript
|
||||
// nav.js 中的 URL 转换逻辑
|
||||
data-url="${(child.url || '').replace('/admin/', '/admincpp/')}"
|
||||
```
|
||||
|
||||
### 5.3 主框架布局
|
||||
|
||||
```
|
||||
┌──────────────┬────────────────────────────────────┐
|
||||
│ .layui-side │ .top_right │
|
||||
│ (侧边栏导航) │ ┌ .header_title ──┬ .user_right ┐ │
|
||||
│ │ │ 标题 │ 用户名 退出 │ │
|
||||
│ .layui-side- │ └─────────────────┴─────────────┘ │
|
||||
│ scroll │ │
|
||||
│ │ .main_content │
|
||||
│ ul#nav │ ┌──────────────────────────────┐ │
|
||||
│ (菜单树) │ │ iframe#iframeId │ │
|
||||
│ │ │ (加载各功能页面) │ │
|
||||
│ │ │ │ │
|
||||
│ │ └──────────────────────────────┘ │
|
||||
└──────────────┴────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、小程序 API (app/Cppwechat.php)
|
||||
|
||||
位于 `/application/app/controller/Cppwechat.php`,为 CPP 小程序提供后端接口。
|
||||
|
||||
### 6.1 API 列表
|
||||
|
||||
| 方法 | URL | 说明 |
|
||||
|------|-----|------|
|
||||
| selectRealtimeInfoList() | /app/Cppwechat/selectRealtimeInfoList | 首页资讯列表 |
|
||||
| calculate() | /app/Cppwechat/calculate | CPP 生长减速预测计算 |
|
||||
| selectRecordList() | /app/Cppwechat/selectRecordList | 计算历史记录 |
|
||||
| deleteRecord() | /app/Cppwechat/deleteRecord | 删除计算记录 |
|
||||
| submitFeedback() | /app/Cppwechat/submitFeedback | 提交意见反馈 |
|
||||
| wechatLogin() | /app/Cppwechat/wechatLogin | 微信登录 |
|
||||
| getToken() | /app/Cppwechat/getToken | 获取登录 Token |
|
||||
| getUserBaseInfo() | /app/Cppwechat/getUserBaseInfo | 获取用户基本信息 |
|
||||
|
||||
### 6.2 预测模型公式
|
||||
|
||||
```
|
||||
交互项 = 骨龄 × 子宫长
|
||||
比值项 = LH峰值 / FSH峰值
|
||||
log(FSH峰值) = ln(FSH峰值)
|
||||
|
||||
logit(p) = -2.8457
|
||||
+ 0.1198 × (骨龄 × 子宫长)
|
||||
+ 1.0411 × ln(FSH峰值)
|
||||
- 0.4832 × 治疗3月FSH
|
||||
- 0.0044 × 基础IGF-1
|
||||
+ 0.4207 × (LH峰值 / FSH峰值)
|
||||
- 0.8303 × 子宫宽
|
||||
|
||||
p = exp(logit) / (1 + exp(logit))
|
||||
```
|
||||
|
||||
### 6.3 输入参数
|
||||
|
||||
| 字段 | 说明 | 范围 | 单位 |
|
||||
|------|------|------|------|
|
||||
| bone_age | 初诊骨龄 | 5.0 – 13.0 | 岁 |
|
||||
| uterus_length | 初诊子宫长 | 1.0 – 4.5 | cm |
|
||||
| uterus_width | 初诊子宫宽 | 0.5 – 3.5 | cm |
|
||||
| lh_peak | LH 峰值 | 0.5 – 90.0 | IU/L |
|
||||
| fsh_peak | FSH 峰值 | 0.5 – 25.0 | IU/L |
|
||||
| fsh_3m | 治疗3月FSH | 0.0 – 8.0 | IU/L |
|
||||
| igf1 | 基础IGF-1 | 100 – 800 | ng/mL |
|
||||
|
||||
### 6.4 风险分级
|
||||
|
||||
| 等级 | 概率范围 | 临床建议 |
|
||||
|------|----------|----------|
|
||||
| 低风险 | p < 0.430 | 继续目前 GnRHa 治疗方案,常规6个月随访 |
|
||||
| 中风险 | 0.430 ≤ p ≤ 0.572 | 缩短随访间隔至3个月,关注GV下降趋势 |
|
||||
| 高风险 | p > 0.572 | 每2-3个月密切随访,尽早考虑 rhGH 联合干预 |
|
||||
|
||||
### 6.5 性能指标
|
||||
|
||||
- **AUC**: 0.718 (Bootstrap 矫正 0.687)
|
||||
- **Hosmer-Lemeshow**: P = 0.909(校准优秀)
|
||||
|
||||
---
|
||||
|
||||
## 七、数据库表结构
|
||||
|
||||
### 7.1 t_sys_cpp_calculate_record(计算记录)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | varchar(32) PK | MD5 唯一ID |
|
||||
| uid | int(11) | 用户ID |
|
||||
| name | varchar(32) | 患者姓名 |
|
||||
| bone_age | decimal(5,2) | 初诊骨龄 |
|
||||
| uterus_length | decimal(5,2) | 初诊子宫长 |
|
||||
| uterus_width | decimal(5,2) | 初诊子宫宽 |
|
||||
| lh_peak | decimal(6,2) | LH 峰值 |
|
||||
| fsh_peak | decimal(6,2) | FSH 峰值 |
|
||||
| fsh_3m | decimal(5,2) | 治疗3月 FSH |
|
||||
| igf1 | decimal(7,2) | 基础 IGF-1 |
|
||||
| calculate_result | decimal(6,4) | 预测概率 p |
|
||||
| risk_level | varchar(10) | 风险等级 |
|
||||
| create_time | datetime | 创建时间 |
|
||||
|
||||
### 7.2 t_sys_cpp_feedback(意见反馈)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | int(11) PK AUTO_INCREMENT | 自增ID |
|
||||
| uid | varchar(50) | 用户ID |
|
||||
| content | text | 反馈内容 |
|
||||
| create_time | datetime | 提交时间 |
|
||||
|
||||
### 7.3 t_sys_wechat_user(微信用户)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| uid | int(11) PK AUTO_INCREMENT | 用户ID |
|
||||
| openid | varchar(64) | 微信 OpenID |
|
||||
| nickname | varchar(64) | 微信昵称 |
|
||||
| headimg | varchar(200) | 头像URL |
|
||||
| create_time | datetime | 注册时间 |
|
||||
|
||||
### 7.4 t_sys_user(后台管理员)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | int(11) PK AUTO_INCREMENT | 管理员ID |
|
||||
| user_name | varchar(125) | 姓名 |
|
||||
| user_head | varchar(125) | 头像 |
|
||||
| phone | varchar(11) | 手机号(登录账号) |
|
||||
| password | varchar(64) | MD5 密码 |
|
||||
| type | int(2) | 用户类型 (1=管理员) |
|
||||
| status | int(2) | 状态 (1=正常) |
|
||||
|
||||
### 7.5 t_sys_menu(菜单配置 — 三模块共享)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | varchar(32) PK | 菜单ID |
|
||||
| pid | varchar(64) | 父级ID (0=一级) |
|
||||
| menu_name | varchar(64) | 菜单名称 |
|
||||
| url | varchar(255) | 菜单URL |
|
||||
| seq_on | int(255) | 排序 |
|
||||
| menu_icon | varchar(100) | 图标 |
|
||||
|
||||
当前菜单数据:
|
||||
```
|
||||
id=1 pid=0 menu_name=小程序
|
||||
├── id=2 pid=1 menu_name=小程序设置 url=/admin/Wechatset/wechatRealTimeInfo
|
||||
├── id=3 pid=1 menu_name=小程序注册用户 url=/admin/Wechatinfro/wechatUserList
|
||||
└── id=4 pid=1 menu_name=计算记录 url=/admin/Wechatinfro/wechatRecordList
|
||||
```
|
||||
|
||||
> 注:三个模块共享此表。各模块的 `nav.js` 会在渲染时自动将 `/admin/` 替换为各自的模块路径。
|
||||
|
||||
### 7.6 t_sys_wechat_real_time_info(首页资讯 — 三模块共享)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | varchar(32) PK | 资讯ID |
|
||||
| title_plain | varchar(255) | 标题 |
|
||||
| thumbnail | varchar(125) | 缩略图 |
|
||||
| excerpt_plain | text | 摘要 |
|
||||
| url | varchar(125) | 详情链接 |
|
||||
| create_time | datetime | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 八、登录凭证
|
||||
|
||||
| 后台 | URL | 账号 | 密码 |
|
||||
|------|-----|------|------|
|
||||
| CPP | http://101.43.95.130/admincpp/login | 13212345678 | 123456 |
|
||||
| GHD | http://101.43.95.130/adminghd/login | 13212345678 | 123456 |
|
||||
| 通用 | http://101.43.95.130/admin/login | 13212345678 | 123456 |
|
||||
|
||||
> 三个后台共用 `t_sys_user` 表,使用同一套账号密码。
|
||||
|
||||
---
|
||||
|
||||
## 九、服务器信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 服务器 IP | 101.43.95.130 |
|
||||
| SSH 用户 | renjianbo / 123456 |
|
||||
| Web 目录 | /www/wwwroot/code/ |
|
||||
| PHP 版本 | PHP 7.x |
|
||||
| 框架 | ThinkPHP 5.0 |
|
||||
| 数据库 | MySQL (127.0.0.1), 库名 ruilai |
|
||||
| 数据库用户 | rootrui / X2)jB+k%YH.p |
|
||||
| Web 服务器 | Nginx |
|
||||
| 管理面板 | 宝塔 (BT Panel) |
|
||||
Reference in New Issue
Block a user