From 1f209e6761f41d1ebb995263635fed831493a23a Mon Sep 17 00:00:00 2001 From: liwentao Date: Wed, 24 Jun 2026 05:07:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=90=8E=E5=8F=B0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=B3=BB=E7=BB=9F=EF=BC=88=E7=AD=94=E8=BE=A9=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gym-manage-api/docs/cuit-auth-api.md | 189 ++ gym-manage-api/docs/employee-api.md | 343 ++ gym-manage-api/docs/info.txt | 51 + .../datacount/domain/MemberDailySignIn.java | 44 + .../datacount/domain/MemberMonthlySignIn.java | 49 + .../datacount/domain/MemberSignInDetail.java | 54 + .../GroupCourseTimeoutScheduler.java | 67 + .../.mvn/wrapper/maven-wrapper.properties | 3 + gym-manage-api/gym-manage-cuit/pom.xml | 114 + .../manage/auth/converter/UserConverter.java | 63 + .../novalon/gym/manage/auth/dao/UserDao.java | 17 + .../novalon/gym/manage/auth/domain/User.java | 73 + .../gym/manage/auth/dto/LoginRequest.java | 32 + .../gym/manage/auth/dto/LoginResponse.java | 62 + .../novalon/gym/manage/auth/dto/UserInfo.java | 84 + .../gym/manage/auth/entity/UserEntity.java | 86 + .../gym/manage/auth/handler/AuthHandler.java | 83 + .../auth/repository/AuthRepository.java | 14 + .../repository/impl/AuthRepositoryImpl.java | 50 + .../gym/manage/auth/service/IAuthService.java | 13 + .../auth/service/impl/AuthServiceImpl.java | 48 + .../novalon/gym/manage/auth/util/JwtUtil.java | 80 + .../gym/manage/auth/util/ResponseCode.java | 34 + .../src/main/resources/application.yaml | 16 + .../GymManageCuitApplicationTests.java | 15 + gym-manage-coach/.gitignore | 4 + gym-manage-coach/App.vue | 368 +++ gym-manage-coach/api/auth.js | 30 + gym-manage-coach/api/checkin.js | 38 + gym-manage-coach/api/course.js | 89 + gym-manage-coach/index.html | 20 + gym-manage-coach/main.js | 22 + gym-manage-coach/manifest.json | 72 + gym-manage-coach/pages.json | 45 + gym-manage-coach/pages/course/detail.vue | 824 +++++ gym-manage-coach/pages/course/list.vue | 377 +++ gym-manage-coach/pages/index/index.vue | 449 +++ gym-manage-coach/pages/login/login.vue | 385 +++ gym-manage-coach/static/logo.png | Bin 0 -> 4023 bytes gym-manage-coach/store/auth.js | 56 + gym-manage-coach/uni.promisify.adaptor.js | 13 + gym-manage-coach/uni.scss | 39 + gym-manage-coach/utils/index.js | 133 + gym-manage-coach/utils/request.js | 122 + gym-manage-coach/vite.config.js | 17 + gym-manage-cuit/.gitignore | 39 + gym-manage-cuit/.prettierrc.json | 6 + gym-manage-cuit/.vscode/extensions.json | 6 + gym-manage-cuit/README.md | 42 + gym-manage-cuit/env.d.ts | 1 + gym-manage-cuit/exmp/index.html | 802 +++++ gym-manage-cuit/index.html | 13 + gym-manage-cuit/package.json | 36 + gym-manage-cuit/pnpm-lock.yaml | 2844 +++++++++++++++++ gym-manage-cuit/public/favicon.ico | Bin 0 -> 4286 bytes gym-manage-cuit/src/App.vue | 50 + gym-manage-cuit/src/api/auth.ts | 42 + gym-manage-cuit/src/api/coach.ts | 29 + gym-manage-cuit/src/api/datacount.ts | 139 + gym-manage-cuit/src/api/dict.ts | 129 + gym-manage-cuit/src/api/employee.ts | 128 + gym-manage-cuit/src/api/groupCourse.ts | 187 ++ .../src/api/groupCourseRecommend.ts | 71 + gym-manage-cuit/src/api/member.ts | 162 + gym-manage-cuit/src/api/memberCard.ts | 89 + gym-manage-cuit/src/api/notice.ts | 58 + gym-manage-cuit/src/api/operationLog.ts | 66 + gym-manage-cuit/src/api/request.ts | 35 + gym-manage-cuit/src/api/role.ts | 207 ++ gym-manage-cuit/src/components/AppLayout.vue | 651 ++++ gym-manage-cuit/src/composables/useToast.ts | 29 + gym-manage-cuit/src/main.ts | 12 + gym-manage-cuit/src/router/index.ts | 119 + gym-manage-cuit/src/stores/auth.ts | 88 + gym-manage-cuit/src/utils/ossUpload.ts | 56 + gym-manage-cuit/src/views/CoachManage.vue | 464 +++ .../src/views/Dashboard-script.txt | 124 + gym-manage-cuit/src/views/Dashboard.vue | 617 ++++ gym-manage-cuit/src/views/DataReport.vue | 599 ++++ gym-manage-cuit/src/views/DictManage.vue | 923 ++++++ gym-manage-cuit/src/views/EmployeeManage.vue | 1273 ++++++++ gym-manage-cuit/src/views/GroupCourse.vue | 1386 ++++++++ .../src/views/GroupCourseCancel.vue | 596 ++++ .../src/views/GroupCourseRecommend.vue | 396 +++ gym-manage-cuit/src/views/GroupCourseType.vue | 981 ++++++ gym-manage-cuit/src/views/Login.vue | 259 ++ .../src/views/MemberCardManage.vue | 817 +++++ gym-manage-cuit/src/views/MemberManage.vue | 1028 ++++++ gym-manage-cuit/src/views/MemberSignIn.vue | 887 +++++ gym-manage-cuit/src/views/NoticeManage.vue | 592 ++++ gym-manage-cuit/src/views/OperationLog.vue | 1172 +++++++ gym-manage-cuit/src/views/RoleManage.vue | 1427 +++++++++ gym-manage-cuit/tsconfig.app.json | 18 + gym-manage-cuit/tsconfig.json | 11 + gym-manage-cuit/tsconfig.node.json | 27 + gym-manage-cuit/vite.config.ts | 28 + log.text | 506 +++ log2.text | 45 + 98 files changed, 25099 insertions(+) create mode 100644 gym-manage-api/docs/cuit-auth-api.md create mode 100644 gym-manage-api/docs/employee-api.md create mode 100644 gym-manage-api/docs/info.txt create mode 100644 gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberDailySignIn.java create mode 100644 gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberMonthlySignIn.java create mode 100644 gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberSignInDetail.java create mode 100644 gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseTimeoutScheduler.java create mode 100644 gym-manage-api/gym-manage-cuit/.mvn/wrapper/maven-wrapper.properties create mode 100644 gym-manage-api/gym-manage-cuit/pom.xml create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/converter/UserConverter.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dao/UserDao.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/domain/User.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginRequest.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginResponse.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/UserInfo.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/entity/UserEntity.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/handler/AuthHandler.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/AuthRepository.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/impl/AuthRepositoryImpl.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/IAuthService.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/impl/AuthServiceImpl.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/JwtUtil.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/ResponseCode.java create mode 100644 gym-manage-api/gym-manage-cuit/src/main/resources/application.yaml create mode 100644 gym-manage-api/gym-manage-cuit/src/test/java/cn/novalon/gym/manage/cuit/gymmanagecuit/GymManageCuitApplicationTests.java create mode 100644 gym-manage-coach/.gitignore create mode 100644 gym-manage-coach/App.vue create mode 100644 gym-manage-coach/api/auth.js create mode 100644 gym-manage-coach/api/checkin.js create mode 100644 gym-manage-coach/api/course.js create mode 100644 gym-manage-coach/index.html create mode 100644 gym-manage-coach/main.js create mode 100644 gym-manage-coach/manifest.json create mode 100644 gym-manage-coach/pages.json create mode 100644 gym-manage-coach/pages/course/detail.vue create mode 100644 gym-manage-coach/pages/course/list.vue create mode 100644 gym-manage-coach/pages/index/index.vue create mode 100644 gym-manage-coach/pages/login/login.vue create mode 100644 gym-manage-coach/static/logo.png create mode 100644 gym-manage-coach/store/auth.js create mode 100644 gym-manage-coach/uni.promisify.adaptor.js create mode 100644 gym-manage-coach/uni.scss create mode 100644 gym-manage-coach/utils/index.js create mode 100644 gym-manage-coach/utils/request.js create mode 100644 gym-manage-coach/vite.config.js create mode 100644 gym-manage-cuit/.gitignore create mode 100644 gym-manage-cuit/.prettierrc.json create mode 100644 gym-manage-cuit/.vscode/extensions.json create mode 100644 gym-manage-cuit/README.md create mode 100644 gym-manage-cuit/env.d.ts create mode 100644 gym-manage-cuit/exmp/index.html create mode 100644 gym-manage-cuit/index.html create mode 100644 gym-manage-cuit/package.json create mode 100644 gym-manage-cuit/pnpm-lock.yaml create mode 100644 gym-manage-cuit/public/favicon.ico create mode 100644 gym-manage-cuit/src/App.vue create mode 100644 gym-manage-cuit/src/api/auth.ts create mode 100644 gym-manage-cuit/src/api/coach.ts create mode 100644 gym-manage-cuit/src/api/datacount.ts create mode 100644 gym-manage-cuit/src/api/dict.ts create mode 100644 gym-manage-cuit/src/api/employee.ts create mode 100644 gym-manage-cuit/src/api/groupCourse.ts create mode 100644 gym-manage-cuit/src/api/groupCourseRecommend.ts create mode 100644 gym-manage-cuit/src/api/member.ts create mode 100644 gym-manage-cuit/src/api/memberCard.ts create mode 100644 gym-manage-cuit/src/api/notice.ts create mode 100644 gym-manage-cuit/src/api/operationLog.ts create mode 100644 gym-manage-cuit/src/api/request.ts create mode 100644 gym-manage-cuit/src/api/role.ts create mode 100644 gym-manage-cuit/src/components/AppLayout.vue create mode 100644 gym-manage-cuit/src/composables/useToast.ts create mode 100644 gym-manage-cuit/src/main.ts create mode 100644 gym-manage-cuit/src/router/index.ts create mode 100644 gym-manage-cuit/src/stores/auth.ts create mode 100644 gym-manage-cuit/src/utils/ossUpload.ts create mode 100644 gym-manage-cuit/src/views/CoachManage.vue create mode 100644 gym-manage-cuit/src/views/Dashboard-script.txt create mode 100644 gym-manage-cuit/src/views/Dashboard.vue create mode 100644 gym-manage-cuit/src/views/DataReport.vue create mode 100644 gym-manage-cuit/src/views/DictManage.vue create mode 100644 gym-manage-cuit/src/views/EmployeeManage.vue create mode 100644 gym-manage-cuit/src/views/GroupCourse.vue create mode 100644 gym-manage-cuit/src/views/GroupCourseCancel.vue create mode 100644 gym-manage-cuit/src/views/GroupCourseRecommend.vue create mode 100644 gym-manage-cuit/src/views/GroupCourseType.vue create mode 100644 gym-manage-cuit/src/views/Login.vue create mode 100644 gym-manage-cuit/src/views/MemberCardManage.vue create mode 100644 gym-manage-cuit/src/views/MemberManage.vue create mode 100644 gym-manage-cuit/src/views/MemberSignIn.vue create mode 100644 gym-manage-cuit/src/views/NoticeManage.vue create mode 100644 gym-manage-cuit/src/views/OperationLog.vue create mode 100644 gym-manage-cuit/src/views/RoleManage.vue create mode 100644 gym-manage-cuit/tsconfig.app.json create mode 100644 gym-manage-cuit/tsconfig.json create mode 100644 gym-manage-cuit/tsconfig.node.json create mode 100644 gym-manage-cuit/vite.config.ts create mode 100644 log.text create mode 100644 log2.text diff --git a/gym-manage-api/docs/cuit-auth-api.md b/gym-manage-api/docs/cuit-auth-api.md new file mode 100644 index 0000000..8231aa2 --- /dev/null +++ b/gym-manage-api/docs/cuit-auth-api.md @@ -0,0 +1,189 @@ +# 认证管理模块 API 文档 + +> **文档版本**: v1.0 +> **创建日期**: 2026-06-16 +> **作者**: 张翔 +> **状态**: 正式发布 + +--- + +## 目录 + +1. [概述](#概述) +2. [基础路径](#基础路径) +3. [认证接口](#认证接口) + - [用户名+密码登录](#用户名密码登录) + - [获取用户信息](#获取用户信息) +4. [数据模型](#数据模型) + - [LoginRequest](#loginrequest) + - [LoginResponse](#loginresponse) + - [UserInfo](#userinfo) +5. [响应码说明](#响应码说明) + +--- + +## 概述 + +认证管理模块提供用户登录认证和用户信息查询功能。采用 Spring WebFlux 响应式编程,支持高并发场景。 + +## 基础路径 + +所有接口的基础路径为: `http://{host}:{port}/api/auth` + +--- + +## 认证接口 + +### 用户名+密码登录 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | POST | +| **接口路径** | `/api/auth/login` | +| **所属文件** | `AuthHandler.java` | + +**请求参数**: + +| 参数名 | 类型 | 必填 | 默认值 | 说明 | +|--------|------|------|--------|------| +| username | string | 是 | - | 用户名 | +| password | string | 是 | - | 密码 | + +**成功响应** (200 OK): + +```json +{ + "code": 200, + "message": "登录成功", + "data": { + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "tokenType": "Bearer", + "expiresIn": 7200, + "userInfo": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "phone": "13800138000", + "nickname": "超级管理员", + "status": 1, + "roleId": 1 + } + } +} +``` + +**失败响应** (400 Bad Request): + +```json +{ + "code": 400, + "message": "用户名或密码错误" +} +``` + +--- + +### 获取用户信息 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | GET | +| **接口路径** | `/api/auth/users/{id}` | +| **所属文件** | `AuthHandler.java` | + +**路径参数**: + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| id | Long | 是 | 用户ID | + +**成功响应** (200 OK): + +```json +{ + "code": 200, + "message": "获取用户信息成功", + "data": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "phone": "13800138000", + "nickname": "超级管理员", + "status": 1, + "roleId": 1 + } +} +``` + +**失败响应** (400 Bad Request): + +```json +{ + "code": 400, + "message": "无效的用户ID" +} +``` + +--- + +## 数据模型 + +### LoginRequest + +用户登录请求对象。 + +| 字段 | 类型 | 必填 | 说明 | 示例 | +|------|------|------|------|------| +| username | string | 是 | 用户名 | admin | +| password | string | 是 | 密码 | Test@123 | + +### LoginResponse + +用户登录响应对象。 + +| 字段 | 类型 | 说明 | 示例 | +|------|------|------|------| +| accessToken | string | 访问令牌 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | +| refreshToken | string | 刷新令牌 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | +| tokenType | string | 令牌类型 | Bearer | +| expiresIn | Long | 过期时间(秒) | 7200 | +| userInfo | UserInfo | 用户信息 | - | + +### UserInfo + +用户信息对象。 + +| 字段 | 类型 | 说明 | 示例 | +|------|------|------|------| +| id | Long | 用户ID | 1 | +| username | string | 用户名 | admin | +| email | string | 邮箱 | admin@example.com | +| phone | string | 手机号 | 13800138000 | +| nickname | string | 昵称 | 超级管理员 | +| status | Integer | 状态:0-禁用,1-正常 | 1 | +| roleId | Long | 角色ID | 1 | + +--- + +## 响应码说明 + +| 响应码 | 说明 | +|--------|------| +| 200 | 成功 | +| 400 | 请求参数错误(如用户名密码错误、无效的用户ID) | +| 401 | 未授权(认证失败) | +| 403 | 禁止访问 | +| 404 | 资源未找到 | +| 409 | 冲突(如重复数据) | +| 500 | 服务器内部错误 | + +--- + +## 业务规则 + +1. 登录成功后返回的 `accessToken` 用于后续接口的身份认证 +2. `accessToken` 有效期为 2 小时(7200 秒) +3. `refreshToken` 用于刷新 `accessToken`,有效期为 7 天 +4. 用户状态 `status` 为 0 时表示禁用,无法登录 +5. 所有需要认证的接口需要在请求头中携带 `Authorization: Bearer {accessToken}` diff --git a/gym-manage-api/docs/employee-api.md b/gym-manage-api/docs/employee-api.md new file mode 100644 index 0000000..9d77eed --- /dev/null +++ b/gym-manage-api/docs/employee-api.md @@ -0,0 +1,343 @@ +# 员工管理模块 API 文档 + +> **文档版本**: v1.0 +> **创建日期**: 2026-06-20 +> **作者**: AI Assistant +> **状态**: 正式发布 + +--- + +## 目录 + +1. [概述](#概述) +2. [基础路径](#基础路径) +3. [员工管理接口](#员工管理接口) + - [分页获取员工列表(含角色信息)](#分页获取员工列表含角色信息) +4. [用户管理接口(复用)](#用户管理接口复用) + - [创建员工账号](#创建员工账号) + - [获取员工详情](#获取员工详情) + - [更新员工信息](#更新员工信息) + - [逻辑删除员工](#逻辑删除员工) + - [修改密码](#修改密码) + - [为用户分配角色](#为用户分配角色) + - [获取用户的角色](#获取用户的角色) +5. [角色管理接口(复用)](#角色管理接口复用) + - [获取所有角色](#获取所有角色) +6. [数据模型](#数据模型) + - [UserRegisterRequest](#userregisterrequest) + - [EmployeePageResponse](#employeepageresponse) + - [RoleInfo](#roleinfo) + +--- + +## 概述 + +员工管理模块为店长(超级管理员 admin)提供新员工账号创建和权限分配功能。该模块复用已有的用户管理、角色管理接口,并新增了带角色信息的员工分页查询接口。 + +## 基础路径 + +所有接口的基础路径为: `http://{host}:{port}/api` + +--- + +## 员工管理接口 + +### 分页获取员工列表(含角色信息) + +> **新增接口**:该接口在已有 `/api/users/page` 基础上,额外返回每个员工的角色详细信息。 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | GET | +| **接口路径** | `/api/employees/page` | +| **所属文件** | `SysUserHandler.java` | + +**请求参数**: + +| 参数名 | 类型 | 必填 | 默认值 | 说明 | +|--------|------|------|--------|------| +| page | int | 否 | 0 | 页码(从0开始) | +| size | int | 否 | 10 | 每页数量 | +| sort | string | 否 | id | 排序字段 | +| order | string | 否 | asc | 排序方向(asc/desc) | +| keyword | string | 否 | - | 搜索关键字(匹配用户名/昵称) | + +**成功响应** (200 OK): + +```json +{ + "content": [ + { + "id": 1, + "username": "admin", + "nickname": "超级管理员", + "email": "admin@novalon.com", + "phone": "13800138000", + "avatar": null, + "status": 1, + "roles": [ + { + "id": 1, + "roleName": "超级管理员", + "roleKey": "admin", + "roleSort": 1 + } + ], + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" + } + ], + "totalPages": 1, + "totalElements": 1, + "currentPage": 0, + "pageSize": 10, + "first": true, + "last": true +} +``` + +--- + +## 用户管理接口(复用) + +以下接口为 `SysUserHandler` 中已有的用户管理接口,可直接用于员工管理。 + +### 创建员工账号 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | POST | +| **接口路径** | `/api/users` | +| **所属文件** | `SysUserHandler.java` | + +**请求体**: + +```json +{ + "username": "newstaff", + "password": "Staff@123", + "nickname": "新员工", + "email": "staff@novalon.com", + "phone": "13900139001", + "roles": [2, 3] +} +``` + +**成功响应** (201 Created): + +```json +{ + "id": 11, + "username": "newstaff", + "nickname": "新员工", + "email": "staff@novalon.com", + "phone": "13900139001", + "status": 1, + "createdAt": "2026-06-20T10:00:00", + "updatedAt": "2026-06-20T10:00:00" +} +``` + +**校验规则**: +- `username`: 3-50位,只能包含字母、数字、下划线和横线 +- `password`: 8-20位,必须包含大小写字母和数字 +- `email`: 合法邮箱格式 +- `phone`: 中国大陆手机号格式(1[3-9]开头的11位数字) + +### 获取员工详情 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | GET | +| **接口路径** | `/api/users/{id}` | +| **所属文件** | `SysUserHandler.java` | + +**成功响应** (200 OK): + +```json +{ + "id": 1, + "username": "admin", + "nickname": "超级管理员", + "email": "admin@novalon.com", + "phone": "13800138000", + "avatar": null, + "status": 1, + "roles": [1], + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" +} +``` + +### 更新员工信息 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | PUT | +| **接口路径** | `/api/users/{id}` | +| **所属文件** | `SysUserHandler.java` | + +**请求体**: + +```json +{ + "email": "newemail@novalon.com", + "roleId": 2, + "status": 1 +} +``` + +### 逻辑删除员工 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | POST | +| **接口路径** | `/api/users/{id}/action/logical-delete` | +| **所属文件** | `SysUserHandler.java` | + +### 修改密码 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | POST | +| **接口路径** | `/api/users/{id}/action/change-password` | +| **所属文件** | `SysUserHandler.java` | + +**请求体**: + +```json +{ + "oldPassword": "Old@123", + "newPassword": "New@456" +} +``` + +### 为用户分配角色 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | POST | +| **接口路径** | `/api/users/{id}/roles` | +| **所属文件** | `SysUserHandler.java` | + +**请求体**: + +```json +{ + "roleIds": ["2", "3"] +} +``` + +### 获取用户的角色 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | GET | +| **接口路径** | `/api/users/{id}/roles` | +| **所属文件** | `SysUserHandler.java` | + +--- + +## 角色管理接口(复用) + +### 获取所有角色 + +| 属性 | 值 | +|------|-----| +| **HTTP方法** | GET | +| **接口路径** | `/api/roles` | +| **所属文件** | `SysRoleHandler.java` | + +**成功响应** (200 OK): + +```json +[ + { + "id": 1, + "roleName": "超级管理员", + "roleKey": "admin", + "roleSort": 1, + "status": 1, + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" + }, + { + "id": 2, + "roleName": "测试管理员", + "roleKey": "test_admin", + "roleSort": 2, + "status": 1, + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" + }, + { + "id": 3, + "roleName": "普通用户", + "roleKey": "normal_user", + "roleSort": 3, + "status": 1, + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" + }, + { + "id": 4, + "roleName": "访客", + "roleKey": "guest", + "roleSort": 4, + "status": 1, + "createdAt": "2026-03-13T10:00:00", + "updatedAt": "2026-03-13T10:00:00" + } +] +``` + +--- + +## 数据模型 + +### UserRegisterRequest + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| username | String | 是 | 用户名(3-50位字母数字下划线横线) | +| password | String | 是 | 密码(8-20位含大小写字母和数字) | +| nickname | String | 否 | 昵称 | +| email | String | 是 | 邮箱 | +| phone | String | 是 | 手机号(中国大陆11位) | +| roles | List\ | 否 | 角色ID列表 | + +### EmployeePageResponse + +| 字段 | 类型 | 说明 | +|------|------|------| +| content | List\ | 员工列表 | +| totalPages | int | 总页数 | +| totalElements | long | 总记录数 | +| currentPage | int | 当前页码 | +| pageSize | int | 每页数量 | +| first | boolean | 是否第一页 | +| last | boolean | 是否最后一页 | + +### EmployeeInfo + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | Long | 用户ID | +| username | String | 用户名 | +| nickname | String | 昵称 | +| email | String | 邮箱 | +| phone | String | 手机号 | +| avatar | String | 头像URL | +| status | Integer | 状态:0-禁用, 1-正常 | +| roles | List\ | 角色列表 | +| createdAt | String | 创建时间 | +| updatedAt | String | 更新时间 | + +### RoleInfo + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | Long | 角色ID | +| roleName | String | 角色名称 | +| roleKey | String | 角色标识 | +| roleSort | Integer | 排序号 | diff --git a/gym-manage-api/docs/info.txt b/gym-manage-api/docs/info.txt new file mode 100644 index 0000000..173d77f --- /dev/null +++ b/gym-manage-api/docs/info.txt @@ -0,0 +1,51 @@ +# soybean-admin-mock + +## Docs +- [🦊一分钟,了解 Apifox !](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/doc-2825188.md): + +## API Docs +- Auth [用户名+密码登录](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-100526985.md): +- Auth [获取用户信息](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-120399825.md): +- Auth [刷新token](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-120415125.md): +- Auth [自定义后端错误](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-158477619.md): +- 前端路由 [获取用户路由数据](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-120415303.md): +- 前端路由 [路由是否存在](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-120415373.md): 当用户访问一个路由失败时,有可能是没有该路由的权限,或者没有该路由,所以需要判断路由是否存在 +- 前端路由 [获取固定的路由数据(不需要权限)](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-158516240.md): +- 前端路由 [获取react用户路由](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-273820808.md): +- 调试 [debug](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-125438392.md): +- 调试 [debug post](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-134021864.md): +- 系统管理 [系统管理 - 获取角色列表](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-145344387.md): +- 系统管理 [系统管理 - 获取用户列表](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-149754769.md): +- 系统管理 [系统管理 - 获取用户列表(废弃)](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-145387463.md): +- 系统管理 [获取所有角色](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-145409928.md): +- 系统管理 [获取菜单列表](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-145421249.md): +- 系统管理 [系统管理 - 获取菜单列表](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-157945109.md): +- 系统管理 [获取所有页面组件](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-157988353.md): +- 系统管理 [获取菜单树](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-158414289.md): +- 项目配置 [获取用户配置](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-229492806.md): +- 项目配置 [保存用户配置](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-229493074.md): +- 用户 [postApiUsersLogin](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003433.md): 用户登录 +- 用户 [postApiUsersRegister](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003434.md): 用户注册 +- 用户 [getApiUsersProfile](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003435.md): 获取用户个人信息 +- 用户 [putApiUsersPassword](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003436.md): 更新用户密码 +- 用户 [postApiUsersLogout](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003437.md): 用户登出 +- 角色 [getApiRoles](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003438.md): 获取所有角色 +- 角色 [postApiRoles](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003439.md): 创建角色 +- 角色 [getApiRolesById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003440.md): 获取角色详情 +- 角色 [putApiRolesById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003441.md): 更新角色 +- 角色 [deleteApiRolesById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003442.md): 删除角色 +- 权限 [getApiPermissions](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003443.md): 获取所有权限 +- 权限 [postApiPermissions](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003444.md): 创建权限 +- 权限 [getApiPermissionsById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003445.md): 获取权限详情 +- 权限 [putApiPermissionsById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003446.md): 更新权限 +- 权限 [deleteApiPermissionsById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003447.md): 删除权限 +- 菜单 [getApiMenusUser](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003448.md): 获取用户菜单 +- 菜单 [getApiMenus](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003449.md): 获取所有菜单 +- 菜单 [postApiMenus](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003450.md): 创建菜单 +- 菜单 [getApiMenusById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003451.md): 获取菜单详情 +- 菜单 [putApiMenusById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003452.md): 更新菜单 +- 菜单 [deleteApiMenusById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003453.md): 删除菜单 +- 文件 [postApiFilesUpload](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003454.md): 上传文件 +- 文件 [getApiFilesById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003455.md): 获取文件信息 +- 文件 [deleteApiFilesById](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003456.md): 删除文件 +- 文件 [getApiFilesUser](https://s.apifox.cn/35c8727a-d3ab-47e9-8863-ef8e37df6887/api-281003457.md): 获取用户文件列表 diff --git a/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberDailySignIn.java b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberDailySignIn.java new file mode 100644 index 0000000..2bd7ad1 --- /dev/null +++ b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberDailySignIn.java @@ -0,0 +1,44 @@ +package cn.novalon.gym.manage.datacount.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 会员每日签到明细 + * + * @author system + * @date 2026-06-17 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberDailySignIn { + + /** + * 会员ID + */ + private Long memberId; + + /** + * 签到时间 + */ + private String signInTime; + + /** + * 签到状态:SUCCESS / FAILED + */ + private String signInStatus; + + /** + * 签到方式:QR_CODE / MANUAL / FACE + */ + private String signInType; + + /** + * 失败原因(仅失败时) + */ + private String failReason; +} diff --git a/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberMonthlySignIn.java b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberMonthlySignIn.java new file mode 100644 index 0000000..bd6c596 --- /dev/null +++ b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberMonthlySignIn.java @@ -0,0 +1,49 @@ +package cn.novalon.gym.manage.datacount.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 会员月度签到统计 + * + * @author system + * @date 2026-06-17 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberMonthlySignIn { + + /** + * 会员ID + */ + private Long memberId; + + /** + * 会员姓名 + */ + private String memberName; + + /** + * 统计月份(格式:yyyy-MM) + */ + private String month; + + /** + * 当月签到总次数 + */ + private Long totalSignIns; + + /** + * 当月成功签到次数 + */ + private Long successSignIns; + + /** + * 当月失败签到次数 + */ + private Long failedSignIns; +} diff --git a/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberSignInDetail.java b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberSignInDetail.java new file mode 100644 index 0000000..5d2535b --- /dev/null +++ b/gym-manage-api/gym-dataCount/src/main/java/cn/novalon/gym/manage/datacount/domain/MemberSignInDetail.java @@ -0,0 +1,54 @@ +package cn.novalon.gym.manage.datacount.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 会员签到明细 + * + * @author system + * @date 2026-06-16 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MemberSignInDetail { + + /** + * 会员ID + */ + private Long memberId; + + /** + * 会员姓名 + */ + private String memberName; + + /** + * 会员手机号 + */ + private String memberPhone; + + /** + * 签到总次数 + */ + private Long totalSignIns; + + /** + * 成功签到次数 + */ + private Long successSignIns; + + /** + * 失败签到次数 + */ + private Long failedSignIns; + + /** + * 最近签到时间 + */ + private String lastSignInTime; +} diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseTimeoutScheduler.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseTimeoutScheduler.java new file mode 100644 index 0000000..ad8a191 --- /dev/null +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseTimeoutScheduler.java @@ -0,0 +1,67 @@ +package cn.novalon.gym.manage.groupcourse.scheduler; + +import cn.novalon.gym.manage.groupcourse.service.IGroupCourseService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 团课超时与自动结课定时任务 + * + * 功能: + * 1. 检查已超时未开课的课程,标记为超时并返还用户权益 + * 2. 检查已超时未结课的课程,自动结课并发送教练警告 + * + * @author 张翔 + * @date 2026-06-23 + */ +@Component +public class GroupCourseTimeoutScheduler { + + private static final Logger logger = LoggerFactory.getLogger(GroupCourseTimeoutScheduler.class); + + private final IGroupCourseService groupCourseService; + + public GroupCourseTimeoutScheduler(IGroupCourseService groupCourseService) { + this.groupCourseService = groupCourseService; + } + + /** + * 每分钟检查一次超时未开课的课程 + * 超时条件:status='0' 且 actual_start_time IS NULL 且 start_time + 10分钟 < 当前时间 + */ + @Scheduled(fixedRate = 60000) + public void checkAndHandleTimeoutCourses() { + logger.debug("定时任务开始检查超时未开课的团课"); + + groupCourseService.processTimeoutCourses() + .subscribe( + count -> { + if (count > 0) { + logger.warn("定时任务完成,处理了 {} 个超时团课,已返还用户权益", count); + } + }, + error -> logger.error("超时团课处理定时任务执行失败:{}", error.getMessage(), error) + ); + } + + /** + * 每分钟检查一次需要自动结课的课程 + * 自动结课条件:status='3'(进行中) 且 actual_end_time IS NULL 且 end_time + 10分钟 < 当前时间 + */ + @Scheduled(fixedRate = 60000) + public void checkAndHandleAutoEndCourses() { + logger.debug("定时任务开始检查需要自动结课的团课"); + + groupCourseService.processAutoEndCourses() + .subscribe( + count -> { + if (count > 0) { + logger.warn("定时任务完成,自动结课 {} 个团课,请通知相关教练", count); + } + }, + error -> logger.error("自动结课定时任务执行失败:{}", error.getMessage(), error) + ); + } +} diff --git a/gym-manage-api/gym-manage-cuit/.mvn/wrapper/maven-wrapper.properties b/gym-manage-api/gym-manage-cuit/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..216df05 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip diff --git a/gym-manage-api/gym-manage-cuit/pom.xml b/gym-manage-api/gym-manage-cuit/pom.xml new file mode 100644 index 0000000..2e87ffa --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/pom.xml @@ -0,0 +1,114 @@ + + + 4.0.0 + + cn.novalon.gym.manage + gym-manage-api + 1.0.0 + ../pom.xml + + cn.novalon.gym.manage + gym-manage-cuit + 1.0.0 + gym-manage-cuit + Auth Management Module + + + + + + + + + + + + + + + 21 + + + + cn.novalon.gym.manage + manage-common + ${project.version} + + + cn.novalon.gym.manage + manage-sys + ${project.version} + + + cn.novalon.gym.manage + manage-db + ${project.version} + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-data-r2dbc + + + org.springframework.boot + spring-boot-starter-validation + + + org.springdoc + springdoc-openapi-starter-webflux-ui + + + org.springframework.boot + spring-boot-starter-test + test + + + io.swagger.core.v3 + swagger-annotations-jakarta + 2.2.43 + compile + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.boot + spring-boot-starter-security + + + + io.jsonwebtoken + jjwt-api + + + io.jsonwebtoken + jjwt-impl + runtime + + + io.jsonwebtoken + jjwt-jackson + runtime + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/converter/UserConverter.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/converter/UserConverter.java new file mode 100644 index 0000000..ba9c591 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/converter/UserConverter.java @@ -0,0 +1,63 @@ +package cn.novalon.gym.manage.auth.converter; + +import cn.novalon.gym.manage.auth.domain.User; +import cn.novalon.gym.manage.auth.dto.UserInfo; +import cn.novalon.gym.manage.auth.entity.UserEntity; + +public class UserConverter { + + public static User toDomain(UserEntity entity) { + if (entity == null) { + return null; + } + User user = new User(); + user.setId(entity.getId()); + user.setUsername(entity.getUsername()); + user.setEmail(entity.getEmail()); + user.setPhone(entity.getPhone()); + user.setNickname(entity.getNickname()); + user.setStatus(entity.getStatus()); + user.setRoleId(entity.getRoleId()); + user.setCreateBy(entity.getCreateBy()); + user.setUpdateBy(entity.getUpdateBy()); + user.setCreatedAt(entity.getCreatedAt()); + user.setUpdatedAt(entity.getUpdatedAt()); + user.setDeletedAt(entity.getDeletedAt()); + return user; + } + + public static UserEntity toEntity(User domain) { + if (domain == null) { + return null; + } + UserEntity entity = new UserEntity(); + entity.setId(domain.getId()); + entity.setUsername(domain.getUsername()); + entity.setEmail(domain.getEmail()); + entity.setPhone(domain.getPhone()); + entity.setNickname(domain.getNickname()); + entity.setStatus(domain.getStatus()); + entity.setRoleId(domain.getRoleId()); + entity.setCreateBy(domain.getCreateBy()); + entity.setUpdateBy(domain.getUpdateBy()); + entity.setCreatedAt(domain.getCreatedAt()); + entity.setUpdatedAt(domain.getUpdatedAt()); + entity.setDeletedAt(domain.getDeletedAt()); + return entity; + } + + public static UserInfo toUserInfo(User user) { + if (user == null) { + return null; + } + UserInfo userInfo = new UserInfo(); + userInfo.setId(user.getId()); + userInfo.setUsername(user.getUsername()); + userInfo.setEmail(user.getEmail()); + userInfo.setPhone(user.getPhone()); + userInfo.setNickname(user.getNickname()); + userInfo.setStatus(user.getStatus()); + userInfo.setRoleId(user.getRoleId()); + return userInfo; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dao/UserDao.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dao/UserDao.java new file mode 100644 index 0000000..aacdad4 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dao/UserDao.java @@ -0,0 +1,17 @@ +package cn.novalon.gym.manage.auth.dao; + +import cn.novalon.gym.manage.auth.entity.UserEntity; +import org.springframework.data.r2dbc.repository.Query; +import org.springframework.data.r2dbc.repository.R2dbcRepository; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Mono; + +@Repository +public interface UserDao extends R2dbcRepository { + + @Query("SELECT * FROM sys_user WHERE username = :username AND deleted_at IS NULL") + Mono findByUsername(String username); + + @Query("SELECT * FROM sys_user WHERE id = :id AND deleted_at IS NULL") + Mono findByIdAndDeletedAtIsNull(Long id); +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/domain/User.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/domain/User.java new file mode 100644 index 0000000..6a65add --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/domain/User.java @@ -0,0 +1,73 @@ +package cn.novalon.gym.manage.auth.domain; + +import cn.novalon.gym.manage.sys.core.domain.BaseDomain; +import io.swagger.v3.oas.annotations.media.Schema; + +public class User extends BaseDomain { + + @Schema(description = "用户名", example = "admin") + private String username; + + @Schema(description = "邮箱", example = "admin@example.com") + private String email; + + @Schema(description = "手机号", example = "13800138000") + private String phone; + + @Schema(description = "昵称", example = "超级管理员") + private String nickname; + + @Schema(description = "状态:0-禁用,1-正常", example = "1") + private Integer status; + + @Schema(description = "角色ID", example = "1") + private Long roleId; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getRoleId() { + return roleId; + } + + public void setRoleId(Long roleId) { + this.roleId = roleId; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginRequest.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginRequest.java new file mode 100644 index 0000000..9cd4f20 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginRequest.java @@ -0,0 +1,32 @@ +package cn.novalon.gym.manage.auth.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; + +@Schema(description = "用户登录请求") +public class LoginRequest { + + @NotBlank(message = "用户名不能为空") + @Schema(description = "用户名", example = "admin", required = true) + private String username; + + @NotBlank(message = "密码不能为空") + @Schema(description = "密码", example = "Test@123", required = true) + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginResponse.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginResponse.java new file mode 100644 index 0000000..79c7f37 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/LoginResponse.java @@ -0,0 +1,62 @@ +package cn.novalon.gym.manage.auth.dto; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "用户登录响应") +public class LoginResponse { + + @Schema(description = "访问令牌") + private String accessToken; + + @Schema(description = "刷新令牌") + private String refreshToken; + + @Schema(description = "令牌类型", example = "Bearer") + private String tokenType; + + @Schema(description = "过期时间(秒)", example = "7200") + private Long expiresIn; + + @Schema(description = "用户信息") + private UserInfo userInfo; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getTokenType() { + return tokenType; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + public Long getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(Long expiresIn) { + this.expiresIn = expiresIn; + } + + public UserInfo getUserInfo() { + return userInfo; + } + + public void setUserInfo(UserInfo userInfo) { + this.userInfo = userInfo; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/UserInfo.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/UserInfo.java new file mode 100644 index 0000000..8b23678 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/dto/UserInfo.java @@ -0,0 +1,84 @@ +package cn.novalon.gym.manage.auth.dto; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "用户信息") +public class UserInfo { + + @Schema(description = "用户ID", example = "1") + private Long id; + + @Schema(description = "用户名", example = "admin") + private String username; + + @Schema(description = "邮箱", example = "admin@example.com") + private String email; + + @Schema(description = "手机号", example = "13800138000") + private String phone; + + @Schema(description = "昵称", example = "超级管理员") + private String nickname; + + @Schema(description = "状态:0-禁用,1-正常", example = "1") + private Integer status; + + @Schema(description = "角色ID", example = "1") + private Long roleId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getRoleId() { + return roleId; + } + + public void setRoleId(Long roleId) { + this.roleId = roleId; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/entity/UserEntity.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/entity/UserEntity.java new file mode 100644 index 0000000..3cf6857 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/entity/UserEntity.java @@ -0,0 +1,86 @@ +package cn.novalon.gym.manage.auth.entity; + +import cn.novalon.gym.manage.db.entity.BaseEntity; +import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.Table; + +@Table("sys_user") +public class UserEntity extends BaseEntity { + + @Column("username") + private String username; + + @Column("password") + private String password; + + @Column("email") + private String email; + + @Column("phone") + private String phone; + + @Column("nickname") + private String nickname; + + @Column("status") + private Integer status; + + @Column("role_id") + private Long roleId; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long getRoleId() { + return roleId; + } + + public void setRoleId(Long roleId) { + this.roleId = roleId; + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/handler/AuthHandler.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/handler/AuthHandler.java new file mode 100644 index 0000000..66db16f --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/handler/AuthHandler.java @@ -0,0 +1,83 @@ +package cn.novalon.gym.manage.auth.handler; + +import cn.novalon.gym.manage.auth.dto.LoginRequest; +import cn.novalon.gym.manage.auth.dto.LoginResponse; +import cn.novalon.gym.manage.auth.dto.UserInfo; +import cn.novalon.gym.manage.auth.service.IAuthService; +import cn.novalon.gym.manage.auth.util.ResponseCode; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Validator; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; + +@Component +@Tag(name = "认证管理", description = "用户认证相关操作") +public class AuthHandler { + + private final IAuthService authService; + private final Validator validator; + + public AuthHandler(IAuthService authService, Validator validator) { + this.authService = authService; + this.validator = validator; + } + + @Operation(summary = "用户名+密码登录", description = "使用用户名和密码进行登录认证") + public Mono login(ServerRequest request) { + return request.bodyToMono(LoginRequest.class) + .flatMap(loginRequest -> { + return authService.login(loginRequest) + .flatMap(response -> { + Map result = new HashMap<>(); + result.put("code", ResponseCode.SUCCESS); + result.put("message", "登录成功"); + result.put("data", response); + return ServerResponse.ok().bodyValue(result); + }) + .onErrorResume(error -> { + Map errorResponse = new HashMap<>(); + errorResponse.put("code", ResponseCode.BAD_REQUEST); + errorResponse.put("message", error.getMessage()); + return ServerResponse.badRequest().bodyValue(errorResponse); + }); + }) + .onErrorResume(error -> { + Map errorResponse = new HashMap<>(); + errorResponse.put("code", ResponseCode.BAD_REQUEST); + errorResponse.put("message", "请求参数错误: " + error.getMessage()); + return ServerResponse.badRequest().bodyValue(errorResponse); + }); + } + + @Operation(summary = "获取用户信息", description = "根据用户ID获取用户详细信息") + public Mono getUserInfo(ServerRequest request) { + try { + Long userId = Long.valueOf(request.pathVariable("id")); + return authService.getUserInfo(userId) + .flatMap(userInfo -> { + Map result = new HashMap<>(); + result.put("code", ResponseCode.SUCCESS); + result.put("message", "获取用户信息成功"); + result.put("data", userInfo); + return ServerResponse.ok().bodyValue(result); + }) + .onErrorResume(error -> { + Map errorResponse = new HashMap<>(); + errorResponse.put("code", ResponseCode.BAD_REQUEST); + errorResponse.put("message", error.getMessage()); + return ServerResponse.badRequest().bodyValue(errorResponse); + }); + } catch (NumberFormatException e) { + Map errorResponse = new HashMap<>(); + errorResponse.put("code", ResponseCode.BAD_REQUEST); + errorResponse.put("message", "无效的用户ID"); + return ServerResponse.badRequest().bodyValue(errorResponse); + } + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/AuthRepository.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/AuthRepository.java new file mode 100644 index 0000000..eac57ea --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/AuthRepository.java @@ -0,0 +1,14 @@ +package cn.novalon.gym.manage.auth.repository; + +import cn.novalon.gym.manage.auth.domain.User; +import cn.novalon.gym.manage.auth.dto.LoginRequest; +import reactor.core.publisher.Mono; + +public interface AuthRepository { + + Mono findByUsername(String username); + + Mono findById(Long id); + + Mono validateLogin(LoginRequest request); +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/impl/AuthRepositoryImpl.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/impl/AuthRepositoryImpl.java new file mode 100644 index 0000000..6db1544 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/repository/impl/AuthRepositoryImpl.java @@ -0,0 +1,50 @@ +package cn.novalon.gym.manage.auth.repository.impl; + +import cn.novalon.gym.manage.auth.converter.UserConverter; +import cn.novalon.gym.manage.auth.dao.UserDao; +import cn.novalon.gym.manage.auth.domain.User; +import cn.novalon.gym.manage.auth.dto.LoginRequest; +import cn.novalon.gym.manage.auth.repository.AuthRepository; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +@Component +public class AuthRepositoryImpl implements AuthRepository { + + private final UserDao userDao; + private final PasswordEncoder passwordEncoder; + + public AuthRepositoryImpl(UserDao userDao, PasswordEncoder passwordEncoder) { + this.userDao = userDao; + this.passwordEncoder = passwordEncoder; + } + + @Override + public Mono findByUsername(String username) { + return userDao.findByUsername(username) + .map(UserConverter::toDomain); + } + + @Override + public Mono findById(Long id) { + return userDao.findByIdAndDeletedAtIsNull(id) + .map(UserConverter::toDomain); + } + + @Override + public Mono validateLogin(LoginRequest request) { + return userDao.findByUsername(request.getUsername()) + .flatMap(userEntity -> { + if (userEntity.getStatus() == 0) { + return Mono.error(new RuntimeException("用户已被禁用")); + } + if (passwordEncoder.matches(request.getPassword(), userEntity.getPassword())) { + return Mono.just(UserConverter.toDomain(userEntity)); + } else { + return Mono.error(new RuntimeException("用户名或密码错误")); + } + }) + .switchIfEmpty(Mono.error(new RuntimeException("用户名或密码错误"))); + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/IAuthService.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/IAuthService.java new file mode 100644 index 0000000..29f5bca --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/IAuthService.java @@ -0,0 +1,13 @@ +package cn.novalon.gym.manage.auth.service; + +import cn.novalon.gym.manage.auth.dto.LoginRequest; +import cn.novalon.gym.manage.auth.dto.LoginResponse; +import cn.novalon.gym.manage.auth.dto.UserInfo; +import reactor.core.publisher.Mono; + +public interface IAuthService { + + Mono login(LoginRequest request); + + Mono getUserInfo(Long userId); +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/impl/AuthServiceImpl.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000..01add46 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/service/impl/AuthServiceImpl.java @@ -0,0 +1,48 @@ +package cn.novalon.gym.manage.auth.service.impl; + +import cn.novalon.gym.manage.auth.converter.UserConverter; +import cn.novalon.gym.manage.auth.dto.LoginRequest; +import cn.novalon.gym.manage.auth.dto.LoginResponse; +import cn.novalon.gym.manage.auth.dto.UserInfo; +import cn.novalon.gym.manage.auth.repository.AuthRepository; +import cn.novalon.gym.manage.auth.service.IAuthService; +import cn.novalon.gym.manage.auth.util.JwtUtil; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class AuthServiceImpl implements IAuthService { + + private final AuthRepository authRepository; + private final JwtUtil jwtUtil; + + public AuthServiceImpl(AuthRepository authRepository, JwtUtil jwtUtil) { + this.authRepository = authRepository; + this.jwtUtil = jwtUtil; + } + + @Override + public Mono login(LoginRequest request) { + return authRepository.validateLogin(request) + .flatMap(user -> { + String accessToken = jwtUtil.generateToken(user.getId(), user.getUsername()); + String refreshToken = jwtUtil.generateRefreshToken(user.getId(), user.getUsername()); + + LoginResponse response = new LoginResponse(); + response.setAccessToken(accessToken); + response.setRefreshToken(refreshToken); + response.setTokenType("Bearer"); + response.setExpiresIn(7200L); + response.setUserInfo(UserConverter.toUserInfo(user)); + + return Mono.just(response); + }); + } + + @Override + public Mono getUserInfo(Long userId) { + return authRepository.findById(userId) + .map(UserConverter::toUserInfo) + .switchIfEmpty(Mono.error(new RuntimeException("用户不存在"))); + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/JwtUtil.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/JwtUtil.java new file mode 100644 index 0000000..79e9a28 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/JwtUtil.java @@ -0,0 +1,80 @@ +package cn.novalon.gym.manage.auth.util; + +import cn.novalon.gym.manage.common.config.JwtProperties; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Component +public class JwtUtil { + + private final JwtProperties jwtProperties; + + public JwtUtil(JwtProperties jwtProperties) { + this.jwtProperties = jwtProperties; + } + + private SecretKey getSigningKey() { + return Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8)); + } + + public String generateToken(Long userId, String username) { + Map claims = new HashMap<>(); + claims.put("userId", userId); + claims.put("username", username); + + return Jwts.builder() + .setClaims(claims) + .setSubject(username) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration())) + .signWith(getSigningKey()) + .compact(); + } + + public String generateRefreshToken(Long userId, String username) { + Map claims = new HashMap<>(); + claims.put("userId", userId); + claims.put("username", username); + + return Jwts.builder() + .setClaims(claims) + .setSubject(username + "_refresh") + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 7)) + .signWith(getSigningKey()) + .compact(); + } + + public Claims parseToken(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + public Long getUserIdFromToken(String token) { + return parseToken(token).get("userId", Long.class); + } + + public String getUsernameFromToken(String token) { + return parseToken(token).getSubject(); + } + + public boolean validateToken(String token) { + try { + parseToken(token); + return true; + } catch (Exception e) { + return false; + } + } +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/ResponseCode.java b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/ResponseCode.java new file mode 100644 index 0000000..74ace56 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/java/cn/novalon/gym/manage/auth/util/ResponseCode.java @@ -0,0 +1,34 @@ +package cn.novalon.gym.manage.auth.util; + +/** + * HTTP 响应状态码常量类 + * + * @author 张翔 + * @date 2026-06-16 + */ +public class ResponseCode { + + private ResponseCode() { + } + + /** 成功 */ + public static final int SUCCESS = 200; + + /** 客户端错误:请求参数有误 */ + public static final int BAD_REQUEST = 400; + + /** 客户端错误:未授权 */ + public static final int UNAUTHORIZED = 401; + + /** 客户端错误:禁止访问 */ + public static final int FORBIDDEN = 403; + + /** 客户端错误:资源未找到 */ + public static final int NOT_FOUND = 404; + + /** 客户端错误:冲突(如重复数据) */ + public static final int CONFLICT = 409; + + /** 服务器错误:内部服务器错误 */ + public static final int INTERNAL_SERVER_ERROR = 500; +} \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/main/resources/application.yaml b/gym-manage-api/gym-manage-cuit/src/main/resources/application.yaml new file mode 100644 index 0000000..53f6d59 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/main/resources/application.yaml @@ -0,0 +1,16 @@ +# JWT Configuration +jwt: + secret: mySecretKeyForJwtTokenGenerationThatIsLongEnoughForHS256Algorithm + expiration: 7200 # 2 hours in seconds + refresh-expiration: 604800 # 7 days in seconds + +# Server Configuration +server: + port: 8080 + +# Spring Configuration +spring: + application: + name: gym-manage-cuit + profiles: + active: dev \ No newline at end of file diff --git a/gym-manage-api/gym-manage-cuit/src/test/java/cn/novalon/gym/manage/cuit/gymmanagecuit/GymManageCuitApplicationTests.java b/gym-manage-api/gym-manage-cuit/src/test/java/cn/novalon/gym/manage/cuit/gymmanagecuit/GymManageCuitApplicationTests.java new file mode 100644 index 0000000..a3da713 --- /dev/null +++ b/gym-manage-api/gym-manage-cuit/src/test/java/cn/novalon/gym/manage/cuit/gymmanagecuit/GymManageCuitApplicationTests.java @@ -0,0 +1,15 @@ +package cn.novalon.gym.manage.cuit.gymmanagecuit; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@Disabled("模块无独立SpringBootApplication,需通过manage-app运行集成测试") +class GymManageCuitApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/gym-manage-coach/.gitignore b/gym-manage-coach/.gitignore new file mode 100644 index 0000000..2370852 --- /dev/null +++ b/gym-manage-coach/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +unpackage/ +.hbuilderx/ +.DS_Store diff --git a/gym-manage-coach/App.vue b/gym-manage-coach/App.vue new file mode 100644 index 0000000..0fb6019 --- /dev/null +++ b/gym-manage-coach/App.vue @@ -0,0 +1,368 @@ + + + diff --git a/gym-manage-coach/api/auth.js b/gym-manage-coach/api/auth.js new file mode 100644 index 0000000..1c8db7d --- /dev/null +++ b/gym-manage-coach/api/auth.js @@ -0,0 +1,30 @@ +/** + * 认证API + * 对应后端: /api/auth/* + */ + +import request from '@/utils/request.js' + +/** + * 用户名+密码登录(教练端) + * POST /api/auth/login + */ +export function login(params) { + return request.post('/api/auth/login', { ...params, target: 'coach' }) +} + +/** + * 获取用户信息 + * GET /api/auth/users/{id} + */ +export function getUserInfo(id) { + return request.get(`/api/auth/users/${id}`) +} + +/** + * 获取用户角色 + * GET /api/users/{id}/roles + */ +export function getUserRoles(id) { + return request.get(`/api/users/${id}/roles`) +} diff --git a/gym-manage-coach/api/checkin.js b/gym-manage-coach/api/checkin.js new file mode 100644 index 0000000..27d6eba --- /dev/null +++ b/gym-manage-coach/api/checkin.js @@ -0,0 +1,38 @@ +/** + * 签到管理API + * 对应后端: /api/checkIn/*, /api/datacount/* + */ + +import request from '@/utils/request.js' + +/** + * 获取签到记录列表 + * GET /api/checkIn/records + */ +export function getSignInRecords(params = {}) { + return request.get('/api/checkIn/records', params) +} + +/** + * 获取签到统计 + * GET /api/checkIn/statistics + */ +export function getSignInStatistics(params = {}) { + return request.get('/api/checkIn/statistics', params) +} + +/** + * 签到(会员扫码签到时调用) + * POST /api/checkIn + */ +export function doCheckIn(data) { + return request.post('/api/checkIn', data) +} + +/** + * 获取签到明细(会员维度) + * GET /api/datacount/signin/details + */ +export function getSignInDetails(params = {}) { + return request.get('/api/datacount/signin/details', params) +} diff --git a/gym-manage-coach/api/course.js b/gym-manage-coach/api/course.js new file mode 100644 index 0000000..bdc28a9 --- /dev/null +++ b/gym-manage-coach/api/course.js @@ -0,0 +1,89 @@ +/** + * 团课管理API + * 对应后端: /api/groupCourse/* 和 /api/coach/courses + */ + +import request from '@/utils/request.js' + +/** + * 获取当前教练自己教授的团课列表(教练专属) + * GET /api/coach/courses + * JWT令牌中自动携带教练身份,后端返回该教练的所有团课 + */ +export function getCoachCourses() { + return request.get('/api/coach/courses') +} + +/** + * 获取所有团课列表 + * GET /api/groupCourse/list + */ +export function getCourseList(includeDeleted = false) { + return request.get('/api/groupCourse/list', { includeDeleted }) +} + +/** + * 分页获取团课 + * POST /api/groupCourse/page + */ +export function getCoursePage(params, includeDeleted = false) { + return request.post('/api/groupCourse/page', params, { params: { includeDeleted } }) +} + +/** + * 多条件搜索团课 + * POST /api/groupCourse/search + */ +export function searchCourses(params) { + return request.post('/api/groupCourse/search', params) +} + +/** + * 根据ID获取团课详情 + * GET /api/groupCourse/{id} + */ +export function getCourseById(id) { + return request.get(`/api/groupCourse/${id}`) +} + +/** + * 根据ID获取团课完整信息(含类型和标签) + * GET /api/groupCourse/{id}/detail + */ +export function getCourseDetail(id) { + return request.get(`/api/groupCourse/${id}/detail`) +} + +/** + * 获取团课类型列表 + * GET /api/groupCourse/types + */ +export function getCourseTypes() { + return request.get('/api/groupCourse/types') +} + +/** + * 查询课程预约记录(教练查看自己团课的预约会员) + * GET /api/groupCourse/bookings/course/{courseId} + */ +export function getBookingsByCourseId(courseId) { + return request.get(`/api/groupCourse/bookings/course/${courseId}`) +} + +/** + * 教练开课 + * POST /api/groupCourse/{id}/start + * body: { actualStartTime: 'yyyy-MM-ddTHH:mm:ss' } + */ +export function startCourse(id, actualStartTime) { + return request.post(`/api/groupCourse/${id}/start`, { actualStartTime }) +} + +/** + * 教练结课 + * POST /api/groupCourse/{id}/end + * body: { actualEndTime: 'yyyy-MM-ddTHH:mm:ss' } + */ +export function endCourse(id, actualEndTime) { + return request.post(`/api/groupCourse/${id}/end`, { actualEndTime }) +} diff --git a/gym-manage-coach/index.html b/gym-manage-coach/index.html new file mode 100644 index 0000000..e2a7744 --- /dev/null +++ b/gym-manage-coach/index.html @@ -0,0 +1,20 @@ + + + + + + GymManage 教练端 + + + + +
+ + + diff --git a/gym-manage-coach/main.js b/gym-manage-coach/main.js new file mode 100644 index 0000000..20ad8f1 --- /dev/null +++ b/gym-manage-coach/main.js @@ -0,0 +1,22 @@ +import App from './App' + +// #ifndef VUE3 +import Vue from 'vue' +import './uni.promisify.adaptor' +Vue.config.productionTip = false +App.mpType = 'app' +const app = new Vue({ + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + return { + app + } +} +// #endif diff --git a/gym-manage-coach/manifest.json b/gym-manage-coach/manifest.json new file mode 100644 index 0000000..7adc9ea --- /dev/null +++ b/gym-manage-coach/manifest.json @@ -0,0 +1,72 @@ +{ + "name" : "gym-manage-coach", + "appid" : "", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "3" +} diff --git a/gym-manage-coach/pages.json b/gym-manage-coach/pages.json new file mode 100644 index 0000000..8e525bf --- /dev/null +++ b/gym-manage-coach/pages.json @@ -0,0 +1,45 @@ +{ + "pages": [ + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "GymManage 教练端", + "navigationStyle": "custom" + } + }, + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "教练工作台", + "navigationBarBackgroundColor": "#4f7cff", + "navigationBarTextStyle": "white" + } + }, + { + "path": "pages/course/list", + "style": { + "navigationBarTitleText": "我的团课", + "navigationBarBackgroundColor": "#4f7cff", + "navigationBarTextStyle": "white" + } + }, + { + "path": "pages/course/detail", + "style": { + "navigationBarTitleText": "团课详情", + "navigationBarBackgroundColor": "#4f7cff", + "navigationBarTextStyle": "white" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "GymManage 教练端", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#f6f8fc" + }, + "easycom": { + "autoscan": true, + "custom": {} + } +} diff --git a/gym-manage-coach/pages/course/detail.vue b/gym-manage-coach/pages/course/detail.vue new file mode 100644 index 0000000..b43aab5 --- /dev/null +++ b/gym-manage-coach/pages/course/detail.vue @@ -0,0 +1,824 @@ + + + + + diff --git a/gym-manage-coach/pages/course/list.vue b/gym-manage-coach/pages/course/list.vue new file mode 100644 index 0000000..27fd265 --- /dev/null +++ b/gym-manage-coach/pages/course/list.vue @@ -0,0 +1,377 @@ + + + + + diff --git a/gym-manage-coach/pages/index/index.vue b/gym-manage-coach/pages/index/index.vue new file mode 100644 index 0000000..3400aec --- /dev/null +++ b/gym-manage-coach/pages/index/index.vue @@ -0,0 +1,449 @@ + + + + + diff --git a/gym-manage-coach/pages/login/login.vue b/gym-manage-coach/pages/login/login.vue new file mode 100644 index 0000000..3656398 --- /dev/null +++ b/gym-manage-coach/pages/login/login.vue @@ -0,0 +1,385 @@ + + + + + diff --git a/gym-manage-coach/static/logo.png b/gym-manage-coach/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a GIT binary patch literal 4023 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 SYs}WS&%*SCNx89m_ { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/gym-manage-coach/uni.scss b/gym-manage-coach/uni.scss new file mode 100644 index 0000000..a32c4be --- /dev/null +++ b/gym-manage-coach/uni.scss @@ -0,0 +1,39 @@ +/** + * uni-app内置样式变量 - 教练端定制 + * 基于 gym-manage-cuit 蓝色系风格 + */ + +/* 行为相关颜色 */ +$uni-color-primary: #4f7cff; +$uni-color-success: #10b981; +$uni-color-warning: #f59e0b; +$uni-color-error: #ef4444; + +/* 文字颜色 */ +$uni-text-color: #1e293b; +$uni-text-color-inverse: #ffffff; +$uni-text-color-grey: #94a3b8; +$uni-text-color-placeholder: #a0aec0; +$uni-text-color-disable: #cbd5e1; + +/* 背景颜色 */ +$uni-bg-color: #ffffff; +$uni-bg-color-grey: #f6f8fc; +$uni-bg-color-hover: #eef3ff; +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); + +/* 边框颜色 */ +$uni-border-color: #e2e8f0; + +/* 尺寸 */ +$uni-font-size-sm: 12px; +$uni-font-size-base: 14px; +$uni-font-size-lg: 16px; + +$uni-img-size-sm: 20px; +$uni-img-size-base: 28px; +$uni-img-size-lg: 40px; + +/* 间距 */ +$uni-spacing-col-base: 16px; +$uni-spacing-row-base: 12px; diff --git a/gym-manage-coach/utils/index.js b/gym-manage-coach/utils/index.js new file mode 100644 index 0000000..ac789a4 --- /dev/null +++ b/gym-manage-coach/utils/index.js @@ -0,0 +1,133 @@ +/** + * 工具函数 + */ + +/** + * 格式化日期时间 + */ +export function formatDateTime(dateStr, showTime = true) { + if (!dateStr) return '--' + const d = new Date(dateStr) + const pad = (n) => String(n).padStart(2, '0') + const date = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` + if (!showTime) return date + return `${date} ${pad(d.getHours())}:${pad(d.getMinutes())}` +} + +/** + * 格式化日期 + */ +export function formatDate(dateStr) { + return formatDateTime(dateStr, false) +} + +/** + * 格式化时间 + */ +export function formatTime(dateStr) { + if (!dateStr) return '--' + const d = new Date(dateStr) + const pad = (n) => String(n).padStart(2, '0') + return `${pad(d.getHours())}:${pad(d.getMinutes())}` +} + +/** + * 格式化时间(短格式:MM/DD HH:mm) + */ +export function formatTimeShort(dateStr) { + if (!dateStr) return '--' + const d = new Date(dateStr) + const pad = (n) => String(n).padStart(2, '0') + return `${d.getMonth() + 1}/${d.getDate()} ${pad(d.getHours())}:${pad(d.getMinutes())}` +} + +/** + * 课程状态(由后端 GET /api/groupCourse/statuses 统一提供,避免前后端各自硬编码) + */ +let _statusMap = null +let _statusClassMap = null + +const DEFAULT_STATUS_MAP = { '0': '正常', '1': '已取消', '2': '已结束', '3': '进行中', '4': '超时' } +const DEFAULT_STATUS_CLASS = { '0': 'green', '1': 'orange', '2': 'gray', '3': 'blue', '4': 'red' } + +/** + * 从后端加载课程状态映射,返回 Promise + */ +export async function loadCourseStatuses() { + try { + const res = await uni.request({ + url: `${getBaseUrl()}/api/groupCourse/statuses`, + method: 'GET' + }) + if (res.statusCode === 200 && res.data?.success && Array.isArray(res.data.data)) { + const map = {} + const cls = {} + res.data.data.forEach(item => { + map[String(item.dbValue)] = item.label + cls[String(item.dbValue)] = item.cssClass + }) + _statusMap = map + _statusClassMap = cls + return true + } + } catch (e) { + console.warn('加载课程状态映射失败,使用默认映射:', e) + } + return false +} + +function getBaseUrl() { + // #ifdef H5 + return '/gym-api' + // #endif + // #ifndef H5 + return 'http://localhost:8084' + // #endif +} + +function getStatusMap() { + return _statusMap || DEFAULT_STATUS_MAP +} + +function getStatusClassMap() { + return _statusClassMap || DEFAULT_STATUS_CLASS +} + +export function getCourseStatusLabel(status, deletedAt) { + if (deletedAt) return '已删除' + return getStatusMap()[String(status)] || '未知' +} + +export function getCourseStatusClass(status, deletedAt) { + if (deletedAt) return 'tag-gray' + return 'tag-' + (getStatusClassMap()[String(status)] || 'gray') +} + +/** + * 判断课程是否有实际时间记录 + */ +export function hasActualTime(course) { + return !!(course && (course.actualStartTime || course.actualEndTime)) +} + +/** + * Toast 提示 + */ +export function showToast(title, icon = 'none') { + uni.showToast({ title, icon, duration: 2000 }) +} + +/** + * 确认弹窗 + */ +export function showConfirm(content, title = '提示') { + return new Promise((resolve) => { + uni.showModal({ + title, + content, + success: (res) => { + resolve(res.confirm) + } + }) + }) +} diff --git a/gym-manage-coach/utils/request.js b/gym-manage-coach/utils/request.js new file mode 100644 index 0000000..a8c09b3 --- /dev/null +++ b/gym-manage-coach/utils/request.js @@ -0,0 +1,122 @@ +/** + * HTTP请求封装 - 基于 uni.request + * 风格参考 gym-manage-cuit 的 request.ts + */ + +// 后端API基础地址 +// H5端: 使用 /gym-api 前缀走vite代理(避免与源码 api/ 目录冲突),代理重写为 /api +// App端: 直接请求后端域名 +// #ifdef H5 +const BASE_URL = '/gym-api' +// #endif +// #ifndef H5 +const BASE_URL = 'http://localhost:8084' +// #endif + +// token存储key +const TOKEN_KEY = 'coach_access_token' +const REFRESH_TOKEN_KEY = 'coach_refresh_token' +const USER_INFO_KEY = 'coach_user_info' + +function getToken() { + return uni.getStorageSync(TOKEN_KEY) || '' +} + +function getRefreshToken() { + return uni.getStorageSync(REFRESH_TOKEN_KEY) || '' +} + +function setToken(token) { + uni.setStorageSync(TOKEN_KEY, token) +} + +function setRefreshToken(token) { + uni.setStorageSync(REFRESH_TOKEN_KEY, token) +} + +function clearAuth() { + uni.removeStorageSync(TOKEN_KEY) + uni.removeStorageSync(REFRESH_TOKEN_KEY) + uni.removeStorageSync(USER_INFO_KEY) +} + +/** + * 发起请求 + */ +function request(options) { + return new Promise((resolve, reject) => { + const token = getToken() + const header = { + 'Content-Type': 'application/json', + ...(options.header || {}) + } + + if (token) { + header['Authorization'] = `Bearer ${token}` + } + + uni.request({ + url: BASE_URL + options.url, + method: options.method || 'GET', + data: options.data || {}, + header: header, + timeout: options.timeout || 15000, + success: (res) => { + const statusCode = res.statusCode + if (statusCode >= 200 && statusCode < 300) { + resolve(res.data) + } else if (statusCode === 401) { + // token过期,清除登录状态 + const isLoginRequest = options.url?.includes('/auth/login') + if (!isLoginRequest) { + clearAuth() + uni.reLaunch({ url: '/pages/login/login' }) + } + reject(res) + } else { + reject(res) + } + }, + fail: (err) => { + uni.showToast({ + title: '网络请求失败', + icon: 'none', + duration: 2000 + }) + reject(err) + } + }) + }) +} + +// 导出便捷方法 +request.get = function(url, params = {}) { + let query = '' + if (Object.keys(params).length > 0) { + const parts = [] + for (const key in params) { + if (params[key] !== undefined && params[key] !== null && params[key] !== '') { + parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) + } + } + if (parts.length > 0) { + query = '?' + parts.join('&') + } + } + return request({ url: url + query, method: 'GET' }) +} + +request.post = function(url, data = {}) { + return request({ url, method: 'POST', data }) +} + +request.put = function(url, data = {}) { + return request({ url, method: 'PUT', data }) +} + +request.delete = function(url, data = {}) { + return request({ url, method: 'DELETE', data }) +} + +export { request, getToken, setToken, setRefreshToken, clearAuth, TOKEN_KEY, USER_INFO_KEY } +export default request diff --git a/gym-manage-coach/vite.config.js b/gym-manage-coach/vite.config.js new file mode 100644 index 0000000..f748efa --- /dev/null +++ b/gym-manage-coach/vite.config.js @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import uni from '@dcloudio/vite-plugin-uni' + +export default defineConfig({ + plugins: [uni()], + server: { + port: 8081, + proxy: { + '/gym-api': { + target: 'http://localhost:8084', + changeOrigin: true, + secure: false, + rewrite: (path) => path.replace(/^\/gym-api/, '') + } + } + } +}) diff --git a/gym-manage-cuit/.gitignore b/gym-manage-cuit/.gitignore new file mode 100644 index 0000000..cd68f14 --- /dev/null +++ b/gym-manage-cuit/.gitignore @@ -0,0 +1,39 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + +.eslintcache + +# Cypress +/cypress/videos/ +/cypress/screenshots/ + +# Vitest +__screenshots__/ + +# Vite +*.timestamp-*-*.mjs diff --git a/gym-manage-cuit/.prettierrc.json b/gym-manage-cuit/.prettierrc.json new file mode 100644 index 0000000..29a2402 --- /dev/null +++ b/gym-manage-cuit/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "singleQuote": true, + "printWidth": 100 +} diff --git a/gym-manage-cuit/.vscode/extensions.json b/gym-manage-cuit/.vscode/extensions.json new file mode 100644 index 0000000..aecab6c --- /dev/null +++ b/gym-manage-cuit/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "esbenp.prettier-vscode" + ] +} diff --git a/gym-manage-cuit/README.md b/gym-manage-cuit/README.md new file mode 100644 index 0000000..30716dd --- /dev/null +++ b/gym-manage-cuit/README.md @@ -0,0 +1,42 @@ +# gym-manage-cuit + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Recommended Browser Setup + +- Chromium-based browsers (Chrome, Edge, Brave, etc.): + - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) + - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters) +- Firefox: + - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) + - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/) + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +pnpm install +``` + +### Compile and Hot-Reload for Development + +```sh +pnpm dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +pnpm build +``` diff --git a/gym-manage-cuit/env.d.ts b/gym-manage-cuit/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/gym-manage-cuit/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/gym-manage-cuit/exmp/index.html b/gym-manage-cuit/exmp/index.html new file mode 100644 index 0000000..f3513be --- /dev/null +++ b/gym-manage-cuit/exmp/index.html @@ -0,0 +1,802 @@ + + + + + + Soybean 风格 · 后台管理示范 + + + + + + + + + + +
+ +
+
+

仪表盘

+

欢迎回来,这是您的数据概览

+
+
+ + + +
+
+ + +
+
+
总用户
+
12,486
+
12.5%
+
+
+
总收入
+
$84,392
+
8.2%
+
+
+
订单量
+
3,211
+
2.1%
+
+
+
转化率
+
24.8%
+
4.3%
+
+
+ + +
+
+
+

周趋势

+ 查看详情 +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+

最近动态

+ 全部 +
+
+
+ +
+
新用户注册
+
15分钟前
+
+
+
+ +
+
订单 #10234 已完成
+
1小时前
+
+
+
+ +
+
系统更新 v2.5.0
+
3小时前
+
+
+
+ +
+
新评论:产品 X
+
5小时前
+
+
+
+
+
+ + +
+
+

最新订单

+ 管理订单 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
订单号客户金额状态日期
#10234张 伟$129.00已完成2026-06-15
#10233李 娜$89.50处理中2026-06-15
#10232王 强$245.00待付款2026-06-14
#10231陈 丽$54.90已完成2026-06-14
+
+ 显示 4 条 / 共 23 条 +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/gym-manage-cuit/index.html b/gym-manage-cuit/index.html new file mode 100644 index 0000000..a99af8d --- /dev/null +++ b/gym-manage-cuit/index.html @@ -0,0 +1,13 @@ + + + + + + + GymManage 后台管理 + + +
+ + + diff --git a/gym-manage-cuit/package.json b/gym-manage-cuit/package.json new file mode 100644 index 0000000..8c833ca --- /dev/null +++ b/gym-manage-cuit/package.json @@ -0,0 +1,36 @@ +{ + "name": "gym-manage-cuit", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build", + "format": "prettier --write --experimental-cli src/" + }, + "dependencies": { + "ali-oss": "^6.23.0", + "axios": "^1.18.0", + "pinia": "^3.0.4", + "vue": "^3.5.32", + "vue-router": "^5.0.4" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.4", + "@types/node": "^24.12.2", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "npm-run-all2": "^8.0.4", + "prettier": "3.8.3", + "typescript": "~6.0.0", + "vite": "^8.0.8", + "vite-plugin-vue-devtools": "^8.1.1", + "vue-tsc": "^3.2.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } +} diff --git a/gym-manage-cuit/pnpm-lock.yaml b/gym-manage-cuit/pnpm-lock.yaml new file mode 100644 index 0000000..976323f --- /dev/null +++ b/gym-manage-cuit/pnpm-lock.yaml @@ -0,0 +1,2844 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + ali-oss: + specifier: ^6.23.0 + version: 6.23.0 + axios: + specifier: ^1.18.0 + version: 1.18.0 + pinia: + specifier: ^3.0.4 + version: 3.0.4(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)) + vue: + specifier: ^3.5.32 + version: 3.5.38(typescript@6.0.3) + vue-router: + specifier: ^5.0.4 + version: 5.1.0(@vue/compiler-sfc@3.5.38)(pinia@3.0.4(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)))(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3)) + devDependencies: + '@tsconfig/node24': + specifier: ^24.0.4 + version: 24.0.4 + '@types/node': + specifier: ^24.12.2 + version: 24.13.2 + '@vitejs/plugin-vue': + specifier: ^6.0.6 + version: 6.0.7(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3)) + '@vue/tsconfig': + specifier: ^0.9.1 + version: 0.9.1(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)) + npm-run-all2: + specifier: ^8.0.4 + version: 8.0.4 + prettier: + specifier: 3.8.3 + version: 3.8.3 + typescript: + specifier: ~6.0.0 + version: 6.0.3 + vite: + specifier: ^8.0.8 + version: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + vite-plugin-vue-devtools: + specifier: ^8.1.1 + version: 8.1.3(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3)) + vue-tsc: + specifier: ^3.2.6 + version: 3.3.5(typescript@6.0.3) + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@8.0.0-rc.6': + resolution: {integrity: sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@8.0.0-rc.6': + resolution: {integrity: sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@8.0.0-rc.6': + resolution: {integrity: sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@8.0.0-rc.6': + resolution: {integrity: sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==} + engines: {node: ^22.18.0 || >=24.11.0} + hasBin: true + + '@babel/plugin-proposal-decorators@7.29.7': + resolution: {integrity: sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-decorators@7.29.7': + resolution: {integrity: sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@babel/types@8.0.0-rc.6': + resolution: {integrity: sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tsconfig/node24@24.0.4': + resolution: {integrity: sha512-2A933l5P5oCbv6qSxHs7ckKwobs8BDAe9SJ/Xr2Hy+nDlwmLE1GhFh/g/vXGRZWgxBg9nX/5piDtHR9Dkw/XuA==} + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + + '@types/node@24.13.2': + resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} + + '@vitejs/plugin-vue@6.0.7': + resolution: {integrity: sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vue-macros/common@3.1.2': + resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + + '@vue/babel-helper-vue-transform-on@1.5.0': + resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} + + '@vue/babel-plugin-jsx@1.5.0': + resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@1.5.0': + resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.38': + resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + + '@vue/compiler-dom@3.5.38': + resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} + + '@vue/compiler-sfc@3.5.38': + resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + + '@vue/compiler-ssr@3.5.38': + resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} + + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + + '@vue/devtools-api@8.1.3': + resolution: {integrity: sha512-73NMCvxXh8Hyozc/jiwqTFWVcCMyi11U1zmrq4DoukQJnuo8JHt6FsNu4HdeUDa8SpIp5vb7Q22GWgIq0efsXg==} + + '@vue/devtools-core@8.1.3': + resolution: {integrity: sha512-xezkv5/CPH/o5C8PE2Len9MnTJMsctYYQbKbbUiNOJpKd+fRHj27nKDb/sbtYI8NSQduegeQhCJGKRgAiOV6Uw==} + peerDependencies: + vue: ^3.0.0 + + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + + '@vue/devtools-kit@8.1.3': + resolution: {integrity: sha512-cRn7GXiCQkMYU2Z3h3pM4YO/ndbx9FY1yLDAqIqPLcmIq4H6zAOJHein6tvZU3AfPwgrodqLiPBEF+YQaS8AxA==} + + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + + '@vue/devtools-shared@8.1.3': + resolution: {integrity: sha512-CM3uIPL+v+lrJUk33+pxspYo0MhuMWlCvf7zC9fybifvCPyM2jUbYRPwoYEJgYbwRqPikm5HozbUhp60MF2QuA==} + + '@vue/language-core@3.3.5': + resolution: {integrity: sha512-UkKu5nhX89fg4VhlG/FOeI10G3cj/7radKT/cy9BT4Q9qJmJlSTAc/dP63Xqs29aypN4f39xUV6PsLNk/dcD6g==} + + '@vue/reactivity@3.5.38': + resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} + + '@vue/runtime-core@3.5.38': + resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} + + '@vue/runtime-dom@3.5.38': + resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} + + '@vue/server-renderer@3.5.38': + resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + peerDependencies: + vue: 3.5.38 + + '@vue/shared@3.5.38': + resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + + '@vue/tsconfig@0.9.1': + resolution: {integrity: sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==} + peerDependencies: + typescript: '>= 5.8' + vue: ^3.4.0 + peerDependenciesMeta: + typescript: + optional: true + vue: + optional: true + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + address@1.2.2: + resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} + engines: {node: '>= 10.0.0'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agentkeepalive@3.5.3: + resolution: {integrity: sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==} + engines: {node: '>= 4.0.0'} + + ali-oss@6.23.0: + resolution: {integrity: sha512-FipRmyd16Pr/tEey/YaaQ/24Pc3HEpLM9S1DRakEuXlSLXNIJnu1oJtHM53eVYpvW3dXapSjrip3xylZUTIZVQ==} + engines: {node: '>=8'} + + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} + engines: {node: '>=14'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.9.0: + resolution: {integrity: sha512-IJdzo2vLiElBxKzwS36VsCue/62d6IdWjnPB2v3nuPKeWGynp6FF/CYoLa5i/3jXH/z97ZDdsXz6abpgM6w07A==} + engines: {node: '>=20.19.0'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.18.0: + resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==} + + baseline-browser-mapping@2.10.37: + resolution: {integrity: sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==} + engines: {node: '>=6.0.0'} + hasBin: true + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + + bowser@1.9.4: + resolution: {integrity: sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + + copy-to@2.0.1: + resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dateformat@2.2.0: + resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + default-user-agent@1.0.0: + resolution: {integrity: sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==} + engines: {node: '>= 0.10.0'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + digest-header@1.1.0: + resolution: {integrity: sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==} + engines: {node: '>= 8.0.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.373: + resolution: {integrity: sha512-G2Hym8JIf/QreuseqkDibgH8Ci8KfJzqGDKdakbhSx9UltwRBH2cBLAWU/lBX0sCdv0TlhyxQyDCnSfxgMWsjA==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + end-or-error@1.0.1: + resolution: {integrity: sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==} + engines: {node: '>= 0.11.14'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + formstream@1.5.2: + resolution: {integrity: sha512-NASf0lgxC1AyKNXQIrXTEYkiX99LhCEXTkiGObXAkpBui86a4u8FjH1o2bGb3PpqI3kafC+yw4zWeK6l6VHTgg==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-ready@1.0.0: + resolution: {integrity: sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-class-hotfix@0.0.6: + resolution: {integrity: sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-type-of@1.4.0: + resolution: {integrity: sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==} + + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + + js-base64@2.6.4: + resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@4.0.0: + resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} + engines: {node: ^18.17.0 || >=20.5.0} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jstoxml@2.2.9: + resolution: {integrity: sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-hex@1.0.1: + resolution: {integrity: sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ==} + engines: {node: '>=8.0.0'} + + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + engines: {node: '>=18'} + + npm-normalize-package-bin@4.0.0: + resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} + engines: {node: ^18.17.0 || >=20.5.0} + + npm-run-all2@8.0.4: + resolution: {integrity: sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==} + engines: {node: ^20.5.0 || >=22.0.0, npm: '>= 10'} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + + os-name@1.0.3: + resolution: {integrity: sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==} + engines: {node: '>=0.10.0'} + hasBin: true + + osx-release@1.1.0: + resolution: {integrity: sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==} + engines: {node: '>=0.10.0'} + hasBin: true + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pidtree@0.6.1: + resolution: {integrity: sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==} + engines: {node: '>=0.10'} + hasBin: true + + pinia@3.0.4: + resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} + peerDependencies: + typescript: '>=4.5.0' + vue: ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + engines: {node: '>=0.6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + read-package-json-fast@4.0.0: + resolution: {integrity: sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==} + engines: {node: ^18.17.0 || >=20.5.0} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + sdk-base@2.0.1: + resolution: {integrity: sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.4: + resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} + engines: {node: '>= 0.4'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + stream-http@2.8.2: + resolution: {integrity: sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==} + + stream-wormhole@1.1.0: + resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==} + engines: {node: '>=4.0.0'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + to-arraybuffer@1.0.1: + resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unescape@1.0.1: + resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==} + engines: {node: '>=0.10.0'} + + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + urllib@2.44.1: + resolution: {integrity: sha512-vreOVvFizoiIz5NK9IYMgUknkriHHBVccn2VFfJhgKz6O2qwm0SgjFk4OpXFRDXpdrTx8EzM1DB0/pejrqXwPA==} + engines: {node: '>= 0.10.0'} + peerDependencies: + proxy-agent: ^5.0.0 + peerDependenciesMeta: + proxy-agent: + optional: true + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utility@1.18.0: + resolution: {integrity: sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==} + engines: {node: '>= 0.12.0'} + + vite-dev-rpc@2.0.0: + resolution: {integrity: sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0 + + vite-hot-client@2.2.0: + resolution: {integrity: sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0 + + vite-plugin-inspect@11.4.1: + resolution: {integrity: sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^6.0.0 || ^7.0.0-0 || ^8.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + vite-plugin-vue-devtools@8.1.3: + resolution: {integrity: sha512-KBTUhbTXvY+GsCdShnCHG4WdijEV74KIDxhF8erfSs5g5mS13g/cPRUf4mLpD10qr5FqHYosNt0j6rP5kpiS1Q==} + engines: {node: '>=v14.21.3'} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + + vite-plugin-vue-inspector@6.0.0: + resolution: {integrity: sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-router@5.1.0: + resolution: {integrity: sha512-HAbiLzLEHQwxPgvsbOJDAwtavszEgLwri6XfyrsPECIFez8+59xc9LofWVdc/HEaSRT822lJ8H9Ns38VVond5g==} + peerDependencies: + '@pinia/colada': '>=0.21.2' + '@vue/compiler-sfc': ^3.5.34 + pinia: ^3.0.4 + vite: ^7.0.0 || ^8.0.0 + vue: ^3.5.34 + peerDependenciesMeta: + '@pinia/colada': + optional: true + '@vue/compiler-sfc': + optional: true + pinia: + optional: true + vite: + optional: true + + vue-tsc@3.3.5: + resolution: {integrity: sha512-Rzh/G2MmNlMSAMTiQEjDrsb4dgB/jbtEM47rVN2NtidF1dfb/q4w4QvpQBtW5+y3y5H27Hjh7deVwk+YB02fNg==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.5.38: + resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + win-release@1.1.1: + resolution: {integrity: sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + + xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@8.0.0-rc.6': + dependencies: + '@babel/parser': 8.0.0-rc.6 + '@babel/types': 8.0.0-rc.6 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-string-parser@8.0.0-rc.6': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-identifier@8.0.0-rc.6': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/parser@8.0.0-rc.6': + dependencies: + '@babel/types': 8.0.0-rc.6 + + '@babel/plugin-proposal-decorators@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-decorators': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-syntax-decorators@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@babel/types@8.0.0-rc.6': + dependencies: + '@babel/helper-string-parser': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@oxc-project/types@0.133.0': {} + + '@polka/url@1.0.0-next.29': {} + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@tsconfig/node24@24.0.4': {} + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/jsesc@2.5.1': {} + + '@types/node@24.13.2': + dependencies: + undici-types: 7.18.2 + + '@vitejs/plugin-vue@6.0.7(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + vue: 3.5.38(typescript@6.0.3) + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue-macros/common@3.1.2(vue@3.5.38(typescript@6.0.3))': + dependencies: + '@vue/compiler-sfc': 3.5.38 + ast-kit: 2.2.0 + local-pkg: 1.2.1 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.1 + optionalDependencies: + vue: 3.5.38(typescript@6.0.3) + + '@vue/babel-helper-vue-transform-on@1.5.0': {} + + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.7)': + dependencies: + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@vue/babel-helper-vue-transform-on': 1.5.0 + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.7) + '@vue/shared': 3.5.38 + optionalDependencies: + '@babel/core': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.7)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/parser': 7.29.7 + '@vue/compiler-sfc': 3.5.38 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.38 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.38': + dependencies: + '@vue/compiler-core': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/compiler-sfc@3.5.38': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.38 + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.15 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.38': + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/devtools-api@7.7.9': + dependencies: + '@vue/devtools-kit': 7.7.9 + + '@vue/devtools-api@8.1.3': + dependencies: + '@vue/devtools-kit': 8.1.3 + + '@vue/devtools-core@8.1.3(vue@3.5.38(typescript@6.0.3))': + dependencies: + '@vue/devtools-kit': 8.1.3 + '@vue/devtools-shared': 8.1.3 + vue: 3.5.38(typescript@6.0.3) + + '@vue/devtools-kit@7.7.9': + dependencies: + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-kit@8.1.3': + dependencies: + '@vue/devtools-shared': 8.1.3 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@7.7.9': + dependencies: + rfdc: 1.4.1 + + '@vue/devtools-shared@8.1.3': {} + + '@vue/language-core@3.3.5': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.38 + '@vue/shared': 3.5.38 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.4 + + '@vue/reactivity@3.5.38': + dependencies: + '@vue/shared': 3.5.38 + + '@vue/runtime-core@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/shared': 3.5.38 + + '@vue/runtime-dom@3.5.38': + dependencies: + '@vue/reactivity': 3.5.38 + '@vue/runtime-core': 3.5.38 + '@vue/shared': 3.5.38 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@6.0.3))': + dependencies: + '@vue/compiler-ssr': 3.5.38 + '@vue/shared': 3.5.38 + vue: 3.5.38(typescript@6.0.3) + + '@vue/shared@3.5.38': {} + + '@vue/tsconfig@0.9.1(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3))': + optionalDependencies: + typescript: 6.0.3 + vue: 3.5.38(typescript@6.0.3) + + acorn@8.17.0: {} + + address@1.2.2: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agentkeepalive@3.5.3: + dependencies: + humanize-ms: 1.2.1 + + ali-oss@6.23.0: + dependencies: + address: 1.2.2 + agentkeepalive: 3.5.3 + bowser: 1.9.4 + copy-to: 2.0.1 + dateformat: 2.2.0 + debug: 4.4.3 + destroy: 1.2.0 + end-or-error: 1.0.1 + get-ready: 1.0.0 + humanize-ms: 1.2.1 + is-type-of: 1.4.0 + js-base64: 2.6.4 + jstoxml: 2.2.9 + lodash: 4.18.1 + merge-descriptors: 1.0.3 + mime: 2.6.0 + platform: 1.3.6 + pump: 3.0.4 + qs: 6.15.2 + sdk-base: 2.0.1 + stream-http: 2.8.2 + stream-wormhole: 1.1.0 + urllib: 2.44.1 + utility: 1.18.0 + xml2js: 0.6.2 + transitivePeerDependencies: + - proxy-agent + - supports-color + + alien-signals@3.2.1: {} + + ansi-styles@6.2.3: {} + + ansis@4.3.1: {} + + any-promise@1.3.0: {} + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.7 + pathe: 2.0.3 + + ast-walker-scope@0.9.0: + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + ast-kit: 2.2.0 + + asynckit@0.4.0: {} + + axios@1.18.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + baseline-browser-mapping@2.10.37: {} + + birpc@2.9.0: {} + + birpc@4.0.0: {} + + bowser@1.9.4: {} + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.37 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.373 + node-releases: 2.0.47 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + builtin-status-codes@3.0.0: {} + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-lite@1.0.30001799: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + + copy-to@2.0.1: {} + + core-util-is@1.0.3: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + dateformat@2.2.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + default-user-agent@1.0.0: + dependencies: + os-name: 1.0.3 + + define-lazy-prop@3.0.0: {} + + delayed-stream@1.0.0: {} + + destroy@1.2.0: {} + + detect-libc@2.1.2: {} + + digest-header@1.1.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.373: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + end-or-error@1.0.1: {} + + entities@7.0.1: {} + + error-stack-parser-es@1.0.5: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + estree-walker@2.0.2: {} + + exsolve@1.0.8: {} + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + follow-redirects@1.16.0: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + formstream@1.5.2: + dependencies: + destroy: 1.2.0 + mime: 2.6.0 + node-hex: 1.0.1 + pause-stream: 0.0.11 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-ready@1.0.0: {} + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hookable@5.5.3: {} + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + is-class-hotfix@0.0.6: {} + + is-docker@3.0.0: {} + + is-extendable@0.1.1: {} + + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-type-of@1.4.0: + dependencies: + core-util-is: 1.0.3 + is-class-hotfix: 0.0.6 + isstream: 0.1.2 + + is-what@5.5.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + isexe@3.1.5: {} + + isstream@0.1.2: {} + + js-base64@2.6.4: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json-parse-even-better-errors@4.0.0: {} + + json5@2.2.3: {} + + jstoxml@2.2.9: {} + + kolorist@1.8.0: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + lodash@4.18.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + memorystream@0.3.1: {} + + merge-descriptors@1.0.3: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + minimist@1.2.8: {} + + mitt@3.0.1: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.12: {} + + node-hex@1.0.1: {} + + node-releases@2.0.47: {} + + npm-normalize-package-bin@4.0.0: {} + + npm-run-all2@8.0.4: + dependencies: + ansi-styles: 6.2.3 + cross-spawn: 7.0.6 + memorystream: 0.3.1 + picomatch: 4.0.4 + pidtree: 0.6.1 + read-package-json-fast: 4.0.0 + shell-quote: 1.8.4 + which: 5.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + obug@2.1.3: {} + + ohash@2.0.11: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + + os-name@1.0.3: + dependencies: + osx-release: 1.1.0 + win-release: 1.1.1 + + osx-release@1.1.0: + dependencies: + minimist: 1.2.8 + + path-browserify@1.0.1: {} + + path-key@3.1.1: {} + + pathe@2.0.3: {} + + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + + perfect-debounce@1.0.0: {} + + perfect-debounce@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pidtree@0.6.1: {} + + pinia@3.0.4(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)): + dependencies: + '@vue/devtools-api': 7.7.9 + vue: 3.5.38(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + platform@1.3.6: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + powershell-utils@0.1.0: {} + + prettier@3.8.3: {} + + process-nextick-args@2.0.1: {} + + proxy-from-env@2.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + qs@6.15.2: + dependencies: + side-channel: 1.1.1 + + quansync@0.2.11: {} + + read-package-json-fast@4.0.0: + dependencies: + json-parse-even-better-errors: 4.0.0 + npm-normalize-package-bin: 4.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readdirp@5.0.0: {} + + rfdc@1.4.1: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + run-applescript@7.1.0: {} + + safe-buffer@5.1.2: {} + + safer-buffer@2.1.2: {} + + sax@1.6.0: {} + + scule@1.3.0: {} + + sdk-base@2.0.1: + dependencies: + get-ready: 1.0.0 + + semver@5.7.2: {} + + semver@6.3.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.4: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + speakingurl@14.0.1: {} + + statuses@1.5.0: {} + + stream-http@2.8.2: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 2.3.8 + to-arraybuffer: 1.0.1 + xtend: 4.0.2 + + stream-wormhole@1.1.0: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through@2.3.8: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + to-arraybuffer@1.0.1: {} + + totalist@3.0.1: {} + + tslib@2.8.1: + optional: true + + typescript@6.0.3: {} + + ufo@1.6.4: {} + + undici-types@7.18.2: {} + + unescape@1.0.1: + dependencies: + extend-shallow: 2.0.1 + + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.4 + + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + urllib@2.44.1: + dependencies: + any-promise: 1.3.0 + content-type: 1.0.5 + default-user-agent: 1.0.0 + digest-header: 1.1.0 + ee-first: 1.1.1 + formstream: 1.5.2 + humanize-ms: 1.2.1 + iconv-lite: 0.6.3 + pump: 3.0.4 + qs: 6.15.2 + statuses: 1.5.0 + utility: 1.18.0 + + util-deprecate@1.0.2: {} + + utility@1.18.0: + dependencies: + copy-to: 2.0.1 + escape-html: 1.0.3 + mkdirp: 0.5.6 + mz: 2.7.0 + unescape: 1.0.1 + + vite-dev-rpc@2.0.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)): + dependencies: + birpc: 4.0.0 + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + vite-hot-client: 2.2.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)) + + vite-hot-client@2.2.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)): + dependencies: + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + + vite-plugin-inspect@11.4.1(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)): + dependencies: + ansis: 4.3.1 + error-stack-parser-es: 1.0.5 + obug: 2.1.3 + ohash: 2.0.11 + open: 11.0.0 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + vite-dev-rpc: 2.0.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)) + + vite-plugin-vue-devtools@8.1.3(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3)): + dependencies: + '@vue/devtools-core': 8.1.3(vue@3.5.38(typescript@6.0.3)) + '@vue/devtools-kit': 8.1.3 + '@vue/devtools-shared': 8.1.3 + sirv: 3.0.2 + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + vite-plugin-inspect: 11.4.1(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)) + vite-plugin-vue-inspector: 6.0.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)) + transitivePeerDependencies: + - '@nuxt/kit' + - supports-color + - vue + + vite-plugin-vue-inspector@6.0.0(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-proposal-decorators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.7) + '@vue/compiler-dom': 3.5.38 + kolorist: 1.8.0 + magic-string: 0.30.21 + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + + vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.2 + fsevents: 2.3.3 + yaml: 2.9.0 + + vscode-uri@3.1.0: {} + + vue-router@5.1.0(@vue/compiler-sfc@3.5.38)(pinia@3.0.4(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)))(vite@8.0.16(@types/node@24.13.2)(yaml@2.9.0))(vue@3.5.38(typescript@6.0.3)): + dependencies: + '@babel/generator': 8.0.0-rc.6 + '@vue-macros/common': 3.1.2(vue@3.5.38(typescript@6.0.3)) + '@vue/devtools-api': 8.1.3 + ast-walker-scope: 0.9.0 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.4 + scule: 1.3.0 + tinyglobby: 0.2.17 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 + vue: 3.5.38(typescript@6.0.3) + yaml: 2.9.0 + optionalDependencies: + '@vue/compiler-sfc': 3.5.38 + pinia: 3.0.4(typescript@6.0.3)(vue@3.5.38(typescript@6.0.3)) + vite: 8.0.16(@types/node@24.13.2)(yaml@2.9.0) + + vue-tsc@3.3.5(typescript@6.0.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.3.5 + typescript: 6.0.3 + + vue@3.5.38(typescript@6.0.3): + dependencies: + '@vue/compiler-dom': 3.5.38 + '@vue/compiler-sfc': 3.5.38 + '@vue/runtime-dom': 3.5.38 + '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@6.0.3)) + '@vue/shared': 3.5.38 + optionalDependencies: + typescript: 6.0.3 + + webpack-virtual-modules@0.6.2: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@5.0.0: + dependencies: + isexe: 3.1.5 + + win-release@1.1.1: + dependencies: + semver: 5.7.2 + + wrappy@1.0.2: {} + + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + + xml2js@0.6.2: + dependencies: + sax: 1.6.0 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + + xtend@4.0.2: {} + + yallist@3.1.1: {} + + yaml@2.9.0: {} diff --git a/gym-manage-cuit/public/favicon.ico b/gym-manage-cuit/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/gym-manage-cuit/src/App.vue b/gym-manage-cuit/src/App.vue new file mode 100644 index 0000000..3d36b36 --- /dev/null +++ b/gym-manage-cuit/src/App.vue @@ -0,0 +1,50 @@ + + + + + \ No newline at end of file diff --git a/gym-manage-cuit/src/api/auth.ts b/gym-manage-cuit/src/api/auth.ts new file mode 100644 index 0000000..3974f22 --- /dev/null +++ b/gym-manage-cuit/src/api/auth.ts @@ -0,0 +1,42 @@ +import request from './request' + +export interface LoginParams { + username: string + password: string +} + +export interface UserInfo { + id: number + username: string + email: string + phone: string + nickname: string + status: number + roleId: number +} + +export interface LoginResponse { + accessToken: string + refreshToken: string + tokenType: string + expiresIn: number + userInfo: UserInfo +} + +export interface ApiResponse { + code: number + message: string + data: T +} + +export function login(params: LoginParams): Promise> { + return request.post('/api/auth/login', { ...params, target: 'admin' }) +} + +export function getUserInfo(id: number): Promise> { + return request.get(`/api/auth/users/${id}`) +} + +export function verifyPassword(params: LoginParams): Promise> { + return request.post('/api/auth/login', params) +} \ No newline at end of file diff --git a/gym-manage-cuit/src/api/coach.ts b/gym-manage-cuit/src/api/coach.ts new file mode 100644 index 0000000..e8be49f --- /dev/null +++ b/gym-manage-cuit/src/api/coach.ts @@ -0,0 +1,29 @@ +import request from './request' +import type { GroupCourse } from './groupCourse' + +export interface CoachInfo { + id: number + username: string + nickname: string + email: string + phone: string + avatar: string | null + status: number + createdAt: string + updatedAt: string +} + +/** 获取所有教练用户列表(店长/管理员用) */ +export function getCoachList(): Promise { + return request.get('/api/users/role/coach') +} + +/** 获取当前登录教练自己教授的团课(教练自用) */ +export function getCoachCourses(): Promise { + return request.get('/api/coach/courses') +} + +/** 根据教练ID查询该教练教授的所有团课(店长/管理员用) */ +export function getCoachCoursesById(coachId: number): Promise { + return request.get(`/api/coach/${coachId}/courses`) +} diff --git a/gym-manage-cuit/src/api/datacount.ts b/gym-manage-cuit/src/api/datacount.ts new file mode 100644 index 0000000..d6e8f76 --- /dev/null +++ b/gym-manage-cuit/src/api/datacount.ts @@ -0,0 +1,139 @@ +import request from './request' + +export interface MemberStatistics { + statDate: string + newMembers: number + activeMembers: number + totalMembers: number + signInMembers: number + bookingMembers: number + cancelMembers: number +} + +export interface BookingStatistics { + statDate: string + newBookings: number + cancelBookings: number + attendBookings: number + absentBookings: number + attendanceRate: number + cancelRate: number +} + +export interface SignInStatistics { + statDate: string + totalSignIns: number + successSignIns: number + failSignIns: number + successRate: number + signInTypeDistribution: Record +} + +export interface StatisticsSummary { + statDate: string + generatedAt: string + memberStatistics: MemberStatistics + bookingStatistics: BookingStatistics + signInStatistics: SignInStatistics +} + +export function getSummary(params?: { + statType?: string + periodType?: string + startTime?: string + endTime?: string +}): Promise { + return request.get('/api/datacount/summary', { params }) +} + +export function getMemberStatistics(params?: { + periodType?: string + startTime?: string + endTime?: string +}): Promise { + return request.get('/api/datacount/member', { params }) +} + +export function getBookingStatistics(params?: { + periodType?: string + startTime?: string + endTime?: string +}): Promise { + return request.get('/api/datacount/booking', { params }) +} + +export interface MemberSignInDetail { + memberId: number + memberName: string + memberPhone: string + totalSignIns: number + successSignIns: number + failedSignIns: number + lastSignInTime: string +} + +export interface MemberSignInResponse { + statDate: string + total: number + page: number + size: number + list: MemberSignInDetail[] +} + +export function getSignInStatistics(params?: { + periodType?: string + startTime?: string + endTime?: string +}): Promise { + return request.get('/api/datacount/signin', { params }) +} + +export interface MemberMonthlySignIn { + memberId: number + memberName: string + month: string + totalSignIns: number + successSignIns: number + failedSignIns: number +} + +export interface MemberDailySignIn { + memberId: number + signInTime: string + signInStatus: string + signInType: string + failReason: string | null +} + +export function getMemberSignInDetails(params?: { + periodType?: string + startTime?: string + endTime?: string + page?: number + size?: number +}): Promise { + return request.get('/api/datacount/member/signin', { params }) +} + +export function getMemberMonthlySignIns(memberId: number): Promise { + return request.get(`/api/datacount/member/${memberId}/monthly-signin`) +} + +export function getMemberDailySignIns(memberId: number, month: string): Promise { + return request.get(`/api/datacount/member/${memberId}/monthly-signin`, { params: { month } }) +} + +/** + * 导出数据统计报表(返回Excel文件Blob) + */ +export function exportStatistics(params?: { + statType?: string + periodType?: string + startTime?: string + endTime?: string +}): Promise { + return request.get('/api/datacount/export', { + params, + responseType: 'blob', + }) +} \ No newline at end of file diff --git a/gym-manage-cuit/src/api/dict.ts b/gym-manage-cuit/src/api/dict.ts new file mode 100644 index 0000000..2d3cfc1 --- /dev/null +++ b/gym-manage-cuit/src/api/dict.ts @@ -0,0 +1,129 @@ +import request from './request' + +// ==================== 字典类型 ==================== + +export interface SysDictType { + id: number + dictName: string + dictType: string + status: string + remark: string | null + createBy: string | null + updateBy: string | null + createdAt: string + updatedAt: string + deletedAt: string | null +} + +export interface CreateDictTypeDto { + dictName: string + dictType: string + status?: string + remark?: string +} + +export interface UpdateDictTypeDto { + dictName?: string + status?: string + remark?: string +} + +/** 获取所有字典类型 */ +export function getAllDictTypes(): Promise { + return request.get('/api/dict/types') +} + +/** 根据ID获取字典类型 */ +export function getDictTypeById(id: number): Promise { + return request.get(`/api/dict/types/${id}`) +} + +/** 根据类型编码获取字典类型 */ +export function getDictTypeByType(dictType: string): Promise { + return request.get(`/api/dict/types/type/${dictType}`) +} + +/** 创建字典类型 */ +export function createDictType(data: CreateDictTypeDto): Promise { + return request.post('/api/dict/types', data) +} + +/** 更新字典类型 */ +export function updateDictType(id: number, data: UpdateDictTypeDto): Promise { + return request.put(`/api/dict/types/${id}`, data) +} + +/** 删除字典类型 */ +export function deleteDictType(id: number): Promise { + return request.delete(`/api/dict/types/${id}`) +} + +// ==================== 字典数据 ==================== + +export interface SysDictData { + id: number + dictSort: number + dictLabel: string + dictValue: string + dictType: string + cssClass: string | null + listClass: string | null + isDefault: string + status: string + createBy: string | null + updateBy: string | null + createdAt: string + updatedAt: string + deletedAt: string | null +} + +export interface CreateDictDataDto { + dictSort?: number + dictLabel: string + dictValue: string + dictType: string + cssClass?: string + listClass?: string + isDefault?: string + status?: string +} + +export interface UpdateDictDataDto { + dictSort?: number + dictLabel?: string + dictValue?: string + cssClass?: string + listClass?: string + isDefault?: string + status?: string +} + +/** 获取所有字典数据 */ +export function getAllDictData(): Promise { + return request.get('/api/dict/data') +} + +/** 根据类型获取字典数据 */ +export function getDictDataByType(dictType: string): Promise { + return request.get(`/api/dict/data/type/${dictType}`) +} + +/** 根据ID获取字典数据 */ +export function getDictDataById(id: number): Promise { + return request.get(`/api/dict/data/${id}`) +} + +/** 创建字典数据 */ +export function createDictData(data: CreateDictDataDto): Promise { + return request.post('/api/dict/data', data) +} + +/** 更新字典数据 */ +export function updateDictData(id: number, data: UpdateDictDataDto): Promise { + return request.put(`/api/dict/data/${id}`, data) +} + +/** 删除字典数据 */ +export function deleteDictData(id: number): Promise { + return request.delete(`/api/dict/data/${id}`) +} diff --git a/gym-manage-cuit/src/api/employee.ts b/gym-manage-cuit/src/api/employee.ts new file mode 100644 index 0000000..e23e1e0 --- /dev/null +++ b/gym-manage-cuit/src/api/employee.ts @@ -0,0 +1,128 @@ +import request from './request' + +// ==================== 类型定义 ==================== + +export interface RoleInfo { + id: number + roleName: string + roleKey: string + roleSort: number +} + +export interface EmployeeInfo { + id: number + username: string + nickname: string + email: string + phone: string + avatar: string | null + status: number + roles: RoleInfo[] + createdAt: string + updatedAt: string + deletedAt: string | null +} + +export interface EmployeePageResponse { + content: EmployeeInfo[] + totalPages: number + totalElements: number + currentPage: number + pageSize: number + first: boolean + last: boolean +} + +export interface SysRole { + id: number + roleName: string + roleKey: string + roleSort: number + status: number + createdAt: string + updatedAt: string +} + +export interface CreateEmployeeDto { + username: string + password: string + nickname?: string + email: string + phone: string + roles?: number[] +} + +export interface UpdateEmployeeDto { + email?: string + roleId?: number + status?: number +} + +export interface AssignRolesDto { + roleIds: string[] +} + +export interface ChangePasswordDto { + oldPassword: string + newPassword: string +} + +// ==================== API 方法 ==================== + +/** 分页获取员工列表(含角色信息) */ +export function getEmployeesByPage(params: { + page?: number + size?: number + sort?: string + order?: string + keyword?: string + includeDeleted?: boolean +}): Promise { + return request.get('/api/employees/page', { params }) +} + +/** 获取已删除的账号列表 */ +export function getDeletedEmployees(params: { + page?: number + size?: number + keyword?: string +}): Promise { + return request.get('/api/employees/page', { + params: { ...params, includeDeleted: true } + }) +} + +/** 获取所有角色 */ +export function getAllRoles(): Promise { + return request.get('/api/roles') +} + +/** 创建员工账号 */ +export function createEmployee(data: CreateEmployeeDto): Promise { + return request.post('/api/users', data) +} + +/** 获取员工详情 */ +export function getEmployeeById(id: number): Promise { + return request.get(`/api/users/${id}`) +} + +/** 更新员工信息 */ +export function updateEmployee(id: number, data: UpdateEmployeeDto): Promise { + return request.put(`/api/users/${id}`, data) +} + +/** 逻辑删除员工 */ +export function deleteEmployee(id: number): Promise { + return request.post(`/api/users/${id}/action/logical-delete`) +} + +/** 修改员工密码(管理员重置) */ +export function changeEmployeePassword(id: number, data: ChangePasswordDto): Promise { + return request.post(`/api/users/${id}/action/change-password`, data) +} + +/** 为员工分配角色 */ +export function assignRoles(id: number, data: AssignRolesDto): Promise { + return request.post(`/api/users/${id}/roles`, data) +} diff --git a/gym-manage-cuit/src/api/groupCourse.ts b/gym-manage-cuit/src/api/groupCourse.ts new file mode 100644 index 0000000..2fec885 --- /dev/null +++ b/gym-manage-cuit/src/api/groupCourse.ts @@ -0,0 +1,187 @@ +import request from './request' + +export interface GroupCourse { + id: number + courseName: string + coachId: number + courseType: number + typeName?: string + startTime: string + endTime: string + maxMembers: number + currentMembers: number + status: number + actualStartTime?: string | null + actualEndTime?: string | null + location: string + coverImage: string + description: string + pointCardAmount?: number + storedValueAmount?: number + createdAt: string + updatedAt: string + deletedAt?: string | null +} + +export interface CoursePageParams { + page: number + size: number + sort?: string + order?: string + keyword?: string +} + +export interface CourseSearchParams { + courseName?: string + courseType?: number + startDate?: string + endDate?: string + timePeriod?: string + priceSort?: string + remainingMost?: boolean + page?: number + size?: number +} + +export interface PageResult { + content: T[] + totalPages: number + totalElements: number + currentPage: number + pageSize: number + first: boolean + last: boolean +} + +export interface ApiResult { + success: boolean + message: string + data: T +} + +export function getCourseList(includeDeleted = false): Promise { + return request.get('/api/groupCourse/list', { params: { includeDeleted } }) +} + +export function getCoursePage( + params: CoursePageParams, + includeDeleted = false, +): Promise<{ data: GroupCourse[]; totalPages: number; totalElements: number; page: number; size: number }> { + return request.post('/api/groupCourse/page', params, { + params: { includeDeleted }, + }) +} + +export function searchCourses( + params: CourseSearchParams, +): Promise>> { + return request.post('/api/groupCourse/search', params) +} + +export function getCourseById(id: number): Promise { + return request.get(`/api/groupCourse/${id}`) +} + +export function getCourseDetail(id: number): Promise { + return request.get(`/api/groupCourse/${id}/detail`) +} + +export function createCourse(data: Partial): Promise> { + return request.post('/api/groupCourse', data) +} + +export function updateCourse(id: number, data: Partial): Promise> { + return request.put(`/api/groupCourse/${id}`, data) +} + +export function cancelCourse(id: number): Promise> { + return request.post(`/api/groupCourse/${id}/cancel`) +} + +export function deleteCourse(id: number): Promise> { + return request.delete(`/api/groupCourse/${id}`) +} + +export function getCourseTypes(includeDeleted = false): Promise { + return request.get('/api/groupCourse/types', { params: { includeDeleted } }) +} + +// --- 团课类型管理 --- +export interface CourseType { + id: number + typeName: string + baseDifficulty?: number + description?: string + category?: string + createdAt?: string + updatedAt?: string +} + +export function getTypeList(includeDeleted = false, sortField?: string, sortDirection?: string): Promise { + const params: Record = { includeDeleted } + if (sortField && sortDirection) { + params.sortField = sortField + params.sortDirection = sortDirection + } + return request.get('/api/groupCourse/types', { params }) +} + +export function getTypeById(id: number): Promise { + return request.get(`/api/groupCourse/types/${id}`) +} + +export function createType(data: Partial): Promise> { + return request.post('/api/groupCourse/types', data) +} + +export function updateType(id: number, data: Partial): Promise> { + return request.put(`/api/groupCourse/types/${id}`, data) +} + +export function deleteType(id: number, password: string): Promise> { + return request.post(`/api/groupCourse/types/${id}/delete`, { password }) +} + +// --- 团课标签管理 --- +export interface CourseLabel { + id: number + labelName: string + color?: string + description?: string +} + +export function getAllLabels(): Promise { + return request.get('/api/groupCourse/labels') +} + +export function createLabel(data: { labelName: string; color?: string }): Promise> { + return request.post('/api/groupCourse/labels', data) +} + +export function getLabelsByTypeId(typeId: number): Promise { + return request.get(`/api/groupCourse/types/${typeId}/labels`) +} + +export function addLabelsToType(typeId: number, labelIds: number[]): Promise> { + return request.post(`/api/groupCourse/types/${typeId}/labels`, { labelIds }) +} + +export function removeLabelFromType(typeId: number, labelId: number): Promise> { + return request.delete(`/api/groupCourse/types/${typeId}/labels/${labelId}`) +} + +export function removeLabelsFromType(typeId: number, labelIds: number[]): Promise> { + return request.post(`/api/groupCourse/types/${typeId}/labels/delete-batch`, { labelIds }) +} + +// --- 课程状态映射(从后端统一获取,避免硬编码)--- +export interface CourseStatusItem { + value: number + dbValue: string + label: string + cssClass: string +} + +export function fetchCourseStatuses(): Promise> { + return request.get('/api/groupCourse/statuses') +} \ No newline at end of file diff --git a/gym-manage-cuit/src/api/groupCourseRecommend.ts b/gym-manage-cuit/src/api/groupCourseRecommend.ts new file mode 100644 index 0000000..ae525f1 --- /dev/null +++ b/gym-manage-cuit/src/api/groupCourseRecommend.ts @@ -0,0 +1,71 @@ +import request from './request' +import type { GroupCourse } from './groupCourse' + +export interface GroupCourseRecommend { + id: number + courseId: number + recommendTitle: string + recommendContent: string + recommendReason: string + priority: number + isActive: boolean + groupCourse?: GroupCourse + createdAt: string + updatedAt: string +} + +export interface ApiResult { + success: boolean + message: string + data: T +} + +export function getRecommendList( + sortBy = 'priority', + sortOrder = 'desc', +): Promise { + return request.get('/api/groupCourse/recommend/list', { + params: { sortBy, sortOrder }, + }) +} + +export function getActiveRecommends(): Promise { + return request.get('/api/groupCourse/recommend/active') +} + +export function getRecommendById(id: number): Promise { + return request.get(`/api/groupCourse/recommend/${id}`) +} + +export function getRecommendByCourseId(courseId: number): Promise { + return request.get(`/api/groupCourse/recommend/course/${courseId}`) +} + +export function createRecommend( + data: Partial, +): Promise> { + return request.post('/api/groupCourse/recommend', data) +} + +export function updateRecommend( + id: number, + data: Partial, +): Promise> { + return request.put(`/api/groupCourse/recommend/${id}`, data) +} + +export function deleteRecommend(id: number): Promise> { + return request.delete(`/api/groupCourse/recommend/${id}`) +} + +export function enableRecommend( + id: number, +): Promise> { + return request.post(`/api/groupCourse/recommend/${id}/enable`) +} + +export function disableRecommend( + id: number, +): Promise> { + return request.post(`/api/groupCourse/recommend/${id}/disable`) +} \ No newline at end of file diff --git a/gym-manage-cuit/src/api/member.ts b/gym-manage-cuit/src/api/member.ts new file mode 100644 index 0000000..7a4f9ed --- /dev/null +++ b/gym-manage-cuit/src/api/member.ts @@ -0,0 +1,162 @@ +import request from './request' + +export interface Member { + id: number + memberNo: string + nickname: string + phone: string + gender: number + genderDesc?: string + birthday: string | null + address: string + avatar: string + subscribed: boolean + lastLoginAt: string + createdAt: string + updatedAt: string + deletedAt: string | null + isDeleted: boolean + openid?: string + unionId?: string +} + +export interface MemberCardInfo { + id: number + status: string + statusDesc: string + remainingTimes: number + remainingAmount: number + expireTime: string | null + purchaseTime: string | null + memberCardId: number + memberCardName: string + memberCardType: string + memberCardTypeDesc: string + memberCardPrice: number + memberCardValidityDays: number | null + memberCardTotalTimes: number | null + memberCardAmount: number | null + memberCardStatus: number + memberCardStatusDesc: string + extraConfig: string | null + createdAt: string + updatedAt: string +} + +export interface MemberDetail { + id: number + memberNo: string + nickname: string + phone: string + genderDesc: string + birthday: string | null + address: string + avatar: string + subscribed: boolean + lastLoginAt: string + createdAt: string + memberCards: MemberCardInfo[] + activeCardCount: number + inactiveCardCount: number +} + +export interface UpdateMemberDto { + nickname?: string + gender?: number + birthday?: string + avatar?: string + address?: string +} + +export function getAllMembers(pageNum: number = 1, pageSize: number = 10): Promise { + return request.get('/api/admin/members/all', { + params: { pageNum, pageSize }, + }) +} + +export function searchMembers( + searchValue: string, + pageNum: number = 1, + pageSize: number = 10, +): Promise { + return request.get('/api/admin/members', { + params: { searchValue, pageNum, pageSize }, + }) +} + +export function getMemberDetail(id: number): Promise { + return request.get(`/api/admin/member/${id}`) +} + +export function updateMember(id: number, data: UpdateMemberDto): Promise { + return request.put(`/api/admin/member/${id}`, data) +} + +export function adminUpdatePhone(id: number, phone: string): Promise { + return request.post(`/api/admin/member/${id}/phone`, { phone }) +} + +// ==================== 会员卡管理 ==================== + +/** 可用会员卡类型 */ +export interface MemberCardType { + id: number + memberCardId: number + memberCardName: string + memberCardType: string + memberCardPrice: number + memberCardValidityDays: number | null + memberCardTotalTimes: number | null + memberCardAmount: number | null + memberCardStatus: number + extraConfig: string | null + createdAt: string + updatedAt: string +} + +/** 会员持有的卡记录 */ +export interface MemberCardRecord { + id: number + memberCardRecordId: number + memberId: number + memberCardId: number + status: string + remainingTimes: number + remainingAmount: number + expireTime: string | null + sourceOrderId: number | null + purchaseTime: string + version: number + cardComposition: string | null + createdAt: string + updatedAt: string +} + +/** 获取上架中的会员卡类型 */ +export function getActiveCards(): Promise { + return request.get('/api/member-cards/active') +} + +/** 获取会员持有的卡记录 */ +export function getMemberCardRecords(memberId: number): Promise { + return request.get(`/api/member-card-records/my-cards/${memberId}`) +} + +/** 为会员购买/绑定会员卡 */ +export function purchaseCard(memberId: number, memberCardId: number): Promise { + return request.post('/api/member-card-records/purchase', { + memberId, + memberCardId, + sourceOrderId: null, + }) +} + +/** 退卡/解绑 */ +export function refundCard(recordId: number): Promise { + return request.post(`/api/member-card-records/${recordId}/refund`) +} + +/** 验证管理员密码 */ +export function verifyAdminPassword(password: string): Promise { + return request.post('/api/admin/verify-password', { password }) +} diff --git a/gym-manage-cuit/src/api/memberCard.ts b/gym-manage-cuit/src/api/memberCard.ts new file mode 100644 index 0000000..6698b74 --- /dev/null +++ b/gym-manage-cuit/src/api/memberCard.ts @@ -0,0 +1,89 @@ +import request from './request' + +export interface MemberCard { + memberCardId: number + memberCardName: string + memberCardType: string + memberCardPrice: number + memberCardValidityDays: number | null + memberCardTotalTimes: number | null + memberCardAmount: number | null + memberCardStatus: number + extraConfig: string | null + createdAt: string + updatedAt: string +} + +export interface CreateMemberCardDto { + memberCardName: string + memberCardType: string + memberCardPrice: number + memberCardValidityDays?: number + memberCardTotalTimes?: number + memberCardAmount?: number + memberCardStatus?: number + extraConfig?: string +} + +export interface UpdateMemberCardDto { + memberCardName?: string + memberCardType?: string + memberCardPrice?: number + memberCardValidityDays?: number + memberCardTotalTimes?: number + memberCardAmount?: number + memberCardStatus?: number + extraConfig?: string +} + +export interface MemberCardQuery { + status?: number + name?: string + type?: string + minPrice?: number + maxPrice?: number + page?: number + size?: number +} + +/** + * 分页查询会员卡类型列表 + */ +export function listMemberCards(query: MemberCardQuery): Promise { + return request.get('/api/member-cards', { params: query }) +} + +/** + * 查询上架的会员卡类型 + */ +export function getActiveCards(status: number = 1): Promise { + return request.get('/api/member-cards/active', { params: { status } }) +} + +/** + * 查询会员卡类型详情 + */ +export function getMemberCardById(id: number): Promise { + return request.get(`/api/member-cards/${id}`) +} + +/** + * 创建会员卡类型 + */ +export function createMemberCard(data: CreateMemberCardDto): Promise { + return request.post('/api/member-cards', data) +} + +/** + * 更新会员卡类型 + */ +export function updateMemberCard(id: number, data: UpdateMemberCardDto): Promise { + return request.put(`/api/member-cards/${id}`, data) +} + +/** + * 删除会员卡类型(逻辑删除) + */ +export function deleteMemberCard(id: number): Promise { + return request.delete(`/api/member-cards/${id}`) +} diff --git a/gym-manage-cuit/src/api/notice.ts b/gym-manage-cuit/src/api/notice.ts new file mode 100644 index 0000000..12706e1 --- /dev/null +++ b/gym-manage-cuit/src/api/notice.ts @@ -0,0 +1,58 @@ +import request from './request' + +export interface SysNotice { + id: number + noticeTitle: string + noticeType: string + noticeContent: string + status: string + createBy: string | null + updateBy: string | null + createdAt: string + updatedAt: string + deletedAt: string | null +} + +export interface CreateNoticeDto { + noticeTitle: string + noticeType: string + noticeContent: string + status?: string +} + +export interface UpdateNoticeDto { + noticeTitle?: string + noticeType?: string + noticeContent?: string + status?: string +} + +/** 获取所有公告 */ +export function getAllNotices(): Promise { + return request.get('/api/notices') +} + +/** 根据ID获取公告 */ +export function getNoticeById(id: number): Promise { + return request.get(`/api/notices/${id}`) +} + +/** 根据状态获取公告 */ +export function getNoticesByStatus(status: string): Promise { + return request.get(`/api/notices/status/${status}`) +} + +/** 创建公告 */ +export function createNotice(data: CreateNoticeDto): Promise { + return request.post('/api/notices', data) +} + +/** 更新公告 */ +export function updateNotice(id: number, data: UpdateNoticeDto): Promise { + return request.put(`/api/notices/${id}`, data) +} + +/** 删除公告 */ +export function deleteNotice(id: number): Promise { + return request.delete(`/api/notices/${id}`) +} diff --git a/gym-manage-cuit/src/api/operationLog.ts b/gym-manage-cuit/src/api/operationLog.ts new file mode 100644 index 0000000..b9b6b71 --- /dev/null +++ b/gym-manage-cuit/src/api/operationLog.ts @@ -0,0 +1,66 @@ +import request from './request' + +export interface OperationLog { + id: number + username: string + operation: string + method: string + params: string | null + result: string | null + ip: string + duration: number + status: string + errorMsg: string | null + createBy: string | null + updateBy: string | null + createdAt: string + updatedAt: string + deletedAt: string | null +} + +export interface OperationLogPageResponse { + content: OperationLog[] + totalPages: number + totalElements: number + currentPage: number + pageSize: number + first: boolean + last: boolean +} + +export function getOperationLogs(params?: { + page?: number + size?: number + sort?: string + order?: string + keyword?: string + username?: string + operation?: string + status?: string + startTime?: string + endTime?: string + ip?: string + method?: string +}): Promise { + return request.get('/api/logs/operation/page', { params }) +} + +export function getOperationLogCount(): Promise { + return request.get('/api/logs/operation/count') +} + +export function exportOperationLogs(params?: { + username?: string + operation?: string + status?: string + startTime?: string + endTime?: string + ip?: string + method?: string + keyword?: string +}): Promise { + return request.get('/api/logs/operation/export', { + params, + responseType: 'blob', + }) +} diff --git a/gym-manage-cuit/src/api/request.ts b/gym-manage-cuit/src/api/request.ts new file mode 100644 index 0000000..fd33044 --- /dev/null +++ b/gym-manage-cuit/src/api/request.ts @@ -0,0 +1,35 @@ +import axios from 'axios' + +const request = axios.create({ + timeout: 15000, + headers: { + 'Content-Type': 'application/json', + }, +}) + +request.interceptors.request.use( + (config) => { + const token = localStorage.getItem('accessToken') + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + (error) => Promise.reject(error), +) + +request.interceptors.response.use( + (response) => response.data, + (error) => { + const isLoginRequest = error.config?.url?.includes('/auth/login') + if (error.response?.status === 401 && !isLoginRequest) { + localStorage.removeItem('accessToken') + localStorage.removeItem('refreshToken') + localStorage.removeItem('userInfo') + window.location.href = '/login' + } + return Promise.reject(error) + }, +) + +export default request \ No newline at end of file diff --git a/gym-manage-cuit/src/api/role.ts b/gym-manage-cuit/src/api/role.ts new file mode 100644 index 0000000..32c43e3 --- /dev/null +++ b/gym-manage-cuit/src/api/role.ts @@ -0,0 +1,207 @@ +import request from './request' + +// ==================== 类型定义 ==================== + +export interface SysRole { + id: number + roleName: string + roleKey: string + roleSort: number + status: number + createBy?: string + updateBy?: string + createdAt: string + updatedAt: string + deletedAt?: string | null +} + +export interface SysPermission { + id: number + permissionName: string + permissionCode: string + resource: string + action: string + description: string + status: number + createBy?: string + updateBy?: string + createdAt: string + updatedAt: string + deletedAt?: string | null +} + +export interface RolePageResponse { + content: SysRole[] + totalPages: number + totalElements: number + currentPage: number + pageSize: number + first: boolean + last: boolean +} + +export interface CreateRoleDto { + roleName: string + roleKey: string + roleSort?: number + status?: number +} + +export interface UpdateRoleDto { + roleName?: string + roleKey?: string + roleSort?: number + status?: number +} + +export interface CreatePermissionDto { + permissionName: string + permissionCode: string + resource: string + action: string + description?: string + status?: number +} + +/** 权限分组(按业务模块) */ +export interface PermissionGroup { + category: string + module: string + moduleLabel: string + permissions: SysPermission[] +} + +// ==================== 权限工具函数 ==================== + +/** 模块中文名映射 */ +const moduleLabelMap: Record = { + user: '用户管理', + role: '角色管理', + permission: '权限管理', + menu: '菜单管理', + dict: '字典管理', + config: '系统配置', + log: '日志管理', + file: '文件管理', + notice: '公告管理', + member: '会员管理', + memberCard: '会员卡管理', + groupCourse: '团课管理', + groupCourseType: '团课类型管理', + groupCourseRecommend: '团课推荐管理', + groupCourseBooking: '团课预约管理', + checkIn: '签到管理', + dataCount: '数据统计', + employee: '员工管理', +} + +/** 从权限编码中解析模块名 */ +export function parseModuleFromCode(code: string): { category: string; module: string } { + const parts = code.split(':') + return { category: parts[0] || 'other', module: parts[1] || 'other' } +} + +/** 获取模块中文标签 */ +export function getModuleLabel(mod: string): string { + return moduleLabelMap[mod] || mod +} + +/** 将权限列表按模块分组 */ +export function groupPermissionsByModule(permissions: SysPermission[]): PermissionGroup[] { + const map = new Map() + for (const perm of permissions) { + const { category, module } = parseModuleFromCode(perm.permissionCode) + const key = `${category}:${module}` + if (!map.has(key)) { + map.set(key, { category, module, moduleLabel: getModuleLabel(module), permissions: [] }) + } + map.get(key)!.permissions.push(perm) + } + // 业务模块在前,系统模块在后;同类别按模块名排序 + return [...map.values()].sort((a, b) => { + if (a.category !== b.category) return a.category === 'business' ? -1 : 1 + return a.module.localeCompare(b.module) + }) +} + +// ==================== 角色 API ==================== + +/** 获取所有角色 */ +export function getAllRoles(): Promise { + return request.get('/api/roles') +} + +/** 分页获取角色 */ +export function getRolesByPage(params: { + page?: number + size?: number + sort?: string + order?: string + keyword?: string +}): Promise { + return request.get('/api/roles/page', { params }) +} + +/** 获取角色详情 */ +export function getRoleById(id: number): Promise { + return request.get(`/api/roles/${id}`) +} + +/** 创建角色 */ +export function createRole(data: CreateRoleDto): Promise { + return request.post('/api/roles', data) +} + +/** 更新角色 */ +export function updateRole(id: number, data: UpdateRoleDto): Promise { + return request.put(`/api/roles/${id}`, data) +} + +/** 删除角色(逻辑删除) */ +export function deleteRole(id: number): Promise { + return request.delete(`/api/roles/${id}`) +} + +/** 恢复角色 */ +export function restoreRole(id: number): Promise { + return request.post(`/api/roles/${id}/restore`) +} + +// ==================== 角色权限关联 API ==================== + +/** 获取角色的权限列表 */ +export function getRolePermissions(roleId: number): Promise { + return request.get(`/api/roles/${roleId}/permissions`) +} + +/** 为角色分配权限 */ +export function assignPermissionsToRole(roleId: number, permissionIds: number[]): Promise { + return request.post(`/api/roles/${roleId}/permissions`, { permissionIds }) +} + +// ==================== 权限 API ==================== + +/** 获取所有权限 */ +export function getAllPermissions(): Promise { + return request.get('/api/permissions') +} + +/** 获取权限详情 */ +export function getPermissionById(id: number): Promise { + return request.get(`/api/permissions/${id}`) +} + +/** 创建权限 */ +export function createPermission(data: CreatePermissionDto): Promise { + return request.post('/api/permissions', data) +} + +/** 更新权限 */ +export function updatePermission(id: number, data: SysPermission): Promise { + return request.put(`/api/permissions/${id}`, data) +} + +/** 删除权限 */ +export function deletePermission(id: number): Promise { + return request.delete(`/api/permissions/${id}`) +} diff --git a/gym-manage-cuit/src/components/AppLayout.vue b/gym-manage-cuit/src/components/AppLayout.vue new file mode 100644 index 0000000..1a9a01f --- /dev/null +++ b/gym-manage-cuit/src/components/AppLayout.vue @@ -0,0 +1,651 @@ + + + + + + + \ No newline at end of file diff --git a/gym-manage-cuit/src/composables/useToast.ts b/gym-manage-cuit/src/composables/useToast.ts new file mode 100644 index 0000000..e8c5dd5 --- /dev/null +++ b/gym-manage-cuit/src/composables/useToast.ts @@ -0,0 +1,29 @@ +import { ref } from 'vue' + +type ToastType = 'success' | 'error' | 'info' + +interface ToastItem { + id: number + message: string + type: ToastType +} + +let nextId = 0 +const toasts = ref([]) + +function push(message: string, type: ToastType = 'info') { + const id = nextId++ + toasts.value.push({ id, message, type }) + setTimeout(() => { + toasts.value = toasts.value.filter((t) => t.id !== id) + }, 2500) +} + +export function useToast() { + return { + toasts, + success: (msg: string) => push(msg, 'success'), + error: (msg: string) => push(msg, 'error'), + info: (msg: string) => push(msg, 'info'), + } +} diff --git a/gym-manage-cuit/src/main.ts b/gym-manage-cuit/src/main.ts new file mode 100644 index 0000000..fda1e6e --- /dev/null +++ b/gym-manage-cuit/src/main.ts @@ -0,0 +1,12 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/gym-manage-cuit/src/router/index.ts b/gym-manage-cuit/src/router/index.ts new file mode 100644 index 0000000..eb9aa97 --- /dev/null +++ b/gym-manage-cuit/src/router/index.ts @@ -0,0 +1,119 @@ +import { createRouter, createWebHistory } from 'vue-router' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + redirect: '/dashboard', + }, + { + path: '/login', + name: 'Login', + component: () => import('@/views/Login.vue'), + meta: { title: '登录' }, + }, + { + path: '/dashboard', + name: 'Dashboard', + component: () => import('@/views/Dashboard.vue'), + meta: { title: '仪表盘', requiresAuth: true }, + }, + { + path: '/group-course', + name: 'GroupCourse', + component: () => import('@/views/GroupCourse.vue'), + meta: { title: '团课管理', requiresAuth: true }, + }, + { + path: '/group-course-recommend', + name: 'GroupCourseRecommend', + component: () => import('@/views/GroupCourseRecommend.vue'), + meta: { title: '推荐团课管理', requiresAuth: true }, + }, + { + path: '/group-course-cancel', + name: 'GroupCourseCancel', + component: () => import('@/views/GroupCourseCancel.vue'), + meta: { title: '取消团课', requiresAuth: true }, + }, + { + path: '/group-course-types', + name: 'GroupCourseType', + component: () => import('@/views/GroupCourseType.vue'), + meta: { title: '类型管理', requiresAuth: true }, + }, + { + path: '/coach-manage', + name: 'CoachManage', + component: () => import('@/views/CoachManage.vue'), + meta: { title: '教练管理', requiresAuth: true }, + }, + { + path: '/member-manage', + name: 'MemberManage', + component: () => import('@/views/MemberManage.vue'), + meta: { title: '会员管理', requiresAuth: true }, + }, + { + path: '/member-card-manage', + name: 'MemberCardManage', + component: () => import('@/views/MemberCardManage.vue'), + meta: { title: '会员卡管理', requiresAuth: true }, + }, + { + path: '/member-signin', + name: 'MemberSignIn', + component: () => import('@/views/MemberSignIn.vue'), + meta: { title: '签到明细', requiresAuth: true }, + }, + { + path: '/data-report', + name: 'DataReport', + component: () => import('@/views/DataReport.vue'), + meta: { title: '数据报表', requiresAuth: true }, + }, + { + path: '/operation-log', + name: 'OperationLog', + component: () => import('@/views/OperationLog.vue'), + meta: { title: '操作日志', requiresAuth: true }, + }, + { + path: '/employee-manage', + name: 'EmployeeManage', + component: () => import('@/views/EmployeeManage.vue'), + meta: { title: '账号管理', requiresAuth: true }, + }, + { + path: '/role-manage', + name: 'RoleManage', + component: () => import('@/views/RoleManage.vue'), + meta: { title: '角色权限', requiresAuth: true }, + }, + { + path: '/notice-manage', + name: 'NoticeManage', + component: () => import('@/views/NoticeManage.vue'), + meta: { title: '系统公告', requiresAuth: true }, + }, + { + path: '/dict-manage', + name: 'DictManage', + component: () => import('@/views/DictManage.vue'), + meta: { title: '字典管理', requiresAuth: true }, + }, + ], +}) + +router.beforeEach((to) => { + const token = localStorage.getItem('accessToken') + if (to.meta.requiresAuth && !token) { + return '/login' + } + if (to.path === '/login' && token) { + return '/dashboard' + } +}) + +export default router \ No newline at end of file diff --git a/gym-manage-cuit/src/stores/auth.ts b/gym-manage-cuit/src/stores/auth.ts new file mode 100644 index 0000000..4b91e75 --- /dev/null +++ b/gym-manage-cuit/src/stores/auth.ts @@ -0,0 +1,88 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { login as loginApi, type UserInfo } from '@/api/auth' +import request from '@/api/request' + +function safeJsonParse(key: string): T | null { + try { + const raw = localStorage.getItem(key) + if (!raw) return null + return JSON.parse(raw) + } catch { + localStorage.removeItem(key) + return null + } +} + +export const useAuthStore = defineStore('auth', () => { + const accessToken = ref(localStorage.getItem('accessToken') || '') + const refreshToken = ref(localStorage.getItem('refreshToken') || '') + const userInfo = ref(safeJsonParse('userInfo')) + const permissions = ref(safeJsonParse('userPermissions') || []) + const roleNames = ref(safeJsonParse('userRoleNames') || []) + + const isLoggedIn = computed(() => !!accessToken.value) + const nickname = computed(() => userInfo.value?.nickname || '管理员') + const username = computed(() => userInfo.value?.username || '') + const isAdmin = computed(() => userInfo.value?.id === 1) + const roleDisplay = computed(() => roleNames.value.length > 0 ? roleNames.value.join('、') : '管理员') + const hasPermission = (code: string) => { + return permissions.value.some((p) => p === code || p.startsWith(code + ':')) + } + + async function login(username: string, password: string) { + const res = await loginApi({ username, password }) + // 兼容两种响应格式:{ code, message, data } 包裹 或 直接返回 login data + const data = res.data ?? res + accessToken.value = data.accessToken + refreshToken.value = data.refreshToken + userInfo.value = data.userInfo + + localStorage.setItem('accessToken', accessToken.value) + localStorage.setItem('refreshToken', refreshToken.value) + localStorage.setItem('userInfo', JSON.stringify(userInfo.value)) + + // 登录后获取用户权限 + await fetchPermissions() + } + + async function fetchPermissions() { + if (!userInfo.value?.id) return + try { + const roles: any[] = await request.get(`/api/users/${userInfo.value.id}/roles`) + if (!roles.length) return + const allCodes: string[] = [] + const names: string[] = [] + for (const role of roles) { + if (role.roleName) names.push(role.roleName) + try { + const perms: any[] = await request.get(`/api/roles/${role.id}/permissions`) + for (const p of perms) { + if (p.permissionCode && !allCodes.includes(p.permissionCode)) { + allCodes.push(p.permissionCode) + } + } + } catch { /* skip */ } + } + permissions.value = allCodes + roleNames.value = names + localStorage.setItem('userPermissions', JSON.stringify(allCodes)) + localStorage.setItem('userRoleNames', JSON.stringify(names)) + } catch { /* ignore */ } + } + + function logout() { + accessToken.value = '' + refreshToken.value = '' + userInfo.value = null + permissions.value = [] + roleNames.value = [] + localStorage.removeItem('accessToken') + localStorage.removeItem('refreshToken') + localStorage.removeItem('userInfo') + localStorage.removeItem('userPermissions') + localStorage.removeItem('userRoleNames') + } + + return { accessToken, refreshToken, userInfo, permissions, roleNames, isLoggedIn, nickname, username, isAdmin, roleDisplay, hasPermission, login, fetchPermissions, logout } +}) \ No newline at end of file diff --git a/gym-manage-cuit/src/utils/ossUpload.ts b/gym-manage-cuit/src/utils/ossUpload.ts new file mode 100644 index 0000000..360966d --- /dev/null +++ b/gym-manage-cuit/src/utils/ossUpload.ts @@ -0,0 +1,56 @@ +import request from '@/api/request' + +interface UploadResult { + success: boolean + message: string + url: string +} + +/** + * 上传团课封面图片(通过后端API上传到阿里云OSS,base64方式) + * @param file 图片文件 + * @returns OSS访问地址 + */ +export async function uploadCourseImage(file: File): Promise { + const base64 = await fileToBase64(file) + const ext = file.name.split('.').pop() || 'png' + + const result = await request.post( + '/api/groupCourse/upload/cover', + { image: base64, filename: file.name, extension: ext }, + ) + + if (result.success && result.url) { + return result.url + } + + throw new Error(result.message || '上传失败') +} + +function fileToBase64(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onload = () => { + const result = reader.result as string + // 去掉 data:image/xxx;base64, 前缀 + const base64 = result.split(',')[1] + if (!base64) { + reject(new Error('读取文件失败')) + return + } + resolve(base64) + } + reader.onerror = () => reject(new Error('读取文件失败')) + reader.readAsDataURL(file) + }) +} + +/** + * 将OSS原始URL转为后端代理URL,用于前端安全展示图片 + * @param ossUrl OSS原始访问地址 + * @returns 代理URL + */ +export function getProxyUrl(ossUrl: string): string { + if (!ossUrl) return '' + return `/api/groupCourse/cover-image/proxy?url=${encodeURIComponent(ossUrl)}` +} diff --git a/gym-manage-cuit/src/views/CoachManage.vue b/gym-manage-cuit/src/views/CoachManage.vue new file mode 100644 index 0000000..94d13bb --- /dev/null +++ b/gym-manage-cuit/src/views/CoachManage.vue @@ -0,0 +1,464 @@ + + + + + diff --git a/gym-manage-cuit/src/views/Dashboard-script.txt b/gym-manage-cuit/src/views/Dashboard-script.txt new file mode 100644 index 0000000..47c8096 --- /dev/null +++ b/gym-manage-cuit/src/views/Dashboard-script.txt @@ -0,0 +1,124 @@ + diff --git a/gym-manage-cuit/src/views/Dashboard.vue b/gym-manage-cuit/src/views/Dashboard.vue new file mode 100644 index 0000000..8fc6e03 --- /dev/null +++ b/gym-manage-cuit/src/views/Dashboard.vue @@ -0,0 +1,617 @@ + + + + + diff --git a/gym-manage-cuit/src/views/DataReport.vue b/gym-manage-cuit/src/views/DataReport.vue new file mode 100644 index 0000000..b45d059 --- /dev/null +++ b/gym-manage-cuit/src/views/DataReport.vue @@ -0,0 +1,599 @@ + + + + + diff --git a/gym-manage-cuit/src/views/DictManage.vue b/gym-manage-cuit/src/views/DictManage.vue new file mode 100644 index 0000000..6698466 --- /dev/null +++ b/gym-manage-cuit/src/views/DictManage.vue @@ -0,0 +1,923 @@ + + + + + diff --git a/gym-manage-cuit/src/views/EmployeeManage.vue b/gym-manage-cuit/src/views/EmployeeManage.vue new file mode 100644 index 0000000..0873844 --- /dev/null +++ b/gym-manage-cuit/src/views/EmployeeManage.vue @@ -0,0 +1,1273 @@ + + + + + diff --git a/gym-manage-cuit/src/views/GroupCourse.vue b/gym-manage-cuit/src/views/GroupCourse.vue new file mode 100644 index 0000000..657cc18 --- /dev/null +++ b/gym-manage-cuit/src/views/GroupCourse.vue @@ -0,0 +1,1386 @@ + + + + + diff --git a/gym-manage-cuit/src/views/GroupCourseCancel.vue b/gym-manage-cuit/src/views/GroupCourseCancel.vue new file mode 100644 index 0000000..d7a9563 --- /dev/null +++ b/gym-manage-cuit/src/views/GroupCourseCancel.vue @@ -0,0 +1,596 @@ + + + + + diff --git a/gym-manage-cuit/src/views/GroupCourseRecommend.vue b/gym-manage-cuit/src/views/GroupCourseRecommend.vue new file mode 100644 index 0000000..e23f233 --- /dev/null +++ b/gym-manage-cuit/src/views/GroupCourseRecommend.vue @@ -0,0 +1,396 @@ + + + + + \ No newline at end of file diff --git a/gym-manage-cuit/src/views/GroupCourseType.vue b/gym-manage-cuit/src/views/GroupCourseType.vue new file mode 100644 index 0000000..9156424 --- /dev/null +++ b/gym-manage-cuit/src/views/GroupCourseType.vue @@ -0,0 +1,981 @@ + + + + + diff --git a/gym-manage-cuit/src/views/Login.vue b/gym-manage-cuit/src/views/Login.vue new file mode 100644 index 0000000..ac9d5ff --- /dev/null +++ b/gym-manage-cuit/src/views/Login.vue @@ -0,0 +1,259 @@ + + + + + \ No newline at end of file diff --git a/gym-manage-cuit/src/views/MemberCardManage.vue b/gym-manage-cuit/src/views/MemberCardManage.vue new file mode 100644 index 0000000..c6ee2ef --- /dev/null +++ b/gym-manage-cuit/src/views/MemberCardManage.vue @@ -0,0 +1,817 @@ + + + + + diff --git a/gym-manage-cuit/src/views/MemberManage.vue b/gym-manage-cuit/src/views/MemberManage.vue new file mode 100644 index 0000000..402e592 --- /dev/null +++ b/gym-manage-cuit/src/views/MemberManage.vue @@ -0,0 +1,1028 @@ + + + + + diff --git a/gym-manage-cuit/src/views/MemberSignIn.vue b/gym-manage-cuit/src/views/MemberSignIn.vue new file mode 100644 index 0000000..0000d43 --- /dev/null +++ b/gym-manage-cuit/src/views/MemberSignIn.vue @@ -0,0 +1,887 @@ + + + + + diff --git a/gym-manage-cuit/src/views/NoticeManage.vue b/gym-manage-cuit/src/views/NoticeManage.vue new file mode 100644 index 0000000..b60b75f --- /dev/null +++ b/gym-manage-cuit/src/views/NoticeManage.vue @@ -0,0 +1,592 @@ + + + + + diff --git a/gym-manage-cuit/src/views/OperationLog.vue b/gym-manage-cuit/src/views/OperationLog.vue new file mode 100644 index 0000000..706e7c4 --- /dev/null +++ b/gym-manage-cuit/src/views/OperationLog.vue @@ -0,0 +1,1172 @@ + + + + + diff --git a/gym-manage-cuit/src/views/RoleManage.vue b/gym-manage-cuit/src/views/RoleManage.vue new file mode 100644 index 0000000..038f50e --- /dev/null +++ b/gym-manage-cuit/src/views/RoleManage.vue @@ -0,0 +1,1427 @@ + + + + + diff --git a/gym-manage-cuit/tsconfig.app.json b/gym-manage-cuit/tsconfig.app.json new file mode 100644 index 0000000..c0f2d86 --- /dev/null +++ b/gym-manage-cuit/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + // Extra safety for array and object lookups, but may have false positives. + "noUncheckedIndexedAccess": true, + + // Path mapping for cleaner imports. + "paths": { + "@/*": ["./src/*"] + }, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + } +} diff --git a/gym-manage-cuit/tsconfig.json b/gym-manage-cuit/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/gym-manage-cuit/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/gym-manage-cuit/tsconfig.node.json b/gym-manage-cuit/tsconfig.node.json new file mode 100644 index 0000000..c9b2bad --- /dev/null +++ b/gym-manage-cuit/tsconfig.node.json @@ -0,0 +1,27 @@ +// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping. +{ + "extends": "@tsconfig/node24/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + // Most tools use transpilation instead of Node.js's native type-stripping. + // Bundler mode provides a smoother developer experience. + "module": "preserve", + "moduleResolution": "bundler", + + // Include Node.js types and avoid accidentally including other `@types/*` packages. + "types": ["node"], + + // Disable emitting output during `vue-tsc --build`, which is used for type-checking only. + "noEmit": true, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" + } +} diff --git a/gym-manage-cuit/vite.config.ts b/gym-manage-cuit/vite.config.ts new file mode 100644 index 0000000..9084fdb --- /dev/null +++ b/gym-manage-cuit/vite.config.ts @@ -0,0 +1,28 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, + server: { + proxy: { + '/api': { + target: 'http://localhost:8084', + changeOrigin: true + }, + }, + }, + // 🔑 新增:配置部署子路径 + base: '/cuit/', +}) \ No newline at end of file diff --git a/log.text b/log.text new file mode 100644 index 0000000..144d7f0 --- /dev/null +++ b/log.text @@ -0,0 +1,506 @@ +2026-06-23T10:54:53.046+08:00 TRACE 26872 --- [gym-manage-api] [io-8084-exec-10] o.s.w.s.adapter.HttpWebHandlerAdapter : [417bbf24] HTTP POST "/api/groupCourse/upload/cover", headers={masked} +2026-06-23T10:54:53.049+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-12] o.s.w.s.s.DefaultWebSessionManager : Created new WebSession. +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dictionaries" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/change-password" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/logical-delete" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/logical-delete" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/action/restore" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/restore" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/roles" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/menus" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles/{id}/restore" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles/{id}/permissions" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/config" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/login" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/exception" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/operation" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/login" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/register" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.052+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/logout" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/cuit/auth/login" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dict/types" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dict/data" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/notices" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/messages" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/files/upload" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/permissions" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/auth/miniapp/login" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/auth/mp/callback" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/phone/bind" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/admin/member/{id}/phone" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/admin/verify-password" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-cards" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/purchase" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/renew" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/use" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/refund" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/process-expired" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-transactions" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/page" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{id}/delete" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/labels" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{typeId}/labels" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{typeId}/labels/delete-batch" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/book" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/booking/{bookingId}/cancel" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend/{id}/enable" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend/{id}/disable" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/{id}/cancel" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/signin/{memberId}" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/search" does not match against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/upload/cover" matches against value "/api/groupCourse/upload/cover" +2026-06-23T10:54:53.053+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.function.server.RouterFunctions : [417bbf24] Matched (POST && /api/groupCourse/upload/cover) +2026-06-23T10:54:53.053+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-12] o.s.w.r.f.s.s.RouterFunctionMapping : [417bbf24] Mapped to cn.novalon.gym.manage.app.config.SystemRouter$$Lambda/0x0000029da89d68b0@70fe15d +2026-06-23T10:54:53.057+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] org.springframework.web.HttpLogging : [417bbf24] Decoded [{image=/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAQ2BDgDASIAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAUGAQQHAwII/8QATxAAAgEEAAMFBwICBgYHBgYDAAECAwQFEQYhMQcSQVGRExRhcYGh0SKxMsEVFiMzQlIkQ1NicvAXJTRUkpPhNTZzdILxREVVY4OyVqLS/8QAGgEBAAMBAQEAAAAAAAAAAAAAAAECAwQFBv/EACgRAQEAAgICAwEBAQACAgMAAAABAhEDMQQhEkFRBRMiFDIVYSMzcf/aAAwDAQACEQMRAD8A7EADBUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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, filename=0db23e42d1ae03d34ea33d3c4c0c4d85.jpeg, extension=jpeg}] +2026-06-23T10:54:53.326+08:00 INFO 26872 --- [gym-manage-api] [ parallel-12] c.n.gym.manage.groupcourse.util.OSSUtil : 文件上传到OSS成功: localPath=C:\Users\29827\AppData\Local\Temp\course_cover_10550364472985404300\d12fa255-6f9c-4ece-a209-8b314e42c8a4.jpeg, ossUrl=https://ycc-filesaver.oss-cn-beijing.aliyuncs.com/course/d12fa255-6f9c-4ece-a209-8b314e42c8a4.jpeg +2026-06-23T10:54:53.328+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-12] org.springframework.web.HttpLogging : [417bbf24] Encoding [{success=true, message=上传成功, url=https://ycc-filesaver.oss-cn-beijing.aliyuncs.com/course/d12fa255-6f9c-4ece-a209-8b314e42c8a4.jpeg}] +2026-06-23T10:54:53.330+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-12] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO sys_operation_log (username, operation, method, params, result, ip, duration, status, id, create_by, update_by, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)] +2026-06-23T10:54:53.333+08:00 INFO 26872 --- [gym-manage-api] [actor-tcp-nio-1] c.n.g.m.sys.audit.OperationLogWebFilter : 操作日志保存成功: 团课管理 - 上传团课封面 +2026-06-23T10:54:53.333+08:00 TRACE 26872 --- [gym-manage-api] [actor-tcp-nio-1] o.s.w.s.adapter.HttpWebHandlerAdapter : [417bbf24] Completed 200 OK, headers={masked} +2026-06-23T10:54:53.334+08:00 TRACE 26872 --- [gym-manage-api] [actor-tcp-nio-1] org.springframework.web.HttpLogging : [417bbf24] onComplete +2026-06-23T10:54:53.339+08:00 TRACE 26872 --- [gym-manage-api] [nio-8084-exec-6] o.s.w.s.adapter.HttpWebHandlerAdapter : [1b87f544] HTTP POST "/api/groupCourse", headers={masked} +2026-06-23T10:54:53.345+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-1] o.s.w.s.s.DefaultWebSessionManager : Created new WebSession. +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dictionaries" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/change-password" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/logical-delete" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/logical-delete" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/action/restore" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/action/restore" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/users/{id}/roles" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/menus" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles/{id}/restore" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/roles/{id}/permissions" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/config" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/login" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/exception" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/logs/operation" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.347+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/login" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/register" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/auth/logout" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/cuit/auth/login" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dict/types" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/dict/data" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/notices" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/messages" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/files/upload" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/permissions" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/auth/miniapp/login" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/auth/mp/callback" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member/phone/bind" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/admin/member/{id}/phone" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/admin/verify-password" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-cards" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/purchase" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/renew" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/use" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/{recordId}/refund" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-records/process-expired" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/member-card-transactions" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/page" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{id}/delete" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/labels" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{typeId}/labels" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/types/{typeId}/labels/delete-batch" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/book" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/booking/{bookingId}/cancel" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.348+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "PUT" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "DELETE" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend/{id}/enable" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse/recommend/{id}/disable" does not match against value "/api/groupCourse" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "GET" does not match against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Method "POST" matches against value "POST" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.server.RequestPredicates : Pattern "/api/groupCourse" matches against value "/api/groupCourse" +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.function.server.RouterFunctions : [1b87f544] Matched (POST && /api/groupCourse) +2026-06-23T10:54:53.349+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-1] o.s.w.r.f.s.s.RouterFunctionMapping : [1b87f544] Mapped to cn.novalon.gym.manage.app.config.SystemRouter$$Lambda/0x0000029da89d5c20@1a5e19fe +2026-06-23T10:54:53.349+08:00 TRACE 26872 --- [gym-manage-api] [ parallel-1] org.springframework.web.HttpLogging : [1b87f544] Decoded [cn.novalon.gym.manage.groupcourse.domain.GroupCourse@0] +2026-06-23T10:54:53.349+08:00 INFO 26872 --- [gym-manage-api] [ parallel-1] c.n.g.m.g.c.GroupCourseConverter : 转换bean,domain-entity: +2026-06-23T10:54:53.351+08:00 DEBUG 26872 --- [gym-manage-api] [ parallel-1] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO group_course (course_name, coach_id, course_type, max_members, current_members, status, location, cover_image, description, point_card_amount, stored_value_amount, create_by, update_by, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)] +2026-06-23T10:54:53.352+08:00 ERROR 26872 --- [gym-manage-api] [actor-tcp-nio-1] c.n.g.m.g.s.impl.GroupCourseService : 团课创建失败 - error: executeMany; SQL [INSERT INTO group_course (course_name, coach_id, course_type, max_members, current_members, status, location, cover_image, description, point_card_amount, stored_value_amount, create_by, update_by, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)]; null value in column "start_time" of relation "group_course" violates not-null constraint +2026-06-23T10:54:53.352+08:00 TRACE 26872 --- [gym-manage-api] [actor-tcp-nio-1] org.springframework.web.HttpLogging : [1b87f544] Encoding [{success=false, message=executeMany; SQL [INSERT INTO group_course (course_name, coach_id, course_type, max_members, current_members, status, location, cover_image, description, point_card_amount, stored_value_amount, create_by, update_by, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)]; null value in column "start_time" of relation "group_course" violates not-null constraint}] +2026-06-23T10:54:53.353+08:00 DEBUG 26872 --- [gym-manage-api] [actor-tcp-nio-1] o.s.r2dbc.core.DefaultDatabaseClient : Executing SQL statement [INSERT INTO sys_operation_log (username, operation, method, params, result, ip, duration, status, id, create_by, update_by, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)] +2026-06-23T10:54:53.355+08:00 INFO 26872 --- [gym-manage-api] [actor-tcp-nio-1] c.n.g.m.sys.audit.OperationLogWebFilter : 操作日志保存成功: 团课管理 - 创建团课 +2026-06-23T10:54:53.355+08:00 TRACE 26872 --- [gym-manage-api] [actor-tcp-nio-1] o.s.w.s.adapter.HttpWebHandlerAdapter : [1b87f544] Completed 400 BAD_REQUEST, headers={masked} +2026-06-23T10:54:53.355+08:00 TRACE 26872 --- [gym-manage-api] [actor-tcp-nio-1] org.springframework.web.HttpLogging : [1b87f544] onComplete diff --git a/log2.text b/log2.text new file mode 100644 index 0000000..a6a03ca --- /dev/null +++ b/log2.text @@ -0,0 +1,45 @@ +应用异常: TypeError: can't access property "attendRate", $setup.summary.bookingStatistics is null + default Dashboard.vue:422 + renderFnWithContext runtime-core.esm-bundler.js:702 + renderSlot runtime-core.esm-bundler.js:3277 + _sfc_render AppLayout.vue:252 + renderComponentRoot runtime-core.esm-bundler.js:4580 + componentUpdateFn runtime-core.esm-bundler.js:6223 + run reactivity.esm-bundler.js:260 + runIfDirty reactivity.esm-bundler.js:298 + callWithErrorHandling runtime-core.esm-bundler.js:199 + flushJobs runtime-core.esm-bundler.js:408 + promise callback*queueFlush runtime-core.esm-bundler.js:322 + queueJob runtime-core.esm-bundler.js:317 + scheduler runtime-core.esm-bundler.js:6274 + trigger reactivity.esm-bundler.js:288 + endBatch reactivity.esm-bundler.js:346 + notify reactivity.esm-bundler.js:637 + trigger reactivity.esm-bundler.js:611 + set value reactivity.esm-bundler.js:1542 + fetchData Dashboard.vue:128 + createHook runtime-core.esm-bundler.js:3104 + callWithErrorHandling runtime-core.esm-bundler.js:199 + callWithAsyncErrorHandling runtime-core.esm-bundler.js:206 + __weh runtime-core.esm-bundler.js:3084 + flushPostFlushCbs runtime-core.esm-bundler.js:385 + flushJobs runtime-core.esm-bundler.js:427 + promise callback*queueFlush runtime-core.esm-bundler.js:322 + queuePostFlushCb runtime-core.esm-bundler.js:336 + queueEffectWithSuspense runtime-core.esm-bundler.js:7574 + scheduler runtime-core.esm-bundler.js:891 + scheduler reactivity.esm-bundler.js:1946 + trigger reactivity.esm-bundler.js:288 + endBatch reactivity.esm-bundler.js:346 + notify reactivity.esm-bundler.js:637 + trigger reactivity.esm-bundler.js:611 + set value reactivity.esm-bundler.js:1542 + finalizeNavigation vue-router.js:1348 + pushWithRedirect vue-router.js:1276 + promise callback*pushWithRedirect vue-router.js:1264 + push vue-router.js:1217 + handleLogin Login.vue:23 + cacheKey runtime-dom.esm-bundler.js:1857 + callWithErrorHandling runtime-core.esm-bundler.js:199 + callWithAsyncErrorHandling runtime-core.esm-bundler.js:206 + invoker \ No newline at end of file