commit 3f6131167822e70d3735debb03ab20b1d52fd8a4 Author: zhouwentao Date: Wed Dec 17 11:24:26 2025 +0800 初始化代码 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e0d590e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "core-comand", + "type": "go", + "request": "launch", + "mode": "auto", + // 运行目录 + "program": "${workspaceFolder}\\cmd\\core-command", + // 构建参数 + "buildFlags": "-tags=include_nats_messaging", + // 环境变量 + "env": { + "EDGEX_SECURITY_SECRET_STORE":"false", + // "GODEBUG":"schedtrace=100000" + }, + // 启动参数 ["-env" , 'prod'] + "args":[ + "-cp=consul.http://127.0.0.1:8500", "-o=true" + ] + }, + { + "name": "server", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/server", + "cwd": "${workspaceFolder}/server", + "env": {}, + "args": [] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5480842 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "kiroAgent.configureMCP": "Disabled" +} \ No newline at end of file diff --git a/Help.md b/Help.md new file mode 100644 index 0000000..af6da5c --- /dev/null +++ b/Help.md @@ -0,0 +1,46 @@ +#### 关于 Swagger 文档更新流程: + +新增接口后更新文档步骤: + +在 Controller 方法上添加 Swagger 注解(@Summary、@Param、@Router 等) +在 server 目录运行 swag init 重新生成文档 +重启服务器 +常用 Swagger 注解说明: + +```go +// @Summary 接口简介 +// @Description 详细描述 +// @Tags 分组标签 +// @Accept json +// @Produce json +// @Param name query/path/body 类型 是否必填 "描述" +// @Success 200 {object} Response "成功描述" +// @Failure 400 {object} Response "失败描述" +// @Router /path [get/post/put/delete] +``` + +#### 批量修改/新增/删除 + +Mapper 层: | 方法 | 说明 | |------|------| | UpdateFields(id, fields) | 动态字段更新,只更新指定字段 | | BatchCreate(items, batchSize) | 批量插入,分批处理 | | BatchUpdate(items) | 批量更新 (根据主键) | | BatchUpsert(items, updateColumns) | 批量插入或更新 (存在则更新) | | BatchDelete(ids) | 批量删除 | + +Service 层: 同样的方法,自动处理 UUID 生成。 + +使用示例: + +``` +// 动态字段更新 - 只更新指定字段 +service.UpdateFields("xxx-id", map[string]interface{}{ + "school_name": "新名称", + "plan_num": 100, +}) + +// 批量插入 +items := []entity.SchoolMajor{{...}, {...}} +service.BatchCreate(items) + +// 批量插入或更新 (存在则更新指定字段) +service.BatchUpsert(items, []string{"school_name", "plan_num"}) + +// 批量删除 +service.BatchDelete([]string{"id1", "id2", "id3"}) +``` \ No newline at end of file diff --git a/Task1.md b/Task1.md new file mode 100644 index 0000000..6162d08 --- /dev/null +++ b/Task1.md @@ -0,0 +1,121 @@ +#### mysql 配置 +url: jdbc:mysql://81.70.191.16:3306/yitisheng?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai +username: root +password: Db$7Hn#4Jm9Pq2!Xz +driver-class-name: com.mysql.cj.jdbc.Driver + +#### mysql中的表 +```sql +CREATE TABLE yitisheng.`yx_calculation_major_2025_2` ( + `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `score_id` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '成绩单id', + `school_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学校代码', + `major_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业代码', + `major_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业名称', + `enrollment_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '招生代码', + `tuition` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '学费', + `detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '备注', + `category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '科类(文科/理科)', + `rules_enroll_probability` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式', + `batch` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '批次', + `student_old_converted_score` decimal(10,4) DEFAULT '0.0000' COMMENT '学生的未换算折合分数', + `student_converted_score` decimal(10,4) DEFAULT '0.0000' COMMENT '学生的折合分数', + `enroll_probability` decimal(10,4) DEFAULT '0.0000' COMMENT '录取率', + `probability_operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取概率计算规则运算符', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `major_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业类型', + `major_type_child` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '二级专业类型', + `plan_num` int DEFAULT '0' COMMENT '计划招生人数', + `main_subjects` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '主考科目', + `limitation` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '院校限制', + `other_score_limitation` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '其他分数限制', + `rules_enroll_probability_sx` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式缩写', + `kslx` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '考试类型(统考/校考)', + `private_student_converted_score` decimal(10,4) DEFAULT '0.0000' COMMENT '内部折合分数', + `private_rules_enroll_probability` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '内部录取方式', + `private_probability_operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '内部录取方式运算符', + `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '状态', + PRIMARY KEY (`id`) USING BTREE, + KEY `a_score_id` (`score_id`), + KEY `a_id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- yitisheng.yx_school_major definition + +CREATE TABLE `yx_school_major` ( + `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `school_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学校代码', + `school_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学校名称', + `major_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业代码', + `major_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业名称', + `major_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业类型', + `major_type_child` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '二级专业类型', + `main_subjects` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '主考科目', + `enrollment_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '招生代码', + `category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '科类(文科/理科)', + `batch` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '批次', + `tuition` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '学费', + `plan_num` int DEFAULT '0' COMMENT '计划招生人数', + `detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '备注', + `semester` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学制', + `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新日期', + `rules_enroll_probability_sx` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式缩写', + `rules_enroll_probability` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式', + `probability_operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取概率计算规则运算符', + `cultural_control_line` decimal(10,4) DEFAULT '0.0000' COMMENT '文化分省控线', + `special_control_line` decimal(10,4) DEFAULT '0.0000' COMMENT '专项分数线', + `check_master` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否使用主项成绩', + `limitation` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '院校限制', + `professional_score_limitation` decimal(10,4) DEFAULT '0.0000' COMMENT '专业分数限制', + `english_score_limitation` decimal(10,4) DEFAULT '0.0000' COMMENT '英语成绩限制', + `chinese_score_limitation` decimal(10,4) DEFAULT '0.0000' COMMENT '语文成绩限制', + `cultural_score_limitation` decimal(10,4) DEFAULT '0.0000' COMMENT '文化分数限制', + `kslx` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '统考' COMMENT '考试类型(统考/校考)', + `private_probability_operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '内部展示录取方式运算符', + `private_rules_enroll_probability` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '内部录取方式', + `state` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '使用状态', + PRIMARY KEY (`id`) USING BTREE, + KEY `s_state` (`state`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='院校专业关联表'; + +-- yitisheng.yx_history_major_enroll definition + +CREATE TABLE `yx_history_major_enroll` ( + `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `school_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学校代码', + `school_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学校名称', + `institution_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '院校代码', + `major_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业代码', + `major_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业名称', + `major_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业类型', + `enrollment_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '招生代码', + `category` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '科类', + `year` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '年份', + `enroll_num` int DEFAULT '0' COMMENT '招生人数', + `score_line_difference` decimal(10,2) DEFAULT '0.00' COMMENT '最低分数差', + `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新日期', + `sys_org_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '所属部门', + `detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '备注', + `rules_enroll_probability` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式', + `control_line` decimal(10,4) DEFAULT '0.0000' COMMENT '省控线', + `admission_line` decimal(10,4) DEFAULT '0.0000' COMMENT '录取线', + `probability_operator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '录取方式运算符', + `batch` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '批次', + `one_volunteer_admission_num` int DEFAULT '0' COMMENT '一志愿录取数', + `admission_num` int DEFAULT '0' COMMENT '录取人数', + `actual_pitcher_num` int DEFAULT '0' COMMENT '实际投档人数', + `check_master` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '是否使用主项成绩', + `major_type_child` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '专业类别子级', + `main_subjects` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '主考科目', + `tuition` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '学费', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='历年艺术类招生录取分数表'; +``` + +我需要分层架构,实现类似Java中的Entity,Mapper,Service,Controller。 diff --git a/Task2.md b/Task2.md new file mode 100644 index 0000000..66c0ff6 --- /dev/null +++ b/Task2.md @@ -0,0 +1,56 @@ +#### Redis +81.70.191.16:56379 +密码:Rd@5Wk8#Nv3Yt6$Bm +数据库:1 + +帮我增加Redis的使用。 + +```sql +-- yitisheng.sys_user definition + +CREATE TABLE `sys_user` ( + `id` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '主键id', + `username` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '登录账号', + `realname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '真实姓名', + `password` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '密码', + `salt` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT 'md5密码盐', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '头像', + `birthday` datetime DEFAULT NULL COMMENT '生日', + `sex` tinyint(1) DEFAULT NULL COMMENT '性别(0-默认未知,1-男,2-女)', + `email` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '电子邮件', + `phone` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '电话', + `org_code` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '登录会话的机构编码', + `status` tinyint(1) DEFAULT NULL COMMENT '性别(1-正常,2-冻结)', + `del_flag` tinyint(1) DEFAULT NULL COMMENT '删除状态(0-正常,1-已删除)', + `third_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '第三方登录的唯一标识', + `third_type` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '第三方类型', + `activiti_sync` tinyint(1) DEFAULT NULL COMMENT '同步工作流引擎(1-同步,0-不同步)', + `work_no` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '工号,唯一键', + `telephone` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '座机号', + `create_by` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `user_identity` tinyint(1) DEFAULT NULL COMMENT '身份(1普通成员 2上级)', + `depart_ids` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '负责部门', + `client_id` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '设备ID', + `login_tenant_id` int DEFAULT NULL COMMENT '上次登录选择租户ID', + `bpm_status` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '流程入职离职状态', + `wx_open_id` varchar(50) DEFAULT NULL COMMENT '微信openId', + `dy_open_id` varchar(50) DEFAULT NULL COMMENT '抖音openId', + `ip` varchar(255) DEFAULT NULL COMMENT '注册时ip地址', + `show_linediff` varchar(2) DEFAULT '0' COMMENT '是否显示历年线差', + `program_type` varchar(32) DEFAULT NULL COMMENT '所属程序', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uniq_sys_user_work_no` (`work_no`) USING BTREE, + UNIQUE KEY `uniq_sys_user_username` (`username`) USING BTREE, + UNIQUE KEY `uniq_sys_user_email` (`email`) USING BTREE, + KEY `idx_su_status` (`status`) USING BTREE, + KEY `idx_su_del_flag` (`del_flag`) USING BTREE, + KEY `idx_su_del_username` (`username`,`del_flag`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='用户表'; +``` + +增加modules/ 包,将目前calculation_major、history_major_enroll、school_major的相关代码及文件名均增加数据库表前缀(yx_这种),然后将yx_模块代码移动到modules/yx/模块下。 + +增加sys_user表的常规代码至modules/system/。以及封装用户登录和信息的代码,将用户的登录状态储存至Redis中,同时代码中接口需要登录鉴权后才可以访问(个别可使用类似Java的shiroFilterFactoryBean过滤必须登录鉴权才可访问),在接口代码中可以获取当前用户的登录信息。 diff --git a/server/.gitattributes b/server/.gitattributes new file mode 100644 index 0000000..1194292 --- /dev/null +++ b/server/.gitattributes @@ -0,0 +1 @@ +*.go linguist-language=Go \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..d9949e6 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,11 @@ +## ide +**/.idea +*.iml +rebel.xml + +## backend +**/target +**/logs + +## front +**/*.lock diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..942bef4 --- /dev/null +++ b/server/README.md @@ -0,0 +1,174 @@ +# 艺考招生管理系统 API + +基于 Go + Gin + GORM + Redis 的 RESTful API 服务。 + +## 技术栈 + +- Go 1.21+ +- Gin (Web框架) +- GORM (ORM框架) +- MySQL 8.0 +- Redis (会话存储/限流) +- Swaggo (API文档) + +## 项目结构 + +``` +server/ +├── main.go +├── config/ +│ ├── config.go # 应用配置 (日志/安全/限流) +│ ├── database.go # MySQL配置 +│ └── redis.go # Redis配置 +├── common/ +│ ├── response.go # 统一响应 +│ ├── context.go # 上下文工具 +│ ├── logger.go # 日志工具 +│ └── password.go # 密码加密 (PBE) +├── middleware/ +│ ├── auth.go # 登录鉴权 +│ ├── security.go # 安全校验 (防暴力入侵) +│ └── ratelimit.go # 接口限流 +├── modules/ +│ ├── system/ # 系统模块 +│ └── yx/ # 艺考模块 +├── logs/ # 日志目录 +│ └── 2025-12-17-1.html # HTML格式日志 +└── docs/ # Swagger文档 +``` + +## 快速开始 + +```bash +cd server +go mod tidy +swag init +go run main.go +``` + +## 配置说明 + +修改 `config/config.go`: + +```go +var AppConfig = &appConfig{ + // 日志配置 + Log: LogConfig{ + Level: "debug", // debug/info/warn/error + Dir: "logs", // 日志目录 + Console: true, // 是否输出到控制台 + }, + // 安全配置 + Security: SecurityConfig{ + Enable: true, // 是否启用 + HeaderKey: "X-App-Sign", // 签名字段 + SecretKey: "yts@2025#secure", // 签名密钥 + }, + // 限流配置 + RateLimit: RateLimitConfig{ + Enable: true, + Default: RateLimitRule{Interval: 2, MaxRequests: 1}, // 默认2秒1次 + Rules: map[string]RateLimitRule{ + "/api/auth/login": {Interval: 5, MaxRequests: 1}, // 登录5秒1次 + }, + }, +} +``` + +## 功能说明 + +### 1. 日志系统 + +- 支持 debug/info/warn/error 级别 +- 输出到 HTML 文件,按日期和启动次数命名 +- 可配置是否同时输出到控制台 + +```go +common.Debug("调试信息: %s", msg) +common.Info("普通信息: %s", msg) +common.Warn("警告信息: %s", msg) +common.LogError("错误信息: %s", msg) +``` + +### 2. 安全校验 (防暴力入侵) + +请求头需携带签名: +``` +X-App-Sign: MD5(timestamp + secretKey) +X-App-Timestamp: 毫秒时间戳 +``` + +前端签名示例 (JavaScript): +```javascript +const timestamp = Date.now().toString(); +const sign = md5(timestamp + 'yts@2025#secure'); + +fetch('/api/xxx', { + headers: { + 'X-App-Sign': sign, + 'X-App-Timestamp': timestamp, + 'Authorization': 'Bearer ' + token + } +}); +``` + +### 3. 接口限流 + +- 基于 Redis 滑动窗口算法 +- 支持按用户ID或IP限流 +- 不同接口可配置不同规则 + +默认规则: 2秒1次 +超过限制返回: `{"code": 429, "message": "操作过快,请稍后再试"}` + +配置示例: +```go +Rules: map[string]RateLimitRule{ + "/api/auth/login": {Interval: 5, MaxRequests: 1}, // 5秒1次 + "/api/yx-school-majors": {Interval: 1, MaxRequests: 5}, // 1秒5次 +} +``` + +## 中间件执行顺序 + +``` +请求 -> 安全校验 -> 限流 -> 登录鉴权 -> Controller +``` + +## 白名单配置 + +```go +// 安全校验白名单 +middleware.AddSecurityWhitelist("/api/public/xxx") + +// 限流白名单 +middleware.AddRateLimitWhitelist("/api/public/xxx") + +// 登录鉴权白名单 +middleware.AddWhiteList("/api/public/xxx") +``` + +## API 接口 + +### 认证 +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/auth/login | 登录 | +| POST | /api/auth/logout | 登出 | +| GET | /api/auth/info | 获取当前用户 | + +### 用户管理 `/api/sys-users` +### 院校专业 `/api/yx-school-majors` +### 历年招生 `/api/yx-history-enrolls` +### 计算专业 `/api/yx-calculation-majors` + +## 日志文件示例 + +日志以 HTML 格式保存,支持浏览器直接打开查看: + +``` +logs/ +├── 2025-12-17-1.html # 第1次启动 +├── 2025-12-17-2.html # 第2次启动 +└── 2025-12-18-1.html # 新的一天 +``` diff --git a/server/common/context.go b/server/common/context.go new file mode 100644 index 0000000..8301629 --- /dev/null +++ b/server/common/context.go @@ -0,0 +1,41 @@ +// Package common 公共包 +package common + +import ( + "server/modules/system/entity" + + "github.com/gin-gonic/gin" +) + +const ContextUserKey = "loginUser" + +// GetLoginUser 从上下文获取当前登录用户 +// 在Controller中使用: user := common.GetLoginUser(c) +func GetLoginUser(c *gin.Context) *entity.LoginUser { + value, exists := c.Get(ContextUserKey) + if !exists { + return nil + } + if user, ok := value.(*entity.LoginUser); ok { + return user + } + return nil +} + +// GetLoginUserID 获取当前登录用户ID +func GetLoginUserID(c *gin.Context) string { + user := GetLoginUser(c) + if user != nil { + return user.ID + } + return "" +} + +// GetLoginUsername 获取当前登录用户名 +func GetLoginUsername(c *gin.Context) string { + user := GetLoginUser(c) + if user != nil { + return user.Username + } + return "" +} diff --git a/server/common/logger.go b/server/common/logger.go new file mode 100644 index 0000000..4ada086 --- /dev/null +++ b/server/common/logger.go @@ -0,0 +1,210 @@ +// Package common 日志工具 +package common + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sync" + "time" + + "server/config" +) + +// 日志级别 +const ( + LevelDebug = iota + LevelInfo + LevelWarn + LevelError +) + +var levelNames = map[int]string{ + LevelDebug: "DEBUG", + LevelInfo: "INFO", + LevelWarn: "WARN", + LevelError: "ERROR", +} + +var levelValues = map[string]int{ + "debug": LevelDebug, + "info": LevelInfo, + "warn": LevelWarn, + "error": LevelError, +} + +// Logger 日志记录器 +type Logger struct { + level int + file *os.File + htmlWriter *htmlLogWriter + mu sync.Mutex + console bool +} + +var ( + defaultLogger *Logger + startCount int + once sync.Once +) + +// InitLogger 初始化日志 +func InitLogger() { + once.Do(func() { + cfg := config.AppConfig.Log + level := levelValues[cfg.Level] + + // 创建日志目录 + if err := os.MkdirAll(cfg.Dir, 0755); err != nil { + fmt.Println("创建日志目录失败:", err) + return + } + + // 计算启动次数 + startCount = getStartCount(cfg.Dir) + + // 创建日志文件 + filename := fmt.Sprintf("%s-%d.html", time.Now().Format("2006-01-02"), startCount) + logFilepath := filepath.Join(cfg.Dir, filename) + + file, err := os.OpenFile(logFilepath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + fmt.Println("创建日志文件失败:", err) + return + } + + htmlWriter := newHtmlLogWriter(file) + + defaultLogger = &Logger{ + level: level, + file: file, + htmlWriter: htmlWriter, + console: cfg.Console, + } + + fmt.Printf("日志文件: %s\n", logFilepath) + }) +} + +// getStartCount 获取今日启动次数 +func getStartCount(dir string) int { + today := time.Now().Format("2006-01-02") + pattern := filepath.Join(dir, today+"*.html") + matches, _ := filepath.Glob(pattern) + return len(matches) + 1 +} + +// CloseLogger 关闭日志 +func CloseLogger() { + if defaultLogger != nil && defaultLogger.file != nil { + defaultLogger.htmlWriter.writeFooter() + defaultLogger.file.Close() + } +} + +func (l *Logger) log(level int, format string, args ...interface{}) { + if l == nil || level < l.level { + return + } + + l.mu.Lock() + defer l.mu.Unlock() + + msg := fmt.Sprintf(format, args...) + timestamp := time.Now().Format("2006-01-02 15:04:05.000") + levelName := levelNames[level] + + // 写入HTML文件 + l.htmlWriter.writeLog(timestamp, levelName, msg) + + // 输出到控制台 + if l.console { + fmt.Printf("[%s] [%s] %s\n", timestamp, levelName, msg) + } +} + +// LogDebug 调试日志 +func LogDebug(format string, args ...interface{}) { + if defaultLogger != nil { + defaultLogger.log(LevelDebug, format, args...) + } +} + +// LogInfo 信息日志 +func LogInfo(format string, args ...interface{}) { + if defaultLogger != nil { + defaultLogger.log(LevelInfo, format, args...) + } +} + +// LogWarn 警告日志 +func LogWarn(format string, args ...interface{}) { + if defaultLogger != nil { + defaultLogger.log(LevelWarn, format, args...) + } +} + +// LogError 错误日志 +func LogError(format string, args ...interface{}) { + if defaultLogger != nil { + defaultLogger.log(LevelError, format, args...) + } +} + +// 简短别名 +var ( + Debug = LogDebug + Info = LogInfo + Warn = LogWarn +) + +// htmlLogWriter HTML日志写入器 +type htmlLogWriter struct { + writer io.Writer + initialized bool +} + +func newHtmlLogWriter(w io.Writer) *htmlLogWriter { + hw := &htmlLogWriter{writer: w} + hw.writeHeader() + return hw +} + +func (h *htmlLogWriter) writeHeader() { + html := ` + + + +应用日志 + + + +

