From 7598280fc1ea0aa586016c0bcd28209727a0f231 Mon Sep 17 00:00:00 2001 From: fallen-angle <1853633282@qq.com> Date: Wed, 4 May 2022 20:06:21 +0800 Subject: [PATCH] feat: management && notify --- docs/docs.go | 145 +++++++++++++++++++ docs/swagger.json | 145 +++++++++++++++++++ docs/swagger.yaml | 92 ++++++++++++ global/global.go | 27 +++- handler/errors.go | 16 ++- handler/management.go | 68 +++++++++ handler/statistics.go | 11 ++ handler/utils.go | 10 ++ initialize/cron.go | 1 + models/investigate.go | 63 -------- models/management.go | 156 ++++++++++++++++++++ models/notify.go | 9 ++ models/statistic.go | 39 +++++ models/utils.go | 60 +++++++- router/investigate.go | 17 --- router/management.go | 17 +++ router/router.go | 2 +- router/statistics.go | 1 + service/investigate/faker.go | 46 ------ service/investigate/investigate.go | 1 - service/management/faker.go | 104 ++++++++++++++ service/management/location.go | 22 +++ service/management/observation.go | 223 +++++++++++++++++++++++++++++ service/notify/notify.go | 44 ++++++ service/statistics/cache.go | 20 ++- service/statistics/statistics.go | 26 ++++ service/user/user.go | 1 - utils/jwt.go | 3 +- 28 files changed, 1226 insertions(+), 143 deletions(-) create mode 100644 handler/management.go delete mode 100644 models/investigate.go create mode 100644 models/management.go create mode 100644 models/notify.go delete mode 100644 router/investigate.go create mode 100644 router/management.go delete mode 100644 service/investigate/faker.go delete mode 100644 service/investigate/investigate.go create mode 100644 service/management/faker.go create mode 100644 service/management/location.go create mode 100644 service/management/observation.go create mode 100644 service/notify/notify.go diff --git a/docs/docs.go b/docs/docs.go index 90c5936..df0be5b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -310,6 +310,37 @@ const docTemplate = `{ } } }, + "/statistics/china/trend": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Statistics" + ], + "summary": "china trend", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.ChinaTrend" + } + } + } + ] + } + } + } + } + }, "/statistics/city/{sort}": { "get": { "produces": [ @@ -741,6 +772,9 @@ const docTemplate = `{ "name": { "type": "string" }, + "parent": { + "type": "string" + }, "today": { "$ref": "#/definitions/models.AreaToday" }, @@ -939,6 +973,100 @@ const docTemplate = `{ } } }, + "models.ChinaDay": { + "type": "object", + "properties": { + "confirm": { + "type": "integer" + }, + "date": { + "type": "string" + }, + "dead": { + "type": "integer" + }, + "deadRate": { + "type": "string" + }, + "heal": { + "type": "integer" + }, + "healRate": { + "type": "string" + }, + "importedCase": { + "type": "integer" + }, + "localConfirm": { + "type": "integer" + }, + "localConfirmH5": { + "type": "integer" + }, + "local_acc_confirm": { + "type": "integer" + }, + "noInfect": { + "type": "integer" + }, + "noInfectH5": { + "type": "integer" + }, + "nowConfirm": { + "type": "integer" + }, + "nowSevere": { + "type": "integer" + }, + "suspect": { + "type": "integer" + }, + "y": { + "type": "string" + } + } + }, + "models.ChinaDayAdd": { + "type": "object", + "properties": { + "confirm": { + "type": "integer" + }, + "date": { + "type": "string" + }, + "dead": { + "type": "integer" + }, + "deadRate": { + "type": "string" + }, + "heal": { + "type": "integer" + }, + "healRate": { + "type": "string" + }, + "importedCase": { + "type": "integer" + }, + "infect": { + "type": "integer" + }, + "localConfirmadd": { + "type": "integer" + }, + "localinfectionadd": { + "type": "integer" + }, + "suspect": { + "type": "integer" + }, + "y": { + "type": "string" + } + } + }, "models.ChinaTotal": { "type": "object", "properties": { @@ -986,6 +1114,23 @@ const docTemplate = `{ } } }, + "models.ChinaTrend": { + "type": "object", + "properties": { + "ChinaDayList": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ChinaDay" + } + }, + "chinaDayAddList": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ChinaDayAdd" + } + } + } + }, "models.ListArticle": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 37eb012..ff5d86c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -300,6 +300,37 @@ } } }, + "/statistics/china/trend": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Statistics" + ], + "summary": "china trend", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/utils.GinResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/models.ChinaTrend" + } + } + } + ] + } + } + } + } + }, "/statistics/city/{sort}": { "get": { "produces": [ @@ -731,6 +762,9 @@ "name": { "type": "string" }, + "parent": { + "type": "string" + }, "today": { "$ref": "#/definitions/models.AreaToday" }, @@ -929,6 +963,100 @@ } } }, + "models.ChinaDay": { + "type": "object", + "properties": { + "confirm": { + "type": "integer" + }, + "date": { + "type": "string" + }, + "dead": { + "type": "integer" + }, + "deadRate": { + "type": "string" + }, + "heal": { + "type": "integer" + }, + "healRate": { + "type": "string" + }, + "importedCase": { + "type": "integer" + }, + "localConfirm": { + "type": "integer" + }, + "localConfirmH5": { + "type": "integer" + }, + "local_acc_confirm": { + "type": "integer" + }, + "noInfect": { + "type": "integer" + }, + "noInfectH5": { + "type": "integer" + }, + "nowConfirm": { + "type": "integer" + }, + "nowSevere": { + "type": "integer" + }, + "suspect": { + "type": "integer" + }, + "y": { + "type": "string" + } + } + }, + "models.ChinaDayAdd": { + "type": "object", + "properties": { + "confirm": { + "type": "integer" + }, + "date": { + "type": "string" + }, + "dead": { + "type": "integer" + }, + "deadRate": { + "type": "string" + }, + "heal": { + "type": "integer" + }, + "healRate": { + "type": "string" + }, + "importedCase": { + "type": "integer" + }, + "infect": { + "type": "integer" + }, + "localConfirmadd": { + "type": "integer" + }, + "localinfectionadd": { + "type": "integer" + }, + "suspect": { + "type": "integer" + }, + "y": { + "type": "string" + } + } + }, "models.ChinaTotal": { "type": "object", "properties": { @@ -976,6 +1104,23 @@ } } }, + "models.ChinaTrend": { + "type": "object", + "properties": { + "ChinaDayList": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ChinaDay" + } + }, + "chinaDayAddList": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ChinaDayAdd" + } + } + } + }, "models.ListArticle": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4d46eb2..0d09b62 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -7,6 +7,8 @@ definitions: type: array name: type: string + parent: + type: string today: $ref: '#/definitions/models.AreaToday' total: @@ -144,6 +146,68 @@ definitions: chinaTotal: $ref: '#/definitions/models.ChinaTotal' type: object + models.ChinaDay: + properties: + confirm: + type: integer + date: + type: string + dead: + type: integer + deadRate: + type: string + heal: + type: integer + healRate: + type: string + importedCase: + type: integer + local_acc_confirm: + type: integer + localConfirm: + type: integer + localConfirmH5: + type: integer + noInfect: + type: integer + noInfectH5: + type: integer + nowConfirm: + type: integer + nowSevere: + type: integer + suspect: + type: integer + "y": + type: string + type: object + models.ChinaDayAdd: + properties: + confirm: + type: integer + date: + type: string + dead: + type: integer + deadRate: + type: string + heal: + type: integer + healRate: + type: string + importedCase: + type: integer + infect: + type: integer + localConfirmadd: + type: integer + localinfectionadd: + type: integer + suspect: + type: integer + "y": + type: string + type: object models.ChinaTotal: properties: confirm: @@ -175,6 +239,17 @@ definitions: suspect: type: integer type: object + models.ChinaTrend: + properties: + ChinaDayList: + items: + $ref: '#/definitions/models.ChinaDay' + type: array + chinaDayAddList: + items: + $ref: '#/definitions/models.ChinaDayAdd' + type: array + type: object models.ListArticle: properties: cover: @@ -422,6 +497,23 @@ paths: summary: china data tags: - Statistics + /statistics/china/trend: + get: + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/utils.GinResponse' + - properties: + data: + $ref: '#/definitions/models.ChinaTrend' + type: object + summary: china trend + tags: + - Statistics /statistics/city/{sort}: get: parameters: diff --git a/global/global.go b/global/global.go index 7d40c34..ef3ebb4 100644 --- a/global/global.go +++ b/global/global.go @@ -35,10 +35,11 @@ func GetHttpClient(key string) (*http.Client, error) { } const ( - CHINA_NCOV_STATISTIC_URL = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf" - ENV_NOLOG = "nolog" - TOKEN_EXPIRE_DAYS = 15 - FACKER_HOST = "http://myhost.fallen-angle.com:5000/" + CHINA_NCOV_STATISTIC_URL = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf" + CHINA_NCOV_STATISTIC_TREND_URL = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=chinaDayList,chinaDayAddList" + ENV_NOLOG = "nolog" + TOKEN_EXPIRE_DAYS = 15 + FACKER_HOST = "http://myhost.fallen-angle.com:5000/" REGISTER_REDIS_KEY = "register_key" CHANGEPWD_REDIS_KEY = "changepwd_key" @@ -57,4 +58,22 @@ var ( "WORKER": 8, "ADMIN": 12, } + HEALTH_SITUATION_ID_MAP = map[string]int{ + "OTHER": 0, + "PATIENT": 1, + "CONTACT": 2, + "SUB_CONTACT": 3, + } + MEASURE_SITUATION_ID_MAP = map[string]int{ + "NO_MEASURE": 0, + "NO_RISK": 1, + "TREATING": 2, + "CENTRALIZED": 3, + "HOME": 4, + } + PCR_RESULT_ID_MAP = map[string]int{ + "NONE": 0, + "NEGATIVE": 1, + "POSITIVE": 2, + } ) diff --git a/handler/errors.go b/handler/errors.go index 0fd5a71..5d6f57f 100644 --- a/handler/errors.go +++ b/handler/errors.go @@ -9,11 +9,13 @@ import ( // This file is define some business error const ( - BAD_REQUEST = "Bad Request" - DATA_NOT_FOUND = "Data not Found" - STATUS_DATA_NOT_FOUND = 210 - FORBIDDENT = "FORBIDDENT" - PAGE_NOT_FOUND = "404 page not found" + BAD_REQUEST = "Bad Request" + DATA_NOT_FOUND = "Data not Found" + STATUS_DATA_NOT_FOUND = 210 + FORBIDDENT = "FORBIDDENT" + PAGE_NOT_FOUND = "404 page not found" + STATUS_OPERATION_FAILED = 410 + OPERATION_FAILED = "operation failed" ) func RequestError(c *gin.Context, code int, data interface{}) { @@ -40,3 +42,7 @@ func Forbidden(c *gin.Context) { func UrlNotFound(c *gin.Context) { c.String(http.StatusNotFound, PAGE_NOT_FOUND) } + +func OperationFailed(c *gin.Context) { + c.String(STATUS_OPERATION_FAILED, OPERATION_FAILED) +} diff --git a/handler/management.go b/handler/management.go new file mode 100644 index 0000000..436c3b3 --- /dev/null +++ b/handler/management.go @@ -0,0 +1,68 @@ +package handler + +import ( + "nCovTrack-Backend/service/management" + "nCovTrack-Backend/utils" + "strconv" + + "github.com/gin-gonic/gin" +) + +func PullContactHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + patientId, _ := strconv.Atoi(c.Param("patientId")) + rowsAffected := management.PullFromFaker(claims, patientId) + if rowsAffected == -1 { + DataNotFound(c, map[string]interface{}{"patientId": patientId}) + return + } + utils.Succ(c, map[string]interface{}{"pullAmount": rowsAffected}) +} + +func ListObservationsHandler(c *gin.Context) { + jsonMap := bindQuery(c) + utils.Succ(c, management.ListObservation(jsonMap)) +} + +func InsertObservationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + observaion := bindJson(c) + delete(observaion, "id") + ok := management.InsertObservation(claims, observaion) + if ok { + utils.Succ(c, nil) + } else { + OperationFailed(c) + } +} + +func GetObservationHandler(c *gin.Context) { + id, _ := strconv.Atoi(c.Param("id")) + utils.Succ(c, management.GetObservation(id)) +} + +func ListLocationHandler(c *gin.Context) { + queryMap := bindQuery(c) + utils.Succ(c, management.ListLocation(queryMap)) +} + +func InsertLocationHandler(c *gin.Context) { + claims := utils.ClaimsFromHeader(c) + locationMap := bindJson(c) + ok := management.InsertLocation(claims, locationMap) + if ok { + utils.Succ(c, nil) + } else { + OperationFailed(c) + } +} + +func DeleteLocationHandler(c *gin.Context) { + id, _ := strconv.Atoi(c.Param("id")) + ok := management.DeleteLocation(id) + if ok { + utils.Succ(c, nil) + } else { + OperationFailed(c) + } +} diff --git a/handler/statistics.go b/handler/statistics.go index 951057e..ed0b95f 100644 --- a/handler/statistics.go +++ b/handler/statistics.go @@ -57,3 +57,14 @@ func ChinaDataHandler(c *gin.Context) { data := service.GetChinaNCovStatistic() utils.Succ(c, data) } + +// ChinaTrendHandler Get china data +// @Tags Statistics +// @Produce json +// @Summary china trend +// @Success 200 {object} utils.GinResponse{data=models.ChinaTrend} +// @Router /statistics/china/trend [get] +func ChinaTrendHandler(c *gin.Context) { + data := service.GetChinaTrend() + utils.Succ(c, data) +} diff --git a/handler/utils.go b/handler/utils.go index e7eb807..0e760de 100644 --- a/handler/utils.go +++ b/handler/utils.go @@ -2,6 +2,7 @@ package handler import ( "encoding/json" + "github.com/gin-gonic/gin" ) @@ -46,3 +47,12 @@ func bindJsonStruct[T any](c *gin.Context) map[string]interface{} { } return jsonMap } + +func bindQuery(c *gin.Context) map[string]interface{} { + jsonMap := map[string]interface{}{} + queries := c.Request.URL.Query() + for k := range queries { + jsonMap[k] = c.Query(k) + } + return jsonMap +} diff --git a/initialize/cron.go b/initialize/cron.go index adff2a0..f0c11a6 100644 --- a/initialize/cron.go +++ b/initialize/cron.go @@ -10,5 +10,6 @@ func initCron() { c := cron.New() //c.AddFunc("@every 10s", func() { global.Redis.Set("OK", time.Now().String(), time.Duration(10*time.Hour)) }) c.AddFunc("@every 10m", statistics.CacheNCov) + c.AddFunc("@every 8h", statistics.CacheNCovTrend) c.Start() } diff --git a/models/investigate.go b/models/investigate.go deleted file mode 100644 index 4f2df9d..0000000 --- a/models/investigate.go +++ /dev/null @@ -1,63 +0,0 @@ -package models - -import ( - "fmt" - "time" -) - -type FakerDate time.Time - -const ( - timeFormat = "2006-01-02" -) - -func (t *FakerDate) UnmarshalJSON(data []byte) (err error) { - fmt.Println(string(data)) - newTime, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local) - *t = FakerDate(newTime) - return -} - -func (t FakerDate) MarshalJSON() ([]byte, error) { - fmt.Println(time.Time(t).Format(timeFormat)) - timeStr := fmt.Sprintf("\"%s\"", time.Time(t).Format(timeFormat)) - return []byte(timeStr), nil -} - -func (t FakerDate) String() string { - return time.Time(t).Format(timeFormat) -} - -type HotelContactRequest struct { - Name string `json:"name"` - Age int `json:"age,string"` - Sex int `json:"sex,string"` - Phone string `json:"phone"` - Address string `json:"address"` - HotelCode string `json:"hotel_code"` - HotelName string `json:"hotel_name"` - LocateCityId string `json:"locate_city_id"` - Identification string `json:"identification"` - InData FakerDate `json:"in_data"` - OutData FakerDate `json:"out_data"` -} - -type RailwayContactRequest struct { - Name string `json:"name"` - Age int `json:"age,string"` - Sex int `json:"sex,string"` - Phone int `json:"phone"` - Address string `json:"address"` - Train string `json:"train"` - Launch FakerDate `json:"launch"` - Identification string `json:"identification"` -} - -type PatientRequest struct { - Name string `json:"name"` - Age int `json:"age,string"` - Sex int `json:"sex,string"` - Phone string `json:"phone"` - Address string `json:"address"` - Identification string `json:"identification"` -} diff --git a/models/management.go b/models/management.go new file mode 100644 index 0000000..722cf56 --- /dev/null +++ b/models/management.go @@ -0,0 +1,156 @@ +package models + +import ( + "fmt" + "time" +) + +type BackObservation struct { + ID int `gorm:"primaryKey;column:id" json:"id"` // ID + Name string `gorm:"column:name" json:"name"` // 姓名 + Age int `gorm:"column:age" json:"age"` // 年龄 + Sex int `gorm:"column:sex" json:"sex"` // 性别 + Phone string `gorm:"column:phone" json:"phone"` // 手机号码 + Identification string `gorm:"column:identification" json:"identification"` // 身份证号 + ContactPerson int `gorm:"column:contact_person" json:"contactPerson"` // 接触者id + Region string `gorm:"column:region" json:"region"` // 受观察者所在区域 + Address string `gorm:"column:address" json:"address"` // 受观察者所在具体地点 + HealthSituation int `gorm:"column:health_situation" json:"healthSituation"` // 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + HealthChangeTime time.Time `gorm:"column:health_change_time" json:"healthChangeTime"` // 患者健康状况转化时间 + MeasureSituation int `gorm:"column:measure_situation" json:"measureSituation"` // 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + Trajectory string `gorm:"column:trajectory" json:"trajectory"` // 行程轨迹 + CreateUser int `gorm:"column:create_user" json:"createUser"` // 创建者 + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 创建时间 + ModifyUser int `gorm:"column:modify_user" json:"modifyUser"` // 修改者 + ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 修改时间 + IsDelete int `gorm:"column:is_delete" json:"isDelete"` // 删除标志 +} + +type BackLocation struct { + ID int `gorm:"primaryKey;column:id" json:"id"` // ID + Name string `gorm:"column:name" json:"name"` // 地点名 + Region string `gorm:"column:region" json:"region"` // 地点所在地区 + Address string `gorm:"column:address" json:"address"` // 地点的精确地址 + PrincipalName string `gorm:"column:principal_name" json:"principalName"` // 负责人姓名 + PrincipalPhone string `gorm:"column:principal_phone" json:"principalPhone"` // 负责人电话 + CreateUser int `gorm:"column:create_user" json:"createUser"` // 创建者 + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 创建时间 + ModifyUser int `gorm:"column:modify_user" json:"modifyUser"` // 修改者 + ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 修改时间 + IsDelete int `gorm:"column:is_delete" json:"isDelete"` // 删除标志 +} + +type BackPcr struct { + ID int `gorm:"primaryKey;column:id" json:"id"` // ID + Observation int `gorm:"column:observation" json:"observation"` // 观察对象ID + DetectTime time.Time `gorm:"column:detect_time" json:"detectTime"` // 核酸检测时间 + DetectResult int `gorm:"column:detect_result" json:"detectResult"` // 核酸检测结果:0-未检测,1-阴性,2-阳性 + CreateUser int `gorm:"column:create_user" json:"createUser"` // 创建者 + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 创建时间 + ModifyUser int `gorm:"column:modify_user" json:"modifyUser"` // 修改者 + ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 修改时间 + IsDelete int `gorm:"column:is_delete" json:"isDelete"` // 删除标志 +} + +type BackSituationRecord struct { + ID int `gorm:"primaryKey;column:id" json:"id"` // ID + Observation int `gorm:"column:observation" json:"observation"` // 观察对象 + Record string `gorm:"column:record" json:"record"` // 状态转化记录 + CreateUser int `gorm:"column:create_user" json:"createUser"` // 创建者 + CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 创建时间 + ModifyUser int `gorm:"column:modify_user" json:"modifyUser"` // 修改者 + ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 修改时间 + IsDelete int `gorm:"column:is_delete" json:"isDelete"` // 删除标志 +} + +type ListObeservation struct { + ID int `json:"id"` + Name string `json:"name"` // 姓名 + Age int `json:"age"` // 年龄 + Sex int `json:"sex"` // 性别 + Phone string `json:"phone"` // 手机号码 + Identification string `json:"identification"` // 身份证号 + ContactPerson int `json:"contactPerson"` // 接触者id + Region string `json:"region"` // 受观察者所在区域 + Address string `json:"address"` // 受观察者所在具体地点 + HealthSituation int `json:"healthSituation"` // 被观察者的疫情状况:0- 其他,1-患者,2-密接,3-次密接 + HealthChangeTime time.Time `json:"healthChangeTime"` // 患者健康状况转化时间 + MeasureSituation int `json:"measureSituation"` // 受观察者被采取措施状况 :0-未采取措施,1-解除风险,2-正在治疗,3-集中隔离,4-居家隔离 + Trajectory string `json:"trajectory"` // 行程轨迹 + CreateUser int `json:"createUser"` // 创建者 + CreateTime time.Time `json:"createTime"` // 创建时间 + ModifyUser int `json:"modifyUser"` // 修改者 + ModifyTime time.Time `json:"modifyTime"` // 修改时间 + PcrTime time.Time `json:"pcrTime"` //核酸时间 + PcrResult int `json:"pcrResult"` //核酸结果 + RecordTime time.Time `json:"recordTime"` //状态转换时间 + Record string `json:"record"` //状态转换内容 +} + +type QueryObservation struct { + BackObservation + PcrRecord []BackPcr `json:"pcrRecord"` + SituationRecord []BackSituationRecord `json:"situationRecord"` +} + +func init() { + initJcMap[BackObservation]() + initJcMap[BackLocation]() + initJcMap[BackPcr]() + initJcMap[BackSituationRecord]() +} + +type FakerDate time.Time + +const ( + timeFormat = "2006-01-02" +) + +func (t *FakerDate) UnmarshalJSON(data []byte) (err error) { + newTime, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local) + *t = FakerDate(newTime) + return +} + +func (t FakerDate) MarshalJSON() ([]byte, error) { + timeStr := fmt.Sprintf("\"%s\"", time.Time(t).Format(timeFormat)) + return []byte(timeStr), nil +} + +func (t FakerDate) String() string { + return time.Time(t).Format(timeFormat) +} + +type HotelContactRequest struct { + Name string `json:"name"` + Age int `json:"age,string"` + Sex int `json:"sex,string"` + Phone string `json:"phone"` + Address string `json:"address"` + HotelCode string `json:"hotel_code"` + HotelName string `json:"hotel_name"` + LocateCityId string `json:"locate_city_id"` + Identification string `json:"identification"` + InData FakerDate `json:"in_data"` + OutData FakerDate `json:"out_data"` +} + +type RailwayContactRequest struct { + Name string `json:"name"` + Age int `json:"age,string"` + Sex int `json:"sex,string"` + Phone string `json:"phone"` + Address string `json:"address"` + Train string `json:"train"` + Launch FakerDate `json:"launch"` + Identification string `json:"identification"` +} + +type PatientRequest struct { + Name string `json:"name"` + Age int `json:"age,string"` + Sex int `json:"sex,string"` + Phone string `json:"phone"` + Address string `json:"address"` + Identification string `json:"identification"` +} diff --git a/models/notify.go b/models/notify.go new file mode 100644 index 0000000..430461f --- /dev/null +++ b/models/notify.go @@ -0,0 +1,9 @@ +package models + +import "time" + +type BackNotification struct { + Time time.Time `json:"time"` + Kind int `json:"kind"` + Content string `json:"content"` +} diff --git a/models/statistic.go b/models/statistic.go index 47a624d..4e74d9c 100644 --- a/models/statistic.go +++ b/models/statistic.go @@ -59,3 +59,42 @@ type ChinaData struct { ChinaAdd ChinaAdd `json:"chinaAdd"` ChinaTotal ChinaTotal `json:"chinaTotal"` } + +type ChinaDayAdd struct { + DeadRate string `json:"deadRate"` + HealRate string `json:"healRate"` + Date string `json:"date"` + Year string `json:"y"` + Confirm int `json:"confirm"` + Suspect int `json:"suspect"` + Dead int `json:"dead"` + Infect int `json:"infect"` + Heal int `json:"heal"` + ImportedCase int `json:"importedCase"` + Localinfectionadd int `json:"localinfectionadd"` + LocalConfirmadd int `json:"localConfirmadd"` +} + +type ChinaDay struct { + DeadRate string `json:"deadRate"` + NoInfect int `json:"noInfect"` + LocalConfirm int `json:"localConfirm"` + ImportedCase int `json:"importedCase"` + Date string `json:"date"` + LocalConfirmH5 int `json:"localConfirmH5"` + Suspect int `json:"suspect"` + Dead int `json:"dead"` + Heal int `json:"heal"` + Year string `json:"y"` + Confirm int `json:"confirm"` + NowConfirm int `json:"nowConfirm"` + HealRate string `json:"healRate"` + NowSevere int `json:"nowSevere"` + NoInfectH5 int `json:"noInfectH5"` + LocalAccConfirm int `json:"local_acc_confirm"` +} + +type ChinaTrend struct { + ChinaDayList []ChinaDay `json:"ChinaDayList"` + ChinaDayAddList []ChinaDayAdd `json:"chinaDayAddList"` +} diff --git a/models/utils.go b/models/utils.go index e953838..89fdee9 100644 --- a/models/utils.go +++ b/models/utils.go @@ -60,17 +60,60 @@ func MapJ2c[T any](jsonMap map[string]interface{}, ignoreNil bool) (colMap map[s return colMap } +func MapsJ2c[T any](jsonMaps []map[string]interface{}, ignoreNil bool) (colMaps []map[string]interface{}) { + for _, jsonMap := range jsonMaps { + colMap := MapJ2c[T](jsonMap, ignoreNil) + colMaps = append(colMaps, colMap) + } + return colMaps +} + +func MapC2j[T any](colMap map[string]interface{}, ignoreNil bool) (jsonMap map[string]interface{}) { + tName := reflect.TypeOf(new(T)).Elem().Name() + tC2jMap := c2jMap[tName] + if tC2jMap == nil { + panic(tName + " is not init registered int j2cMap") + } + + jsonMap = make(map[string]interface{}) + for k, v := range colMap { + //TODO 无法转换 + if jsonKey := tC2jMap[k]; jsonKey != "" && (!ignoreNil || v != nil) { + jsonMap[jsonKey] = v + } + } + return jsonMap +} + +func MapsC2j[T any](jsonMaps []map[string]interface{}, ignoreNil bool) (colMaps []map[string]interface{}) { + for _, jsonMap := range jsonMaps { + colMap := MapC2j[T](jsonMap, ignoreNil) + colMaps = append(colMaps, colMap) + } + return colMaps +} + // BeforeSave need to set some field while insert or update func BeforeSave(colMap map[string]interface{}, user int) { - if colMap["id"] == nil { + if colMap["id"] == nil || int(colMap["id"].(float64)) == 0 { colMap["create_time"] = time.Now() if user != -1 { colMap["create_user"] = user + } else { + colMap["create_user"] = 0 } } colMap["modify_time"] = time.Now() if user != -1 { colMap["modify_user"] = user + } else { + colMap["modify_user"] = 0 + } +} + +func BeforeBatchSave(colMaps *[]map[string]interface{}, user int) { + for _, colMap := range *colMaps { + BeforeSave(colMap, user) } } @@ -81,7 +124,7 @@ func BeforeSave(colMap map[string]interface{}, user int) { func Upsert[T any](colMap map[string]interface{}) (ok bool, rowsAffected int64) { var tx *gorm.DB - if colMap["id"] == nil { + if colMap["id"] == nil || int(colMap["id"].(float64)) == 0 { tx = global.Db.Model(new(T)).Create(colMap) } else { tx = global.Db.Model(new(T)).Where("id = ?", colMap["id"]).Updates(colMap) @@ -93,6 +136,15 @@ func Upsert[T any](colMap map[string]interface{}) (ok bool, rowsAffected int64) return true, tx.RowsAffected } +func BatchInsert[T any](colMaps []map[string]interface{}) (ok bool, rowsAffected int64) { + tx := global.Db.Model(new(T)).Create(&colMaps) + if tx.Error != nil { + fmt.Println(tx.Error) + return false, 0 + } + return true, tx.RowsAffected +} + func Update[T any](queryMap []map[string]interface{}, updateMap map[string]interface{}) (ok bool, rowsAffected int64) { tx := global.Db.Model(new(T)) for _, e := range queryMap { @@ -120,6 +172,10 @@ func DeleteById[T any](id int) (ok bool, rowsAffected int64) { return true, rowsAffected } +func DropById[T any](id int) { + global.Db.Model(new(T)).Delete("id = ?", id) +} + func List[T any](queryMap []map[string]interface{}) *[]map[string]interface{} { tx := global.Db.Model(new(T)) for _, e := range queryMap { diff --git a/router/investigate.go b/router/investigate.go deleted file mode 100644 index 8306398..0000000 --- a/router/investigate.go +++ /dev/null @@ -1,17 +0,0 @@ -package router - -import ( - "github.com/gin-gonic/gin" - "nCovTrack-Backend/service/investigate" - "net/http" -) - -func investigatePublicRouter(router *gin.RouterGroup) { - investigateRouter := router.Group("investigate") - { - investigateRouter.GET("/test", func(c *gin.Context) { - investigate.QueryHotelContacts() - c.JSON(http.StatusOK, nil) - }) - } -} diff --git a/router/management.go b/router/management.go new file mode 100644 index 0000000..6ab7e52 --- /dev/null +++ b/router/management.go @@ -0,0 +1,17 @@ +package router + +import ( + "nCovTrack-Backend/handler" + + "github.com/gin-gonic/gin" +) + +func managementPublicRouter(router *gin.RouterGroup) { + managementRouter := router.Group("/management") + { + managementRouter.GET("/observation/contact/pull/:patientId", handler.PullContactHandler) + managementRouter.GET("/observation", handler.ListObservationsHandler) + managementRouter.POST("/observation", handler.InsertObservationHandler) + managementRouter.GET("/observation/:id", handler.GetObservationHandler) + } +} diff --git a/router/router.go b/router/router.go index 756e095..651d884 100644 --- a/router/router.go +++ b/router/router.go @@ -15,7 +15,7 @@ func BusiRouter() { statisticRouter(publicRouter) articlePublicRouter(publicRouter) userPublicRouter(publicRouter) - investigatePublicRouter(publicRouter) + managementPublicRouter(publicRouter) } // Private diff --git a/router/statistics.go b/router/statistics.go index 58a9f4c..54ac853 100644 --- a/router/statistics.go +++ b/router/statistics.go @@ -13,5 +13,6 @@ func statisticRouter(router *gin.RouterGroup) { statisticsRouter.GET("/country/child", handler.CountryDataHandler) statisticsRouter.GET("/country", handler.CountryDataHandler) statisticsRouter.GET("/china", handler.ChinaDataHandler) + statisticsRouter.GET("/china/trend", handler.ChinaTrendHandler) } } diff --git a/service/investigate/faker.go b/service/investigate/faker.go deleted file mode 100644 index b51f816..0000000 --- a/service/investigate/faker.go +++ /dev/null @@ -1,46 +0,0 @@ -package investigate - -import ( - "encoding/json" - "nCovTrack-Backend/global" - "nCovTrack-Backend/models" - "nCovTrack-Backend/utils" -) - -func fakerGetRequest(uri string) string { - resStr := utils.GetWhioutHeader(global.FACKER_HOST + uri) - var res utils.GinResponse - _ = json.Unmarshal([]byte(resStr), &res) - dataStr, _ := json.Marshal(res.Data) - return string(dataStr) -} - -func QueryHotelContacts() []models.HotelContactRequest { - dataStr := fakerGetRequest("query/contacts/hotel/320581199103182689") - var data []models.HotelContactRequest - err := json.Unmarshal([]byte(dataStr), &data) - if err != nil { - panic(err) - } - return data -} - -func QueryRailwayContacts() []models.RailwayContactRequest { - dataStr := fakerGetRequest("query/contacts/railway/320581199103182689") - var data []models.RailwayContactRequest - err := json.Unmarshal([]byte(dataStr), &data) - if err != nil { - panic(err) - } - return data -} - -func QueryPatients() []models.PatientRequest { - dataStr := fakerGetRequest("query/contacts/railway/320581199103182689") - var data []models.PatientRequest - err := json.Unmarshal([]byte(dataStr), &data) - if err != nil { - panic(err) - } - return data -} diff --git a/service/investigate/investigate.go b/service/investigate/investigate.go deleted file mode 100644 index 7f35188..0000000 --- a/service/investigate/investigate.go +++ /dev/null @@ -1 +0,0 @@ -package investigate diff --git a/service/management/faker.go b/service/management/faker.go new file mode 100644 index 0000000..559e973 --- /dev/null +++ b/service/management/faker.go @@ -0,0 +1,104 @@ +package management + +import ( + "encoding/json" + "fmt" + "nCovTrack-Backend/global" + "nCovTrack-Backend/models" + "nCovTrack-Backend/utils" + "strings" + "time" +) + +func fakerGetRequest(uri string) string { + resStr := utils.GetWhioutHeader(global.FACKER_HOST + uri) + var res utils.GinResponse + _ = json.Unmarshal([]byte(resStr), &res) + dataStr, _ := json.Marshal(res.Data) + return string(dataStr) +} + +func queryHotelContacts(identification string) []models.HotelContactRequest { + dataStr := fakerGetRequest("query/contacts/hotel/" + identification) + var data []models.HotelContactRequest + err := json.Unmarshal([]byte(dataStr), &data) + if err != nil { + panic(err) + } + return data +} + +func queryRailwayContacts(identification string) []models.RailwayContactRequest { + dataStr := fakerGetRequest("query/contacts/railway/" + identification) + var data []models.RailwayContactRequest + err := json.Unmarshal([]byte(dataStr), &data) + if err != nil { + panic(err) + } + return data +} + +func queryPatients(identification string) []models.PatientRequest { + dataStr := fakerGetRequest("query/contacts/railway/" + identification) + var data []models.PatientRequest + err := json.Unmarshal([]byte(dataStr), &data) + if err != nil { + panic(err) + } + return data +} + +func queryContacts(identification string) []models.BackObservation { + hotelContacts := queryHotelContacts(identification) + railwayContacts := queryRailwayContacts(identification) + observations := append(fakerContacts2Observations(hotelContacts), fakerContacts2Observations(railwayContacts)...) + return observations +} + +func splitFakerAddress(fakerAddress string) string { + addresses := strings.Split(fakerAddress, " ") + return addresses[1] + " " + addresses[2] +} + +func fakerContacts2Observations(contacts any) []models.BackObservation { + var observations []models.BackObservation + switch contacts.(type) { + case []models.HotelContactRequest: + for _, contact := range contacts.([]models.HotelContactRequest) { + tranjectory := fmt.Sprintf("在%s-%s期间,与患者同期留宿%s", contact.InData.String(), contact.OutData.String(), contact.HotelName) + observation := &models.BackObservation{ + Name: contact.Name, + Age: contact.Age, + Sex: contact.Sex, + Phone: contact.Phone, + Identification: contact.Identification, + Region: splitFakerAddress(contact.Address), + Address: "", + HealthSituation: global.HEALTH_SITUATION_ID_MAP["CONTACT"], + HealthChangeTime: time.Now(), + MeasureSituation: global.MEASURE_SITUATION_ID_MAP["NOMEASURE"], + Trajectory: tranjectory, + } + observations = append(observations, *observation) + } + case []models.RailwayContactRequest: + for _, contact := range contacts.([]models.RailwayContactRequest) { + tranjectory := fmt.Sprintf("在%s,与患者同期乘坐%s", contact.Launch.String(), contact.Train) + observation := &models.BackObservation{ + Name: contact.Name, + Age: contact.Age, + Sex: contact.Sex, + Phone: contact.Phone, + Identification: contact.Identification, + Region: splitFakerAddress(contact.Address), + Address: "", + HealthSituation: global.HEALTH_SITUATION_ID_MAP["CONTACT"], + HealthChangeTime: time.Now(), + MeasureSituation: global.MEASURE_SITUATION_ID_MAP["NOMEASURE"], + Trajectory: tranjectory, + } + observations = append(observations, *observation) + } + } + return observations +} diff --git a/service/management/location.go b/service/management/location.go new file mode 100644 index 0000000..5564d4e --- /dev/null +++ b/service/management/location.go @@ -0,0 +1,22 @@ +package management + +import ( + "nCovTrack-Backend/models" +) + +func InsertLocation(claims models.TokenClaims, locationJMap map[string]interface{}) bool { + locationCMap := models.MapJ2c[models.BackLocation](locationJMap, true) + models.BeforeSave(locationCMap, claims.ID) + ok, rowsAffected := models.Upsert[models.BackLocation](locationCMap) + return (ok && rowsAffected != 0) +} + +func ListLocation(queryJMap map[string]any) *[]map[string]any { + queryCMap := models.MapJ2c[models.BackLocation](queryJMap, true) + return models.ListField[models.BackLocation]([]map[string]any{queryCMap}, true, "is_delete") +} + +func DeleteLocation(id int) bool { + ok, rowsAffected := models.DeleteById[models.BackLocation](id) + return (ok && rowsAffected != 0) +} diff --git a/service/management/observation.go b/service/management/observation.go new file mode 100644 index 0000000..8b9e84c --- /dev/null +++ b/service/management/observation.go @@ -0,0 +1,223 @@ +package management + +import ( + "fmt" + "nCovTrack-Backend/global" + "nCovTrack-Backend/models" + "nCovTrack-Backend/utils" + "time" +) + +func PullFromFaker(claims models.TokenClaims, patientId int) int64 { + // Get patient's identification by id + queryMap := []map[string]interface{}{{"id": patientId}} + patient := models.GetField[models.BackObservation](queryMap, false, "identification") + if patient == nil || patient["identification"] == nil { + return -1 + } + + // Pull contacts form faker + observations := queryContacts(patient["identification"].(string)) + // Set ContactPerson + for i := range observations { + observations[i].ContactPerson = patientId + } + // Insert into db + var observationsJMap []map[string]interface{} + utils.Strcut2Map(observations, &observationsJMap) + observationsCMap := models.MapsJ2c[models.BackObservation](observationsJMap, false) + models.BeforeBatchSave(&observationsCMap, claims.ID) + _, rowsAffected := models.BatchInsert[models.BackObservation](observationsCMap) + // Generate situation record + if rowsAffected != 0 { + pullSituationRecord(claims, observations) + } + return rowsAffected +} + +func ListObservation(jsonMap map[string]interface{}) []models.ListObeservation { + colMap := models.MapJ2c[models.BackObservation](jsonMap, true) + queryMap := []map[string]interface{}{colMap} + return listObservation(queryMap) +} + +func GetObservation(id int) map[string]interface{} { + observationCMap := models.GetField[models.BackObservation]([]map[string]interface{}{{"id": id}}, true, "is_delete") + observationJMap := models.MapC2j[models.BackObservation](observationCMap, true) + pcrRecordCMap := models.ListField[models.BackPcr]([]map[string]interface{}{{"observation": id}}, true, "is_delete") + pcrRecordJMap := models.MapsC2j[models.BackPcr](*pcrRecordCMap, true) + situationRecordCMap := models.ListField[models.BackSituationRecord]([]map[string]interface{}{{"observation": id}}, true, "is_delete") + situationRecordJMap := models.MapsC2j[models.BackSituationRecord](*situationRecordCMap, true) + observationJMap["pcrRecord"] = pcrRecordJMap + observationJMap["situationRecord"] = situationRecordJMap + return observationJMap +} + +func InsertObservation(claims models.TokenClaims, jsonMap map[string]interface{}) bool { + colMap := models.MapJ2c[models.BackObservation](jsonMap, true) + models.BeforeSave(colMap, claims.ID) + ok, rowsAffected := models.Upsert[models.BackObservation](colMap) + queryMap := []map[string]interface{}{{"identification": jsonMap["identification"]}} + // Get result after insert, assemble record will use it. + newObservation := models.GetField[models.BackObservation](queryMap, true) + recordOk := insertSituationRecord(claims, map[string]interface{}{}, newObservation) + return (ok && recordOk && rowsAffected != 0) +} + +func UpdateObservation(claims models.TokenClaims, jsonMap map[string]any) bool { + colMap := models.MapJ2c[models.BackObservation](jsonMap, true) + models.BeforeSave(colMap, claims.ID) + oldMap := models.Get[models.BackObservation]([]map[string]interface{}{{"id": jsonMap["id"]}}) + insertSituationRecord(claims, oldMap, colMap) + return false +} + +// listObservation the queryMap need with table name +// @Param queryMap the colMap of models.BackObservation +func listObservation(queryMap []map[string]interface{}) []models.ListObeservation { + var observations []models.ListObeservation + tx := global.Db.Model(new((models.BackObservation))). + Select("back_observation.*, back_pcr.detect_time AS pcr_time, detect_result AS pcr_result," + + "back_situation_record.create_time AS record_time, back_situation_record.record AS record"). + Joins("LEFT JOIN back_pcr ON back_observation.id = back_pcr.observation"). + Joins("LEFT JOIN back_situation_record ON back_observation.id = back_situation_record.observation") + for _, query := range queryMap { + query["is_delete"] = 0 + // Add the table prefix + fullQuery := map[string]interface{}{} + for k := range query { + fullQuery["back_observation."+k] = query[k] + } + tx = tx.Or(fullQuery) + } + tx.Find(&observations) + return observations +} + +func pullSituationRecord(claims models.TokenClaims, observations []models.BackObservation) { + // Query observations' id + var identifications []string + for _, observation := range observations { + identifications = append(identifications, observation.Identification) + } + queryMap := []map[string]interface{}{{"identification": identifications}} + observationMaps := models.ListField[models.BackObservation](queryMap, false, "id", "identification") + // Assemble records + var records []models.BackSituationRecord + recordContent := record00_20() + for _, observationMap := range *observationMaps { + record := models.BackSituationRecord{Observation: observationMap["id"].(int), Record: recordContent} + records = append(records, record) + } + // Insert into db + var recordsJMaps []map[string]interface{} + utils.Strcut2Map(records, &recordsJMaps) + recordsCMaps := models.MapsJ2c[models.BackSituationRecord](recordsJMaps, true) + models.BeforeBatchSave(&recordsCMaps, claims.ID) + models.BatchInsert[models.BackSituationRecord](recordsCMaps) + // Notify the admin of pull region + // Send email to the region admin +} + +func updateObservationRegion(region string) { + // Add to notify + // Send email to the target region amdin +} + +func updateWhileDiagnosis(claims models.TokenClaims, patientId int) { + // Update sub contact to contact and nomeasure + // Add to notify +} + +func insertSituationRecord(claims models.TokenClaims, oldObservation, newObservation map[string]interface{}) bool { + var oldSituation, newSituation string + if oldObservation["id"] == nil { + // insert observation + oldSituation = "00" + } else { + // update observation + oldSituation = fmt.Sprintf("%d%d", oldObservation["health_situation"], oldObservation["measure_situation"]) + } + if newObservation["health_situation"] == nil || newObservation["measure_situation"] == nil { + // Situation not update + return true + } + newSituation = fmt.Sprintf("%d%d", newObservation["health_situation"], newObservation["measure_situation"]) + + // Situation not update + if oldSituation == newSituation { + return true + } + // Set record content accrodding the situation convertions + var recordContent string + situationConvert := oldSituation + "_" + newSituation + switch situationConvert { + case "00_10": + recordContent = record00_10() + case "00_20": + recordContent = record00_20() + case "00_30": + recordContent = record00_30() + case "00_12": + recordContent = record00_12(newObservation["region"].(string), newObservation["address"].(string)) + case "10_12": + recordContent = record10_12(newObservation["region"].(string), newObservation["address"].(string)) + case "12_01", "23_01", "24_01", "33_01", "34_01": + recordContent = record___01() + case "20_23", "30_33", "24_23", "34_33": + recordContent = record____3(newObservation["region"].(string), newObservation["address"].(string)) + case "20_24", "30_34", "23_24", "33_34": + recordContent = record____4(newObservation["region"].(string), newObservation["address"].(string)) + default: + if oldSituation != "00" { + models.Upsert[models.BackObservation](oldObservation) + } else { + models.DropById[models.BackObservation](newObservation["id"].(int)) + } + return false + } + record := models.BackSituationRecord{Observation: newObservation["id"].(int), Record: recordContent} + var recordJMap map[string]interface{} + utils.Strcut2Map(record, &recordJMap) + recordCMap := models.MapJ2c[models.BackSituationRecord](recordJMap, true) + models.BeforeSave(recordCMap, claims.ID) + models.Upsert[models.BackSituationRecord](recordCMap) + return true +} + +func record00_10() string { + date := utils.FormatDate(time.Now()) + return date + " 确诊为患者" +} +func record00_12(region, address string) string { + date := utils.FormatDate(time.Now()) + return fmt.Sprintf("%s 于 %s %s 确诊为患者", date, region, address) +} +func record00_20() string { + date := utils.FormatDate(time.Now()) + return date + " 转为密接" +} +func record00_30() string { + date := utils.FormatDate(time.Now()) + return date + " 转为次密接" +} +func record___01() string { + date := utils.FormatDate(time.Now()) + return fmt.Sprintf("%s 解除风险", date) +} +func record10_12(region, address string) string { + date := utils.FormatDate(time.Now()) + return fmt.Sprintf("%s 转至医院:%s %s", date, region, address) +} +func record___10() string { + date := utils.FormatDate(time.Now()) + return date + " 确诊为患者" +} +func record____3(region, address string) string { + date := utils.FormatDate(time.Now()) + return fmt.Sprintf("%s 集中隔离至:%s %s", date, region, address) +} +func record____4(region, address string) string { + date := utils.FormatDate(time.Now()) + return fmt.Sprintf("%s 进行居家隔离:%s %s", date, region, address) +} diff --git a/service/notify/notify.go b/service/notify/notify.go new file mode 100644 index 0000000..b7e1a06 --- /dev/null +++ b/service/notify/notify.go @@ -0,0 +1,44 @@ +package notify + +import ( + "encoding/json" + "nCovTrack-Backend/global" + "nCovTrack-Backend/models" + "strconv" +) + +const ( + NOTIFY_KEY = "notification_" + NOTIFY_DEL_VALUE = "notify_del" +) + +func InsertNotification(userId int, notification models.BackNotification) { + key := NOTIFY_KEY + strconv.Itoa(userId) + valueStr, _ := json.Marshal(notification) + global.Redis.RPush(key, valueStr) +} + +func DeleteNotification(userId int, index int) { + key := NOTIFY_KEY + strconv.Itoa(userId) + pipe := global.Redis.TxPipeline() + pipe.LSet(key, int64(index), NOTIFY_DEL_VALUE) + pipe.LRem(key, 2, NOTIFY_DEL_VALUE) + pipe.Exec() +} + +func QueryNotificationLen(userId int) int { + key := NOTIFY_KEY + strconv.Itoa(userId) + return int(global.Redis.LLen(key).Val()) +} + +func ListNotifycation(userId int, start, end int) []models.BackNotification { + key := NOTIFY_KEY + strconv.Itoa(userId) + var notifications []models.BackNotification + notificationStrArr := global.Redis.LRange(key, int64(start), int64(end)).Val() + for _, notificationStr := range notificationStrArr { + var notification models.BackNotification + json.Unmarshal([]byte(notificationStr), ¬ification) + notifications = append(notifications, notification) + } + return notifications +} diff --git a/service/statistics/cache.go b/service/statistics/cache.go index 2f002ee..1629089 100644 --- a/service/statistics/cache.go +++ b/service/statistics/cache.go @@ -27,11 +27,13 @@ const ( rds_CITY_LEVEL_TOTAL_CONFIRM_KEY = "cityLevelTotalConfirm" rds_LAST_UPDATE_TIME = "statisticsLastUpdateTime" rds_LAST_CACHE_TIME = "statisticsLastCacheTime" + rds_CHINA_DAY_ADD_LIST_KEY = "chinaDayAdd" + rds_CHINA_DAY_LIST_KEY = "chinaDay" SORT_TODAY_CONFIRM = "today" SORT_TOTAL_CONFIRM = "total" SORT_NOW_CONFIRM = "now" - + D json_FOREIGN_COUNTRY = "境外" json_FOREIGN_CITY = "外地" json_TO_BE_CONFIRM = "待确认" @@ -54,6 +56,22 @@ func cacheNCovStatistics() { cacheChinaInfo(nCovResData) cacheLevelInfo(nCovResData) cacheLastUpdateTime(nCovResData) + resp = utils.GetWhioutHeader(global.CHINA_NCOV_STATISTIC_TREND_URL) +} + +func CacheNCovTrend() { + resp := utils.GetWhioutHeader(global.CHINA_NCOV_STATISTIC_TREND_URL) + var nCovRes map[string]interface{} + json.Unmarshal([]byte(resp), &nCovRes) + nCovResData := nCovRes["data"].(map[string]interface{}) + cacheChinaTrend(nCovResData) +} + +func cacheChinaTrend(data map[string]interface{}) { + chinaDayAdd, _ := json.Marshal(data["chinaDayAddList"]) + chinaDay, _ := json.Marshal(data["chinaDayList"]) + global.Redis.Set(rds_CHINA_DAY_ADD_LIST_KEY, chinaDayAdd, 0) + global.Redis.Set(rds_CHINA_DAY_LIST_KEY, chinaDay, 0) } func cacheChinaInfo(data map[string]interface{}) { diff --git a/service/statistics/statistics.go b/service/statistics/statistics.go index 501a57c..2fa7a45 100644 --- a/service/statistics/statistics.go +++ b/service/statistics/statistics.go @@ -51,6 +51,32 @@ func GetChinaNCovStatistic() models.ChinaData { return data } +func GetChinaDayAdd() []models.ChinaDayAdd { + chinaDayAddStr := global.Redis.Get(rds_CHINA_DAY_ADD_LIST_KEY).Val() + if chinaDayAddStr == "" { + CacheNCovTrend() + chinaDayAddStr = global.Redis.Get(rds_CHINA_DAY_ADD_LIST_KEY).Val() + } + var chinaDayAddList []models.ChinaDayAdd + json.Unmarshal([]byte(chinaDayAddStr), &chinaDayAddList) + return chinaDayAddList +} + +func GetChinaDay() []models.ChinaDay { + chinaDayStr := global.Redis.Get(rds_CHINA_DAY_LIST_KEY).Val() + if chinaDayStr == "" { + CacheNCovTrend() + chinaDayStr = global.Redis.Get(rds_CHINA_DAY_LIST_KEY).Val() + } + var chinaDayList []models.ChinaDay + json.Unmarshal([]byte(chinaDayStr), &chinaDayList) + return chinaDayList +} + +func GetChinaTrend() models.ChinaTrend { + return models.ChinaTrend{ChinaDayAddList: GetChinaDayAdd(), ChinaDayList: GetChinaDay()} +} + func getEntireRedisList(key string) []interface{} { var data []interface{} dataStrArr := global.Redis.LRange(key, 0, -1).Val() diff --git a/service/user/user.go b/service/user/user.go index 7015f49..752c1cf 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -17,7 +17,6 @@ const ( // Login if login success, will return token func Login(user map[string]interface{}) (token string) { - // TODO: need to detect is passed or not account := user["account"].(string) var queryMap []map[string]interface{} if strings.Contains(account, "@") { diff --git a/utils/jwt.go b/utils/jwt.go index ea149de..5ef56e9 100644 --- a/utils/jwt.go +++ b/utils/jwt.go @@ -2,7 +2,6 @@ package utils import ( "encoding/json" - "fmt" "nCovTrack-Backend/global" "nCovTrack-Backend/models" "time" @@ -59,7 +58,7 @@ func RenewToken(tokenStr string) string { if expireDuration.Hours() > float64(global.ServerSettings.Jwt.RenewAheadDays*24) { return tokenStr } - fmt.Println(expireDuration) + //fmt.Println(expireDuration) claims["exp"] = time.Now().Add(global.TOKEN_EXPIRE_DAYS * 24 * time.Hour).Unix() token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims)