pax_global_header 0000666 0000000 0000000 00000000064 13631640576 0014525 g ustar 00root root 0000000 0000000 52 comment=c1e5407407cdb8467f1e261b67e8755c9ac57388 leyoutu_server.git/ 0000775 0000000 0000000 00000000000 13631640576 0014747 5 ustar 00root root 0000000 0000000 leyoutu_server.git/.gitignore 0000664 0000000 0000000 00000000046 13631640576 0016737 0 ustar 00root root 0000000 0000000 main tiles Upload Console Bin/Monitor leyoutu_server.git/API/ 0000775 0000000 0000000 00000000000 13631640576 0015360 5 ustar 00root root 0000000 0000000 leyoutu_server.git/API/Complaint.go 0000664 0000000 0000000 00000006543 13631640576 0017645 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "math" "regexp" "strconv" "time" ) // @Title 增加投诉 // @Description 投诉 - 增加投诉 // @Accept json // @Produce json // @Param Mobile 18616619599 string true "联系电话" // @Param Name 高先生 string true "姓名" // @Param Code 123456 string true "验证码" // @Param Sex 男 string true "性别" // @Param ScenicId 5e1ed07524e03431008b4572 string true "景区id" // @Param Type 1 string true "类型" // @Param Content 卫生不干净 string true "投诉内容" // @Param Image ["http://www.xx.com/123.jpg","http://www.xx.com/123.jpg"] string true "照片数组" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /CreateComplaint? [post] func CreateComplaint(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") reg := regexp.MustCompile(Regular) if !reg.MatchString(c.PostForm("Mobile")) { c.JSON(200, tools.ResponseError{ 1, "手机号格式不正确", }) return } if c.PostForm("Mobile") == "" { c.JSON(200, tools.ResponseError{ 1, "手机号为空", }) return } // 检查验证码 cacheCode := DB.Redis.Get("code_" + c.PostForm("Mobile")) if cacheCode != c.PostForm("Code") { c.JSON(200, tools.ResponseError{ 1, "验证码不正确", }) return } var images []string json.Unmarshal([]byte(c.PostForm("Image")), &images) DB.CComplaint.InsertOne(tools.GetContext(), DB.SComplaint{ c.PostForm("Type"), c.PostForm("ScenicId"), c.PostForm("Mobile"), c.PostForm("Name"), c.PostForm("Sex"), c.PostForm("Content"), images, "", time.Now().Unix(), }) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 查询所有投诉 // @Description 投诉 - 查询所有投诉 // @Accept json // @Produce json // @Param Page 1 int true "当前第几页" // @Success 200 {object} tools.ResponseSeccess "" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllComplaint? [get] func AllComplaint(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") total, _ := DB.CComplaint.CountDocuments(tools.GetContext(), bson.M{}) limit, _ := strconv.ParseInt(c.Query("Limit"),10,64) if limit == 0 { limit = 50 } currPage, _ := strconv.ParseInt(c.Query("Page"),10,64) if currPage == 0 { currPage = 1 } skip := (currPage - 1) * limit var aComplaint = []bson.M{} cur, err := DB.CComplaint.Find(tools.GetContext(), bson.M{}, &options.FindOptions{Limit: &limit, Skip: &skip, Sort: bson.M{"_id": -1}}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e bson.M cur.Decode(&e) aComplaint = append(aComplaint,e) } } c.JSON(200, tools.Page{ 0, total, currPage, int(math.Ceil(float64(total) / float64(limit))), limit, aComplaint, }) } leyoutu_server.git/API/DealyMessage.go 0000664 0000000 0000000 00000010661 13631640576 0020256 0 ustar 00root root 0000000 0000000 package Api import ( "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "letu/Lib/DelayMessage" "letu/Lib/Token" ) // @Title 查询用户的定时提醒 // @Description 查询用户的定时提醒 // @Accept json // @Produce json // @Param UserId 5dfb03070a9ac17ac7a82054 string true "用户id" // @Param Token wgergejfwe string true "用户token" // @Success 200 {object} tools.ResponseSeccess "DelayTime=执行时间;Type=类型(0请求url地址1发送app通知);Fail失败次数;Title=通知标题;Content=通知内容;UDID=设备id" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /DealyMessage/Info? [get] func DealyMessageInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") _, err := primitive.ObjectIDFromHex(c.Query("UserId")) if c.Query("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.Query("UserId")) != c.Query("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } var aDelayMessage []DelayMessage.Message cur, err := DelayMessage.CDelayMessage.Find(tools.GetContext(), bson.M{"UserId": c.Query("UserId")}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DelayMessage.Message cur.Decode(&e) aDelayMessage = append(aDelayMessage,e) } } if aDelayMessage == nil { aDelayMessage = []DelayMessage.Message{} } c.JSON(200, tools.ResponseSeccess{ 0, aDelayMessage, }) } // @Title 创建提醒 // @Description 创建提醒 // @Accept json // @Produce json // @Param UserId 5dfb03070a9ac17ac7a82054 string true "用户id" // @Param Token wgergejfwe string true "用户token" // @Param UDID 5dfb03070a9ac17ac7a82054 string true "设备id" // @Param Title 表演时间提醒 string true "标题" // @Param Content 5分钟后有表演 string true "内容" // @Param DelayTime 1579066863 string true "到达这个时间戳就执行" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /DealyMessage/Create? [post] func CreateDealyMessage(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") _,err := primitive.ObjectIDFromHex(c.PostForm("UserId")) if c.PostForm("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.PostForm("UserId")) != c.PostForm("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } err = DelayMessage.GlobalDM.AddTaskForAppMessage(c.PostForm("DelayTime"), c.PostForm("UDID"), c.PostForm("Title"), c.PostForm("Content"), c.PostForm("UserId")) if err == nil { c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } else { c.JSON(200, tools.ResponseError{ 1, err.Error(), }) } } // @Title 删除提醒 // @Description 删除提醒 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "提醒id" // @Param UserId 5dfb03070a9ac17ac7a82054 string true "用户id" // @Param Token wgergejfwe string true "用户token" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /DealyMessage/Remove? [post] func RemoveDealyMessage(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") _,err := primitive.ObjectIDFromHex(c.PostForm("UserId")) if c.PostForm("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.PostForm("UserId")) != c.PostForm("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } DelayMessage.GlobalDM.DelTaskForId(c.PostForm("id")) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } leyoutu_server.git/API/Icon.go 0000664 0000000 0000000 00000006547 13631640576 0016613 0 ustar 00root root 0000000 0000000 package Api import ( "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" ) // @Title 返回图标基础信息 // @Description 图标管理 - 返回图标基础信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "图标id" // @Success 200 {object} tools.ResponseSeccess "Name名称:Picture图片地址:id图标id" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Icon/Info? [get] func IconInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Query("id") == "" { c.JSON(200, tools.ResponseError{ 1, "id为空", }) return } var SIcon *DB.SIcons objID, _ := primitive.ObjectIDFromHex(c.Query("id")) DB.CIcons.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&SIcon) c.JSON(200, tools.ResponseSeccess{ 0, SIcon, }) } // @Title 更新图标信息 // @Description 图标管理 - 增加或修改图标信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "图标id" // @Success 200 {object} tools.ResponseSeccess "Name名称:Picture图片地址:id图标id:ScenicId景区id" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Icon/Update? [post] func UpdateIcon(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId := c.PostForm("ScenicId") if ScenicId == "" || ScenicId == "undefined" { c.JSON(200, tools.ResponseError{ 1, "缺少ScenicId(景区id)", }) return } var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() } else { id, _ = primitive.ObjectIDFromHex(pid) } upsert := true DB.CIcons.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "Name": c.PostForm("Name"), "Picture": c.PostForm("Picture"), "ScenicId": ScenicId, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 所有图标 // @Description 图标管理 - 所有图标 // @Accept json // @Produce json // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Success 200 {object} tools.ResponseSeccess "Name名称:Picture图片地址:id图标id:ScenicId景区id" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Icon/All? [get] func AllIcons(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId := c.Query("ScenicId") if ScenicId == "" || ScenicId == "undefined" { c.JSON(200, tools.ResponseError{ 1, "缺少ScenicId(景区id)", }) return } var SIcons = []DB.SIcons{} cur, err := DB.CIcons.Find(tools.GetContext(), bson.M{"ScenicId": ScenicId}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SIcons cur.Decode(&e) SIcons = append(SIcons,e) } } c.JSON(200, tools.ResponseSeccess{ 0, SIcons, }) } leyoutu_server.git/API/Investigation.go 0000664 0000000 0000000 00000004766 13631640576 0020547 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "math" "strconv" ) // @Title 增加调查 // @Description 问券调查 - 增加调查 // @Accept json // @Produce json // @Param UserId 1111111 string true "UserId" // @Param Mobile 18616619599 string true "联系电话" // @Param type 1 string true "类型" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Investigation/Save? [post] func SaveInvestigation(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Data map[string]interface{} json.Unmarshal([]byte(c.PostForm("Data")), &Data) DB.CInvestigation.InsertOne(tools.GetContext(),DB.SInvestigation{ c.PostForm("UserId"), c.PostForm("Mobile"), Data, }) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 查询所有问券调查 // @Description 问券调查 - 查询所有问券调查 // @Accept json // @Produce json // @Param Page 1 int true "当前第几页" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"total":1,"currpage":1,"totalpages":1,"prepage":20,"result":}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Investigation/List? [get] func AllInvestigation(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") total,_ := DB.CComplaint.CountDocuments(tools.GetContext(), bson.M{}) limit, _ := strconv.ParseInt(c.Query("Limit"),10,64) if limit == 0 { limit = 50 } currPage, _ := strconv.ParseInt(c.Query("Page"),10,64) if currPage == 0 { currPage = 1 } skip := (currPage - 1) * limit var aInvestigation []DB.SInvestigation cur, err := DB.CInvestigation.Find(tools.GetContext(), bson.M{}, &options.FindOptions{Limit: &limit, Skip: &skip, Sort: bson.M{"_id": -1}}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SInvestigation cur.Decode(&e) aInvestigation = append(aInvestigation,e) } } c.JSON(200, tools.Page{ 0, total, currPage, int(math.Ceil(float64(total) / float64(limit))), limit, aInvestigation, }) } leyoutu_server.git/API/Item.go 0000664 0000000 0000000 00000015415 13631640576 0016613 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "strconv" "time" ) // @Title 查询设备信息 // @Description 设备管理 - 查询设备信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "设备id" // @Success 200 {object} tools.ResponseSeccess "Tags所属标签,标签有分类;LimitHeight限高;PlayDuration游玩时长;SceneTime场次时间;Picture照片;Voice音频;AverageConsumption平均消费;Menu菜单, OpenHours开放时间: LocationDescription位置描述; Reminder温馨提示; State运行状态0=正常1=停运" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /ItemInfo? [get] func ItemInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Query("id") == "" { c.JSON(200, tools.ResponseError{ 1, "空", }) return } var SItem DB.SItem objID,_ := primitive.ObjectIDFromHex(c.Query("id")) DB.CItem.FindOne(tools.GetContext(),bson.M{"_id": objID}).Decode(&SItem) c.JSON(200, tools.ResponseSeccess{ 0, SItem, }) } // @Title 查询所有游玩项目 // @Description 设备管理 - 查询所有游玩项目 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "Tags所属标签,标签有分类;LimitHeight限高;PlayDuration游玩时长;SceneTime场次时间;Picture照片;Voice音频;AverageConsumption平均消费;Menu菜单, OpenHours开放时间: LocationDescription位置描述; Reminder温馨提示; State运行状态0=正常1=停运" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllItems? [get] func AllItems(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var aItems = []DB.SItem{} cur, err := DB.CItem.Find(tools.GetContext(), bson.M{}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SItem cur.Decode(&e) aItems = append(aItems,e) } } c.JSON(200, aItems) } // @Title 更新设施 // @Description 设备管理 - 更新设施 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "Tags所属标签,标签有分类;LimitHeight限高;PlayDuration游玩时长;SceneTime场次时间;Picture照片;Voice音频;AverageConsumption平均消费;Menu菜单, OpenHours开放时间: LocationDescription位置描述; Reminder温馨提示; State运行状态0=正常1=停运" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateItem? [post] func UpdateItem(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Location DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) var Tags []DB.STag json.Unmarshal([]byte(c.PostForm("Tags")), &Tags) var Picture []string json.Unmarshal([]byte(c.PostForm("Picture")), &Picture) var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() } else { id,_ = primitive.ObjectIDFromHex(pid) } poststate, _ := strconv.Atoi(c.PostForm("State")) upsert := true DB.CItem.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "Name": c.PostForm("Name"), "SubName": c.PostForm("SubName"), "Location": Location, "Icon": c.PostForm("Icon"), "LimitHeight": c.PostForm("LimitHeight"), "PlayDuration": c.PostForm("PlayDuration"), "SceneTime": c.PostForm("SceneTime"), "Picture": Picture, "Voice": c.PostForm("Voice"), "Tel": c.PostForm("Tel"), "AverageConsumption": c.PostForm("AverageConsumption"), "Menu": c.PostForm("Menu"), "Tags": Tags, "OpenHours": c.PostForm("OpenHours"), "LocationDescription": c.PostForm("LocationDescription"), "Reminder": c.PostForm("Reminder"), "State": poststate, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) // 更新等待时间 allteim := DB.Redis.Get("AllItemTime") jsond,_ := json.Marshal(allteim) var ItemTime map[string]string json.Unmarshal([]byte(jsond), &ItemTime) if poststate == 1{ ItemTime[c.PostForm("id")] = "--" } if poststate == 0{ ItemTime[c.PostForm("id")] = "0" } DB.Redis.Set("AllItemTime", ItemTime, time.Second*60*60*24*30) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } type ItemTime struct { Id string `json:"id"` Time string `json:"time"` } // @Title 更新等待时间 // @Description 设备管理 - 更新等待时间 // @Accept json // @Produce json // @Param item [{"id":"5df864740a9ac17ac7a7feb8","time":"20"},{"id":"5df8660924e03417008b4567","time":"33"}] string true "设备列表" // @Success 200 {object} tools.ResponseSeccess "{errcode: 0, result: "ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateItemTime? [post] func UpdateItemTime(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var ItemTime []ItemTime json.Unmarshal([]byte(c.PostForm("items")), &ItemTime) var RedisData = make(map[string]string) for _, v := range ItemTime { RedisData[v.Id] = v.Time } DB.Redis.Set("AllItemTime", RedisData, time.Second*60*60*24*30) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 获得所有设备的等待时间 // @Description 设备管理 - 获得所有设备的等待时间 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "{5df864740a9ac17ac7a7feb8: '20',.....}" // @Failure 500 {object} tools.ResponseError "{}" // @Router /AllItemTime? [get] func AllItemTime(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") //Device := DB.SDevice{ // c.Request.Header.Get("DeviceId"), // c.Request.Header.Get("Mac"), // c.Request.Header.Get("UDID"), // c.Request.Header.Get("SystemVersion"), // c.Request.Header.Get("SystemModel"), // c.Request.Header.Get("AppVersion"), // c.Request.Header.Get("AppVersion"), // c.Request.Header.Get("DeviceToken"), //} //spew.Dump(Device) allteim := DB.Redis.Get("AllItemTime") if allteim != nil { c.JSON(200, allteim) } else { c.String(200, "{}") } } leyoutu_server.git/API/Layout.go 0000664 0000000 0000000 00000000262 13631640576 0017164 0 ustar 00root root 0000000 0000000 package Api import ( "net/http" ) func Layout(res http.ResponseWriter, req *http.Request) bool { //fmt.Println("layout") // //res.Write([]byte("layout")) return true } leyoutu_server.git/API/Line.go 0000664 0000000 0000000 00000006420 13631640576 0016600 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" ) // @Title 查询线路信息 // @Description 查询线路信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "id" // @Success 200 {object} tools.ResponseSeccess "Name名称;SubName副标题;PlayDuration游玩时长;Suitable适合人群;Location线路点坐标;Annotations需要点亮的设施id;Distance距离" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /LineInfo? [get] func LineInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Query("id") == "" { c.JSON(200, tools.ResponseError{ 1, "空", }) return } var SLine DB.SLine objID, _ := primitive.ObjectIDFromHex(c.Query("id")) DB.CLine.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&SLine) c.JSON(200, tools.ResponseSeccess{ 0, SLine, }) } // @Title 查询所有线路 // @Description 查询所有线路 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "Name名称;SubName副标题;PlayDuration游玩时长;Suitable适合人群;Location线路点坐标;Annotations需要点亮的设施id;Distance距离" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllLine? [get] func AllLine(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var aLine []DB.SLine cur, err := DB.CLine.Find(tools.GetContext(), bson.M{}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SLine cur.Decode(&e) aLine = append(aLine,e) } } c.JSON(200, aLine) } // @Title 更新线路 // @Description 更新线路 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateLine? [post] func UpdateLine(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Location []DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) var Annotations []string json.Unmarshal([]byte(c.PostForm("Annotations")), &Annotations) var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() } else { id,_ = primitive.ObjectIDFromHex(pid) } upsert := true DB.CLine.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "Name": c.PostForm("Name"), "SubName": c.PostForm("SubName"), "PlayDuration": c.PostForm("PlayDuration"), "Suitable": c.PostForm("Suitable"), "Content": c.PostForm("Content"), "Distance": c.PostForm("Distance"), "Annotations": Annotations, "Location": Location, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } leyoutu_server.git/API/Scenic.go 0000664 0000000 0000000 00000011673 13631640576 0017123 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" ) // @Title 返回景区基础信息 // @Description 返回景区基础信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "景区id" // @Success 200 {object} tools.ResponseSeccess "Name名称;Describe介绍;OpenHours营业时间;Picture最上面图片;ShopAdPicture商城列表页图片;ItemScenicPicture项目场次照片;ActivityPicture活动照片;VideoList视频(VideoPicture=首桢图片);InvestigationUrl问券调查的url;RangeLocation景区范围(多个坐标点)" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /ScenicInfo? [get] func ScenicInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Query("id") == "" { c.JSON(200, tools.ResponseError{ 1, "空", }) return } var Scenic *DB.SScenic objID,_ := primitive.ObjectIDFromHex(c.Query("id")) DB.CScenic.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&Scenic) c.JSON(200, tools.ResponseSeccess{ 0, Scenic, }) } // @Title 更新景区基础信息 // @Description 更新景区基础信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "景区id" // @Success 200 {object} tools.ResponseSeccess "Name名称;Describe介绍;OpenHours营业时间;Picture最上面图片;ShopAdPicture商城列表页图片;ItemScenicPicture项目场次照片;ActivityPicture活动照片;VideoList视频(VideoPicture=首桢图片);InvestigationUrl问券调查的url;RangeLocation景区范围(多个坐标点)" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateScenic? [post] func UpdateScenic(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Location DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) var RangeLocation []DB.SLocation json.Unmarshal([]byte(c.PostForm("RangeLocation")), &RangeLocation) var Picture []DB.SPicture json.Unmarshal([]byte(c.PostForm("Picture")), &Picture) var ShopAdPicture []DB.SPicture json.Unmarshal([]byte(c.PostForm("ShopAdPicture")), &ShopAdPicture) var ItemScenicPicture []DB.SPicture json.Unmarshal([]byte(c.PostForm("ItemScenicPicture")), &ItemScenicPicture) var ActivityPicture []DB.SPicture json.Unmarshal([]byte(c.PostForm("ActivityPicture")), &ActivityPicture) var VideoList []DB.SVideo json.Unmarshal([]byte(c.PostForm("VideoList")), &VideoList) var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() // 新景区,初始化 initScenic(id.Hex()) } else { id,_ = primitive.ObjectIDFromHex(pid) } upsert := true DB.CScenic.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "Name": c.PostForm("Name"), "Describe": c.PostForm("Describe"), "Location": Location, "RangeLocation": RangeLocation, "OpenHours": c.PostForm("OpenHours"), "Mobile": c.PostForm("Mobile"), "Address": c.PostForm("Address"), "InvestigationUrl": c.PostForm("InvestigationUrl"), "Picture": Picture, "ShopAdPicture": ShopAdPicture, "ItemScenicPicture": ItemScenicPicture, "ActivityPicture": ActivityPicture, "VideoList": VideoList, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } func initScenic(id string) { var dba []interface{} dba = append(dba,DB.STag{ id, "type", "服务设施", }) dba = append(dba,DB.STag{ id, "type", "游乐设施", }) dba = append(dba,DB.STag{ id, "type", "餐饮", }) dba = append(dba,DB.STag{ id, "type", "购物", }) DB.CTags.InsertMany(tools.GetContext(),dba[1:]) } // @Title 所有景区基础信息 // @Description 所有景区基础信息 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllScenic? [get] func AllScenic(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Scenic []DB.SScenic cur, err := DB.CScenic.Find(tools.GetContext(), bson.M{}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SScenic cur.Decode(&e) Scenic = append(Scenic,e) } } if Scenic == nil { Scenic = []DB.SScenic{} } c.JSON(200, tools.ResponseSeccess{ 0, Scenic, }) } leyoutu_server.git/API/Shop.go 0000664 0000000 0000000 00000006542 13631640576 0016627 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" ) // @Title 查询商品信息 // @Description 查询商品信息 // @Accept json // @Produce json // @Param id 5dfb03070a9ac17ac7a82054 string true "id" // @Success 200 {object} tools.ResponseSeccess "Price=价格;ShopName=店铺名称;KvPhoto用于列表页的图片;TopPhoto详情页最上面的轮播图;Images详情页下面的产品详细图" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /CommodityInfo? [get] func CommodityInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Query("id") == "" { c.JSON(200, tools.ResponseError{ 1, "空", }) return } var SCommodity DB.SCommodity objID, _ := primitive.ObjectIDFromHex(c.Query("id")) DB.CCommodity.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&SCommodity) c.JSON(200, tools.ResponseSeccess{ 0, SCommodity, }) } // @Title 查询所有商品 // @Description 查询所有商品 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "Price=价格;ShopName=店铺名称;KvPhoto用于列表页的图片;TopPhoto详情页最上面的轮播图;Images详情页下面的产品详细图" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllCommodity? [get] func AllCommodity(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var aCommoditys []DB.SCommodity cur, err := DB.CCommodity.Find(tools.GetContext(), bson.M{}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SCommodity cur.Decode(&e) aCommoditys = append(aCommoditys,e) } } c.JSON(200, aCommoditys) } // @Title 更新商品 // @Description 更新商品 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateCommodity? [post] func UpdateCommodity(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Picture []string json.Unmarshal([]byte(c.PostForm("Images")), &Picture) var TopPhoto []DB.SPicture json.Unmarshal([]byte(c.PostForm("TopPhoto")), &TopPhoto) //var Location DB.SLocation //json.Unmarshal([]byte(c.PostForm("Location")), &Location) var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() } else { id,_ = primitive.ObjectIDFromHex(pid) } upsert := true DB.CCommodity.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "Name": c.PostForm("Name"), "Price": c.PostForm("Price"), "ShopName": c.PostForm("ShopName"), "KvPhoto": c.PostForm("KvPhoto"), "TopPhoto": TopPhoto, "ItemId": c.PostForm("ItemId"), "Images": Picture, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } leyoutu_server.git/API/Sms.go 0000664 0000000 0000000 00000004654 13631640576 0016462 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi" "github.com/gin-gonic/gin" "letu/DB" "letu/Lib" "time" ) // @Title 发送短信验证码 // @Description 发送短信验证码 // @Accept json // @Produce json // @Param Mobile 18616619599 string true "手机号" // @Param Location {"Latitude": 119, "Longitude": 39} string true "位置" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}验证码1分钟内有效" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Sms/Send? [post] func Send(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.PostForm("Mobile") == "" { c.JSON(200, tools.ResponseError{ 1, "手机号不正确", }) return } if c.PostForm("Location") == "" { c.JSON(200, tools.ResponseError{ 1, "缺少位置信息", }) return } //cacheCode := DB.Redis.Get("code_"+c.PostForm("Mobile")) //if cacheCode != nil { // c.JSON(200, tools.ResponseError{ // 1, // "code没有过期", // }) // return //} code := Lib.SmsCode(6) client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", "LTAI4FdQeNMQXRU6u5J3EFQc", "PwvyF5rRNBWLDya41WrCpvENevYZGi") request := dysmsapi.CreateSendSmsRequest() request.Scheme = "https" request.PhoneNumbers = c.PostForm("Mobile") request.SignName = "乐游图" request.TemplateCode = "SMS_182595013" request.TemplateParam = "{\"code\":\"" + string(code) + "\"}" response, err := client.SendSms(request) var reserr string if err != nil { println(err.Error()) reserr = err.Error() } else { reserr = response.Code if response.Code == "OK" { DB.Redis.Set("code_"+c.PostForm("Mobile"), code, time.Second*60*5) } } var Location DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) //go func(res *dysmsapi.SendSmsResponse) { DB.CSystemLog.InsertOne(tools.GetContext(),DB.SSystemLog{ "", "", c.PostForm("Mobile"), 6001, "调用第三方发送短信接口", time.Now().Unix(), Location, string(code), reserr, }) //}(response) if response.Code == "OK" { c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } else { c.JSON(200, tools.ResponseSeccess{ 1, "验证码发送失败", }) } } func CreateAccessLog() { } leyoutu_server.git/API/Tag.go 0000664 0000000 0000000 00000012730 13631640576 0016425 0 ustar 00root root 0000000 0000000 package Api import ( "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "letu/DB" "letu/Lib/LeYouTu" "time" ) // @Title 标签列表 // @Description 标签 - 所有标签 // @Accept json // @Produce json // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":[{"Type":"menu","Name":"服务设施"},{"Type":"normal","Name":"不错"},{"Type":"thrilling","Name":"刺激"},{"Type":"recommend","Name":"必玩"}]}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllTag? [get] func AllTag(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } var Stags []DB.STag cur, err := DB.CTags.Find(tools.GetContext(), bson.M{"ScenicId": ScenicId}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.STag cur.Decode(&e) Stags = append(Stags,e) } } if Stags == nil { Stags = []DB.STag{} } c.JSON(200, tools.ResponseSeccess{ 0, Stags, }) } // @Title 标签列表 // @Description 标签 - 按照标签分组查看所有标签 // @Accept json // @Produce json // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":[{"Tags":["儿童","成人","青少年"],"Type":"age"}]}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllTagGroup? [get] func AllTagGroup(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } // cache cache := DB.Redis.Get("Tags_" + ScenicId) if cache != nil { c.JSON(200, tools.ResponseSeccess{ 0, cache, }) println("读取缓存Tags", cache) return } var Stags []DB.STag cur, err := DB.CTags.Find(tools.GetContext(), bson.M{"ScenicId": ScenicId}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.STag cur.Decode(&e) Stags = append(Stags,e) } } if Stags == nil { Stags = []DB.STag{} } Group := make(map[string][]string) // 去重 for _, v := range Stags { Group[v.Type] = append(Group[v.Type], v.Name) } // 转为数组 aGroup := []Tag{} for k, v := range Group { aGroup = append(aGroup, Tag{k, v}) } DB.Redis.Set("Tags_"+ScenicId, aGroup, time.Second*3600*24) c.JSON(200, tools.ResponseSeccess{ 0, aGroup, }) } // @Title 标签 // @Description 标签 - 增加标签 // @Accept json // @Produce json // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Param TagName 广场 string true "标签名称" // @Param TagGroup location string true "群组名称" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Tag/Create? [post] func CreateTag(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } if c.PostForm("TagName") == "" { c.JSON(200, tools.ResponseError{ 1, "标签名称不能为空", }) return } if c.PostForm("TagGroup") == "" { c.JSON(200, tools.ResponseError{ 1, "群组名称不能为空", }) return } if c.PostForm("TagGroup") == "type" { c.JSON(200, tools.ResponseError{ 1, "此类型只能加不能加", }) return } DB.CTags.InsertOne(tools.GetContext(),DB.STag{ ScenicId, c.PostForm("TagGroup"), c.PostForm("TagName"), }) DB.Redis.Delete("Tags_" + ScenicId) println("清楚缓存Tags") c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 标签 // @Description 标签 - 删除标签 // @Accept json // @Produce json // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Param TagName 广场 string true "标签名称" // @Param TagGroup location string true "群组名称" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Tag/Remove? [post] func RemoveTag(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } if c.PostForm("TagName") == "" { c.JSON(200, tools.ResponseError{ 1, "标签名称不能为空", }) return } if c.PostForm("TagGroup") == "" { c.JSON(200, tools.ResponseError{ 1, "群组名称不能为空", }) return } if c.PostForm("TagGroup") == "type" { c.JSON(200, tools.ResponseError{ 1, "此类型只能加不能删", }) return } DB.CTags.DeleteOne(tools.GetContext(), bson.M{"ScenicId": ScenicId,"Name":c.PostForm("TagName"),"Type":c.PostForm("TagGroup")}) DB.Redis.Delete("Tags_" + ScenicId) println("清楚缓存Tags") c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } type Tag struct { Type string Tags []string } leyoutu_server.git/API/Tiles.go 0000664 0000000 0000000 00000001414 13631640576 0016767 0 ustar 00root root 0000000 0000000 package Api import ( "fmt" "github.com/gin-gonic/gin" "io/ioutil" "os" ) func Tiles(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") dir, _ := os.Getwd() //path := dir + "/tiles/" + c.Query("z") + "/" + c.Query("x") + "/" + c.Query("y") + ".jpg" path := fmt.Sprintf("%s/tiles/%s/%s/%s.jpg",dir,c.Query("z"),c.Query("x"),c.Query("y")) if !PathExists(path) { path = dir + "/tiles/blank.png" } b, err := ioutil.ReadFile(path) if err != nil { fmt.Print(err) } c.Data(200, "Content-type: image/jpeg", b) } func PathExists(path string) (bool) { _, err := os.Stat(path) if err == nil { return true } if os.IsNotExist(err) { return false } return false } leyoutu_server.git/API/TopMenus.go 0000664 0000000 0000000 00000005164 13631640576 0017467 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "letu/Lib/LeYouTu" ) // @Title 查询所有菜单 // @Description 菜单管理 - 查询所有菜单 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":[{"Id":"","ScenicId":"","Title":"玩水","Tags":["玩水"]},{"Id":"","ScenicId":"","Title":"设施","Tags":["服务设施","游玩项目"]}]}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /TopMenus/All? [get] func AllTopMenus(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } var STopMenus []DB.STopMenus cur, err := DB.CTopMenus.Find(tools.GetContext(), bson.M{"ScenicId": ScenicId}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.STopMenus cur.Decode(&e) STopMenus = append(STopMenus,e) } } if STopMenus == nil { STopMenus = []DB.STopMenus{} } c.JSON(200, tools.ResponseSeccess{ 0, STopMenus, }) } // @Title 更新菜单 // @Description 菜单管理 - 更新菜单 // @Accept json // @Produce json // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":[{"Id":"","ScenicId":"","Title":"玩水","Tags":["玩水"]},{"Id":"","ScenicId":"","Title":"设施","Tags":["服务设施","游玩项目"]}]}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /TopMenus/Update? [post] func UpdateTopMenus(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") ScenicId, err := LeYouTu.GetScenicId(c) if err != nil { return } if c.PostForm("Tags") == "" { c.JSON(200, tools.ResponseError{ 1, "标签不能为空", }) return } var Tags []string json.Unmarshal([]byte(c.PostForm("Tags")), &Tags) var id primitive.ObjectID if pid := c.PostForm("id"); pid == "null" { id = primitive.NewObjectID() } else { id,_ = primitive.ObjectIDFromHex(pid) } upsert := true DB.CTopMenus.FindOneAndUpdate(tools.GetContext(), bson.M{"_id": id}, bson.M{"$set": bson.M{ "ScenicId": ScenicId, "Title": c.PostForm("Title"), "Tags": Tags, }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } leyoutu_server.git/API/Trajectory.go 0000664 0000000 0000000 00000002041 13631640576 0020032 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "letu/DB" "time" ) // @Title 保存用户移动轨迹 // @Description 保存用户移动轨迹(5分钟提交一次) // @Accept json // @Produce json // @Param UserId 5dfb03070a9ac17ac7a82054 string true "用户id" // @Param Location {"Latitude": 119, "Longitude": 39} string true "经纬度" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Trajectory/Save? [post] func SaveTrajectory(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") var Location DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) DB.CTrajectory.InsertOne(tools.GetContext(),DB.STrajectory{ c.PostForm("UserId"), Location, time.Now().Unix(), }) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } leyoutu_server.git/API/Upload.go 0000664 0000000 0000000 00000002112 13631640576 0017127 0 ustar 00root root 0000000 0000000 package Api import ( "fmt" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "path" "strconv" "time" ) // @Title 上传文件 // @Description 上传 // @Accept json // @Produce json // @Param file 1 file true "文件" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"图片地址"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /Upload? [post] func Upload(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") file, err := c.FormFile("file") if err != nil { c.JSON(200, tools.ResponseError{ 1, "a Bad request", }) return } fileName := file.Filename fileExt := path.Ext(fileName) filePath := "Upload/" + strconv.Itoa(int(time.Now().UnixNano())) + fileExt if err := c.SaveUploadedFile(file, filePath); err != nil { fmt.Println(err) c.JSON(200, tools.ResponseError{ 1, "upload file err", }) return } c.JSON(200, tools.ResponseSeccess{ 0, "/" + filePath, }) } leyoutu_server.git/API/User.go 0000664 0000000 0000000 00000026604 13631640576 0016635 0 ustar 00root root 0000000 0000000 package Api import ( "crypto/sha256" "encoding/hex" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "letu/Lib/Token" "regexp" "strconv" "time" ) var Regular = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$" // @Title 登录 // @Description 用户管理 - 用户登录&注册 // @Accept json // @Produce json // @Param Mobile aaron string true "手机号" // @Param Code 1 string true "验证码(使用验证码的新手机号自动注册)" // @Param DeviceId abc123 string false "手机唯一识别码,不重复(存放于http.header中)" // @Param Mac abc123 string false "网卡Mac地址(存放于http.header中)" // @Param SystemType ios string false "ios,android(存放于http.header中)" // @Param SystemVersion 13.01 string false "手机版本(存放于http.header中)" // @Param SystemModel iphone8 string false "手机型号(存放于http.header中)" // @Param AppVersion 1.0 string false "app版本号(存放于http.header中)" // @Param DeviceToken abc string false "推送token(存放于http.header中)" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":{"Id":"5e09c64c1c09c6f0f7ca2fa9","Token":"640bf934e425aba5d3c90998b2641f2f0ca07261d334d9615d1cd4790b5f34e7"}} 调用其它需要登陆的接口时携带token,有过期时间" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /LoginUser? [post] func LoginUser(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") reg := regexp.MustCompile(Regular) if !reg.MatchString(c.PostForm("Mobile")) { c.JSON(200, tools.ResponseError{ 1, "手机号格式不正确", }) return } if c.PostForm("Mobile") == "" || c.PostForm("Code") == "" { c.JSON(200, tools.ResponseError{ 1, "手机号和验证码不能空", }) return } // 生成token tokenunit8 := sha256.Sum256([]byte(c.PostForm("Mobile") + c.PostForm("Code") + strconv.FormatInt(time.Now().UnixNano(), 10))) token := hex.EncodeToString(tokenunit8[:32]) // 检查验证码 cacheCode := DB.Redis.Get("code_" + c.PostForm("Mobile")) selected := bson.M{} var User *DB.SMember if cacheCode == c.PostForm("Code") { selected["Mobile"] = c.PostForm("Mobile") DB.CMember.FindOne(tools.GetContext(), selected).Decode(&User) // 验证码匹配,但手机号不存在 if User == nil { objectID := primitive.NewObjectID() User := DB.SMember{ &objectID, "", "", "", c.PostForm("Mobile"), "", "", "", DB.SDevice{ c.Request.Header.Get("DeviceId"), c.Request.Header.Get("Mac"), c.Request.Header.Get("UDID"), c.Request.Header.Get("SystemVersion"), c.Request.Header.Get("SystemModel"), c.Request.Header.Get("AppVersion"), c.Request.Header.Get("AppVersion"), c.Request.Header.Get("DeviceToken"), }, } DB.CMember.InsertOne(tools.GetContext(),User) } } else { c.JSON(200, tools.ResponseError{ 1, "验证码不正确", }) return } // 更新用户信息 //DB.CMember.Update( // bson.M{"_id": User.Id}, // bson.M{"$set": bson.M{"Token": token}}, //) // 更新token Token.SaveToken(User.Id.Hex(), token) User.Token = token c.JSON(200, tools.ResponseSeccess{ 0, User, }) } // @Title 注册客户端 // @Description 用户管理 - 注册客户端 // @Accept json // @Produce json // @Param DeviceId abc123 string false "手机唯一识别码,不重复(存放于http.header中)" // @Param Mac abc123 string false "网卡Mac地址(存放于http.header中)" // @Param SystemType ios string false "ios,android(存放于http.header中)" // @Param SystemVersion 13.01 string false "手机版本(存放于http.header中)" // @Param SystemModel iphone8 string false "手机型号(存放于http.header中)" // @Param AppVersion 1.0 string false "app版本号(存放于http.header中)" // @Param DeviceToken abc string false "推送token(存放于http.header中)" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /RegisterDevice? [post] func RegisterDevice(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Request.Header.Get("DeviceId") == "" { c.JSON(200, tools.ResponseError{ 1, "DeviceId不正确", }) return } upsert := true DB.CDevice.FindOneAndUpdate(tools.GetContext(), bson.M{"DeviceId":c.Request.Header.Get("DeviceId")}, bson.M{"$set": bson.M{ "Mac":c.Request.Header.Get("Mac"), "UDID":c.Request.Header.Get("UDID"), "SystemType":c.Request.Header.Get("SystemType"), "SystemVersion":c.Request.Header.Get("SystemVersion"), "SystemModel":c.Request.Header.Get("SystemModel"), "AppVersion":c.Request.Header.Get("AppVersion"), "DeviceToken":c.Request.Header.Get("DeviceToken"), }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 用户信息 // @Description 用户管理 - 获取用户信息 // @Accept json // @Produce json // @Param id aaron string true "用户id" // @Param Token wgergejfwe string true "用户token" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":{"Id":"5e09c64c1c09c6f0f7ca2fa9","Token":"640bf934e425aba5d3c90998b2641f2f0ca07261d334d9615d1cd4790b5f34e7"}}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UserInfo? [get] func UserInfo(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") objID,err := primitive.ObjectIDFromHex(c.Query("id")) if c.Query("Token") == "" || err!=nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.Query("id")) != c.Query("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } var User DB.SMember DB.CMember.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&User) User.Device = DB.SDevice{} c.JSON(200, tools.ResponseSeccess{ 0, User, }) } // @Title 用户信息 // @Description 用户管理 - 检查Token是否过期 // @Accept json // @Produce json // @Param id aaron string true "用户id" // @Param Token wgergejfwe string true "用户token" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":401,"errmsg":"token过期"}" // @Router /CheckToken? [post] func CheckToken(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") _,err := primitive.ObjectIDFromHex(c.PostForm("id")) if c.PostForm("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.PostForm("id")) != c.PostForm("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 修改用户信息 // @Description 用户管理 - 修改用户信息 // @Accept json // @Produce json // @Param id aaron string true "用户id"" // @Param Token wgergejfwe string true "用户token" // @Param Birthday 2010.10.10 string true "生日" // @Param FullName aarongao string true "全名" // @Param Code 12345678 string true "6位验证码" // @Param Mobile 18616619599 string true "手机,同用户名" // @Param Sex 男 string true "性别" // @Param Openid 12345 string true "微信id" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UpdateUser? [post] func UpdateUser(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") _,err := primitive.ObjectIDFromHex(c.PostForm("id")) if c.PostForm("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.PostForm("id")) != c.PostForm("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } reg := regexp.MustCompile(Regular) if !reg.MatchString(c.PostForm("Mobile")) { c.JSON(200, tools.ResponseError{ 1, "手机号格式不正确", }) return } if c.PostForm("Mobile") == "" || c.PostForm("Code") == "" { c.JSON(200, tools.ResponseError{ 1, "手机号或验证码不能为空", }) return } //if c.PostForm("Password") != c.PostForm("ConfirmPassword") { // c.JSON(200, tools.ResponseError{ // 1, // "2次密码不一致", // }) // return //} // 检查验证码 code := DB.Redis.Get("code_" + c.PostForm("Mobile")) if code == "" || code != c.PostForm("Code") { c.JSON(200, tools.ResponseError{ 1, "验证码错误", }) return } objID,_ := primitive.ObjectIDFromHex(c.PostForm("id")) _, err = DB.CMember.UpdateOne(tools.GetContext(), bson.M{"_id": objID}, bson.M{"$set": bson.M{ "Birthday": c.PostForm("Birthday"), "FullName": c.PostForm("FullName"), "Mobile": c.PostForm("Mobile"), "Sex": c.PostForm("Sex"), }}, ) if err == nil { var User *DB.SMember objID,_ := primitive.ObjectIDFromHex(c.PostForm("id")) DB.CMember.FindOne(tools.GetContext(), bson.M{"_id": objID}).Decode(&User) c.JSON(200, tools.ResponseSeccess{ 0, User, }) } else { c.JSON(200, tools.ResponseError{ 1, err.Error(), }) } } // @Title 删除用户 // @Description 用户管理 - 删除用户(注销) // @Accept json // @Produce json // @Param id aaron string true "用户id"" // @Param Token wgergejfwe string true "用户token" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /RemoveUser? [post] func RemoveUser(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") objID,err := primitive.ObjectIDFromHex(c.PostForm("id")) if c.PostForm("Token") == "" || err != nil { c.JSON(200, tools.ResponseError{ 1, "Token或者用户id不正确", }) return } if Token.GetToken(c.PostForm("id")) != c.PostForm("Token") { c.JSON(200, tools.ResponseError{ 401, "token过期", }) return } _, err = DB.CMember.DeleteOne(tools.GetContext(), bson.M{"_id": objID}) if err == nil { c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } else { c.JSON(200, tools.ResponseError{ 1, err.Error(), }) } } leyoutu_server.git/API/UserLog.go 0000664 0000000 0000000 00000011513 13631640576 0017270 0 ustar 00root root 0000000 0000000 package Api import ( "encoding/json" "github.com/aarongao/tools" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" "letu/DB" "math" "strconv" "time" ) // @Title 增加访问日志 // @Description 增加用户行为日志 // @Accept json // @Produce json // @Param Type 访问页面 string true "安装;卸载;访问页面;使用功能;缩放地图;进入景区" // @Param SubType 景区详情 string true "推荐;景区详情;登陆;商城;投诉建议;问券调查....(app中能点的都加上)" // @Param ScenicId 5dfb03070a9ac17ac7a82054 string true "景区id" // @Param UserId 5dfb03070a9ac17ac7a82054 string true "用户ID" // @Param UserName Aaron string true "用户名称" // @Param Location {"Latitude": 119, "Longitude": 39} string true "位置" // @Param Remarks 备注 string true "备注" // @Param Source 用户分享 string true "来源" // @Param DeviceId abc123 string true "手机唯一识别码,不重复(存放于http.header中)" // @Param Mac abc123 string true "网卡Mac地址(存放于http.header中)" // @Param SystemType ios string true "ios,android(存放于http.header中)" // @Param SystemVersion 13.01 string true "手机版本(存放于http.header中)" // @Param SystemModel iphone8 string true "手机型号(存放于http.header中)" // @Param AppVersion 1.0 string true "app版本号(存放于http.header中)" // @Param DeviceToken abc string true "推送token(存放于http.header中)" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"result":"ok"}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /UserLog? [post] func UserLog(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") if c.Request.Header.Get("DeviceId") == "" { c.JSON(200, tools.ResponseError{ 1, "DeviceId不正确", }) return } var Location DB.SLocation json.Unmarshal([]byte(c.PostForm("Location")), &Location) DB.CUserLog.InsertOne(tools.GetContext(),DB.SUserLog{ c.PostForm("Type"), c.PostForm("SubType"), c.PostForm("ScenicId"), c.PostForm("UserId"), c.PostForm("UserName"), time.Now().Unix(), Location, c.PostForm("Remarks"), c.Request.Host, c.PostForm("Source"), DB.SDevice{ c.Request.Header.Get("DeviceId"), c.Request.Header.Get("Mac"), c.Request.Header.Get("UDID"), c.Request.Header.Get("SystemVersion"), c.Request.Header.Get("SystemModel"), c.Request.Header.Get("AppVersion"), c.Request.Header.Get("AppVersion"), c.Request.Header.Get("DeviceToken"), }, }) upsert := true DB.CDevice.FindOneAndUpdate(tools.GetContext(), bson.M{"DeviceId": c.Request.Header.Get("DeviceId")}, bson.M{"$set": bson.M{ "Mac": c.Request.Header.Get("Mac"), "UDID": c.Request.Header.Get("UDID"), "SystemType": c.Request.Header.Get("SystemType"), "SystemVersion": c.Request.Header.Get("SystemVersion"), "SystemModel": c.Request.Header.Get("SystemModel"), "AppVersion": c.Request.Header.Get("AppVersion"), "DeviceToken": c.Request.Header.Get("DeviceToken"), }}, &options.FindOneAndUpdateOptions{ Upsert: &upsert, }, ) c.JSON(200, tools.ResponseSeccess{ 0, "ok", }) } // @Title 查询所有用户行为 // @Description 查询所有用户行为 // @Accept json // @Produce json // @Param Page 1 int true "当前第几页" // @Success 200 {object} tools.ResponseSeccess "{"errcode":0,"total":1,"currpage":1,"totalpages":1,"prepage":20,"result":}" // @Failure 500 {object} tools.ResponseError "{"errcode":1,"errmsg":"错误原因"}" // @Router /AllUserLog? [get] func AllUserLog(c *gin.Context) { c.Header("Access-Control-Allow-Origin", c.Request.Header.Get("Origin")) c.Header("Access-Control-Allow-Credentials", "true") total,_ := DB.CUserLog.CountDocuments(tools.GetContext(), bson.M{}) limit, _ := strconv.ParseInt(c.Query("Limit"),10,64) if limit == 0 { limit = 50 } currPage, _ := strconv.ParseInt(c.Query("Page"),10,64) if currPage == 0 { currPage = 1 } skip := (currPage - 1) * limit var aUserLog []DB.SUserLog cur, err := DB.CUserLog.Find(tools.GetContext(), bson.M{}, &options.FindOptions{Limit: &limit, Skip: &skip, Sort: bson.M{"_id": -1}}) defer cur.Close(tools.GetContext()) if err == nil { for cur.Next(tools.GetContext()) { var e DB.SUserLog cur.Decode(&e) aUserLog = append(aUserLog,e) } } c.JSON(200, tools.Page{ 0, total, currPage, int(math.Ceil(float64(total) / float64(limit))), limit, aUserLog, }) } leyoutu_server.git/API/Ws.go 0000664 0000000 0000000 00000001565 13631640576 0016307 0 ustar 00root root 0000000 0000000 package Api import ( "fmt" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" uuid "github.com/satori/go.uuid" "letu/Lib/Ws" ) var wsupgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } func WsPage(c *gin.Context) { conn, err := wsupgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { fmt.Println("Failed to set websocket upgrade: %+v", err) return } // websocket connect _uuid, _ := uuid.NewV4() client := &Ws.Client{ _uuid.String(), conn, } Ws.Manager.Register <- client for { _, msg, err := conn.ReadMessage() if err != nil { println(err.Error()) Ws.Manager.Unregister <- client client.Socket.Close() break } sMsg := string(msg) println("收到消息:", sMsg) switch sMsg { case "test": client.Send([]byte("hahaha")) case "test2": client.Send([]byte("hahaha2")) } } } leyoutu_server.git/Bin/ 0000775 0000000 0000000 00000000000 13631640576 0015457 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Bin/Monitor.go 0000664 0000000 0000000 00000002447 13631640576 0017444 0 ustar 00root root 0000000 0000000 package main import ( "encoding/json" "github.com/aarongao/tools" "github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi" "time" ) var lastState = 0 func main() { for { time.Sleep(30 * time.Second) httpState, body, error := tools.GET("http://leyoutu.st-i.com.cn/AllScenic") if httpState == 200 && error == nil { oBody := tools.ResponseSeccess{} json.Unmarshal([]byte(body), &oBody) rlen := len(oBody.Result.([]interface{})) if oBody.ErrCode != 0 || rlen == 0 { sms(1) } else { sms(2) } } else { sms(1) } } } func sms(state int) { stateString := "" if state == 1{ stateString = "Fail" } if state == 2{ stateString = "Success" } println("state:",stateString) if lastState == 0 { lastState = state } if lastState != state{ lastState = state client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", "LTAI4FdQeNMQXRU6u5J3EFQc", "PwvyF5rRNBWLDya41WrCpvENevYZGi") request := dysmsapi.CreateSendSmsRequest() request.Scheme = "https" request.PhoneNumbers = "18616619599" request.SignName = "乐游图" request.TemplateCode = "SMS_182595013" request.TemplateParam = "{\"code\":\"" + stateString +"\"}" response, err := client.SendSms(request) if err != nil { println(err.Error()) } println("SMS:", response.Code) } } leyoutu_server.git/Config/ 0000775 0000000 0000000 00000000000 13631640576 0016154 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Config/config.go 0000664 0000000 0000000 00000000233 13631640576 0017746 0 ustar 00root root 0000000 0000000 package Config type Config struct { TagType []string DbPath string DbName string DbUser string DbPassword string RedisPath string } leyoutu_server.git/Config/config.json 0000664 0000000 0000000 00000000262 13631640576 0020314 0 ustar 00root root 0000000 0000000 { "tagType": ["menu","normal"], "dbPath": "127.0.0.1:27017", "dbName": "LeYouTu", "dbUser": "leyoutu", "dbPassword": "leyoutu123456", "redisPath": "127.0.0.1:6379" } leyoutu_server.git/DB/ 0000775 0000000 0000000 00000000000 13631640576 0015234 5 ustar 00root root 0000000 0000000 leyoutu_server.git/DB/db.go 0000664 0000000 0000000 00000023505 13631640576 0016155 0 ustar 00root root 0000000 0000000 package DB import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "letu/Lib/Cache" ) var Redis *Cache.Redis var CItem *mongo.Collection //所有游玩项目内容 var CComplaint *mongo.Collection //投诉 var CInvestigation *mongo.Collection //调查 var CMember *mongo.Collection //会员 var CCommodity *mongo.Collection //商城 var CTags *mongo.Collection //标签 var CScenic *mongo.Collection //景区 var CLine *mongo.Collection //推荐线路 var CUserLog *mongo.Collection //用户行为记录 var CSystemLog *mongo.Collection //操作记录 var CTrajectory *mongo.Collection //移动轨迹 var CIcons *mongo.Collection //图标信息 var CTopMenus *mongo.Collection //菜单 var CDevice *mongo.Collection //设备清单 var DB *mongo.Database type SItem struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` Name string `bson:"Name" json:"Name"` SubName string `bson:"SubName" json:"SubName"` Location SLocation `bson:"Location" json:"Location"` Tags []STag `bson:"Tags" json:"Tags"` Icon string `bson:"Icon" json:"Icon"` LimitHeight string `bson:"LimitHeight" json:"LimitHeight"` //限高 PlayDuration string `bson:"PlayDuration" json:"PlayDuration"` //游玩时长 SceneTime string `bson:"SceneTime" json:"SceneTime"` //场次时间 Picture []string `bson:"Picture" json:"Picture"` Voice string `bson:"Voice" json:"Voice"` //音频 Tel string `bson:"Tel" json:"Tel"` AverageConsumption string `bson:"AverageConsumption" json:"AverageConsumption"` //人均消费 Menu string `bson:"Menu" json:"Menu"` //目录 Time string `bson:"Time" json:"Time"` OpenHours string `bson:"OpenHours" json:"OpenHours"` //开放时间 LocationDescription string `bson:"LocationDescription" json:"LocationDescription"` //位置描述 Reminder string `bson:"Reminder" json:"Reminder"` //温馨提示 State int `bson:"State" json:"State"` // 运行状态0=正常1=停运 } type SIcons struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` ScenicId string `bson:"ScenicId" json:"ScenicId"` Name string `bson:"Name" json:"Name"` Picture string `bson:"Picture" json:"Picture"` } type STrajectory struct { UserId string `bson:"UserId" json:"UserId"` // 用户ID Location SLocation `bson:"Location" json:"Location"` Time int64 `bson:"Time" json:"Time"` } type SLocation struct { Latitude float64 `bson:"Latitude" json:"Latitude"` //纬度 Longitude float64 `bson:"Longitude" json:"Longitude"` //经度 } type STopMenus struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` ScenicId string `bson:"ScenicId" json:"ScenicId"` Title string `bson:"Title" json:"Title"` //菜单标题 Tags []string `bson:"Tags" json:"Tags"` //标签 } type SDevice struct { DeviceId string `bson:"DeviceId" json:"DeviceId"` Mac string `bson:"Mac" json:"Mac"` UDID string `bson:"UDID" json:"UDID"` SystemType string `bson:"SystemType" json:"SystemType"` //ios,android SystemVersion string `bson:"SystemVersion" json:"SystemVersion"` //系统版本 SystemModel string `bson:"SystemModel" json:"SystemModel"` //机型 AppVersion string `bson:"AppVersion" json:"AppVersion"` //app版本 DeviceToken string `bson:"DeviceToken" json:"DeviceToken"` //用于推送的token } type SUserLog struct { Type string `bson:"Type" json:"Type"` // Log(事件)类型 SubType string `bson:"SubType" json:"SubType"` // 分类 ScenicId string `bson:"ScenicId" json:"ScenicId"` UserId string `bson:"UserId" json:"UserId"` // 用户ID UserName string `bson:"UserName" json:"UserName"` //用户名称 DateTime int64 `bson:"DateTime" json:"DateTime"` //时间戳 Location SLocation `bson:"Location" json:"Location"` //位置 Remarks string `bson:"Remarks" json:"Remarks"` //备注 Ip string `bson:"Ip" json:"Ip"` Source string `bson:"Source" json:"Source"` //来源 Device SDevice `bson:"Device" json:"Device"` //设备信息 } type SSystemLog struct { UserId string `bson:"UserId" json:"UserId"` // 用户ID UserName string `bson:"UserName" json:"UserName"` //用户名称 Mobile string `bson:"Mobile" json:"Mobile"` //手机号 TypeNum int64 `bson:"TypeNum" json:"TypeNum"` //类型编号 TypeName string `bson:"TypeName" json:"TypeName"` //类型名称 DateTime int64 `bson:"DateTime" json:"DateTime"` //时间戳 Location SLocation `bson:"Location" json:"Location"` //位置 Content string `bson:"Content" json:"Content"` //内容 Error interface{} `bson:"Error" json:"Error"` //错误信息 } type SCommodity struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` Name string `bson:"Name" json:"Name"` Price string `bson:"Price" json:"Price"` ShopName string `bson:"ShopName" json:"ShopName"` ItemId string `bson:"ItemId" json:"ItemId"` //项目id KvPhoto string `bson:"KvPhoto" json:"KvPhoto"` //用于列表页的图片 TopPhoto []SPicture `bson:"TopPhoto" json:"TopPhoto"` //详情页最上面的轮播图 Images []string `bson:"Images" json:"Images"` //详情页下面的产品详细图 } type SLine struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` Name string `bson:"Name" json:"Name"` SubName string `bson:"SubName" json:"SubName"` //游玩时长 Location []SLocation `bson:"Location" json:"Location"` //线路点坐标 PlayDuration string `bson:"PlayDuration" json:"PlayDuration"` Suitable string `bson:"Suitable" json:"Suitable"` //适合人群 Content string `bson:"Content" json:"Content"` Distance string `bson:"Distance" json:"Distance"` // 距离 Annotations []string `bson:"Annotations" json:"Annotations"` //需要点亮的设施id } type SComplaint struct { Type string `bson:"Type" json:"Type"` ScenicId string `bson:"ScenicId" json:"ScenicId"` // 景区id Mobile string `bson:"Mobile" json:"Mobile"` FullName string `bson:"FullName" json:"FullName"` Sex string `bson:"Sex" json:"Sex"` Content string `bson:"Content" json:"Content"` Image []string `bson:"Image" json:"Image"` State string `bson:"State" json:"State"` // 处理状态(未处理,已处理) DateTime int64 `bson:"DateTime" json:"DateTime"` //时间戳 } type SInvestigation struct { UserId string `bson:"UserId" json:"UserId"` // 用户ID Mobile string `bson:"Mobile" json:"Mobile"` //手机号 Data interface{} `bson:"Data" json:"Data"` } type SMember struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` Password string `bson:"Password" json:"Password"` Birthday string `bson:"Birthday" json:"Birthday"` FullName string `bson:"FullName" json:"FullName"` Mobile string `bson:"Mobile" json:"Mobile"` Openid string `bson:"Openid" json:"Openid"` Token string `bson:"Token" json:"Token"` Sex string `bson:"Sex" json:"Sex"` Device SDevice `bson:"Device" json:"Device"` //设备信息 } type STag struct { ScenicId string `bson:"ScenicId" json:"ScenicId"` Type string `bson:"Type" json:"Type"` Name string `bson:"Name" json:"Name"` } type SPicture struct { Src string `bson:"Src" json:"Src"` // 地址,也可能是视频地址 Link string `bson:"Link" json:"Link"` // 链接地址 } type SVideo struct { Src string `bson:"Src" json:"Src"` // 地址,也可能是视频地址 Link string `bson:"Link" json:"Link"` // 链接地址 VideoPicture string `bson:"VideoPicture" json:"VideoPicture"` // 用于视频的首桢图 Title string `bson:"Title" json:"Title"` // 标题 } type SScenic struct { Id *primitive.ObjectID `bson:"_id" json:"Id" valid:"required"` Name string `bson:"Name" json:"Name"` Describe string `bson:"Describe" json:"Describe"` OpenHours string `bson:"OpenHours" json:"OpenHours"` //营业时间 Mobile string `bson:"Mobile" json:"Mobile"` Address string `bson:"Address" json:"Address"` InvestigationUrl string `bson:"InvestigationUrl" json:"InvestigationUrl"` //问券调查的url地址 Location SLocation `bson:"Location" json:"Location"` Picture []SPicture `bson:"Picture" json:"Picture"` ShopAdPicture []SPicture `bson:"ShopAdPicture" json:"ShopAdPicture"` //商城列表页图片 ItemScenicPicture []SPicture `bson:"ItemScenicPicture" json:"ItemScenicPicture"` //项目场次照片 ActivityPicture []SPicture `bson:"ActivityPicture" json:"ActivityPicture"` //活动照片 VideoList []SVideo `bson:"VideoList" json:"VideoList"` RangeLocation []SLocation `bson:"RangeLocation" json:"RangeLocation"` //景区范围 } leyoutu_server.git/Lib/ 0000775 0000000 0000000 00000000000 13631640576 0015455 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/Cache/ 0000775 0000000 0000000 00000000000 13631640576 0016460 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/Cache/redis.go 0000664 0000000 0000000 00000004121 13631640576 0020113 0 ustar 00root root 0000000 0000000 package Cache import ( "encoding/json" "github.com/garyburd/redigo/redis" "time" ) //Redis redis cache type Redis struct { conn *redis.Pool } //RedisOpts redis 连接属性 type RedisOpts struct { Host string `yml:"host" json:"host"` Password string `yml:"password" json:"password"` Database int `yml:"database" json:"database"` MaxIdle int `yml:"max_idle" json:"max_idle"` MaxActive int `yml:"max_active" json:"max_active"` IdleTimeout int32 `yml:"idle_timeout" json:"idle_timeout"` //second } //NewRedis 实例化 func NewRedis(opts *RedisOpts) *Redis { pool := &redis.Pool{ MaxActive: opts.MaxActive, MaxIdle: opts.MaxIdle, IdleTimeout: time.Second * time.Duration(opts.IdleTimeout), Dial: func() (redis.Conn, error) { return redis.Dial("tcp", opts.Host, redis.DialDatabase(opts.Database), redis.DialPassword(opts.Password), ) }, TestOnBorrow: func(conn redis.Conn, t time.Time) error { if time.Since(t) < time.Minute { return nil } _, err := conn.Do("PING") return err }, } return &Redis{pool} } //Get 获取一个值 func (r *Redis) Get(key string) interface{} { conn := r.conn.Get() defer conn.Close() var data []byte var err error if data, err = redis.Bytes(conn.Do("GET", key)); err != nil { return nil } var reply interface{} if err = json.Unmarshal(data, &reply); err != nil { return nil } return reply } //Set 设置一个值 func (r *Redis) Set(key string, val interface{}, timeout time.Duration) (err error) { conn := r.conn.Get() defer conn.Close() var data []byte if data, err = json.Marshal(val); err != nil { return } _, err = conn.Do("SETEX", key, int64(timeout/time.Second), data) return } //IsExist 判断key是否存在 func (r *Redis) IsExist(key string) bool { conn := r.conn.Get() defer conn.Close() a, _ := conn.Do("EXISTS", key) i := a.(int64) if i > 0 { return true } return false } //Delete 删除 func (r *Redis) Delete(key string) error { conn := r.conn.Get() defer conn.Close() if _, err := conn.Do("DEL", key); err != nil { return err } return nil } leyoutu_server.git/Lib/Code.go 0000664 0000000 0000000 00000000502 13631640576 0016653 0 ustar 00root root 0000000 0000000 package Lib import ( "fmt" "math/rand" "strings" "time" ) func SmsCode(width int) string { numeric := [10]byte{0,1,2,3,4,5,6,7,8,9} r := len(numeric) rand.Seed(time.Now().UnixNano()) var sb strings.Builder for i := 0; i < width; i++ { fmt.Fprintf(&sb, "%d", numeric[ rand.Intn(r) ]) } return sb.String() } leyoutu_server.git/Lib/DelayMessage/ 0000775 0000000 0000000 00000000000 13631640576 0020020 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/DelayMessage/delaymessage.go 0000664 0000000 0000000 00000017063 13631640576 0023021 0 ustar 00root root 0000000 0000000 package DelayMessage import ( "context" "encoding/json" "fmt" "github.com/aarongao/tools" "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/bson" "io/ioutil" "net/http" "strconv" "sync" "time" ) // 延迟消息 var CDelayMessage *mongo.Collection var CDelayErrorLog *mongo.Collection var GlobalDM *DelayMessage type Message struct { Id *primitive.ObjectID `bson:"_id" json:"_id"` //延时时间 DelayTime int64 //callbackUrl CallbackUrl string `bson:"CallbackUrl" json:"CallbackUrl"` //失败次数 Fail int // 类型0=geturl;1=发送app消息 Type int8 `bson:"Type" json:"Type"` Title string `bson:"Title" json:"Title"` Content string `bson:"Content" json:"Content"` UDID string `bson:"UDID" json:"UDID"` UserId string `bson:"UserId" json:"UserId"` } // addTask func (dm *DelayMessage) AddTaskForGetUrl(delayTime string, userid string, callbackUrl string) error { iTIme, _ := strconv.Atoi(delayTime) i64Time := int64(iTIme) nowTimeU := time.Now().Unix() iDelayTIme := i64Time - nowTimeU if i64Time <= nowTimeU { return errors.New("delayTime error...") } if callbackUrl == "" { return errors.New("callbackUrl error...") } objectID := primitive.NewObjectID() _Message := &Message{&objectID, i64Time, callbackUrl, 0, 0, "", "", "", userid} ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) CDelayMessage.InsertOne(ctx, _Message) //添加任务 //iDelayTIme = 3 dm.AddTask(time.Now().Add(time.Second*time.Duration(iDelayTIme)), Callback, _Message) fmt.Println("增加新任务:", "当前位置", dm.curIndex, ",", iDelayTIme, "秒后触发", _Message.CallbackUrl) println(objectID.Hex()) return nil } func (dm *DelayMessage) AddTaskForAppMessage(delayTime string, udid string, title string, content string, userid string) error { iTIme, _ := strconv.Atoi(delayTime) i64Time := int64(iTIme) nowTimeU := time.Now().Unix() iDelayTIme := i64Time - nowTimeU if i64Time <= nowTimeU { return errors.New("delayTime error...") } if udid == "" { return errors.New("udid error...") } if title == "" { return errors.New("title error...") } if content == "" { return errors.New("content error...") } if userid == "" { return errors.New("userid error...") } objectID := primitive.NewObjectID() _Message := &Message{&objectID, i64Time, "", 0, 1, title, content, udid, userid} CDelayMessage.InsertOne(tools.GetContext(), _Message) //添加任务 //iDelayTIme = 3 dm.AddTask(time.Now().Add(time.Second*time.Duration(iDelayTIme)), Callback, _Message) fmt.Println("增加新任务:", "当前位置", dm.curIndex, ",", iDelayTIme, "秒后触发", _Message.Title) //println(objectID.Hex()) return nil } // delTask func (dm *DelayMessage) DelTaskForId(id string) { defer func() { if r := recover(); r != nil { fmt.Println("[E]", r) } }() objID, _ := primitive.ObjectIDFromHex(id) CDelayMessage.DeleteOne(tools.GetContext(), bson.M{"_id": objID}) i := dm.DelTask(id) println("删除定时任务:", strconv.Itoa(i)) } func (dm *DelayMessage) Show() { //取出当前的槽的任务 fmt.Println("---------------------------------") for k, _ := range dm.slots { tasks := dm.slots[k] for _, v2 := range tasks { fmt.Println("当前秒数:", dm.curIndex, "下一任务:", k, "圈数:", v2.cycleNum, v2.params.CallbackUrl) } } fmt.Println("---------------------------------") } func Callback(key *primitive.ObjectID, message *Message) { var body string var err error if message.Type == 0 { body, err = HttpGet(message.CallbackUrl) if err != nil { //fmt.Println(err,message) } } else if message.Type == 1 { // 推送app消息 //client, err := push.NewClientWithAccessKey("cn-hangzhou", "28332889", "4c0b32d5fd0822a9de703e177798e8ca") // //request := push.CreatePushMessageToiOSRequest() //request.Scheme = "https" // //response, err := client.PushMessageToiOS(request) //if err != nil { // fmt.Print(err.Error()) //} //fmt.Printf("response is %#v\n", response) } json, _ := json.Marshal(message) if body != "ok" { CDelayMessage.DeleteOne(tools.GetContext(), bson.M{"_id": *key}) fmt.Println("完成任务:", string(json)) } else { //message.Fail++ //if message.Fail == 3 { // fmt.Println(color.Red("放弃任务:"), message.CallbackUrl) // CDelayMessage.Remove(bson.M{"_id": *key}) // dbErrorLog.InsertOne(tools.GetContext(),message) //} else { // fmt.Println("重新添加任务:", message) // dm.AddTask(time.Now().Add(time.Second*10), key, callback, message) //} fmt.Println("放弃任务:", string(json)) //CDelayMessage.Remove(bson.M{"_id": *key}) CDelayErrorLog.InsertOne(tools.GetContext(), message) } } type DelayMessage struct { //当前下标 curIndex int //环形槽 sync.RWMutex slots [3600]map[*primitive.ObjectID]*Task //启动时间 startTime time.Time } //执行的任务函数 type TaskFunc func(key *primitive.ObjectID, message *Message) //任务 type Task struct { //循环次数 cycleNum int //执行的函数 exec TaskFunc params *Message } //创建一个延迟消息 func NewDelayMessage() *DelayMessage { dm := &DelayMessage{ curIndex: 0, startTime: time.Now(), } for i := 0; i < 3600; i++ { dm.slots[i] = make(map[*primitive.ObjectID]*Task) } return dm } //启动延迟消息 func (dm *DelayMessage) Start() { //go dm.taskLoop() go dm.timeLoop() select {} } //处理每1秒的任务 func (dm *DelayMessage) taskLoop() { //取出当前的槽的任务 tasks := dm.slots[dm.curIndex] if len(tasks) > 0 { //遍历任务,判断任务循环次数等于0,则运行任务 //否则任务循环次数减1 for k, v := range tasks { if v.cycleNum == 0 { go v.exec(k, v.params) //删除运行过的任务 dm.RLock() delete(tasks, k) dm.RUnlock() } else { v.cycleNum-- } } } } //处理每1秒移动下标 func (dm *DelayMessage) timeLoop() { defer func() { fmt.Println("timeLoop exit") }() for { time.Sleep(time.Second) //fmt.Println(time.Now().Format("2006-01-02 15:04:05")) //判断当前下标,如果等于3599则重置为0,否则加1 dm.taskLoop() if dm.curIndex == 3599 { dm.curIndex = 0 } else { dm.curIndex++ } } } //添加任务 func (dm *DelayMessage) AddTask(t time.Time, exec TaskFunc, message *Message) error { if dm.startTime.After(t) { return errors.New("时间错误") } //计算循环次数 cycleNum := int((t.Unix() - time.Now().Unix()) / 3600) //计算任务所在的slots的下标 ix := (t.Unix() - time.Now().Unix() + int64(dm.curIndex)) % 3600 fmt.Println("AddTask-----", cycleNum, "圈后的第", ix, "位") //把任务加入tasks中 tasks := dm.slots[ix] //if _, ok := tasks[key]; ok { // return errors.New("该slots中已存在key为" + key + "的任务") //} dm.Lock() tasks[message.Id] = &Task{ cycleNum: cycleNum, exec: exec, params: message, } dm.Unlock() return nil } //删除任务 func (dm *DelayMessage) DelTask(key string) int { i := 0 for _, v := range dm.slots { for k2, _ := range v { if key == k2.Hex() { i++ delete(v, k2) } } } return i } var c = &http.Client{ Timeout: 5 * time.Second, } func HttpGet(url string) (string, error) { //fmt.Println(color.Yellow("http request: "), color.Yellow(url)) resp, err := c.Get(url) if err != nil { return "", err } defer func() { if err := recover(); err == nil { resp.Body.Close() } }() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } sBody := string(body) //fmt.Println(color.Yellow(sBody)) return sBody, nil } leyoutu_server.git/Lib/LeYouTu/ 0000775 0000000 0000000 00000000000 13631640576 0017023 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/LeYouTu/Controllers.go 0000664 0000000 0000000 00000001201 13631640576 0021652 0 ustar 00root root 0000000 0000000 package LeYouTu import ( "github.com/gin-gonic/gin" ) type Controllers struct { Layout func(c *gin.Context) bool } func (this *Controllers) POST(handFunc func(c *gin.Context)) func(c *gin.Context) { return this.HandleFunc(handFunc, "POST") } func (this *Controllers) GET(handFunc func(c *gin.Context)) func(c *gin.Context) { return this.HandleFunc(handFunc, "GET") } func (this *Controllers) HandleFunc(handFunc func(c *gin.Context), httpMethod string) func(c *gin.Context) { return func(c *gin.Context) { if c.Request.Method != httpMethod { //res.Write([]byte(http.StatusText(http.StatusMethodNotAllowed))) return } } } leyoutu_server.git/Lib/LeYouTu/tools.go 0000664 0000000 0000000 00000001026 13631640576 0020511 0 ustar 00root root 0000000 0000000 package LeYouTu import ( "github.com/aarongao/tools" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) func GetScenicId(c *gin.Context) (ScenicId string, error error) { if c.Request.Method == "POST" { ScenicId = c.PostForm("ScenicId") } if c.Request.Method == "GET" { ScenicId = c.Query("ScenicId") } if ScenicId == "" || ScenicId == "undefined" { c.JSON(200, tools.ResponseError{ 1, "缺少ScenicId(景区id)", }) return "", errors.New("缺少ScenicId(景区id)") } else { return ScenicId, nil } } leyoutu_server.git/Lib/Token/ 0000775 0000000 0000000 00000000000 13631640576 0016535 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/Token/token.go 0000664 0000000 0000000 00000000442 13631640576 0020204 0 ustar 00root root 0000000 0000000 package Token import ( "letu/DB" "time" ) func GetToken(mobile string) string { token := DB.Redis.Get("token_" + mobile) if token == nil { return "" } return token.(string) } func SaveToken(mobile, token string) { DB.Redis.Set("token_"+mobile, token, time.Second*3600*24*365) } leyoutu_server.git/Lib/Ws/ 0000775 0000000 0000000 00000000000 13631640576 0016046 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Lib/Ws/Ws.go 0000664 0000000 0000000 00000003331 13631640576 0016766 0 ustar 00root root 0000000 0000000 package Ws import ( "encoding/json" "github.com/gorilla/websocket" ) // ClientManager is a websocket manager type ClientManager struct { Clients map[*Client]bool Broadcast chan []byte Register chan *Client Unregister chan *Client } // Client is a websocket client type Client struct { ID string Socket *websocket.Conn } // Message is an object for websocket message which is mapped to json type type Message struct { Sender string `json:"sender,omitempty"` Recipient string `json:"recipient,omitempty"` Content string `json:"content,omitempty"` } // Manager define a ws server manager var Manager = ClientManager{ Broadcast: make(chan []byte), Register: make(chan *Client), Unregister: make(chan *Client), Clients: make(map[*Client]bool), } // Start is to start a ws server func (manager *ClientManager) Start() { for { select { case conn := <-manager.Register: manager.Clients[conn] = true jsonMessage, _ := json.Marshal(&Message{Content: "/A new socket has connected."}) manager.Send(jsonMessage, conn) case conn := <-manager.Unregister: if _, ok := manager.Clients[conn]; ok { delete(manager.Clients, conn) jsonMessage, _ := json.Marshal(&Message{Content: "/A socket has disconnected."}) manager.Send(jsonMessage, conn) } case message := <-manager.Broadcast: for conn := range manager.Clients { conn.Socket.WriteMessage(1, message) } } } } // Send is to send ws message to ws client func (manager *ClientManager) Send(message []byte, ignore *Client) { for conn := range manager.Clients { if conn != ignore { conn.Socket.WriteMessage(1, message) } } } func (c *Client) Send(message []byte) { c.Socket.WriteMessage(websocket.TextMessage, message) } leyoutu_server.git/Policy/ 0000775 0000000 0000000 00000000000 13631640576 0016206 5 ustar 00root root 0000000 0000000 leyoutu_server.git/Policy/Privacy.html 0000664 0000000 0000000 00000166407 13631640576 0020527 0 ustar 00root root 0000000 0000000
《乐游图软件隐私政策》
乐游图软件(以下或称“我们”)非常注重保护用户(“您”)的个人信息及隐私,我们深知个人信息对您的重要性,并将按照法律法规要求和业界成熟的安全标准,采取相应的安全保护措施来保护您的个人信息。我们希望通过本隐私政策向您清晰地介绍在使用我们的软件\服务时,我们如何处理您的个人信息,以及我们为您提供的访问、更正、删除和保护这些信息的方式。
本政策将帮助您了解以下内容:
1. 我们如何防卫和使用您的个人信息;
2. 我们如何使用 Cookie 和同类技术;
3. 我们如何共享、转让、公开披露您的个人信息;
4. 我们如何保存和保护您的个人信息;
5. 您如何管理您的个人信息;
6. 未成年人的个人信息保护;
7. 通知和修订;
8. 如何联系我们;
9. 附录。
【特别提示】请您在使用我们提供的各项产品\服务前,仔细阅读并充分理解本《隐私政策》(重点内容我们已将字体加粗请您特别关注)并作出相应选择。一旦您使用或继续使用我们的产品\服务时,即意味着您同意我们按照本隐私政策处理您的相关信息。
如对本隐私政策有任何疑问,您可以通过App上提供的联系方式\客服系统与我们联系。
乐游图软件所有的产品\服务(包括乐游图软件提供的产品\服务及未设独立隐私政策的乐游图软件关联方提供的产品\服务)均适用本隐私政策。
“乐游图软件的产品\服务”是指乐游图软件网络及技术服务提供者通过下述途径向您提供的产品\服务:包括但不限于客户端以及相关微信开放平台账号或小程序等。
此外,针对某些特定的产品\服务,我们还将制定特定的隐私政策,并在向您提供这些特定的产品\服务之前加以说明。如相关特定的隐私政策与本隐私政策有不一致之处,适用该特定隐私政策。
请您注意,本政策不适用于您通过我们的产品\服务而接入的其他第三方产品\服务(“其他第三方”,包括但不限于您的交易相对方、任何第三方网站以及第三方服务提供者),具体规定请参照该第三方的隐私政策或类似声明。
一、我们如何收集和使用您的个人信息
我们会遵循正当、合法、必要的原则,出于本政策所述的以下目的,收集和使用您在使用服务过程中主动提供或产生的个人信息:帮助您成为我们的用户,向您提供产品\服务,为您优化用户体验,为您提供安全保障:
(一)帮助您成为我们的用户
为遵守法律法规的要求,以及向您提供更个性化、更便捷的服务,在您注册成为乐游图软件用户时,您需要至少提供手机号码以创建乐游图软件账号,并完善相关的网络身份识别信息(如头像、昵称及登录密码等);如果您仅需使用浏览、搜索等功能,您无需注册成为我们的用户以及提供上述信息。
在提供账号信息的过程中,如果您愿意额外补充如下个人信息,将有助于我们向您提供更为个性化的服务:包括您的性别、生日、常居地、家乡、喜好、家庭信息等。如果您不提供该等信息,不会影响您享受乐游图软件服务的基本功能。
(二)向您提供产品\服务
1. 您向我们提供的个人信息
预订\下单:您在乐游图软件上预订\下单景区收费服务、景区商品等相关服务时,您可能需要提供联系人信息(姓名、性别、电话号码等)、地址信息、服务偏好等;
您在乐游图软件上预订\下单景区收费服务、景区商品等相关服务时,您可能需要根据有关法律规定提供您的实名身份信息(包括但不限于您的身份证、军官证、护照、驾驶证等载明您身份的证件照片、复印件、号码等)、联系人信息(姓名、性别、电话号码等)、电子邮箱地址(用于确认订单信息等)、个人照片(用于初诊等)、同行人信息、紧急联络人信息等。
支付:您在乐游图软件上支付时,您可以选择乐游图软件或者与乐游图软件合作的第三方支付机构(如微信支付、QQ钱包、Apple Pay、支付宝等支付通道)所提供的支付服务。支付功能本身并不收集您的个人信息,但我们需要将您的乐游图软件订单信息及对账信息与这些支付机构共享以确认您的支付指令并完成支付。
客服:当您与我们的客服取得联系时,我们的系统可能会记录您与客服之间的通讯记录,以及使用您的账号信息以便核验身份;当您需要我们提供与您订单相关的客户服务时,我们可能会查询您的相关订单信息以便给予您适当的帮助和处理;当您需要客服协助您修改有关信息(如配送地址、联系方式等)时,您可能还需要提供上述信息外的其他信息以便完成修改。
您在乐游图软件上生成的订单中,将可能包含您的身份信息、联络信息、位置信息、支付信息等,这些都属于敏感信息,请您谨慎向他人展示或对外提供,我们也将会在展示订单信息时,在保证信息可用性的基础上尽量做去标识化处理。
2. 我们在您使用服务过程中可能收集的个人信息
为了满足法律法规及提供服务的基本要求,保障您的账号安全与系统运行安全,我们会收集您在使用我们服务过程中产生的相关信息,包括:
(一)日志信息。当您使用我们提供的产品\服务时,我们会自动收集您使用我们服务的详细情况,并作为有关的网络日志保存,包括但不限于您的IP地址、浏览器的类型、使用的语言、操作系统的版本、访问的日期和时间、及您请求的网页记录等信息。
(二)位置信息。为了便捷您发现景区周边的餐饮、酒店、景点、商场、银行等生活服务信息,当您开启手机设备定位功能并使用我们的乐游图服务时,我们不会使用有关技术对您的实际位置进行定位,这些技术包括 IP 地址、GPS 以及能够提供相关信息的Wi-Fi 接入点、蓝牙和基站等传感器技术。我们可能会将您的位置信息发送给乐游图合作的第三方做进一步的计算、转换及纠偏,以实现我们为您提供景区导览的目的。
请您注意,大多数移动设备都允许您关闭定位服务,具体方法建议您参考或联系您移动设备的服务商或生产商,一旦您通过系统授权关闭定位功能,停止我们对您位置信息的访问,您将可能无法使用我们基于景区地理位置为您提供的服务,或者无法达到相关服务的预期效果。
(三)设备信息。我们可能会根据您在软件安装及使用中的具体权限,接收并记录您在接受我们服务过程中使用的相关设备信息,例如设备型号、唯一设备标识符、操作系统、分辨率、电信运营商等软硬件信息等。
对于从您使用相同乐游图软件账号登录各种设备上收集到的信息,我们可能会将它们进行关联,以便我们能在这些设备上为您提供一致的服务。
3. 我们可能间接收集到的您的个人信息
为能向您提供更优质的服务,同时为能确认交易状态及为您提供售后与争议解决服务,经您授权后我们会通过您选择的交易对象和交易直接涉及支付机构等收集与交易进度相关的您的交易等信息,以便于我们处理您的订单并保证服务的顺利完成,或者更好地预防诈骗、刷单等恶意行为。我们会依据法律法规的要求以及与第三方的约定,经您授权后向乐游图软件的关联方、合作伙伴等获得您的有关信息,并对其信息来源的合法性进行确认后使用您的这些信息。
如果您授权使用第三方账号登录时,我们会从第三方获取您共享的账号信息(如头像、昵称等),并在您同意本隐私政策后将您的第三方账户与乐游图软件账户进行绑定。
(三)改进我们的产品\服务
为维护、改进我们的产品或服务质量,向您提供个性化的服务,我们可能会在符合法律规定并根据您具体授权的情况下收集并使用如下信息:
1. 我们可能会收集您的订单信息、浏览及搜索信息等,以及将您在乐游图软件上使用某项服务中提供的信息与来自其他服务中的信息结合起来,进行综合统计、分析以形成用户画像,用来向您推荐或展示您可能感兴趣的产品\服务信息,或者通过系统向您展示个性化的第三方推广信息。包括在App页面向您推送消息通知,为您提供智能推荐,给您发送推广短信等。
如您不希望收到App页面上的消息通知,可以在首次安装App时拒绝接收消息通知,或者在移动端操作系统中的“通知”中心关掉对应的通知功能;如您不希望接受我们的智能推荐服务,可以自主选择按照距离、好评、价格等方式进行排序;如您不希望接收我们给您发送的推广短信,可通过信息中相应的退订功能进行退订。当您选择退出定向推送后,可以按照本隐私政策中第五部分有关删除您的个人信息的路径删除您的相关个人信息。
2.我们可能会收集您在参与产品\服务调查时主动向我们提供的信息,以及您与我们的关联方、合作伙伴之间互动时提供的相关信息,以便于您追踪订单情况、发起用户投诉以及我们优化客户服务的质量与流程。
3.我们可能将业务中收集的个人信息用于统计分析和改进运营,从而改进我们的产品、服务或营销计划;又如为改进我们系统而进行的技术改造、网络维护、故障排除、内部政策与流程制定、生成内部报告等。
4.您可以授权(通过本隐私政策及独立的《信息授权使用协议》等)使用我们的服务创建交流与分享功能,并允许乐游图软件获取您手机或其他第三方社交平台中的通讯录信息和公开信息(头像、昵称等),从而使您及您通讯录中同样授权开通此项功能的联系人,能够在乐游图软件上分享有关内容(头像、昵称、评价信息等)以实现互动功能。此项功能您可以在好友设置中关闭,一旦关闭您将可能无法实现与您的好友在乐游图软件进行分享交流,但不会影响您享受乐游图软件服务的基本功能。
(四)为您提供安全保障
为提高您使用我们提供的服务的安全性,更准确地预防钓鱼网站欺诈和木马病毒,我们可能会使用或整合您的个人信息以及我们的关联方、合作伙伴取得您授权或者依法共享的信息,根据您的使用习惯和常用软件信息等来综合判断您的账号及交易风险,包括验证身份,预防、发现、调查可能存在的欺诈、网络病毒、网络攻击等安全风险以及违反我们或关联方协议、政策或规则等行为,以保护您、其他用户、我们或关联方的合法权益,并记录一些我们认为有风险的链接(“URL”)。
(五)其他用途
我们将信息用于本政策未载明的其他用途,或者将基于特定目的收集而来的信息用于其他目的时,会单独征求您的授权同意。
(六)请您知悉,以下情形中,我们收集、使用个人信息无需征得您的授权同意:
1、与国家安全、国防安全有关的;
2、与公共安全、公共卫生、重大公共利益有关的;
3、与犯罪侦查、起诉、审判和判决执行等有关的;
4、出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
5、所收集的个人信息是个人信息主体自行向社会公众公开的;
6、从合法公开披露的信息中收集的您的个人信息的,如合法的新闻报道、政府信息公开等渠道;
7、根据您的要求签订合同所必需的;
8、用于维护所提供的产品与/或服务的安全稳定运行所必需的,例如发现、处置产品与/或服务的故障;
9、为合法的新闻报道所必需的;
10、学术研究机构基于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的;
11、法律法规规定的其他情形。
请注意,无法与任何特定个人直接建立联系的数据,不属于个人信息。如果我们将无法与任何特定个人建立联系的数据与其他信息结合用于识别自然人个人身份,或者将其与个人信息结合使用,则在结合使用期间,此类信息将被视为个人信息。
二、我们如何使用Cookie和同类技术
(一)Cookie的使用
为确保网站正常高效运转、为您获得更轻松的访问体验、向您推荐您可能感兴趣的内容,我们会在您的设备终端\系统上存储名为 Cookie的小数据文件。 Cookie会帮助您在后续访问我们网站时调用您的信息,简化您填写个人信息(例如一键登录等)的流程;帮助您优化对广告的选择与互动;保护您的数据安全等。 我们不会将 Cookie用于本隐私政策所述目的之外的任何用途。您可根据自己的偏好管理或删除 Cookie。您可以清除计算机或移动设备上保存的所有 Cookie,您有权接受或拒绝Cookie。大多数浏览器会自动接受Cookie,但您通常可根据自己的需要来修改浏览器的设置以拒绝Cookie;另外,您也可以清除软件内保存的所有Cookie。但您可能因此无法完全体验我们某些便捷性和安全性的服务功能。
(二)网络Beacon和同类技术的使用
除Cookie外,我们网页上常会包含一些电子图象(称为“单像素”GIF文件或“网络Beacon”)等其他同类技术,它们可以帮助网站计算浏览网页的用户或访问某些Cookie。我们使用网络Beacon的方式有:
(1)我们通过在我们网站上使用网络Beacon,计算用户访问数量,并通过访问Cookie辨认注册用户。
(2)我们通过得到的Cookie信息,可以在我们网站提供个性化服务。
三、我们如何共享、转让、公开披露您的个人信息
(一)共享
1、我们不会与乐游图软件以外的任何公司、组织和个人共享您的个人信息,但以下情况除外:
(1)事先获得您明确的同意或授权;
(2)基于法定情形下:根据法律法规的规定、诉讼争议解决需要,或行政、司法等有权机关依法提出的要求;
(3)与关联方共享:为向您提供一致化服务以及便于您进行统一管理,我们可能会将您的个人信息与我们的关联方共享。但我们只会共享必要的个人信息,如果我们共享您的个人敏感信息或者关联方改变个人信息的使用目的,将再次征求您的授权同意。
(4)与合作伙伴分享:我们可能会向业务合作伙伴共享为您提供服务所必要的订单信息、账户信息、支付信息等。我们的业务合作伙伴包括以下类型:
供应商\服务提供商。仅为实现本政策中声明的目的,我们的某些服务将由业务合作伙伴提供。以保障为您提供的服务顺利完成,我们可能会将您的个人信息共享给上述合作伙伴,包括配送业务、技术服务、支付服务、金融业务等。其中可能包括您的联络信息、订单信息、支付信息、地址信息等,以保障为您提供的服务顺利完成。例如在您使用我们的外卖服务时,我们必须与配送服务提供商共享您的订单和配送信息,以保证订单的安全准确送达;又如我们需要将您的订单号和订单金额与第三方支付机构共享以实现其确认您的支付指令并完成支付等。
其他业务合作伙伴。我们还可能与委托我们进行推广和广告投放的合作伙伴共享信息,但我们仅会向这些合作伙伴提供推广的覆盖面、有效性以及统计类等信息,而不会提供可以识别您身份的个人信息。
(5)基于协议约定:依据您与我们签署的相关协议(包括在线签署的电子协议及平台规则)或法律文件,有必要向第三方共享时;
(6)基于合理商业习惯:例如在我们计划与其他公司进行资本市场活动(包括但不限于IPO,债券发行)接受尽职调查时等;
(7)基于学术研究;例如为科研机构开展统计或学术研究之必要;
(8)基于符合法律法规的社会公共利益等。
请您知悉,即使已经取得您的授权同意,我们也仅会出于合法、正当、必要、特定、明确的目的共享您的个人信息,并尽量对共享内容中的个人信息进行去标识化处理。其中您的联络信息和地址信息属于个人敏感信息,我们已经采取了“默认号码保护”、“地址隐藏”等举措尽全力保护您的个人信息。
对我们仅为实现本政策中声明的目的与之共享个人信息的公司、组织和个人,我们会与其签署严格的信息保护和保密协定,要求他们遵守协议并采取相关的安全措施来保护您的个人信息。
(二)转让
随着我们业务的发展,我们及我们的关联方有可能进行合并、收购、资产转让或类似的交易,如涉及个人信息的转让,我们会要求受让您个人信息的公司、组织继续接受本隐私政策的约束,否则,我们将要求该公司、组织重新征求您的授权同意。
(三)公开披露
我们仅会在以下情况下,且采取符合业界标准的安全防护措施的前提下,才可能公开披露您的个人信息:
1、根据您的需求,在您明确同意的披露方式下披露您所指定的个人信息;
2、根据法律、法规的要求、强制性的行政执法或司法要求所必须提供您个人信息的情况下,我们可能会依据所要求的个人信息类型和披露方式公开披露您的个人信息。在符合法律法规的前提下,当我们收到上述披露信息的请求时,我们会要求必须出具与之相应的法律文件,如传票或调查函。
(四)共享、转让、公开披露个人信息时事先征得授权同意的例外
以下情形中,共享、转让、公开披露您的个人信息无需事先征得您的授权同意:
1、与国家安全、国防安全有关的;
2、与公共安全、公共卫生、重大公共利益有关的;
3、与犯罪侦查、起诉、审判和判决执行等有关的;
4、出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
5、其他维护公共利益的情形,例如您的信用评价信息需要被公开\共享;
6、您自行向社会公众公开的个人信息;
7、从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。
根据法律规定,共享、转让、公开披露经去标识化处理的个人信息,且确保数据接收方无法复原并重新识别个人信息主体的,我们对此类数据的处理将无需另行向您通知并征得您的同意。
请注意,您在使用我们服务时自愿发布甚至公开分享的信息,可能会涉及您或他人的个人信息甚至个人敏感信息,如您的交易信息,以及您在评价时选择上传包含个人信息的文字、图片或视频等各种形式的信息。请您在使用我们的服务时更加谨慎地考虑,是否要发布甚至公开分享相关信息。
四、我们如何保存和保护您的个人信息
(一)个人信息的保存
1、保存期限:除非依据法律法规或双方约定,我们仅会在实现目的所必需的最短时间内留存您的相关个人信息。在您主动注销账号时,我们将根据法律法规的要求尽快删除您的个人信息或作匿名化处理,有关注销账号的相关规则和流程,请参见本政策附件中的《用户注销协议》。
2、保存地域:原则上,我们在中华人民共和国境内收集和产生的个人信息,将存储在中国境内,但以下情形除外:
法律法规有明确规定的;
单独征得您的授权同意;
您主动发起的跨境预定、下单、交易等个人行为(如购买国际机票、预订国际酒店等)。
在上述情形中,我们会并要求数据接收方按照本隐私政策以及其他相关的安全保密措施来处理个人信息。
3、终止运营:如果发生终止运营等情形,我们将会至少提前30天通知您,并在终止运营后对您的个人信息进行删除或匿名化处理。
(二)个人信息的保护措施
1、数据安全措施
为保障您的信息安全,我们努力采取各种符合业界标准的物理、电子和管理方面的安全措施来保护您的个人信息,建立数据分类分级制度、数据安全管理规范、数据安全开发规范来管理规范个人信息的存储和使用。
乐游图软件通过信息接触者保密协议、监控和审计机制来对数据进行全面安全控制。防止您的个人信息遭到未经授权访问、公开披露、使用、修改、损坏或丢失。例如在您的浏览器与“服务”之间交换数据(如信用卡信息)时采用SSL加密保护技术;同时对网站本身提供https安全浏览方式;使用加密技术确保数据的保密性;使用受信赖的保护机制防止数据遭到恶意攻击;部署访问控制机制,确保只有授权人员才可访问个人信息;以及举办安全和隐私保护培训课程,加强员工对于保护个人信息重要性的认识。
2、安全认证
我们已先后通过了公安部信息安全等级保护三级认证、第三方支付行业(支付卡行业PCI DSS)数据安全标准国际认证、ISO27001信息安全管理体系国际认证等认证资质,并与监管机构、第三方测评机构建立了良好的协调沟通机制,及时抵御并处置各类信息安全威胁,为您的信息安全提供全方位保障。
3、请您知悉并理解,互联网并非绝对安全的环境,我们强烈建议您通过安全方式、使用复杂密码,协助我们保证您的账号安全。如您发现自己的个人信息泄密,尤其是您的账户或密码发生泄露,请您立即根据本隐私政策中提供的联系方式联络我们,以便我们采取相应措施。
4、安全事件
在不幸发生个人信息安全事件后,我们会立即成立专项应急小组,启动应急预案,防止安全事件扩大,并按照法律法规的要求及时向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。我们将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知您,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。同时,我们还将按照监管部门要求,主动上报个人信息安全事件的处置情况。
五、您如何管理您的个人信息
您对您的个人信息享有以下权利:
(一)您有权访问、更正、删除您的个人信息,法律法规规定的例外情况除外。您可以通过以下方式管理您的信息:
账户信息——您可以访问、更正您账户中的个人资料及账号信息(身份认证信息除外)、支付信息、账号绑定信息等,也可以更改您的密码、添加安全信息或关闭您的账户等,您可以通过访问网页及App在设置中执行此类操作。
搜索浏览信息——您可以在乐游图软件App中访问或清除您的搜索历史记录、查看和修改兴趣以及管理其他数据。
订单信息——您可以通过访问“我的订单”页面查看您的所有已经完成、待付款、待售后、待评价的订单。您可以选择删除已完成的订单信息,但这样可能导致我们无法根据您的购买信息而准确提供相应的售后服务。
评论信息——您可以通过访问乐游图软件App页面上的“评价”、“评价中心”访问、更正、清除您的评论内容。
如果您无法通过上述链接管理这些个人信息,您可以随时联系我们的客服。我们将在30天内回复您的访问请求。
(二)改变您授权同意的范围或撤回授权
您可以通过在乐游图软件App中删除信息、更改隐私设置以及在浏览器或操作系统中关闭设备功能等方式改变同意范围或撤回您的授权。
请您理解,当您执行上述操作后,我们将无法继续为您提供撤回同意或授权所对应的服务,但不会影响此前基于您的授权而开展的个人信息处理。
(三)注销账户
您有权注销您的乐游图软件账户,您可以通过访问App页面上的“设置”—“安全中心”——“注销账号”中进行在线操作;或者拨打我们的客服电话进行协助注销。
如果您无法通过上述方式访问、更正或删除您的个人信息以及注销账号,或者如果您认为乐游图软件存在违反法律的规定收集、使用您个人信息的情形,您可以通过我们的客服或通过本隐私政策提供的其他方式与我们取得联系。为了保障安全,我们可能需要您提供相应方式证明您的身份和请求的正当性,我们将在收到您反馈并验证您的身份后的30天内答复您的请求。对于您合理的请求,我们原则上不收取费用,但对多次重复、超出合理限度的请求,我们将视情收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际(例如,涉及备份磁带上存放的信息)的请求,我们可能会予以拒绝。
(四)拒绝接受定向推送及营销信息
拒绝营销——您可以通过回复“TD”退订我们发送给您的营销短信。拒绝定向推送——您可以在搜索相关服务时拒绝选择“智能排序”的算法推荐模式,而选择“距离优先”、“低价优先”等非定向的推荐模式使用我们的产品\服务。
六、未成年人的个人信息保护
乐游图软件非常重视对未成年人个人信息的保护。我们的网站和服务主要面向成人。如您为未成年人的,建议您请您的父母或监护人仔细阅读本隐私权政策,并在征得您的父母或监护人同意的前提下使用我们的服务或向我们提供信息。
对于经父母或监护人同意使用我们的产品或服务而收集未成年人个人信息的情况,我们只会在法律法规允许、父母或监护人明确同意或者保护未成年人所必要的情况下使用、共享、转让或披露此信息。
如果我们发现自己在未事先获得可证实的父母或法定监护人同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关数据。
七、通知和修订
为给您提供更好的服务,我们的业务将不时变化,本隐私政策也将随之调整。未经您明确同意,我们不会削减您依据本隐私政策所应享有的权利。我们会通过在我们网站、移动端上发出更新版本或以其他方式提醒您相关内容的更新,也请您访问我们以便及时了解最新的隐私政策。在前述情况下,若您继续使用我们的服务,即表示同意接受修订后的本政策并受之约束。
八、如何联系我们
如果您对于我们的个人信息处理行为存在任何投诉举报需求,您可以通过乐游图网站\App上提供的联系方式\客服系统与我们联系并作充分描述,我们将在验证您身份的30天内答复您的请求并尽力解决。
如果您对我们的回复不满意,特别是认为我们的个人信息处理行为损害了您的合法权益,您还可以通过向被告住所地有管辖权的法院提起诉讼。
附录:
1、个人信息:指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。本隐私政策中可能涉及到的个人信息包括但不限于:个人基本信息(包括姓名、电话号码、性别、住址、生日等);个人身份信息(包括身份证、军官证、护照、驾驶证等);网络身份标识信息(包括系统账号、IP地址、邮箱地址及与前述有关的密码、口令、口令保护答案);个人财产信息(包括银行账号、交易和消费记录、信贷记录以及虚拟财产信息等);个人健康生理信息(包括病症、病历、病史等);联系人信息(包括通讯录、好友列表等);个人上网记录(包括网站浏览记录、点击记录等);个人设备信息(包括硬件型号、操作系统类型、唯一设备识别码等描述个人常用设备基本情况的信息);个人位置信息(包括行踪轨迹、精准定位信息、住宿信息、经纬度等)。
2、个人敏感信息:是指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息。本隐私政策中可能涉及到的个人敏感信息包括:个人身份信息(包括身份证、军官证、护照、驾驶证等);个人财产信息(银行账号、交易和消费记录、信贷记录以及虚拟财产信息等);网络身份识别信息(包括账户名、账户昵称、邮箱地址及与前述有关的密码与密码保护问题和答案);其他信息(个人电话号码、婚史、宗教信仰、行踪轨迹等)。
3、乐游图软件:本政策所称的乐游图软件是指乐游图软件及其旗下现有和未来设立的相关关联公司的单称或合称。
4、关联账号:您可以使用相同的手机号码登录乐游图软件所提供的产品\服务,以便于我们基于关联账号向您提供一致的服务以及您进行统一管理。
法律声明
乐游图提醒您:在您使用乐游图的各项服务前,请您务必仔细阅读并透彻理解本声明。如果您使用乐游图,您的使用行为将被视为对本声明全部内容的认可。
知识产权声明
乐游图软件所提供的各项服务的所有权和运作权归赛拓信息技术有限公司责任(以下简称“本公司”)。除特别说明或者法律另有特别规定外,本公司是乐游图及其中所刊登全部资料、信息的知识产权的唯一所有人。除法律法规或者本平台另有规定/约定外,用户通过乐游图发布的消息一经发布即向公众传播和共享。
本网站所刊登的全部资料包括但不限于网站架构、程序设计、程序代码、页面图文、音频、视频等信息(包括并不限于景区描述等)。
除法律特别规定或者政府明确要求外,在未取得本站书面明确许可前,任何单位或者个人不得将本网站的任何知识产权对象进行任何目的的使用,任何单位或个人不得以任何方式以任何文字对本站资料作全部和局部复制、转载、引用和链接,任何单位或者个人不得以任何方式引诱、要求本网站注册用户或者第三方复制转载本网站内容或者同意该单位或者个人复制转载本网站内容,亦不得通过技术手段抓取本网站内容。任何注册用户将在本网站注册用户名和密码提供给任何第三方用于许可其复制本站内容的,将构成对注册协议的违反,并可能导致其账户被关闭或者处罚。
用户保证不会将已发表于本站的信息资料,以任何形式发布或授权其它网站(及媒体)使用。同时,在法律允许的范围内,乐游图保留删除站内各类不符合规定的点评信息或者其他任何信息而不通知用户的权利。
任何违反本站知识产权声明的行为,本站保留追究其行为人法律责任的权利。
侵权投诉须知
1. 根据《中华人民共和国侵权责任法》第三十六条之规定,任何第三方认为用户利用乐游图软件侵害其民事权益或实施侵权行为的,包括但不限于侮辱、诽谤等,被侵权人有权书面通知乐游图采取删除、屏蔽、断开链接等必要措施。
2. 根据《信息网络传播权保护条例》之规定,任何第三方认为乐游图所涉及的作品、表演、录音录像制品,侵犯自己的信息网络传播权或者被删除、改变了自己的权利管理电子信息的,可以向乐游图提交书面通知,要求乐游图删除该侵权作品,或者断开链接。通知书应当包含下列内容:
(一)权利人的姓名(名称)、联系方式和地址;
(二)要求删除或者断开链接的侵权作品、表演、录音录像制品的名称和网络地址;
(三)构成侵权的初步证明材料。
权利人应当对通知书的真实性负责。
您同时应该了解,根据《信息网络传播权保护条例》之规定,乐游图有权将您的投诉通知书转送至相关服务对象。该服务对象接到转送的通知书后,认为其提供的作品、表演、录音录像制品未侵犯他人权利的,可以向乐游图提交书面说明,要求恢复被删除的作品、表演、录音录像制品,或者恢复与被断开的作品、表演、录音录像制品的链接。乐游图接到服务对象的书面说明后,有权立即恢复被删除的作品、表演、录音录像制品,或者恢复与被断开的作品、表演、录音录像制品的链接,同时将该服务对象的书面说明转送投诉人。此种情形下,您不得再通知乐游图删除该作品、表演、录音录像制品,或者断开与该作品、表演、录音录像制品的链接。
3. 任何第三方(包括但不限于企业、公司、单位或个人等)认为乐游图用户发布的任何信息侵犯其合法权益的,包括但不限于以上两点,在有充分法律法规及证据足以证明的情况下,可以按照本指引文件提供的联系方式进行投诉。
4.为了明确法律责任,方便乐游图依法依约及时作出处理,除前述指引已提及之投诉内容外,侵权投诉还应包含下述信息:
(1)被侵权人的证明材料,或被侵权作品的原始链接及其它证明材料。
(2)侵权信息或作品在乐游图上的具体链接。
(3)侵权投诉人的联络方式,以便乐游图相关部门能及时回复您的投诉,最好包括电子邮件地址、电话号码或手机等。
(4)投诉内容须包括以下声明:“本人本着诚信原则,有证据认为该对象侵害本人或他人的合法权益。本人承诺投诉全部信息真实、准确,否则自愿承担一切后果。”
(5)本人亲笔签字并注明日期,如代理他人投诉的,必须出具授权人签字、盖章的授权书。
5.投诉人可以通过下列方式通知乐游图,将投诉资料邮寄至下述地址:
邮寄地址:辽宁省大连市高新园区黄浦路533号海创国际产业大厦11层02-04室
邮政编码:116000
收件人:旅游事业部(乐游图)
电话:0411-84820955
6.当对其投诉内容的准确性、客观性、合法性、完整性承担责任。如果侵权投诉不实,则用户可能承担法律责任;如果投诉通知内容不准确、不完整,则投诉人应承担因此造成的后果。
7.投诉人须了解,乐游图仅有权利和义务在法律法规规定及平台规则约定的范围内,在网站工作人员的认知水平和能力、资格范围内对投诉作出判断和处理或答复。这一处理机制不同于也无意替代司法机关的裁断。乐游图亦无意介入投诉人与被投诉人之间的纠纷。乐游图不对您的投诉是否能够得到某种结果作出任何承诺或者保证,亦不因对您的投诉处理行为而承担任何义务或者责任。
作弊检测
若乐游图通过技术检测、人工抽检等手段有合理理由怀疑用户资料信息为错误、不实、失效或不完整,本网站有权暂停或终止用户的账号,并拒绝现在或将来使用本站网站网络服务的全部或部分,同时保留追索用户不当得利返还的权利。
再次感谢您对乐游图软件的信任和使用!
赛拓信息技术有限公司
2020年3月1日生效