From 7c060c216a6f7785cd899596f7ffb419cc13ad60 Mon Sep 17 00:00:00 2001 From: summer <> Date: Thu, 16 Oct 2025 13:28:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(1.0):=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + README.md | 15 + cmd/gormgen/README.md | 39 + cmd/gormgen/main.go | 105 + cmd/handlergen/README.md | 28 + cmd/handlergen/handler_template.go.tpl | 265 ++ cmd/handlergen/main.go | 90 + cmd/mfmt/README.md | 38 + cmd/mfmt/main.go | 206 + configs/configs.go | 85 + configs/constants.go | 55 + configs/dev_configs.toml | 0 configs/fat_configs.toml | 19 + configs/pro_configs.toml | 2 + configs/uat_configs.toml | 2 + docs/docs.go | 3791 +++++++++++++++++ docs/swagger.json | 3765 ++++++++++++++++ docs/swagger.yaml | 2588 +++++++++++ go.mod | 110 + go.sum | 845 ++++ internal/alert/alert.go | 11 + internal/api/admin/admin.go | 21 + internal/api/admin/func_login.go | 125 + internal/code/README.md | 13 + internal/code/code.go | 34 + internal/code/zh-cn.go | 9 + internal/cron/cron.go | 97 + internal/cron/cron_add_job.go | 35 + internal/cron/cron_add_task.go | 21 + internal/cron/cron_remove_task.go | 7 + internal/cron/cron_start.go | 14 + internal/cron/cron_stop.go | 6 + internal/cron/cron_stop_job.go | 17 + internal/dblogger/request_logger.go | 38 + internal/metrics/metrics.go | 19 + internal/metrics/prometheus.go | 59 + internal/pkg/color/string_darwin.go | 47 + internal/pkg/color/string_linux.go | 47 + internal/pkg/color/string_windows.go | 47 + internal/pkg/core/context.go | 462 ++ internal/pkg/core/core.go | 549 +++ internal/pkg/core/error.go | 82 + internal/pkg/cors/cors.go | 39 + internal/pkg/cryptoaes/cryptoaes.go | 72 + internal/pkg/cryptoaes/cryptoaes_test.go | 15 + internal/pkg/cryptorsa/cryptorsa.go | 92 + internal/pkg/cryptorsa/cryptorsa_test.go | 53 + internal/pkg/debug/logger.go | 40 + internal/pkg/env/env.go | 77 + internal/pkg/errors/err.go | 100 + internal/pkg/errors/err_test.go | 34 + internal/pkg/httpclient/client.go | 110 + internal/pkg/idgen/idgen.go | 14 + internal/pkg/idgen/idgen_test.go | 7 + internal/pkg/jsonutil/jsonutil.go | 10 + internal/pkg/jwtoken/jwtoken.go | 80 + internal/pkg/jwtoken/jwtoken_test.go | 40 + internal/pkg/logger/logger.go | 394 ++ internal/pkg/logger/logger_test.go | 60 + internal/pkg/shutdown/shutdown.go | 18 + internal/pkg/startup/info.go | 58 + internal/pkg/timeutil/timeutil.go | 101 + internal/pkg/timeutil/timeutil_test.go | 19 + internal/pkg/trace/debug.go | 6 + internal/pkg/trace/http.go | 7 + internal/pkg/trace/mongo.go | 9 + internal/pkg/trace/redis.go | 8 + internal/pkg/trace/sql.go | 9 + internal/pkg/trace/trace.go | 152 + internal/pkg/utils/utils.go | 275 ++ internal/pkg/utils/utils_test.go | 30 + internal/pkg/validation/validation.go | 46 + internal/proposal/alert.go | 28 + internal/proposal/metrics.go | 25 + internal/proposal/request_logger.go | 28 + internal/proposal/session.go | 19 + internal/repository/mysql/dao/admin.gen.go | 368 ++ .../repository/mysql/dao/app_keyword.gen.go | 344 ++ .../mysql/dao/app_keyword_reply.gen.go | 356 ++ .../mysql/dao/app_message_log.gen.go | 352 ++ internal/repository/mysql/dao/app_user.gen.go | 336 ++ internal/repository/mysql/dao/article.gen.go | 348 ++ .../mysql/dao/diagnostic_record.gen.go | 364 ++ internal/repository/mysql/dao/doctor.gen.go | 368 ++ internal/repository/mysql/dao/gen.go | 159 + .../repository/mysql/dao/log_operation.gen.go | 336 ++ .../repository/mysql/dao/log_request.gen.go | 364 ++ .../repository/mysql/dao/mini_program.gen.go | 352 ++ .../mysql/dao/miniprogram_access_token.gen.go | 332 ++ internal/repository/mysql/dao/patient.gen.go | 440 ++ .../dao/patient_emergency_symptom.gen.go | 348 ++ .../mysql/dao/patient_follow_plan.gen.go | 352 ++ .../dao/patient_follow_questionnaire.gen.go | 568 +++ .../mysql/dao/patient_medicine_record.gen.go | 368 ++ .../mysql/dao/patient_medicine_scheme.gen.go | 356 ++ .../mysql/dao/patient_medicine_task.gen.go | 376 ++ .../mysql/dao/sms_verification_code.gen.go | 344 ++ internal/repository/mysql/dao/symptom.gen.go | 344 ++ internal/repository/mysql/model/admin.gen.go | 33 + .../repository/mysql/model/app_keyword.gen.go | 27 + .../mysql/model/app_keyword_reply.gen.go | 30 + .../mysql/model/app_message_log.gen.go | 29 + .../repository/mysql/model/app_user.gen.go | 21 + .../repository/mysql/model/article.gen.go | 28 + .../mysql/model/diagnostic_record.gen.go | 32 + internal/repository/mysql/model/doctor.gen.go | 33 + .../mysql/model/log_operation.gen.go | 25 + .../repository/mysql/model/log_request.gen.go | 32 + .../mysql/model/mini_program.gen.go | 29 + .../model/miniprogram_access_token.gen.go | 24 + .../repository/mysql/model/patient.gen.go | 51 + .../model/patient_emergency_symptom.gen.go | 28 + .../mysql/model/patient_follow_plan.gen.go | 29 + .../model/patient_follow_questionnaire.gen.go | 83 + .../model/patient_medicine_record.gen.go | 33 + .../model/patient_medicine_scheme.gen.go | 30 + .../mysql/model/patient_medicine_task.gen.go | 35 + .../mysql/model/sms_verification_code.gen.go | 27 + .../repository/mysql/model/symptom.gen.go | 27 + internal/repository/mysql/mysql.go | 131 + internal/repository/mysql/plugin.go | 83 + internal/router/interceptor/admin_auth.go | 80 + internal/router/interceptor/interceptor.go | 38 + internal/router/router.go | 58 + main.go | 100 + scripts/swagger.bat | 9 + scripts/swagger.sh | 5 + 127 files changed, 24951 insertions(+) create mode 100644 cmd/gormgen/README.md create mode 100644 cmd/gormgen/main.go create mode 100644 cmd/handlergen/README.md create mode 100644 cmd/handlergen/handler_template.go.tpl create mode 100644 cmd/handlergen/main.go create mode 100644 cmd/mfmt/README.md create mode 100644 cmd/mfmt/main.go create mode 100644 configs/configs.go create mode 100644 configs/constants.go create mode 100644 configs/dev_configs.toml create mode 100644 configs/fat_configs.toml create mode 100644 configs/pro_configs.toml create mode 100644 configs/uat_configs.toml create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/alert/alert.go create mode 100644 internal/api/admin/admin.go create mode 100644 internal/api/admin/func_login.go create mode 100644 internal/code/README.md create mode 100644 internal/code/code.go create mode 100644 internal/code/zh-cn.go create mode 100644 internal/cron/cron.go create mode 100644 internal/cron/cron_add_job.go create mode 100644 internal/cron/cron_add_task.go create mode 100644 internal/cron/cron_remove_task.go create mode 100644 internal/cron/cron_start.go create mode 100644 internal/cron/cron_stop.go create mode 100644 internal/cron/cron_stop_job.go create mode 100644 internal/dblogger/request_logger.go create mode 100644 internal/metrics/metrics.go create mode 100644 internal/metrics/prometheus.go create mode 100644 internal/pkg/color/string_darwin.go create mode 100644 internal/pkg/color/string_linux.go create mode 100644 internal/pkg/color/string_windows.go create mode 100644 internal/pkg/core/context.go create mode 100644 internal/pkg/core/core.go create mode 100644 internal/pkg/core/error.go create mode 100644 internal/pkg/cors/cors.go create mode 100644 internal/pkg/cryptoaes/cryptoaes.go create mode 100644 internal/pkg/cryptoaes/cryptoaes_test.go create mode 100644 internal/pkg/cryptorsa/cryptorsa.go create mode 100644 internal/pkg/cryptorsa/cryptorsa_test.go create mode 100644 internal/pkg/debug/logger.go create mode 100644 internal/pkg/env/env.go create mode 100644 internal/pkg/errors/err.go create mode 100644 internal/pkg/errors/err_test.go create mode 100644 internal/pkg/httpclient/client.go create mode 100644 internal/pkg/idgen/idgen.go create mode 100644 internal/pkg/idgen/idgen_test.go create mode 100644 internal/pkg/jsonutil/jsonutil.go create mode 100644 internal/pkg/jwtoken/jwtoken.go create mode 100644 internal/pkg/jwtoken/jwtoken_test.go create mode 100644 internal/pkg/logger/logger.go create mode 100644 internal/pkg/logger/logger_test.go create mode 100644 internal/pkg/shutdown/shutdown.go create mode 100644 internal/pkg/startup/info.go create mode 100644 internal/pkg/timeutil/timeutil.go create mode 100644 internal/pkg/timeutil/timeutil_test.go create mode 100644 internal/pkg/trace/debug.go create mode 100644 internal/pkg/trace/http.go create mode 100644 internal/pkg/trace/mongo.go create mode 100644 internal/pkg/trace/redis.go create mode 100644 internal/pkg/trace/sql.go create mode 100644 internal/pkg/trace/trace.go create mode 100644 internal/pkg/utils/utils.go create mode 100644 internal/pkg/utils/utils_test.go create mode 100644 internal/pkg/validation/validation.go create mode 100644 internal/proposal/alert.go create mode 100644 internal/proposal/metrics.go create mode 100644 internal/proposal/request_logger.go create mode 100644 internal/proposal/session.go create mode 100644 internal/repository/mysql/dao/admin.gen.go create mode 100644 internal/repository/mysql/dao/app_keyword.gen.go create mode 100644 internal/repository/mysql/dao/app_keyword_reply.gen.go create mode 100644 internal/repository/mysql/dao/app_message_log.gen.go create mode 100644 internal/repository/mysql/dao/app_user.gen.go create mode 100644 internal/repository/mysql/dao/article.gen.go create mode 100644 internal/repository/mysql/dao/diagnostic_record.gen.go create mode 100644 internal/repository/mysql/dao/doctor.gen.go create mode 100644 internal/repository/mysql/dao/gen.go create mode 100644 internal/repository/mysql/dao/log_operation.gen.go create mode 100644 internal/repository/mysql/dao/log_request.gen.go create mode 100644 internal/repository/mysql/dao/mini_program.gen.go create mode 100644 internal/repository/mysql/dao/miniprogram_access_token.gen.go create mode 100644 internal/repository/mysql/dao/patient.gen.go create mode 100644 internal/repository/mysql/dao/patient_emergency_symptom.gen.go create mode 100644 internal/repository/mysql/dao/patient_follow_plan.gen.go create mode 100644 internal/repository/mysql/dao/patient_follow_questionnaire.gen.go create mode 100644 internal/repository/mysql/dao/patient_medicine_record.gen.go create mode 100644 internal/repository/mysql/dao/patient_medicine_scheme.gen.go create mode 100644 internal/repository/mysql/dao/patient_medicine_task.gen.go create mode 100644 internal/repository/mysql/dao/sms_verification_code.gen.go create mode 100644 internal/repository/mysql/dao/symptom.gen.go create mode 100644 internal/repository/mysql/model/admin.gen.go create mode 100644 internal/repository/mysql/model/app_keyword.gen.go create mode 100644 internal/repository/mysql/model/app_keyword_reply.gen.go create mode 100644 internal/repository/mysql/model/app_message_log.gen.go create mode 100644 internal/repository/mysql/model/app_user.gen.go create mode 100644 internal/repository/mysql/model/article.gen.go create mode 100644 internal/repository/mysql/model/diagnostic_record.gen.go create mode 100644 internal/repository/mysql/model/doctor.gen.go create mode 100644 internal/repository/mysql/model/log_operation.gen.go create mode 100644 internal/repository/mysql/model/log_request.gen.go create mode 100644 internal/repository/mysql/model/mini_program.gen.go create mode 100644 internal/repository/mysql/model/miniprogram_access_token.gen.go create mode 100644 internal/repository/mysql/model/patient.gen.go create mode 100644 internal/repository/mysql/model/patient_emergency_symptom.gen.go create mode 100644 internal/repository/mysql/model/patient_follow_plan.gen.go create mode 100644 internal/repository/mysql/model/patient_follow_questionnaire.gen.go create mode 100644 internal/repository/mysql/model/patient_medicine_record.gen.go create mode 100644 internal/repository/mysql/model/patient_medicine_scheme.gen.go create mode 100644 internal/repository/mysql/model/patient_medicine_task.gen.go create mode 100644 internal/repository/mysql/model/sms_verification_code.gen.go create mode 100644 internal/repository/mysql/model/symptom.gen.go create mode 100644 internal/repository/mysql/mysql.go create mode 100644 internal/repository/mysql/plugin.go create mode 100644 internal/router/interceptor/admin_auth.go create mode 100644 internal/router/interceptor/interceptor.go create mode 100644 internal/router/router.go create mode 100644 main.go create mode 100644 scripts/swagger.bat create mode 100755 scripts/swagger.sh diff --git a/.gitignore b/.gitignore index 5b90e79..3dc4b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ go.work.sum # env file .env +*.idea + +resources/* \ No newline at end of file diff --git a/README.md b/README.md index 51720b9..f2f6674 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ # mini-chat +## 接口文档 + +- 接口文档:http://127.0.0.1:9991/swagger/index.html +- 心跳检测:http://127.0.0.1:9991/system/health + +## 服务地址 + +- https://mini-chat.1024tool.vip/swagger/index.html + +## 打包命令 + +### MAC +``` +$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags '-w -s' -trimpath -o miniChat +``` diff --git a/cmd/gormgen/README.md b/cmd/gormgen/README.md new file mode 100644 index 0000000..b33018a --- /dev/null +++ b/cmd/gormgen/README.md @@ -0,0 +1,39 @@ +## 自动生成数据库模型和常见的 CRUD 操作 + +### Usage + +```shell +go run cmd/gormgen/main.go -h + +Usage of ./cmd/gormgen/main.go: + -dsn string + consult[https://gorm.io/docs/connecting_to_the_database.html] + -tables string + enter the required data table or leave it blank +``` + +#### -dsn + +用于连接数据库的DSN reference: https://gorm.io/docs/connecting_to_the_database.html + +#### -tables + +指定要生成的表名称,默认所有表。 + +eg : + +```shell +--tables="orders" # generate from `orders` + +--tables="orders,users" # generate from `orders` and `users` + +--tables="" # generate from all tables +``` + +## 示例 + +```shell +# 根目录下执行 +go run cmd/gormgen/main.go -dsn "root:api2api..@tcp(sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555)/mini_chat?charset=utf8mb4&parseTime=True&loc=Local" -tables "log_operation,log_request,admin,app_keyword,app_keyword_reply,app_user,app_message_log,mini_program" + +``` diff --git a/cmd/gormgen/main.go b/cmd/gormgen/main.go new file mode 100644 index 0000000..cb3f586 --- /dev/null +++ b/cmd/gormgen/main.go @@ -0,0 +1,105 @@ +package main + +import ( + "flag" + "log" + "os" + "strings" + + "gorm.io/driver/mysql" + "gorm.io/driver/sqlite" + "gorm.io/gen" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func main() { + dsn := flag.String("dsn", "", "consult[https://gorm.io/docs/connecting_to_the_database.html]") + db := flag.String("db", "", "input mysql|sqlite") + tables := flag.String("tables", "", "enter the required data table or leave it blank") + flag.Parse() + + if *dsn == "" { + log.Fatal("dsn cannot be empty, please provide a valid dsn value.") + } + + if *db == "" { + *db = "mysql" + } + + // 初始化 GORM 数据库连接 + var gormDb *gorm.DB + var err error + var daoPath string + var modelPath string + + switch *db { + case "mysql": + gormDb, err = gorm.Open(mysql.Open(*dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + }, + }) + + daoPath = "/internal/repository/mysql/dao" + modelPath = "/internal/repository/mysql/model" + case "sqlite": + gormDb, err = gorm.Open(sqlite.Open(*dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + }, + }) + + daoPath = "/internal/repository/sqlite/dao" + modelPath = "/internal/repository/sqlite/model" + default: + log.Fatalf("Unsupported database type: %s. Supported types: mysql, sqlite", *db) + } + + if err != nil { + log.Fatalf("failed to connect database: %s", err.Error()) + } + + // 获取当前工作目录 + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting working directory:%s", err.Error()) + } + + // 初始化代码生成器 + g := gen.NewGenerator(gen.Config{ + OutPath: wd + daoPath, // 指定生成代码的输出目录 + ModelPkgPath: wd + modelPath, // 指定模型文件存放的包路径 + Mode: gen.WithoutContext | gen.WithDefaultQuery, + }) + + // 使用已连接的数据库 + g.UseDB(gormDb) + + // 生成表的模型 + tableMaps := strings.Split(*tables, ",") + if len(tableMaps) == 0 || *tables == "" { + g.ApplyBasic( + g.GenerateAllTable()..., + ) + } else { + tableList := make([]string, 0, len(tableMaps)) + for _, tableName := range tableMaps { + _tableName := strings.TrimSpace(string(tableName)) // trim leading and trailing space in tableName + if _tableName == "" { // skip empty tableName + continue + } + tableList = append(tableList, _tableName) + } + + // Execute some data table tasks + models := make([]interface{}, len(tableList)) + for i, tableName := range tableList { + models[i] = g.GenerateModel(tableName) + } + g.ApplyBasic(models...) + } + + // 生成代码 + g.Execute() +} diff --git a/cmd/handlergen/README.md b/cmd/handlergen/README.md new file mode 100644 index 0000000..3b5e397 --- /dev/null +++ b/cmd/handlergen/README.md @@ -0,0 +1,28 @@ +## 自动生成数据库模型和常见的 CRUD 操作 + +### Usage + +```shell +go run cmd/handlergen/main.go -h + +Usage of ./cmd/handlergen/main.go: + -table string + enter the required data table +``` + +#### -table + +指定要生成的表名称。 + +eg : + +```shell +--tables="admin" # generate from `admin` +``` + +## 示例 + +```shell +# 根目录下执行 +go run cmd/handlergen/main.go -table "customer" +``` diff --git a/cmd/handlergen/handler_template.go.tpl b/cmd/handlergen/handler_template.go.tpl new file mode 100644 index 0000000..47ece10 --- /dev/null +++ b/cmd/handlergen/handler_template.go.tpl @@ -0,0 +1,265 @@ +package {{.PackageName}} + +import ( + "net/http" + "strconv" + + "mini-chat/internal/code" + "mini-chat/internal/pkg/core" + "WeChatService/internal/pkg/logger" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/dao" + "mini-chat/internal/repository/mysql/model" + + "go.uber.org/zap" + "gorm.io/gorm" +) + +type handler struct { + logger logger.CustomLoggerLogger + writeDB *dao.Query + readDB *dao.Query +} + +type genResultInfo struct { + RowsAffected int64 `json:"rows_affected"` + Error error `json:"error"` +} + +func New(logger logger.CustomLogger, db mysql.Repo) *handler { + return &handler{ + logger: logger, + writeDB: dao.Use(db.GetDbW()), + readDB: dao.Use(db.GetDbR()), + } +} + +// Create 新增数据 +// @Summary 新增数据 +// @Description 新增数据 +// @Tags API.{{.VariableName}} +// @Accept json +// @Produce json +// @Param RequestBody body model.{{.StructName}} true "请求参数" +// @Success 200 {object} model.{{.StructName}} +// @Failure 400 {object} code.Failure +// @Router /api/{{.VariableName}} [post] +func (h *handler) Create() core.HandlerFunc { + return func(ctx core.Context) { + var createData model.{{.StructName}} + if err := ctx.ShouldBindJSON(&createData); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + err.Error()), + ) + return + } + + if err := h.writeDB.{{.StructName}}.WithContext(ctx.RequestContext()).Create(&createData); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + return + } + + ctx.Payload(createData) + } +} + +// List 获取列表数据 +// @Summary 获取列表数据 +// @Description 获取列表数据 +// @Tags API.{{.VariableName}} +// @Accept json +// @Produce json +// @Success 200 {object} []model.{{.StructName}} +// @Failure 400 {object} code.Failure +// @Router /api/{{.VariableName}}s [get] +func (h *handler) List() core.HandlerFunc { + return func(ctx core.Context) { + list, err := h.readDB.{{.StructName}}.WithContext(ctx.RequestContext()).Find() + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + return + } + + ctx.Payload(list) + } +} + +// GetByID 根据 ID 获取数据 +// @Summary 根据 ID 获取数据 +// @Description 根据 ID 获取数据 +// @Tags API.{{.VariableName}} +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} model.{{.StructName}} +// @Failure 400 {object} code.Failure +// @Router /api/{{.VariableName}}/{id} [get] +func (h *handler) GetByID() core.HandlerFunc { + return func(ctx core.Context) { + id, err := strconv.Atoi(ctx.Param("id")) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + err.Error()), + ) + return + } + + info, err := h.readDB.{{.StructName}}.WithContext(ctx.RequestContext()).Where(h.readDB.{{.StructName}}.ID.Eq(int32(id))).First() + if err != nil { + if err == gorm.ErrRecordNotFound { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + "record not found"), + ) + } else { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + } + return + } + + ctx.Payload(info) + } +} + +// DeleteByID 根据 ID 删除数据 +// @Summary 根据 ID 删除数据 +// @Description 根据 ID 删除数据 +// @Tags API.{{.VariableName}} +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} genResultInfo +// @Failure 400 {object} code.Failure +// @Router /api/{{.VariableName}}/{id} [delete] +func (h *handler) DeleteByID() core.HandlerFunc { + return func(ctx core.Context) { + id, err := strconv.Atoi(ctx.Param("id")) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + err.Error()), + ) + return + } + + info, err := h.readDB.{{.StructName}}.WithContext(ctx.RequestContext()).Where(h.readDB.{{.StructName}}.ID.Eq(int32(id))).First() + if err != nil { + if err == gorm.ErrRecordNotFound { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + "record not found"), + ) + } else { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + } + return + } + + result, err := h.writeDB.{{.StructName}}.Delete(info) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + } + + resultInfo := new(genResultInfo) + resultInfo.RowsAffected = result.RowsAffected + resultInfo.Error = result.Error + + ctx.Payload(resultInfo) + } +} + +// UpdateByID 根据 ID 更新数据 +// @Summary 根据 ID 更新数据 +// @Description 根据 ID 更新数据 +// @Tags API.{{.VariableName}} +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Param RequestBody body model.{{.StructName}} true "请求参数" +// @Success 200 {object} genResultInfo +// @Failure 400 {object} code.Failure +// @Router /api/{{.VariableName}}/{id} [put] +func (h *handler) UpdateByID() core.HandlerFunc { + return func(ctx core.Context) { + id, err := strconv.Atoi(ctx.Param("id")) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + err.Error()), + ) + return + } + + var updateData map[string]interface{} + if err := ctx.ShouldBindJSON(&updateData); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + return + } + + info, err := h.readDB.{{.StructName}}.WithContext(ctx.RequestContext()).Where(h.readDB.{{.StructName}}.ID.Eq(int32(id))).First() + if err != nil { + if err == gorm.ErrRecordNotFound { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + "record not found"), + ) + } else { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + } + return + } + + result, err := h.writeDB.{{.StructName}}.WithContext(ctx.RequestContext()).Where(h.writeDB.{{.StructName}}.ID.Eq(info.ID)).Updates(updateData) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ServerError, + err.Error()), + ) + return + } + + resultInfo := new(genResultInfo) + resultInfo.RowsAffected = result.RowsAffected + resultInfo.Error = result.Error + + ctx.Payload(resultInfo) + } +} diff --git a/cmd/handlergen/main.go b/cmd/handlergen/main.go new file mode 100644 index 0000000..4767d82 --- /dev/null +++ b/cmd/handlergen/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path/filepath" + "strings" + "text/template" +) + +type TemplateData struct { + PackageName string + VariableName string + StructName string +} + +func main() { + table := flag.String("table", "", "enter the required data table") + flag.Parse() + + tableName := *table + if tableName == "" { + log.Fatal("table cannot be empty, please provide a valid table name.") + } + + // 获取当前工作目录 + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting working directory:%s", err.Error()) + } + + // 模板文件路径 + tmplPath := fmt.Sprintf("%s/cmd/handlergen/handler_template.go.tpl", wd) + tmpl, err := template.ParseFiles(tmplPath) + if err != nil { + log.Fatal(err) + } + + log.Printf("Template file parsed: %s", tmplPath) + + // 替换的变量 + data := TemplateData{ + PackageName: tableName, + VariableName: tableName, + StructName: toCamelCase(tableName), + } + + // 生成文件的目录和文件名 + outputDir := fmt.Sprintf("%s/internal/api/%s", wd, tableName) + outputFile := filepath.Join(outputDir, fmt.Sprintf("%s.gen.go", tableName)) + + // 创建目录 + err = os.MkdirAll(outputDir, os.ModePerm) + if err != nil { + log.Fatal(err) + } + + // 创建文件 + file, err := os.Create(outputFile) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + log.Printf("File created: %s", outputFile) + + // 执行模板并生成文件 + err = tmpl.Execute(file, data) + if err != nil { + log.Fatal(err) + } + + log.Println("Template execution completed successfully.") +} + +// 将字符串转为驼峰式命名 +func toCamelCase(s string) string { + // 用下划线分割字符串 + parts := strings.Split(s, "_") + + // 对每个部分首字母大写 + for i := 0; i < len(parts); i++ { + parts[i] = strings.Title(parts[i]) + } + + // 拼接所有部分 + return strings.Join(parts, "") +} diff --git a/cmd/mfmt/README.md b/cmd/mfmt/README.md new file mode 100644 index 0000000..340f2fb --- /dev/null +++ b/cmd/mfmt/README.md @@ -0,0 +1,38 @@ +## 代码格式化工具:`mfmt` + +### 概述 + +`mfmt` 是一个高效的代码格式化工具,旨在帮助开发者按照既定规则格式化 Go 语言代码。它特别关注于 import 语句的分组排序和代码风格的统一。 + +### 功能特点 + +1. **Import 语句分组排序**: + - **标准库**:自动将属于 Go 标准库的包归为一组。 + - **本地模块**:将当前模块名(从 `go.mod` 文件中的 `module` 声明获取)为前缀的包归为一组。 + - **第三方包**:将不属于上述两类的包归为一组。 + +2. **文件和目录跳过规则**: + - 忽略以点(`.`)开头的文件或目录。 + - 忽略非 `.go` 后缀的文件。 + - 忽略 `vendor` 目录。 + - 忽略文件名以 `.pb.go` 或 `gen.go` 结尾的文件。 + +3. **代码格式化**: + - 使用 `format.Source` 对文件内容进行格式化,确保代码符合 Go 的格式标准。 + +### 应用场景 + +- **代码质量检查**:自动检查代码格式,提升代码质量。 +- **项目规范管理**:自动化项目代码规范,减少人工干预。 +- **团队协作**:在团队中保持代码风格的一致性,特别是在 import 组织和注释规范化方面。 + +### 使用方法 + +在项目的根目录下执行以下命令: + +```shell +# 在项目根目录下运行 +go run mfmt/main.go +``` + +这将对项目中的 Go 代码文件进行格式化,按照上述规则重新组织 import 语句,并确保代码风格统一。 \ No newline at end of file diff --git a/cmd/mfmt/main.go b/cmd/mfmt/main.go new file mode 100644 index 0000000..bb4eb1a --- /dev/null +++ b/cmd/mfmt/main.go @@ -0,0 +1,206 @@ +package main + +import ( + "bufio" + "bytes" + "crypto/sha256" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + "mini-chat/internal/pkg/errors" + + "go.uber.org/zap" + "golang.org/x/tools/go/packages" +) + +var stdlib = make(map[string]bool) + +func init() { + pkgs, err := packages.Load(nil, "std") + if err != nil { + log.Fatal("get go stdlib err", zap.Error(err)) + } + + for _, pkg := range pkgs { + if !strings.HasPrefix(pkg.ID, "vendor") { + stdlib[pkg.ID] = true + } + } +} + +var module string + +func init() { + file, err := os.Open("./go.mod") + if err != nil { + log.Fatal("no go.mod file found", zap.Error(err)) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(line, "module ") { + module = strings.TrimSpace(line[7:]) + break + } + } + + if module == "" { + log.Fatal("go.mod illegal") + } +} + +func main() { + wd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting working directory:%s", err.Error()) + } + + err = filepath.Walk(wd, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() || + strings.HasPrefix(path, ".") || + strings.HasPrefix(path, "vendor") || + strings.HasSuffix(path, ".pb.go") || + strings.HasSuffix(path, "gen.go") || + filepath.Ext(path) != ".go" { + return nil + } + + raw, err := ioutil.ReadFile(path) + if err != nil { + return errors.Wrapf(err, "read file %s err", path) + } + + digest0 := sha256.Sum256(raw) + if raw, err = format.Source(raw); err != nil { + return errors.Wrapf(err, "format file %s err", path) + } + + file, err := parser.ParseFile(token.NewFileSet(), "", raw, 0) + if err != nil { + return errors.Wrapf(err, "parse file %s err", path) + } + + var first, last int + var imports []*ast.ImportSpec + comments := make(map[string]string) + + ast.Inspect(file, func(n ast.Node) bool { + switch spec := n.(type) { + case *ast.ImportSpec: + if first == 0 { + first = int(spec.Pos()) + } + last = int(spec.End()) + + imports = append(imports, spec) + + k := last - 1 + for ; k < len(raw); k++ { + if raw[k] == '\r' || raw[k] == '\n' { + break + } + } + + comment := string(raw[last-1 : k]) + if index := strings.Index(comment, "//"); index != -1 { + comments[spec.Path.Value] = strings.TrimSpace(comment[index+2:]) + } + } + return true + }) + + if imports != nil { + buf := bytes.NewBuffer(nil) + buf.Write(raw[:first-2]) + buf.WriteString(sort(imports, comments)) + buf.Write(raw[last-1:]) + + if raw, err = format.Source(buf.Bytes()); err != nil { + return errors.Wrapf(err, "double format file %s err", path) + } + } + + digest1 := sha256.Sum256(raw) + if !bytes.Equal(digest0[:], digest1[:]) { + fmt.Println(path) + } + + if err = ioutil.WriteFile(path, raw, info.Mode()); err != nil { + return errors.Wrapf(err, "write file %s err", path) + } + + return nil + }) + if err != nil { + log.Fatal("scan project err", zap.Error(err)) + } +} + +func sort(imports []*ast.ImportSpec, comments map[string]string) string { + system := bytes.NewBuffer(nil) + group := bytes.NewBuffer(nil) + others := bytes.NewBuffer(nil) + + for _, pkg := range imports { + value := strings.Trim(pkg.Path.Value, `"`) + switch { + case stdlib[value]: + if pkg.Name != nil { + system.WriteString(pkg.Name.String()) + system.WriteString(" ") + } + + system.WriteString(pkg.Path.Value) + if comment, ok := comments[pkg.Path.Value]; ok { + system.WriteString(" ") + system.WriteString("// ") + system.WriteString(comment) + } + system.WriteString("\n") + + case strings.HasPrefix(value, module): + if pkg.Name != nil { + group.WriteString(pkg.Name.String()) + group.WriteString(" ") + } + + group.WriteString(pkg.Path.Value) + if comment, ok := comments[pkg.Path.Value]; ok { + group.WriteString(" ") + group.WriteString("// ") + group.WriteString(comment) + } + group.WriteString("\n") + + default: + if pkg.Name != nil { + others.WriteString(pkg.Name.String()) + others.WriteString(" ") + } + + others.WriteString(pkg.Path.Value) + if comment, ok := comments[pkg.Path.Value]; ok { + others.WriteString(" ") + others.WriteString("// ") + others.WriteString(comment) + } + others.WriteString("\n") + } + } + + return fmt.Sprintf("%s\n%s\n%s", system.String(), group.String(), others.String()) +} diff --git a/configs/configs.go b/configs/configs.go new file mode 100644 index 0000000..76c915e --- /dev/null +++ b/configs/configs.go @@ -0,0 +1,85 @@ +package configs + +import ( + "bytes" + _ "embed" + "io" + + "mini-chat/internal/pkg/env" + + "github.com/spf13/viper" +) + +var config = new(Config) + +type Config struct { + MySQL struct { + Read struct { + Addr string `toml:"addr"` + User string `toml:"user"` + Pass string `toml:"pass"` + Name string `toml:"name"` + } `toml:"read"` + Write struct { + Addr string `toml:"addr"` + User string `toml:"user"` + Pass string `toml:"pass"` + Name string `toml:"name"` + } `toml:"write"` + } `toml:"mysql"` + + JWT struct { + AdminSecret string `toml:"admin_secret"` + PatientSecret string `toml:"patient_secret"` + DoctorSecret string `toml:"doctor_secret"` + } `toml:"jwt"` + + Language struct { + Local string `toml:"local"` + } `toml:"language"` +} + +var ( + //go:embed dev_configs.toml + devConfigs []byte + + //go:embed fat_configs.toml + fatConfigs []byte + + //go:embed uat_configs.toml + uatConfigs []byte + + //go:embed pro_configs.toml + proConfigs []byte +) + +func init() { + var r io.Reader + + switch env.Active().Value() { + case "dev": + r = bytes.NewReader(devConfigs) + case "fat": + r = bytes.NewReader(fatConfigs) + case "uat": + r = bytes.NewReader(uatConfigs) + case "pro": + r = bytes.NewReader(proConfigs) + default: + r = bytes.NewReader(fatConfigs) + } + + viper.SetConfigType("toml") + + if err := viper.ReadConfig(r); err != nil { + panic(err) + } + + if err := viper.Unmarshal(config); err != nil { + panic(err) + } +} + +func Get() Config { + return *config +} diff --git a/configs/constants.go b/configs/constants.go new file mode 100644 index 0000000..ad7b71a --- /dev/null +++ b/configs/constants.go @@ -0,0 +1,55 @@ +package configs + +import ( + "log" + "os" + "path/filepath" + "strings" +) + +const ( + // ProjectName 项目名称 + ProjectName = "mini-chat" + + // ProjectPort 项目端口 + ProjectPort = ":9991" + + // ProjectAccessLogFile 项目访问日志存放文件 + ProjectAccessLogFile = "./logs/" + ProjectName + "-access.log" + + // ZhCN 简体中文 - 中国 + ZhCN = "zh-cn" + + // EnUS 英文 - 美国 + EnUS = "en-us" + + // CustomerProjectNameZh 客户项目中文名称 + CustomerProjectNameZh = "微聊" + + // CustomerProjectNameEn 客户项目英文名称 + CustomerProjectNameEn = "Mini Chat" + + // CustomerProjectVersion 客户项目版本 + CustomerProjectVersion = "Release-2025101601" +) + +// GetResourcesFilePath 获取资源文件路径 +func GetResourcesFilePath() string { + return filepath.Join(getProjectPath(), "resources") +} + +// getProjectPath 获取项目路径 +func getProjectPath() string { + executablePath, err := os.Executable() + if err != nil { + log.Println("Error getting executable path:", err) + return "" + } + + // 检查路径是否含有临时目录特征,这里仅为示例,实际情况可能需要更复杂的判断 + if strings.Contains(executablePath, "/tmp/") || strings.Contains(executablePath, "var/folders/") { + return "" + } else { + return filepath.Dir(executablePath) + } +} diff --git a/configs/dev_configs.toml b/configs/dev_configs.toml new file mode 100644 index 0000000..e69de29 diff --git a/configs/fat_configs.toml b/configs/fat_configs.toml new file mode 100644 index 0000000..4f5c850 --- /dev/null +++ b/configs/fat_configs.toml @@ -0,0 +1,19 @@ +[language] +local = 'zh-cn' + +[mysql.read] +addr = 'sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555' +name = 'mini_chat' +pass = 'api2api..' +user = 'root' + +[mysql.write] +addr = 'sh-cynosdbmysql-grp-88th45wy.sql.tencentcdb.com:28555' +name = 'mini_chat' +pass = 'api2api..' +user = 'root' + +[jwt] +admin_secret = "m9ycX9RTPyuYTWw9FrMm" +patient_secret = "p0yxX0RTPyuYTWw0FrPp" +doctor_secret = "d8ycC8RTPyuYTWw8FrDd" \ No newline at end of file diff --git a/configs/pro_configs.toml b/configs/pro_configs.toml new file mode 100644 index 0000000..139597f --- /dev/null +++ b/configs/pro_configs.toml @@ -0,0 +1,2 @@ + + diff --git a/configs/uat_configs.toml b/configs/uat_configs.toml new file mode 100644 index 0000000..139597f --- /dev/null +++ b/configs/uat_configs.toml @@ -0,0 +1,2 @@ + + diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..093a61d --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,3791 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/admin/article/create": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "新增文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "新增文章", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.createArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.createArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/article/delete": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "删除文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "删除文章", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.deleteArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.deleteArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/article/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "编辑文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "编辑文章", + "parameters": [ + { + "type": "string", + "description": "编号ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.modifyArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.modifyArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/articles": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "文章列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "文章列表", + "parameters": [ + { + "type": "string", + "description": "文章标题", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "开始时间", + "name": "start_time", + "in": "query" + }, + { + "type": "string", + "description": "结束时间", + "name": "end_time", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.listResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/form_policy_token": { + "post": { + "description": "Form 临时访问凭证", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.临时访问凭证" + ], + "summary": "Form 临时访问凭证", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.policyTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/login": { + "post": { + "description": "管理员登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.登录" + ], + "summary": "管理员登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/admin.loginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.loginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/patients": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患者管理" + ], + "summary": "患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术开始时间(格式:2025-06-06)", + "name": "operative_date_start", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁结束结束时间(格式:2025-06-06)", + "name": "operative_date_end", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访开始时间(格式:2025-06-06)", + "name": "next_follow_date_start", + "in": "query" + }, + { + "type": "string", + "description": "下次回访结束时间(格式:2025-06-06)", + "name": "next_follow_date_end", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.patientListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/patients/export": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "导出患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/ms-excel" + ], + "tags": [ + "管理端.患者管理" + ], + "summary": "导出患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术开始时间(格式:2025-06-06)", + "name": "operative_date_start", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁结束结束时间(格式:2025-06-06)", + "name": "operative_date_end", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访开始时间(格式:2025-06-06)", + "name": "next_follow_date_start", + "in": "query" + }, + { + "type": "string", + "description": "下次回访结束时间(格式:2025-06-06)", + "name": "next_follow_date_end", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/policy_token": { + "post": { + "description": "临时访问凭证", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.临时访问凭证" + ], + "summary": "临时访问凭证", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.policyTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/doctor/login": { + "post": { + "description": "医生登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "医生端.登录" + ], + "summary": "医生登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/doctor.loginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/doctor.loginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/doctor/patients": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "医生端.患者列表" + ], + "summary": "患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/doctor.patientListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/articles": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "健康教育文章列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.健康教育" + ], + "summary": "健康教育文章列表", + "parameters": [ + { + "type": "string", + "description": "文章标题", + "name": "title", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.listResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/basic/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.BasicInfoResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/bind_tag": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "设置手术时间标签", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.SCRM" + ], + "summary": "设置手术时间标签", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.bindTagRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.bindTagResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/chat/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.ChatListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/code_login": { + "post": { + "description": "患者验证码登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "患者验证码登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.codeLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.codeLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/diagnostic": { + "post": { + "description": "诊断信息录入", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.诊断信息录入" + ], + "summary": "诊断信息录入", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.diagnosticRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.diagnosticResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/diagnostic/search": { + "post": { + "description": "查询诊断结果", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.诊断信息录入" + ], + "summary": "查询诊断结果", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.searchRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.searchResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/follow_plans": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "随访计划列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.随访" + ], + "summary": "随访计划列表", + "parameters": [ + { + "type": "integer", + "description": "数据类型(1:当前时间之后的随访计划 2:全部的随访计划)", + "name": "type", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.followPlanListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/follow_questionnaire": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "填写随访问卷", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.随访" + ], + "summary": "填写随访问卷", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.followQuestionnaireCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.followQuestionnaireCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/forgot_password": { + "post": { + "description": "忘记密码", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "忘记密码", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.forgotPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.forgotPasswordResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/info": { + "post": { + "description": "智能体信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.患者信息【智能体】" + ], + "summary": "智能体信息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.agentInfoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.agentInfoResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_record/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/patient.schemeRecordModifyResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_records": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "服药记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.服药打卡" + ], + "summary": "服药记录列表", + "parameters": [ + { + "type": "integer", + "description": "时间类型(1:今天 2:近7天 3:近30天 4:近90天)", + "name": "time_type", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "打卡状态(0:不限 1:未完成 2:已完成)", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeRecodeListRequest" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_scheme": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "新增用药方案", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "新增用药方案", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.schemeCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_scheme/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "编辑用药方案", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "编辑用药方案", + "parameters": [ + { + "type": "string", + "description": "编号ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.schemeCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_schemes": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "用药方案列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "用药方案列表", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/password_login": { + "post": { + "description": "患者密码登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "患者密码登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.passwordLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.passwordLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/questionnaire_info": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "随访问卷详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.患者信息【通用】" + ], + "summary": "随访问卷详情", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.questionnaireInfoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/service_patient.QuestionnaireDetailResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/questionnaires/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.QuestionnaireListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/quick_login": { + "post": { + "description": "手机号快捷登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "手机号快捷登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.quickLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.codeLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/send_code": { + "post": { + "description": "发送验证码", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "发送验证码", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.sendCodeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.sendCodeResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/set_personal_information": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "设置个人信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "设置个人信息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.setPersonalInformationRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.setPersonalInformationResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/symptom/submit": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "症状自检提交", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.紧急通道.症状自检" + ], + "summary": "症状自检提交", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.symptomSubmitRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.symptomSubmitResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/symptoms": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "症状列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.紧急通道.症状自检" + ], + "summary": "症状列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.symptomListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + } + }, + "definitions": { + "admin.loginRequest": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, + "admin.loginResponse": { + "type": "object", + "properties": { + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "admin.patientListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "admin.patientListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/admin.patientListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "admin.policyTokenResponse": { + "type": "object", + "properties": { + "token": { + "description": "临时访问凭证", + "type": "string" + } + } + }, + "article.createArticleRequest": { + "type": "object", + "required": [ + "content", + "title" + ], + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.createArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "article.deleteArticleRequest": { + "type": "object", + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "文章ID(多个用,分割)", + "type": "string" + } + } + }, + "article.deleteArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "article.listData": { + "type": "object", + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "created_at": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "文章编号", + "type": "integer" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.listResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/article.listData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "article.modifyArticleRequest": { + "type": "object", + "required": [ + "content", + "title" + ], + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.modifyArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "code.Failure": { + "type": "object", + "properties": { + "code": { + "description": "业务码", + "type": "integer" + }, + "message": { + "description": "描述信息", + "type": "string" + } + } + }, + "doctor.loginRequest": { + "type": "object", + "required": [ + "mobile", + "password" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "doctor.loginResponse": { + "type": "object", + "properties": { + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "doctor.patientListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "doctor.patientListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/doctor.patientListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.agentInfoRequest": { + "type": "object", + "required": [ + "source", + "wx_user_id" + ], + "properties": { + "source": { + "description": "来源(固定值:agent)", + "type": "string" + }, + "wx_user_id": { + "description": "微信用户ID", + "type": "string" + } + } + }, + "patient.agentInfoResponse": { + "type": "object", + "properties": { + "basic_info": { + "description": "基础信息", + "allOf": [ + { + "$ref": "#/definitions/patient.basicInfo" + } + ] + }, + "follow_plan_list": { + "description": "随访计划数据列表", + "type": "array", + "items": { + "$ref": "#/definitions/patient.planList" + } + }, + "follow_questionnaire_list": { + "description": "随访问卷数据列表", + "type": "array", + "items": { + "$ref": "#/definitions/patient.questionnaireDetailList" + } + } + } + }, + "patient.basicInfo": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "ggt_compared": { + "description": "GGT 指数(较上次)", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "patient.bindTagRequest": { + "type": "object", + "required": [ + "wx_user_id" + ], + "properties": { + "wx_user_id": { + "description": "微信ID", + "type": "string" + } + } + }, + "patient.bindTagResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.codeLoginRequest": { + "type": "object", + "required": [ + "code", + "mobile" + ], + "properties": { + "code": { + "description": "验证码", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + } + } + }, + "patient.codeLoginResponse": { + "type": "object", + "properties": { + "is_personal_information_complete": { + "description": "是否完善个人信息", + "type": "boolean" + }, + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "patient.diagnosticRequest": { + "type": "object", + "required": [ + "day", + "gallbladder_image", + "mmp_7", + "mobile", + "portal_vein_branch_image", + "portal_vein_cross_image", + "username" + ], + "properties": { + "day": { + "description": "日龄(天)", + "type": "integer" + }, + "gallbladder_image": { + "description": "胆囊照片", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7检测值", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "用户OPEN ID", + "type": "string" + }, + "portal_vein_branch_image": { + "description": "门静脉左右分支照片", + "type": "string" + }, + "portal_vein_cross_image": { + "description": "门静脉右支横截照片", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.diagnosticResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "OPEN ID", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.followPlanListData": { + "type": "object", + "properties": { + "id": { + "description": "编号", + "type": "integer" + }, + "plan_date": { + "description": "计划日期", + "type": "string" + }, + "plan_name": { + "description": "计划名称", + "type": "string" + }, + "questionnaire_id": { + "description": "随访记录ID", + "type": "integer" + }, + "status": { + "description": "完成状态(1:未完成 2:已完成)", + "type": "integer" + } + } + }, + "patient.followPlanListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.followPlanListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.followQuestionnaireCreateRequest": { + "type": "object", + "required": [ + "follow_date", + "follow_hospital", + "follow_name", + "height", + "weight" + ], + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "plan_id": { + "description": "随访计划ID", + "type": "integer" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "questionnaire_id": { + "description": "随访记录ID(编辑时传递此值)", + "type": "integer" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "patient.followQuestionnaireCreateResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.forgotPasswordRequest": { + "type": "object", + "required": [ + "code", + "mobile", + "password", + "password2" + ], + "properties": { + "code": { + "description": "验证码", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "新密码 (MD5加密后的密码)", + "type": "string" + }, + "password2": { + "description": "确认密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "patient.forgotPasswordResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.listData": { + "type": "object", + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "created_at": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "文章编号", + "type": "integer" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "patient.listResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.listData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.passwordLoginRequest": { + "type": "object", + "required": [ + "mobile", + "password" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "patient.passwordLoginResponse": { + "type": "object", + "properties": { + "is_personal_information_complete": { + "description": "是否完善个人信息", + "type": "boolean" + }, + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "patient.planList": { + "type": "object", + "properties": { + "id": { + "description": "编号", + "type": "integer" + }, + "plan_date": { + "description": "计划日期", + "type": "string" + }, + "plan_name": { + "description": "计划名称", + "type": "string" + } + } + }, + "patient.questionnaireDetailList": { + "type": "object", + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "id": { + "description": "随访记录ID", + "type": "integer" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "patient.questionnaireInfoRequest": { + "type": "object", + "required": [ + "questionnaire_id" + ], + "properties": { + "patient_id": { + "description": "患者ID", + "type": "integer" + }, + "questionnaire_id": { + "description": "随访问卷ID", + "type": "integer" + } + } + }, + "patient.quickLoginRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "description": "动态令牌", + "type": "string" + } + } + }, + "patient.schemeCreateRequest": { + "type": "object", + "required": [ + "detail", + "end_date", + "reminder", + "start_date" + ], + "properties": { + "detail": { + "description": "药品详情(JSON格式)", + "type": "string" + }, + "end_date": { + "description": "结束日期(格式:2025-05-30)", + "type": "string" + }, + "reminder": { + "description": "提醒时间(JSON格式)", + "type": "string" + }, + "start_date": { + "description": "开始日期(格式:2025-05-30)", + "type": "string" + } + } + }, + "patient.schemeCreateResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.schemeListData": { + "type": "object", + "properties": { + "detail": { + "description": "药品信息(JSON格式)", + "type": "string" + }, + "end_date": { + "description": "用药结束日期", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "reminder": { + "description": "用药提醒(JSON格式)", + "type": "string" + }, + "start_date": { + "description": "用药开始日期", + "type": "string" + } + } + }, + "patient.schemeListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.schemeListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.schemeRecodeListRequest": { + "type": "object", + "required": [ + "time_type" + ], + "properties": { + "page": { + "description": "当前页码,默认为第一页", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "status": { + "description": "打卡状态(0:不限 1:未完成 2:已完成)", + "type": "integer" + }, + "time_type": { + "description": "时间类型(1:今天 2:近7天 3:近30天 4:近90天)", + "type": "integer" + } + } + }, + "patient.schemeRecordModifyResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.searchRequest": { + "type": "object", + "required": [ + "mobile", + "user_id", + "username" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "OPEN ID", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.searchResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + }, + "success": { + "description": "查询结果成功与否", + "type": "boolean" + } + } + }, + "patient.sendCodeRequest": { + "type": "object", + "required": [ + "mobile", + "type" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "type": { + "description": "验证码类型(1:登录场景 2:忘记密码场景)", + "type": "integer" + } + } + }, + "patient.sendCodeResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.setPersonalInformationRequest": { + "type": "object", + "required": [ + "birth_number", + "birth_weight", + "birthday", + "conception_type", + "delivery_type", + "gestational_week", + "operative_date", + "parity_number", + "prenatal_check_type", + "sex", + "username" + ], + "properties": { + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "operative_date": { + "description": "手术日期(格式:2025-05-30)", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "sex": { + "description": "性别(1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.setPersonalInformationResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.symptomListData": { + "type": "object", + "properties": { + "description": { + "description": "描述", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "title": { + "description": "症状", + "type": "string" + } + } + }, + "patient.symptomListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.symptomListData" + } + } + } + }, + "patient.symptomSubmitRequest": { + "type": "object", + "required": [ + "detail" + ], + "properties": { + "detail": { + "description": "症状详情", + "type": "string" + } + } + }, + "patient.symptomSubmitResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "service_patient.BasicInfoResponse": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "ggt_compared": { + "description": "GGT 指数(较上次)", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "service_patient.ChatListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/service_patient.chatListData" + } + } + } + }, + "service_patient.QuestionnaireDetailResponse": { + "type": "object", + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "id": { + "description": "随访记录ID", + "type": "integer" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "service_patient.QuestionnaireListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/service_patient.questionnaireListData" + } + } + } + }, + "service_patient.chatListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "id": { + "type": "integer" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + } + } + }, + "service_patient.questionnaireListData": { + "type": "object", + "properties": { + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + } + } + } + }, + "securityDefinitions": { + "LoginVerifyToken": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "v0.0.1", + Host: "", + BasePath: "/", + Schemes: []string{}, + Title: "mini-chat 接口文档", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..83b3e6f --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,3765 @@ +{ + "swagger": "2.0", + "info": { + "title": "mini-chat 接口文档", + "contact": {}, + "version": "v0.0.1" + }, + "basePath": "/", + "paths": { + "/admin/article/create": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "新增文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "新增文章", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.createArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.createArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/article/delete": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "删除文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "删除文章", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.deleteArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.deleteArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/article/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "编辑文章", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "编辑文章", + "parameters": [ + { + "type": "string", + "description": "编号ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/article.modifyArticleRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.modifyArticleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/articles": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "文章列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患教文章" + ], + "summary": "文章列表", + "parameters": [ + { + "type": "string", + "description": "文章标题", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "开始时间", + "name": "start_time", + "in": "query" + }, + { + "type": "string", + "description": "结束时间", + "name": "end_time", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/article.listResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/form_policy_token": { + "post": { + "description": "Form 临时访问凭证", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.临时访问凭证" + ], + "summary": "Form 临时访问凭证", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.policyTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/login": { + "post": { + "description": "管理员登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.登录" + ], + "summary": "管理员登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/admin.loginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.loginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/patients": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.患者管理" + ], + "summary": "患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术开始时间(格式:2025-06-06)", + "name": "operative_date_start", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁结束结束时间(格式:2025-06-06)", + "name": "operative_date_end", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访开始时间(格式:2025-06-06)", + "name": "next_follow_date_start", + "in": "query" + }, + { + "type": "string", + "description": "下次回访结束时间(格式:2025-06-06)", + "name": "next_follow_date_end", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.patientListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/patients/export": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "导出患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/ms-excel" + ], + "tags": [ + "管理端.患者管理" + ], + "summary": "导出患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术开始时间(格式:2025-06-06)", + "name": "operative_date_start", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁结束结束时间(格式:2025-06-06)", + "name": "operative_date_end", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访开始时间(格式:2025-06-06)", + "name": "next_follow_date_start", + "in": "query" + }, + { + "type": "string", + "description": "下次回访结束时间(格式:2025-06-06)", + "name": "next_follow_date_end", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/admin/policy_token": { + "post": { + "description": "临时访问凭证", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "管理端.临时访问凭证" + ], + "summary": "临时访问凭证", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/admin.policyTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/doctor/login": { + "post": { + "description": "医生登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "医生端.登录" + ], + "summary": "医生登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/doctor.loginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/doctor.loginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/doctor/patients": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "患者列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "医生端.患者列表" + ], + "summary": "患者列表", + "parameters": [ + { + "type": "string", + "description": "姓名", + "name": "username", + "in": "query" + }, + { + "type": "string", + "description": "账号", + "name": "mobile", + "in": "query" + }, + { + "type": "string", + "description": "胆道闭锁手术时间(格式:2025-06-06)", + "name": "operative_date", + "in": "query" + }, + { + "type": "string", + "description": "下次回访时间(格式:2025-06-06)", + "name": "next_follow_date", + "in": "query" + }, + { + "type": "integer", + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "name": "risk_type", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/doctor.patientListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/articles": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "健康教育文章列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.健康教育" + ], + "summary": "健康教育文章列表", + "parameters": [ + { + "type": "string", + "description": "文章标题", + "name": "title", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.listResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/basic/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.BasicInfoResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/bind_tag": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "设置手术时间标签", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.SCRM" + ], + "summary": "设置手术时间标签", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.bindTagRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.bindTagResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/chat/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.ChatListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/code_login": { + "post": { + "description": "患者验证码登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "患者验证码登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.codeLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.codeLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/diagnostic": { + "post": { + "description": "诊断信息录入", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.诊断信息录入" + ], + "summary": "诊断信息录入", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.diagnosticRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.diagnosticResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/diagnostic/search": { + "post": { + "description": "查询诊断结果", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.诊断信息录入" + ], + "summary": "查询诊断结果", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.searchRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.searchResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/follow_plans": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "随访计划列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.随访" + ], + "summary": "随访计划列表", + "parameters": [ + { + "type": "integer", + "description": "数据类型(1:当前时间之后的随访计划 2:全部的随访计划)", + "name": "type", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.followPlanListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/follow_questionnaire": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "填写随访问卷", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.随访" + ], + "summary": "填写随访问卷", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.followQuestionnaireCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.followQuestionnaireCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/forgot_password": { + "post": { + "description": "忘记密码", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "忘记密码", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.forgotPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.forgotPasswordResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/info": { + "post": { + "description": "智能体信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.患者信息【智能体】" + ], + "summary": "智能体信息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.agentInfoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.agentInfoResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_record/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/patient.schemeRecordModifyResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_records": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "服药记录列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.首页.服药打卡" + ], + "summary": "服药记录列表", + "parameters": [ + { + "type": "integer", + "description": "时间类型(1:今天 2:近7天 3:近30天 4:近90天)", + "name": "time_type", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "打卡状态(0:不限 1:未完成 2:已完成)", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeRecodeListRequest" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_scheme": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "新增用药方案", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "新增用药方案", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.schemeCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_scheme/{id}": { + "put": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "编辑用药方案", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "编辑用药方案", + "parameters": [ + { + "type": "string", + "description": "编号ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.schemeCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeCreateResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/medicine_schemes": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "用药方案列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.我的.用药方案" + ], + "summary": "用药方案列表", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "当前页码", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "default": 20, + "description": "每页返回的数据量,最多 100 条", + "name": "page_size", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.schemeListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/password_login": { + "post": { + "description": "患者密码登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "患者密码登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.passwordLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.passwordLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/questionnaire_info": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "随访问卷详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.患者信息【通用】" + ], + "summary": "随访问卷详情", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.questionnaireInfoRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/service_patient.QuestionnaireDetailResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/questionnaires/{id}": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "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/service_patient.QuestionnaireListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/quick_login": { + "post": { + "description": "手机号快捷登录", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "手机号快捷登录", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.quickLoginRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.codeLoginResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/send_code": { + "post": { + "description": "发送验证码", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "发送验证码", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.sendCodeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.sendCodeResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/set_personal_information": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "设置个人信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.登录" + ], + "summary": "设置个人信息", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.setPersonalInformationRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.setPersonalInformationResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/symptom/submit": { + "post": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "症状自检提交", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.紧急通道.症状自检" + ], + "summary": "症状自检提交", + "parameters": [ + { + "description": "请求参数", + "name": "RequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/patient.symptomSubmitRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.symptomSubmitResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + }, + "/patient/symptoms": { + "get": { + "security": [ + { + "LoginVerifyToken": [] + } + ], + "description": "症状列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "患者端.紧急通道.症状自检" + ], + "summary": "症状列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/patient.symptomListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/code.Failure" + } + } + } + } + } + }, + "definitions": { + "admin.loginRequest": { + "type": "object", + "required": [ + "password", + "username" + ], + "properties": { + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, + "admin.loginResponse": { + "type": "object", + "properties": { + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "admin.patientListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "admin.patientListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/admin.patientListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "admin.policyTokenResponse": { + "type": "object", + "properties": { + "token": { + "description": "临时访问凭证", + "type": "string" + } + } + }, + "article.createArticleRequest": { + "type": "object", + "required": [ + "content", + "title" + ], + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.createArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "article.deleteArticleRequest": { + "type": "object", + "required": [ + "ids" + ], + "properties": { + "ids": { + "description": "文章ID(多个用,分割)", + "type": "string" + } + } + }, + "article.deleteArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "article.listData": { + "type": "object", + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "created_at": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "文章编号", + "type": "integer" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.listResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/article.listData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "article.modifyArticleRequest": { + "type": "object", + "required": [ + "content", + "title" + ], + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "article.modifyArticleResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "code.Failure": { + "type": "object", + "properties": { + "code": { + "description": "业务码", + "type": "integer" + }, + "message": { + "description": "描述信息", + "type": "string" + } + } + }, + "doctor.loginRequest": { + "type": "object", + "required": [ + "mobile", + "password" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "doctor.loginResponse": { + "type": "object", + "properties": { + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "doctor.patientListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "doctor.patientListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/doctor.patientListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.agentInfoRequest": { + "type": "object", + "required": [ + "source", + "wx_user_id" + ], + "properties": { + "source": { + "description": "来源(固定值:agent)", + "type": "string" + }, + "wx_user_id": { + "description": "微信用户ID", + "type": "string" + } + } + }, + "patient.agentInfoResponse": { + "type": "object", + "properties": { + "basic_info": { + "description": "基础信息", + "allOf": [ + { + "$ref": "#/definitions/patient.basicInfo" + } + ] + }, + "follow_plan_list": { + "description": "随访计划数据列表", + "type": "array", + "items": { + "$ref": "#/definitions/patient.planList" + } + }, + "follow_questionnaire_list": { + "description": "随访问卷数据列表", + "type": "array", + "items": { + "$ref": "#/definitions/patient.questionnaireDetailList" + } + } + } + }, + "patient.basicInfo": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "ggt_compared": { + "description": "GGT 指数(较上次)", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "patient.bindTagRequest": { + "type": "object", + "required": [ + "wx_user_id" + ], + "properties": { + "wx_user_id": { + "description": "微信ID", + "type": "string" + } + } + }, + "patient.bindTagResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.codeLoginRequest": { + "type": "object", + "required": [ + "code", + "mobile" + ], + "properties": { + "code": { + "description": "验证码", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + } + } + }, + "patient.codeLoginResponse": { + "type": "object", + "properties": { + "is_personal_information_complete": { + "description": "是否完善个人信息", + "type": "boolean" + }, + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "patient.diagnosticRequest": { + "type": "object", + "required": [ + "day", + "gallbladder_image", + "mmp_7", + "mobile", + "portal_vein_branch_image", + "portal_vein_cross_image", + "username" + ], + "properties": { + "day": { + "description": "日龄(天)", + "type": "integer" + }, + "gallbladder_image": { + "description": "胆囊照片", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7检测值", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "用户OPEN ID", + "type": "string" + }, + "portal_vein_branch_image": { + "description": "门静脉左右分支照片", + "type": "string" + }, + "portal_vein_cross_image": { + "description": "门静脉右支横截照片", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.diagnosticResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "OPEN ID", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.followPlanListData": { + "type": "object", + "properties": { + "id": { + "description": "编号", + "type": "integer" + }, + "plan_date": { + "description": "计划日期", + "type": "string" + }, + "plan_name": { + "description": "计划名称", + "type": "string" + }, + "questionnaire_id": { + "description": "随访记录ID", + "type": "integer" + }, + "status": { + "description": "完成状态(1:未完成 2:已完成)", + "type": "integer" + } + } + }, + "patient.followPlanListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.followPlanListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.followQuestionnaireCreateRequest": { + "type": "object", + "required": [ + "follow_date", + "follow_hospital", + "follow_name", + "height", + "weight" + ], + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "plan_id": { + "description": "随访计划ID", + "type": "integer" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "questionnaire_id": { + "description": "随访记录ID(编辑时传递此值)", + "type": "integer" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "patient.followQuestionnaireCreateResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.forgotPasswordRequest": { + "type": "object", + "required": [ + "code", + "mobile", + "password", + "password2" + ], + "properties": { + "code": { + "description": "验证码", + "type": "string" + }, + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "新密码 (MD5加密后的密码)", + "type": "string" + }, + "password2": { + "description": "确认密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "patient.forgotPasswordResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.listData": { + "type": "object", + "properties": { + "content": { + "description": "文章内容", + "type": "string" + }, + "cover_image": { + "description": "文章封面图", + "type": "string" + }, + "created_at": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "文章编号", + "type": "integer" + }, + "title": { + "description": "文章标题", + "type": "string" + } + } + }, + "patient.listResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.listData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.passwordLoginRequest": { + "type": "object", + "required": [ + "mobile", + "password" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "password": { + "description": "密码 (MD5加密后的密码)", + "type": "string" + } + } + }, + "patient.passwordLoginResponse": { + "type": "object", + "properties": { + "is_personal_information_complete": { + "description": "是否完善个人信息", + "type": "boolean" + }, + "token": { + "description": "登录成功后颁发的 Token", + "type": "string" + } + } + }, + "patient.planList": { + "type": "object", + "properties": { + "id": { + "description": "编号", + "type": "integer" + }, + "plan_date": { + "description": "计划日期", + "type": "string" + }, + "plan_name": { + "description": "计划名称", + "type": "string" + } + } + }, + "patient.questionnaireDetailList": { + "type": "object", + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "id": { + "description": "随访记录ID", + "type": "integer" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "patient.questionnaireInfoRequest": { + "type": "object", + "required": [ + "questionnaire_id" + ], + "properties": { + "patient_id": { + "description": "患者ID", + "type": "integer" + }, + "questionnaire_id": { + "description": "随访问卷ID", + "type": "integer" + } + } + }, + "patient.quickLoginRequest": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "description": "动态令牌", + "type": "string" + } + } + }, + "patient.schemeCreateRequest": { + "type": "object", + "required": [ + "detail", + "end_date", + "reminder", + "start_date" + ], + "properties": { + "detail": { + "description": "药品详情(JSON格式)", + "type": "string" + }, + "end_date": { + "description": "结束日期(格式:2025-05-30)", + "type": "string" + }, + "reminder": { + "description": "提醒时间(JSON格式)", + "type": "string" + }, + "start_date": { + "description": "开始日期(格式:2025-05-30)", + "type": "string" + } + } + }, + "patient.schemeCreateResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.schemeListData": { + "type": "object", + "properties": { + "detail": { + "description": "药品信息(JSON格式)", + "type": "string" + }, + "end_date": { + "description": "用药结束日期", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "reminder": { + "description": "用药提醒(JSON格式)", + "type": "string" + }, + "start_date": { + "description": "用药开始日期", + "type": "string" + } + } + }, + "patient.schemeListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.schemeListData" + } + }, + "page": { + "description": "当前页码", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "total": { + "description": "符合查询条件的总记录数", + "type": "integer" + } + } + }, + "patient.schemeRecodeListRequest": { + "type": "object", + "required": [ + "time_type" + ], + "properties": { + "page": { + "description": "当前页码,默认为第一页", + "type": "integer" + }, + "page_size": { + "description": "每页返回的数据量", + "type": "integer" + }, + "status": { + "description": "打卡状态(0:不限 1:未完成 2:已完成)", + "type": "integer" + }, + "time_type": { + "description": "时间类型(1:今天 2:近7天 3:近30天 4:近90天)", + "type": "integer" + } + } + }, + "patient.schemeRecordModifyResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.searchRequest": { + "type": "object", + "required": [ + "mobile", + "user_id", + "username" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "open_id": { + "description": "OPEN ID", + "type": "string" + }, + "user_id": { + "description": "用户ID(唯一ID)", + "type": "string" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.searchResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + }, + "success": { + "description": "查询结果成功与否", + "type": "boolean" + } + } + }, + "patient.sendCodeRequest": { + "type": "object", + "required": [ + "mobile", + "type" + ], + "properties": { + "mobile": { + "description": "手机号", + "type": "string" + }, + "type": { + "description": "验证码类型(1:登录场景 2:忘记密码场景)", + "type": "integer" + } + } + }, + "patient.sendCodeResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.setPersonalInformationRequest": { + "type": "object", + "required": [ + "birth_number", + "birth_weight", + "birthday", + "conception_type", + "delivery_type", + "gestational_week", + "operative_date", + "parity_number", + "prenatal_check_type", + "sex", + "username" + ], + "properties": { + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "operative_date": { + "description": "手术日期(格式:2025-05-30)", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "sex": { + "description": "性别(1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + } + } + }, + "patient.setPersonalInformationResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "patient.symptomListData": { + "type": "object", + "properties": { + "description": { + "description": "描述", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + }, + "title": { + "description": "症状", + "type": "string" + } + } + }, + "patient.symptomListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/patient.symptomListData" + } + } + } + }, + "patient.symptomSubmitRequest": { + "type": "object", + "required": [ + "detail" + ], + "properties": { + "detail": { + "description": "症状详情", + "type": "string" + } + } + }, + "patient.symptomSubmitResponse": { + "type": "object", + "properties": { + "message": { + "description": "提示信息", + "type": "string" + } + } + }, + "service_patient.BasicInfoResponse": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "birth_number": { + "description": "产次(0:未知 1:1产 2:2产 3:≥3产)", + "type": "integer" + }, + "birth_weight": { + "description": "出生体重(克)", + "type": "integer" + }, + "birthday": { + "description": "出生日期(格式:2025-05-30)", + "type": "string" + }, + "conception_type": { + "description": "受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)", + "type": "integer" + }, + "delivery_type": { + "description": "分娩方式(0:未知 1:顺产 2:剖宫产)", + "type": "integer" + }, + "gestational_week": { + "description": "孕周", + "type": "integer" + }, + "ggt_compared": { + "description": "GGT 指数(较上次)", + "type": "string" + }, + "height_growth_curve_type": { + "description": "身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + }, + "id_number": { + "description": "身份证号", + "type": "string" + }, + "mobile": { + "description": "账号", + "type": "string" + }, + "next_follow_date": { + "description": "下次随访时间", + "type": "string" + }, + "operative_date": { + "description": "胆道闭锁手术时间", + "type": "string" + }, + "parity_number": { + "description": "胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)", + "type": "integer" + }, + "postoperative_duration": { + "description": "术后时长", + "type": "string" + }, + "prenatal_check_remark": { + "description": "产检异常描述", + "type": "string" + }, + "prenatal_check_type": { + "description": "产检是否异常(0:未知 1:有 2:无)", + "type": "integer" + }, + "risk_type": { + "description": "风险类型(0:未知 1:低危 2:中危 3:高危)", + "type": "integer" + }, + "risk_value": { + "description": "风险值", + "type": "string" + }, + "sex": { + "description": "性别(0:未知 1:男 2:女)", + "type": "integer" + }, + "username": { + "description": "姓名", + "type": "string" + }, + "weight_growth_curve_type": { + "description": "体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)", + "type": "integer" + } + } + }, + "service_patient.ChatListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/service_patient.chatListData" + } + } + } + }, + "service_patient.QuestionnaireDetailResponse": { + "type": "object", + "properties": { + "albumin": { + "description": "白蛋白(g/L)", + "type": "string" + }, + "alp": { + "description": "ALP(U/L)", + "type": "string" + }, + "aptt": { + "description": "APTT(s)", + "type": "string" + }, + "b_mode_image": { + "description": "B超报告(多张用,分割)", + "type": "string" + }, + "blood_routine_image": { + "description": "血常规检查报告(多张用,分割)", + "type": "string" + }, + "coagulation_function_image": { + "description": "凝血功能检查报告(多张用,分割)", + "type": "string" + }, + "common_bile_duct": { + "description": "胆总管(mm)", + "type": "string" + }, + "crp": { + "description": "CRP(mg/L)", + "type": "string" + }, + "ddr": { + "description": "DDR", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "elastography_maximum": { + "description": "弹性成像最大值(kPa)", + "type": "string" + }, + "elastography_median": { + "description": "弹性成像中位数(kPa)", + "type": "string" + }, + "elastography_minimum": { + "description": "弹性成像最小值(kPa)", + "type": "string" + }, + "fib": { + "description": "FIB(g/L)", + "type": "string" + }, + "fiber_block_size": { + "description": "纤维块大小(mm)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "gallbladder_size": { + "description": "胆囊大小(mm)", + "type": "string" + }, + "ggt": { + "description": "GGT(U/L)", + "type": "string" + }, + "grain_grass": { + "description": "谷草(U/L)", + "type": "string" + }, + "gu_bing": { + "description": "谷丙(U/L)", + "type": "string" + }, + "head_circumference": { + "description": "头围(CM)", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "hemoglobin": { + "description": "血红蛋白 (g/L)", + "type": "string" + }, + "high_hip": { + "description": "上臀围(CM)", + "type": "string" + }, + "id": { + "description": "随访记录ID", + "type": "integer" + }, + "inr": { + "description": "INR", + "type": "string" + }, + "is_have_ascites": { + "description": "有无腹水(1:是 2:否)", + "type": "integer" + }, + "is_have_cyst": { + "description": "有无肝囊肿(1:是 2:否)", + "type": "integer" + }, + "liver_echo": { + "description": "肝回声", + "type": "string" + }, + "liver_elasticity_value": { + "description": "肝弹性值", + "type": "string" + }, + "liver_function_image": { + "description": "肝功能检查报告(多张用,分割)", + "type": "string" + }, + "main_portal_vein": { + "description": "门静脉主干内径(mm)", + "type": "string" + }, + "mdt_image": { + "description": "MDT电子病历(多张用,分割)", + "type": "string" + }, + "mmp_7": { + "description": "MMP-7(ng/mL)", + "type": "string" + }, + "npdp": { + "description": "NPDP(mg/L)", + "type": "string" + }, + "nutritional_indicator_image": { + "description": "营养指标检查报告(多张用,分割)", + "type": "string" + }, + "oh_d": { + "description": "25(OH)D (ng/ml)", + "type": "string" + }, + "oh_d2": { + "description": "25(OH)D2 (ng/ml)", + "type": "string" + }, + "oh_d3": { + "description": "25(OH)D3 (ng/ml)", + "type": "string" + }, + "platelets": { + "description": "血小板(10^9/L)", + "type": "string" + }, + "pt": { + "description": "PT(s)", + "type": "string" + }, + "pta": { + "description": "PTA(%)", + "type": "string" + }, + "pvv": { + "description": "门静脉流速", + "type": "string" + }, + "red_blood_cells": { + "description": "红细胞 (10^9/L)", + "type": "string" + }, + "spleen_rib_area": { + "description": "脾肋下(mm)", + "type": "string" + }, + "total_bile_acid": { + "description": "总胆汁酸(g/L)", + "type": "string" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "tt": { + "description": "TT(s)", + "type": "string" + }, + "under_the_liver_rib": { + "description": "肝肋下(mm)", + "type": "string" + }, + "under_the_xiphoid_liver": { + "description": "肝剑突下(mm)", + "type": "string" + }, + "vitamin_a": { + "description": "维生素A (ng/ml)", + "type": "string" + }, + "vitamin_e": { + "description": "维生素E (ng/ml)", + "type": "string" + }, + "vitamin_k": { + "description": "维生素K (ng/ml)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + }, + "white_blood_cells": { + "description": "白细胞 (10^9/L)", + "type": "string" + } + } + }, + "service_patient.QuestionnaireListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/service_patient.questionnaireListData" + } + } + } + }, + "service_patient.chatListData": { + "type": "object", + "properties": { + "age": { + "description": "年龄", + "type": "string" + }, + "direct_bilirubin": { + "description": "直接胆红素(µmol/L)", + "type": "string" + }, + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "height": { + "description": "身高(CM)", + "type": "string" + }, + "id": { + "type": "integer" + }, + "total_bilirubin": { + "description": "总胆红素(µmol/L)", + "type": "string" + }, + "weight": { + "description": "体重(KG)", + "type": "string" + } + } + }, + "service_patient.questionnaireListData": { + "type": "object", + "properties": { + "follow_date": { + "description": "随访日期", + "type": "string" + }, + "follow_hospital": { + "description": "随访医院", + "type": "string" + }, + "follow_name": { + "description": "随访名称", + "type": "string" + }, + "id": { + "description": "编号", + "type": "integer" + } + } + } + }, + "securityDefinitions": { + "LoginVerifyToken": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..38ae37f --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,2588 @@ +basePath: / +definitions: + admin.loginRequest: + properties: + password: + description: 密码 (MD5加密后的密码) + type: string + username: + description: 用户名 + type: string + required: + - password + - username + type: object + admin.loginResponse: + properties: + token: + description: 登录成功后颁发的 Token + type: string + type: object + admin.patientListData: + properties: + age: + description: 年龄 + type: string + height_growth_curve_type: + description: 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + id: + description: 编号 + type: integer + mobile: + description: 账号 + type: string + next_follow_date: + description: 下次随访时间 + type: string + operative_date: + description: 胆道闭锁手术时间 + type: string + postoperative_duration: + description: 术后时长 + type: string + risk_type: + description: 风险类型(0:未知 1:低危 2:中危 3:高危) + type: integer + risk_value: + description: 风险值 + type: string + sex: + description: 性别(0:未知 1:男 2:女) + type: integer + username: + description: 姓名 + type: string + weight_growth_curve_type: + description: 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + type: object + admin.patientListResponse: + properties: + list: + items: + $ref: '#/definitions/admin.patientListData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + admin.policyTokenResponse: + properties: + token: + description: 临时访问凭证 + type: string + type: object + article.createArticleRequest: + properties: + content: + description: 文章内容 + type: string + cover_image: + description: 文章封面图 + type: string + title: + description: 文章标题 + type: string + required: + - content + - title + type: object + article.createArticleResponse: + properties: + message: + description: 提示信息 + type: string + type: object + article.deleteArticleRequest: + properties: + ids: + description: 文章ID(多个用,分割) + type: string + required: + - ids + type: object + article.deleteArticleResponse: + properties: + message: + description: 提示信息 + type: string + type: object + article.listData: + properties: + content: + description: 文章内容 + type: string + cover_image: + description: 文章封面图 + type: string + created_at: + description: 创建时间 + type: string + id: + description: 文章编号 + type: integer + title: + description: 文章标题 + type: string + type: object + article.listResponse: + properties: + list: + items: + $ref: '#/definitions/article.listData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + article.modifyArticleRequest: + properties: + content: + description: 文章内容 + type: string + cover_image: + description: 文章封面图 + type: string + title: + description: 文章标题 + type: string + required: + - content + - title + type: object + article.modifyArticleResponse: + properties: + message: + description: 提示信息 + type: string + type: object + code.Failure: + properties: + code: + description: 业务码 + type: integer + message: + description: 描述信息 + type: string + type: object + doctor.loginRequest: + properties: + mobile: + description: 手机号 + type: string + password: + description: 密码 (MD5加密后的密码) + type: string + required: + - mobile + - password + type: object + doctor.loginResponse: + properties: + token: + description: 登录成功后颁发的 Token + type: string + type: object + doctor.patientListData: + properties: + age: + description: 年龄 + type: string + avatar: + description: 头像 + type: string + height_growth_curve_type: + description: 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + id: + description: 编号 + type: integer + mobile: + description: 账号 + type: string + next_follow_date: + description: 下次随访时间 + type: string + operative_date: + description: 胆道闭锁手术时间 + type: string + postoperative_duration: + description: 术后时长 + type: string + risk_type: + description: 风险类型(0:未知 1:低危 2:中危 3:高危) + type: integer + risk_value: + description: 风险值 + type: string + sex: + description: 性别(0:未知 1:男 2:女) + type: integer + username: + description: 姓名 + type: string + weight_growth_curve_type: + description: 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + type: object + doctor.patientListResponse: + properties: + list: + items: + $ref: '#/definitions/doctor.patientListData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + patient.agentInfoRequest: + properties: + source: + description: 来源(固定值:agent) + type: string + wx_user_id: + description: 微信用户ID + type: string + required: + - source + - wx_user_id + type: object + patient.agentInfoResponse: + properties: + basic_info: + allOf: + - $ref: '#/definitions/patient.basicInfo' + description: 基础信息 + follow_plan_list: + description: 随访计划数据列表 + items: + $ref: '#/definitions/patient.planList' + type: array + follow_questionnaire_list: + description: 随访问卷数据列表 + items: + $ref: '#/definitions/patient.questionnaireDetailList' + type: array + type: object + patient.basicInfo: + properties: + age: + description: 年龄 + type: string + avatar: + description: 头像 + type: string + birth_number: + description: 产次(0:未知 1:1产 2:2产 3:≥3产) + type: integer + birth_weight: + description: 出生体重(克) + type: integer + birthday: + description: 出生日期(格式:2025-05-30) + type: string + conception_type: + description: 受孕方式(0:未知 1:自然受孕 2:辅助生殖技术) + type: integer + delivery_type: + description: 分娩方式(0:未知 1:顺产 2:剖宫产) + type: integer + gestational_week: + description: 孕周 + type: integer + ggt_compared: + description: GGT 指数(较上次) + type: string + height_growth_curve_type: + description: 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + id_number: + description: 身份证号 + type: string + mobile: + description: 账号 + type: string + next_follow_date: + description: 下次随访时间 + type: string + operative_date: + description: 胆道闭锁手术时间 + type: string + parity_number: + description: 胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎) + type: integer + postoperative_duration: + description: 术后时长 + type: string + prenatal_check_remark: + description: 产检异常描述 + type: string + prenatal_check_type: + description: 产检是否异常(0:未知 1:有 2:无) + type: integer + risk_type: + description: 风险类型(0:未知 1:低危 2:中危 3:高危) + type: integer + risk_value: + description: 风险值 + type: string + sex: + description: 性别(0:未知 1:男 2:女) + type: integer + username: + description: 姓名 + type: string + weight_growth_curve_type: + description: 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + type: object + patient.bindTagRequest: + properties: + wx_user_id: + description: 微信ID + type: string + required: + - wx_user_id + type: object + patient.bindTagResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.codeLoginRequest: + properties: + code: + description: 验证码 + type: string + mobile: + description: 手机号 + type: string + required: + - code + - mobile + type: object + patient.codeLoginResponse: + properties: + is_personal_information_complete: + description: 是否完善个人信息 + type: boolean + token: + description: 登录成功后颁发的 Token + type: string + type: object + patient.diagnosticRequest: + properties: + day: + description: 日龄(天) + type: integer + gallbladder_image: + description: 胆囊照片 + type: string + mmp_7: + description: MMP-7检测值 + type: string + mobile: + description: 手机号 + type: string + open_id: + description: 用户OPEN ID + type: string + portal_vein_branch_image: + description: 门静脉左右分支照片 + type: string + portal_vein_cross_image: + description: 门静脉右支横截照片 + type: string + user_id: + description: 用户ID(唯一ID) + type: string + username: + description: 姓名 + type: string + required: + - day + - gallbladder_image + - mmp_7 + - mobile + - portal_vein_branch_image + - portal_vein_cross_image + - username + type: object + patient.diagnosticResponse: + properties: + message: + description: 提示信息 + type: string + mobile: + description: 手机号 + type: string + open_id: + description: OPEN ID + type: string + user_id: + description: 用户ID(唯一ID) + type: string + username: + description: 姓名 + type: string + type: object + patient.followPlanListData: + properties: + id: + description: 编号 + type: integer + plan_date: + description: 计划日期 + type: string + plan_name: + description: 计划名称 + type: string + questionnaire_id: + description: 随访记录ID + type: integer + status: + description: 完成状态(1:未完成 2:已完成) + type: integer + type: object + patient.followPlanListResponse: + properties: + list: + items: + $ref: '#/definitions/patient.followPlanListData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + patient.followQuestionnaireCreateRequest: + properties: + albumin: + description: 白蛋白(g/L) + type: string + alp: + description: ALP(U/L) + type: string + aptt: + description: APTT(s) + type: string + b_mode_image: + description: B超报告(多张用,分割) + type: string + blood_routine_image: + description: 血常规检查报告(多张用,分割) + type: string + coagulation_function_image: + description: 凝血功能检查报告(多张用,分割) + type: string + common_bile_duct: + description: 胆总管(mm) + type: string + crp: + description: CRP(mg/L) + type: string + ddr: + description: DDR + type: string + direct_bilirubin: + description: 直接胆红素(µmol/L) + type: string + elastography_maximum: + description: 弹性成像最大值(kPa) + type: string + elastography_median: + description: 弹性成像中位数(kPa) + type: string + elastography_minimum: + description: 弹性成像最小值(kPa) + type: string + fib: + description: FIB(g/L) + type: string + fiber_block_size: + description: 纤维块大小(mm) + type: string + follow_date: + description: 随访日期 + type: string + follow_hospital: + description: 随访医院 + type: string + follow_name: + description: 随访名称 + type: string + gallbladder_size: + description: 胆囊大小(mm) + type: string + ggt: + description: GGT(U/L) + type: string + grain_grass: + description: 谷草(U/L) + type: string + gu_bing: + description: 谷丙(U/L) + type: string + head_circumference: + description: 头围(CM) + type: string + height: + description: 身高(CM) + type: string + hemoglobin: + description: 血红蛋白 (g/L) + type: string + high_hip: + description: 上臀围(CM) + type: string + inr: + description: INR + type: string + is_have_ascites: + description: 有无腹水(1:是 2:否) + type: integer + is_have_cyst: + description: 有无肝囊肿(1:是 2:否) + type: integer + liver_echo: + description: 肝回声 + type: string + liver_elasticity_value: + description: 肝弹性值 + type: string + liver_function_image: + description: 肝功能检查报告(多张用,分割) + type: string + main_portal_vein: + description: 门静脉主干内径(mm) + type: string + mdt_image: + description: MDT电子病历(多张用,分割) + type: string + mmp_7: + description: MMP-7(ng/mL) + type: string + npdp: + description: NPDP(mg/L) + type: string + nutritional_indicator_image: + description: 营养指标检查报告(多张用,分割) + type: string + oh_d: + description: 25(OH)D (ng/ml) + type: string + oh_d2: + description: 25(OH)D2 (ng/ml) + type: string + oh_d3: + description: 25(OH)D3 (ng/ml) + type: string + plan_id: + description: 随访计划ID + type: integer + platelets: + description: 血小板(10^9/L) + type: string + pt: + description: PT(s) + type: string + pta: + description: PTA(%) + type: string + pvv: + description: 门静脉流速 + type: string + questionnaire_id: + description: 随访记录ID(编辑时传递此值) + type: integer + red_blood_cells: + description: 红细胞 (10^9/L) + type: string + spleen_rib_area: + description: 脾肋下(mm) + type: string + total_bile_acid: + description: 总胆汁酸(g/L) + type: string + total_bilirubin: + description: 总胆红素(µmol/L) + type: string + tt: + description: TT(s) + type: string + under_the_liver_rib: + description: 肝肋下(mm) + type: string + under_the_xiphoid_liver: + description: 肝剑突下(mm) + type: string + vitamin_a: + description: 维生素A (ng/ml) + type: string + vitamin_e: + description: 维生素E (ng/ml) + type: string + vitamin_k: + description: 维生素K (ng/ml) + type: string + weight: + description: 体重(KG) + type: string + white_blood_cells: + description: 白细胞 (10^9/L) + type: string + required: + - follow_date + - follow_hospital + - follow_name + - height + - weight + type: object + patient.followQuestionnaireCreateResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.forgotPasswordRequest: + properties: + code: + description: 验证码 + type: string + mobile: + description: 手机号 + type: string + password: + description: 新密码 (MD5加密后的密码) + type: string + password2: + description: 确认密码 (MD5加密后的密码) + type: string + required: + - code + - mobile + - password + - password2 + type: object + patient.forgotPasswordResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.listData: + properties: + content: + description: 文章内容 + type: string + cover_image: + description: 文章封面图 + type: string + created_at: + description: 创建时间 + type: string + id: + description: 文章编号 + type: integer + title: + description: 文章标题 + type: string + type: object + patient.listResponse: + properties: + list: + items: + $ref: '#/definitions/patient.listData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + patient.passwordLoginRequest: + properties: + mobile: + description: 手机号 + type: string + password: + description: 密码 (MD5加密后的密码) + type: string + required: + - mobile + - password + type: object + patient.passwordLoginResponse: + properties: + is_personal_information_complete: + description: 是否完善个人信息 + type: boolean + token: + description: 登录成功后颁发的 Token + type: string + type: object + patient.planList: + properties: + id: + description: 编号 + type: integer + plan_date: + description: 计划日期 + type: string + plan_name: + description: 计划名称 + type: string + type: object + patient.questionnaireDetailList: + properties: + albumin: + description: 白蛋白(g/L) + type: string + alp: + description: ALP(U/L) + type: string + aptt: + description: APTT(s) + type: string + b_mode_image: + description: B超报告(多张用,分割) + type: string + blood_routine_image: + description: 血常规检查报告(多张用,分割) + type: string + coagulation_function_image: + description: 凝血功能检查报告(多张用,分割) + type: string + common_bile_duct: + description: 胆总管(mm) + type: string + crp: + description: CRP(mg/L) + type: string + ddr: + description: DDR + type: string + direct_bilirubin: + description: 直接胆红素(µmol/L) + type: string + elastography_maximum: + description: 弹性成像最大值(kPa) + type: string + elastography_median: + description: 弹性成像中位数(kPa) + type: string + elastography_minimum: + description: 弹性成像最小值(kPa) + type: string + fib: + description: FIB(g/L) + type: string + fiber_block_size: + description: 纤维块大小(mm) + type: string + follow_date: + description: 随访日期 + type: string + follow_hospital: + description: 随访医院 + type: string + follow_name: + description: 随访名称 + type: string + gallbladder_size: + description: 胆囊大小(mm) + type: string + ggt: + description: GGT(U/L) + type: string + grain_grass: + description: 谷草(U/L) + type: string + gu_bing: + description: 谷丙(U/L) + type: string + head_circumference: + description: 头围(CM) + type: string + height: + description: 身高(CM) + type: string + hemoglobin: + description: 血红蛋白 (g/L) + type: string + high_hip: + description: 上臀围(CM) + type: string + id: + description: 随访记录ID + type: integer + inr: + description: INR + type: string + is_have_ascites: + description: 有无腹水(1:是 2:否) + type: integer + is_have_cyst: + description: 有无肝囊肿(1:是 2:否) + type: integer + liver_echo: + description: 肝回声 + type: string + liver_elasticity_value: + description: 肝弹性值 + type: string + liver_function_image: + description: 肝功能检查报告(多张用,分割) + type: string + main_portal_vein: + description: 门静脉主干内径(mm) + type: string + mdt_image: + description: MDT电子病历(多张用,分割) + type: string + mmp_7: + description: MMP-7(ng/mL) + type: string + npdp: + description: NPDP(mg/L) + type: string + nutritional_indicator_image: + description: 营养指标检查报告(多张用,分割) + type: string + oh_d: + description: 25(OH)D (ng/ml) + type: string + oh_d2: + description: 25(OH)D2 (ng/ml) + type: string + oh_d3: + description: 25(OH)D3 (ng/ml) + type: string + platelets: + description: 血小板(10^9/L) + type: string + pt: + description: PT(s) + type: string + pta: + description: PTA(%) + type: string + pvv: + description: 门静脉流速 + type: string + red_blood_cells: + description: 红细胞 (10^9/L) + type: string + spleen_rib_area: + description: 脾肋下(mm) + type: string + total_bile_acid: + description: 总胆汁酸(g/L) + type: string + total_bilirubin: + description: 总胆红素(µmol/L) + type: string + tt: + description: TT(s) + type: string + under_the_liver_rib: + description: 肝肋下(mm) + type: string + under_the_xiphoid_liver: + description: 肝剑突下(mm) + type: string + vitamin_a: + description: 维生素A (ng/ml) + type: string + vitamin_e: + description: 维生素E (ng/ml) + type: string + vitamin_k: + description: 维生素K (ng/ml) + type: string + weight: + description: 体重(KG) + type: string + white_blood_cells: + description: 白细胞 (10^9/L) + type: string + type: object + patient.questionnaireInfoRequest: + properties: + patient_id: + description: 患者ID + type: integer + questionnaire_id: + description: 随访问卷ID + type: integer + required: + - questionnaire_id + type: object + patient.quickLoginRequest: + properties: + code: + description: 动态令牌 + type: string + required: + - code + type: object + patient.schemeCreateRequest: + properties: + detail: + description: 药品详情(JSON格式) + type: string + end_date: + description: 结束日期(格式:2025-05-30) + type: string + reminder: + description: 提醒时间(JSON格式) + type: string + start_date: + description: 开始日期(格式:2025-05-30) + type: string + required: + - detail + - end_date + - reminder + - start_date + type: object + patient.schemeCreateResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.schemeListData: + properties: + detail: + description: 药品信息(JSON格式) + type: string + end_date: + description: 用药结束日期 + type: string + id: + description: 编号 + type: integer + reminder: + description: 用药提醒(JSON格式) + type: string + start_date: + description: 用药开始日期 + type: string + type: object + patient.schemeListResponse: + properties: + list: + items: + $ref: '#/definitions/patient.schemeListData' + type: array + page: + description: 当前页码 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + total: + description: 符合查询条件的总记录数 + type: integer + type: object + patient.schemeRecodeListRequest: + properties: + page: + description: 当前页码,默认为第一页 + type: integer + page_size: + description: 每页返回的数据量 + type: integer + status: + description: 打卡状态(0:不限 1:未完成 2:已完成) + type: integer + time_type: + description: 时间类型(1:今天 2:近7天 3:近30天 4:近90天) + type: integer + required: + - time_type + type: object + patient.schemeRecordModifyResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.searchRequest: + properties: + mobile: + description: 手机号 + type: string + open_id: + description: OPEN ID + type: string + user_id: + description: 用户ID(唯一ID) + type: string + username: + description: 姓名 + type: string + required: + - mobile + - user_id + - username + type: object + patient.searchResponse: + properties: + message: + description: 提示信息 + type: string + success: + description: 查询结果成功与否 + type: boolean + type: object + patient.sendCodeRequest: + properties: + mobile: + description: 手机号 + type: string + type: + description: 验证码类型(1:登录场景 2:忘记密码场景) + type: integer + required: + - mobile + - type + type: object + patient.sendCodeResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.setPersonalInformationRequest: + properties: + avatar: + description: 头像 + type: string + birth_number: + description: 产次(0:未知 1:1产 2:2产 3:≥3产) + type: integer + birth_weight: + description: 出生体重(克) + type: integer + birthday: + description: 出生日期(格式:2025-05-30) + type: string + conception_type: + description: 受孕方式(0:未知 1:自然受孕 2:辅助生殖技术) + type: integer + delivery_type: + description: 分娩方式(0:未知 1:顺产 2:剖宫产) + type: integer + gestational_week: + description: 孕周 + type: integer + id_number: + description: 身份证号 + type: string + operative_date: + description: 手术日期(格式:2025-05-30) + type: string + parity_number: + description: 胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎) + type: integer + prenatal_check_remark: + description: 产检异常描述 + type: string + prenatal_check_type: + description: 产检是否异常(0:未知 1:有 2:无) + type: integer + sex: + description: 性别(1:男 2:女) + type: integer + username: + description: 姓名 + type: string + required: + - birth_number + - birth_weight + - birthday + - conception_type + - delivery_type + - gestational_week + - operative_date + - parity_number + - prenatal_check_type + - sex + - username + type: object + patient.setPersonalInformationResponse: + properties: + message: + description: 提示信息 + type: string + type: object + patient.symptomListData: + properties: + description: + description: 描述 + type: string + id: + description: 编号 + type: integer + title: + description: 症状 + type: string + type: object + patient.symptomListResponse: + properties: + list: + items: + $ref: '#/definitions/patient.symptomListData' + type: array + type: object + patient.symptomSubmitRequest: + properties: + detail: + description: 症状详情 + type: string + required: + - detail + type: object + patient.symptomSubmitResponse: + properties: + message: + description: 提示信息 + type: string + type: object + service_patient.BasicInfoResponse: + properties: + age: + description: 年龄 + type: string + avatar: + description: 头像 + type: string + birth_number: + description: 产次(0:未知 1:1产 2:2产 3:≥3产) + type: integer + birth_weight: + description: 出生体重(克) + type: integer + birthday: + description: 出生日期(格式:2025-05-30) + type: string + conception_type: + description: 受孕方式(0:未知 1:自然受孕 2:辅助生殖技术) + type: integer + delivery_type: + description: 分娩方式(0:未知 1:顺产 2:剖宫产) + type: integer + gestational_week: + description: 孕周 + type: integer + ggt_compared: + description: GGT 指数(较上次) + type: string + height_growth_curve_type: + description: 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + id_number: + description: 身份证号 + type: string + mobile: + description: 账号 + type: string + next_follow_date: + description: 下次随访时间 + type: string + operative_date: + description: 胆道闭锁手术时间 + type: string + parity_number: + description: 胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎) + type: integer + postoperative_duration: + description: 术后时长 + type: string + prenatal_check_remark: + description: 产检异常描述 + type: string + prenatal_check_type: + description: 产检是否异常(0:未知 1:有 2:无) + type: integer + risk_type: + description: 风险类型(0:未知 1:低危 2:中危 3:高危) + type: integer + risk_value: + description: 风险值 + type: string + sex: + description: 性别(0:未知 1:男 2:女) + type: integer + username: + description: 姓名 + type: string + weight_growth_curve_type: + description: 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + type: integer + type: object + service_patient.ChatListResponse: + properties: + list: + items: + $ref: '#/definitions/service_patient.chatListData' + type: array + type: object + service_patient.QuestionnaireDetailResponse: + properties: + albumin: + description: 白蛋白(g/L) + type: string + alp: + description: ALP(U/L) + type: string + aptt: + description: APTT(s) + type: string + b_mode_image: + description: B超报告(多张用,分割) + type: string + blood_routine_image: + description: 血常规检查报告(多张用,分割) + type: string + coagulation_function_image: + description: 凝血功能检查报告(多张用,分割) + type: string + common_bile_duct: + description: 胆总管(mm) + type: string + crp: + description: CRP(mg/L) + type: string + ddr: + description: DDR + type: string + direct_bilirubin: + description: 直接胆红素(µmol/L) + type: string + elastography_maximum: + description: 弹性成像最大值(kPa) + type: string + elastography_median: + description: 弹性成像中位数(kPa) + type: string + elastography_minimum: + description: 弹性成像最小值(kPa) + type: string + fib: + description: FIB(g/L) + type: string + fiber_block_size: + description: 纤维块大小(mm) + type: string + follow_date: + description: 随访日期 + type: string + follow_hospital: + description: 随访医院 + type: string + follow_name: + description: 随访名称 + type: string + gallbladder_size: + description: 胆囊大小(mm) + type: string + ggt: + description: GGT(U/L) + type: string + grain_grass: + description: 谷草(U/L) + type: string + gu_bing: + description: 谷丙(U/L) + type: string + head_circumference: + description: 头围(CM) + type: string + height: + description: 身高(CM) + type: string + hemoglobin: + description: 血红蛋白 (g/L) + type: string + high_hip: + description: 上臀围(CM) + type: string + id: + description: 随访记录ID + type: integer + inr: + description: INR + type: string + is_have_ascites: + description: 有无腹水(1:是 2:否) + type: integer + is_have_cyst: + description: 有无肝囊肿(1:是 2:否) + type: integer + liver_echo: + description: 肝回声 + type: string + liver_elasticity_value: + description: 肝弹性值 + type: string + liver_function_image: + description: 肝功能检查报告(多张用,分割) + type: string + main_portal_vein: + description: 门静脉主干内径(mm) + type: string + mdt_image: + description: MDT电子病历(多张用,分割) + type: string + mmp_7: + description: MMP-7(ng/mL) + type: string + npdp: + description: NPDP(mg/L) + type: string + nutritional_indicator_image: + description: 营养指标检查报告(多张用,分割) + type: string + oh_d: + description: 25(OH)D (ng/ml) + type: string + oh_d2: + description: 25(OH)D2 (ng/ml) + type: string + oh_d3: + description: 25(OH)D3 (ng/ml) + type: string + platelets: + description: 血小板(10^9/L) + type: string + pt: + description: PT(s) + type: string + pta: + description: PTA(%) + type: string + pvv: + description: 门静脉流速 + type: string + red_blood_cells: + description: 红细胞 (10^9/L) + type: string + spleen_rib_area: + description: 脾肋下(mm) + type: string + total_bile_acid: + description: 总胆汁酸(g/L) + type: string + total_bilirubin: + description: 总胆红素(µmol/L) + type: string + tt: + description: TT(s) + type: string + under_the_liver_rib: + description: 肝肋下(mm) + type: string + under_the_xiphoid_liver: + description: 肝剑突下(mm) + type: string + vitamin_a: + description: 维生素A (ng/ml) + type: string + vitamin_e: + description: 维生素E (ng/ml) + type: string + vitamin_k: + description: 维生素K (ng/ml) + type: string + weight: + description: 体重(KG) + type: string + white_blood_cells: + description: 白细胞 (10^9/L) + type: string + type: object + service_patient.QuestionnaireListResponse: + properties: + list: + items: + $ref: '#/definitions/service_patient.questionnaireListData' + type: array + type: object + service_patient.chatListData: + properties: + age: + description: 年龄 + type: string + direct_bilirubin: + description: 直接胆红素(µmol/L) + type: string + follow_date: + description: 随访日期 + type: string + height: + description: 身高(CM) + type: string + id: + type: integer + total_bilirubin: + description: 总胆红素(µmol/L) + type: string + weight: + description: 体重(KG) + type: string + type: object + service_patient.questionnaireListData: + properties: + follow_date: + description: 随访日期 + type: string + follow_hospital: + description: 随访医院 + type: string + follow_name: + description: 随访名称 + type: string + id: + description: 编号 + type: integer + type: object +info: + contact: {} + title: mini-chat 接口文档 + version: v0.0.1 +paths: + /admin/article/{id}: + put: + consumes: + - application/json + description: 编辑文章 + parameters: + - description: 编号ID + in: path + name: id + required: true + type: string + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/article.modifyArticleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/article.modifyArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 编辑文章 + tags: + - 管理端.患教文章 + /admin/article/create: + post: + consumes: + - application/json + description: 新增文章 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/article.createArticleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/article.createArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 新增文章 + tags: + - 管理端.患教文章 + /admin/article/delete: + post: + consumes: + - application/json + description: 删除文章 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/article.deleteArticleRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/article.deleteArticleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 删除文章 + tags: + - 管理端.患教文章 + /admin/articles: + get: + consumes: + - application/json + description: 文章列表 + parameters: + - description: 文章标题 + in: query + name: title + type: string + - description: 开始时间 + in: query + name: start_time + type: string + - description: 结束时间 + in: query + name: end_time + type: string + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/article.listResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 文章列表 + tags: + - 管理端.患教文章 + /admin/form_policy_token: + post: + consumes: + - application/json + description: Form 临时访问凭证 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/admin.policyTokenResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: Form 临时访问凭证 + tags: + - 管理端.临时访问凭证 + /admin/login: + post: + consumes: + - application/json + description: 管理员登录 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/admin.loginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/admin.loginResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 管理员登录 + tags: + - 管理端.登录 + /admin/patients: + get: + consumes: + - application/json + description: 患者列表 + parameters: + - description: 姓名 + in: query + name: username + type: string + - description: 账号 + in: query + name: mobile + type: string + - description: 胆道闭锁手术时间(格式:2025-06-06) + in: query + name: operative_date + type: string + - description: 胆道闭锁手术开始时间(格式:2025-06-06) + in: query + name: operative_date_start + type: string + - description: 胆道闭锁结束结束时间(格式:2025-06-06) + in: query + name: operative_date_end + type: string + - description: 下次回访时间(格式:2025-06-06) + in: query + name: next_follow_date + type: string + - description: 下次回访开始时间(格式:2025-06-06) + in: query + name: next_follow_date_start + type: string + - description: 下次回访结束时间(格式:2025-06-06) + in: query + name: next_follow_date_end + type: string + - description: 风险类型(0:未知 1:低危 2:中危 3:高危) + in: query + name: risk_type + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/admin.patientListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 患者列表 + tags: + - 管理端.患者管理 + /admin/patients/export: + get: + consumes: + - application/json + description: 导出患者列表 + parameters: + - description: 姓名 + in: query + name: username + type: string + - description: 账号 + in: query + name: mobile + type: string + - description: 胆道闭锁手术时间(格式:2025-06-06) + in: query + name: operative_date + type: string + - description: 胆道闭锁手术开始时间(格式:2025-06-06) + in: query + name: operative_date_start + type: string + - description: 胆道闭锁结束结束时间(格式:2025-06-06) + in: query + name: operative_date_end + type: string + - description: 下次回访时间(格式:2025-06-06) + in: query + name: next_follow_date + type: string + - description: 下次回访开始时间(格式:2025-06-06) + in: query + name: next_follow_date_start + type: string + - description: 下次回访结束时间(格式:2025-06-06) + in: query + name: next_follow_date_end + type: string + - description: 风险类型(0:未知 1:低危 2:中危 3:高危) + in: query + name: risk_type + type: integer + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/ms-excel + responses: + "200": + description: OK + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 导出患者列表 + tags: + - 管理端.患者管理 + /admin/policy_token: + post: + consumes: + - application/json + description: 临时访问凭证 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/admin.policyTokenResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 临时访问凭证 + tags: + - 管理端.临时访问凭证 + /doctor/login: + post: + consumes: + - application/json + description: 医生登录 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/doctor.loginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/doctor.loginResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 医生登录 + tags: + - 医生端.登录 + /doctor/patients: + get: + consumes: + - application/json + description: 患者列表 + parameters: + - description: 姓名 + in: query + name: username + type: string + - description: 账号 + in: query + name: mobile + type: string + - description: 胆道闭锁手术时间(格式:2025-06-06) + in: query + name: operative_date + type: string + - description: 下次回访时间(格式:2025-06-06) + in: query + name: next_follow_date + type: string + - description: 风险类型(0:未知 1:低危 2:中危 3:高危) + in: query + name: risk_type + type: integer + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/doctor.patientListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 患者列表 + tags: + - 医生端.患者列表 + /patient/articles: + get: + consumes: + - application/json + description: 健康教育文章列表 + parameters: + - description: 文章标题 + in: query + name: title + type: string + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.listResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 健康教育文章列表 + tags: + - 患者端.我的.健康教育 + /patient/basic/{id}: + 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/service_patient.BasicInfoResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 基本信息 + tags: + - 患者端.患者信息【通用】 + /patient/bind_tag: + post: + consumes: + - application/json + description: 设置手术时间标签 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.bindTagRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.bindTagResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 设置手术时间标签 + tags: + - 患者端.SCRM + /patient/chat/{id}: + 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/service_patient.ChatListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 图表数据列表 + tags: + - 患者端.患者信息【通用】 + /patient/code_login: + post: + consumes: + - application/json + description: 患者验证码登录 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.codeLoginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.codeLoginResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 患者验证码登录 + tags: + - 患者端.登录 + /patient/diagnostic: + post: + consumes: + - application/json + description: 诊断信息录入 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.diagnosticRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.diagnosticResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 诊断信息录入 + tags: + - 患者端.诊断信息录入 + /patient/diagnostic/search: + post: + consumes: + - application/json + description: 查询诊断结果 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.searchRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.searchResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 查询诊断结果 + tags: + - 患者端.诊断信息录入 + /patient/follow_plans: + get: + consumes: + - application/json + description: 随访计划列表 + parameters: + - description: 数据类型(1:当前时间之后的随访计划 2:全部的随访计划) + in: query + name: type + required: true + type: integer + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.followPlanListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 随访计划列表 + tags: + - 患者端.首页.随访 + /patient/follow_questionnaire: + post: + consumes: + - application/json + description: 填写随访问卷 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.followQuestionnaireCreateRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.followQuestionnaireCreateResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 填写随访问卷 + tags: + - 患者端.首页.随访 + /patient/forgot_password: + post: + consumes: + - application/json + description: 忘记密码 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.forgotPasswordRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.forgotPasswordResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 忘记密码 + tags: + - 患者端.登录 + /patient/info: + post: + consumes: + - application/json + description: 智能体信息 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.agentInfoRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.agentInfoResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 智能体信息 + tags: + - 患者端.患者信息【智能体】 + /patient/medicine_record/{id}: + put: + 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/patient.schemeRecordModifyResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 服药打卡 + tags: + - 患者端.首页.服药打卡 + /patient/medicine_records: + get: + consumes: + - application/json + description: 服药记录列表 + parameters: + - description: 时间类型(1:今天 2:近7天 3:近30天 4:近90天) + in: query + name: time_type + required: true + type: integer + - description: 打卡状态(0:不限 1:未完成 2:已完成) + in: query + name: status + type: integer + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.schemeRecodeListRequest' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 服药记录列表 + tags: + - 患者端.首页.服药打卡 + /patient/medicine_scheme: + post: + consumes: + - application/json + description: 新增用药方案 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.schemeCreateRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.schemeCreateResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 新增用药方案 + tags: + - 患者端.我的.用药方案 + /patient/medicine_scheme/{id}: + put: + consumes: + - application/json + description: 编辑用药方案 + parameters: + - description: 编号ID + in: path + name: id + required: true + type: string + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.schemeCreateRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.schemeCreateResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 编辑用药方案 + tags: + - 患者端.我的.用药方案 + /patient/medicine_schemes: + get: + consumes: + - application/json + description: 用药方案列表 + parameters: + - default: 1 + description: 当前页码 + in: query + name: page + required: true + type: integer + - default: 20 + description: 每页返回的数据量,最多 100 条 + in: query + name: page_size + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.schemeListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 用药方案列表 + tags: + - 患者端.我的.用药方案 + /patient/password_login: + post: + consumes: + - application/json + description: 患者密码登录 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.passwordLoginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.passwordLoginResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 患者密码登录 + tags: + - 患者端.登录 + /patient/questionnaire_info: + post: + consumes: + - application/json + description: 随访问卷详情 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.questionnaireInfoRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/service_patient.QuestionnaireDetailResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 随访问卷详情 + tags: + - 患者端.患者信息【通用】 + /patient/questionnaires/{id}: + 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/service_patient.QuestionnaireListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 随访问卷列表 + tags: + - 患者端.患者信息【通用】 + /patient/quick_login: + post: + consumes: + - application/json + description: 手机号快捷登录 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.quickLoginRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.codeLoginResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 手机号快捷登录 + tags: + - 患者端.登录 + /patient/send_code: + post: + consumes: + - application/json + description: 发送验证码 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.sendCodeRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.sendCodeResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + summary: 发送验证码 + tags: + - 患者端.登录 + /patient/set_personal_information: + get: + consumes: + - application/json + description: 设置个人信息 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.setPersonalInformationRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.setPersonalInformationResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 设置个人信息 + tags: + - 患者端.登录 + /patient/symptom/submit: + post: + consumes: + - application/json + description: 症状自检提交 + parameters: + - description: 请求参数 + in: body + name: RequestBody + required: true + schema: + $ref: '#/definitions/patient.symptomSubmitRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.symptomSubmitResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 症状自检提交 + tags: + - 患者端.紧急通道.症状自检 + /patient/symptoms: + get: + consumes: + - application/json + description: 症状列表 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/patient.symptomListResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/code.Failure' + security: + - LoginVerifyToken: [] + summary: 症状列表 + tags: + - 患者端.紧急通道.症状自检 +securityDefinitions: + LoginVerifyToken: + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bf4f311 --- /dev/null +++ b/go.mod @@ -0,0 +1,110 @@ +module mini-chat + +go 1.19 + +require ( + github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 + github.com/alibabacloud-go/openapi-util v0.1.1 + github.com/alibabacloud-go/tea v1.3.9 + github.com/alibabacloud-go/tea-utils/v2 v2.0.7 + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible + github.com/aliyun/credentials-go v1.4.6 + github.com/bwmarrin/snowflake v0.3.0 + github.com/bytedance/sonic v1.13.2 + github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be + github.com/fatih/color v1.14.1 + github.com/gin-contrib/pprof v1.4.0 + github.com/gin-gonic/gin v1.9.1 + github.com/go-playground/locales v0.14.1 + github.com/go-playground/universal-translator v0.18.1 + github.com/go-playground/validator/v10 v10.15.0 + github.com/go-resty/resty/v2 v2.10.0 + github.com/golang-jwt/jwt/v5 v5.2.0 + github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5 + github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.17.0 + github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644 + github.com/spf13/cast v1.5.1 + github.com/spf13/viper v1.17.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.2 + github.com/tealeg/xlsx v1.0.5 + go.uber.org/multierr v1.10.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.27.0 + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + gopkg.in/natefinch/lumberjack.v2 v2.2.1 + gorm.io/driver/mysql v1.5.2 + gorm.io/driver/sqlite v1.4.3 + gorm.io/gen v0.3.26 + gorm.io/gorm v1.25.9 + gorm.io/plugin/dbresolver v1.5.0 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect + github.com/alibabacloud-go/debug v1.0.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/clbanning/mxj/v2 v2.7.0 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-sqlite3 v1.14.15 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/mapstructure v1.5.0 // 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.1.0 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect + github.com/rs/cors v1.8.1 // indirect + github.com/sagikazarmark/locafero v0.3.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.10.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.4.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect + gorm.io/hints v1.1.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5fd5a1d --- /dev/null +++ b/go.sum @@ -0,0 +1,845 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g= +github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY= +github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8= +github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= +github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7 h1:ASXSBga98QrGMxbIThCD6jAti09gedLfvry6yJtsoBE= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7/go.mod h1:TBpgqm3XofZz2LCYjZhektGPU7ArEgascyzbm4SjFo4= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= +github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= +github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= +github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28= +github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea v1.3.8/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= +github.com/alibabacloud-go/tea v1.3.9 h1:bjgt1bvdY780vz/17iWNNtbXl4A77HWntWMeaUF3So0= +github.com/alibabacloud-go/tea v1.3.9/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= +github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= +github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8Y0ClOk= +github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= +github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg= +github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +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.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +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.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw= +github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5 h1:kCvm3G3u+eTRbjfLPyfsfznJtraYEfZer/UvQ6CaQhI= +github.com/jakecoffman/cron v0.0.0-20190106200828-7e2009c226a5/go.mod h1:6DM2KNNK69jRu0lAHmYK9LYxmqpNjYHOaNp/ZxttD4U= +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.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= +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/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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rs/cors v1.8.1 h1:OrP+y5H+5Md29ACTA9imbALaKHwOSUZkcizaG0LT5ow= +github.com/rs/cors v1.8.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644 h1:BBwREPixt0iE77C9z7DOenoeh5OGFrzyL1cWOp5oQTs= +github.com/rs/cors/wrapper/gin v0.0.0-20231013084403-73f81b45a644/go.mod h1:gmu40DuK3SLdKUzGOUofS3UDZwyeOUy6ZjPPuaALatw= +github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= +github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= +github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE= +github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= +golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +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.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/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.0.0-20220811171246-fbc7d0a398ab/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.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +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.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/datatypes v1.1.1-0.20230130040222-c43177d3cf8c h1:jWdr7cHgl8c/ua5vYbR2WhSp+NQmzhsj0xoY3foTzW8= +gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c/go.mod h1:SH2K9R+2RMjuX1CkCONrPwoe9JzVv2hkQvEu4bXGojE= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= +gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= +gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= +gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8= +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= +gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= +gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY= +gorm.io/gen v0.3.26/go.mod h1:a5lq5y3w4g5LMxBcw0wnO6tYUCdNutWODq5LrIt75LE= +gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8= +gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw= +gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y= +gorm.io/plugin/dbresolver v1.5.0 h1:XVHLxh775eP0CqVh3vcfJtYqja3uFl5Wr3cKlY8jgDY= +gorm.io/plugin/dbresolver v1.5.0/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/alert/alert.go b/internal/alert/alert.go new file mode 100644 index 0000000..daea1ef --- /dev/null +++ b/internal/alert/alert.go @@ -0,0 +1,11 @@ +package alert + +import ( + "mini-chat/internal/proposal" +) + +func NotifyHandler() func(msg *proposal.AlertMessage) { + return func(msg *proposal.AlertMessage) { + + } +} diff --git a/internal/api/admin/admin.go b/internal/api/admin/admin.go new file mode 100644 index 0000000..4841444 --- /dev/null +++ b/internal/api/admin/admin.go @@ -0,0 +1,21 @@ +package admin + +import ( + "mini-chat/internal/pkg/logger" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/dao" +) + +type handler struct { + logger logger.CustomLogger + writeDB *dao.Query + readDB *dao.Query +} + +func New(logger logger.CustomLogger, db mysql.Repo) *handler { + return &handler{ + logger: logger, + writeDB: dao.Use(db.GetDbW()), + readDB: dao.Use(db.GetDbR()), + } +} diff --git a/internal/api/admin/func_login.go b/internal/api/admin/func_login.go new file mode 100644 index 0000000..c51b9b1 --- /dev/null +++ b/internal/api/admin/func_login.go @@ -0,0 +1,125 @@ +package admin + +import ( + "fmt" + "net/http" + "time" + + "mini-chat/configs" + "mini-chat/internal/code" + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/jwtoken" + "mini-chat/internal/pkg/utils" + "mini-chat/internal/pkg/validation" + "mini-chat/internal/proposal" + + "gorm.io/gorm" +) + +type loginRequest struct { + Username string `json:"username" binding:"required"` // 用户名 + Password string `json:"password" binding:"required"` // 密码 (MD5加密后的密码) +} + +type loginResponse struct { + Token string `json:"token"` // 登录成功后颁发的 Token +} + +// Login 管理员登录 +// @Summary 管理员登录 +// @Description 管理员登录 +// @Tags 管理端.登录 +// @Accept json +// @Produce json +// @Param RequestBody body loginRequest true "请求参数" +// @Success 200 {object} loginResponse +// @Failure 400 {object} code.Failure +// @Router /admin/login [post] +func (h *handler) Login() core.HandlerFunc { + return func(ctx core.Context) { + req := new(loginRequest) + res := new(loginResponse) + if err := ctx.ShouldBindJSON(req); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.ParamBindError, + validation.Error(err)), + ) + return + } + + // 验证用户是否存在 + info, err := h.readDB.Admin.WithContext(ctx.RequestContext()).Where(h.readDB.Admin.Username.Eq(req.Username)).First() + if err != nil && err != gorm.ErrRecordNotFound { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s: %s", code.Text(code.AdminLoginError), err.Error())), + ) + return + } + + if err == gorm.ErrRecordNotFound { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s: %s", code.Text(code.AdminLoginError), "账号不存在,请联系管理员。")), + ) + return + } + + // 验证登录状态 + if info.LoginStatus != 1 { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s:账号已被禁用", code.Text(code.AdminLoginError))), + ) + return + } + + // 验证密码 + if !utils.VerifyAdminHashedPassword(info.Password, req.Password) { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s:用户名或密码错误,请联系管理员。", code.Text(code.AdminLoginError))), + ) + return + } + + // 设置 Session 信息 + sessionUserInfo := proposal.SessionUserInfo{ + Id: info.ID, + UserName: info.Username, + NickName: info.Nickname, + Platform: "管理端", + } + + // 设置载荷数据、有效期,生成 JWT Token String + tokenString, err := jwtoken.New(configs.Get().JWT.AdminSecret).Sign(sessionUserInfo, 3*24*time.Hour) + if err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s:token 生成失败(%s)", code.Text(code.AdminLoginError), err.Error())), + ) + return + } + + info.LastLoginTime = time.Now() + info.LastLoginIP = utils.GetIP(ctx.Request()) + info.LastLoginHash = utils.MD5(tokenString) + if err := h.writeDB.Admin.WithContext(ctx.RequestContext()).Save(info); err != nil { + ctx.AbortWithError(core.Error( + http.StatusBadRequest, + code.AdminLoginError, + fmt.Sprintf("%s:%s", code.Text(code.AdminLoginError), err.Error())), + ) + return + } + + res.Token = tokenString + ctx.Payload(res) + } +} diff --git a/internal/code/README.md b/internal/code/README.md new file mode 100644 index 0000000..2b09761 --- /dev/null +++ b/internal/code/README.md @@ -0,0 +1,13 @@ +## 错误码规则 + +- 错误码需在 `code` 包中进行定义。 + +#### 错误码为 5 位数 + +| 1 | 01 | 01 | +| :------ | :------ | :------ | +| 服务级错误码 | 模块级错误码 | 具体错误码 | + +- 服务级错误码:1 位数进行表示,比如 1 为系统级错误;2 为普通错误,通常是由用户非法操作引起。 +- 模块级错误码:2 位数进行表示,比如 01 为用户模块;02 为订单模块。 +- 具体的错误码:2 位数进行表示,比如 01 为手机号不合法;02 为验证码输入错误。 \ No newline at end of file diff --git a/internal/code/code.go b/internal/code/code.go new file mode 100644 index 0000000..8ba3b5f --- /dev/null +++ b/internal/code/code.go @@ -0,0 +1,34 @@ +package code + +import ( + _ "embed" + + "mini-chat/configs" +) + +//go:embed code.go +var ByteCodeFile []byte + +// Failure 错误时返回结构 +type Failure struct { + Code int `json:"code"` // 业务码 + Message string `json:"message"` // 描述信息 +} + +const ( + ServerError = 10101 + ParamBindError = 10102 + JWTAuthVerifyError = 10103 + + AdminLoginError = 20101 +) + +func Text(code int) string { + lang := configs.Get().Language.Local + + if lang == configs.ZhCN { + return zhCNText[code] + } + + return zhCNText[code] +} diff --git a/internal/code/zh-cn.go b/internal/code/zh-cn.go new file mode 100644 index 0000000..0ca77f2 --- /dev/null +++ b/internal/code/zh-cn.go @@ -0,0 +1,9 @@ +package code + +var zhCNText = map[int]string{ + ServerError: "内部服务器错误", + ParamBindError: "参数错误", + JWTAuthVerifyError: "JWT 授权验证错误", + + AdminLoginError: "登录失败", +} diff --git a/internal/cron/cron.go b/internal/cron/cron.go new file mode 100644 index 0000000..86b96d5 --- /dev/null +++ b/internal/cron/cron.go @@ -0,0 +1,97 @@ +package cron + +import ( + "context" + "sync" + + "mini-chat/internal/pkg/errors" + "mini-chat/internal/pkg/logger" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/model" + + "github.com/jakecoffman/cron" +) + +var _ Server = (*server)(nil) + +type taskCount struct { + wg sync.WaitGroup + exit chan struct{} +} + +func (tc *taskCount) i() {} + +func (tc *taskCount) Add() { + tc.wg.Add(1) +} + +func (tc *taskCount) Done() { + tc.wg.Done() +} + +func (tc *taskCount) Exit() { + tc.wg.Done() + <-tc.exit +} + +func (tc *taskCount) Wait() { + tc.Add() + tc.wg.Wait() + close(tc.exit) +} + +type server struct { + logger logger.CustomLogger + db mysql.Repo + cron *cron.Cron + taskCount *taskCount + taskContext map[string]context.CancelFunc // 存储任务的取消上下文 + mu sync.Mutex // 保护 taskContext 的互斥 +} + +type Server interface { + i() + + // Start 启动 cron 服务 + Start() + + // Stop 停止 cron 服务 + Stop() + + // AddTask 增加定时任务 + AddTask(task *model.PatientMedicineTask) + + // AddJob 增加定时任务执行的工作内容 + AddJob(task *model.PatientMedicineTask, execUser string) cron.FuncJob + + // StopJob 停止定时任务 + StopJob(taskCode string) + + // RemoveTask 删除定时任务 + RemoveTask(taskCode string) + + Entries() []*cron.Entry +} + +func New(logger logger.CustomLogger, db mysql.Repo) (Server, error) { + if logger == nil { + return nil, errors.New("logger required") + } + + return &server{ + logger: logger, + cron: cron.New(), + db: db, + taskCount: &taskCount{ + wg: sync.WaitGroup{}, + exit: make(chan struct{}), + }, + taskContext: make(map[string]context.CancelFunc), + }, nil +} + +func (s *server) i() {} + +func (s *server) Entries() []*cron.Entry { + return s.cron.Entries() +} diff --git a/internal/cron/cron_add_job.go b/internal/cron/cron_add_job.go new file mode 100644 index 0000000..fc38acc --- /dev/null +++ b/internal/cron/cron_add_job.go @@ -0,0 +1,35 @@ +package cron + +import ( + "context" + "fmt" + + "mini-chat/internal/repository/mysql/model" + + "github.com/jakecoffman/cron" +) + +func (s *server) AddJob(task *model.PatientMedicineTask, execUser string) cron.FuncJob { + _, cancel := context.WithCancel(context.Background()) + + s.mu.Lock() + s.taskContext[task.Code] = cancel + s.mu.Unlock() + + return func() { + s.taskCount.Add() + defer func() { + s.taskCount.Done() + + s.mu.Lock() + delete(s.taskContext, task.Code) // 清理任务上下文 + s.mu.Unlock() + + if err := recover(); err != nil { + s.logger.Error(fmt.Sprintf("[定时任务] 任务编码:%s, 执行异常: %+v", task.Code, err)) + } + }() + + // 执行任务 + } +} diff --git a/internal/cron/cron_add_task.go b/internal/cron/cron_add_task.go new file mode 100644 index 0000000..7d3a3a0 --- /dev/null +++ b/internal/cron/cron_add_task.go @@ -0,0 +1,21 @@ +package cron + +import ( + "fmt" + "strings" + + "mini-chat/internal/repository/mysql/model" +) + +func (s *server) AddTask(task *model.PatientMedicineTask) { + defer func() { + if err := recover(); err != nil { + s.logger.Error(fmt.Sprintf("[定时任务] 任务编号: %s, 添加异常: %+v", task.Code, err)) + } + }() + + spec := "0 " + strings.TrimSpace(task.Spec) + name := fmt.Sprintf("cron_task_%s", task.Code) + + s.cron.AddFunc(spec, s.AddJob(task, "定时任务"), name) +} diff --git a/internal/cron/cron_remove_task.go b/internal/cron/cron_remove_task.go new file mode 100644 index 0000000..e6533e2 --- /dev/null +++ b/internal/cron/cron_remove_task.go @@ -0,0 +1,7 @@ +package cron + +import "fmt" + +func (s *server) RemoveTask(taskCode string) { + s.cron.RemoveJob(fmt.Sprintf("cron_task_%s", taskCode)) +} diff --git a/internal/cron/cron_start.go b/internal/cron/cron_start.go new file mode 100644 index 0000000..67dce36 --- /dev/null +++ b/internal/cron/cron_start.go @@ -0,0 +1,14 @@ +package cron + +func (s *server) Start() { + s.cron.Start() + go s.taskCount.Wait() + + // 初始化任务 + s.initTask() +} + +// initTask 初始化任务 +func (s *server) initTask() { + +} diff --git a/internal/cron/cron_stop.go b/internal/cron/cron_stop.go new file mode 100644 index 0000000..b818524 --- /dev/null +++ b/internal/cron/cron_stop.go @@ -0,0 +1,6 @@ +package cron + +func (s *server) Stop() { + s.cron.Stop() + s.taskCount.Exit() +} diff --git a/internal/cron/cron_stop_job.go b/internal/cron/cron_stop_job.go new file mode 100644 index 0000000..7540f26 --- /dev/null +++ b/internal/cron/cron_stop_job.go @@ -0,0 +1,17 @@ +package cron + +import ( + "fmt" +) + +func (s *server) StopJob(taskCode string) { + s.mu.Lock() + cancel, ok := s.taskContext[taskCode] + s.mu.Unlock() + + if ok { + cancel() // 调取消函数停止任务 + } else { + s.logger.Info(fmt.Sprintf("任务未找到: %s", taskCode)) + } +} diff --git a/internal/dblogger/request_logger.go b/internal/dblogger/request_logger.go new file mode 100644 index 0000000..164181e --- /dev/null +++ b/internal/dblogger/request_logger.go @@ -0,0 +1,38 @@ +package dblogger + +import ( + "fmt" + "log" + "time" + + "mini-chat/internal/proposal" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/dao" + "mini-chat/internal/repository/mysql/model" + + "github.com/spf13/cast" +) + +func LoggerHandler(db mysql.Repo) func(msg *proposal.RequestLoggerMessage) { + return func(msg *proposal.RequestLoggerMessage) { + logData := new(model.LogRequest) + logData.Tid = msg.Tid + logData.Username = msg.Username + logData.Host = msg.HOST + logData.Path = msg.Path + logData.Method = msg.Method + logData.HTTPCode = int32(msg.HTTPCode) + logData.BusinessCode = int32(msg.BusinessCode) + logData.CostMilliseconds = float64(cast.ToFloat32(fmt.Sprintf("%.2f", msg.CostSeconds*1000))) + logData.IsSuccess = -1 + if msg.IsSuccess == true { + logData.IsSuccess = 1 + } + logData.Content = msg.Content + logData.CreatedAt = time.Now() + + if err := dao.Use(db.GetDbW()).LogRequest.Create(logData); err != nil { + log.Println(fmt.Sprintf("日志写入失败: %s", err.Error())) + } + } +} diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go new file mode 100644 index 0000000..e267459 --- /dev/null +++ b/internal/metrics/metrics.go @@ -0,0 +1,19 @@ +package metrics + +import ( + "mini-chat/internal/proposal" +) + +// RecordHandler 指标处理 +func RecordHandler() func(msg *proposal.MetricsMessage) { + return func(msg *proposal.MetricsMessage) { + RecordMetrics( + msg.Method, + msg.Path, + msg.IsSuccess, + msg.HTTPCode, + msg.BusinessCode, + msg.CostSeconds, + ) + } +} diff --git a/internal/metrics/prometheus.go b/internal/metrics/prometheus.go new file mode 100644 index 0000000..82f476f --- /dev/null +++ b/internal/metrics/prometheus.go @@ -0,0 +1,59 @@ +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/spf13/cast" +) + +const ( + namespace = "custom_namespace" + subsystem = "gin_api_mono" +) + +// metricsRequestsTotal metrics for request total 计数器(Counter) +var metricsRequestsTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "requests_total", + Help: "request(ms) total", + }, + []string{"method", "path"}, +) + +// metricsRequestsCost metrics for requests cost 累积直方图(Histogram) +var metricsRequestsCost = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: "requests_cost", + Help: "request(ms) cost milliseconds", + }, + []string{"method", "path", "success", "http_code", "business_code", "cost_milliseconds"}, +) + +// 根据需要,可定制其他指标,操作如下: +// 1. 定义需要的指标 +// 2. init() 中注册 +// 3. RecordMetrics() 中传值 + +func init() { + prometheus.MustRegister(metricsRequestsTotal, metricsRequestsCost) +} + +// RecordMetrics 记录指标 +func RecordMetrics(method, path string, success bool, httpCode, businessCode int, costSeconds float64) { + metricsRequestsTotal.With(prometheus.Labels{ + "method": method, + "path": path, + }).Inc() + + metricsRequestsCost.With(prometheus.Labels{ + "method": method, + "path": path, + "success": cast.ToString(success), + "http_code": cast.ToString(httpCode), + "business_code": cast.ToString(businessCode), + "cost_milliseconds": cast.ToString(costSeconds * 1000), + }).Observe(costSeconds) +} diff --git a/internal/pkg/color/string_darwin.go b/internal/pkg/color/string_darwin.go new file mode 100644 index 0000000..4dacb96 --- /dev/null +++ b/internal/pkg/color/string_darwin.go @@ -0,0 +1,47 @@ +//go:build darwin +// +build darwin + +package color + +import ( + "fmt" + "math/rand" + "strconv" +) + +var _ = RandomColor() + +// RandomColor generates a random color. +func RandomColor() string { + return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16)) +} + +// Yellow ... +func Yellow(msg string) string { + return fmt.Sprintf("\x1b[33m%s\x1b[0m", msg) +} + +// Red ... +func Red(msg string) string { + return fmt.Sprintf("\x1b[31m%s\x1b[0m", msg) +} + +// Redf ... +func Redf(msg string, arg interface{}) string { + return fmt.Sprintf("\x1b[31m%s\x1b[0m %+v\n", msg, arg) +} + +// Blue ... +func Blue(msg string) string { + return fmt.Sprintf("\x1b[34m%s\x1b[0m", msg) +} + +// Green ... +func Green(msg string) string { + return fmt.Sprintf("\x1b[32m%s\x1b[0m", msg) +} + +// Greenf ... +func Greenf(msg string, arg interface{}) string { + return fmt.Sprintf("\x1b[32m%s\x1b[0m %+v\n", msg, arg) +} diff --git a/internal/pkg/color/string_linux.go b/internal/pkg/color/string_linux.go new file mode 100644 index 0000000..48120fd --- /dev/null +++ b/internal/pkg/color/string_linux.go @@ -0,0 +1,47 @@ +//go:build linux +// +build linux + +package color + +import ( + "fmt" + "math/rand" + "strconv" +) + +var _ = RandomColor() + +// RandomColor generates a random color. +func RandomColor() string { + return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16)) +} + +// Yellow ... +func Yellow(msg string) string { + return fmt.Sprintf("\x1b[33m%s\x1b[0m", msg) +} + +// Red ... +func Red(msg string) string { + return fmt.Sprintf("\x1b[31m%s\x1b[0m", msg) +} + +// Redf ... +func Redf(msg string, arg interface{}) string { + return fmt.Sprintf("\x1b[31m%s\x1b[0m %+v\n", msg, arg) +} + +// Blue ... +func Blue(msg string) string { + return fmt.Sprintf("\x1b[34m%s\x1b[0m", msg) +} + +// Green ... +func Green(msg string) string { + return fmt.Sprintf("\x1b[32m%s\x1b[0m", msg) +} + +// Greenf ... +func Greenf(msg string, arg interface{}) string { + return fmt.Sprintf("\x1b[32m%s\x1b[0m %+v\n", msg, arg) +} diff --git a/internal/pkg/color/string_windows.go b/internal/pkg/color/string_windows.go new file mode 100644 index 0000000..98ad6e4 --- /dev/null +++ b/internal/pkg/color/string_windows.go @@ -0,0 +1,47 @@ +//go:build windows +// +build windows + +package color + +import ( + "fmt" + "math/rand" + "strconv" +) + +var _ = RandomColor() + +// RandomColor generates a random color. +func RandomColor() string { + return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16)) +} + +// Yellow ... +func Yellow(msg string) string { + return fmt.Sprintf("%s", msg) +} + +// Red ... +func Red(msg string) string { + return fmt.Sprintf("%s", msg) +} + +// Redf ... +func Redf(msg string, arg interface{}) string { + return fmt.Sprintf("%s %+v\n", msg, arg) +} + +// Blue ... +func Blue(msg string) string { + return fmt.Sprintf("%s", msg) +} + +// Green ... +func Green(msg string) string { + return fmt.Sprintf("%s", msg) +} + +// Greenf ... +func Greenf(msg string, arg interface{}) string { + return fmt.Sprintf("%s %+v\n", msg, arg) +} diff --git a/internal/pkg/core/context.go b/internal/pkg/core/context.go new file mode 100644 index 0000000..2a7b3cd --- /dev/null +++ b/internal/pkg/core/context.go @@ -0,0 +1,462 @@ +package core + +import ( + "bytes" + stdctx "context" + "fmt" + "io/ioutil" + "mime/multipart" + "net/http" + "net/url" + "path" + "strings" + "sync" + + "mini-chat/internal/pkg/logger" + "mini-chat/internal/pkg/trace" + "mini-chat/internal/proposal" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +type HandlerFunc func(c Context) + +type Trace = trace.T + +const ( + _Alias = "_alias_" + _TraceName = "_trace_" + _LoggerName = "_logger_" + _BodyName = "_body_" + _PayloadName = "_payload_" + _SessionUserInfo = "_session_user_info" + _AbortErrorName = "_abort_error_" + _IsRecordMetrics = "_is_record_metrics_" +) + +var contextPool = &sync.Pool{ + New: func() interface{} { + return new(context) + }, +} + +func newContext(ctx *gin.Context) Context { + context := contextPool.Get().(*context) + context.ctx = ctx + return context +} + +func releaseContext(ctx Context) { + c := ctx.(*context) + c.ctx = nil + contextPool.Put(c) +} + +var _ Context = (*context)(nil) + +type Context interface { + init() + + // ShouldBindQuery 反序列化 querystring + // tag: `form:"xxx"` (注:不要写成 query) + ShouldBindQuery(obj interface{}) error + + // ShouldBindPostForm 反序列化 postform (querystring会被忽略) + // tag: `form:"xxx"` + ShouldBindPostForm(obj interface{}) error + + // ShouldBindForm 同时反序列化 querystring 和 postform; + // 当 querystring 和 postform 存在相同字段时,postform 优先使用。 + // tag: `form:"xxx"` + ShouldBindForm(obj interface{}) error + + // ShouldBindJSON 反序列化 postjson + // tag: `json:"xxx"` + ShouldBindJSON(obj interface{}) error + + // ShouldBindXML 反序列化 xml + // tag: `xml:"xxx"` + ShouldBindXML(obj interface{}) error + + // ShouldBindURI 反序列化 path 参数(如路由路径为 /user/:name) + // tag: `uri:"xxx"` + ShouldBindURI(obj interface{}) error + + // Redirect 重定向 + Redirect(code int, location string) + + // Trace 获取 Trace 对象 + Trace() Trace + setTrace(trace Trace) + disableTrace() + + // Logger 获取 Logger 对象 + Logger() logger.CustomLogger + setLogger(logger logger.CustomLogger) + + // Payload 正确返回 + Payload(payload interface{}) + getPayload() interface{} + + // File 文件下载 + File(filePath string) + + // HTML 返回界面 + HTML(name string, obj interface{}) + + // String 返回字符串 + String(str string) + + // XML 返回 XML + XML(obj interface{}) + + // ExcelData 返回二进制数据 + ExcelData(filename string, byteData []byte) + + // FormFile 通过表单上传文件 + FormFile(name string) (*multipart.FileHeader, error) + + // SaveUploadedFile 将表单文件上传到本地 + SaveUploadedFile(file *multipart.FileHeader, dst string) error + + // AbortWithError 错误返回 + AbortWithError(err BusinessError) + abortError() BusinessError + + // Header 获取 Header 对象 + Header() http.Header + // GetHeader 获取 Header + GetHeader(key string) string + // SetHeader 设置 Header + SetHeader(key, value string) + + // SessionUserInfo 当前用户信息 + SessionUserInfo() proposal.SessionUserInfo + setSessionUserInfo(info proposal.SessionUserInfo) + + // Alias 设置路由别名 for metrics path + Alias() string + setAlias(path string) + + // disableRecordMetrics 设置禁止记录指标 + disableRecordMetrics() + ableRecordMetrics() + isRecordMetrics() bool + + // RequestInputParams 获取所有参数 + RequestInputParams() url.Values + // RequestPostFormParams 获取 PostForm 参数 + RequestPostFormParams() url.Values + // RequestPathParams 获取路由参数的值 + RequestPathParams(key string) string + // Request 获取 Request 对象 + Request() *http.Request + // RawData 获取 Request.Body + RawData() []byte + // Method 获取 Request.Method + Method() string + // Host 获取 Request.Host + Host() string + // Path 获取 请求的路径 Request.URL.Path (不附带 querystring) + Path() string + // URI 获取 unescape 后的 Request.URL.RequestURI() + URI() string + // RequestContext 获取请求的 context (当 client 关闭后,会自动 canceled) + RequestContext() StdContext + + // ResponseWriter 获取 ResponseWriter 对象 + ResponseWriter() gin.ResponseWriter + + // Param 获取 URL 参数 + Param(key string) string +} + +type context struct { + ctx *gin.Context +} + +type StdContext struct { + stdctx.Context + Trace + logger.CustomLogger +} + +func (c *context) init() { + body, err := c.ctx.GetRawData() + if err != nil { + panic(err) + } + + c.ctx.Set(_BodyName, body) // cache body是为了trace使用 + c.ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // re-construct req body +} + +// ShouldBindQuery 反序列化querystring +// tag: `form:"xxx"` (注:不要写成query) +func (c *context) ShouldBindQuery(obj interface{}) error { + return c.ctx.ShouldBindWith(obj, binding.Query) +} + +// ShouldBindPostForm 反序列化 postform (querystring 会被忽略) +// tag: `form:"xxx"` +func (c *context) ShouldBindPostForm(obj interface{}) error { + return c.ctx.ShouldBindWith(obj, binding.FormPost) +} + +// ShouldBindForm 同时反序列化querystring和postform; +// 当querystring和postform存在相同字段时,postform优先使用。 +// tag: `form:"xxx"` +func (c *context) ShouldBindForm(obj interface{}) error { + return c.ctx.ShouldBindWith(obj, binding.Form) +} + +// ShouldBindJSON 反序列化postjson +// tag: `json:"xxx"` +func (c *context) ShouldBindJSON(obj interface{}) error { + return c.ctx.ShouldBindWith(obj, binding.JSON) +} + +// ShouldBindXML 反序列化xml +// tag: `xml:"xxx"` +func (c *context) ShouldBindXML(obj interface{}) error { + return c.ctx.ShouldBindWith(obj, binding.XML) +} + +// ShouldBindURI 反序列化path参数(如路由路径为 /user/:name) +// tag: `uri:"xxx"` +func (c *context) ShouldBindURI(obj interface{}) error { + return c.ctx.ShouldBindUri(obj) +} + +// Redirect 重定向 +func (c *context) Redirect(code int, location string) { + c.ctx.Redirect(code, location) +} + +func (c *context) Trace() Trace { + t, ok := c.ctx.Get(_TraceName) + if !ok || t == nil { + return nil + } + + return t.(Trace) +} + +func (c *context) setTrace(trace Trace) { + c.ctx.Set(_TraceName, trace) +} + +func (c *context) disableTrace() { + c.setTrace(nil) +} + +func (c *context) Logger() logger.CustomLogger { + getLogger, ok := c.ctx.Get(_LoggerName) + if !ok { + return nil + } + + return getLogger.(logger.CustomLogger) +} + +func (c *context) setLogger(logger logger.CustomLogger) { + c.ctx.Set(_LoggerName, logger) +} + +func (c *context) getPayload() interface{} { + if payload, ok := c.ctx.Get(_PayloadName); ok != false { + return payload + } + return nil +} + +func (c *context) Payload(payload interface{}) { + c.ctx.Set(_PayloadName, payload) +} + +func (c *context) File(filePath string) { + c.ctx.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", path.Base(filePath))) + c.ctx.Writer.Header().Add("Content-Type", "application/octet-stream") + c.ctx.File(filePath) +} + +func (c *context) HTML(name string, obj interface{}) { + c.ctx.HTML(200, name+".html", obj) +} + +func (c *context) String(str string) { + c.ctx.String(200, str) +} + +func (c *context) XML(obj interface{}) { + c.ctx.XML(200, obj) +} + +func (c *context) ExcelData(fileName string, data []byte) { + c.ctx.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", url.QueryEscape(fileName))) + c.ctx.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + c.ctx.Data(http.StatusOK, "application/vnd.ms-excel", data) +} + +func (c *context) FormFile(name string) (*multipart.FileHeader, error) { + return c.ctx.FormFile(name) +} + +func (c *context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { + return c.ctx.SaveUploadedFile(file, dst) +} + +func (c *context) Header() http.Header { + header := c.ctx.Request.Header + + clone := make(http.Header, len(header)) + for k, v := range header { + value := make([]string, len(v)) + copy(value, v) + + clone[k] = value + } + return clone +} + +func (c *context) GetHeader(key string) string { + return c.ctx.GetHeader(key) +} + +func (c *context) SetHeader(key, value string) { + c.ctx.Header(key, value) +} + +func (c *context) SessionUserInfo() proposal.SessionUserInfo { + val, ok := c.ctx.Get(_SessionUserInfo) + if !ok { + return proposal.SessionUserInfo{} + } + + return val.(proposal.SessionUserInfo) +} + +func (c *context) setSessionUserInfo(info proposal.SessionUserInfo) { + c.ctx.Set(_SessionUserInfo, info) +} + +func (c *context) AbortWithError(err BusinessError) { + if err != nil { + httpCode := err.HTTPCode() + if httpCode == 0 { + httpCode = http.StatusInternalServerError + } + + c.ctx.AbortWithStatus(httpCode) + c.ctx.Set(_AbortErrorName, err) + } +} + +func (c *context) abortError() BusinessError { + err, _ := c.ctx.Get(_AbortErrorName) + return err.(BusinessError) +} + +func (c *context) Alias() string { + path, ok := c.ctx.Get(_Alias) + if !ok { + return "" + } + + return path.(string) +} + +func (c *context) setAlias(path string) { + if path = strings.TrimSpace(path); path != "" { + c.ctx.Set(_Alias, path) + } +} + +func (c *context) isRecordMetrics() bool { + isRecordMetrics, ok := c.ctx.Get(_IsRecordMetrics) + if !ok { + return false + } + + return isRecordMetrics.(bool) +} + +func (c *context) ableRecordMetrics() { + c.ctx.Set(_IsRecordMetrics, true) +} + +func (c *context) disableRecordMetrics() { + c.ctx.Set(_IsRecordMetrics, false) +} + +// RequestInputParams 获取所有参数 +func (c *context) RequestInputParams() url.Values { + _ = c.ctx.Request.ParseForm() + return c.ctx.Request.Form +} + +// RequestPostFormParams 获取 PostForm 参数 +func (c *context) RequestPostFormParams() url.Values { + _ = c.ctx.Request.ParseForm() + return c.ctx.Request.PostForm +} + +// RequestPathParams 获取路由参数的值 +func (c *context) RequestPathParams(key string) string { + return c.ctx.Param(key) +} + +// Request 获取 Request +func (c *context) Request() *http.Request { + return c.ctx.Request +} + +func (c *context) RawData() []byte { + body, ok := c.ctx.Get(_BodyName) + if !ok { + return nil + } + + return body.([]byte) +} + +// Method 请求的method +func (c *context) Method() string { + return c.ctx.Request.Method +} + +// Host 请求的host +func (c *context) Host() string { + return c.ctx.Request.Host +} + +// Path 请求的路径(不附带querystring) +func (c *context) Path() string { + return c.ctx.Request.URL.Path +} + +// URI unescape后的uri +func (c *context) URI() string { + uri, _ := url.QueryUnescape(c.ctx.Request.URL.RequestURI()) + return uri +} + +// RequestContext (包装 Trace + Logger) 获取请求的 context (当client关闭后,会自动canceled) +func (c *context) RequestContext() StdContext { + return StdContext{ + c.ctx.Request.Context(), + c.Trace(), + c.Logger(), + } +} + +// ResponseWriter 获取 ResponseWriter +func (c *context) ResponseWriter() gin.ResponseWriter { + return c.ctx.Writer +} + +// Param 获取 URL 参数 +func (c *context) Param(key string) string { + return c.ctx.Param(key) +} diff --git a/internal/pkg/core/core.go b/internal/pkg/core/core.go new file mode 100644 index 0000000..0de94c5 --- /dev/null +++ b/internal/pkg/core/core.go @@ -0,0 +1,549 @@ +package core + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "runtime/debug" + "time" + + "mini-chat/configs" + _ "mini-chat/docs" + "mini-chat/internal/code" + "mini-chat/internal/pkg/cors" + "mini-chat/internal/pkg/env" + "mini-chat/internal/pkg/errors" + "mini-chat/internal/pkg/logger" + "mini-chat/internal/pkg/startup" + "mini-chat/internal/pkg/timeutil" + "mini-chat/internal/pkg/trace" + "mini-chat/internal/proposal" + + "github.com/gin-contrib/pprof" + "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus/promhttp" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" + "go.uber.org/multierr" + "go.uber.org/zap" +) + +type Option func(*option) + +type option struct { + enablePProf bool + enableSwagger bool + enablePrometheus bool + enableCors bool + alertNotify proposal.AlertHandler + recordHandler proposal.RecordHandler + requestLoggerHandler proposal.RequestLoggerHandler +} + +// WithEnablePProf 启用 pprof +func WithEnablePProf() Option { + return func(opt *option) { + opt.enablePProf = true + } +} + +// WithEnableSwagger 启用 swagger +func WithEnableSwagger() Option { + return func(opt *option) { + opt.enableSwagger = true + } +} + +// WithEnablePrometheus 启用 prometheus +func WithEnablePrometheus(recordHandler proposal.RecordHandler) Option { + return func(opt *option) { + opt.enablePrometheus = true + opt.recordHandler = recordHandler + } +} + +// WithAlertNotify 设置告警通知 +func WithAlertNotify(alertHandler proposal.AlertHandler) Option { + return func(opt *option) { + opt.alertNotify = alertHandler + } +} + +// WithRequestLogger 设置请求日志 +func WithRequestLogger(loggerHandler proposal.RequestLoggerHandler) Option { + return func(opt *option) { + opt.requestLoggerHandler = loggerHandler + } +} + +// WithEnableCors 设置支持跨域 +func WithEnableCors() Option { + return func(opt *option) { + opt.enableCors = true + } +} + +// DisableTraceLog 禁止记录日志 +func DisableTraceLog(ctx Context) { + ctx.disableTrace() +} + +// DisableRecordMetrics 禁止记录指标 +func DisableRecordMetrics(ctx Context) { + ctx.disableRecordMetrics() +} + +// AliasForRecordMetrics 对请求路径起个别名,用于记录指标。 +// 如:Get /user/:username 这样的路径,因为 username 会有非常多的情况,这样记录指标非常不友好。 +func AliasForRecordMetrics(path string) HandlerFunc { + return func(ctx Context) { + ctx.setAlias(path) + } +} + +// WrapAuthHandler 用来处理 Auth 的入口 +func WrapAuthHandler(handler func(Context) (sessionUserInfo proposal.SessionUserInfo, err BusinessError)) HandlerFunc { + return func(ctx Context) { + sessionUserInfo, err := handler(ctx) + if err != nil { + ctx.AbortWithError(err) + return + } + + ctx.setSessionUserInfo(sessionUserInfo) + } +} + +// RouterGroup 包装gin的RouterGroup +type RouterGroup interface { + Group(string, ...HandlerFunc) RouterGroup + IRoutes +} + +var _ IRoutes = (*router)(nil) + +// IRoutes 包装gin的IRoutes +type IRoutes interface { + Any(string, ...HandlerFunc) + GET(string, ...HandlerFunc) + POST(string, ...HandlerFunc) + DELETE(string, ...HandlerFunc) + PATCH(string, ...HandlerFunc) + PUT(string, ...HandlerFunc) + OPTIONS(string, ...HandlerFunc) + HEAD(string, ...HandlerFunc) +} + +type router struct { + group *gin.RouterGroup +} + +func (r *router) Group(relativePath string, handlers ...HandlerFunc) RouterGroup { + group := r.group.Group(relativePath, wrapHandlers(handlers...)...) + return &router{group: group} +} + +func (r *router) Any(relativePath string, handlers ...HandlerFunc) { + r.group.Any(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) GET(relativePath string, handlers ...HandlerFunc) { + r.group.GET(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) POST(relativePath string, handlers ...HandlerFunc) { + r.group.POST(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) DELETE(relativePath string, handlers ...HandlerFunc) { + r.group.DELETE(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) PATCH(relativePath string, handlers ...HandlerFunc) { + r.group.PATCH(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) PUT(relativePath string, handlers ...HandlerFunc) { + r.group.PUT(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) OPTIONS(relativePath string, handlers ...HandlerFunc) { + r.group.OPTIONS(relativePath, wrapHandlers(handlers...)...) +} + +func (r *router) HEAD(relativePath string, handlers ...HandlerFunc) { + r.group.HEAD(relativePath, wrapHandlers(handlers...)...) +} + +func wrapHandlers(handlers ...HandlerFunc) []gin.HandlerFunc { + funcs := make([]gin.HandlerFunc, len(handlers)) + for i, handler := range handlers { + handler := handler + funcs[i] = func(c *gin.Context) { + ctx := newContext(c) + defer releaseContext(ctx) + + handler(ctx) + } + } + + return funcs +} + +var _ Mux = (*mux)(nil) + +// Mux http mux +type Mux interface { + ServeHTTP(w http.ResponseWriter, req *http.Request) + Group(relativePath string, handlers ...HandlerFunc) RouterGroup + Routes() gin.RoutesInfo +} + +type mux struct { + engine *gin.Engine +} + +func (m *mux) ServeHTTP(w http.ResponseWriter, req *http.Request) { + m.engine.ServeHTTP(w, req) +} + +func (m *mux) Group(relativePath string, handlers ...HandlerFunc) RouterGroup { + return &router{ + group: m.engine.Group(relativePath, wrapHandlers(handlers...)...), + } +} + +func (m *mux) Routes() gin.RoutesInfo { + return m.engine.Routes() +} + +func New(logger logger.CustomLogger, options ...Option) (Mux, error) { + if logger == nil { + return nil, errors.New("logger required") + } + + gin.SetMode(gin.ReleaseMode) + mux := &mux{ + engine: gin.New(), + } + + // 启动信息 + startup.PrintInfo() + + mux.engine.StaticFS("resources", gin.Dir(configs.GetResourcesFilePath(), true)) + + // withoutTracePaths 这些请求,默认不记录日志 + withoutTracePaths := map[string]bool{ + "/metrics": true, + + "/debug/pprof/": true, + "/debug/pprof/cmdline": true, + "/debug/pprof/profile": true, + "/debug/pprof/symbol": true, + "/debug/pprof/trace": true, + "/debug/pprof/allocs": true, + "/debug/pprof/block": true, + "/debug/pprof/goroutine": true, + "/debug/pprof/heap": true, + "/debug/pprof/mutex": true, + "/debug/pprof/threadcreate": true, + + "/favicon.ico": true, + + "/system/health": true, + } + + opt := new(option) + for _, f := range options { + f(opt) + } + + if opt.enablePProf { + if !env.Active().IsPro() { + pprof.Register(mux.engine) // register pprof to gin + } + } + + if opt.enableSwagger { + if !env.Active().IsPro() { + mux.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // register swagger + } + } + + if opt.enablePrometheus { + mux.engine.GET("/metrics", gin.WrapH(promhttp.Handler())) // register prometheus + } + + if opt.enableCors { + mux.engine.Use(cors.New()) + } + + // recover 两次,防止 recover 过程中时发生 panic + mux.engine.Use(func(ctx *gin.Context) { + defer func() { + if err := recover(); err != nil { + logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", string(debug.Stack()))) + } + }() + + ctx.Next() + }) + + mux.engine.Use(func(ctx *gin.Context) { + + if ctx.Writer.Status() == http.StatusNotFound { + return + } + + ts := time.Now() + + context := newContext(ctx) + defer releaseContext(context) + + context.init() + context.setLogger(logger) + context.ableRecordMetrics() + + if !withoutTracePaths[ctx.Request.URL.Path] { + if traceId := context.GetHeader(trace.Header); traceId != "" { + context.setTrace(trace.New(traceId)) + } else { + context.setTrace(trace.New("")) + } + } + + defer func() { + var ( + response interface{} + businessCode int + businessCodeMsg string + abortErr error + traceId string + ) + + if ct := context.Trace(); ct != nil { + context.SetHeader(trace.Header, ct.ID()) + traceId = ct.ID() + } + + session := context.SessionUserInfo() + + panicStackInfo := "" + panicError := "" + + // region 发生 Panic 异常发送告警提醒 + if err := recover(); err != nil { + panicStackInfo = string(debug.Stack()) + panicError = fmt.Sprintf("%+v", err) + // logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo)) + context.AbortWithError(Error( + http.StatusInternalServerError, + code.ServerError, + code.Text(code.ServerError)), + ) + + UID := session.UserName + + if alertHandler := opt.alertNotify; alertHandler != nil { + alertHandler(&proposal.AlertMessage{ + ProjectName: configs.ProjectName, + Env: env.Active().Value(), + TraceID: traceId, + UID: UID, + HOST: context.Host(), + URI: context.URI(), + Method: context.Method(), + ErrorMessage: err, + ErrorStack: panicStackInfo, + Time: time.Now().Format(timeutil.CSTLayout), + }) + } + } + // endregion + + // region 发生错误,进行返回 + if ctx.IsAborted() { + for i := range ctx.Errors { + multierr.AppendInto(&abortErr, ctx.Errors[i]) + } + + UID := session.UserName + + if err := context.abortError(); err != nil { // customer err + // 判断是否需要发送告警通知 + if err.IsAlert() { + if alertHandler := opt.alertNotify; alertHandler != nil { + alertHandler(&proposal.AlertMessage{ + ProjectName: configs.ProjectName, + Env: env.Active().Value(), + TraceID: traceId, + UID: UID, + HOST: context.Host(), + URI: context.URI(), + Method: context.Method(), + ErrorMessage: err.Message(), + ErrorStack: fmt.Sprintf("%+v", err.StackError()), + Time: time.Now().Format(timeutil.CSTLayout), + }) + } + } + + multierr.AppendInto(&abortErr, err.StackError()) + businessCode = err.BusinessCode() + businessCodeMsg = err.Message() + response = &code.Failure{ + Code: businessCode, + Message: businessCodeMsg, + } + ctx.JSON(err.HTTPCode(), response) + } + } + // endregion + + // region 正确返回 + response = context.getPayload() + if response != nil { + //tokenString := ctx.GetHeader("Authorization") + //if tokenString != "" { + // refreshTokenString, err := jwtoken.New(configs.Get().JWT.Secret).Refresh(tokenString) + // if err == nil { + // context.SetHeader("X-Authorization", refreshTokenString) + // } + //} + ctx.JSON(http.StatusOK, response) + } + // endregion + + // region 记录指标 + if opt.recordHandler != nil && context.isRecordMetrics() { + path := context.Path() + if alias := context.Alias(); alias != "" { + path = alias + } + + opt.recordHandler(&proposal.MetricsMessage{ + HOST: context.Host(), + Path: path, + Method: context.Method(), + HTTPCode: ctx.Writer.Status(), + BusinessCode: businessCode, + CostSeconds: time.Since(ts).Seconds(), + IsSuccess: !ctx.IsAborted() && (ctx.Writer.Status() == http.StatusOK), + }) + } + // endregion + + // region 记录日志 + var t *trace.Trace + if x := context.Trace(); x != nil { + t = x.(*trace.Trace) + } else { + return + } + + decodedURL, _ := url.QueryUnescape(ctx.Request.URL.RequestURI()) + + // ctx.Request.Header,精简 Header 参数 + traceHeader := map[string]string{ + "Content-Type": ctx.GetHeader("Content-Type"), + } + + t.WithRequest(&trace.Request{ + TTL: "un-limit", + Method: ctx.Request.Method, + DecodedURL: decodedURL, + Header: traceHeader, + Body: string(context.RawData()), + }) + + var responseBody interface{} + + if response != nil { + responseBody = response + } + + t.WithResponse(&trace.Response{ + Header: ctx.Writer.Header(), + HttpCode: ctx.Writer.Status(), + HttpCodeMsg: http.StatusText(ctx.Writer.Status()), + BusinessCode: businessCode, + BusinessCodeMsg: businessCodeMsg, + Body: responseBody, + CostSeconds: time.Since(ts).Seconds(), + }) + + if panicStackInfo != "" && panicError != "" { + t.AppendDebug(&trace.Debug{ + Stack: panicStackInfo, + Value: []any{panicError}, + }) + } + + t.Success = !ctx.IsAborted() && (ctx.Writer.Status() == http.StatusOK) + t.CostSeconds = time.Since(ts).Seconds() + + //logger.Info("trace-log", + // zap.Any("method", ctx.Request.Method), + // zap.Any("path", decodedURL), + // zap.Any("http_code", ctx.Writer.Status()), + // zap.Any("business_code", businessCode), + // zap.Any("success", t.Success), + // zap.Any("cost_seconds", t.CostSeconds), + // zap.Any("trace_id", t.Identifier), + // zap.Any("trace_info", t), + // zap.Error(abortErr), + //) + + traceInfo := "" + if traceJsonData, err := json.Marshal(t); err == nil { + traceInfo = string(traceJsonData) + } + + // region 记录接口的访问日志 + if opt.requestLoggerHandler != nil { + opt.requestLoggerHandler(&proposal.RequestLoggerMessage{ + Tid: traceId, + Username: session.UserName, + HOST: context.Host(), + Path: decodedURL, + Method: ctx.Request.Method, + HTTPCode: ctx.Writer.Status(), + BusinessCode: businessCode, + CostSeconds: t.CostSeconds, + IsSuccess: t.Success, + Content: traceInfo, + }) + } + // endregion + + // endregion + }() + + ctx.Next() + }) + + mux.engine.NoMethod(wrapHandlers(DisableTraceLog)...) + mux.engine.NoRoute(wrapHandlers(DisableTraceLog)...) + + system := mux.Group("/system") + { + // 健康检查 + system.GET("/health", func(ctx Context) { + resp := &struct { + Time string `json:"time"` + Environment string `json:"environment"` + Host string `json:"host"` + Status string `json:"status"` + }{ + Time: timeutil.CSTLayoutString(), + Environment: env.Active().Value(), + Host: ctx.Host(), + Status: "ok", + } + ctx.Payload(resp) + }) + } + + return mux, nil +} diff --git a/internal/pkg/core/error.go b/internal/pkg/core/error.go new file mode 100644 index 0000000..80c80b1 --- /dev/null +++ b/internal/pkg/core/error.go @@ -0,0 +1,82 @@ +package core + +import ( + "mini-chat/internal/pkg/errors" +) + +var _ BusinessError = (*businessError)(nil) + +type BusinessError interface { + // i 为了避免被其他包实现 + i() + + // WithError 设置错误信息 + WithError(err error) BusinessError + + // WithAlert 设置告警通知 + WithAlert() BusinessError + + // BusinessCode 获取业务码 + BusinessCode() int + + // HTTPCode 获取 HTTP 状态码 + HTTPCode() int + + // Message 获取错误描述 + Message() string + + // StackError 获取带堆栈的错误信息 + StackError() error + + // IsAlert 是否开启告警通知 + IsAlert() bool +} + +type businessError struct { + httpCode int // HTTP 状态码 + businessCode int // 业务码 + message string // 错误描述 + stackError error // 含有堆栈信息的错误 + isAlert bool // 是否告警通知 +} + +func Error(httpCode, businessCode int, message string) BusinessError { + return &businessError{ + httpCode: httpCode, + businessCode: businessCode, + message: message, + isAlert: false, + } +} + +func (e *businessError) i() {} + +func (e *businessError) WithError(err error) BusinessError { + e.stackError = errors.WithStack(err) + return e +} + +func (e *businessError) WithAlert() BusinessError { + e.isAlert = true + return e +} + +func (e *businessError) HTTPCode() int { + return e.httpCode +} + +func (e *businessError) BusinessCode() int { + return e.businessCode +} + +func (e *businessError) Message() string { + return e.message +} + +func (e *businessError) StackError() error { + return e.stackError +} + +func (e *businessError) IsAlert() bool { + return e.isAlert +} diff --git a/internal/pkg/cors/cors.go b/internal/pkg/cors/cors.go new file mode 100644 index 0000000..496dde0 --- /dev/null +++ b/internal/pkg/cors/cors.go @@ -0,0 +1,39 @@ +package cors + +import ( + "net/http" + + "github.com/gin-gonic/gin" + ginCors "github.com/rs/cors/wrapper/gin" +) + +func New() gin.HandlerFunc { + return ginCors.New(ginCors.Options{ + // AllowedOrigins 允许的来源(域名),可以是一个具体的域名或使用通配符 "*" 表示允许所有来源。 + // []string{"http://example.com", "http://another-domain.com"}, + AllowedOrigins: []string{"*"}, + + // AllowedMethods 允许的 HTTP 方法,例如 "GET"、"POST"、"PUT" 等。 + AllowedMethods: []string{ + http.MethodGet, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + http.MethodHead, + http.MethodOptions, + }, + + // AllowedHeaders 允许的请求标头,例如 "Authorization"、"Content-Type" 等。 + AllowedHeaders: []string{"*"}, + + // MaxAge 预检请求的最大缓存时间(秒),用于减少预检请求的频率。 + MaxAge: 86400, + + // AllowCredentials 是否允许携带身份凭证(如 Cookie)。 + AllowCredentials: true, + + // OptionsPassthrough 是否将 OPTIONS 请求传递给下一个处理函数,设置为 true 可以在 Gin 的路由中使用 OPTIONS 请求处理函数。 + OptionsPassthrough: true, + }) +} diff --git a/internal/pkg/cryptoaes/cryptoaes.go b/internal/pkg/cryptoaes/cryptoaes.go new file mode 100644 index 0000000..e466d76 --- /dev/null +++ b/internal/pkg/cryptoaes/cryptoaes.go @@ -0,0 +1,72 @@ +package cryptoaes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" +) + +// Encrypt 加密算法 +func Encrypt(key, plaintext string) (string, error) { + keyByte := []byte(key) + plaintextByte := []byte(plaintext) + + // 创建一个 AES 块 + block, err := aes.NewCipher(keyByte) + if err != nil { + return "", err + } + + // 对明文进行填充 + padding := aes.BlockSize - (len(plaintext) % aes.BlockSize) + padText := append(plaintextByte, bytes.Repeat([]byte{byte(padding)}, padding)...) + + ciphertext := make([]byte, aes.BlockSize+len(padText)) + + // 生成随机的 IV + iv := ciphertext[:aes.BlockSize] + if _, err := rand.Read(iv); err != nil { + return "", err + } + + // 解密数据 + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], padText) + + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + +// Decrypt 解密算法 +func Decrypt(key, ciphertext string) (string, error) { + ciphertextByte, err := base64.StdEncoding.DecodeString(ciphertext) + if err != nil { + return "", err + } + + // 创建一个 AES 块 + block, err := aes.NewCipher([]byte(key)) + if err != nil { + panic(err) + } + + // 提取 IV + iv := ciphertextByte[:aes.BlockSize] + + // 提取密文 + ciphertextByteWithoutIV := ciphertextByte[aes.BlockSize:] + + // 创建一个 CBC 模式的 AES 解密器 + mode := cipher.NewCBCDecrypter(block, iv) + + // 解密数据 + decrypted := make([]byte, len(ciphertextByteWithoutIV)) + mode.CryptBlocks(decrypted, ciphertextByteWithoutIV) + + // 去除填充字节 + padding := int(decrypted[len(decrypted)-1]) + decrypted = decrypted[:len(decrypted)-padding] + + return string(decrypted), nil +} diff --git a/internal/pkg/cryptoaes/cryptoaes_test.go b/internal/pkg/cryptoaes/cryptoaes_test.go new file mode 100644 index 0000000..f06e18d --- /dev/null +++ b/internal/pkg/cryptoaes/cryptoaes_test.go @@ -0,0 +1,15 @@ +package cryptoaes + +import "testing" + +const ( + key = "m52psEZHSn4!&hbs" +) + +func TestEncrypt2(t *testing.T) { + t.Log(Encrypt(key, "mini-chat")) +} + +func TestDecrypt(t *testing.T) { + t.Log(Decrypt(key, "qAyQtb9bkvbDFW47H5DGDVwTjw399k13xM2ceBg/OGc=")) +} diff --git a/internal/pkg/cryptorsa/cryptorsa.go b/internal/pkg/cryptorsa/cryptorsa.go new file mode 100644 index 0000000..0c652a6 --- /dev/null +++ b/internal/pkg/cryptorsa/cryptorsa.go @@ -0,0 +1,92 @@ +package cryptorsa + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" +) + +// GenerateKey 生成一个 2048 位的 RSA 密钥对 +func GenerateKey() { + // 生成一个 2048 位的 RSA 密钥对 + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + panic(err) + } + + // 获取私钥的字节表示 + privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey) + + // 将私钥字节放入 PEM 块中 + privateKeyPEM := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: privateKeyBytes, + } + + // 将 PEM 块编码为字符串 + privateKeyStr := string(pem.EncodeToMemory(privateKeyPEM)) + + // 获取公钥的字节表示 + publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) + if err != nil { + panic(err) + } + + // 将公钥字节放入 PEM 块中 + publicKeyPEM := &pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKeyBytes, + } + + // 将 PEM 块编码为字符串 + publicKeyStr := string(pem.EncodeToMemory(publicKeyPEM)) + + fmt.Println(fmt.Sprintf("RSA 公钥:\n%s", publicKeyStr)) + fmt.Println(fmt.Sprintf("RSA 私钥:\n%s", privateKeyStr)) + fmt.Println("你可以将这些字符串保存到文件中或传递给其他程序使用,记得妥善保管私钥,避免泄露!") + +} + +// PublicKeyEncrypt 公钥加密 +func PublicKeyEncrypt(publicKey, plaintext string) (string, error) { + // pem 解码 + block, _ := pem.Decode([]byte(publicKey)) + + // x509 解码 + publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return "", err + } + + //对明文进行加密 + ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, publicKeyInterface.(*rsa.PublicKey), []byte(plaintext)) + if err != nil { + return "", err + } + + //返回密文 + return base64.URLEncoding.EncodeToString(ciphertext), nil +} + +// PrivateKeyDecrypt 私钥解密 +func PrivateKeyDecrypt(privateKey, ciphertext string) (string, error) { + // pem 解码 + block, _ := pem.Decode([]byte(privateKey)) + + // X509 解码 + rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return "", err + } + + ciphertextBytes, err := base64.URLEncoding.DecodeString(ciphertext) + + //对密文进行解密 + plaintext, _ := rsa.DecryptPKCS1v15(rand.Reader, rsaPrivateKey, ciphertextBytes) + + //返回明文 + return string(plaintext), nil +} diff --git a/internal/pkg/cryptorsa/cryptorsa_test.go b/internal/pkg/cryptorsa/cryptorsa_test.go new file mode 100644 index 0000000..a86d7dc --- /dev/null +++ b/internal/pkg/cryptorsa/cryptorsa_test.go @@ -0,0 +1,53 @@ +package cryptorsa + +import "testing" + +const ( + publicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtoO/YB9GpcdIspc10Esy +MSKfBVspAnHsBOiyLmzlHXYfHdOf04aC+rDLC8UTbxm3/VGLTef+b7N9a6BQskjX +aMoMceKlWihdmvJPD+6ybEpSjcGXj8aaDEjJjiJhLnk1zJ5d+J9OQd5xgRSFtEFy ++OiWEhkqlwMxjFNIY0xXD0iHlnLyrAaB4Jlwp2uIwq6MCzVAJnzF/+8cov6YXfVQ +YwITDthHGG1KviPQlx5a9Nvjx/jEn1pN8OzcJKI3CRpCEuAP+80xts3nXBFUC5nT +ouHfTxyriV4r4XEO+N7H3QTBuIZ7Wr8XRFtJQcFAgye2eNJtfYMpYKb+wjqVAbR6 +qwIDAQAB +-----END PUBLIC KEY-----` + + privateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtoO/YB9GpcdIspc10EsyMSKfBVspAnHsBOiyLmzlHXYfHdOf +04aC+rDLC8UTbxm3/VGLTef+b7N9a6BQskjXaMoMceKlWihdmvJPD+6ybEpSjcGX +j8aaDEjJjiJhLnk1zJ5d+J9OQd5xgRSFtEFy+OiWEhkqlwMxjFNIY0xXD0iHlnLy +rAaB4Jlwp2uIwq6MCzVAJnzF/+8cov6YXfVQYwITDthHGG1KviPQlx5a9Nvjx/jE +n1pN8OzcJKI3CRpCEuAP+80xts3nXBFUC5nTouHfTxyriV4r4XEO+N7H3QTBuIZ7 +Wr8XRFtJQcFAgye2eNJtfYMpYKb+wjqVAbR6qwIDAQABAoIBADF0VYDYOK5m513s +9xnvpjQGK4yp/Ny6vbc+zjkiLJrlDN1qIF6Sjh8blIkl53QtRduQIu0DNcBSpGNr +VzJX5nZweRrKzP82/NYlXiL1DMenA+OBV24P5GH7vxGSYz7SfS9qog/iKrRSb/MH ++oqzSVIEw9U3mIC+zsg1MOInJ1fuXAy/rZUKL3Aw5WBwQ8+I7F1bYEn21k5TSgw4 +nnt5o+gK/ooMqLL3eB/CJs3T8RqoHkL5nxt1aVZYCdF7rglMLWpANWneNU3hEteN +5AvBuo+NOt230/bqK3SkqOofVPJjLiyhoMqPGDUGuC76dGm8KfQojovFpz/tSxGU +BVsUh/ECgYEA0a9t4Yzf/aJthVneZMO5vcSCfIHgLEdSAAnFMHGkNBbtgKSfbshM +7nE8vatihkcU7McuZeULFKX/db4rfRahGvuMlH8k5Wzvr+LqcrZQnR27d25+cQiD +P0p3NRyX6KIYuBcKvarP2hthjN7FwzQ7EF9xQ4OZHHHswkgvd493KU0CgYEA3tP3 +OQPSLQU5MCncxW36Xy6gk4gjYvPIcOG6ME3/hlE6cupOQaRXrG+VadItgJEofZNR +GePZWMflAe1ntja3N8dZ8hJ5bdGpYsx+rf0BYz/BFXYwWqPxHpoHz+bw797NPKMv +8yOjqLOzvjUZ8ecIvFpUsseZczwa3fPfP3smd9cCgYEAxOP3R40iXmUAdfDW9MMc +S+aTqBnDx5AInWSPNlffGdJVnS/3TOzj4BmQMYEWeIOSUGsPVDpn1zGv2H2DFGgF +SvLdJCrnGE7cGcn231P2CjH678BfFgAqTWm82bBJq/VZRLLOMR6NIX4IcWBVTmBi +/ZLBJeYSBTWsXRmvCJM8DxkCgYBVUuccrujhEln2pmECPH2dytX0CDI8psq+5sCL +1KIexaXS8QNsQUjNH6Ef9zozO+I8S5fHiSblxw1a8pQ/Aq6frjcz6X0T3y+0REfR +ycqpPXVrCWm0m4gtxp9tLapev3rpWDd5K9F0PPN7xwubRHNk5FYAa0vIA2DqUoLO +5RIy2wKBgQCtyXWbcdG3Acrz90PmZzGIcAHIje+5a9mvOQTZaa7yBxn5RU+jZWqg +dzRc2cWCabOJX/skT2vKwAzGPaJN3tRhwLxLnVnSv5mrnoMq/0FG2fJ4kSjXcjwt +/vAm3+3D5KKCAqO/3Umdg2U64h+8jzMO7DtwCYJro2VWNytmgwsL/g== +-----END RSA PRIVATE KEY-----` +) + +func TestPublicKeyEncrypt(t *testing.T) { + plaintext := "mini-chat" + t.Log(PublicKeyEncrypt(publicKey, plaintext)) +} + +func TestPrivateKeyDecrypt(t *testing.T) { + ciphertext := "bpPQp-PI-9HFjtro8Iowv7RNhY1todIhmjFkmmwjIana5RIp6ZkfkjN7_auZp_5Xo9htF_1kJ7L4cE4ixDT8l0R4u3ZGvfYJ3lP7d-De7rk_vvrEdetGEh-VGAhp3iHRgypV8CErt0JNCXcCEM_Bk87K5FLThFoU997c9IYdS6vO1WGcLsd_qzqWGxolNrSJt_oWrX4BEwu8PtVomSHbV7oG3XBRFcitzx6Ye9SjFrouUks5snzj9_2FqLoNE6dRRBPvyR0Iz753dE3CqgxUDjBhQftXPufx6r5XU1EJ4DcZDk6ZRAplOo_bgqTa91cfKhddIfdyg9nxcovmoxxyKg==" + t.Log(PrivateKeyDecrypt(privateKey, ciphertext)) +} diff --git a/internal/pkg/debug/logger.go b/internal/pkg/debug/logger.go new file mode 100644 index 0000000..0f16c0c --- /dev/null +++ b/internal/pkg/debug/logger.go @@ -0,0 +1,40 @@ +package debug + +import ( + "runtime" + "strconv" + + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/trace" +) + +type debug struct { + ctx core.StdContext +} + +func WithContext(ctx core.StdContext) *debug { + return &debug{ + ctx: ctx, + } +} + +func (d *debug) Logger(value ...any) { + debugInfo := new(trace.Debug) + + defer func() { + if d.ctx.Trace != nil { + debugInfo.Stack = fileWithLineNum() + debugInfo.Value = value + d.ctx.Trace.AppendDebug(debugInfo) + } + }() +} + +func fileWithLineNum() string { + _, file, line, ok := runtime.Caller(3) + if ok { + return file + ":" + strconv.FormatInt(int64(line), 10) + } + + return "" +} diff --git a/internal/pkg/env/env.go b/internal/pkg/env/env.go new file mode 100644 index 0000000..615bb8c --- /dev/null +++ b/internal/pkg/env/env.go @@ -0,0 +1,77 @@ +package env + +import ( + "flag" + "fmt" + "strings" +) + +var ( + active Environment + dev Environment = &environment{value: "dev"} + fat Environment = &environment{value: "fat"} + uat Environment = &environment{value: "uat"} + pro Environment = &environment{value: "pro"} +) + +var _ Environment = (*environment)(nil) + +// Environment 环境配置 +type Environment interface { + Value() string + IsDev() bool + IsFat() bool + IsUat() bool + IsPro() bool + t() +} + +type environment struct { + value string +} + +func (e *environment) Value() string { + return e.value +} + +func (e *environment) IsDev() bool { + return e.value == "dev" +} + +func (e *environment) IsFat() bool { + return e.value == "fat" +} + +func (e *environment) IsUat() bool { + return e.value == "uat" +} + +func (e *environment) IsPro() bool { + return e.value == "pro" +} + +func (e *environment) t() {} + +func init() { + env := flag.String("env", "", "请输入运行环境:\n dev:开发环境\n fat:测试环境\n uat:预上线环境\n pro:正式环境\n") + flag.Parse() + + switch strings.ToLower(strings.TrimSpace(*env)) { + case "dev": + active = dev + case "fat": + active = fat + case "uat": + active = uat + case "pro": + active = pro + default: + active = fat + fmt.Println("Warning: '-env' cannot be found, or it is illegal. The default 'fat' will be used.") + } +} + +// Active 当前配置的env +func Active() Environment { + return active +} diff --git a/internal/pkg/errors/err.go b/internal/pkg/errors/err.go new file mode 100644 index 0000000..935e367 --- /dev/null +++ b/internal/pkg/errors/err.go @@ -0,0 +1,100 @@ +package errors + +import ( + "fmt" + "io" + "runtime" + + "github.com/pkg/errors" +) + +func callers() []uintptr { + var pcs [32]uintptr + l := runtime.Callers(3, pcs[:]) + return pcs[:l] +} + +// Error a error with caller stack information +type Error interface { + error + t() +} + +var _ Error = (*item)(nil) +var _ fmt.Formatter = (*item)(nil) + +type item struct { + msg string + stack []uintptr +} + +func (i *item) Error() string { + return i.msg +} + +func (i *item) t() {} + +// Format used by go.uber.org/zap in Verbose +func (i *item) Format(s fmt.State, verb rune) { + io.WriteString(s, i.msg) + io.WriteString(s, "\n") + + for _, pc := range i.stack { + fmt.Fprintf(s, "%+v\n", errors.Frame(pc)) + } +} + +// New create a new error +func New(msg string) Error { + return &item{msg: msg, stack: callers()} +} + +// Errorf create a new error +func Errorf(format string, args ...interface{}) Error { + return &item{msg: fmt.Sprintf(format, args...), stack: callers()} +} + +// Wrap with some extra message into err +func Wrap(err error, msg string) Error { + if err == nil { + return nil + } + + e, ok := err.(*item) + if !ok { + return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()} + } + + e.msg = fmt.Sprintf("%s; %s", msg, e.msg) + return e +} + +// Wrapf with some extra message into err +func Wrapf(err error, format string, args ...interface{}) Error { + if err == nil { + return nil + } + + msg := fmt.Sprintf(format, args...) + + e, ok := err.(*item) + if !ok { + return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()} + } + + e.msg = fmt.Sprintf("%s; %s", msg, e.msg) + return e +} + +// WithStack add caller stack information +func WithStack(err error) Error { + if err == nil { + return nil + } + + if e, ok := err.(*item); ok { + return e + } + + return &item{msg: err.Error(), stack: callers()} +} diff --git a/internal/pkg/errors/err_test.go b/internal/pkg/errors/err_test.go new file mode 100644 index 0000000..5a8a6ea --- /dev/null +++ b/internal/pkg/errors/err_test.go @@ -0,0 +1,34 @@ +package errors + +import ( + "errors" + "testing" + + "go.uber.org/zap" +) + +func TestErr(t *testing.T) { + logger, _ := zap.NewProduction() + + logger.Info("errorf", zap.Error(Errorf("%s %d", "127.0.0.1", 80))) + + err := New("a dummy err") + logger.Info("new", zap.Error(err)) + + err = Wrap(err, "ping timeout err") + logger.Info("wrap", zap.Error(err)) + + err = Wrapf(err, "ip: %s port: %d", "localhost", 80) + logger.Info("wrapf", zap.Error(err)) + + err = WithStack(err) + logger.Info("withstack", zap.Error(err)) + + logger.Info("wrap std", zap.Error(Wrap(errors.New("std err"), "some err occurs"))) + + logger.Info("wrapf std", zap.Error(Wrapf(errors.New("std err"), "ip: %s port: %d", "localhost", 80))) + + logger.Info("withstack std", zap.Error(WithStack(errors.New("std err")))) + + t.Logf("%+v", New("a dummy error")) +} diff --git a/internal/pkg/httpclient/client.go b/internal/pkg/httpclient/client.go new file mode 100644 index 0000000..427ec05 --- /dev/null +++ b/internal/pkg/httpclient/client.go @@ -0,0 +1,110 @@ +package httpclient + +import ( + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/trace" + + "github.com/bytedance/sonic" + "github.com/go-resty/resty/v2" +) + +type customInterceptor struct { + ctx core.StdContext +} + +func (i *customInterceptor) OnResponse(client *resty.Client, response *resty.Response) error { + requestInfo := map[string]interface{}{ + "request-id": i.ctx.Trace.ID(), + "url": response.Request.URL, + "method": response.Request.Method, + "header": response.Request.Header, + "path_params": response.Request.PathParams, + "body": response.Request.Body, + "request_time": response.Request.Time.Format("2006-01-02 15:04:05"), + + "ti-DNSLookup": response.Request.TraceInfo().DNSLookup, + "ti-ConnTime": response.Request.TraceInfo().ConnTime.String(), + "ti-TCPConnTime": response.Request.TraceInfo().TCPConnTime.String(), + "ti-TLSHandshake": response.Request.TraceInfo().TLSHandshake.String(), + "ti-ServerTime": response.Request.TraceInfo().ServerTime.String(), + "ti-IsConnReused": response.Request.TraceInfo().IsConnReused, + "ti-IsConnWasIdle": response.Request.TraceInfo().IsConnWasIdle, + "ti-ConnIdleTime": response.Request.TraceInfo().ConnIdleTime.String(), + "ti-RequestAttempt": response.Request.TraceInfo().RequestAttempt, + "ti-RemoteAddr": response.Request.TraceInfo().RemoteAddr.String(), + } + + responseInfo := map[string]interface{}{ + "status_code": response.StatusCode(), + "status": response.Status(), + "proto": response.Proto(), + "header": response.Header(), + "total_time": response.Request.TraceInfo().TotalTime.String(), + "received_at": response.ReceivedAt().Format("2006-01-02 15:04:05"), + "body": string(response.Body()), + } + + httpLog := new(trace.HttpLog) + httpLog.Request = requestInfo + httpLog.Response = responseInfo + httpLog.CostSeconds = response.Time().Seconds() + + i.ctx.Trace.AppendThirdPartyRequests(httpLog) + + return nil +} + +func (i *customInterceptor) OnError(request *resty.Request, err error) { + requestInfo := map[string]interface{}{ + "request-id": i.ctx.Trace.ID(), + "url": request.URL, + "method": request.Method, + "header": request.Header, + "path_params": request.PathParams, + "body": request.Body, + "request_time": request.Time.Format("2006-01-02 15:04:05"), + } + + responseInfo := map[string]interface{}{ + "error": err.Error(), + } + + httpLog := new(trace.HttpLog) + httpLog.Request = requestInfo + httpLog.Response = responseInfo + httpLog.CostSeconds = request.TraceInfo().TotalTime.Seconds() + + i.ctx.Trace.AppendThirdPartyRequests(httpLog) +} + +func GetHttpClientWithContext(ctx core.StdContext) *resty.Client { + client := resty.New(). + EnableTrace(). + SetJSONUnmarshaler(func(data []byte, v interface{}) error { + // 配置 Sonic 宽松模式 + return sonic.Config{ + ValidateString: false, + }.Froze().Unmarshal(data, v) + }) + + interceptor := &customInterceptor{ + ctx: ctx, + } + + client.OnAfterResponse(interceptor.OnResponse) + + client.OnError(interceptor.OnError) + + return client +} + +func GetHttpClient() *resty.Client { + return resty.New(). + EnableTrace(). + SetJSONUnmarshaler(func(data []byte, v interface{}) error { + // 配置 Sonic 宽松模式 + return sonic.Config{ + ValidateString: false, + }.Froze().Unmarshal(data, v) + }) +} diff --git a/internal/pkg/idgen/idgen.go b/internal/pkg/idgen/idgen.go new file mode 100644 index 0000000..8ba310b --- /dev/null +++ b/internal/pkg/idgen/idgen.go @@ -0,0 +1,14 @@ +package idgen + +import ( + "github.com/bwmarrin/snowflake" +) + +func GenerateUniqueID() string { + node, err := snowflake.NewNode(1) + if err != nil { + panic(err) + } + + return node.Generate().String() +} diff --git a/internal/pkg/idgen/idgen_test.go b/internal/pkg/idgen/idgen_test.go new file mode 100644 index 0000000..2aa2ac7 --- /dev/null +++ b/internal/pkg/idgen/idgen_test.go @@ -0,0 +1,7 @@ +package idgen + +import "testing" + +func TestGenerateUniqueID(t *testing.T) { + t.Log(GenerateUniqueID()) +} diff --git a/internal/pkg/jsonutil/jsonutil.go b/internal/pkg/jsonutil/jsonutil.go new file mode 100644 index 0000000..5fba4be --- /dev/null +++ b/internal/pkg/jsonutil/jsonutil.go @@ -0,0 +1,10 @@ +package jsonutil + +import "github.com/bytedance/sonic" + +// 配置 Sonic 宽松模式 +var jsonKit = sonic.Config{ValidateString: false}.Froze() + +func Unmarshal(data []byte, v any) error { + return jsonKit.Unmarshal(data, v) +} diff --git a/internal/pkg/jwtoken/jwtoken.go b/internal/pkg/jwtoken/jwtoken.go new file mode 100644 index 0000000..2007ecf --- /dev/null +++ b/internal/pkg/jwtoken/jwtoken.go @@ -0,0 +1,80 @@ +package jwtoken + +import ( + "time" + + "mini-chat/internal/proposal" + + "github.com/golang-jwt/jwt/v5" +) + +var _ Token = (*token)(nil) + +type Token interface { + i() + Sign(jwtInfo proposal.SessionUserInfo, expireDuration time.Duration) (tokenString string, err error) + Parse(tokenString string) (*claims, error) + Refresh(tokenString string) (refreshTokenString string, err error) +} + +type token struct { + secret string +} + +type claims struct { + proposal.SessionUserInfo + jwt.RegisteredClaims +} + +func New(secret string) Token { + return &token{ + secret: secret, + } +} + +func (t *token) i() {} + +func (t *token) Sign(sessionUserInfo proposal.SessionUserInfo, expireDuration time.Duration) (tokenString string, err error) { + claims := claims{ + sessionUserInfo, + jwt.RegisteredClaims{ + NotBefore: jwt.NewNumericDate(time.Now()), + IssuedAt: jwt.NewNumericDate(time.Now()), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)), + }, + } + + tokenString, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(t.secret)) + return +} + +func (t *token) Parse(tokenString string) (*claims, error) { + tokenClaims, err := jwt.ParseWithClaims(tokenString, &claims{}, func(token *jwt.Token) (interface{}, error) { + return []byte(t.secret), nil + }) + + if tokenClaims != nil { + if claims, ok := tokenClaims.Claims.(*claims); ok && tokenClaims.Valid { + return claims, nil + } + } + + return nil, err +} + +func (t *token) Refresh(tokenString string) (refreshTokenString string, err error) { + tokenClaims, err := jwt.ParseWithClaims(tokenString, &claims{}, func(token *jwt.Token) (interface{}, error) { + return []byte(t.secret), nil + }) + + if tokenClaims != nil { + if claims, ok := tokenClaims.Claims.(*claims); ok && tokenClaims.Valid { + claims.IssuedAt = jwt.NewNumericDate(time.Now()) + claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Hour * 24)) + refreshTokenString, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(t.secret)) + return + } + } + + return refreshTokenString, err +} diff --git a/internal/pkg/jwtoken/jwtoken_test.go b/internal/pkg/jwtoken/jwtoken_test.go new file mode 100644 index 0000000..3a6d3a2 --- /dev/null +++ b/internal/pkg/jwtoken/jwtoken_test.go @@ -0,0 +1,40 @@ +package jwtoken + +import ( + "fmt" + "testing" + "time" + + "mini-chat/internal/proposal" +) + +const secret = "i1ydX9RtHyuJTrw7frcu" + +func TestSign(t *testing.T) { + sessionUserInfo := proposal.SessionUserInfo{ + Id: 1001, + UserName: "mini-chat", + NickName: "mono", + } + + tokenString, err := New(secret).Sign(sessionUserInfo, 24*time.Hour) + + fmt.Println(tokenString, err) + if err != nil { + t.Error("sign error", err) + return + } + + t.Log(tokenString) +} + +func TestParse(t *testing.T) { + tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTAwMSwidXNlcm5hbWUiOiJnaW4tYXBpLW1vbm8iLCJuaWNrbmFtZSI6Im1vbm8iLCJleHAiOjE3MDQ3ODY3NDcsIm5iZiI6MTcwNDcwMDM0NywiaWF0IjoxNzA0NzAwMzQ3fQ.22pCSb-aSv4BvaYnw3anryMrCpAY2I7zidkCZseWxcQ" + jwtInfo, err := New(secret).Parse(tokenString) + if err != nil { + t.Error("parse error", err) + return + } + + t.Log(jwtInfo) +} diff --git a/internal/pkg/logger/logger.go b/internal/pkg/logger/logger.go new file mode 100644 index 0000000..123c137 --- /dev/null +++ b/internal/pkg/logger/logger.go @@ -0,0 +1,394 @@ +package logger + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "os" + "path/filepath" + "time" + + "mini-chat/internal/repository/mysql/dao" + "mini-chat/internal/repository/mysql/model" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" +) + +const ( + // DefaultLevel the default log level + DefaultLevel = zapcore.InfoLevel + + // DefaultTimeLayout the default time layout; + DefaultTimeLayout = time.RFC3339 +) + +// Option custom setup config +type Option func(*option) + +type option struct { + level zapcore.Level + fields map[string]string + file io.Writer + timeLayout string + outputInConsole bool +} + +// WithDebugLevel only greater than 'level' will output +func WithDebugLevel() Option { + return func(opt *option) { + opt.level = zapcore.DebugLevel + } +} + +// WithInfoLevel only greater than 'level' will output +func WithInfoLevel() Option { + return func(opt *option) { + opt.level = zapcore.InfoLevel + } +} + +// WithWarnLevel only greater than 'level' will output +func WithWarnLevel() Option { + return func(opt *option) { + opt.level = zapcore.WarnLevel + } +} + +// WithErrorLevel only greater than 'level' will output +func WithErrorLevel() Option { + return func(opt *option) { + opt.level = zapcore.ErrorLevel + } +} + +// WithField add some field(s) to log +func WithField(key, value string) Option { + return func(opt *option) { + opt.fields[key] = value + } +} + +// WithFileP write log to some file +func WithFileP(file string) Option { + dir := filepath.Dir(file) + if err := os.MkdirAll(dir, 0766); err != nil { + panic(err) + } + + f, err := os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0766) + if err != nil { + panic(err) + } + + return func(opt *option) { + opt.file = zapcore.Lock(f) + } +} + +// WithFileRotationP write log to some file with rotation +func WithFileRotationP(file string) Option { + dir := filepath.Dir(file) + if err := os.MkdirAll(dir, 0766); err != nil { + panic(err) + } + + return func(opt *option) { + opt.file = &lumberjack.Logger{ // concurrent-safed + Filename: file, // 文件路径 + MaxSize: 128, // 单个文件最大尺寸,默认单位 M + MaxBackups: 300, // 最多保留 300 个备份 + MaxAge: 30, // 最大时间,默认单位 day + LocalTime: true, // 使用本地时间 + Compress: true, // 是否压缩 disabled by default + } + } +} + +// WithTimeLayout custom time format +func WithTimeLayout(timeLayout string) Option { + return func(opt *option) { + opt.timeLayout = timeLayout + } +} + +// WithOutputInConsole write log to os.Stdout or os.Stderr +func WithOutputInConsole() Option { + return func(opt *option) { + opt.outputInConsole = true + } +} + +// NewJSONLogger return a json-encoder zap logger, +func NewJSONLogger(opts ...Option) (*zap.Logger, error) { + opt := &option{level: DefaultLevel, fields: make(map[string]string)} + for _, f := range opts { + f(opt) + } + + timeLayout := DefaultTimeLayout + if opt.timeLayout != "" { + timeLayout = opt.timeLayout + } + + // similar to zap.NewProductionEncoderConfig() + encoderConfig := zapcore.EncoderConfig{ + TimeKey: "time", + LevelKey: "level", + NameKey: "logger", // used by logger.Named(key); optional; useless + CallerKey: "caller", + MessageKey: "msg", + StacktraceKey: "stacktrace", // use by zap.AddStacktrace; optional; useless + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.LowercaseLevelEncoder, // 小写编码器 + EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format(timeLayout)) + }, + EncodeDuration: zapcore.MillisDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, // 全路径编码器 + } + + jsonEncoder := zapcore.NewJSONEncoder(encoderConfig) + + // lowPriority usd by info\debug\warn + lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl >= opt.level && lvl < zapcore.ErrorLevel + }) + + // highPriority usd by error\panic\fatal + highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl >= opt.level && lvl >= zapcore.ErrorLevel + }) + + stdout := zapcore.Lock(os.Stdout) // lock for concurrent safe + stderr := zapcore.Lock(os.Stderr) // lock for concurrent safe + + core := zapcore.NewTee() + + if opt.outputInConsole { + core = zapcore.NewTee( + zapcore.NewCore(jsonEncoder, + zapcore.NewMultiWriteSyncer(stdout), + lowPriority, + ), + zapcore.NewCore(jsonEncoder, + zapcore.NewMultiWriteSyncer(stderr), + highPriority, + ), + ) + } + + if opt.file != nil { + core = zapcore.NewTee(core, + zapcore.NewCore(jsonEncoder, + zapcore.AddSync(opt.file), + zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl >= opt.level + }), + ), + ) + } + + logger := zap.New(core, + zap.AddCaller(), + zap.ErrorOutput(stderr), + ) + + for key, value := range opt.fields { + logger = logger.WithOptions(zap.Fields(zapcore.Field{Key: key, Type: zapcore.StringType, String: value})) + } + + return logger, nil +} + +// CustomLogger 自定义日志记录器 +type customLogger struct { + db *dao.Query + logger *zap.Logger +} + +var _ CustomLogger = (*customLogger)(nil) + +type CustomLogger interface { + i() + Info(msg string, fields ...zap.Field) + Debug(msg string, fields ...zap.Field) + Warn(msg string, fields ...zap.Field) + Error(msg string, fields ...zap.Field) + Fatal(msg string, fields ...zap.Field) + Sync() error +} + +// NewCustomLogger 创建自定义日志记录器 +func NewCustomLogger(db *dao.Query, opts ...Option) (CustomLogger, error) { + logger, err := NewJSONLogger(opts...) + if err != nil { + return nil, err + } + return &customLogger{ + db: db, + logger: logger, + }, nil +} + +func (c *customLogger) i() { +} + +// fieldsToJSON 将 zap.Field 转换为 JSON 字符串 +func (c *customLogger) fieldsToJSON(msg string, fields []zap.Field) (string, error) { + // 创建一个 buffer 来存储编码后的 JSON + buffer := &bytes.Buffer{} + + // 创建一个 zapcore.Encoder 对象 + encoderConfig := zap.NewProductionEncoderConfig() + encoder := zapcore.NewJSONEncoder(encoderConfig) + + // 创建一个 zapcore.Core 对象 + core := zapcore.NewCore(encoder, zapcore.AddSync(buffer), zap.InfoLevel) + + // 创建一个 zap.Logger 对象 + tempLogger := zap.New(core) + + // 使用 tempLogger 记录一条日志,只包含 fields + tempLogger.Info(msg, fields...) + + // 获取编码后的 JSON 字符串 + jsonStr := buffer.String() + + // 去掉最后的换行符 + if len(jsonStr) > 0 && jsonStr[len(jsonStr)-1] == '\n' { + jsonStr = jsonStr[:len(jsonStr)-1] + } + + // 解析 JSON 字符串以确保格式正确 + var parsedJSON map[string]interface{} + err := json.Unmarshal([]byte(jsonStr), &parsedJSON) + if err != nil { + return "", err + } + + // 重新编码为 JSON 字符串 + jsonBytes, err := json.Marshal(parsedJSON) + if err != nil { + return "", err + } + + return string(jsonBytes), nil +} + +// fieldsJsonToDB 将 zap.Field 转换为数据库记录 +func (c *customLogger) fieldsJsonToDB(level, msg string, fields []zap.Field) { + content := "" + + jsonFields, err := c.fieldsToJSON(msg, fields) + if err != nil { + c.logger.Error("Failed to convert zap fields to JSON", zap.Error(err)) + } else { + content = jsonFields + } + + if c.db != nil { + if err := c.db.LogOperation.Create(&model.LogOperation{ + Level: level, + Msg: msg, + Content: content, + CreatedAt: time.Now(), + }); err != nil { + log.Println(fmt.Sprintf("Failed to create log operation record: %s", err.Error())) + } + } else { + log.Println(level, msg, content) + } +} + +// Info 重写 Info 方法 +func (c *customLogger) Info(msg string, fields ...zap.Field) { + c.logger.Info(msg, fields...) + c.fieldsJsonToDB("info", msg, fields) +} + +// Debug 调用底层 Debug 方法 +func (c *customLogger) Debug(msg string, fields ...zap.Field) { + c.logger.Debug(msg, fields...) + c.fieldsJsonToDB("debug", msg, fields) +} + +// Warn 调用底层 Warn 方法 +func (c *customLogger) Warn(msg string, fields ...zap.Field) { + c.logger.Warn(msg, fields...) + c.fieldsJsonToDB("warn", msg, fields) +} + +// Error 调用底层 Error 方法 +func (c *customLogger) Error(msg string, fields ...zap.Field) { + c.logger.Error(msg, fields...) + c.fieldsJsonToDB("error", msg, fields) +} + +// Fatal 调用底层 Fatal 方法 +func (c *customLogger) Fatal(msg string, fields ...zap.Field) { + c.logger.Fatal(msg, fields...) + c.fieldsJsonToDB("fatal", msg, fields) +} + +// Sync 调用底层 Sync 方法 +func (c *customLogger) Sync() error { + return c.logger.Sync() +} + +// With 调用底层 With 方法 +//func (c *customLogger) With(db mysql.Repo, fields ...zap.Field) *customLogger { +// return &customLogger{db: db, logger: c.logger.With(fields...)} +//} + +var _ Meta = (*meta)(nil) + +// Meta key-value +type Meta interface { + Key() string + Value() interface{} + meta() +} + +type meta struct { + key string + value interface{} +} + +func (m *meta) Key() string { + return m.key +} + +func (m *meta) Value() interface{} { + return m.value +} + +func (m *meta) meta() {} + +// NewMeta create meat +func NewMeta(key string, value interface{}) Meta { + return &meta{key: key, value: value} +} + +// WrapMeta wrap meta to zap fields +func WrapMeta(err error, metas ...Meta) (fields []zap.Field) { + capacity := len(metas) + 1 // namespace meta + if err != nil { + capacity++ + } + + fields = make([]zap.Field, 0, capacity) + if err != nil { + fields = append(fields, zap.Error(err)) + } + + fields = append(fields, zap.Namespace("meta")) + for _, meta := range metas { + fields = append(fields, zap.Any(meta.Key(), meta.Value())) + } + + return +} diff --git a/internal/pkg/logger/logger_test.go b/internal/pkg/logger/logger_test.go new file mode 100644 index 0000000..7e92e7e --- /dev/null +++ b/internal/pkg/logger/logger_test.go @@ -0,0 +1,60 @@ +package logger + +import ( + "testing" + + "mini-chat/internal/pkg/timeutil" + + "github.com/pkg/errors" + "go.uber.org/zap" +) + +func TestJSONLogger(t *testing.T) { + logger, err := NewJSONLogger( + WithField("defined_key", "defined_value"), + WithTimeLayout(timeutil.CSTLayout), + WithOutputInConsole(), + ) + if err != nil { + t.Fatal(err) + } + defer logger.Sync() + + err = errors.New("pkg error") + logger.Error("err occurs", WrapMeta(nil, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...) + logger.Error("err occurs", WrapMeta(err, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...) + +} + +func TestCustomLogger(t *testing.T) { + logger, err := NewCustomLogger(nil, + WithField("defined_key", "defined_value"), + WithTimeLayout(timeutil.CSTLayout), + //WithOutputInConsole(), + + ) + + if err != nil { + t.Fatal(err) + } + defer logger.Sync() + + err = errors.New("pkg error") + logger.Info("none err") + logger.Info("with err", zap.Error(err)) + logger.Info("err occurs", WrapMeta(nil, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...) + logger.Info("err occurs", WrapMeta(err, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...) +} + +func BenchmarkJsonLogger(b *testing.B) { + b.ResetTimer() + logger, err := NewJSONLogger( + WithField("defined_key", "defined_value"), + ) + if err != nil { + b.Fatal(err) + } + + defer logger.Sync() + +} diff --git a/internal/pkg/shutdown/shutdown.go b/internal/pkg/shutdown/shutdown.go new file mode 100644 index 0000000..0f43681 --- /dev/null +++ b/internal/pkg/shutdown/shutdown.go @@ -0,0 +1,18 @@ +package shutdown + +import ( + "os" + "os/signal" + "syscall" +) + +// Close 监听signal并停止 +func Close(handler func()) { + ctx := make(chan os.Signal, 1) + signal.Notify(ctx, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) + + <-ctx + signal.Stop(ctx) + + handler() +} diff --git a/internal/pkg/startup/info.go b/internal/pkg/startup/info.go new file mode 100644 index 0000000..4f1ead1 --- /dev/null +++ b/internal/pkg/startup/info.go @@ -0,0 +1,58 @@ +package startup + +import ( + "fmt" + "runtime" + "time" + + "mini-chat/configs" + "mini-chat/internal/pkg/env" + + "github.com/common-nighthawk/go-figure" + "github.com/fatih/color" +) + +type status struct { + CustomerProjectNameZh string `json:"customer_project_name_zh"` + CustomerProjectNameEn string `json:"customer_project_name_en"` + CustomerProjectVersion string `json:"customer_project_version"` + ProjectPort string `json:"project_port"` + ProjectEnv string `json:"project_env"` + RuntimeVersion string `json:"runtime_version"` + Now string `json:"now"` +} + +func PrintInfo() { + // 创建 ASCII 艺术标题 + fmt.Println() + myFigure := figure.NewColorFigure(configs.CustomerProjectNameEn, "", "green", true) + myFigure.Print() + + // 项目信息 + green := color.New(color.FgGreen).Add(color.Bold) + green.Printf("▌ 客户项目: %s\n", configs.CustomerProjectNameZh) + green.Printf("▌ 项目版本: %s\n", configs.CustomerProjectVersion) + green.Printf("▌ 启动时间: %s\n", time.Now().Format("2006-01-02 15:04:05")) + green.Printf("▌ 运行环境: %s %s\n", runtime.GOOS, runtime.Version()) + green.Printf("▌ 服务端口: [%s]\n", configs.ProjectPort) + green.Printf("▌ 服务配置: [%s]\n", env.Active().Value()) + + // 服务状态 + fmt.Println() + yellow := color.New(color.FgYellow).Add(color.Bold) + yellow.Printf("▌ 数据库连接: ✔ 已建立\n") + + fmt.Println() +} + +func Info() *status { + return &status{ + CustomerProjectNameZh: configs.CustomerProjectNameZh, + CustomerProjectNameEn: configs.CustomerProjectNameEn, + CustomerProjectVersion: configs.CustomerProjectVersion, + ProjectPort: configs.ProjectPort, + ProjectEnv: env.Active().Value(), + RuntimeVersion: fmt.Sprintf("%s %s", runtime.GOOS, runtime.Version()), + Now: time.Now().Format("2006-01-02 15:04:05"), + } +} diff --git a/internal/pkg/timeutil/timeutil.go b/internal/pkg/timeutil/timeutil.go new file mode 100644 index 0000000..e432e03 --- /dev/null +++ b/internal/pkg/timeutil/timeutil.go @@ -0,0 +1,101 @@ +package timeutil + +import ( + "fmt" + "math" + "net/http" + "time" +) + +var ( + cst *time.Location +) + +// CSTLayout China Standard Time Layout +const CSTLayout = "2006-01-02 15:04:05" + +func init() { + var err error + if cst, err = time.LoadLocation("Asia/Shanghai"); err != nil { + panic(err) + } + + // 默认设置为中国时区 + time.Local = cst +} + +// RFC3339ToCSTLayout convert rfc3339 value to china standard time layout +// 2020-11-08T08:18:46+08:00 => 2020-11-08 08:18:46 +func RFC3339ToCSTLayout(value string) (string, error) { + ts, err := time.Parse(time.RFC3339, value) + if err != nil { + return "", err + } + + return ts.In(cst).Format(CSTLayout), nil +} + +// CSTLayoutString 格式化时间 +// 返回 "2006-01-02 15:04:05" 格式的时间 +func CSTLayoutString() string { + ts := time.Now() + return ts.In(cst).Format(CSTLayout) +} + +// ParseCSTInLocation 格式化时间 +func ParseCSTInLocation(date string) (time.Time, error) { + return time.ParseInLocation(CSTLayout, date, cst) +} + +// ParseHMInLocation 格式化时间 +func ParseHMInLocation(date string) (time.Time, error) { + return time.ParseInLocation("15:04", date, cst) +} + +// CSTLayoutStringToUnix 返回 unix 时间戳 +// 2020-01-24 21:11:11 => 1579871471 +func CSTLayoutStringToUnix(cstLayoutString string) (int64, error) { + stamp, err := time.ParseInLocation(CSTLayout, cstLayoutString, cst) + if err != nil { + return 0, err + } + return stamp.Unix(), nil +} + +// GMTLayoutString 格式化时间 +// 返回 "Mon, 02 Jan 2006 15:04:05 GMT" 格式的时间 +func GMTLayoutString() string { + return time.Now().In(cst).Format(http.TimeFormat) +} + +// ParseGMTInLocation 格式化时间 +func ParseGMTInLocation(date string) (time.Time, error) { + return time.ParseInLocation(http.TimeFormat, date, cst) +} + +// SubInLocation 计算时间差 +func SubInLocation(ts time.Time) float64 { + return math.Abs(time.Now().In(cst).Sub(ts).Seconds()) +} + +// FriendlyTime 返回一个友好的时间格式 +func FriendlyTime(t time.Time) string { + now := time.Now() + diff := now.Sub(t) + + // 计算差异的分钟数 + minutes := int(diff.Minutes()) + + switch { + case minutes < 1: + return "刚刚" + case minutes < 60: + return fmt.Sprintf("%d分钟前", minutes) + case minutes < 1440: // 一天的分钟数 + hours := minutes / 60 + return fmt.Sprintf("%d小时前", hours) + default: + // 如果超过一天,可以返回更详细的日期格式 + return t.Format("2006-01-02 15:04") + } +} diff --git a/internal/pkg/timeutil/timeutil_test.go b/internal/pkg/timeutil/timeutil_test.go new file mode 100644 index 0000000..c05b02f --- /dev/null +++ b/internal/pkg/timeutil/timeutil_test.go @@ -0,0 +1,19 @@ +package timeutil + +import "testing" + +func TestRFC3339ToCSTLayout(t *testing.T) { + t.Log(RFC3339ToCSTLayout("2020-11-08T08:18:46+08:00")) +} + +func TestCSTLayoutString(t *testing.T) { + t.Log(CSTLayoutString()) +} + +func TestCSTLayoutStringToUnix(t *testing.T) { + t.Log(CSTLayoutStringToUnix("2020-01-24 21:11:11")) +} + +func TestGMTLayoutString(t *testing.T) { + t.Log(GMTLayoutString()) +} diff --git a/internal/pkg/trace/debug.go b/internal/pkg/trace/debug.go new file mode 100644 index 0000000..46306a3 --- /dev/null +++ b/internal/pkg/trace/debug.go @@ -0,0 +1,6 @@ +package trace + +type Debug struct { + Stack string `json:"stack"` // 文件地址和行号 + Value []any `json:"value"` // 值 +} diff --git a/internal/pkg/trace/http.go b/internal/pkg/trace/http.go new file mode 100644 index 0000000..a09476e --- /dev/null +++ b/internal/pkg/trace/http.go @@ -0,0 +1,7 @@ +package trace + +type HttpLog struct { + Request map[string]interface{} `json:"request"` // 请求信息 + Response map[string]interface{} `json:"response"` // 响应信息 + CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒) +} diff --git a/internal/pkg/trace/mongo.go b/internal/pkg/trace/mongo.go new file mode 100644 index 0000000..729f45e --- /dev/null +++ b/internal/pkg/trace/mongo.go @@ -0,0 +1,9 @@ +package trace + +type Mongo struct { + Time string `json:"time"` // 时间,格式:2006-01-02 15:04:05 + Database string `json:"database"` // 数据库名称 + Command string `json:"command"` // 命令 + Reply string `json:"reply"` // 响应 + CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒) +} diff --git a/internal/pkg/trace/redis.go b/internal/pkg/trace/redis.go new file mode 100644 index 0000000..f94cd4c --- /dev/null +++ b/internal/pkg/trace/redis.go @@ -0,0 +1,8 @@ +package trace + +type Redis struct { + Time string `json:"time"` // 时间,格式:2006-01-02 15:04:05 + Stack string `json:"stack"` // 文件地址和行号 + Cmd interface{} `json:"cmd"` // 操作 + CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒) +} diff --git a/internal/pkg/trace/sql.go b/internal/pkg/trace/sql.go new file mode 100644 index 0000000..d24c16c --- /dev/null +++ b/internal/pkg/trace/sql.go @@ -0,0 +1,9 @@ +package trace + +type SQL struct { + Time string `json:"time"` // 时间,格式:2006-01-02 15:04:05 + Stack string `json:"stack"` // 文件地址和行号 + SQL string `json:"sql"` // SQL 语句 + Rows int64 `json:"rows_affected"` // 影响行数 + CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒) +} diff --git a/internal/pkg/trace/trace.go b/internal/pkg/trace/trace.go new file mode 100644 index 0000000..1a0e1ae --- /dev/null +++ b/internal/pkg/trace/trace.go @@ -0,0 +1,152 @@ +package trace + +import ( + "sync" + + "mini-chat/internal/pkg/idgen" +) + +const Header = "TRACE-ID" + +var _ T = (*Trace)(nil) + +type T interface { + i() + ID() string + WithRequest(req *Request) *Trace + WithResponse(resp *Response) *Trace + AppendThirdPartyRequests(http *HttpLog) *Trace + AppendSQL(sql *SQL) *Trace + AppendDebug(debug *Debug) *Trace + AppendRedis(redis *Redis) *Trace + AppendMongo(mongo *Mongo) *Trace +} + +// Trace 记录的参数 +type Trace struct { + mux sync.Mutex + Identifier string `json:"trace_id"` // 链路ID + Request *Request `json:"request"` // 请求信息 + Response *Response `json:"response"` // 返回信息 + ThirdPartyRequests []*HttpLog `json:"third_party_requests"` // 调用第三方接口的信息 + Debugs []*Debug `json:"debugs"` // 调试信息 + SQLs []*SQL `json:"sqls"` // 执行的 SQL 信息 + Redis []*Redis `json:"redis"` // 执行的 Redis 信息 + Mongos []*Mongo `json:"mongos"` // 执行的 Mongo 信息 + Success bool `json:"success"` // 请求结果 true or false + CostSeconds float64 `json:"cost_seconds"` // 执行时长(单位秒) +} + +// Request 请求信息 +type Request struct { + TTL string `json:"ttl"` // 请求超时时间 + Method string `json:"method"` // 请求方式 + DecodedURL string `json:"decoded_url"` // 请求地址 + Header interface{} `json:"header"` // 请求 Header 信息 + Body interface{} `json:"body"` // 请求 Body 信息 +} + +// Response 响应信息 +type Response struct { + Header interface{} `json:"header"` // Header 信息 + Body interface{} `json:"body"` // Body 信息 + BusinessCode int `json:"business_code,omitempty"` // 业务码 + BusinessCodeMsg string `json:"business_code_msg,omitempty"` // 提示信息 + HttpCode int `json:"http_code"` // HTTP 状态码 + HttpCodeMsg string `json:"http_code_msg"` // HTTP 状态码信息 + CostSeconds float64 `json:"cost_seconds"` // 执行时间(单位秒) +} + +func New(id string) *Trace { + if id == "" { + id = idgen.GenerateUniqueID() + } + + return &Trace{ + Identifier: id, + } +} + +func (t *Trace) i() {} + +// ID 唯一标识符 +func (t *Trace) ID() string { + return t.Identifier +} + +// WithRequest 设置 request 信息 +func (t *Trace) WithRequest(req *Request) *Trace { + t.Request = req + return t +} + +// WithResponse 设置 response 信息 +func (t *Trace) WithResponse(resp *Response) *Trace { + t.Response = resp + return t +} + +// AppendThirdPartyRequests 追加 HTTP 三方请求日志 +func (t *Trace) AppendThirdPartyRequests(http *HttpLog) *Trace { + if http == nil { + return t + } + + t.mux.Lock() + defer t.mux.Unlock() + + t.ThirdPartyRequests = append(t.ThirdPartyRequests, http) + return t +} + +// AppendDebug 追加 debug 日志 +func (t *Trace) AppendDebug(debug *Debug) *Trace { + if debug == nil { + return t + } + + t.mux.Lock() + defer t.mux.Unlock() + + t.Debugs = append(t.Debugs, debug) + return t +} + +// AppendSQL 追加 SQL 执行日志 +func (t *Trace) AppendSQL(sql *SQL) *Trace { + if sql == nil { + return t + } + + t.mux.Lock() + defer t.mux.Unlock() + + t.SQLs = append(t.SQLs, sql) + return t +} + +// AppendRedis 追加 Redis 执行日志 +func (t *Trace) AppendRedis(redis *Redis) *Trace { + if redis == nil { + return t + } + + t.mux.Lock() + defer t.mux.Unlock() + + t.Redis = append(t.Redis, redis) + return t +} + +// AppendMongo 追加 Mongo 执行日志 +func (t *Trace) AppendMongo(mongo *Mongo) *Trace { + if mongo == nil { + return t + } + + t.mux.Lock() + defer t.mux.Unlock() + + t.Mongos = append(t.Mongos, mongo) + return t +} diff --git a/internal/pkg/utils/utils.go b/internal/pkg/utils/utils.go new file mode 100644 index 0000000..0fef360 --- /dev/null +++ b/internal/pkg/utils/utils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "bytes" + "crypto/md5" + "encoding/base64" + "encoding/hex" + "fmt" + "net" + "net/http" + "strings" + "time" + + "github.com/tealeg/xlsx" + "golang.org/x/crypto/bcrypt" +) + +// GenerateAdminHashedPassword [管理端]生成密码 +func GenerateAdminHashedPassword(password string) (string, error) { + salt := "7M&7p7euU=MM" + passwordWithSalt := password + salt + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(passwordWithSalt), bcrypt.DefaultCost) + if err != nil { + return "", err + } + + return string(hashedPassword), nil +} + +// VerifyAdminHashedPassword [管理端]验证密码 +func VerifyAdminHashedPassword(hashedPassword, password string) bool { + salt := "7M&7p7euU=MM" + passwordWithSalt := password + salt + + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword+salt), []byte(passwordWithSalt)) + return err == nil +} + +// GenerateDoctorHashedPassword [医生端]生成密码 +func GenerateDoctorHashedPassword(password string) (string, error) { + salt := "9M&9p9euU=DD" + passwordWithSalt := password + salt + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(passwordWithSalt), bcrypt.DefaultCost) + if err != nil { + return "", err + } + + return string(hashedPassword), nil +} + +// VerifyDoctorHashedPassword [医生端]验证密码 +func VerifyDoctorHashedPassword(hashedPassword, password string) bool { + salt := "9M&9p9euU=DD" + passwordWithSalt := password + salt + + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword+salt), []byte(passwordWithSalt)) + return err == nil +} + +// GeneratePatientHashedPassword [患者端]生成密码 +func GeneratePatientHashedPassword(password string) (string, error) { + salt := "8T&8p8euU=PP" + passwordWithSalt := password + salt + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(passwordWithSalt), bcrypt.DefaultCost) + if err != nil { + return "", err + } + + return string(hashedPassword), nil +} + +// VerifyPatientHashedPassword [患者端]验证密码 +func VerifyPatientHashedPassword(hashedPassword, password string) bool { + salt := "8T&8p8euU=PP" + passwordWithSalt := password + salt + + err := bcrypt.CompareHashAndPassword([]byte(hashedPassword+salt), []byte(passwordWithSalt)) + return err == nil +} + +// ToExcel 生成 Excel +func ToExcel(titleList []string, dataList []interface{}) []byte { + // 生成一个新的文件 + file := xlsx.NewFile() + + // 添加sheet页 + sheet, _ := file.AddSheet("Sheet1") + + // 插入表头 + titleRow := sheet.AddRow() + for _, v := range titleList { + cell := titleRow.AddCell() + cell.Value = v + } + + // 插入内容 + for _, v := range dataList { + row := sheet.AddRow() + row.WriteStruct(v, -1) + } + + var buffer bytes.Buffer + _ = file.Write(&buffer) + return buffer.Bytes() +} + +func MD5(text string) string { + hash := md5.New() + hash.Write([]byte(text)) + hashBytes := hash.Sum(nil) + return hex.EncodeToString(hashBytes) +} + +// GetIP 尝试从 HTTP 请求中获取真实的客户端 IP 地址 +func GetIP(r *http.Request) string { + // 从 X-Forwarded-For 头部获取IP地址 + xForwardedFor := r.Header.Get("X-Forwarded-For") + if xForwardedFor != "" { + // 可能有多个IP地址,通常第一个是客户端的真实IP + ips := strings.Split(xForwardedFor, ",") + if len(ips) > 0 { + return strings.TrimSpace(ips[0]) + } + } + + // 如果没有 X-Forwarded-For 头部,尝试从 X-Real-IP 获取 + xRealIP := r.Header.Get("X-Real-IP") + if xRealIP != "" { + return strings.TrimSpace(xRealIP) + } + + // 如果没有代理头部,最后退回到 RemoteAddr + ip, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + // 如果处理RemoteAddr出错,返回空字符串 + return "" + } + return ip +} + +// FriendlyTimeAgo 友好时间 +func FriendlyTimeAgo(date time.Time) string { + now := time.Now() + + if date.After(now) { + return "未来的日期" + } + + diff := now.Sub(date) + minutes := int(diff.Minutes()) + hours := int(diff.Hours()) + days := int(hours / 24) + + // 小于1分钟 + if minutes < 1 { + return "刚刚" + } + + // 小于1小时 + if hours < 1 { + return fmt.Sprintf("%d分钟", minutes) + } + + // 小于1天 + if hours < 24 { + return fmt.Sprintf("%d小时", hours) + } + + // 小于1周 + if days < 7 { + return fmt.Sprintf("%d天", days) + } + + // 小于1个月 + if days < 30 { + return fmt.Sprintf("%d周", days/7) + } + + // 小于1年 + if days < 365 { + months := int(days / 30) + if months < 1 { + return fmt.Sprintf("%d天", days) + } + + return fmt.Sprintf("%d个月", months) + } + + // 大于等于1年 + years := days / 365 + remainingDays := days % 365 + months := remainingDays / 30 + + if months == 0 { + return fmt.Sprintf("%d年", years) + } + return fmt.Sprintf("%d年%d个月", years, months) +} + +// FriendlySubTime 时间相减 +func FriendlySubTime(birthday, date time.Time) string { + diff := date.Sub(birthday) + minutes := int(diff.Minutes()) + hours := int(diff.Hours()) + days := int(hours / 24) + + // 小于1分钟 + if minutes < 1 { + return "刚刚" + } + + // 小于1小时 + if hours < 1 { + return fmt.Sprintf("%d分钟", minutes) + } + + // 小于1天 + if hours < 24 { + return fmt.Sprintf("%d小时", hours) + } + + // 小于1周 + if days < 7 { + return fmt.Sprintf("%d天", days) + } + + // 小于1个月 + if days < 30 { + return fmt.Sprintf("%d周", days/7) + } + + // 小于1年 + if days < 365 { + months := int(days / 30) + if months < 1 { + return fmt.Sprintf("%d天", days) + } + + return fmt.Sprintf("%d个月", months) + } + + // 大于等于1年 + years := days / 365 + remainingDays := days % 365 + months := remainingDays / 30 + + if months == 0 { + return fmt.Sprintf("%d岁", years) + } + return fmt.Sprintf("%d岁%d个月", years, months) +} + +func XorEncrypt(phone, key string) string { + result := make([]byte, len(phone)) + for i := 0; i < len(phone); i++ { + result[i] = phone[i] ^ key[i%len(key)] + } + return base64.StdEncoding.EncodeToString(result) +} + +func XorDecrypt(encrypted, key string) (string, error) { + data, err := base64.StdEncoding.DecodeString(encrypted) + if err != nil { + return "", err + } + + result := make([]byte, len(data)) + for i := 0; i < len(data); i++ { + result[i] = data[i] ^ key[i%len(key)] + } + return string(result), nil +} diff --git a/internal/pkg/utils/utils_test.go b/internal/pkg/utils/utils_test.go new file mode 100644 index 0000000..a2f165a --- /dev/null +++ b/internal/pkg/utils/utils_test.go @@ -0,0 +1,30 @@ +package utils + +import ( + "fmt" + "testing" + "time" +) + +func TestGenerateAdminHashedPassword(t *testing.T) { + t.Log(MD5("admin2025")) + t.Log(GenerateAdminHashedPassword(MD5("admin2025"))) +} + +func TestGenerateDoctorHashedPassword(t *testing.T) { + t.Log(MD5("doctor2025")) + t.Log(GenerateDoctorHashedPassword(MD5("doctor2025"))) +} + +func TestGeneratePatientHashedPassword(t *testing.T) { + t.Log(MD5("patient2025")) + t.Log(GeneratePatientHashedPassword(MD5("patient2025"))) +} + +func TestXorEncrypt(t *testing.T) { + t.Log(XorEncrypt(fmt.Sprintf("%s%d", "13800000001", time.Now().Local().Unix()), "999999")) +} + +func TestXorDecrypt(t *testing.T) { + t.Log(XorDecrypt("CAoBCQkJCQkJCQgIDgwKAQwKCg8B", "999999")) +} diff --git a/internal/pkg/validation/validation.go b/internal/pkg/validation/validation.go new file mode 100644 index 0000000..9f0b157 --- /dev/null +++ b/internal/pkg/validation/validation.go @@ -0,0 +1,46 @@ +package validation + +import ( + "fmt" + + "mini-chat/configs" + + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/locales/en" + "github.com/go-playground/locales/zh" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" + enTranslation "github.com/go-playground/validator/v10/translations/en" + zhTranslation "github.com/go-playground/validator/v10/translations/zh" +) + +var trans ut.Translator + +func init() { + lang := configs.Get().Language.Local + + if lang == configs.ZhCN { + trans, _ = ut.New(zh.New()).GetTranslator("zh") + if err := zhTranslation.RegisterDefaultTranslations(binding.Validator.Engine().(*validator.Validate), trans); err != nil { + fmt.Println("validator zh translation error", err) + } + } + + if lang == configs.EnUS { + trans, _ = ut.New(en.New()).GetTranslator("en") + if err := enTranslation.RegisterDefaultTranslations(binding.Validator.Engine().(*validator.Validate), trans); err != nil { + fmt.Println("validator en translation error", err) + } + } +} + +func Error(err error) (message string) { + if validationErrors, ok := err.(validator.ValidationErrors); !ok { + return err.Error() + } else { + for _, e := range validationErrors { + message += e.Translate(trans) + ";" + } + } + return message +} diff --git a/internal/proposal/alert.go b/internal/proposal/alert.go new file mode 100644 index 0000000..8749377 --- /dev/null +++ b/internal/proposal/alert.go @@ -0,0 +1,28 @@ +package proposal + +import ( + "encoding/json" +) + +// AlertMessage 告警信息 +type AlertMessage struct { + ProjectName string `json:"project_name"` // 项目名称 + Env string `json:"env"` // 运行环境 + UID string `json:"uid"` // 用户标示 + TraceID string `json:"trace_id"` // 当前请求的唯一ID + HOST string `json:"host"` // 当前请求的 HOST + URI string `json:"uri"` // 当前请求的 URI + Method string `json:"method"` // 当前请求的 Method + ErrorMessage interface{} `json:"error_message"` // 错误信息 + ErrorStack string `json:"error_stack"` // 堆栈信息 + Time string `json:"time"` // 发生时间 +} + +// Marshal 序列化到JSON +func (a *AlertMessage) Marshal() (jsonRaw []byte) { + jsonRaw, _ = json.Marshal(a) + return +} + +// AlertHandler 告警处理的句柄 +type AlertHandler func(msg *AlertMessage) diff --git a/internal/proposal/metrics.go b/internal/proposal/metrics.go new file mode 100644 index 0000000..d325733 --- /dev/null +++ b/internal/proposal/metrics.go @@ -0,0 +1,25 @@ +package proposal + +import ( + "encoding/json" +) + +// MetricsMessage 指标信息 +type MetricsMessage struct { + HOST string `json:"host"` // 请求 HOST + Path string `json:"path"` // 请求 Path + Method string `json:"method"` // 请求 Method + HTTPCode int `json:"http_code"` // HTTP 状态码 + BusinessCode int `json:"business_code"` // 业务码 + CostSeconds float64 `json:"cost_seconds"` // 耗时,单位:秒 + IsSuccess bool `json:"is_success"` // 状态,是否成功 +} + +// Marshal 序列化到JSON +func (m *MetricsMessage) Marshal() (jsonRaw []byte) { + jsonRaw, _ = json.Marshal(m) + return +} + +// RecordHandler 指标的记录句柄 +type RecordHandler func(msg *MetricsMessage) diff --git a/internal/proposal/request_logger.go b/internal/proposal/request_logger.go new file mode 100644 index 0000000..b53de54 --- /dev/null +++ b/internal/proposal/request_logger.go @@ -0,0 +1,28 @@ +package proposal + +import ( + "encoding/json" +) + +// RequestLoggerMessage 日志消息 +type RequestLoggerMessage struct { + Tid string `json:"tid"` // 请求链路 ID + Username string `json:"username"` // 用户名 + HOST string `json:"host"` // 请求 HOST + Path string `json:"path"` // 请求 Path + Method string `json:"method"` // 请求 Method + HTTPCode int `json:"http_code"` // HTTP 状态码 + BusinessCode int `json:"business_code"` // 业务码 + CostSeconds float64 `json:"cost_seconds"` // 耗时,单位:秒 + IsSuccess bool `json:"is_success"` // 状态,是否成功 + Content string `json:"content"` // 内容 +} + +// Marshal 序列化到JSON +func (m *RequestLoggerMessage) Marshal() (jsonRaw []byte) { + jsonRaw, _ = json.Marshal(m) + return +} + +// RequestLoggerHandler 日志记录句柄 +type RequestLoggerHandler func(msg *RequestLoggerMessage) diff --git a/internal/proposal/session.go b/internal/proposal/session.go new file mode 100644 index 0000000..8d635ae --- /dev/null +++ b/internal/proposal/session.go @@ -0,0 +1,19 @@ +package proposal + +import ( + "encoding/json" +) + +// SessionUserInfo 当前用户会话信息 +type SessionUserInfo struct { + Id int32 `json:"id"` // ID + UserName string `json:"username"` // 用户名 + NickName string `json:"nickname"` // 昵称 + Platform string `json:"platform"` // 平台 +} + +// Marshal 序列化到JSON +func (user *SessionUserInfo) Marshal() (jsonRaw []byte) { + jsonRaw, _ = json.Marshal(user) + return +} diff --git a/internal/repository/mysql/dao/admin.gen.go b/internal/repository/mysql/dao/admin.gen.go new file mode 100644 index 0000000..69b4a4e --- /dev/null +++ b/internal/repository/mysql/dao/admin.gen.go @@ -0,0 +1,368 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newAdmin(db *gorm.DB, opts ...gen.DOOption) admin { + _admin := admin{} + + _admin.adminDo.UseDB(db, opts...) + _admin.adminDo.UseModel(&model.Admin{}) + + tableName := _admin.adminDo.TableName() + _admin.ALL = field.NewAsterisk(tableName) + _admin.ID = field.NewInt32(tableName, "id") + _admin.Username = field.NewString(tableName, "username") + _admin.Nickname = field.NewString(tableName, "nickname") + _admin.Mobile = field.NewString(tableName, "mobile") + _admin.Password = field.NewString(tableName, "password") + _admin.LoginStatus = field.NewInt32(tableName, "login_status") + _admin.LastLoginTime = field.NewTime(tableName, "last_login_time") + _admin.LastLoginIP = field.NewString(tableName, "last_login_ip") + _admin.LastLoginHash = field.NewString(tableName, "last_login_hash") + _admin.CreatedUser = field.NewString(tableName, "created_user") + _admin.CreatedAt = field.NewTime(tableName, "created_at") + _admin.UpdatedUser = field.NewString(tableName, "updated_user") + _admin.UpdatedAt = field.NewTime(tableName, "updated_at") + + _admin.fillFieldMap() + + return _admin +} + +// admin 管理员表 +type admin struct { + adminDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Username field.String // 用户名 + Nickname field.String // 昵称 + Mobile field.String // 手机号 + Password field.String // 密码 + LoginStatus field.Int32 // 登录状态(1:启用 0:禁用) + LastLoginTime field.Time // 最后一次登录时间 + LastLoginIP field.String // 最后一次登录IP + LastLoginHash field.String // 最后一次登录 Hash + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (a admin) Table(newTableName string) *admin { + a.adminDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a admin) As(alias string) *admin { + a.adminDo.DO = *(a.adminDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *admin) updateTableName(table string) *admin { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.Username = field.NewString(table, "username") + a.Nickname = field.NewString(table, "nickname") + a.Mobile = field.NewString(table, "mobile") + a.Password = field.NewString(table, "password") + a.LoginStatus = field.NewInt32(table, "login_status") + a.LastLoginTime = field.NewTime(table, "last_login_time") + a.LastLoginIP = field.NewString(table, "last_login_ip") + a.LastLoginHash = field.NewString(table, "last_login_hash") + a.CreatedUser = field.NewString(table, "created_user") + a.CreatedAt = field.NewTime(table, "created_at") + a.UpdatedUser = field.NewString(table, "updated_user") + a.UpdatedAt = field.NewTime(table, "updated_at") + + a.fillFieldMap() + + return a +} + +func (a *admin) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *admin) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 13) + a.fieldMap["id"] = a.ID + a.fieldMap["username"] = a.Username + a.fieldMap["nickname"] = a.Nickname + a.fieldMap["mobile"] = a.Mobile + a.fieldMap["password"] = a.Password + a.fieldMap["login_status"] = a.LoginStatus + a.fieldMap["last_login_time"] = a.LastLoginTime + a.fieldMap["last_login_ip"] = a.LastLoginIP + a.fieldMap["last_login_hash"] = a.LastLoginHash + a.fieldMap["created_user"] = a.CreatedUser + a.fieldMap["created_at"] = a.CreatedAt + a.fieldMap["updated_user"] = a.UpdatedUser + a.fieldMap["updated_at"] = a.UpdatedAt +} + +func (a admin) clone(db *gorm.DB) admin { + a.adminDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a admin) replaceDB(db *gorm.DB) admin { + a.adminDo.ReplaceDB(db) + return a +} + +type adminDo struct{ gen.DO } + +func (a adminDo) Debug() *adminDo { + return a.withDO(a.DO.Debug()) +} + +func (a adminDo) WithContext(ctx context.Context) *adminDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a adminDo) ReadDB() *adminDo { + return a.Clauses(dbresolver.Read) +} + +func (a adminDo) WriteDB() *adminDo { + return a.Clauses(dbresolver.Write) +} + +func (a adminDo) Session(config *gorm.Session) *adminDo { + return a.withDO(a.DO.Session(config)) +} + +func (a adminDo) Clauses(conds ...clause.Expression) *adminDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a adminDo) Returning(value interface{}, columns ...string) *adminDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a adminDo) Not(conds ...gen.Condition) *adminDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a adminDo) Or(conds ...gen.Condition) *adminDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a adminDo) Select(conds ...field.Expr) *adminDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a adminDo) Where(conds ...gen.Condition) *adminDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a adminDo) Order(conds ...field.Expr) *adminDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a adminDo) Distinct(cols ...field.Expr) *adminDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a adminDo) Omit(cols ...field.Expr) *adminDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a adminDo) Join(table schema.Tabler, on ...field.Expr) *adminDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a adminDo) LeftJoin(table schema.Tabler, on ...field.Expr) *adminDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a adminDo) RightJoin(table schema.Tabler, on ...field.Expr) *adminDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a adminDo) Group(cols ...field.Expr) *adminDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a adminDo) Having(conds ...gen.Condition) *adminDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a adminDo) Limit(limit int) *adminDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a adminDo) Offset(offset int) *adminDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a adminDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *adminDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a adminDo) Unscoped() *adminDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a adminDo) Create(values ...*model.Admin) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a adminDo) CreateInBatches(values []*model.Admin, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a adminDo) Save(values ...*model.Admin) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a adminDo) First() (*model.Admin, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Admin), nil + } +} + +func (a adminDo) Take() (*model.Admin, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Admin), nil + } +} + +func (a adminDo) Last() (*model.Admin, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Admin), nil + } +} + +func (a adminDo) Find() ([]*model.Admin, error) { + result, err := a.DO.Find() + return result.([]*model.Admin), err +} + +func (a adminDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Admin, err error) { + buf := make([]*model.Admin, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a adminDo) FindInBatches(result *[]*model.Admin, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a adminDo) Attrs(attrs ...field.AssignExpr) *adminDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a adminDo) Assign(attrs ...field.AssignExpr) *adminDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a adminDo) Joins(fields ...field.RelationField) *adminDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a adminDo) Preload(fields ...field.RelationField) *adminDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a adminDo) FirstOrInit() (*model.Admin, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Admin), nil + } +} + +func (a adminDo) FirstOrCreate() (*model.Admin, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Admin), nil + } +} + +func (a adminDo) FindByPage(offset int, limit int) (result []*model.Admin, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a adminDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a adminDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a adminDo) Delete(models ...*model.Admin) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *adminDo) withDO(do gen.Dao) *adminDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/app_keyword.gen.go b/internal/repository/mysql/dao/app_keyword.gen.go new file mode 100644 index 0000000..c94fbb0 --- /dev/null +++ b/internal/repository/mysql/dao/app_keyword.gen.go @@ -0,0 +1,344 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newAppKeyword(db *gorm.DB, opts ...gen.DOOption) appKeyword { + _appKeyword := appKeyword{} + + _appKeyword.appKeywordDo.UseDB(db, opts...) + _appKeyword.appKeywordDo.UseModel(&model.AppKeyword{}) + + tableName := _appKeyword.appKeywordDo.TableName() + _appKeyword.ALL = field.NewAsterisk(tableName) + _appKeyword.ID = field.NewInt32(tableName, "id") + _appKeyword.AppID = field.NewString(tableName, "app_id") + _appKeyword.Keyword = field.NewString(tableName, "keyword") + _appKeyword.CreatedUser = field.NewString(tableName, "created_user") + _appKeyword.CreatedAt = field.NewTime(tableName, "created_at") + _appKeyword.UpdatedUser = field.NewString(tableName, "updated_user") + _appKeyword.UpdatedAt = field.NewTime(tableName, "updated_at") + + _appKeyword.fillFieldMap() + + return _appKeyword +} + +// appKeyword 关键字表 +type appKeyword struct { + appKeywordDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + AppID field.String // 小程序ID + Keyword field.String // 关键字 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (a appKeyword) Table(newTableName string) *appKeyword { + a.appKeywordDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a appKeyword) As(alias string) *appKeyword { + a.appKeywordDo.DO = *(a.appKeywordDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *appKeyword) updateTableName(table string) *appKeyword { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.AppID = field.NewString(table, "app_id") + a.Keyword = field.NewString(table, "keyword") + a.CreatedUser = field.NewString(table, "created_user") + a.CreatedAt = field.NewTime(table, "created_at") + a.UpdatedUser = field.NewString(table, "updated_user") + a.UpdatedAt = field.NewTime(table, "updated_at") + + a.fillFieldMap() + + return a +} + +func (a *appKeyword) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *appKeyword) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 7) + a.fieldMap["id"] = a.ID + a.fieldMap["app_id"] = a.AppID + a.fieldMap["keyword"] = a.Keyword + a.fieldMap["created_user"] = a.CreatedUser + a.fieldMap["created_at"] = a.CreatedAt + a.fieldMap["updated_user"] = a.UpdatedUser + a.fieldMap["updated_at"] = a.UpdatedAt +} + +func (a appKeyword) clone(db *gorm.DB) appKeyword { + a.appKeywordDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a appKeyword) replaceDB(db *gorm.DB) appKeyword { + a.appKeywordDo.ReplaceDB(db) + return a +} + +type appKeywordDo struct{ gen.DO } + +func (a appKeywordDo) Debug() *appKeywordDo { + return a.withDO(a.DO.Debug()) +} + +func (a appKeywordDo) WithContext(ctx context.Context) *appKeywordDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a appKeywordDo) ReadDB() *appKeywordDo { + return a.Clauses(dbresolver.Read) +} + +func (a appKeywordDo) WriteDB() *appKeywordDo { + return a.Clauses(dbresolver.Write) +} + +func (a appKeywordDo) Session(config *gorm.Session) *appKeywordDo { + return a.withDO(a.DO.Session(config)) +} + +func (a appKeywordDo) Clauses(conds ...clause.Expression) *appKeywordDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a appKeywordDo) Returning(value interface{}, columns ...string) *appKeywordDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a appKeywordDo) Not(conds ...gen.Condition) *appKeywordDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a appKeywordDo) Or(conds ...gen.Condition) *appKeywordDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a appKeywordDo) Select(conds ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a appKeywordDo) Where(conds ...gen.Condition) *appKeywordDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a appKeywordDo) Order(conds ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a appKeywordDo) Distinct(cols ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a appKeywordDo) Omit(cols ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a appKeywordDo) Join(table schema.Tabler, on ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a appKeywordDo) LeftJoin(table schema.Tabler, on ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a appKeywordDo) RightJoin(table schema.Tabler, on ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a appKeywordDo) Group(cols ...field.Expr) *appKeywordDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a appKeywordDo) Having(conds ...gen.Condition) *appKeywordDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a appKeywordDo) Limit(limit int) *appKeywordDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a appKeywordDo) Offset(offset int) *appKeywordDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a appKeywordDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *appKeywordDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a appKeywordDo) Unscoped() *appKeywordDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a appKeywordDo) Create(values ...*model.AppKeyword) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a appKeywordDo) CreateInBatches(values []*model.AppKeyword, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a appKeywordDo) Save(values ...*model.AppKeyword) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a appKeywordDo) First() (*model.AppKeyword, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.AppKeyword), nil + } +} + +func (a appKeywordDo) Take() (*model.AppKeyword, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.AppKeyword), nil + } +} + +func (a appKeywordDo) Last() (*model.AppKeyword, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.AppKeyword), nil + } +} + +func (a appKeywordDo) Find() ([]*model.AppKeyword, error) { + result, err := a.DO.Find() + return result.([]*model.AppKeyword), err +} + +func (a appKeywordDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppKeyword, err error) { + buf := make([]*model.AppKeyword, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a appKeywordDo) FindInBatches(result *[]*model.AppKeyword, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a appKeywordDo) Attrs(attrs ...field.AssignExpr) *appKeywordDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a appKeywordDo) Assign(attrs ...field.AssignExpr) *appKeywordDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a appKeywordDo) Joins(fields ...field.RelationField) *appKeywordDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a appKeywordDo) Preload(fields ...field.RelationField) *appKeywordDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a appKeywordDo) FirstOrInit() (*model.AppKeyword, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.AppKeyword), nil + } +} + +func (a appKeywordDo) FirstOrCreate() (*model.AppKeyword, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.AppKeyword), nil + } +} + +func (a appKeywordDo) FindByPage(offset int, limit int) (result []*model.AppKeyword, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a appKeywordDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a appKeywordDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a appKeywordDo) Delete(models ...*model.AppKeyword) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *appKeywordDo) withDO(do gen.Dao) *appKeywordDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/app_keyword_reply.gen.go b/internal/repository/mysql/dao/app_keyword_reply.gen.go new file mode 100644 index 0000000..7095803 --- /dev/null +++ b/internal/repository/mysql/dao/app_keyword_reply.gen.go @@ -0,0 +1,356 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newAppKeywordReply(db *gorm.DB, opts ...gen.DOOption) appKeywordReply { + _appKeywordReply := appKeywordReply{} + + _appKeywordReply.appKeywordReplyDo.UseDB(db, opts...) + _appKeywordReply.appKeywordReplyDo.UseModel(&model.AppKeywordReply{}) + + tableName := _appKeywordReply.appKeywordReplyDo.TableName() + _appKeywordReply.ALL = field.NewAsterisk(tableName) + _appKeywordReply.ID = field.NewInt32(tableName, "id") + _appKeywordReply.AppID = field.NewString(tableName, "app_id") + _appKeywordReply.KeywordID = field.NewInt32(tableName, "keyword_id") + _appKeywordReply.IntervalSeconds = field.NewInt32(tableName, "interval_seconds") + _appKeywordReply.Type = field.NewInt32(tableName, "type") + _appKeywordReply.Content = field.NewString(tableName, "content") + _appKeywordReply.CreatedUser = field.NewString(tableName, "created_user") + _appKeywordReply.CreatedAt = field.NewTime(tableName, "created_at") + _appKeywordReply.UpdatedUser = field.NewString(tableName, "updated_user") + _appKeywordReply.UpdatedAt = field.NewTime(tableName, "updated_at") + + _appKeywordReply.fillFieldMap() + + return _appKeywordReply +} + +// appKeywordReply 关键字回复表 +type appKeywordReply struct { + appKeywordReplyDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + AppID field.String // 小程序ID + KeywordID field.Int32 // 关联 app_keyword 表的ID + IntervalSeconds field.Int32 // 时间间隔,单位为秒 + Type field.Int32 // 类型(1:文本 2:图片 3:语音条 4:视频 5=小程序 6=地理位置 7=链接 8=GIF图 9=名片 10=文件 11=转人工) + Content field.String // 内容 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (a appKeywordReply) Table(newTableName string) *appKeywordReply { + a.appKeywordReplyDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a appKeywordReply) As(alias string) *appKeywordReply { + a.appKeywordReplyDo.DO = *(a.appKeywordReplyDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *appKeywordReply) updateTableName(table string) *appKeywordReply { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.AppID = field.NewString(table, "app_id") + a.KeywordID = field.NewInt32(table, "keyword_id") + a.IntervalSeconds = field.NewInt32(table, "interval_seconds") + a.Type = field.NewInt32(table, "type") + a.Content = field.NewString(table, "content") + a.CreatedUser = field.NewString(table, "created_user") + a.CreatedAt = field.NewTime(table, "created_at") + a.UpdatedUser = field.NewString(table, "updated_user") + a.UpdatedAt = field.NewTime(table, "updated_at") + + a.fillFieldMap() + + return a +} + +func (a *appKeywordReply) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *appKeywordReply) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 10) + a.fieldMap["id"] = a.ID + a.fieldMap["app_id"] = a.AppID + a.fieldMap["keyword_id"] = a.KeywordID + a.fieldMap["interval_seconds"] = a.IntervalSeconds + a.fieldMap["type"] = a.Type + a.fieldMap["content"] = a.Content + a.fieldMap["created_user"] = a.CreatedUser + a.fieldMap["created_at"] = a.CreatedAt + a.fieldMap["updated_user"] = a.UpdatedUser + a.fieldMap["updated_at"] = a.UpdatedAt +} + +func (a appKeywordReply) clone(db *gorm.DB) appKeywordReply { + a.appKeywordReplyDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a appKeywordReply) replaceDB(db *gorm.DB) appKeywordReply { + a.appKeywordReplyDo.ReplaceDB(db) + return a +} + +type appKeywordReplyDo struct{ gen.DO } + +func (a appKeywordReplyDo) Debug() *appKeywordReplyDo { + return a.withDO(a.DO.Debug()) +} + +func (a appKeywordReplyDo) WithContext(ctx context.Context) *appKeywordReplyDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a appKeywordReplyDo) ReadDB() *appKeywordReplyDo { + return a.Clauses(dbresolver.Read) +} + +func (a appKeywordReplyDo) WriteDB() *appKeywordReplyDo { + return a.Clauses(dbresolver.Write) +} + +func (a appKeywordReplyDo) Session(config *gorm.Session) *appKeywordReplyDo { + return a.withDO(a.DO.Session(config)) +} + +func (a appKeywordReplyDo) Clauses(conds ...clause.Expression) *appKeywordReplyDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a appKeywordReplyDo) Returning(value interface{}, columns ...string) *appKeywordReplyDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a appKeywordReplyDo) Not(conds ...gen.Condition) *appKeywordReplyDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a appKeywordReplyDo) Or(conds ...gen.Condition) *appKeywordReplyDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a appKeywordReplyDo) Select(conds ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a appKeywordReplyDo) Where(conds ...gen.Condition) *appKeywordReplyDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a appKeywordReplyDo) Order(conds ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a appKeywordReplyDo) Distinct(cols ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a appKeywordReplyDo) Omit(cols ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a appKeywordReplyDo) Join(table schema.Tabler, on ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a appKeywordReplyDo) LeftJoin(table schema.Tabler, on ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a appKeywordReplyDo) RightJoin(table schema.Tabler, on ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a appKeywordReplyDo) Group(cols ...field.Expr) *appKeywordReplyDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a appKeywordReplyDo) Having(conds ...gen.Condition) *appKeywordReplyDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a appKeywordReplyDo) Limit(limit int) *appKeywordReplyDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a appKeywordReplyDo) Offset(offset int) *appKeywordReplyDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a appKeywordReplyDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *appKeywordReplyDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a appKeywordReplyDo) Unscoped() *appKeywordReplyDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a appKeywordReplyDo) Create(values ...*model.AppKeywordReply) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a appKeywordReplyDo) CreateInBatches(values []*model.AppKeywordReply, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a appKeywordReplyDo) Save(values ...*model.AppKeywordReply) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a appKeywordReplyDo) First() (*model.AppKeywordReply, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.AppKeywordReply), nil + } +} + +func (a appKeywordReplyDo) Take() (*model.AppKeywordReply, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.AppKeywordReply), nil + } +} + +func (a appKeywordReplyDo) Last() (*model.AppKeywordReply, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.AppKeywordReply), nil + } +} + +func (a appKeywordReplyDo) Find() ([]*model.AppKeywordReply, error) { + result, err := a.DO.Find() + return result.([]*model.AppKeywordReply), err +} + +func (a appKeywordReplyDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppKeywordReply, err error) { + buf := make([]*model.AppKeywordReply, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a appKeywordReplyDo) FindInBatches(result *[]*model.AppKeywordReply, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a appKeywordReplyDo) Attrs(attrs ...field.AssignExpr) *appKeywordReplyDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a appKeywordReplyDo) Assign(attrs ...field.AssignExpr) *appKeywordReplyDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a appKeywordReplyDo) Joins(fields ...field.RelationField) *appKeywordReplyDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a appKeywordReplyDo) Preload(fields ...field.RelationField) *appKeywordReplyDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a appKeywordReplyDo) FirstOrInit() (*model.AppKeywordReply, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.AppKeywordReply), nil + } +} + +func (a appKeywordReplyDo) FirstOrCreate() (*model.AppKeywordReply, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.AppKeywordReply), nil + } +} + +func (a appKeywordReplyDo) FindByPage(offset int, limit int) (result []*model.AppKeywordReply, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a appKeywordReplyDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a appKeywordReplyDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a appKeywordReplyDo) Delete(models ...*model.AppKeywordReply) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *appKeywordReplyDo) withDO(do gen.Dao) *appKeywordReplyDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/app_message_log.gen.go b/internal/repository/mysql/dao/app_message_log.gen.go new file mode 100644 index 0000000..e90a2b6 --- /dev/null +++ b/internal/repository/mysql/dao/app_message_log.gen.go @@ -0,0 +1,352 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newAppMessageLog(db *gorm.DB, opts ...gen.DOOption) appMessageLog { + _appMessageLog := appMessageLog{} + + _appMessageLog.appMessageLogDo.UseDB(db, opts...) + _appMessageLog.appMessageLogDo.UseModel(&model.AppMessageLog{}) + + tableName := _appMessageLog.appMessageLogDo.TableName() + _appMessageLog.ALL = field.NewAsterisk(tableName) + _appMessageLog.ID = field.NewInt32(tableName, "id") + _appMessageLog.AppID = field.NewString(tableName, "app_id") + _appMessageLog.SenderID = field.NewString(tableName, "sender_id") + _appMessageLog.SenderName = field.NewString(tableName, "sender_name") + _appMessageLog.SendTime = field.NewTime(tableName, "send_time") + _appMessageLog.ReceiverID = field.NewString(tableName, "receiver_id") + _appMessageLog.MsgType = field.NewInt32(tableName, "msg_type") + _appMessageLog.Content = field.NewString(tableName, "content") + _appMessageLog.CreatedAt = field.NewTime(tableName, "created_at") + + _appMessageLog.fillFieldMap() + + return _appMessageLog +} + +// appMessageLog 消息日志表 +type appMessageLog struct { + appMessageLogDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + AppID field.String // 小程序ID + SenderID field.String // 发送人ID + SenderName field.String // 发送人昵称 + SendTime field.Time // 发送时间 + ReceiverID field.String // 接收人ID + MsgType field.Int32 // 信息类型 + Content field.String // 内容 + CreatedAt field.Time // 创建时间 + + fieldMap map[string]field.Expr +} + +func (a appMessageLog) Table(newTableName string) *appMessageLog { + a.appMessageLogDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a appMessageLog) As(alias string) *appMessageLog { + a.appMessageLogDo.DO = *(a.appMessageLogDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *appMessageLog) updateTableName(table string) *appMessageLog { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.AppID = field.NewString(table, "app_id") + a.SenderID = field.NewString(table, "sender_id") + a.SenderName = field.NewString(table, "sender_name") + a.SendTime = field.NewTime(table, "send_time") + a.ReceiverID = field.NewString(table, "receiver_id") + a.MsgType = field.NewInt32(table, "msg_type") + a.Content = field.NewString(table, "content") + a.CreatedAt = field.NewTime(table, "created_at") + + a.fillFieldMap() + + return a +} + +func (a *appMessageLog) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *appMessageLog) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 9) + a.fieldMap["id"] = a.ID + a.fieldMap["app_id"] = a.AppID + a.fieldMap["sender_id"] = a.SenderID + a.fieldMap["sender_name"] = a.SenderName + a.fieldMap["send_time"] = a.SendTime + a.fieldMap["receiver_id"] = a.ReceiverID + a.fieldMap["msg_type"] = a.MsgType + a.fieldMap["content"] = a.Content + a.fieldMap["created_at"] = a.CreatedAt +} + +func (a appMessageLog) clone(db *gorm.DB) appMessageLog { + a.appMessageLogDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a appMessageLog) replaceDB(db *gorm.DB) appMessageLog { + a.appMessageLogDo.ReplaceDB(db) + return a +} + +type appMessageLogDo struct{ gen.DO } + +func (a appMessageLogDo) Debug() *appMessageLogDo { + return a.withDO(a.DO.Debug()) +} + +func (a appMessageLogDo) WithContext(ctx context.Context) *appMessageLogDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a appMessageLogDo) ReadDB() *appMessageLogDo { + return a.Clauses(dbresolver.Read) +} + +func (a appMessageLogDo) WriteDB() *appMessageLogDo { + return a.Clauses(dbresolver.Write) +} + +func (a appMessageLogDo) Session(config *gorm.Session) *appMessageLogDo { + return a.withDO(a.DO.Session(config)) +} + +func (a appMessageLogDo) Clauses(conds ...clause.Expression) *appMessageLogDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a appMessageLogDo) Returning(value interface{}, columns ...string) *appMessageLogDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a appMessageLogDo) Not(conds ...gen.Condition) *appMessageLogDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a appMessageLogDo) Or(conds ...gen.Condition) *appMessageLogDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a appMessageLogDo) Select(conds ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a appMessageLogDo) Where(conds ...gen.Condition) *appMessageLogDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a appMessageLogDo) Order(conds ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a appMessageLogDo) Distinct(cols ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a appMessageLogDo) Omit(cols ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a appMessageLogDo) Join(table schema.Tabler, on ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a appMessageLogDo) LeftJoin(table schema.Tabler, on ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a appMessageLogDo) RightJoin(table schema.Tabler, on ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a appMessageLogDo) Group(cols ...field.Expr) *appMessageLogDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a appMessageLogDo) Having(conds ...gen.Condition) *appMessageLogDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a appMessageLogDo) Limit(limit int) *appMessageLogDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a appMessageLogDo) Offset(offset int) *appMessageLogDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a appMessageLogDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *appMessageLogDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a appMessageLogDo) Unscoped() *appMessageLogDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a appMessageLogDo) Create(values ...*model.AppMessageLog) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a appMessageLogDo) CreateInBatches(values []*model.AppMessageLog, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a appMessageLogDo) Save(values ...*model.AppMessageLog) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a appMessageLogDo) First() (*model.AppMessageLog, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.AppMessageLog), nil + } +} + +func (a appMessageLogDo) Take() (*model.AppMessageLog, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.AppMessageLog), nil + } +} + +func (a appMessageLogDo) Last() (*model.AppMessageLog, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.AppMessageLog), nil + } +} + +func (a appMessageLogDo) Find() ([]*model.AppMessageLog, error) { + result, err := a.DO.Find() + return result.([]*model.AppMessageLog), err +} + +func (a appMessageLogDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppMessageLog, err error) { + buf := make([]*model.AppMessageLog, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a appMessageLogDo) FindInBatches(result *[]*model.AppMessageLog, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a appMessageLogDo) Attrs(attrs ...field.AssignExpr) *appMessageLogDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a appMessageLogDo) Assign(attrs ...field.AssignExpr) *appMessageLogDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a appMessageLogDo) Joins(fields ...field.RelationField) *appMessageLogDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a appMessageLogDo) Preload(fields ...field.RelationField) *appMessageLogDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a appMessageLogDo) FirstOrInit() (*model.AppMessageLog, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.AppMessageLog), nil + } +} + +func (a appMessageLogDo) FirstOrCreate() (*model.AppMessageLog, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.AppMessageLog), nil + } +} + +func (a appMessageLogDo) FindByPage(offset int, limit int) (result []*model.AppMessageLog, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a appMessageLogDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a appMessageLogDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a appMessageLogDo) Delete(models ...*model.AppMessageLog) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *appMessageLogDo) withDO(do gen.Dao) *appMessageLogDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/app_user.gen.go b/internal/repository/mysql/dao/app_user.gen.go new file mode 100644 index 0000000..a2517a0 --- /dev/null +++ b/internal/repository/mysql/dao/app_user.gen.go @@ -0,0 +1,336 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newAppUser(db *gorm.DB, opts ...gen.DOOption) appUser { + _appUser := appUser{} + + _appUser.appUserDo.UseDB(db, opts...) + _appUser.appUserDo.UseModel(&model.AppUser{}) + + tableName := _appUser.appUserDo.TableName() + _appUser.ALL = field.NewAsterisk(tableName) + _appUser.ID = field.NewInt32(tableName, "id") + _appUser.AppID = field.NewString(tableName, "app_id") + _appUser.UserID = field.NewString(tableName, "user_id") + _appUser.UserName = field.NewString(tableName, "user_name") + _appUser.UserAvatar = field.NewString(tableName, "user_avatar") + + _appUser.fillFieldMap() + + return _appUser +} + +// appUser 小程序的用户表 +type appUser struct { + appUserDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + AppID field.String // 小程序ID + UserID field.String // 用户ID + UserName field.String // 用户昵称 + UserAvatar field.String // 用户头像 + + fieldMap map[string]field.Expr +} + +func (a appUser) Table(newTableName string) *appUser { + a.appUserDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a appUser) As(alias string) *appUser { + a.appUserDo.DO = *(a.appUserDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *appUser) updateTableName(table string) *appUser { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.AppID = field.NewString(table, "app_id") + a.UserID = field.NewString(table, "user_id") + a.UserName = field.NewString(table, "user_name") + a.UserAvatar = field.NewString(table, "user_avatar") + + a.fillFieldMap() + + return a +} + +func (a *appUser) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *appUser) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 5) + a.fieldMap["id"] = a.ID + a.fieldMap["app_id"] = a.AppID + a.fieldMap["user_id"] = a.UserID + a.fieldMap["user_name"] = a.UserName + a.fieldMap["user_avatar"] = a.UserAvatar +} + +func (a appUser) clone(db *gorm.DB) appUser { + a.appUserDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a appUser) replaceDB(db *gorm.DB) appUser { + a.appUserDo.ReplaceDB(db) + return a +} + +type appUserDo struct{ gen.DO } + +func (a appUserDo) Debug() *appUserDo { + return a.withDO(a.DO.Debug()) +} + +func (a appUserDo) WithContext(ctx context.Context) *appUserDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a appUserDo) ReadDB() *appUserDo { + return a.Clauses(dbresolver.Read) +} + +func (a appUserDo) WriteDB() *appUserDo { + return a.Clauses(dbresolver.Write) +} + +func (a appUserDo) Session(config *gorm.Session) *appUserDo { + return a.withDO(a.DO.Session(config)) +} + +func (a appUserDo) Clauses(conds ...clause.Expression) *appUserDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a appUserDo) Returning(value interface{}, columns ...string) *appUserDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a appUserDo) Not(conds ...gen.Condition) *appUserDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a appUserDo) Or(conds ...gen.Condition) *appUserDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a appUserDo) Select(conds ...field.Expr) *appUserDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a appUserDo) Where(conds ...gen.Condition) *appUserDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a appUserDo) Order(conds ...field.Expr) *appUserDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a appUserDo) Distinct(cols ...field.Expr) *appUserDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a appUserDo) Omit(cols ...field.Expr) *appUserDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a appUserDo) Join(table schema.Tabler, on ...field.Expr) *appUserDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a appUserDo) LeftJoin(table schema.Tabler, on ...field.Expr) *appUserDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a appUserDo) RightJoin(table schema.Tabler, on ...field.Expr) *appUserDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a appUserDo) Group(cols ...field.Expr) *appUserDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a appUserDo) Having(conds ...gen.Condition) *appUserDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a appUserDo) Limit(limit int) *appUserDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a appUserDo) Offset(offset int) *appUserDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a appUserDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *appUserDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a appUserDo) Unscoped() *appUserDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a appUserDo) Create(values ...*model.AppUser) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a appUserDo) CreateInBatches(values []*model.AppUser, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a appUserDo) Save(values ...*model.AppUser) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a appUserDo) First() (*model.AppUser, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.AppUser), nil + } +} + +func (a appUserDo) Take() (*model.AppUser, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.AppUser), nil + } +} + +func (a appUserDo) Last() (*model.AppUser, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.AppUser), nil + } +} + +func (a appUserDo) Find() ([]*model.AppUser, error) { + result, err := a.DO.Find() + return result.([]*model.AppUser), err +} + +func (a appUserDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AppUser, err error) { + buf := make([]*model.AppUser, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a appUserDo) FindInBatches(result *[]*model.AppUser, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a appUserDo) Attrs(attrs ...field.AssignExpr) *appUserDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a appUserDo) Assign(attrs ...field.AssignExpr) *appUserDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a appUserDo) Joins(fields ...field.RelationField) *appUserDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a appUserDo) Preload(fields ...field.RelationField) *appUserDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a appUserDo) FirstOrInit() (*model.AppUser, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.AppUser), nil + } +} + +func (a appUserDo) FirstOrCreate() (*model.AppUser, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.AppUser), nil + } +} + +func (a appUserDo) FindByPage(offset int, limit int) (result []*model.AppUser, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a appUserDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a appUserDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a appUserDo) Delete(models ...*model.AppUser) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *appUserDo) withDO(do gen.Dao) *appUserDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/article.gen.go b/internal/repository/mysql/dao/article.gen.go new file mode 100644 index 0000000..006f84e --- /dev/null +++ b/internal/repository/mysql/dao/article.gen.go @@ -0,0 +1,348 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newArticle(db *gorm.DB, opts ...gen.DOOption) article { + _article := article{} + + _article.articleDo.UseDB(db, opts...) + _article.articleDo.UseModel(&model.Article{}) + + tableName := _article.articleDo.TableName() + _article.ALL = field.NewAsterisk(tableName) + _article.ID = field.NewInt32(tableName, "id") + _article.Title = field.NewString(tableName, "title") + _article.CoverImage = field.NewString(tableName, "cover_image") + _article.Content = field.NewString(tableName, "content") + _article.CreatedUser = field.NewString(tableName, "created_user") + _article.CreatedAt = field.NewTime(tableName, "created_at") + _article.UpdatedUser = field.NewString(tableName, "updated_user") + _article.UpdatedAt = field.NewTime(tableName, "updated_at") + + _article.fillFieldMap() + + return _article +} + +// article 文章表 +type article struct { + articleDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Title field.String // 文章标题 + CoverImage field.String // 文章封面图 + Content field.String // 文章内容 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (a article) Table(newTableName string) *article { + a.articleDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a article) As(alias string) *article { + a.articleDo.DO = *(a.articleDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *article) updateTableName(table string) *article { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewInt32(table, "id") + a.Title = field.NewString(table, "title") + a.CoverImage = field.NewString(table, "cover_image") + a.Content = field.NewString(table, "content") + a.CreatedUser = field.NewString(table, "created_user") + a.CreatedAt = field.NewTime(table, "created_at") + a.UpdatedUser = field.NewString(table, "updated_user") + a.UpdatedAt = field.NewTime(table, "updated_at") + + a.fillFieldMap() + + return a +} + +func (a *article) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *article) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 8) + a.fieldMap["id"] = a.ID + a.fieldMap["title"] = a.Title + a.fieldMap["cover_image"] = a.CoverImage + a.fieldMap["content"] = a.Content + a.fieldMap["created_user"] = a.CreatedUser + a.fieldMap["created_at"] = a.CreatedAt + a.fieldMap["updated_user"] = a.UpdatedUser + a.fieldMap["updated_at"] = a.UpdatedAt +} + +func (a article) clone(db *gorm.DB) article { + a.articleDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a article) replaceDB(db *gorm.DB) article { + a.articleDo.ReplaceDB(db) + return a +} + +type articleDo struct{ gen.DO } + +func (a articleDo) Debug() *articleDo { + return a.withDO(a.DO.Debug()) +} + +func (a articleDo) WithContext(ctx context.Context) *articleDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a articleDo) ReadDB() *articleDo { + return a.Clauses(dbresolver.Read) +} + +func (a articleDo) WriteDB() *articleDo { + return a.Clauses(dbresolver.Write) +} + +func (a articleDo) Session(config *gorm.Session) *articleDo { + return a.withDO(a.DO.Session(config)) +} + +func (a articleDo) Clauses(conds ...clause.Expression) *articleDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a articleDo) Returning(value interface{}, columns ...string) *articleDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a articleDo) Not(conds ...gen.Condition) *articleDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a articleDo) Or(conds ...gen.Condition) *articleDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a articleDo) Select(conds ...field.Expr) *articleDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a articleDo) Where(conds ...gen.Condition) *articleDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a articleDo) Order(conds ...field.Expr) *articleDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a articleDo) Distinct(cols ...field.Expr) *articleDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a articleDo) Omit(cols ...field.Expr) *articleDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a articleDo) Join(table schema.Tabler, on ...field.Expr) *articleDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a articleDo) LeftJoin(table schema.Tabler, on ...field.Expr) *articleDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a articleDo) RightJoin(table schema.Tabler, on ...field.Expr) *articleDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a articleDo) Group(cols ...field.Expr) *articleDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a articleDo) Having(conds ...gen.Condition) *articleDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a articleDo) Limit(limit int) *articleDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a articleDo) Offset(offset int) *articleDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a articleDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *articleDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a articleDo) Unscoped() *articleDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a articleDo) Create(values ...*model.Article) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a articleDo) CreateInBatches(values []*model.Article, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a articleDo) Save(values ...*model.Article) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a articleDo) First() (*model.Article, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Article), nil + } +} + +func (a articleDo) Take() (*model.Article, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Article), nil + } +} + +func (a articleDo) Last() (*model.Article, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Article), nil + } +} + +func (a articleDo) Find() ([]*model.Article, error) { + result, err := a.DO.Find() + return result.([]*model.Article), err +} + +func (a articleDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Article, err error) { + buf := make([]*model.Article, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a articleDo) FindInBatches(result *[]*model.Article, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a articleDo) Attrs(attrs ...field.AssignExpr) *articleDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a articleDo) Assign(attrs ...field.AssignExpr) *articleDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a articleDo) Joins(fields ...field.RelationField) *articleDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a articleDo) Preload(fields ...field.RelationField) *articleDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a articleDo) FirstOrInit() (*model.Article, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Article), nil + } +} + +func (a articleDo) FirstOrCreate() (*model.Article, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Article), nil + } +} + +func (a articleDo) FindByPage(offset int, limit int) (result []*model.Article, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a articleDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a articleDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a articleDo) Delete(models ...*model.Article) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *articleDo) withDO(do gen.Dao) *articleDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/internal/repository/mysql/dao/diagnostic_record.gen.go b/internal/repository/mysql/dao/diagnostic_record.gen.go new file mode 100644 index 0000000..1d37987 --- /dev/null +++ b/internal/repository/mysql/dao/diagnostic_record.gen.go @@ -0,0 +1,364 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newDiagnosticRecord(db *gorm.DB, opts ...gen.DOOption) diagnosticRecord { + _diagnosticRecord := diagnosticRecord{} + + _diagnosticRecord.diagnosticRecordDo.UseDB(db, opts...) + _diagnosticRecord.diagnosticRecordDo.UseModel(&model.DiagnosticRecord{}) + + tableName := _diagnosticRecord.diagnosticRecordDo.TableName() + _diagnosticRecord.ALL = field.NewAsterisk(tableName) + _diagnosticRecord.ID = field.NewInt32(tableName, "id") + _diagnosticRecord.UserID = field.NewString(tableName, "user_id") + _diagnosticRecord.Username = field.NewString(tableName, "username") + _diagnosticRecord.Mobile = field.NewString(tableName, "mobile") + _diagnosticRecord.Mmp7 = field.NewString(tableName, "mmp_7") + _diagnosticRecord.Day = field.NewInt32(tableName, "day") + _diagnosticRecord.GallbladderImage = field.NewString(tableName, "gallbladder_image") + _diagnosticRecord.PortalVeinBranchImage = field.NewString(tableName, "portal_vein_branch_image") + _diagnosticRecord.PortalVeinCrossImage = field.NewString(tableName, "portal_vein_cross_image") + _diagnosticRecord.IdentifyResult = field.NewString(tableName, "identify_result") + _diagnosticRecord.CreatedUser = field.NewString(tableName, "created_user") + _diagnosticRecord.CreatedAt = field.NewTime(tableName, "created_at") + + _diagnosticRecord.fillFieldMap() + + return _diagnosticRecord +} + +// diagnosticRecord 诊断记录表 +type diagnosticRecord struct { + diagnosticRecordDo + + ALL field.Asterisk + ID field.Int32 // 主键 + UserID field.String // 用户ID(openid) + Username field.String // 姓名 + Mobile field.String // 手机号 + Mmp7 field.String // MMP-7检测值 + Day field.Int32 // 日龄(天) + GallbladderImage field.String // 胆囊照片 + PortalVeinBranchImage field.String // 门静脉左右分支照片 + PortalVeinCrossImage field.String // 门静脉右支横截照片 + IdentifyResult field.String // 识别结果 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + + fieldMap map[string]field.Expr +} + +func (d diagnosticRecord) Table(newTableName string) *diagnosticRecord { + d.diagnosticRecordDo.UseTable(newTableName) + return d.updateTableName(newTableName) +} + +func (d diagnosticRecord) As(alias string) *diagnosticRecord { + d.diagnosticRecordDo.DO = *(d.diagnosticRecordDo.As(alias).(*gen.DO)) + return d.updateTableName(alias) +} + +func (d *diagnosticRecord) updateTableName(table string) *diagnosticRecord { + d.ALL = field.NewAsterisk(table) + d.ID = field.NewInt32(table, "id") + d.UserID = field.NewString(table, "user_id") + d.Username = field.NewString(table, "username") + d.Mobile = field.NewString(table, "mobile") + d.Mmp7 = field.NewString(table, "mmp_7") + d.Day = field.NewInt32(table, "day") + d.GallbladderImage = field.NewString(table, "gallbladder_image") + d.PortalVeinBranchImage = field.NewString(table, "portal_vein_branch_image") + d.PortalVeinCrossImage = field.NewString(table, "portal_vein_cross_image") + d.IdentifyResult = field.NewString(table, "identify_result") + d.CreatedUser = field.NewString(table, "created_user") + d.CreatedAt = field.NewTime(table, "created_at") + + d.fillFieldMap() + + return d +} + +func (d *diagnosticRecord) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := d.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (d *diagnosticRecord) fillFieldMap() { + d.fieldMap = make(map[string]field.Expr, 12) + d.fieldMap["id"] = d.ID + d.fieldMap["user_id"] = d.UserID + d.fieldMap["username"] = d.Username + d.fieldMap["mobile"] = d.Mobile + d.fieldMap["mmp_7"] = d.Mmp7 + d.fieldMap["day"] = d.Day + d.fieldMap["gallbladder_image"] = d.GallbladderImage + d.fieldMap["portal_vein_branch_image"] = d.PortalVeinBranchImage + d.fieldMap["portal_vein_cross_image"] = d.PortalVeinCrossImage + d.fieldMap["identify_result"] = d.IdentifyResult + d.fieldMap["created_user"] = d.CreatedUser + d.fieldMap["created_at"] = d.CreatedAt +} + +func (d diagnosticRecord) clone(db *gorm.DB) diagnosticRecord { + d.diagnosticRecordDo.ReplaceConnPool(db.Statement.ConnPool) + return d +} + +func (d diagnosticRecord) replaceDB(db *gorm.DB) diagnosticRecord { + d.diagnosticRecordDo.ReplaceDB(db) + return d +} + +type diagnosticRecordDo struct{ gen.DO } + +func (d diagnosticRecordDo) Debug() *diagnosticRecordDo { + return d.withDO(d.DO.Debug()) +} + +func (d diagnosticRecordDo) WithContext(ctx context.Context) *diagnosticRecordDo { + return d.withDO(d.DO.WithContext(ctx)) +} + +func (d diagnosticRecordDo) ReadDB() *diagnosticRecordDo { + return d.Clauses(dbresolver.Read) +} + +func (d diagnosticRecordDo) WriteDB() *diagnosticRecordDo { + return d.Clauses(dbresolver.Write) +} + +func (d diagnosticRecordDo) Session(config *gorm.Session) *diagnosticRecordDo { + return d.withDO(d.DO.Session(config)) +} + +func (d diagnosticRecordDo) Clauses(conds ...clause.Expression) *diagnosticRecordDo { + return d.withDO(d.DO.Clauses(conds...)) +} + +func (d diagnosticRecordDo) Returning(value interface{}, columns ...string) *diagnosticRecordDo { + return d.withDO(d.DO.Returning(value, columns...)) +} + +func (d diagnosticRecordDo) Not(conds ...gen.Condition) *diagnosticRecordDo { + return d.withDO(d.DO.Not(conds...)) +} + +func (d diagnosticRecordDo) Or(conds ...gen.Condition) *diagnosticRecordDo { + return d.withDO(d.DO.Or(conds...)) +} + +func (d diagnosticRecordDo) Select(conds ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Select(conds...)) +} + +func (d diagnosticRecordDo) Where(conds ...gen.Condition) *diagnosticRecordDo { + return d.withDO(d.DO.Where(conds...)) +} + +func (d diagnosticRecordDo) Order(conds ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Order(conds...)) +} + +func (d diagnosticRecordDo) Distinct(cols ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Distinct(cols...)) +} + +func (d diagnosticRecordDo) Omit(cols ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Omit(cols...)) +} + +func (d diagnosticRecordDo) Join(table schema.Tabler, on ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Join(table, on...)) +} + +func (d diagnosticRecordDo) LeftJoin(table schema.Tabler, on ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.LeftJoin(table, on...)) +} + +func (d diagnosticRecordDo) RightJoin(table schema.Tabler, on ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.RightJoin(table, on...)) +} + +func (d diagnosticRecordDo) Group(cols ...field.Expr) *diagnosticRecordDo { + return d.withDO(d.DO.Group(cols...)) +} + +func (d diagnosticRecordDo) Having(conds ...gen.Condition) *diagnosticRecordDo { + return d.withDO(d.DO.Having(conds...)) +} + +func (d diagnosticRecordDo) Limit(limit int) *diagnosticRecordDo { + return d.withDO(d.DO.Limit(limit)) +} + +func (d diagnosticRecordDo) Offset(offset int) *diagnosticRecordDo { + return d.withDO(d.DO.Offset(offset)) +} + +func (d diagnosticRecordDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *diagnosticRecordDo { + return d.withDO(d.DO.Scopes(funcs...)) +} + +func (d diagnosticRecordDo) Unscoped() *diagnosticRecordDo { + return d.withDO(d.DO.Unscoped()) +} + +func (d diagnosticRecordDo) Create(values ...*model.DiagnosticRecord) error { + if len(values) == 0 { + return nil + } + return d.DO.Create(values) +} + +func (d diagnosticRecordDo) CreateInBatches(values []*model.DiagnosticRecord, batchSize int) error { + return d.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (d diagnosticRecordDo) Save(values ...*model.DiagnosticRecord) error { + if len(values) == 0 { + return nil + } + return d.DO.Save(values) +} + +func (d diagnosticRecordDo) First() (*model.DiagnosticRecord, error) { + if result, err := d.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.DiagnosticRecord), nil + } +} + +func (d diagnosticRecordDo) Take() (*model.DiagnosticRecord, error) { + if result, err := d.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.DiagnosticRecord), nil + } +} + +func (d diagnosticRecordDo) Last() (*model.DiagnosticRecord, error) { + if result, err := d.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.DiagnosticRecord), nil + } +} + +func (d diagnosticRecordDo) Find() ([]*model.DiagnosticRecord, error) { + result, err := d.DO.Find() + return result.([]*model.DiagnosticRecord), err +} + +func (d diagnosticRecordDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.DiagnosticRecord, err error) { + buf := make([]*model.DiagnosticRecord, 0, batchSize) + err = d.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (d diagnosticRecordDo) FindInBatches(result *[]*model.DiagnosticRecord, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return d.DO.FindInBatches(result, batchSize, fc) +} + +func (d diagnosticRecordDo) Attrs(attrs ...field.AssignExpr) *diagnosticRecordDo { + return d.withDO(d.DO.Attrs(attrs...)) +} + +func (d diagnosticRecordDo) Assign(attrs ...field.AssignExpr) *diagnosticRecordDo { + return d.withDO(d.DO.Assign(attrs...)) +} + +func (d diagnosticRecordDo) Joins(fields ...field.RelationField) *diagnosticRecordDo { + for _, _f := range fields { + d = *d.withDO(d.DO.Joins(_f)) + } + return &d +} + +func (d diagnosticRecordDo) Preload(fields ...field.RelationField) *diagnosticRecordDo { + for _, _f := range fields { + d = *d.withDO(d.DO.Preload(_f)) + } + return &d +} + +func (d diagnosticRecordDo) FirstOrInit() (*model.DiagnosticRecord, error) { + if result, err := d.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.DiagnosticRecord), nil + } +} + +func (d diagnosticRecordDo) FirstOrCreate() (*model.DiagnosticRecord, error) { + if result, err := d.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.DiagnosticRecord), nil + } +} + +func (d diagnosticRecordDo) FindByPage(offset int, limit int) (result []*model.DiagnosticRecord, count int64, err error) { + result, err = d.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = d.Offset(-1).Limit(-1).Count() + return +} + +func (d diagnosticRecordDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = d.Count() + if err != nil { + return + } + + err = d.Offset(offset).Limit(limit).Scan(result) + return +} + +func (d diagnosticRecordDo) Scan(result interface{}) (err error) { + return d.DO.Scan(result) +} + +func (d diagnosticRecordDo) Delete(models ...*model.DiagnosticRecord) (result gen.ResultInfo, err error) { + return d.DO.Delete(models) +} + +func (d *diagnosticRecordDo) withDO(do gen.Dao) *diagnosticRecordDo { + d.DO = *do.(*gen.DO) + return d +} diff --git a/internal/repository/mysql/dao/doctor.gen.go b/internal/repository/mysql/dao/doctor.gen.go new file mode 100644 index 0000000..8be5e34 --- /dev/null +++ b/internal/repository/mysql/dao/doctor.gen.go @@ -0,0 +1,368 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newDoctor(db *gorm.DB, opts ...gen.DOOption) doctor { + _doctor := doctor{} + + _doctor.doctorDo.UseDB(db, opts...) + _doctor.doctorDo.UseModel(&model.Doctor{}) + + tableName := _doctor.doctorDo.TableName() + _doctor.ALL = field.NewAsterisk(tableName) + _doctor.ID = field.NewInt32(tableName, "id") + _doctor.Username = field.NewString(tableName, "username") + _doctor.Nickname = field.NewString(tableName, "nickname") + _doctor.Mobile = field.NewString(tableName, "mobile") + _doctor.Password = field.NewString(tableName, "password") + _doctor.LoginStatus = field.NewInt32(tableName, "login_status") + _doctor.LastLoginTime = field.NewTime(tableName, "last_login_time") + _doctor.LastLoginIP = field.NewString(tableName, "last_login_ip") + _doctor.LastLoginHash = field.NewString(tableName, "last_login_hash") + _doctor.CreatedUser = field.NewString(tableName, "created_user") + _doctor.CreatedAt = field.NewTime(tableName, "created_at") + _doctor.UpdatedUser = field.NewString(tableName, "updated_user") + _doctor.UpdatedAt = field.NewTime(tableName, "updated_at") + + _doctor.fillFieldMap() + + return _doctor +} + +// doctor 医生表 +type doctor struct { + doctorDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Username field.String // 用户名 + Nickname field.String // 昵称 + Mobile field.String // 手机号 + Password field.String // 密码 + LoginStatus field.Int32 // 登录状态(1:启用 0:禁用) + LastLoginTime field.Time // 最后一次登录时间 + LastLoginIP field.String // 最后一次登录IP + LastLoginHash field.String // 最后一次登录 Hash + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (d doctor) Table(newTableName string) *doctor { + d.doctorDo.UseTable(newTableName) + return d.updateTableName(newTableName) +} + +func (d doctor) As(alias string) *doctor { + d.doctorDo.DO = *(d.doctorDo.As(alias).(*gen.DO)) + return d.updateTableName(alias) +} + +func (d *doctor) updateTableName(table string) *doctor { + d.ALL = field.NewAsterisk(table) + d.ID = field.NewInt32(table, "id") + d.Username = field.NewString(table, "username") + d.Nickname = field.NewString(table, "nickname") + d.Mobile = field.NewString(table, "mobile") + d.Password = field.NewString(table, "password") + d.LoginStatus = field.NewInt32(table, "login_status") + d.LastLoginTime = field.NewTime(table, "last_login_time") + d.LastLoginIP = field.NewString(table, "last_login_ip") + d.LastLoginHash = field.NewString(table, "last_login_hash") + d.CreatedUser = field.NewString(table, "created_user") + d.CreatedAt = field.NewTime(table, "created_at") + d.UpdatedUser = field.NewString(table, "updated_user") + d.UpdatedAt = field.NewTime(table, "updated_at") + + d.fillFieldMap() + + return d +} + +func (d *doctor) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := d.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (d *doctor) fillFieldMap() { + d.fieldMap = make(map[string]field.Expr, 13) + d.fieldMap["id"] = d.ID + d.fieldMap["username"] = d.Username + d.fieldMap["nickname"] = d.Nickname + d.fieldMap["mobile"] = d.Mobile + d.fieldMap["password"] = d.Password + d.fieldMap["login_status"] = d.LoginStatus + d.fieldMap["last_login_time"] = d.LastLoginTime + d.fieldMap["last_login_ip"] = d.LastLoginIP + d.fieldMap["last_login_hash"] = d.LastLoginHash + d.fieldMap["created_user"] = d.CreatedUser + d.fieldMap["created_at"] = d.CreatedAt + d.fieldMap["updated_user"] = d.UpdatedUser + d.fieldMap["updated_at"] = d.UpdatedAt +} + +func (d doctor) clone(db *gorm.DB) doctor { + d.doctorDo.ReplaceConnPool(db.Statement.ConnPool) + return d +} + +func (d doctor) replaceDB(db *gorm.DB) doctor { + d.doctorDo.ReplaceDB(db) + return d +} + +type doctorDo struct{ gen.DO } + +func (d doctorDo) Debug() *doctorDo { + return d.withDO(d.DO.Debug()) +} + +func (d doctorDo) WithContext(ctx context.Context) *doctorDo { + return d.withDO(d.DO.WithContext(ctx)) +} + +func (d doctorDo) ReadDB() *doctorDo { + return d.Clauses(dbresolver.Read) +} + +func (d doctorDo) WriteDB() *doctorDo { + return d.Clauses(dbresolver.Write) +} + +func (d doctorDo) Session(config *gorm.Session) *doctorDo { + return d.withDO(d.DO.Session(config)) +} + +func (d doctorDo) Clauses(conds ...clause.Expression) *doctorDo { + return d.withDO(d.DO.Clauses(conds...)) +} + +func (d doctorDo) Returning(value interface{}, columns ...string) *doctorDo { + return d.withDO(d.DO.Returning(value, columns...)) +} + +func (d doctorDo) Not(conds ...gen.Condition) *doctorDo { + return d.withDO(d.DO.Not(conds...)) +} + +func (d doctorDo) Or(conds ...gen.Condition) *doctorDo { + return d.withDO(d.DO.Or(conds...)) +} + +func (d doctorDo) Select(conds ...field.Expr) *doctorDo { + return d.withDO(d.DO.Select(conds...)) +} + +func (d doctorDo) Where(conds ...gen.Condition) *doctorDo { + return d.withDO(d.DO.Where(conds...)) +} + +func (d doctorDo) Order(conds ...field.Expr) *doctorDo { + return d.withDO(d.DO.Order(conds...)) +} + +func (d doctorDo) Distinct(cols ...field.Expr) *doctorDo { + return d.withDO(d.DO.Distinct(cols...)) +} + +func (d doctorDo) Omit(cols ...field.Expr) *doctorDo { + return d.withDO(d.DO.Omit(cols...)) +} + +func (d doctorDo) Join(table schema.Tabler, on ...field.Expr) *doctorDo { + return d.withDO(d.DO.Join(table, on...)) +} + +func (d doctorDo) LeftJoin(table schema.Tabler, on ...field.Expr) *doctorDo { + return d.withDO(d.DO.LeftJoin(table, on...)) +} + +func (d doctorDo) RightJoin(table schema.Tabler, on ...field.Expr) *doctorDo { + return d.withDO(d.DO.RightJoin(table, on...)) +} + +func (d doctorDo) Group(cols ...field.Expr) *doctorDo { + return d.withDO(d.DO.Group(cols...)) +} + +func (d doctorDo) Having(conds ...gen.Condition) *doctorDo { + return d.withDO(d.DO.Having(conds...)) +} + +func (d doctorDo) Limit(limit int) *doctorDo { + return d.withDO(d.DO.Limit(limit)) +} + +func (d doctorDo) Offset(offset int) *doctorDo { + return d.withDO(d.DO.Offset(offset)) +} + +func (d doctorDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *doctorDo { + return d.withDO(d.DO.Scopes(funcs...)) +} + +func (d doctorDo) Unscoped() *doctorDo { + return d.withDO(d.DO.Unscoped()) +} + +func (d doctorDo) Create(values ...*model.Doctor) error { + if len(values) == 0 { + return nil + } + return d.DO.Create(values) +} + +func (d doctorDo) CreateInBatches(values []*model.Doctor, batchSize int) error { + return d.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (d doctorDo) Save(values ...*model.Doctor) error { + if len(values) == 0 { + return nil + } + return d.DO.Save(values) +} + +func (d doctorDo) First() (*model.Doctor, error) { + if result, err := d.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Doctor), nil + } +} + +func (d doctorDo) Take() (*model.Doctor, error) { + if result, err := d.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Doctor), nil + } +} + +func (d doctorDo) Last() (*model.Doctor, error) { + if result, err := d.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Doctor), nil + } +} + +func (d doctorDo) Find() ([]*model.Doctor, error) { + result, err := d.DO.Find() + return result.([]*model.Doctor), err +} + +func (d doctorDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Doctor, err error) { + buf := make([]*model.Doctor, 0, batchSize) + err = d.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (d doctorDo) FindInBatches(result *[]*model.Doctor, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return d.DO.FindInBatches(result, batchSize, fc) +} + +func (d doctorDo) Attrs(attrs ...field.AssignExpr) *doctorDo { + return d.withDO(d.DO.Attrs(attrs...)) +} + +func (d doctorDo) Assign(attrs ...field.AssignExpr) *doctorDo { + return d.withDO(d.DO.Assign(attrs...)) +} + +func (d doctorDo) Joins(fields ...field.RelationField) *doctorDo { + for _, _f := range fields { + d = *d.withDO(d.DO.Joins(_f)) + } + return &d +} + +func (d doctorDo) Preload(fields ...field.RelationField) *doctorDo { + for _, _f := range fields { + d = *d.withDO(d.DO.Preload(_f)) + } + return &d +} + +func (d doctorDo) FirstOrInit() (*model.Doctor, error) { + if result, err := d.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Doctor), nil + } +} + +func (d doctorDo) FirstOrCreate() (*model.Doctor, error) { + if result, err := d.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Doctor), nil + } +} + +func (d doctorDo) FindByPage(offset int, limit int) (result []*model.Doctor, count int64, err error) { + result, err = d.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = d.Offset(-1).Limit(-1).Count() + return +} + +func (d doctorDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = d.Count() + if err != nil { + return + } + + err = d.Offset(offset).Limit(limit).Scan(result) + return +} + +func (d doctorDo) Scan(result interface{}) (err error) { + return d.DO.Scan(result) +} + +func (d doctorDo) Delete(models ...*model.Doctor) (result gen.ResultInfo, err error) { + return d.DO.Delete(models) +} + +func (d *doctorDo) withDO(do gen.Dao) *doctorDo { + d.DO = *do.(*gen.DO) + return d +} diff --git a/internal/repository/mysql/dao/gen.go b/internal/repository/mysql/dao/gen.go new file mode 100644 index 0000000..0786798 --- /dev/null +++ b/internal/repository/mysql/dao/gen.go @@ -0,0 +1,159 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + "database/sql" + + "gorm.io/gorm" + + "gorm.io/gen" + + "gorm.io/plugin/dbresolver" +) + +var ( + Q = new(Query) + Admin *admin + AppKeyword *appKeyword + AppKeywordReply *appKeywordReply + AppMessageLog *appMessageLog + AppUser *appUser + LogOperation *logOperation + LogRequest *logRequest + MiniProgram *miniProgram +) + +func SetDefault(db *gorm.DB, opts ...gen.DOOption) { + *Q = *Use(db, opts...) + Admin = &Q.Admin + AppKeyword = &Q.AppKeyword + AppKeywordReply = &Q.AppKeywordReply + AppMessageLog = &Q.AppMessageLog + AppUser = &Q.AppUser + LogOperation = &Q.LogOperation + LogRequest = &Q.LogRequest + MiniProgram = &Q.MiniProgram +} + +func Use(db *gorm.DB, opts ...gen.DOOption) *Query { + return &Query{ + db: db, + Admin: newAdmin(db, opts...), + AppKeyword: newAppKeyword(db, opts...), + AppKeywordReply: newAppKeywordReply(db, opts...), + AppMessageLog: newAppMessageLog(db, opts...), + AppUser: newAppUser(db, opts...), + LogOperation: newLogOperation(db, opts...), + LogRequest: newLogRequest(db, opts...), + MiniProgram: newMiniProgram(db, opts...), + } +} + +type Query struct { + db *gorm.DB + + Admin admin + AppKeyword appKeyword + AppKeywordReply appKeywordReply + AppMessageLog appMessageLog + AppUser appUser + LogOperation logOperation + LogRequest logRequest + MiniProgram miniProgram +} + +func (q *Query) Available() bool { return q.db != nil } + +func (q *Query) clone(db *gorm.DB) *Query { + return &Query{ + db: db, + Admin: q.Admin.clone(db), + AppKeyword: q.AppKeyword.clone(db), + AppKeywordReply: q.AppKeywordReply.clone(db), + AppMessageLog: q.AppMessageLog.clone(db), + AppUser: q.AppUser.clone(db), + LogOperation: q.LogOperation.clone(db), + LogRequest: q.LogRequest.clone(db), + MiniProgram: q.MiniProgram.clone(db), + } +} + +func (q *Query) ReadDB() *Query { + return q.ReplaceDB(q.db.Clauses(dbresolver.Read)) +} + +func (q *Query) WriteDB() *Query { + return q.ReplaceDB(q.db.Clauses(dbresolver.Write)) +} + +func (q *Query) ReplaceDB(db *gorm.DB) *Query { + return &Query{ + db: db, + Admin: q.Admin.replaceDB(db), + AppKeyword: q.AppKeyword.replaceDB(db), + AppKeywordReply: q.AppKeywordReply.replaceDB(db), + AppMessageLog: q.AppMessageLog.replaceDB(db), + AppUser: q.AppUser.replaceDB(db), + LogOperation: q.LogOperation.replaceDB(db), + LogRequest: q.LogRequest.replaceDB(db), + MiniProgram: q.MiniProgram.replaceDB(db), + } +} + +type queryCtx struct { + Admin *adminDo + AppKeyword *appKeywordDo + AppKeywordReply *appKeywordReplyDo + AppMessageLog *appMessageLogDo + AppUser *appUserDo + LogOperation *logOperationDo + LogRequest *logRequestDo + MiniProgram *miniProgramDo +} + +func (q *Query) WithContext(ctx context.Context) *queryCtx { + return &queryCtx{ + Admin: q.Admin.WithContext(ctx), + AppKeyword: q.AppKeyword.WithContext(ctx), + AppKeywordReply: q.AppKeywordReply.WithContext(ctx), + AppMessageLog: q.AppMessageLog.WithContext(ctx), + AppUser: q.AppUser.WithContext(ctx), + LogOperation: q.LogOperation.WithContext(ctx), + LogRequest: q.LogRequest.WithContext(ctx), + MiniProgram: q.MiniProgram.WithContext(ctx), + } +} + +func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error { + return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...) +} + +func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx { + tx := q.db.Begin(opts...) + return &QueryTx{Query: q.clone(tx), Error: tx.Error} +} + +type QueryTx struct { + *Query + Error error +} + +func (q *QueryTx) Commit() error { + return q.db.Commit().Error +} + +func (q *QueryTx) Rollback() error { + return q.db.Rollback().Error +} + +func (q *QueryTx) SavePoint(name string) error { + return q.db.SavePoint(name).Error +} + +func (q *QueryTx) RollbackTo(name string) error { + return q.db.RollbackTo(name).Error +} diff --git a/internal/repository/mysql/dao/log_operation.gen.go b/internal/repository/mysql/dao/log_operation.gen.go new file mode 100644 index 0000000..f46a831 --- /dev/null +++ b/internal/repository/mysql/dao/log_operation.gen.go @@ -0,0 +1,336 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newLogOperation(db *gorm.DB, opts ...gen.DOOption) logOperation { + _logOperation := logOperation{} + + _logOperation.logOperationDo.UseDB(db, opts...) + _logOperation.logOperationDo.UseModel(&model.LogOperation{}) + + tableName := _logOperation.logOperationDo.TableName() + _logOperation.ALL = field.NewAsterisk(tableName) + _logOperation.ID = field.NewInt32(tableName, "id") + _logOperation.Level = field.NewString(tableName, "level") + _logOperation.Msg = field.NewString(tableName, "msg") + _logOperation.Content = field.NewString(tableName, "content") + _logOperation.CreatedAt = field.NewTime(tableName, "created_at") + + _logOperation.fillFieldMap() + + return _logOperation +} + +// logOperation 内部日志表 +type logOperation struct { + logOperationDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Level field.String // 错误级别 + Msg field.String // 错误信息 + Content field.String // 错误内容 + CreatedAt field.Time // 创建时间 + + fieldMap map[string]field.Expr +} + +func (l logOperation) Table(newTableName string) *logOperation { + l.logOperationDo.UseTable(newTableName) + return l.updateTableName(newTableName) +} + +func (l logOperation) As(alias string) *logOperation { + l.logOperationDo.DO = *(l.logOperationDo.As(alias).(*gen.DO)) + return l.updateTableName(alias) +} + +func (l *logOperation) updateTableName(table string) *logOperation { + l.ALL = field.NewAsterisk(table) + l.ID = field.NewInt32(table, "id") + l.Level = field.NewString(table, "level") + l.Msg = field.NewString(table, "msg") + l.Content = field.NewString(table, "content") + l.CreatedAt = field.NewTime(table, "created_at") + + l.fillFieldMap() + + return l +} + +func (l *logOperation) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := l.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (l *logOperation) fillFieldMap() { + l.fieldMap = make(map[string]field.Expr, 5) + l.fieldMap["id"] = l.ID + l.fieldMap["level"] = l.Level + l.fieldMap["msg"] = l.Msg + l.fieldMap["content"] = l.Content + l.fieldMap["created_at"] = l.CreatedAt +} + +func (l logOperation) clone(db *gorm.DB) logOperation { + l.logOperationDo.ReplaceConnPool(db.Statement.ConnPool) + return l +} + +func (l logOperation) replaceDB(db *gorm.DB) logOperation { + l.logOperationDo.ReplaceDB(db) + return l +} + +type logOperationDo struct{ gen.DO } + +func (l logOperationDo) Debug() *logOperationDo { + return l.withDO(l.DO.Debug()) +} + +func (l logOperationDo) WithContext(ctx context.Context) *logOperationDo { + return l.withDO(l.DO.WithContext(ctx)) +} + +func (l logOperationDo) ReadDB() *logOperationDo { + return l.Clauses(dbresolver.Read) +} + +func (l logOperationDo) WriteDB() *logOperationDo { + return l.Clauses(dbresolver.Write) +} + +func (l logOperationDo) Session(config *gorm.Session) *logOperationDo { + return l.withDO(l.DO.Session(config)) +} + +func (l logOperationDo) Clauses(conds ...clause.Expression) *logOperationDo { + return l.withDO(l.DO.Clauses(conds...)) +} + +func (l logOperationDo) Returning(value interface{}, columns ...string) *logOperationDo { + return l.withDO(l.DO.Returning(value, columns...)) +} + +func (l logOperationDo) Not(conds ...gen.Condition) *logOperationDo { + return l.withDO(l.DO.Not(conds...)) +} + +func (l logOperationDo) Or(conds ...gen.Condition) *logOperationDo { + return l.withDO(l.DO.Or(conds...)) +} + +func (l logOperationDo) Select(conds ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Select(conds...)) +} + +func (l logOperationDo) Where(conds ...gen.Condition) *logOperationDo { + return l.withDO(l.DO.Where(conds...)) +} + +func (l logOperationDo) Order(conds ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Order(conds...)) +} + +func (l logOperationDo) Distinct(cols ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Distinct(cols...)) +} + +func (l logOperationDo) Omit(cols ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Omit(cols...)) +} + +func (l logOperationDo) Join(table schema.Tabler, on ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Join(table, on...)) +} + +func (l logOperationDo) LeftJoin(table schema.Tabler, on ...field.Expr) *logOperationDo { + return l.withDO(l.DO.LeftJoin(table, on...)) +} + +func (l logOperationDo) RightJoin(table schema.Tabler, on ...field.Expr) *logOperationDo { + return l.withDO(l.DO.RightJoin(table, on...)) +} + +func (l logOperationDo) Group(cols ...field.Expr) *logOperationDo { + return l.withDO(l.DO.Group(cols...)) +} + +func (l logOperationDo) Having(conds ...gen.Condition) *logOperationDo { + return l.withDO(l.DO.Having(conds...)) +} + +func (l logOperationDo) Limit(limit int) *logOperationDo { + return l.withDO(l.DO.Limit(limit)) +} + +func (l logOperationDo) Offset(offset int) *logOperationDo { + return l.withDO(l.DO.Offset(offset)) +} + +func (l logOperationDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *logOperationDo { + return l.withDO(l.DO.Scopes(funcs...)) +} + +func (l logOperationDo) Unscoped() *logOperationDo { + return l.withDO(l.DO.Unscoped()) +} + +func (l logOperationDo) Create(values ...*model.LogOperation) error { + if len(values) == 0 { + return nil + } + return l.DO.Create(values) +} + +func (l logOperationDo) CreateInBatches(values []*model.LogOperation, batchSize int) error { + return l.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (l logOperationDo) Save(values ...*model.LogOperation) error { + if len(values) == 0 { + return nil + } + return l.DO.Save(values) +} + +func (l logOperationDo) First() (*model.LogOperation, error) { + if result, err := l.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.LogOperation), nil + } +} + +func (l logOperationDo) Take() (*model.LogOperation, error) { + if result, err := l.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.LogOperation), nil + } +} + +func (l logOperationDo) Last() (*model.LogOperation, error) { + if result, err := l.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.LogOperation), nil + } +} + +func (l logOperationDo) Find() ([]*model.LogOperation, error) { + result, err := l.DO.Find() + return result.([]*model.LogOperation), err +} + +func (l logOperationDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.LogOperation, err error) { + buf := make([]*model.LogOperation, 0, batchSize) + err = l.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (l logOperationDo) FindInBatches(result *[]*model.LogOperation, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return l.DO.FindInBatches(result, batchSize, fc) +} + +func (l logOperationDo) Attrs(attrs ...field.AssignExpr) *logOperationDo { + return l.withDO(l.DO.Attrs(attrs...)) +} + +func (l logOperationDo) Assign(attrs ...field.AssignExpr) *logOperationDo { + return l.withDO(l.DO.Assign(attrs...)) +} + +func (l logOperationDo) Joins(fields ...field.RelationField) *logOperationDo { + for _, _f := range fields { + l = *l.withDO(l.DO.Joins(_f)) + } + return &l +} + +func (l logOperationDo) Preload(fields ...field.RelationField) *logOperationDo { + for _, _f := range fields { + l = *l.withDO(l.DO.Preload(_f)) + } + return &l +} + +func (l logOperationDo) FirstOrInit() (*model.LogOperation, error) { + if result, err := l.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.LogOperation), nil + } +} + +func (l logOperationDo) FirstOrCreate() (*model.LogOperation, error) { + if result, err := l.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.LogOperation), nil + } +} + +func (l logOperationDo) FindByPage(offset int, limit int) (result []*model.LogOperation, count int64, err error) { + result, err = l.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = l.Offset(-1).Limit(-1).Count() + return +} + +func (l logOperationDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = l.Count() + if err != nil { + return + } + + err = l.Offset(offset).Limit(limit).Scan(result) + return +} + +func (l logOperationDo) Scan(result interface{}) (err error) { + return l.DO.Scan(result) +} + +func (l logOperationDo) Delete(models ...*model.LogOperation) (result gen.ResultInfo, err error) { + return l.DO.Delete(models) +} + +func (l *logOperationDo) withDO(do gen.Dao) *logOperationDo { + l.DO = *do.(*gen.DO) + return l +} diff --git a/internal/repository/mysql/dao/log_request.gen.go b/internal/repository/mysql/dao/log_request.gen.go new file mode 100644 index 0000000..d0c700a --- /dev/null +++ b/internal/repository/mysql/dao/log_request.gen.go @@ -0,0 +1,364 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newLogRequest(db *gorm.DB, opts ...gen.DOOption) logRequest { + _logRequest := logRequest{} + + _logRequest.logRequestDo.UseDB(db, opts...) + _logRequest.logRequestDo.UseModel(&model.LogRequest{}) + + tableName := _logRequest.logRequestDo.TableName() + _logRequest.ALL = field.NewAsterisk(tableName) + _logRequest.ID = field.NewInt32(tableName, "id") + _logRequest.Tid = field.NewString(tableName, "tid") + _logRequest.Username = field.NewString(tableName, "username") + _logRequest.Host = field.NewString(tableName, "host") + _logRequest.Path = field.NewString(tableName, "path") + _logRequest.Method = field.NewString(tableName, "method") + _logRequest.HTTPCode = field.NewInt32(tableName, "http_code") + _logRequest.BusinessCode = field.NewInt32(tableName, "business_code") + _logRequest.CostMilliseconds = field.NewFloat64(tableName, "cost_milliseconds") + _logRequest.IsSuccess = field.NewInt32(tableName, "is_success") + _logRequest.Content = field.NewString(tableName, "content") + _logRequest.CreatedAt = field.NewTime(tableName, "created_at") + + _logRequest.fillFieldMap() + + return _logRequest +} + +// logRequest 请求日志表 +type logRequest struct { + logRequestDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Tid field.String // 请求链路 ID + Username field.String // 登录名 + Host field.String // 请求 HOST + Path field.String // 请求 Path + Method field.String // 请求 Method + HTTPCode field.Int32 // HTTP 状态码 + BusinessCode field.Int32 // 业务码 + CostMilliseconds field.Float64 // 耗时(毫秒) + IsSuccess field.Int32 // 是否成功(1=是 -1=否) + Content field.String // 内容 + CreatedAt field.Time // 创建时间 + + fieldMap map[string]field.Expr +} + +func (l logRequest) Table(newTableName string) *logRequest { + l.logRequestDo.UseTable(newTableName) + return l.updateTableName(newTableName) +} + +func (l logRequest) As(alias string) *logRequest { + l.logRequestDo.DO = *(l.logRequestDo.As(alias).(*gen.DO)) + return l.updateTableName(alias) +} + +func (l *logRequest) updateTableName(table string) *logRequest { + l.ALL = field.NewAsterisk(table) + l.ID = field.NewInt32(table, "id") + l.Tid = field.NewString(table, "tid") + l.Username = field.NewString(table, "username") + l.Host = field.NewString(table, "host") + l.Path = field.NewString(table, "path") + l.Method = field.NewString(table, "method") + l.HTTPCode = field.NewInt32(table, "http_code") + l.BusinessCode = field.NewInt32(table, "business_code") + l.CostMilliseconds = field.NewFloat64(table, "cost_milliseconds") + l.IsSuccess = field.NewInt32(table, "is_success") + l.Content = field.NewString(table, "content") + l.CreatedAt = field.NewTime(table, "created_at") + + l.fillFieldMap() + + return l +} + +func (l *logRequest) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := l.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (l *logRequest) fillFieldMap() { + l.fieldMap = make(map[string]field.Expr, 12) + l.fieldMap["id"] = l.ID + l.fieldMap["tid"] = l.Tid + l.fieldMap["username"] = l.Username + l.fieldMap["host"] = l.Host + l.fieldMap["path"] = l.Path + l.fieldMap["method"] = l.Method + l.fieldMap["http_code"] = l.HTTPCode + l.fieldMap["business_code"] = l.BusinessCode + l.fieldMap["cost_milliseconds"] = l.CostMilliseconds + l.fieldMap["is_success"] = l.IsSuccess + l.fieldMap["content"] = l.Content + l.fieldMap["created_at"] = l.CreatedAt +} + +func (l logRequest) clone(db *gorm.DB) logRequest { + l.logRequestDo.ReplaceConnPool(db.Statement.ConnPool) + return l +} + +func (l logRequest) replaceDB(db *gorm.DB) logRequest { + l.logRequestDo.ReplaceDB(db) + return l +} + +type logRequestDo struct{ gen.DO } + +func (l logRequestDo) Debug() *logRequestDo { + return l.withDO(l.DO.Debug()) +} + +func (l logRequestDo) WithContext(ctx context.Context) *logRequestDo { + return l.withDO(l.DO.WithContext(ctx)) +} + +func (l logRequestDo) ReadDB() *logRequestDo { + return l.Clauses(dbresolver.Read) +} + +func (l logRequestDo) WriteDB() *logRequestDo { + return l.Clauses(dbresolver.Write) +} + +func (l logRequestDo) Session(config *gorm.Session) *logRequestDo { + return l.withDO(l.DO.Session(config)) +} + +func (l logRequestDo) Clauses(conds ...clause.Expression) *logRequestDo { + return l.withDO(l.DO.Clauses(conds...)) +} + +func (l logRequestDo) Returning(value interface{}, columns ...string) *logRequestDo { + return l.withDO(l.DO.Returning(value, columns...)) +} + +func (l logRequestDo) Not(conds ...gen.Condition) *logRequestDo { + return l.withDO(l.DO.Not(conds...)) +} + +func (l logRequestDo) Or(conds ...gen.Condition) *logRequestDo { + return l.withDO(l.DO.Or(conds...)) +} + +func (l logRequestDo) Select(conds ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Select(conds...)) +} + +func (l logRequestDo) Where(conds ...gen.Condition) *logRequestDo { + return l.withDO(l.DO.Where(conds...)) +} + +func (l logRequestDo) Order(conds ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Order(conds...)) +} + +func (l logRequestDo) Distinct(cols ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Distinct(cols...)) +} + +func (l logRequestDo) Omit(cols ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Omit(cols...)) +} + +func (l logRequestDo) Join(table schema.Tabler, on ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Join(table, on...)) +} + +func (l logRequestDo) LeftJoin(table schema.Tabler, on ...field.Expr) *logRequestDo { + return l.withDO(l.DO.LeftJoin(table, on...)) +} + +func (l logRequestDo) RightJoin(table schema.Tabler, on ...field.Expr) *logRequestDo { + return l.withDO(l.DO.RightJoin(table, on...)) +} + +func (l logRequestDo) Group(cols ...field.Expr) *logRequestDo { + return l.withDO(l.DO.Group(cols...)) +} + +func (l logRequestDo) Having(conds ...gen.Condition) *logRequestDo { + return l.withDO(l.DO.Having(conds...)) +} + +func (l logRequestDo) Limit(limit int) *logRequestDo { + return l.withDO(l.DO.Limit(limit)) +} + +func (l logRequestDo) Offset(offset int) *logRequestDo { + return l.withDO(l.DO.Offset(offset)) +} + +func (l logRequestDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *logRequestDo { + return l.withDO(l.DO.Scopes(funcs...)) +} + +func (l logRequestDo) Unscoped() *logRequestDo { + return l.withDO(l.DO.Unscoped()) +} + +func (l logRequestDo) Create(values ...*model.LogRequest) error { + if len(values) == 0 { + return nil + } + return l.DO.Create(values) +} + +func (l logRequestDo) CreateInBatches(values []*model.LogRequest, batchSize int) error { + return l.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (l logRequestDo) Save(values ...*model.LogRequest) error { + if len(values) == 0 { + return nil + } + return l.DO.Save(values) +} + +func (l logRequestDo) First() (*model.LogRequest, error) { + if result, err := l.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.LogRequest), nil + } +} + +func (l logRequestDo) Take() (*model.LogRequest, error) { + if result, err := l.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.LogRequest), nil + } +} + +func (l logRequestDo) Last() (*model.LogRequest, error) { + if result, err := l.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.LogRequest), nil + } +} + +func (l logRequestDo) Find() ([]*model.LogRequest, error) { + result, err := l.DO.Find() + return result.([]*model.LogRequest), err +} + +func (l logRequestDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.LogRequest, err error) { + buf := make([]*model.LogRequest, 0, batchSize) + err = l.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (l logRequestDo) FindInBatches(result *[]*model.LogRequest, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return l.DO.FindInBatches(result, batchSize, fc) +} + +func (l logRequestDo) Attrs(attrs ...field.AssignExpr) *logRequestDo { + return l.withDO(l.DO.Attrs(attrs...)) +} + +func (l logRequestDo) Assign(attrs ...field.AssignExpr) *logRequestDo { + return l.withDO(l.DO.Assign(attrs...)) +} + +func (l logRequestDo) Joins(fields ...field.RelationField) *logRequestDo { + for _, _f := range fields { + l = *l.withDO(l.DO.Joins(_f)) + } + return &l +} + +func (l logRequestDo) Preload(fields ...field.RelationField) *logRequestDo { + for _, _f := range fields { + l = *l.withDO(l.DO.Preload(_f)) + } + return &l +} + +func (l logRequestDo) FirstOrInit() (*model.LogRequest, error) { + if result, err := l.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.LogRequest), nil + } +} + +func (l logRequestDo) FirstOrCreate() (*model.LogRequest, error) { + if result, err := l.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.LogRequest), nil + } +} + +func (l logRequestDo) FindByPage(offset int, limit int) (result []*model.LogRequest, count int64, err error) { + result, err = l.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = l.Offset(-1).Limit(-1).Count() + return +} + +func (l logRequestDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = l.Count() + if err != nil { + return + } + + err = l.Offset(offset).Limit(limit).Scan(result) + return +} + +func (l logRequestDo) Scan(result interface{}) (err error) { + return l.DO.Scan(result) +} + +func (l logRequestDo) Delete(models ...*model.LogRequest) (result gen.ResultInfo, err error) { + return l.DO.Delete(models) +} + +func (l *logRequestDo) withDO(do gen.Dao) *logRequestDo { + l.DO = *do.(*gen.DO) + return l +} diff --git a/internal/repository/mysql/dao/mini_program.gen.go b/internal/repository/mysql/dao/mini_program.gen.go new file mode 100644 index 0000000..354bb89 --- /dev/null +++ b/internal/repository/mysql/dao/mini_program.gen.go @@ -0,0 +1,352 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newMiniProgram(db *gorm.DB, opts ...gen.DOOption) miniProgram { + _miniProgram := miniProgram{} + + _miniProgram.miniProgramDo.UseDB(db, opts...) + _miniProgram.miniProgramDo.UseModel(&model.MiniProgram{}) + + tableName := _miniProgram.miniProgramDo.TableName() + _miniProgram.ALL = field.NewAsterisk(tableName) + _miniProgram.ID = field.NewInt32(tableName, "id") + _miniProgram.AppID = field.NewString(tableName, "app_id") + _miniProgram.Name = field.NewString(tableName, "name") + _miniProgram.Description = field.NewString(tableName, "description") + _miniProgram.Avatar = field.NewString(tableName, "avatar") + _miniProgram.CreatedUser = field.NewString(tableName, "created_user") + _miniProgram.CreatedAt = field.NewTime(tableName, "created_at") + _miniProgram.UpdatedUser = field.NewString(tableName, "updated_user") + _miniProgram.UpdatedAt = field.NewTime(tableName, "updated_at") + + _miniProgram.fillFieldMap() + + return _miniProgram +} + +// miniProgram 小程序表 +type miniProgram struct { + miniProgramDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + AppID field.String // 小程序ID + Name field.String // 名称 + Description field.String // 描述 + Avatar field.String // 头像 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (m miniProgram) Table(newTableName string) *miniProgram { + m.miniProgramDo.UseTable(newTableName) + return m.updateTableName(newTableName) +} + +func (m miniProgram) As(alias string) *miniProgram { + m.miniProgramDo.DO = *(m.miniProgramDo.As(alias).(*gen.DO)) + return m.updateTableName(alias) +} + +func (m *miniProgram) updateTableName(table string) *miniProgram { + m.ALL = field.NewAsterisk(table) + m.ID = field.NewInt32(table, "id") + m.AppID = field.NewString(table, "app_id") + m.Name = field.NewString(table, "name") + m.Description = field.NewString(table, "description") + m.Avatar = field.NewString(table, "avatar") + m.CreatedUser = field.NewString(table, "created_user") + m.CreatedAt = field.NewTime(table, "created_at") + m.UpdatedUser = field.NewString(table, "updated_user") + m.UpdatedAt = field.NewTime(table, "updated_at") + + m.fillFieldMap() + + return m +} + +func (m *miniProgram) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := m.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (m *miniProgram) fillFieldMap() { + m.fieldMap = make(map[string]field.Expr, 9) + m.fieldMap["id"] = m.ID + m.fieldMap["app_id"] = m.AppID + m.fieldMap["name"] = m.Name + m.fieldMap["description"] = m.Description + m.fieldMap["avatar"] = m.Avatar + m.fieldMap["created_user"] = m.CreatedUser + m.fieldMap["created_at"] = m.CreatedAt + m.fieldMap["updated_user"] = m.UpdatedUser + m.fieldMap["updated_at"] = m.UpdatedAt +} + +func (m miniProgram) clone(db *gorm.DB) miniProgram { + m.miniProgramDo.ReplaceConnPool(db.Statement.ConnPool) + return m +} + +func (m miniProgram) replaceDB(db *gorm.DB) miniProgram { + m.miniProgramDo.ReplaceDB(db) + return m +} + +type miniProgramDo struct{ gen.DO } + +func (m miniProgramDo) Debug() *miniProgramDo { + return m.withDO(m.DO.Debug()) +} + +func (m miniProgramDo) WithContext(ctx context.Context) *miniProgramDo { + return m.withDO(m.DO.WithContext(ctx)) +} + +func (m miniProgramDo) ReadDB() *miniProgramDo { + return m.Clauses(dbresolver.Read) +} + +func (m miniProgramDo) WriteDB() *miniProgramDo { + return m.Clauses(dbresolver.Write) +} + +func (m miniProgramDo) Session(config *gorm.Session) *miniProgramDo { + return m.withDO(m.DO.Session(config)) +} + +func (m miniProgramDo) Clauses(conds ...clause.Expression) *miniProgramDo { + return m.withDO(m.DO.Clauses(conds...)) +} + +func (m miniProgramDo) Returning(value interface{}, columns ...string) *miniProgramDo { + return m.withDO(m.DO.Returning(value, columns...)) +} + +func (m miniProgramDo) Not(conds ...gen.Condition) *miniProgramDo { + return m.withDO(m.DO.Not(conds...)) +} + +func (m miniProgramDo) Or(conds ...gen.Condition) *miniProgramDo { + return m.withDO(m.DO.Or(conds...)) +} + +func (m miniProgramDo) Select(conds ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Select(conds...)) +} + +func (m miniProgramDo) Where(conds ...gen.Condition) *miniProgramDo { + return m.withDO(m.DO.Where(conds...)) +} + +func (m miniProgramDo) Order(conds ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Order(conds...)) +} + +func (m miniProgramDo) Distinct(cols ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Distinct(cols...)) +} + +func (m miniProgramDo) Omit(cols ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Omit(cols...)) +} + +func (m miniProgramDo) Join(table schema.Tabler, on ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Join(table, on...)) +} + +func (m miniProgramDo) LeftJoin(table schema.Tabler, on ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.LeftJoin(table, on...)) +} + +func (m miniProgramDo) RightJoin(table schema.Tabler, on ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.RightJoin(table, on...)) +} + +func (m miniProgramDo) Group(cols ...field.Expr) *miniProgramDo { + return m.withDO(m.DO.Group(cols...)) +} + +func (m miniProgramDo) Having(conds ...gen.Condition) *miniProgramDo { + return m.withDO(m.DO.Having(conds...)) +} + +func (m miniProgramDo) Limit(limit int) *miniProgramDo { + return m.withDO(m.DO.Limit(limit)) +} + +func (m miniProgramDo) Offset(offset int) *miniProgramDo { + return m.withDO(m.DO.Offset(offset)) +} + +func (m miniProgramDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *miniProgramDo { + return m.withDO(m.DO.Scopes(funcs...)) +} + +func (m miniProgramDo) Unscoped() *miniProgramDo { + return m.withDO(m.DO.Unscoped()) +} + +func (m miniProgramDo) Create(values ...*model.MiniProgram) error { + if len(values) == 0 { + return nil + } + return m.DO.Create(values) +} + +func (m miniProgramDo) CreateInBatches(values []*model.MiniProgram, batchSize int) error { + return m.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (m miniProgramDo) Save(values ...*model.MiniProgram) error { + if len(values) == 0 { + return nil + } + return m.DO.Save(values) +} + +func (m miniProgramDo) First() (*model.MiniProgram, error) { + if result, err := m.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.MiniProgram), nil + } +} + +func (m miniProgramDo) Take() (*model.MiniProgram, error) { + if result, err := m.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.MiniProgram), nil + } +} + +func (m miniProgramDo) Last() (*model.MiniProgram, error) { + if result, err := m.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.MiniProgram), nil + } +} + +func (m miniProgramDo) Find() ([]*model.MiniProgram, error) { + result, err := m.DO.Find() + return result.([]*model.MiniProgram), err +} + +func (m miniProgramDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.MiniProgram, err error) { + buf := make([]*model.MiniProgram, 0, batchSize) + err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (m miniProgramDo) FindInBatches(result *[]*model.MiniProgram, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return m.DO.FindInBatches(result, batchSize, fc) +} + +func (m miniProgramDo) Attrs(attrs ...field.AssignExpr) *miniProgramDo { + return m.withDO(m.DO.Attrs(attrs...)) +} + +func (m miniProgramDo) Assign(attrs ...field.AssignExpr) *miniProgramDo { + return m.withDO(m.DO.Assign(attrs...)) +} + +func (m miniProgramDo) Joins(fields ...field.RelationField) *miniProgramDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Joins(_f)) + } + return &m +} + +func (m miniProgramDo) Preload(fields ...field.RelationField) *miniProgramDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Preload(_f)) + } + return &m +} + +func (m miniProgramDo) FirstOrInit() (*model.MiniProgram, error) { + if result, err := m.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.MiniProgram), nil + } +} + +func (m miniProgramDo) FirstOrCreate() (*model.MiniProgram, error) { + if result, err := m.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.MiniProgram), nil + } +} + +func (m miniProgramDo) FindByPage(offset int, limit int) (result []*model.MiniProgram, count int64, err error) { + result, err = m.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = m.Offset(-1).Limit(-1).Count() + return +} + +func (m miniProgramDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = m.Count() + if err != nil { + return + } + + err = m.Offset(offset).Limit(limit).Scan(result) + return +} + +func (m miniProgramDo) Scan(result interface{}) (err error) { + return m.DO.Scan(result) +} + +func (m miniProgramDo) Delete(models ...*model.MiniProgram) (result gen.ResultInfo, err error) { + return m.DO.Delete(models) +} + +func (m *miniProgramDo) withDO(do gen.Dao) *miniProgramDo { + m.DO = *do.(*gen.DO) + return m +} diff --git a/internal/repository/mysql/dao/miniprogram_access_token.gen.go b/internal/repository/mysql/dao/miniprogram_access_token.gen.go new file mode 100644 index 0000000..c683286 --- /dev/null +++ b/internal/repository/mysql/dao/miniprogram_access_token.gen.go @@ -0,0 +1,332 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newMiniprogramAccessToken(db *gorm.DB, opts ...gen.DOOption) miniprogramAccessToken { + _miniprogramAccessToken := miniprogramAccessToken{} + + _miniprogramAccessToken.miniprogramAccessTokenDo.UseDB(db, opts...) + _miniprogramAccessToken.miniprogramAccessTokenDo.UseModel(&model.MiniprogramAccessToken{}) + + tableName := _miniprogramAccessToken.miniprogramAccessTokenDo.TableName() + _miniprogramAccessToken.ALL = field.NewAsterisk(tableName) + _miniprogramAccessToken.ID = field.NewInt32(tableName, "id") + _miniprogramAccessToken.AccessToken = field.NewString(tableName, "access_token") + _miniprogramAccessToken.CreatedAt = field.NewTime(tableName, "created_at") + _miniprogramAccessToken.ExpiredAt = field.NewTime(tableName, "expired_at") + + _miniprogramAccessToken.fillFieldMap() + + return _miniprogramAccessToken +} + +// miniprogramAccessToken 小程序 access_token 表 +type miniprogramAccessToken struct { + miniprogramAccessTokenDo + + ALL field.Asterisk + ID field.Int32 // 主键 + AccessToken field.String // access_token + CreatedAt field.Time // 创建时间 + ExpiredAt field.Time // 过期时间 + + fieldMap map[string]field.Expr +} + +func (m miniprogramAccessToken) Table(newTableName string) *miniprogramAccessToken { + m.miniprogramAccessTokenDo.UseTable(newTableName) + return m.updateTableName(newTableName) +} + +func (m miniprogramAccessToken) As(alias string) *miniprogramAccessToken { + m.miniprogramAccessTokenDo.DO = *(m.miniprogramAccessTokenDo.As(alias).(*gen.DO)) + return m.updateTableName(alias) +} + +func (m *miniprogramAccessToken) updateTableName(table string) *miniprogramAccessToken { + m.ALL = field.NewAsterisk(table) + m.ID = field.NewInt32(table, "id") + m.AccessToken = field.NewString(table, "access_token") + m.CreatedAt = field.NewTime(table, "created_at") + m.ExpiredAt = field.NewTime(table, "expired_at") + + m.fillFieldMap() + + return m +} + +func (m *miniprogramAccessToken) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := m.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (m *miniprogramAccessToken) fillFieldMap() { + m.fieldMap = make(map[string]field.Expr, 4) + m.fieldMap["id"] = m.ID + m.fieldMap["access_token"] = m.AccessToken + m.fieldMap["created_at"] = m.CreatedAt + m.fieldMap["expired_at"] = m.ExpiredAt +} + +func (m miniprogramAccessToken) clone(db *gorm.DB) miniprogramAccessToken { + m.miniprogramAccessTokenDo.ReplaceConnPool(db.Statement.ConnPool) + return m +} + +func (m miniprogramAccessToken) replaceDB(db *gorm.DB) miniprogramAccessToken { + m.miniprogramAccessTokenDo.ReplaceDB(db) + return m +} + +type miniprogramAccessTokenDo struct{ gen.DO } + +func (m miniprogramAccessTokenDo) Debug() *miniprogramAccessTokenDo { + return m.withDO(m.DO.Debug()) +} + +func (m miniprogramAccessTokenDo) WithContext(ctx context.Context) *miniprogramAccessTokenDo { + return m.withDO(m.DO.WithContext(ctx)) +} + +func (m miniprogramAccessTokenDo) ReadDB() *miniprogramAccessTokenDo { + return m.Clauses(dbresolver.Read) +} + +func (m miniprogramAccessTokenDo) WriteDB() *miniprogramAccessTokenDo { + return m.Clauses(dbresolver.Write) +} + +func (m miniprogramAccessTokenDo) Session(config *gorm.Session) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Session(config)) +} + +func (m miniprogramAccessTokenDo) Clauses(conds ...clause.Expression) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Clauses(conds...)) +} + +func (m miniprogramAccessTokenDo) Returning(value interface{}, columns ...string) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Returning(value, columns...)) +} + +func (m miniprogramAccessTokenDo) Not(conds ...gen.Condition) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Not(conds...)) +} + +func (m miniprogramAccessTokenDo) Or(conds ...gen.Condition) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Or(conds...)) +} + +func (m miniprogramAccessTokenDo) Select(conds ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Select(conds...)) +} + +func (m miniprogramAccessTokenDo) Where(conds ...gen.Condition) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Where(conds...)) +} + +func (m miniprogramAccessTokenDo) Order(conds ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Order(conds...)) +} + +func (m miniprogramAccessTokenDo) Distinct(cols ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Distinct(cols...)) +} + +func (m miniprogramAccessTokenDo) Omit(cols ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Omit(cols...)) +} + +func (m miniprogramAccessTokenDo) Join(table schema.Tabler, on ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Join(table, on...)) +} + +func (m miniprogramAccessTokenDo) LeftJoin(table schema.Tabler, on ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.LeftJoin(table, on...)) +} + +func (m miniprogramAccessTokenDo) RightJoin(table schema.Tabler, on ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.RightJoin(table, on...)) +} + +func (m miniprogramAccessTokenDo) Group(cols ...field.Expr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Group(cols...)) +} + +func (m miniprogramAccessTokenDo) Having(conds ...gen.Condition) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Having(conds...)) +} + +func (m miniprogramAccessTokenDo) Limit(limit int) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Limit(limit)) +} + +func (m miniprogramAccessTokenDo) Offset(offset int) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Offset(offset)) +} + +func (m miniprogramAccessTokenDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Scopes(funcs...)) +} + +func (m miniprogramAccessTokenDo) Unscoped() *miniprogramAccessTokenDo { + return m.withDO(m.DO.Unscoped()) +} + +func (m miniprogramAccessTokenDo) Create(values ...*model.MiniprogramAccessToken) error { + if len(values) == 0 { + return nil + } + return m.DO.Create(values) +} + +func (m miniprogramAccessTokenDo) CreateInBatches(values []*model.MiniprogramAccessToken, batchSize int) error { + return m.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (m miniprogramAccessTokenDo) Save(values ...*model.MiniprogramAccessToken) error { + if len(values) == 0 { + return nil + } + return m.DO.Save(values) +} + +func (m miniprogramAccessTokenDo) First() (*model.MiniprogramAccessToken, error) { + if result, err := m.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.MiniprogramAccessToken), nil + } +} + +func (m miniprogramAccessTokenDo) Take() (*model.MiniprogramAccessToken, error) { + if result, err := m.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.MiniprogramAccessToken), nil + } +} + +func (m miniprogramAccessTokenDo) Last() (*model.MiniprogramAccessToken, error) { + if result, err := m.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.MiniprogramAccessToken), nil + } +} + +func (m miniprogramAccessTokenDo) Find() ([]*model.MiniprogramAccessToken, error) { + result, err := m.DO.Find() + return result.([]*model.MiniprogramAccessToken), err +} + +func (m miniprogramAccessTokenDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.MiniprogramAccessToken, err error) { + buf := make([]*model.MiniprogramAccessToken, 0, batchSize) + err = m.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (m miniprogramAccessTokenDo) FindInBatches(result *[]*model.MiniprogramAccessToken, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return m.DO.FindInBatches(result, batchSize, fc) +} + +func (m miniprogramAccessTokenDo) Attrs(attrs ...field.AssignExpr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Attrs(attrs...)) +} + +func (m miniprogramAccessTokenDo) Assign(attrs ...field.AssignExpr) *miniprogramAccessTokenDo { + return m.withDO(m.DO.Assign(attrs...)) +} + +func (m miniprogramAccessTokenDo) Joins(fields ...field.RelationField) *miniprogramAccessTokenDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Joins(_f)) + } + return &m +} + +func (m miniprogramAccessTokenDo) Preload(fields ...field.RelationField) *miniprogramAccessTokenDo { + for _, _f := range fields { + m = *m.withDO(m.DO.Preload(_f)) + } + return &m +} + +func (m miniprogramAccessTokenDo) FirstOrInit() (*model.MiniprogramAccessToken, error) { + if result, err := m.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.MiniprogramAccessToken), nil + } +} + +func (m miniprogramAccessTokenDo) FirstOrCreate() (*model.MiniprogramAccessToken, error) { + if result, err := m.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.MiniprogramAccessToken), nil + } +} + +func (m miniprogramAccessTokenDo) FindByPage(offset int, limit int) (result []*model.MiniprogramAccessToken, count int64, err error) { + result, err = m.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = m.Offset(-1).Limit(-1).Count() + return +} + +func (m miniprogramAccessTokenDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = m.Count() + if err != nil { + return + } + + err = m.Offset(offset).Limit(limit).Scan(result) + return +} + +func (m miniprogramAccessTokenDo) Scan(result interface{}) (err error) { + return m.DO.Scan(result) +} + +func (m miniprogramAccessTokenDo) Delete(models ...*model.MiniprogramAccessToken) (result gen.ResultInfo, err error) { + return m.DO.Delete(models) +} + +func (m *miniprogramAccessTokenDo) withDO(do gen.Dao) *miniprogramAccessTokenDo { + m.DO = *do.(*gen.DO) + return m +} diff --git a/internal/repository/mysql/dao/patient.gen.go b/internal/repository/mysql/dao/patient.gen.go new file mode 100644 index 0000000..95753db --- /dev/null +++ b/internal/repository/mysql/dao/patient.gen.go @@ -0,0 +1,440 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatient(db *gorm.DB, opts ...gen.DOOption) patient { + _patient := patient{} + + _patient.patientDo.UseDB(db, opts...) + _patient.patientDo.UseModel(&model.Patient{}) + + tableName := _patient.patientDo.TableName() + _patient.ALL = field.NewAsterisk(tableName) + _patient.ID = field.NewInt32(tableName, "id") + _patient.Mobile = field.NewString(tableName, "mobile") + _patient.Username = field.NewString(tableName, "username") + _patient.Sex = field.NewInt32(tableName, "sex") + _patient.Password = field.NewString(tableName, "password") + _patient.Avatar = field.NewString(tableName, "avatar") + _patient.IDNumber = field.NewString(tableName, "id_number") + _patient.Birthday = field.NewTime(tableName, "birthday") + _patient.BirthWeight = field.NewInt32(tableName, "birth_weight") + _patient.OperativeDate = field.NewTime(tableName, "operative_date") + _patient.NextFollowDate = field.NewTime(tableName, "next_follow_date") + _patient.ParityNumber = field.NewInt32(tableName, "parity_number") + _patient.BirthNumber = field.NewInt32(tableName, "birth_number") + _patient.ConceptionType = field.NewInt32(tableName, "conception_type") + _patient.GestationalWeek = field.NewInt32(tableName, "gestational_week") + _patient.PrenatalCheckType = field.NewInt32(tableName, "prenatal_check_type") + _patient.PrenatalCheckRemark = field.NewString(tableName, "prenatal_check_remark") + _patient.DeliveryType = field.NewInt32(tableName, "delivery_type") + _patient.RiskType = field.NewInt32(tableName, "risk_type") + _patient.RiskValue = field.NewString(tableName, "risk_value") + _patient.HeightGenerateCurveType = field.NewInt32(tableName, "height_generate_curve_type") + _patient.WeightGenerateCurveType = field.NewInt32(tableName, "weight_generate_curve_type") + _patient.LoginStatus = field.NewInt32(tableName, "login_status") + _patient.LastLoginTime = field.NewTime(tableName, "last_login_time") + _patient.LastLoginIP = field.NewString(tableName, "last_login_ip") + _patient.LastLoginHash = field.NewString(tableName, "last_login_hash") + _patient.WxUserID = field.NewString(tableName, "wx_user_id") + _patient.CreatedUser = field.NewString(tableName, "created_user") + _patient.CreatedAt = field.NewTime(tableName, "created_at") + _patient.UpdatedUser = field.NewString(tableName, "updated_user") + _patient.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patient.fillFieldMap() + + return _patient +} + +// patient 患者表 +type patient struct { + patientDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Mobile field.String // 手机号 + Username field.String // 姓名 + Sex field.Int32 // 性别(1:男 2:女) + Password field.String // 密码 + Avatar field.String // 头像地址 + IDNumber field.String // 身份证号 + Birthday field.Time // 出生日期 + BirthWeight field.Int32 // 出生体重(克) + OperativeDate field.Time // 手术日期 + NextFollowDate field.Time // 下次随访时间 + ParityNumber field.Int32 // 胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎) + BirthNumber field.Int32 // 产次(0:未知 1:1产 2:2产 3:≥3产) + ConceptionType field.Int32 // 受孕方式(0:未知 1:自然受孕 2:辅助生殖技术) + GestationalWeek field.Int32 // 孕周 + PrenatalCheckType field.Int32 // 产检是否异常(0:未知 1:有 2:无) + PrenatalCheckRemark field.String // 产检异常备注 + DeliveryType field.Int32 // 分娩方式(0:未知 1:顺产 2:剖宫产) + RiskType field.Int32 // 风险类型(0:未知 1:低危 2:中危 3:高危) + RiskValue field.String // 风险值 + HeightGenerateCurveType field.Int32 // 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + WeightGenerateCurveType field.Int32 // 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + LoginStatus field.Int32 // 登录状态(1:启用 0:禁用) + LastLoginTime field.Time // 最后一次登录时间 + LastLoginIP field.String // 最后一次登录IP + LastLoginHash field.String // 最后一次登录 Hash + WxUserID field.String // 微信ID + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patient) Table(newTableName string) *patient { + p.patientDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patient) As(alias string) *patient { + p.patientDo.DO = *(p.patientDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patient) updateTableName(table string) *patient { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.Mobile = field.NewString(table, "mobile") + p.Username = field.NewString(table, "username") + p.Sex = field.NewInt32(table, "sex") + p.Password = field.NewString(table, "password") + p.Avatar = field.NewString(table, "avatar") + p.IDNumber = field.NewString(table, "id_number") + p.Birthday = field.NewTime(table, "birthday") + p.BirthWeight = field.NewInt32(table, "birth_weight") + p.OperativeDate = field.NewTime(table, "operative_date") + p.NextFollowDate = field.NewTime(table, "next_follow_date") + p.ParityNumber = field.NewInt32(table, "parity_number") + p.BirthNumber = field.NewInt32(table, "birth_number") + p.ConceptionType = field.NewInt32(table, "conception_type") + p.GestationalWeek = field.NewInt32(table, "gestational_week") + p.PrenatalCheckType = field.NewInt32(table, "prenatal_check_type") + p.PrenatalCheckRemark = field.NewString(table, "prenatal_check_remark") + p.DeliveryType = field.NewInt32(table, "delivery_type") + p.RiskType = field.NewInt32(table, "risk_type") + p.RiskValue = field.NewString(table, "risk_value") + p.HeightGenerateCurveType = field.NewInt32(table, "height_generate_curve_type") + p.WeightGenerateCurveType = field.NewInt32(table, "weight_generate_curve_type") + p.LoginStatus = field.NewInt32(table, "login_status") + p.LastLoginTime = field.NewTime(table, "last_login_time") + p.LastLoginIP = field.NewString(table, "last_login_ip") + p.LastLoginHash = field.NewString(table, "last_login_hash") + p.WxUserID = field.NewString(table, "wx_user_id") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patient) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patient) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 31) + p.fieldMap["id"] = p.ID + p.fieldMap["mobile"] = p.Mobile + p.fieldMap["username"] = p.Username + p.fieldMap["sex"] = p.Sex + p.fieldMap["password"] = p.Password + p.fieldMap["avatar"] = p.Avatar + p.fieldMap["id_number"] = p.IDNumber + p.fieldMap["birthday"] = p.Birthday + p.fieldMap["birth_weight"] = p.BirthWeight + p.fieldMap["operative_date"] = p.OperativeDate + p.fieldMap["next_follow_date"] = p.NextFollowDate + p.fieldMap["parity_number"] = p.ParityNumber + p.fieldMap["birth_number"] = p.BirthNumber + p.fieldMap["conception_type"] = p.ConceptionType + p.fieldMap["gestational_week"] = p.GestationalWeek + p.fieldMap["prenatal_check_type"] = p.PrenatalCheckType + p.fieldMap["prenatal_check_remark"] = p.PrenatalCheckRemark + p.fieldMap["delivery_type"] = p.DeliveryType + p.fieldMap["risk_type"] = p.RiskType + p.fieldMap["risk_value"] = p.RiskValue + p.fieldMap["height_generate_curve_type"] = p.HeightGenerateCurveType + p.fieldMap["weight_generate_curve_type"] = p.WeightGenerateCurveType + p.fieldMap["login_status"] = p.LoginStatus + p.fieldMap["last_login_time"] = p.LastLoginTime + p.fieldMap["last_login_ip"] = p.LastLoginIP + p.fieldMap["last_login_hash"] = p.LastLoginHash + p.fieldMap["wx_user_id"] = p.WxUserID + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patient) clone(db *gorm.DB) patient { + p.patientDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patient) replaceDB(db *gorm.DB) patient { + p.patientDo.ReplaceDB(db) + return p +} + +type patientDo struct{ gen.DO } + +func (p patientDo) Debug() *patientDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientDo) WithContext(ctx context.Context) *patientDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientDo) ReadDB() *patientDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientDo) WriteDB() *patientDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientDo) Session(config *gorm.Session) *patientDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientDo) Clauses(conds ...clause.Expression) *patientDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientDo) Returning(value interface{}, columns ...string) *patientDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientDo) Not(conds ...gen.Condition) *patientDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientDo) Or(conds ...gen.Condition) *patientDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientDo) Select(conds ...field.Expr) *patientDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientDo) Where(conds ...gen.Condition) *patientDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientDo) Order(conds ...field.Expr) *patientDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientDo) Distinct(cols ...field.Expr) *patientDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientDo) Omit(cols ...field.Expr) *patientDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientDo) Join(table schema.Tabler, on ...field.Expr) *patientDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientDo) Group(cols ...field.Expr) *patientDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientDo) Having(conds ...gen.Condition) *patientDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientDo) Limit(limit int) *patientDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientDo) Offset(offset int) *patientDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientDo) Unscoped() *patientDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientDo) Create(values ...*model.Patient) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientDo) CreateInBatches(values []*model.Patient, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientDo) Save(values ...*model.Patient) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientDo) First() (*model.Patient, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Patient), nil + } +} + +func (p patientDo) Take() (*model.Patient, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Patient), nil + } +} + +func (p patientDo) Last() (*model.Patient, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Patient), nil + } +} + +func (p patientDo) Find() ([]*model.Patient, error) { + result, err := p.DO.Find() + return result.([]*model.Patient), err +} + +func (p patientDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Patient, err error) { + buf := make([]*model.Patient, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientDo) FindInBatches(result *[]*model.Patient, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientDo) Attrs(attrs ...field.AssignExpr) *patientDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientDo) Assign(attrs ...field.AssignExpr) *patientDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientDo) Joins(fields ...field.RelationField) *patientDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientDo) Preload(fields ...field.RelationField) *patientDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientDo) FirstOrInit() (*model.Patient, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Patient), nil + } +} + +func (p patientDo) FirstOrCreate() (*model.Patient, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Patient), nil + } +} + +func (p patientDo) FindByPage(offset int, limit int) (result []*model.Patient, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientDo) Delete(models ...*model.Patient) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientDo) withDO(do gen.Dao) *patientDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_emergency_symptom.gen.go b/internal/repository/mysql/dao/patient_emergency_symptom.gen.go new file mode 100644 index 0000000..049af89 --- /dev/null +++ b/internal/repository/mysql/dao/patient_emergency_symptom.gen.go @@ -0,0 +1,348 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientEmergencySymptom(db *gorm.DB, opts ...gen.DOOption) patientEmergencySymptom { + _patientEmergencySymptom := patientEmergencySymptom{} + + _patientEmergencySymptom.patientEmergencySymptomDo.UseDB(db, opts...) + _patientEmergencySymptom.patientEmergencySymptomDo.UseModel(&model.PatientEmergencySymptom{}) + + tableName := _patientEmergencySymptom.patientEmergencySymptomDo.TableName() + _patientEmergencySymptom.ALL = field.NewAsterisk(tableName) + _patientEmergencySymptom.ID = field.NewInt32(tableName, "id") + _patientEmergencySymptom.PatientID = field.NewInt32(tableName, "patient_id") + _patientEmergencySymptom.Symptom = field.NewString(tableName, "symptom") + _patientEmergencySymptom.Conclusion = field.NewString(tableName, "conclusion") + _patientEmergencySymptom.CreatedUser = field.NewString(tableName, "created_user") + _patientEmergencySymptom.CreatedAt = field.NewTime(tableName, "created_at") + _patientEmergencySymptom.UpdatedUser = field.NewString(tableName, "updated_user") + _patientEmergencySymptom.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientEmergencySymptom.fillFieldMap() + + return _patientEmergencySymptom +} + +// patientEmergencySymptom 患者紧急症状表 +type patientEmergencySymptom struct { + patientEmergencySymptomDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PatientID field.Int32 // 患者ID + Symptom field.String // 症状信息(JSON格式) + Conclusion field.String // 结论 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientEmergencySymptom) Table(newTableName string) *patientEmergencySymptom { + p.patientEmergencySymptomDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientEmergencySymptom) As(alias string) *patientEmergencySymptom { + p.patientEmergencySymptomDo.DO = *(p.patientEmergencySymptomDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientEmergencySymptom) updateTableName(table string) *patientEmergencySymptom { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.PatientID = field.NewInt32(table, "patient_id") + p.Symptom = field.NewString(table, "symptom") + p.Conclusion = field.NewString(table, "conclusion") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientEmergencySymptom) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientEmergencySymptom) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 8) + p.fieldMap["id"] = p.ID + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["symptom"] = p.Symptom + p.fieldMap["conclusion"] = p.Conclusion + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientEmergencySymptom) clone(db *gorm.DB) patientEmergencySymptom { + p.patientEmergencySymptomDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientEmergencySymptom) replaceDB(db *gorm.DB) patientEmergencySymptom { + p.patientEmergencySymptomDo.ReplaceDB(db) + return p +} + +type patientEmergencySymptomDo struct{ gen.DO } + +func (p patientEmergencySymptomDo) Debug() *patientEmergencySymptomDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientEmergencySymptomDo) WithContext(ctx context.Context) *patientEmergencySymptomDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientEmergencySymptomDo) ReadDB() *patientEmergencySymptomDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientEmergencySymptomDo) WriteDB() *patientEmergencySymptomDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientEmergencySymptomDo) Session(config *gorm.Session) *patientEmergencySymptomDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientEmergencySymptomDo) Clauses(conds ...clause.Expression) *patientEmergencySymptomDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientEmergencySymptomDo) Returning(value interface{}, columns ...string) *patientEmergencySymptomDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientEmergencySymptomDo) Not(conds ...gen.Condition) *patientEmergencySymptomDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientEmergencySymptomDo) Or(conds ...gen.Condition) *patientEmergencySymptomDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientEmergencySymptomDo) Select(conds ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientEmergencySymptomDo) Where(conds ...gen.Condition) *patientEmergencySymptomDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientEmergencySymptomDo) Order(conds ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientEmergencySymptomDo) Distinct(cols ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientEmergencySymptomDo) Omit(cols ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientEmergencySymptomDo) Join(table schema.Tabler, on ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientEmergencySymptomDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientEmergencySymptomDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientEmergencySymptomDo) Group(cols ...field.Expr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientEmergencySymptomDo) Having(conds ...gen.Condition) *patientEmergencySymptomDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientEmergencySymptomDo) Limit(limit int) *patientEmergencySymptomDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientEmergencySymptomDo) Offset(offset int) *patientEmergencySymptomDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientEmergencySymptomDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientEmergencySymptomDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientEmergencySymptomDo) Unscoped() *patientEmergencySymptomDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientEmergencySymptomDo) Create(values ...*model.PatientEmergencySymptom) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientEmergencySymptomDo) CreateInBatches(values []*model.PatientEmergencySymptom, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientEmergencySymptomDo) Save(values ...*model.PatientEmergencySymptom) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientEmergencySymptomDo) First() (*model.PatientEmergencySymptom, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientEmergencySymptom), nil + } +} + +func (p patientEmergencySymptomDo) Take() (*model.PatientEmergencySymptom, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientEmergencySymptom), nil + } +} + +func (p patientEmergencySymptomDo) Last() (*model.PatientEmergencySymptom, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientEmergencySymptom), nil + } +} + +func (p patientEmergencySymptomDo) Find() ([]*model.PatientEmergencySymptom, error) { + result, err := p.DO.Find() + return result.([]*model.PatientEmergencySymptom), err +} + +func (p patientEmergencySymptomDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientEmergencySymptom, err error) { + buf := make([]*model.PatientEmergencySymptom, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientEmergencySymptomDo) FindInBatches(result *[]*model.PatientEmergencySymptom, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientEmergencySymptomDo) Attrs(attrs ...field.AssignExpr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientEmergencySymptomDo) Assign(attrs ...field.AssignExpr) *patientEmergencySymptomDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientEmergencySymptomDo) Joins(fields ...field.RelationField) *patientEmergencySymptomDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientEmergencySymptomDo) Preload(fields ...field.RelationField) *patientEmergencySymptomDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientEmergencySymptomDo) FirstOrInit() (*model.PatientEmergencySymptom, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientEmergencySymptom), nil + } +} + +func (p patientEmergencySymptomDo) FirstOrCreate() (*model.PatientEmergencySymptom, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientEmergencySymptom), nil + } +} + +func (p patientEmergencySymptomDo) FindByPage(offset int, limit int) (result []*model.PatientEmergencySymptom, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientEmergencySymptomDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientEmergencySymptomDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientEmergencySymptomDo) Delete(models ...*model.PatientEmergencySymptom) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientEmergencySymptomDo) withDO(do gen.Dao) *patientEmergencySymptomDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_follow_plan.gen.go b/internal/repository/mysql/dao/patient_follow_plan.gen.go new file mode 100644 index 0000000..3a4a62a --- /dev/null +++ b/internal/repository/mysql/dao/patient_follow_plan.gen.go @@ -0,0 +1,352 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientFollowPlan(db *gorm.DB, opts ...gen.DOOption) patientFollowPlan { + _patientFollowPlan := patientFollowPlan{} + + _patientFollowPlan.patientFollowPlanDo.UseDB(db, opts...) + _patientFollowPlan.patientFollowPlanDo.UseModel(&model.PatientFollowPlan{}) + + tableName := _patientFollowPlan.patientFollowPlanDo.TableName() + _patientFollowPlan.ALL = field.NewAsterisk(tableName) + _patientFollowPlan.ID = field.NewInt32(tableName, "id") + _patientFollowPlan.PatientID = field.NewInt32(tableName, "patient_id") + _patientFollowPlan.PlanName = field.NewString(tableName, "plan_name") + _patientFollowPlan.PlanDate = field.NewTime(tableName, "plan_date") + _patientFollowPlan.Status = field.NewInt32(tableName, "status") + _patientFollowPlan.CreatedUser = field.NewString(tableName, "created_user") + _patientFollowPlan.CreatedAt = field.NewTime(tableName, "created_at") + _patientFollowPlan.UpdatedUser = field.NewString(tableName, "updated_user") + _patientFollowPlan.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientFollowPlan.fillFieldMap() + + return _patientFollowPlan +} + +// patientFollowPlan 患者随访计划表 +type patientFollowPlan struct { + patientFollowPlanDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PatientID field.Int32 // 患者ID + PlanName field.String // 计划名称 + PlanDate field.Time // 计划时间 + Status field.Int32 // 完成状态(1:未完成 2:已完成) + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientFollowPlan) Table(newTableName string) *patientFollowPlan { + p.patientFollowPlanDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientFollowPlan) As(alias string) *patientFollowPlan { + p.patientFollowPlanDo.DO = *(p.patientFollowPlanDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientFollowPlan) updateTableName(table string) *patientFollowPlan { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.PatientID = field.NewInt32(table, "patient_id") + p.PlanName = field.NewString(table, "plan_name") + p.PlanDate = field.NewTime(table, "plan_date") + p.Status = field.NewInt32(table, "status") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientFollowPlan) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientFollowPlan) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 9) + p.fieldMap["id"] = p.ID + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["plan_name"] = p.PlanName + p.fieldMap["plan_date"] = p.PlanDate + p.fieldMap["status"] = p.Status + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientFollowPlan) clone(db *gorm.DB) patientFollowPlan { + p.patientFollowPlanDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientFollowPlan) replaceDB(db *gorm.DB) patientFollowPlan { + p.patientFollowPlanDo.ReplaceDB(db) + return p +} + +type patientFollowPlanDo struct{ gen.DO } + +func (p patientFollowPlanDo) Debug() *patientFollowPlanDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientFollowPlanDo) WithContext(ctx context.Context) *patientFollowPlanDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientFollowPlanDo) ReadDB() *patientFollowPlanDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientFollowPlanDo) WriteDB() *patientFollowPlanDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientFollowPlanDo) Session(config *gorm.Session) *patientFollowPlanDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientFollowPlanDo) Clauses(conds ...clause.Expression) *patientFollowPlanDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientFollowPlanDo) Returning(value interface{}, columns ...string) *patientFollowPlanDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientFollowPlanDo) Not(conds ...gen.Condition) *patientFollowPlanDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientFollowPlanDo) Or(conds ...gen.Condition) *patientFollowPlanDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientFollowPlanDo) Select(conds ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientFollowPlanDo) Where(conds ...gen.Condition) *patientFollowPlanDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientFollowPlanDo) Order(conds ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientFollowPlanDo) Distinct(cols ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientFollowPlanDo) Omit(cols ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientFollowPlanDo) Join(table schema.Tabler, on ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientFollowPlanDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientFollowPlanDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientFollowPlanDo) Group(cols ...field.Expr) *patientFollowPlanDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientFollowPlanDo) Having(conds ...gen.Condition) *patientFollowPlanDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientFollowPlanDo) Limit(limit int) *patientFollowPlanDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientFollowPlanDo) Offset(offset int) *patientFollowPlanDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientFollowPlanDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientFollowPlanDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientFollowPlanDo) Unscoped() *patientFollowPlanDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientFollowPlanDo) Create(values ...*model.PatientFollowPlan) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientFollowPlanDo) CreateInBatches(values []*model.PatientFollowPlan, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientFollowPlanDo) Save(values ...*model.PatientFollowPlan) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientFollowPlanDo) First() (*model.PatientFollowPlan, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowPlan), nil + } +} + +func (p patientFollowPlanDo) Take() (*model.PatientFollowPlan, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowPlan), nil + } +} + +func (p patientFollowPlanDo) Last() (*model.PatientFollowPlan, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowPlan), nil + } +} + +func (p patientFollowPlanDo) Find() ([]*model.PatientFollowPlan, error) { + result, err := p.DO.Find() + return result.([]*model.PatientFollowPlan), err +} + +func (p patientFollowPlanDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientFollowPlan, err error) { + buf := make([]*model.PatientFollowPlan, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientFollowPlanDo) FindInBatches(result *[]*model.PatientFollowPlan, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientFollowPlanDo) Attrs(attrs ...field.AssignExpr) *patientFollowPlanDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientFollowPlanDo) Assign(attrs ...field.AssignExpr) *patientFollowPlanDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientFollowPlanDo) Joins(fields ...field.RelationField) *patientFollowPlanDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientFollowPlanDo) Preload(fields ...field.RelationField) *patientFollowPlanDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientFollowPlanDo) FirstOrInit() (*model.PatientFollowPlan, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowPlan), nil + } +} + +func (p patientFollowPlanDo) FirstOrCreate() (*model.PatientFollowPlan, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowPlan), nil + } +} + +func (p patientFollowPlanDo) FindByPage(offset int, limit int) (result []*model.PatientFollowPlan, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientFollowPlanDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientFollowPlanDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientFollowPlanDo) Delete(models ...*model.PatientFollowPlan) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientFollowPlanDo) withDO(do gen.Dao) *patientFollowPlanDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_follow_questionnaire.gen.go b/internal/repository/mysql/dao/patient_follow_questionnaire.gen.go new file mode 100644 index 0000000..83d66f7 --- /dev/null +++ b/internal/repository/mysql/dao/patient_follow_questionnaire.gen.go @@ -0,0 +1,568 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientFollowQuestionnaire(db *gorm.DB, opts ...gen.DOOption) patientFollowQuestionnaire { + _patientFollowQuestionnaire := patientFollowQuestionnaire{} + + _patientFollowQuestionnaire.patientFollowQuestionnaireDo.UseDB(db, opts...) + _patientFollowQuestionnaire.patientFollowQuestionnaireDo.UseModel(&model.PatientFollowQuestionnaire{}) + + tableName := _patientFollowQuestionnaire.patientFollowQuestionnaireDo.TableName() + _patientFollowQuestionnaire.ALL = field.NewAsterisk(tableName) + _patientFollowQuestionnaire.ID = field.NewInt32(tableName, "id") + _patientFollowQuestionnaire.PatientID = field.NewInt32(tableName, "patient_id") + _patientFollowQuestionnaire.PlanID = field.NewInt32(tableName, "plan_id") + _patientFollowQuestionnaire.FollowName = field.NewString(tableName, "follow_name") + _patientFollowQuestionnaire.FollowDate = field.NewTime(tableName, "follow_date") + _patientFollowQuestionnaire.FollowHospital = field.NewString(tableName, "follow_hospital") + _patientFollowQuestionnaire.Height = field.NewString(tableName, "height") + _patientFollowQuestionnaire.Weight = field.NewString(tableName, "weight") + _patientFollowQuestionnaire.HeadCircumference = field.NewString(tableName, "head_circumference") + _patientFollowQuestionnaire.HighHip = field.NewString(tableName, "high_hip") + _patientFollowQuestionnaire.LiverFunctionImage = field.NewString(tableName, "liver_function_image") + _patientFollowQuestionnaire.TotalBilirubin = field.NewString(tableName, "total_bilirubin") + _patientFollowQuestionnaire.DirectBilirubin = field.NewString(tableName, "direct_bilirubin") + _patientFollowQuestionnaire.TotalBileAcid = field.NewString(tableName, "total_bile_acid") + _patientFollowQuestionnaire.Albumin = field.NewString(tableName, "albumin") + _patientFollowQuestionnaire.GrainGrass = field.NewString(tableName, "grain_grass") + _patientFollowQuestionnaire.GuBing = field.NewString(tableName, "gu_bing") + _patientFollowQuestionnaire.Ggt = field.NewString(tableName, "ggt") + _patientFollowQuestionnaire.Alp = field.NewString(tableName, "alp") + _patientFollowQuestionnaire.CoagulationFunctionImage = field.NewString(tableName, "coagulation_function_image") + _patientFollowQuestionnaire.Crp = field.NewString(tableName, "crp") + _patientFollowQuestionnaire.Ddr = field.NewString(tableName, "ddr") + _patientFollowQuestionnaire.Inr = field.NewString(tableName, "inr") + _patientFollowQuestionnaire.Pt = field.NewString(tableName, "pt") + _patientFollowQuestionnaire.Pta = field.NewString(tableName, "pta") + _patientFollowQuestionnaire.Aptt = field.NewString(tableName, "aptt") + _patientFollowQuestionnaire.Tt = field.NewString(tableName, "tt") + _patientFollowQuestionnaire.Fib = field.NewString(tableName, "fib") + _patientFollowQuestionnaire.Npdp = field.NewString(tableName, "npdp") + _patientFollowQuestionnaire.Mmp7 = field.NewString(tableName, "mmp_7") + _patientFollowQuestionnaire.BloodRoutineImage = field.NewString(tableName, "blood_routine_image") + _patientFollowQuestionnaire.Platelets = field.NewString(tableName, "platelets") + _patientFollowQuestionnaire.Hemoglobin = field.NewString(tableName, "hemoglobin") + _patientFollowQuestionnaire.WhiteBloodCells = field.NewString(tableName, "white_blood_cells") + _patientFollowQuestionnaire.RedBloodCells = field.NewString(tableName, "red_blood_cells") + _patientFollowQuestionnaire.NutritionalIndicatorImage = field.NewString(tableName, "nutritional_indicator_image") + _patientFollowQuestionnaire.OhD3 = field.NewString(tableName, "oh_d3") + _patientFollowQuestionnaire.OhD2 = field.NewString(tableName, "oh_d2") + _patientFollowQuestionnaire.OhD = field.NewString(tableName, "oh_d") + _patientFollowQuestionnaire.VitaminA = field.NewString(tableName, "vitamin_a") + _patientFollowQuestionnaire.VitaminK = field.NewString(tableName, "vitamin_k") + _patientFollowQuestionnaire.VitaminE = field.NewString(tableName, "vitamin_e") + _patientFollowQuestionnaire.BModeImage = field.NewString(tableName, "b_mode_image") + _patientFollowQuestionnaire.UnderTheLiverRib = field.NewString(tableName, "under_the_liver_rib") + _patientFollowQuestionnaire.UnderTheXiphoidLiver = field.NewString(tableName, "under_the_xiphoid_liver") + _patientFollowQuestionnaire.SpleenRibArea = field.NewString(tableName, "spleen_rib_area") + _patientFollowQuestionnaire.MainPortalVein = field.NewString(tableName, "main_portal_vein") + _patientFollowQuestionnaire.LiverEcho = field.NewString(tableName, "liver_echo") + _patientFollowQuestionnaire.GallbladderSize = field.NewString(tableName, "gallbladder_size") + _patientFollowQuestionnaire.CommonBileDuct = field.NewString(tableName, "common_bile_duct") + _patientFollowQuestionnaire.FiberBlockSize = field.NewString(tableName, "fiber_block_size") + _patientFollowQuestionnaire.Pvv = field.NewString(tableName, "pvv") + _patientFollowQuestionnaire.LiverElasticityValue = field.NewString(tableName, "liver_elasticity_value") + _patientFollowQuestionnaire.IsHaveCyst = field.NewInt32(tableName, "is_have_cyst") + _patientFollowQuestionnaire.IsHaveAscites = field.NewInt32(tableName, "is_have_ascites") + _patientFollowQuestionnaire.ElastographyMinimum = field.NewString(tableName, "elastography_minimum") + _patientFollowQuestionnaire.ElastographyMaximum = field.NewString(tableName, "elastography_maximum") + _patientFollowQuestionnaire.ElastographyMedian = field.NewString(tableName, "elastography_median") + _patientFollowQuestionnaire.MdtImage = field.NewString(tableName, "mdt_image") + _patientFollowQuestionnaire.CreatedUser = field.NewString(tableName, "created_user") + _patientFollowQuestionnaire.CreatedAt = field.NewTime(tableName, "created_at") + _patientFollowQuestionnaire.UpdatedUser = field.NewString(tableName, "updated_user") + _patientFollowQuestionnaire.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientFollowQuestionnaire.fillFieldMap() + + return _patientFollowQuestionnaire +} + +// patientFollowQuestionnaire 患者随访问卷表 +type patientFollowQuestionnaire struct { + patientFollowQuestionnaireDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PatientID field.Int32 // 患者ID + PlanID field.Int32 // 随访计划ID + FollowName field.String // 随访名称 + FollowDate field.Time // 随访日期 + FollowHospital field.String // 随访医院 + Height field.String // 身高(CM) + Weight field.String // 体重(KG) + HeadCircumference field.String // 头围(CM) + HighHip field.String // 上臀围(CM) + LiverFunctionImage field.String // 肝功能检查报告(多张用,分割) + TotalBilirubin field.String // 总胆红素(µmol/L) + DirectBilirubin field.String // 直接胆红素(µmol/L) + TotalBileAcid field.String // 总胆汁酸(g/L) + Albumin field.String // 白蛋白(g/L) + GrainGrass field.String // 谷草(U/L) + GuBing field.String // 谷丙(U/L) + Ggt field.String // GGT(U/L) + Alp field.String // ALP(U/L) + CoagulationFunctionImage field.String // 凝血功能检查报告(多张用,分割) + Crp field.String // CRP(mg/L) + Ddr field.String // DDR + Inr field.String // INR + Pt field.String // PT(s) + Pta field.String // PTA(%) + Aptt field.String // APTT(s) + Tt field.String // TT(s) + Fib field.String // FIB(g/L) + Npdp field.String // NPDP(mg/L) + Mmp7 field.String // MMP-7(ng/mL) + BloodRoutineImage field.String // 血常规检查报告(多张用,分割) + Platelets field.String // 血小板(10^9/L) + Hemoglobin field.String // 血红蛋白 (g/L) + WhiteBloodCells field.String // 白细胞 (10^9/L) + RedBloodCells field.String // 红细胞 (10^9/L) + NutritionalIndicatorImage field.String // 营养指标检查报告(多张用,分割) + OhD3 field.String // 25(OH)D3 (ng/ml) + OhD2 field.String // 25(OH)D2 (ng/ml) + OhD field.String // 25(OH)D (ng/ml) + VitaminA field.String // 维生素A (ng/ml) + VitaminK field.String // 维生素K (ng/ml) + VitaminE field.String // 维生素E (ng/ml) + BModeImage field.String // B超报告(多张用,分割) + UnderTheLiverRib field.String // 肝肋下(mm) + UnderTheXiphoidLiver field.String // 肝剑突下(mm) + SpleenRibArea field.String // 脾肋下(mm) + MainPortalVein field.String // 门静脉主干内径(mm) + LiverEcho field.String // 肝回声 + GallbladderSize field.String // 胆囊大小(mm) + CommonBileDuct field.String // 胆总管(mm) + FiberBlockSize field.String // 纤维块大小(mm) + Pvv field.String // 门静脉流速 + LiverElasticityValue field.String // 肝弹性值 + IsHaveCyst field.Int32 // 有无肝囊肿(1:是 2:否) + IsHaveAscites field.Int32 // 有无腹水(1:是 2:否) + ElastographyMinimum field.String // 弹性成像最小值(kPa) + ElastographyMaximum field.String // 弹性成像最大值(kPa) + ElastographyMedian field.String // 弹性成像中位数(kPa) + MdtImage field.String // MDT电子病历(多张用,分割) + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientFollowQuestionnaire) Table(newTableName string) *patientFollowQuestionnaire { + p.patientFollowQuestionnaireDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientFollowQuestionnaire) As(alias string) *patientFollowQuestionnaire { + p.patientFollowQuestionnaireDo.DO = *(p.patientFollowQuestionnaireDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientFollowQuestionnaire) updateTableName(table string) *patientFollowQuestionnaire { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.PatientID = field.NewInt32(table, "patient_id") + p.PlanID = field.NewInt32(table, "plan_id") + p.FollowName = field.NewString(table, "follow_name") + p.FollowDate = field.NewTime(table, "follow_date") + p.FollowHospital = field.NewString(table, "follow_hospital") + p.Height = field.NewString(table, "height") + p.Weight = field.NewString(table, "weight") + p.HeadCircumference = field.NewString(table, "head_circumference") + p.HighHip = field.NewString(table, "high_hip") + p.LiverFunctionImage = field.NewString(table, "liver_function_image") + p.TotalBilirubin = field.NewString(table, "total_bilirubin") + p.DirectBilirubin = field.NewString(table, "direct_bilirubin") + p.TotalBileAcid = field.NewString(table, "total_bile_acid") + p.Albumin = field.NewString(table, "albumin") + p.GrainGrass = field.NewString(table, "grain_grass") + p.GuBing = field.NewString(table, "gu_bing") + p.Ggt = field.NewString(table, "ggt") + p.Alp = field.NewString(table, "alp") + p.CoagulationFunctionImage = field.NewString(table, "coagulation_function_image") + p.Crp = field.NewString(table, "crp") + p.Ddr = field.NewString(table, "ddr") + p.Inr = field.NewString(table, "inr") + p.Pt = field.NewString(table, "pt") + p.Pta = field.NewString(table, "pta") + p.Aptt = field.NewString(table, "aptt") + p.Tt = field.NewString(table, "tt") + p.Fib = field.NewString(table, "fib") + p.Npdp = field.NewString(table, "npdp") + p.Mmp7 = field.NewString(table, "mmp_7") + p.BloodRoutineImage = field.NewString(table, "blood_routine_image") + p.Platelets = field.NewString(table, "platelets") + p.Hemoglobin = field.NewString(table, "hemoglobin") + p.WhiteBloodCells = field.NewString(table, "white_blood_cells") + p.RedBloodCells = field.NewString(table, "red_blood_cells") + p.NutritionalIndicatorImage = field.NewString(table, "nutritional_indicator_image") + p.OhD3 = field.NewString(table, "oh_d3") + p.OhD2 = field.NewString(table, "oh_d2") + p.OhD = field.NewString(table, "oh_d") + p.VitaminA = field.NewString(table, "vitamin_a") + p.VitaminK = field.NewString(table, "vitamin_k") + p.VitaminE = field.NewString(table, "vitamin_e") + p.BModeImage = field.NewString(table, "b_mode_image") + p.UnderTheLiverRib = field.NewString(table, "under_the_liver_rib") + p.UnderTheXiphoidLiver = field.NewString(table, "under_the_xiphoid_liver") + p.SpleenRibArea = field.NewString(table, "spleen_rib_area") + p.MainPortalVein = field.NewString(table, "main_portal_vein") + p.LiverEcho = field.NewString(table, "liver_echo") + p.GallbladderSize = field.NewString(table, "gallbladder_size") + p.CommonBileDuct = field.NewString(table, "common_bile_duct") + p.FiberBlockSize = field.NewString(table, "fiber_block_size") + p.Pvv = field.NewString(table, "pvv") + p.LiverElasticityValue = field.NewString(table, "liver_elasticity_value") + p.IsHaveCyst = field.NewInt32(table, "is_have_cyst") + p.IsHaveAscites = field.NewInt32(table, "is_have_ascites") + p.ElastographyMinimum = field.NewString(table, "elastography_minimum") + p.ElastographyMaximum = field.NewString(table, "elastography_maximum") + p.ElastographyMedian = field.NewString(table, "elastography_median") + p.MdtImage = field.NewString(table, "mdt_image") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientFollowQuestionnaire) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientFollowQuestionnaire) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 63) + p.fieldMap["id"] = p.ID + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["plan_id"] = p.PlanID + p.fieldMap["follow_name"] = p.FollowName + p.fieldMap["follow_date"] = p.FollowDate + p.fieldMap["follow_hospital"] = p.FollowHospital + p.fieldMap["height"] = p.Height + p.fieldMap["weight"] = p.Weight + p.fieldMap["head_circumference"] = p.HeadCircumference + p.fieldMap["high_hip"] = p.HighHip + p.fieldMap["liver_function_image"] = p.LiverFunctionImage + p.fieldMap["total_bilirubin"] = p.TotalBilirubin + p.fieldMap["direct_bilirubin"] = p.DirectBilirubin + p.fieldMap["total_bile_acid"] = p.TotalBileAcid + p.fieldMap["albumin"] = p.Albumin + p.fieldMap["grain_grass"] = p.GrainGrass + p.fieldMap["gu_bing"] = p.GuBing + p.fieldMap["ggt"] = p.Ggt + p.fieldMap["alp"] = p.Alp + p.fieldMap["coagulation_function_image"] = p.CoagulationFunctionImage + p.fieldMap["crp"] = p.Crp + p.fieldMap["ddr"] = p.Ddr + p.fieldMap["inr"] = p.Inr + p.fieldMap["pt"] = p.Pt + p.fieldMap["pta"] = p.Pta + p.fieldMap["aptt"] = p.Aptt + p.fieldMap["tt"] = p.Tt + p.fieldMap["fib"] = p.Fib + p.fieldMap["npdp"] = p.Npdp + p.fieldMap["mmp_7"] = p.Mmp7 + p.fieldMap["blood_routine_image"] = p.BloodRoutineImage + p.fieldMap["platelets"] = p.Platelets + p.fieldMap["hemoglobin"] = p.Hemoglobin + p.fieldMap["white_blood_cells"] = p.WhiteBloodCells + p.fieldMap["red_blood_cells"] = p.RedBloodCells + p.fieldMap["nutritional_indicator_image"] = p.NutritionalIndicatorImage + p.fieldMap["oh_d3"] = p.OhD3 + p.fieldMap["oh_d2"] = p.OhD2 + p.fieldMap["oh_d"] = p.OhD + p.fieldMap["vitamin_a"] = p.VitaminA + p.fieldMap["vitamin_k"] = p.VitaminK + p.fieldMap["vitamin_e"] = p.VitaminE + p.fieldMap["b_mode_image"] = p.BModeImage + p.fieldMap["under_the_liver_rib"] = p.UnderTheLiverRib + p.fieldMap["under_the_xiphoid_liver"] = p.UnderTheXiphoidLiver + p.fieldMap["spleen_rib_area"] = p.SpleenRibArea + p.fieldMap["main_portal_vein"] = p.MainPortalVein + p.fieldMap["liver_echo"] = p.LiverEcho + p.fieldMap["gallbladder_size"] = p.GallbladderSize + p.fieldMap["common_bile_duct"] = p.CommonBileDuct + p.fieldMap["fiber_block_size"] = p.FiberBlockSize + p.fieldMap["pvv"] = p.Pvv + p.fieldMap["liver_elasticity_value"] = p.LiverElasticityValue + p.fieldMap["is_have_cyst"] = p.IsHaveCyst + p.fieldMap["is_have_ascites"] = p.IsHaveAscites + p.fieldMap["elastography_minimum"] = p.ElastographyMinimum + p.fieldMap["elastography_maximum"] = p.ElastographyMaximum + p.fieldMap["elastography_median"] = p.ElastographyMedian + p.fieldMap["mdt_image"] = p.MdtImage + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientFollowQuestionnaire) clone(db *gorm.DB) patientFollowQuestionnaire { + p.patientFollowQuestionnaireDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientFollowQuestionnaire) replaceDB(db *gorm.DB) patientFollowQuestionnaire { + p.patientFollowQuestionnaireDo.ReplaceDB(db) + return p +} + +type patientFollowQuestionnaireDo struct{ gen.DO } + +func (p patientFollowQuestionnaireDo) Debug() *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientFollowQuestionnaireDo) WithContext(ctx context.Context) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientFollowQuestionnaireDo) ReadDB() *patientFollowQuestionnaireDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientFollowQuestionnaireDo) WriteDB() *patientFollowQuestionnaireDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientFollowQuestionnaireDo) Session(config *gorm.Session) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientFollowQuestionnaireDo) Clauses(conds ...clause.Expression) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientFollowQuestionnaireDo) Returning(value interface{}, columns ...string) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientFollowQuestionnaireDo) Not(conds ...gen.Condition) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientFollowQuestionnaireDo) Or(conds ...gen.Condition) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientFollowQuestionnaireDo) Select(conds ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientFollowQuestionnaireDo) Where(conds ...gen.Condition) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientFollowQuestionnaireDo) Order(conds ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientFollowQuestionnaireDo) Distinct(cols ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientFollowQuestionnaireDo) Omit(cols ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientFollowQuestionnaireDo) Join(table schema.Tabler, on ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientFollowQuestionnaireDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientFollowQuestionnaireDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientFollowQuestionnaireDo) Group(cols ...field.Expr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientFollowQuestionnaireDo) Having(conds ...gen.Condition) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientFollowQuestionnaireDo) Limit(limit int) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientFollowQuestionnaireDo) Offset(offset int) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientFollowQuestionnaireDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientFollowQuestionnaireDo) Unscoped() *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientFollowQuestionnaireDo) Create(values ...*model.PatientFollowQuestionnaire) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientFollowQuestionnaireDo) CreateInBatches(values []*model.PatientFollowQuestionnaire, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientFollowQuestionnaireDo) Save(values ...*model.PatientFollowQuestionnaire) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientFollowQuestionnaireDo) First() (*model.PatientFollowQuestionnaire, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowQuestionnaire), nil + } +} + +func (p patientFollowQuestionnaireDo) Take() (*model.PatientFollowQuestionnaire, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowQuestionnaire), nil + } +} + +func (p patientFollowQuestionnaireDo) Last() (*model.PatientFollowQuestionnaire, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowQuestionnaire), nil + } +} + +func (p patientFollowQuestionnaireDo) Find() ([]*model.PatientFollowQuestionnaire, error) { + result, err := p.DO.Find() + return result.([]*model.PatientFollowQuestionnaire), err +} + +func (p patientFollowQuestionnaireDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientFollowQuestionnaire, err error) { + buf := make([]*model.PatientFollowQuestionnaire, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientFollowQuestionnaireDo) FindInBatches(result *[]*model.PatientFollowQuestionnaire, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientFollowQuestionnaireDo) Attrs(attrs ...field.AssignExpr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientFollowQuestionnaireDo) Assign(attrs ...field.AssignExpr) *patientFollowQuestionnaireDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientFollowQuestionnaireDo) Joins(fields ...field.RelationField) *patientFollowQuestionnaireDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientFollowQuestionnaireDo) Preload(fields ...field.RelationField) *patientFollowQuestionnaireDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientFollowQuestionnaireDo) FirstOrInit() (*model.PatientFollowQuestionnaire, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowQuestionnaire), nil + } +} + +func (p patientFollowQuestionnaireDo) FirstOrCreate() (*model.PatientFollowQuestionnaire, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientFollowQuestionnaire), nil + } +} + +func (p patientFollowQuestionnaireDo) FindByPage(offset int, limit int) (result []*model.PatientFollowQuestionnaire, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientFollowQuestionnaireDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientFollowQuestionnaireDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientFollowQuestionnaireDo) Delete(models ...*model.PatientFollowQuestionnaire) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientFollowQuestionnaireDo) withDO(do gen.Dao) *patientFollowQuestionnaireDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_medicine_record.gen.go b/internal/repository/mysql/dao/patient_medicine_record.gen.go new file mode 100644 index 0000000..9cbeb40 --- /dev/null +++ b/internal/repository/mysql/dao/patient_medicine_record.gen.go @@ -0,0 +1,368 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientMedicineRecord(db *gorm.DB, opts ...gen.DOOption) patientMedicineRecord { + _patientMedicineRecord := patientMedicineRecord{} + + _patientMedicineRecord.patientMedicineRecordDo.UseDB(db, opts...) + _patientMedicineRecord.patientMedicineRecordDo.UseModel(&model.PatientMedicineRecord{}) + + tableName := _patientMedicineRecord.patientMedicineRecordDo.TableName() + _patientMedicineRecord.ALL = field.NewAsterisk(tableName) + _patientMedicineRecord.ID = field.NewInt32(tableName, "id") + _patientMedicineRecord.PatientID = field.NewInt32(tableName, "patient_id") + _patientMedicineRecord.SchemeID = field.NewInt32(tableName, "scheme_id") + _patientMedicineRecord.MedicineDate = field.NewTime(tableName, "medicine_date") + _patientMedicineRecord.MedicineTimeType = field.NewInt32(tableName, "medicine_time_type") + _patientMedicineRecord.MedicineTime = field.NewString(tableName, "medicine_time") + _patientMedicineRecord.Detail = field.NewString(tableName, "detail") + _patientMedicineRecord.Status = field.NewInt32(tableName, "status") + _patientMedicineRecord.StatusAt = field.NewTime(tableName, "status_at") + _patientMedicineRecord.CreatedUser = field.NewString(tableName, "created_user") + _patientMedicineRecord.CreatedAt = field.NewTime(tableName, "created_at") + _patientMedicineRecord.UpdatedUser = field.NewString(tableName, "updated_user") + _patientMedicineRecord.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientMedicineRecord.fillFieldMap() + + return _patientMedicineRecord +} + +// patientMedicineRecord 患者用药记录表 +type patientMedicineRecord struct { + patientMedicineRecordDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PatientID field.Int32 // 患者ID + SchemeID field.Int32 // 用药方案ID + MedicineDate field.Time // 用药日期 + MedicineTimeType field.Int32 // 用药时间类型(1:早上 2:中午 3:晚上) + MedicineTime field.String // 用药时间 + Detail field.String // 药品信息(JSON格式) + Status field.Int32 // 用药状态(1:未完成 2:已完成) + StatusAt field.Time // 已完成时间(打卡时间) + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientMedicineRecord) Table(newTableName string) *patientMedicineRecord { + p.patientMedicineRecordDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientMedicineRecord) As(alias string) *patientMedicineRecord { + p.patientMedicineRecordDo.DO = *(p.patientMedicineRecordDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientMedicineRecord) updateTableName(table string) *patientMedicineRecord { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.PatientID = field.NewInt32(table, "patient_id") + p.SchemeID = field.NewInt32(table, "scheme_id") + p.MedicineDate = field.NewTime(table, "medicine_date") + p.MedicineTimeType = field.NewInt32(table, "medicine_time_type") + p.MedicineTime = field.NewString(table, "medicine_time") + p.Detail = field.NewString(table, "detail") + p.Status = field.NewInt32(table, "status") + p.StatusAt = field.NewTime(table, "status_at") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientMedicineRecord) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientMedicineRecord) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 13) + p.fieldMap["id"] = p.ID + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["scheme_id"] = p.SchemeID + p.fieldMap["medicine_date"] = p.MedicineDate + p.fieldMap["medicine_time_type"] = p.MedicineTimeType + p.fieldMap["medicine_time"] = p.MedicineTime + p.fieldMap["detail"] = p.Detail + p.fieldMap["status"] = p.Status + p.fieldMap["status_at"] = p.StatusAt + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientMedicineRecord) clone(db *gorm.DB) patientMedicineRecord { + p.patientMedicineRecordDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientMedicineRecord) replaceDB(db *gorm.DB) patientMedicineRecord { + p.patientMedicineRecordDo.ReplaceDB(db) + return p +} + +type patientMedicineRecordDo struct{ gen.DO } + +func (p patientMedicineRecordDo) Debug() *patientMedicineRecordDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientMedicineRecordDo) WithContext(ctx context.Context) *patientMedicineRecordDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientMedicineRecordDo) ReadDB() *patientMedicineRecordDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientMedicineRecordDo) WriteDB() *patientMedicineRecordDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientMedicineRecordDo) Session(config *gorm.Session) *patientMedicineRecordDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientMedicineRecordDo) Clauses(conds ...clause.Expression) *patientMedicineRecordDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientMedicineRecordDo) Returning(value interface{}, columns ...string) *patientMedicineRecordDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientMedicineRecordDo) Not(conds ...gen.Condition) *patientMedicineRecordDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientMedicineRecordDo) Or(conds ...gen.Condition) *patientMedicineRecordDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientMedicineRecordDo) Select(conds ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientMedicineRecordDo) Where(conds ...gen.Condition) *patientMedicineRecordDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientMedicineRecordDo) Order(conds ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientMedicineRecordDo) Distinct(cols ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientMedicineRecordDo) Omit(cols ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientMedicineRecordDo) Join(table schema.Tabler, on ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientMedicineRecordDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientMedicineRecordDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientMedicineRecordDo) Group(cols ...field.Expr) *patientMedicineRecordDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientMedicineRecordDo) Having(conds ...gen.Condition) *patientMedicineRecordDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientMedicineRecordDo) Limit(limit int) *patientMedicineRecordDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientMedicineRecordDo) Offset(offset int) *patientMedicineRecordDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientMedicineRecordDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientMedicineRecordDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientMedicineRecordDo) Unscoped() *patientMedicineRecordDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientMedicineRecordDo) Create(values ...*model.PatientMedicineRecord) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientMedicineRecordDo) CreateInBatches(values []*model.PatientMedicineRecord, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientMedicineRecordDo) Save(values ...*model.PatientMedicineRecord) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientMedicineRecordDo) First() (*model.PatientMedicineRecord, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineRecord), nil + } +} + +func (p patientMedicineRecordDo) Take() (*model.PatientMedicineRecord, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineRecord), nil + } +} + +func (p patientMedicineRecordDo) Last() (*model.PatientMedicineRecord, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineRecord), nil + } +} + +func (p patientMedicineRecordDo) Find() ([]*model.PatientMedicineRecord, error) { + result, err := p.DO.Find() + return result.([]*model.PatientMedicineRecord), err +} + +func (p patientMedicineRecordDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientMedicineRecord, err error) { + buf := make([]*model.PatientMedicineRecord, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientMedicineRecordDo) FindInBatches(result *[]*model.PatientMedicineRecord, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientMedicineRecordDo) Attrs(attrs ...field.AssignExpr) *patientMedicineRecordDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientMedicineRecordDo) Assign(attrs ...field.AssignExpr) *patientMedicineRecordDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientMedicineRecordDo) Joins(fields ...field.RelationField) *patientMedicineRecordDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientMedicineRecordDo) Preload(fields ...field.RelationField) *patientMedicineRecordDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientMedicineRecordDo) FirstOrInit() (*model.PatientMedicineRecord, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineRecord), nil + } +} + +func (p patientMedicineRecordDo) FirstOrCreate() (*model.PatientMedicineRecord, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineRecord), nil + } +} + +func (p patientMedicineRecordDo) FindByPage(offset int, limit int) (result []*model.PatientMedicineRecord, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientMedicineRecordDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientMedicineRecordDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientMedicineRecordDo) Delete(models ...*model.PatientMedicineRecord) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientMedicineRecordDo) withDO(do gen.Dao) *patientMedicineRecordDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_medicine_scheme.gen.go b/internal/repository/mysql/dao/patient_medicine_scheme.gen.go new file mode 100644 index 0000000..d3fa4a7 --- /dev/null +++ b/internal/repository/mysql/dao/patient_medicine_scheme.gen.go @@ -0,0 +1,356 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientMedicineScheme(db *gorm.DB, opts ...gen.DOOption) patientMedicineScheme { + _patientMedicineScheme := patientMedicineScheme{} + + _patientMedicineScheme.patientMedicineSchemeDo.UseDB(db, opts...) + _patientMedicineScheme.patientMedicineSchemeDo.UseModel(&model.PatientMedicineScheme{}) + + tableName := _patientMedicineScheme.patientMedicineSchemeDo.TableName() + _patientMedicineScheme.ALL = field.NewAsterisk(tableName) + _patientMedicineScheme.ID = field.NewInt32(tableName, "id") + _patientMedicineScheme.PatientID = field.NewInt32(tableName, "patient_id") + _patientMedicineScheme.StartDate = field.NewTime(tableName, "start_date") + _patientMedicineScheme.EndDate = field.NewTime(tableName, "end_date") + _patientMedicineScheme.Detail = field.NewString(tableName, "detail") + _patientMedicineScheme.Reminder = field.NewString(tableName, "reminder") + _patientMedicineScheme.CreatedUser = field.NewString(tableName, "created_user") + _patientMedicineScheme.CreatedAt = field.NewTime(tableName, "created_at") + _patientMedicineScheme.UpdatedUser = field.NewString(tableName, "updated_user") + _patientMedicineScheme.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientMedicineScheme.fillFieldMap() + + return _patientMedicineScheme +} + +// patientMedicineScheme 患者用药方案表 +type patientMedicineScheme struct { + patientMedicineSchemeDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PatientID field.Int32 // 患者ID + StartDate field.Time // 用药开始日期 + EndDate field.Time // 用药结束日期 + Detail field.String // 药品信息(JSON格式) + Reminder field.String // 用药提醒(JSON格式) + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientMedicineScheme) Table(newTableName string) *patientMedicineScheme { + p.patientMedicineSchemeDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientMedicineScheme) As(alias string) *patientMedicineScheme { + p.patientMedicineSchemeDo.DO = *(p.patientMedicineSchemeDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientMedicineScheme) updateTableName(table string) *patientMedicineScheme { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.PatientID = field.NewInt32(table, "patient_id") + p.StartDate = field.NewTime(table, "start_date") + p.EndDate = field.NewTime(table, "end_date") + p.Detail = field.NewString(table, "detail") + p.Reminder = field.NewString(table, "reminder") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientMedicineScheme) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientMedicineScheme) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 10) + p.fieldMap["id"] = p.ID + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["start_date"] = p.StartDate + p.fieldMap["end_date"] = p.EndDate + p.fieldMap["detail"] = p.Detail + p.fieldMap["reminder"] = p.Reminder + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientMedicineScheme) clone(db *gorm.DB) patientMedicineScheme { + p.patientMedicineSchemeDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientMedicineScheme) replaceDB(db *gorm.DB) patientMedicineScheme { + p.patientMedicineSchemeDo.ReplaceDB(db) + return p +} + +type patientMedicineSchemeDo struct{ gen.DO } + +func (p patientMedicineSchemeDo) Debug() *patientMedicineSchemeDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientMedicineSchemeDo) WithContext(ctx context.Context) *patientMedicineSchemeDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientMedicineSchemeDo) ReadDB() *patientMedicineSchemeDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientMedicineSchemeDo) WriteDB() *patientMedicineSchemeDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientMedicineSchemeDo) Session(config *gorm.Session) *patientMedicineSchemeDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientMedicineSchemeDo) Clauses(conds ...clause.Expression) *patientMedicineSchemeDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientMedicineSchemeDo) Returning(value interface{}, columns ...string) *patientMedicineSchemeDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientMedicineSchemeDo) Not(conds ...gen.Condition) *patientMedicineSchemeDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientMedicineSchemeDo) Or(conds ...gen.Condition) *patientMedicineSchemeDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientMedicineSchemeDo) Select(conds ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientMedicineSchemeDo) Where(conds ...gen.Condition) *patientMedicineSchemeDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientMedicineSchemeDo) Order(conds ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientMedicineSchemeDo) Distinct(cols ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientMedicineSchemeDo) Omit(cols ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientMedicineSchemeDo) Join(table schema.Tabler, on ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientMedicineSchemeDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientMedicineSchemeDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientMedicineSchemeDo) Group(cols ...field.Expr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientMedicineSchemeDo) Having(conds ...gen.Condition) *patientMedicineSchemeDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientMedicineSchemeDo) Limit(limit int) *patientMedicineSchemeDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientMedicineSchemeDo) Offset(offset int) *patientMedicineSchemeDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientMedicineSchemeDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientMedicineSchemeDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientMedicineSchemeDo) Unscoped() *patientMedicineSchemeDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientMedicineSchemeDo) Create(values ...*model.PatientMedicineScheme) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientMedicineSchemeDo) CreateInBatches(values []*model.PatientMedicineScheme, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientMedicineSchemeDo) Save(values ...*model.PatientMedicineScheme) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientMedicineSchemeDo) First() (*model.PatientMedicineScheme, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineScheme), nil + } +} + +func (p patientMedicineSchemeDo) Take() (*model.PatientMedicineScheme, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineScheme), nil + } +} + +func (p patientMedicineSchemeDo) Last() (*model.PatientMedicineScheme, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineScheme), nil + } +} + +func (p patientMedicineSchemeDo) Find() ([]*model.PatientMedicineScheme, error) { + result, err := p.DO.Find() + return result.([]*model.PatientMedicineScheme), err +} + +func (p patientMedicineSchemeDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientMedicineScheme, err error) { + buf := make([]*model.PatientMedicineScheme, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientMedicineSchemeDo) FindInBatches(result *[]*model.PatientMedicineScheme, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientMedicineSchemeDo) Attrs(attrs ...field.AssignExpr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientMedicineSchemeDo) Assign(attrs ...field.AssignExpr) *patientMedicineSchemeDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientMedicineSchemeDo) Joins(fields ...field.RelationField) *patientMedicineSchemeDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientMedicineSchemeDo) Preload(fields ...field.RelationField) *patientMedicineSchemeDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientMedicineSchemeDo) FirstOrInit() (*model.PatientMedicineScheme, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineScheme), nil + } +} + +func (p patientMedicineSchemeDo) FirstOrCreate() (*model.PatientMedicineScheme, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineScheme), nil + } +} + +func (p patientMedicineSchemeDo) FindByPage(offset int, limit int) (result []*model.PatientMedicineScheme, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientMedicineSchemeDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientMedicineSchemeDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientMedicineSchemeDo) Delete(models ...*model.PatientMedicineScheme) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientMedicineSchemeDo) withDO(do gen.Dao) *patientMedicineSchemeDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/patient_medicine_task.gen.go b/internal/repository/mysql/dao/patient_medicine_task.gen.go new file mode 100644 index 0000000..6415cb1 --- /dev/null +++ b/internal/repository/mysql/dao/patient_medicine_task.gen.go @@ -0,0 +1,376 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newPatientMedicineTask(db *gorm.DB, opts ...gen.DOOption) patientMedicineTask { + _patientMedicineTask := patientMedicineTask{} + + _patientMedicineTask.patientMedicineTaskDo.UseDB(db, opts...) + _patientMedicineTask.patientMedicineTaskDo.UseModel(&model.PatientMedicineTask{}) + + tableName := _patientMedicineTask.patientMedicineTaskDo.TableName() + _patientMedicineTask.ALL = field.NewAsterisk(tableName) + _patientMedicineTask.ID = field.NewInt32(tableName, "id") + _patientMedicineTask.Code = field.NewString(tableName, "code") + _patientMedicineTask.Title = field.NewString(tableName, "title") + _patientMedicineTask.Spec = field.NewString(tableName, "spec") + _patientMedicineTask.Status = field.NewInt32(tableName, "status") + _patientMedicineTask.IsRunning = field.NewInt32(tableName, "is_running") + _patientMedicineTask.RunTime = field.NewTime(tableName, "run_time") + _patientMedicineTask.RunStartTime = field.NewTime(tableName, "run_start_time") + _patientMedicineTask.RunEndTime = field.NewTime(tableName, "run_end_time") + _patientMedicineTask.PatientID = field.NewInt32(tableName, "patient_id") + _patientMedicineTask.MedicineRecordID = field.NewInt32(tableName, "medicine_record_id") + _patientMedicineTask.CreatedUser = field.NewString(tableName, "created_user") + _patientMedicineTask.CreatedAt = field.NewTime(tableName, "created_at") + _patientMedicineTask.UpdatedUser = field.NewString(tableName, "updated_user") + _patientMedicineTask.UpdatedAt = field.NewTime(tableName, "updated_at") + + _patientMedicineTask.fillFieldMap() + + return _patientMedicineTask +} + +// patientMedicineTask 患者用药提醒(任务)表 +type patientMedicineTask struct { + patientMedicineTaskDo + + ALL field.Asterisk + ID field.Int32 // 主键ID + Code field.String // 任务编码 + Title field.String // 标题 + Spec field.String // 时间表达式 + Status field.Int32 // 状态(1:禁用 2:启用) + IsRunning field.Int32 // 执行中(0:未执行 1:执行中 2:执行完毕) + RunTime field.Time // 预期执行时间 + RunStartTime field.Time // 执行开始时间 + RunEndTime field.Time // 执行结束时间 + PatientID field.Int32 // 患者ID + MedicineRecordID field.Int32 // 用药记录ID + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (p patientMedicineTask) Table(newTableName string) *patientMedicineTask { + p.patientMedicineTaskDo.UseTable(newTableName) + return p.updateTableName(newTableName) +} + +func (p patientMedicineTask) As(alias string) *patientMedicineTask { + p.patientMedicineTaskDo.DO = *(p.patientMedicineTaskDo.As(alias).(*gen.DO)) + return p.updateTableName(alias) +} + +func (p *patientMedicineTask) updateTableName(table string) *patientMedicineTask { + p.ALL = field.NewAsterisk(table) + p.ID = field.NewInt32(table, "id") + p.Code = field.NewString(table, "code") + p.Title = field.NewString(table, "title") + p.Spec = field.NewString(table, "spec") + p.Status = field.NewInt32(table, "status") + p.IsRunning = field.NewInt32(table, "is_running") + p.RunTime = field.NewTime(table, "run_time") + p.RunStartTime = field.NewTime(table, "run_start_time") + p.RunEndTime = field.NewTime(table, "run_end_time") + p.PatientID = field.NewInt32(table, "patient_id") + p.MedicineRecordID = field.NewInt32(table, "medicine_record_id") + p.CreatedUser = field.NewString(table, "created_user") + p.CreatedAt = field.NewTime(table, "created_at") + p.UpdatedUser = field.NewString(table, "updated_user") + p.UpdatedAt = field.NewTime(table, "updated_at") + + p.fillFieldMap() + + return p +} + +func (p *patientMedicineTask) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := p.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (p *patientMedicineTask) fillFieldMap() { + p.fieldMap = make(map[string]field.Expr, 15) + p.fieldMap["id"] = p.ID + p.fieldMap["code"] = p.Code + p.fieldMap["title"] = p.Title + p.fieldMap["spec"] = p.Spec + p.fieldMap["status"] = p.Status + p.fieldMap["is_running"] = p.IsRunning + p.fieldMap["run_time"] = p.RunTime + p.fieldMap["run_start_time"] = p.RunStartTime + p.fieldMap["run_end_time"] = p.RunEndTime + p.fieldMap["patient_id"] = p.PatientID + p.fieldMap["medicine_record_id"] = p.MedicineRecordID + p.fieldMap["created_user"] = p.CreatedUser + p.fieldMap["created_at"] = p.CreatedAt + p.fieldMap["updated_user"] = p.UpdatedUser + p.fieldMap["updated_at"] = p.UpdatedAt +} + +func (p patientMedicineTask) clone(db *gorm.DB) patientMedicineTask { + p.patientMedicineTaskDo.ReplaceConnPool(db.Statement.ConnPool) + return p +} + +func (p patientMedicineTask) replaceDB(db *gorm.DB) patientMedicineTask { + p.patientMedicineTaskDo.ReplaceDB(db) + return p +} + +type patientMedicineTaskDo struct{ gen.DO } + +func (p patientMedicineTaskDo) Debug() *patientMedicineTaskDo { + return p.withDO(p.DO.Debug()) +} + +func (p patientMedicineTaskDo) WithContext(ctx context.Context) *patientMedicineTaskDo { + return p.withDO(p.DO.WithContext(ctx)) +} + +func (p patientMedicineTaskDo) ReadDB() *patientMedicineTaskDo { + return p.Clauses(dbresolver.Read) +} + +func (p patientMedicineTaskDo) WriteDB() *patientMedicineTaskDo { + return p.Clauses(dbresolver.Write) +} + +func (p patientMedicineTaskDo) Session(config *gorm.Session) *patientMedicineTaskDo { + return p.withDO(p.DO.Session(config)) +} + +func (p patientMedicineTaskDo) Clauses(conds ...clause.Expression) *patientMedicineTaskDo { + return p.withDO(p.DO.Clauses(conds...)) +} + +func (p patientMedicineTaskDo) Returning(value interface{}, columns ...string) *patientMedicineTaskDo { + return p.withDO(p.DO.Returning(value, columns...)) +} + +func (p patientMedicineTaskDo) Not(conds ...gen.Condition) *patientMedicineTaskDo { + return p.withDO(p.DO.Not(conds...)) +} + +func (p patientMedicineTaskDo) Or(conds ...gen.Condition) *patientMedicineTaskDo { + return p.withDO(p.DO.Or(conds...)) +} + +func (p patientMedicineTaskDo) Select(conds ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Select(conds...)) +} + +func (p patientMedicineTaskDo) Where(conds ...gen.Condition) *patientMedicineTaskDo { + return p.withDO(p.DO.Where(conds...)) +} + +func (p patientMedicineTaskDo) Order(conds ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Order(conds...)) +} + +func (p patientMedicineTaskDo) Distinct(cols ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Distinct(cols...)) +} + +func (p patientMedicineTaskDo) Omit(cols ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Omit(cols...)) +} + +func (p patientMedicineTaskDo) Join(table schema.Tabler, on ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Join(table, on...)) +} + +func (p patientMedicineTaskDo) LeftJoin(table schema.Tabler, on ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.LeftJoin(table, on...)) +} + +func (p patientMedicineTaskDo) RightJoin(table schema.Tabler, on ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.RightJoin(table, on...)) +} + +func (p patientMedicineTaskDo) Group(cols ...field.Expr) *patientMedicineTaskDo { + return p.withDO(p.DO.Group(cols...)) +} + +func (p patientMedicineTaskDo) Having(conds ...gen.Condition) *patientMedicineTaskDo { + return p.withDO(p.DO.Having(conds...)) +} + +func (p patientMedicineTaskDo) Limit(limit int) *patientMedicineTaskDo { + return p.withDO(p.DO.Limit(limit)) +} + +func (p patientMedicineTaskDo) Offset(offset int) *patientMedicineTaskDo { + return p.withDO(p.DO.Offset(offset)) +} + +func (p patientMedicineTaskDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *patientMedicineTaskDo { + return p.withDO(p.DO.Scopes(funcs...)) +} + +func (p patientMedicineTaskDo) Unscoped() *patientMedicineTaskDo { + return p.withDO(p.DO.Unscoped()) +} + +func (p patientMedicineTaskDo) Create(values ...*model.PatientMedicineTask) error { + if len(values) == 0 { + return nil + } + return p.DO.Create(values) +} + +func (p patientMedicineTaskDo) CreateInBatches(values []*model.PatientMedicineTask, batchSize int) error { + return p.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (p patientMedicineTaskDo) Save(values ...*model.PatientMedicineTask) error { + if len(values) == 0 { + return nil + } + return p.DO.Save(values) +} + +func (p patientMedicineTaskDo) First() (*model.PatientMedicineTask, error) { + if result, err := p.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineTask), nil + } +} + +func (p patientMedicineTaskDo) Take() (*model.PatientMedicineTask, error) { + if result, err := p.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineTask), nil + } +} + +func (p patientMedicineTaskDo) Last() (*model.PatientMedicineTask, error) { + if result, err := p.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineTask), nil + } +} + +func (p patientMedicineTaskDo) Find() ([]*model.PatientMedicineTask, error) { + result, err := p.DO.Find() + return result.([]*model.PatientMedicineTask), err +} + +func (p patientMedicineTaskDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PatientMedicineTask, err error) { + buf := make([]*model.PatientMedicineTask, 0, batchSize) + err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (p patientMedicineTaskDo) FindInBatches(result *[]*model.PatientMedicineTask, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return p.DO.FindInBatches(result, batchSize, fc) +} + +func (p patientMedicineTaskDo) Attrs(attrs ...field.AssignExpr) *patientMedicineTaskDo { + return p.withDO(p.DO.Attrs(attrs...)) +} + +func (p patientMedicineTaskDo) Assign(attrs ...field.AssignExpr) *patientMedicineTaskDo { + return p.withDO(p.DO.Assign(attrs...)) +} + +func (p patientMedicineTaskDo) Joins(fields ...field.RelationField) *patientMedicineTaskDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Joins(_f)) + } + return &p +} + +func (p patientMedicineTaskDo) Preload(fields ...field.RelationField) *patientMedicineTaskDo { + for _, _f := range fields { + p = *p.withDO(p.DO.Preload(_f)) + } + return &p +} + +func (p patientMedicineTaskDo) FirstOrInit() (*model.PatientMedicineTask, error) { + if result, err := p.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineTask), nil + } +} + +func (p patientMedicineTaskDo) FirstOrCreate() (*model.PatientMedicineTask, error) { + if result, err := p.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.PatientMedicineTask), nil + } +} + +func (p patientMedicineTaskDo) FindByPage(offset int, limit int) (result []*model.PatientMedicineTask, count int64, err error) { + result, err = p.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = p.Offset(-1).Limit(-1).Count() + return +} + +func (p patientMedicineTaskDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = p.Count() + if err != nil { + return + } + + err = p.Offset(offset).Limit(limit).Scan(result) + return +} + +func (p patientMedicineTaskDo) Scan(result interface{}) (err error) { + return p.DO.Scan(result) +} + +func (p patientMedicineTaskDo) Delete(models ...*model.PatientMedicineTask) (result gen.ResultInfo, err error) { + return p.DO.Delete(models) +} + +func (p *patientMedicineTaskDo) withDO(do gen.Dao) *patientMedicineTaskDo { + p.DO = *do.(*gen.DO) + return p +} diff --git a/internal/repository/mysql/dao/sms_verification_code.gen.go b/internal/repository/mysql/dao/sms_verification_code.gen.go new file mode 100644 index 0000000..f51313e --- /dev/null +++ b/internal/repository/mysql/dao/sms_verification_code.gen.go @@ -0,0 +1,344 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newSmsVerificationCode(db *gorm.DB, opts ...gen.DOOption) smsVerificationCode { + _smsVerificationCode := smsVerificationCode{} + + _smsVerificationCode.smsVerificationCodeDo.UseDB(db, opts...) + _smsVerificationCode.smsVerificationCodeDo.UseModel(&model.SmsVerificationCode{}) + + tableName := _smsVerificationCode.smsVerificationCodeDo.TableName() + _smsVerificationCode.ALL = field.NewAsterisk(tableName) + _smsVerificationCode.ID = field.NewInt32(tableName, "id") + _smsVerificationCode.PhoneNumber = field.NewString(tableName, "phone_number") + _smsVerificationCode.VerificationCode = field.NewString(tableName, "verification_code") + _smsVerificationCode.Type = field.NewInt32(tableName, "type") + _smsVerificationCode.IsUsed = field.NewInt32(tableName, "is_used") + _smsVerificationCode.CreatedUser = field.NewString(tableName, "created_user") + _smsVerificationCode.CreatedAt = field.NewTime(tableName, "created_at") + + _smsVerificationCode.fillFieldMap() + + return _smsVerificationCode +} + +// smsVerificationCode 短信验证码表 +type smsVerificationCode struct { + smsVerificationCodeDo + + ALL field.Asterisk + ID field.Int32 // 主键 + PhoneNumber field.String // 手机号码 + VerificationCode field.String // 验证码 + Type field.Int32 // 类型(1=登录 2=忘记密码) + IsUsed field.Int32 // 是否已使用(0:未使用,1:已使用) + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + + fieldMap map[string]field.Expr +} + +func (s smsVerificationCode) Table(newTableName string) *smsVerificationCode { + s.smsVerificationCodeDo.UseTable(newTableName) + return s.updateTableName(newTableName) +} + +func (s smsVerificationCode) As(alias string) *smsVerificationCode { + s.smsVerificationCodeDo.DO = *(s.smsVerificationCodeDo.As(alias).(*gen.DO)) + return s.updateTableName(alias) +} + +func (s *smsVerificationCode) updateTableName(table string) *smsVerificationCode { + s.ALL = field.NewAsterisk(table) + s.ID = field.NewInt32(table, "id") + s.PhoneNumber = field.NewString(table, "phone_number") + s.VerificationCode = field.NewString(table, "verification_code") + s.Type = field.NewInt32(table, "type") + s.IsUsed = field.NewInt32(table, "is_used") + s.CreatedUser = field.NewString(table, "created_user") + s.CreatedAt = field.NewTime(table, "created_at") + + s.fillFieldMap() + + return s +} + +func (s *smsVerificationCode) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := s.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (s *smsVerificationCode) fillFieldMap() { + s.fieldMap = make(map[string]field.Expr, 7) + s.fieldMap["id"] = s.ID + s.fieldMap["phone_number"] = s.PhoneNumber + s.fieldMap["verification_code"] = s.VerificationCode + s.fieldMap["type"] = s.Type + s.fieldMap["is_used"] = s.IsUsed + s.fieldMap["created_user"] = s.CreatedUser + s.fieldMap["created_at"] = s.CreatedAt +} + +func (s smsVerificationCode) clone(db *gorm.DB) smsVerificationCode { + s.smsVerificationCodeDo.ReplaceConnPool(db.Statement.ConnPool) + return s +} + +func (s smsVerificationCode) replaceDB(db *gorm.DB) smsVerificationCode { + s.smsVerificationCodeDo.ReplaceDB(db) + return s +} + +type smsVerificationCodeDo struct{ gen.DO } + +func (s smsVerificationCodeDo) Debug() *smsVerificationCodeDo { + return s.withDO(s.DO.Debug()) +} + +func (s smsVerificationCodeDo) WithContext(ctx context.Context) *smsVerificationCodeDo { + return s.withDO(s.DO.WithContext(ctx)) +} + +func (s smsVerificationCodeDo) ReadDB() *smsVerificationCodeDo { + return s.Clauses(dbresolver.Read) +} + +func (s smsVerificationCodeDo) WriteDB() *smsVerificationCodeDo { + return s.Clauses(dbresolver.Write) +} + +func (s smsVerificationCodeDo) Session(config *gorm.Session) *smsVerificationCodeDo { + return s.withDO(s.DO.Session(config)) +} + +func (s smsVerificationCodeDo) Clauses(conds ...clause.Expression) *smsVerificationCodeDo { + return s.withDO(s.DO.Clauses(conds...)) +} + +func (s smsVerificationCodeDo) Returning(value interface{}, columns ...string) *smsVerificationCodeDo { + return s.withDO(s.DO.Returning(value, columns...)) +} + +func (s smsVerificationCodeDo) Not(conds ...gen.Condition) *smsVerificationCodeDo { + return s.withDO(s.DO.Not(conds...)) +} + +func (s smsVerificationCodeDo) Or(conds ...gen.Condition) *smsVerificationCodeDo { + return s.withDO(s.DO.Or(conds...)) +} + +func (s smsVerificationCodeDo) Select(conds ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Select(conds...)) +} + +func (s smsVerificationCodeDo) Where(conds ...gen.Condition) *smsVerificationCodeDo { + return s.withDO(s.DO.Where(conds...)) +} + +func (s smsVerificationCodeDo) Order(conds ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Order(conds...)) +} + +func (s smsVerificationCodeDo) Distinct(cols ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Distinct(cols...)) +} + +func (s smsVerificationCodeDo) Omit(cols ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Omit(cols...)) +} + +func (s smsVerificationCodeDo) Join(table schema.Tabler, on ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Join(table, on...)) +} + +func (s smsVerificationCodeDo) LeftJoin(table schema.Tabler, on ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.LeftJoin(table, on...)) +} + +func (s smsVerificationCodeDo) RightJoin(table schema.Tabler, on ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.RightJoin(table, on...)) +} + +func (s smsVerificationCodeDo) Group(cols ...field.Expr) *smsVerificationCodeDo { + return s.withDO(s.DO.Group(cols...)) +} + +func (s smsVerificationCodeDo) Having(conds ...gen.Condition) *smsVerificationCodeDo { + return s.withDO(s.DO.Having(conds...)) +} + +func (s smsVerificationCodeDo) Limit(limit int) *smsVerificationCodeDo { + return s.withDO(s.DO.Limit(limit)) +} + +func (s smsVerificationCodeDo) Offset(offset int) *smsVerificationCodeDo { + return s.withDO(s.DO.Offset(offset)) +} + +func (s smsVerificationCodeDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *smsVerificationCodeDo { + return s.withDO(s.DO.Scopes(funcs...)) +} + +func (s smsVerificationCodeDo) Unscoped() *smsVerificationCodeDo { + return s.withDO(s.DO.Unscoped()) +} + +func (s smsVerificationCodeDo) Create(values ...*model.SmsVerificationCode) error { + if len(values) == 0 { + return nil + } + return s.DO.Create(values) +} + +func (s smsVerificationCodeDo) CreateInBatches(values []*model.SmsVerificationCode, batchSize int) error { + return s.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (s smsVerificationCodeDo) Save(values ...*model.SmsVerificationCode) error { + if len(values) == 0 { + return nil + } + return s.DO.Save(values) +} + +func (s smsVerificationCodeDo) First() (*model.SmsVerificationCode, error) { + if result, err := s.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.SmsVerificationCode), nil + } +} + +func (s smsVerificationCodeDo) Take() (*model.SmsVerificationCode, error) { + if result, err := s.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.SmsVerificationCode), nil + } +} + +func (s smsVerificationCodeDo) Last() (*model.SmsVerificationCode, error) { + if result, err := s.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.SmsVerificationCode), nil + } +} + +func (s smsVerificationCodeDo) Find() ([]*model.SmsVerificationCode, error) { + result, err := s.DO.Find() + return result.([]*model.SmsVerificationCode), err +} + +func (s smsVerificationCodeDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.SmsVerificationCode, err error) { + buf := make([]*model.SmsVerificationCode, 0, batchSize) + err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (s smsVerificationCodeDo) FindInBatches(result *[]*model.SmsVerificationCode, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return s.DO.FindInBatches(result, batchSize, fc) +} + +func (s smsVerificationCodeDo) Attrs(attrs ...field.AssignExpr) *smsVerificationCodeDo { + return s.withDO(s.DO.Attrs(attrs...)) +} + +func (s smsVerificationCodeDo) Assign(attrs ...field.AssignExpr) *smsVerificationCodeDo { + return s.withDO(s.DO.Assign(attrs...)) +} + +func (s smsVerificationCodeDo) Joins(fields ...field.RelationField) *smsVerificationCodeDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Joins(_f)) + } + return &s +} + +func (s smsVerificationCodeDo) Preload(fields ...field.RelationField) *smsVerificationCodeDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Preload(_f)) + } + return &s +} + +func (s smsVerificationCodeDo) FirstOrInit() (*model.SmsVerificationCode, error) { + if result, err := s.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.SmsVerificationCode), nil + } +} + +func (s smsVerificationCodeDo) FirstOrCreate() (*model.SmsVerificationCode, error) { + if result, err := s.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.SmsVerificationCode), nil + } +} + +func (s smsVerificationCodeDo) FindByPage(offset int, limit int) (result []*model.SmsVerificationCode, count int64, err error) { + result, err = s.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = s.Offset(-1).Limit(-1).Count() + return +} + +func (s smsVerificationCodeDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = s.Count() + if err != nil { + return + } + + err = s.Offset(offset).Limit(limit).Scan(result) + return +} + +func (s smsVerificationCodeDo) Scan(result interface{}) (err error) { + return s.DO.Scan(result) +} + +func (s smsVerificationCodeDo) Delete(models ...*model.SmsVerificationCode) (result gen.ResultInfo, err error) { + return s.DO.Delete(models) +} + +func (s *smsVerificationCodeDo) withDO(do gen.Dao) *smsVerificationCodeDo { + s.DO = *do.(*gen.DO) + return s +} diff --git a/internal/repository/mysql/dao/symptom.gen.go b/internal/repository/mysql/dao/symptom.gen.go new file mode 100644 index 0000000..1f64f6a --- /dev/null +++ b/internal/repository/mysql/dao/symptom.gen.go @@ -0,0 +1,344 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" + + "mini-chat/internal/repository/mysql/model" +) + +func newSymptom(db *gorm.DB, opts ...gen.DOOption) symptom { + _symptom := symptom{} + + _symptom.symptomDo.UseDB(db, opts...) + _symptom.symptomDo.UseModel(&model.Symptom{}) + + tableName := _symptom.symptomDo.TableName() + _symptom.ALL = field.NewAsterisk(tableName) + _symptom.ID = field.NewInt32(tableName, "id") + _symptom.Title = field.NewString(tableName, "title") + _symptom.Description = field.NewString(tableName, "description") + _symptom.CreatedUser = field.NewString(tableName, "created_user") + _symptom.CreatedAt = field.NewTime(tableName, "created_at") + _symptom.UpdatedUser = field.NewString(tableName, "updated_user") + _symptom.UpdatedAt = field.NewTime(tableName, "updated_at") + + _symptom.fillFieldMap() + + return _symptom +} + +// symptom 症状表 +type symptom struct { + symptomDo + + ALL field.Asterisk + ID field.Int32 // 主键 + Title field.String // 症状 + Description field.String // 描述 + CreatedUser field.String // 创建人 + CreatedAt field.Time // 创建时间 + UpdatedUser field.String // 更新人 + UpdatedAt field.Time // 更新时间 + + fieldMap map[string]field.Expr +} + +func (s symptom) Table(newTableName string) *symptom { + s.symptomDo.UseTable(newTableName) + return s.updateTableName(newTableName) +} + +func (s symptom) As(alias string) *symptom { + s.symptomDo.DO = *(s.symptomDo.As(alias).(*gen.DO)) + return s.updateTableName(alias) +} + +func (s *symptom) updateTableName(table string) *symptom { + s.ALL = field.NewAsterisk(table) + s.ID = field.NewInt32(table, "id") + s.Title = field.NewString(table, "title") + s.Description = field.NewString(table, "description") + s.CreatedUser = field.NewString(table, "created_user") + s.CreatedAt = field.NewTime(table, "created_at") + s.UpdatedUser = field.NewString(table, "updated_user") + s.UpdatedAt = field.NewTime(table, "updated_at") + + s.fillFieldMap() + + return s +} + +func (s *symptom) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := s.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (s *symptom) fillFieldMap() { + s.fieldMap = make(map[string]field.Expr, 7) + s.fieldMap["id"] = s.ID + s.fieldMap["title"] = s.Title + s.fieldMap["description"] = s.Description + s.fieldMap["created_user"] = s.CreatedUser + s.fieldMap["created_at"] = s.CreatedAt + s.fieldMap["updated_user"] = s.UpdatedUser + s.fieldMap["updated_at"] = s.UpdatedAt +} + +func (s symptom) clone(db *gorm.DB) symptom { + s.symptomDo.ReplaceConnPool(db.Statement.ConnPool) + return s +} + +func (s symptom) replaceDB(db *gorm.DB) symptom { + s.symptomDo.ReplaceDB(db) + return s +} + +type symptomDo struct{ gen.DO } + +func (s symptomDo) Debug() *symptomDo { + return s.withDO(s.DO.Debug()) +} + +func (s symptomDo) WithContext(ctx context.Context) *symptomDo { + return s.withDO(s.DO.WithContext(ctx)) +} + +func (s symptomDo) ReadDB() *symptomDo { + return s.Clauses(dbresolver.Read) +} + +func (s symptomDo) WriteDB() *symptomDo { + return s.Clauses(dbresolver.Write) +} + +func (s symptomDo) Session(config *gorm.Session) *symptomDo { + return s.withDO(s.DO.Session(config)) +} + +func (s symptomDo) Clauses(conds ...clause.Expression) *symptomDo { + return s.withDO(s.DO.Clauses(conds...)) +} + +func (s symptomDo) Returning(value interface{}, columns ...string) *symptomDo { + return s.withDO(s.DO.Returning(value, columns...)) +} + +func (s symptomDo) Not(conds ...gen.Condition) *symptomDo { + return s.withDO(s.DO.Not(conds...)) +} + +func (s symptomDo) Or(conds ...gen.Condition) *symptomDo { + return s.withDO(s.DO.Or(conds...)) +} + +func (s symptomDo) Select(conds ...field.Expr) *symptomDo { + return s.withDO(s.DO.Select(conds...)) +} + +func (s symptomDo) Where(conds ...gen.Condition) *symptomDo { + return s.withDO(s.DO.Where(conds...)) +} + +func (s symptomDo) Order(conds ...field.Expr) *symptomDo { + return s.withDO(s.DO.Order(conds...)) +} + +func (s symptomDo) Distinct(cols ...field.Expr) *symptomDo { + return s.withDO(s.DO.Distinct(cols...)) +} + +func (s symptomDo) Omit(cols ...field.Expr) *symptomDo { + return s.withDO(s.DO.Omit(cols...)) +} + +func (s symptomDo) Join(table schema.Tabler, on ...field.Expr) *symptomDo { + return s.withDO(s.DO.Join(table, on...)) +} + +func (s symptomDo) LeftJoin(table schema.Tabler, on ...field.Expr) *symptomDo { + return s.withDO(s.DO.LeftJoin(table, on...)) +} + +func (s symptomDo) RightJoin(table schema.Tabler, on ...field.Expr) *symptomDo { + return s.withDO(s.DO.RightJoin(table, on...)) +} + +func (s symptomDo) Group(cols ...field.Expr) *symptomDo { + return s.withDO(s.DO.Group(cols...)) +} + +func (s symptomDo) Having(conds ...gen.Condition) *symptomDo { + return s.withDO(s.DO.Having(conds...)) +} + +func (s symptomDo) Limit(limit int) *symptomDo { + return s.withDO(s.DO.Limit(limit)) +} + +func (s symptomDo) Offset(offset int) *symptomDo { + return s.withDO(s.DO.Offset(offset)) +} + +func (s symptomDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *symptomDo { + return s.withDO(s.DO.Scopes(funcs...)) +} + +func (s symptomDo) Unscoped() *symptomDo { + return s.withDO(s.DO.Unscoped()) +} + +func (s symptomDo) Create(values ...*model.Symptom) error { + if len(values) == 0 { + return nil + } + return s.DO.Create(values) +} + +func (s symptomDo) CreateInBatches(values []*model.Symptom, batchSize int) error { + return s.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (s symptomDo) Save(values ...*model.Symptom) error { + if len(values) == 0 { + return nil + } + return s.DO.Save(values) +} + +func (s symptomDo) First() (*model.Symptom, error) { + if result, err := s.DO.First(); err != nil { + return nil, err + } else { + return result.(*model.Symptom), nil + } +} + +func (s symptomDo) Take() (*model.Symptom, error) { + if result, err := s.DO.Take(); err != nil { + return nil, err + } else { + return result.(*model.Symptom), nil + } +} + +func (s symptomDo) Last() (*model.Symptom, error) { + if result, err := s.DO.Last(); err != nil { + return nil, err + } else { + return result.(*model.Symptom), nil + } +} + +func (s symptomDo) Find() ([]*model.Symptom, error) { + result, err := s.DO.Find() + return result.([]*model.Symptom), err +} + +func (s symptomDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Symptom, err error) { + buf := make([]*model.Symptom, 0, batchSize) + err = s.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (s symptomDo) FindInBatches(result *[]*model.Symptom, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return s.DO.FindInBatches(result, batchSize, fc) +} + +func (s symptomDo) Attrs(attrs ...field.AssignExpr) *symptomDo { + return s.withDO(s.DO.Attrs(attrs...)) +} + +func (s symptomDo) Assign(attrs ...field.AssignExpr) *symptomDo { + return s.withDO(s.DO.Assign(attrs...)) +} + +func (s symptomDo) Joins(fields ...field.RelationField) *symptomDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Joins(_f)) + } + return &s +} + +func (s symptomDo) Preload(fields ...field.RelationField) *symptomDo { + for _, _f := range fields { + s = *s.withDO(s.DO.Preload(_f)) + } + return &s +} + +func (s symptomDo) FirstOrInit() (*model.Symptom, error) { + if result, err := s.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*model.Symptom), nil + } +} + +func (s symptomDo) FirstOrCreate() (*model.Symptom, error) { + if result, err := s.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*model.Symptom), nil + } +} + +func (s symptomDo) FindByPage(offset int, limit int) (result []*model.Symptom, count int64, err error) { + result, err = s.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = s.Offset(-1).Limit(-1).Count() + return +} + +func (s symptomDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = s.Count() + if err != nil { + return + } + + err = s.Offset(offset).Limit(limit).Scan(result) + return +} + +func (s symptomDo) Scan(result interface{}) (err error) { + return s.DO.Scan(result) +} + +func (s symptomDo) Delete(models ...*model.Symptom) (result gen.ResultInfo, err error) { + return s.DO.Delete(models) +} + +func (s *symptomDo) withDO(do gen.Dao) *symptomDo { + s.DO = *do.(*gen.DO) + return s +} diff --git a/internal/repository/mysql/model/admin.gen.go b/internal/repository/mysql/model/admin.gen.go new file mode 100644 index 0000000..6f0dced --- /dev/null +++ b/internal/repository/mysql/model/admin.gen.go @@ -0,0 +1,33 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAdmin = "admin" + +// Admin 管理员表 +type Admin struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Username string `gorm:"column:username;not null;comment:用户名" json:"username"` // 用户名 + Nickname string `gorm:"column:nickname;not null;comment:昵称" json:"nickname"` // 昵称 + Mobile string `gorm:"column:mobile;not null;comment:手机号" json:"mobile"` // 手机号 + Password string `gorm:"column:password;not null;comment:密码" json:"password"` // 密码 + LoginStatus int32 `gorm:"column:login_status;not null;default:1;comment:登录状态(1:启用 0:禁用)" json:"login_status"` // 登录状态(1:启用 0:禁用) + LastLoginTime time.Time `gorm:"column:last_login_time;not null;default:CURRENT_TIMESTAMP;comment:最后一次登录时间" json:"last_login_time"` // 最后一次登录时间 + LastLoginIP string `gorm:"column:last_login_ip;not null;comment:最后一次登录IP" json:"last_login_ip"` // 最后一次登录IP + LastLoginHash string `gorm:"column:last_login_hash;not null;comment:最后一次登录 Hash" json:"last_login_hash"` // 最后一次登录 Hash + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName Admin's table name +func (*Admin) TableName() string { + return TableNameAdmin +} diff --git a/internal/repository/mysql/model/app_keyword.gen.go b/internal/repository/mysql/model/app_keyword.gen.go new file mode 100644 index 0000000..0bf1ada --- /dev/null +++ b/internal/repository/mysql/model/app_keyword.gen.go @@ -0,0 +1,27 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAppKeyword = "app_keyword" + +// AppKeyword 关键字表 +type AppKeyword struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + AppID string `gorm:"column:app_id;not null;comment:小程序ID" json:"app_id"` // 小程序ID + Keyword string `gorm:"column:keyword;not null;comment:关键字" json:"keyword"` // 关键字 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName AppKeyword's table name +func (*AppKeyword) TableName() string { + return TableNameAppKeyword +} diff --git a/internal/repository/mysql/model/app_keyword_reply.gen.go b/internal/repository/mysql/model/app_keyword_reply.gen.go new file mode 100644 index 0000000..f007ddb --- /dev/null +++ b/internal/repository/mysql/model/app_keyword_reply.gen.go @@ -0,0 +1,30 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAppKeywordReply = "app_keyword_reply" + +// AppKeywordReply 关键字回复表 +type AppKeywordReply struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + AppID string `gorm:"column:app_id;not null;comment:小程序ID" json:"app_id"` // 小程序ID + KeywordID int32 `gorm:"column:keyword_id;not null;comment:关联 app_keyword 表的ID" json:"keyword_id"` // 关联 app_keyword 表的ID + IntervalSeconds int32 `gorm:"column:interval_seconds;not null;comment:时间间隔,单位为秒" json:"interval_seconds"` // 时间间隔,单位为秒 + Type int32 `gorm:"column:type;not null;comment:类型(1:文本 2:图片 3:语音条 4:视频 5=小程序 6=地理位置 7=链接 8=GIF图 9=名片 10=文件 11=转人工)" json:"type"` // 类型(1:文本 2:图片 3:语音条 4:视频 5=小程序 6=地理位置 7=链接 8=GIF图 9=名片 10=文件 11=转人工) + Content string `gorm:"column:content;not null;comment:内容" json:"content"` // 内容 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName AppKeywordReply's table name +func (*AppKeywordReply) TableName() string { + return TableNameAppKeywordReply +} diff --git a/internal/repository/mysql/model/app_message_log.gen.go b/internal/repository/mysql/model/app_message_log.gen.go new file mode 100644 index 0000000..9e3a5cc --- /dev/null +++ b/internal/repository/mysql/model/app_message_log.gen.go @@ -0,0 +1,29 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameAppMessageLog = "app_message_log" + +// AppMessageLog 消息日志表 +type AppMessageLog struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + AppID string `gorm:"column:app_id;not null;comment:小程序ID" json:"app_id"` // 小程序ID + SenderID string `gorm:"column:sender_id;not null;comment:发送人ID" json:"sender_id"` // 发送人ID + SenderName string `gorm:"column:sender_name;not null;comment:发送人昵称" json:"sender_name"` // 发送人昵称 + SendTime time.Time `gorm:"column:send_time;comment:发送时间" json:"send_time"` // 发送时间 + ReceiverID string `gorm:"column:receiver_id;not null;comment:接收人ID" json:"receiver_id"` // 接收人ID + MsgType int32 `gorm:"column:msg_type;not null;comment:信息类型" json:"msg_type"` // 信息类型 + Content string `gorm:"column:content;not null;comment:内容" json:"content"` // 内容 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 +} + +// TableName AppMessageLog's table name +func (*AppMessageLog) TableName() string { + return TableNameAppMessageLog +} diff --git a/internal/repository/mysql/model/app_user.gen.go b/internal/repository/mysql/model/app_user.gen.go new file mode 100644 index 0000000..afe0836 --- /dev/null +++ b/internal/repository/mysql/model/app_user.gen.go @@ -0,0 +1,21 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +const TableNameAppUser = "app_user" + +// AppUser 小程序的用户表 +type AppUser struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + AppID string `gorm:"column:app_id;not null;comment:小程序ID" json:"app_id"` // 小程序ID + UserID string `gorm:"column:user_id;not null;comment:用户ID" json:"user_id"` // 用户ID + UserName string `gorm:"column:user_name;not null;comment:用户昵称" json:"user_name"` // 用户昵称 + UserAvatar string `gorm:"column:user_avatar;not null;comment:用户头像" json:"user_avatar"` // 用户头像 +} + +// TableName AppUser's table name +func (*AppUser) TableName() string { + return TableNameAppUser +} diff --git a/internal/repository/mysql/model/article.gen.go b/internal/repository/mysql/model/article.gen.go new file mode 100644 index 0000000..5769a81 --- /dev/null +++ b/internal/repository/mysql/model/article.gen.go @@ -0,0 +1,28 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameArticle = "article" + +// Article 文章表 +type Article struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Title string `gorm:"column:title;not null;comment:文章标题" json:"title"` // 文章标题 + CoverImage string `gorm:"column:cover_image;not null;comment:文章封面图" json:"cover_image"` // 文章封面图 + Content string `gorm:"column:content;not null;comment:文章内容" json:"content"` // 文章内容 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName Article's table name +func (*Article) TableName() string { + return TableNameArticle +} diff --git a/internal/repository/mysql/model/diagnostic_record.gen.go b/internal/repository/mysql/model/diagnostic_record.gen.go new file mode 100644 index 0000000..d22c726 --- /dev/null +++ b/internal/repository/mysql/model/diagnostic_record.gen.go @@ -0,0 +1,32 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameDiagnosticRecord = "diagnostic_record" + +// DiagnosticRecord 诊断记录表 +type DiagnosticRecord struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + UserID string `gorm:"column:user_id;not null;comment:用户ID(openid)" json:"user_id"` // 用户ID(openid) + Username string `gorm:"column:username;not null;comment:姓名" json:"username"` // 姓名 + Mobile string `gorm:"column:mobile;not null;comment:手机号" json:"mobile"` // 手机号 + Mmp7 string `gorm:"column:mmp_7;not null;comment:MMP-7检测值" json:"mmp_7"` // MMP-7检测值 + Day int32 `gorm:"column:day;not null;comment:日龄(天)" json:"day"` // 日龄(天) + GallbladderImage string `gorm:"column:gallbladder_image;not null;comment:胆囊照片" json:"gallbladder_image"` // 胆囊照片 + PortalVeinBranchImage string `gorm:"column:portal_vein_branch_image;not null;comment:门静脉左右分支照片" json:"portal_vein_branch_image"` // 门静脉左右分支照片 + PortalVeinCrossImage string `gorm:"column:portal_vein_cross_image;not null;comment:门静脉右支横截照片" json:"portal_vein_cross_image"` // 门静脉右支横截照片 + IdentifyResult string `gorm:"column:identify_result;not null;comment:识别结果" json:"identify_result"` // 识别结果 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 +} + +// TableName DiagnosticRecord's table name +func (*DiagnosticRecord) TableName() string { + return TableNameDiagnosticRecord +} diff --git a/internal/repository/mysql/model/doctor.gen.go b/internal/repository/mysql/model/doctor.gen.go new file mode 100644 index 0000000..a8752b4 --- /dev/null +++ b/internal/repository/mysql/model/doctor.gen.go @@ -0,0 +1,33 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameDoctor = "doctor" + +// Doctor 医生表 +type Doctor struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Username string `gorm:"column:username;not null;comment:用户名" json:"username"` // 用户名 + Nickname string `gorm:"column:nickname;not null;comment:昵称" json:"nickname"` // 昵称 + Mobile string `gorm:"column:mobile;not null;comment:手机号" json:"mobile"` // 手机号 + Password string `gorm:"column:password;not null;comment:密码" json:"password"` // 密码 + LoginStatus int32 `gorm:"column:login_status;not null;default:1;comment:登录状态(1:启用 0:禁用)" json:"login_status"` // 登录状态(1:启用 0:禁用) + LastLoginTime time.Time `gorm:"column:last_login_time;not null;default:CURRENT_TIMESTAMP;comment:最后一次登录时间" json:"last_login_time"` // 最后一次登录时间 + LastLoginIP string `gorm:"column:last_login_ip;not null;comment:最后一次登录IP" json:"last_login_ip"` // 最后一次登录IP + LastLoginHash string `gorm:"column:last_login_hash;not null;comment:最后一次登录 Hash" json:"last_login_hash"` // 最后一次登录 Hash + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName Doctor's table name +func (*Doctor) TableName() string { + return TableNameDoctor +} diff --git a/internal/repository/mysql/model/log_operation.gen.go b/internal/repository/mysql/model/log_operation.gen.go new file mode 100644 index 0000000..b2deab1 --- /dev/null +++ b/internal/repository/mysql/model/log_operation.gen.go @@ -0,0 +1,25 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameLogOperation = "log_operation" + +// LogOperation 内部日志表 +type LogOperation struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Level string `gorm:"column:level;not null;comment:错误级别" json:"level"` // 错误级别 + Msg string `gorm:"column:msg;not null;comment:错误信息" json:"msg"` // 错误信息 + Content string `gorm:"column:content;not null;comment:错误内容" json:"content"` // 错误内容 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 +} + +// TableName LogOperation's table name +func (*LogOperation) TableName() string { + return TableNameLogOperation +} diff --git a/internal/repository/mysql/model/log_request.gen.go b/internal/repository/mysql/model/log_request.gen.go new file mode 100644 index 0000000..c8170c9 --- /dev/null +++ b/internal/repository/mysql/model/log_request.gen.go @@ -0,0 +1,32 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameLogRequest = "log_request" + +// LogRequest 请求日志表 +type LogRequest struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Tid string `gorm:"column:tid;not null;comment:请求链路 ID" json:"tid"` // 请求链路 ID + Username string `gorm:"column:username;not null;comment:登录名" json:"username"` // 登录名 + Host string `gorm:"column:host;not null;comment:请求 HOST" json:"host"` // 请求 HOST + Path string `gorm:"column:path;not null;comment:请求 Path" json:"path"` // 请求 Path + Method string `gorm:"column:method;not null;comment:请求 Method" json:"method"` // 请求 Method + HTTPCode int32 `gorm:"column:http_code;not null;comment:HTTP 状态码" json:"http_code"` // HTTP 状态码 + BusinessCode int32 `gorm:"column:business_code;not null;comment:业务码" json:"business_code"` // 业务码 + CostMilliseconds float64 `gorm:"column:cost_milliseconds;not null;default:0.00;comment:耗时(毫秒)" json:"cost_milliseconds"` // 耗时(毫秒) + IsSuccess int32 `gorm:"column:is_success;not null;comment:是否成功(1=是 -1=否)" json:"is_success"` // 是否成功(1=是 -1=否) + Content string `gorm:"column:content;not null;comment:内容" json:"content"` // 内容 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 +} + +// TableName LogRequest's table name +func (*LogRequest) TableName() string { + return TableNameLogRequest +} diff --git a/internal/repository/mysql/model/mini_program.gen.go b/internal/repository/mysql/model/mini_program.gen.go new file mode 100644 index 0000000..3a6821a --- /dev/null +++ b/internal/repository/mysql/model/mini_program.gen.go @@ -0,0 +1,29 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameMiniProgram = "mini_program" + +// MiniProgram 小程序表 +type MiniProgram struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + AppID string `gorm:"column:app_id;not null;comment:小程序ID" json:"app_id"` // 小程序ID + Name string `gorm:"column:name;not null;comment:名称" json:"name"` // 名称 + Description string `gorm:"column:description;not null;comment:描述" json:"description"` // 描述 + Avatar string `gorm:"column:avatar;not null;comment:头像" json:"avatar"` // 头像 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName MiniProgram's table name +func (*MiniProgram) TableName() string { + return TableNameMiniProgram +} diff --git a/internal/repository/mysql/model/miniprogram_access_token.gen.go b/internal/repository/mysql/model/miniprogram_access_token.gen.go new file mode 100644 index 0000000..741511a --- /dev/null +++ b/internal/repository/mysql/model/miniprogram_access_token.gen.go @@ -0,0 +1,24 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameMiniprogramAccessToken = "miniprogram_access_token" + +// MiniprogramAccessToken 小程序 access_token 表 +type MiniprogramAccessToken struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + AccessToken string `gorm:"column:access_token;not null;comment:access_token" json:"access_token"` // access_token + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + ExpiredAt time.Time `gorm:"column:expired_at;not null;default:CURRENT_TIMESTAMP;comment:过期时间" json:"expired_at"` // 过期时间 +} + +// TableName MiniprogramAccessToken's table name +func (*MiniprogramAccessToken) TableName() string { + return TableNameMiniprogramAccessToken +} diff --git a/internal/repository/mysql/model/patient.gen.go b/internal/repository/mysql/model/patient.gen.go new file mode 100644 index 0000000..cbd4ab4 --- /dev/null +++ b/internal/repository/mysql/model/patient.gen.go @@ -0,0 +1,51 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatient = "patient" + +// Patient 患者表 +type Patient struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Mobile string `gorm:"column:mobile;not null;comment:手机号" json:"mobile"` // 手机号 + Username string `gorm:"column:username;not null;comment:姓名" json:"username"` // 姓名 + Sex int32 `gorm:"column:sex;not null;comment:性别(1:男 2:女)" json:"sex"` // 性别(1:男 2:女) + Password string `gorm:"column:password;not null;comment:密码" json:"password"` // 密码 + Avatar string `gorm:"column:avatar;not null;comment:头像地址" json:"avatar"` // 头像地址 + IDNumber string `gorm:"column:id_number;not null;comment:身份证号" json:"id_number"` // 身份证号 + Birthday time.Time `gorm:"column:birthday;comment:出生日期" json:"birthday"` // 出生日期 + BirthWeight int32 `gorm:"column:birth_weight;not null;comment:出生体重(克)" json:"birth_weight"` // 出生体重(克) + OperativeDate time.Time `gorm:"column:operative_date;comment:手术日期" json:"operative_date"` // 手术日期 + NextFollowDate time.Time `gorm:"column:next_follow_date;comment:下次随访时间" json:"next_follow_date"` // 下次随访时间 + ParityNumber int32 `gorm:"column:parity_number;not null;comment:胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎)" json:"parity_number"` // 胎次(0:未知 1:1胎 2:胎 3:胎 4:≥4胎) + BirthNumber int32 `gorm:"column:birth_number;not null;comment:产次(0:未知 1:1产 2:2产 3:≥3产)" json:"birth_number"` // 产次(0:未知 1:1产 2:2产 3:≥3产) + ConceptionType int32 `gorm:"column:conception_type;not null;comment:受孕方式(0:未知 1:自然受孕 2:辅助生殖技术)" json:"conception_type"` // 受孕方式(0:未知 1:自然受孕 2:辅助生殖技术) + GestationalWeek int32 `gorm:"column:gestational_week;not null;comment:孕周" json:"gestational_week"` // 孕周 + PrenatalCheckType int32 `gorm:"column:prenatal_check_type;not null;comment:产检是否异常(0:未知 1:有 2:无)" json:"prenatal_check_type"` // 产检是否异常(0:未知 1:有 2:无) + PrenatalCheckRemark string `gorm:"column:prenatal_check_remark;not null;comment:产检异常备注" json:"prenatal_check_remark"` // 产检异常备注 + DeliveryType int32 `gorm:"column:delivery_type;not null;comment:分娩方式(0:未知 1:顺产 2:剖宫产)" json:"delivery_type"` // 分娩方式(0:未知 1:顺产 2:剖宫产) + RiskType int32 `gorm:"column:risk_type;not null;comment:风险类型(0:未知 1:低危 2:中危 3:高危)" json:"risk_type"` // 风险类型(0:未知 1:低危 2:中危 3:高危) + RiskValue string `gorm:"column:risk_value;not null;comment:风险值" json:"risk_value"` // 风险值 + HeightGenerateCurveType int32 `gorm:"column:height_generate_curve_type;not null;comment:身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)" json:"height_generate_curve_type"` // 身高生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + WeightGenerateCurveType int32 `gorm:"column:weight_generate_curve_type;not null;comment:体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离)" json:"weight_generate_curve_type"` // 体重生长曲线类型(0:未知 1:轻度偏离 2:正常 3:重度偏离) + LoginStatus int32 `gorm:"column:login_status;not null;default:1;comment:登录状态(1:启用 0:禁用)" json:"login_status"` // 登录状态(1:启用 0:禁用) + LastLoginTime time.Time `gorm:"column:last_login_time;not null;default:CURRENT_TIMESTAMP;comment:最后一次登录时间" json:"last_login_time"` // 最后一次登录时间 + LastLoginIP string `gorm:"column:last_login_ip;not null;comment:最后一次登录IP" json:"last_login_ip"` // 最后一次登录IP + LastLoginHash string `gorm:"column:last_login_hash;not null;comment:最后一次登录 Hash" json:"last_login_hash"` // 最后一次登录 Hash + WxUserID string `gorm:"column:wx_user_id;not null;comment:微信ID" json:"wx_user_id"` // 微信ID + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName Patient's table name +func (*Patient) TableName() string { + return TableNamePatient +} diff --git a/internal/repository/mysql/model/patient_emergency_symptom.gen.go b/internal/repository/mysql/model/patient_emergency_symptom.gen.go new file mode 100644 index 0000000..f028898 --- /dev/null +++ b/internal/repository/mysql/model/patient_emergency_symptom.gen.go @@ -0,0 +1,28 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientEmergencySymptom = "patient_emergency_symptom" + +// PatientEmergencySymptom 患者紧急症状表 +type PatientEmergencySymptom struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + Symptom string `gorm:"column:symptom;not null;comment:症状信息(JSON格式)" json:"symptom"` // 症状信息(JSON格式) + Conclusion string `gorm:"column:conclusion;not null;comment:结论" json:"conclusion"` // 结论 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientEmergencySymptom's table name +func (*PatientEmergencySymptom) TableName() string { + return TableNamePatientEmergencySymptom +} diff --git a/internal/repository/mysql/model/patient_follow_plan.gen.go b/internal/repository/mysql/model/patient_follow_plan.gen.go new file mode 100644 index 0000000..5d4d0ed --- /dev/null +++ b/internal/repository/mysql/model/patient_follow_plan.gen.go @@ -0,0 +1,29 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientFollowPlan = "patient_follow_plan" + +// PatientFollowPlan 患者随访计划表 +type PatientFollowPlan struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + PlanName string `gorm:"column:plan_name;not null;default:0;comment:计划名称" json:"plan_name"` // 计划名称 + PlanDate time.Time `gorm:"column:plan_date;comment:计划时间" json:"plan_date"` // 计划时间 + Status int32 `gorm:"column:status;not null;comment:完成状态(1:未完成 2:已完成)" json:"status"` // 完成状态(1:未完成 2:已完成) + CreatedUser string `gorm:"column:created_user;not null;default:0;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;default:0;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientFollowPlan's table name +func (*PatientFollowPlan) TableName() string { + return TableNamePatientFollowPlan +} diff --git a/internal/repository/mysql/model/patient_follow_questionnaire.gen.go b/internal/repository/mysql/model/patient_follow_questionnaire.gen.go new file mode 100644 index 0000000..cee163e --- /dev/null +++ b/internal/repository/mysql/model/patient_follow_questionnaire.gen.go @@ -0,0 +1,83 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientFollowQuestionnaire = "patient_follow_questionnaire" + +// PatientFollowQuestionnaire 患者随访问卷表 +type PatientFollowQuestionnaire struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + PlanID int32 `gorm:"column:plan_id;not null;comment:随访计划ID" json:"plan_id"` // 随访计划ID + FollowName string `gorm:"column:follow_name;not null;comment:随访名称" json:"follow_name"` // 随访名称 + FollowDate time.Time `gorm:"column:follow_date;comment:随访日期" json:"follow_date"` // 随访日期 + FollowHospital string `gorm:"column:follow_hospital;not null;comment:随访医院" json:"follow_hospital"` // 随访医院 + Height string `gorm:"column:height;not null;comment:身高(CM)" json:"height"` // 身高(CM) + Weight string `gorm:"column:weight;not null;comment:体重(KG)" json:"weight"` // 体重(KG) + HeadCircumference string `gorm:"column:head_circumference;not null;comment:头围(CM)" json:"head_circumference"` // 头围(CM) + HighHip string `gorm:"column:high_hip;not null;comment:上臀围(CM)" json:"high_hip"` // 上臀围(CM) + LiverFunctionImage string `gorm:"column:liver_function_image;comment:肝功能检查报告(多张用,分割)" json:"liver_function_image"` // 肝功能检查报告(多张用,分割) + TotalBilirubin string `gorm:"column:total_bilirubin;not null;comment:总胆红素(µmol/L)" json:"total_bilirubin"` // 总胆红素(µmol/L) + DirectBilirubin string `gorm:"column:direct_bilirubin;not null;comment:直接胆红素(µmol/L)" json:"direct_bilirubin"` // 直接胆红素(µmol/L) + TotalBileAcid string `gorm:"column:total_bile_acid;not null;comment:总胆汁酸(g/L)" json:"total_bile_acid"` // 总胆汁酸(g/L) + Albumin string `gorm:"column:albumin;not null;comment:白蛋白(g/L)" json:"albumin"` // 白蛋白(g/L) + GrainGrass string `gorm:"column:grain_grass;not null;comment:谷草(U/L)" json:"grain_grass"` // 谷草(U/L) + GuBing string `gorm:"column:gu_bing;not null;comment:谷丙(U/L)" json:"gu_bing"` // 谷丙(U/L) + Ggt string `gorm:"column:ggt;not null;comment:GGT(U/L)" json:"ggt"` // GGT(U/L) + Alp string `gorm:"column:alp;not null;comment:ALP(U/L)" json:"alp"` // ALP(U/L) + CoagulationFunctionImage string `gorm:"column:coagulation_function_image;comment:凝血功能检查报告(多张用,分割)" json:"coagulation_function_image"` // 凝血功能检查报告(多张用,分割) + Crp string `gorm:"column:crp;not null;comment:CRP(mg/L)" json:"crp"` // CRP(mg/L) + Ddr string `gorm:"column:ddr;not null;comment:DDR" json:"ddr"` // DDR + Inr string `gorm:"column:inr;not null;comment:INR" json:"inr"` // INR + Pt string `gorm:"column:pt;not null;comment:PT(s)" json:"pt"` // PT(s) + Pta string `gorm:"column:pta;not null;comment:PTA(%)" json:"pta"` // PTA(%) + Aptt string `gorm:"column:aptt;not null;comment:APTT(s)" json:"aptt"` // APTT(s) + Tt string `gorm:"column:tt;not null;comment:TT(s)" json:"tt"` // TT(s) + Fib string `gorm:"column:fib;not null;comment:FIB(g/L)" json:"fib"` // FIB(g/L) + Npdp string `gorm:"column:npdp;not null;comment:NPDP(mg/L)" json:"npdp"` // NPDP(mg/L) + Mmp7 string `gorm:"column:mmp_7;not null;comment:MMP-7(ng/mL)" json:"mmp_7"` // MMP-7(ng/mL) + BloodRoutineImage string `gorm:"column:blood_routine_image;comment:血常规检查报告(多张用,分割)" json:"blood_routine_image"` // 血常规检查报告(多张用,分割) + Platelets string `gorm:"column:platelets;not null;comment:血小板(10^9/L)" json:"platelets"` // 血小板(10^9/L) + Hemoglobin string `gorm:"column:hemoglobin;not null;comment:血红蛋白 (g/L)" json:"hemoglobin"` // 血红蛋白 (g/L) + WhiteBloodCells string `gorm:"column:white_blood_cells;not null;comment:白细胞 (10^9/L)" json:"white_blood_cells"` // 白细胞 (10^9/L) + RedBloodCells string `gorm:"column:red_blood_cells;not null;comment:红细胞 (10^9/L)" json:"red_blood_cells"` // 红细胞 (10^9/L) + NutritionalIndicatorImage string `gorm:"column:nutritional_indicator_image;comment:营养指标检查报告(多张用,分割)" json:"nutritional_indicator_image"` // 营养指标检查报告(多张用,分割) + OhD3 string `gorm:"column:oh_d3;not null;comment:25(OH)D3 (ng/ml)" json:"oh_d3"` // 25(OH)D3 (ng/ml) + OhD2 string `gorm:"column:oh_d2;not null;comment:25(OH)D2 (ng/ml)" json:"oh_d2"` // 25(OH)D2 (ng/ml) + OhD string `gorm:"column:oh_d;not null;comment:25(OH)D (ng/ml)" json:"oh_d"` // 25(OH)D (ng/ml) + VitaminA string `gorm:"column:vitamin_a;not null;comment:维生素A (ng/ml)" json:"vitamin_a"` // 维生素A (ng/ml) + VitaminK string `gorm:"column:vitamin_k;not null;comment:维生素K (ng/ml)" json:"vitamin_k"` // 维生素K (ng/ml) + VitaminE string `gorm:"column:vitamin_e;not null;comment:维生素E (ng/ml)" json:"vitamin_e"` // 维生素E (ng/ml) + BModeImage string `gorm:"column:b_mode_image;comment:B超报告(多张用,分割)" json:"b_mode_image"` // B超报告(多张用,分割) + UnderTheLiverRib string `gorm:"column:under_the_liver_rib;not null;comment:肝肋下(mm)" json:"under_the_liver_rib"` // 肝肋下(mm) + UnderTheXiphoidLiver string `gorm:"column:under_the_xiphoid_liver;not null;comment:肝剑突下(mm)" json:"under_the_xiphoid_liver"` // 肝剑突下(mm) + SpleenRibArea string `gorm:"column:spleen_rib_area;not null;comment:脾肋下(mm)" json:"spleen_rib_area"` // 脾肋下(mm) + MainPortalVein string `gorm:"column:main_portal_vein;not null;comment:门静脉主干内径(mm)" json:"main_portal_vein"` // 门静脉主干内径(mm) + LiverEcho string `gorm:"column:liver_echo;not null;comment:肝回声" json:"liver_echo"` // 肝回声 + GallbladderSize string `gorm:"column:gallbladder_size;not null;comment:胆囊大小(mm)" json:"gallbladder_size"` // 胆囊大小(mm) + CommonBileDuct string `gorm:"column:common_bile_duct;not null;comment:胆总管(mm)" json:"common_bile_duct"` // 胆总管(mm) + FiberBlockSize string `gorm:"column:fiber_block_size;not null;comment:纤维块大小(mm)" json:"fiber_block_size"` // 纤维块大小(mm) + Pvv string `gorm:"column:pvv;not null;comment:门静脉流速" json:"pvv"` // 门静脉流速 + LiverElasticityValue string `gorm:"column:liver_elasticity_value;not null;comment:肝弹性值" json:"liver_elasticity_value"` // 肝弹性值 + IsHaveCyst int32 `gorm:"column:is_have_cyst;not null;comment:有无肝囊肿(1:是 2:否)" json:"is_have_cyst"` // 有无肝囊肿(1:是 2:否) + IsHaveAscites int32 `gorm:"column:is_have_ascites;not null;comment:有无腹水(1:是 2:否)" json:"is_have_ascites"` // 有无腹水(1:是 2:否) + ElastographyMinimum string `gorm:"column:elastography_minimum;not null;comment:弹性成像最小值(kPa)" json:"elastography_minimum"` // 弹性成像最小值(kPa) + ElastographyMaximum string `gorm:"column:elastography_maximum;not null;comment:弹性成像最大值(kPa)" json:"elastography_maximum"` // 弹性成像最大值(kPa) + ElastographyMedian string `gorm:"column:elastography_median;not null;comment:弹性成像中位数(kPa)" json:"elastography_median"` // 弹性成像中位数(kPa) + MdtImage string `gorm:"column:mdt_image;comment:MDT电子病历(多张用,分割)" json:"mdt_image"` // MDT电子病历(多张用,分割) + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientFollowQuestionnaire's table name +func (*PatientFollowQuestionnaire) TableName() string { + return TableNamePatientFollowQuestionnaire +} diff --git a/internal/repository/mysql/model/patient_medicine_record.gen.go b/internal/repository/mysql/model/patient_medicine_record.gen.go new file mode 100644 index 0000000..7bff2e2 --- /dev/null +++ b/internal/repository/mysql/model/patient_medicine_record.gen.go @@ -0,0 +1,33 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientMedicineRecord = "patient_medicine_record" + +// PatientMedicineRecord 患者用药记录表 +type PatientMedicineRecord struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + SchemeID int32 `gorm:"column:scheme_id;not null;comment:用药方案ID" json:"scheme_id"` // 用药方案ID + MedicineDate time.Time `gorm:"column:medicine_date;comment:用药日期" json:"medicine_date"` // 用药日期 + MedicineTimeType int32 `gorm:"column:medicine_time_type;not null;comment:用药时间类型(1:早上 2:中午 3:晚上)" json:"medicine_time_type"` // 用药时间类型(1:早上 2:中午 3:晚上) + MedicineTime string `gorm:"column:medicine_time;not null;comment:用药时间" json:"medicine_time"` // 用药时间 + Detail string `gorm:"column:detail;not null;comment:药品信息(JSON格式)" json:"detail"` // 药品信息(JSON格式) + Status int32 `gorm:"column:status;not null;default:1;comment:用药状态(1:未完成 2:已完成)" json:"status"` // 用药状态(1:未完成 2:已完成) + StatusAt time.Time `gorm:"column:status_at;comment:已完成时间(打卡时间)" json:"status_at"` // 已完成时间(打卡时间) + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientMedicineRecord's table name +func (*PatientMedicineRecord) TableName() string { + return TableNamePatientMedicineRecord +} diff --git a/internal/repository/mysql/model/patient_medicine_scheme.gen.go b/internal/repository/mysql/model/patient_medicine_scheme.gen.go new file mode 100644 index 0000000..319e7ba --- /dev/null +++ b/internal/repository/mysql/model/patient_medicine_scheme.gen.go @@ -0,0 +1,30 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientMedicineScheme = "patient_medicine_scheme" + +// PatientMedicineScheme 患者用药方案表 +type PatientMedicineScheme struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + StartDate time.Time `gorm:"column:start_date;comment:用药开始日期" json:"start_date"` // 用药开始日期 + EndDate time.Time `gorm:"column:end_date;comment:用药结束日期" json:"end_date"` // 用药结束日期 + Detail string `gorm:"column:detail;not null;comment:药品信息(JSON格式)" json:"detail"` // 药品信息(JSON格式) + Reminder string `gorm:"column:reminder;not null;comment:用药提醒(JSON格式)" json:"reminder"` // 用药提醒(JSON格式) + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientMedicineScheme's table name +func (*PatientMedicineScheme) TableName() string { + return TableNamePatientMedicineScheme +} diff --git a/internal/repository/mysql/model/patient_medicine_task.gen.go b/internal/repository/mysql/model/patient_medicine_task.gen.go new file mode 100644 index 0000000..ff1402a --- /dev/null +++ b/internal/repository/mysql/model/patient_medicine_task.gen.go @@ -0,0 +1,35 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNamePatientMedicineTask = "patient_medicine_task" + +// PatientMedicineTask 患者用药提醒(任务)表 +type PatientMedicineTask struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键ID" json:"id"` // 主键ID + Code string `gorm:"column:code;not null;comment:任务编码" json:"code"` // 任务编码 + Title string `gorm:"column:title;not null;comment:标题" json:"title"` // 标题 + Spec string `gorm:"column:spec;not null;comment:时间表达式" json:"spec"` // 时间表达式 + Status int32 `gorm:"column:status;not null;comment:状态(1:禁用 2:启用)" json:"status"` // 状态(1:禁用 2:启用) + IsRunning int32 `gorm:"column:is_running;not null;comment:执行中(0:未执行 1:执行中 2:执行完毕)" json:"is_running"` // 执行中(0:未执行 1:执行中 2:执行完毕) + RunTime time.Time `gorm:"column:run_time;comment:预期执行时间" json:"run_time"` // 预期执行时间 + RunStartTime time.Time `gorm:"column:run_start_time;comment:执行开始时间" json:"run_start_time"` // 执行开始时间 + RunEndTime time.Time `gorm:"column:run_end_time;comment:执行结束时间" json:"run_end_time"` // 执行结束时间 + PatientID int32 `gorm:"column:patient_id;not null;comment:患者ID" json:"patient_id"` // 患者ID + MedicineRecordID int32 `gorm:"column:medicine_record_id;not null;comment:用药记录ID" json:"medicine_record_id"` // 用药记录ID + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName PatientMedicineTask's table name +func (*PatientMedicineTask) TableName() string { + return TableNamePatientMedicineTask +} diff --git a/internal/repository/mysql/model/sms_verification_code.gen.go b/internal/repository/mysql/model/sms_verification_code.gen.go new file mode 100644 index 0000000..38af085 --- /dev/null +++ b/internal/repository/mysql/model/sms_verification_code.gen.go @@ -0,0 +1,27 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameSmsVerificationCode = "sms_verification_code" + +// SmsVerificationCode 短信验证码表 +type SmsVerificationCode struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + PhoneNumber string `gorm:"column:phone_number;not null;comment:手机号码" json:"phone_number"` // 手机号码 + VerificationCode string `gorm:"column:verification_code;not null;comment:验证码" json:"verification_code"` // 验证码 + Type int32 `gorm:"column:type;not null;comment:类型(1=登录 2=忘记密码)" json:"type"` // 类型(1=登录 2=忘记密码) + IsUsed int32 `gorm:"column:is_used;not null;comment:是否已使用(0:未使用,1:已使用)" json:"is_used"` // 是否已使用(0:未使用,1:已使用) + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 +} + +// TableName SmsVerificationCode's table name +func (*SmsVerificationCode) TableName() string { + return TableNameSmsVerificationCode +} diff --git a/internal/repository/mysql/model/symptom.gen.go b/internal/repository/mysql/model/symptom.gen.go new file mode 100644 index 0000000..959f191 --- /dev/null +++ b/internal/repository/mysql/model/symptom.gen.go @@ -0,0 +1,27 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package model + +import ( + "time" +) + +const TableNameSymptom = "symptom" + +// Symptom 症状表 +type Symptom struct { + ID int32 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键" json:"id"` // 主键 + Title string `gorm:"column:title;not null;comment:症状" json:"title"` // 症状 + Description string `gorm:"column:description;not null;comment:描述" json:"description"` // 描述 + CreatedUser string `gorm:"column:created_user;not null;comment:创建人" json:"created_user"` // 创建人 + CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"` // 创建时间 + UpdatedUser string `gorm:"column:updated_user;not null;comment:更新人" json:"updated_user"` // 更新人 + UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"` // 更新时间 +} + +// TableName Symptom's table name +func (*Symptom) TableName() string { + return TableNameSymptom +} diff --git a/internal/repository/mysql/mysql.go b/internal/repository/mysql/mysql.go new file mode 100644 index 0000000..a044e01 --- /dev/null +++ b/internal/repository/mysql/mysql.go @@ -0,0 +1,131 @@ +package mysql + +import ( + "fmt" + "log" + "os" + "time" + + "mini-chat/configs" + "mini-chat/internal/pkg/errors" + + "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "gorm.io/gorm/schema" +) + +var _ Repo = (*dbRepo)(nil) + +type Repo interface { + i() + GetDbR() *gorm.DB + GetDbW() *gorm.DB + DbRClose() error + DbWClose() error +} + +type dbRepo struct { + DbR *gorm.DB + DbW *gorm.DB +} + +func New() (Repo, error) { + cfg := configs.Get().MySQL + dbr, err := dbConnect(cfg.Read.User, cfg.Read.Pass, cfg.Read.Addr, cfg.Read.Name) + if err != nil { + return nil, err + } + + dbw, err := dbConnect(cfg.Write.User, cfg.Write.Pass, cfg.Write.Addr, cfg.Write.Name) + if err != nil { + return nil, err + } + + return &dbRepo{ + DbR: dbr, + DbW: dbw, + }, nil +} + +func (d *dbRepo) i() {} + +func (d *dbRepo) GetDbR() *gorm.DB { + return d.DbR +} + +func (d *dbRepo) GetDbW() *gorm.DB { + return d.DbW +} + +func (d *dbRepo) DbRClose() error { + sqlDB, err := d.DbR.DB() + if err != nil { + return err + } + return sqlDB.Close() +} + +func (d *dbRepo) DbWClose() error { + sqlDB, err := d.DbW.DB() + if err != nil { + return err + } + return sqlDB.Close() +} + +func dbConnect(user, pass, addr, dbName string) (*gorm.DB, error) { + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=%t&loc=%s", + user, + pass, + addr, + dbName, + true, + "Local") + + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer + logger.Config{ + SlowThreshold: time.Second, // Slow SQL threshold + LogLevel: logger.Warn, // Log level + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger + ParameterizedQueries: true, // Don't include params in the SQL log + Colorful: false, // Disable color + }, + ) + + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + }, + Logger: newLogger, // 日志配置 + }) + + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("[db connection failed] Database name: %s", dbName)) + } + + db.Set("gorm:table_options", "CHARSET=utf8mb4") + + sqlDB, err := db.DB() + if err != nil { + return nil, err + } + + // 设置连接池 用于设置最大打开的连接数,默认值为0表示不限制.设置最大的连接数,可以避免并发太高导致连接mysql出现too many connections的错误。 + sqlDB.SetMaxOpenConns(100) + + // 设置最大连接数 用于设置闲置的连接数.设置闲置的连接数则当开启的一个连接使用完成后可以放在池里等候下一次使用。 + sqlDB.SetMaxIdleConns(5) + + // 设置最大连接超时 + sqlDB.SetConnMaxLifetime(time.Minute * 2) + + // 使用插件 + err = db.Use(&TracePlugin{}) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/internal/repository/mysql/plugin.go b/internal/repository/mysql/plugin.go new file mode 100644 index 0000000..3362e9b --- /dev/null +++ b/internal/repository/mysql/plugin.go @@ -0,0 +1,83 @@ +package mysql + +import ( + "time" + + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/timeutil" + "mini-chat/internal/pkg/trace" + + "gorm.io/gorm" + "gorm.io/gorm/utils" +) + +const ( + callBackBeforeName = "core:before" + callBackAfterName = "core:after" + startTime = "_start_time" +) + +type TracePlugin struct{} + +func (op *TracePlugin) Name() string { + return "tracePlugin" +} + +func (op *TracePlugin) Initialize(db *gorm.DB) (err error) { + // 开始前 + _ = db.Callback().Create().Before("gorm:before_create").Register(callBackBeforeName, before) + _ = db.Callback().Query().Before("gorm:query").Register(callBackBeforeName, before) + _ = db.Callback().Delete().Before("gorm:before_delete").Register(callBackBeforeName, before) + _ = db.Callback().Update().Before("gorm:setup_reflect_value").Register(callBackBeforeName, before) + _ = db.Callback().Row().Before("gorm:row").Register(callBackBeforeName, before) + _ = db.Callback().Raw().Before("gorm:raw").Register(callBackBeforeName, before) + + // 结束后 + _ = db.Callback().Create().After("gorm:after_create").Register(callBackAfterName, after) + _ = db.Callback().Query().After("gorm:after_query").Register(callBackAfterName, after) + _ = db.Callback().Delete().After("gorm:after_delete").Register(callBackAfterName, after) + _ = db.Callback().Update().After("gorm:after_update").Register(callBackAfterName, after) + _ = db.Callback().Row().After("gorm:row").Register(callBackAfterName, after) + _ = db.Callback().Raw().After("gorm:raw").Register(callBackAfterName, after) + return +} + +var _ gorm.Plugin = &TracePlugin{} + +func before(db *gorm.DB) { + db.InstanceSet(startTime, time.Now()) + return +} + +func after(db *gorm.DB) { + _ctx := db.Statement.Context + ctx, ok := _ctx.(core.StdContext) + if !ok { + return + } + + _ts, isExist := db.InstanceGet(startTime) + if !isExist { + return + } + + ts, ok := _ts.(time.Time) + if !ok { + return + } + + sql := db.Dialector.Explain(db.Statement.SQL.String(), db.Statement.Vars...) + + sqlInfo := new(trace.SQL) + sqlInfo.Time = timeutil.CSTLayoutString() + sqlInfo.SQL = sql + sqlInfo.Stack = utils.FileWithLineNum() + sqlInfo.Rows = db.Statement.RowsAffected + sqlInfo.CostSeconds = time.Since(ts).Seconds() + + if ctx.Trace != nil { + ctx.Trace.AppendSQL(sqlInfo) + } + + return +} diff --git a/internal/router/interceptor/admin_auth.go b/internal/router/interceptor/admin_auth.go new file mode 100644 index 0000000..3014b3a --- /dev/null +++ b/internal/router/interceptor/admin_auth.go @@ -0,0 +1,80 @@ +package interceptor + +import ( + "net/http" + + "mini-chat/configs" + "mini-chat/internal/code" + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/jwtoken" + "mini-chat/internal/pkg/utils" + "mini-chat/internal/proposal" + "mini-chat/internal/repository/mysql/dao" + + "gorm.io/gorm" +) + +func (i *interceptor) AdminTokenAuthVerify(ctx core.Context) (sessionUserInfo proposal.SessionUserInfo, err core.BusinessError) { + headerAuthorizationString := ctx.GetHeader("Authorization") + if headerAuthorizationString == "" { + err = core.Error( + http.StatusUnauthorized, + code.JWTAuthVerifyError, + "无法确认您的身份,请进行登录。") + + return + } + + // 验证 JWT 是否合法 + jwtClaims, jwtErr := jwtoken.New(configs.Get().JWT.AdminSecret).Parse(headerAuthorizationString) + if jwtErr != nil { + err = core.Error( + http.StatusUnauthorized, + code.JWTAuthVerifyError, + "您的账号登录过期,请重新登录。") + + return + } + + // 验证用户状态 + info, dbErr := dao.Use(i.db.GetDbR()).Admin.WithContext(ctx.RequestContext()).Where(dao.Use(i.db.GetDbR()).Admin.ID.Eq(jwtClaims.Id)).First() + if dbErr != nil && dbErr != gorm.ErrRecordNotFound { + err = core.Error( + http.StatusUnauthorized, + code.ServerError, + "身份验证失败,如需帮助请联系我们。") + + return + } + + if dbErr == gorm.ErrRecordNotFound { + err = core.Error( + http.StatusUnauthorized, + code.ServerError, + "无法确认您的身份,请进行登录。") + + return + } + + if utils.MD5(headerAuthorizationString) != info.LastLoginHash { + err = core.Error( + http.StatusUnauthorized, + code.JWTAuthVerifyError, + "您的账号已在别处登录,为了保护您的账户安全,请重新登录。") + return + } + + // 验证登录状态 + if info.LoginStatus != 1 { + err = core.Error( + http.StatusUnauthorized, + code.ServerError, + "您的账号已被禁用,如需帮助请联系我们。").WithAlert() + + return + } + + sessionUserInfo = jwtClaims.SessionUserInfo + + return +} diff --git a/internal/router/interceptor/interceptor.go b/internal/router/interceptor/interceptor.go new file mode 100644 index 0000000..f0fb6f9 --- /dev/null +++ b/internal/router/interceptor/interceptor.go @@ -0,0 +1,38 @@ +package interceptor + +import ( + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/logger" + "mini-chat/internal/proposal" + "mini-chat/internal/repository/mysql" +) + +var _ Interceptor = (*interceptor)(nil) + +type Interceptor interface { + // AdminTokenAuthVerify 管理端授权验证 + AdminTokenAuthVerify(ctx core.Context) (sessionUserInfo proposal.SessionUserInfo, err core.BusinessError) + + // DoctorTokenAuthVerify 医生端授权验证 + DoctorTokenAuthVerify(ctx core.Context) (sessionUserInfo proposal.SessionUserInfo, err core.BusinessError) + + // PatientTokenAuthVerify 患者端授权验证 + PatientTokenAuthVerify(ctx core.Context) (sessionUserInfo proposal.SessionUserInfo, err core.BusinessError) + + // i 为了避免被其他包实现 + i() +} + +type interceptor struct { + logger logger.CustomLogger + db mysql.Repo +} + +func New(logger logger.CustomLogger, db mysql.Repo) Interceptor { + return &interceptor{ + logger: logger, + db: db, + } +} + +func (i *interceptor) i() {} diff --git a/internal/router/router.go b/internal/router/router.go new file mode 100644 index 0000000..11c6e0d --- /dev/null +++ b/internal/router/router.go @@ -0,0 +1,58 @@ +package router + +import ( + "github.com/pkg/errors" + "mini-chat/internal/alert" + "mini-chat/internal/api/admin" + "mini-chat/internal/cron" + "mini-chat/internal/dblogger" + "mini-chat/internal/pkg/core" + "mini-chat/internal/pkg/logger" + "mini-chat/internal/pkg/startup" + "mini-chat/internal/repository/mysql" +) + +func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (core.Mux, error) { + if logger == nil { + return nil, errors.New("logger required") + } + + if db == nil { + return nil, errors.New("db required") + } + + mux, err := core.New(logger, + core.WithEnableCors(), + core.WithEnableSwagger(), + core.WithEnablePProf(), + core.WithAlertNotify(alert.NotifyHandler()), + core.WithRequestLogger(dblogger.LoggerHandler(db)), + ) + + if err != nil { + panic(err) + } + + // 实例化拦截器 + // interceptorHandler := interceptor.New(logger, db) + + adminHandler := admin.New(logger, db) + + // 管理端非认证接口路由组 + adminNonAuthApiRouter := mux.Group("/admin") + { + adminNonAuthApiRouter.GET("/license/status", func(ctx core.Context) { + ctx.Payload(startup.Info()) + }) + + adminNonAuthApiRouter.POST("/login", adminHandler.Login()) // 登录 + } + + // 管理端认证接口路由组 + //adminAuthApiRouter := mux.Group("/admin", core.WrapAuthHandler(interceptorHandler.AdminTokenAuthVerify)) + //{ + // + //} + + return mux, nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..87e6e94 --- /dev/null +++ b/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "context" + "fmt" + "net/http" + + "mini-chat/configs" + "mini-chat/internal/cron" + "mini-chat/internal/pkg/env" + "mini-chat/internal/pkg/logger" + "mini-chat/internal/pkg/shutdown" + "mini-chat/internal/pkg/timeutil" + "mini-chat/internal/repository/mysql" + "mini-chat/internal/repository/mysql/dao" + "mini-chat/internal/router" + + "go.uber.org/zap" +) + +// @title mini-chat 接口文档 +// @version v0.0.1 + +// @securityDefinitions.apikey LoginVerifyToken +// @in header +// @name Authorization + +// @BasePath / +func main() { + // 初始化 MySQL + dbRepo, err := mysql.New() + if err != nil { + panic(err) + } + + // 初始化 自定义 Logger + customLogger, err := logger.NewCustomLogger(dao.Use(dbRepo.GetDbW()), + //logger.WithOutputInConsole(), + logger.WithField("domain", fmt.Sprintf("%s[%s]", configs.ProjectName, env.Active().Value())), + logger.WithTimeLayout(timeutil.CSTLayout), + logger.WithFileRotationP(configs.ProjectAccessLogFile), + ) + + if err != nil { + panic(err) + } + + defer func() { + _ = customLogger.Sync() + }() + + // 初始化 Cron + cronServer, err := cron.New(customLogger, dbRepo) + if err != nil { + panic(err) + } + cronServer.Start() + + // 初始化 HTTP 服务 + mux, err := router.NewHTTPMux(customLogger, dbRepo, cronServer) + if err != nil { + panic(err) + } + + server := &http.Server{ + Addr: configs.ProjectPort, + Handler: mux, + } + + go func() { + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + customLogger.Fatal("http server startup err", zap.Error(err)) + } + }() + + // 优雅关闭 + shutdown.Close( + func() { + // 关闭 http server + if err := server.Shutdown(context.TODO()); err != nil { + customLogger.Error("server shutdown err", zap.Error(err)) + } + + // 关闭 db master (支持读写) + if err := dbRepo.DbWClose(); err != nil { + customLogger.Error("dbw close err", zap.Error(err)) + } + + // 关闭 db slave (仅支持读) + if err := dbRepo.DbRClose(); err != nil { + customLogger.Error("dbr close err", zap.Error(err)) + } + + // 关闭 cron + if cronServer != nil { + cronServer.Stop() + } + }, + ) +} diff --git a/scripts/swagger.bat b/scripts/swagger.bat new file mode 100644 index 0000000..48616e4 --- /dev/null +++ b/scripts/swagger.bat @@ -0,0 +1,9 @@ +@echo off +chcp 65001 +echo. +echo Regenerating swagger doc +echo. +go install github.com/swaggo/swag/cmd/swag@v1.16.2 +swag init +echo. +echo Done. \ No newline at end of file diff --git a/scripts/swagger.sh b/scripts/swagger.sh new file mode 100755 index 0000000..d2195f0 --- /dev/null +++ b/scripts/swagger.sh @@ -0,0 +1,5 @@ +#!/bin/bash +printf "\nRegenerating swagger doc\n\n" +go install github.com/swaggo/swag/cmd/swag@v1.16.2 +time swag init +printf "\nDone.\n\n" \ No newline at end of file