commit d9ece60bff12c1dcb80bef535b0bbe70824ec5a9 Author: zhangtao Date: Fri Aug 1 16:38:08 2025 +0800 first commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..610a3ed --- /dev/null +++ b/.editorconfig @@ -0,0 +1,34 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# 顶层配置文件 +root = true + +# 所有文件通用配置 +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +# Go 文件配置 +[*.go] +indent_size = 4 +indent_style = tab + +# Markdown 文件配置 +[*.md] +trim_trailing_whitespace = false + +# YAML 文件配置 +[*.{yml,yaml}] +indent_size = 2 + +# JSON 文件配置 +[*.json] +indent_size = 2 + +# Shell 脚本配置 +[*.sh] +end_of_line = lf \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..55bffd8 --- /dev/null +++ b/.env @@ -0,0 +1,12 @@ +PORT=3000 +MYSQL_DSN="root:200967tao@tcp(www.suyun.store:3306)/ego?charset=utf8mb4&parseTime=True&loc=Local" +REDIS_ADDR="www.suyun.store:6379" +REDIS_PW="tao200967" +REDIS_DB="0" +REDIS_POOL_SIZE=20 +REDIS_READ_TIMEOUT=3s +JWT_SECRET="YouOnlyLiveOnce" +GIN_MODE="test" +LOG_LEVEL="info" +LOG_PATH="./logs/" +CORS_ALLOWED_ORIGINS="http://www.unbug.cn:3000,http://127.0.0.1:3000" diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b425372 --- /dev/null +++ b/.env.example @@ -0,0 +1,12 @@ +PORT=3000 +MYSQL_DSN="root:200967tao@tcp(192.168.1.12:3306)/ego?charset=utf8mb4&parseTime=True&loc=Local" +REDIS_ADDR="192.168.1.12:6379" +REDIS_PW="200967tao" +REDIS_DB="0" +REDIS_POOL_SIZE=20 +REDIS_READ_TIMEOUT=3s +JWT_SECRET="YouOnlyLiveOnce" +GIN_MODE="test" +LOG_LEVEL="info" +LOG_PATH="./logs/" +CORS_ALLOWED_ORIGINS="http://localhost:3000,http://127.0.0.1:8080" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.idea/DeployHelper.iml b/.idea/DeployHelper.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/DeployHelper.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..c2bae49 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f4a8ec6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + Android + + + Bitwise operation issuesJava + + + Bitwise operation issuesJavaScript and TypeScript + + + Class structureJava + + + Code maturityJava + + + Code style issuesJava + + + CodeSpring CoreSpring + + + Compiler issuesJava + + + Control flow issuesJava + + + CorrectnessLintAndroid + + + Cucumber + + + FinalizationJava + + + GeneralJavaScript and TypeScript + + + Groovy + + + HTTP Client + + + IconsUsabilityLintAndroid + + + ImportsJava + + + Inheritance issuesJava + + + InternationalizationLintAndroid + + + InteroperabilityLintAndroid + + + JUnitJava + + + JVM languages + + + Java + + + Java 14Java language level migration aidsJava + + + Java 15Java language level migration aidsJava + + + Java 5Java language level migration aidsJava + + + Java 7Java language level migration aidsJava + + + Java 8Java language level migration aidsJava + + + Java 9Java language level migration aidsJava + + + Java language level migration aidsJava + + + JavaScript and TypeScript + + + JavadocJava + + + Kotlin + + + LintAndroid + + + MigrationKotlin + + + Numeric issuesJava + + + Other problemsKotlin + + + PerformanceJava + + + PerformanceLintAndroid + + + Potentially confusing code constructsGroovy + + + Potentially confusing code constructsJavaScript and TypeScript + + + Probable bugsJava + + + Probable bugsKotlin + + + Reactive Streams + + + ReactorReactive Streams + + + Redundant constructsKotlin + + + Resource managementJava + + + SQL + + + SecurityLintAndroid + + + Spring + + + Spring AOPSpring + + + Spring BootSpring + + + Spring CoreSpring + + + Style issuesKotlin + + + Test frameworksJVM languages + + + TestNGJava + + + Threading issuesJava + + + UI form + + + UsabilityLintAndroid + + + XMLSpring CoreSpring + + + + + Android + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9af488d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..719a531 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + { + "associatedIndex": 5 +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1754033774462 + + + + + + + true + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..35e7a3c --- /dev/null +++ b/Makefile @@ -0,0 +1,183 @@ +.PHONY: build run test clean docker-build docker-run docker-compose-up docker-compose-down wire docs fmt lint deps dev-setup build-all install-tools check-env mod-tidy + +# 构建变量 +BINARY_NAME=ego +MAIN_FILE=cmd/ego/main.go +DOCKER_IMAGE=ego:latest +GOOS ?= $(shell go env GOOS) +GOARCH ?= $(shell go env GOARCH) + +# Go版本检查 +GO_VERSION := $(shell go version | cut -d ' ' -f 3 | sed 's/go//') +REQUIRED_GO_VERSION := 1.21 + +# 默认目标 +.DEFAULT_GOAL := help + +# 帮助信息 +help: ## 显示帮助信息 + @echo "可用的命令:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +# 环境检查 +check-env: ## 检查开发环境 + @echo "检查Go版本..." + @if [ "$(shell printf '%s\n' $(REQUIRED_GO_VERSION) $(GO_VERSION) | sort -V | head -n1)" != "$(REQUIRED_GO_VERSION)" ]; then \ + echo "错误: 需要Go $(REQUIRED_GO_VERSION)或更高版本,当前版本: $(GO_VERSION)"; \ + exit 1; \ + fi + @echo "✓ Go版本检查通过: $(GO_VERSION)" + @echo "检查必要工具..." + @command -v git >/dev/null 2>&1 || { echo "错误: 需要安装git"; exit 1; } + @echo "✓ 环境检查完成" + +# 构建 +build: check-env ## 构建应用程序 + @echo "构建 $(BINARY_NAME)..." + @go build -ldflags="-w -s" -o $(BINARY_NAME) ./$(MAIN_FILE) + @echo "✓ 构建完成: $(BINARY_NAME)" + +# 运行 +run: check-env ## 运行应用程序 + @echo "运行应用程序..." + @go run ./$(MAIN_FILE) + +# 开发模式运行 +dev: check-env ## 开发模式运行(调试模式) + @echo "以开发模式运行..." + @GIN_MODE=debug LOG_LEVEL=debug go run ./$(MAIN_FILE) + +# 测试 +test: ## 运行测试 + @echo "运行测试..." + @go test -v -race -coverprofile=coverage.out ./... + @go tool cover -html=coverage.out -o coverage.html + @echo "✓ 测试完成,覆盖率报告: coverage.html" + +# 基准测试 +bench: ## 运行基准测试 + @echo "运行基准测试..." + @go test -bench=. -benchmem ./... + +# 清理 +clean: ## 清理构建文件 + @echo "清理构建文件..." + @go clean + @rm -f $(BINARY_NAME) + @rm -f cmd/ego/$(BINARY_NAME) + @rm -f coverage.out coverage.html + @rm -rf dist/ + @echo "✓ 清理完成" + +# 整理依赖 +mod-tidy: ## 整理Go模块依赖 + @echo "整理依赖..." + @go mod tidy + @go mod verify + @echo "✓ 依赖整理完成" + +# Docker 构建 +docker-build: ## 构建Docker镜像 + @echo "构建Docker镜像..." + @docker build -f deployments/Dockerfile -t $(DOCKER_IMAGE) . + @echo "✓ Docker镜像构建完成: $(DOCKER_IMAGE)" + +# Docker 运行 +docker-run: ## 运行Docker容器 + @echo "运行Docker容器..." + @docker run -p 3000:3000 --env-file .env $(DOCKER_IMAGE) + +# Docker Compose 启动 +docker-compose-up: ## 使用Docker Compose启动服务 + @echo "启动Docker Compose服务..." + @docker-compose -f deployments/docker-compose.yml up -d + @echo "✓ 服务已启动" + +# Docker Compose 停止 +docker-compose-down: ## 停止Docker Compose服务 + @echo "停止Docker Compose服务..." + @docker-compose -f deployments/docker-compose.yml down + @echo "✓ 服务已停止" + +# 生成 wire 依赖注入代码 +wire: ## 生成依赖注入代码 + @echo "生成Wire依赖注入代码..." + @cd internal/wire && wire + @echo "✓ Wire代码生成完成" + +# 生成 API 文档 +docs: ## 生成API文档 + @echo "生成API文档..." + @swag init -g $(MAIN_FILE) -o ./api --parseDependency --parseInternal + @echo "✓ API文档生成完成" + +# 安装依赖 +deps: check-env ## 下载依赖包 + @echo "下载依赖包..." + @go mod download + @go mod verify + @echo "✓ 依赖下载完成" + +# 代码格式化 +fmt: ## 格式化代码 + @echo "格式化代码..." + @go fmt ./... + @gofmt -w . + @echo "✓ 代码格式化完成" + +# 代码检查 +lint: ## 代码静态检查 + @echo "运行代码检查..." + @golangci-lint run --timeout=5m + @echo "✓ 代码检查完成" + +# 安全检查 +security: ## 运行安全检查 + @echo "运行安全检查..." + @govulncheck ./... + @echo "✓ 安全检查完成" + +# 开发环境设置 +dev-setup: check-env ## 设置开发环境 + @echo "设置开发环境..." + @if [ ! -f "configs/config.yaml" ]; then \ + cp "configs/config.yaml.example" "configs/config.yaml"; \ + echo "✓ 配置文件已创建: configs/config.yaml"; \ + fi + @if [ ! -f ".env" ]; then \ + cp ".env.example" ".env" 2>/dev/null || echo "# 请根据需要设置环境变量" > .env; \ + echo "✓ 环境变量文件已创建: .env"; \ + fi + @mkdir -p logs + @echo "✓ 日志目录已创建: logs/" + @$(MAKE) deps + @$(MAKE) install-tools + @$(MAKE) wire + @echo "✓ 开发环境设置完成!" + +# 构建所有平台 +build-all: check-env ## 构建所有平台的二进制文件 + @echo "构建所有平台..." + @mkdir -p dist + @GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o dist/$(BINARY_NAME)-linux-amd64 ./$(MAIN_FILE) + @GOOS=windows GOARCH=amd64 go build -ldflags="-w -s" -o dist/$(BINARY_NAME)-windows-amd64.exe ./$(MAIN_FILE) + @GOOS=darwin GOARCH=amd64 go build -ldflags="-w -s" -o dist/$(BINARY_NAME)-darwin-amd64 ./$(MAIN_FILE) + @GOOS=darwin GOARCH=arm64 go build -ldflags="-w -s" -o dist/$(BINARY_NAME)-darwin-arm64 ./$(MAIN_FILE) + @echo "✓ 所有平台构建完成,文件位于 dist/ 目录" + +# 安装开发工具 +install-tools: ## 安装开发工具 + @echo "安装开发工具..." + @go install github.com/swaggo/swag/cmd/swag@latest + @go install github.com/google/wire/cmd/wire@latest + @go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + @go install golang.org/x/vuln/cmd/govulncheck@latest + @echo "✓ 开发工具安装完成" + +# 运行所有检查 +check-all: fmt lint test security ## 运行所有代码质量检查 + @echo "✓ 所有检查完成" + +# 发布准备 +release-prep: check-all build-all docs ## 准备发布版本 + @echo "✓ 发布准备完成" diff --git a/api/api/5daeb2f60dc9a5143eb1c9ee907dc7d2.jpeg b/api/api/5daeb2f60dc9a5143eb1c9ee907dc7d2.jpeg new file mode 100644 index 0000000..a5c5752 Binary files /dev/null and b/api/api/5daeb2f60dc9a5143eb1c9ee907dc7d2.jpeg differ diff --git a/api/api/8b2e95d1-a86f-4c75-8b6e-6d4308a0d7f0.jpg b/api/api/8b2e95d1-a86f-4c75-8b6e-6d4308a0d7f0.jpg new file mode 100644 index 0000000..b80bbdb Binary files /dev/null and b/api/api/8b2e95d1-a86f-4c75-8b6e-6d4308a0d7f0.jpg differ diff --git a/api/swagger.json b/api/swagger.json new file mode 100644 index 0000000..a6f66aa --- /dev/null +++ b/api/swagger.json @@ -0,0 +1,4345 @@ +{ + "swagger": "2.0", + "info": { + "description": "EGO 系统 API 文档", + "title": "EGO API", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0" + }, + "host": "127.0.0.1:3000", + "basePath": "/", + "paths": { + "/api/v1/sysConfig": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "创建配置", + "parameters": [ + { + "description": "配置信息", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "批量删除配置", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询系统配置列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "条件查询配置", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询系统配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "批量查询配置", + "parameters": [ + { + "description": "配置ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取系统配置详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "更新配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "配置信息", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "删除配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "创建部门", + "parameters": [ + { + "description": "部门信息", + "name": "dept", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDept" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除部门", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "批量删除部门", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询部门列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "条件查询部门", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询部门", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "批量查询部门", + "parameters": [ + { + "description": "部门ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取部门详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "获取部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "更新部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "部门信息", + "name": "dept", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDept" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "删除部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "创建字典数据", + "parameters": [ + { + "description": "字典数据信息", + "name": "dictData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除字典数据", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "批量删除字典数据", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询字典数据列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "条件查询字典数据", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询字典数据", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "批量查询字典数据", + "parameters": [ + { + "description": "字典数据ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取字典数据详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "获取字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "更新字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "字典数据信息", + "name": "dictData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "删除字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "创建字典类型", + "parameters": [ + { + "description": "字典类型信息", + "name": "dictType", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除字典类型", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "批量删除字典类型", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询字典类型列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "条件查询字典类型", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询字典类型", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "批量查询字典类型", + "parameters": [ + { + "description": "字典类型ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取字典类型详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "获取字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "更新字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "字典类型信息", + "name": "dictType", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "删除字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "创建文件记录", + "parameters": [ + { + "description": "文件信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysFile" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "批量删除文件记录", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/condition": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据条件查询文件记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "条件查询文件记录", + "parameters": [ + { + "description": "查询条件", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/list": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表获取文件记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "批量获取文件记录", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/{id}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID获取文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "获取文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID更新文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "更新文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "文件信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysFile" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID删除文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "删除文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "创建定时任务", + "parameters": [ + { + "description": "定时任务信息", + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysJob" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除任务", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "批量删除任务", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询定时任务列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "条件查询定时任务", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询定时任务", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "批量查询定时任务", + "parameters": [ + { + "description": "定时任务ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取定时任务详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "获取定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "更新定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "定时任务信息", + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysJob" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "删除定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "创建菜单", + "parameters": [ + { + "description": "菜单信息", + "name": "menu", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysMenu" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "条件查询菜单", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/ids": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量删除菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "批量删除菜单", + "parameters": [ + { + "description": "菜单ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "批量查询菜单", + "parameters": [ + { + "description": "菜单ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/user": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取当前用户的菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "获取用户菜单", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取菜单信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "获取菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新菜单信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "更新菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "菜单信息", + "name": "menu", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysMenu" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "删除菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "创建通知公告", + "parameters": [ + { + "description": "通知公告信息", + "name": "notice", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysNotice" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除通知", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "批量删除通知", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询通知公告列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "条件查询通知公告", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询通知公告", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "批量查询通知公告", + "parameters": [ + { + "description": "通知公告ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取通知公告详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "获取通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "更新通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "通知公告信息", + "name": "notice", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysNotice" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "删除通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "创建操作日志", + "parameters": [ + { + "description": "操作日志信息", + "name": "operLog", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysOperLog" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除操作日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "批量删除操作日志", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询操作日志列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "条件查询操作日志", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询操作日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "批量查询操作日志", + "parameters": [ + { + "description": "操作日志ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取操作日志详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "获取操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "更新操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "操作日志信息", + "name": "operLog", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysOperLog" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "删除操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "创建岗位", + "parameters": [ + { + "description": "岗位信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysPost" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "批量删除岗位", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/condition": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据条件查询岗位列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "条件查询岗位", + "parameters": [ + { + "description": "查询条件", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/list": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表获取岗位列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "批量获取岗位", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/{id}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID获取岗位信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "获取岗位信息", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID更新岗位信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "更新岗位", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "岗位信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysPost" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID删除岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "删除岗位", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "角色信息", + "name": "role", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysRole" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "批量删除角色", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询角色列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "条件查询角色", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "批量查询角色", + "parameters": [ + { + "description": "角色ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/user": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取指定用户的角色列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取用户角色", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取角色信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新角色信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "更新角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "角色信息", + "name": "role", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysRole" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "删除角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/{id}/menus": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取指定角色的菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取角色菜单", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "为角色分配菜单权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "分配菜单权限", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "菜单ID列表", + "name": "menuIds", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "批量删除用户", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询用户列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "条件查询用户", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "批量查询用户", + "parameters": [ + { + "description": "用户ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/logout": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "用户退出登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/me": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取当前登录用户的详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "获取当前用户信息", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取用户信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "获取用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新用户信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "更新用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "用户信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "删除用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/user/login": { + "post": { + "description": "用户登录接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "用户登录信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service.UserLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/user/register": { + "post": { + "description": "新用户注册接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户注册", + "parameters": [ + { + "description": "用户注册信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service.UserRegisterRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/ping": { + "get": { + "description": "Get a message from the server", + "produces": [ + "application/json" + ], + "summary": "Get a message", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + } + }, + "definitions": { + "model.MenuMeta": { + "type": "object", + "properties": { + "icon": { + "type": "string" + }, + "title": { + "$ref": "#/definitions/model.Title" + } + } + }, + "model.SysConfig": { + "type": "object", + "properties": { + "configID": { + "type": "string" + }, + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDept": { + "type": "object", + "properties": { + "ancestors": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptId": { + "type": "string" + }, + "deptName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "leader": { + "type": "string" + }, + "orderNum": { + "type": "integer" + }, + "parentId": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDictData": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "cssClass": { + "type": "string" + }, + "dictCode": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDictType": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "dictId": { + "type": "string" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysFile": { + "type": "object", + "properties": { + "businessId": { + "type": "string" + }, + "businessType": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "fileKey": { + "type": "string" + }, + "fileName": { + "type": "string" + }, + "fileSize": { + "type": "integer" + }, + "fileType": { + "type": "string" + }, + "id": { + "type": "string" + }, + "revision": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysJob": { + "type": "object", + "properties": { + "concurrent": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "cronExpression": { + "type": "string" + }, + "invokeTarget": { + "type": "string" + }, + "jobGroup": { + "type": "string" + }, + "jobId": { + "type": "string" + }, + "jobName": { + "type": "string" + }, + "misfirePolicy": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysMenu": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SysMenu" + } + }, + "component": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "en_US": { + "type": "string" + }, + "frameBlank": { + "type": "boolean" + }, + "frameSrc": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "isCache": { + "type": "string" + }, + "isFrame": { + "type": "string" + }, + "menuID": { + "type": "string" + }, + "menuType": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/model.MenuMeta" + }, + "name": { + "type": "string" + }, + "orderNum": { + "type": "integer" + }, + "parentID": { + "type": "string" + }, + "path": { + "type": "string" + }, + "perms": { + "type": "string" + }, + "query": { + "type": "string" + }, + "redirect": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "visible": { + "type": "string" + }, + "zh_CN": { + "type": "string" + } + } + }, + "model.SysNotice": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "noticeContent": { + "type": "string" + }, + "noticeId": { + "type": "string" + }, + "noticeTitle": { + "type": "string" + }, + "noticeType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysOperLog": { + "type": "object", + "properties": { + "businessType": { + "type": "integer" + }, + "deptName": { + "type": "string" + }, + "errorMsg": { + "type": "string" + }, + "jsonResult": { + "type": "string" + }, + "method": { + "type": "string" + }, + "operIP": { + "type": "string" + }, + "operId": { + "type": "string" + }, + "operLocation": { + "type": "string" + }, + "operName": { + "type": "string" + }, + "operParam": { + "type": "string" + }, + "operTime": { + "type": "string" + }, + "operUrl": { + "type": "string" + }, + "operatorType": { + "type": "integer" + }, + "requestMethod": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "trackId": { + "type": "string" + } + } + }, + "model.SysPost": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "string" + }, + "postName": { + "type": "string" + }, + "postSort": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysRole": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptCheckStrictly": { + "type": "boolean" + }, + "menuCheckStrictly": { + "type": "boolean" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "string" + }, + "roleKey": { + "type": "string" + }, + "roleName": { + "type": "string" + }, + "roleSort": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysUser": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptId": { + "type": "string" + }, + "email": { + "type": "string" + }, + "gender": { + "type": "string" + }, + "loginDate": { + "type": "string" + }, + "loginIP": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "passWord": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "resourceInvoke": { + "type": "string" + }, + "selectKey": { + "type": "string" + }, + "solt": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "userType": { + "type": "string" + } + } + }, + "model.Title": { + "type": "object", + "properties": { + "en_US": { + "type": "string" + }, + "zh_CN": { + "type": "string" + } + } + }, + "serializer.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "error": { + "type": "string" + }, + "msg": { + "type": "string" + } + } + }, + "service.UserLoginRequest": { + "type": "object", + "required": [ + "account", + "checked", + "password" + ], + "properties": { + "account": { + "type": "string", + "maxLength": 30, + "minLength": 5 + }, + "checked": { + "type": "boolean" + }, + "password": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "phone": { + "type": "string" + }, + "verifyCode": { + "type": "string" + } + } + }, + "service.UserRegisterRequest": { + "type": "object", + "required": [ + "nickName", + "passWord", + "passWordConfirm", + "userName" + ], + "properties": { + "nickName": { + "type": "string", + "maxLength": 30, + "minLength": 2 + }, + "passWord": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "passWordConfirm": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "userName": { + "type": "string", + "maxLength": 30, + "minLength": 5 + } + } + }, + "types.Column": { + "type": "object", + "properties": { + "exp": { + "description": "expressions, which default to = when the value is null, have =, !=, \u003e, \u003e=, \u003c, \u003c=, like, in", + "type": "string" + }, + "logic": { + "description": "logical type, defaults to and when the value is null, with \u0026(and), ||(or)", + "type": "string" + }, + "name": { + "description": "column name", + "type": "string" + }, + "value": { + "description": "column value" + } + } + }, + "types.Params": { + "type": "object", + "properties": { + "columns": { + "description": "not required", + "type": "array", + "items": { + "$ref": "#/definitions/types.Column" + } + }, + "limit": { + "type": "integer", + "minimum": 10 + }, + "page": { + "type": "integer", + "minimum": 0 + }, + "sort": { + "type": "string" + } + } + }, + "types.Payload": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "securityDefinitions": { + "BearerAuth": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} diff --git a/api/swagger.yaml b/api/swagger.yaml new file mode 100644 index 0000000..7e56749 --- /dev/null +++ b/api/swagger.yaml @@ -0,0 +1,2742 @@ +basePath: / +definitions: + model.MenuMeta: + properties: + icon: + type: string + title: + $ref: '#/definitions/model.Title' + type: object + model.SysConfig: + properties: + configID: + type: string + configKey: + type: string + configName: + type: string + configType: + type: string + configValue: + type: string + createBy: + type: string + createTime: + type: string + remark: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysDept: + properties: + ancestors: + type: string + createBy: + type: string + createTime: + type: string + delFlag: + type: string + deptId: + type: string + deptName: + type: string + email: + type: string + leader: + type: string + orderNum: + type: integer + parentId: + type: string + phone: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysDictData: + properties: + createBy: + type: string + createTime: + type: string + cssClass: + type: string + dictCode: + type: string + dictLabel: + type: string + dictSort: + type: integer + dictType: + type: string + dictValue: + type: string + isDefault: + type: string + listClass: + type: string + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysDictType: + properties: + createBy: + type: string + createTime: + type: string + dictId: + type: string + dictName: + type: string + dictType: + type: string + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysFile: + properties: + businessId: + type: string + businessType: + type: string + createBy: + type: string + createTime: + type: string + delFlag: + type: string + fileKey: + type: string + fileName: + type: string + fileSize: + type: integer + fileType: + type: string + id: + type: string + revision: + type: integer + type: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysJob: + properties: + concurrent: + type: string + createBy: + type: string + createTime: + type: string + cronExpression: + type: string + invokeTarget: + type: string + jobGroup: + type: string + jobId: + type: string + jobName: + type: string + misfirePolicy: + type: string + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysMenu: + properties: + children: + items: + $ref: '#/definitions/model.SysMenu' + type: array + component: + type: string + createBy: + type: string + createTime: + type: string + en_US: + type: string + frameBlank: + type: boolean + frameSrc: + type: string + icon: + type: string + isCache: + type: string + isFrame: + type: string + menuID: + type: string + menuType: + type: string + meta: + $ref: '#/definitions/model.MenuMeta' + name: + type: string + orderNum: + type: integer + parentID: + type: string + path: + type: string + perms: + type: string + query: + type: string + redirect: + type: string + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + visible: + type: string + zh_CN: + type: string + type: object + model.SysNotice: + properties: + createBy: + type: string + createTime: + type: string + noticeContent: + type: string + noticeId: + type: string + noticeTitle: + type: string + noticeType: + type: string + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysOperLog: + properties: + businessType: + type: integer + deptName: + type: string + errorMsg: + type: string + jsonResult: + type: string + method: + type: string + operIP: + type: string + operId: + type: string + operLocation: + type: string + operName: + type: string + operParam: + type: string + operTime: + type: string + operUrl: + type: string + operatorType: + type: integer + requestMethod: + type: string + status: + type: integer + title: + type: string + trackId: + type: string + type: object + model.SysPost: + properties: + createBy: + type: string + createTime: + type: string + postCode: + type: string + postId: + type: string + postName: + type: string + postSort: + type: integer + remark: + type: string + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysRole: + properties: + createBy: + type: string + createTime: + type: string + dataScope: + type: string + delFlag: + type: string + deptCheckStrictly: + type: boolean + menuCheckStrictly: + type: boolean + remark: + type: string + roleId: + type: string + roleKey: + type: string + roleName: + type: string + roleSort: + type: integer + status: + type: string + updateBy: + type: string + updateTime: + type: string + type: object + model.SysUser: + properties: + avatar: + type: string + createBy: + type: string + createTime: + type: string + delFlag: + type: string + deptId: + type: string + email: + type: string + gender: + type: string + loginDate: + type: string + loginIP: + type: string + nickName: + type: string + passWord: + type: string + phoneNumber: + type: string + remark: + type: string + resourceInvoke: + type: string + selectKey: + type: string + solt: + type: integer + status: + type: string + updateBy: + type: string + updateTime: + type: string + userId: + type: string + userName: + type: string + userType: + type: string + type: object + model.Title: + properties: + en_US: + type: string + zh_CN: + type: string + type: object + serializer.Response: + properties: + code: + type: integer + data: { } + error: + type: string + msg: + type: string + type: object + service.UserLoginRequest: + properties: + account: + maxLength: 30 + minLength: 5 + type: string + checked: + type: boolean + password: + maxLength: 40 + minLength: 8 + type: string + phone: + type: string + verifyCode: + type: string + required: + - account + - checked + - password + type: object + service.UserRegisterRequest: + properties: + nickName: + maxLength: 30 + minLength: 2 + type: string + passWord: + maxLength: 40 + minLength: 8 + type: string + passWordConfirm: + maxLength: 40 + minLength: 8 + type: string + userName: + maxLength: 30 + minLength: 5 + type: string + required: + - nickName + - passWord + - passWordConfirm + - userName + type: object + types.Column: + properties: + exp: + description: expressions, which default to = when the value is null, have + =, !=, >, >=, <, <=, like, in + type: string + logic: + description: logical type, defaults to and when the value is null, with &(and), + ||(or) + type: string + name: + description: column name + type: string + value: + description: column value + type: object + types.Params: + properties: + columns: + description: not required + items: + $ref: '#/definitions/types.Column' + type: array + limit: + minimum: 10 + type: integer + page: + minimum: 0 + type: integer + sort: + type: string + type: object + types.Payload: + properties: + ids: + items: + type: string + type: array + type: object +host: 127.0.0.1:3000 +info: + contact: + email: support@swagger.io + name: API Support + url: http://www.swagger.io/support + description: EGO 系统 API 文档 + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: http://swagger.io/terms/ + title: EGO API + version: "1.0" +paths: + /api/v1/sysConfig: + post: + consumes: + - application/json + description: 创建新的系统配置信息 + parameters: + - description: 配置信息 + in: body + name: config + required: true + schema: + $ref: '#/definitions/model.SysConfig' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建配置 + tags: + - 配置管理 + /api/v1/sysConfig/{id}: + delete: + consumes: + - application/json + description: 根据ID删除系统配置信息 + parameters: + - description: 配置ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除配置 + tags: + - 配置管理 + get: + consumes: + - application/json + description: 根据ID获取系统配置详细信息 + parameters: + - description: 配置ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取配置 + tags: + - 配置管理 + put: + consumes: + - application/json + description: 根据ID更新系统配置信息 + parameters: + - description: 配置ID + in: path + name: id + required: true + type: string + - description: 配置信息 + in: body + name: config + required: true + schema: + $ref: '#/definitions/model.SysConfig' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新配置 + tags: + - 配置管理 + /api/v1/sysConfig/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除配置 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除配置 + tags: + - 配置管理 + /api/v1/sysConfig/condition: + post: + consumes: + - application/json + description: 根据条件查询系统配置列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询配置 + tags: + - 配置管理 + /api/v1/sysConfig/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询系统配置 + parameters: + - description: 配置ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询配置 + tags: + - 配置管理 + /api/v1/sysDept: + post: + consumes: + - application/json + description: 创建新的部门信息 + parameters: + - description: 部门信息 + in: body + name: dept + required: true + schema: + $ref: '#/definitions/model.SysDept' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建部门 + tags: + - 部门管理 + /api/v1/sysDept/{id}: + delete: + consumes: + - application/json + description: 根据ID删除部门信息 + parameters: + - description: 部门ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除部门 + tags: + - 部门管理 + get: + consumes: + - application/json + description: 根据ID获取部门详细信息 + parameters: + - description: 部门ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取部门 + tags: + - 部门管理 + put: + consumes: + - application/json + description: 根据ID更新部门信息 + parameters: + - description: 部门ID + in: path + name: id + required: true + type: string + - description: 部门信息 + in: body + name: dept + required: true + schema: + $ref: '#/definitions/model.SysDept' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新部门 + tags: + - 部门管理 + /api/v1/sysDept/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除部门 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除部门 + tags: + - 部门管理 + /api/v1/sysDept/condition: + post: + consumes: + - application/json + description: 根据条件查询部门列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询部门 + tags: + - 部门管理 + /api/v1/sysDept/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询部门 + parameters: + - description: 部门ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询部门 + tags: + - 部门管理 + /api/v1/sysDictData: + post: + consumes: + - application/json + description: 创建新的字典数据信息 + parameters: + - description: 字典数据信息 + in: body + name: dictData + required: true + schema: + $ref: '#/definitions/model.SysDictData' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建字典数据 + tags: + - 字典数据 + /api/v1/sysDictData/{id}: + delete: + consumes: + - application/json + description: 根据ID删除字典数据信息 + parameters: + - description: 字典数据ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除字典数据 + tags: + - 字典数据 + get: + consumes: + - application/json + description: 根据ID获取字典数据详细信息 + parameters: + - description: 字典数据ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取字典数据 + tags: + - 字典数据 + put: + consumes: + - application/json + description: 根据ID更新字典数据信息 + parameters: + - description: 字典数据ID + in: path + name: id + required: true + type: string + - description: 字典数据信息 + in: body + name: dictData + required: true + schema: + $ref: '#/definitions/model.SysDictData' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新字典数据 + tags: + - 字典数据 + /api/v1/sysDictData/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除字典数据 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除字典数据 + tags: + - 字典数据 + /api/v1/sysDictData/condition: + post: + consumes: + - application/json + description: 根据条件查询字典数据列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询字典数据 + tags: + - 字典数据 + /api/v1/sysDictData/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询字典数据 + parameters: + - description: 字典数据ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询字典数据 + tags: + - 字典数据 + /api/v1/sysDictType: + post: + consumes: + - application/json + description: 创建新的字典类型信息 + parameters: + - description: 字典类型信息 + in: body + name: dictType + required: true + schema: + $ref: '#/definitions/model.SysDictType' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建字典类型 + tags: + - 字典类型 + /api/v1/sysDictType/{id}: + delete: + consumes: + - application/json + description: 根据ID删除字典类型信息 + parameters: + - description: 字典类型ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除字典类型 + tags: + - 字典类型 + get: + consumes: + - application/json + description: 根据ID获取字典类型详细信息 + parameters: + - description: 字典类型ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取字典类型 + tags: + - 字典类型 + put: + consumes: + - application/json + description: 根据ID更新字典类型信息 + parameters: + - description: 字典类型ID + in: path + name: id + required: true + type: string + - description: 字典类型信息 + in: body + name: dictType + required: true + schema: + $ref: '#/definitions/model.SysDictType' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新字典类型 + tags: + - 字典类型 + /api/v1/sysDictType/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除字典类型 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除字典类型 + tags: + - 字典类型 + /api/v1/sysDictType/condition: + post: + consumes: + - application/json + description: 根据条件查询字典类型列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询字典类型 + tags: + - 字典类型 + /api/v1/sysDictType/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询字典类型 + parameters: + - description: 字典类型ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询字典类型 + tags: + - 字典类型 + /api/v1/sysFile: + post: + consumes: + - application/json + description: 创建文件记录 + parameters: + - description: 文件信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/model.SysFile' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 创建文件记录 + tags: + - 文件管理 + /api/v1/sysFile/{id}: + delete: + consumes: + - application/json + description: 根据ID删除文件记录 + parameters: + - description: 文件ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 删除文件记录 + tags: + - 文件管理 + get: + consumes: + - application/json + description: 根据ID获取文件记录 + parameters: + - description: 文件ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 获取文件记录 + tags: + - 文件管理 + put: + consumes: + - application/json + description: 根据ID更新文件记录 + parameters: + - description: 文件ID + in: path + name: id + required: true + type: string + - description: 文件信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/model.SysFile' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 更新文件记录 + tags: + - 文件管理 + /api/v1/sysFile/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除文件记录 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除文件记录 + tags: + - 文件管理 + /api/v1/sysFile/condition: + post: + consumes: + - application/json + description: 根据条件查询文件记录列表 + parameters: + - description: 查询条件 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 条件查询文件记录 + tags: + - 文件管理 + /api/v1/sysFile/list: + post: + consumes: + - application/json + description: 根据ID列表获取文件记录列表 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量获取文件记录 + tags: + - 文件管理 + /api/v1/sysJob: + post: + consumes: + - application/json + description: 创建新的定时任务信息 + parameters: + - description: 定时任务信息 + in: body + name: job + required: true + schema: + $ref: '#/definitions/model.SysJob' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建定时任务 + tags: + - 定时任务 + /api/v1/sysJob/{id}: + delete: + consumes: + - application/json + description: 根据ID删除定时任务信息 + parameters: + - description: 定时任务ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除定时任务 + tags: + - 定时任务 + get: + consumes: + - application/json + description: 根据ID获取定时任务详细信息 + parameters: + - description: 定时任务ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取定时任务 + tags: + - 定时任务 + put: + consumes: + - application/json + description: 根据ID更新定时任务信息 + parameters: + - description: 定时任务ID + in: path + name: id + required: true + type: string + - description: 定时任务信息 + in: body + name: job + required: true + schema: + $ref: '#/definitions/model.SysJob' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新定时任务 + tags: + - 定时任务 + /api/v1/sysJob/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除任务 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除任务 + tags: + - 定时任务 + /api/v1/sysJob/condition: + post: + consumes: + - application/json + description: 根据条件查询定时任务列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询定时任务 + tags: + - 定时任务 + /api/v1/sysJob/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询定时任务 + parameters: + - description: 定时任务ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询定时任务 + tags: + - 定时任务 + /api/v1/sysMenu: + post: + consumes: + - application/json + description: 创建新菜单 + parameters: + - description: 菜单信息 + in: body + name: menu + required: true + schema: + $ref: '#/definitions/model.SysMenu' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建菜单 + tags: + - 菜单管理 + /api/v1/sysMenu/{id}: + delete: + consumes: + - application/json + description: 根据ID删除菜单 + parameters: + - description: 菜单ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除菜单 + tags: + - 菜单管理 + get: + consumes: + - application/json + description: 根据ID获取菜单信息 + parameters: + - description: 菜单ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取菜单 + tags: + - 菜单管理 + put: + consumes: + - application/json + description: 根据ID更新菜单信息 + parameters: + - description: 菜单ID + in: path + name: id + required: true + type: string + - description: 菜单信息 + in: body + name: menu + required: true + schema: + $ref: '#/definitions/model.SysMenu' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新菜单 + tags: + - 菜单管理 + /api/v1/sysMenu/condition: + post: + consumes: + - application/json + description: 根据条件查询菜单列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询菜单 + tags: + - 菜单管理 + /api/v1/sysMenu/ids: + delete: + consumes: + - application/json + description: 根据ID列表批量删除菜单 + parameters: + - description: 菜单ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量删除菜单 + tags: + - 菜单管理 + /api/v1/sysMenu/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询菜单 + parameters: + - description: 菜单ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询菜单 + tags: + - 菜单管理 + /api/v1/sysMenu/user: + get: + consumes: + - application/json + description: 获取当前用户的菜单列表 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取用户菜单 + tags: + - 菜单管理 + /api/v1/sysNotice: + post: + consumes: + - application/json + description: 创建新的通知公告信息 + parameters: + - description: 通知公告信息 + in: body + name: notice + required: true + schema: + $ref: '#/definitions/model.SysNotice' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建通知公告 + tags: + - 通知管理 + /api/v1/sysNotice/{id}: + delete: + consumes: + - application/json + description: 根据ID删除通知公告信息 + parameters: + - description: 通知公告ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除通知公告 + tags: + - 通知管理 + get: + consumes: + - application/json + description: 根据ID获取通知公告详细信息 + parameters: + - description: 通知公告ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取通知公告 + tags: + - 通知管理 + put: + consumes: + - application/json + description: 根据ID更新通知公告信息 + parameters: + - description: 通知公告ID + in: path + name: id + required: true + type: string + - description: 通知公告信息 + in: body + name: notice + required: true + schema: + $ref: '#/definitions/model.SysNotice' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新通知公告 + tags: + - 通知管理 + /api/v1/sysNotice/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除通知 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除通知 + tags: + - 通知管理 + /api/v1/sysNotice/condition: + post: + consumes: + - application/json + description: 根据条件查询通知公告列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询通知公告 + tags: + - 通知管理 + /api/v1/sysNotice/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询通知公告 + parameters: + - description: 通知公告ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询通知公告 + tags: + - 通知管理 + /api/v1/sysOperLog: + post: + consumes: + - application/json + description: 创建新的操作日志信息 + parameters: + - description: 操作日志信息 + in: body + name: operLog + required: true + schema: + $ref: '#/definitions/model.SysOperLog' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建操作日志 + tags: + - 操作日志 + /api/v1/sysOperLog/{id}: + delete: + consumes: + - application/json + description: 根据ID删除操作日志信息 + parameters: + - description: 操作日志ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除操作日志 + tags: + - 操作日志 + get: + consumes: + - application/json + description: 根据ID获取操作日志详细信息 + parameters: + - description: 操作日志ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取操作日志 + tags: + - 操作日志 + put: + consumes: + - application/json + description: 根据ID更新操作日志信息 + parameters: + - description: 操作日志ID + in: path + name: id + required: true + type: string + - description: 操作日志信息 + in: body + name: operLog + required: true + schema: + $ref: '#/definitions/model.SysOperLog' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新操作日志 + tags: + - 操作日志 + /api/v1/sysOperLog/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除操作日志 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除操作日志 + tags: + - 操作日志 + /api/v1/sysOperLog/condition: + post: + consumes: + - application/json + description: 根据条件查询操作日志列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询操作日志 + tags: + - 操作日志 + /api/v1/sysOperLog/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询操作日志 + parameters: + - description: 操作日志ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询操作日志 + tags: + - 操作日志 + /api/v1/sysPost: + post: + consumes: + - application/json + description: 创建岗位 + parameters: + - description: 岗位信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/model.SysPost' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 创建岗位 + tags: + - 岗位管理 + /api/v1/sysPost/{id}: + delete: + consumes: + - application/json + description: 根据ID删除岗位 + parameters: + - description: 岗位ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 删除岗位 + tags: + - 岗位管理 + get: + consumes: + - application/json + description: 根据ID获取岗位信息 + parameters: + - description: 岗位ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 获取岗位信息 + tags: + - 岗位管理 + put: + consumes: + - application/json + description: 根据ID更新岗位信息 + parameters: + - description: 岗位ID + in: path + name: id + required: true + type: string + - description: 岗位信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/model.SysPost' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 更新岗位 + tags: + - 岗位管理 + /api/v1/sysPost/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除岗位 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除岗位 + tags: + - 岗位管理 + /api/v1/sysPost/condition: + post: + consumes: + - application/json + description: 根据条件查询岗位列表 + parameters: + - description: 查询条件 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 条件查询岗位 + tags: + - 岗位管理 + /api/v1/sysPost/list: + post: + consumes: + - application/json + description: 根据ID列表获取岗位列表 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量获取岗位 + tags: + - 岗位管理 + /api/v1/sysRole: + post: + consumes: + - application/json + description: 创建新角色 + parameters: + - description: 角色信息 + in: body + name: role + required: true + schema: + $ref: '#/definitions/model.SysRole' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建角色 + tags: + - 角色管理 + /api/v1/sysRole/{id}: + delete: + consumes: + - application/json + description: 根据ID删除角色 + parameters: + - description: 角色ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除角色 + tags: + - 角色管理 + get: + consumes: + - application/json + description: 根据ID获取角色信息 + parameters: + - description: 角色ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取角色 + tags: + - 角色管理 + put: + consumes: + - application/json + description: 根据ID更新角色信息 + parameters: + - description: 角色ID + in: path + name: id + required: true + type: string + - description: 角色信息 + in: body + name: role + required: true + schema: + $ref: '#/definitions/model.SysRole' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新角色 + tags: + - 角色管理 + /api/v1/sysRole/{id}/menus: + get: + consumes: + - application/json + description: 获取指定角色的菜单列表 + parameters: + - description: 角色ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取角色菜单 + tags: + - 角色管理 + post: + consumes: + - application/json + description: 为角色分配菜单权限 + parameters: + - description: 角色ID + in: path + name: id + required: true + type: string + - description: 菜单ID列表 + in: body + name: menuIds + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 分配菜单权限 + tags: + - 角色管理 + /api/v1/sysRole/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除角色 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除角色 + tags: + - 角色管理 + /api/v1/sysRole/condition: + post: + consumes: + - application/json + description: 根据条件查询角色列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询角色 + tags: + - 角色管理 + /api/v1/sysRole/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询角色 + parameters: + - description: 角色ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询角色 + tags: + - 角色管理 + /api/v1/sysRole/user: + get: + consumes: + - application/json + description: 获取指定用户的角色列表 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取用户角色 + tags: + - 角色管理 + /api/v1/sysUser: + post: + consumes: + - application/json + description: 创建新用户 + parameters: + - description: 用户信息 + in: body + name: user + required: true + schema: + $ref: '#/definitions/model.SysUser' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 创建用户 + tags: + - 用户管理 + /api/v1/sysUser/{id}: + delete: + consumes: + - application/json + description: 根据ID删除用户 + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 删除用户 + tags: + - 用户管理 + get: + consumes: + - application/json + description: 根据ID获取用户信息 + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取用户 + tags: + - 用户管理 + put: + consumes: + - application/json + description: 根据ID更新用户信息 + parameters: + - description: 用户ID + in: path + name: id + required: true + type: string + - description: 用户信息 + in: body + name: user + required: true + schema: + $ref: '#/definitions/model.SysUser' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 更新用户 + tags: + - 用户管理 + /api/v1/sysUser/batch: + delete: + consumes: + - application/json + description: 根据ID列表批量删除用户 + parameters: + - description: ID列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/types.Payload' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - ApiKeyAuth: [ ] + summary: 批量删除用户 + tags: + - 用户管理 + /api/v1/sysUser/condition: + post: + consumes: + - application/json + description: 根据条件查询用户列表 + parameters: + - description: 查询条件 + in: body + name: query + required: true + schema: + $ref: '#/definitions/types.Params' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 条件查询用户 + tags: + - 用户管理 + /api/v1/sysUser/list/ids: + post: + consumes: + - application/json + description: 根据ID列表批量查询用户 + parameters: + - description: 用户ID列表 + in: body + name: ids + required: true + schema: + items: + type: string + type: array + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 批量查询用户 + tags: + - 用户管理 + /api/v1/sysUser/logout: + post: + consumes: + - application/json + description: 用户退出登录 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 用户登出 + tags: + - 用户管理 + /api/v1/sysUser/me: + get: + consumes: + - application/json + description: 获取当前登录用户的详细信息 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + security: + - BearerAuth: [ ] + summary: 获取当前用户信息 + tags: + - 用户管理 + /api/v1/user/login: + post: + consumes: + - application/json + description: 用户登录接口 + parameters: + - description: 用户登录信息 + in: body + name: user + required: true + schema: + $ref: '#/definitions/service.UserLoginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + summary: 用户登录 + tags: + - 用户管理 + /api/v1/user/register: + post: + consumes: + - application/json + description: 新用户注册接口 + parameters: + - description: 用户注册信息 + in: body + name: user + required: true + schema: + $ref: '#/definitions/service.UserRegisterRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/serializer.Response' + summary: 用户注册 + tags: + - 用户管理 + /ping: + get: + description: Get a message from the server + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: + type: string + type: object + summary: Get a message +securityDefinitions: + BearerAuth: + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/bin/ego b/bin/ego new file mode 100644 index 0000000..3daca06 Binary files /dev/null and b/bin/ego differ diff --git a/cmd/ego/main.go b/cmd/ego/main.go new file mode 100644 index 0000000..a4c77e1 --- /dev/null +++ b/cmd/ego/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "context" + "ego/internal/conf" + "ego/internal/router" + "ego/pkg/logger" + "errors" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +// @title EGO API +// @version 1.0 +// @description EGO 系统 API 文档 +// @termsOfService http://swagger.io/terms/ +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @host 127.0.0.1:3000 +// @BasePath / +// @securityDefinitions.apikey BearerAuth +// @in header +// @name Authorization + +func main() { + // 从配置文件读取配置 + if err := conf.Init(); err != nil { + logger.Error(nil, "配置初始化失败", zap.Error(err)) + os.Exit(1) + } + + // 设置 gin 模式 + ginMode := getGinMode() + gin.SetMode(ginMode) + logger.Info(nil, "Gin模式设置完成", zap.String("mode", ginMode)) + + // 创建路由 + engine := router.NewRouter() + + // 获取服务端口 + port := getServerPort() + + // 创建HTTP服务器 + server := &http.Server{ + Addr: port, + Handler: engine, + ReadTimeout: 15 * time.Second, + WriteTimeout: 15 * time.Second, + IdleTimeout: 60 * time.Second, + } + + // 在goroutine中启动服务器 + go func() { + logger.Info(nil, "服务器启动中...", zap.String("addr", port)) + if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + logger.Error(nil, "服务器启动失败", zap.Error(err)) + os.Exit(1) + } + }() + + logger.Info(nil, "服务器启动成功", zap.String("addr", port)) + + // 等待中断信号来优雅地关闭服务器 + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + + logger.Info(nil, "收到关闭信号,开始优雅关闭服务器...") + + // 创建一个5秒超时的context + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // 优雅关闭HTTP服务器 + if err := server.Shutdown(ctx); err != nil { + logger.Error(nil, "服务器强制关闭", zap.Error(err)) + } else { + logger.Info(nil, "HTTP服务器已优雅关闭") + } + + // 关闭其他资源 + conf.Close() + + logger.Info(nil, "服务器关闭完成") +} + +// getGinMode 获取Gin运行模式 +func getGinMode() string { + mode := os.Getenv("GIN_MODE") + if mode == "" { + mode = gin.ReleaseMode // 默认为生产模式 + } + + // 验证模式是否有效 + switch mode { + case gin.DebugMode, gin.ReleaseMode, gin.TestMode: + return mode + default: + logger.Warn(nil, "无效的GIN_MODE,使用默认值", + zap.String("invalid_mode", mode), + zap.String("default_mode", gin.ReleaseMode)) + return gin.ReleaseMode + } +} + +// getServerPort 获取服务器端口 +func getServerPort() string { + port := os.Getenv("SERVER_PORT") + if port == "" { + port = ":3000" // 默认端口 + } + + // 确保端口格式正确 + if port[0] != ':' { + port = ":" + port + } + + return port +} diff --git a/configs/config.yaml.example b/configs/config.yaml.example new file mode 100644 index 0000000..8690e5f --- /dev/null +++ b/configs/config.yaml.example @@ -0,0 +1,33 @@ +# EGO 应用配置示例文件 +# 复制此文件为 config.yaml 并根据实际情况修改配置 + +server: + port: ":3000" + mode: "release" # debug, release, test + +database: + host: "localhost" + port: 3306 + user: "your_username" + password: "your_password" + dbname: "ego_db" + charset: "utf8mb4" + parse_time: true + loc: "Local" + +redis: + host: "localhost" + port: 6379 + password: "" + db: 0 + +jwt: + secret: "your_jwt_secret_key" + expire_time: 24h + +log: + level: "info" # debug, info, warn, error + file_path: "logs/app.log" + max_size: 100 # MB + max_age: 30 # days + max_backups: 5 \ No newline at end of file diff --git a/deployments/Dockerfile b/deployments/Dockerfile new file mode 100644 index 0000000..3a8c421 --- /dev/null +++ b/deployments/Dockerfile @@ -0,0 +1,41 @@ +# 构建阶段 +FROM golang:1.23-alpine AS builder + +# 设置工作目录 +WORKDIR /app + +# 安装必要的包 +RUN apk add --no-cache git ca-certificates tzdata + +# 复制go mod文件 +COPY go.mod go.sum ./ + +# 下载依赖 +RUN go mod download + +# 复制源代码 +COPY . . + +# 构建应用程序 +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o ego ./cmd/ego + +# 运行阶段 +FROM alpine:latest + +# 安装ca证书和时区数据 +RUN apk --no-cache add ca-certificates tzdata + +# 设置工作目录 +WORKDIR /app + +# 从构建阶段复制二进制文件 +COPY --from=builder /app/ego . + +# 创建必要的目录 +RUN mkdir -p logs configs + +# 暴露端口 +EXPOSE 3000 + +# 运行应用程序 +CMD ["./ego"] \ No newline at end of file diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml new file mode 100644 index 0000000..9a8dde7 --- /dev/null +++ b/deployments/docker-compose.yml @@ -0,0 +1,53 @@ +services: + ego-app: + build: + context: .. + dockerfile: deployments/Dockerfile + ports: + - "3000:3000" + environment: + - GIN_MODE=release + depends_on: + - mysql + - redis + volumes: + - ../configs:/app/configs + - ../logs:/app/logs + networks: + - ego-network + + mysql: + image: mysql:8.0 + container_name: ego-mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_DATABASE: ego_db + MYSQL_USER: ego_user + MYSQL_PASSWORD: ego_password + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + - ../sql:/docker-entrypoint-initdb.d + networks: + - ego-network + + redis: + image: redis:7-alpine + container_name: ego-redis + restart: always + ports: + - "6379:6379" + volumes: + - redis_data:/data + networks: + - ego-network + +volumes: + mysql_data: + redis_data: + +networks: + ego-network: + driver: bridge diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..2576757 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,4369 @@ +// 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}}", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/v1/sysConfig": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "创建配置", + "parameters": [ + { + "description": "配置信息", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "批量删除配置", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询系统配置列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "条件查询配置", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询系统配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "批量查询配置", + "parameters": [ + { + "description": "配置ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysConfig/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取系统配置详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "更新配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "配置信息", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除系统配置信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "配置管理" + ], + "summary": "删除配置", + "parameters": [ + { + "type": "string", + "description": "配置ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "创建部门", + "parameters": [ + { + "description": "部门信息", + "name": "dept", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDept" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除部门", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "批量删除部门", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询部门列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "条件查询部门", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询部门", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "批量查询部门", + "parameters": [ + { + "description": "部门ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDept/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取部门详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "获取部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "更新部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "部门信息", + "name": "dept", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDept" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除部门信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "部门管理" + ], + "summary": "删除部门", + "parameters": [ + { + "type": "string", + "description": "部门ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "创建字典数据", + "parameters": [ + { + "description": "字典数据信息", + "name": "dictData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除字典数据", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "批量删除字典数据", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询字典数据列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "条件查询字典数据", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询字典数据", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "批量查询字典数据", + "parameters": [ + { + "description": "字典数据ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictData/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取字典数据详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "获取字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "更新字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "字典数据信息", + "name": "dictData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictData" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除字典数据信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典数据" + ], + "summary": "删除字典数据", + "parameters": [ + { + "type": "string", + "description": "字典数据ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "创建字典类型", + "parameters": [ + { + "description": "字典类型信息", + "name": "dictType", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除字典类型", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "批量删除字典类型", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询字典类型列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "条件查询字典类型", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询字典类型", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "批量查询字典类型", + "parameters": [ + { + "description": "字典类型ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysDictType/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取字典类型详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "获取字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "更新字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "字典类型信息", + "name": "dictType", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysDictType" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除字典类型信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "字典类型" + ], + "summary": "删除字典类型", + "parameters": [ + { + "type": "string", + "description": "字典类型ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "创建文件记录", + "parameters": [ + { + "description": "文件信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysFile" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "批量删除文件记录", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/condition": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据条件查询文件记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "条件查询文件记录", + "parameters": [ + { + "description": "查询条件", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/list": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表获取文件记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "批量获取文件记录", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysFile/{id}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID获取文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "获取文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID更新文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "更新文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "文件信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysFile" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID删除文件记录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "文件管理" + ], + "summary": "删除文件记录", + "parameters": [ + { + "type": "string", + "description": "文件ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "创建定时任务", + "parameters": [ + { + "description": "定时任务信息", + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysJob" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除任务", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "批量删除任务", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询定时任务列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "条件查询定时任务", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询定时任务", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "批量查询定时任务", + "parameters": [ + { + "description": "定时任务ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysJob/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取定时任务详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "获取定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "更新定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "定时任务信息", + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysJob" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除定时任务信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "定时任务" + ], + "summary": "删除定时任务", + "parameters": [ + { + "type": "string", + "description": "定时任务ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "创建菜单", + "parameters": [ + { + "description": "菜单信息", + "name": "menu", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysMenu" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "条件查询菜单", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/ids": { + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量删除菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "批量删除菜单", + "parameters": [ + { + "description": "菜单ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "批量查询菜单", + "parameters": [ + { + "description": "菜单ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/user": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取当前用户的菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "获取用户菜单", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysMenu/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取菜单信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "获取菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新菜单信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "更新菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "菜单信息", + "name": "menu", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysMenu" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除菜单", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "菜单管理" + ], + "summary": "删除菜单", + "parameters": [ + { + "type": "string", + "description": "菜单ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "创建通知公告", + "parameters": [ + { + "description": "通知公告信息", + "name": "notice", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysNotice" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除通知", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "批量删除通知", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询通知公告列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "条件查询通知公告", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询通知公告", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "批量查询通知公告", + "parameters": [ + { + "description": "通知公告ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysNotice/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取通知公告详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "获取通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "更新通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "通知公告信息", + "name": "notice", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysNotice" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除通知公告信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "通知管理" + ], + "summary": "删除通知公告", + "parameters": [ + { + "type": "string", + "description": "通知公告ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "创建操作日志", + "parameters": [ + { + "description": "操作日志信息", + "name": "operLog", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysOperLog" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除操作日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "批量删除操作日志", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询操作日志列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "条件查询操作日志", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询操作日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "批量查询操作日志", + "parameters": [ + { + "description": "操作日志ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysOperLog/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取操作日志详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "获取操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "更新操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "操作日志信息", + "name": "operLog", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysOperLog" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除操作日志信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "操作日志" + ], + "summary": "删除操作日志", + "parameters": [ + { + "type": "string", + "description": "操作日志ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "创建岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "创建岗位", + "parameters": [ + { + "description": "岗位信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysPost" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "批量删除岗位", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/condition": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据条件查询岗位列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "条件查询岗位", + "parameters": [ + { + "description": "查询条件", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/list": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表获取岗位列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "批量获取岗位", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysPost/{id}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID获取岗位信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "获取岗位信息", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID更新岗位信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "更新岗位", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "岗位信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysPost" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID删除岗位", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "岗位管理" + ], + "summary": "删除岗位", + "parameters": [ + { + "type": "string", + "description": "岗位ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "角色信息", + "name": "role", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysRole" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "批量删除角色", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询角色列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "条件查询角色", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "批量查询角色", + "parameters": [ + { + "description": "角色ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/user": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取指定用户的角色列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取用户角色", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取角色信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新角色信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "更新角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "角色信息", + "name": "role", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysRole" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除角色", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "删除角色", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysRole/{id}/menus": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取指定角色的菜单列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "获取角色菜单", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "为角色分配菜单权限", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "角色管理" + ], + "summary": "分配菜单权限", + "parameters": [ + { + "type": "string", + "description": "角色ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "菜单ID列表", + "name": "menuIds", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "创建用户", + "parameters": [ + { + "description": "用户信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/batch": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "根据ID列表批量删除用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "批量删除用户", + "parameters": [ + { + "description": "ID列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Payload" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/condition": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据条件查询用户列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "条件查询用户", + "parameters": [ + { + "description": "查询条件", + "name": "query", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.Params" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/list/ids": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID列表批量查询用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "批量查询用户", + "parameters": [ + { + "description": "用户ID列表", + "name": "ids", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/logout": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "用户退出登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户登出", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/me": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取当前登录用户的详细信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "获取当前用户信息", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/sysUser/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取用户信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "获取用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID更新用户信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "更新用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "用户信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.SysUser" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID删除用户", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "删除用户", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/user/login": { + "post": { + "description": "用户登录接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "用户登录信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service.UserLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/api/v1/user/register": { + "post": { + "description": "新用户注册接口", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "用户管理" + ], + "summary": "用户注册", + "parameters": [ + { + "description": "用户注册信息", + "name": "user", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/service.UserRegisterRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/serializer.Response" + } + } + } + } + }, + "/ping": { + "get": { + "description": "Get a message from the server", + "produces": [ + "application/json" + ], + "summary": "Get a message", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + } + }, + "definitions": { + "model.MenuMeta": { + "type": "object", + "properties": { + "icon": { + "type": "string" + }, + "title": { + "$ref": "#/definitions/model.Title" + } + } + }, + "model.SysConfig": { + "type": "object", + "properties": { + "configID": { + "type": "string" + }, + "configKey": { + "type": "string" + }, + "configName": { + "type": "string" + }, + "configType": { + "type": "string" + }, + "configValue": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDept": { + "type": "object", + "properties": { + "ancestors": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptId": { + "type": "string" + }, + "deptName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "leader": { + "type": "string" + }, + "orderNum": { + "type": "integer" + }, + "parentId": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDictData": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "cssClass": { + "type": "string" + }, + "dictCode": { + "type": "string" + }, + "dictLabel": { + "type": "string" + }, + "dictSort": { + "type": "integer" + }, + "dictType": { + "type": "string" + }, + "dictValue": { + "type": "string" + }, + "isDefault": { + "type": "string" + }, + "listClass": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysDictType": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "dictId": { + "type": "string" + }, + "dictName": { + "type": "string" + }, + "dictType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysFile": { + "type": "object", + "properties": { + "businessId": { + "type": "string" + }, + "businessType": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "fileKey": { + "type": "string" + }, + "fileName": { + "type": "string" + }, + "fileSize": { + "type": "integer" + }, + "fileType": { + "type": "string" + }, + "id": { + "type": "string" + }, + "revision": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysJob": { + "type": "object", + "properties": { + "concurrent": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "cronExpression": { + "type": "string" + }, + "invokeTarget": { + "type": "string" + }, + "jobGroup": { + "type": "string" + }, + "jobId": { + "type": "string" + }, + "jobName": { + "type": "string" + }, + "misfirePolicy": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysMenu": { + "type": "object", + "properties": { + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/model.SysMenu" + } + }, + "component": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "en_US": { + "type": "string" + }, + "frameBlank": { + "type": "boolean" + }, + "frameSrc": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "isCache": { + "type": "string" + }, + "isFrame": { + "type": "string" + }, + "menuID": { + "type": "string" + }, + "menuType": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/model.MenuMeta" + }, + "name": { + "type": "string" + }, + "orderNum": { + "type": "integer" + }, + "parentID": { + "type": "string" + }, + "path": { + "type": "string" + }, + "perms": { + "type": "string" + }, + "query": { + "type": "string" + }, + "redirect": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "visible": { + "type": "string" + }, + "zh_CN": { + "type": "string" + } + } + }, + "model.SysNotice": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "noticeContent": { + "type": "string" + }, + "noticeId": { + "type": "string" + }, + "noticeTitle": { + "type": "string" + }, + "noticeType": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysOperLog": { + "type": "object", + "properties": { + "businessType": { + "type": "integer" + }, + "deptName": { + "type": "string" + }, + "errorMsg": { + "type": "string" + }, + "jsonResult": { + "type": "string" + }, + "method": { + "type": "string" + }, + "operIP": { + "type": "string" + }, + "operId": { + "type": "string" + }, + "operLocation": { + "type": "string" + }, + "operName": { + "type": "string" + }, + "operParam": { + "type": "string" + }, + "operTime": { + "type": "string" + }, + "operUrl": { + "type": "string" + }, + "operatorType": { + "type": "integer" + }, + "requestMethod": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "trackId": { + "type": "string" + } + } + }, + "model.SysPost": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "postCode": { + "type": "string" + }, + "postId": { + "type": "string" + }, + "postName": { + "type": "string" + }, + "postSort": { + "type": "integer" + }, + "remark": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysRole": { + "type": "object", + "properties": { + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptCheckStrictly": { + "type": "boolean" + }, + "menuCheckStrictly": { + "type": "boolean" + }, + "remark": { + "type": "string" + }, + "roleId": { + "type": "string" + }, + "roleKey": { + "type": "string" + }, + "roleName": { + "type": "string" + }, + "roleSort": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + } + } + }, + "model.SysUser": { + "type": "object", + "properties": { + "avatar": { + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createTime": { + "type": "string" + }, + "delFlag": { + "type": "string" + }, + "deptId": { + "type": "string" + }, + "email": { + "type": "string" + }, + "gender": { + "type": "string" + }, + "loginDate": { + "type": "string" + }, + "loginIP": { + "type": "string" + }, + "nickName": { + "type": "string" + }, + "passWord": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "remark": { + "type": "string" + }, + "resourceInvoke": { + "type": "string" + }, + "selectKey": { + "type": "string" + }, + "solt": { + "type": "integer" + }, + "status": { + "type": "string" + }, + "updateBy": { + "type": "string" + }, + "updateTime": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName": { + "type": "string" + }, + "userType": { + "type": "string" + } + } + }, + "model.Title": { + "type": "object", + "properties": { + "en_US": { + "type": "string" + }, + "zh_CN": { + "type": "string" + } + } + }, + "serializer.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "error": { + "type": "string" + }, + "msg": { + "type": "string" + } + } + }, + "service.UserLoginRequest": { + "type": "object", + "required": [ + "account", + "checked", + "password" + ], + "properties": { + "account": { + "type": "string", + "maxLength": 30, + "minLength": 5 + }, + "checked": { + "type": "boolean" + }, + "password": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "phone": { + "type": "string" + }, + "verifyCode": { + "type": "string" + } + } + }, + "service.UserRegisterRequest": { + "type": "object", + "required": [ + "nickName", + "passWord", + "passWordConfirm", + "userName" + ], + "properties": { + "nickName": { + "type": "string", + "maxLength": 30, + "minLength": 2 + }, + "passWord": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "passWordConfirm": { + "type": "string", + "maxLength": 40, + "minLength": 8 + }, + "userName": { + "type": "string", + "maxLength": 30, + "minLength": 5 + } + } + }, + "types.Column": { + "type": "object", + "properties": { + "exp": { + "description": "expressions, which default to = when the value is null, have =, !=, \u003e, \u003e=, \u003c, \u003c=, like, in", + "type": "string" + }, + "logic": { + "description": "logical type, defaults to and when the value is null, with \u0026(and), ||(or)", + "type": "string" + }, + "name": { + "description": "column name", + "type": "string" + }, + "value": { + "description": "column value" + } + } + }, + "types.Params": { + "type": "object", + "properties": { + "columns": { + "description": "not required", + "type": "array", + "items": { + "$ref": "#/definitions/types.Column" + } + }, + "limit": { + "type": "integer", + "minimum": 10 + }, + "page": { + "type": "integer", + "minimum": 0 + }, + "sort": { + "type": "string" + } + } + }, + "types.Payload": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "securityDefinitions": { + "BearerAuth": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "127.0.0.1:3000", + BasePath: "/", + Schemes: []string{}, + Title: "EGO API", + Description: "EGO 系统 API 文档", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..76f8c22 --- /dev/null +++ b/go.mod @@ -0,0 +1,76 @@ +module ego + +go 1.23.0 + +require ( + github.com/gin-contrib/cors v1.7.6 + github.com/gin-gonic/gin v1.10.1 + github.com/go-playground/validator/v10 v10.27.0 + github.com/golang-jwt/jwt/v4 v4.5.2 + github.com/google/uuid v1.6.0 + github.com/google/wire v0.6.0 + github.com/joho/godotenv v1.5.1 + github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible + github.com/redis/go-redis/v9 v9.11.0 + github.com/shirou/gopsutil/v3 v3.24.5 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.4 + go.uber.org/zap v1.27.0 + golang.org/x/crypto v0.40.0 + gopkg.in/yaml.v2 v2.4.0 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.30.0 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/bytedance/sonic v1.13.3 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jonboulle/clockwork v0.5.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lestrrat-go/strftime v1.1.0 // indirect + github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattn/go-isatty v0.0.20 // 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.2.4 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.19.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/tools v0.35.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..59058d7 --- /dev/null +++ b/go.sum @@ -0,0 +1,265 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +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.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0= +github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +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.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY= +github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk= +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 v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +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.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= +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.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= +github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +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.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg= +github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/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/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= +github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +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.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= +golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/arch v0.19.0 h1:LmbDQUodHThXE+htjrnmVD73M//D9GTH6wFZjyDkjyU= +golang.org/x/arch v0.19.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +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.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +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/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +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/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +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.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/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs= +gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/internal/cache/cache.go b/internal/cache/cache.go new file mode 100644 index 0000000..54dd2dd --- /dev/null +++ b/internal/cache/cache.go @@ -0,0 +1,194 @@ +package cache + +import ( + "context" + "ego/pkg/logger" + "fmt" + "os" + "strconv" + "sync" + "time" + + "github.com/redis/go-redis/v9" + "go.uber.org/zap" +) + +var ( + RedisClient *redis.Client + once sync.Once + initErr error +) + +// RedisConfig Redis连接配置 +type RedisConfig struct { + Addr string `env:"REDIS_ADDR"` + Password string `env:"REDIS_PW"` + DB int `env:"REDIS_DB"` + MaxRetries int `env:"REDIS_RETRIES"` + PoolSize int `env:"REDIS_POOL_SIZE"` + ReadTimeout time.Duration `env:"REDIS_READ_TIMEOUT"` +} + +// Redis 初始化Redis连接 +func Redis() error { + once.Do(func() { + initErr = initRedis() + }) + return initErr +} + +// initRedis 实际的Redis初始化逻辑 +func initRedis() error { + config, err := loadRedisConfig() + if err != nil { + logger.Error(nil, "Redis配置加载失败", zap.Error(err)) + return fmt.Errorf("redis配置加载失败: %w", err) + } + + // 创建客户端 + client := redis.NewClient(&redis.Options{ + Addr: config.Addr, + Password: config.Password, + DB: config.DB, + MaxRetries: config.MaxRetries, + PoolSize: config.PoolSize, + ReadTimeout: config.ReadTimeout, + WriteTimeout: config.ReadTimeout * 2, + // 添加更多配置选项 + DialTimeout: 5 * time.Second, + PoolTimeout: 4 * time.Second, + MinIdleConns: 2, + }) + + // 验证连接 + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := client.Ping(ctx).Err(); err != nil { + logger.Error(nil, "Redis连接失败", + zap.Error(err), + zap.String("addr", config.Addr), + zap.Int("db", config.DB)) + return fmt.Errorf("Redis连接失败: %w", err) + } + + RedisClient = client + logger.Info(nil, "Redis连接成功", + zap.String("address", config.Addr), + zap.Int("db", config.DB), + zap.Int("pool_size", config.PoolSize), + zap.Duration("read_timeout", config.ReadTimeout)) + + return nil +} + +// Close 关闭Redis连接 +func Close() error { + if RedisClient != nil { + err := RedisClient.Close() + if err != nil { + logger.Error(nil, "关闭Redis失败", zap.Error(err)) + return fmt.Errorf("关闭Redis失败: %w", err) + } + logger.Info(nil, "Redis已关闭") + } + return nil +} + +// GetClient 获取Redis客户端(用于外部调用) +func GetClient() (*redis.Client, error) { + if RedisClient == nil { + return nil, fmt.Errorf("Redis连接未初始化") + } + return RedisClient, nil +} + +// IsConnected 检查Redis连接状态 +func IsConnected() bool { + if RedisClient == nil { + return false + } + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + return RedisClient.Ping(ctx).Err() == nil +} + +// loadRedisConfig 从环境变量加载配置 +func loadRedisConfig() (*RedisConfig, error) { + // 必要参数校验 + addr := getEnvWithDefault("REDIS_ADDR", "localhost:6379") + + dbStr := getEnvWithDefault("REDIS_DB", "0") + db, err := strconv.Atoi(dbStr) + if err != nil { + return nil, fmt.Errorf("无效的 REDIS_DB 值 '%s': %w", dbStr, err) + } + + // 基础配置 + config := &RedisConfig{ + Addr: addr, + Password: os.Getenv("REDIS_PW"), // 密码可以为空 + DB: db, + MaxRetries: 5, + PoolSize: 10, + ReadTimeout: 5 * time.Second, + } + + // 读取扩展配置 + if err := loadExtendedConfig(config); err != nil { + return nil, fmt.Errorf("加载扩展配置失败: %w", err) + } + + return config, nil +} + +// loadExtendedConfig 加载扩展配置 +func loadExtendedConfig(config *RedisConfig) error { + // 连接池大小 + if val := os.Getenv("REDIS_POOL_SIZE"); val != "" { + poolSize, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("无效的 REDIS_POOL_SIZE 值 '%s': %w", val, err) + } + if poolSize <= 0 { + return fmt.Errorf("REDIS_POOL_SIZE 必须大于 0") + } + config.PoolSize = poolSize + } + + // 重试次数 + if val := os.Getenv("REDIS_RETRIES"); val != "" { + retries, err := strconv.Atoi(val) + if err != nil { + return fmt.Errorf("无效的 REDIS_RETRIES 值 '%s': %w", val, err) + } + if retries < 0 { + return fmt.Errorf("REDIS_RETRIES 不能小于 0") + } + config.MaxRetries = retries + } + + // 读取超时 + if val := os.Getenv("REDIS_READ_TIMEOUT"); val != "" { + timeout, err := time.ParseDuration(val) + if err != nil { + return fmt.Errorf("无效的 REDIS_READ_TIMEOUT 值 '%s': %w", val, err) + } + if timeout <= 0 { + return fmt.Errorf("REDIS_READ_TIMEOUT 必须大于 0") + } + config.ReadTimeout = timeout + } + + return nil +} + +// getEnvWithDefault 获取环境变量,如果不存在则返回默认值 +func getEnvWithDefault(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} diff --git a/internal/conf/common.go b/internal/conf/common.go new file mode 100644 index 0000000..cdf34a0 --- /dev/null +++ b/internal/conf/common.go @@ -0,0 +1,46 @@ +package conf + +import ( + conf "ego/internal/conf/locales" + "ego/internal/serializer" + "ego/pkg/logger" + "encoding/json" + "errors" + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// Ping 状态检查页面 +// @Summary Get a message +// @Description Get a message from the server +// @Produce json +// @Success 200 {object} map[string]string +// @Router /ping [get] +func Ping(c *gin.Context) { + logger.Info(c, "Ping", zap.Field{Key: "msg", Type: zapcore.StringType, String: "Ping"}) + c.JSON(200, serializer.Succ("tong", nil)) +} + +// ErrorResponse 返回错误消息 +func ErrorResponse(err error) serializer.Response { + var ve validator.ValidationErrors + if errors.As(err, &ve) { + for _, e := range ve { + field := conf.T(fmt.Sprintf("Field.%s", e.Field())) + tag := conf.T(fmt.Sprintf("Tag.Valid.%s", e.Tag())) + return serializer.ParamErr( + fmt.Sprintf("%s%s", field, tag), + err, + ) + } + } + var unmarshalTypeError *json.UnmarshalTypeError + if errors.As(err, &unmarshalTypeError) { + return serializer.ParamErr("JSON类型不匹配", err) + } + return serializer.ParamErr("参数错误", err) +} diff --git a/internal/conf/conf.go b/internal/conf/conf.go new file mode 100644 index 0000000..f0b4917 --- /dev/null +++ b/internal/conf/conf.go @@ -0,0 +1,116 @@ +package conf + +import ( + "ego/internal/cache" + "ego/internal/conf/locales" + "ego/internal/util" + "ego/pkg/logger" + "fmt" + "os" + + "github.com/joho/godotenv" + "go.uber.org/zap" +) + +// Init 初始化所有配置 +func Init() error { + // 1. 加载环境变量 + if err := loadEnvironmentVariables(); err != nil { + // 这里不能使用logger,因为还没初始化 + return fmt.Errorf("环境变量加载失败: %w", err) + } + + // 2. 初始化日志系统(在验证环境变量之前,因为后续步骤需要使用logger) + if err := logger.BuildLogger(); err != nil { + // 这里不能使用logger,因为初始化失败了 + return fmt.Errorf("日志系统初始化失败: %w", err) + } + + // 3. 验证必要环境变量 + if err := validateRequiredEnvVars(); err != nil { + logger.Error(nil, "环境变量验证失败", zap.Error(err)) + return fmt.Errorf("环境变量验证失败: %w", err) + } + + // 4. 加载翻译文件 + if err := locales.LoadLocales(); err != nil { + logger.Error(nil, "翻译文件加载失败", zap.Error(err)) + return fmt.Errorf("翻译文件加载失败: %w", err) + } + + // 5. 连接数据库 + mysqlDSN := os.Getenv("MYSQL_DSN") + if err := Database(mysqlDSN); err != nil { + logger.Error(nil, "数据库初始化失败", zap.Error(err)) + return fmt.Errorf("数据库初始化失败: %w", err) + } + + // 6. 连接 Redis + if err := cache.Redis(); err != nil { + logger.Error(nil, "Redis初始化失败", zap.Error(err)) + return fmt.Errorf("Redis初始化失败: %w", err) + } + + // 7. 输出JWT密钥状态日志(在logger初始化完成后) + util.LogJwtKeyStatus() + + logger.Info(nil, "所有配置初始化完成") + return nil +} + +// Close 关闭所有资源 +func Close() { + logger.Info(nil, "开始关闭应用程序资源...") + + // 关闭数据库 + if err := closeDatabase(); err != nil { + logger.Error(nil, "数据库关闭失败", zap.Error(err)) + } else { + logger.Info(nil, "数据库已关闭") + } + + // 关闭 Redis + if err := cache.Close(); err != nil { + logger.Error(nil, "Redis关闭失败", zap.Error(err)) + } else { + logger.Info(nil, "Redis已关闭") + } + + logger.Info(nil, "应用程序资源关闭完成") +} + +// loadEnvironmentVariables 加载环境变量并处理错误 +func loadEnvironmentVariables() error { + // 尝试加载.env文件,如果文件不存在也不报错 + if err := godotenv.Load(); err != nil { + // 只有在文件存在但读取失败时才报错 + if !os.IsNotExist(err) { + return fmt.Errorf("加载 .env 文件失败: %w", err) + } + // .env文件不存在,使用系统环境变量 + logger.Info(nil, ".env 文件不存在,使用系统环境变量") + } else { + logger.Info(nil, "成功加载 .env 文件") + } + return nil +} + +// validateRequiredEnvVars 验证必要的环境变量 +func validateRequiredEnvVars() error { + requiredVars := map[string]string{ + "MYSQL_DSN": "数据库连接字符串", + } + + var missingVars []string + for envVar, description := range requiredVars { + if os.Getenv(envVar) == "" { + missingVars = append(missingVars, fmt.Sprintf("%s (%s)", envVar, description)) + } + } + + if len(missingVars) > 0 { + return fmt.Errorf("缺少必要环境变量: %v", missingVars) + } + + return nil +} diff --git a/internal/conf/db.go b/internal/conf/db.go new file mode 100644 index 0000000..fbf5aa9 --- /dev/null +++ b/internal/conf/db.go @@ -0,0 +1,181 @@ +package conf + +import ( + "database/sql" + "ego/pkg/logger" + "fmt" + "log" + "os" + "sync" + "time" + + "go.uber.org/zap" + "gorm.io/driver/mysql" + "gorm.io/gorm" + glogger "gorm.io/gorm/logger" + "gorm.io/gorm/schema" +) + +var ( + // Db 数据库链接单例 + Db *gorm.DB + once sync.Once + dbInitErr error +) + +// NewDb 初始化数据库连接 +func NewDb() *gorm.DB { + return Db +} + +// Database 初始化mysql连接 +func Database(connString string) error { + once.Do(func() { + dbInitErr = initDatabase(connString) + }) + return dbInitErr +} + +// initDatabase 实际的数据库初始化逻辑 +func initDatabase(connString string) error { + if connString == "" { + err := fmt.Errorf("数据库连接字符串不能为空") + logger.Error(nil, "数据库初始化失败", zap.Error(err)) + return err + } + + // 初始化GORM日志配置 + logLevel := getGormLogLevel() + newLogger := glogger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), + glogger.Config{ + SlowThreshold: time.Second, + LogLevel: logLevel, + IgnoreRecordNotFoundError: true, + Colorful: false, + }, + ) + + // 配置 gorm + db, err := gorm.Open(mysql.Open(connString), &gorm.Config{ + DisableForeignKeyConstraintWhenMigrating: true, + Logger: newLogger, + NamingStrategy: schema.NamingStrategy{TablePrefix: ""}, + }) + + if err != nil { + logger.Error(nil, "数据库连接失败", zap.Error(err), zap.String("connString", maskConnectionString(connString))) + return fmt.Errorf("数据库连接失败: %w", err) + } + + // 获取底层的sql.DB对象 + sqlDB, err := db.DB() + if err != nil { + logger.Error(nil, "获取数据库实例失败", zap.Error(err)) + return fmt.Errorf("获取数据库实例失败: %w", err) + } + + // 配置连接池 + if err := configureConnectionPool(sqlDB); err != nil { + logger.Error(nil, "配置数据库连接池失败", zap.Error(err)) + return fmt.Errorf("配置数据库连接池失败: %w", err) + } + + // 测试数据库连接 + if err := sqlDB.Ping(); err != nil { + logger.Error(nil, "数据库连接测试失败", zap.Error(err)) + return fmt.Errorf("数据库连接测试失败: %w", err) + } + + Db = db + logger.Info(nil, "数据库连接成功", + zap.String("connString", maskConnectionString(connString)), + zap.Int("maxOpenConns", 20), + zap.Int("maxIdleConns", 10)) + + return nil +} + +// configureConnectionPool 配置数据库连接池 +func configureConnectionPool(sqlDB *sql.DB) error { + // 设置空闲连接池中连接的最大数量 + sqlDB.SetMaxIdleConns(10) + // 设置打开数据库连接的最大数量 + sqlDB.SetMaxOpenConns(20) + // 设置连接可复用的最大时间 + sqlDB.SetConnMaxLifetime(time.Hour) + // 设置连接空闲的最大时间 + sqlDB.SetConnMaxIdleTime(time.Minute * 30) + + return nil +} + +// getGormLogLevel 根据环境变量获取GORM日志级别 +func getGormLogLevel() glogger.LogLevel { + switch os.Getenv("GORM_LOG_LEVEL") { + case "silent": + return glogger.Silent + case "error": + return glogger.Error + case "warn": + return glogger.Warn + case "info": + return glogger.Info + default: + // 根据应用环境决定默认级别 + if os.Getenv("GIN_MODE") == "release" { + return glogger.Error + } + return glogger.Info + } +} + +// maskConnectionString 遮盖连接字符串中的敏感信息 +func maskConnectionString(connString string) string { + // 简单遮盖密码部分,实际项目中可以使用更复杂的正则表达式 + return "***已遮盖敏感信息***" +} + +// Migration 执行数据迁移 +func Migration() error { + if Db == nil { + return fmt.Errorf("数据库连接未初始化") + } + + // 自动迁移模式 + models := []any{} + + for _, model := range models { + if err := Db.AutoMigrate(model); err != nil { + logger.Error(nil, "数据库迁移失败", + zap.Error(err), + zap.String("model", fmt.Sprintf("%T", model))) + return fmt.Errorf("迁移模型 %T 失败: %w", model, err) + } + } + + logger.Info(nil, "数据库迁移完成", zap.Int("models", len(models))) + return nil +} + +// GetDB 获取数据库连接(用于外部调用) +func GetDB() (*gorm.DB, error) { + if Db == nil { + return nil, fmt.Errorf("数据库连接未初始化") + } + return Db, nil +} + +// closeDatabase 安全关闭数据库连接 +func closeDatabase() error { + if Db == nil { + return nil + } + + sqlDB, err := Db.DB() + if err != nil { + return fmt.Errorf("获取数据库连接失败: %w", err) + } + + return sqlDB.Close() +} diff --git a/internal/conf/locales/i18n.go b/internal/conf/locales/i18n.go new file mode 100644 index 0000000..6f54d0d --- /dev/null +++ b/internal/conf/locales/i18n.go @@ -0,0 +1,60 @@ +package locales + +import ( + _ "embed" + "strings" + + "gopkg.in/yaml.v2" +) + +//go:embed zh-cn.yaml +var Zhcn string + +// Dictionary 字典 +var Dictionary *map[any]any + +// LoadLocales 读取国际化文件 +func LoadLocales() error { + m := make(map[any]any) + err := yaml.Unmarshal([]byte(Zhcn), &m) + if err != nil { + return err + } + + Dictionary = &m + + return nil +} + +// T 翻译 +func T(key string) string { + dic := *Dictionary + keys := strings.Split(key, ".") + for index, path := range keys { + // 如果到达了最后一层,寻找目标翻译 + if len(keys) == (index + 1) { + for k, v := range dic { + if k, ok := k.(string); ok { + if k == path { + if value, ok := v.(string); ok { + return value + } + } + } + } + return path + } + // 如果还有下一层,继续寻找 + for k, v := range dic { + if ks, ok := k.(string); !ok { + return "" + } else if ks == path { + if dic, ok = v.(map[any]any); !ok { + return path + } + } + } + } + + return "" +} diff --git a/internal/conf/locales/zh-cn.yaml b/internal/conf/locales/zh-cn.yaml new file mode 100644 index 0000000..23be15b --- /dev/null +++ b/internal/conf/locales/zh-cn.yaml @@ -0,0 +1,11 @@ +Tag: + required: "必须存在,而且不能为空" + min: "不够长" + max: "太长" +Field: + Name: "名称" + Nickname: "用户昵称" + UserName: "用户名" + PassWord: "密码" + PassWordConfirm: "密码校验" + Checked: "已选中" diff --git a/internal/example_test.go b/internal/example_test.go new file mode 100644 index 0000000..6c767dc --- /dev/null +++ b/internal/example_test.go @@ -0,0 +1,17 @@ +package test + +import ( + "testing" +) + +// TestSetup 是测试设置函数 +func TestSetup(t *testing.T) { + // 这里可以添加测试前的设置代码 + t.Log("测试环境设置") +} + +// TestTeardown 是测试清理函数 +func TestTeardown(t *testing.T) { + // 这里可以添加测试后的清理代码 + t.Log("测试环境清理") +} diff --git a/internal/handler/base_handler.go b/internal/handler/base_handler.go new file mode 100644 index 0000000..a8a7c1c --- /dev/null +++ b/internal/handler/base_handler.go @@ -0,0 +1,20 @@ +package handler + +import "github.com/gin-gonic/gin" + +type BaseHandler interface { + // Create 创建 + Create(c *gin.Context) + // DeleteByID 删除 + DeleteByID(c *gin.Context) + // UpdateByID 更新 + UpdateByID(c *gin.Context) + // GetByID 获取单个 + GetByID(c *gin.Context) + // DeleteByIDs 批量删除 + DeleteByIDs(c *gin.Context) + // GetByCondition 条件查询 + GetByCondition(c *gin.Context) + // ListByIDs 批量查询 + ListByIDs(c *gin.Context) +} diff --git a/internal/handler/sys_deploy_file_handler.go b/internal/handler/sys_deploy_file_handler.go new file mode 100644 index 0000000..653c651 --- /dev/null +++ b/internal/handler/sys_deploy_file_handler.go @@ -0,0 +1,92 @@ +package handler + +import ( + "ego/internal/service" + "ego/pkg/logger" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +// SysDeployFileHandler 部署文件处理器 +type SysDeployFileHandler struct { + deployFileService *service.SysDeployFileService +} + +// NewSysDeployFileHandler 构建部署文件处理器 +func NewSysDeployFileHandler(deployFileService *service.SysDeployFileService) *SysDeployFileHandler { + return &SysDeployFileHandler{ + deployFileService: deployFileService, + } +} + +// Create 创建部署文件记录 +// @Summary 创建部署文件记录 +// @Description 创建新的部署文件记录 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +// @Param deployFile body model.SysDeployFile true "部署文件信息" +// @Success 200 {object} serializer.Response +// @Router /deploy-files [post] +func (h *SysDeployFileHandler) Create(c *gin.Context) { + logger.Info(c, "创建部署文件记录") + c.JSON(200, h.deployFileService.Create(c)) +} + +// GetByID 根据ID获取部署文件记录 +// @Summary 获取部署文件记录 +// @Description 根据ID获取部署文件记录详情 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +// @Param id path string true "部署ID" +// @Success 200 {object} serializer.Response +// @Router /deploy-files/{id} [get] +func (h *SysDeployFileHandler) GetByID(c *gin.Context) { + logger.Info(c, "获取部署文件记录", zap.String("id", c.Param("id"))) + c.JSON(200, h.deployFileService.GetByID(c)) +} + +// UpdateByID 根据ID更新部署文件记录 +// @Summary 更新部署文件记录 +// @Description 根据ID更新部署文件记录 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +// @Param id path string true "部署ID" +// @Param deployFile body model.SysDeployFile true "部署文件信息" +// @Success 200 {object} serializer.Response +// @Router /deploy-files/{id} [put] +func (h *SysDeployFileHandler) UpdateByID(c *gin.Context) { + logger.Info(c, "更新部署文件记录", zap.String("id", c.Param("id"))) + c.JSON(200, h.deployFileService.UpdateByID(c)) +} + +// DeleteByID 根据ID删除部署文件记录 +// @Summary 删除部署文件记录 +// @Description 根据ID删除部署文件记录 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +// @Param id path string true "部署ID" +// @Success 200 {object} serializer.Response +// @Router /deploy-files/{id} [delete] +func (h *SysDeployFileHandler) DeleteByID(c *gin.Context) { + logger.Info(c, "删除部署文件记录", zap.String("id", c.Param("id"))) + c.JSON(200, h.deployFileService.DeleteByID(c)) +} + +// GetByCondition 条件查询部署文件记录 +// @Summary 条件查询部署文件记录 +// @Description 根据条件分页查询部署文件记录 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +// @Param params query types.Params true "查询参数" +// @Success 200 {object} serializer.Response +// @Router /deploy-files [get] +func (h *SysDeployFileHandler) GetByCondition(c *gin.Context) { + logger.Info(c, "条件查询部署文件记录") + c.JSON(200, h.deployFileService.GetByCondition(c)) +} diff --git a/internal/handler/sys_login_log_handler.go b/internal/handler/sys_login_log_handler.go new file mode 100644 index 0000000..181b8d6 --- /dev/null +++ b/internal/handler/sys_login_log_handler.go @@ -0,0 +1,55 @@ +package handler + +import ( + "ego/internal/service" + "net/http" + + "github.com/gin-gonic/gin" +) + +// SysLoginLogHandler 登录日志处理器 +type SysLoginLogHandler struct { + sysLoginLogService *service.SysLoginLogService +} + +// NewSysLoginLogHandler 构建登录日志处理器 +func NewSysLoginLogHandler(sysLoginLogService *service.SysLoginLogService) *SysLoginLogHandler { + return &SysLoginLogHandler{ + sysLoginLogService: sysLoginLogService, + } +} + +// Create 创建登录日志 +func (h *SysLoginLogHandler) Create(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.Create(c)) +} + +// DeleteByID 根据ID删除登录日志 +func (h *SysLoginLogHandler) DeleteByID(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.DeleteByID(c)) +} + +// UpdateByID 根据ID更新登录日志 +func (h *SysLoginLogHandler) UpdateByID(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.UpdateByID(c)) +} + +// GetByID 根据ID获取登录日志 +func (h *SysLoginLogHandler) GetByID(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.GetByID(c)) +} + +// GetByCondition 根据条件获取登录日志 +func (h *SysLoginLogHandler) GetByCondition(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.GetByCondition(c)) +} + +// ListByIDs 根据ID列表获取登录日志 +func (h *SysLoginLogHandler) ListByIDs(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.ListByIDs(c)) +} + +// DeleteByIDs 根据ID列表删除登录日志 +func (h *SysLoginLogHandler) DeleteByIDs(c *gin.Context) { + c.JSON(http.StatusOK, h.sysLoginLogService.DeleteByIDs(c)) +} diff --git a/internal/handler/sys_upload_handler.go b/internal/handler/sys_upload_handler.go new file mode 100644 index 0000000..d574ef0 --- /dev/null +++ b/internal/handler/sys_upload_handler.go @@ -0,0 +1,34 @@ +package handler + +import ( + "ego/internal/service" + "net/http" + + "github.com/gin-gonic/gin" +) + +// SysUploadHandler 文件上传处理器 +type SysUploadHandler struct { + UploadSvc *service.SysUploadService +} + +// NewSysUploadHandler 构建文件上传处理器 +func NewSysUploadHandler(uploadSvc *service.SysUploadService) *SysUploadHandler { + return &SysUploadHandler{ + UploadSvc: uploadSvc, + } +} + +// UploadZip 上传压缩包 +// @Summary 上传压缩包 +// @Description 上传包含index.html的压缩包并解压到指定目录 +// @Tags 文件上传 +// @Accept multipart/form-data +// @Produce json +// @Security ApiKeyAuth +// @Param file formData file true "压缩包文件" +// @Success 200 {object} serializer.Response +// @Router /api/v1/upload/zip [post] +func (h *SysUploadHandler) UploadZip(c *gin.Context) { + c.JSON(http.StatusOK, h.UploadSvc.UploadZip(c)) +} diff --git a/internal/handler/sys_user_handler.go b/internal/handler/sys_user_handler.go new file mode 100644 index 0000000..c2777fc --- /dev/null +++ b/internal/handler/sys_user_handler.go @@ -0,0 +1,176 @@ +package handler + +import ( + "ego/internal/serializer" + "ego/internal/service" + "ego/internal/types" + "net/http" + + "github.com/gin-gonic/gin" +) + +type SysUserHandler struct { + UserSvc *service.SysUserService +} + +// NewSysUserHandler 提供 SysUserHandler 的实例 +func NewSysUserHandler(userSvc *service.SysUserService) *SysUserHandler { + return &SysUserHandler{ + UserSvc: userSvc, + } +} + +// Create 创建用户 +// @Summary 创建用户 +// @Description 创建新用户 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param user body model.SysUser true "用户信息" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser [post] +func (h *SysUserHandler) Create(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.Create(c)) +} + +// DeleteByID 删除用户 +// @Summary 删除用户 +// @Description 根据ID删除用户 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "用户ID" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/{id} [delete] +func (h *SysUserHandler) DeleteByID(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.DeleteByID(c)) +} + +// UpdateByID 更新用户 +// @Summary 更新用户 +// @Description 根据ID更新用户信息 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "用户ID" +// @Param user body model.SysUser true "用户信息" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/{id} [put] +func (h *SysUserHandler) UpdateByID(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.UpdateByID(c)) +} + +// GetByID 根据ID查询用户 +// @Summary 获取用户 +// @Description 根据ID获取用户信息 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param id path string true "用户ID" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/{id} [get] +func (h *SysUserHandler) GetByID(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.GetByID(c)) +} + +// DeleteByIDs 批量删除用户 +// @Summary 批量删除用户 +// @Description 根据ID列表批量删除用户 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param data body types.Payload true "ID列表" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/batch [delete] +func (h *SysUserHandler) DeleteByIDs(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.DeleteByIDs(c)) +} + +// GetByCondition 根据条件查询用户 +// @Summary 条件查询用户 +// @Description 根据条件查询用户列表 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param query body types.Params true "查询条件" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/condition [post] +func (h *SysUserHandler) GetByCondition(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.GetByCondition(c)) +} + +// ListByIDs 根据ID列表查询用户 +// @Summary 批量查询用户 +// @Description 根据ID列表批量查询用户 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param ids body []string true "用户ID列表" +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/list/ids [post] +func (h *SysUserHandler) ListByIDs(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.ListByIDs(c)) +} + +// UserRegister 用户注册接口 +// @Summary 用户注册 +// @Description 新用户注册接口 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Param user body service.UserRegisterRequest true "用户注册信息" +// @Success 200 {object} serializer.Response +// @Router /api/v1/user/register [post] +func (h *SysUserHandler) UserRegister(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.Register(c)) +} + +// UserLogin 用户登录接口 +// @Summary 用户登录 +// @Description 用户登录接口 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Param user body service.UserLoginRequest true "用户登录信息" +// @Success 200 {object} serializer.Response +// @Router /api/v1/user/login [post] +func (h *SysUserHandler) UserLogin(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.Login(c)) +} + +// UserMe 用户详情 +// @Summary 获取当前用户信息 +// @Description 获取当前登录用户的详细信息 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/me [get] +func (h *SysUserHandler) UserMe(c *gin.Context) { + if user, err := h.UserSvc.CurrentUser(c); err == nil { + c.JSON(http.StatusOK, types.BuildUserResponse(*user)) + } else { + c.JSON(http.StatusOK, serializer.Err(http.StatusInternalServerError, "获取用户信息失败!", err)) + } +} + +// UserLogout 用户登出 +// @Summary 用户登出 +// @Description 用户退出登录 +// @Tags 用户管理 +// @Accept json +// @Produce json +// @Security BearerAuth +// @Success 200 {object} serializer.Response +// @Router /api/v1/sysUser/logout [post] +func (h *SysUserHandler) UserLogout(c *gin.Context) { + c.JSON(http.StatusOK, h.UserSvc.UserLogout(c)) +} diff --git a/internal/middleware/cors.go b/internal/middleware/cors.go new file mode 100644 index 0000000..17c4178 --- /dev/null +++ b/internal/middleware/cors.go @@ -0,0 +1,73 @@ +package middleware + +import ( + _ "ego/docs" + "ego/pkg/logger" + "os" + "regexp" + "strings" + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +// Cors 跨域配置(支持环境变量动态配置) +func Cors() gin.HandlerFunc { + config := cors.DefaultConfig() + + // 设置基础配置 + config.AllowMethods = []string{ + "GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", + } + config.AllowHeaders = []string{ + "Origin", "Content-Length", "Content-Type", "Cookie", "Authorization", + "X-Requested-With", "X-CSRF-Token", // 添加常用自定义头 + } + config.AllowCredentials = true + config.MaxAge = 12 * time.Hour // 预检请求缓存12小时 + + // 根据环境配置允许的来源 + if gin.Mode() == gin.ReleaseMode { + // 生产环境:从环境变量读取允许的域名(逗号分隔) + origins := os.Getenv("CORS_ALLOWED_ORIGINS") + if origins == "" { + // 如果环境变量未设置,使用默认的安全配置 + logger.Warn(nil, "CORS_ALLOWED_ORIGINS 环境变量未设置,使用默认安全配置") + config.AllowOrigins = []string{ + "https://yourdomain.com", // 请替换为实际域名 + } + } else { + // 清理空白字符并分割 + originList := make([]string, 0) + for _, origin := range strings.Split(origins, ",") { + trimmed := strings.TrimSpace(origin) + if trimmed != "" { + originList = append(originList, trimmed) + } + } + config.AllowOrigins = originList + } + } else { + // 开发环境:匹配本地开发域名 + config.AllowOriginFunc = func(origin string) bool { + // 匹配 http://localhost:端口 或 http://127.0.0.1:端口 + re := regexp.MustCompile(`^http://(localhost|127\.0\.0\.1):\d+$`) + return re.MatchString(origin) + } + } + + // 输出当前生效的配置(方便调试) + if logger.Logger != nil { + logger.Info(nil, "跨域配置初始化完成", + zap.Any("允许方法", config.AllowMethods), + zap.Any("允许头", config.AllowHeaders), + zap.Any("允许来源", config.AllowOrigins), + zap.Duration("MaxAge", config.MaxAge), + zap.String("模式", gin.Mode()), + ) + } + + return cors.New(config) +} diff --git a/internal/middleware/jwt.go b/internal/middleware/jwt.go new file mode 100644 index 0000000..675aa87 --- /dev/null +++ b/internal/middleware/jwt.go @@ -0,0 +1,91 @@ +package middleware + +import ( + "ego/internal/serializer" + "ego/internal/util" + "ego/pkg/logger" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +// AuthRequired 验证 JWT 的中间件 +func AuthRequired() gin.HandlerFunc { + return func(c *gin.Context) { + // 获取Authorization头 + authHeader := c.GetHeader("Authorization") + if authHeader == "" { + sendUnauthorized(c, "缺少认证头") + return + } + + // 检查Bearer前缀 + if !strings.HasPrefix(authHeader, "Bearer ") { + sendUnauthorized(c, "无效的认证格式,请使用Bearer Token") + return + } + + // 提取token + tokenString := strings.TrimPrefix(authHeader, "Bearer ") + if tokenString == "" { + sendUnauthorized(c, "Token不能为空") + return + } + + // 验证token + claims, err := util.ValidateToken(tokenString) + if err != nil { + logger.Error(c, "Token验证失败", zap.Error(err)) + sendUnauthorized(c, "Token验证失败: "+err.Error()) + return + } + + // 检查Redis中的token状态 + redisKey := util.TokenGroup + claims.Username + val, err := util.Get(c, redisKey) + if err != nil { + logger.Error(c, "Redis验证失败", + zap.Error(err), + zap.String("redisKey", redisKey)) + sendUnauthorized(c, "登录状态验证失败") + return + } + + if val == "" { + logger.Warn(c, "Token已过期或已注销", + zap.String("username", claims.Username)) + sendUnauthorized(c, "登录状态已过期,请重新登录") + return + } + + // 验证Redis中的token是否与当前token一致 + if val != tokenString { + logger.Warn(c, "Token不匹配,可能存在重复登录", + zap.String("username", claims.Username)) + sendUnauthorized(c, "登录状态异常,请重新登录") + return + } + + // 将用户信息存储到context中 + c.Set("userID", claims.ID) + c.Set("username", claims.Username) + c.Set("id", claims.ID) // 保持向后兼容 + + logger.Debug(c, "JWT认证成功", + zap.String("userID", claims.ID), + zap.String("username", claims.Username)) + + c.Next() + } +} + +// sendUnauthorized 发送401未授权响应 +func sendUnauthorized(c *gin.Context, message string) { + c.AbortWithStatusJSON(http.StatusUnauthorized, serializer.Response{ + Code: http.StatusUnauthorized, + Msg: message, + Data: nil, + }) +} diff --git a/internal/middleware/login_log.go b/internal/middleware/login_log.go new file mode 100644 index 0000000..9772c04 --- /dev/null +++ b/internal/middleware/login_log.go @@ -0,0 +1,70 @@ +package middleware + +import ( + "ego/internal/model" + "ego/internal/service" + "ego/internal/util" + "ego/pkg/logger" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "gorm.io/gorm" +) + +// LoginLogMiddleware 登录日志中间件 +func LoginLogMiddleware(db *gorm.DB) gin.HandlerFunc { + return func(c *gin.Context) { + // 只处理登录请求 + if c.Request.URL.Path != "/api/v1/user/login" { + c.Next() + return + } + // 执行登录逻辑 + c.Next() + // 登录成功 + recordLoginLog(c, db) + } +} + +// recordLoginLog 记录登录日志 +func recordLoginLog(c *gin.Context, db *gorm.DB) { + // 获取User-Agent + userAgent := c.GetHeader("User-Agent") + // 获取当前时间 + now := time.Now() + + var status, msg string + + if c.GetString("status") == "1" { + status = "1" + msg = "登录成功" + } else { + status = "0" + msg = c.GetString("msg") + } + // 创建登录日志 + loginLog := model.SysLoginLog{ + UserId: c.GetString("account"), + IpAddr: c.ClientIP(), + LoginLocation: "", // TODO: 需要集成IP地理位置查询服务 + Browser: userAgent, + Os: util.ParseUserAgent(userAgent), + Status: status, + Msg: msg, + LoginTime: &now, + UpdateTime: &now, + CreateTime: &now, + } + + sequenceService := service.SysSequenceServiceBuilder(loginLog.TableName()) + id, err := sequenceService.GenerateId() + if err != nil { + logger.Error(c, "生成日志ID失败", zap.Error(err)) + return + } + loginLog.Id = id + if err := db.Create(&loginLog).Error; err != nil { + logger.Error(c, "记录登录日志失败!", zap.Error(err)) + } +} diff --git a/internal/middleware/unified_return.go b/internal/middleware/unified_return.go new file mode 100644 index 0000000..ace13b4 --- /dev/null +++ b/internal/middleware/unified_return.go @@ -0,0 +1,20 @@ +package middleware + +import ( + "ego/internal/serializer" + "ego/pkg/logger" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" +) + +// UnifiedErrorResponse 统一错误处理中间件 +func UnifiedErrorResponse() gin.HandlerFunc { + return gin.CustomRecovery(func(c *gin.Context, err any) { + // 1. 记录完整错误日志 + logger.Error(c, fmt.Sprintf("系统错误: %v", err)) + // 2. 返回统一的Json风格 + c.AbortWithStatusJSON(http.StatusOK, serializer.Err(http.StatusInternalServerError, "系统繁忙稍后重试!", err.(error))) + }) +} diff --git a/internal/middleware/zap_log.go b/internal/middleware/zap_log.go new file mode 100644 index 0000000..b40a111 --- /dev/null +++ b/internal/middleware/zap_log.go @@ -0,0 +1,27 @@ +package middleware + +import ( + "ego/pkg/logger" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +// GinZapLogger Gin 日志中间件 +func GinZapLogger() gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + trackID := logger.GetTrackID(c) + c.Next() + + // 记录请求日志 + logger.Info(c, "Handled request", + zap.String("trackID", trackID), + zap.String("method", c.Request.Method), + zap.String("path", c.Request.URL.Path), + zap.Int("status", c.Writer.Status()), + zap.Duration("duration", time.Since(start)), + ) + } +} diff --git a/internal/model/sys_deploy_file.go b/internal/model/sys_deploy_file.go new file mode 100644 index 0000000..3bd937b --- /dev/null +++ b/internal/model/sys_deploy_file.go @@ -0,0 +1,49 @@ +package model + +import ( + "time" +) + +// SysDeployFile 部署文件记录表 +type SysDeployFile struct { + DeployId string `gorm:"column:deploy_id;type:varchar(64);primary_key;comment:部署ID" json:"deployId"` + FileName string `gorm:"column:file_name;type:varchar(255);not null;comment:原始文件名" json:"fileName"` + ProjectName string `gorm:"column:project_name;type:varchar(100);not null;comment:项目名称" json:"projectName"` + Domain string `gorm:"column:domain;type:varchar(255);not null;comment:访问域名" json:"domain"` + DeployPath string `gorm:"column:deploy_path;type:varchar(500);not null;comment:部署路径" json:"deployPath"` + FileSize int64 `gorm:"column:file_size;type:bigint;comment:文件大小(字节)" json:"fileSize"` + FileHash string `gorm:"column:file_hash;type:varchar(64);comment:文件哈希值" json:"fileHash"` + Status string `gorm:"column:status;type:char(1);default:1;comment:状态(0停用 1正常 2部署中 3部署失败)" json:"status"` + DeployStatus string `gorm:"column:deploy_status;type:char(1);default:0;comment:部署状态(0未部署 1部署成功 2部署失败)" json:"deployStatus"` + ErrorMsg string `gorm:"column:error_msg;type:text;comment:错误信息" json:"errorMsg"` + Version string `gorm:"column:version;type:varchar(50);comment:版本号" json:"version"` + Description string `gorm:"column:description;type:varchar(500);comment:描述" json:"description"` + DelFlag string `gorm:"column:del_flag;type:char(1);default:0;comment:删除标志(0代表存在 1代表删除)" json:"delFlag"` + CreateBy string `gorm:"column:create_by;type:varchar(64);comment:创建者" json:"createBy"` + CreateTime *time.Time `gorm:"column:create_time;type:datetime;comment:创建时间" json:"createTime"` + UpdateBy string `gorm:"column:update_by;type:varchar(64);comment:更新者" json:"updateBy"` + UpdateTime *time.Time `gorm:"column:update_time;type:datetime;comment:更新时间" json:"updateTime"` + DeployTime *time.Time `gorm:"column:deploy_time;type:datetime;comment:部署时间" json:"deployTime"` + LastAccessTime *time.Time `gorm:"column:last_access_time;type:datetime;comment:最后访问时间" json:"lastAccessTime"` + AccessCount int64 `gorm:"column:access_count;type:bigint;default:0;comment:访问次数" json:"accessCount"` +} + +// TableName 表名 +func (m *SysDeployFile) TableName() string { + return "sys_deploy_file" +} + +// DeployFileStatus 部署文件状态常量 +const ( + DeployFileStatusDisabled = "0" // 停用 + DeployFileStatusNormal = "1" // 正常 + DeployFileStatusDeploying = "2" // 部署中 + DeployFileStatusFailed = "3" // 部署失败 +) + +// DeployStatus 部署状态常量 +const ( + DeployStatusNotDeployed = "0" // 未部署 + DeployStatusSuccess = "1" // 部署成功 + DeployStatusFailed = "2" // 部署失败 +) \ No newline at end of file diff --git a/internal/model/sys_login_log.go b/internal/model/sys_login_log.go new file mode 100644 index 0000000..58c3626 --- /dev/null +++ b/internal/model/sys_login_log.go @@ -0,0 +1,25 @@ +package model + +import "time" + +// SysLoginLog 系统登录日志 +type SysLoginLog struct { + Id string `gorm:"column:id;type:varchar(64);primary_key;comment:主键" json:"id"` + UserId string `gorm:"column:user_id;type:varchar(64);comment:用户ID" json:"userId"` + IpAddr string `gorm:"column:ip_addr;type:varchar(128);comment:登录IP地址" json:"ipAddr"` + LoginLocation string `gorm:"column:login_location;type:varchar(255);comment:登录地点" json:"loginLocation"` + Browser string `gorm:"column:browser;type:varchar(128);comment:浏览器类型" json:"browser"` + Os string `gorm:"column:os;type:varchar(50);comment:操作系统" json:"os"` + Status string `gorm:"column:status;type:varchar(10);comment:登录状态(0成功 1失败)" json:"status"` + Msg string `gorm:"column:msg;type:varchar(255);comment:提示消息" json:"msg"` + LoginTime *time.Time `gorm:"column:login_time;type:varchar(20);comment:登录时间" json:"loginTime"` + CreateBy string `gorm:"column:create_by;type:varchar(64);comment:创建者" json:"createBy"` + CreateTime *time.Time `gorm:"column:create_time;type:datetime;comment:创建时间" json:"createTime"` + UpdateBy string `gorm:"column:update_by;type:varchar(64);comment:更新者" json:"updateBy"` + UpdateTime *time.Time `gorm:"column:update_time;type:datetime;comment:更新时间" json:"updateTime"` +} + +// TableName 设置表名 +func (SysLoginLog) TableName() string { + return "sys_login_log" +} diff --git a/internal/model/sys_sequence.go b/internal/model/sys_sequence.go new file mode 100644 index 0000000..4c07340 --- /dev/null +++ b/internal/model/sys_sequence.go @@ -0,0 +1,13 @@ +package model + +// SysSequence 系统序列表 +type SysSequence struct { + Name string `gorm:"column:table_name;type:varchar(32);not null;comment:表名" json:"name"` + Seq int `gorm:"column:seq;type:int(11);not null;comment:序列" json:"seq"` + Prefix string `gorm:"column:Prefix;type:varchar(32);not null;comment:前缀" json:"prefix"` +} + +// TableName table name +func (m *SysSequence) TableName() string { + return "sys_sequence" +} diff --git a/internal/model/sys_user.go b/internal/model/sys_user.go new file mode 100644 index 0000000..1ab1fe3 --- /dev/null +++ b/internal/model/sys_user.go @@ -0,0 +1,36 @@ +package model + +import ( + "time" +) + +// SysUser 用户信息表 +type SysUser struct { + UserId string `gorm:"column:user_id;type:varchar(64);primary_key;comment:用户ID" json:"userId"` + DeptId string `gorm:"column:dept_id;type:varchar(64);comment:部门ID" json:"deptId"` + UserName string `gorm:"column:user_name;type:varchar(30);not null;comment:用户账号" json:"userName"` + NickName string `gorm:"column:nick_name;type:varchar(30);not null;comment:用户昵称" json:"nickName"` + UserType string `gorm:"column:user_type;type:varchar(2);default:00;comment:用户类型(00系统用户)" json:"userType"` + Email string `gorm:"column:email;type:varchar(50);comment:用户邮箱" json:"email"` + PhoneNumber string `gorm:"column:phone_number;type:varchar(11);comment:手机号码" json:"phoneNumber"` + Solt int `gorm:"column:solt;type:int(11);comment:排序" json:"solt"` + Gender string `gorm:"column:gender;type:char(1);default:0;comment:用户性别(0男 1女 2未知)" json:"gender"` + Avatar string `gorm:"column:avatar;type:varchar(100);comment:头像地址" json:"avatar"` + PassWord string `gorm:"column:pass_word;type:varchar(100);comment:密码" json:"passWord"` + Status string `gorm:"column:status;type:char(1);default:0;comment:帐号状态(0正常 1停用)" json:"status"` + DelFlag string `gorm:"column:del_flag;type:char(1);default:0;comment:删除标志(0代表存在 2代表删除)" json:"delFlag"` + LoginIP string `gorm:"column:login_ip;type:varchar(128);comment:最后登录IP" json:"loginIP"` + LoginDate *time.Time `gorm:"column:login_date;type:datetime;comment:最后登录时间" json:"loginDate"` + ResourceInvoke string `gorm:"column:resource_invoke;type:varchar(255);comment:资源来源映射,多个用,分割" json:"resourceInvoke"` + CreateBy string `gorm:"column:create_by;type:varchar(64);comment:创建者" json:"createBy"` + CreateTime *time.Time `gorm:"column:create_time;type:datetime;comment:创建时间" json:"createTime"` + UpdateBy string `gorm:"column:update_by;type:varchar(64);comment:更新者" json:"updateBy"` + UpdateTime *time.Time `gorm:"column:update_time;type:datetime;comment:更新时间" json:"updateTime"` + Remark string `gorm:"column:remark;type:varchar(500);comment:备注" json:"remark"` + SelectKey string `gorm:"column:select_key;type:varchar(64);comment:动态验证" json:"selectKey"` +} + +// TableName table name +func (m *SysUser) TableName() string { + return "sys_user" +} diff --git a/internal/router/routers.go b/internal/router/routers.go new file mode 100644 index 0000000..4dc6577 --- /dev/null +++ b/internal/router/routers.go @@ -0,0 +1,44 @@ +package router + +import ( + "ego/internal/conf" + "ego/internal/middleware" + + "github.com/gin-gonic/gin" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" +) + +var ( + apiRouterFns []func(r *gin.RouterGroup) +) + +// NewRouter 路由配置 +func NewRouter() *gin.Engine { + // gin 实例 + engine := gin.Default() + // 跨域处理 + engine.Use(middleware.Cors()) + // zap 日志 + engine.Use(middleware.GinZapLogger()) + // 统一错误处理 + engine.Use(middleware.UnifiedErrorResponse()) + // 登录日志中间件 + engine.Use(middleware.LoginLogMiddleware(conf.Db)) + + // swagger + if gin.Mode() != gin.ReleaseMode { + engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + } + // register routers, middleware support + registerRouters(engine, "/api/v1", apiRouterFns) + return engine +} + +// registerRouters 注册路由 +func registerRouters(r *gin.Engine, groupPath string, routerFns []func(*gin.RouterGroup), handlers ...gin.HandlerFunc) { + rg := r.Group(groupPath, handlers...) + for _, fn := range routerFns { + fn(rg) + } +} diff --git a/internal/router/sys_deploy_file_router.go b/internal/router/sys_deploy_file_router.go new file mode 100644 index 0000000..32b8abf --- /dev/null +++ b/internal/router/sys_deploy_file_router.go @@ -0,0 +1,34 @@ +package router + +import ( + "ego/internal/handler" + "ego/internal/middleware" + "ego/internal/wire" + + "github.com/gin-gonic/gin" +) + +func init() { + apiRouterFns = append(apiRouterFns, func(group *gin.RouterGroup) { + SysDeployFileHandlerRouter(group, wire.InjectSysDeployFileHandler()) + }) +} + +// SysDeployFileHandlerRouter 部署文件相关路由 +// @Summary 部署文件管理路由 +// @Description 包含部署文件的增删改查等接口 +// @Tags 部署文件管理 +// @Accept json +// @Produce json +func SysDeployFileHandlerRouter(group *gin.RouterGroup, h *handler.SysDeployFileHandler) { + // 部署文件管理路由组 + g := group.Group("/deploy-files") + // 鉴权 + g.Use(middleware.AuthRequired()) + + g.POST("/", h.Create) + g.GET("/:id", h.GetByID) + g.PUT("/", h.UpdateByID) + g.DELETE("/:id", h.DeleteByID) + g.GET("", h.GetByCondition) +} diff --git a/internal/router/sys_login_log_router.go b/internal/router/sys_login_log_router.go new file mode 100644 index 0000000..69d4f64 --- /dev/null +++ b/internal/router/sys_login_log_router.go @@ -0,0 +1,34 @@ +package router + +import ( + "ego/internal/handler" + "ego/internal/middleware" + "ego/internal/wire" + + "github.com/gin-gonic/gin" +) + +// @tag.name 登录记录 +// @tag.description 登录记录相关的所有接口,包括创建、删除、更新、查询等 + +func init() { + apiRouterFns = append(apiRouterFns, func(group *gin.RouterGroup) { + SysLoginLogRouter(group, wire.InjectSysLoginLogHandler()) + }) +} + +// SysLoginLogRouter 登录日志路由 +func SysLoginLogRouter(r *gin.RouterGroup, h *handler.SysLoginLogHandler) { + g := r.Group("/sysLoginLog") + // 登录日志需要认证 + g.Use(middleware.AuthRequired()) + { + g.POST("/create", h.Create) + g.POST("/delete", h.DeleteByID) + g.POST("/update", h.UpdateByID) + g.POST("/get", h.GetByID) + g.POST("/list", h.GetByCondition) + g.POST("/list/ids", h.ListByIDs) + g.POST("/delete/ids", h.DeleteByIDs) + } +} diff --git a/internal/router/sys_upload_router.go b/internal/router/sys_upload_router.go new file mode 100644 index 0000000..3d3d941 --- /dev/null +++ b/internal/router/sys_upload_router.go @@ -0,0 +1,22 @@ +package router + +import ( + "ego/internal/handler" + "ego/internal/wire" + "github.com/gin-gonic/gin" +) + +func init() { + apiRouterFns = append(apiRouterFns, func(group *gin.RouterGroup) { + SysUploadHandlerRouter(group, wire.InjectSysUploadHandler()) + }) +} + +// SysUploadHandlerRouter 文件上传路由 +func SysUploadHandlerRouter(r *gin.RouterGroup, h *handler.SysUploadHandler) { + upload := r.Group("/upload") + //upload.Use(middleware.AuthRequired()) + { + upload.POST("/zip", h.UploadZip) + } +} diff --git a/internal/router/sys_user_router.go b/internal/router/sys_user_router.go new file mode 100644 index 0000000..c087e45 --- /dev/null +++ b/internal/router/sys_user_router.go @@ -0,0 +1,53 @@ +package router + +import ( + "ego/internal/handler" + "ego/internal/middleware" + "ego/internal/wire" + + "github.com/gin-gonic/gin" +) + +// @title EGO API +// @version 1.0 +// @description EGO 系统 API 文档 +// @termsOfService http://swagger.io/terms/ + +// @tag.name 用户管理 +// @tag.description 用户相关的所有接口,包括注册、登录、信息管理等 + +func init() { + apiRouterFns = append(apiRouterFns, func(group *gin.RouterGroup) { + SysUserHandlerRouter(group, wire.InjectSysUserHandler()) + }) +} + +// SysUserHandlerRouter 用户相关路由 +// @Summary 用户管理路由 +// @Description 包含用户注册、登录、信息管理等接口 +// @Tags 用户管理 +// @Accept json +// @Produce json +func SysUserHandlerRouter(group *gin.RouterGroup, h *handler.SysUserHandler) { + // 不需要认证 + rg := group.Group("/user") + rg.POST("/register", h.UserRegister) + rg.POST("/login", h.UserLogin) + + g := group.Group("/sysUser") + // 鉴权 + g.Use(middleware.AuthRequired()) + + g.POST("/", h.Create) + g.DELETE("/:id", h.DeleteByID) + g.PUT("/", h.UpdateByID) + g.GET("/:id", h.GetByID) + g.DELETE("/batch", h.DeleteByIDs) + + g.POST("/condition", h.GetByCondition) + g.POST("/list/ids", h.ListByIDs) + g.GET("/me", h.UserMe) + + g.POST("/logout", h.UserLogout) + +} diff --git a/internal/serializer/common.go b/internal/serializer/common.go new file mode 100644 index 0000000..cd0a398 --- /dev/null +++ b/internal/serializer/common.go @@ -0,0 +1,78 @@ +package serializer + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" +) + +// Response 基础序列化器 +type Response struct { + Code int `json:"code"` + Data any `json:"data,omitempty"` + Msg string `json:"msg"` + Error string `json:"error,omitempty"` +} + +// TrackedErrorResponse 有追踪信息的错误响应 +type TrackedErrorResponse struct { + Response + TrackID string `json:"track_id"` +} + +const ( + CodeCheckLogin = 401 + CodeNoRightErr = 403 + CodeDBError = 50001 + CodeEncryptError = 50002 + CodeParamErr = 40001 +) + +// CheckLogin 检查登录 +func CheckLogin() Response { + return Err(CodeCheckLogin, "未登录", nil) +} + +// Err 通用错误处理 +func Err(errCode int, msg string, err error) Response { + if msg == "" { + msg = "未知错误" + } + res := Response{ + Code: errCode, + Msg: msg, + } + if err != nil && gin.Mode() != gin.ReleaseMode { + res.Error = fmt.Sprintf("%+v", err) + } + return res +} + +// DBErr 数据库操作失败 +func DBErr(msg string, err error) Response { + if msg == "" { + msg = "数据库操作失败" + } + return Err(CodeDBError, msg, err) +} + +// ParamErr 各种参数错误 +func ParamErr(msg string, err error) Response { + if msg == "" { + msg = "参数错误" + } + return Err(CodeParamErr, msg, err) +} + +// Succ 返回结果 +func Succ(msg string, data any) Response { + if msg == "" { + msg = "操作成功!" + } + return Response{ + Code: http.StatusOK, + Msg: msg, + Data: data, + } +} diff --git a/internal/service/sys_deploy_file_service.go b/internal/service/sys_deploy_file_service.go new file mode 100644 index 0000000..60c3a24 --- /dev/null +++ b/internal/service/sys_deploy_file_service.go @@ -0,0 +1,227 @@ +package service + +import ( + "crypto/md5" + "ego/internal/model" + "ego/internal/serializer" + "ego/internal/types" + "ego/pkg/logger" + "fmt" + "io" + "time" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +// SysDeployFileService 部署文件服务 +type SysDeployFileService struct { + Db *gorm.DB +} + +// NewSysDeployFileService 构建部署文件服务 +func NewSysDeployFileService(db *gorm.DB) *SysDeployFileService { + return &SysDeployFileService{ + Db: db, + } +} + +// Create 创建部署文件记录 +func (s *SysDeployFileService) Create(c *gin.Context) serializer.Response { + var deployFile model.SysDeployFile + if err := c.ShouldBind(&deployFile); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + // 生成部署ID + if id, err := SysSequenceServiceBuilder(deployFile.TableName()).GenerateId(); err == nil { + deployFile.DeployId = id + } else { + return serializer.DBErr("序列生成失败!", err) + } + + // 设置默认值 + now := time.Now() + deployFile.CreateTime = &now + deployFile.Status = model.DeployFileStatusNormal + deployFile.DeployStatus = model.DeployStatusNotDeployed + deployFile.DelFlag = "0" + + // 获取当前用户 + if createBy := c.GetString("id"); createBy != "" { + deployFile.CreateBy = createBy + } + + if err := s.Db.Create(&deployFile).Error; err != nil { + logger.Error(c, "创建部署文件记录失败!") + return serializer.DBErr("创建部署文件记录失败!", err) + } + + return serializer.Succ("创建部署文件记录成功!", deployFile) +} + +// GetByID 根据ID获取部署文件记录 +func (s *SysDeployFileService) GetByID(c *gin.Context) serializer.Response { + var deployFile model.SysDeployFile + if err := s.Db.Where("deploy_id = ? AND del_flag = ?", c.Param("id"), "0").First(&deployFile).Error; err != nil { + logger.Error(c, "获取部署文件记录失败!") + return serializer.DBErr("获取部署文件记录失败!", err) + } + return serializer.Succ("查询成功!", deployFile) +} + +// UpdateByID 根据ID更新部署文件记录 +func (s *SysDeployFileService) UpdateByID(c *gin.Context) serializer.Response { + var deployFile model.SysDeployFile + if err := c.ShouldBind(&deployFile); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + id := deployFile.DeployId + if id == "" { + logger.Error(c, "id 不可为空!") + return serializer.ParamErr("id不可为空!", fmt.Errorf("id不可为空")) + } + + // 设置更新时间 + now := time.Now() + deployFile.UpdateTime = &now + + // 获取当前用户 + if updateBy := c.GetString("id"); updateBy != "" { + deployFile.UpdateBy = updateBy + } + + if err := s.Db.Model(&deployFile).Where("deploy_id = ? AND del_flag = ?", id, "0").Updates(&deployFile).Error; err != nil { + logger.Error(c, "更新部署文件记录失败!") + return serializer.DBErr("更新部署文件记录失败!", err) + } + return serializer.Succ("更新部署文件记录成功!", deployFile) +} + +// DeleteByID 根据ID删除部署文件记录 +func (s *SysDeployFileService) DeleteByID(c *gin.Context) serializer.Response { + id := c.Param("id") + if id == "" { + logger.Error(c, "id 不可为空!") + return serializer.ParamErr("id不可为空!", fmt.Errorf("id不可为空")) + } + + // 软删除 + data := map[string]any{ + "del_flag": "1", + "update_time": time.Now(), + "update_by": c.GetString("id"), + } + + if err := s.Db.Model(&model.SysDeployFile{}).Where("deploy_id = ?", id).Updates(data).Error; err != nil { + logger.Error(c, "删除部署文件记录失败!") + return serializer.DBErr("删除部署文件记录失败!", err) + } + + return serializer.Succ("删除部署文件记录成功!", nil) +} + +// GetByCondition 条件查询部署文件记录 +func (s *SysDeployFileService) GetByCondition(c *gin.Context) serializer.Response { + var p types.Params + if err := c.ShouldBind(&p); err != nil { + return serializer.ParamErr("参数绑定失败!", err) + } + + queryStr, args, err := p.ConvertToGormConditions() + if err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + var total int64 + var deployFiles []model.SysDeployFile + offset := (p.Page - 1) * p.Limit + + // 构建基础查询 + db := s.Db.Model(&model.SysDeployFile{}) + + // 如果有查询条件,添加条件 + if queryStr != "" { + db = db.Where(queryStr, args...) + } + + // 排序 + if p.Sort != "" { + db = db.Order(p.Sort) + } else { + db = db.Order("create_time DESC") + } + + // 执行分页查询 + if err := db.Where("del_flag = ?", "0").Offset(offset).Limit(p.Limit).Find(&deployFiles).Error; err != nil { + logger.Error(c, "获取部署文件记录失败!") + return serializer.DBErr("获取部署文件记录失败!", err) + } + + // 执行总数查询 + if err := db.Where("del_flag = ?", "0").Count(&total).Error; err != nil { + logger.Error(c, "获取部署文件记录总数失败!") + return serializer.DBErr("获取部署文件记录总数失败!", err) + } + + return serializer.Succ("查询成功!", gin.H{ + "total": total, + "items": deployFiles, + "page": p.Page, + "limit": p.Limit, + }) +} + +// UpdateDeployStatus 更新部署状态 +func (s *SysDeployFileService) UpdateDeployStatus(deployId, status, errorMsg string) error { + data := map[string]any{ + "deploy_status": status, + "update_time": time.Now(), + } + + if status == model.DeployStatusSuccess { + now := time.Now() + data["deploy_time"] = &now + } + + if errorMsg != "" { + data["error_msg"] = errorMsg + } + + return s.Db.Model(&model.SysDeployFile{}).Where("deploy_id = ?", deployId).Updates(data).Error +} + +// UpdateAccessInfo 更新访问信息 +func (s *SysDeployFileService) UpdateAccessInfo(deployId string) error { + now := time.Now() + return s.Db.Model(&model.SysDeployFile{}). + Where("deploy_id = ?", deployId). + Updates(map[string]any{ + "last_access_time": &now, + "access_count": gorm.Expr("access_count + 1"), + }).Error +} + +// GetByDomain 根据域名获取部署文件记录 +func (s *SysDeployFileService) GetByDomain(domain string) (*model.SysDeployFile, error) { + var deployFile model.SysDeployFile + err := s.Db.Where("domain = ? AND status = ? AND del_flag = ?", + domain, model.DeployFileStatusNormal, "0").First(&deployFile).Error + if err != nil { + return nil, err + } + return &deployFile, nil +} + +// CalculateFileHash 计算文件哈希值 +func (s *SysDeployFileService) CalculateFileHash(reader io.Reader) (string, error) { + hash := md5.New() + if _, err := io.Copy(hash, reader); err != nil { + return "", err + } + return fmt.Sprintf("%x", hash.Sum(nil)), nil +} diff --git a/internal/service/sys_login_log_service.go b/internal/service/sys_login_log_service.go new file mode 100644 index 0000000..9e08e9f --- /dev/null +++ b/internal/service/sys_login_log_service.go @@ -0,0 +1,161 @@ +package service + +import ( + "ego/internal/model" + "ego/internal/serializer" + "ego/internal/types" + "ego/pkg/logger" + "fmt" + "time" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +// SysLoginLogService 登录日志服务 +type SysLoginLogService struct { + Db *gorm.DB +} + +// NewSysLoginLogService 构建登录日志服务 +func NewSysLoginLogService(db *gorm.DB) *SysLoginLogService { + return &SysLoginLogService{ + Db: db, + } +} + +// Create 创建登录日志 +func (s *SysLoginLogService) Create(c *gin.Context) serializer.Response { + var loginLog model.SysLoginLog + if err := c.ShouldBind(&loginLog); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + // 生成登录日志ID + id, err := SysSequenceServiceBuilder(loginLog.TableName()).GenerateId() + if err != nil { + return serializer.DBErr("创建登录日志失败!", err) + } + loginLog.Id = id + + now := time.Now() + loginLog.LoginTime = &now + + if err := s.Db.Create(&loginLog).Error; err != nil { + logger.Error(c, "创建登录日志失败!") + return serializer.DBErr("创建登录日志失败!", err) + } + return serializer.Succ("创建登录日志成功!", loginLog) +} + +// DeleteByID 根据ID删除登录日志 +func (s *SysLoginLogService) DeleteByID(c *gin.Context) serializer.Response { + var loginLog model.SysLoginLog + if err := c.ShouldBind(&loginLog); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + if err := s.Db.Delete(&loginLog).Error; err != nil { + logger.Error(c, "删除登录日志失败!") + return serializer.DBErr("删除登录日志失败!", err) + } + return serializer.Succ("删除登录日志成功!", nil) +} + +// UpdateByID 根据ID更新登录日志 +func (s *SysLoginLogService) UpdateByID(c *gin.Context) serializer.Response { + var loginLog model.SysLoginLog + if err := c.ShouldBind(&loginLog); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + if err := s.Db.Model(&loginLog).Updates(loginLog).Error; err != nil { + logger.Error(c, "更新登录日志失败!") + return serializer.DBErr("更新登录日志失败!", err) + } + return serializer.Succ("更新登录日志成功!", loginLog) +} + +// GetByID 根据ID获取登录日志 +func (s *SysLoginLogService) GetByID(c *gin.Context) serializer.Response { + var loginLog model.SysLoginLog + if err := c.ShouldBind(&loginLog); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + if err := s.Db.First(&loginLog).Error; err != nil { + logger.Error(c, "获取登录日志失败!") + return serializer.DBErr("获取登录日志失败!", err) + } + return serializer.Succ("获取登录日志成功!", loginLog) +} + +// GetByCondition 根据条件获取登录日志 +func (s *SysLoginLogService) GetByCondition(c *gin.Context) serializer.Response { + var loginLog model.SysLoginLog + if err := c.ShouldBind(&loginLog); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + var loginLogs []model.SysLoginLog + if err := s.Db.Where(&loginLog).Find(&loginLogs).Error; err != nil { + logger.Error(c, "获取登录日志失败!") + return serializer.DBErr("获取登录日志失败!", err) + } + return serializer.Succ("获取登录日志成功!", loginLogs) +} + +// ListByIDs 根据ID列表获取登录日志 +func (s *SysLoginLogService) ListByIDs(c *gin.Context) serializer.Response { + var ids types.Payload + if err := c.ShouldBind(&ids); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + var loginLogs []model.SysLoginLog + if err := s.Db.Where("id IN ?", ids.Ids).Find(&loginLogs).Error; err != nil { + logger.Error(c, "获取登录日志失败!") + return serializer.DBErr("获取登录日志失败!", err) + } + return serializer.Succ("获取登录日志成功!", loginLogs) +} + +// DeleteByIDs 根据ID列表删除登录日志 +func (s *SysLoginLogService) DeleteByIDs(c *gin.Context) serializer.Response { + var ids types.Payload + if err := c.ShouldBind(&ids); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + if err := s.Db.Where("id IN ?", ids.Ids).Delete(&model.SysLoginLog{}).Error; err != nil { + logger.Error(c, "删除登录日志失败!") + return serializer.DBErr("删除登录日志失败!", err) + } + return serializer.Succ("删除登录日志成功!", nil) +} + +// CreateLogging 创建登录日志 +func (s *SysLoginLogService) CreateLogging(sysLoginLog *model.SysLoginLog, c *gin.Context) error { + // 生成登录日志ID + id, err := SysSequenceServiceBuilder(sysLoginLog.TableName()).GenerateId() + if err != nil { + return fmt.Errorf("生成登录日志ID失败: %v", err) + } + sysLoginLog.Id = id + + now := time.Now() + sysLoginLog.LoginTime = &now + + if err := s.Db.Create(sysLoginLog).Error; err != nil { + logger.Error(c, "创建登录日志失败!") + return fmt.Errorf("创建登录日志失败: %v", err) + } + return nil +} diff --git a/internal/service/sys_sequence_service.go b/internal/service/sys_sequence_service.go new file mode 100644 index 0000000..54d3cf0 --- /dev/null +++ b/internal/service/sys_sequence_service.go @@ -0,0 +1,31 @@ +package service + +import ( + "ego/internal/conf" + "strings" + "sync" +) + +type SysSequenceService struct { + mutex sync.Mutex + tableName string +} + +// SysSequenceServiceBuilder 创建一个SysSequenceService +func SysSequenceServiceBuilder(tableName string) *SysSequenceService { + return &SysSequenceService{ + tableName: tableName, + } +} + +// GenerateId 根据表名生成ID(使用序列) +func (s *SysSequenceService) GenerateId() (string, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + var id string + err := conf.Db.Raw("SELECT NEXTVAL(?)", strings.ToLower(s.tableName)).Scan(&id).Error + if err != nil { + return "", err + } + return id, nil +} diff --git a/internal/service/sys_upload_service.go b/internal/service/sys_upload_service.go new file mode 100644 index 0000000..5c79845 --- /dev/null +++ b/internal/service/sys_upload_service.go @@ -0,0 +1,246 @@ +package service + +import ( + "archive/zip" + "crypto/md5" + "ego/internal/model" + "ego/internal/serializer" + "ego/pkg/logger" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "gorm.io/gorm" +) + +// SysUploadService 文件上传服务 +type SysUploadService struct { + Db *gorm.DB +} + +// NewSysUploadService 构建文件上传服务 +func NewSysUploadService(db *gorm.DB) *SysUploadService { + return &SysUploadService{ + Db: db, + } +} + +// UploadZip 上传压缩包 +func (s *SysUploadService) UploadZip(c *gin.Context) serializer.Response { + // 获取上传的文件 + file, err := c.FormFile("file") + if err != nil { + logger.Error(c, "获取上传文件失败!") + return serializer.ParamErr("获取上传文件失败!", err) + } + + // 校验文件类型 + if !strings.HasSuffix(strings.ToLower(file.Filename), ".zip") { + logger.Error(c, "只支持zip格式文件!") + return serializer.ParamErr("只支持zip格式文件!", nil) + } + + // 获取文件名(不包含扩展名) + filename := strings.TrimSuffix(file.Filename, filepath.Ext(file.Filename)) + + // 检查目标文件夹是否存在 + targetDir := filepath.Join("/home", filename) + if _, err := os.Stat(targetDir); !os.IsNotExist(err) { + logger.Error(c, "目标文件夹已存在!") + return serializer.ParamErr("目标文件夹已存在!", nil) + } + + // 打开上传的文件 + src, err := file.Open() + if err != nil { + logger.Error(c, "打开上传文件失败!") + return serializer.ParamErr("打开上传文件失败!", err) + } + defer src.Close() + + // 创建临时文件 + tempFile, err := os.CreateTemp("", "upload-*.zip") + if err != nil { + logger.Error(c, "创建临时文件失败!") + return serializer.ParamErr("创建临时文件失败!", err) + } + defer os.Remove(tempFile.Name()) + defer tempFile.Close() + + // 复制文件内容到临时文件 + if _, err := io.Copy(tempFile, src); err != nil { + logger.Error(c, "复制文件内容失败!") + return serializer.ParamErr("复制文件内容失败!", err) + } + + // 校验压缩包是否包含index.html + hasIndexHtml, err := s.validateZipFile(tempFile.Name()) + if err != nil { + logger.Error(c, "校验压缩包失败!") + return serializer.ParamErr("校验压缩包失败!", err) + } + + if !hasIndexHtml { + logger.Error(c, "压缩包必须包含index.html文件!") + return serializer.ParamErr("压缩包必须包含index.html文件!", nil) + } + + // 创建目标目录 + if err := os.MkdirAll(targetDir, 0755); err != nil { + logger.Error(c, "创建目标目录失败!") + return serializer.ParamErr("创建目标目录失败!", err) + } + + // 解压文件 + if err := s.extractZip(tempFile.Name(), targetDir); err != nil { + // 如果解压失败,删除已创建的目录 + os.RemoveAll(targetDir) + logger.Error(c, "解压文件失败!") + return serializer.ParamErr("解压文件失败!", err) + } + + // 返回域名格式的结果 + domain := fmt.Sprintf("%s.unbug.cn", filename) + + // 创建部署文件记录 + deployFile := model.SysDeployFile{ + FileName: file.Filename, + ProjectName: filename, + Domain: domain, + DeployPath: targetDir, + FileSize: file.Size, + Status: model.DeployFileStatusNormal, + DeployStatus: model.DeployStatusSuccess, + Description: fmt.Sprintf("自动部署项目: %s", filename), + } + + // 生成部署ID + if id, err := SysSequenceServiceBuilder(deployFile.TableName()).GenerateId(); err == nil { + deployFile.DeployId = id + } else { + logger.Error(c, "生成部署ID失败!", zap.Error(err)) + return serializer.DBErr("生成部署ID失败!", err) + } + + // 计算文件哈希值 + if fileHash, err := s.calculateFileHash(tempFile.Name()); err == nil { + deployFile.FileHash = fileHash + } + + // 设置时间 + now := time.Now() + deployFile.CreateTime = &now + deployFile.DeployTime = &now + deployFile.DelFlag = "0" + + // 获取当前用户 + if createBy := c.GetString("id"); createBy != "" { + deployFile.CreateBy = createBy + } + + // 保存到数据库 + if err := s.Db.Create(&deployFile).Error; err != nil { + logger.Error(c, "保存部署文件记录失败!", zap.Error(err)) + // 即使保存记录失败,也不影响文件部署 + } + + return serializer.Succ("上传成功!", map[string]interface{}{ + "domain": domain, + "path": targetDir, + "deployId": deployFile.DeployId, + }) +} + +// validateZipFile 校验压缩包是否包含index.html +func (s *SysUploadService) validateZipFile(zipPath string) (bool, error) { + reader, err := zip.OpenReader(zipPath) + if err != nil { + return false, err + } + defer reader.Close() + + for _, file := range reader.File { + if strings.ToLower(filepath.Base(file.Name)) == "index.html" { + return true, nil + } + } + + return false, nil +} + +// extractZip 解压zip文件到指定目录 +func (s *SysUploadService) extractZip(zipPath, destDir string) error { + reader, err := zip.OpenReader(zipPath) + if err != nil { + return err + } + defer reader.Close() + + // 创建目标目录 + if err := os.MkdirAll(destDir, 0755); err != nil { + return err + } + + // 提取文件 + for _, file := range reader.File { + rc, err := file.Open() + if err != nil { + return err + } + defer rc.Close() + + // 构建文件路径 + path := filepath.Join(destDir, file.Name) + + // 检查路径是否安全(防止路径遍历攻击) + if !strings.HasPrefix(path, filepath.Clean(destDir)+string(os.PathSeparator)) { + return fmt.Errorf("invalid file path: %s", file.Name) + } + + if file.FileInfo().IsDir() { + // 创建目录 + if err := os.MkdirAll(path, file.FileInfo().Mode()); err != nil { + return err + } + } else { + // 创建文件的父目录 + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + + // 创建文件 + outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.FileInfo().Mode()) + if err != nil { + return err + } + defer outFile.Close() + + // 复制文件内容 + if _, err := io.Copy(outFile, rc); err != nil { + return err + } + } + } + + return nil +} + +// calculateFileHash 计算文件哈希值 +func (s *SysUploadService) calculateFileHash(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", err + } + defer file.Close() + + hash := md5.New() + if _, err := io.Copy(hash, file); err != nil { + return "", err + } + return fmt.Sprintf("%x", hash.Sum(nil)), nil +} diff --git a/internal/service/sys_user_service.go b/internal/service/sys_user_service.go new file mode 100644 index 0000000..682e200 --- /dev/null +++ b/internal/service/sys_user_service.go @@ -0,0 +1,427 @@ +package service + +import ( + "ego/internal/model" + "ego/internal/serializer" + "ego/internal/types" + "ego/internal/util" + "ego/pkg/logger" + "fmt" + "time" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "golang.org/x/crypto/bcrypt" + "gorm.io/gorm" +) + +const ( + // PassWordCost 密码加密难度 + PassWordCost = 12 + // Suspend 被封禁用户 + Suspend = "-1" + // Active 未激活用户 + Active = "1" + // Inactive 激活用户 + Inactive = "0" +) + +// SysUserService 管理用户登录的服务 +type SysUserService struct { + Db *gorm.DB +} + +// NewSysUserService 构建用户登录服务 +func NewSysUserService(db *gorm.DB) *SysUserService { + return &SysUserService{ + Db: db, + } +} + +type UserLoginRequest struct { + Account string `form:"account" json:"account" binding:"required,min=5,max=30"` + PassWord string `form:"password" json:"password" binding:"required,min=8,max=40"` + Checked *bool `form:"checked" json:"checked" binding:"required"` + Phone string `form:"phone" json:"phone"` + VerifyCode string `form:"verifyCode" json:"verifyCode"` +} + +// UserRegisterRequest 用户注册表单验证 +type UserRegisterRequest struct { + NickName string `form:"nickName" json:"nickName" binding:"required,min=2,max=30"` + UserName string `form:"userName" json:"userName" binding:"required,min=5,max=30"` + PassWord string `form:"passWord" json:"passWord" binding:"required,min=8,max=40"` + PasswordConfirm string `form:"passWordConfirm" json:"passWordConfirm" binding:"required,min=8,max=40"` +} + +// Login 用户登录函数 +func (s *SysUserService) Login(c *gin.Context) serializer.Response { + var user model.SysUser + u := UserLoginRequest{} + if err := c.ShouldBind(&u); err != nil { + logger.Error(c, "参数绑定错误!", zap.Error(err)) + c.Set("msg", "参数绑定错误!") + return serializer.Err(serializer.CodeParamErr, "参数绑定错误!", err) + } + c.Set("account", u.Account) + if err := s.Db.Where("user_name = ?", u.Account).First(&user).Error; err != nil { + logger.Error(c, "账号或密码错误!") + c.Set("msg", "账号或密码错误!") + return serializer.ParamErr("账号或密码错误!", nil) + } + if user.Status == Suspend { + logger.Error(c, "账号已封禁!") + c.Set("msg", "账号已封禁!") + return serializer.ParamErr("账号已封禁!", nil) + } + if user.Status == Inactive { + logger.Error(c, "账号未激活!") + c.Set("msg", "账号未激活!") + return serializer.ParamErr("账号未激活!", nil) + } + if !CheckPassWord(u.PassWord, user.PassWord) { + logger.Error(c, "账号或密码错误!") + c.Set("msg", "账号或密码错误!") + return serializer.ParamErr("账号或密码错误!", nil) + } + if token, err := util.GenerateToken(user.UserId, user.UserName); err == nil { + logger.Info(c, "用户登录", zap.String("redisKey", util.TokenGroup+user.UserName)) + // 删除key + del := util.Del(c, util.TokenGroup+user.UserName) + if del != nil { + logger.Error(c, "redis 删除失败!", zap.Error(del)) + c.Set("msg", "redis 删除失败!") + return serializer.ParamErr("系统繁忙稍后重试!", nil) + } + // 结果放入redis + set := util.Set(c, util.TokenGroup+user.UserName, token, time.Hour*24) + if set != nil { + logger.Error(c, "redis 放入失败!", zap.Error(set)) + c.Set("msg", "redis 放入失败!") + return serializer.ParamErr("系统繁忙稍后重试!", nil) + } + c.Set("status", Active) + return types.BuildUserResponseHasToken(user, token) + } + return serializer.ParamErr("系统繁忙稍后重试!", nil) +} + +// UserLogout 退出登录 +func (s *SysUserService) UserLogout(c *gin.Context) serializer.Response { + // 退出登录 + go func() { + tokenString := c.GetHeader("Authorization") + token, err := util.ParseToken(tokenString[8:]) + if err == nil { + username := token["username"].(string) + // 删除key + if err := util.Del(c, util.TokenGroup+username); err != nil { + logger.Error(c, "退出登录失败!", zap.Error(err)) + } else { + logger.Info(c, "用户退出登录成功!", zap.String("redisKey", util.TokenGroup+username)) + } + } + }() + return serializer.Succ("退出登录成功!", true) +} + +// GetUser 用ID获取用户 +func GetUser(id string, d *gorm.DB) (model.SysUser, error) { + var user model.SysUser + result := d.Where("user_id = ?", id).First(&user) + if result.Error == nil { + user.PassWord = "" // 清除密码 + } + return user, result.Error +} + +// SetPassWord 设置密码 +func SetPassWord(passWord string, sysUser *model.SysUser) error { + bytes, err := bcrypt.GenerateFromPassword([]byte(passWord), PassWordCost) + if err != nil { + return err + } + sysUser.PassWord = string(bytes) + return nil +} + +// CheckPassWord 校验密码 +func CheckPassWord(password string, passwordDigest string) bool { + err := bcrypt.CompareHashAndPassword([]byte(passwordDigest), []byte(password)) + return err == nil +} + +// valid 验证表单 +func (s *SysUserService) valid(u *UserRegisterRequest) *serializer.Response { + if u.PasswordConfirm != u.PassWord { + return &serializer.Response{ + Code: 40001, + Msg: "两次输入的密码不相同", + } + } + + count := int64(0) + s.Db.Model(&model.SysUser{}).Where("nick_name = ?", u.NickName).Count(&count) + if count > 0 { + return &serializer.Response{ + Code: 40001, + Msg: "昵称被占用", + } + } + + count = 0 + s.Db.Model(&model.SysUser{}).Where("user_name = ?", u.UserName).Count(&count) + if count > 0 { + return &serializer.Response{ + Code: 40001, + Msg: "用户名已经注册", + } + } + + return nil +} + +// Register 用户注册 +func (s *SysUserService) Register(c *gin.Context) serializer.Response { + u := UserRegisterRequest{} + if err := c.ShouldBind(&u); err != nil { + return serializer.Err(serializer.CodeParamErr, "参数绑定错误!", err) + } + now := time.Now() + user := model.SysUser{ + NickName: u.NickName, + UserName: u.UserName, + Status: Active, + CreateTime: &now, + } + // 生成ID + if id, err := SysSequenceServiceBuilder(user.TableName()).GenerateId(); err == nil { + user.UserId = id + } else { + return serializer.DBErr("序列生成失败!", err) + } + // 表单验证 + if err := s.valid(&u); err != nil { + logger.Error(c, err.Msg, zap.String("NickName", u.NickName), zap.String("UserName", u.UserName)) + return *err + } + // 密码加密 + if err := SetPassWord(u.PassWord, &user); err != nil { + logger.Error(c, "密码加密失败!") + return serializer.Err(serializer.CodeEncryptError, "密码加密失败!", err) + } + // 使用事务封装数据库操作 + err := s.Db.Transaction(func(tx *gorm.DB) error { + if err := tx.Create(&user).Error; err != nil { + return err + } + return nil + }) + if err != nil { + logger.Error(c, "注册失败!") + return serializer.ParamErr("注册失败", err) + } + return types.BuildUserResponse(user) +} + +// Create 创建用户 +func (s *SysUserService) Create(c *gin.Context) serializer.Response { + var user model.SysUser + if err := c.ShouldBind(&user); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + if user.Status == "" { + user.Status = Active + } + + now := time.Now() + user.CreateTime = &now + + createBy := c.GetString("id") + user.CreateBy = createBy + + id, err := SysSequenceServiceBuilder(user.TableName()).GenerateId() + if err != nil { + return serializer.DBErr("创建用户失败!", err) + } + user.UserId = id + + if err := s.Db.Create(&user).Error; err != nil { + logger.Error(c, "创建用户失败!") + return serializer.DBErr("创建用户失败!", err) + } + return serializer.Succ("创建用户成功!", user) +} + +// DeleteByID 根据ID删除用户 +func (s *SysUserService) DeleteByID(c *gin.Context) serializer.Response { + id := c.Param("id") + if id == "" { + logger.Error(c, "id 不可为空!") + } + + // 删除逻辑 + data := map[string]any{ + "del_flag": "1", + "update_time": time.Now(), + "update_by": c.GetString("id"), + } + + var user model.SysUser + if err := s.Db.Model(&user).Where("user_id = ?", id).Updates(data).Error; err != nil { + logger.Error(c, "未查询用户信息!") + return serializer.DBErr("删除用户失败!", err) + } + + return serializer.Succ("删除用户成功!", user) +} + +// UpdateByID 根据ID更新用户 +func (s *SysUserService) UpdateByID(c *gin.Context) serializer.Response { + var user model.SysUser + if err := c.ShouldBind(&user); err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + id := user.UserId + if id == "" { + logger.Error(c, "id 不可为空!") + return serializer.ParamErr("id不可为空!", fmt.Errorf("id不可为空")) + } + + if err := s.Db.Model(&user).Where("user_id = ?", id).Updates(&user).Error; err != nil { + logger.Error(c, "更新用户信息失败!") + return serializer.DBErr("更新用户信息失败!", err) + } + return serializer.Succ("更新用户信息成功!", user) +} + +// GetByID 根据ID获取用户 +func (s *SysUserService) GetByID(c *gin.Context) serializer.Response { + var user model.SysUser + if err := s.Db.Where("user_id = ?", c.Param("id")).First(&user).Error; err != nil { + logger.Error(c, "获取用户信息失败!") + return serializer.DBErr("获取用户信息失败!", err) + } + user.PassWord = "" // 清除密码 + return serializer.Succ("查询成功!", user) +} + +// DeleteByIDs 批量删除用户 +func (s *SysUserService) DeleteByIDs(c *gin.Context) serializer.Response { + var ids types.Payload + if err := c.ShouldBind(&ids); err != nil { + return serializer.ParamErr("参数绑定失败!", err) + } + + // 删除逻辑 + data := map[string]any{ + "del_flag": "1", + "update_time": time.Now(), + "update_by": c.GetString("id"), + } + + if err := s.Db.Model(&model.SysUser{}).Where("user_id in (?)", ids.Ids).Updates(data).Error; err != nil { + logger.Error(c, "批量删除用户失败!") + return serializer.DBErr("批量删除用户失败!", err) + } + return serializer.Succ("批量删除用户成功!", nil) +} + +// GetByCondition 条件查询用户 +func (s *SysUserService) GetByCondition(c *gin.Context) serializer.Response { + var p types.Params + if err := c.ShouldBind(&p); err != nil { + return serializer.ParamErr("参数绑定失败!", err) + } + + queryStr, args, err := p.ConvertToGormConditions() + if err != nil { + logger.Error(c, "参数绑定失败!") + return serializer.ParamErr("参数绑定失败!", err) + } + + var total int64 + var users []model.SysUser + offset := (p.Page - 1) * p.Limit + + // 构建基础查询 + db := s.Db.Model(&model.SysUser{}) + + // 如果有查询条件,添加条件 + if queryStr != "" { + db = db.Where(queryStr, args...) + } + + // 排序 + if p.Sort != "" { + db = db.Order(p.Sort) + } + + // 执行分页查询 + if err := db.Where("del_flag = ?", "0").Offset(offset).Limit(p.Limit).Find(&users).Error; err != nil { + logger.Error(c, "获取用户信息失败!") + return serializer.DBErr("获取用户信息失败!", err) + } + + // 清除所有用户的密码 + for i := range users { + users[i].PassWord = "" + } + + // 执行总数查询 + if err := db.Where("del_flag = ?", "0").Count(&total).Error; err != nil { + logger.Error(c, "获取用户总数失败!") + return serializer.DBErr("获取用户总数失败!", err) + } + + return serializer.Succ("查询成功!", gin.H{ + "total": total, + "items": users, + "page": p.Page, + "limit": p.Limit, + }) +} + +// ListByIDs 根据ID列表获取用户 +func (s *SysUserService) ListByIDs(c *gin.Context) serializer.Response { + var ids types.Payload + if err := c.ShouldBind(&ids); err != nil { + return serializer.ParamErr("参数绑定失败!", err) + } + + var users []model.SysUser + if err := s.Db.Where("user_id in (?)", ids.Ids).Find(&users).Error; err != nil { + logger.Error(c, "获取用户信息失败!") + return serializer.DBErr("获取用户信息失败!", err) + } + + // 清除所有用户的密码 + for i := range users { + users[i].PassWord = "" + } + + return serializer.Succ("查询成功!", users) +} + +// CurrentUser 获取当前用户 +func (s *SysUserService) CurrentUser(c *gin.Context) (*model.SysUser, error) { + tokenString := c.GetHeader("Authorization") + var user model.SysUser + token, err := util.ParseToken(tokenString[8:]) + if err != nil { + return nil, fmt.Errorf("获取当前用户失败! %v", err) + } + + id := token["id"].(string) + if err := s.Db.Model(&user).Where("user_id = ?", id).First(&user).Error; err != nil { + logger.Error(c, "获取当前用户失败!", zap.Error(err)) + return nil, err + } + // 清除密码 + user.PassWord = "" + return &user, nil +} diff --git a/internal/types/page.go b/internal/types/page.go new file mode 100644 index 0000000..7440b87 --- /dev/null +++ b/internal/types/page.go @@ -0,0 +1,100 @@ +package types + +import "strings" + +var defaultMaxSize = 1000 + +// SetMaxSize change the default maximum number of pages per page +func SetMaxSize(max int) { + if max < 10 { + max = 10 + } + defaultMaxSize = max +} + +// Page info +type Page struct { + page int // page number, starting from page 0 + limit int // number per page + sort string // sort fields, default is id backwards, you can add - sign before the field to indicate reverse order, no - sign to indicate ascending order, multiple fields separated by comma +} + +// Page get page value +func (p *Page) Page() int { + return p.page +} + +// Limit number per page +func (p *Page) Limit() int { + return p.limit +} + +// Size number per page +// Deprecated: use Limit instead +func (p *Page) Size() int { + return p.limit +} + +// Sort get sort field +func (p *Page) Sort() string { + return p.sort +} + +// Offset get offset value +func (p *Page) Offset() int { + return p.page * p.limit +} + +// DefaultPage default page, number 20 per page, sorted by id backwards +func DefaultPage(page int) *Page { + if page < 0 { + page = 0 + } + return &Page{ + page: page, + limit: 20, + sort: "id DESC", + } +} + +// NewPage custom page, starting from page 0. +// the parameter columnNames indicates a sort field, if empty means id descending, +// if there are multiple column names, separated by a comma, +// a '-' sign in front of each column name indicates descending order, otherwise ascending order. +func NewPage(page int, limit int, columnNames string) *Page { + if page < 0 { + page = 0 + } + if limit > defaultMaxSize || limit < 1 { + limit = defaultMaxSize + } + + return &Page{ + page: page, + limit: limit, + sort: getSort(columnNames), + } +} + +// convert to mysql sort, each column name preceded by a '-' sign, indicating descending order, otherwise ascending order, example: +// +// columnNames="name" means sort by name in ascending order, +// columnNames="-name" means sort by name descending, +// columnNames="name,age" means sort by name in ascending order, otherwise sort by age in ascending order, +// columnNames="-name,-age" means sort by name descending before sorting by age descending. +func getSort(columnNames string) string { + columnNames = strings.Replace(columnNames, " ", "", -1) + if columnNames == "" { + return "id DESC" + } + names := strings.Split(columnNames, ",") + strs := make([]string, 0, len(names)) + for _, name := range names { + if name[0] == '-' && len(name) > 1 { + strs = append(strs, name[1:]+" DESC") + } else { + strs = append(strs, name+" ASC") + } + } + return strings.Join(strs, ", ") +} diff --git a/internal/types/query_condition.go b/internal/types/query_condition.go new file mode 100644 index 0000000..aa55b38 --- /dev/null +++ b/internal/types/query_condition.go @@ -0,0 +1,525 @@ +package types + +import ( + "fmt" + "strings" +) + +const ( + // Eq 等于 + Eq = "eq" + // Neq 不等于 + Neq = "neq" + // Gt 大于 + Gt = "gt" + // Gte 大于等于 + Gte = "gte" + // Lt 小于 + Lt = "lt" + // Lte 小于等于 + Lte = "lte" + // Like 模糊查询 + Like = "like" + // In 包含 + In = "in" + // AND 逻辑与 + AND string = "and" + // OR 逻辑或 + OR string = "or" +) + +// expMap 表达式映射表,将查询条件转换为SQL表达式 +var expMap = map[string]string{ + Eq: " = ", + Neq: " <> ", + Gt: " > ", + Gte: " >= ", + Lt: " < ", + Lte: " <= ", + Like: " LIKE ", + In: " IN ", + + "=": " = ", + "!=": " <> ", + ">": " > ", + ">=": " >= ", + "<": " < ", + "<=": " <= ", +} + +// logicMap 逻辑运算符映射表,将逻辑运算符转换为SQL逻辑运算符 +var logicMap = map[string]string{ + AND: " AND ", + OR: " OR ", + + "&": " AND ", + "&&": " AND ", + "|": " OR ", + "||": " OR ", + "AND": " AND ", + "OR": " OR ", +} + +// Params 查询参数结构体 +type Params struct { + Page int `json:"page" form:"page" binding:"gte=0"` // 页码,从0开始 + Limit int `json:"limit" form:"limit" binding:"gte=10"` // 每页数量 + Sort string `json:"sort,omitempty" form:"sort" binding:""` // 排序字段 + Columns []Column `json:"columns,omitempty" form:"columns"` // 查询条件列表 +} + +// Column 查询条件结构体 +type Column struct { + Name string `json:"name" form:"name"` // 字段名 + Exp string `json:"exp" form:"exp"` // 表达式类型,默认为等于(=),支持 =, !=, >, >=, <, <=, like, in + Value any `json:"value" form:"value"` // 字段值 + Logic string `json:"logic" form:"logic"` // 逻辑运算符,默认为and,支持 &(and), ||(or) +} + +// checkValid 检查查询条件是否有效 +func (c *Column) checkValid() error { + if c.Name == "" { + return fmt.Errorf("字段名不能为空") + } + return nil +} + +// convert 将表达式类型和逻辑运算符转换为SQL语句 +func (c *Column) convert() error { + if c.Exp == "" { + c.Exp = Eq + } + if v, ok := expMap[strings.ToLower(c.Exp)]; ok { //nolint + c.Exp = v + if c.Exp == " LIKE " { + c.Value = fmt.Sprintf("%%%v%%", c.Value) + } + if c.Exp == " IN " { + val, ok := c.Value.(string) + if !ok { + return fmt.Errorf("IN查询的值类型无效: '%s'", c.Value) + } + var iVal []any + ss := strings.Split(val, ",") + for _, s := range ss { + iVal = append(iVal, s) + } + c.Value = iVal + } + } else { + return fmt.Errorf("未知的表达式类型: '%s'", c.Exp) + } + + if c.Logic == "" { + c.Logic = AND + } + if v, ok := logicMap[strings.ToLower(c.Logic)]; ok { //nolint + c.Logic = v + } else { + return fmt.Errorf("未知的逻辑运算符类型: '%s'", c.Logic) + } + + return nil +} + +// ConvertToPage 转换为分页参数 +func (p *Params) ConvertToPage() (order string, limit int, offset int) { //nolint + page := NewPage(p.Page, p.Limit, p.Sort) + order = page.sort + limit = page.limit + offset = page.page * page.limit + return //nolint +} + +// ConvertToGormConditions 将查询条件转换为GORM兼容的参数 +// 忽略最后一个条件的逻辑运算符,无论是单条件还是多条件查询 +func (p *Params) ConvertToGormConditions() (string, []any, error) { + str := "" + var args []any + var validColumns []Column + + // 过滤掉空值参数 + for _, column := range p.Columns { + if column.Value != nil && column.Value != "" { + validColumns = append(validColumns, column) + } + } + + l := len(validColumns) + if l == 0 { + return "", nil, nil + } + + isUseIN := true + if l == 1 { + isUseIN = false + } + field := validColumns[0].Name + + for i, column := range validColumns { + if err := column.checkValid(); err != nil { + return "", nil, err + } + + err := column.convert() + if err != nil { + return "", nil, err + } + + symbol := "?" + if column.Exp == " IN " { + symbol = "(?)" + } + if i == l-1 { // 忽略最后一个条件的逻辑运算符 + str += column.Name + column.Exp + symbol + } else { + str += column.Name + column.Exp + symbol + column.Logic + } + args = append(args, column.Value) + + // 当多个条件字段相同时,判断是否使用IN查询 + if isUseIN { + if field != column.Name { + isUseIN = false + continue + } + if column.Exp != expMap[Eq] { + isUseIN = false + } + } + } + + if isUseIN { + str = field + " IN (?)" + args = []any{args} + } + + return str, args, nil +} + +// Conditions 查询条件结构体 +type Conditions struct { + Columns []Column `json:"columns" form:"columns" binding:"min=1"` // 查询条件列表 +} + +// CheckValid 检查查询条件是否有效 +func (c *Conditions) CheckValid() error { + if len(c.Columns) == 0 { + return fmt.Errorf("查询条件不能为空") + } + + for _, column := range c.Columns { + err := column.checkValid() + if err != nil { + return err + } + if column.Exp != "" { + if _, ok := expMap[column.Exp]; !ok { + return fmt.Errorf("未知的表达式类型: '%s'", column.Exp) + } + } + if column.Logic != "" { + if _, ok := logicMap[column.Logic]; !ok { + return fmt.Errorf("未知的逻辑运算符类型: '%s'", column.Logic) + } + } + } + + return nil +} + +// ConvertToGorm 将查询条件转换为GORM兼容的参数 +// 忽略最后一个条件的逻辑运算符,无论是单条件还是多条件查询 +func (c *Conditions) ConvertToGorm() (string, []any, error) { + p := &Params{Columns: c.Columns} + return p.ConvertToGormConditions() +} + +// Payload 通用负载结构体 +type Payload struct { + Ids []string `json:"ids"` // ID列表 +} + +// QueryBuilder 查询构造器,提供链式调用方式 +type QueryBuilder struct { + params *Params +} + +// NewQueryBuilder 创建查询构造器 +func NewQueryBuilder() *QueryBuilder { + return &QueryBuilder{ + params: &Params{ + Page: 1, + Limit: 10, + Columns: make([]Column, 0), + }, + } +} + +// Page 设置页码 +func (qb *QueryBuilder) Page(page int) *QueryBuilder { + qb.params.Page = page + return qb +} + +// Limit 设置每页数量 +func (qb *QueryBuilder) Limit(limit int) *QueryBuilder { + qb.params.Limit = limit + return qb +} + +// Sort 设置排序 +func (qb *QueryBuilder) Sort(sort string) *QueryBuilder { + qb.params.Sort = sort + return qb +} + +// Eq 等于条件 +func (qb *QueryBuilder) Eq(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Eq, + Value: value, + Logic: AND, + }) + return qb +} + +// Like 模糊查询条件 +func (qb *QueryBuilder) Like(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Like, + Value: value, + Logic: AND, + }) + return qb +} + +// In 包含条件 +func (qb *QueryBuilder) In(name string, values ...any) *QueryBuilder { + var valueStr []string + for _, v := range values { + valueStr = append(valueStr, fmt.Sprintf("%v", v)) + } + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: In, + Value: strings.Join(valueStr, ","), + Logic: AND, + }) + return qb +} + +// Gt 大于条件 +func (qb *QueryBuilder) Gt(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Gt, + Value: value, + Logic: AND, + }) + return qb +} + +// Gte 大于等于条件 +func (qb *QueryBuilder) Gte(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Gte, + Value: value, + Logic: AND, + }) + return qb +} + +// Lt 小于条件 +func (qb *QueryBuilder) Lt(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Lt, + Value: value, + Logic: AND, + }) + return qb +} + +// Lte 小于等于条件 +func (qb *QueryBuilder) Lte(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Lte, + Value: value, + Logic: AND, + }) + return qb +} + +// Neq 不等于条件 +func (qb *QueryBuilder) Neq(name string, value any) *QueryBuilder { + qb.params.Columns = append(qb.params.Columns, Column{ + Name: name, + Exp: Neq, + Value: value, + Logic: AND, + }) + return qb +} + +// Or 设置最后一个条件为OR逻辑 +func (qb *QueryBuilder) Or() *QueryBuilder { + if len(qb.params.Columns) > 0 { + qb.params.Columns[len(qb.params.Columns)-1].Logic = OR + } + return qb +} + +// Build 构建查询参数 +func (qb *QueryBuilder) Build() *Params { + return qb.params +} + +// ToGormConditions 转换为GORM条件 +func (qb *QueryBuilder) ToGormConditions() (string, []any, error) { + return qb.params.ConvertToGormConditions() +} + +// URLQuery URL查询参数结构,支持通用的URL参数解析 +type URLQuery struct { + Page int `json:"page" form:"page" binding:"gte=0"` + Limit int `json:"limit" form:"limit" binding:"gte=10"` + Sort string `json:"sort,omitempty" form:"sort"` + Query string `json:"query,omitempty" form:"query"` // 通用查询字符串,格式:field1=value1&field2__like=value2 +} + +// ParseQuery 解析查询字符串为Params +func (uq *URLQuery) ParseQuery() (*Params, error) { + params := &Params{ + Page: uq.Page, + Limit: uq.Limit, + Sort: uq.Sort, + Columns: make([]Column, 0), + } + + if uq.Query == "" { + return params, nil + } + + // 简单的查询字符串解析,支持 field=value 和 field__exp=value 格式 + pairs := strings.Split(uq.Query, "&") + for _, pair := range pairs { + kv := strings.Split(pair, "=") + if len(kv) != 2 { + continue + } + + key := strings.TrimSpace(kv[0]) + value := strings.TrimSpace(kv[1]) + + if key == "" || value == "" { + continue + } + + // 支持特殊语法:字段名__操作符 + parts := strings.Split(key, "__") + fieldName := parts[0] + exp := Eq // 默认等于 + + if len(parts) > 1 { + switch parts[1] { + case "like": + exp = Like + case "gt": + exp = Gt + case "gte": + exp = Gte + case "lt": + exp = Lt + case "lte": + exp = Lte + case "neq": + exp = Neq + case "in": + exp = In + } + } + + params.Columns = append(params.Columns, Column{ + Name: fieldName, + Exp: exp, + Value: value, + Logic: AND, + }) + } + + return params, nil +} + +// ToGormConditions 转换为GORM条件 +func (uq *URLQuery) ToGormConditions() (string, []any, error) { + params, err := uq.ParseQuery() + if err != nil { + return "", nil, err + } + return params.ConvertToGormConditions() +} + +// KeyValueQuery 键值对查询结构,支持动态字段查询 +type KeyValueQuery struct { + Page int `json:"page" form:"page" binding:"gte=0"` + Limit int `json:"limit" form:"limit" binding:"gte=10"` + Sort string `json:"sort,omitempty" form:"sort"` + Conditions map[string]interface{} `json:"conditions,omitempty" form:"conditions"` // 动态查询条件 +} + +// ToParams 转换为标准Params结构 +func (kv *KeyValueQuery) ToParams() *Params { + params := &Params{ + Page: kv.Page, + Limit: kv.Limit, + Sort: kv.Sort, + Columns: make([]Column, 0), + } + + for key, value := range kv.Conditions { + if value != nil && value != "" { + // 支持特殊语法:字段名__操作符 + parts := strings.Split(key, "__") + fieldName := parts[0] + exp := Eq // 默认等于 + + if len(parts) > 1 { + switch parts[1] { + case "like": + exp = Like + case "gt": + exp = Gt + case "gte": + exp = Gte + case "lt": + exp = Lt + case "lte": + exp = Lte + case "neq": + exp = Neq + case "in": + exp = In + } + } + + params.Columns = append(params.Columns, Column{ + Name: fieldName, + Exp: exp, + Value: value, + Logic: AND, + }) + } + } + + return params +} + +// ToGormConditions 转换为GORM条件 +func (kv *KeyValueQuery) ToGormConditions() (string, []any, error) { + return kv.ToParams().ConvertToGormConditions() +} diff --git a/internal/types/user.go b/internal/types/user.go new file mode 100644 index 0000000..21644d6 --- /dev/null +++ b/internal/types/user.go @@ -0,0 +1,53 @@ +package types + +import ( + "ego/internal/model" + "ego/internal/serializer" + "net/http" +) + +// User 用户序列化器 +type User struct { + ID string `json:"id"` + UserName string `json:"userName"` + Nickname string `json:"nickName"` + Token string `json:"token"` + Status string `json:"status"` + Avatar string `json:"avatar"` + CreatedAt int64 `json:"createdAt"` +} + +// BuildUser 序列化用户 +func BuildUser(user model.SysUser) User { + return User{ + ID: user.UserId, + UserName: user.UserName, + Nickname: user.NickName, + Status: user.Status, + Avatar: user.Avatar, + CreatedAt: user.CreateTime.Unix(), + } +} + +// BuildUserHasToken BuildUser 序列化用户 +func BuildUserHasToken(user model.SysUser, token string) User { + return User{ + ID: user.UserId, + UserName: user.UserName, + Nickname: user.NickName, + Status: user.Status, + Avatar: user.Avatar, + CreatedAt: user.CreateTime.Unix(), + Token: token, + } +} + +// BuildUserResponse 序列化用户响应 +func BuildUserResponse(user model.SysUser) serializer.Response { + return serializer.Response{Code: http.StatusOK, Data: BuildUser(user)} +} + +// BuildUserResponseHasToken BuildUserResponse 序列化用户响应 +func BuildUserResponseHasToken(user model.SysUser, token string) serializer.Response { + return serializer.Response{Code: http.StatusOK, Msg: "登录成功!", Data: BuildUserHasToken(user, token)} +} diff --git a/internal/util/common.go b/internal/util/common.go new file mode 100644 index 0000000..e8ad186 --- /dev/null +++ b/internal/util/common.go @@ -0,0 +1,23 @@ +package util + +import ( + "math/rand" + "strings" + "time" +) + +// RandStringRunes 返回随机字符串 +func RandStringRunes(n int) string { + var letterRunes = []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + rand.NewSource(time.Now().UnixNano()) + b := make([]rune, n) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} + +// GenerateID 生成32位唯一ID +func GenerateID() string { + return strings.ToLower(RandStringRunes(32)) +} diff --git a/internal/util/jwt_utils.go b/internal/util/jwt_utils.go new file mode 100644 index 0000000..fbcd2f5 --- /dev/null +++ b/internal/util/jwt_utils.go @@ -0,0 +1,157 @@ +package util + +import ( + "ego/pkg/logger" + "fmt" + "os" + "sync" + "time" + + "github.com/golang-jwt/jwt/v4" + "go.uber.org/zap" +) + +const ( + TokenExpireTime = 24 * time.Hour // Token 过期时间(24小时) + // TokenGroup token + TokenGroup = "user_token:" +) + +var ( + // JwtKey JWT签名密钥 + JwtKey []byte + jwtKeyOnce sync.Once +) + +// Claims JWT声明结构 +type Claims struct { + ID string `json:"id"` + Username string `json:"username"` + jwt.RegisteredClaims +} + +// initJwtKey 懒加载方式初始化JWT密钥 +func initJwtKey() { + jwtKeyOnce.Do(func() { + secret := os.Getenv("JWT_SECRET") + if secret == "" { + secret = "default-jwt-secret-please-change-in-production" + // 注意:这里不能使用logger,因为可能还没初始化 + // 如果需要日志,在配置初始化完成后再输出 + } + JwtKey = []byte(secret) + }) +} + +// getJwtKey 获取JWT密钥,确保已初始化 +func getJwtKey() []byte { + initJwtKey() + return JwtKey +} + +// GenerateToken 生成JWT Token +func GenerateToken(id, username string) (string, error) { + if id == "" || username == "" { + return "", fmt.Errorf("用户ID和用户名不能为空") + } + + key := getJwtKey() + expireTime := time.Now().Add(TokenExpireTime) + + claims := &Claims{ + ID: id, + Username: username, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(expireTime), + IssuedAt: jwt.NewNumericDate(time.Now()), + NotBefore: jwt.NewNumericDate(time.Now()), + Issuer: "ego-system", + Subject: username, + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + tokenString, err := token.SignedString(key) + if err != nil { + // 安全地记录错误,如果logger已初始化 + if logger.Logger != nil { + logger.Error(nil, "JWT Token生成失败", zap.Error(err)) + } + return "", fmt.Errorf("token生成失败: %w", err) + } + + return tokenString, nil +} + +// ParseToken 解析JWT Token +func ParseToken(tokenString string) (jwt.MapClaims, error) { + if tokenString == "" { + return nil, fmt.Errorf("token不能为空") + } + + key := getJwtKey() + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("无效的签名方法: %v", token.Header["alg"]) + } + return key, nil + }) + + if err != nil { + // 安全地记录错误,如果logger已初始化 + if logger.Logger != nil { + logger.Error(nil, "JWT Token解析失败", zap.Error(err)) + } + return nil, fmt.Errorf("token解析失败: %w", err) + } + + if !token.Valid { + return nil, fmt.Errorf("token无效或已过期") + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return nil, fmt.Errorf("token claims格式错误") + } + + return claims, nil +} + +// ValidateToken 验证Token有效性 +func ValidateToken(tokenString string) (*Claims, error) { + if tokenString == "" { + return nil, fmt.Errorf("token不能为空") + } + + key := getJwtKey() + token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (any, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("无效的签名方法: %v", token.Header["alg"]) + } + return key, nil + }) + + if err != nil { + // 安全地记录错误,如果logger已初始化 + if logger.Logger != nil { + logger.Error(nil, "JWT Token验证失败", zap.Error(err)) + } + return nil, fmt.Errorf("token验证失败: %w", err) + } + + if claims, ok := token.Claims.(*Claims); ok && token.Valid { + return claims, nil + } + + return nil, fmt.Errorf("token无效") +} + +// LogJwtKeyStatus 在配置初始化完成后输出JWT密钥状态日志 +func LogJwtKeyStatus() { + secret := os.Getenv("JWT_SECRET") + if secret == "" { + logger.Warn(nil, "使用默认JWT密钥,生产环境请设置JWT_SECRET环境变量") + } else { + logger.Info(nil, "JWT密钥已从环境变量加载") + } +} diff --git a/internal/util/redis_util.go b/internal/util/redis_util.go new file mode 100644 index 0000000..547479b --- /dev/null +++ b/internal/util/redis_util.go @@ -0,0 +1,76 @@ +package util + +import ( + "ego/pkg/logger" + "time" + + "github.com/gin-gonic/gin" + + "ego/internal/cache" + + "github.com/redis/go-redis/v9" + "go.uber.org/zap" +) + +// Set 设置键值对到Redis +func Set(ctx *gin.Context, key string, value any, expiration time.Duration) error { + err := cache.RedisClient.Set(ctx, key, value, expiration).Err() + if err != nil { + logger.Error(ctx, "Redis Set 失败", zap.Error(err)) + return err + } + return nil +} + +// Get 从Redis获取键值对 +func Get(ctx *gin.Context, key string) (string, error) { + val, err := cache.RedisClient.Get(ctx, key).Result() + if err == redis.Nil { + logger.Info(ctx, "Redis key 不存在", zap.String("key", key)) + return "", nil + } else if err != nil { + logger.Error(ctx, "Redis Get 失败", zap.Error(err)) + return "", err + } + return val, nil +} + +// Del 从Redis删除键 +func Del(ctx *gin.Context, key string) error { + err := cache.RedisClient.Del(ctx, key).Err() + if err != nil { + logger.Error(ctx, "Redis Del 失败", zap.Error(err)) + return err + } + return nil +} + +// Exists 检查Redis中是否存在键 +func Exists(ctx *gin.Context, key string) (bool, error) { + val, err := cache.RedisClient.Exists(ctx, key).Result() + if err != nil { + logger.Error(ctx, "Redis Exists 失败", zap.Error(err)) + return false, err + } + return val > 0, nil +} + +// Incr 对Redis中的键进行自增操作 +func Incr(ctx *gin.Context, key string) (int64, error) { + val, err := cache.RedisClient.Incr(ctx, key).Result() + if err != nil { + logger.Error(ctx, "Redis Incr 失败", zap.Error(err)) + return 0, err + } + return val, nil +} + +// Decr 对Redis中的键进行自减操作 +func Decr(ctx *gin.Context, key string) (int64, error) { + val, err := cache.RedisClient.Decr(ctx, key).Result() + if err != nil { + logger.Error(ctx, "Redis Decr 失败", zap.Error(err)) + return 0, err + } + return val, nil +} diff --git a/internal/util/string_utils.go b/internal/util/string_utils.go new file mode 100644 index 0000000..281898d --- /dev/null +++ b/internal/util/string_utils.go @@ -0,0 +1,13 @@ +package util + +import "strings" + +// TrimSpaces 去除字符串两端的空格 +func TrimSpaces(s string) string { + return strings.ReplaceAll(s, " ", "") +} + +// IsStringEmpty 判断字符串是否为空 +func IsStringEmpty(s string) bool { + return TrimSpaces(s) == "" +} diff --git a/internal/util/user_agent.go b/internal/util/user_agent.go new file mode 100644 index 0000000..6a57557 --- /dev/null +++ b/internal/util/user_agent.go @@ -0,0 +1,38 @@ +package util + +import ( + "strings" +) + +// ParseUserAgent 解析User-Agent字符串,返回操作系统信息 +func ParseUserAgent(userAgent string) string { + if userAgent == "" { + return "未知" + } + + userAgent = strings.ToLower(userAgent) + + // 操作系统判断 + switch { + case strings.Contains(userAgent, "windows"): + return "Windows" + case strings.Contains(userAgent, "macintosh") || strings.Contains(userAgent, "mac os x"): + return "MacOS" + case strings.Contains(userAgent, "linux"): + return "Linux" + case strings.Contains(userAgent, "android"): + return "Android" + case strings.Contains(userAgent, "iphone") || strings.Contains(userAgent, "ipad") || strings.Contains(userAgent, "ipod"): + return "iOS" + case strings.Contains(userAgent, "freebsd"): + return "FreeBSD" + case strings.Contains(userAgent, "openbsd"): + return "OpenBSD" + case strings.Contains(userAgent, "netbsd"): + return "NetBSD" + case strings.Contains(userAgent, "sunos"): + return "Solaris" + default: + return "未知" + } +} diff --git a/internal/wire/wire.go b/internal/wire/wire.go new file mode 100644 index 0000000..baeff72 --- /dev/null +++ b/internal/wire/wire.go @@ -0,0 +1,70 @@ +//go:build wireinject +// +build wireinject + +// The build tag makes sure the stub is not built in the final build. +package wire + +import ( + "ego/internal/conf" + "ego/internal/handler" + "ego/internal/service" + + "github.com/google/wire" +) + +// DBSet 提供数据库连接 +var DBSet = wire.NewSet( + conf.NewDb, // 依赖 conf 包的 NewDb +) + +// HandlerSet 处理器集合 +var HandlerSet = wire.NewSet( + handler.NewSysUserHandler, + handler.NewSysLoginLogHandler, + handler.NewSysUploadHandler, + handler.NewSysDeployFileHandler, +) + +// UserServiceSet 定义 service 层依赖 +var UserServiceSet = wire.NewSet( + service.NewSysUserService, +) + +// LoginLogServiceSet 服务器信息服务层依赖 +var LoginLogServiceSet = wire.NewSet( + service.NewSysLoginLogService, +) + +// UploadServiceSet 文件上传服务层依赖 +var UploadServiceSet = wire.NewSet( + service.NewSysUploadService, +) + +// DeployFileServiceSet 部署文件服务层依赖 +var DeployFileServiceSet = wire.NewSet( + service.NewSysDeployFileService, +) + +// InjectSysUserHandler 注入 handler +func InjectSysUserHandler() *handler.SysUserHandler { + panic(wire.Build( + HandlerSet, + UserServiceSet, + DBSet, + )) +} + +// InjectSysLoginLogHandler 注入登录记录信息处理器 +func InjectSysLoginLogHandler() *handler.SysLoginLogHandler { + panic(wire.Build(HandlerSet, LoginLogServiceSet, DBSet)) +} + +// InjectSysUploadHandler 注入文件上传处理器 +func InjectSysUploadHandler() *handler.SysUploadHandler { + panic(wire.Build(HandlerSet, UploadServiceSet, DBSet)) +} + +// InjectSysDeployFileHandler 注入部署文件处理器 +func InjectSysDeployFileHandler() *handler.SysDeployFileHandler { + panic(wire.Build(HandlerSet, DeployFileServiceSet, DBSet)) +} diff --git a/logs/ego.20250716.log b/logs/ego.20250716.log new file mode 100644 index 0000000..f36d503 --- /dev/null +++ b/logs/ego.20250716.log @@ -0,0 +1,104 @@ +{"level":"info","ts":"2025-07-16 13:54:37.697","caller":"sync/once.go:76","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-07-16 13:54:37.792","caller":"conf/db.go:92","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-07-16 13:54:37.871","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-07-16 13:54:37.871","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-07-16 13:54:37.871","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-07-16 13:54:37.872","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-07-16 13:54:37.872","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-07-16 13:54:37.873","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-07-16 13:54:37.873","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-07-16 13:54:44.112","caller":"ego/main.go:93","msg":"服务器关闭完成"} +{"level":"info","ts":"2025-07-16 13:58:18.971","caller":"sync/once.go:76","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-07-16 13:58:19.104","caller":"conf/db.go:92","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-07-16 13:58:19.157","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 13:58:21.145","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-07-16 13:58:21.146","caller":"ego/main.go:93","msg":"服务器关闭完成"} +{"level":"info","ts":"2025-07-16 14:18:56.26","caller":"sync/once.go:76","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-07-16 14:18:56.401","caller":"conf/db.go:92","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-07-16 14:18:56.464","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-07-16 14:18:56.464","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-07-16 14:18:56.464","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-07-16 14:18:56.464","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-07-16 14:18:56.464","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-07-16 14:18:56.465","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:18:56.465","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:21:00.48","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"60125fcd-186e-402e-b8cc-e0a56984cf7a","method":"POST","path":"/:3000127.0.0.1/upload/zip","status":404,"duration":0,"trackID":"60125fcd-186e-402e-b8cc-e0a56984cf7a"} +{"level":"info","ts":"2025-07-16 14:21:00.559","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001178","trackID":"60125fcd-186e-402e-b8cc-e0a56984cf7a"} +{"level":"info","ts":"2025-07-16 14:22:03.926","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"ca81f555-f462-4133-a957-01ff3beff525","method":"POST","path":"/:3000127.0.0.1/api/v1/upload/zip","status":404,"duration":0,"trackID":"ca81f555-f462-4133-a957-01ff3beff525"} +{"level":"info","ts":"2025-07-16 14:22:03.957","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001179","trackID":"ca81f555-f462-4133-a957-01ff3beff525"} +{"level":"info","ts":"2025-07-16 14:23:27.959","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-07-16 14:23:27.96","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-07-16 14:23:27.961","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-07-16 14:23:27.961","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-07-16 14:23:27.962","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:23:27.962","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:23:27.962","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-07-16 14:23:27.962","caller":"ego/main.go:93","msg":"服务器关闭完成"} +{"level":"info","ts":"2025-07-16 14:23:32.987","caller":"sync/once.go:76","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-07-16 14:23:33.148","caller":"conf/db.go:92","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-07-16 14:23:33.204","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-07-16 14:23:33.204","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-07-16 14:23:33.204","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-07-16 14:23:33.204","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-07-16 14:23:33.204","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-07-16 14:23:33.205","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:23:33.205","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:23:36.633","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"5cf28fd2-49d3-4784-80d3-78fa745ab292","method":"POST","path":"/:3000127.0.0.1/api/v1/upload/zip","status":404,"duration":0,"trackID":"5cf28fd2-49d3-4784-80d3-78fa745ab292"} +{"level":"info","ts":"2025-07-16 14:23:36.741","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001180","trackID":"5cf28fd2-49d3-4784-80d3-78fa745ab292"} +{"level":"info","ts":"2025-07-16 14:23:48.474","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-07-16 14:23:48.474","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-07-16 14:23:48.474","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-07-16 14:23:48.474","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-07-16 14:23:48.475","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:23:48.475","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:23:48.475","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-07-16 14:23:48.475","caller":"ego/main.go:93","msg":"服务器关闭完成"} +{"level":"info","ts":"2025-07-16 14:24:31.605","caller":"sync/once.go:76","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-07-16 14:24:31.728","caller":"conf/db.go:92","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-07-16 14:24:31.774","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-07-16 14:24:31.774","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-07-16 14:24:31.774","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-07-16 14:24:31.774","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-07-16 14:24:31.775","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-07-16 14:24:31.775","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:24:31.775","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-07-16 14:25:05.982","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"76d2a5f2-dd16-40a4-8bdb-9acff8c5f873","method":"POST","path":"/:3000127.0.0.1/api/v1/upload/zip","status":404,"duration":15.5752447,"trackID":"76d2a5f2-dd16-40a4-8bdb-9acff8c5f873"} +{"level":"info","ts":"2025-07-16 14:25:06.018","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001181","trackID":"76d2a5f2-dd16-40a4-8bdb-9acff8c5f873"} +{"level":"error","ts":"2025-07-16 14:26:13.328","caller":"service/sys_user_service.go:62","msg":"参数绑定错误!","error":"EOF","trackID":"64311c08-a64d-4658-84df-fe8c9037c417"} +{"level":"info","ts":"2025-07-16 14:26:13.419","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"64311c08-a64d-4658-84df-fe8c9037c417","method":"POST","path":"/api/v1/user/login","status":200,"duration":2.4723363,"trackID":"64311c08-a64d-4658-84df-fe8c9037c417"} +{"level":"info","ts":"2025-07-16 14:26:13.452","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001182","trackID":"64311c08-a64d-4658-84df-fe8c9037c417"} +{"level":"info","ts":"2025-07-16 14:26:48.039","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"8dc8c313-3973-46f6-9b20-2428288b3a8e","method":"POST","path":"/api/v1/upload/zip","status":200,"duration":2.6992122,"trackID":"8dc8c313-3973-46f6-9b20-2428288b3a8e"} +{"level":"info","ts":"2025-07-16 14:26:48.071","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001183","trackID":"8dc8c313-3973-46f6-9b20-2428288b3a8e"} +{"level":"error","ts":"2025-07-16 14:27:57.545","caller":"service/sys_upload_service.go:46","msg":"目标文件夹已存在!","trackID":"92742f89-9afd-4f1e-8cee-50ab55c547df"} +{"level":"info","ts":"2025-07-16 14:27:57.545","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"92742f89-9afd-4f1e-8cee-50ab55c547df","method":"POST","path":"/api/v1/upload/zip","status":200,"duration":15.0455176,"trackID":"92742f89-9afd-4f1e-8cee-50ab55c547df"} +{"level":"info","ts":"2025-07-16 14:27:57.605","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001184","trackID":"92742f89-9afd-4f1e-8cee-50ab55c547df"} +{"level":"error","ts":"2025-07-16 14:28:09.967","caller":"service/sys_upload_service.go:46","msg":"目标文件夹已存在!","trackID":"3f6df601-8965-4f4a-b791-7ba07e076ada"} +{"level":"info","ts":"2025-07-16 14:28:09.967","caller":"middleware/zap_log.go:25","msg":"Handled request","trackID":"3f6df601-8965-4f4a-b791-7ba07e076ada","method":"POST","path":"/api/v1/upload/zip","status":200,"duration":1.9901575,"trackID":"3f6df601-8965-4f4a-b791-7ba07e076ada"} +{"level":"info","ts":"2025-07-16 14:28:10","caller":"service/sys_oper_log_service.go:167","msg":"保存操作日志成功","OperId":"SOL0000001185","trackID":"3f6df601-8965-4f4a-b791-7ba07e076ada"} +{"level":"info","ts":"2025-07-16 14:29:42.669","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-07-16 14:29:42.669","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-07-16 14:29:42.669","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-07-16 14:29:42.67","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-07-16 14:29:42.67","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:29:42.67","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-07-16 14:29:42.67","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-07-16 14:29:42.67","caller":"ego/main.go:93","msg":"服务器关闭完成"} diff --git a/logs/ego.20250801.log b/logs/ego.20250801.log new file mode 100644 index 0000000..d74221f --- /dev/null +++ b/logs/ego.20250801.log @@ -0,0 +1,17 @@ +{"level":"info","ts":"2025-08-01 16:14:47.443","caller":"sync/once.go:78","msg":"日志系统初始化成功","log_path":"./logs/","log_level":"info"} +{"level":"info","ts":"2025-08-01 16:14:47.69","caller":"conf/db.go:91","msg":"数据库连接成功","connString":"***已遮盖敏感信息***","maxOpenConns":20,"maxIdleConns":10} +{"level":"info","ts":"2025-08-01 16:14:47.783","caller":"cache/cache.go:76","msg":"Redis连接成功","address":"www.suyun.store:6379","db":0,"pool_size":20,"read_timeout":3} +{"level":"info","ts":"2025-08-01 16:14:47.783","caller":"util/jwt_utils.go:155","msg":"JWT密钥已从环境变量加载"} +{"level":"info","ts":"2025-08-01 16:14:47.783","caller":"conf/conf.go:57","msg":"所有配置初始化完成"} +{"level":"info","ts":"2025-08-01 16:14:47.783","caller":"ego/main.go:44","msg":"Gin模式设置完成","mode":"test"} +{"level":"info","ts":"2025-08-01 16:14:47.784","caller":"middleware/cors.go:63","msg":"跨域配置初始化完成","允许方法":["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"],"允许头":["Origin","Content-Length","Content-Type","Cookie","Authorization","X-Requested-With","X-CSRF-Token"],"允许来源":[],"MaxAge":43200,"模式":"test"} +{"level":"info","ts":"2025-08-01 16:14:47.784","caller":"ego/main.go:70","msg":"服务器启动成功","addr":":3000"} +{"level":"info","ts":"2025-08-01 16:14:47.784","caller":"ego/main.go:63","msg":"服务器启动中...","addr":":3000"} +{"level":"info","ts":"2025-08-01 16:14:52.21","caller":"ego/main.go:77","msg":"收到关闭信号,开始优雅关闭服务器..."} +{"level":"info","ts":"2025-08-01 16:14:52.21","caller":"ego/main.go:87","msg":"HTTP服务器已优雅关闭"} +{"level":"info","ts":"2025-08-01 16:14:52.21","caller":"conf/conf.go:63","msg":"开始关闭应用程序资源..."} +{"level":"info","ts":"2025-08-01 16:14:52.211","caller":"conf/conf.go:69","msg":"数据库已关闭"} +{"level":"info","ts":"2025-08-01 16:14:52.211","caller":"cache/cache.go:93","msg":"Redis已关闭"} +{"level":"info","ts":"2025-08-01 16:14:52.211","caller":"conf/conf.go:76","msg":"Redis已关闭"} +{"level":"info","ts":"2025-08-01 16:14:52.211","caller":"conf/conf.go:79","msg":"应用程序资源关闭完成"} +{"level":"info","ts":"2025-08-01 16:14:52.211","caller":"ego/main.go:93","msg":"服务器关闭完成"} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..603a323 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,170 @@ +package logger + +import ( + "fmt" + "log" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + rotatelogs "github.com/lestrrat-go/file-rotatelogs" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +const ( + TRACKED = "trackID" +) + +var ( + Logger *zap.Logger + loggerMux sync.Once + CallerSkip = 2 + initErr error +) + +// BuildLogger 初始化日志系统 +func BuildLogger() error { + loggerMux.Do(func() { + initErr = initLogger() + }) + return initErr +} + +// initLogger 实际的日志初始化逻辑 +func initLogger() error { + logLevel := getLogLevel() + logPath := os.Getenv("LOG_PATH") + if logPath == "" { + logPath = "./logs" // 默认日志路径 + } + + // 尝试创建日志目录 + if err := os.MkdirAll(logPath, 0755); err != nil { + // 使用标准库的log记录错误,因为zap还没初始化 + log.Printf("无法创建日志目录 %s: %v", logPath, err) + return fmt.Errorf("无法创建日志目录 %s: %w", logPath, err) + } + + // 配置滚动日志(按天滚动,保留28天) + logFileName := filepath.Join(logPath, "ego.%Y%m%d.log") + logs, err := rotatelogs.New( + logFileName, + rotatelogs.WithMaxAge(28*24*time.Hour), + rotatelogs.WithRotationTime(24*time.Hour), + ) + if err != nil { + log.Printf("创建滚动日志失败: %v", err) + return fmt.Errorf("创建滚动日志失败: %w", err) + } + + // 配置控制台输出 + consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()) + consoleSyncer := zapcore.AddSync(os.Stdout) + + // 配置文件输出(生产环境JSON格式) + prodEncoderConfig := zap.NewProductionEncoderConfig() + prodEncoderConfig.EncodeTime = TimeEncoder + prodEncoderConfig.CallerKey = "caller" + prodEncoderConfig.EncodeCaller = zapcore.ShortCallerEncoder + prodEncoder := zapcore.NewJSONEncoder(prodEncoderConfig) + fileSyncer := zapcore.AddSync(logs) + + // 创建日志核心 + core := zapcore.NewTee( + zapcore.NewCore(consoleEncoder, consoleSyncer, logLevel), + zapcore.NewCore(prodEncoder, fileSyncer, logLevel), + ) + + // 初始化 Logger + Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(CallerSkip)) + + // 记录初始化成功 + Logger.Info("日志系统初始化成功", + zap.String("log_path", logPath), + zap.String("log_level", logLevel.String()), + ) + + return nil +} + +// Debug 记录调试日志 +func Debug(c *gin.Context, msg string, fields ...zap.Field) { + if Logger != nil { + logWithTrack(c, zap.DebugLevel, msg, fields...) + } +} + +// Info 记录信息日志 +func Info(c *gin.Context, msg string, fields ...zap.Field) { + if Logger != nil { + logWithTrack(c, zap.InfoLevel, msg, fields...) + } +} + +// Warn 记录警告日志 +func Warn(c *gin.Context, msg string, fields ...zap.Field) { + if Logger != nil { + logWithTrack(c, zap.WarnLevel, msg, fields...) + } +} + +// Error 记录错误日志 +func Error(c *gin.Context, msg string, fields ...zap.Field) { + if Logger != nil { + logWithTrack(c, zap.ErrorLevel, msg, fields...) + } +} + +// logWithTrack 封装带 trackID 的日志记录 +func logWithTrack(c *gin.Context, level zapcore.Level, msg string, fields ...zap.Field) { + if Logger == nil { + return + } + + if c == nil { + Logger.Check(level, msg).Write(fields...) + return + } + trackID := GetTrackID(c) + Logger.Check(level, msg).Write(append(fields, zap.String("trackID", trackID))...) +} + +// GetTrackID 获取或生成 trackID +func GetTrackID(c *gin.Context) string { + if trackID, exists := c.Get(TRACKED); exists { + return trackID.(string) + } + if random, err := uuid.NewRandom(); err == nil { + // 生成新的 trackID 并存入上下文 + newTrackID := strings.ToLower(random.String()) + c.Set(TRACKED, newTrackID) + return newTrackID + } + return "" +} + +// getLogLevel 根据环境变量获取日志级别 +func getLogLevel() zapcore.Level { + switch strings.ToLower(os.Getenv("LOG_LEVEL")) { + case "debug": + return zap.DebugLevel + case "info": + return zap.InfoLevel + case "warn": + return zap.WarnLevel + case "error": + return zap.ErrorLevel + default: + return zap.InfoLevel // 默认使用 Info 级别 + } +} + +// TimeEncoder 自定义时间格式 +func TimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format("2006-01-02 15:04:05.999")) +} diff --git a/scripts/generate_swagger.bat b/scripts/generate_swagger.bat new file mode 100644 index 0000000..391f785 --- /dev/null +++ b/scripts/generate_swagger.bat @@ -0,0 +1,5 @@ +@echo off +echo 生成 Swagger 文档... + + +echo 生成完成! diff --git a/scripts/generate_swagger.sh b/scripts/generate_swagger.sh new file mode 100644 index 0000000..de0b35e --- /dev/null +++ b/scripts/generate_swagger.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo 生成 Swagger 文档... + + +echo 生成完成! diff --git a/sql/deploy_file.sql b/sql/deploy_file.sql new file mode 100644 index 0000000..d7160c3 --- /dev/null +++ b/sql/deploy_file.sql @@ -0,0 +1,57 @@ +-- 部署文件记录表 +CREATE TABLE `sys_deploy_file` ( + `deploy_id` varchar(64) NOT NULL COMMENT '部署ID', + `file_name` varchar(255) NOT NULL COMMENT '原始文件名', + `project_name` varchar(100) NOT NULL COMMENT '项目名称', + `domain` varchar(255) NOT NULL COMMENT '访问域名', + `deploy_path` varchar(500) NOT NULL COMMENT '部署路径', + `file_size` bigint DEFAULT NULL COMMENT '文件大小(字节)', + `file_hash` varchar(64) DEFAULT NULL COMMENT '文件哈希值', + `status` char(1) DEFAULT '1' COMMENT '状态(0停用 1正常 2部署中 3部署失败)', + `deploy_status` char(1) DEFAULT '0' COMMENT '部署状态(0未部署 1部署成功 2部署失败)', + `error_msg` text COMMENT '错误信息', + `version` varchar(50) DEFAULT NULL COMMENT '版本号', + `description` varchar(500) DEFAULT NULL COMMENT '描述', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + `create_by` varchar(64) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deploy_time` datetime DEFAULT NULL COMMENT '部署时间', + `last_access_time` datetime DEFAULT NULL COMMENT '最后访问时间', + `access_count` bigint DEFAULT '0' COMMENT '访问次数', + PRIMARY KEY (`deploy_id`), + KEY `idx_project_name` (`project_name`), + KEY `idx_domain` (`domain`), + KEY `idx_status` (`status`), + KEY `idx_deploy_status` (`deploy_status`), + KEY `idx_create_time` (`create_time`), + KEY `idx_del_flag` (`del_flag`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='部署文件记录表'; + +-- 插入示例数据 +INSERT INTO `sys_deploy_file` ( + `deploy_id`, + `file_name`, + `project_name`, + `domain`, + `deploy_path`, + `file_size`, + `status`, + `deploy_status`, + `description`, + `create_by`, + `create_time` +) VALUES ( + 'DEPLOY001', + 'my-project-v1.0.0.zip', + 'my-project', + 'my-project.unbug.cn', + '/home/my-project', + 1048576, + '1', + '1', + '示例项目部署文件', + 'admin', + NOW() +); \ No newline at end of file diff --git a/sql/login_log.sql b/sql/login_log.sql new file mode 100644 index 0000000..c2b1644 --- /dev/null +++ b/sql/login_log.sql @@ -0,0 +1,56 @@ +create table if not exists ego.sys_login_log +( + id + varchar +( + 64 +) not null comment '访问ID' primary key, + user_id varchar +( + 64 +) default '' null comment '用户ID', + ip_addr varchar +( + 128 +) default '' null comment '登录IP地址', + login_location varchar +( + 255 +) default '' null comment '登录地点', + browser varchar +( + 50 +) default '' null comment '浏览器类型', + os varchar +( + 50 +) default '' null comment '操作系统', + status varchar +( + 10 +) default '0' null comment '登录状态(0成功 1失败)', + msg varchar +( + 255 +) default '' null comment '提示消息', + login_time datetime null comment '登录时间', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注' + ) comment '系统访问记录' charset = utf8mb3; + +-- 创建索引 +create index idx_user_id on ego.sys_login_log (user_id); +create index idx_login_time on ego.sys_login_log (login_time); +create index idx_status on ego.sys_login_log (status); diff --git a/sql/system.sql b/sql/system.sql new file mode 100644 index 0000000..3d36217 --- /dev/null +++ b/sql/system.sql @@ -0,0 +1,638 @@ +create table if not exists ego.sys_config +( + config_id + varchar +( + 64 +) not null comment '参数主键' + primary key, + config_name varchar +( + 100 +) default '' null comment '参数名称', + config_key varchar +( + 100 +) default '' null comment '参数键名', + config_value varchar +( + 500 +) default '' null comment '参数键值', + config_type char default 'N' null comment '系统内置(Y是 N否)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注' + ) + comment '参数配置表' charset = utf8mb3; + +create table if not exists ego.sys_dept +( + dept_id + varchar +( + 64 +) not null comment '部门id' + primary key, + parent_id varchar(64) default '0' null comment '父部门id', + ancestors varchar +( + 50 +) default '' null comment '祖级列表', + dept_name varchar +( + 30 +) default '' null comment '部门名称', + order_num int default 0 null comment '显示顺序', + leader varchar +( + 20 +) null comment '负责人', + phone varchar +( + 11 +) null comment '联系电话', + email varchar +( + 50 +) null comment '邮箱', + status char default '0' null comment '部门状态(0正常 1停用)', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间' + ) + comment '部门表' charset = utf8mb3; + +create table if not exists ego.sys_dict_data +( + dict_code + varchar +( + 64 +) not null comment '字典编码' + primary key, + dict_sort int default 0 null comment '字典排序', + dict_label varchar +( + 100 +) default '' null comment '字典标签', + dict_value varchar +( + 100 +) default '' null comment '字典键值', + dict_type varchar +( + 100 +) default '' null comment '字典类型', + css_class varchar +( + 100 +) null comment '样式属性(其他样式扩展)', + list_class varchar +( + 100 +) null comment '表格回显样式', + is_default char default 'N' null comment '是否默认(Y是 N否)', + status char default '0' null comment '状态(0正常 1停用)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注' + ) + comment '字典数据表' charset = utf8mb3; + +create table if not exists ego.sys_dict_type +( + dict_id + varchar +( + 64 +) not null comment '字典主键' + primary key, + dict_name varchar +( + 100 +) default '' null comment '字典名称', + dict_type varchar +( + 100 +) default '' null comment '字典类型', + status char default '0' null comment '状态(0正常 1停用)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注', + constraint dict_type + unique +( + dict_type +) + ) + comment '字典类型表' charset = utf8mb3; + +create table if not exists ego.sys_file +( + id + varchar +( + 64 +) not null comment '主键' + primary key, + file_name varchar +( + 128 +) not null comment '文件名称', + file_type varchar +( + 32 +) null comment '文件类型', + file_size bigint null comment '文件大小', + file_key varchar +( + 128 +) null comment '文件Key', + type varchar +( + 4 +) null comment '业务类型', + business_id varchar +( + 64 +) null comment '业务主键', + business_type varchar +( + 32 +) null comment '业务类型', + del_flag varchar(32) default '0' null comment '是否删除', + revision int default 0 null comment '乐观锁', + create_by varchar +( + 32 +) null comment '创建人', + create_time datetime null comment '创建时间', + update_by varchar +( + 32 +) null comment '更新人', + update_time datetime null comment '更新时间' + ) + comment 'sys_file 文件表' charset = utf8mb3; + +create index businessId_index + on ego.sys_file (business_id); + +create table if not exists ego.sys_job +( + job_id varchar(64) not null comment '任务ID', + job_name varchar(64) default '' not null comment '任务名称', + job_group varchar(64) default 'DEFAULT' not null comment '任务组名', + invoke_target varchar(500) not null comment '调用目标字符串', + cron_expression varchar +( + 255 +) default '' null comment 'cron执行表达式', + misfire_policy varchar +( + 20 +) default '3' null comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + concurrent char default '1' null comment '是否并发执行(0允许 1禁止)', + status char default '0' null comment '状态(0正常 1暂停)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) default '' null comment '备注信息', + primary key (job_id, job_name, job_group) + ) + comment '定时任务调度表' charset = utf8mb3; + +create table if not exists ego.sys_job_log +( + job_log_id + varchar +( + 64 +) not null comment '任务日志ID' + primary key, + job_name varchar +( + 64 +) not null comment '任务名称', + job_group varchar +( + 64 +) not null comment '任务组名', + invoke_target varchar +( + 500 +) not null comment '调用目标字符串', + job_message varchar +( + 500 +) null comment '日志信息', + status char default '0' null comment '执行状态(0正常 1失败)', + exception_info varchar +( + 2000 +) default '' null comment '异常信息', + create_time datetime null comment '创建时间' + ) + comment '定时任务调度日志表' charset = utf8mb3; + +create table if not exists ego.sys_logininfor +( + info_id + varchar +( + 64 +) not null comment '访问ID' + primary key, + user_name varchar +( + 50 +) default '' null comment '用户账号', + ipaddr varchar +( + 128 +) default '' null comment '登录IP地址', + login_location varchar +( + 255 +) default '' null comment '登录地点', + browser varchar +( + 50 +) default '' null comment '浏览器类型', + os varchar +( + 50 +) default '' null comment '操作系统', + status char default '0' null comment '登录状态(0成功 1失败)', + msg varchar +( + 1024 +) default '' null comment '提示消息', + login_time datetime null comment '访问时间' + ) + comment '系统访问记录' charset = utf8mb3; + +create table if not exists ego.sys_menu +( + menu_id + varchar +( + 64 +) not null comment '菜单ID' + primary key, + menu_name varchar +( + 50 +) not null comment '菜单名称', + parent_id varchar(64) default '0' null comment '父菜单ID', + order_num int default 0 null comment '显示顺序', + path varchar +( + 200 +) default '' null comment '路由地址', + component varchar +( + 255 +) null comment '组件路径', + query varchar +( + 255 +) null comment '路由参数', + is_frame char(2) default '1' null comment '是否为外链(0是 1否)', + is_cache char(2) default '0' null comment '是否缓存(0缓存 1不缓存)', + menu_type char default '' null comment '菜单类型(M目录 C菜单 F按钮)', + visible char default '0' null comment '菜单状态(0显示 1隐藏)', + status char default '0' null comment '菜单状态(0正常 1停用)', + perms varchar +( + 100 +) null comment '权限标识', + icon varchar(100) default '#' null comment '菜单图标', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) default '' null comment '备注' + ) + comment '菜单权限表' charset = utf8mb3; + +create table if not exists ego.sys_notice +( + notice_id + varchar +( + 64 +) not null comment '公告ID' + primary key, + notice_title varchar +( + 50 +) not null comment '公告标题', + notice_type char not null comment '公告类型(1通知 2公告)', + notice_content longtext null comment '公告内容', + status char default '0' null comment '公告状态(0正常 1关闭)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 255 +) null comment '备注' + ) + comment '通知公告表' charset = utf8mb3; + +create table if not exists ego.sys_oper_log +( + oper_id + varchar +( + 64 +) not null comment '日志主键' + primary key, + title varchar(50) default '' null comment '模块标题', + business_type int default 0 null comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' null comment '方法名称', + request_method varchar(64) default '' null comment '请求方式', + operator_type int default 0 null comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' null comment '操作人员', + dept_name varchar(50) default '' null comment '部门名称', + oper_url varchar(255) default '' null comment '请求URL', + oper_ip varchar(128) default '' null comment '主机地址', + oper_location varchar(255) default '' null comment '操作地点', + oper_param varchar(2000) default '' null comment '请求参数', + json_result varchar(2000) default '' null comment '返回参数', + status int default 0 null comment '操作状态(0正常 1异常)', + error_msg varchar(2000) default '' null comment '错误消息', + oper_time datetime null comment '操作时间' + ) + comment '操作日志记录' charset = utf8mb3; + +create table if not exists ego.sys_post +( + post_id + varchar +( + 64 +) not null comment '岗位ID' + primary key, + post_code varchar +( + 64 +) not null comment '岗位编码', + post_name varchar +( + 50 +) not null comment '岗位名称', + post_sort int not null comment '显示顺序', + status char not null comment '状态(0正常 1停用)', + create_by varchar(64) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar(64) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注' + ) + comment '岗位信息表' charset = utf8mb3; + +create table if not exists ego.sys_role +( + role_id + varchar +( + 64 +) not null comment '角色ID' + primary key, + role_name varchar +( + 30 +) not null comment '角色名称', + role_key varchar +( + 100 +) not null comment '角色权限字符串', + role_sort int not null comment '显示顺序', + data_scope char default '1' null comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + menu_check_strictly tinyint(1) default 1 null comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 null comment '部门树选择项是否关联显示', + status char not null comment '角色状态(0正常 1停用)', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注' + ) + comment '角色信息表' charset = utf8mb3; + +create table if not exists ego.sys_role_dept +( + role_id varchar(64) not null comment '角色ID', + dept_id varchar(64) not null comment '部门ID', + primary key (role_id, dept_id) + ) + comment '角色和部门关联表' charset = utf8mb3; + +create table if not exists ego.sys_role_menu +( + role_id varchar(64) not null comment '角色ID', + menu_id varchar(64) not null comment '菜单ID', + primary key (role_id, menu_id) + ) + comment '角色和菜单关联表' charset = utf8mb3; + +create table if not exists ego.sys_sequence +( + table_name varchar(32) not null comment '表名', + seq int not null comment '序列', + prefix varchar(32) not null comment '前缀', + primary key (table_name, seq, prefix) + ) + comment '系统序列表' charset = utf8mb3; + +create table if not exists ego.sys_user +( + user_id + varchar +( + 64 +) not null comment '用户ID' + primary key, + dept_id varchar +( + 64 +) null comment '部门ID', + user_name varchar +( + 30 +) not null comment '用户账号', + nick_name varchar +( + 30 +) not null comment '用户昵称', + user_type varchar(2) default '00' null comment '用户类型(00系统用户)', + email varchar +( + 50 +) default '' null comment '用户邮箱', + phone_number varchar +( + 11 +) default '' null comment '手机号码', + solt int null comment '排序', + gender char default '0' null comment '用户性别(0男 1女 2未知)', + avatar varchar +( + 100 +) default '' null comment '头像地址', + pass_word varchar +( + 100 +) default '' null comment '密码', + status char default '0' null comment '帐号状态(0正常 1停用)', + del_flag char default '0' null comment '删除标志(0代表存在 2代表删除)', + login_ip varchar +( + 128 +) default '' null comment '最后登录IP', + login_date datetime null comment '最后登录时间', + resource_invoke varchar +( + 255 +) null comment '资源来源映射,多个用,分割', + create_by varchar +( + 64 +) default '' null comment '创建者', + create_time datetime null comment '创建时间', + update_by varchar +( + 64 +) default '' null comment '更新者', + update_time datetime null comment '更新时间', + remark varchar +( + 500 +) null comment '备注', + select_key varchar +( + 64 +) null comment '动态验证' + ) + comment '用户信息表' charset = utf8mb3; + +create table if not exists ego.sys_user_post +( + user_id varchar(64) not null comment '用户ID', + post_id varchar(64) not null comment '岗位ID', + primary key (user_id, post_id) + ) + comment '用户与岗位关联表' charset = utf8mb3; + +create table if not exists ego.sys_user_role +( + user_id varchar(64) not null comment '用户ID', + role_id varchar(64) not null comment '角色ID', + primary key (user_id, role_id) + ) + comment '用户和角色关联表' charset = utf8mb3; + +create +definer = root@`%` function ego.CURRVAL(seq_name varchar(30)) returns varchar(50) deterministic +BEGIN + DECLARE +seq_val INT; + DECLARE +prefix_val VARCHAR(32); +SELECT seq, prefix +INTO seq_val, prefix_val +FROM sys_sequence +WHERE table_name = seq_name; +RETURN concat(prefix_val, LPAD(seq_val, 10, '0')); +END; + +create +definer = root@`%` function ego.NEXTVAL(seq_name varchar(30)) returns varchar(30) deterministic +BEGIN +UPDATE sys_sequence +SET SEQ = SEQ + 1 +WHERE TABLE_NAME = seq_name; +RETURN CURRVAL(seq_name); +END;