diff --git a/app/controllers/lostAndFoundController/create.go b/app/controllers/lostAndFoundController/create.go new file mode 100644 index 0000000..864266c --- /dev/null +++ b/app/controllers/lostAndFoundController/create.go @@ -0,0 +1,52 @@ +package lostAndFoundController + +import ( + "4u-go/app/apiException" + "4u-go/app/models" + "4u-go/app/services/lostAndFoundService" + "4u-go/app/utils" + "github.com/gin-gonic/gin" +) + +type createLostAndFoundData struct { + Type bool `json:"type"` // 1-失物 0-寻物 + Name string `json:"name" binding:"required"` // 物品名称 + Introduction string `json:"introduction" binding:"required"` // 物品介绍 + Campus uint8 `json:"campus" binding:"required"` // 校区 1-朝晖 2-屏峰 3-莫干山 + Kind uint8 `json:"kind"` // 物品种类 1其他2证件3箱包4首饰5现金6电子产品7钥匙 + Place string `json:"place" binding:"required"` // 丢失或拾得地点 + Time string `json:"time" binding:"required"` // 丢失或拾得时间 + Imgs string `json:"imgs" binding:"required"` // 物品图片,多个图片以逗号分隔 + Contact string `json:"contact" binding:"required"` // 联系方式 +} + +// CreateLostAndFound 创建一条失物招领 +func CreateLostAndFound(c *gin.Context) { + var data createLostAndFoundData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + err = lostAndFoundService.SaveLostAndFound(models.LostAndFoundRecord{ + Type: data.Type, + Name: data.Name, + Introduction: data.Introduction, + Campus: data.Campus, + Kind: data.Kind, + Place: data.Place, + Time: data.Time, + Imgs: data.Imgs, + Publisher: utils.GetUser(c).StudentID, + Contact: data.Contact, + IsProcessed: 2, + IsApproved: 2, + }) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, nil) +} diff --git a/app/controllers/lostAndFoundController/delete.go b/app/controllers/lostAndFoundController/delete.go new file mode 100644 index 0000000..50117ce --- /dev/null +++ b/app/controllers/lostAndFoundController/delete.go @@ -0,0 +1,51 @@ +package lostAndFoundController + +import ( + "errors" + + "4u-go/app/apiException" + "4u-go/app/models" + "4u-go/app/services/lostAndFoundService" + "4u-go/app/utils" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type deleteLostAndFoundData struct { + ID uint `json:"id" binding:"required"` +} + +// DeleteLostAndFound 撤回一条失物招领 +func DeleteLostAndFound(c *gin.Context) { + var data deleteLostAndFoundData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + // 判断失物招领是否存在 + record, err := lostAndFoundService.GetLostAndFoundById(data.ID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + apiException.AbortWithException(c, apiException.ResourceNotFound, err) + } else { + apiException.AbortWithException(c, apiException.ServerError, err) + } + return + } + + user := utils.GetUser(c) + if user.Type != models.SuperAdmin && user.Type != models.ForU && user.StudentID != record.Publisher { + apiException.AbortWithException(c, apiException.NotPermission, nil) + return + } + + err = lostAndFoundService.DeleteLostAndFoundById(data.ID) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, nil) +} diff --git a/app/controllers/lostAndFoundController/get.go b/app/controllers/lostAndFoundController/get.go new file mode 100644 index 0000000..a28eafc --- /dev/null +++ b/app/controllers/lostAndFoundController/get.go @@ -0,0 +1,164 @@ +package lostAndFoundController + +import ( + "errors" + + "4u-go/app/apiException" + "4u-go/app/services/lostAndFoundService" + "4u-go/app/utils" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type getLostAndFoundListData struct { + Type bool `json:"type"` // 1-失物 0-寻物 + Campus uint8 `json:"campus" binding:"required"` // 校区 1-朝晖 2-屏峰 3-莫干山 + Kind uint8 `json:"kind"` // 物品种类 0全部1其他2证件3箱包4首饰5现金6电子产品7钥匙 +} +type getLostAndFoundListResponse struct { + LostAndFoundList []lostAndFoundElement `json:"list"` +} +type lostAndFoundElement struct { + ID uint `json:"id"` + Imgs string `json:"imgs"` + Name string `json:"name"` + Place string `json:"place"` + Time string `json:"time"` + Introduction string `json:"introduction"` +} + +// GetLostAndFoundList 获取失物招领列表 +func GetLostAndFoundList(c *gin.Context) { + var data getLostAndFoundListData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + list, err := lostAndFoundService.GetLostAndFoundList(data.Type, data.Campus, data.Kind) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + lostAndFoundList := make([]lostAndFoundElement, 0) + for _, record := range list { + lostAndFoundList = append(lostAndFoundList, lostAndFoundElement{ + ID: record.ID, + Imgs: record.Imgs, + Name: record.Name, + Place: record.Place, + Time: record.Time, + Introduction: record.Introduction, + }) + } + + utils.JsonSuccessResponse(c, getLostAndFoundListResponse{ + LostAndFoundList: lostAndFoundList, + }) +} + +type getLostAndFoundContentData struct { + ID uint `json:"id" binding:"required"` +} + +// GetLostAndFoundContact 获取失物招领联系方式 +func GetLostAndFoundContact(c *gin.Context) { + var data getLostAndFoundContentData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + contact, err := lostAndFoundService.GetLostAndFoundContact(data.ID, utils.GetUser(c).StudentID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + apiException.AbortWithException(c, apiException.ResourceNotFound, err) + } else { + apiException.AbortWithException(c, apiException.ServerError, err) + } + return + } + + utils.JsonSuccessResponse(c, contact) +} + +type latestLostAndFoundResponse struct { + Type bool `json:"type"` + Imgs string `json:"imgs"` + Name string `json:"name"` + Place string `json:"place"` + Introduction string `json:"introduction"` +} + +// GetLatestLostAndFound 获取最新失物招领 +func GetLatestLostAndFound(c *gin.Context) { + record, err := lostAndFoundService.GetLatestLostAndFound() + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, latestLostAndFoundResponse{ + Type: record.Type, + Imgs: record.Imgs, + Name: record.Name, + Place: record.Place, + Introduction: record.Introduction, + }) +} + +type getLostAndFoundStatusData struct { + Status uint8 `json:"status"` // 状态 0-已撤回 1-已审核 2-审核中 +} +type getLostAndFoundStatusResponse struct { + List []lostAndFoundStatusElement `json:"list"` +} +type lostAndFoundStatusElement struct { + ID uint `json:"id"` + Type bool `json:"type"` + Imgs string `json:"imgs"` + Name string `json:"name"` + Kind uint8 `json:"kind"` + Place string `json:"place"` + Time string `json:"time"` + Introduction string `json:"introduction"` + IsApproved uint8 `json:"is_approved"` +} + +// GetUserLostAndFoundStatus 查看失物招领信息的状态 +func GetUserLostAndFoundStatus(c *gin.Context) { + var data getLostAndFoundStatusData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + list, err := lostAndFoundService.GetUserLostAndFoundStatus(utils.GetUser(c).StudentID, data.Status) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + lostAndFoundList := make([]lostAndFoundStatusElement, 0) + for _, record := range list { + lostAndFoundList = append(lostAndFoundList, lostAndFoundStatusElement{ + ID: record.ID, + Type: record.Type, + Imgs: record.Imgs, + Name: record.Name, + Kind: record.Kind, + Place: record.Place, + Time: record.Time, + Introduction: record.Introduction, + IsApproved: record.IsApproved, + }) + } + + utils.JsonSuccessResponse(c, getLostAndFoundStatusResponse{ + List: lostAndFoundList, + }) +} diff --git a/app/controllers/lostAndFoundController/update.go b/app/controllers/lostAndFoundController/update.go new file mode 100644 index 0000000..e0825ad --- /dev/null +++ b/app/controllers/lostAndFoundController/update.go @@ -0,0 +1,152 @@ +package lostAndFoundController + +import ( + "errors" + + "4u-go/app/apiException" + "4u-go/app/models" + "4u-go/app/services/lostAndFoundService" + "4u-go/app/utils" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type reviewLostAndFoundData struct { + ID uint `json:"id" binding:"required"` + IsApproved bool `json:"is_approved"` +} + +// ReviewLostAndFound 审核失物招领 +func ReviewLostAndFound(c *gin.Context) { + var data reviewLostAndFoundData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + // 判断失物招领是否存在 + _, err = lostAndFoundService.GetLostAndFoundById(data.ID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + apiException.AbortWithException(c, apiException.ResourceNotFound, err) + } else { + apiException.AbortWithException(c, apiException.ServerError, err) + } + return + } + + err = lostAndFoundService.ReviewLostAndFound(data.ID, data.IsApproved) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, nil) +} + +type updateLostAndFoundData struct { + ID uint `json:"id" binding:"required"` + Type bool `json:"type"` // 1-失物 0-寻物 + Name string `json:"name"` // 物品名称 + Introduction string `json:"introduction"` // 物品介绍 + Campus uint8 `json:"campus"` // 校区 1-朝晖 2-屏峰 3-莫干山 + Kind uint8 `json:"kind"` // 物品种类 1其他2证件3箱包4首饰5现金6电子产品7钥匙 + Place string `json:"place"` // 丢失或拾得地点 + Time string `json:"time"` // 丢失或拾得时间 + Imgs string `json:"imgs"` // 物品图片,多个图片以逗号分隔 + PickupPlace string `json:"pickup_place"` // 失物领取地点 + Contact string `json:"contact"` // 联系方式 +} + +// UpdateLostAndFound 修改失物招领 +func UpdateLostAndFound(c *gin.Context) { + var data updateLostAndFoundData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + // 判断失物招领是否存在 + record, err := lostAndFoundService.GetLostAndFoundById(data.ID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + apiException.AbortWithException(c, apiException.ResourceNotFound, err) + } else { + apiException.AbortWithException(c, apiException.ServerError, err) + } + return + } + + user := utils.GetUser(c) + if user.Type != models.SuperAdmin && user.Type != models.ForU { + apiException.AbortWithException(c, apiException.NotPermission, nil) + return + } + + { // 更新失物招领信息 + record.Type = data.Type + record.Name = data.Name + record.Introduction = data.Introduction + record.Campus = data.Campus + record.Kind = data.Kind + record.Place = data.Place + record.Time = data.Time + record.Imgs = data.Imgs + record.Contact = data.Contact + record.IsApproved = 2 + record.IsProcessed = 2 + } + + err = lostAndFoundService.SaveLostAndFound(record) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, nil) +} + +type updateLostAndFoundStatusData struct { + ID uint `json:"id" binding:"required"` +} + +// UpdateLostAndFoundStatus 用户设置失物招领为已完成 +func UpdateLostAndFoundStatus(c *gin.Context) { + var data updateLostAndFoundStatusData + err := c.ShouldBindJSON(&data) + if err != nil { + apiException.AbortWithException(c, apiException.ParamError, err) + return + } + + // 判断失物招领是否存在 + record, err := lostAndFoundService.GetLostAndFoundById(data.ID) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + apiException.AbortWithException(c, apiException.ResourceNotFound, err) + } else { + apiException.AbortWithException(c, apiException.ServerError, err) + } + return + } + + user := utils.GetUser(c) + if user.StudentID != record.Publisher { + apiException.AbortWithException(c, apiException.NotPermission, nil) + return + } + + { // 更新失物招领信息 + record.IsProcessed = 1 + } + + err = lostAndFoundService.SaveLostAndFound(record) + if err != nil { + apiException.AbortWithException(c, apiException.ServerError, err) + return + } + + utils.JsonSuccessResponse(c, nil) +} diff --git a/app/models/contactViewRecord.go b/app/models/contactViewRecord.go new file mode 100644 index 0000000..5d1b7e8 --- /dev/null +++ b/app/models/contactViewRecord.go @@ -0,0 +1,11 @@ +package models + +import "time" + +// ContactViewRecord 联系方式查看记录的结构体 +type ContactViewRecord struct { + ID uint `json:"id"` + RecordID uint `json:"record_id"` // 失物招领记录编号 + StudentID string `json:"-"` // 查看者学号 + CreatedAt time.Time `json:"created_at" gorm:"type:timestamp;"` // 记录创建时间 +} diff --git a/app/models/lostAndFoundRecord.go b/app/models/lostAndFoundRecord.go index 3a6f952..ca0e82e 100644 --- a/app/models/lostAndFoundRecord.go +++ b/app/models/lostAndFoundRecord.go @@ -4,18 +4,18 @@ import "time" // LostAndFoundRecord 失物招领记录的结构体 type LostAndFoundRecord struct { - ID uint `json:"id"` - Type bool `json:"type"` // 1-失物 0-寻物 - ItemName string `json:"item_name"` // 物品名称 - Introduction string `json:"introduction"` // 物品介绍 - Campus uint8 `json:"campus"` // 校区 1-朝晖 2-屏峰 3-莫干山 - Kind string `json:"kind"` // 物品种类 0其他1证件2箱包3首饰4现金5电子产品6钥匙 - LostOrFoundPlace string `json:"lost_or_found_place"` // 丢失或拾得地点 - LostOrFoundTime string `json:"lost_or_found_time"` // 丢失或拾得时间 - Imgs string `json:"imgs"` // 物品图片,多个图片以逗号分隔 - Publisher string `json:"publisher"` // 发布者 - PickupPlace string `json:"pickup_place"` // 失物领取地点 - Contact string `json:"contact"` // 寻物联系方式 - PublishTime time.Time `json:"publish_time" gorm:"type:timestamp;"` // 发布时间 - IsProcessed bool `json:"-"` // 是否已处理 + ID uint `json:"id"` + Type bool `json:"type"` // 1-失物 0-寻物 + Name string `json:"name"` // 物品名称 + Introduction string `json:"introduction"` // 物品介绍 + Campus uint8 `json:"campus"` // 校区 1-朝晖 2-屏峰 3-莫干山 + Kind uint8 `json:"kind"` // 物品种类 1其他2证件3箱包4首饰5现金6电子产品7钥匙 + Place string `json:"place"` // 丢失或拾得地点 + Time string `json:"time"` // 丢失或拾得时间 + Imgs string `json:"imgs"` // 物品图片,多个图片以逗号分隔 + Contact string `json:"contact"` // 联系方式 + CreatedAt time.Time `json:"created_at" gorm:"type:timestamp;"` // 发布时间 + IsProcessed uint8 `json:"is_processed"` // 是否完成 0-已取消 1-已完成 2-进行中 + Publisher string `json:"-"` // 发布者 + IsApproved uint8 `json:"-"` // 是否审核通过 0-未通过 1-已通过 2-待审核 } diff --git a/app/services/lostAndFoundService/delete.go b/app/services/lostAndFoundService/delete.go new file mode 100644 index 0000000..82c1be5 --- /dev/null +++ b/app/services/lostAndFoundService/delete.go @@ -0,0 +1,12 @@ +package lostAndFoundService + +import ( + "4u-go/app/models" + "4u-go/config/database" +) + +// DeleteLostAndFoundById 通过 ID 撤回一条失物招领 +func DeleteLostAndFoundById(recordId uint) error { + result := database.DB.Model(&models.LostAndFoundRecord{}).Where("id = ?", recordId).Update("is_processed", 0) + return result.Error +} diff --git a/app/services/lostAndFoundService/get.go b/app/services/lostAndFoundService/get.go new file mode 100644 index 0000000..e7fd56d --- /dev/null +++ b/app/services/lostAndFoundService/get.go @@ -0,0 +1,69 @@ +package lostAndFoundService + +import ( + "4u-go/app/models" + "4u-go/config/database" +) + +// GetLostAndFoundById 获取指定ID的失物招领 +func GetLostAndFoundById(id uint) (record models.LostAndFoundRecord, err error) { + result := database.DB.Where("id = ?", id).First(&record) + err = result.Error + return record, err +} + +// GetLostAndFoundList 获取失物招领列表 +func GetLostAndFoundList(Type bool, campus, kind uint8) (records []models.LostAndFoundRecord, err error) { + if kind == 0 { + result := database.DB.Where("type = ? AND campus = ? AND is_processed = 2 AND is_approved = 1", Type, campus).Order("created_at desc").Find(&records) + err = result.Error + return records, err + } else { + result := database.DB.Where("type = ? AND campus = ? AND kind = ? AND is_processed = 2 AND is_approved = 1", Type, campus, kind).Order("created_at desc").Find(&records) + err = result.Error + return records, err + } +} + +// GetLostAndFoundContact 获取失物招领联系方式 +func GetLostAndFoundContact(id uint, studentID string) (contact string, err error) { + result, err := GetLostAndFoundById(id) + if err != nil { + return "", err + } else { + var record models.ContactViewRecord + record.RecordID = id + record.StudentID = studentID + res := database.DB.Save(&record) + if res.Error != nil { + return "", res.Error + } else { + return result.Contact, nil + } + } +} + +// GetLatestLostAndFound 获取最新失物招领 +func GetLatestLostAndFound() (record models.LostAndFoundRecord, err error) { + result := database.DB.Where("is_processed = 2 AND is_approved = 1").Order("created_at desc").First(&record) + err = result.Error + return record, err +} + +// GetUserLostAndFoundStatus 查看失物招领信息的状态 +func GetUserLostAndFoundStatus(publisher string, status uint8) (records []models.LostAndFoundRecord, err error) { + if status == 0 { + result := database.DB.Where("publisher = ? AND is_processed = ?", publisher, 0).Order("created_at desc").Find(&records) + err = result.Error + return records, err + } else if status == 1 { + result := database.DB.Where("publisher = ? AND (is_approved = 0 OR is_approved = 1)", publisher).Order("created_at desc").Find(&records) + err = result.Error + return records, err + } else { + result := database.DB.Where("publisher = ? AND is_approved = ?", publisher, 2).Order("created_at desc").Find(&records) + err = result.Error + return records, err + + } +} diff --git a/app/services/lostAndFoundService/save.go b/app/services/lostAndFoundService/save.go new file mode 100644 index 0000000..28f6caa --- /dev/null +++ b/app/services/lostAndFoundService/save.go @@ -0,0 +1,12 @@ +package lostAndFoundService + +import ( + "4u-go/app/models" + "4u-go/config/database" +) + +// SaveLostAndFound 向数据库中保存一条失物招领 +func SaveLostAndFound(record models.LostAndFoundRecord) error { + result := database.DB.Save(&record) + return result.Error +} diff --git a/app/services/lostAndFoundService/update.go b/app/services/lostAndFoundService/update.go new file mode 100644 index 0000000..a6df7af --- /dev/null +++ b/app/services/lostAndFoundService/update.go @@ -0,0 +1,16 @@ +package lostAndFoundService + +import ( + "4u-go/app/models" + "4u-go/config/database" +) + +// ReviewLostAndFound 审核失物招领 +func ReviewLostAndFound(recordId uint, isApproved bool) error { + if isApproved == true { + result := database.DB.Model(&models.LostAndFoundRecord{}).Where("id = ?", recordId).Updates(map[string]interface{}{"is_approved": 1, "is_processed": 2}) + return result.Error + } + result := database.DB.Model(&models.LostAndFoundRecord{}).Where("id = ?", recordId).Updates(map[string]interface{}{"is_approved": 0, "is_processed": 1}) + return result.Error +} diff --git a/config/database/migrations.go b/config/database/migrations.go index 3716902..b7d9b46 100755 --- a/config/database/migrations.go +++ b/config/database/migrations.go @@ -14,5 +14,6 @@ func autoMigrate(db *gorm.DB) error { &models.LostAndFoundRecord{}, &models.Website{}, &models.College{}, + &models.ContactViewRecord{}, ) } diff --git a/config/router/router.go b/config/router/router.go index 0cf6f65..a6ba629 100644 --- a/config/router/router.go +++ b/config/router/router.go @@ -5,6 +5,7 @@ import ( "4u-go/app/controllers/adminController" "4u-go/app/controllers/announcementController" "4u-go/app/controllers/collegeController" + "4u-go/app/controllers/lostAndFoundController" "4u-go/app/controllers/objectController" "4u-go/app/controllers/userController" "4u-go/app/controllers/websiteController" @@ -73,5 +74,18 @@ func Init(r *gin.Engine) { website.GET("/admin", midwares.CheckAdmin, websiteController.GetEditableWebsites) } + + lostAndFound := api.Group("/lost-and-found") + { + lostAndFound.POST("", midwares.CheckLogin, lostAndFoundController.CreateLostAndFound) + lostAndFound.DELETE("", midwares.CheckLogin, lostAndFoundController.DeleteLostAndFound) + lostAndFound.PUT("", midwares.CheckAdmin, lostAndFoundController.ReviewLostAndFound) + lostAndFound.PUT("/admin", midwares.CheckLogin, lostAndFoundController.UpdateLostAndFound) + lostAndFound.GET("/list", lostAndFoundController.GetLostAndFoundList) + lostAndFound.GET("", midwares.CheckLogin, lostAndFoundController.GetLostAndFoundContact) + lostAndFound.GET("/latest", lostAndFoundController.GetLatestLostAndFound) + lostAndFound.GET("/user", midwares.CheckLogin, lostAndFoundController.GetUserLostAndFoundStatus) + lostAndFound.PUT("/user", midwares.CheckLogin, lostAndFoundController.UpdateLostAndFoundStatus) + } } }