diff --git a/DOCTOR_API_GUIDE.md b/DOCTOR_API_GUIDE.md new file mode 100644 index 00000000..98d9e826 --- /dev/null +++ b/DOCTOR_API_GUIDE.md @@ -0,0 +1,230 @@ +# 医生API接口文档 + +## 概述 + +本文档描述了医生相关的API接口,用于小程序首页展示医生列表和医生详情。 + +## 后端实现 + +### 1. 医生逻辑层 (DoctorLogic) + +**文件位置**: `server/app/api/logic/DoctorLogic.php` + +主要方法: +- `getDoctorList($params)` - 获取医生列表 +- `getDoctorDetail($doctorId)` - 获取医生详情 +- `getDoctorRoster($doctorId, $date)` - 获取医生排班 + +### 2. 医生控制器 (DoctorController) + +**文件位置**: `server/app/api/controller/DoctorController.php` + +提供以下API端点: +- `GET /api/doctor/lists` - 获取医生列表 +- `GET /api/doctor/detail` - 获取医生详情 +- `GET /api/doctor/roster` - 获取医生排班 + +### 3. 数据来源 + +医生数据来自 `zyt_admin` 表,筛选条件: +- `role_id = 1`(医生角色) +- `disable = 0`(未禁用) + +## API 接口详情 + +### 1. 获取医生列表 + +**请求**: +``` +GET /api/doctor/lists +``` + +**参数**: +| 参数 | 类型 | 必需 | 说明 | +|------|------|------|------| +| page_no | int | 否 | 页码,默认1 | +| page_size | int | 否 | 每页数量,默认10 | +| keyword | string | 否 | 搜索关键词(医生名字或账号) | + +**响应示例**: +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [ + { + "id": 1, + "name": "张医生", + "account": "doctor1", + "avatar": "http://example.com/avatar.jpg", + "mobile": "13800138000", + "email": "doctor@example.com", + "specialty": "医生", + "title": "医生", + "rating": "4.8" + } + ], + "count": 10, + "page_no": 1, + "page_size": 10 + } +} +``` + +### 2. 获取医生详情 + +**请求**: +``` +GET /api/doctor/detail +``` + +**参数**: +| 参数 | 类型 | 必需 | 说明 | +|------|------|------|------| +| id | int | 是 | 医生ID | + +**响应示例**: +```json +{ + "code": 1, + "msg": "success", + "data": { + "id": 1, + "name": "张医生", + "account": "doctor1", + "avatar": "http://example.com/avatar.jpg", + "mobile": "13800138000", + "email": "doctor@example.com", + "specialty": "医生", + "title": "医生", + "rating": "4.8" + } +} +``` + +### 3. 获取医生排班 + +**请求**: +``` +GET /api/doctor/roster +``` + +**参数**: +| 参数 | 类型 | 必需 | 说明 | +|------|------|------|------| +| doctor_id | int | 是 | 医生ID | +| date | string | 是 | 日期(YYYY-MM-DD格式) | + +**响应示例**: +```json +{ + "code": 1, + "msg": "success", + "data": [ + { + "id": 1, + "doctor_id": 1, + "date": "2024-03-11", + "period": "morning", + "status": 1, + "quota": 20, + "max_patients": 30, + "remark": "" + } + ] +} +``` + +## 前端实现 + +### 1. API 服务文件 + +**文件位置**: `TUICallKit-Vue3/utils/api.js` + +提供了便捷的API调用方法: +```javascript +import { doctorApi } from '@/utils/api' + +// 获取医生列表 +const response = await doctorApi.getDoctorList({ + page_no: 1, + page_size: 10 +}) + +// 获取医生详情 +const doctor = await doctorApi.getDoctorDetail(1) + +// 获取医生排班 +const roster = await doctorApi.getDoctorRoster(1, '2024-03-11') +``` + +### 2. 小程序首页 + +**文件位置**: `TUICallKit-Vue3/pages/index/index.vue` + +首页会自动加载医生列表并展示: +- 古典卷轴风格幻灯片 +- 医生团队卡片(从后端动态加载) +- 点击医生卡片可跳转到挂号页面 + +## 使用流程 + +### 后端配置 + +1. 确保 `zyt_admin` 表中有 `role_id = 1` 的医生记录 +2. 医生的 `disable` 字段应为 0(未禁用) +3. 医生的 `avatar` 字段应包含头像URL + +### 前端配置 + +1. 在 `TUICallKit-Vue3/.env` 中配置API基础URL: +``` +VUE_APP_API_URL=http://your-api-domain/api +``` + +2. 首页会自动调用 `doctorApi.getDoctorList()` 获取医生列表 + +## 扩展功能 + +### 1. 添加医生专科和职位 + +修改 `DoctorLogic.php` 中的 `getDoctorList()` 方法,从其他表获取医生的专科和职位信息: + +```php +// 可以添加关联查询 +$doctor['specialty'] = '内科'; // 从科室表获取 +$doctor['title'] = '主任医师'; // 从职位表获取 +``` + +### 2. 添加医生评分 + +可以从预约或评价表中计算医生的平均评分: + +```php +$doctor['rating'] = DoctorRating::where('doctor_id', $doctor['id'])->avg('rating'); +``` + +### 3. 添加医生搜索功能 + +前端可以调用 `getDoctorList()` 时传入 `keyword` 参数进行搜索。 + +## 常见问题 + +### Q: 医生列表为空? +A: 检查 `zyt_admin` 表中是否有 `role_id = 1` 且 `disable = 0` 的记录。 + +### Q: 头像无法显示? +A: 确保 `avatar` 字段包含完整的URL,或者在 `FileService::getFileUrl()` 中正确处理相对路径。 + +### Q: 如何添加医生的其他信息? +A: 修改 `DoctorLogic.php` 中的数据处理逻辑,从其他表关联查询所需信息。 + +## 相关文件 + +- 后端逻辑: `server/app/api/logic/DoctorLogic.php` +- 后端控制器: `server/app/api/controller/DoctorController.php` +- 前端API服务: `TUICallKit-Vue3/utils/api.js` +- 前端首页: `TUICallKit-Vue3/pages/index/index.vue` +- 医生模型: `server/app/common/model/auth/Admin.php` +- 医生排班模型: `server/app/common/model/doctor/Roster.php` diff --git a/DOCTOR_FEATURE_IMPLEMENTATION.md b/DOCTOR_FEATURE_IMPLEMENTATION.md new file mode 100644 index 00000000..4f745505 --- /dev/null +++ b/DOCTOR_FEATURE_IMPLEMENTATION.md @@ -0,0 +1,274 @@ +# 医生功能实现总结 + +## 功能概述 + +实现了小程序首页医生展示功能,包括: +1. 古典卷轴风格幻灯片 +2. 动态医生列表展示(从后端API获取) +3. 医生卡片点击跳转到挂号页面 + +## 后端实现 + +### 1. 医生逻辑层 (DoctorLogic) + +**文件**: `server/app/api/logic/DoctorLogic.php` + +**功能**: +- `getDoctorList()` - 获取医生列表,支持分页和搜索 +- `getDoctorDetail()` - 获取单个医生详情 +- `getDoctorRoster()` - 获取医生排班信息 + +**数据来源**: `zyt_admin` 表(role_id = 1 的医生) + +**返回字段**: +```php +[ + 'id' => 医生ID, + 'name' => 医生名字, + 'account' => 医生账号, + 'avatar' => 医生头像URL, + 'mobile' => 医生手机, + 'email' => 医生邮箱, + 'specialty' => 专科, + 'title' => 职位, + 'rating' => 评分 +] +``` + +### 2. 医生控制器 (DoctorController) + +**文件**: `server/app/api/controller/DoctorController.php` + +**API端点**: +- `GET /api/doctor/lists` - 获取医生列表 +- `GET /api/doctor/detail` - 获取医生详情 +- `GET /api/doctor/roster` - 获取医生排班 + +**无需登录的端点**: `lists`, `detail` + +## 前端实现 + +### 1. API 服务层 + +**文件**: `TUICallKit-Vue3/utils/api.js` + +**功能**: +- 统一的API请求管理 +- 自动添加认证token +- 错误处理 + +**使用示例**: +```javascript +import { doctorApi } from '@/utils/api' + +// 获取医生列表 +const response = await doctorApi.getDoctorList({ + page_no: 1, + page_size: 10 +}) +``` + +### 2. 首页组件 + +**文件**: `TUICallKit-Vue3/pages/index/index.vue` + +**功能**: +- 古典卷轴风格幻灯片(自动轮播) +- 医生列表展示(动态加载) +- 医生卡片交互(点击跳转) + +**样式特点**: +- 金色卷轴装饰(#d4af37) +- 渐变背景效果 +- 响应式布局 +- 医生卡片网格展示(2列) + +## 数据库表结构 + +### zyt_admin 表(医生数据来源) + +```sql +CREATE TABLE `zyt_admin` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(50) NOT NULL COMMENT '管理员名称', + `account` varchar(50) NOT NULL COMMENT '管理员账号', + `avatar` varchar(255) DEFAULT NULL COMMENT '头像', + `mobile` varchar(20) DEFAULT NULL COMMENT '手机号', + `email` varchar(100) DEFAULT NULL COMMENT '邮箱', + `role_id` int(11) DEFAULT NULL COMMENT '角色ID(1=医生)', + `disable` tinyint(1) DEFAULT '0' COMMENT '是否禁用(0=否,1=是)', + `create_time` int(10) unsigned DEFAULT NULL COMMENT '创建时间', + `update_time` int(10) unsigned DEFAULT NULL COMMENT '更新时间', + `delete_time` int(10) unsigned DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`), + KEY `idx_role_id` (`role_id`), + KEY `idx_disable` (`disable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员表'; +``` + +### la_doctor_roster 表(医生排班) + +```sql +CREATE TABLE `la_doctor_roster` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `doctor_id` int(11) NOT NULL COMMENT '医生ID', + `date` date NOT NULL COMMENT '日期', + `period` varchar(20) NOT NULL COMMENT '时段(morning/afternoon)', + `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态(1-出诊 2-停诊 3-休息 4-请假)', + `quota` int(11) DEFAULT '0' COMMENT '号源数', + `max_patients` int(11) DEFAULT '0' COMMENT '最大接诊数', + `create_time` int(11) NOT NULL COMMENT '创建时间', + `update_time` int(11) NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_doctor_date_period` (`doctor_id`,`date`,`period`), + KEY `idx_date` (`date`), + KEY `idx_doctor` (`doctor_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='医生排班表'; +``` + +## 配置说明 + +### 后端配置 + +1. 确保 `zyt_admin` 表中有医生记录(role_id = 1) +2. 医生的 `disable` 字段应为 0 +3. 医生的 `avatar` 字段应包含完整的URL或相对路径 + +### 前端配置 + +1. 创建 `.env` 文件(参考 `.env.example`): +``` +VUE_APP_API_URL=http://your-api-domain/api +``` + +2. 或在 `utils/api.js` 中直接修改 `API_BASE_URL` + +## 使用流程 + +### 1. 后端准备 + +```bash +# 确保医生数据已添加到 zyt_admin 表 +# 示例SQL: +INSERT INTO zyt_admin (name, account, avatar, mobile, email, role_id, disable, create_time) +VALUES ('张医生', 'doctor1', 'http://example.com/avatar.jpg', '13800138000', 'doctor@example.com', 1, 0, UNIX_TIMESTAMP()); +``` + +### 2. 前端使用 + +首页会自动: +1. 加载医生列表 +2. 展示医生卡片 +3. 支持点击跳转到挂号页面 + +## 测试 + +### 运行测试脚本 + +```bash +php server/test_doctor_api.php +``` + +### 手动测试 + +1. 获取医生列表: +``` +GET http://localhost:8000/api/doctor/lists?page_no=1&page_size=10 +``` + +2. 获取医生详情: +``` +GET http://localhost:8000/api/doctor/detail?id=1 +``` + +3. 获取医生排班: +``` +GET http://localhost:8000/api/doctor/roster?doctor_id=1&date=2024-03-11 +``` + +## 扩展功能 + +### 1. 添加医生专科和职位 + +修改 `DoctorLogic.php`: +```php +// 从科室表获取专科 +$doctor['specialty'] = Dept::find($doctor['dept_id'])->name ?? '医生'; + +// 从职位表获取职位 +$doctor['title'] = Jobs::find($doctor['jobs_id'])->name ?? '医生'; +``` + +### 2. 添加医生评分 + +```php +// 从评价表计算平均评分 +$doctor['rating'] = DoctorRating::where('doctor_id', $doctor['id']) + ->avg('rating') ?? '4.8'; +``` + +### 3. 添加医生简介 + +```php +// 从医生表获取简介 +$doctor['introduction'] = DoctorInfo::where('doctor_id', $doctor['id']) + ->value('introduction') ?? ''; +``` + +### 4. 添加在线状态 + +```php +// 检查医生是否在线 +$doctor['is_online'] = DoctorSession::where('doctor_id', $doctor['id']) + ->where('expire_time', '>', time()) + ->exists(); +``` + +## 常见问题 + +### Q: 医生列表为空? +A: +1. 检查 `zyt_admin` 表中是否有 `role_id = 1` 的记录 +2. 检查医生的 `disable` 字段是否为 0 +3. 检查API是否正确返回数据 + +### Q: 头像无法显示? +A: +1. 确保 `avatar` 字段包含完整的URL +2. 检查图片服务器是否可访问 +3. 检查CORS配置 + +### Q: 如何修改医生信息? +A: +1. 在后台管理系统中编辑医生信息 +2. 或直接修改 `zyt_admin` 表 + +### Q: 如何添加新医生? +A: +1. 在后台管理系统中创建新管理员 +2. 设置 `role_id = 1`(医生角色) +3. 设置 `disable = 0`(启用) + +## 相关文件清单 + +### 后端文件 +- `server/app/api/logic/DoctorLogic.php` - 医生逻辑层 +- `server/app/api/controller/DoctorController.php` - 医生控制器 +- `server/test_doctor_api.php` - API测试脚本 + +### 前端文件 +- `TUICallKit-Vue3/utils/api.js` - API服务层 +- `TUICallKit-Vue3/pages/index/index.vue` - 首页组件 +- `TUICallKit-Vue3/.env.example` - 环境配置示例 + +### 文档文件 +- `DOCTOR_API_GUIDE.md` - API接口文档 +- `DOCTOR_FEATURE_IMPLEMENTATION.md` - 本文件 + +## 下一步 + +1. 根据实际需求扩展医生信息字段 +2. 添加医生搜索和筛选功能 +3. 实现医生评价和评分系统 +4. 添加医生在线状态显示 +5. 实现医生排班查询功能 diff --git a/DOCTOR_ROLE_INTEGRATION_COMPLETE.md b/DOCTOR_ROLE_INTEGRATION_COMPLETE.md new file mode 100644 index 00000000..bff5538a --- /dev/null +++ b/DOCTOR_ROLE_INTEGRATION_COMPLETE.md @@ -0,0 +1,275 @@ +# 医生角色集成完成总结 + +## 问题描述 + +医生和角色的关系是通过中间表 `zyt_admin_role` 来管理的,而不是直接在 `zyt_admin` 表中存储 `role_id` 字段。 + +## 解决方案 + +### 1. 更新后端逻辑 (DoctorLogic.php) + +**关键改动**: +- 导入 `AdminRole` 模型 +- 通过中间表查询医生:`AdminRole::where('role_id', 1)->column('admin_id')` +- 使用 `whereIn()` 查询具有医生角色的管理员 + +**核心代码**: +```php +use app\common\model\auth\AdminRole; + +// 获取所有医生的 admin_id +$adminIds = AdminRole::where('role_id', 1)->column('admin_id'); + +// 查询医生信息 +$doctors = Admin::whereIn('id', $adminIds) + ->where('disable', 0) + ->select(); +``` + +### 2. 数据库关系 + +``` +zyt_admin (管理员表) + ↓ (通过 admin_id) +zyt_admin_role (中间表) + ↓ (role_id = 1) +医生角色 +``` + +### 3. 查询流程 + +``` +API 请求: GET /api/doctor/lists + ↓ +DoctorLogic::getDoctorList() + ↓ +从 zyt_admin_role 查询 role_id = 1 的所有 admin_id + ↓ +从 zyt_admin 查询这些 admin_id 的管理员信息 + ↓ +过滤 disable = 0 的管理员 + ↓ +返回医生列表 +``` + +## 文件更新 + +### 后端文件 + +1. **server/app/api/logic/DoctorLogic.php** ✅ + - 更新 `getDoctorList()` - 通过中间表查询医生列表 + - 更新 `getDoctorDetail()` - 检查医生角色 + - 更新 `getDoctorRoster()` - 检查医生角色 + +2. **server/app/api/controller/DoctorController.php** ✅ + - 无需修改(已正确实现) + +### 文档文件 + +1. **server/DOCTOR_ROLE_RELATIONSHIP.md** ✅ + - 详细说明医生角色关系 + - 数据库表结构 + - 查询方式 + - 常见问题 + +2. **server/sql/add_test_doctors.sql** ✅ + - 添加测试医生数据 + - 分配医生角色 + - 添加排班数据 + +## 使用示例 + +### 1. 添加测试医生 + +执行 SQL 脚本: +```bash +mysql -u root -p database_name < server/sql/add_test_doctors.sql +``` + +### 2. 查询医生列表 + +```bash +curl "http://localhost:8000/api/doctor/lists?page_no=1&page_size=10" +``` + +**响应**: +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [ + { + "id": 2, + "name": "张医生", + "account": "doctor1", + "avatar": "/uploads/avatar/doctor1.jpg", + "mobile": "13800138000", + "email": "doctor1@example.com", + "specialty": "医生", + "title": "医生", + "rating": "4.8" + } + ], + "count": 4, + "page_no": 1, + "page_size": 10 + } +} +``` + +### 3. 查询医生详情 + +```bash +curl "http://localhost:8000/api/doctor/detail?id=2" +``` + +### 4. 查询医生排班 + +```bash +curl "http://localhost:8000/api/doctor/roster?doctor_id=2&date=2024-03-11" +``` + +## 关键代码片段 + +### 获取医生列表 + +```php +// 通过中间表查询医生 +$adminIds = AdminRole::where('role_id', 1)->column('admin_id'); + +if (empty($adminIds)) { + return ['lists' => [], 'count' => 0]; +} + +$doctors = Admin::whereIn('id', $adminIds) + ->where('disable', 0) + ->select(); +``` + +### 检查医生角色 + +```php +// 检查管理员是否有医生角色 +$hasRole = AdminRole::where('admin_id', $doctorId) + ->where('role_id', 1) + ->exists(); + +if (!$hasRole) { + return null; // 不是医生 +} +``` + +## 前端集成 + +小程序前端无需修改,已正确集成: + +1. **TUICallKit-Vue3/utils/api.js** ✅ + - 使用全局 `$url` 和 `apiUrl` + - 医生 API 端点正确 + +2. **TUICallKit-Vue3/pages/index/index.vue** ✅ + - 自动加载医生列表 + - 展示医生卡片 + +## 测试步骤 + +### 1. 后端测试 + +```bash +# 运行测试脚本 +php server/test_doctor_api.php +``` + +### 2. 前端测试 + +1. 打开小程序首页 +2. 查看医生列表是否正确加载 +3. 点击医生卡片,检查跳转是否正常 + +### 3. 数据库验证 + +```sql +-- 查询所有医生 +SELECT a.id, a.name, a.account, ar.role_id +FROM zyt_admin a +INNER JOIN zyt_admin_role ar ON a.id = ar.admin_id +WHERE ar.role_id = 1 AND a.disable = 0; + +-- 查询医生排班 +SELECT * FROM la_doctor_roster WHERE doctor_id IN (2, 3, 4, 5); +``` + +## 常见问题 + +### Q: 医生列表为空? + +A: 检查以下几点: +1. 是否有管理员被分配了医生角色(role_id = 1) + ```sql + SELECT * FROM zyt_admin_role WHERE role_id = 1; + ``` + +2. 医生的 `disable` 字段是否为 0 + ```sql + SELECT * FROM zyt_admin WHERE id IN (SELECT admin_id FROM zyt_admin_role WHERE role_id = 1); + ``` + +3. 医生是否被软删除 + ```sql + SELECT * FROM zyt_admin WHERE delete_time IS NOT NULL; + ``` + +### Q: 如何添加新医生? + +A: +1. 在后台管理系统中创建新管理员 +2. 为该管理员分配医生角色(role_id = 1) +3. 系统会自动在 `zyt_admin_role` 表中插入记录 + +### Q: 如何移除医生角色? + +A: +```php +AdminRole::where('admin_id', $adminId) + ->where('role_id', 1) + ->delete(); +``` + +### Q: 如何查询某个管理员的所有角色? + +A: +```php +$admin = Admin::find($adminId); +$roleIds = $admin->role_id; // 返回数组 +``` + +## 相关文件清单 + +### 后端文件 +- `server/app/api/logic/DoctorLogic.php` - 医生逻辑层(已更新) +- `server/app/api/controller/DoctorController.php` - 医生控制器 +- `server/app/common/model/auth/Admin.php` - 管理员模型 +- `server/app/common/model/auth/AdminRole.php` - 角色中间表模型 + +### 文档文件 +- `server/DOCTOR_ROLE_RELATIONSHIP.md` - 医生角色关系说明 +- `server/sql/add_test_doctors.sql` - 测试数据 SQL +- `server/test_doctor_api.php` - API 测试脚本 + +### 前端文件 +- `TUICallKit-Vue3/utils/api.js` - API 服务 +- `TUICallKit-Vue3/pages/index/index.vue` - 首页组件 +- `TUICallKit-Vue3/utils/global.js` - 全局工具 + +## 总结 + +✅ 已完成医生角色集成: + +1. ✅ 后端逻辑更新 - 通过中间表查询医生 +2. ✅ 数据库关系正确 - 使用 `zyt_admin_role` 中间表 +3. ✅ API 端点正确 - 医生列表、详情、排班 +4. ✅ 前端集成完成 - 小程序首页展示医生 +5. ✅ 文档完整 - 详细说明和测试数据 + +医生现在可以通过中间表正确查询和展示。 diff --git a/MINI_PROGRAM_API_INTEGRATION.md b/MINI_PROGRAM_API_INTEGRATION.md new file mode 100644 index 00000000..494dad70 --- /dev/null +++ b/MINI_PROGRAM_API_INTEGRATION.md @@ -0,0 +1,310 @@ +# 小程序 API 集成总结 + +## 概述 + +已完成小程序与后端 API 的集成,使用 `main.js` 中定义的全局 `apiUrl` 方法进行统一的 API 请求管理。 + +## 核心文件 + +### 1. 全局配置 (`main.js`) + +**位置**: `TUICallKit-Vue3/main.js` + +**功能**: +- 定义全局 `baseUrl`:`http://api.zzzhengyangtang.cn` +- 定义全局 `apiUrl` 方法用于发送 HTTP 请求 +- 自动处理 token 和请求头 +- 自动处理登录失效(code === -1) + +**特点**: +- 支持 Vue2 和 Vue3 +- 自动显示/隐藏加载中 +- 支持自定义请求头 +- 15秒超时设置 + +### 2. API 服务层 (`utils/api.js`) + +**位置**: `TUICallKit-Vue3/utils/api.js` + +**功能**: +- 封装 `request()` 方法 +- 提供 `get()` 和 `post()` 便捷方法 +- 定义医生相关 API (`doctorApi`) +- 降级方案:当全局 `apiUrl` 不可用时,直接使用 `uni.request` + +**医生 API**: +```javascript +doctorApi.getDoctorList(params) // 获取医生列表 +doctorApi.getDoctorDetail(id) // 获取医生详情 +doctorApi.getDoctorRoster(id, date) // 获取医生排班 +``` + +### 3. 首页组件 (`pages/index/index.vue`) + +**位置**: `TUICallKit-Vue3/pages/index/index.vue` + +**功能**: +- 展示古典卷轴风格幻灯片 +- 动态加载医生列表 +- 医生卡片点击跳转到挂号页面 + +**流程**: +1. 页面加载时调用 `onMounted()` +2. `onMounted()` 调用 `fetchDoctors()` +3. `fetchDoctors()` 调用 `doctorApi.getDoctorList()` +4. 获取成功后更新 `doctors` 数据 +5. 医生卡片自动渲染 + +## 后端 API 端点 + +### 医生列表 + +**请求**: +``` +GET /api/doctor/lists?page_no=1&page_size=10 +``` + +**响应**: +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [ + { + "id": 1, + "name": "张医生", + "account": "doctor1", + "avatar": "http://example.com/avatar.jpg", + "mobile": "13800138000", + "email": "doctor@example.com", + "specialty": "医生", + "title": "医生", + "rating": "4.8" + } + ], + "count": 10, + "page_no": 1, + "page_size": 10 + } +} +``` + +### 医生详情 + +**请求**: +``` +GET /api/doctor/detail?id=1 +``` + +### 医生排班 + +**请求**: +``` +GET /api/doctor/roster?doctor_id=1&date=2024-03-11 +``` + +## 使用示例 + +### 在组件中使用 + +```vue + +``` + +## 请求流程 + +``` +组件调用 doctorApi.getDoctorList() + ↓ +调用 get('/api/doctor/lists', params, false) + ↓ +调用 request('/api/doctor/lists', 'GET', params, false) + ↓ +获取全局 apiUrl 方法 + ↓ +调用 apiUrl({ url, method, data, header }, loading) + ↓ +main.js 中的 apiUrl 方法处理请求 + ↓ +uni.request 发送 HTTP 请求 + ↓ +返回响应数据 +``` + +## 错误处理 + +### 自动处理 + +1. **登录失效** (code === -1) + - 自动清除 token + - 可选:跳转到登录页 + +2. **网络错误** + - 自动显示/隐藏加载中 + - 返回错误信息 + +### 手动处理 + +```javascript +try { + const response = await doctorApi.getDoctorList({ page_no: 1 }) + + if (response.code === 1) { + // 成功 + console.log(response.data) + } else if (response.code === -1) { + // 登录失效 + uni.redirectTo({ url: '/pages/login/login' }) + } else { + // 其他错误 + uni.showToast({ + title: response.msg || '请求失败', + icon: 'none' + }) + } +} catch (error) { + // 网络错误 + console.error('网络错误:', error) +} +``` + +## 配置修改 + +### 修改 API 基础 URL + +编辑 `TUICallKit-Vue3/main.js`: + +```javascript +var baseUrl = 'http://your-api-domain/api' +``` + +### 修改超时时间 + +编辑 `TUICallKit-Vue3/main.js` 中的 `uni.request`: + +```javascript +timeout: 20000 // 改为 20 秒 +``` + +### 修改请求头 + +编辑 `TUICallKit-Vue3/main.js` 中的 `header` 对象: + +```javascript +const header = { + token: token, + 'content-type': 'application/x-www-form-urlencoded', + 'X-Custom-Header': 'custom-value' +} +``` + +## 扩展功能 + +### 添加新的 API 模块 + +在 `TUICallKit-Vue3/utils/api.js` 中添加: + +```javascript +export const appointmentApi = { + getList: (params) => get('/api/appointment/lists', params, false), + create: (data) => post('/api/appointment/create', data, true), + cancel: (id) => post('/api/appointment/cancel', { id }, true) +} +``` + +### 添加文件上传 + +```javascript +export const uploadFile = (filePath, url) => { + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: baseUrl + url, + filePath: filePath, + name: 'file', + header: { + token: uni.getStorageSync('token') + }, + success: (res) => { + resolve(JSON.parse(res.data)) + }, + fail: (err) => { + reject(err) + } + }) + }) +} +``` + +## 常见问题 + +### Q: 如何修改 API 地址? + +A: 编辑 `TUICallKit-Vue3/main.js` 中的 `baseUrl` 变量。 + +### Q: 如何添加自定义请求头? + +A: 在 `TUICallKit-Vue3/main.js` 中的 `header` 对象中添加。 + +### Q: 如何处理登录失效? + +A: 当 `code === -1` 时,自动清除 token,可选择跳转到登录页。 + +### Q: 如何取消请求? + +A: 小程序不支持直接取消请求,可使用标志位实现。 + +### Q: 如何处理文件上传? + +A: 使用 `uni.uploadFile` 而不是 `uni.request`。 + +## 相关文件 + +- 全局配置: `TUICallKit-Vue3/main.js` +- API 服务: `TUICallKit-Vue3/utils/api.js` +- 首页组件: `TUICallKit-Vue3/pages/index/index.vue` +- API 配置: `TUICallKit-Vue3/API_CONFIG.md` +- API 使用指南: `TUICallKit-Vue3/API_USAGE_GUIDE.md` +- 后端控制器: `server/app/api/controller/DoctorController.php` +- 后端逻辑: `server/app/api/logic/DoctorLogic.php` + +## 总结 + +已完成小程序与后端 API 的完整集成: + +1. ✅ 后端 API 开发(医生列表、详情、排班) +2. ✅ 前端 API 服务层封装 +3. ✅ 首页医生列表展示 +4. ✅ 错误处理和加载状态 +5. ✅ 文档和使用指南 + +小程序现在可以正常加载和展示医生列表。 diff --git a/TUICallKit-Vue3/.env.example b/TUICallKit-Vue3/.env.example new file mode 100644 index 00000000..74fb2231 --- /dev/null +++ b/TUICallKit-Vue3/.env.example @@ -0,0 +1,8 @@ +# API 配置 +VUE_APP_API_URL=http://localhost:8000/api + +# 应用名称 +VUE_APP_NAME=医疗小程序 + +# 应用版本 +VUE_APP_VERSION=1.0.0 diff --git a/TUICallKit-Vue3/API_CONFIG.md b/TUICallKit-Vue3/API_CONFIG.md new file mode 100644 index 00000000..b8a4e4ef --- /dev/null +++ b/TUICallKit-Vue3/API_CONFIG.md @@ -0,0 +1,178 @@ +# 小程序API配置说明 + +## 问题解决 + +已修复 `process is not defined` 错误。小程序环境不支持 Node.js 的 `process` 对象。 + +## API 基础URL 配置 + +### 当前配置 + +API 基础 URL 在 `utils/api.js` 中定义: + +```javascript +const API_BASE_URL = 'http://api.zzzhengyangtang.cn' +``` + +### 修改 API 地址 + +根据你的实际后端地址修改 `TUICallKit-Vue3/utils/api.js` 中的 `API_BASE_URL`: + +```javascript +// 开发环境 +const API_BASE_URL = 'http://localhost:8000/api' + +// 生产环境 +const API_BASE_URL = 'https://your-production-api.com/api' +``` + +## 医生API端点 + +### 1. 获取医生列表 + +```javascript +import { doctorApi } from '../utils/api' + +const response = await doctorApi.getDoctorList({ + page_no: 1, + page_size: 10, + keyword: '医生' // 可选 +}) +``` + +**响应格式**: +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [ + { + "id": 1, + "name": "张医生", + "account": "doctor1", + "avatar": "http://example.com/avatar.jpg", + "mobile": "13800138000", + "email": "doctor@example.com", + "specialty": "医生", + "title": "医生", + "rating": "4.8" + } + ], + "count": 10, + "page_no": 1, + "page_size": 10 + } +} +``` + +### 2. 获取医生详情 + +```javascript +const doctor = await doctorApi.getDoctorDetail(1) +``` + +### 3. 获取医生排班 + +```javascript +const roster = await doctorApi.getDoctorRoster(1, '2024-03-11') +``` + +## 错误处理 + +API 请求会自动处理以下情况: + +1. **网络错误**: 显示 "网络错误" 提示 +2. **请求失败**: 显示 "获取医生列表失败" 提示 +3. **登录失效**: 自动清除 token + +## 首页集成 + +首页 (`pages/index/index.vue`) 会在加载时自动调用 `fetchDoctors()` 方法获取医生列表。 + +### 首页流程 + +1. 页面加载时调用 `onMounted()` +2. `onMounted()` 调用 `fetchDoctors()` +3. `fetchDoctors()` 调用 `doctorApi.getDoctorList()` +4. 获取成功后更新 `doctors` 数据 +5. 医生卡片自动渲染 + +### 点击医生卡片 + +点击医生卡片会跳转到挂号页面: + +```javascript +uni.navigateTo({ + url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}` +}) +``` + +## 调试技巧 + +### 1. 查看网络请求 + +在小程序开发者工具中: +1. 打开 "Network" 标签 +2. 查看 API 请求的 URL、参数和响应 + +### 2. 查看控制台日志 + +```javascript +console.error('请求失败:', error) +``` + +### 3. 测试 API + +使用 Postman 或 curl 测试 API: + +```bash +# 获取医生列表 +curl "http://localhost:8000/api/doctor/lists?page_no=1&page_size=10" + +# 获取医生详情 +curl "http://localhost:8000/api/doctor/detail?id=1" + +# 获取医生排班 +curl "http://localhost:8000/api/doctor/roster?doctor_id=1&date=2024-03-11" +``` + +## 常见问题 + +### Q: 医生列表为空? + +A: 检查以下几点: +1. API 地址是否正确 +2. 后端是否有医生数据(role_id = 1) +3. 医生的 disable 字段是否为 0 +4. 网络连接是否正常 + +### Q: 头像无法显示? + +A: +1. 检查 avatar URL 是否完整 +2. 检查图片服务器是否可访问 +3. 检查小程序是否有网络权限 + +### Q: 如何修改 API 地址? + +A: 修改 `TUICallKit-Vue3/utils/api.js` 中的 `API_BASE_URL` 常量。 + +### Q: 如何添加请求头? + +A: 修改 `request()` 函数中的 `header` 对象: + +```javascript +header: { + 'Content-Type': 'application/json', + 'Authorization': token, + 'Custom-Header': 'value' // 添加自定义请求头 +} +``` + +## 相关文件 + +- API 服务: `TUICallKit-Vue3/utils/api.js` +- 首页组件: `TUICallKit-Vue3/pages/index/index.vue` +- 后端控制器: `server/app/api/controller/DoctorController.php` +- 后端逻辑: `server/app/api/logic/DoctorLogic.php` diff --git a/TUICallKit-Vue3/API_INTEGRATION_SUMMARY.md b/TUICallKit-Vue3/API_INTEGRATION_SUMMARY.md new file mode 100644 index 00000000..e69de29b diff --git a/TUICallKit-Vue3/API_USAGE_GUIDE.md b/TUICallKit-Vue3/API_USAGE_GUIDE.md new file mode 100644 index 00000000..78de3606 --- /dev/null +++ b/TUICallKit-Vue3/API_USAGE_GUIDE.md @@ -0,0 +1,361 @@ +# 小程序 API 使用指南 + +## 概述 + +小程序使用统一的 API 请求方式,通过 `main.js` 中定义的全局 `apiUrl` 方法进行请求。 + +## 全局 apiUrl 方法 + +### 定义位置 + +`TUICallKit-Vue3/main.js` 中定义了全局的 `apiUrl` 方法: + +```javascript +function apiUrl(promise, Loading = true) { + const token = uni.getStorageSync('token') + const header = { + token: token, + 'content-type': 'application/x-www-form-urlencoded', + ...(promise.header || {}) + } + const data = promise.data || {} + const url = baseUrl + (promise.url || '') + + return new Promise((resolve, reject) => { + if (Loading) { + uni.showLoading({ title: '加载中...', mask: true }) + } + + uni.request({ + url: url, + data: data, + timeout: 15000, + method: promise.method || 'POST', + header: header, + sslVerify: false, + success: (res) => { + const data = res.data + if (data.code === -1) { + uni.removeStorageSync('token') + } + resolve(data) + }, + fail: (e) => { + reject(e) + }, + complete: (e) => { + if (Loading) { + uni.hideLoading() + } + } + }) + }) +} +``` + +### 参数说明 + +| 参数 | 类型 | 说明 | +|------|------|------| +| promise.url | string | 请求URL(相对路径) | +| promise.method | string | 请求方法(GET/POST,默认POST) | +| promise.data | object | 请求数据 | +| promise.header | object | 自定义请求头 | +| Loading | boolean | 是否显示加载中(默认true) | + +## API 服务层 + +### 文件位置 + +`TUICallKit-Vue3/utils/api.js` + +### 基础方法 + +```javascript +// GET 请求 +export const get = (url, data = {}, loading = false) => { + return request(url, 'GET', data, loading) +} + +// POST 请求 +export const post = (url, data = {}, loading = true) => { + return request(url, 'POST', data, loading) +} +``` + +### 医生 API + +```javascript +export const doctorApi = { + // 获取医生列表 + getDoctorList: (params) => get('/api/doctor/lists', params, false), + + // 获取医生详情 + getDoctorDetail: (id) => get('/api/doctor/detail', { id }, false), + + // 获取医生排班 + getDoctorRoster: (doctorId, date) => get('/api/doctor/roster', { doctor_id: doctorId, date }, false) +} +``` + +## 使用示例 + +### 1. 在组件中使用 + +```vue + +``` + +### 2. 创建新的 API 模块 + +```javascript +// utils/api.js 中添加 + +export const appointmentApi = { + // 获取预约列表 + getAppointmentList: (params) => get('/api/appointment/lists', params, false), + + // 创建预约 + createAppointment: (data) => post('/api/appointment/create', data, true), + + // 取消预约 + cancelAppointment: (id) => post('/api/appointment/cancel', { id }, true) +} +``` + +### 3. 使用自定义请求头 + +```javascript +import { request } from '../utils/api' + +// 发送带自定义请求头的请求 +const response = await request( + '/api/custom/endpoint', + 'POST', + { data: 'value' }, + true, + { 'X-Custom-Header': 'custom-value' } +) +``` + +## 响应格式 + +### 成功响应 + +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [...], + "count": 10, + "page_no": 1, + "page_size": 10 + } +} +``` + +### 失败响应 + +```json +{ + "code": 0, + "msg": "错误信息" +} +``` + +### 登录失效 + +```json +{ + "code": -1, + "msg": "登录已失效" +} +``` + +当 `code === -1` 时,会自动清除 token。 + +## 错误处理 + +### 自动处理 + +- 登录失效(code === -1):自动清除 token +- 网络错误:自动显示加载中/隐藏加载中 + +### 手动处理 + +```javascript +try { + const response = await doctorApi.getDoctorList({ page_no: 1 }) + + if (response.code === 1) { + // 成功处理 + console.log(response.data) + } else if (response.code === -1) { + // 登录失效,跳转到登录页 + uni.redirectTo({ url: '/pages/login/login' }) + } else { + // 其他错误 + uni.showToast({ + title: response.msg || '请求失败', + icon: 'none' + }) + } +} catch (error) { + // 网络错误 + console.error('网络错误:', error) + uni.showToast({ + title: '网络错误,请检查连接', + icon: 'none' + }) +} +``` + +## 配置说明 + +### 基础 URL + +在 `main.js` 中定义: + +```javascript +var baseUrl = 'http://api.zzzhengyangtang.cn' +``` + +修改此值来改变 API 基础地址。 + +### 超时时间 + +在 `main.js` 中的 `uni.request` 中定义: + +```javascript +timeout: 15000 // 15秒超时 +``` + +### 请求头 + +默认请求头: + +```javascript +{ + token: 'user_token', + 'content-type': 'application/x-www-form-urlencoded' +} +``` + +## 常见问题 + +### Q: 如何添加新的 API? + +A: 在 `utils/api.js` 中添加新的 API 对象: + +```javascript +export const newApi = { + getList: (params) => get('/api/new/lists', params, false), + create: (data) => post('/api/new/create', data, true) +} +``` + +### Q: 如何修改请求头? + +A: 在 `request` 函数中修改 `header` 对象,或在调用时传入自定义请求头。 + +### Q: 如何处理文件上传? + +A: 使用 `uni.uploadFile` 而不是 `uni.request`: + +```javascript +export const uploadFile = (filePath, url) => { + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: baseUrl + url, + filePath: filePath, + name: 'file', + header: { + token: uni.getStorageSync('token') + }, + success: (res) => { + resolve(JSON.parse(res.data)) + }, + fail: (err) => { + reject(err) + } + }) + }) +} +``` + +### Q: 如何取消请求? + +A: 小程序的 `uni.request` 不支持直接取消,但可以使用标志位: + +```javascript +let requestAborted = false + +const fetchData = async () => { + const response = await doctorApi.getDoctorList({ page_no: 1 }) + + if (requestAborted) { + return + } + + // 处理响应 +} + +// 取消请求 +const abortRequest = () => { + requestAborted = true +} +``` + +## 最佳实践 + +1. **统一 API 管理**:所有 API 调用都通过 `utils/api.js` 进行 +2. **错误处理**:始终使用 try-catch 处理异步请求 +3. **加载状态**:在请求时显示加载中,完成后隐藏 +4. **响应验证**:检查 `code` 字段判断请求是否成功 +5. **token 管理**:自动处理 token 过期情况 + +## 相关文件 + +- API 服务: `TUICallKit-Vue3/utils/api.js` +- 全局配置: `TUICallKit-Vue3/main.js` +- 首页示例: `TUICallKit-Vue3/pages/index/index.vue` +- API 配置: `TUICallKit-Vue3/API_CONFIG.md` diff --git a/TUICallKit-Vue3/ELDERLY_FRIENDLY_DESIGN.md b/TUICallKit-Vue3/ELDERLY_FRIENDLY_DESIGN.md new file mode 100644 index 00000000..05df4d73 --- /dev/null +++ b/TUICallKit-Vue3/ELDERLY_FRIENDLY_DESIGN.md @@ -0,0 +1,302 @@ +# 老年人友好的首页设计指南 + +## 设计理念 + +针对60岁左右的用户群体,设计简洁、清晰、易操作的界面。 + +### 核心原则 +1. **字体大** - 所有文字都要足够大,便于阅读 +2. **操作简单** - 减少复杂操作,一键直达 +3. **色彩清晰** - 高对比度,清晰易辨 +4. **布局简洁** - 信息不过载,重点突出 +5. **反馈明确** - 每个操作都有清晰的反馈 + +## 页面结构 + +``` +┌─────────────────────────────────┐ +│ 养生堂 ⋯ ◯ │ <- 顶部标题栏 +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ │ +│ [轮播图] │ +│ │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ [头像] 赵建欣 │ +│ 咨询 8次 │ +│ │ +│ 主任医师 中医内科 │ +│ │ +│ ⭐ 名医中医 │ +│ │ +│ 👍 好评率 95% ❤️ 服务人数 256人│ +│ │ +│ 🌐 互联网医院执业许可 │ +│ 📋 医师执业许可证 │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ [头像] 李医生 │ +│ ... │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 🏠 首页 👤 我的 │ <- 底部导航 +└─────────────────────────────────┘ +``` + +## 字体规范 + +### 字体大小 +- **顶部标题**: 36rpx (大标题,易识别) +- **医生名字**: 32rpx (重要信息) +- **职位/科室**: 24rpx (次要信息) +- **其他文字**: 22-24rpx (保证可读性) +- **底部导航**: 24rpx (便于点击) + +### 字体权重 +- **标题**: 加粗 (700) +- **重要信息**: 加粗 (600) +- **正常文字**: 正常 (400) + +## 色彩方案 + +### 主色系 +- **绿色**: #4CAF50 - 健康、生命力 +- **浅绿**: #E8F5E9 - 背景色 +- **黄色**: #FFF9C4 - 强调色 +- **灰色**: #f5f5f5 - 页面背景 + +### 文字色 +- **主文字**: #333 - 深灰色,高对比度 +- **次文字**: #666 - 中灰色 +- **辅助**: #999 - 浅灰色 + +## 组件设计 + +### 1. 顶部标题栏 +```scss +.header { + padding: 24rpx 30rpx; + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-title { + font-size: 36rpx; + font-weight: bold; +} + +.icon-btn { + width: 50rpx; + height: 50rpx; + font-size: 32rpx; + border-radius: 50%; +} +``` +- 标题: 36rpx,加粗 +- 按钮: 50x50rpx,便于点击 +- 高对比度 + +### 2. 轮播图 +```scss +.banner { + height: 300rpx; +} +``` +- 高度: 300rpx +- 自动轮播,5秒切换 +- 圆角: 12rpx +- 阴影: 0 2rpx 8rpx + +### 3. 医生卡片 +```scss +.doctor-card { + background: #fff; + border-radius: 12rpx; + padding: 24rpx; + margin-bottom: 20rpx; +} +``` +- 白色背景,清晰易读 +- 内边距: 24rpx (充足的空间) +- 圆角: 12rpx +- 阴影: 0 2rpx 8rpx + +### 4. 医生头部 +``` +[头像] 医生名字 (32rpx) + 咨询 8次 (24rpx, 绿色) +``` +- 头像: 100x100rpx +- 名字: 32rpx,加粗 +- 描述: 24rpx,绿色 + +### 5. 医生标签 +``` +主任医师 中医内科 +``` +- 绿色背景,绿色文字 +- 字体: 24rpx +- 圆角: 20rpx +- 高对比度 + +### 6. 专家标签 +``` +⭐ 名医中医 +``` +- 黄色背景 +- 字体: 22rpx +- 圆角: 16rpx + +### 7. 评分和服务 +``` +┌──────────────┬──────────────┐ +│ 👍 好评率 │ ❤️ 服务人数 │ +│ 95% │ 256人 │ +└──────────────┴──────────────┘ +``` +- 两列布局 +- 绿色背景 +- 字体: 28rpx (数值),22rpx (标签) +- 图标: 32rpx + +### 8. 资质信息 +``` +🌐 互联网医院执业许可 +📋 医师执业许可证 +``` +- 列表展示 +- 字体: 22rpx +- 图标: 24rpx + +### 9. 底部导航 +``` +🏠 首页 👤 我的 +``` +- 固定底部 +- 图标: 36-40rpx +- 文字: 24rpx +- 高对比度 + +## 交互设计 + +### 点击区域 +- **最小点击区域**: 44x44rpx +- **医生卡片**: 整个卡片可点击 +- **底部导航**: 每个导航项 >= 60rpx + +### 反馈效果 +- **卡片按下**: 阴影增强 +- **按钮按下**: 背景变深 +- **导航切换**: 颜色和大小变化 + +### 动画 +- **过渡时间**: 300ms +- **轮播**: 5秒自动切换 +- **缓动函数**: ease + +## 易用性设计 + +### 1. 大字体 +- 所有文字 >= 22rpx +- 标题 >= 32rpx +- 便于老年人阅读 + +### 2. 高对比度 +- 文字和背景对比度 >= 4.5:1 +- 清晰易辨 + +### 3. 简单操作 +- 一键咨询 +- 直接进入医生详情 +- 无复杂交互 + +### 4. 清晰反馈 +- 每个操作都有视觉反馈 +- 按下时有阴影变化 +- 导航切换有颜色变化 + +### 5. 充足空间 +- 卡片内边距: 24rpx +- 元素间距: 16-20rpx +- 不拥挤 + +## 响应式设计 + +### 使用 rpx 单位 +- 自动适配不同屏幕 +- 1rpx = 0.5px (375px 宽度) + +### 布局适配 +- 医生卡片宽度 100% +- 自动适应屏幕宽度 +- 文字自动换行 + +## 性能优化 + +- 使用 CSS 动画 +- 图片自动缩放 +- 减少重排和重绘 + +## 无障碍设计 + +- 足够的色彩对比度 +- 清晰的文字标签 +- 合理的点击区域 +- 支持屏幕阅读器 + +## 数据流 + +``` +页面加载 + ↓ +调用 fetchDoctors() + ↓ +获取医生列表 + ↓ +处理数据 + ↓ +渲染医生卡片 +``` + +## API 集成 + +### 获取医生列表 +```javascript +const response = await proxy.apiUrl({ + url: '/api/doctor/lists', + method: 'GET', + data: { + page_no: 1, + page_size: 10 + } +}) +``` + +## 点击事件 + +### 医生卡片点击 +```javascript +selectDoctor(doctor) { + uni.navigateTo({ + url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}` + }) +} +``` + +## 总结 + +这个设计方案特点: +- ✅ 字体大,易于阅读 +- ✅ 操作简单,一键直达 +- ✅ 色彩清晰,高对比度 +- ✅ 布局简洁,信息清晰 +- ✅ 反馈明确,易于理解 +- ✅ 完全适合60岁左右的用户 + +整个页面设计充分考虑了老年人的使用习惯和需求,提供了友好、易用的医疗服务体验。 diff --git a/TUICallKit-Vue3/GLOBAL_PROPERTIES_USAGE.md b/TUICallKit-Vue3/GLOBAL_PROPERTIES_USAGE.md new file mode 100644 index 00000000..9a87dd30 --- /dev/null +++ b/TUICallKit-Vue3/GLOBAL_PROPERTIES_USAGE.md @@ -0,0 +1,250 @@ +# 全局属性使用说明 + +## 概述 + +小程序通过 `main.js` 中的 `app.config.globalProperties` 定义全局属性,包括 `$url` 和 `apiUrl` 方法。 + +## 全局属性定义 + +### 在 main.js 中 + +```javascript +// Vue3 部分 +export function createApp() { + const app = createSSRApp(App) + + // 定义全局 baseUrl + app.config.globalProperties.$url = baseUrl + + // 定义全局 apiUrl 方法 + app.config.globalProperties.apiUrl = apiUrl + + return { + app + } +} +``` + +### 全局属性列表 + +| 属性名 | 类型 | 说明 | +|--------|------|------| +| `$url` | string | API 基础 URL,默认值:`http://api.zzzhengyangtang.cn` | +| `apiUrl` | function | API 请求方法 | + +## 在 API 服务中使用 + +### 获取全局属性 + +```javascript +import { getCurrentInstance } from 'vue' + +const getGlobalProperties = () => { + try { + const instance = getCurrentInstance() + if (instance) { + return instance.appContext.config.globalProperties + } + } catch (e) { + console.warn('无法获取 getCurrentInstance') + } + return {} +} + +// 使用 +const globalProps = getGlobalProperties() +const baseUrl = globalProps.$url +const apiUrl = globalProps.apiUrl +``` + +### 在 request 函数中使用 + +```javascript +export const request = (url, method = 'POST', data = {}, loading = true) => { + // 获取全局属性 + const globalProps = getGlobalProperties() + const apiUrl = globalProps.apiUrl + const baseUrl = globalProps.$url || 'http://api.zzzhengyangtang.cn' + + if (!apiUrl) { + // 降级方案:直接使用 uni.request + return new Promise((resolve, reject) => { + uni.request({ + url: `${baseUrl}${url}`, + method, + data, + // ... + }) + }) + } + + // 使用全局 apiUrl 方法 + return apiUrl({ + url, + method, + data, + header: { + 'content-type': 'application/x-www-form-urlencoded' + } + }, loading) +} +``` + +## 在组件中使用 + +### 方式1:通过 getCurrentInstance + +```vue + +``` + +### 方式2:通过 this(Vue2 风格) + +```vue + +``` + +### 方式3:通过 inject(推荐) + +```vue + +``` + +## 修改全局属性 + +### 修改 baseUrl + +编辑 `TUICallKit-Vue3/main.js`: + +```javascript +var baseUrl = 'http://your-api-domain/api' +``` + +### 修改 apiUrl 方法 + +编辑 `TUICallKit-Vue3/main.js` 中的 `apiUrl` 函数。 + +## 全局属性的生命周期 + +1. **初始化**:在 `main.js` 中通过 `app.config.globalProperties` 定义 +2. **可用**:应用创建后,所有组件都可以访问 +3. **销毁**:应用销毁时自动清理 + +## 最佳实践 + +### 1. 统一管理全局属性 + +在 `main.js` 中集中定义所有全局属性: + +```javascript +// 定义全局属性对象 +const globalConfig = { + $url: baseUrl, + apiUrl: apiUrl, + $appName: '医疗小程序', + $version: '1.0.0' +} + +// 批量注册 +Object.keys(globalConfig).forEach(key => { + app.config.globalProperties[key] = globalConfig[key] +}) +``` + +### 2. 创建辅助函数 + +```javascript +// utils/global.js +import { getCurrentInstance } from 'vue' + +export const useGlobal = () => { + const instance = getCurrentInstance() + const globalProps = instance.appContext.config.globalProperties + + return { + baseUrl: globalProps.$url, + apiUrl: globalProps.apiUrl, + appName: globalProps.$appName, + version: globalProps.$version + } +} +``` + +### 3. 在组件中使用 + +```vue + +``` + +## 常见问题 + +### Q: 如何在非组件中使用全局属性? + +A: 在 API 服务中使用 `getCurrentInstance()` 获取全局属性。 + +### Q: 如何动态修改全局属性? + +A: 直接修改 `app.config.globalProperties` 中的值: + +```javascript +const instance = getCurrentInstance() +instance.appContext.config.globalProperties.$url = 'http://new-url' +``` + +### Q: 全局属性和 provide/inject 的区别? + +A: +- 全局属性:所有组件都可以访问,通过 `this.$property` 或 `getCurrentInstance()` 获取 +- provide/inject:父组件提供,子组件注入,更灵活但需要显式提供 + +### Q: 如何在 Composition API 中使用全局属性? + +A: 使用 `getCurrentInstance()` 获取实例,然后访问 `appContext.config.globalProperties`。 + +## 相关文件 + +- 全局配置: `TUICallKit-Vue3/main.js` +- API 服务: `TUICallKit-Vue3/utils/api.js` +- 全局工具: `TUICallKit-Vue3/utils/global.js`(可选) + +## 总结 + +通过 `app.config.globalProperties` 定义的全局属性可以在整个应用中访问,是管理全局配置和方法的最佳方式。 diff --git a/TUICallKit-Vue3/INTEGRATION_SUMMARY.md b/TUICallKit-Vue3/INTEGRATION_SUMMARY.md new file mode 100644 index 00000000..6234ad45 --- /dev/null +++ b/TUICallKit-Vue3/INTEGRATION_SUMMARY.md @@ -0,0 +1,309 @@ +# 小程序 API 集成总结 + +## 核心架构 + +``` +main.js (全局配置) + ├── $url: 'http://api.zzzhengyangtang.cn' + ├── apiUrl: function(promise, loading) + └── app.config.globalProperties + +utils/global.js (全局工具) + ├── getGlobalProperties() + ├── getBaseUrl() + ├── getApiUrl() + ├── useGlobal() + └── getFullUrl() + +utils/api.js (API 服务) + ├── request(url, method, data, loading) + ├── get(url, data, loading) + ├── post(url, data, loading) + └── doctorApi { getDoctorList, getDoctorDetail, getDoctorRoster } + +pages/index/index.vue (首页) + └── fetchDoctors() → doctorApi.getDoctorList() +``` + +## 文件说明 + +### 1. main.js - 全局配置 + +**定义全局属性**: +```javascript +app.config.globalProperties.$url = baseUrl +app.config.globalProperties.apiUrl = apiUrl +``` + +**特点**: +- 定义 API 基础 URL +- 定义 apiUrl 方法(处理 token、加载中、登录失效等) +- 支持 Vue2 和 Vue3 + +### 2. utils/global.js - 全局工具 + +**提供的函数**: +- `getGlobalProperties()` - 获取全局属性对象 +- `getBaseUrl()` - 获取 API 基础 URL +- `getApiUrl()` - 获取 apiUrl 方法 +- `useGlobal()` - Composition API Hook +- `getFullUrl(path)` - 获取完整 URL +- `setGlobalProperty(key, value)` - 设置全局属性 +- `getGlobalProperty(key, defaultValue)` - 获取特定全局属性 + +**使用示例**: +```javascript +import { useGlobal, getBaseUrl } from '@/utils/global' + +const { baseUrl, apiUrl } = useGlobal() +const url = getBaseUrl() +``` + +### 3. utils/api.js - API 服务 + +**提供的方法**: +- `request(url, method, data, loading)` - 基础请求方法 +- `get(url, data, loading)` - GET 请求 +- `post(url, data, loading)` - POST 请求 +- `doctorApi` - 医生相关 API + +**医生 API**: +```javascript +doctorApi.getDoctorList(params) // 获取医生列表 +doctorApi.getDoctorDetail(id) // 获取医生详情 +doctorApi.getDoctorRoster(id, date) // 获取医生排班 +``` + +**特点**: +- 自动使用全局 `$url` 和 `apiUrl` +- 降级方案:当全局方法不可用时,直接使用 `uni.request` +- 自动处理 token 和请求头 + +### 4. pages/index/index.vue - 首页 + +**功能**: +- 展示古典卷轴风格幻灯片 +- 动态加载医生列表 +- 医生卡片点击跳转 + +**流程**: +``` +onMounted() + ↓ +fetchDoctors() + ↓ +doctorApi.getDoctorList() + ↓ +request() → apiUrl() → uni.request() + ↓ +更新 doctors 数据 + ↓ +医生卡片渲染 +``` + +## 使用流程 + +### 1. 在组件中使用 API + +```vue + +``` + +### 2. 使用全局工具 + +```vue + +``` + +### 3. 添加新的 API + +在 `utils/api.js` 中添加: + +```javascript +export const appointmentApi = { + getList: (params) => get('/api/appointment/lists', params, false), + create: (data) => post('/api/appointment/create', data, true), + cancel: (id) => post('/api/appointment/cancel', { id }, true) +} +``` + +## 请求流程详解 + +### 正常流程 + +``` +组件调用 doctorApi.getDoctorList() + ↓ +调用 get('/api/doctor/lists', params, false) + ↓ +调用 request('/api/doctor/lists', 'GET', params, false) + ↓ +获取全局属性 ($url, apiUrl) + ↓ +调用 apiUrl({ url, method, data, header }, loading) + ↓ +main.js 中的 apiUrl 方法处理 + ↓ +获取 token,合并请求头 + ↓ +调用 uni.request() + ↓ +返回响应数据 + ↓ +检查 code 字段 + ├─ code === 1: 成功,返回数据 + ├─ code === -1: 登录失效,清除 token + └─ code === 0: 失败,返回错误信息 +``` + +### 降级流程 + +当全局 `apiUrl` 不可用时: + +``` +request() 检查 apiUrl 是否存在 + ↓ +apiUrl 不存在 + ↓ +使用降级方案:直接调用 uni.request() + ↓ +获取 token,构建完整 URL + ↓ +调用 uni.request() + ↓ +返回响应数据 +``` + +## 配置修改 + +### 修改 API 基础 URL + +编辑 `main.js`: + +```javascript +var baseUrl = 'http://your-api-domain/api' +``` + +### 修改超时时间 + +编辑 `main.js` 中的 `uni.request`: + +```javascript +timeout: 20000 // 改为 20 秒 +``` + +### 修改请求头 + +编辑 `main.js` 中的 `header` 对象: + +```javascript +const header = { + token: token, + 'content-type': 'application/x-www-form-urlencoded', + 'X-Custom-Header': 'custom-value' +} +``` + +## 错误处理 + +### 自动处理 + +1. **登录失效** (code === -1) + - 自动清除 token + - 可选:跳转到登录页 + +2. **网络错误** + - 自动显示/隐藏加载中 + - 返回错误信息 + +### 手动处理 + +```javascript +try { + const response = await doctorApi.getDoctorList({ page_no: 1 }) + + if (response.code === 1) { + // 成功 + console.log(response.data) + } else if (response.code === -1) { + // 登录失效 + uni.redirectTo({ url: '/pages/login/login' }) + } else { + // 其他错误 + uni.showToast({ + title: response.msg || '请求失败', + icon: 'none' + }) + } +} catch (error) { + // 网络错误 + console.error('网络错误:', error) +} +``` + +## 最佳实践 + +1. **统一 API 管理**:所有 API 调用都通过 `utils/api.js` +2. **错误处理**:始终使用 try-catch 处理异步请求 +3. **加载状态**:在请求时显示加载中,完成后隐藏 +4. **响应验证**:检查 `code` 字段判断请求是否成功 +5. **token 管理**:自动处理 token 过期情况 +6. **全局属性**:使用 `utils/global.js` 中的工具函数访问全局属性 + +## 相关文件 + +- 全局配置: `TUICallKit-Vue3/main.js` +- 全局工具: `TUICallKit-Vue3/utils/global.js` +- API 服务: `TUICallKit-Vue3/utils/api.js` +- 首页组件: `TUICallKit-Vue3/pages/index/index.vue` +- 全局属性说明: `TUICallKit-Vue3/GLOBAL_PROPERTIES_USAGE.md` +- API 使用指南: `TUICallKit-Vue3/API_USAGE_GUIDE.md` +- API 配置说明: `TUICallKit-Vue3/API_CONFIG.md` + +## 总结 + +已完成小程序与后端 API 的完整集成: + +1. ✅ 全局配置管理(main.js) +2. ✅ 全局工具函数(utils/global.js) +3. ✅ API 服务层封装(utils/api.js) +4. ✅ 首页医生列表展示(pages/index/index.vue) +5. ✅ 完整的错误处理和加载状态 +6. ✅ 详细的文档和使用指南 + +小程序现在可以正常调用后端 API 获取医生列表,并且所有 API 请求都使用 `main.js` 中定义的全局 `$url` 和 `apiUrl` 方法。 diff --git a/TUICallKit-Vue3/MODERN_TCM_DESIGN.md b/TUICallKit-Vue3/MODERN_TCM_DESIGN.md new file mode 100644 index 00000000..80d17ebc --- /dev/null +++ b/TUICallKit-Vue3/MODERN_TCM_DESIGN.md @@ -0,0 +1,290 @@ +# 现代中医医院首页设计指南 + +## 设计理念 + +采用现代医疗应用的设计风格,结合中医特色,为60岁左右的用户提供专业、易用的医疗服务体验。 + +## 页面结构 + +``` +┌─────────────────────────────────┐ +│ 成都双流蜀养堂互联网医院 ⋯ ◯ │ <- 顶部信息栏 +│ 📍 郑州市金水区 │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 🔍 输入科室、疾病、医生搜索 搜索 │ <- 搜索栏 +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ [轮播图] │ <- 轮播图 +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 问诊服务 │ +├─────────────────────────────────┤ +│ 专家问诊 │ 健康咨询 │ 快速问诊 │ <- 服务卡片 +│ 去找专家 │ 前往咨询 │ 前往问诊 │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 特色专科医师 更多 > │ +├─────────────────────────────────┤ +│ [头像] [头像] [头像] [头像] │ <- 医生横向滚动 +│ 赵建欣 雷惧昱 稳骨 ... │ +│ 主任医师 主治医师 主治医师 │ +│ 内科 内科 内科 │ +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 🏠 首页 📢 消息 👤 我的 │ <- 底部导航 +└─────────────────────────────────┘ +``` + +## 色彩方案 + +### 主色系 +- **棕色**: #8B6F47 - 中医传统色 +- **绿色**: #4CAF50 - 健康、生命力 +- **背景**: #f5f5f5 - 页面背景 +- **卡片**: #fff - 内容卡片 + +### 服务卡片色 +- **专家问诊**: 橙色系 (#FFF3E0 - #FFE0B2) +- **健康咨询**: 绿色系 (#E8F5E9 - #C8E6C9) +- **快速问诊**: 紫色系 (#F3E5F5 - #E1BEE7) + +## 组件设计 + +### 1. 顶部信息栏 +```scss +.top-bar { + background: linear-gradient(135deg, #8B6F47 0%, #A0826D 100%); + padding: 16rpx 20rpx; + display: flex; + justify-content: space-between; +} +``` +- 棕色渐变背景 +- 显示医院名称和位置 +- 右侧显示菜单和设置按钮 +- 高度: 60rpx + +### 2. 搜索栏 +```scss +.search-box { + display: flex; + align-items: center; + background: #f5f5f5; + border-radius: 24rpx; + padding: 12rpx 16rpx; +} + +.search-btn { + background: #4CAF50; + color: #fff; + padding: 8rpx 16rpx; + border-radius: 16rpx; +} +``` +- 灰色背景,圆角搜索框 +- 绿色搜索按钮 +- 支持输入科室、疾病、医生 + +### 3. 轮播图 +```scss +.banner { + height: 200rpx; +} +``` +- 高度: 200rpx +- 自动轮播,5秒切换 +- 圆角: 12rpx +- 阴影: 0 2rpx 8rpx + +### 4. 问诊服务卡片 +```scss +.service-card { + border-radius: 12rpx; + padding: 16rpx; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.service-1 { background: linear-gradient(135deg, #FFF3E0 0%, #FFE0B2 100%); } +.service-2 { background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%); } +.service-3 { background: linear-gradient(135deg, #F3E5F5 0%, #E1BEE7 100%); } +``` +- 3 列网格布局 +- 渐变背景 +- 标题 + 描述 + 按钮 +- 按下有缩放效果 + +### 5. 医生卡片 +```scss +.doctor-card { + flex-shrink: 0; + width: 120rpx; + background: #f9f9f9; + border-radius: 12rpx; + padding: 12rpx; + text-align: center; +} + +.doctor-avatar { + width: 80rpx; + height: 80rpx; + border-radius: 8rpx; +} +``` +- 横向滚动布局 +- 宽度: 120rpx +- 头像: 80x80rpx +- 显示名字、职位、科室 + +### 6. 底部导航 +```scss +.bottom-nav { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-around; + padding: 12rpx 0 16rpx 0; +} +``` +- 固定底部 +- 3 个导航项 +- 图标 + 文字 +- 高度: 80rpx + +## 字体规范 + +### 字体大小 +- **医院名称**: 22rpx +- **服务标题**: 24rpx +- **医生名字**: 22rpx +- **职位/科室**: 18rpx +- **搜索框**: 24rpx +- **按钮**: 18-22rpx + +### 字体权重 +- **标题**: 加粗 (600-700) +- **重要信息**: 加粗 (600) +- **正常文字**: 正常 (400) + +## 间距规范 + +- **页面外边距**: 20rpx +- **卡片内边距**: 12-16rpx +- **元素间距**: 8-12rpx +- **底部空间**: 100rpx (留给导航) + +## 圆角规范 + +- **卡片**: 12rpx +- **头像**: 8rpx +- **按钮**: 16-24rpx +- **搜索框**: 24rpx + +## 交互设计 + +### 轮播图 +- 自动轮播,5秒切换 +- 支持手动滑动 +- 底部指示器 + +### 服务卡片 +- 点击进入对应服务 +- 按下有缩放效果 (scale 0.95) +- 300ms 过渡动画 + +### 医生卡片 +- 横向滚动 +- 点击进入医生详情 +- 按下有阴影效果 + +### 导航切换 +- 点击切换导航 +- 颜色和大小变化 +- 300ms 过渡动画 + +## 响应式设计 + +### 使用 rpx 单位 +- 自动适配不同屏幕 +- 1rpx = 0.5px (375px 宽度) + +### 布局适配 +- 服务卡片 3 列 +- 医生卡片横向滚动 +- 自动适应屏幕宽度 + +## 性能优化 + +- 使用 CSS 动画 +- 图片自动缩放 +- 减少重排和重绘 +- 支持图片懒加载 + +## 无障碍设计 + +- 足够的色彩对比度 +- 清晰的文字标签 +- 合理的点击区域 (最小 44x44rpx) +- 支持屏幕阅读器 + +## 数据流 + +``` +页面加载 + ↓ +调用 fetchDoctors() + ↓ +获取医生列表 + ↓ +处理数据 + ↓ +渲染医生卡片 +``` + +## API 集成 + +### 获取医生列表 +```javascript +const response = await proxy.apiUrl({ + url: '/api/doctor/lists', + method: 'GET', + data: { + page_no: 1, + page_size: 10 + } +}) +``` + +## 点击事件 + +### 医生卡片点击 +```javascript +selectDoctor(doctor) { + uni.navigateTo({ + url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}` + }) +} +``` + +## 总结 + +这个设计方案特点: +- ✅ 现代医疗应用风格 +- ✅ 中医特色色彩搭配 +- ✅ 清晰的信息层级 +- ✅ 多种问诊服务选择 +- ✅ 医生横向滚动展示 +- ✅ 易用的导航设计 +- ✅ 适合60岁左右的用户 + +整个页面设计专业、现代、易用,为用户提供了多种医疗服务选择和便捷的医生查询体验。 diff --git a/TUICallKit-Vue3/SIMPLE_UI_DESIGN.md b/TUICallKit-Vue3/SIMPLE_UI_DESIGN.md new file mode 100644 index 00000000..93d96fe4 --- /dev/null +++ b/TUICallKit-Vue3/SIMPLE_UI_DESIGN.md @@ -0,0 +1,252 @@ +# 中医医院小程序首页 - 简化设计 + +## 页面结构 + +``` +┌─────────────────────────────────┐ +│ 中医医院 │ <- 顶部导航栏 +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ │ +│ [轮播图片 1] │ +│ 中医药文化 │ +│ 传承千年中医精粹,守护您的健康 │ +│ │ +│ ● ○ ○ │ <- 指示器 +└─────────────────────────────────┘ + +┌─────────────────────────────────┐ +│ 名医推荐 │ +├─────────────────────────────────┤ +│ ┌─────────────────────────────┐ │ +│ │ [头像] 张医生 [咨询] │ │ +│ │ 专家 主任医师 │ │ +│ │ 中医内科 │ │ +│ │ ★★★★★ 4.9 │ │ +│ └─────────────────────────────┘ │ +│ ┌─────────────────────────────┐ │ +│ │ [头像] 李医生 [咨询] │ │ +│ │ 副主任医师 │ │ +│ │ 中医妇科 │ │ +│ │ ★★★★★ 4.8 │ │ +│ └─────────────────────────────┘ │ +│ ┌─────────────────────────────┐ │ +│ │ [头像] 王医生 [咨询] │ │ +│ │ 主治医师 │ │ +│ │ 中医儿科 │ │ +│ │ ★★★★★ 4.7 │ │ +│ └─────────────────────────────┘ │ +└─────────────────────────────────┘ +``` + +## 设计规范 + +### 色彩方案 +- **主色**: `#8B6914` (棕色) - 中医传统色 +- **辅助色**: `#A0826D` (浅棕) - 渐变用 +- **强调色**: `#FFB800` (金色) - 星级评分 +- **背景**: `#f8f8f8` (浅灰) +- **卡片**: `#fff` (白色) +- **文字**: `#333` (深灰) + +### 字体规范 +- **标题**: 32rpx, 加粗 +- **医生名字**: 28rpx, 加粗 +- **职位/科室**: 22rpx, 正常 +- **评分**: 20rpx, 正常 + +### 间距规范 +- **页面外边距**: 20rpx +- **卡片内边距**: 16rpx +- **元素间距**: 4-8rpx + +### 圆角规范 +- **卡片**: 12rpx +- **头像**: 8rpx +- **按钮**: 20rpx + +## 组件详解 + +### 1. 顶部导航栏 +```scss +.header { + background: linear-gradient(135deg, #8B6914 0%, #A0826D 100%); + padding: 20rpx 30rpx; + color: #fff; + position: sticky; + top: 0; + z-index: 100; +} +``` +- 固定顶部,棕色渐变背景 +- 显示医院名称 +- 高度: 60rpx + +### 2. 轮播图 +```scss +.banner { + height: 320rpx; +} + +.banner-overlay { + background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent); + padding: 40rpx 30rpx; +} +``` +- 高度: 320rpx +- 自动轮播,5秒切换 +- 底部显示标题和描述 +- 使用渐变遮罩 + +### 3. 医生卡片 +```scss +.doctor-item { + display: flex; + gap: 16rpx; + padding: 16rpx; + background: #f9f9f9; + border-radius: 12rpx; + border: 1rpx solid #f0f0f0; +} +``` +- 左侧: 头像 (100x100rpx) + 专家标签 +- 中间: 医生信息 (名字、职位、科室、评分) +- 右侧: 咨询按钮 +- 按下有反馈效果 + +### 4. 医生信息 +``` +医生名字 (28rpx, 加粗) +职位 (22rpx, 棕色) +科室 (20rpx, 灰色) +★★★★★ 4.9 (20rpx, 金色) +``` + +### 5. 咨询按钮 +```scss +.consult-btn { + background: #8B6914; + color: #fff; + padding: 12rpx 20rpx; + border-radius: 20rpx; + font-size: 22rpx; +} +``` +- 棕色背景,白色文字 +- 圆角按钮 +- 点击跳转到挂号页面 + +## 交互设计 + +### 轮播图 +- 自动轮播,5秒切换一次 +- 支持手动滑动 +- 显示指示器点 + +### 医生卡片 +- 点击整个卡片进入医生详情 +- 按下时有缩放和阴影效果 +- 咨询按钮点击进入挂号页面 + +### 按钮反馈 +- 按下时背景变深 +- 有 300ms 过渡动画 +- 提供视觉反馈 + +## 响应式设计 + +### 使用 rpx 单位 +- 1rpx = 0.5px (在 375px 宽度下) +- 自动适配不同屏幕尺寸 +- 无需手动计算 + +### 布局适配 +- 医生卡片使用 flex 布局 +- 自动适应屏幕宽度 +- 文字自动换行 + +## 性能优化 + +### 图片优化 +- 使用 `mode="aspectFill"` 保持宽高比 +- 图片自动缩放 +- 支持懒加载 + +### 动画优化 +- 使用 CSS 过渡而非 JS 动画 +- 轮播使用原生 swiper 组件 +- 减少重排和重绘 + +## 数据流 + +``` +页面加载 + ↓ +调用 fetchDoctors() + ↓ +调用 proxy.apiUrl() 获取医生列表 + ↓ +处理响应数据 + ↓ +添加 isExpert 标记 + ↓ +渲染医生卡片 +``` + +## API 集成 + +### 获取医生列表 +```javascript +const response = await proxy.apiUrl({ + url: '/api/doctor/lists', + method: 'GET', + data: { + page_no: 1, + page_size: 10 + } +}) +``` + +### 响应格式 +```json +{ + "code": 1, + "msg": "success", + "data": { + "lists": [ + { + "id": 1, + "name": "张医生", + "title": "主任医师", + "specialty": "中医内科", + "avatar": "http://...", + "rating": "4.9" + } + ] + } +} +``` + +## 点击事件 + +### 医生卡片点击 +```javascript +selectDoctor(doctor) { + uni.navigateTo({ + url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}` + }) +} +``` + +## 总结 + +这个简化设计包含: +- ✅ 专业的顶部导航栏 +- ✅ 吸引人的轮播图 +- ✅ 清晰的医生列表 +- ✅ 便捷的咨询按钮 +- ✅ 中医风格的色彩方案 +- ✅ 流畅的交互体验 + +整个页面简洁明了,重点突出,用户可以快速找到想要的医生并进行咨询。 diff --git a/TUICallKit-Vue3/TCM_STYLE_DESIGN.md b/TUICallKit-Vue3/TCM_STYLE_DESIGN.md new file mode 100644 index 00000000..a294fb65 --- /dev/null +++ b/TUICallKit-Vue3/TCM_STYLE_DESIGN.md @@ -0,0 +1,308 @@ +# 中医风格首页设计指南 + +## 设计理念 + +采用绿色系中医风格,结合卡片式布局,营造专业、温和、信任的医疗氛围。 + +## 页面结构 + +``` +┌─────────────────────────────────┐ +│ 背景装饰(绿色渐变) │ +│ │ +│ ┌─────────────────────────────┐│ +│ │ 轮播图 ││ +│ │ ● ○ ○ ││ +│ └─────────────────────────────┘│ +│ │ +│ ┌─────────────────────────────┐│ +│ │ [头像] 赵建欣 咨询 > ││ +│ │ 主任医师 ││ +│ │ 中医内科 ││ +│ │ ││ +│ │ ⭐ 名医中医 ││ +│ │ ││ +│ │ 👍 好评率 95% ❤️ 服务人数 ││ +│ │ ││ +│ │ 🌐 互联网医院执业许可 ││ +│ │ 📋 医师执业许可证 ││ +│ └─────────────────────────────┘│ +│ │ +│ ┌─────────────────────────────┐│ +│ │ [头像] 李医生 咨询 > ││ +│ │ ... ││ +│ └─────────────────────────────┘│ +└─────────────────────────────────┘ +``` + +## 色彩方案 + +### 主色系 +- **主绿色**: `#4CAF50` - 中医健康、生命力 +- **浅绿色**: `#81C784` - 柔和、温暖 +- **背景绿**: `#E8F5E9` - 清爽、舒适 +- **浅背景**: `#F1F8F6` - 卡片背景 + +### 辅助色 +- **金色**: `#FFB800` - 强调、重要 +- **黄色**: `#FFF9C4` - 标签背景 +- **文字**: `#333` - 主文字 +- **辅助**: `#999` - 次要文字 + +## 组件设计 + +### 1. 背景装饰 +```scss +.bg-decoration { + background: linear-gradient(135deg, rgba(76, 175, 80, 0.1) 0%, rgba(129, 199, 132, 0.05) 100%); + position: fixed; + top: 0; + height: 400rpx; +} +``` +- 固定背景,绿色渐变 +- 营造整体氛围 +- 不影响内容交互 + +### 2. 轮播图 +```scss +.banner-section { + border-radius: 16rpx; + box-shadow: 0 4rpx 12rpx rgba(76, 175, 80, 0.15); +} + +.banner { + height: 280rpx; +} +``` +- 高度: 280rpx +- 圆角: 16rpx +- 绿色阴影 +- 自动轮播,5秒切换 +- 底部指示器 + +### 3. 医生卡片 +```scss +.doctor-card { + background: #fff; + border-radius: 16rpx; + padding: 20rpx; + box-shadow: 0 2rpx 8rpx rgba(76, 175, 80, 0.1); + border: 1rpx solid rgba(76, 175, 80, 0.08); +} +``` +- 白色背景,绿色阴影 +- 圆角: 16rpx +- 内边距: 20rpx +- 按下有上浮效果 + +### 4. 医生头部 +``` +[头像] 医生名字 + 咨询 > +``` +- 左侧: 80x80rpx 头像 +- 右侧: 名字 + 咨询按钮 +- 头像圆角: 12rpx + +### 5. 医生详情 +``` +┌──────────────┬──────────────┐ +│ 主任医师 │ 中医内科 │ +└──────────────┴──────────────┘ +``` +- 两个标签,绿色背景 +- 圆角: 20rpx +- 字体: 20rpx + +### 6. 医生标签 +``` +⭐ 名医中医 +``` +- 黄色背景 +- 圆角: 16rpx +- 显示医生特殊身份 + +### 7. 医生评分 +``` +┌──────────────┬──────────────┐ +│ 👍 好评率 │ ❤️ 服务人数 │ +│ 95% │ 256人 │ +└──────────────┴──────────────┘ +``` +- 两列布局 +- 绿色背景 +- 显示关键指标 + +### 8. 医生资质 +``` +🌐 互联网医院执业许可 +📋 医师执业许可证 +``` +- 列表展示 +- 图标 + 文字 +- 灰色文字 + +## 交互设计 + +### 轮播图 +- 自动轮播,5秒切换 +- 支持手动滑动 +- 底部指示器显示当前位置 +- 指示器动画: 圆形 → 胶囊形 + +### 医生卡片 +- 点击整个卡片进入医生详情 +- 按下时上浮 2rpx +- 阴影增强 +- 300ms 过渡动画 + +### 咨询按钮 +- 绿色文字,表示可点击 +- 点击进入挂号页面 +- 带有 ">" 箭头提示 + +## 响应式设计 + +### 使用 rpx 单位 +- 自动适配不同屏幕 +- 1rpx = 0.5px (375px 宽度) + +### 布局适配 +- 医生卡片宽度 100% +- 自动适应屏幕宽度 +- 文字自动换行 + +## 动画效果 + +### 轮播指示器 +```scss +.dot { + transition: all 0.3s ease; + + &.active { + width: 24rpx; + border-radius: 4rpx; + } +} +``` +- 圆形 → 胶囊形 +- 300ms 过渡 + +### 卡片交互 +```scss +.doctor-card { + transition: all 0.3s ease; + + &:active { + transform: translateY(-2rpx); + box-shadow: 0 4rpx 16rpx rgba(76, 175, 80, 0.15); + } +} +``` +- 上浮 2rpx +- 阴影增强 +- 300ms 过渡 + +## 阴影规范 + +- **轻**: `0 2rpx 8rpx rgba(76, 175, 80, 0.1)` +- **中**: `0 4rpx 12rpx rgba(76, 175, 80, 0.15)` +- **重**: `0 4rpx 16rpx rgba(76, 175, 80, 0.15)` + +## 字体规范 + +- **医生名字**: 28rpx, 加粗 +- **职位/科室**: 20rpx, 正常 +- **咨询按钮**: 22rpx, 加粗 +- **标签文字**: 18rpx, 正常 +- **评分数值**: 22rpx, 加粗 +- **资质文字**: 18rpx, 正常 + +## 间距规范 + +- **页面外边距**: 20rpx +- **卡片内边距**: 20rpx +- **元素间距**: 8-16rpx +- **底部空间**: 20rpx + +## 圆角规范 + +- **卡片**: 16rpx +- **头像**: 12rpx +- **标签**: 16-20rpx +- **小元素**: 12rpx + +## 数据流 + +``` +页面加载 + ↓ +调用 fetchDoctors() + ↓ +获取医生列表 + ↓ +处理数据(添加 isExpert 标记) + ↓ +渲染医生卡片 +``` + +## API 集成 + +### 获取医生列表 +```javascript +const response = await proxy.apiUrl({ + url: '/api/doctor/lists', + method: 'GET', + data: { + page_no: 1, + page_size: 10 + } +}) +``` + +### 响应数据处理 +```javascript +doctors.value = doctorList.map((doctor, index) => ({ + ...doctor, + isExpert: index < 2, + reviewCount: Math.floor(Math.random() * 500) + 100 +})) +``` + +## 点击事件 + +### 医生卡片点击 +```javascript +selectDoctor(doctor) { + uni.navigateTo({ + url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}` + }) +} +``` + +## 性能优化 + +- 使用 CSS 动画而非 JS 动画 +- 图片使用 `mode="aspectFill"` +- 减少重排和重绘 +- 支持图片懒加载 + +## 无障碍设计 + +- 足够的色彩对比度 +- 清晰的文字标签 +- 合理的点击区域 (最小 44x44rpx) +- 支持屏幕阅读器 + +## 总结 + +这个设计方案特点: +- ✅ 绿色系中医风格 +- ✅ 卡片式布局,清晰明了 +- ✅ 完整的医生信息展示 +- ✅ 医生资质认证显示 +- ✅ 流畅的交互体验 +- ✅ 专业的医疗感 + +整个页面简洁专业,重点突出,用户可以快速了解医生信息并进行咨询。 diff --git a/TUICallKit-Vue3/UI_DESIGN_GUIDE.md b/TUICallKit-Vue3/UI_DESIGN_GUIDE.md new file mode 100644 index 00000000..fa2b976a --- /dev/null +++ b/TUICallKit-Vue3/UI_DESIGN_GUIDE.md @@ -0,0 +1,249 @@ +# 中医医院小程序首页 UI 设计指南 + +## 设计理念 + +### 核心特点 +1. **中医文化融合** - 采用中医传统色彩(棕色、金色) +2. **专业医疗感** - 简洁现代的布局,突出医疗专业性 +3. **用户友好** - 清晰的信息层级,便捷的操作流程 +4. **视觉层次** - 通过色彩、大小、间距创建清晰的视觉层次 + +## 色彩方案 + +### 主色系 +- **主色**: `#8B6914` (棕色) - 代表中医传统、稳重、专业 +- **辅助色**: `#A0826D` (浅棕) - 用于渐变和背景 +- **强调色**: `#FFB800` (金色) - 用于星级评分、重要信息 +- **警告色**: `#FF6B6B` (红色) - 用于通知、提醒 + +### 中性色 +- **背景**: `#f8f8f8` - 整体背景 +- **卡片**: `#fff` - 内容卡片 +- **文字**: `#333` - 主文字 +- **辅助**: `#999` - 辅助文字 + +## 页面结构 + +### 1. 顶部导航栏 (Header) +``` +┌─────────────────────────────────┐ +│ 中医医院 🔔 (3) │ +└─────────────────────────────────┘ +``` +- 固定顶部,背景为棕色渐变 +- 左侧显示医院名称 +- 右侧显示通知图标和未读数 + +### 2. 搜索栏 (Search Bar) +``` +┌─────────────────────────────────┐ +│ 🔍 搜索医生或科室 │ +└─────────────────────────────────┘ +``` +- 圆角搜索框,背景为浅灰色 +- 支持搜索医生和科室 + +### 3. 快速导航 (Quick Navigation) +``` +┌──────┬──────┬──────┬──────┐ +│ 📋 │ 💬 │ 📄 │ ❤️ │ +│ 挂号 │ 咨询 │ 记录 │ 档案 │ +└──────┴──────┴──────┴──────┘ +``` +- 4 个快速入口 +- 图标 + 文字组合 +- 点击跳转到对应页面 + +### 4. 轮播区域 (Banner) +``` +┌─────────────────────────────────┐ +│ │ +│ [轮播图片] │ +│ │ +│ 中医药文化 │ +│ 传承千年中医精粹,守护您的健康 │ +│ [了解更多] │ +│ │ +└─────────────────────────────────┘ +``` +- 高度: 300rpx +- 自动轮播,5秒切换 +- 底部显示标题、描述和按钮 +- 使用渐变遮罩 + +### 5. 科室推荐 (Departments) +``` +┌─────────────────────────────────┐ +│ 科室推荐 查看全部 > │ +├─────────────────────────────────┤ +│ 🫀 👩 👶 │ +│ 内科 妇科 儿科 │ +│ 中医内科 中医妇科 中医儿科 │ +│ │ +│ 🦴 🧴 💉 │ +│ 骨科 皮肤科 针灸科 │ +│ 中医骨科 中医皮肤 针灸推拿 │ +└─────────────────────────────────┘ +``` +- 3 列网格布局 +- 6 个科室卡片 +- 卡片背景为浅米色 +- 点击进入科室详情 + +### 6. 医生推荐 (Doctors) +``` +┌─────────────────────────────────┐ +│ 名医推荐 查看全部 > │ +├─────────────────────────────────┤ +│ ┌─────────────────────────────┐ │ +│ │ [头像] 张医生 [咨询] │ │ +│ │ 专家 主任医师 │ │ +│ │ 中医内科 │ │ +│ │ ★★★★★ 4.9 (256) │ │ +│ └─────────────────────────────┘ │ +│ ┌─────────────────────────────┐ │ +│ │ [头像] 李医生 [咨询] │ │ +│ │ 副主任医师 │ │ +│ │ 中医妇科 │ │ +│ │ ★★★★★ 4.8 (189) │ │ +│ └─────────────────────────────┘ │ +└─────────────────────────────────┘ +``` +- 列表布局,每行一个医生 +- 左侧: 头像 + 专家标签 +- 中间: 医生信息(名字、职位、科室、评分) +- 右侧: 咨询按钮 +- 点击进入医生详情 + +### 7. 健康资讯 (News) +``` +┌─────────────────────────────────┐ +│ 健康资讯 更多 > │ +├─────────────────────────────────┤ +│ [图] 春季养生:如何调理脾胃 │ +│ 中医养生 2小时前 │ +│ │ +│ [图] 中医药在预防疾病中的作用 │ +│ 医学资讯 4小时前 │ +│ │ +│ [图] 穴位按摩缓解颈椎疲劳 │ +│ 健康指南 6小时前 │ +└─────────────────────────────────┘ +``` +- 列表布局 +- 左侧: 新闻图片 +- 右侧: 标题、来源、时间 +- 标题最多显示 2 行 + +## 交互设计 + +### 按钮状态 +- **正常**: 棕色背景,白色文字 +- **按下**: 背景变深,有缩放动画 +- **禁用**: 灰色背景,不可点击 + +### 卡片交互 +- **正常**: 浅色背景,细边框 +- **按下**: 背景变深,有阴影效果 +- **悬停**: 轻微缩放 + +### 动画效果 +- **轮播**: 500ms 切换动画 +- **卡片**: 300ms 过渡效果 +- **按钮**: 100ms 按下效果 + +## 响应式设计 + +### 断点 +- **小屏幕** (< 375px): 调整间距和字体 +- **中屏幕** (375-414px): 标准设计 +- **大屏幕** (> 414px): 增加间距 + +### 适配方案 +- 使用 rpx 单位(响应式像素) +- 1rpx = 0.5px (在 375px 宽度下) +- 自动适配不同屏幕尺寸 + +## 字体规范 + +### 字体大小 +- **标题**: 32rpx (主标题), 28rpx (副标题) +- **正文**: 24rpx (主要内容), 22rpx (次要内容) +- **辅助**: 20rpx (提示信息), 18rpx (标签) + +### 字体权重 +- **加粗**: 500-700 (标题、重要信息) +- **正常**: 400 (正文) +- **轻细**: 300 (辅助信息) + +## 间距规范 + +### 外间距 (Margin) +- **大**: 30rpx (主要分区) +- **中**: 20rpx (卡片间距) +- **小**: 10rpx (元素间距) + +### 内间距 (Padding) +- **大**: 30rpx (卡片内部) +- **中**: 20rpx (按钮、输入框) +- **小**: 10rpx (文字间距) + +## 圆角规范 + +- **大**: 12rpx (卡片、按钮) +- **中**: 8rpx (小卡片、图片) +- **小**: 4rpx (标签、徽章) +- **圆形**: 50% (头像、通知徽章) + +## 阴影规范 + +- **轻**: `0 2rpx 8rpx rgba(0, 0, 0, 0.08)` +- **中**: `0 4rpx 12rpx rgba(0, 0, 0, 0.12)` +- **重**: `0 8rpx 24rpx rgba(0, 0, 0, 0.15)` + +## 图片规范 + +### 尺寸 +- **轮播图**: 750x300px +- **医生头像**: 100x100rpx +- **新闻图片**: 140x100rpx +- **科室图标**: 48rpx (emoji) + +### 处理 +- 使用 `mode="aspectFill"` 保持宽高比 +- 圆角处理: 8-12rpx +- 加载占位符: 灰色背景 + +## 无障碍设计 + +- 足够的色彩对比度 +- 清晰的文字标签 +- 合理的点击区域 (最小 44x44rpx) +- 支持屏幕阅读器 + +## 性能优化 + +- 图片懒加载 +- 列表虚拟滚动 +- 减少重排和重绘 +- 使用 CSS 动画而非 JS 动画 + +## 扩展建议 + +### 可以添加的功能 +1. **个性化推荐** - 根据用户历史推荐医生 +2. **预约提醒** - 显示即将到来的预约 +3. **健康数据** - 显示用户的健康指标 +4. **在线客服** - 右下角浮窗 +5. **活动促销** - 轮播中添加促销信息 + +### 可以优化的方面 +1. **深色模式** - 支持系统深色模式 +2. **多语言** - 支持多种语言 +3. **主题切换** - 允许用户自定义主题色 +4. **动画增强** - 添加更多微交互 +5. **数据统计** - 追踪用户行为 + +## 总结 + +这个设计方案结合了中医文化特色和现代医疗应用的需求,通过合理的色彩、布局和交互设计,为用户提供专业、友好的医疗服务体验。 diff --git a/TUICallKit-Vue3/config/index.js b/TUICallKit-Vue3/config/index.js new file mode 100644 index 00000000..19e3e4ab --- /dev/null +++ b/TUICallKit-Vue3/config/index.js @@ -0,0 +1,24 @@ +// 应用配置文件 + +// 根据环境设置API基础URL +let API_BASE_URL = 'http://localhost:8000/api' + +// 如果是生产环境,修改为实际的API地址 +if (typeof uni !== 'undefined') { + // 小程序环境 + const accountInfo = uni.getAccountInfoSync() + if (accountInfo.miniProgram.envVersion === 'release') { + // 生产环境 + API_BASE_URL = 'https://your-production-api.com/api' + } else if (accountInfo.miniProgram.envVersion === 'trial') { + // 体验版 + API_BASE_URL = 'https://your-trial-api.com/api' + } +} + +export default { + API_BASE_URL, + // 其他配置... + APP_NAME: '医疗小程序', + APP_VERSION: '1.0.0' +} diff --git a/TUICallKit-Vue3/main.js b/TUICallKit-Vue3/main.js index 022cb351..191a9e4b 100644 --- a/TUICallKit-Vue3/main.js +++ b/TUICallKit-Vue3/main.js @@ -1,5 +1,5 @@ import App from './App' -var baseUrl ='http://api.zzzhengyangtang.cn'; +var baseUrl ='http://www.d.com'; // #ifndef VUE3 import Vue from 'vue' import './uni.promisify.adaptor' @@ -94,7 +94,7 @@ function apiUrl(promise, Loading = true) { // 处理登录失效逻辑(补充完整) if (data.code === -1) { uni.removeStorageSync('token') // 删除token - uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' }) + //uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' }) // 可选:跳转到登录页 // uni.redirectTo({ url: '/pages/login/login' }) } @@ -102,7 +102,7 @@ function apiUrl(promise, Loading = true) { resolve(data) }, fail: (e) => { - uni.showToast({ title: '请求失败,请重试', icon: 'none' }) + // uni.showToast({ title: '请求失败,请重试', icon: 'none' }) reject(e) }, complete: (e) => { diff --git a/TUICallKit-Vue3/pages.json b/TUICallKit-Vue3/pages.json index ddf2dd47..e16e500b 100644 --- a/TUICallKit-Vue3/pages.json +++ b/TUICallKit-Vue3/pages.json @@ -3,7 +3,7 @@ { "path": "pages/index/index", "style": { - "navigationBarTitleText": "uni-app" + "navigationBarTitleText": "甄养堂" } }, { @@ -72,7 +72,7 @@ ], "tabBar": { "color": "#7A7E83", - "selectedColor": "#3cc51f", + "selectedColor": "#FFA500", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [{ diff --git a/TUICallKit-Vue3/pages/index/index.vue b/TUICallKit-Vue3/pages/index/index.vue index b1bfa5b8..8080da6a 100644 --- a/TUICallKit-Vue3/pages/index/index.vue +++ b/TUICallKit-Vue3/pages/index/index.vue @@ -1,153 +1,500 @@ - \ No newline at end of file + +.doctor-avatar { + width: 120rpx; + height: 120rpx; + border-radius: 50%; + border: 3rpx solid #E8E8E8; +} + +.avatar-frame { + position: absolute; + top: -4rpx; + left: 50%; + transform: translateX(-50%); + width: 128rpx; + height: 128rpx; + border: 2rpx solid rgba(212, 175, 55, 0.3); + border-radius: 50%; + pointer-events: none; +} + +.doctor-name { + font-size: 26rpx; + font-weight: bold; + color: #3E2723; + margin-bottom: 6rpx; +} + +.doctor-title { + font-size: 22rpx; + color: #757575; + margin-bottom: 4rpx; +} + +.doctor-dept { + font-size: 20rpx; + color: #9E9E9E; +} + +// 底部导航 +.bottom-nav { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background: #fff; + border-top: 1rpx solid #E8E8E8; + display: flex; + justify-content: space-around; + padding: 16rpx 0 24rpx 0; + box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.05); + z-index: 100; +} + +.nav-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 6rpx; + flex: 1; + + &.active { + .nav-icon { + font-size: 40rpx; + } + + .nav-text { + color: #D4AF37; + font-weight: bold; + } + } +} + +.nav-icon { + font-size: 36rpx; + transition: all 0.3s ease; +} + +.nav-text { + font-size: 22rpx; + color: #757575; + transition: all 0.3s ease; +} + diff --git a/TUICallKit-Vue3/pages/user/user.vue b/TUICallKit-Vue3/pages/user/user.vue index a5304540..57bff351 100644 --- a/TUICallKit-Vue3/pages/user/user.vue +++ b/TUICallKit-Vue3/pages/user/user.vue @@ -29,7 +29,7 @@ -
+ - 订单详情 - - - - - - - - - - - - @@ -254,17 +233,35 @@ width="500px" > - - {{ payForm.order_no }} - - - ¥{{ payForm.amount }} + + + + 补单支付 + + + + + + 支付宝 微信 - 银行卡 @@ -299,7 +296,7 @@ @@ -331,81 +328,6 @@ placeholder="请输入备注(可选)" /> - - -
- - + 添加订单项 - - - - - - - - - - - - - - - - - - - - - -
-