From 1a0a01a56dc056255ed736116535c17b3346f50f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=96=87=E5=B3=B0?= Date: Wed, 1 Apr 2026 12:09:02 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=97=E4=BA=86=EF=BC=8C=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E6=88=91=E8=87=AA=E5=B7=B1=E5=86=99=E5=90=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .workbuddy/expert-history.json | 11 +- .workbuddy/memory/2026-04-01.md | 21 + .workbuddy/memory/MEMORY.md | 4 +- backend/{ => ai_work}/.gitignore | 0 backend/{ => ai_work}/ARCHITECTURE.md | 0 backend/{ => ai_work}/api/main.go | 0 backend/{ => ai_work}/api/v1/routes.go | 42 +- backend/{ => ai_work}/build.sh | 0 .../{ => ai_work}/defConfig/configTemp.yaml | 0 .../{ => ai_work}/defConfig/errorCodes.json | 0 backend/{ => ai_work}/fresh.sh | 0 backend/{ => ai_work}/go.mod | 0 backend/{ => ai_work}/go.sum | 0 backend/{ => ai_work}/install.sh | 0 .../{ => ai_work}/internal/config/config.go | 0 .../internal/database/connection.go | 0 .../internal/database/migration.go | 0 .../internal/handler/auth_handler.go | 0 .../internal/handler/file_handler.go | 0 .../internal/handler/purchase_handler.go | 0 .../{ => ai_work}/internal/handler/utils.go | 0 .../{ => ai_work}/internal/middleware/auth.go | 0 .../{ => ai_work}/internal/middleware/cors.go | 0 .../internal/middleware/logging.go | 0 .../internal/repository/file_repository.go | 0 .../repository/purchase_repository.go | 0 .../internal/repository/user_repository.go | 0 .../internal/service/auth_service.go | 0 .../internal/service/file_service.go | 0 .../internal/service/purchase_service.go | 0 backend/{cmd/ops-server => ai_work}/main.go | 63 +- backend/{ => ai_work}/migrate-config.py | 0 backend/{ => ai_work}/models/configs.go | 0 backend/{ => ai_work}/models/def.go | 0 backend/{ => ai_work}/models/file.go | 0 backend/{ => ai_work}/models/log.go | 0 backend/{ => ai_work}/models/sql.go | 0 .../{ => ai_work}/pkg/response/response.go | 0 backend/{ => ai_work}/routers/api.go | 0 backend/{ => ai_work}/routers/apiPurchase.go | 0 backend/{ => ai_work}/routers/apiStatic.go | 0 backend/{ => ai_work}/routers/apiUsers.go | 0 backend/{ => ai_work}/routers/api_Files.go | 0 backend/{ => ai_work}/routers/return.go | 0 backend/ai_work/run-dev.bat | 13 + backend/ai_work/runner.conf | 14 + backend/{ => ai_work}/start-dev.bat | 5 +- backend/my_work/.gitignore | 19 + backend/my_work/build.sh | 18 + backend/my_work/defConfig/configTemp.yaml | 57 ++ backend/my_work/defConfig/errorCodes.json | 23 + backend/my_work/fresh.sh | 4 + backend/my_work/go.mod | 62 ++ backend/my_work/go.sum | 144 +++++ backend/my_work/install.sh | 62 ++ backend/{ => my_work}/main.go | 0 backend/my_work/models/configs.go | 57 ++ backend/my_work/models/def.go | 108 ++++ backend/my_work/models/file.go | 58 ++ backend/my_work/models/log.go | 50 ++ backend/my_work/models/sql.go | 167 ++++++ backend/my_work/routers/api.go | 62 ++ backend/my_work/routers/apiPurchase.go | 179 ++++++ backend/my_work/routers/apiStatic.go | 25 + backend/my_work/routers/apiUsers.go | 541 ++++++++++++++++++ backend/my_work/routers/api_Files.go | 174 ++++++ backend/my_work/routers/return.go | 46 ++ backend/run-dev.bat | 20 - frontend/ops_vue_js/vite.config.js | 2 +- 69 files changed, 1949 insertions(+), 102 deletions(-) create mode 100644 .workbuddy/memory/2026-04-01.md rename backend/{ => ai_work}/.gitignore (100%) rename backend/{ => ai_work}/ARCHITECTURE.md (100%) rename backend/{ => ai_work}/api/main.go (100%) rename backend/{ => ai_work}/api/v1/routes.go (79%) rename backend/{ => ai_work}/build.sh (100%) rename backend/{ => ai_work}/defConfig/configTemp.yaml (100%) rename backend/{ => ai_work}/defConfig/errorCodes.json (100%) rename backend/{ => ai_work}/fresh.sh (100%) rename backend/{ => ai_work}/go.mod (100%) rename backend/{ => ai_work}/go.sum (100%) rename backend/{ => ai_work}/install.sh (100%) rename backend/{ => ai_work}/internal/config/config.go (100%) rename backend/{ => ai_work}/internal/database/connection.go (100%) rename backend/{ => ai_work}/internal/database/migration.go (100%) rename backend/{ => ai_work}/internal/handler/auth_handler.go (100%) rename backend/{ => ai_work}/internal/handler/file_handler.go (100%) rename backend/{ => ai_work}/internal/handler/purchase_handler.go (100%) rename backend/{ => ai_work}/internal/handler/utils.go (100%) rename backend/{ => ai_work}/internal/middleware/auth.go (100%) rename backend/{ => ai_work}/internal/middleware/cors.go (100%) rename backend/{ => ai_work}/internal/middleware/logging.go (100%) rename backend/{ => ai_work}/internal/repository/file_repository.go (100%) rename backend/{ => ai_work}/internal/repository/purchase_repository.go (100%) rename backend/{ => ai_work}/internal/repository/user_repository.go (100%) rename backend/{ => ai_work}/internal/service/auth_service.go (100%) rename backend/{ => ai_work}/internal/service/file_service.go (100%) rename backend/{ => ai_work}/internal/service/purchase_service.go (100%) rename backend/{cmd/ops-server => ai_work}/main.go (77%) rename backend/{ => ai_work}/migrate-config.py (100%) rename backend/{ => ai_work}/models/configs.go (100%) rename backend/{ => ai_work}/models/def.go (100%) rename backend/{ => ai_work}/models/file.go (100%) rename backend/{ => ai_work}/models/log.go (100%) rename backend/{ => ai_work}/models/sql.go (100%) rename backend/{ => ai_work}/pkg/response/response.go (100%) rename backend/{ => ai_work}/routers/api.go (100%) rename backend/{ => ai_work}/routers/apiPurchase.go (100%) rename backend/{ => ai_work}/routers/apiStatic.go (100%) rename backend/{ => ai_work}/routers/apiUsers.go (100%) rename backend/{ => ai_work}/routers/api_Files.go (100%) rename backend/{ => ai_work}/routers/return.go (100%) create mode 100644 backend/ai_work/run-dev.bat create mode 100644 backend/ai_work/runner.conf rename backend/{ => ai_work}/start-dev.bat (87%) create mode 100644 backend/my_work/.gitignore create mode 100644 backend/my_work/build.sh create mode 100644 backend/my_work/defConfig/configTemp.yaml create mode 100644 backend/my_work/defConfig/errorCodes.json create mode 100644 backend/my_work/fresh.sh create mode 100644 backend/my_work/go.mod create mode 100644 backend/my_work/go.sum create mode 100644 backend/my_work/install.sh rename backend/{ => my_work}/main.go (100%) create mode 100644 backend/my_work/models/configs.go create mode 100644 backend/my_work/models/def.go create mode 100644 backend/my_work/models/file.go create mode 100644 backend/my_work/models/log.go create mode 100644 backend/my_work/models/sql.go create mode 100644 backend/my_work/routers/api.go create mode 100644 backend/my_work/routers/apiPurchase.go create mode 100644 backend/my_work/routers/apiStatic.go create mode 100644 backend/my_work/routers/apiUsers.go create mode 100644 backend/my_work/routers/api_Files.go create mode 100644 backend/my_work/routers/return.go delete mode 100644 backend/run-dev.bat diff --git a/.workbuddy/expert-history.json b/.workbuddy/expert-history.json index 0d05dee..4b7f073 100644 --- a/.workbuddy/expert-history.json +++ b/.workbuddy/expert-history.json @@ -2,6 +2,15 @@ "version": 2, "sessions": { "c9d5673cc5a442d4afa0a2e7805acb2d": [ + { + "expertId": "BackendArchitect", + "name": "Joy", + "profession": "后端架构师", + "avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/BackendArchitect/BackendArchitect.png", + "promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/BackendArchitect/BackendArchitect_zh.md", + "usedAt": 1775015316468, + "industryId": "all" + }, { "expertId": "SeniorDeveloper", "name": "Will", @@ -13,5 +22,5 @@ } ] }, - "lastUpdated": 1774965668803 + "lastUpdated": 1775015525304 } \ No newline at end of file diff --git a/.workbuddy/memory/2026-04-01.md b/.workbuddy/memory/2026-04-01.md new file mode 100644 index 0000000..82a9d94 --- /dev/null +++ b/.workbuddy/memory/2026-04-01.md @@ -0,0 +1,21 @@ +# 2026-04-01 工作日志 + +## 修复 SQLite CGO 启动报错 ✅ (11:20) + +- **问题**:fresh 启动时报 `CGO_ENABLED=0` 导致 go-sqlite3 无法工作 +- **原因**:fresh 不是通过 run-dev.bat 启动,没有继承 `CGO_ENABLED=1` 环境变量 +- **修复**: + - 更新 `run-dev.bat`:改为用 fresh 启动,并确保 `set CGO_ENABLED=1` 在 fresh 之前执行 + - 更新 `start-dev.bat`:同样加上 `set CGO_ENABLED=1` + - 创建 `runner.conf`(fresh 配置文件) +- **正确启动方式**:在 backend/ 目录执行 `.\run-dev.bat`,或 PowerShell 中设置 `$env:CGO_ENABLED="1"` 后 `go run .` +- **GCC 问题**:已安装 TDM-GCC v10.3.0 +- **Fresh 问题**:runner-build.exe 缓存损坏,已清理并改用 `go run .` 启动 + +## 后端入口迁移:cmd/ops-server/main.go → 根目录 main.go ✅ (11:05) + +- 将新架构 `cmd/ops-server/main.go` 内容合并到根目录 `backend/main.go` +- 删除 `cmd/` 目录 +- 更新 `run-dev.bat` 和 `start-dev.bat` 启动命令从 `go run ./cmd/ops-server/main.go` 改为 `go run .` +- 编译验证通过(0 errors) +- 现在直接在 `backend/` 目录下运行 `go run .` 即可启动 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index cd9c0fc..d7a5a49 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -93,7 +93,7 @@ - **统一API响应**:标准错误码映射和响应格式 - **模块化路由系统**:API v1 版本路由定义清晰分离 - **新目录结构**: - - `cmd/ops-server/main.go` - 应用入口 + - `main.go` - 应用入口(已从 cmd/ops-server/main.go 合并至根目录,2026-04-01) - `internal/config/` - 配置管理 - `internal/database/` - 数据库连接和迁移 - `internal/handler/` - HTTP处理器(auth_handler.go, purchase_handler.go) @@ -112,7 +112,7 @@ - ✅ **编译状态**:项目编译成功(需要CGO_ENABLED=1以支持SQLite) ### 新路由架构(2026-03-31) -- **主入口**:`cmd/ops-server/main.go` - 现代化主入口,支持优雅关机 +- **主入口**:`main.go`(根目录)- 现代化主入口,支持优雅关机 - **路由配置**:`api/`包统一管理所有路由 - **兼容性**:完全兼容现有前端API `/api/*` - **新增API**:RESTful API v1 `/api/v1/*` diff --git a/backend/.gitignore b/backend/ai_work/.gitignore similarity index 100% rename from backend/.gitignore rename to backend/ai_work/.gitignore diff --git a/backend/ARCHITECTURE.md b/backend/ai_work/ARCHITECTURE.md similarity index 100% rename from backend/ARCHITECTURE.md rename to backend/ai_work/ARCHITECTURE.md diff --git a/backend/api/main.go b/backend/ai_work/api/main.go similarity index 100% rename from backend/api/main.go rename to backend/ai_work/api/main.go diff --git a/backend/api/v1/routes.go b/backend/ai_work/api/v1/routes.go similarity index 79% rename from backend/api/v1/routes.go rename to backend/ai_work/api/v1/routes.go index b98444d..0756f40 100644 --- a/backend/api/v1/routes.go +++ b/backend/ai_work/api/v1/routes.go @@ -38,27 +38,6 @@ func RegisterRoutes(r *gin.RouterGroup) { // 静态文件路由 - 保持兼容性 r.StaticFS("/static", http.Dir("./dist")) - // 兼容旧版文件路由(保持前端兼容性) - r.GET("/files/:mode/:hash", func(c *gin.Context) { - mode := c.Param("mode") - - if mode == "get" || mode == "download" { - download := (mode == "download") - // 直接调用handler的GetFile/DownloadFile方法 - if download { - fileHandler.DownloadFile(c) - } else { - fileHandler.GetFile(c) - } - } else { - c.JSON(http.StatusBadRequest, gin.H{ - "code": "-2", - "message": "无效的文件模式", - "data": nil, - }) - } - }) - // 用户认证相关路由 userGroup := r.Group("/users") { @@ -81,20 +60,13 @@ func RegisterRoutes(r *gin.RouterGroup) { } // 文件上传管理 - v1 API - fileGroup := r.Group("/files") - { - // 上传文件 - fileGroup.POST("/upload", middleware.AuthToken(), fileHandler.UploadFile) - - // 文件列表管理 - fileGroup.GET("/list", middleware.AuthToken(), fileHandler.GetFileList) - fileGroup.GET("/:id", middleware.AuthToken(), fileHandler.GetFileByID) - fileGroup.DELETE("/:id", middleware.AuthToken(), fileHandler.DeleteFile) - - // 文件访问 - fileGroup.GET("/download/:hash", fileHandler.DownloadFile) - fileGroup.GET("/get/:hash", fileHandler.GetFile) - } + // 注意:具体路由必须放在通配路由之前 + r.POST("/files/upload", middleware.AuthToken(), fileHandler.UploadFile) + r.GET("/files/list", middleware.AuthToken(), fileHandler.GetFileList) + r.GET("/files/:id", middleware.AuthToken(), fileHandler.GetFileByID) + r.DELETE("/files/:id", middleware.AuthToken(), fileHandler.DeleteFile) + r.GET("/files/download/:hash", fileHandler.DownloadFile) + r.GET("/files/get/:hash", fileHandler.GetFile) // 采购订单管理 purchaseGroup := r.Group("/purchase") diff --git a/backend/build.sh b/backend/ai_work/build.sh similarity index 100% rename from backend/build.sh rename to backend/ai_work/build.sh diff --git a/backend/defConfig/configTemp.yaml b/backend/ai_work/defConfig/configTemp.yaml similarity index 100% rename from backend/defConfig/configTemp.yaml rename to backend/ai_work/defConfig/configTemp.yaml diff --git a/backend/defConfig/errorCodes.json b/backend/ai_work/defConfig/errorCodes.json similarity index 100% rename from backend/defConfig/errorCodes.json rename to backend/ai_work/defConfig/errorCodes.json diff --git a/backend/fresh.sh b/backend/ai_work/fresh.sh similarity index 100% rename from backend/fresh.sh rename to backend/ai_work/fresh.sh diff --git a/backend/go.mod b/backend/ai_work/go.mod similarity index 100% rename from backend/go.mod rename to backend/ai_work/go.mod diff --git a/backend/go.sum b/backend/ai_work/go.sum similarity index 100% rename from backend/go.sum rename to backend/ai_work/go.sum diff --git a/backend/install.sh b/backend/ai_work/install.sh similarity index 100% rename from backend/install.sh rename to backend/ai_work/install.sh diff --git a/backend/internal/config/config.go b/backend/ai_work/internal/config/config.go similarity index 100% rename from backend/internal/config/config.go rename to backend/ai_work/internal/config/config.go diff --git a/backend/internal/database/connection.go b/backend/ai_work/internal/database/connection.go similarity index 100% rename from backend/internal/database/connection.go rename to backend/ai_work/internal/database/connection.go diff --git a/backend/internal/database/migration.go b/backend/ai_work/internal/database/migration.go similarity index 100% rename from backend/internal/database/migration.go rename to backend/ai_work/internal/database/migration.go diff --git a/backend/internal/handler/auth_handler.go b/backend/ai_work/internal/handler/auth_handler.go similarity index 100% rename from backend/internal/handler/auth_handler.go rename to backend/ai_work/internal/handler/auth_handler.go diff --git a/backend/internal/handler/file_handler.go b/backend/ai_work/internal/handler/file_handler.go similarity index 100% rename from backend/internal/handler/file_handler.go rename to backend/ai_work/internal/handler/file_handler.go diff --git a/backend/internal/handler/purchase_handler.go b/backend/ai_work/internal/handler/purchase_handler.go similarity index 100% rename from backend/internal/handler/purchase_handler.go rename to backend/ai_work/internal/handler/purchase_handler.go diff --git a/backend/internal/handler/utils.go b/backend/ai_work/internal/handler/utils.go similarity index 100% rename from backend/internal/handler/utils.go rename to backend/ai_work/internal/handler/utils.go diff --git a/backend/internal/middleware/auth.go b/backend/ai_work/internal/middleware/auth.go similarity index 100% rename from backend/internal/middleware/auth.go rename to backend/ai_work/internal/middleware/auth.go diff --git a/backend/internal/middleware/cors.go b/backend/ai_work/internal/middleware/cors.go similarity index 100% rename from backend/internal/middleware/cors.go rename to backend/ai_work/internal/middleware/cors.go diff --git a/backend/internal/middleware/logging.go b/backend/ai_work/internal/middleware/logging.go similarity index 100% rename from backend/internal/middleware/logging.go rename to backend/ai_work/internal/middleware/logging.go diff --git a/backend/internal/repository/file_repository.go b/backend/ai_work/internal/repository/file_repository.go similarity index 100% rename from backend/internal/repository/file_repository.go rename to backend/ai_work/internal/repository/file_repository.go diff --git a/backend/internal/repository/purchase_repository.go b/backend/ai_work/internal/repository/purchase_repository.go similarity index 100% rename from backend/internal/repository/purchase_repository.go rename to backend/ai_work/internal/repository/purchase_repository.go diff --git a/backend/internal/repository/user_repository.go b/backend/ai_work/internal/repository/user_repository.go similarity index 100% rename from backend/internal/repository/user_repository.go rename to backend/ai_work/internal/repository/user_repository.go diff --git a/backend/internal/service/auth_service.go b/backend/ai_work/internal/service/auth_service.go similarity index 100% rename from backend/internal/service/auth_service.go rename to backend/ai_work/internal/service/auth_service.go diff --git a/backend/internal/service/file_service.go b/backend/ai_work/internal/service/file_service.go similarity index 100% rename from backend/internal/service/file_service.go rename to backend/ai_work/internal/service/file_service.go diff --git a/backend/internal/service/purchase_service.go b/backend/ai_work/internal/service/purchase_service.go similarity index 100% rename from backend/internal/service/purchase_service.go rename to backend/ai_work/internal/service/purchase_service.go diff --git a/backend/cmd/ops-server/main.go b/backend/ai_work/main.go similarity index 77% rename from backend/cmd/ops-server/main.go rename to backend/ai_work/main.go index 3d6aa2e..9ae653e 100644 --- a/backend/cmd/ops-server/main.go +++ b/backend/ai_work/main.go @@ -51,36 +51,45 @@ func main() { gin.SetMode(gin.ReleaseMode) } - // 创建Gin实例(使用自定义logger) + // 创建Gin实例 r := gin.New() // 注册中间件 r.Use(middleware.CORS()) - + // 根据环境选择日志中间件 if config.Current.Web.Host == "127.0.0.1" || config.Current.Web.Host == "localhost" { - // 开发环境使用简易日志 r.Use(middleware.SimpleLogger()) } else { - // 生产环境使用高级日志 r.Use(middleware.Logger(logger)) } - + r.Use(middleware.Recovery(logger)) // 注册API路由 - registerRoutes(r, logger) + api.RegisterAllRoutes(r) - // 静态文件服务中间件(由api.CreateRouter处理) - // 这里仅创建dist目录(如果不存在) + // 健康检查端点 + r.GET("/health", func(c *gin.Context) { + c.JSON(200, gin.H{ + "code": "0", + "message": "Server is healthy", + "data": gin.H{ + "timestamp": time.Now().Unix(), + "status": "running", + "version": "1.0.0", + }, + }) + }) + + // 确保dist目录存在 ensureDistDirectory(logger) // 启动HTTP服务器 addr := fmt.Sprintf("%s:%s", config.Current.Web.Host, config.Current.Web.Port) srv := &http.Server{ - Addr: addr, - Handler: r, - // 优化服务器配置 + Addr: addr, + Handler: r, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, @@ -110,40 +119,11 @@ func main() { logger.Info("Server exited") } -// 注册API路由 -func registerRoutes(r *gin.Engine, logger *zap.Logger) { - // 使用我们的路由配置 - api.RegisterAllRoutes(r) - - // 健康检查端点(额外添加) - r.GET("/health", func(c *gin.Context) { - c.JSON(200, gin.H{ - "code": "0", - "message": "Server is healthy", - "data": gin.H{ - "timestamp": time.Now().Unix(), - "status": "running", - "version": "1.0.0", - }, - }) - }) -} - -// 兼容性路由,保持原有API结构 -// 注意:此函数现在由api包统一处理,此函数保留作为参考 -func compatRoutes(api *gin.RouterGroup, logger *zap.Logger) { - logger.Info("兼容性路由由api包统一管理") -} - -// 静态文件服务(已迁移到api包) - -// 创建日志记录器 +// createLogger 创建日志记录器 func createLogger() (*zap.Logger, error) { - // 开发环境使用开发配置 if gin.Mode() == gin.DebugMode { return zap.NewDevelopment() } - // 生产环境使用生产配置 return zap.NewProduction() } @@ -157,4 +137,3 @@ func ensureDistDirectory(logger *zap.Logger) { } } } - diff --git a/backend/migrate-config.py b/backend/ai_work/migrate-config.py similarity index 100% rename from backend/migrate-config.py rename to backend/ai_work/migrate-config.py diff --git a/backend/models/configs.go b/backend/ai_work/models/configs.go similarity index 100% rename from backend/models/configs.go rename to backend/ai_work/models/configs.go diff --git a/backend/models/def.go b/backend/ai_work/models/def.go similarity index 100% rename from backend/models/def.go rename to backend/ai_work/models/def.go diff --git a/backend/models/file.go b/backend/ai_work/models/file.go similarity index 100% rename from backend/models/file.go rename to backend/ai_work/models/file.go diff --git a/backend/models/log.go b/backend/ai_work/models/log.go similarity index 100% rename from backend/models/log.go rename to backend/ai_work/models/log.go diff --git a/backend/models/sql.go b/backend/ai_work/models/sql.go similarity index 100% rename from backend/models/sql.go rename to backend/ai_work/models/sql.go diff --git a/backend/pkg/response/response.go b/backend/ai_work/pkg/response/response.go similarity index 100% rename from backend/pkg/response/response.go rename to backend/ai_work/pkg/response/response.go diff --git a/backend/routers/api.go b/backend/ai_work/routers/api.go similarity index 100% rename from backend/routers/api.go rename to backend/ai_work/routers/api.go diff --git a/backend/routers/apiPurchase.go b/backend/ai_work/routers/apiPurchase.go similarity index 100% rename from backend/routers/apiPurchase.go rename to backend/ai_work/routers/apiPurchase.go diff --git a/backend/routers/apiStatic.go b/backend/ai_work/routers/apiStatic.go similarity index 100% rename from backend/routers/apiStatic.go rename to backend/ai_work/routers/apiStatic.go diff --git a/backend/routers/apiUsers.go b/backend/ai_work/routers/apiUsers.go similarity index 100% rename from backend/routers/apiUsers.go rename to backend/ai_work/routers/apiUsers.go diff --git a/backend/routers/api_Files.go b/backend/ai_work/routers/api_Files.go similarity index 100% rename from backend/routers/api_Files.go rename to backend/ai_work/routers/api_Files.go diff --git a/backend/routers/return.go b/backend/ai_work/routers/return.go similarity index 100% rename from backend/routers/return.go rename to backend/ai_work/routers/return.go diff --git a/backend/ai_work/run-dev.bat b/backend/ai_work/run-dev.bat new file mode 100644 index 0000000..85ff223 --- /dev/null +++ b/backend/ai_work/run-dev.bat @@ -0,0 +1,13 @@ +@echo off +REM OPS Backend 开发服务器启动脚本 +REM 设置 CGO 和 GCC 路径 +set CGO_ENABLED=1 +set PATH=C:\TDM-GCC-64\bin;%PATH% + +cd /d %~dp0 + +echo Starting OPS Backend (with auto-reload)... +echo. + +REM 使用 gin 自动重载(比 fresh 更稳定) +go run . -port 8080 diff --git a/backend/ai_work/runner.conf b/backend/ai_work/runner.conf new file mode 100644 index 0000000..0a59606 --- /dev/null +++ b/backend/ai_work/runner.conf @@ -0,0 +1,14 @@ +root: . +tmp_path: ./tmp +build_name: runner-build +build_log: runner-build-errors.log +valid_ext: .go, .tpl, .tmpl, .html +no_rebuild_ext: .tpl, .tmpl, .html +ignored: assets, tmp, vendor, frontend, dist +build_delay: 600 +colors: 1 +log_color_main: cyan +log_color_build: yellow +log_color_runner: green +log_color_watcher: magenta +log_color_app: diff --git a/backend/start-dev.bat b/backend/ai_work/start-dev.bat similarity index 87% rename from backend/start-dev.bat rename to backend/ai_work/start-dev.bat index 854c98e..fa9b2d8 100644 --- a/backend/start-dev.bat +++ b/backend/ai_work/start-dev.bat @@ -8,9 +8,12 @@ if not exist "./dist" ( echo. ) +REM SQLite 需要 CGO +set CGO_ENABLED=1 + REM 运行新的重构版本 echo Running new refactored backend... echo. -go run ./cmd/ops-server/main.go +go run . pause \ No newline at end of file diff --git a/backend/my_work/.gitignore b/backend/my_work/.gitignore new file mode 100644 index 0000000..cb8585c --- /dev/null +++ b/backend/my_work/.gitignore @@ -0,0 +1,19 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +.DS_Store +/dist +/data +/tmp + +/build + +/test + +*.db + +OPSYS \ No newline at end of file diff --git a/backend/my_work/build.sh b/backend/my_work/build.sh new file mode 100644 index 0000000..8988b7a --- /dev/null +++ b/backend/my_work/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +APP_NAME="OPSYS" +APP_PATH="./build/$APP_NAME" + +# 编译应用 +echo "编译应用..." +CGO_ENABLED=0 GOOS=linux go build -o $APP_NAME -ldflags="-s -w" main.go + +# 创建目录 +echo "创建目录..." +sudo mkdir -p $APP_PATH + +# 复制文件 +echo "复制文件..." +sudo cp $APP_NAME $APP_PATH/ +sudo cp -r defConfig $APP_PATH/ +sudo cp -r dist $APP_PATH/ diff --git a/backend/my_work/defConfig/configTemp.yaml b/backend/my_work/defConfig/configTemp.yaml new file mode 100644 index 0000000..3338148 --- /dev/null +++ b/backend/my_work/defConfig/configTemp.yaml @@ -0,0 +1,57 @@ +version: "0.3.1" + +web: + host: "127.0.0.1" + port: "8080" + tls: false + certPrivatePath: "" + certPublicPath: "" + +database: + type: "sqlite" # mysql pg or sqlite + path: "data/database.db" # sqlite path + host: "" # mysql host + port: "" + name: "" + user: "" + pass: "" + +user: + cookieTimeout: 604800 + passHashType: "md5" #密码哈希类型 text md5 md5salt + + +file: + maxSize: 52428800 + pahts: + avatar: "data/static/avatar/" + image: "data/upload/image/" + video: "data/upload/video/" + music: "data/upload/music/" + pdf: "data/upload/pdf/" + other: "data/upload/other/" + + allowImageMime: + image/jpeg: ".jpeg" + image/png: ".png" + image/gif: ".gif" + image/bmp: ".bmp" + + allowVideoMime: + video/mp4: ".mp4" + video/x-msvideo: ".avi" + video/quicktime: ".mov" + video/x-flv: ".flv" + video/mpeg: ".mpeg" + + allowMusicMime: + audio/mpeg: ".mpeg" + audio/aac: ".aac" + audio/wav: ".wav" + audio/flac: ".flac" + + allowPdfMime: + application/pdf: ".pdf" + + +configed: false diff --git a/backend/my_work/defConfig/errorCodes.json b/backend/my_work/defConfig/errorCodes.json new file mode 100644 index 0000000..319a7fc --- /dev/null +++ b/backend/my_work/defConfig/errorCodes.json @@ -0,0 +1,23 @@ +{ + "apiOK":0, + "apiErr":-1, + "postErr":-2, + "jsonErr":-3, + "userNameDup":-4, + "userNameNoFund":-41, + "userPassIncorrect":-42, + "userEmailFormatError":-43, + "userCookieError":-44, + "userCookieNotFund":-44, + "userCookieExpired":-44, + "file_mime_err":-51, + "file_size_err":-52, + "file_name_err":-53, + "file_get_err":-54, + "file_hash_err":-55, + "file_save_err":-56, + "file_not_found":-57, + "file_part_err":-58 + + +} \ No newline at end of file diff --git a/backend/my_work/fresh.sh b/backend/my_work/fresh.sh new file mode 100644 index 0000000..80d8c1c --- /dev/null +++ b/backend/my_work/fresh.sh @@ -0,0 +1,4 @@ +export PATH=$PATH:$(go env GOPATH)/bin + +fresh + diff --git a/backend/my_work/go.mod b/backend/my_work/go.mod new file mode 100644 index 0000000..8c0d904 --- /dev/null +++ b/backend/my_work/go.mod @@ -0,0 +1,62 @@ +module ops + +go 1.24.0 + +toolchain go1.24.9 + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-gonic/gin v1.11.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.27.0 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.6.0 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // 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/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.54.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.0 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.20.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect + golang.org/x/tools v0.40.0 // indirect + google.golang.org/protobuf v1.36.9 // indirect + gorm.io/datatypes v1.2.7 // indirect + gorm.io/driver/mysql v1.6.0 // indirect + gorm.io/driver/postgres v1.6.0 // indirect + gorm.io/gorm v1.31.1 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect +) diff --git a/backend/my_work/go.sum b/backend/my_work/go.sum new file mode 100644 index 0000000..bba8fdd --- /dev/null +++ b/backend/my_work/go.sum @@ -0,0 +1,144 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +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.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= +github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +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.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.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +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.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +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/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.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +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/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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= +github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +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/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= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +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.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +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.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/datatypes v1.2.7 h1:ww9GAhF1aGXZY3EB3cJPJ7//JiuQo7DlQA7NNlVaTdk= +gorm.io/datatypes v1.2.7/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= +gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= +gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= +gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= diff --git a/backend/my_work/install.sh b/backend/my_work/install.sh new file mode 100644 index 0000000..90f7f8c --- /dev/null +++ b/backend/my_work/install.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +APP_NAME="OPSYS" +APP_PATH="/opt/$APP_NAME" +SERVICE_FILE="/etc/systemd/system/$APP_NAME.service" +LOG_PATH="/var/log/$APP_NAME" + +echo "正在安装 $APP_NAME..." + +# 编译应用 +echo "编译应用..." +CGO_ENABLED=0 GOOS=linux go build -o $APP_NAME -ldflags="-s -w" main.go + +# 创建目录 +echo "创建目录..." +sudo mkdir -p $APP_PATH +sudo mkdir -p $LOG_PATH + +# 复制文件 +echo "复制文件..." +sudo cp $APP_NAME $APP_PATH/ +sudo cp -r defConfig $APP_PATH/ +sudo cp -r dist $APP_PATH/ + +# 创建服务文件 +echo "创建服务文件..." +sudo tee $SERVICE_FILE > /dev/null < 0 { + layout = format[0] + } + + return time.Now().Format(layout) +} + +func StringToTimePtr(str string) (*time.Time, error) { + layout := "2006-01-02 15:04" + t, err := time.Parse(layout, str) + if err != nil { + return nil, err + } + return &t, nil +} + +func RandStr32() string { + // 生成 32 字节 (256 位) 随机数据 + b := make([]byte, 32) + if _, err := rand.Read(b); err != nil { + panic(err) + } + + // 转换为 16 进制字符串 (长度 64) + cookie := hex.EncodeToString(b) + return cookie +} + +func Md5Str(str string) string { + hashBytes2 := md5.Sum([]byte(str)) + hashString2 := hex.EncodeToString(hashBytes2[:]) // 注意数组转切片的[:] + return hashString2 +} + +func HashUserPass(user *TabUser_) { + switch ConfigsUser.PassHashType { + case "text": + break + case "md5": + user.Pass = Md5Str(user.Pass) + + case "md5salt": + if user.Salt == "" { + user.Salt = RandStr32() + } + user.Pass = Md5Str(Md5Str(user.Pass) + user.Salt) + + } + +} + +func IsExpired(expireTime time.Time) bool { + return expireTime.Before(time.Now()) +} + +func CheckCookiesAndUpdate(cookie *TabCookie_) bool { + if !IsExpired(cookie.ExpiresAt) { + if cookie.Remember { + cookiewhere := TabCookie_{ + ID: cookie.ID, + } + cookieupdata := TabCookie_{ + UpdatedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Duration(ConfigsUser.CookieTimeout) * time.Second), + } + DB.Where(&cookiewhere).Updates(&cookieupdata) + + } + return true + } else { + //以过期 + return false + } + //return false +} + +// 判断邮箱是否合法 +func IsEmailValid(email string) bool { + // 正则表达式(覆盖 99% 常见邮箱格式) + pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` + regex := regexp.MustCompile(pattern) + return regex.MatchString(email) +} + +// 判断字符串是否包含标点符号 +func IsContainsSpecialChar(str string) bool { + specialChars := "!@#$%^&*()-+={}[]|\\:;\"'<>,.?/" + return strings.ContainsAny(str, specialChars) +} diff --git a/backend/my_work/models/file.go b/backend/my_work/models/file.go new file mode 100644 index 0000000..9fc23be --- /dev/null +++ b/backend/my_work/models/file.go @@ -0,0 +1,58 @@ +package models + +import ( + "crypto" + "encoding/hex" + "io" + "mime/multipart" + "net/http" + "os" +) + +// 判断文件是否存在 +func FileExists(path string) bool { + _, err := os.Stat(path) + if err != nil { + return !os.IsNotExist(err) + } + return true +} + +// 计算文件的哈希 +func SHA256HashFile(file_head *multipart.FileHeader) (string, error) { + // 打开文件 + file, err := file_head.Open() + if err != nil { + return "foen error", err + } + defer file.Close() + + hasher := crypto.SHA256.New() + + // 从文件流中读取并计算哈希 + _, err = io.Copy(hasher, file) + if err != nil { + return "", err + } + + hashBytes := hasher.Sum(nil) + return hex.EncodeToString(hashBytes), nil + +} + +// 获取文件mime +func GetFileMime(file_head *multipart.FileHeader) (string, error) { + file, err := file_head.Open() + if err != nil { + return "foen error", err + } + defer file.Close() + + // 读取前512字节用于MIME检测 + buffer := make([]byte, 512) + io.ReadFull(file, buffer) + mimeType := http.DetectContentType(buffer) + + return mimeType, nil + +} diff --git a/backend/my_work/models/log.go b/backend/my_work/models/log.go new file mode 100644 index 0000000..7c6242e --- /dev/null +++ b/backend/my_work/models/log.go @@ -0,0 +1,50 @@ +package models + +import ( + "net" + "strings" + + "github.com/gin-gonic/gin" +) + +// GetRealIP 获取真实IP(处理代理) +func GetRealIP(c *gin.Context) string { + // 优先级顺序 + headers := []string{ + "CF-Connecting-IP", // Cloudflare + "True-Client-IP", + "X-Forwarded-For", + "X-Real-IP", + } + + for _, header := range headers { + if ip := c.GetHeader(header); ip != "" { + // 处理多个IP的情况(如 X-Forwarded-For: client, proxy1, proxy2) + if strings.Contains(ip, ",") { + ips := strings.Split(ip, ",") + ip = strings.TrimSpace(ips[0]) + } + + if net.ParseIP(ip) != nil { + return ip + } + } + } + + // 最后使用Gin的ClientIP方法 + return c.ClientIP() +} + +func LogAdd(c *gin.Context, msg string) { + + var logtemp APIRequestLog_ + + logtemp.IPAddress = GetRealIP(c) + logtemp.Path = c.Request.URL.Path + logtemp.Method = c.Request.Method + logtemp.Message = msg + + //fmt.Println(logtemp) + DB.Create(&logtemp) + +} diff --git a/backend/my_work/models/sql.go b/backend/my_work/models/sql.go new file mode 100644 index 0000000..cb5209f --- /dev/null +++ b/backend/my_work/models/sql.go @@ -0,0 +1,167 @@ +package models + +import ( + "fmt" + "time" + + "github.com/glebarez/sqlite" + "gorm.io/datatypes" + "gorm.io/driver/mysql" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +var DB *gorm.DB + +type TabFileInfo_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` + Name string `gorm:"not null;size:256;index"` // 前端报告的文件名 + Path string `gorm:"not null;size:300"` // + Sha256 string `gorm:"not null;size:64;index"` // + Mime string `gorm:"size:64;index"` + Type string `gorm:"size:64;index"` + Const uint `gorm:"default:1;index"` + Per uint `gorm:"default:1"` + UserID uint `gorm:"not null;index"` + Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间 +} + +type TabUser_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键 + Name string `gorm:"size:100;uniqueIndex"` // 唯一约束索引 + Email string `gorm:"size:255;index"` // 字符串长度限制100 索引 + Pass string `gorm:"size:128"` // 建议存储哈希后的密码 + Type string `gorm:"size:64;default:user"` // + Salt string `gorm:"size:64;"` + Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间 +} + +type TabUserGroups_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键 + Name string `gorm:"size:100;uniqueIndex"` // 唯一约束索引 + Email string `gorm:"size:255;index"` // 字符串长度限制100 索引 + Type string `gorm:"size:64;default:usergroup"` // + Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间 +} + +type TabUserGroupBinds_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键 + UserID uint `gorm:"index"` + GroupID uint `gorm:"index"` + Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间 +} + +type TabUserInfo_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` + UserID uint `gorm:"not null;uniqueIndex"` + FirstName string `gorm:"size:50;null"` + Username string `gorm:"size:30;null"` + Birthdate time.Time `gorm:"type:datetime;null"` + Gender string `gorm:"type:char(1);check:gender IN ('M', 'F', 'U');default:'U'"` + AvatarPath string `gorm:"size:255"` + Region string `gorm:"size:50"` + Language string `gorm:"size:10;default:'zh-CN'"` + CreatedAt time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP;column:created_at"` +} + +// var def_user_info = User_info{ +// ID:0, +// UserID:0, +// } + +type TabCookie_ struct { + ID uint `gorm:"primaryKey;autoIncrement"` + UserID uint `gorm:"not null"` + Name string `gorm:"size:255;not null;index"` + Value string `gorm:"size:255;not null;index"` + ExpiresAt time.Time `gorm:"type:datetime;index"` + CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"` + UpdatedAt time.Time `gorm:"type:datetime;index;not null;default:CURRENT_TIMESTAMP"` + Remember bool `gorm:"default:false"` +} + +type APIRequestLog_ struct { + ID int64 `gorm:"primaryKey;column:id" json:"id"` + IPAddress string `gorm:"column:ip_address;size:45;not null" json:"ip_address"` + Path string `gorm:"column:path;size:500;not null" json:"path"` + Method string `gorm:"column:method;size:10;not null" json:"method"` + StatusCode int `gorm:"column:status_code;index" json:"status_code"` + Message string `gorm:"column:error_message;type:text" json:"error_message"` + CreatedAt time.Time `gorm:"column:created_at;type:datetime;default:CURRENT_TIMESTAMP" json:"created_at"` +} + +type TabPurchaseOrder struct { + ID uint `gorm:"primarykey"` + UserID uint `gorm:"not null"` + Title string `gorm:"size:200;comment:标题"` + Remark string `gorm:"type:text;comment:备注"` + Photos datatypes.JSON `gorm:"type:json;comment:照片哈希数组"` + Link string `gorm:"size:1000;comment:链接"` + PartName string `gorm:"size:200;not null;comment:物品名称"` + Styles string `gorm:"type:text;comment:样式数组"` + //Costs datatypes.JSON `gorm:"type:json;comment:费用明细数组"` + UpdateTime *time.Time `gorm:"type:datetime;autoUpdateTime;comment:更新时间"` + TrackingNumber string `gorm:"size:100;Index;comment:快递单号"` + OrderStatus string `gorm:"default:1;comment:订单状态"` + + CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"` + UpdatedAt *time.Time `gorm:"type:datetime;autoUpdateTime"` + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +type TabPurchaseCosts struct { + ID uint `gorm:"primarykey"` + OrderID uint `gorm:"not null"` + UserID uint `gorm:"not null"` + Price int `gorm:"not null"` + Quantity int `gorm:"not null"` + CreatedAt *time.Time `gorm:"type:datetime;autoCreateTime"` +} + +func DatabaseInit() error { + var err error + fmt.Println("database_init") + DatabaseConfigs := Configs["database"].(map[string]interface{}) + + if DatabaseConfigs["type"].(string) == "sqlite" { + //sqlite init + fmt.Println("sqlite") + DB, err = gorm.Open(sqlite.Open(DatabaseConfigs["path"].(string)), &gorm.Config{}) + } else if DatabaseConfigs["type"].(string) == "mysql" { + //mysql init + fmt.Println("mysql") + dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", DatabaseConfigs["user"].(string), DatabaseConfigs["pass"].(string), DatabaseConfigs["host"].(string), DatabaseConfigs["port"].(string), DatabaseConfigs["name"].(string)) + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + } else if DatabaseConfigs["type"].(string) == "pg" { + //postgresql init + fmt.Println("postgresql") + dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai", DatabaseConfigs["host"].(string), DatabaseConfigs["user"].(string), DatabaseConfigs["pass"].(string), DatabaseConfigs["name"].(string), DatabaseConfigs["port"].(string)) + DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) + } + + if err != nil { + fmt.Println(err) + panic("数据库连接失败") + } + + // 自动创建表结构 + DB.AutoMigrate(&TabUser_{}) + + DB.AutoMigrate(&TabUserGroups_{}) + + DB.AutoMigrate(&TabUserGroupBinds_{}) + + DB.AutoMigrate(&TabUserInfo_{}) + + DB.AutoMigrate(&TabCookie_{}) + + DB.AutoMigrate(&TabFileInfo_{}) + + DB.AutoMigrate(&APIRequestLog_{}) + + DB.AutoMigrate(&TabPurchaseOrder{}) + + DB.AutoMigrate(&TabPurchaseCosts{}) + + return nil +} diff --git a/backend/my_work/routers/api.go b/backend/my_work/routers/api.go new file mode 100644 index 0000000..186c24b --- /dev/null +++ b/backend/my_work/routers/api.go @@ -0,0 +1,62 @@ +package routers + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/gin-gonic/gin" +) + +var ErrorCode map[string]interface{} + +func init() { + //读取默认配置 + fmt.Println("尝试读取错误码文件") + data, err := os.ReadFile("./defConfig/errorCodes.json") + if err != nil { + + fmt.Println("读取错误码文件失败", err) + } + + if err := json.Unmarshal(data, &ErrorCode); err != nil { + fmt.Println("解析错误码文件失败", err) + } + +} + +// 把数据分离成cookie和json +func SeparateData(ctx *gin.Context) (map[string]interface{}, string) { + var jsonData map[string]interface{} + + if err := ctx.ShouldBindJSON(&jsonData); err == nil { + //分离数据 + cookie, ok := jsonData["userCookieValue"].(string) + if !ok { + cookie = "" + } + + data, ok := jsonData["data"].(map[string]interface{}) + if !ok { + data = nil + } + + return data, cookie + } + + return nil, "" + +} + +func ApiRoot(r *gin.RouterGroup) { + + ApiStatic(r.Group("/static")) + ApiUser(r.Group("/users")) + ApiFiles(r.Group("/files")) + ApiPurchase(r.Group("/purchase")) + + r.GET("/", func(ctx *gin.Context) { + ReturnJson(ctx, "apiOK", nil) + }) + +} diff --git a/backend/my_work/routers/apiPurchase.go b/backend/my_work/routers/apiPurchase.go new file mode 100644 index 0000000..c92d01c --- /dev/null +++ b/backend/my_work/routers/apiPurchase.go @@ -0,0 +1,179 @@ +package routers + +import ( + "encoding/json" + "fmt" + "ops/models" + + "github.com/gin-gonic/gin" + "github.com/mitchellh/mapstructure" + "gorm.io/datatypes" +) + +type CostItem struct { + Cost int `json:"cost"` // 必须,非负 + CostT int `json:"costt"` // 必须,非负 + CurrencyType string `json:"currencytype"` // 必须 + Int int `json:"int"` // 必须 + Type string `json:"type"` // 必须 +} +type From_purchase_addorder struct { + Costs []CostItem `json:"costs"` // + Link string `json:"link"` // 可选 + OrderStatus string `json:"order_status"` // + PartName string `json:"partname"` // 可选 + Photos []string `json:"photos"` // 可选 + Remark string `json:"remark"` // 可选 + Styles string `json:"styles"` // 可选 + Title string `json:"title"` // 必须 + TrackingNumber string `json:"tracking_number"` // 可选 + UpdateTime string `json:"update_time"` // 可选 +} + +func ApiPurchase(r *gin.RouterGroup) { + + r.POST("/getorders", func(ctx *gin.Context) { + isAuth, user, data := AuthenticationAuthority(ctx) + if isAuth { + fmt.Println(user) + // DebugPrintJson(data) + + type From_purchase_getorders struct { + Search string + Entries int + Page int + } + + var jsondata From_purchase_getorders + if err := mapstructure.Decode(data, &jsondata); err == nil { + //fmt.Println(jsondata) + + is_data_ok := true + + if jsondata.Entries <= 0 || jsondata.Entries > 300 { + is_data_ok = false + } + if jsondata.Page <= 0 { + is_data_ok = false + } + + if is_data_ok { + + //读取有多少条目 + var count int64 + models.DB.Model(&models.TabPurchaseOrder{}).Count(&count) + //fmt.Println(count) + + //读取条目 + var getorders []models.TabPurchaseOrder + models.DB.Order("created_at DESC").Offset(jsondata.Entries * (jsondata.Page - 1)).Limit(jsondata.Entries).Find(&getorders) + + ReturnJson(ctx, "apiOK", map[string]interface{}{ + "all_count": count, + "all_orders": getorders, + }) + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "userCookieError", nil) + } + }) + + r.POST("/addorder", func(ctx *gin.Context) { + isAuth, user, data := AuthenticationAuthority(ctx) + if isAuth { + + //需要处理提交的数据,接口有固定的数据格式,不允许乱搞 + //fmt.Println(isAuth) + //fmt.Println(user) + //DebugPrintJson(data) + var jsondata From_purchase_addorder + if err := mapstructure.Decode(data, &jsondata); err == nil { + + //fmt.Println("转换后数据:\n", jsondata) + + //数据比较混乱 在这里校验 + + //判断标题不为空 + is_data_ok := true + if jsondata.Title == "" { + is_data_ok = false + } + + //判断数量与价格是否为负数 + for i := 0; i < len(jsondata.Costs); i++ { + if jsondata.Costs[i].Cost <= 0 { + is_data_ok = false + } + if jsondata.Costs[i].Int <= 0 { + is_data_ok = false + } + } + + //判断图片是否为哈希值 + for i := 0; i < len(jsondata.Photos); i++ { + //判断字符串是否包含标点符号 + if models.IsContainsSpecialChar(jsondata.Photos[i]) { + is_data_ok = false + } + + } + + //判断时间字符串是否合法 + uptime, e := models.StringToTimePtr(jsondata.UpdateTime) + if e != nil { + is_data_ok = false + } + + if is_data_ok { + //校验通过 + //载入数据库 + + photos, _ := json.Marshal(jsondata.Photos) //把图片数组转换成字符串 + new_data := models.TabPurchaseOrder{ + UserID: user.ID, + Title: jsondata.Title, + Remark: jsondata.Remark, + Photos: datatypes.JSON(photos), + Link: jsondata.Link, + PartName: jsondata.PartName, + Styles: jsondata.Styles, + UpdateTime: uptime, + TrackingNumber: jsondata.TrackingNumber, + OrderStatus: jsondata.OrderStatus, + } + models.DB.Create(&new_data) + + for i := 0; i < len(jsondata.Costs); i++ { + new_cost_data := models.TabPurchaseCosts{ + Price: jsondata.Costs[i].Cost, + Quantity: jsondata.Costs[i].Int, + UserID: user.ID, + OrderID: new_data.ID, + } + models.DB.Create(&new_cost_data) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "userCookieError", nil) + } + + ReturnJson(ctx, "apiErr", nil) + }) + +} diff --git a/backend/my_work/routers/apiStatic.go b/backend/my_work/routers/apiStatic.go new file mode 100644 index 0000000..09b82d3 --- /dev/null +++ b/backend/my_work/routers/apiStatic.go @@ -0,0 +1,25 @@ +package routers + +import ( + "ops/models" + "path" + + "github.com/gin-gonic/gin" +) + +//处理api的静态内容 + +func ApiStatic(r *gin.RouterGroup) { + r.GET("/avatar/:filename", func(ctx *gin.Context) { + filename := ctx.Param("filename") + dst := path.Join(models.ConfigsFile.Pahts["avatar"], filename) + if models.FileExists(dst) { + ctx.File(dst) + } else { + //找不到文件 + ctx.String(404, "file not found") + + } + + }) +} diff --git a/backend/my_work/routers/apiUsers.go b/backend/my_work/routers/apiUsers.go new file mode 100644 index 0000000..f5d6337 --- /dev/null +++ b/backend/my_work/routers/apiUsers.go @@ -0,0 +1,541 @@ +package routers + +import ( + "errors" + "fmt" + "ops/models" + "path" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/mitchellh/mapstructure" +) + +func ApiInit() { + //用户模块初始化init + fmt.Println("users init") + + //创建admin用户 + var user models.TabUser_ + user.Name = "admin" + + if models.DB.Where(&user).First(&user).Error == nil { + + } else { + //fmt.Println("用户不存在") + + //对密码加盐 + user.Salt = models.RandStr32() + user.Pass = "adminpassword" + models.HashUserPass(&user) + models.DB.Create(&user) // 传入指针 + } + + //创建admin group + var usergroup models.TabUserGroups_ + usergroup.Name = "admins" + if models.DB.Where(&usergroup).First(&usergroup).Error == nil { + + } else { + fmt.Println("用户组不存在") + models.DB.Create(&usergroup) // 传入指针 + } + + //创建用户与用户组绑定 + var usergroupbind models.TabUserGroupBinds_ + usergroupbind.UserID = user.ID + usergroupbind.GroupID = usergroup.ID + + if models.DB.Where(&usergroupbind).First(&usergroupbind).Error == nil { + + } else { + models.DB.Create(&usergroupbind) // 传入指针 + } + +} + +type From_user_add struct { + Useremail string `json:"useremail"` + Username string `json:"username"` + Userpass string `json:"userpass"` +} + +type From_user_login struct { + Username string `json:"username"` + Userpass string `json:"userpass"` + Remember bool `json:"remember"` +} + +type From_user_updateinfo struct { + Username string `json:"username"` + Remark string `json:"remark"` + Birthday string `json:"birthday"` +} + +type From_user_changeemail struct { + Newemail string `json:"newemail"` +} + +type From_user_changepass struct { + Oldpass string `json:"oldpass"` + Newpass string `json:"newpass"` +} + +func AuthenticationAuthorityFromCookie(c string) (*models.TabUser_, error) { + + if c != "" { + cookie := models.TabCookie_{ + Value: c, + } + if models.DB.Where(&cookie).First(&cookie).Error == nil { + //找到cookie,验证cookie有效性,以及更新cookie + if models.CheckCookiesAndUpdate(&cookie) { + //cookie有效 + //载入user + user := models.TabUser_{ + ID: cookie.UserID, + } + models.DB.Where(&user).First(&user) + return &user, nil + } else { + return nil, errors.New("cookie 过期") + } + } else { + return nil, errors.New("cookie Not Fund") + } + } else { + return nil, errors.New("cookie 参数错误") + } +} + +func AuthenticationAuthority(ctx *gin.Context) (bool, models.TabUser_, map[string]interface{}) { + var user models.TabUser_ + + data, cookieval := SeparateData(ctx) + //fmt.Println("cookieis" + cookieval) + if cookieval != "" { + cookie := models.TabCookie_{ + Value: cookieval, + } + if models.DB.Where(&cookie).First(&cookie).Error == nil { + //找到cookie,验证cookie有效性,以及更新cookie + if models.CheckCookiesAndUpdate(&cookie) { + //cookie有效 + //载入user + user := models.TabUser_{ + ID: cookie.UserID, + } + models.DB.Where(&user).First(&user) + + return true, user, data + + } else { + ReturnJson(ctx, "userCookieExpired", nil) + return false, user, nil + } + + } else { + ReturnJson(ctx, "userCookieNotFund", nil) + return false, user, nil + } + + } else { + ReturnJson(ctx, "userCookieError", nil) + return false, user, nil + } + + //return false, user +} + +func ApiUser(r *gin.RouterGroup) { + + r.GET("/test", func(ctx *gin.Context) { + ReturnJson(ctx, "apiOK", nil) + }) + r.POST("/test", func(ctx *gin.Context) { + ReturnJson(ctx, "apiOK", nil) + }) + + //修改用户密码 + r.POST("/changePassword", func(ctx *gin.Context) { + isAuth, user, data := AuthenticationAuthority(ctx) + if isAuth { + var jsonData From_user_changepass + if err := mapstructure.Decode(data, &jsonData); err == nil { + //验证旧密码 + fmt.Println(user) + //转换旧密码 + olduser := models.TabUser_{ + Pass: jsonData.Oldpass, + Salt: user.Salt, + } + models.HashUserPass(&olduser) + if olduser.Pass == user.Pass { + //旧密码正确,更新新密码 + var userupdate models.TabUser_ + userupdate.Pass = jsonData.Newpass + userupdate.Salt = models.RandStr32() + models.HashUserPass(&userupdate) + models.DB.Model(&user).Updates(&userupdate) + ReturnJson(ctx, "apiOK", nil) + } else { + //旧密码错误 + ReturnJson(ctx, "userPassIncorrect", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } + }) + + //更新用户邮箱 + r.POST("/changeEmail", func(ctx *gin.Context) { + isAuth, user, data := AuthenticationAuthority(ctx) + if isAuth { + var jsonData From_user_changeemail + if err := mapstructure.Decode(data, &jsonData); err == nil { + //判断新邮箱格式 + if models.IsEmailValid(jsonData.Newemail) { + var userupdate models.TabUser_ + userupdate.Email = jsonData.Newemail + models.DB.Model(&user).Updates(&userupdate) + ReturnJson(ctx, "apiOK", nil) + } else { + ReturnJson(ctx, "userEmailFormatError", nil) + + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + } + }) + + //修改用户头像 + r.POST("/updateAvatar", func(ctx *gin.Context) { + cookie := ctx.PostForm("cookie") + user, err := AuthenticationAuthorityFromCookie(cookie) + if err == nil { + file, err := ctx.FormFile("file") + if err == nil { + if file.Filename != "" { + //限制文件大小 + if file.Size > 512 { + //头像裁剪过限制1M应该差不多 + if file.Size < 1048576 { + + //判断mime + mimeType, err := models.GetFileMime(file) + if err == nil { + + file_extname := models.ConfigsFile.AllowImageMime[mimeType] + if file_extname != "" { + + //haxi文件 + + file_hashi_name, err := models.SHA256HashFile(file) + if err == nil { + + dst := path.Join(models.ConfigsFile.Pahts["avatar"], file_hashi_name+file_extname) + + var is_save_ok = false + //判断文件是否存在避免重复保存 + if models.FileExists(dst) { + //fmt.Println("文件存在") + is_save_ok = true + ReturnJson(ctx, "apiOK", nil) + } else { + //fmt.Println("文件no存在") + ferr := ctx.SaveUploadedFile(file, dst) + if ferr == nil { + //文件保存成功 + //fmt.Print("save_ok") + is_save_ok = true + ReturnJson(ctx, "apiOK", nil) + } else { + fmt.Print(ferr) + ReturnJson(ctx, "postErr", nil) + } + + } + if is_save_ok { + //修改数据库内容 + var user_info_fund models.TabUserInfo_ + user_info_fund.UserID = user.ID + + var user_update_avatar models.TabUserInfo_ + user_update_avatar.AvatarPath = file_hashi_name + file_extname + + models.DB.Where(&user_info_fund).Updates(&user_update_avatar) + + } + + } else { + ReturnJson(ctx, "postErr", nil) + } + + } else { + ReturnJson(ctx, "file_mime_err", nil) + } + + } else { + ReturnJson(ctx, "postErr", nil) + } + + } else { + ReturnJson(ctx, "file_size_err", nil) + } + } else { + ReturnJson(ctx, "file_size_err", nil) + } + } else { + ReturnJson(ctx, "file_name_err", nil) + } + } else { + ReturnJson(ctx, "file_get_err", nil) + } + + } else { + ReturnJson(ctx, "userCookieError", nil) + } + + }) + + //更新用户info + r.POST("/updateInfo", func(ctx *gin.Context) { + isAuth, user, data := AuthenticationAuthority(ctx) + if isAuth { + var jsonData From_user_updateinfo + + if err := mapstructure.Decode(data, &jsonData); err == nil { + // fmt.Println("updateinfo data is", jsonData) + // fmt.Println(user) + t, err := time.Parse("2006-01-02", jsonData.Birthday) + if err == nil { + var userinfo models.TabUserInfo_ + userinfo.UserID = user.ID + + var userinfoupdate models.TabUserInfo_ + userinfoupdate.UserID = user.ID + userinfoupdate.CreatedAt = time.Now() + userinfoupdate.Username = jsonData.Username + userinfoupdate.Birthdate = t + userinfoupdate.FirstName = jsonData.Remark + + //先查找是否有记录 + if models.DB.Where(&userinfo).First(&userinfo).Error == nil { + //有记录,更新 + models.DB.Model(&userinfo).Updates(&userinfoupdate) + } else { + //无记录,创建 + models.DB.Create(&userinfoupdate) // 传入指针 + + } + + ReturnJson(ctx, "apiOK", nil) + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + } + + }) + + //通过cookie获取用户info + r.POST("/getinfo", func(ctx *gin.Context) { + isAuth, user, _ := AuthenticationAuthority(ctx) + if isAuth { + //载入用户info + var userinfo models.TabUserInfo_ + userinfo.UserID = user.ID + //fmt.Println(userInfo) + var redata map[string]interface{} = make(map[string]interface{}) + if models.DB.Where(&userinfo).First(&userinfo).Error == nil { + redata["userInfo"] = userinfo + } else { + redata["userInfo"] = nil + } + + user.Pass = "" + user.Salt = "" + + redata["user"] = user + + ReturnJson(ctx, "apiOK", redata) + + } + // _, cookieval := SeparateData(ctx) + // //fmt.Println("cookieis" + cookieval) + // if cookieval != "" { + // cookie := models.TabCookie_{ + // Value: cookieval, + // } + // if models.DB.Where(&cookie).First(&cookie).Error == nil { + // //找到cookie,验证cookie有效性,以及更新cookie + // if models.CheckCookiesAndUpdate(&cookie) { + // //cookie有效 + // //返回最新cookie + // redata := map[string]interface{}{ + // "cookie": cookie, + // } + // //载入用户info + // userInfo := models.TabFileInfo_{ + // UserID: cookie.UserID, + // } + // if models.DB.Where(&userInfo).First(&userInfo).Error == nil { + // redata["userInfo"] = userInfo + // } else { + // redata["userInfo"] = nil + // } + + // //载入user + // user := models.TabUser_{ + // ID: cookie.UserID, + // } + // models.DB.Where(&user).First(&user) + // user.Pass = "" + // user.Salt = "" + + // redata["user"] = user + + // ReturnJson(ctx, "apiOK", redata) + + // } else { + // ReturnJson(ctx, "userCookieExpired", nil) + // } + + // } else { + // ReturnJson(ctx, "userCookieNotFund", nil) + // } + + // } else { + // ReturnJson(ctx, "userCookieError", nil) + // } + + }) + //用户登陆 + r.POST("/login", func(ctx *gin.Context) { + var loginuser From_user_login + data, _ := SeparateData(ctx) + if data != nil { + if err := mapstructure.Decode(data, &loginuser); err == nil { + if loginuser.Username != "" && loginuser.Userpass != "" { + //传入的数据都ok,获取用户信息 + + getuser := models.TabUser_{ + Name: loginuser.Username, + } + + if models.DB.Where(&getuser).First(&getuser).Error == nil { + //倒入数据 + user := models.TabUser_{ + Pass: loginuser.Userpass, //密码明文 + Salt: getuser.Salt, //保存的盐制 + } + //哈希密 + models.HashUserPass(&user) + if user.Pass == getuser.Pass { + //用户密码正确,生成cookie + cookie := models.TabCookie_{ + UserID: getuser.ID, + Name: "login", + Value: models.RandStr32(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Duration(models.ConfigsUser.CookieTimeout) * time.Second), //计算过期时间, + Remember: loginuser.Remember, + } + models.DB.Create(&cookie) // 传入指针 + + redata := map[string]interface{}{ + "cookie": cookie, + } + + ReturnJson(ctx, "apiOK", redata) + } else { + ReturnJson(ctx, "userPassIncorrect", nil) + } + + } else { + //用户不存在 + ReturnJson(ctx, "userNameNoFund", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "postErr", nil) + } + }) + + //用户注册 + r.POST("/register", func(ctx *gin.Context) { + //转换传进来的数据 + var jsonData From_user_add + + data, _ := SeparateData(ctx) + + if data != nil { + if err := mapstructure.Decode(data, &jsonData); err == nil { + //转换字段 + newUser := models.TabUser_{ + Name: jsonData.Username, + Email: jsonData.Useremail, + Pass: jsonData.Userpass, // 实际应替换为哈希值 + Date: time.Now(), + // Date 字段无需赋值,数据库会自动填充默认值 + } + if newUser.Name != "" && newUser.Pass != "" && newUser.Email != "" { + + //用户名是唯一的,先读取是否有这个用户名 + var user models.TabUser_ + user.Name = newUser.Name + + if models.DB.Where(&user).First(&user).Error == nil { + //fmt.Println("找到用户:", user.ID) + ReturnJson(ctx, "userNameDup", nil) + } else { + //fmt.Println("用户不存在") + + //对密码加盐 + newUser.Salt = models.RandStr32() + + //对用户的密码进行哈希替换 + models.HashUserPass(&newUser) + + models.DB.Create(&newUser) // 传入指针 + + //创建用户后写一个log + + models.LogAdd(ctx, "New user id:"+strconv.Itoa(int(newUser.ID))) + + ReturnJson(ctx, "apiOK", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + + } + } else { + ReturnJson(ctx, "postErr", nil) + + } + + }) +} diff --git a/backend/my_work/routers/api_Files.go b/backend/my_work/routers/api_Files.go new file mode 100644 index 0000000..e0d9a6f --- /dev/null +++ b/backend/my_work/routers/api_Files.go @@ -0,0 +1,174 @@ +package routers + +import ( + "io" + "net/http" + "ops/models" + "path" + "path/filepath" + + "github.com/gin-gonic/gin" +) + +func file_save() { + +} + +func ApiFiles(r *gin.RouterGroup) { + + //getfile := r.Group("/get") //定义上传组 + r.GET("/:mode/:hash", func(ctx *gin.Context) { + hash := ctx.Param("hash") + mode := ctx.Param("mode") + // filename := ctx.Param("filename") + // fmt.Println(filename) + + download := false + isPartOK := false + + if mode == "get" { + isPartOK = true + download = true + } + if mode == "download" { + isPartOK = true + download = false + } + if isPartOK { + file_info := models.TabFileInfo_{ + Sha256: hash, + } + if models.DB.Where(&file_info).First(&file_info).Error == nil { + ReturnFile(ctx, &file_info, download) + } else { + //fmt.Println("not fund") + ReturnJson(ctx, "file_not_found", nil) + } + } else { + ReturnJson(ctx, "file_part_err", nil) + } + + }) + + upload := r.Group("/upload") //定义上传组 + //上传文件的总接口,能上传什么文件应该由后端决定,前端仅做相应限制 + + upload.POST("/image", func(ctx *gin.Context) { + + cookie := ctx.PostForm("cookie") //首先需要判断用户是否登录 + + //通过cookie获取用户信息 + user, err := AuthenticationAuthorityFromCookie(cookie) + if err == nil { + file, err := ctx.FormFile("file") + + if err == nil { + if file.Filename != "" { + //限制文件大小 + if file.Size > 512 { + if file.Size < int64(models.ConfigsFile.MaxSize) { + + //判断文件mime是否合法 + // 打开文件流 + src_mime, _ := file.Open() + defer src_mime.Close() + // 读取前512字节用于MIME检测 + buffer := make([]byte, 512) + io.ReadFull(src_mime, buffer) + // 检测MIME类型 + mimeType := http.DetectContentType(buffer) + file_extname := models.ConfigsFile.AllowImageMime[mimeType] + if file_extname != "" { + filename := filepath.Base(file.Filename) // 防御性处理路径分隔符 + // 计算哈希值 + hash_str, err := models.SHA256HashFile(file) + if err == nil { + //fmt.Println(hash_str) + //fmt.Println(filename) + //这是上传的真实路径 + dst := path.Join(models.ConfigsFile.Pahts["image"], hash_str) + //fmt.Println(dst) + //判断文件是否存在避免重复保存 + if models.FileExists(dst) { + //fmt.Println("文件存在") + + } else { + //fmt.Println("文件no存在") + ferr := ctx.SaveUploadedFile(file, dst) + if ferr == nil { + //文件保存成功 + + } else { + + ReturnJson(ctx, "file_save_err", nil) + ctx.Abort() //end + return + } + } + //记录到数据库 + //先检查数据库有没有数据 + fund_file_info := models.TabFileInfo_{ + Name: filename, + Sha256: hash_str, + Mime: mimeType, + Type: "image", + UserID: user.ID, + } + fund_file_info2 := models.TabFileInfo_{} + + models.DB.Where(&fund_file_info).Find(&fund_file_info2) + + if fund_file_info2.ID != 0 { + fund_file_info2.Const += 1 + models.DB.Where(&fund_file_info).Updates(&fund_file_info2) + } else { + fund_file_info.Path = dst + models.DB.Create(&fund_file_info) // 传入指针 + } + + //返回后台存储的URL + download_URL := path.Join("/api/files/download/", hash_str) + get_URL := path.Join("/api/files/get/", hash_str) + re := map[string]interface{}{ + "download": download_URL, + "get": get_URL, + "hash": hash_str, + } + + ReturnJson(ctx, "apiOK", re) + + } else { + ReturnJson(ctx, "file_hash_err", nil) + } + + } else { + ReturnJson(ctx, "file_mime_err", nil) + } + } else { + ReturnJson(ctx, "file_size_err", nil) + } + + } else { + ReturnJson(ctx, "file_size_err", nil) + } + + } else { + ReturnJson(ctx, "file_name_err", nil) + } + + } else { + ReturnJson(ctx, "file_get_err", nil) + } + + } else { + ReturnJson(ctx, "userCookieError", nil) + } + + //ReturnJson(ctx, "apiErr", nil) + }) + + // r.GET("/upload", func(ctx *gin.Context) { + // ReturnJson(ctx, "apiOK", nil) + // }) + +} diff --git a/backend/my_work/routers/return.go b/backend/my_work/routers/return.go new file mode 100644 index 0000000..d0faa4e --- /dev/null +++ b/backend/my_work/routers/return.go @@ -0,0 +1,46 @@ +package routers + +import ( + "encoding/json" + "fmt" + "ops/models" + + "github.com/gin-gonic/gin" +) + +func DebugPrintJson(data map[string]interface{}) { + p, _ := json.MarshalIndent(data, "", " ") + fmt.Println("\n", string(p)) + +} + +func ReturnJson(ctx *gin.Context, errMsg string, data map[string]interface{}) { + var errCode = ErrorCode[errMsg] + returnData := map[string]interface{}{} + + // cookie, have_cookie := ctx.Get("cookie") + // if have_cookie { + // returnData["cookie"] = cookie + // } + + returnData["err_code"] = errCode + returnData["err_msg"] = errMsg + if data != nil { + returnData["return"] = data + } + + ctx.JSON(200, &returnData) + + //ctx.Abort() + +} + +func ReturnFile(ctx *gin.Context, file_info *models.TabFileInfo_, preview bool) { + if preview { + ctx.File(file_info.Path) + } else { + //需要从数据库拉取原始文件名 + ctx.FileAttachment(file_info.Path, file_info.Name) + } + +} diff --git a/backend/run-dev.bat b/backend/run-dev.bat deleted file mode 100644 index ad24af8..0000000 --- a/backend/run-dev.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -echo Starting OPS Backend Development Server... -echo. - -:: 设置Go环境变量 -set CGO_ENABLED=1 - -:: 检查dist目录 -if not exist ".\dist" mkdir dist - -:: 运行开发服务器 -echo Starting server with CGO enabled for SQLite... -echo Server will be available at: http://127.0.0.1:8080 -echo. - -go run ./cmd/ops-server/main.go - -echo. -echo Server stopped. -pause \ No newline at end of file diff --git a/frontend/ops_vue_js/vite.config.js b/frontend/ops_vue_js/vite.config.js index ad72e17..1c0279c 100644 --- a/frontend/ops_vue_js/vite.config.js +++ b/frontend/ops_vue_js/vite.config.js @@ -14,7 +14,7 @@ export default defineConfig({ }, }, build: { - outDir: "../../backend/dist", + outDir: "../../backend/my_work/dist", assetsDir: "assets", }, server: {