-
-
- 挂盘项详情页增加曝光页签
-
页面原型如上所示:
字段取值逻辑如下:
访客:同访问页签取值逻辑
操作:需要过滤操作类型,只展示我要买、成交、我要卖、样片、BOM、纠错、客服、分享按钮的操作
对象类型:保持现有访问记录的对象类型
访问页面:访客访问此商品的URL,可能是商品详情页,也可能是在商品列表页直接展开点击该商品的功能区按钮
访问时间:取操作时间
访客来源:访客每天首次访问此商品的来源渠道(含商品详情页+商品列表页的操作)
上一页面:访客每天首次访问此商品的来源URL(含商品详情页+商品列表页的操作)
是否成功:需要根据不同的操作判断是否成功
操作 | 查询源头 | 判断逻辑 |
我要买 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
成交 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
我要卖 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
我要询 | 固定为否 | |
我要供 | 固定为否 | |
样片 | 访问 | 根据UUID+USERID+(操作时间>此按钮的操作时间)查询访问日志里是否有标题是“样片申请”、操作为“答卷提交”的访问记录,如果有则为是,没有则为否 |
BOM | 访问 | 根据UUID+USERID+(操作时间>此按钮的操作时间)查询访问日志里是否有标题是“终端特价申请”、操作为“答卷提交”的访问记录,如果有则为是,没有则为否 |
纠错 | 固定为否 | |
客服 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
分享 | 访问 | 查询操作时间在点击分享按钮后10分钟内,访问日志里是否有访问URL为分享链接的访问记录,如果有则为是,没有则为否 |
接口调用/visit/list
入参
字段名 | 中文解释 |
"current": 0, | 第几页 |
"order_by": "string", | 排序 |
"page_size": 0, | 每页数量 |
"param": { | |
"contact_id": 0, | 联系人ID:联系人详情页需要传,挂盘项详情页不用传 |
"if_compute": true, | 是否计算,默认为否 |
"object_code": "string", | 对象编码:挂盘项详情页传商品号,联系人详情页不用传 |
"object_type": "string", | 对象类型:挂盘项详情页传SHOP_SPU,联系人详情页不用传 |
"total": 0 | 总数 |
返回字段解释:
字段名 | 中文解释 |
browser: "string", | 浏览器 |
click_url: "string", | 下一页面 |
component_name: "string", | 操作名 |
id: "0", | 访问ID |
invitor_user_id: 0, | 邀请人用户ID |
invitor_user_name: "string", | 邀请人名称 |
menu_name: "string", | 菜单名 |
object_code: "string", | 对象编码:商品号(挂盘项详情) |
object_type: "string", | 对象类型:SHOP_SPU(挂盘项详情) |
os: "string", | 操作系统 |
page_id: "0", | 页面ID |
page_shop_id: "0", | 访问页面所属商户ID |
page_shop_name: "string", | 访问页面所属商户名称 |
page_type: "string", | 访问页面类型 |
qr_code: "string", | 邀请码 |
refer_url: "string", | 上一页面 |
title: "string", | 标题 |
url: "string", | 访问页面 |
utm_id: "0", | 推广ID |
utm_source: "string", | 来源渠道 |
uuid: "string", | UUID |
visit_at: "string", | 访问时间 |
visit_at_int: "0", | 访问时间 |
visit_duration: 0, | 访问时长 |
is_success:true | 是否成功 |
visit_ip: "string", | 访问IP |
visitor_id: "string", | 访客ID |
visitor_name: "string", | 访客名称 |
visitor_shop_id: "0", | 访问商户ID |
visitor_type: "string", | 访客类型 |
website_id: "0" | 网站ID |
-
-
- 联系人详情页增加访问页签
-
联系人详情页增加访问页签,原型如上
页签字段查询逻辑:
访问页面:按UUID+访问URL+访问时间汇集,即访客A分别在6.1、6.2、6.5号3天访问了同一个页面多次,则显示3条记录
访问时间:当前访客每天首次访问此URL的时间
访客来源:当前访客每天首次访问此URL的来源渠道
上一页面:当前访客每天首次访问此URL的来源URL
访问时长:当前访客每天首次访问此商品详情页的时间与访客在此页面最晚一次点击其他链接的时间差,统一换算为秒数
下一页面:当前访客在访问此URL页面点击的链接URL,取第一次点击的
曝光数:
页面 | 统计逻辑 |
商品列表页 | 统计当前访客每天在商品列表页产生的所有商品我要买、成交、我要卖、我要询、我要供、样片、BOM、纠错、客服、分享按钮的点击数量总和 |
商品详情页 | 统计当前访客每天在商品详情页对此商品产生的我要买、成交、我要卖、我要询、我要供、样片、BOM、纠错、客服、分享按钮的点击数量总和 |
内容详情页 | 统计当前访客每天在内容详情页产生的打赏、收藏、点赞、微信分享、微博分享、QQ空间分享、邀请、转发、评论、答卷提交按钮的点击数量总和 |
邀请人:如果访问页面有邀请码,则展示邀请码对应的邀请人名称,如果没有则留空
邀请码:如果访问页面有邀请码则显示,如果没有则留空
-
-
- 联系人详情页增加曝光页签
-
页面原型如上所示:
字段取值逻辑如下:
访客:同访问页签取值逻辑
操作:需要过滤操作类型,按下表进行过滤
页面 | 判断条件 | 操作 |
商品列表页 | 标题为“商品” | 我要买、成交、我要卖、样片、BOM、纠错、客服、分享 |
商品详情页 | 操作对象为“商品”,对象ID为商品号 | 我要买、成交、我要卖、样片、BOM、纠错、客服、分享 |
内容详情页 | 操作对象为“内容”,对象ID为publishing_id | 打赏、收藏、点赞、微信分享、分享到微博、分享到QQ空间、邀请、转发、评论、答卷提交 |
对象类型:访问记录的对象类型
访问页面:直接取访问URL字段
访问时间:取操作时间
访客来源:当前访客每天首次访问此URL的来源渠道
上一页面:当前访客每天首次访问此URL的来源URL
是否成功:需要根据不同的操作判断是否成功
操作 | 查询数据源 | 判断逻辑 |
我要买 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
成交 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
我要卖 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
我要询 | 固定为否 | |
我要供 | 固定为否 | |
样片 | 访问 | 根据UUID+USERID+(操作时间>此按钮的操作时间)查询访问日志里是否有标题是“样片申请”、操作为“答卷提交”的访问记录,如果有则为是,没有则为否 |
BOM | 访问 | 根据UUID+USERID+(操作时间>此按钮的操作时间)查询访问日志里是否有标题是“终端特价申请”、操作为“答卷提交”的访问记录,如果有则为是,没有则为否 |
纠错 | 固定为否 | |
客服 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
分享 | 访问 | 查询操作时间在点击分享按钮后60分钟内,访问日志里是否有访问URL为分享链接的访问记录,如果有则为是,没有则为否 |
打赏 | 订单 | 根据UUID+USERID+商品号(操作时间>此按钮的操作时间)查询订单里是否有已支付的数据,如果有则为是,没有则为否 |
收藏 | 访问 | 固定为“是”,因为点了就算成功 |
点赞 | 访问 | 固定为“是”,因为点了就算成功 |
微信分享 | 访问 | 查询操作时间在点击分享按钮后60分钟内,访问日志里是否有访问URL为分享链接的访问记录,如果有则为是,没有则为否 |
分享到微博 | 访问 | 固定为“是”,因为点了就算成功 |
分享到QQ空间 | 访问 | 固定为“是”,因为点了就算成功 |
邀请 | 访问 | 固定为“是”,因为点了就算成功 |
转发 | 内容 | 根据publishing_id查询该文稿对应的content_id是否产生了新的转载发布稿,如果有则为是,否则为否 |
评论 | 内容 | 根据publishing_id+用户ID查询该文稿对应的content_id是否产生了新的评论,如果有则为是,否则为否 |
计算
func (self *WebsiteVisitCompute) ComputeVisitFlag(req *apimodel.VisitFlagRequest, ret *pagemodel.PageResult[*esutm.WebsiteVisitEs]) { if ret.NotExistRecord() { golog.Info("WebsiteVisitRequest ComputeVisitFlag has no records!") return } golog.Info("WebsiteVisitRequest ComputeVisitFlag will compute and saving records:") var user = req.UserID if req.UserId == 0 && user != nil { req.UserId = user.Id } self.ComputeVisitFlagCms(user, ret) self.ComputeVisitFlagAll(user, ret) for i := range ret.Data { var data = ret.Data[i] data.IsSuccess = data.IsSuccess || data.Ok() } go self.SaveVisitFlag(ret) }
func (self *WebsiteVisitCompute) ComputeVisitFlagAll(user *proto.UserID, ret *pagemodel.PageResult[*esutm.WebsiteVisitEs]) { golog.Info("WebsiteVisitRequest ComputeVisitFlagAll ") data := lo.Filter(ret.Data, func(item *esutm.WebsiteVisitEs, index int) bool { return item.IfCmsShopSpu() }) for i := range data { var req = apimodel.FindBeanVisitFlagRequest().FromVisitEs(ret.Data[i]) // ComputeVisitAnswer if req.ComponentName == "样片" || req.ComponentName == "BOM" { self.ComputeVisitAnswer(req, ret) } // 微信分享 if share := self.computeWeixinShareExist(req); share { ret.Data[i].VisitFlag.VisitCms.IfShareWechat = share } // 订单 if orderDone := self.computeOrderDone(req); orderDone { if req.IfShopSpu() { ret.Data[i].VisitFlag.VisitShopspu.IfBuy = orderDone ret.Data[i].VisitFlag.VisitShopspu.IfDealDone = orderDone ret.Data[i].VisitFlag.VisitShopspu.IfSell = orderDone } if req.IfCms() { ret.Data[i].VisitFlag.VisitCms.IfReward = orderDone } } } golog.Info("WebsiteVisitRequest ComputeVisitFlagAll end!") }对象
封装
func (self *VisitFlagRequest) FromVisitEs(data *esutm.WebsiteVisitEs) *VisitFlagRequest { var req = self req.VisitorType = data.VisitorType req.Uuid = data.Uuid req.UserId = gconv.Int64(data.VisitorId) req.ObjectType = data.ObjectType req.ObjectCodes = []string{data.ObjectCode} req.VisitUrl = data.Url req.VisitAtStart = data.VisitAt return self }
func (self *VisitFlagRequest) BuildQueryVisitUser() *elastic.BoolQuery { var q = elastic.NewBoolQuery() q.Must(elastic.NewTermQuery("visitor_type", self.VisitorType)) if self.IfVisitUser() { q.Must(elastic.NewTermQuery("visitor_id", self.UserId)) } else { q.Must(elastic.NewTermQuery("uuid", self.Uuid)) } return q } func (self *VisitFlagRequest) BuildQueryInHour(dateField string) *elastic.BoolQuery { var q = elastic.NewBoolQuery() var start = self.VisitAtStart var end = self.TimeAfterHour(start) q.Must(elastic.NewRangeQuery(dateField).Gte(start.UnixMilli()).Lte(end.UnixMilli())) return q } func (self *VisitFlagRequest) BuildQueryVisitUserInHour() *elastic.BoolQuery { var q = self.BuildQueryVisitUser() var qq = self.BuildQueryInHour("visit_at") q.Must(qq) return q }
func (self *WebsiteVisitCompute) computeOrderDone(req *apimodel.VisitFlagRequest) bool { if !self.IfOrderComponentDone(req.ComponentName) { return false } //实物商品 var number = req.ObjectCodes[0] if req.IfCms() { //内容产品 var find = apidata.FindBeanCmsService().ContentPublishById(gconv.Int64(req.ObjectCodes[0]), 0) if find.NotExistRecord() { return false } number = find.Data[0].PublishedCode } if number == "-1" || number == "" { return false } var rets = apidata.FindBeanListService().ListByNumber(number) if rets.ExistRecord() { var ret = self.FindCommerceLineItem(rets.Data[0].LineId, req) return ret.ExistRecord() } return rets.ExistRecord() }
func (self *WebsiteVisitCompute) FindCommerceLineItem(lineId string, req *apimodel.VisitFlagRequest) *pagemodel.PageResult[*esorder.CommerceLineItemEs] { var q = req.BuildQueryInHour("created_at") q.MustNot(elastic.NewTermsQuery("metadata.status.keyword", "L")) q.Should(elastic.NewTermsQuery("metadata.purchase_line_id.keyword", lineId)) q.Should(elastic.NewTermsQuery("metadata.sales_line_id.keyword", lineId)) q.MinimumNumberShouldMatch(1) var qq = esorder.NewWebFacadeCommerceLineItemEsOf(q) qq.LogQueryMaster(q, "FindCommerceLineItem") return qq.GeneralQueryMax() }
func (self *ListDao) ListByNumber(number string) *pagemodel.PageResult[*eslist.PublishedLineEs] { var q = elastic.NewBoolQuery() q.Must(elastic.NewTermQuery("number", number)) var qq = eslist.NewWebFacadePublishedLineV1EsOf(q) var ret = qq.GeneralQueryPageSize(1) if ret.IsFailed() { qq.LogQueryMaster(q, "ListByNumber") golog.Error("ListByNumber ret:", ret) } qq.LogQueryMaster(q, "ListByNumber") return ret }