应用日志 - ` + time.Now().Format("2006-01-02") + `

+
+` + h.writer.Write([]byte(html)) + h.initialized = true +} + +func (h *htmlLogWriter) writeLog(timestamp, level, msg string) { + html := fmt.Sprintf(`
[%s] [%s] %s
+`, level, timestamp, level, msg) + h.writer.Write([]byte(html)) +} + +func (h *htmlLogWriter) writeFooter() { + html := `
+ +` + h.writer.Write([]byte(html)) +} diff --git a/server/common/password.go b/server/common/password.go new file mode 100644 index 0000000..4cb7082 --- /dev/null +++ b/server/common/password.go @@ -0,0 +1,190 @@ +package common + +import ( + "bytes" + "crypto/cipher" + "crypto/des" + "crypto/md5" + "crypto/rand" + "encoding/hex" + "errors" + "fmt" +) + +// PasswordUtil 对应 Java 类的常量 +const ( + // DefaultSalt 对应 Java 中的 SALT = "63293188" + DefaultSalt = "63293188" + // IterationCount 对应 Java 中的 ITERATIONCOUNT = 1000 + IterationCount = 1000 +) + +// GetSalt 生成 8 字节的随机盐 +func GetSalt() ([]byte, error) { + salt := make([]byte, 8) + _, err := rand.Read(salt) + if err != nil { + return nil, err + } + return salt, nil +} + +// GetStaticSalt 获取静态盐 +func GetStaticSalt() []byte { + return []byte(DefaultSalt) +} + +// Encrypt 加密 +// plaintext: 明文 +// password: 密码 +// salt: 盐 (传入 string, 对应 Java 的 salt 参数) +func Encrypt(plaintext, password, salt string) (string, error) { + // 1. 生成 Key 和 IV + key, iv := deriveKeyAndIV(password, salt, IterationCount) + + // 2. 创建 DES Cipher + block, err := des.NewCipher(key) + if err != nil { + return "", err + } + + // 3. 处理数据 (UTF-8 转 bytes 并填充) + data := []byte(plaintext) + data = pkcs5Padding(data, block.BlockSize()) + + // 4. 加密 (CBC 模式) + blockMode := cipher.NewCBCEncrypter(block, iv) + crypted := make([]byte, len(data)) + blockMode.CryptBlocks(crypted, data) + + // 5. 转十六进制字符串 (对应 Java 的 bytesToHexString) + // Java 的 Integer.toHexString 产生的是小写,这里保持一致, + // 但通常十六进制可以互通。 + return hex.EncodeToString(crypted), nil +} + +// Decrypt 解密 +// ciphertext: 密文 (Hex 字符串) +// password: 密码 +// salt: 盐 +func Decrypt(ciphertext, password, salt string) (string, error) { + // 1. 生成 Key 和 IV + key, iv := deriveKeyAndIV(password, salt, IterationCount) + + // 2. Hex 字符串转 bytes + decodedBytes, err := hex.DecodeString(ciphertext) + if err != nil { + return "", err + } + + // 3. 创建 DES Cipher + block, err := des.NewCipher(key) + if err != nil { + return "", err + } + + // 4. 解密 (CBC 模式) + blockMode := cipher.NewCBCDecrypter(block, iv) + // 密文长度检查 + if len(decodedBytes)%block.BlockSize() != 0 { + return "", errors.New("ciphertext is not a multiple of the block size") + } + origData := make([]byte, len(decodedBytes)) + blockMode.CryptBlocks(origData, decodedBytes) + + // 5. 去除填充 + origData, err = pkcs5UnPadding(origData) + if err != nil { + return "", err + } + + return string(origData), nil +} + +// deriveKeyAndIV 模拟 Java PBEWithMD5AndDES 的密钥派生逻辑 +// 逻辑:MD5(password || salt) -> 迭代 -> 结果前8字节是Key,后8字节是IV +func deriveKeyAndIV(password, salt string, iterations int) ([]byte, []byte) { + // Java PBEKeySpec 处理 password 为 char[],通常转 byte 时依赖编码, + // 此处假设使用 UTF-8 兼容(Java 默认行为通常如此,或者 ASCII) + passBytes := []byte(password) + saltBytes := []byte(salt) + + // 第一次迭代: Hash(pass + salt) + hash := md5.New() + hash.Write(passBytes) + hash.Write(saltBytes) + derived := hash.Sum(nil) + + // 后续迭代: Hash(prev_hash) + for i := 1; i < iterations; i++ { + hash.Reset() + hash.Write(derived) + derived = hash.Sum(nil) + } + + // MD5 结果是 16 字节 + // DES Key 需要 8 字节,IV 需要 8 字节 + // 正好平分 + key := derived[:8] + iv := derived[8:] + + return key, iv +} + +// pkcs5Padding 填充 +func pkcs5Padding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} + +// pkcs5UnPadding 去除填充 +func pkcs5UnPadding(origData []byte) ([]byte, error) { + length := len(origData) + if length == 0 { + return nil, errors.New("decryption error: output length is zero") + } + unpadding := int(origData[length-1]) + if length < unpadding { + return nil, errors.New("decryption error: invalid padding") + } + return origData[:(length - unpadding)], nil +} + +// --- 测试主函数 --- +func main() { + // 测试数据 + plaintext := "admin" + password := "Wang5322570" + //salt := DefaultSalt + salt := "RCGTeGiH" + + fmt.Println("原文:", plaintext) + fmt.Println("密码:", password) + fmt.Println("盐值:", salt) + + // 加密 + encrypted, err := Encrypt(plaintext, password, salt) + if err != nil { + fmt.Println("加密失败:", err) + return + } + // Java代码可能输出小写或手动处理,这里使用 hex.EncodeToString (小写) + // 如果需要大写可以使用 strings.ToUpper(encrypted) + fmt.Println("加密密文 (Hex):", encrypted) + + // 解密 + decrypted, err := Decrypt(encrypted, password, salt) + if err != nil { + fmt.Println("解密失败:", err) + return + } + fmt.Println("解密原文:", decrypted) + + // 验证一致性 + if plaintext == decrypted { + fmt.Println(">> 测试通过!Go版本与逻辑一致。") + } else { + fmt.Println(">> 测试失败!") + } +} diff --git a/server/common/response.go b/server/common/response.go new file mode 100644 index 0000000..7dca734 --- /dev/null +++ b/server/common/response.go @@ -0,0 +1,35 @@ +// Package common 公共包 +package common + +import "github.com/gin-gonic/gin" + +// Response 统一响应结构 +type Response struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data"` +} + +// PageResponse 分页响应 +type PageResponse struct { + List interface{} `json:"list"` + Total int64 `json:"total"` + Page int `json:"page"` + Size int `json:"size"` +} + +func Success(c *gin.Context, data interface{}) { + c.JSON(200, Response{Code: 200, Message: "success", Data: data}) +} + +func SuccessPage(c *gin.Context, list interface{}, total int64, page, size int) { + c.JSON(200, Response{ + Code: 200, + Message: "success", + Data: PageResponse{List: list, Total: total, Page: page, Size: size}, + }) +} + +func Error(c *gin.Context, code int, message string) { + c.JSON(code, Response{Code: code, Message: message, Data: nil}) +} diff --git a/server/config/config.go b/server/config/config.go new file mode 100644 index 0000000..35d6824 --- /dev/null +++ b/server/config/config.go @@ -0,0 +1,60 @@ +// Package config 应用配置 +package config + +// AppConfig 应用配置 +var AppConfig = &appConfig{ + // 日志配置 + Log: LogConfig{ + Level: "debug", // debug/info/warn/error + Dir: "logs", // 日志目录 + Console: true, // 是否同时输出到控制台 + }, + // 安全配置 + Security: SecurityConfig{ + Enable: true, // 是否启用安全校验 + HeaderKey: "X-App-Sign", // 请求头校验字段 + SecretKey: "yts@2025#secure", // 签名密钥 + }, + // 限流配置 + RateLimit: RateLimitConfig{ + Enable: true, + Default: RateLimitRule{Interval: 2, MaxRequests: 3}, // 默认2秒1次 + Rules: map[string]RateLimitRule{ + "/api/auth/login": {Interval: 5, MaxRequests: 1}, // 登录5秒1次 + "/api/yx-school-majors": {Interval: 1, MaxRequests: 5}, // 查询1秒5次 + }, + }, +} + +type appConfig struct { + Log LogConfig + Security SecurityConfig + RateLimit RateLimitConfig +} + +// LogConfig 日志配置 +type LogConfig struct { + Level string // 日志级别 + Dir string // 日志目录 + Console bool // 是否输出到控制台 +} + +// SecurityConfig 安全配置 +type SecurityConfig struct { + Enable bool // 是否启用 + HeaderKey string // 请求头字段名 + SecretKey string // 签名密钥 +} + +// RateLimitConfig 限流配置 +type RateLimitConfig struct { + Enable bool // 是否启用 + Default RateLimitRule // 默认规则 + Rules map[string]RateLimitRule // 特定路径规则 +} + +// RateLimitRule 限流规则 +type RateLimitRule struct { + Interval int // 时间间隔(秒) + MaxRequests int // 最大请求次数 +} diff --git a/server/config/database.go b/server/config/database.go new file mode 100644 index 0000000..b337179 --- /dev/null +++ b/server/config/database.go @@ -0,0 +1,50 @@ +// Package config 配置包,负责应用程序的配置管理 +package config + +import ( + "fmt" + "log" + "time" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +// DB 全局数据库连接实例 +var DB *gorm.DB + +// InitDB 初始化数据库连接 +func InitDB() { + dsn := "root:Db$7Hn#4Jm9Pq2!Xz@tcp(81.70.191.16:3306)/yitisheng?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai" + + var err error + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + log.Fatal("数据库连接失败:", err) + } + + // 获取底层 sql.DB 以配置连接池 + sqlDB, err := DB.DB() + if err != nil { + log.Fatal("获取数据库实例失败:", err) + } + + // 连接池配置 + sqlDB.SetMaxIdleConns(10) // 最大空闲连接数 + sqlDB.SetMaxOpenConns(100) // 最大打开连接数 + sqlDB.SetConnMaxLifetime(time.Hour) // 连接最大存活时间 + + fmt.Println("数据库连接成功") +} + +// CloseDB 关闭数据库连接 +// 在程序退出时调用,释放所有连接 +func CloseDB() { + if DB != nil { + sqlDB, err := DB.DB() + if err == nil { + sqlDB.Close() + fmt.Println("数据库连接已关闭") + } + } +} diff --git a/server/config/redis.go b/server/config/redis.go new file mode 100644 index 0000000..d6e6fba --- /dev/null +++ b/server/config/redis.go @@ -0,0 +1,42 @@ +// Package config Redis配置 +package config + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/redis/go-redis/v9" +) + +// RDB 全局Redis客户端 +var RDB *redis.Client + +// InitRedis 初始化Redis连接 +func InitRedis() { + RDB = redis.NewClient(&redis.Options{ + Addr: "81.70.191.16:56379", + Password: "Rd@5Wk8#Nv3Yt6$Bm", + DB: 1, + PoolSize: 10, // 连接池大小 + }) + + // 测试连接 + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + _, err := RDB.Ping(ctx).Result() + if err != nil { + log.Fatal("Redis连接失败:", err) + } + fmt.Println("Redis连接成功") +} + +// CloseRedis 关闭Redis连接 +func CloseRedis() { + if RDB != nil { + RDB.Close() + fmt.Println("Redis连接已关闭") + } +} diff --git a/server/docs/docs.go b/server/docs/docs.go new file mode 100644 index 0000000..85fca27 --- /dev/null +++ b/server/docs/docs.go @@ -0,0 +1,1448 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/auth/info": { + "get": { + "tags": [ + "认证" + ], + "summary": "获取当前登录用户信息", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/auth/login": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "认证" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "登录信息", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.LoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/auth/logout": { + "post": { + "tags": [ + "认证" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users": { + "get": { + "tags": [ + "用户管理" + ], + "summary": "获取用户列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "用户管理" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users/{id}": { + "get": { + "tags": [ + "用户管理" + ], + "summary": "获取单个用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "用户管理" + ], + "summary": "更新用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "用户信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "用户管理" + ], + "summary": "删除用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "用户管理" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users/{id}/password": { + "put": { + "tags": [ + "用户管理" + ], + "summary": "修改密码", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "密码信息", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.UpdatePasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors": { + "get": { + "tags": [ + "计算专业" + ], + "summary": "获取计算专业列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "计算专业" + ], + "summary": "创建计算专业", + "parameters": [ + { + "description": "计算专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors/batch": { + "post": { + "tags": [ + "计算专业" + ], + "summary": "批量创建计算专业", + "parameters": [ + { + "description": "计算专业列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "计算专业" + ], + "summary": "批量删除计算专业", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors/{id}": { + "get": { + "tags": [ + "计算专业" + ], + "summary": "获取单个计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "计算专业" + ], + "summary": "更新计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "计算专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "计算专业" + ], + "summary": "删除计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "计算专业" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls": { + "get": { + "tags": [ + "历年招生" + ], + "summary": "获取历年招生列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "历年招生" + ], + "summary": "创建历年招生记录", + "parameters": [ + { + "description": "历年招生信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls/batch": { + "post": { + "tags": [ + "历年招生" + ], + "summary": "批量创建历年招生记录", + "parameters": [ + { + "description": "历年招生列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "历年招生" + ], + "summary": "批量删除历年招生记录", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls/{id}": { + "get": { + "tags": [ + "历年招生" + ], + "summary": "获取单个历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "历年招生" + ], + "summary": "更新历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "历年招生信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "历年招生" + ], + "summary": "删除历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "历年招生" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors": { + "get": { + "tags": [ + "院校专业" + ], + "summary": "获取院校专业列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "院校专业" + ], + "summary": "创建院校专业", + "parameters": [ + { + "description": "院校专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors/batch": { + "post": { + "tags": [ + "院校专业" + ], + "summary": "批量创建院校专业", + "parameters": [ + { + "description": "院校专业列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "院校专业" + ], + "summary": "批量删除院校专业", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors/{id}": { + "get": { + "tags": [ + "院校专业" + ], + "summary": "获取单个院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "院校专业" + ], + "summary": "更新院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "院校专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "院校专业" + ], + "summary": "删除院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "院校专业" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + } + }, + "definitions": { + "common.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "message": { + "type": "string" + } + } + }, + "controller.LoginRequest": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "controller.UpdatePasswordRequest": { + "type": "object", + "required": [ + "newPassword", + "oldPassword" + ], + "properties": { + "newPassword": { + "type": "string" + }, + "oldPassword": { + "type": "string" + } + } + }, + "entity.SysUser": { + "type": "object", + "properties": { + "activitiSync": { + "description": "同步工作流引擎", + "type": "integer" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birthday": { + "description": "生日", + "type": "string" + }, + "bpmStatus": { + "description": "流程状态", + "type": "string" + }, + "clientId": { + "description": "设备ID", + "type": "string" + }, + "createBy": { + "description": "创建人", + "type": "string" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "delFlag": { + "description": "删除状态(0-正常,1-已删除)", + "type": "integer" + }, + "departIds": { + "description": "负责部门", + "type": "string" + }, + "dyOpenId": { + "description": "抖音openId", + "type": "string" + }, + "email": { + "description": "电子邮件", + "type": "string" + }, + "id": { + "type": "string" + }, + "ip": { + "description": "注册时ip", + "type": "string" + }, + "loginTenantId": { + "description": "上次登录租户ID", + "type": "integer" + }, + "orgCode": { + "description": "机构编码", + "type": "string" + }, + "phone": { + "description": "电话", + "type": "string" + }, + "programType": { + "description": "所属程序", + "type": "string" + }, + "realname": { + "description": "真实姓名", + "type": "string" + }, + "sex": { + "description": "性别(0-未知,1-男,2-女)", + "type": "integer" + }, + "showLinediff": { + "description": "是否显示历年线差", + "type": "string" + }, + "status": { + "description": "状态(1-正常,2-冻结)", + "type": "integer" + }, + "telephone": { + "description": "座机号", + "type": "string" + }, + "thirdId": { + "description": "第三方登录唯一标识", + "type": "string" + }, + "thirdType": { + "description": "第三方类型", + "type": "string" + }, + "updateBy": { + "description": "更新人", + "type": "string" + }, + "updateTime": { + "description": "更新时间", + "type": "string" + }, + "userIdentity": { + "description": "身份(1普通成员 2上级)", + "type": "integer" + }, + "username": { + "description": "登录账号", + "type": "string" + }, + "workNo": { + "description": "工号", + "type": "string" + }, + "wxOpenId": { + "description": "微信openId", + "type": "string" + } + } + }, + "entity.YxCalculationMajor": { + "type": "object", + "properties": { + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "enrollProbability": { + "type": "number" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kslx": { + "type": "string" + }, + "limitation": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "otherScoreLimitation": { + "type": "string" + }, + "planNum": { + "type": "integer" + }, + "privateProbabilityOperator": { + "type": "string" + }, + "privateRulesEnrollProbability": { + "type": "string" + }, + "privateStudentConvertedScore": { + "type": "number" + }, + "probabilityOperator": { + "type": "string" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "rulesEnrollProbabilitySx": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "scoreId": { + "type": "string" + }, + "state": { + "type": "string" + }, + "studentConvertedScore": { + "type": "number" + }, + "studentOldConvertedScore": { + "type": "number" + }, + "tuition": { + "type": "string" + } + } + }, + "entity.YxHistoryMajorEnroll": { + "type": "object", + "properties": { + "actualPitcherNum": { + "type": "integer" + }, + "admissionLine": { + "type": "number" + }, + "admissionNum": { + "type": "integer" + }, + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "checkMaster": { + "type": "string" + }, + "controlLine": { + "type": "number" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "enrollNum": { + "type": "integer" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "institutionCode": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "oneVolunteerAdmissionNum": { + "type": "integer" + }, + "probabilityOperator": { + "type": "string" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "schoolName": { + "type": "string" + }, + "scoreLineDifference": { + "type": "number" + }, + "sysOrgCode": { + "type": "string" + }, + "tuition": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "year": { + "type": "string" + } + } + }, + "entity.YxSchoolMajor": { + "type": "object", + "properties": { + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "checkMaster": { + "type": "string" + }, + "chineseScoreLimitation": { + "type": "number" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "culturalControlLine": { + "type": "number" + }, + "culturalScoreLimitation": { + "type": "number" + }, + "detail": { + "type": "string" + }, + "englishScoreLimitation": { + "type": "number" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kslx": { + "type": "string" + }, + "limitation": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "planNum": { + "type": "integer" + }, + "privateProbabilityOperator": { + "type": "string" + }, + "privateRulesEnrollProbability": { + "type": "string" + }, + "probabilityOperator": { + "type": "string" + }, + "professionalScoreLimitation": { + "type": "number" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "rulesEnrollProbabilitySx": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "schoolName": { + "type": "string" + }, + "semester": { + "type": "string" + }, + "specialControlLine": { + "type": "number" + }, + "state": { + "type": "string" + }, + "tuition": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "2.0", + Host: "localhost:8080", + BasePath: "/api", + Schemes: []string{}, + Title: "艺考招生管理系统 API", + Description: "提供用户认证、院校专业、历年招生、计算专业的管理接口", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/server/docs/swagger.json b/server/docs/swagger.json new file mode 100644 index 0000000..b823853 --- /dev/null +++ b/server/docs/swagger.json @@ -0,0 +1,1424 @@ +{ + "swagger": "2.0", + "info": { + "description": "提供用户认证、院校专业、历年招生、计算专业的管理接口", + "title": "艺考招生管理系统 API", + "contact": {}, + "version": "2.0" + }, + "host": "localhost:8080", + "basePath": "/api", + "paths": { + "/auth/info": { + "get": { + "tags": [ + "认证" + ], + "summary": "获取当前登录用户信息", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/auth/login": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "认证" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "登录信息", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.LoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/auth/logout": { + "post": { + "tags": [ + "认证" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users": { + "get": { + "tags": [ + "用户管理" + ], + "summary": "获取用户列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "用户管理" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users/{id}": { + "get": { + "tags": [ + "用户管理" + ], + "summary": "获取单个用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "用户管理" + ], + "summary": "更新用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "用户信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "用户管理" + ], + "summary": "删除用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "用户管理" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/sys-users/{id}/password": { + "put": { + "tags": [ + "用户管理" + ], + "summary": "修改密码", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "密码信息", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.UpdatePasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors": { + "get": { + "tags": [ + "计算专业" + ], + "summary": "获取计算专业列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "计算专业" + ], + "summary": "创建计算专业", + "parameters": [ + { + "description": "计算专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors/batch": { + "post": { + "tags": [ + "计算专业" + ], + "summary": "批量创建计算专业", + "parameters": [ + { + "description": "计算专业列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "计算专业" + ], + "summary": "批量删除计算专业", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-calculation-majors/{id}": { + "get": { + "tags": [ + "计算专业" + ], + "summary": "获取单个计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "计算专业" + ], + "summary": "更新计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "计算专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxCalculationMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "计算专业" + ], + "summary": "删除计算专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "计算专业" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls": { + "get": { + "tags": [ + "历年招生" + ], + "summary": "获取历年招生列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "历年招生" + ], + "summary": "创建历年招生记录", + "parameters": [ + { + "description": "历年招生信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls/batch": { + "post": { + "tags": [ + "历年招生" + ], + "summary": "批量创建历年招生记录", + "parameters": [ + { + "description": "历年招生列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "历年招生" + ], + "summary": "批量删除历年招生记录", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-history-enrolls/{id}": { + "get": { + "tags": [ + "历年招生" + ], + "summary": "获取单个历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "历年招生" + ], + "summary": "更新历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "历年招生信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxHistoryMajorEnroll" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "历年招生" + ], + "summary": "删除历年招生记录", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "历年招生" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors": { + "get": { + "tags": [ + "院校专业" + ], + "summary": "获取院校专业列表", + "parameters": [ + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页数量", + "name": "size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "post": { + "tags": [ + "院校专业" + ], + "summary": "创建院校专业", + "parameters": [ + { + "description": "院校专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors/batch": { + "post": { + "tags": [ + "院校专业" + ], + "summary": "批量创建院校专业", + "parameters": [ + { + "description": "院校专业列表", + "name": "items", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "院校专业" + ], + "summary": "批量删除院校专业", + "parameters": [ + { + "description": "ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + }, + "/yx-school-majors/{id}": { + "get": { + "tags": [ + "院校专业" + ], + "summary": "获取单个院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "put": { + "tags": [ + "院校专业" + ], + "summary": "更新院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "院校专业信息", + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/entity.YxSchoolMajor" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "delete": { + "tags": [ + "院校专业" + ], + "summary": "删除院校专业", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + }, + "patch": { + "tags": [ + "院校专业" + ], + "summary": "动态字段更新", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "要更新的字段", + "name": "fields", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.Response" + } + } + } + } + } + }, + "definitions": { + "common.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "message": { + "type": "string" + } + } + }, + "controller.LoginRequest": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "controller.UpdatePasswordRequest": { + "type": "object", + "required": [ + "newPassword", + "oldPassword" + ], + "properties": { + "newPassword": { + "type": "string" + }, + "oldPassword": { + "type": "string" + } + } + }, + "entity.SysUser": { + "type": "object", + "properties": { + "activitiSync": { + "description": "同步工作流引擎", + "type": "integer" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birthday": { + "description": "生日", + "type": "string" + }, + "bpmStatus": { + "description": "流程状态", + "type": "string" + }, + "clientId": { + "description": "设备ID", + "type": "string" + }, + "createBy": { + "description": "创建人", + "type": "string" + }, + "createTime": { + "description": "创建时间", + "type": "string" + }, + "delFlag": { + "description": "删除状态(0-正常,1-已删除)", + "type": "integer" + }, + "departIds": { + "description": "负责部门", + "type": "string" + }, + "dyOpenId": { + "description": "抖音openId", + "type": "string" + }, + "email": { + "description": "电子邮件", + "type": "string" + }, + "id": { + "type": "string" + }, + "ip": { + "description": "注册时ip", + "type": "string" + }, + "loginTenantId": { + "description": "上次登录租户ID", + "type": "integer" + }, + "orgCode": { + "description": "机构编码", + "type": "string" + }, + "phone": { + "description": "电话", + "type": "string" + }, + "programType": { + "description": "所属程序", + "type": "string" + }, + "realname": { + "description": "真实姓名", + "type": "string" + }, + "sex": { + "description": "性别(0-未知,1-男,2-女)", + "type": "integer" + }, + "showLinediff": { + "description": "是否显示历年线差", + "type": "string" + }, + "status": { + "description": "状态(1-正常,2-冻结)", + "type": "integer" + }, + "telephone": { + "description": "座机号", + "type": "string" + }, + "thirdId": { + "description": "第三方登录唯一标识", + "type": "string" + }, + "thirdType": { + "description": "第三方类型", + "type": "string" + }, + "updateBy": { + "description": "更新人", + "type": "string" + }, + "updateTime": { + "description": "更新时间", + "type": "string" + }, + "userIdentity": { + "description": "身份(1普通成员 2上级)", + "type": "integer" + }, + "username": { + "description": "登录账号", + "type": "string" + }, + "workNo": { + "description": "工号", + "type": "string" + }, + "wxOpenId": { + "description": "微信openId", + "type": "string" + } + } + }, + "entity.YxCalculationMajor": { + "type": "object", + "properties": { + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "enrollProbability": { + "type": "number" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kslx": { + "type": "string" + }, + "limitation": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "otherScoreLimitation": { + "type": "string" + }, + "planNum": { + "type": "integer" + }, + "privateProbabilityOperator": { + "type": "string" + }, + "privateRulesEnrollProbability": { + "type": "string" + }, + "privateStudentConvertedScore": { + "type": "number" + }, + "probabilityOperator": { + "type": "string" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "rulesEnrollProbabilitySx": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "scoreId": { + "type": "string" + }, + "state": { + "type": "string" + }, + "studentConvertedScore": { + "type": "number" + }, + "studentOldConvertedScore": { + "type": "number" + }, + "tuition": { + "type": "string" + } + } + }, + "entity.YxHistoryMajorEnroll": { + "type": "object", + "properties": { + "actualPitcherNum": { + "type": "integer" + }, + "admissionLine": { + "type": "number" + }, + "admissionNum": { + "type": "integer" + }, + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "checkMaster": { + "type": "string" + }, + "controlLine": { + "type": "number" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "enrollNum": { + "type": "integer" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "institutionCode": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "oneVolunteerAdmissionNum": { + "type": "integer" + }, + "probabilityOperator": { + "type": "string" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "schoolName": { + "type": "string" + }, + "scoreLineDifference": { + "type": "number" + }, + "sysOrgCode": { + "type": "string" + }, + "tuition": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "year": { + "type": "string" + } + } + }, + "entity.YxSchoolMajor": { + "type": "object", + "properties": { + "batch": { + "type": "string" + }, + "category": { + "type": "string" + }, + "checkMaster": { + "type": "string" + }, + "chineseScoreLimitation": { + "type": "number" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "culturalControlLine": { + "type": "number" + }, + "culturalScoreLimitation": { + "type": "number" + }, + "detail": { + "type": "string" + }, + "englishScoreLimitation": { + "type": "number" + }, + "enrollmentCode": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kslx": { + "type": "string" + }, + "limitation": { + "type": "string" + }, + "mainSubjects": { + "type": "string" + }, + "majorCode": { + "type": "string" + }, + "majorName": { + "type": "string" + }, + "majorType": { + "type": "string" + }, + "majorTypeChild": { + "type": "string" + }, + "planNum": { + "type": "integer" + }, + "privateProbabilityOperator": { + "type": "string" + }, + "privateRulesEnrollProbability": { + "type": "string" + }, + "probabilityOperator": { + "type": "string" + }, + "professionalScoreLimitation": { + "type": "number" + }, + "rulesEnrollProbability": { + "type": "string" + }, + "rulesEnrollProbabilitySx": { + "type": "string" + }, + "schoolCode": { + "type": "string" + }, + "schoolName": { + "type": "string" + }, + "semester": { + "type": "string" + }, + "specialControlLine": { + "type": "number" + }, + "state": { + "type": "string" + }, + "tuition": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml new file mode 100644 index 0000000..1d0469f --- /dev/null +++ b/server/docs/swagger.yaml @@ -0,0 +1,938 @@ +basePath: /api +definitions: + common.Response: + properties: + code: + type: integer + data: {} + message: + type: string + type: object + controller.LoginRequest: + properties: + password: + type: string + username: + type: string + required: + - password + - username + type: object + controller.UpdatePasswordRequest: + properties: + newPassword: + type: string + oldPassword: + type: string + required: + - newPassword + - oldPassword + type: object + entity.SysUser: + properties: + activitiSync: + description: 同步工作流引擎 + type: integer + avatar: + description: 头像 + type: string + birthday: + description: 生日 + type: string + bpmStatus: + description: 流程状态 + type: string + clientId: + description: 设备ID + type: string + createBy: + description: 创建人 + type: string + createTime: + description: 创建时间 + type: string + delFlag: + description: 删除状态(0-正常,1-已删除) + type: integer + departIds: + description: 负责部门 + type: string + dyOpenId: + description: 抖音openId + type: string + email: + description: 电子邮件 + type: string + id: + type: string + ip: + description: 注册时ip + type: string + loginTenantId: + description: 上次登录租户ID + type: integer + orgCode: + description: 机构编码 + type: string + phone: + description: 电话 + type: string + programType: + description: 所属程序 + type: string + realname: + description: 真实姓名 + type: string + sex: + description: 性别(0-未知,1-男,2-女) + type: integer + showLinediff: + description: 是否显示历年线差 + type: string + status: + description: 状态(1-正常,2-冻结) + type: integer + telephone: + description: 座机号 + type: string + thirdId: + description: 第三方登录唯一标识 + type: string + thirdType: + description: 第三方类型 + type: string + updateBy: + description: 更新人 + type: string + updateTime: + description: 更新时间 + type: string + userIdentity: + description: 身份(1普通成员 2上级) + type: integer + username: + description: 登录账号 + type: string + workNo: + description: 工号 + type: string + wxOpenId: + description: 微信openId + type: string + type: object + entity.YxCalculationMajor: + properties: + batch: + type: string + category: + type: string + createTime: + type: string + detail: + type: string + enrollProbability: + type: number + enrollmentCode: + type: string + id: + type: string + kslx: + type: string + limitation: + type: string + mainSubjects: + type: string + majorCode: + type: string + majorName: + type: string + majorType: + type: string + majorTypeChild: + type: string + otherScoreLimitation: + type: string + planNum: + type: integer + privateProbabilityOperator: + type: string + privateRulesEnrollProbability: + type: string + privateStudentConvertedScore: + type: number + probabilityOperator: + type: string + rulesEnrollProbability: + type: string + rulesEnrollProbabilitySx: + type: string + schoolCode: + type: string + scoreId: + type: string + state: + type: string + studentConvertedScore: + type: number + studentOldConvertedScore: + type: number + tuition: + type: string + type: object + entity.YxHistoryMajorEnroll: + properties: + actualPitcherNum: + type: integer + admissionLine: + type: number + admissionNum: + type: integer + batch: + type: string + category: + type: string + checkMaster: + type: string + controlLine: + type: number + createBy: + type: string + createTime: + type: string + detail: + type: string + enrollNum: + type: integer + enrollmentCode: + type: string + id: + type: string + institutionCode: + type: string + mainSubjects: + type: string + majorCode: + type: string + majorName: + type: string + majorType: + type: string + majorTypeChild: + type: string + oneVolunteerAdmissionNum: + type: integer + probabilityOperator: + type: string + rulesEnrollProbability: + type: string + schoolCode: + type: string + schoolName: + type: string + scoreLineDifference: + type: number + sysOrgCode: + type: string + tuition: + type: string + updateBy: + type: string + updateTime: + type: string + year: + type: string + type: object + entity.YxSchoolMajor: + properties: + batch: + type: string + category: + type: string + checkMaster: + type: string + chineseScoreLimitation: + type: number + createBy: + type: string + createTime: + type: string + culturalControlLine: + type: number + culturalScoreLimitation: + type: number + detail: + type: string + englishScoreLimitation: + type: number + enrollmentCode: + type: string + id: + type: string + kslx: + type: string + limitation: + type: string + mainSubjects: + type: string + majorCode: + type: string + majorName: + type: string + majorType: + type: string + majorTypeChild: + type: string + planNum: + type: integer + privateProbabilityOperator: + type: string + privateRulesEnrollProbability: + type: string + probabilityOperator: + type: string + professionalScoreLimitation: + type: number + rulesEnrollProbability: + type: string + rulesEnrollProbabilitySx: + type: string + schoolCode: + type: string + schoolName: + type: string + semester: + type: string + specialControlLine: + type: number + state: + type: string + tuition: + type: string + updateBy: + type: string + updateTime: + type: string + type: object +host: localhost:8080 +info: + contact: {} + description: 提供用户认证、院校专业、历年招生、计算专业的管理接口 + title: 艺考招生管理系统 API + version: "2.0" +paths: + /auth/info: + get: + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取当前登录用户信息 + tags: + - 认证 + /auth/login: + post: + consumes: + - application/json + parameters: + - description: 登录信息 + in: body + name: request + required: true + schema: + $ref: '#/definitions/controller.LoginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 用户登录 + tags: + - 认证 + /auth/logout: + post: + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 用户登出 + tags: + - 认证 + /sys-users: + get: + parameters: + - description: 页码 + in: query + name: page + type: integer + - description: 每页数量 + in: query + name: size + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取用户列表 + tags: + - 用户管理 + post: + parameters: + - description: 用户信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.SysUser' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 创建用户 + tags: + - 用户管理 + /sys-users/{id}: + delete: + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 删除用户 + tags: + - 用户管理 + get: + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取单个用户 + tags: + - 用户管理 + patch: + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + - description: 要更新的字段 + in: body + name: fields + required: true + schema: + additionalProperties: true + type: object + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 动态字段更新 + tags: + - 用户管理 + put: + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + - description: 用户信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.SysUser' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 更新用户 + tags: + - 用户管理 + /sys-users/{id}/password: + put: + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + - description: 密码信息 + in: body + name: request + required: true + schema: + $ref: '#/definitions/controller.UpdatePasswordRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 修改密码 + tags: + - 用户管理 + /yx-calculation-majors: + get: + parameters: + - description: 页码 + in: query + name: page + type: integer + - description: 每页数量 + in: query + name: size + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取计算专业列表 + tags: + - 计算专业 + post: + parameters: + - description: 计算专业信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxCalculationMajor' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 创建计算专业 + tags: + - 计算专业 + /yx-calculation-majors/{id}: + delete: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 删除计算专业 + tags: + - 计算专业 + get: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取单个计算专业 + tags: + - 计算专业 + patch: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 要更新的字段 + in: body + name: fields + required: true + schema: + additionalProperties: true + type: object + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 动态字段更新 + tags: + - 计算专业 + put: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 计算专业信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxCalculationMajor' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 更新计算专业 + tags: + - 计算专业 + /yx-calculation-majors/batch: + delete: + parameters: + - description: ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量删除计算专业 + tags: + - 计算专业 + post: + parameters: + - description: 计算专业列表 + in: body + name: items + required: true + schema: + items: + $ref: '#/definitions/entity.YxCalculationMajor' + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量创建计算专业 + tags: + - 计算专业 + /yx-history-enrolls: + get: + parameters: + - description: 页码 + in: query + name: page + type: integer + - description: 每页数量 + in: query + name: size + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取历年招生列表 + tags: + - 历年招生 + post: + parameters: + - description: 历年招生信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxHistoryMajorEnroll' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 创建历年招生记录 + tags: + - 历年招生 + /yx-history-enrolls/{id}: + delete: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 删除历年招生记录 + tags: + - 历年招生 + get: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取单个历年招生记录 + tags: + - 历年招生 + patch: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 要更新的字段 + in: body + name: fields + required: true + schema: + additionalProperties: true + type: object + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 动态字段更新 + tags: + - 历年招生 + put: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 历年招生信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxHistoryMajorEnroll' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 更新历年招生记录 + tags: + - 历年招生 + /yx-history-enrolls/batch: + delete: + parameters: + - description: ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量删除历年招生记录 + tags: + - 历年招生 + post: + parameters: + - description: 历年招生列表 + in: body + name: items + required: true + schema: + items: + $ref: '#/definitions/entity.YxHistoryMajorEnroll' + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量创建历年招生记录 + tags: + - 历年招生 + /yx-school-majors: + get: + parameters: + - description: 页码 + in: query + name: page + type: integer + - description: 每页数量 + in: query + name: size + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取院校专业列表 + tags: + - 院校专业 + post: + parameters: + - description: 院校专业信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxSchoolMajor' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 创建院校专业 + tags: + - 院校专业 + /yx-school-majors/{id}: + delete: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 删除院校专业 + tags: + - 院校专业 + get: + parameters: + - description: ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 获取单个院校专业 + tags: + - 院校专业 + patch: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 要更新的字段 + in: body + name: fields + required: true + schema: + additionalProperties: true + type: object + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 动态字段更新 + tags: + - 院校专业 + put: + parameters: + - description: ID + in: path + name: id + required: true + type: string + - description: 院校专业信息 + in: body + name: item + required: true + schema: + $ref: '#/definitions/entity.YxSchoolMajor' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 更新院校专业 + tags: + - 院校专业 + /yx-school-majors/batch: + delete: + parameters: + - description: ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量删除院校专业 + tags: + - 院校专业 + post: + parameters: + - description: 院校专业列表 + in: body + name: items + required: true + schema: + items: + $ref: '#/definitions/entity.YxSchoolMajor' + type: array + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.Response' + summary: 批量创建院校专业 + tags: + - 院校专业 +securityDefinitions: + Bearer: + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..78392fd --- /dev/null +++ b/server/go.mod @@ -0,0 +1,57 @@ +module server + +go 1.21 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/google/uuid v1.4.0 + github.com/redis/go-redis/v9 v9.3.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.2 + gorm.io/driver/mysql v1.5.2 + gorm.io/gorm v1.25.5 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.7.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..1942bcb --- /dev/null +++ b/server/go.sum @@ -0,0 +1,188 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= +github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= +gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..fc3834a --- /dev/null +++ b/server/main.go @@ -0,0 +1,132 @@ +// Package main 应用程序入口 +package main + +import ( + "context" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "server/common" + "server/config" + _ "server/docs" + "server/middleware" + sysController "server/modules/system/controller" + yxController "server/modules/yx/controller" + + "github.com/gin-gonic/gin" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" +) + +// @title 艺考招生管理系统 API +// @version 2.0 +// @description 提供用户认证、院校专业、历年招生、计算专业的管理接口 +// @host localhost:8080 +// @BasePath /api +// @securityDefinitions.apikey Bearer +// @in header +// @name Authorization + +func main() { + // 初始化日志 + common.InitLogger() + common.Info("========== 应用启动 ==========") + + // 初始化数据库 + config.InitDB() + common.Info("数据库初始化完成") + + // 初始化Redis + config.InitRedis() + common.Info("Redis初始化完成") + + // 创建 Gin 引擎 + gin.SetMode(gin.ReleaseMode) + r := gin.New() + r.Use(gin.Recovery()) + + // 请求日志中间件 + r.Use(requestLogMiddleware()) + + // Swagger 文档 (不需要登录) + r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + + // API 路由组 + api := r.Group("/api") + + // 中间件顺序: 安全校验 -> 限流 -> 登录鉴权 + api.Use(middleware.SecurityMiddleware()) + api.Use(middleware.RateLimitMiddleware()) + api.Use(middleware.AuthMiddleware()) + + // 注册 System 模块路由 + sysController.NewAuthController().RegisterRoutes(api) + sysController.NewSysUserController().RegisterRoutes(api) + + // 注册 YX 模块路由 + yxController.NewYxSchoolMajorController().RegisterRoutes(api) + yxController.NewYxHistoryMajorEnrollController().RegisterRoutes(api) + yxController.NewYxCalculationMajorController().RegisterRoutes(api) + + // 创建 HTTP 服务器 + srv := &http.Server{ + Addr: ":8080", + Handler: r, + } + + // 启动服务器 + go func() { + common.Info("服务器启动: http://localhost:8080") + common.Info("Swagger文档: http://localhost:8080/swagger/index.html") + log.Println("服务器启动: http://localhost:8080") + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + common.LogError("启动失败: %s", err) + log.Fatalf("启动失败: %s\n", err) + } + }() + + // 优雅关闭 + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + + common.Info("正在关闭服务器...") + log.Println("正在关闭服务器...") + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + common.LogError("服务器关闭异常: %v", err) + log.Fatal("服务器关闭异常:", err) + } + + // 关闭资源 + config.CloseDB() + config.CloseRedis() + common.Info("========== 应用关闭 ==========") + common.CloseLogger() + + log.Println("服务器已退出") +} + +// requestLogMiddleware 请求日志中间件 +func requestLogMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + path := c.Request.URL.Path + method := c.Request.Method + + c.Next() + + latency := time.Since(start) + status := c.Writer.Status() + clientIP := c.ClientIP() + + common.Info("%s %s %d %v %s", method, path, status, latency, clientIP) + } +} diff --git a/server/middleware/auth.go b/server/middleware/auth.go new file mode 100644 index 0000000..7f8e632 --- /dev/null +++ b/server/middleware/auth.go @@ -0,0 +1,77 @@ +// Package middleware 中间件 +package middleware + +import ( + "strings" + + "server/common" + "server/modules/system/service" + + "github.com/gin-gonic/gin" +) + +const ( + // ContextUserKey 上下文中存储用户信息的key + ContextUserKey = "loginUser" + // TokenHeader 请求头中Token的key + TokenHeader = "Authorization" + // TokenPrefix Token前缀 + TokenPrefix = "Bearer " +) + +// 白名单路径 (不需要登录即可访问) +var whiteList = []string{ + "/api/auth/login", + "/api/auth/register", + "/swagger/", +} + +// AuthMiddleware 登录鉴权中间件 +// 类似Java中的Shiro Filter +func AuthMiddleware() gin.HandlerFunc { + userService := service.NewSysUserService() + + return func(c *gin.Context) { + path := c.Request.URL.Path + + // 检查是否在白名单中 + for _, white := range whiteList { + if strings.HasPrefix(path, white) { + c.Next() + return + } + } + + // 获取Token + token := c.GetHeader(TokenHeader) + if token == "" { + common.Error(c, 401, "未登录") + c.Abort() + return + } + + // 去除Bearer前缀 + token = strings.TrimPrefix(token, TokenPrefix) + // if strings.HasPrefix(token, TokenPrefix) { + // token = token[len(TokenPrefix):] + // } + + // 验证Token并获取用户信息 + loginUser, err := userService.GetLoginUser(token) + if err != nil { + common.Error(c, 401, err.Error()) + c.Abort() + return + } + + // 将用户信息存入上下文 + c.Set(ContextUserKey, loginUser) + + c.Next() + } +} + +// AddWhiteList 添加白名单路径 +func AddWhiteList(paths ...string) { + whiteList = append(whiteList, paths...) +} diff --git a/server/middleware/ratelimit.go b/server/middleware/ratelimit.go new file mode 100644 index 0000000..e77bcbb --- /dev/null +++ b/server/middleware/ratelimit.go @@ -0,0 +1,142 @@ +// Package middleware 限流中间件 +package middleware + +import ( + "context" + "fmt" + "strings" + "time" + + "server/common" + "server/config" + + "github.com/gin-gonic/gin" + "github.com/redis/go-redis/v9" +) + +// RateLimitMiddleware 限流中间件 +// 基于 Redis 实现,支持按用户ID或IP限流 +// 不同接口可配置不同的限流规则 +func RateLimitMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + cfg := config.AppConfig.RateLimit + + // 未启用则跳过 + if !cfg.Enable { + c.Next() + return + } + + // 白名单路径跳过 + path := c.Request.URL.Path + if isRateLimitWhitelist(path) { + c.Next() + return + } + + // 获取限流规则 + rule := getRule(path, cfg) + + // 获取限流key (优先用户ID,否则用IP) + key := getRateLimitKey(c, path) + + // 检查是否超过限制 + if !checkRateLimit(key, rule) { + common.Warn("请求过于频繁: Key=%s Path=%s", key, path) + c.JSON(429, map[string]interface{}{ + "code": 429, + "message": "操作过快,请稍后再试", + "data": nil, + }) + c.Abort() + return + } + + c.Next() + } +} + +// getRule 获取路径对应的限流规则 +func getRule(path string, cfg config.RateLimitConfig) config.RateLimitRule { + // 精确匹配 + if rule, ok := cfg.Rules[path]; ok { + return rule + } + + // 前缀匹配 + for rulePath, rule := range cfg.Rules { + if strings.HasPrefix(path, rulePath) { + return rule + } + } + + // 返回默认规则 + return cfg.Default +} + +// getRateLimitKey 获取限流key +func getRateLimitKey(c *gin.Context, path string) string { + // 优先使用用户ID + if user := common.GetLoginUser(c); user != nil { + return fmt.Sprintf("ratelimit:%s:%s", user.ID, path) + } + // 否则使用IP + return fmt.Sprintf("ratelimit:%s:%s", c.ClientIP(), path) +} + +// checkRateLimit 检查是否超过限流 +// 使用 Redis 滑动窗口算法 +func checkRateLimit(key string, rule config.RateLimitRule) bool { + ctx := context.Background() + rdb := config.RDB + + now := time.Now().UnixMilli() + windowStart := now - int64(rule.Interval*1000) + + // 使用 Redis 事务 + pipe := rdb.Pipeline() + + // 移除窗口外的记录 + pipe.ZRemRangeByScore(ctx, key, "0", fmt.Sprintf("%d", windowStart)) + + // 获取当前窗口内的请求数 + countCmd := pipe.ZCard(ctx, key) + + // 添加当前请求 + pipe.ZAdd(ctx, key, redis.Z{ + Score: float64(now), + Member: fmt.Sprintf("%d", now), + }) + + // 设置过期时间 + pipe.Expire(ctx, key, time.Duration(rule.Interval)*time.Second) + + _, err := pipe.Exec(ctx) + if err != nil { + common.LogError("限流检查失败: %v", err) + return true // 出错时放行 + } + + count := countCmd.Val() + return count < int64(rule.MaxRequests) +} + +// 限流白名单 +var rateLimitWhitelist = []string{ + "/swagger/", + "/api/auth/logout", +} + +func isRateLimitWhitelist(path string) bool { + for _, white := range rateLimitWhitelist { + if strings.HasPrefix(path, white) { + return true + } + } + return false +} + +// AddRateLimitWhitelist 添加限流白名单 +func AddRateLimitWhitelist(paths ...string) { + rateLimitWhitelist = append(rateLimitWhitelist, paths...) +} diff --git a/server/middleware/security.go b/server/middleware/security.go new file mode 100644 index 0000000..c6baced --- /dev/null +++ b/server/middleware/security.go @@ -0,0 +1,110 @@ +// Package middleware 安全校验中间件 +package middleware + +import ( + "crypto/md5" + "encoding/hex" + "strconv" + "time" + + "server/common" + "server/config" + + "github.com/gin-gonic/gin" +) + +// SecurityMiddleware 安全校验中间件 +// 防止暴力入侵,校验请求头签名 +// 请求头需携带: +// - X-App-Sign: 签名值 = MD5(timestamp + secretKey) +// - X-App-Timestamp: 时间戳(毫秒) +func SecurityMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + cfg := config.AppConfig.Security + + // 未启用则跳过 + if !cfg.Enable { + c.Next() + return + } + + // 白名单路径跳过 + path := c.Request.URL.Path + if isSecurityWhitelist(path) { + c.Next() + return + } + + // 获取签名和时间戳 + sign := c.GetHeader(cfg.HeaderKey) + timestamp := c.GetHeader("X-App-Timestamp") + + if sign == "" || timestamp == "" { + common.Warn("安全校验失败: 缺少签名头 IP=%s Path=%s", c.ClientIP(), path) + common.Error(c, 403, "非法请求") + c.Abort() + return + } + + // 验证时间戳 (5分钟内有效) + ts, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + common.Warn("安全校验失败: 时间戳格式错误 IP=%s", c.ClientIP()) + common.Error(c, 403, "非法请求") + c.Abort() + return + } + + now := time.Now().UnixMilli() + if abs(now-ts) > 5*60*1000 { // 5分钟 + common.Warn("安全校验失败: 时间戳过期 IP=%s Timestamp=%d", c.ClientIP(), ts) + common.Error(c, 403, "请求已过期") + c.Abort() + return + } + + // 验证签名 + expectedSign := generateSign(timestamp, cfg.SecretKey) + if sign != expectedSign { + common.Warn("安全校验失败: 签名错误 IP=%s Sign=%s Expected=%s", c.ClientIP(), sign, expectedSign) + common.Error(c, 403, "签名错误") + c.Abort() + return + } + + c.Next() + } +} + +// generateSign 生成签名 +func generateSign(timestamp, secretKey string) string { + data := timestamp + secretKey + hash := md5.Sum([]byte(data)) + return hex.EncodeToString(hash[:]) +} + +// 安全校验白名单 +var securityWhitelist = []string{ + "/swagger/", +} + +func isSecurityWhitelist(path string) bool { + for _, white := range securityWhitelist { + if len(path) >= len(white) && path[:len(white)] == white { + return true + } + } + return false +} + +func abs(n int64) int64 { + if n < 0 { + return -n + } + return n +} + +// AddSecurityWhitelist 添加安全校验白名单 +func AddSecurityWhitelist(paths ...string) { + securityWhitelist = append(securityWhitelist, paths...) +} diff --git a/server/modules/system/controller/auth_controller.go b/server/modules/system/controller/auth_controller.go new file mode 100644 index 0000000..aa3b911 --- /dev/null +++ b/server/modules/system/controller/auth_controller.go @@ -0,0 +1,86 @@ +// Package controller 控制器层 +package controller + +import ( + "server/common" + "server/modules/system/service" + + "github.com/gin-gonic/gin" +) + +// LoginRequest 登录请求 +type LoginRequest struct { + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` +} + +// AuthController 认证控制器 +type AuthController struct { + userService *service.SysUserService +} + +func NewAuthController() *AuthController { + return &AuthController{userService: service.NewSysUserService()} +} + +func (ctrl *AuthController) RegisterRoutes(r *gin.RouterGroup) { + r.POST("/auth/login", ctrl.Login) + r.POST("/auth/logout", ctrl.Logout) + r.GET("/auth/info", ctrl.GetUserInfo) +} + +// Login 用户登录 +// @Summary 用户登录 +// @Tags 认证 +// @Accept json +// @Produce json +// @Param request body LoginRequest true "登录信息" +// @Success 200 {object} common.Response +// @Router /auth/login [post] +func (ctrl *AuthController) Login(c *gin.Context) { + var req LoginRequest + if err := c.ShouldBindJSON(&req); err != nil { + common.Error(c, 400, "用户名和密码不能为空") + return + } + + loginUser, token, err := ctrl.userService.Login(req.Username, req.Password) + if err != nil { + common.Error(c, 401, err.Error()) + return + } + + common.Success(c, gin.H{ + "token": token, + "user": loginUser, + }) +} + +// Logout 用户登出 +// @Summary 用户登出 +// @Tags 认证 +// @Success 200 {object} common.Response +// @Router /auth/logout [post] +func (ctrl *AuthController) Logout(c *gin.Context) { + token := c.GetHeader("Authorization") + if len(token) > 7 { + token = token[7:] // 去除 "Bearer " + } + + ctrl.userService.Logout(token) + common.Success(c, nil) +} + +// GetUserInfo 获取当前登录用户信息 +// @Summary 获取当前登录用户信息 +// @Tags 认证 +// @Success 200 {object} common.Response +// @Router /auth/info [get] +func (ctrl *AuthController) GetUserInfo(c *gin.Context) { + user := common.GetLoginUser(c) + if user == nil { + common.Error(c, 401, "未登录") + return + } + common.Success(c, user) +} diff --git a/server/modules/system/controller/sys_user_controller.go b/server/modules/system/controller/sys_user_controller.go new file mode 100644 index 0000000..f51b53a --- /dev/null +++ b/server/modules/system/controller/sys_user_controller.go @@ -0,0 +1,161 @@ +// Package controller 控制器层 +package controller + +import ( + "strconv" + + "server/common" + "server/modules/system/entity" + "server/modules/system/service" + + "github.com/gin-gonic/gin" +) + +type SysUserController struct { + service *service.SysUserService +} + +func NewSysUserController() *SysUserController { + return &SysUserController{service: service.NewSysUserService()} +} + +func (ctrl *SysUserController) RegisterRoutes(r *gin.RouterGroup) { + r.GET("/sys-users", ctrl.List) + r.GET("/sys-users/:id", ctrl.GetByID) + r.POST("/sys-users", ctrl.Create) + r.PUT("/sys-users/:id", ctrl.Update) + r.PATCH("/sys-users/:id", ctrl.UpdateFields) + r.DELETE("/sys-users/:id", ctrl.Delete) + r.PUT("/sys-users/:id/password", ctrl.UpdatePassword) +} + +// @Summary 获取用户列表 +// @Tags 用户管理 +// @Param page query int false "页码" +// @Param size query int false "每页数量" +// @Success 200 {object} common.Response +// @Router /sys-users [get] +func (ctrl *SysUserController) List(c *gin.Context) { + // var user *entity.LoginUser = common.GetLoginUser(c) + // log.Printf(user.Username) + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + size, _ := strconv.Atoi(c.DefaultQuery("size", "10")) + items, total, err := ctrl.service.List(page, size) + if err != nil { + common.Error(c, 500, err.Error()) + return + } + common.SuccessPage(c, items, total, page, size) +} + +// @Summary 获取单个用户 +// @Tags 用户管理 +// @Param id path string true "用户ID" +// @Success 200 {object} common.Response +// @Router /sys-users/{id} [get] +func (ctrl *SysUserController) GetByID(c *gin.Context) { + item, err := ctrl.service.GetByID(c.Param("id")) + if err != nil { + common.Error(c, 404, "未找到") + return + } + common.Success(c, item) +} + +// @Summary 创建用户 +// @Tags 用户管理 +// @Param item body entity.SysUser true "用户信息" +// @Success 200 {object} common.Response +// @Router /sys-users [post] +func (ctrl *SysUserController) Create(c *gin.Context) { + var item entity.SysUser + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + // 设置创建人 + item.CreateBy = common.GetLoginUserID(c) + if err := ctrl.service.Create(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 更新用户 +// @Tags 用户管理 +// @Param id path string true "用户ID" +// @Param item body entity.SysUser true "用户信息" +// @Success 200 {object} common.Response +// @Router /sys-users/{id} [put] +func (ctrl *SysUserController) Update(c *gin.Context) { + var item entity.SysUser + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + item.ID = c.Param("id") + item.UpdateBy = common.GetLoginUserID(c) + if err := ctrl.service.Update(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 动态字段更新 +// @Tags 用户管理 +// @Param id path string true "用户ID" +// @Param fields body map[string]interface{} true "要更新的字段" +// @Success 200 {object} common.Response +// @Router /sys-users/{id} [patch] +func (ctrl *SysUserController) UpdateFields(c *gin.Context) { + var fields map[string]interface{} + if err := c.ShouldBindJSON(&fields); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.UpdateFields(c.Param("id"), fields); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 删除用户 +// @Tags 用户管理 +// @Param id path string true "用户ID" +// @Success 200 {object} common.Response +// @Router /sys-users/{id} [delete] +func (ctrl *SysUserController) Delete(c *gin.Context) { + if err := ctrl.service.Delete(c.Param("id")); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// UpdatePasswordRequest 修改密码请求 +type UpdatePasswordRequest struct { + OldPassword string `json:"oldPassword" binding:"required"` + NewPassword string `json:"newPassword" binding:"required"` +} + +// @Summary 修改密码 +// @Tags 用户管理 +// @Param id path string true "用户ID" +// @Param request body UpdatePasswordRequest true "密码信息" +// @Success 200 {object} common.Response +// @Router /sys-users/{id}/password [put] +func (ctrl *SysUserController) UpdatePassword(c *gin.Context) { + var req UpdatePasswordRequest + if err := c.ShouldBindJSON(&req); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.UpdatePassword(c.Param("id"), req.OldPassword, req.NewPassword); err != nil { + common.Error(c, 400, err.Error()) + return + } + common.Success(c, nil) +} diff --git a/server/modules/system/entity/sys_user.go b/server/modules/system/entity/sys_user.go new file mode 100644 index 0000000..ea299a7 --- /dev/null +++ b/server/modules/system/entity/sys_user.go @@ -0,0 +1,55 @@ +// Package entity 实体层 +package entity + +import "time" + +// SysUser 用户表实体 +type SysUser struct { + ID string `gorm:"column:id;primaryKey" json:"id"` + Username string `gorm:"column:username" json:"username"` // 登录账号 + Realname string `gorm:"column:realname" json:"realname"` // 真实姓名 + Password string `gorm:"column:password" json:"-"` // 密码 (不返回给前端) + Salt string `gorm:"column:salt" json:"-"` // md5密码盐 + Avatar string `gorm:"column:avatar" json:"avatar"` // 头像 + Birthday *time.Time `gorm:"column:birthday" json:"birthday"` // 生日 + Sex int `gorm:"column:sex" json:"sex"` // 性别(0-未知,1-男,2-女) + Email string `gorm:"column:email" json:"email"` // 电子邮件 + Phone string `gorm:"column:phone" json:"phone"` // 电话 + OrgCode string `gorm:"column:org_code" json:"orgCode"` // 机构编码 + Status int `gorm:"column:status" json:"status"` // 状态(1-正常,2-冻结) + DelFlag int `gorm:"column:del_flag" json:"delFlag"` // 删除状态(0-正常,1-已删除) + ThirdID string `gorm:"column:third_id" json:"thirdId"` // 第三方登录唯一标识 + ThirdType string `gorm:"column:third_type" json:"thirdType"` // 第三方类型 + ActivitiSync int `gorm:"column:activiti_sync" json:"activitiSync"` // 同步工作流引擎 + WorkNo string `gorm:"column:work_no" json:"workNo"` // 工号 + Telephone string `gorm:"column:telephone" json:"telephone"` // 座机号 + CreateBy string `gorm:"column:create_by" json:"createBy"` // 创建人 + CreateTime *time.Time `gorm:"column:create_time" json:"createTime"` // 创建时间 + UpdateBy string `gorm:"column:update_by" json:"updateBy"` // 更新人 + UpdateTime *time.Time `gorm:"column:update_time" json:"updateTime"` // 更新时间 + UserIdentity int `gorm:"column:user_identity" json:"userIdentity"` // 身份(1普通成员 2上级) + DepartIds string `gorm:"column:depart_ids" json:"departIds"` // 负责部门 + ClientID string `gorm:"column:client_id" json:"clientId"` // 设备ID + LoginTenantID int `gorm:"column:login_tenant_id" json:"loginTenantId"` // 上次登录租户ID + BpmStatus string `gorm:"column:bpm_status" json:"bpmStatus"` // 流程状态 + WxOpenID string `gorm:"column:wx_open_id" json:"wxOpenId"` // 微信openId + DyOpenID string `gorm:"column:dy_open_id" json:"dyOpenId"` // 抖音openId + IP string `gorm:"column:ip" json:"ip"` // 注册时ip + ShowLinediff string `gorm:"column:show_linediff" json:"showLinediff"` // 是否显示历年线差 + ProgramType string `gorm:"column:program_type" json:"programType"` // 所属程序 +} + +func (SysUser) TableName() string { + return "sys_user" +} + +// LoginUser 登录用户信息 (存储在Redis中) +type LoginUser struct { + ID string `json:"id"` + Username string `json:"username"` + Realname string `json:"realname"` + Avatar string `json:"avatar"` + Phone string `json:"phone"` + Email string `json:"email"` + Token string `json:"token"` +} diff --git a/server/modules/system/mapper/sys_user_mapper.go b/server/modules/system/mapper/sys_user_mapper.go new file mode 100644 index 0000000..3139ccd --- /dev/null +++ b/server/modules/system/mapper/sys_user_mapper.go @@ -0,0 +1,56 @@ +// Package mapper 数据访问层 +package mapper + +import ( + "server/config" + "server/modules/system/entity" +) + +type SysUserMapper struct{} + +func NewSysUserMapper() *SysUserMapper { + return &SysUserMapper{} +} + +func (m *SysUserMapper) FindAll(page, size int) ([]entity.SysUser, int64, error) { + var items []entity.SysUser + var total int64 + config.DB.Model(&entity.SysUser{}).Where("del_flag = 0").Count(&total) + err := config.DB.Where("del_flag = 0").Offset((page - 1) * size).Limit(size).Find(&items).Error + return items, total, err +} + +func (m *SysUserMapper) FindByID(id string) (*entity.SysUser, error) { + var item entity.SysUser + err := config.DB.First(&item, "id = ? AND del_flag = 0", id).Error + return &item, err +} + +func (m *SysUserMapper) FindByUsername(username string) (*entity.SysUser, error) { + var item entity.SysUser + err := config.DB.First(&item, "username = ? AND del_flag = 0", username).Error + return &item, err +} + +func (m *SysUserMapper) FindByPhone(phone string) (*entity.SysUser, error) { + var item entity.SysUser + err := config.DB.First(&item, "phone = ? AND del_flag = 0", phone).Error + return &item, err +} + +func (m *SysUserMapper) Create(item *entity.SysUser) error { + return config.DB.Create(item).Error +} + +func (m *SysUserMapper) Update(item *entity.SysUser) error { + return config.DB.Save(item).Error +} + +func (m *SysUserMapper) UpdateFields(id string, fields map[string]interface{}) error { + return config.DB.Model(&entity.SysUser{}).Where("id = ?", id).Updates(fields).Error +} + +func (m *SysUserMapper) Delete(id string) error { + // 逻辑删除 + return config.DB.Model(&entity.SysUser{}).Where("id = ?", id).Update("del_flag", 1).Error +} diff --git a/server/modules/system/service/sys_user_service.go b/server/modules/system/service/sys_user_service.go new file mode 100644 index 0000000..b1a369f --- /dev/null +++ b/server/modules/system/service/sys_user_service.go @@ -0,0 +1,189 @@ +// Package service 业务逻辑层 +package service + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "time" + + "server/common" + "server/config" + "server/modules/system/entity" + "server/modules/system/mapper" + + "github.com/google/uuid" +) + +const ( + TokenPrefix = "login:token:" // Redis中Token前缀 + TokenExpire = 24 * time.Hour // Token过期时间 +) + +type SysUserService struct { + mapper *mapper.SysUserMapper +} + +func NewSysUserService() *SysUserService { + return &SysUserService{mapper: mapper.NewSysUserMapper()} +} + +// Login 用户登录 +// 密码验证方式与 Java JeecgBoot 兼容: PBEWithMD5AndDES(username, password, salt) +func (s *SysUserService) Login(username, password string) (*entity.LoginUser, string, error) { + // 查询用户 + user, err := s.mapper.FindByUsername(username) + if err != nil { + return nil, "", errors.New("用户不存在") + } + + // 验证状态 + if user.Status == 2 { + return nil, "", errors.New("账号已被冻结") + } + + // 验证密码 (与Java兼容: encrypt(username, password, salt)) + encrypted, err := common.Encrypt(username, password, user.Salt) + if (user.Password != encrypted) || (err != nil) { + return nil, "", errors.New("用户名或密码错误") + } + + // 生成Token + token := s.generateToken() + + // 构建登录用户信息 + loginUser := &entity.LoginUser{ + ID: user.ID, + Username: user.Username, + Realname: user.Realname, + Avatar: user.Avatar, + Phone: user.Phone, + Email: user.Email, + Token: token, + } + + // 存储到Redis + if err := s.saveLoginUser(token, loginUser); err != nil { + return nil, "", errors.New("登录失败,请重试") + } + + return loginUser, token, nil +} + +// Logout 用户登出 +func (s *SysUserService) Logout(token string) error { + ctx := context.Background() + return config.RDB.Del(ctx, TokenPrefix+token).Err() +} + +// GetLoginUser 根据Token获取登录用户信息 +func (s *SysUserService) GetLoginUser(token string) (*entity.LoginUser, error) { + ctx := context.Background() + data, err := config.RDB.Get(ctx, TokenPrefix+token).Result() + if err != nil { + return nil, errors.New("未登录或登录已过期") + } + + var loginUser entity.LoginUser + if err := json.Unmarshal([]byte(data), &loginUser); err != nil { + return nil, errors.New("登录信息异常") + } + + // 刷新过期时间 + config.RDB.Expire(ctx, TokenPrefix+token, TokenExpire) + + return &loginUser, nil +} + +// RefreshToken 刷新Token过期时间 +func (s *SysUserService) RefreshToken(token string) error { + ctx := context.Background() + return config.RDB.Expire(ctx, TokenPrefix+token, TokenExpire).Err() +} + +// 保存登录用户到Redis +func (s *SysUserService) saveLoginUser(token string, user *entity.LoginUser) error { + ctx := context.Background() + data, err := json.Marshal(user) + if err != nil { + return err + } + return config.RDB.Set(ctx, TokenPrefix+token, data, TokenExpire).Err() +} + +// 生成Token +func (s *SysUserService) generateToken() string { + return uuid.New().String() +} + +// ========== 用户管理 ========== + +func (s *SysUserService) List(page, size int) ([]entity.SysUser, int64, error) { + return s.mapper.FindAll(page, size) +} + +func (s *SysUserService) GetByID(id string) (*entity.SysUser, error) { + return s.mapper.FindByID(id) +} + +func (s *SysUserService) Create(item *entity.SysUser) error { + item.ID = uuid.New().String() + // 生成盐值 (8字节) + item.Salt = uuid.New().String()[:8] + // 加密密码 (与Java兼容) + encrypted, err := common.Encrypt(item.Username, item.Password, item.Salt) + if err != nil { + log.Printf("密码加密失败: %v", err) + return fmt.Errorf("密码加密失败: %w,请联系管理员", err) // 仍然返回错误 + } + item.Password = encrypted + item.DelFlag = 0 + item.Status = 1 + now := time.Now() + item.CreateTime = &now + return s.mapper.Create(item) +} + +func (s *SysUserService) Update(item *entity.SysUser) error { + now := time.Now() + item.UpdateTime = &now + return s.mapper.Update(item) +} + +func (s *SysUserService) UpdateFields(id string, fields map[string]interface{}) error { + return s.mapper.UpdateFields(id, fields) +} + +func (s *SysUserService) Delete(id string) error { + return s.mapper.Delete(id) +} + +// UpdatePassword 修改密码 +func (s *SysUserService) UpdatePassword(id, oldPwd, newPwd string) error { + user, err := s.mapper.FindByID(id) + if err != nil { + return errors.New("用户不存在") + } + + // 验证旧密码 + encrypted, err := common.Encrypt(user.Username, oldPwd, user.Salt) + if err != nil { + log.Printf("密码加密失败: %v", err) + return fmt.Errorf("密码加密失败: %w,请联系管理员", err) // 仍然返回错误 + } + if encrypted != user.Password { + return errors.New("原密码错误") + } + + // 生成新密码 + newEncrypted, err := common.Encrypt(user.Username, newPwd, user.Salt) + if err != nil { + log.Printf("密码加密失败: %v", err) + return fmt.Errorf("密码加密失败: %w,请联系管理员", err) // 仍然返回错误 + } + return s.mapper.UpdateFields(id, map[string]interface{}{ + "password": newEncrypted, + }) +} diff --git a/server/modules/yx/controller/yx_calculation_major_controller.go b/server/modules/yx/controller/yx_calculation_major_controller.go new file mode 100644 index 0000000..ae56a63 --- /dev/null +++ b/server/modules/yx/controller/yx_calculation_major_controller.go @@ -0,0 +1,168 @@ +// Package controller 控制器层 +package controller + +import ( + "strconv" + + "server/common" + "server/modules/yx/entity" + "server/modules/yx/service" + + "github.com/gin-gonic/gin" +) + +type YxCalculationMajorController struct { + service *service.YxCalculationMajorService +} + +func NewYxCalculationMajorController() *YxCalculationMajorController { + return &YxCalculationMajorController{service: service.NewYxCalculationMajorService()} +} + +func (ctrl *YxCalculationMajorController) RegisterRoutes(r *gin.RouterGroup) { + r.GET("/yx-calculation-majors", ctrl.List) + r.GET("/yx-calculation-majors/:id", ctrl.GetByID) + r.POST("/yx-calculation-majors", ctrl.Create) + r.PUT("/yx-calculation-majors/:id", ctrl.Update) + r.PATCH("/yx-calculation-majors/:id", ctrl.UpdateFields) + r.DELETE("/yx-calculation-majors/:id", ctrl.Delete) + r.POST("/yx-calculation-majors/batch", ctrl.BatchCreate) + r.DELETE("/yx-calculation-majors/batch", ctrl.BatchDelete) +} + +// @Summary 获取计算专业列表 +// @Tags 计算专业 +// @Param page query int false "页码" +// @Param size query int false "每页数量" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors [get] +func (ctrl *YxCalculationMajorController) List(c *gin.Context) { + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + size, _ := strconv.Atoi(c.DefaultQuery("size", "10")) + items, total, err := ctrl.service.List(page, size) + if err != nil { + common.Error(c, 500, err.Error()) + return + } + common.SuccessPage(c, items, total, page, size) +} + +// @Summary 获取单个计算专业 +// @Tags 计算专业 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/{id} [get] +func (ctrl *YxCalculationMajorController) GetByID(c *gin.Context) { + item, err := ctrl.service.GetByID(c.Param("id")) + if err != nil { + common.Error(c, 404, "未找到") + return + } + common.Success(c, item) +} + +// @Summary 创建计算专业 +// @Tags 计算专业 +// @Param item body entity.YxCalculationMajor true "计算专业信息" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors [post] +func (ctrl *YxCalculationMajorController) Create(c *gin.Context) { + var item entity.YxCalculationMajor + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.Create(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 更新计算专业 +// @Tags 计算专业 +// @Param id path string true "ID" +// @Param item body entity.YxCalculationMajor true "计算专业信息" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/{id} [put] +func (ctrl *YxCalculationMajorController) Update(c *gin.Context) { + var item entity.YxCalculationMajor + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + item.ID = c.Param("id") + if err := ctrl.service.Update(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 动态字段更新 +// @Tags 计算专业 +// @Param id path string true "ID" +// @Param fields body map[string]interface{} true "要更新的字段" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/{id} [patch] +func (ctrl *YxCalculationMajorController) UpdateFields(c *gin.Context) { + var fields map[string]interface{} + if err := c.ShouldBindJSON(&fields); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.UpdateFields(c.Param("id"), fields); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 删除计算专业 +// @Tags 计算专业 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/{id} [delete] +func (ctrl *YxCalculationMajorController) Delete(c *gin.Context) { + if err := ctrl.service.Delete(c.Param("id")); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 批量创建计算专业 +// @Tags 计算专业 +// @Param items body []entity.YxCalculationMajor true "计算专业列表" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/batch [post] +func (ctrl *YxCalculationMajorController) BatchCreate(c *gin.Context) { + var items []entity.YxCalculationMajor + if err := c.ShouldBindJSON(&items); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchCreate(items); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 批量删除计算专业 +// @Tags 计算专业 +// @Param ids body []string true "ID列表" +// @Success 200 {object} common.Response +// @Router /yx-calculation-majors/batch [delete] +func (ctrl *YxCalculationMajorController) BatchDelete(c *gin.Context) { + var ids []string + if err := c.ShouldBindJSON(&ids); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchDelete(ids); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} diff --git a/server/modules/yx/controller/yx_history_major_enroll_controller.go b/server/modules/yx/controller/yx_history_major_enroll_controller.go new file mode 100644 index 0000000..34b5550 --- /dev/null +++ b/server/modules/yx/controller/yx_history_major_enroll_controller.go @@ -0,0 +1,168 @@ +// Package controller 控制器层 +package controller + +import ( + "strconv" + + "server/common" + "server/modules/yx/entity" + "server/modules/yx/service" + + "github.com/gin-gonic/gin" +) + +type YxHistoryMajorEnrollController struct { + service *service.YxHistoryMajorEnrollService +} + +func NewYxHistoryMajorEnrollController() *YxHistoryMajorEnrollController { + return &YxHistoryMajorEnrollController{service: service.NewYxHistoryMajorEnrollService()} +} + +func (ctrl *YxHistoryMajorEnrollController) RegisterRoutes(r *gin.RouterGroup) { + r.GET("/yx-history-enrolls", ctrl.List) + r.GET("/yx-history-enrolls/:id", ctrl.GetByID) + r.POST("/yx-history-enrolls", ctrl.Create) + r.PUT("/yx-history-enrolls/:id", ctrl.Update) + r.PATCH("/yx-history-enrolls/:id", ctrl.UpdateFields) + r.DELETE("/yx-history-enrolls/:id", ctrl.Delete) + r.POST("/yx-history-enrolls/batch", ctrl.BatchCreate) + r.DELETE("/yx-history-enrolls/batch", ctrl.BatchDelete) +} + +// @Summary 获取历年招生列表 +// @Tags 历年招生 +// @Param page query int false "页码" +// @Param size query int false "每页数量" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls [get] +func (ctrl *YxHistoryMajorEnrollController) List(c *gin.Context) { + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + size, _ := strconv.Atoi(c.DefaultQuery("size", "10")) + items, total, err := ctrl.service.List(page, size) + if err != nil { + common.Error(c, 500, err.Error()) + return + } + common.SuccessPage(c, items, total, page, size) +} + +// @Summary 获取单个历年招生记录 +// @Tags 历年招生 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/{id} [get] +func (ctrl *YxHistoryMajorEnrollController) GetByID(c *gin.Context) { + item, err := ctrl.service.GetByID(c.Param("id")) + if err != nil { + common.Error(c, 404, "未找到") + return + } + common.Success(c, item) +} + +// @Summary 创建历年招生记录 +// @Tags 历年招生 +// @Param item body entity.YxHistoryMajorEnroll true "历年招生信息" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls [post] +func (ctrl *YxHistoryMajorEnrollController) Create(c *gin.Context) { + var item entity.YxHistoryMajorEnroll + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.Create(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 更新历年招生记录 +// @Tags 历年招生 +// @Param id path string true "ID" +// @Param item body entity.YxHistoryMajorEnroll true "历年招生信息" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/{id} [put] +func (ctrl *YxHistoryMajorEnrollController) Update(c *gin.Context) { + var item entity.YxHistoryMajorEnroll + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + item.ID = c.Param("id") + if err := ctrl.service.Update(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// @Summary 动态字段更新 +// @Tags 历年招生 +// @Param id path string true "ID" +// @Param fields body map[string]interface{} true "要更新的字段" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/{id} [patch] +func (ctrl *YxHistoryMajorEnrollController) UpdateFields(c *gin.Context) { + var fields map[string]interface{} + if err := c.ShouldBindJSON(&fields); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.UpdateFields(c.Param("id"), fields); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 删除历年招生记录 +// @Tags 历年招生 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/{id} [delete] +func (ctrl *YxHistoryMajorEnrollController) Delete(c *gin.Context) { + if err := ctrl.service.Delete(c.Param("id")); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 批量创建历年招生记录 +// @Tags 历年招生 +// @Param items body []entity.YxHistoryMajorEnroll true "历年招生列表" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/batch [post] +func (ctrl *YxHistoryMajorEnrollController) BatchCreate(c *gin.Context) { + var items []entity.YxHistoryMajorEnroll + if err := c.ShouldBindJSON(&items); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchCreate(items); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// @Summary 批量删除历年招生记录 +// @Tags 历年招生 +// @Param ids body []string true "ID列表" +// @Success 200 {object} common.Response +// @Router /yx-history-enrolls/batch [delete] +func (ctrl *YxHistoryMajorEnrollController) BatchDelete(c *gin.Context) { + var ids []string + if err := c.ShouldBindJSON(&ids); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchDelete(ids); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} diff --git a/server/modules/yx/controller/yx_school_major_controller.go b/server/modules/yx/controller/yx_school_major_controller.go new file mode 100644 index 0000000..e13d96b --- /dev/null +++ b/server/modules/yx/controller/yx_school_major_controller.go @@ -0,0 +1,176 @@ +// Package controller 控制器层 +package controller + +import ( + "strconv" + + "server/common" + "server/modules/yx/entity" + "server/modules/yx/service" + + "github.com/gin-gonic/gin" +) + +type YxSchoolMajorController struct { + service *service.YxSchoolMajorService +} + +func NewYxSchoolMajorController() *YxSchoolMajorController { + return &YxSchoolMajorController{service: service.NewYxSchoolMajorService()} +} + +func (ctrl *YxSchoolMajorController) RegisterRoutes(r *gin.RouterGroup) { + r.GET("/yx-school-majors", ctrl.List) + r.GET("/yx-school-majors/:id", ctrl.GetByID) + r.POST("/yx-school-majors", ctrl.Create) + r.PUT("/yx-school-majors/:id", ctrl.Update) + r.PATCH("/yx-school-majors/:id", ctrl.UpdateFields) + r.DELETE("/yx-school-majors/:id", ctrl.Delete) + r.POST("/yx-school-majors/batch", ctrl.BatchCreate) + r.DELETE("/yx-school-majors/batch", ctrl.BatchDelete) +} + +// List 获取院校专业列表 +// @Summary 获取院校专业列表 +// @Tags 院校专业 +// @Param page query int false "页码" +// @Param size query int false "每页数量" +// @Success 200 {object} common.Response +// @Router /yx-school-majors [get] +func (ctrl *YxSchoolMajorController) List(c *gin.Context) { + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + size, _ := strconv.Atoi(c.DefaultQuery("size", "10")) + items, total, err := ctrl.service.List(page, size) + if err != nil { + common.Error(c, 500, err.Error()) + return + } + common.SuccessPage(c, items, total, page, size) +} + +// GetByID 获取单个院校专业 +// @Summary 获取单个院校专业 +// @Tags 院校专业 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/{id} [get] +func (ctrl *YxSchoolMajorController) GetByID(c *gin.Context) { + item, err := ctrl.service.GetByID(c.Param("id")) + if err != nil { + common.Error(c, 404, "未找到") + return + } + common.Success(c, item) +} + +// Create 创建院校专业 +// @Summary 创建院校专业 +// @Tags 院校专业 +// @Param item body entity.YxSchoolMajor true "院校专业信息" +// @Success 200 {object} common.Response +// @Router /yx-school-majors [post] +func (ctrl *YxSchoolMajorController) Create(c *gin.Context) { + var item entity.YxSchoolMajor + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.Create(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// Update 更新院校专业 +// @Summary 更新院校专业 +// @Tags 院校专业 +// @Param id path string true "ID" +// @Param item body entity.YxSchoolMajor true "院校专业信息" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/{id} [put] +func (ctrl *YxSchoolMajorController) Update(c *gin.Context) { + var item entity.YxSchoolMajor + if err := c.ShouldBindJSON(&item); err != nil { + common.Error(c, 400, "参数错误") + return + } + item.ID = c.Param("id") + if err := ctrl.service.Update(&item); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, item) +} + +// UpdateFields 动态字段更新 +// @Summary 动态字段更新 +// @Tags 院校专业 +// @Param id path string true "ID" +// @Param fields body map[string]interface{} true "要更新的字段" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/{id} [patch] +func (ctrl *YxSchoolMajorController) UpdateFields(c *gin.Context) { + var fields map[string]interface{} + if err := c.ShouldBindJSON(&fields); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.UpdateFields(c.Param("id"), fields); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// Delete 删除院校专业 +// @Summary 删除院校专业 +// @Tags 院校专业 +// @Param id path string true "ID" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/{id} [delete] +func (ctrl *YxSchoolMajorController) Delete(c *gin.Context) { + if err := ctrl.service.Delete(c.Param("id")); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// BatchCreate 批量创建 +// @Summary 批量创建院校专业 +// @Tags 院校专业 +// @Param items body []entity.YxSchoolMajor true "院校专业列表" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/batch [post] +func (ctrl *YxSchoolMajorController) BatchCreate(c *gin.Context) { + var items []entity.YxSchoolMajor + if err := c.ShouldBindJSON(&items); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchCreate(items); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} + +// BatchDelete 批量删除 +// @Summary 批量删除院校专业 +// @Tags 院校专业 +// @Param ids body []string true "ID列表" +// @Success 200 {object} common.Response +// @Router /yx-school-majors/batch [delete] +func (ctrl *YxSchoolMajorController) BatchDelete(c *gin.Context) { + var ids []string + if err := c.ShouldBindJSON(&ids); err != nil { + common.Error(c, 400, "参数错误") + return + } + if err := ctrl.service.BatchDelete(ids); err != nil { + common.Error(c, 500, err.Error()) + return + } + common.Success(c, nil) +} diff --git a/server/modules/yx/entity/yx_calculation_major.go b/server/modules/yx/entity/yx_calculation_major.go new file mode 100644 index 0000000..1f34efa --- /dev/null +++ b/server/modules/yx/entity/yx_calculation_major.go @@ -0,0 +1,40 @@ +// Package entity 实体层 +package entity + +import "time" + +// YxCalculationMajor 计算专业表实体 +type YxCalculationMajor struct { + ID string `gorm:"column:id;primaryKey" json:"id"` + ScoreID string `gorm:"column:score_id" json:"scoreId"` + SchoolCode string `gorm:"column:school_code" json:"schoolCode"` + MajorCode string `gorm:"column:major_code" json:"majorCode"` + MajorName string `gorm:"column:major_name" json:"majorName"` + EnrollmentCode string `gorm:"column:enrollment_code" json:"enrollmentCode"` + Tuition string `gorm:"column:tuition" json:"tuition"` + Detail string `gorm:"column:detail" json:"detail"` + Category string `gorm:"column:category" json:"category"` + RulesEnrollProbability string `gorm:"column:rules_enroll_probability" json:"rulesEnrollProbability"` + Batch string `gorm:"column:batch" json:"batch"` + StudentOldConvertedScore float64 `gorm:"column:student_old_converted_score" json:"studentOldConvertedScore"` + StudentConvertedScore float64 `gorm:"column:student_converted_score" json:"studentConvertedScore"` + EnrollProbability float64 `gorm:"column:enroll_probability" json:"enrollProbability"` + ProbabilityOperator string `gorm:"column:probability_operator" json:"probabilityOperator"` + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` + MajorType string `gorm:"column:major_type" json:"majorType"` + MajorTypeChild string `gorm:"column:major_type_child" json:"majorTypeChild"` + PlanNum int `gorm:"column:plan_num" json:"planNum"` + MainSubjects string `gorm:"column:main_subjects" json:"mainSubjects"` + Limitation string `gorm:"column:limitation" json:"limitation"` + OtherScoreLimitation string `gorm:"column:other_score_limitation" json:"otherScoreLimitation"` + RulesEnrollProbabilitySx string `gorm:"column:rules_enroll_probability_sx" json:"rulesEnrollProbabilitySx"` + Kslx string `gorm:"column:kslx" json:"kslx"` + PrivateStudentConvertedScore float64 `gorm:"column:private_student_converted_score" json:"privateStudentConvertedScore"` + PrivateRulesEnrollProbability string `gorm:"column:private_rules_enroll_probability" json:"privateRulesEnrollProbability"` + PrivateProbabilityOperator string `gorm:"column:private_probability_operator" json:"privateProbabilityOperator"` + State string `gorm:"column:state" json:"state"` +} + +func (YxCalculationMajor) TableName() string { + return "yx_calculation_major_2025_2" +} diff --git a/server/modules/yx/entity/yx_history_major_enroll.go b/server/modules/yx/entity/yx_history_major_enroll.go new file mode 100644 index 0000000..51cd22c --- /dev/null +++ b/server/modules/yx/entity/yx_history_major_enroll.go @@ -0,0 +1,42 @@ +// Package entity 实体层 +package entity + +import "time" + +// YxHistoryMajorEnroll 历年艺术类招生录取分数表实体 +type YxHistoryMajorEnroll struct { + ID string `gorm:"column:id;primaryKey" json:"id"` + SchoolCode string `gorm:"column:school_code" json:"schoolCode"` + SchoolName string `gorm:"column:school_name" json:"schoolName"` + InstitutionCode string `gorm:"column:institution_code" json:"institutionCode"` + MajorCode string `gorm:"column:major_code" json:"majorCode"` + MajorName string `gorm:"column:major_name" json:"majorName"` + MajorType string `gorm:"column:major_type" json:"majorType"` + EnrollmentCode string `gorm:"column:enrollment_code" json:"enrollmentCode"` + Category string `gorm:"column:category" json:"category"` + Year string `gorm:"column:year" json:"year"` + EnrollNum int `gorm:"column:enroll_num" json:"enrollNum"` + ScoreLineDifference float64 `gorm:"column:score_line_difference" json:"scoreLineDifference"` + CreateBy string `gorm:"column:create_by" json:"createBy"` + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` + UpdateBy string `gorm:"column:update_by" json:"updateBy"` + UpdateTime time.Time `gorm:"column:update_time" json:"updateTime"` + SysOrgCode string `gorm:"column:sys_org_code" json:"sysOrgCode"` + Detail string `gorm:"column:detail" json:"detail"` + RulesEnrollProbability string `gorm:"column:rules_enroll_probability" json:"rulesEnrollProbability"` + ControlLine float64 `gorm:"column:control_line" json:"controlLine"` + AdmissionLine float64 `gorm:"column:admission_line" json:"admissionLine"` + ProbabilityOperator string `gorm:"column:probability_operator" json:"probabilityOperator"` + Batch string `gorm:"column:batch" json:"batch"` + OneVolunteerAdmissionNum int `gorm:"column:one_volunteer_admission_num" json:"oneVolunteerAdmissionNum"` + AdmissionNum int `gorm:"column:admission_num" json:"admissionNum"` + ActualPitcherNum int `gorm:"column:actual_pitcher_num" json:"actualPitcherNum"` + CheckMaster string `gorm:"column:check_master" json:"checkMaster"` + MajorTypeChild string `gorm:"column:major_type_child" json:"majorTypeChild"` + MainSubjects string `gorm:"column:main_subjects" json:"mainSubjects"` + Tuition string `gorm:"column:tuition" json:"tuition"` +} + +func (YxHistoryMajorEnroll) TableName() string { + return "yx_history_major_enroll" +} diff --git a/server/modules/yx/entity/yx_school_major.go b/server/modules/yx/entity/yx_school_major.go new file mode 100644 index 0000000..5754770 --- /dev/null +++ b/server/modules/yx/entity/yx_school_major.go @@ -0,0 +1,46 @@ +// Package entity 实体层 +package entity + +import "time" + +// YxSchoolMajor 院校专业关联表实体 +type YxSchoolMajor struct { + ID string `gorm:"column:id;primaryKey" json:"id"` + SchoolCode string `gorm:"column:school_code" json:"schoolCode"` + SchoolName string `gorm:"column:school_name" json:"schoolName"` + MajorCode string `gorm:"column:major_code" json:"majorCode"` + MajorName string `gorm:"column:major_name" json:"majorName"` + MajorType string `gorm:"column:major_type" json:"majorType"` + MajorTypeChild string `gorm:"column:major_type_child" json:"majorTypeChild"` + MainSubjects string `gorm:"column:main_subjects" json:"mainSubjects"` + EnrollmentCode string `gorm:"column:enrollment_code" json:"enrollmentCode"` + Category string `gorm:"column:category" json:"category"` + Batch string `gorm:"column:batch" json:"batch"` + Tuition string `gorm:"column:tuition" json:"tuition"` + PlanNum int `gorm:"column:plan_num" json:"planNum"` + Detail string `gorm:"column:detail" json:"detail"` + Semester string `gorm:"column:semester" json:"semester"` + CreateBy string `gorm:"column:create_by" json:"createBy"` + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` + UpdateBy string `gorm:"column:update_by" json:"updateBy"` + UpdateTime time.Time `gorm:"column:update_time" json:"updateTime"` + RulesEnrollProbabilitySx string `gorm:"column:rules_enroll_probability_sx" json:"rulesEnrollProbabilitySx"` + RulesEnrollProbability string `gorm:"column:rules_enroll_probability" json:"rulesEnrollProbability"` + ProbabilityOperator string `gorm:"column:probability_operator" json:"probabilityOperator"` + CulturalControlLine float64 `gorm:"column:cultural_control_line" json:"culturalControlLine"` + SpecialControlLine float64 `gorm:"column:special_control_line" json:"specialControlLine"` + CheckMaster string `gorm:"column:check_master" json:"checkMaster"` + Limitation string `gorm:"column:limitation" json:"limitation"` + ProfessionalScoreLimitation float64 `gorm:"column:professional_score_limitation" json:"professionalScoreLimitation"` + EnglishScoreLimitation float64 `gorm:"column:english_score_limitation" json:"englishScoreLimitation"` + ChineseScoreLimitation float64 `gorm:"column:chinese_score_limitation" json:"chineseScoreLimitation"` + CulturalScoreLimitation float64 `gorm:"column:cultural_score_limitation" json:"culturalScoreLimitation"` + Kslx string `gorm:"column:kslx" json:"kslx"` + PrivateProbabilityOperator string `gorm:"column:private_probability_operator" json:"privateProbabilityOperator"` + PrivateRulesEnrollProbability string `gorm:"column:private_rules_enroll_probability" json:"privateRulesEnrollProbability"` + State string `gorm:"column:state" json:"state"` +} + +func (YxSchoolMajor) TableName() string { + return "yx_school_major" +} diff --git a/server/modules/yx/mapper/yx_calculation_major_mapper.go b/server/modules/yx/mapper/yx_calculation_major_mapper.go new file mode 100644 index 0000000..e1ed3a5 --- /dev/null +++ b/server/modules/yx/mapper/yx_calculation_major_mapper.go @@ -0,0 +1,74 @@ +// Package mapper 数据访问层 +package mapper + +import ( + "server/config" + "server/modules/yx/entity" + + "gorm.io/gorm/clause" +) + +type YxCalculationMajorMapper struct{} + +func NewYxCalculationMajorMapper() *YxCalculationMajorMapper { + return &YxCalculationMajorMapper{} +} + +func (m *YxCalculationMajorMapper) FindAll(page, size int) ([]entity.YxCalculationMajor, int64, error) { + var items []entity.YxCalculationMajor + var total int64 + config.DB.Model(&entity.YxCalculationMajor{}).Count(&total) + err := config.DB.Offset((page - 1) * size).Limit(size).Find(&items).Error + return items, total, err +} + +func (m *YxCalculationMajorMapper) FindByID(id string) (*entity.YxCalculationMajor, error) { + var item entity.YxCalculationMajor + err := config.DB.First(&item, "id = ?", id).Error + return &item, err +} + +func (m *YxCalculationMajorMapper) Create(item *entity.YxCalculationMajor) error { + return config.DB.Create(item).Error +} + +func (m *YxCalculationMajorMapper) Update(item *entity.YxCalculationMajor) error { + return config.DB.Save(item).Error +} + +func (m *YxCalculationMajorMapper) UpdateFields(id string, fields map[string]interface{}) error { + return config.DB.Model(&entity.YxCalculationMajor{}).Where("id = ?", id).Updates(fields).Error +} + +func (m *YxCalculationMajorMapper) Delete(id string) error { + return config.DB.Delete(&entity.YxCalculationMajor{}, "id = ?", id).Error +} + +func (m *YxCalculationMajorMapper) FindByScoreID(scoreID string) ([]entity.YxCalculationMajor, error) { + var items []entity.YxCalculationMajor + err := config.DB.Where("score_id = ?", scoreID).Find(&items).Error + return items, err +} + +func (m *YxCalculationMajorMapper) BatchCreate(items []entity.YxCalculationMajor, batchSize int) error { + return config.DB.CreateInBatches(items, batchSize).Error +} + +func (m *YxCalculationMajorMapper) BatchUpdate(items []entity.YxCalculationMajor) error { + return config.DB.Save(items).Error +} + +func (m *YxCalculationMajorMapper) BatchUpsert(items []entity.YxCalculationMajor, updateColumns []string) error { + return config.DB.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "id"}}, + DoUpdates: clause.AssignmentColumns(updateColumns), + }).CreateInBatches(items, 100).Error +} + +func (m *YxCalculationMajorMapper) BatchDelete(ids []string) error { + return config.DB.Delete(&entity.YxCalculationMajor{}, "id IN ?", ids).Error +} + +func (m *YxCalculationMajorMapper) DeleteByScoreID(scoreID string) error { + return config.DB.Delete(&entity.YxCalculationMajor{}, "score_id = ?", scoreID).Error +} diff --git a/server/modules/yx/mapper/yx_history_major_enroll_mapper.go b/server/modules/yx/mapper/yx_history_major_enroll_mapper.go new file mode 100644 index 0000000..3b01d56 --- /dev/null +++ b/server/modules/yx/mapper/yx_history_major_enroll_mapper.go @@ -0,0 +1,70 @@ +// Package mapper 数据访问层 +package mapper + +import ( + "server/config" + "server/modules/yx/entity" + + "gorm.io/gorm/clause" +) + +type YxHistoryMajorEnrollMapper struct{} + +func NewYxHistoryMajorEnrollMapper() *YxHistoryMajorEnrollMapper { + return &YxHistoryMajorEnrollMapper{} +} + +func (m *YxHistoryMajorEnrollMapper) FindAll(page, size int) ([]entity.YxHistoryMajorEnroll, int64, error) { + var items []entity.YxHistoryMajorEnroll + var total int64 + config.DB.Model(&entity.YxHistoryMajorEnroll{}).Count(&total) + err := config.DB.Offset((page - 1) * size).Limit(size).Find(&items).Error + return items, total, err +} + +func (m *YxHistoryMajorEnrollMapper) FindByID(id string) (*entity.YxHistoryMajorEnroll, error) { + var item entity.YxHistoryMajorEnroll + err := config.DB.First(&item, "id = ?", id).Error + return &item, err +} + +func (m *YxHistoryMajorEnrollMapper) Create(item *entity.YxHistoryMajorEnroll) error { + return config.DB.Create(item).Error +} + +func (m *YxHistoryMajorEnrollMapper) Update(item *entity.YxHistoryMajorEnroll) error { + return config.DB.Save(item).Error +} + +func (m *YxHistoryMajorEnrollMapper) UpdateFields(id string, fields map[string]interface{}) error { + return config.DB.Model(&entity.YxHistoryMajorEnroll{}).Where("id = ?", id).Updates(fields).Error +} + +func (m *YxHistoryMajorEnrollMapper) Delete(id string) error { + return config.DB.Delete(&entity.YxHistoryMajorEnroll{}, "id = ?", id).Error +} + +func (m *YxHistoryMajorEnrollMapper) FindByYear(year string) ([]entity.YxHistoryMajorEnroll, error) { + var items []entity.YxHistoryMajorEnroll + err := config.DB.Where("year = ?", year).Find(&items).Error + return items, err +} + +func (m *YxHistoryMajorEnrollMapper) BatchCreate(items []entity.YxHistoryMajorEnroll, batchSize int) error { + return config.DB.CreateInBatches(items, batchSize).Error +} + +func (m *YxHistoryMajorEnrollMapper) BatchUpdate(items []entity.YxHistoryMajorEnroll) error { + return config.DB.Save(items).Error +} + +func (m *YxHistoryMajorEnrollMapper) BatchUpsert(items []entity.YxHistoryMajorEnroll, updateColumns []string) error { + return config.DB.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "id"}}, + DoUpdates: clause.AssignmentColumns(updateColumns), + }).CreateInBatches(items, 100).Error +} + +func (m *YxHistoryMajorEnrollMapper) BatchDelete(ids []string) error { + return config.DB.Delete(&entity.YxHistoryMajorEnroll{}, "id IN ?", ids).Error +} diff --git a/server/modules/yx/mapper/yx_school_major_mapper.go b/server/modules/yx/mapper/yx_school_major_mapper.go new file mode 100644 index 0000000..52c12d7 --- /dev/null +++ b/server/modules/yx/mapper/yx_school_major_mapper.go @@ -0,0 +1,64 @@ +// Package mapper 数据访问层 +package mapper + +import ( + "server/config" + "server/modules/yx/entity" + + "gorm.io/gorm/clause" +) + +type YxSchoolMajorMapper struct{} + +func NewYxSchoolMajorMapper() *YxSchoolMajorMapper { + return &YxSchoolMajorMapper{} +} + +func (m *YxSchoolMajorMapper) FindAll(page, size int) ([]entity.YxSchoolMajor, int64, error) { + var items []entity.YxSchoolMajor + var total int64 + config.DB.Model(&entity.YxSchoolMajor{}).Count(&total) + err := config.DB.Offset((page - 1) * size).Limit(size).Find(&items).Error + return items, total, err +} + +func (m *YxSchoolMajorMapper) FindByID(id string) (*entity.YxSchoolMajor, error) { + var item entity.YxSchoolMajor + err := config.DB.First(&item, "id = ?", id).Error + return &item, err +} + +func (m *YxSchoolMajorMapper) Create(item *entity.YxSchoolMajor) error { + return config.DB.Create(item).Error +} + +func (m *YxSchoolMajorMapper) Update(item *entity.YxSchoolMajor) error { + return config.DB.Save(item).Error +} + +func (m *YxSchoolMajorMapper) UpdateFields(id string, fields map[string]interface{}) error { + return config.DB.Model(&entity.YxSchoolMajor{}).Where("id = ?", id).Updates(fields).Error +} + +func (m *YxSchoolMajorMapper) Delete(id string) error { + return config.DB.Delete(&entity.YxSchoolMajor{}, "id = ?", id).Error +} + +func (m *YxSchoolMajorMapper) BatchCreate(items []entity.YxSchoolMajor, batchSize int) error { + return config.DB.CreateInBatches(items, batchSize).Error +} + +func (m *YxSchoolMajorMapper) BatchUpdate(items []entity.YxSchoolMajor) error { + return config.DB.Save(items).Error +} + +func (m *YxSchoolMajorMapper) BatchUpsert(items []entity.YxSchoolMajor, updateColumns []string) error { + return config.DB.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "id"}}, + DoUpdates: clause.AssignmentColumns(updateColumns), + }).CreateInBatches(items, 100).Error +} + +func (m *YxSchoolMajorMapper) BatchDelete(ids []string) error { + return config.DB.Delete(&entity.YxSchoolMajor{}, "id IN ?", ids).Error +} diff --git a/server/modules/yx/service/yx_calculation_major_service.go b/server/modules/yx/service/yx_calculation_major_service.go new file mode 100644 index 0000000..ceed489 --- /dev/null +++ b/server/modules/yx/service/yx_calculation_major_service.go @@ -0,0 +1,74 @@ +// Package service 业务逻辑层 +package service + +import ( + "server/modules/yx/entity" + "server/modules/yx/mapper" + + "github.com/google/uuid" +) + +type YxCalculationMajorService struct { + mapper *mapper.YxCalculationMajorMapper +} + +func NewYxCalculationMajorService() *YxCalculationMajorService { + return &YxCalculationMajorService{mapper: mapper.NewYxCalculationMajorMapper()} +} + +func (s *YxCalculationMajorService) List(page, size int) ([]entity.YxCalculationMajor, int64, error) { + return s.mapper.FindAll(page, size) +} + +func (s *YxCalculationMajorService) GetByID(id string) (*entity.YxCalculationMajor, error) { + return s.mapper.FindByID(id) +} + +func (s *YxCalculationMajorService) Create(item *entity.YxCalculationMajor) error { + item.ID = uuid.New().String() + return s.mapper.Create(item) +} + +func (s *YxCalculationMajorService) Update(item *entity.YxCalculationMajor) error { + return s.mapper.Update(item) +} + +func (s *YxCalculationMajorService) UpdateFields(id string, fields map[string]interface{}) error { + return s.mapper.UpdateFields(id, fields) +} + +func (s *YxCalculationMajorService) Delete(id string) error { + return s.mapper.Delete(id) +} + +func (s *YxCalculationMajorService) GetByScoreID(scoreID string) ([]entity.YxCalculationMajor, error) { + return s.mapper.FindByScoreID(scoreID) +} + +func (s *YxCalculationMajorService) BatchCreate(items []entity.YxCalculationMajor) error { + for i := range items { + items[i].ID = uuid.New().String() + } + return s.mapper.BatchCreate(items, 100) +} + +func (s *YxCalculationMajorService) BatchUpdate(items []entity.YxCalculationMajor) error { + return s.mapper.BatchUpdate(items) +} + +func (s *YxCalculationMajorService) BatchUpsert(items []entity.YxCalculationMajor, updateColumns []string) error { + for i := range items { + if items[i].ID == "" { + items[i].ID = uuid.New().String() + } + } + return s.mapper.BatchUpsert(items, updateColumns) +} + +func (s *YxCalculationMajorService) BatchDelete(ids []string) error { + return s.mapper.BatchDelete(ids) +} + +func (s *YxCalculationMajorService) DeleteByScoreID(scoreID string) error { + return s.mapper.DeleteByScoreID(scoreID) +} diff --git a/server/modules/yx/service/yx_history_major_enroll_service.go b/server/modules/yx/service/yx_history_major_enroll_service.go new file mode 100644 index 0000000..b6aaaf1 --- /dev/null +++ b/server/modules/yx/service/yx_history_major_enroll_service.go @@ -0,0 +1,70 @@ +// Package service 业务逻辑层 +package service + +import ( + "server/modules/yx/entity" + "server/modules/yx/mapper" + + "github.com/google/uuid" +) + +type YxHistoryMajorEnrollService struct { + mapper *mapper.YxHistoryMajorEnrollMapper +} + +func NewYxHistoryMajorEnrollService() *YxHistoryMajorEnrollService { + return &YxHistoryMajorEnrollService{mapper: mapper.NewYxHistoryMajorEnrollMapper()} +} + +func (s *YxHistoryMajorEnrollService) List(page, size int) ([]entity.YxHistoryMajorEnroll, int64, error) { + return s.mapper.FindAll(page, size) +} + +func (s *YxHistoryMajorEnrollService) GetByID(id string) (*entity.YxHistoryMajorEnroll, error) { + return s.mapper.FindByID(id) +} + +func (s *YxHistoryMajorEnrollService) Create(item *entity.YxHistoryMajorEnroll) error { + item.ID = uuid.New().String() + return s.mapper.Create(item) +} + +func (s *YxHistoryMajorEnrollService) Update(item *entity.YxHistoryMajorEnroll) error { + return s.mapper.Update(item) +} + +func (s *YxHistoryMajorEnrollService) UpdateFields(id string, fields map[string]interface{}) error { + return s.mapper.UpdateFields(id, fields) +} + +func (s *YxHistoryMajorEnrollService) Delete(id string) error { + return s.mapper.Delete(id) +} + +func (s *YxHistoryMajorEnrollService) GetByYear(year string) ([]entity.YxHistoryMajorEnroll, error) { + return s.mapper.FindByYear(year) +} + +func (s *YxHistoryMajorEnrollService) BatchCreate(items []entity.YxHistoryMajorEnroll) error { + for i := range items { + items[i].ID = uuid.New().String() + } + return s.mapper.BatchCreate(items, 100) +} + +func (s *YxHistoryMajorEnrollService) BatchUpdate(items []entity.YxHistoryMajorEnroll) error { + return s.mapper.BatchUpdate(items) +} + +func (s *YxHistoryMajorEnrollService) BatchUpsert(items []entity.YxHistoryMajorEnroll, updateColumns []string) error { + for i := range items { + if items[i].ID == "" { + items[i].ID = uuid.New().String() + } + } + return s.mapper.BatchUpsert(items, updateColumns) +} + +func (s *YxHistoryMajorEnrollService) BatchDelete(ids []string) error { + return s.mapper.BatchDelete(ids) +} diff --git a/server/modules/yx/service/yx_school_major_service.go b/server/modules/yx/service/yx_school_major_service.go new file mode 100644 index 0000000..6d3f86d --- /dev/null +++ b/server/modules/yx/service/yx_school_major_service.go @@ -0,0 +1,66 @@ +// Package service 业务逻辑层 +package service + +import ( + "server/modules/yx/entity" + "server/modules/yx/mapper" + + "github.com/google/uuid" +) + +type YxSchoolMajorService struct { + mapper *mapper.YxSchoolMajorMapper +} + +func NewYxSchoolMajorService() *YxSchoolMajorService { + return &YxSchoolMajorService{mapper: mapper.NewYxSchoolMajorMapper()} +} + +func (s *YxSchoolMajorService) List(page, size int) ([]entity.YxSchoolMajor, int64, error) { + return s.mapper.FindAll(page, size) +} + +func (s *YxSchoolMajorService) GetByID(id string) (*entity.YxSchoolMajor, error) { + return s.mapper.FindByID(id) +} + +func (s *YxSchoolMajorService) Create(item *entity.YxSchoolMajor) error { + item.ID = uuid.New().String() + return s.mapper.Create(item) +} + +func (s *YxSchoolMajorService) Update(item *entity.YxSchoolMajor) error { + return s.mapper.Update(item) +} + +func (s *YxSchoolMajorService) UpdateFields(id string, fields map[string]interface{}) error { + return s.mapper.UpdateFields(id, fields) +} + +func (s *YxSchoolMajorService) Delete(id string) error { + return s.mapper.Delete(id) +} + +func (s *YxSchoolMajorService) BatchCreate(items []entity.YxSchoolMajor) error { + for i := range items { + items[i].ID = uuid.New().String() + } + return s.mapper.BatchCreate(items, 100) +} + +func (s *YxSchoolMajorService) BatchUpdate(items []entity.YxSchoolMajor) error { + return s.mapper.BatchUpdate(items) +} + +func (s *YxSchoolMajorService) BatchUpsert(items []entity.YxSchoolMajor, updateColumns []string) error { + for i := range items { + if items[i].ID == "" { + items[i].ID = uuid.New().String() + } + } + return s.mapper.BatchUpsert(items, updateColumns) +} + +func (s *YxSchoolMajorService) BatchDelete(ids []string) error { + return s.mapper.BatchDelete(ids) +}