From 53be594d647210cf22fecd350c916ed3a17806f9 Mon Sep 17 00:00:00 2001 From: 15090180611 <215509543@qq.com> Date: Tue, 14 Jan 2025 17:56:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE=E9=A9=BE?= =?UTF-8?q?=E9=A9=B6=E8=88=B1=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/school/classes/Visit.php | 77 ++++++++++ .../school/classes/VisitDistribution.php | 37 +++++ .../admin/lang/zh-cn/school/classes/visit.php | 20 +++ .../school/classes/visit_distribution.php | 19 +++ .../admin/model/school/classes/Visit.php | 64 +++++++++ .../school/classes/VisitDistribution.php | 60 ++++++++ .../admin/validate/school/classes/Visit.php | 27 ++++ .../school/classes/VisitDistribution.php | 27 ++++ .../admin/view/school/classes/visit/add.html | 33 +++++ .../admin/view/school/classes/visit/edit.html | 33 +++++ .../view/school/classes/visit/index.html | 46 ++++++ .../classes/visit_distribution/add.html | 63 ++++++++ .../classes/visit_distribution/edit.html | 63 ++++++++ .../classes/visit_distribution/index.html | 135 ++++++++++++++++++ application/api/controller/Crontab.php | 3 + application/api/controller/WechatUtil.php | 37 +++++ application/api/controller/school/BigData.php | 64 +++++++++ .../common/library/NightSchoolBigData.php | 75 +++++++--- .../common/listener/classes/ActivityHook.php | 10 +- .../common/listener/classes/ClassesHook.php | 10 +- .../common/model/school/classes/Visit.php | 67 +++++++++ .../school/classes/VisitDistribution.php | 92 ++++++++++++ application/extra/upload.php | 1 + .../school/classes/activity/activity.js | 19 +++ .../js/backend/school/classes/classes_lib.js | 20 +++ .../assets/js/backend/school/classes/visit.js | 67 +++++++++ .../school/classes/visit_distribution.js | 61 ++++++++ 27 files changed, 1211 insertions(+), 19 deletions(-) create mode 100644 application/admin/controller/school/classes/Visit.php create mode 100644 application/admin/controller/school/classes/VisitDistribution.php create mode 100644 application/admin/lang/zh-cn/school/classes/visit.php create mode 100644 application/admin/lang/zh-cn/school/classes/visit_distribution.php create mode 100644 application/admin/model/school/classes/Visit.php create mode 100644 application/admin/model/school/classes/VisitDistribution.php create mode 100644 application/admin/validate/school/classes/Visit.php create mode 100644 application/admin/validate/school/classes/VisitDistribution.php create mode 100644 application/admin/view/school/classes/visit/add.html create mode 100644 application/admin/view/school/classes/visit/edit.html create mode 100644 application/admin/view/school/classes/visit/index.html create mode 100644 application/admin/view/school/classes/visit_distribution/add.html create mode 100644 application/admin/view/school/classes/visit_distribution/edit.html create mode 100644 application/admin/view/school/classes/visit_distribution/index.html create mode 100644 application/common/model/school/classes/Visit.php create mode 100644 application/common/model/school/classes/VisitDistribution.php create mode 100644 public/assets/js/backend/school/classes/visit.js create mode 100644 public/assets/js/backend/school/classes/visit_distribution.js diff --git a/application/admin/controller/school/classes/Visit.php b/application/admin/controller/school/classes/Visit.php new file mode 100644 index 0000000..d7eb44e --- /dev/null +++ b/application/admin/controller/school/classes/Visit.php @@ -0,0 +1,77 @@ +model = new \app\admin\model\school\classes\Visit; + parent::_initialize(); + + $this->view->assign("statusList", $this->model->getStatusList()); + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + + /** + * 查看 + */ + public function index() + { + //当前是否为关联查询 + $this->relationSearch = true; + $this->searchFields = ["id","classes_lib_id","classes_activity_id","lib.title","user.nickname","user.realname","user.mobile","activity.title"]; + //设置过滤方法 + $this->request->filter(['strip_tags', 'trim']); + if ($this->request->isAjax()) { + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + + $list = $this->model + ->with(['lib','activity',"user"]) + ->where($where) + ->order($sort, $order) + ->paginate($limit); + + foreach ($list as $row) { + + $row->getRelation('lib')->visible(['title','headimage']); + $row->getRelation('activity')->visible(['title','headimage']); + $row->getRelation('user')->visible(['nickname', 'realname', 'mobile', 'avatar']); + } + + $result = array("total" => $list->total(), "rows" => $list->items()); + + return json($result); + } + return $this->view->fetch(); + } + +} diff --git a/application/admin/controller/school/classes/VisitDistribution.php b/application/admin/controller/school/classes/VisitDistribution.php new file mode 100644 index 0000000..7b623af --- /dev/null +++ b/application/admin/controller/school/classes/VisitDistribution.php @@ -0,0 +1,37 @@ +model = new \app\admin\model\school\classes\VisitDistribution; + $this->view->assign("indexList", $this->model->getIndexList()); + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + +} diff --git a/application/admin/lang/zh-cn/school/classes/visit.php b/application/admin/lang/zh-cn/school/classes/visit.php new file mode 100644 index 0000000..fec1bae --- /dev/null +++ b/application/admin/lang/zh-cn/school/classes/visit.php @@ -0,0 +1,20 @@ + '课程id', + 'Classes_activity_id' => '活动id', + 'Status' => '访问类型', + 'Status 1' => '课程', + 'Set status to 1' => '设为课程', + 'Status 2' => '活动', + 'Set status to 2' => '设为活动', + 'Createtime' => '访问时间', + 'Lib.title' => '课程标题', + 'Lib.headimage' => '课程头图', + 'Activity.title' => '活动标题', + 'Activity.headimage' => '活动头图', + 'User.nickname' => '访问用户昵称(空为游客)', + 'User.realname' => '访问用户真实姓名', + 'User.avatar' => '访问用户头像', + 'User.mobile' => '访问用户手机号', +]; diff --git a/application/admin/lang/zh-cn/school/classes/visit_distribution.php b/application/admin/lang/zh-cn/school/classes/visit_distribution.php new file mode 100644 index 0000000..bf16b15 --- /dev/null +++ b/application/admin/lang/zh-cn/school/classes/visit_distribution.php @@ -0,0 +1,19 @@ + '分布类型', + 'Index access_source_session_cnt' => '访问来源分布', + 'Set index to access_source_session_cnt'=> '设为访问来源分布', + 'Index access_staytime_info' => '访问时长分布', + 'Set index to access_staytime_info'=> '设为访问时长分布', + 'Index access_depth_info' => '访问深度的分布', + 'Set index to access_depth_info' => '设为访问深度的分布', + 'Ref_date' => '日期格式为yyyymmdd', + 'Key' => '场景id', + 'Value' => '该场景id访问pv', + 'Begin_date' => '开始日期格式为yyyymmdd', + 'End_date' => '结束日期格式为yyyymmdd', + 'Statistics_time' => '统计时间', + 'Miniapp_id' => '微信小程序id', + 'Createtime' => '创建时间' +]; diff --git a/application/admin/model/school/classes/Visit.php b/application/admin/model/school/classes/Visit.php new file mode 100644 index 0000000..fcb044d --- /dev/null +++ b/application/admin/model/school/classes/Visit.php @@ -0,0 +1,64 @@ + __('Status 1'), '2' => __('Status 2')]; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + + + public function lib() + { + return $this->belongsTo('Lib', 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function activity() + { + return $this->belongsTo('Activity', 'classes_activity_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + public function user() + { + return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0); + } +} diff --git a/application/admin/model/school/classes/VisitDistribution.php b/application/admin/model/school/classes/VisitDistribution.php new file mode 100644 index 0000000..37d7ca9 --- /dev/null +++ b/application/admin/model/school/classes/VisitDistribution.php @@ -0,0 +1,60 @@ + __('Index access_source_session_cnt'), 'access_staytime_info' => __('Index access_staytime_info'), 'access_depth_info' => __('Index access_depth_info')]; + } + + + public function getIndexTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['index']) ? $data['index'] : ''); + $list = $this->getIndexList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function getStatisticsTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['statistics_time']) ? $data['statistics_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + protected function setStatisticsTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + +} diff --git a/application/admin/validate/school/classes/Visit.php b/application/admin/validate/school/classes/Visit.php new file mode 100644 index 0000000..4de16f7 --- /dev/null +++ b/application/admin/validate/school/classes/Visit.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/validate/school/classes/VisitDistribution.php b/application/admin/validate/school/classes/VisitDistribution.php new file mode 100644 index 0000000..d45531f --- /dev/null +++ b/application/admin/validate/school/classes/VisitDistribution.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/view/school/classes/visit/add.html b/application/admin/view/school/classes/visit/add.html new file mode 100644 index 0000000..5b4b59d --- /dev/null +++ b/application/admin/view/school/classes/visit/add.html @@ -0,0 +1,33 @@ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ {foreach name="statusList" item="vo"} + + {/foreach} +
+ +
+
+ +
diff --git a/application/admin/view/school/classes/visit/edit.html b/application/admin/view/school/classes/visit/edit.html new file mode 100644 index 0000000..0c8ab59 --- /dev/null +++ b/application/admin/view/school/classes/visit/edit.html @@ -0,0 +1,33 @@ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ {foreach name="statusList" item="vo"} + + {/foreach} +
+ +
+
+ +
diff --git a/application/admin/view/school/classes/visit/index.html b/application/admin/view/school/classes/visit/index.html new file mode 100644 index 0000000..3538e90 --- /dev/null +++ b/application/admin/view/school/classes/visit/index.html @@ -0,0 +1,46 @@ +
+ +
+ {:build_heading(null,FALSE)} + +
+ + +
+
+
+
+
+ + + + {:__('Delete')} + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
diff --git a/application/admin/view/school/classes/visit_distribution/add.html b/application/admin/view/school/classes/visit_distribution/add.html new file mode 100644 index 0000000..f1ff561 --- /dev/null +++ b/application/admin/view/school/classes/visit_distribution/add.html @@ -0,0 +1,63 @@ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
diff --git a/application/admin/view/school/classes/visit_distribution/edit.html b/application/admin/view/school/classes/visit_distribution/edit.html new file mode 100644 index 0000000..b56f298 --- /dev/null +++ b/application/admin/view/school/classes/visit_distribution/edit.html @@ -0,0 +1,63 @@ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
diff --git a/application/admin/view/school/classes/visit_distribution/index.html b/application/admin/view/school/classes/visit_distribution/index.html new file mode 100644 index 0000000..6f06eca --- /dev/null +++ b/application/admin/view/school/classes/visit_distribution/index.html @@ -0,0 +1,135 @@ +
+ +
+ {:build_heading(null,FALSE)} + +
+ + +
+
+
+
+ +
+ + + 访问来源 key 对应关系(index='access_source_session_cnt'),场景值说明参见场景值
+ key 访问来源 对应场景值
+ 1 小程序历史列表 1001 1002 1004
+ 2 搜索 1005 1006 1027 1042 1053 1106 1108 1132
+ 3 会话 1007 1008 1044 1093 1094 1096
+ 4 扫一扫二维码 1011 1025 1047 1105 1124 1150
+ 5 公众号主页 1020
+ 6 聊天顶部 1022
+ 7 系统桌面 1023 1113 1114 1117
+ 8 小程序主页 1024 1135
+ 9 附近的小程序 1026 1033 1068
+ 11 模板消息 1014 1043 1107 1162
+ 12 客服消息 1021
+ 13 公众号菜单 1035 1102 1130
+ 14 APP分享 1036
+ 15 支付完成页 1034 1060 1072 1097 1109 1137 1149
+ 16 长按识别二维码 1012 1048 1050 1125
+ 17 相册选取二维码 1013 1049 1126
+ 18 公众号文章 1058 1091
+ 19 钱包 1019 1057 1061 1066 1070 1071
+ 20 卡包 1028 1128 1148
+ 21 小程序内卡券 1029 1062
+ 22 其他小程序 1037
+ 23 其他小程序返回 1038
+ 24 卡券适用门店列表 1052
+ 25 搜索框快捷入口 1054
+ 26 小程序客服消息 1073 1081
+ 27 公众号下发 1074 1076 1082 1152
+ 28 系统会话菜单 1080 1083 1088
+ 29 任务栏-最近使用 1089
+ 30 长按小程序菜单圆点 1085 1090 1147
+ 31 连wifi成功页 1064 1078
+ 32 城市服务 1092
+ 33 微信广告 1045 1046 1067 1084 1095
+ 34 其他移动应用 1065 1069 1111 1140
+ 35 发现入口-我的小程序 1003 1103
+ 36 任务栏-我的小程序 1104
+ 37 微信圈子 1138 1163
+ 38 手机充值 1098
+ 39 H5 1018 1055
+ 40 插件 1040 1041 1099
+ 41 大家在用 1118 1145
+ 42 发现页 1112 1141 1142 1143
+ 43 浮窗 1131
+ 44 附近的人 1075 1134
+ 45 看一看 1115
+ 46 朋友圈 1009 1110 1154 1155
+ 47 企业微信 1119 1120 1121 1122 1123 1156
+ 48 视频 1136 1144
+ 49 收藏 1010
+ 50 微信红包 1100
+ 51 微信游戏中心 1079 1127
+ 52 摇一摇 1039 1077
+ 53 公众号导购消息 1157
+ 54 识物 1153
+ 55 小程序订单 1151
+ 56 小程序直播 1161
+ 57 群工具 1158 1159 1160
+ 10 其他 除上述外其余场景值
+ 访问来源 key 对应关系(index='access_staytime_info')
+ key 访问时长
+ 1 0-2s
+ 2 3-5s
+ 3 6-10s
+ 4 11-20s
+ 5 20-30s
+ 6 30-50s
+ 7 50-100s
+ 8 >100s
+ 平均访问深度 key 对应关系(index='access_depth_info')
+ key 访问时长
+ 1 1 页
+ 2 2 页
+ 3 3 页
+ 4 4 页
+ 5 5 页
+ 6 6-10 页
+ 7 >10 页
+
+ +
+ + +
+ + + + {:__('Delete')} + + + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
diff --git a/application/api/controller/Crontab.php b/application/api/controller/Crontab.php index 9546ad5..52d4e86 100644 --- a/application/api/controller/Crontab.php +++ b/application/api/controller/Crontab.php @@ -5,6 +5,7 @@ use addons\epay\library\Service; use app\common\controller\Api; use app\common\library\NightSchoolBigData; use app\common\model\school\classes\order\Order; +use app\common\model\school\classes\VisitDistribution; use bw\UrlLock; use think\Cache; @@ -70,6 +71,8 @@ class Crontab extends Api $res = $weMiniTotal->getWeanalysisAppidVisitdistribution($last_days_start_date, $last_days_end_date); $cacheNmae = 'getWeanalysisAppidVisitdistribution' . $last_days_start_date . $last_days_end_date; Cache::set($cacheNmae, $res, (3600 * 24 * 32)); + VisitDistribution::setlog($last_days_start_date,$last_days_end_date,$res); + //微信小程序月趋势 $res = $weMiniTotal->getWeanalysisAppidMonthlyVisittrend($month_start_date, $month_end_date); $cacheNmae = 'getWeanalysisAppidMonthlyVisittrend' . $month_start_date . $month_end_date; diff --git a/application/api/controller/WechatUtil.php b/application/api/controller/WechatUtil.php index 55fa25b..8da128e 100644 --- a/application/api/controller/WechatUtil.php +++ b/application/api/controller/WechatUtil.php @@ -4,6 +4,7 @@ namespace app\api\controller; use addons\epay\library\Service; use app\common\controller\Api; +use app\common\model\school\classes\VisitDistribution; use app\common\model\style\HomeImages; use think\Cache; @@ -410,6 +411,7 @@ class WechatUtil extends Api // 缓存在3600秒之后过期 Cache::set($cacheNmae, $res, (3600 * 24 * 32)); + VisitDistribution::setlog($begin_date,$end_date,$res); } catch (\Exception $e){ // Log::log($e->getMessage()); @@ -576,4 +578,39 @@ class WechatUtil extends Api + + /** + * @ApiTitle(查询微信报错rid信息) + * @ApiSummary(本接口用于查询调用公众号/小程序/第三方平台等接口报错返回的rid详情信息,辅助开发者高效定位问题) + * @ApiMethod(POST) + * @ApiParams (name="rid", type="string", required=true, description="调用接口报错返回的rid") + * @ApiReturn({ + "code" => 1, + "msg" => "获取成功", + "data" => {} + *}) + */ + public function getRidInfo() { + $rid = $this->request->post('rid/s',0); + $cacheNmae = 'getRidInfo' . $rid ; + try { + // 实例对应的接口对象 + $weMiniTotal = new \WeMini\Total(Service::wechatConfig()); + $res = $weMiniTotal->getRidInfo($rid); + + // 缓存在3600秒之后过期 + Cache::set($cacheNmae, $res, (3600 * 24 * 32)); + + } catch (\Exception $e){ +// Log::log($e->getMessage()); + $res = Cache::get($cacheNmae); + if($res){ + $this->success('生成成功', $res); + }else{ + $this->error($e->getMessage(),['errcode'=>$e->getCode()]); + } + } + $this->success('生成成功', $res); + } + } diff --git a/application/api/controller/school/BigData.php b/application/api/controller/school/BigData.php index d1c28e7..8d3866f 100644 --- a/application/api/controller/school/BigData.php +++ b/application/api/controller/school/BigData.php @@ -345,4 +345,68 @@ class BigData extends Api $this->success('返回成功', $res); } + + /** + * @ApiTitle(得到前30天日期) + * @ApiSummary(得到前30天日期) + * @ApiParams(name = "time", type = "string",required=false,description = "计算的当前时间戳") + * @ApiMethod(GET) + * @ApiReturn({ + "code" => 1, + "msg" => "获取成功", + "data" => {} + *}) + */ + public function getLastThirtyDaysDate() + { + + try{ + $lock = new UrlLock(1,"getLastThirtyDaysDate-data-lock-suffix",120,"您的请求过于频繁,请您稍后再试!请求最大锁定间隔5秒/一次!"); + $lock->lock(); + $N = $this->request->request("time/s",0); + $res = NightSchoolBigData::getLastThirtyDaysDate($N); + + }catch (\Throwable $e){ + $lock->free(); +// file_put_contents("test.txt",$e->getMessage().$e->getFile().$e->getLine());//写入文件,一般做正式环境测试 + $this->error($e->getMessage()); + } + $lock->free(); + + $this->success('返回成功', $res); + } + + + /** + * @ApiTitle(访问来源统计) + * @ApiSummary(访问来源统计) + * @ApiParams(name = "start_time", type = "string",required=false,description = "开始时间") + * @ApiParams(name = "end_time", type = "string",required=false,description = "结束时间") + * @ApiMethod(GET) + * @ApiReturn({ + "code" => 1, + "msg" => "获取成功", + "data" => {} + *}) + */ + public function visitDistribution() + { + + try{ + $lock = new UrlLock(1,"visitDistribution-data-lock-suffix",120,"您的请求过于频繁,请您稍后再试!请求最大锁定间隔5秒/一次!"); + $lock->lock(); + $start_time = $this->request->request("start_time/s",0); + $end_time = $this->request->request("end_time/s",0); + $res = NightSchoolBigData::visitDistribution($start_time,$end_time); + + }catch (\Throwable $e){ + $lock->free(); +// file_put_contents("test.txt",$e->getMessage().$e->getFile().$e->getLine());//写入文件,一般做正式环境测试 + $this->error($e->getMessage()); + } + $lock->free(); + + $this->success('返回成功', $res); + } + } diff --git a/application/common/library/NightSchoolBigData.php b/application/common/library/NightSchoolBigData.php index 1ff4c06..ab9ba31 100644 --- a/application/common/library/NightSchoolBigData.php +++ b/application/common/library/NightSchoolBigData.php @@ -12,6 +12,8 @@ use app\common\model\school\classes\ClassesLib; use app\common\model\school\classes\hourorder\Order; use app\common\model\school\classes\Teacher; use app\common\model\school\classes\Type; +use app\common\model\school\classes\Visit; +use app\common\model\school\classes\VisitDistribution; use app\common\model\User; /** @@ -219,6 +221,7 @@ class NightSchoolBigData extends BaseModel $type_data["activity_num_text"] = "活动热度"; $type_data["activity_sign_num"][] = \app\common\model\school\classes\activity\order\Order::where( "createtime",'between',[$time["start"],$time["end"]])->where("status","not in",["-3","6"])->count(); $type_data["activity_num"][] = Activity::where( "createtime",'between',[$time["start"],$time["end"]])->count(); + $type_data["activity_views"][] = Visit::where("status",'2')->where( "createtime",'between',[$time["start"],$time["end"]])->count(); } return compact("dates","type_data"); @@ -241,33 +244,51 @@ class NightSchoolBigData extends BaseModel $time = strtotime("-1 day",$time); } - //得到当前是几号 - $day = date("d",$time); - //用7进行除余,得到余数和整数商 - $mod = $day%7; - //进行除7,截取整数部分(不需要向下或向上取整!) - $day = $day-$mod; - $last_seven = bcdiv($day,7,0); - //如果=0.取上个月的最后一个七天 - if ($last_seven<=0){ - //得到上月最后一天 date('Y-m-d H:i'); - $last_mouth_last_day = strtotime(date("Y-m-01 00:00:00",$time))-1; - $start_date = date("Ymd",strtotime("-6 days",$last_mouth_last_day)); - $end_date = date("Ymd",$last_mouth_last_day); - } +// //得到当前是几号 +// $day = date("d",$time); +// //用7进行除余,得到余数和整数商 +// $mod = $day%7; +// //进行除7,截取整数部分(不需要向下或向上取整!) +// $day = $day-$mod; +// $last_seven = bcdiv($day,7,0); +// //如果=0.取上个月的最后一个七天 +// if ($last_seven<=0){ +// //得到上月最后一天 date('Y-m-d H:i'); +// $last_mouth_last_day = strtotime(date("Y-m-01 00:00:00",$time))-1; +// $start_date = date("Ymd",strtotime("-6 days",$last_mouth_last_day)); +// $end_date = date("Ymd",$last_mouth_last_day); +// } //如果>0,则取本月第$last_seven 个七天 - if ($last_seven>0){ - $last_seven_days = $last_seven * 7; +// if ($last_seven>0){ +// $last_seven_days = $last_seven * 7; $start_date = date("Ymd",strtotime("-6 days",$time)); $end_date = date("Ymd",$time); // $start_date = date("Ymd",strtotime("+".($last_seven_days-7)." days",strtotime(date("Y-m-01 00:00:00",$time)))); // $end_date = date("Ymd",strtotime("+".($last_seven_days-1)." days",strtotime(date("Y-m-01 00:00:00",$time)))); - } +// } return compact("start_date","end_date"); } + public static function getLastThirtyDaysDate($time=null){ + //如果是非数字,转成时间戳 + if ($time &&!is_numeric($time)){ + $time = strtotime($time); + } + if(!$time)$time = time(); + //时间如果是当天,需要减去一天 + if (date("Ymd",$time)==date("Ymd",time())){ + $time = strtotime("-1 day",$time); + } + + $start_date = date("Ymd",strtotime("-29 days",$time)); + $end_date = date("Ymd",$time); + + return compact("start_date","end_date"); + } + + @@ -355,4 +376,24 @@ class NightSchoolBigData extends BaseModel } + public static function visitDistribution($start_time=null,$end_time=null){ + $wheretime= [[]]; + if($start_time && $end_time){ + if(!is_numeric($start_time)) $start_time = strtotime($start_time); + if(!is_numeric($end_time)) $end_time = strtotime($end_time); + $wheretime= [ "statistics_time",'between',[$start_time,$end_time]]; + } + $res = []; + $data = []; + $data["46"] = VisitDistribution::where("index","access_source_session_cnt")->where("key","46")->sum("value"); + + $data["29"] = VisitDistribution::where("index","access_source_session_cnt")->where("key","29")->sum("value"); + $data["2"] = VisitDistribution::where("index","access_source_session_cnt")->where("key","2")->sum("value"); + $data["total"] = VisitDistribution::where("index","access_source_session_cnt")->sum("value"); + $data["sum"] = $data["46"] + $data["29"] + $data["2"]; + $res['access_source_session_cnt'] = $data; + return $res; + + } + } \ No newline at end of file diff --git a/application/common/listener/classes/ActivityHook.php b/application/common/listener/classes/ActivityHook.php index fae257d..4a0ed52 100644 --- a/application/common/listener/classes/ActivityHook.php +++ b/application/common/listener/classes/ActivityHook.php @@ -1,6 +1,7 @@ $activity,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; - +//访问记录 + Visit::create([ + "classes_lib_id"=>0, + "classes_activity_id"=>$activity["id"], + "shop_id"=>$activity["shop_id"], + "status"=>'2', + "user_id"=>$user_id, + ]); } diff --git a/application/common/listener/classes/ClassesHook.php b/application/common/listener/classes/ClassesHook.php index 791e567..323aadd 100644 --- a/application/common/listener/classes/ClassesHook.php +++ b/application/common/listener/classes/ClassesHook.php @@ -2,6 +2,7 @@ namespace app\common\listener\classes; use app\common\model\dyqc\ManystoreShop; use app\common\model\school\classes\Teacher; +use app\common\model\school\classes\Visit; use app\common\model\school\Message; use app\common\model\school\MessageConfig; @@ -174,7 +175,14 @@ class ClassesHook public function classesViewAfter(&$params) { ['classes' => $classes,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; - + //访问记录 + Visit::create([ + "classes_lib_id"=>$classes["id"], + "shop_id"=>$classes["shop_id"], + "classes_activity_id"=>0, + "status"=>'1', + "user_id"=>$user_id, + ]); } public function classesCollectSuccessAfter(&$params) diff --git a/application/common/model/school/classes/Visit.php b/application/common/model/school/classes/Visit.php new file mode 100644 index 0000000..2743c4f --- /dev/null +++ b/application/common/model/school/classes/Visit.php @@ -0,0 +1,67 @@ + __('Status 1'), '2' => __('Status 2')]; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['status']) ? $data['status'] : ''); + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + + + public function lib() + { + return $this->belongsTo(ClassesLib::class, 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + + public function activity() + { + return $this->belongsTo(Activity::class, 'classes_activity_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + + public function user() + { + return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0); + } + +} diff --git a/application/common/model/school/classes/VisitDistribution.php b/application/common/model/school/classes/VisitDistribution.php new file mode 100644 index 0000000..3793224 --- /dev/null +++ b/application/common/model/school/classes/VisitDistribution.php @@ -0,0 +1,92 @@ + __('Index access_source_session_cnt'), 'access_staytime_info' => __('Index access_staytime_info'), 'access_depth_info' => __('Index access_depth_info')]; + } + + + public function getIndexTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['index']) ? $data['index'] : ''); + $list = $this->getIndexList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function getStatisticsTimeTextAttr($value, $data) + { + $value = $value ? $value : (isset($data['statistics_time']) ? $data['statistics_time'] : ''); + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + protected function setStatisticsTimeAttr($value) + { + return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); + } + + + public static function setlog($begin_date,$end_date,$res){ + if(!isset($res["ref_date"]) || !isset($res["list"]))return false; + //statistics_time = 开始时间的时间戳 + //begin_date 和 end_date如果带字符串‘-’ 则去除 + $begin_date = str_replace("-","",$begin_date); + $end_date = str_replace("-","",$end_date); + $data = [ + "ref_date"=>$res["ref_date"], + "begin_date" =>$begin_date, + "end_date" =>$end_date, + "miniapp_id"=>config("site.wx_miniapp_id"), + "statistics_time" => strtotime($res["ref_date"]." 0:0:0"), + ]; + + $list = $res["list"]; + foreach ($list as $k=>$v){ + if(isset($v['index']) && isset($v['item_list'])){ + foreach ($v['item_list'] as $kk=>$vv){ + $data["index"] = $v['index']; + $data["key"] = $vv['key']; + $data["value"] = $vv['value']; +// var_dump(!self::where($data)->find()); + if(!self::where($data)->find()){ + + self::create($data); + } + } + } + } + } + +} diff --git a/application/extra/upload.php b/application/extra/upload.php index 3d4da3b..3f4b9b6 100644 --- a/application/extra/upload.php +++ b/application/extra/upload.php @@ -10,6 +10,7 @@ return [ * CDN地址 */ 'cdnurl' => 'https://testy1.hschool.com.cn', +// 'cdnurl' => '', /** * 文件保存格式 */ diff --git a/public/assets/js/backend/school/classes/activity/activity.js b/public/assets/js/backend/school/classes/activity/activity.js index 43dfb90..b1ee115 100644 --- a/public/assets/js/backend/school/classes/activity/activity.js +++ b/public/assets/js/backend/school/classes/activity/activity.js @@ -148,6 +148,21 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde // return row.status == '2'||row.status == '3'; // } }, + { + name: 'visit', + text: __('查看用户访问记录'), + title: __('查看用户访问记录'), + classname: 'btn btn-dialog', + icon: 'fa fa-handshake-o', + dropdown : '更多', + url: visit_url, + callback: function (data) { + + }, + // visible: function (row) { + // return row.classes_evaluate_id; + // } + }, { name: 'manystore', @@ -422,5 +437,9 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde return 'school/classes/activity/order/order/index?classes_activity_id='+row.id; } + var visit_url = function (row,dom) { + return 'school/classes/visit/index?classes_activity_id='+row.id; + } + return Controller; }); diff --git a/public/assets/js/backend/school/classes/classes_lib.js b/public/assets/js/backend/school/classes/classes_lib.js index 1a837e9..90f7c4e 100644 --- a/public/assets/js/backend/school/classes/classes_lib.js +++ b/public/assets/js/backend/school/classes/classes_lib.js @@ -272,6 +272,22 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde // } }, + { + name: 'visit', + text: __('查看用户访问记录'), + title: __('查看用户访问记录'), + classname: 'btn btn-dialog', + icon: 'fa fa-handshake-o', + dropdown : '更多', + url: visit_url, + callback: function (data) { + + }, + // visible: function (row) { + // return row.classes_evaluate_id; + // } + }, + { name: 'manystore', text: __('查看机构'), @@ -637,6 +653,10 @@ define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, unde return 'manystore/index/index?shop_id='+row.shop_id; } + var visit_url = function (row,dom) { + return 'school/classes/visit/index?classes_lib_id='+row.id; + } + return Controller; }); diff --git a/public/assets/js/backend/school/classes/visit.js b/public/assets/js/backend/school/classes/visit.js new file mode 100644 index 0000000..ed1e49d --- /dev/null +++ b/public/assets/js/backend/school/classes/visit.js @@ -0,0 +1,67 @@ +define(['jquery', 'bootstrap', 'backend', 'csmtable', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'school/classes/visit/index' + location.search, + add_url: 'school/classes/visit/add'+ location.search, + edit_url: 'school/classes/visit/edit'+ location.search, + del_url: 'school/classes/visit/del', + multi_url: 'school/classes/visit/multi', + import_url: 'school/classes/visit/import', + table: 'school_visit', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + fixedRightNumber: 1, + fixedColumns: true, + asyndownload: true, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'user_id', title: __('用户id'),visible:false}, + {field: 'classes_lib_id', title: __('Classes_lib_id')}, + {field: 'classes_activity_id', title: __('Classes_activity_id')}, + {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"2":__('Status 2')}, formatter: Table.api.formatter.status}, + {field: 'user.nickname', title: __('User.nickname'), operate: 'LIKE'}, + {field: 'user.realname', title: __('User.realname'),visible:false, operate: 'LIKE'}, + {field: 'user.mobile', title: __('User.mobile'), operate: 'LIKE'}, + {field: 'user.avatar', title: __('User.avatar'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image}, + + {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'lib.title', title: __('Lib.title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'lib.headimage', title: __('Lib.headimage'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image}, + {field: 'activity.title', title: __('Activity.title'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'activity.headimage', title: __('Activity.headimage'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); diff --git a/public/assets/js/backend/school/classes/visit_distribution.js b/public/assets/js/backend/school/classes/visit_distribution.js new file mode 100644 index 0000000..d6b7026 --- /dev/null +++ b/public/assets/js/backend/school/classes/visit_distribution.js @@ -0,0 +1,61 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'school/classes/visit_distribution/index' + location.search, + add_url: 'school/classes/visit_distribution/add', + edit_url: 'school/classes/visit_distribution/edit', + del_url: 'school/classes/visit_distribution/del', + multi_url: 'school/classes/visit_distribution/multi', + import_url: 'school/classes/visit_distribution/import', + table: 'school_visit_distribution', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + fixedColumns: true, + fixedRightNumber: 1, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'index', title: __('Index'), searchList: {"access_source_session_cnt":__('Index access_source_session_cnt'),"access_staytime_info":__('Index access_staytime_info'),"access_depth_info":__('Index access_depth_info')}, formatter: Table.api.formatter.normal}, + {field: 'ref_date', title: __('Ref_date'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'key', title: __('Key'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'value', title: __('Value'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'begin_date', title: __('Begin_date'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'end_date', title: __('End_date'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'statistics_time', title: __('Statistics_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'miniapp_id', title: __('Miniapp_id'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +});