├── .eslintignore ├── .gitignore ├── LICENSE ├── README.md ├── application ├── app.go └── init.go ├── build_all_linux.bat ├── build_all_mac.bat ├── build_all_win.bat ├── build_init_app_linux.bat ├── build_manager_linux.bat ├── build_report_linux.bat ├── build_sinker_linux.bat ├── cmd ├── init_app │ ├── ck │ │ └── init.go │ ├── kafka │ │ └── init.go │ ├── main.go │ └── mysql │ │ ├── bi.sql │ │ └── init.go ├── manager │ └── main.go ├── report_server │ └── main.go └── sinker │ ├── action │ └── action.go │ ├── geoip │ ├── GeoLite2-City.mmdb │ └── geoip.go │ └── main.go ├── config └── config.json ├── controller ├── app_controller.go ├── base_controller.go ├── behavior_analysis_controller.go ├── debug_data_controller.go ├── gm_operater_log.go ├── manager_role_controller.go ├── manager_user_controller.go ├── metadata_controller.go ├── panel_controller.go ├── rbac_controller.go ├── realdata_controller.go ├── report_controller.go ├── user_group_controller.go └── word_controller.go ├── engine ├── db │ ├── kafka.go │ ├── redis.go │ └── sqlx.go └── logs │ └── log.go ├── go.mod ├── go.sum ├── init_app_start.bat ├── manager_start.bat ├── middleware ├── Exception.go ├── analysis_cache.go ├── fasthttp.go ├── filter_appid.go ├── jwt.go ├── operater_log.go ├── rbac.go └── time.go ├── model ├── app.go ├── config.go ├── crud.go ├── debug_device.go ├── event_data.go ├── gm_operater_log.go ├── gm_role.go ├── gm_user.go ├── message.go ├── pannel_folder.go ├── report_table.go └── user_group.go ├── platform-basic-libs ├── api_config │ └── api_router_config.go ├── jwt │ ├── Jwt.go │ └── exception.go ├── my_error │ └── my_error.go ├── rbac │ └── index.go ├── request │ ├── Exception.go │ ├── Model.go │ └── Request.go ├── response │ ├── Model.go │ └── Response.go ├── service │ ├── analysis │ │ ├── behavior_analysis_service.go │ │ ├── cache.go │ │ ├── event.go │ │ ├── exception.go │ │ ├── funnel.go │ │ ├── interface.go │ │ ├── retention.go │ │ ├── trace.go │ │ ├── user_attr.go │ │ ├── user_event_count.go │ │ ├── user_event_detail.go │ │ ├── user_list.go │ │ ├── utils.go │ │ └── utils │ │ │ ├── count.go │ │ │ ├── sql.go │ │ │ └── user_group.go │ ├── app │ │ └── app_service.go │ ├── consumer_data │ │ ├── real_time_warehousing.go │ │ ├── report_accpet_status.go │ │ └── reportdata2ck.go │ ├── debug_data │ │ └── debug_data.go │ ├── gm_operater_log │ │ └── gm_operater_log_service.go │ ├── gm_role │ │ └── gm_role_service.go │ ├── gm_user │ │ ├── exception.go │ │ └── gm_user_service.go │ ├── meta_data │ │ └── meta_data.go │ ├── myapp │ │ ├── redis.go │ │ └── utils.go │ ├── pannel │ │ └── pannel_service.go │ ├── realdata │ │ └── real_data_service.go │ ├── report │ │ ├── Exception.go │ │ ├── report_interface.go │ │ └── report_service.go │ └── user_group │ │ └── user_group_service.go ├── sinker │ ├── clickhouse.go │ ├── kafka_sarama.go │ ├── model │ │ ├── metric.go │ │ └── topic.go │ └── parse │ │ ├── fastjson.go │ │ ├── parser.go │ │ └── value.go └── util │ ├── array.go │ ├── charset.go │ ├── config.go │ ├── convert.go │ ├── datatype.go │ ├── dir.go │ ├── ecb.go │ ├── errors.go │ ├── exec.go │ ├── gzip.go │ ├── hash.go │ ├── http.go │ ├── interface.go │ ├── json.go │ ├── t_util.go │ ├── time.go │ └── token.go ├── report_start.bat ├── router ├── analysis.go ├── app.go ├── index.go ├── manager_user.go ├── metadata.go ├── operater_log.go ├── panel.go ├── realdata.go ├── user_group.go └── ws.go ├── sdk ├── cocos-creator │ ├── Hello.ts │ ├── report.d.ts │ └── report.js ├── egert │ ├── report.d.ts │ └── report.min.js └── web │ └── report_sdk.js ├── sinker_start.bat ├── views └── fs.go ├── vue ├── .editorconfig ├── .env.development ├── .env.production ├── .env.staging ├── .eslintignore ├── .eslintrc.js ├── .travis.yml ├── LICENSE ├── README.es.md ├── README.ja.md ├── README.md ├── README.zh-CN.md ├── babel.config.js ├── build │ └── index.js ├── debug.log ├── jest.config.js ├── jsconfig.json ├── mock │ ├── article.js │ ├── index.js │ ├── mock-server.js │ ├── remote-search.js │ └── user.js ├── package.json ├── plop-templates │ ├── component │ │ ├── index.hbs │ │ └── prompt.js │ ├── utils.js │ └── view │ │ ├── index.hbs │ │ └── prompt.js ├── plopfile.js ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── analysis.js │ │ ├── api-rbac.js │ │ ├── app.js │ │ ├── metadata.js │ │ ├── operate.js │ │ ├── pannel.js │ │ ├── realdata.js │ │ ├── role.js │ │ ├── user-group.js │ │ ├── user.js │ │ └── 接口管理 │ ├── assets │ │ ├── 401_images │ │ │ └── 401.gif │ │ ├── 404_images │ │ │ ├── 404.png │ │ │ └── 404_cloud.png │ │ ├── custom-theme │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ └── index.css │ │ ├── img │ │ │ ├── arrow-v.svg │ │ │ └── loginbg.jpg │ │ ├── index.ico │ │ └── 静态文件 │ ├── components │ │ ├── AnalyseTools │ │ │ ├── CountSelect.vue │ │ │ ├── FilterDate │ │ │ │ └── Date.vue │ │ │ ├── FilterGroup │ │ │ │ └── index.vue │ │ │ ├── FilterUserGroup │ │ │ │ └── index.vue │ │ │ ├── FilterWhere │ │ │ │ ├── ActionRow.vue │ │ │ │ ├── SmallSelect.vue │ │ │ │ ├── index.vue │ │ │ │ └── values.vue │ │ │ └── Select2 │ │ │ │ └── Select.vue │ │ ├── BackToTop │ │ │ └── index.vue │ │ ├── Breadcrumb │ │ │ └── index.vue │ │ ├── Charts │ │ │ ├── EventCountBar.vue │ │ │ ├── EventCountPie.vue │ │ │ ├── FunnelBar.vue │ │ │ ├── FunnelLine.vue │ │ │ ├── RetentionLine.vue │ │ │ ├── RetentionLine2.vue │ │ │ ├── TraceSankey.vue │ │ │ ├── UserAttrBar.vue │ │ │ ├── UserAttrBar2.vue │ │ │ └── mixins │ │ │ │ ├── resize.js │ │ │ │ └── utils.js │ │ ├── Date │ │ │ └── index.vue │ │ ├── DivEdit │ │ │ └── index.vue │ │ ├── ErrorLog │ │ │ └── index.vue │ │ ├── Hamburger │ │ │ └── index.vue │ │ ├── HeaderSearch │ │ │ └── index.vue │ │ ├── JsonEditor │ │ │ └── index.vue │ │ ├── PageTable │ │ │ └── index.vue │ │ ├── Pagination │ │ │ └── index.vue │ │ ├── Reload │ │ │ └── index.vue │ │ ├── RightPanel │ │ │ └── index.vue │ │ ├── Screenfull │ │ │ └── index.vue │ │ ├── SelectLink │ │ │ └── index.vue │ │ ├── SizeSelect │ │ │ └── index.vue │ │ ├── SqlEditor │ │ │ └── index.vue │ │ ├── Sticky │ │ │ └── index.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── ThemePicker │ │ │ └── index.vue │ │ └── 常用组件 │ ├── directive │ │ ├── clipboard │ │ │ ├── clipboard.js │ │ │ └── index.js │ │ ├── el-drag-dialog │ │ │ ├── drag.js │ │ │ └── index.js │ │ ├── el-table │ │ │ ├── adaptive.js │ │ │ └── index.js │ │ ├── permission │ │ │ ├── index.js │ │ │ └── permission.js │ │ ├── sticky.js │ │ ├── waves │ │ │ ├── index.js │ │ │ ├── waves.css │ │ │ └── waves.js │ │ └── 自定义指示 │ ├── filters │ │ ├── index.js │ │ └── 过滤 │ ├── icons │ │ ├── icon │ │ ├── index.js │ │ ├── svg │ │ │ ├── 404.svg │ │ │ ├── bug.svg │ │ │ ├── chart.svg │ │ │ ├── clipboard.svg │ │ │ ├── component.svg │ │ │ ├── dashboard.svg │ │ │ ├── documentation.svg │ │ │ ├── drag.svg │ │ │ ├── edit.svg │ │ │ ├── education.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── fullscreen.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── international.svg │ │ │ ├── language.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── nested.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── qq.svg │ │ │ ├── search.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── skill.svg │ │ │ ├── star.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── theme.svg │ │ │ ├── tree-table.svg │ │ │ ├── tree.svg │ │ │ ├── user.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ │ └── svgo.yml │ ├── layout │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── HeadNavbar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── Logo.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ ├── VerticalItem.vue │ │ │ │ └── index.vue │ │ │ ├── ModifyPassword │ │ │ │ └── index.vue │ │ │ ├── Navbar.vue │ │ │ ├── Settings │ │ │ │ └── index.vue │ │ │ ├── Sidebar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── Logo.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ ├── TagsView │ │ │ │ ├── ScrollPane.vue │ │ │ │ └── index.vue │ │ │ └── index.js │ │ ├── index.vue │ │ ├── mixin │ │ │ └── ResizeHandler.js │ │ └── 总布局文件 │ ├── main.js │ ├── permission.js │ ├── router │ │ ├── index.js │ │ └── 路由 │ ├── settings.js │ ├── store │ │ ├── getters.js │ │ ├── index.js │ │ ├── modules │ │ │ ├── .idea │ │ │ │ ├── $PRODUCT_WORKSPACE_FILE$ │ │ │ │ ├── .gitignore │ │ │ │ ├── inspectionProfiles │ │ │ │ │ └── profiles_settings.xml │ │ │ │ ├── misc.xml │ │ │ │ ├── modules.iml │ │ │ │ ├── modules.xml │ │ │ │ └── vcs.xml │ │ │ ├── app.js │ │ │ ├── baseData.js │ │ │ ├── errorLog.js │ │ │ ├── permission.js │ │ │ ├── settings.js │ │ │ ├── tagsView.js │ │ │ └── user.js │ │ └── vuex相关 │ ├── styles │ │ ├── EventResult.css │ │ ├── UserAttrResult.css │ │ ├── btn.scss │ │ ├── dashbord-index.css │ │ ├── debug.css │ │ ├── element-ui.scss │ │ ├── element-variables.scss │ │ ├── event.css │ │ ├── funnel-res.css │ │ ├── funnel.css │ │ ├── index.scss │ │ ├── log.css │ │ ├── login.css │ │ ├── manager-event.css │ │ ├── mixin.scss │ │ ├── real-time.css │ │ ├── retention-res.css │ │ ├── retention.css │ │ ├── sidebar.scss │ │ ├── trace-res.css │ │ ├── trace.css │ │ ├── track-data.css │ │ ├── transition.scss │ │ ├── user-as.css │ │ ├── variables.scss │ │ └── 样式 │ ├── utils │ │ ├── auth.js │ │ ├── base-data.js │ │ ├── clipboard.js │ │ ├── date.js │ │ ├── download.js │ │ ├── error-log.js │ │ ├── flexible.js │ │ ├── format.js │ │ ├── get-page-title.js │ │ ├── global.js │ │ ├── help │ │ ├── http.js │ │ ├── index.js │ │ ├── json.js │ │ ├── open-window.js │ │ ├── permission.js │ │ ├── request.js │ │ ├── router-bash.js │ │ ├── router.js │ │ ├── scroll-to.js │ │ ├── singleMsg.js │ │ ├── table.js │ │ ├── time.js │ │ └── validate.js │ ├── vendor │ │ ├── Export2Excel.js │ │ └── Export2Zip.js │ └── views │ │ ├── app │ │ └── index.vue │ │ ├── behavior-analysis │ │ ├── components │ │ │ ├── AddReportTable.vue │ │ │ ├── AddUserGroup.vue │ │ │ ├── EventResult.vue │ │ │ ├── FunnelResult.vue │ │ │ ├── FunnelStep.vue │ │ │ ├── ReportTableList.vue │ │ │ ├── RetentionResult.vue │ │ │ ├── TraceResult.vue │ │ │ └── UserAttrResult.vue │ │ ├── event.vue │ │ ├── funnel.vue │ │ ├── retention.vue │ │ └── trace.vue │ │ ├── dashboard │ │ ├── components │ │ │ ├── ManagerDir.vue │ │ │ ├── ManagerRt.vue │ │ │ └── analysis │ │ │ │ ├── event.vue │ │ │ │ ├── funnel.vue │ │ │ │ ├── retention.vue │ │ │ │ ├── trace.vue │ │ │ │ └── user_attr.vue │ │ └── index.vue │ │ ├── error-page │ │ ├── 401.vue │ │ └── 404.vue │ │ ├── login │ │ ├── auth-redirect.vue │ │ ├── components │ │ │ └── SocialSignin.vue │ │ └── index.vue │ │ ├── manager │ │ ├── components │ │ │ ├── FailData.vue │ │ │ ├── TrackData.vue │ │ │ ├── debug.vue │ │ │ ├── eventAttr.vue │ │ │ ├── metaAttr.vue │ │ │ ├── realData2Es.vue │ │ │ └── realTime.vue │ │ ├── event.vue │ │ └── log.vue │ │ ├── permission │ │ ├── operater_log.vue │ │ ├── role.vue │ │ └── user.vue │ │ ├── redirect │ │ └── index.vue │ │ └── user-analysis │ │ ├── components │ │ └── UserInfoRes.vue │ │ ├── group.vue │ │ ├── index.vue │ │ ├── user_info.vue │ │ └── user_list.vue ├── tests │ └── unit │ │ ├── .eslintrc.js │ │ ├── components │ │ ├── Hamburger.spec.js │ │ └── SvgIcon.spec.js │ │ └── utils │ │ ├── formatTime.spec.js │ │ ├── parseTime.spec.js │ │ └── validate.spec.js └── vue.config.js └── vue_start.bat /.eslintignore: -------------------------------------------------------------------------------- 1 | /views/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/background.exe 2 | /bin/report_server.exe 3 | /bin/sinker.exe 4 | /logs/ 5 | /task/ 6 | /vue/node_modules/ 7 | .... 8 | /bin/ 9 | /.idea/ 10 | /views/dist/static/ 11 | /views/dist/favicon.ico 12 | /views/dist/index.html 13 | /bin/linux/ 14 | /bin/win/ 15 | /.idea/ 16 | /bin/linux/ 17 | /bin/win/ 18 | /views/dist/ 19 | main.go 20 | task 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 作者求工作,tel:13298692154 3 | 4 | ## 铸龙-用户行为分析系统 5 | ----------- 6 | > 铸龙-用户行为分析系统 是一款用于分析用户行为事件的BI软件,功能如下 7 | * 事件分析 8 | * 漏斗分析 9 | * 留存分析 10 | * 智能路径分析 11 | * 报表,面板管理 12 | 13 | > 技术栈主要用 14 | * 前端:vue+elementui+antdv 15 | * 后端:go 16 | 17 | > 所需中间件 18 | * mysql 19 | * redis 20 | * kafka 21 | * clickhouse 22 | 23 | 欢迎大家提出自己的issue。 24 | 25 | 26 | > 相关 27 | 28 | *[下载地址]( https://gitee.com/cynthia520/xwl_bi/releases/v1.0.0 ) 29 | 30 | *[文档地址]( https://www.yuque.com/jianghurenchenggolang/oehqme/hen7qy ) 31 | 32 | *[用户端体验地址]( http://www.ycvod.net ) 33 | 34 | *[后台体验地址]( http://110.42.167.155:8090/#/dashboard ) 用户名: test ,密码: test123456 (因本人穷,所以只是一台1核2g的服务器撑着,望同是开发人,手下留情) 35 | 36 | ## 其他开源项目 37 | * ElasticSearch可视化工具 https://github.com/1340691923/ElasticView 38 | * 软考成绩快查工具 https://github.com/1340691923/SoftTestMonitor 39 | 40 | ### 求职中,个人微信二维码 41 | 42 | 43 | 44 | 45 | 46 | ### QQ群 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /build_all_linux.bat: -------------------------------------------------------------------------------- 1 | cd vue && npm run build:prod && cd .. && set goos=linux&&go build -ldflags="-w -s" -o bin/linux/manager cmd/manager/main.go && go build -ldflags="-w -s" -o bin/linux/report_server cmd/report_server/main.go && go build -ldflags="-w -s" -o bin/linux/sinker cmd/sinker/main.go && go build -ldflags="-w -s" -o bin/linux/init_app cmd/init_app/main.go 2 | echo "build success" -------------------------------------------------------------------------------- /build_all_mac.bat: -------------------------------------------------------------------------------- 1 | cd vue && npm run build:prod && cd .. && SET CGO_ENABLED=0&& SET GOOS=darwin&& SET GOARCH=amd64&& go build -ldflags="-w -s" -o bin/mac/manager cmd/manager/main.go && go build -ldflags="-w -s" -o bin/mac/report_server cmd/report_server/main.go && go build -ldflags="-w -s" -o bin/mac/sinker cmd/sinker/main.go && go build -ldflags="-w -s" -o bin/mac/init_app cmd/init_app/main.go 2 | echo "build success" -------------------------------------------------------------------------------- /build_all_win.bat: -------------------------------------------------------------------------------- 1 | cd vue && npm run build:prod && cd .. && go build -ldflags="-w -s" -o bin/win/manager.exe cmd/manager/main.go && go build -ldflags="-w -s" -o bin/win/report_server.exe cmd/report_server/main.go && go build -ldflags="-w -s" -o bin/win/sinker.exe cmd/sinker/main.go && go build -ldflags="-w -s" -o bin/win/init_app.exe cmd/init_app/main.go 2 | echo "build success" -------------------------------------------------------------------------------- /build_init_app_linux.bat: -------------------------------------------------------------------------------- 1 | set goos=linux&& go build -ldflags="-w -s" -o bin/linux/init_app cmd/init_app/main.go 2 | echo "build success" 3 | -------------------------------------------------------------------------------- /build_manager_linux.bat: -------------------------------------------------------------------------------- 1 | cd vue && npm run build:prod && cd .. && set goos=linux&&go build -ldflags="-w -s" -o bin/linux/manager cmd/manager/main.go 2 | echo "build success" 3 | -------------------------------------------------------------------------------- /build_report_linux.bat: -------------------------------------------------------------------------------- 1 | set goos=linux&& go build -ldflags="-w -s" -o bin/linux/report_server cmd/report_server/main.go 2 | echo "build success" 3 | -------------------------------------------------------------------------------- /build_sinker_linux.bat: -------------------------------------------------------------------------------- 1 | set goos=linux&& go build -ldflags="-w -s" -o bin/linux/sinker cmd/sinker/main.go 2 | echo "build success" 3 | -------------------------------------------------------------------------------- /cmd/init_app/kafka/init.go: -------------------------------------------------------------------------------- 1 | package kafka 2 | 3 | import ( 4 | "fmt" 5 | "github.com/1340691923/xwl_bi/model" 6 | "github.com/Shopify/sarama" 7 | "log" 8 | "time" 9 | ) 10 | 11 | //初始化kafka数据 12 | func Init() { 13 | config := sarama.NewConfig() 14 | 15 | config.Version = sarama.V2_0_0_0 16 | if model.GlobConfig.Comm.Kafka.Username != "" { 17 | config.Net.SASL.Enable = true 18 | config.Net.SASL.User = model.GlobConfig.Comm.Kafka.Username 19 | config.Net.SASL.Password = model.GlobConfig.Comm.Kafka.Password 20 | config.Net.SASL.Handshake = true 21 | } 22 | 23 | config.Consumer.Group.Session.Timeout = 15 * time.Second 24 | config.Consumer.Group.Heartbeat.Interval = 5 * time.Second 25 | 26 | conn, err := sarama.NewClusterAdmin(model.GlobConfig.Comm.Kafka.Addresses, config) 27 | if err != nil { 28 | log.Println(fmt.Sprintf("kafka 链接初始化失败:%s", err.Error())) 29 | panic(err) 30 | } 31 | s, err := conn.ListTopics() 32 | for topic := range s { 33 | log.Println("您所拥有的TOPIC为:", topic) 34 | } 35 | 36 | if _, ok := s[model.GlobConfig.Comm.Kafka.ReportTopicName]; !ok { 37 | detail := sarama.TopicDetail{NumPartitions: model.GlobConfig.Comm.Kafka.NumPartitions, ReplicationFactor: 1} 38 | err = conn.CreateTopic(model.GlobConfig.Comm.Kafka.ReportTopicName, &detail, false) 39 | if err != nil { 40 | log.Println("创建TOPIC失败!", model.GlobConfig.Comm.Kafka.ReportTopicName) 41 | panic(err) 42 | } 43 | 44 | err = conn.Close() 45 | if err != nil { 46 | panic(err) 47 | } 48 | log.Println("初始化TOPIC完成!", model.GlobConfig.Comm.Kafka.ReportTopicName) 49 | } else { 50 | log.Println("您已拥有该TOPIC:", model.GlobConfig.Comm.Kafka.ReportTopicName) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cmd/init_app/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/1340691923/xwl_bi/application" 7 | "github.com/1340691923/xwl_bi/cmd/init_app/ck" 8 | "github.com/1340691923/xwl_bi/cmd/init_app/kafka" 9 | "github.com/1340691923/xwl_bi/cmd/init_app/mysql" 10 | _ "github.com/ClickHouse/clickhouse-go" 11 | _ "github.com/go-sql-driver/mysql" 12 | "log" 13 | ) 14 | 15 | var ( 16 | configFileDir string 17 | configFileName string 18 | configFileExt string 19 | ) 20 | 21 | func init() { 22 | flag.StringVar(&configFileDir, "configFileDir", "config", "配置文件夹名") 23 | flag.StringVar(&configFileName, "configFileName", "config", "配置文件名") 24 | flag.StringVar(&configFileExt, "configFileExt", "json", "配置文件后缀") 25 | flag.Parse() 26 | } 27 | 28 | // 初始化程序 29 | // By 肖文龙 30 | func main() { 31 | 32 | app := application.NewApp( 33 | "init_app", 34 | application.WithConfigFileDir(configFileDir), 35 | application.WithConfigFileName(configFileName), 36 | application.WithConfigFileExt(configFileExt), 37 | application.RegisterInitFnObserver(application.InitLogs), 38 | application.RegisterInitFnObserver(application.InitMysql), 39 | application.RegisterInitFnObserver(application.InitClickHouse), 40 | ) 41 | 42 | err := app.InitConfig(). 43 | NotifyInitFnObservers(). 44 | Error() 45 | 46 | if err != nil { 47 | log.Println(fmt.Sprintf("初始化失败%s", err.Error())) 48 | panic(err) 49 | } 50 | 51 | defer app.Close() 52 | 53 | kafka.Init() 54 | ck.Init() 55 | mysql.Init() 56 | log.Println("数据已全部初始化完毕!") 57 | } 58 | -------------------------------------------------------------------------------- /cmd/init_app/mysql/init.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | _ "embed" 5 | "fmt" 6 | "github.com/1340691923/xwl_bi/engine/db" 7 | "github.com/1340691923/xwl_bi/model" 8 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 9 | "log" 10 | "strings" 11 | ) 12 | 13 | //go:embed bi.sql 14 | var SqlByte []byte 15 | 16 | //初始化mysql数据 17 | func Init() { 18 | var err error 19 | 20 | _, err = db.Sqlx.Exec(` create database if not exists ` + model.GlobConfig.Comm.Mysql.DbName) 21 | 22 | if err != nil { 23 | log.Println(fmt.Sprintf("mysql 执行建库语句失败:%s", err.Error())) 24 | panic(err) 25 | } 26 | 27 | execSqlArr := strings.Split(util.Bytes2str(SqlByte), ";") 28 | 29 | for _, execSql := range execSqlArr { 30 | _, err = db.Sqlx.Exec(execSql) 31 | if err != nil { 32 | log.Println(fmt.Sprintf("mysql 执行建表语句sql:%v失败:%s", execSql, err.Error())) 33 | panic(err) 34 | } 35 | } 36 | 37 | log.Println("初始化mysql数据完成!") 38 | } 39 | -------------------------------------------------------------------------------- /cmd/manager/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/1340691923/xwl_bi/application" 6 | "github.com/1340691923/xwl_bi/engine/logs" 7 | _ "github.com/ClickHouse/clickhouse-go" 8 | _ "github.com/go-sql-driver/mysql" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | var ( 13 | configFileDir string 14 | configFileName string 15 | configFileExt string 16 | ) 17 | 18 | func init() { 19 | flag.StringVar(&configFileDir, "configFileDir", "config", "配置文件夹名") 20 | flag.StringVar(&configFileName, "configFileName", "config", "配置文件名") 21 | flag.StringVar(&configFileExt, "configFileExt", "json", "配置文件后缀") 22 | flag.Parse() 23 | } 24 | 25 | // 管理后台 26 | // By 肖文龙 27 | func main() { 28 | 29 | app := application.NewApp( 30 | "manager", 31 | application.WithConfigFileDir(configFileDir), 32 | application.WithConfigFileName(configFileName), 33 | application.WithConfigFileExt(configFileExt), 34 | application.RegisterInitFnObserver(application.InitLogs), 35 | application.RegisterInitFnObserver(application.InitMysql), 36 | application.RegisterInitFnObserver(application.InitTask), 37 | application.RegisterInitFnObserver(application.InitRbac), 38 | application.RegisterInitFnObserver(application.InitOpenWinBrowser), 39 | application.RegisterInitFnObserver(application.InitClickHouse), 40 | application.RegisterInitFnObserver(application.InitRedisPool), 41 | application.RegisterInitFnObserver(application.InitDebugSarama), 42 | ) 43 | 44 | err := app. 45 | InitConfig(). 46 | NotifyInitFnObservers(). 47 | Error() 48 | 49 | if err != nil { 50 | logs.Logger.Error("BI 初始化失败", zap.String("err.Error()", err.Error())) 51 | panic(err) 52 | } 53 | 54 | defer app.Close() 55 | 56 | app.RunManager() 57 | 58 | app.WaitForExitSign(func() { 59 | logs.Logger.Sugar().Infof("BI 服务停止成功...") 60 | }) 61 | 62 | } 63 | -------------------------------------------------------------------------------- /cmd/sinker/geoip/GeoLite2-City.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1340691923/xwl_bi/9337120b09f855a22c4c5a4e78b84436ef37dc30/cmd/sinker/geoip/GeoLite2-City.mmdb -------------------------------------------------------------------------------- /controller/base_controller.go: -------------------------------------------------------------------------------- 1 | //控制器层 2 | package controller 3 | 4 | import ( 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/request" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/response" 7 | ) 8 | 9 | //父控制器结构体 10 | type BaseController struct { 11 | response.Response 12 | request.Request 13 | } 14 | -------------------------------------------------------------------------------- /controller/gm_operater_log.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/platform-basic-libs/request" 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/response" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/service/gm_operater_log" 7 | "github.com/gofiber/fiber/v2" 8 | ) 9 | 10 | type GmOperaterController struct { 11 | BaseController 12 | } 13 | 14 | //查看后台操作日志 15 | func (this GmOperaterController) ListAction(ctx *fiber.Ctx) error { 16 | 17 | var reqData request.GmOperaterLogList 18 | 19 | if err := ctx.BodyParser(&reqData); err != nil { 20 | return this.Error(ctx, err) 21 | } 22 | 23 | gmOperaterLogService := gm_operater_log.GmOperaterLogService{} 24 | 25 | list, count, err := gmOperaterLogService.List(reqData) 26 | 27 | if err != nil { 28 | return this.Error(ctx, err) 29 | } 30 | 31 | return this.Success(ctx, response.SearchSuccess, map[string]interface{}{"list": list, "count": count}) 32 | } 33 | -------------------------------------------------------------------------------- /controller/rbac_controller.go: -------------------------------------------------------------------------------- 1 | package controller 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/platform-basic-libs/api_config" 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/response" 6 | fiber "github.com/gofiber/fiber/v2" 7 | ) 8 | 9 | //接口访问权限管理 直接放缓存 10 | type RbacController struct { 11 | BaseController 12 | } 13 | 14 | //获取接口路由信息 15 | func (this RbacController) UrlConfig(ctx *fiber.Ctx) error { 16 | apiRouterConfig := api_config.NewApiRouterConfig() 17 | return this.Success(ctx, response.SearchSuccess, apiRouterConfig.GetRouterConfigs()) 18 | } 19 | -------------------------------------------------------------------------------- /engine/db/redis.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "fmt" 5 | "github.com/garyburd/redigo/redis" 6 | "log" 7 | "strings" 8 | ) 9 | 10 | var RedisPool *redis.Pool 11 | 12 | // NewRedisPool 新建一个Redis连接池 URL优先 13 | func NewRedisPool(addr, passwd string, db, maxIdle, MaxActive int) *redis.Pool { 14 | b := strings.HasPrefix(addr, "redis://") 15 | var dialFunc func() (redis.Conn, error) 16 | switch { 17 | case b && passwd == "": 18 | dialFunc = func() (redis.Conn, error) { 19 | return redis.DialURL(addr, redis.DialDatabase(db)) 20 | } 21 | case b && passwd != "": 22 | dialFunc = func() (redis.Conn, error) { 23 | return redis.DialURL(addr, redis.DialDatabase(db), redis.DialPassword(passwd)) 24 | } 25 | case !b && passwd == "": 26 | dialFunc = func() (redis.Conn, error) { 27 | return redis.Dial("tcp", addr, redis.DialDatabase(db)) 28 | } 29 | case !b && passwd != "": 30 | dialFunc = func() (redis.Conn, error) { 31 | return redis.Dial("tcp", addr, redis.DialDatabase(db), redis.DialPassword(passwd)) 32 | } 33 | } 34 | 35 | return &redis.Pool{ 36 | MaxIdle: maxIdle, 37 | MaxActive: MaxActive, 38 | Dial: func() (redis.Conn, error) { 39 | c, err := dialFunc() 40 | if err != nil { 41 | log.Println(fmt.Errorf("redis 连接失败:%v", err)) 42 | } 43 | return c, err 44 | }, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /engine/db/sqlx.go: -------------------------------------------------------------------------------- 1 | //MySql引擎层 2 | package db 3 | 4 | import ( 5 | "fmt" 6 | "github.com/Masterminds/squirrel" 7 | "github.com/jmoiron/sqlx" 8 | "log" 9 | "time" 10 | ) 11 | 12 | // sqlx 全局变量 13 | var Sqlx *sqlx.DB 14 | var ClickHouseSqlx *sqlx.DB 15 | 16 | // 用squirrel生成sql语句 17 | var SqlBuilder = squirrel.StatementBuilder 18 | 19 | type Eq = squirrel.Eq 20 | type Or = squirrel.Or 21 | type And = squirrel.And 22 | 23 | type NotEq = squirrel.NotEq 24 | type Gt = squirrel.Gt 25 | type Lt = squirrel.Lt 26 | type GtOrEq = squirrel.GtOrEq 27 | type LtOrEq = squirrel.LtOrEq 28 | 29 | type Like = squirrel.Like 30 | type Gte = squirrel.GtOrEq 31 | type Lte = squirrel.LtOrEq 32 | type SelectBuilder = squirrel.SelectBuilder 33 | type InsertBuilder = squirrel.InsertBuilder 34 | type UpdateBuilder = squirrel.UpdateBuilder 35 | 36 | // NewMySQL 创建一个连接MySQL的实体池 37 | func NewSQLX(driverName, dbSource string, maxOpenConns, maxIdleConns int) (db *sqlx.DB, err error) { 38 | 39 | db, err = sqlx.Open(driverName, dbSource) 40 | if err != nil { 41 | return 42 | } 43 | if maxOpenConns > 0 { 44 | db.SetMaxOpenConns(maxOpenConns) 45 | } 46 | 47 | if maxIdleConns > 0 { 48 | db.SetMaxIdleConns(maxIdleConns) 49 | } 50 | err = db.Ping() 51 | if err != nil { 52 | return 53 | } 54 | go func() { 55 | for { 56 | err = db.Ping() 57 | if err != nil { 58 | log.Println("mysql db can't connect!") 59 | } 60 | time.Sleep(time.Minute) 61 | } 62 | }() 63 | return 64 | } 65 | 66 | // 创建分页查询 67 | func CreatePage(page, limit uint64) uint64 { 68 | tmp := (page - 1) * limit 69 | return tmp 70 | } 71 | 72 | // 创建模糊查询 73 | func CreateLike(column string) string { 74 | return fmt.Sprint("%", column, "%") 75 | } 76 | -------------------------------------------------------------------------------- /init_app_start.bat: -------------------------------------------------------------------------------- 1 | set dir = %cd% 2 | 3 | set args = "-configFileDir=%cd%\config" 4 | 5 | gowatch -p cmd/init_app/main.go -args=args -o bin/win/init_app.exe -------------------------------------------------------------------------------- /manager_start.bat: -------------------------------------------------------------------------------- 1 | set dir = %cd% 2 | 3 | set args = "-configFileDir=%cd%\config" 4 | 5 | gowatch -p cmd/manager/main.go -args=args -o bin/win/manager.exe -------------------------------------------------------------------------------- /middleware/Exception.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | // 内置异常 4 | const ( 5 | INVALID_PARAMS int = 40001 6 | ERROR_AUTH_CHECK_TOKEN_FAIL int = 40002 7 | ERROR_AUTH_CHECK_TOKEN_TIMEOUT int = 40003 8 | ERROR_RBAC_LOAD int = 40004 9 | ERROR_RBAC_AUTH int = 40005 10 | ) 11 | 12 | // 内置异常表 TOKEN_ERROR 13 | var TOKEN_ERROR = map[int]string{ 14 | INVALID_PARAMS: "Token不能为空", 15 | ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败", 16 | ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时", 17 | ERROR_RBAC_LOAD: "读取rdbc权限列表失败", 18 | ERROR_RBAC_AUTH: "您没有该资源的访问权限", 19 | } 20 | -------------------------------------------------------------------------------- /middleware/analysis_cache.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/platform-basic-libs/service/analysis" 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 6 | "github.com/gofiber/fiber/v2" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | //防止狂点设置3秒的缓存 12 | func AnalysisCache(ctx *fiber.Ctx) error { 13 | cache := analysis.NewCache(time.Second*3, ctx.Path(), ctx.Body()) 14 | 15 | resData, redisErr := cache.LoadData() 16 | if util.FilterRedisNilErr(redisErr) { 17 | return res.Error(ctx, redisErr) 18 | } 19 | 20 | if len(resData) > 0 { 21 | return ctx.Send(resData) 22 | } 23 | 24 | err := ctx.Next() 25 | if err != nil { 26 | return res.Error(ctx, err) 27 | } 28 | if ctx.Response().StatusCode() == http.StatusOK { 29 | err = cache.SetData(ctx.Response().Body()) 30 | if err != nil { 31 | return res.Error(ctx, err) 32 | } 33 | } 34 | 35 | return err 36 | 37 | } 38 | -------------------------------------------------------------------------------- /middleware/filter_appid.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "errors" 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/service/myapp" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 7 | "github.com/gofiber/fiber/v2" 8 | "github.com/tidwall/gjson" 9 | ) 10 | 11 | func FilterAppid(ctx *fiber.Ctx) error { 12 | 13 | appid := gjson.GetBytes(ctx.Body(), "appid").Int() 14 | 15 | if appid == 0 { 16 | return res.Error(ctx, errors.New("请先在左上角选择您的应用")) 17 | } 18 | 19 | list, err := myapp.GetAppidsByToken(util.GetToken(ctx)) 20 | 21 | if err != nil { 22 | return res.Error(ctx, err) 23 | } 24 | haveApp := false 25 | for _, v := range list { 26 | if v.Id == int(appid) { 27 | haveApp = true 28 | break 29 | } 30 | } 31 | 32 | if !haveApp { 33 | return res.Error(ctx, errors.New("您不属于该应用成员")) 34 | } 35 | 36 | err = ctx.Next() 37 | 38 | return err 39 | 40 | } 41 | -------------------------------------------------------------------------------- /middleware/jwt.go: -------------------------------------------------------------------------------- 1 | // 中间件层 2 | package middleware 3 | 4 | import ( 5 | "time" 6 | 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/jwt" 8 | "github.com/1340691923/xwl_bi/platform-basic-libs/my_error" 9 | "github.com/1340691923/xwl_bi/platform-basic-libs/response" 10 | "github.com/1340691923/xwl_bi/platform-basic-libs/service/gm_user" 11 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 12 | fiber "github.com/gofiber/fiber/v2" 13 | ) 14 | 15 | var res response.Response 16 | 17 | func JwtMiddleware(c *fiber.Ctx) error { 18 | 19 | var err error 20 | var claims *jwt.Claims 21 | token := util.GetToken(c) 22 | if _, logoff := util.TokenBucket.Load(token); logoff { 23 | err = my_error.NewBusiness(TOKEN_ERROR, ERROR_AUTH_CHECK_TOKEN_FAIL) 24 | return res.Error(c, err) 25 | } 26 | 27 | if util.GetToken(c) == "" { 28 | err = my_error.NewBusiness(TOKEN_ERROR, INVALID_PARAMS) 29 | return res.Error(c, err) 30 | } 31 | 32 | var service gm_user.GmUserService 33 | claims, err = jwt.ParseToken(token) 34 | if err != nil { 35 | err = my_error.NewBusiness(TOKEN_ERROR, ERROR_AUTH_CHECK_TOKEN_FAIL) 36 | return res.Error(c, err) 37 | } 38 | if time.Now().Unix() > claims.ExpiresAt { 39 | err = my_error.NewBusiness(TOKEN_ERROR, ERROR_AUTH_CHECK_TOKEN_TIMEOUT) 40 | return res.Error(c, err) 41 | } 42 | if !service.IsExitUser(claims) { 43 | err = my_error.NewBusiness(TOKEN_ERROR, ERROR_AUTH_CHECK_TOKEN_TIMEOUT) 44 | return res.Error(c, err) 45 | } 46 | 47 | return c.Next() 48 | } 49 | -------------------------------------------------------------------------------- /middleware/operater_log.go: -------------------------------------------------------------------------------- 1 | // 中间件层 2 | package middleware 3 | 4 | import ( 5 | "github.com/1340691923/xwl_bi/engine/logs" 6 | "github.com/1340691923/xwl_bi/model" 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/jwt" 8 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 9 | fiber "github.com/gofiber/fiber/v2" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | //fiber 没有将fasthttp的 14 | func OperaterLog(ctx *fiber.Ctx) error { 15 | 16 | var err error 17 | token := util.GetToken(ctx) 18 | var claims *jwt.Claims 19 | claims, err = jwt.ParseToken(token) 20 | if err != nil { 21 | logs.Logger.Error("OperaterLog jwt err", zap.Error(err)) 22 | return err 23 | } 24 | 25 | gmOperaterLog := model.GmOperaterLog{ 26 | OperaterName: claims.Username, 27 | OperaterId: int(claims.UserID), 28 | OperaterAction: ctx.Path(), 29 | Method: ctx.Method(), 30 | Body: ctx.Body(), 31 | OperaterRoleId: int(claims.RoleId), 32 | } 33 | 34 | err = gmOperaterLog.Insert() 35 | 36 | if err != nil { 37 | logs.Logger.Error("OperaterLog", zap.Error(err)) 38 | } 39 | 40 | return ctx.Next() 41 | 42 | } 43 | -------------------------------------------------------------------------------- /middleware/rbac.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "strconv" 6 | 7 | "github.com/1340691923/xwl_bi/engine/logs" 8 | "github.com/1340691923/xwl_bi/platform-basic-libs/api_config" 9 | "github.com/1340691923/xwl_bi/platform-basic-libs/jwt" 10 | "github.com/1340691923/xwl_bi/platform-basic-libs/my_error" 11 | "github.com/1340691923/xwl_bi/platform-basic-libs/rbac" 12 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 13 | fiber "github.com/gofiber/fiber/v2" 14 | ) 15 | 16 | const ADMIN_ROLE = 1 17 | 18 | func Rbac(ctx *fiber.Ctx) error { 19 | var err error 20 | token := util.GetToken(ctx) 21 | var claims *jwt.Claims 22 | claims, err = jwt.ParseToken(token) 23 | if err != nil { 24 | logs.Logger.Error("Rbac ", zap.Error(err)) 25 | return err 26 | } 27 | obj := ctx.Path() 28 | 29 | sub := int(claims.RoleId) 30 | apiRouterConfig := api_config.NewApiRouterConfig() 31 | //最高权限用户可免接口鉴权 32 | if sub == ADMIN_ROLE { 33 | return ctx.Next() 34 | } 35 | for _, routerConfig := range apiRouterConfig.GetRouterConfigs() { 36 | if obj == routerConfig.Url { 37 | ok, err := rbac.Enforcer.EnforceSafe(strconv.Itoa(sub), obj, "*") 38 | if err != nil { 39 | return res.Error(ctx, my_error.NewBusiness(TOKEN_ERROR, ERROR_RBAC_LOAD)) 40 | } 41 | if !ok { 42 | return res.Error(ctx, my_error.NewBusiness(TOKEN_ERROR, ERROR_RBAC_AUTH)) 43 | } 44 | } 45 | } 46 | return ctx.Next() 47 | } 48 | -------------------------------------------------------------------------------- /middleware/time.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/1340691923/xwl_bi/engine/logs" 7 | fiber "github.com/gofiber/fiber/v2" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | func Timer(ctx *fiber.Ctx) error { 12 | 13 | // start timer 14 | start := time.Now() 15 | // next routes 16 | err := ctx.Next() 17 | // stop timer 18 | stop := time.Now() 19 | 20 | logs.Logger.Info("时间拦截器", 21 | zap.String("访问资源",ctx.Path()), 22 | zap.Reflect("body",string(ctx.Body())), 23 | zap.String("消耗时间:", stop.Sub(start).String())) 24 | return err 25 | 26 | } 27 | -------------------------------------------------------------------------------- /model/app.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type App struct { 4 | Page uint64 `json:"page" db:"-"` 5 | Limit uint64 `json:"limit" db:"-"` 6 | IsClose *int `db:"is_close" json:"is_close"` 7 | Id int `db:"id" json:"id"` 8 | CreateBy int `db:"create_by" json:"create_by"` 9 | UpdateBy int `db:"update_by" json:"update_by"` 10 | SaveMonth int `db:"save_mouth" json:"save_mouth"` 11 | AppName string `db:"app_name" json:"app_name"` 12 | Descibe string `db:"descibe" json:"descibe"` 13 | AppId string `db:"app_id" json:"app_id"` 14 | AppKey string `db:"app_key" json:"app_key"` 15 | CreateTime string `db:"create_time" json:"create_time"` 16 | UpdateTime string `db:"update_time" json:"update_time"` 17 | AppManager string `db:"app_manager" json:"app_manager"` 18 | } 19 | -------------------------------------------------------------------------------- /model/crud.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/engine/db" 5 | ) 6 | 7 | type Curd interface { 8 | ProcessSqlWhere(sqlA db.SelectBuilder) db.SelectBuilder 9 | TableName() string 10 | ProcessSqlInsert(sqlA db.InsertBuilder) db.InsertBuilder 11 | ProcessSqlUpdate(id int, sqlA db.UpdateBuilder) db.UpdateBuilder 12 | } 13 | 14 | func SearchList(curd Curd, page, limit int, columns string, list interface{}) (err error) { 15 | sqlA := db. 16 | SqlBuilder. 17 | Select(columns). 18 | From(curd.TableName()) 19 | sqlA = curd.ProcessSqlWhere(sqlA) 20 | sql, args, err := sqlA. 21 | Limit(uint64(limit)). 22 | Offset(db.CreatePage(uint64(page), uint64(limit))). 23 | OrderBy("id desc"). 24 | ToSql() 25 | err = db.Sqlx.Select(list, sql, args...) 26 | return 27 | } 28 | 29 | func Count(curd Curd) (count int, err error) { 30 | sqlA := db.SqlBuilder. 31 | Select("count(*)"). 32 | From(curd.TableName()) 33 | sqlA = curd.ProcessSqlWhere(sqlA) 34 | sql, args, err := sqlA.ToSql() 35 | err = db.Sqlx.Get(&count, sql, args...) 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /model/debug_device.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type DebugDevice struct { 4 | Id int `db:"id" json:"id"` 5 | Appid int `db:"appid" json:"appid"` 6 | DeviceId string `db:"device_id" json:"device_id"` 7 | Remark string `db:"remark" json:"remark"` 8 | CreateBy int `db:"create_by" json:"create_by"` 9 | CreateTime string `db:"create_time" json:"create_time"` 10 | } 11 | -------------------------------------------------------------------------------- /model/gm_role.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/1340691923/xwl_bi/engine/db" 4 | 5 | // GmRoleModel 6 | type GmRoleModel struct { 7 | ID int `json:"id" db:"id"` 8 | RoleName string `json:"name" db:"role_name"` 9 | Description string `json:"description" db:"description"` 10 | RoleList string `json:"routes" db:"role_list"` 11 | } 12 | 13 | // GetById 14 | func (this *GmRoleModel) GetById(roleId int) (model GmRoleModel, err error) { 15 | err = db.Sqlx.Get(&model, "select id,role_name,description,role_list from gm_role where id = ?;", roleId) 16 | return 17 | } 18 | 19 | // Update 20 | func (this *GmRoleModel) Update() (err error) { 21 | _, err = db.Sqlx.Exec( 22 | "update gm_role set role_name = ?,description=?,role_list=? where id = ?;", 23 | this.RoleName, this.Description, this.RoleList, this.ID) 24 | return 25 | } 26 | 27 | // Delete 28 | func (this *GmRoleModel) Delete() (err error) { 29 | _, err = db.Sqlx.Exec("delete from gm_role where id = ? ;", this.ID) 30 | return 31 | } 32 | 33 | // Insert 34 | func (this *GmRoleModel) Insert() (id int64, err error) { 35 | rlt, err := db.Sqlx.Exec( 36 | "insert into gm_role (role_name,description,role_list) values (?,?,?);", 37 | this.RoleName, this.Description, this.RoleList) 38 | if err != nil { 39 | return 40 | } 41 | id, err = rlt.LastInsertId() 42 | if err != nil { 43 | return 44 | } 45 | return 46 | } 47 | 48 | // Select 49 | func (this *GmRoleModel) Select() (model []GmRoleModel, err error) { 50 | err = db.Sqlx.Select(&model, "select role_name,description,role_list,id from gm_role;") 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /model/message.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type InputMessage struct { 6 | Topic string 7 | Partition int 8 | Key []byte 9 | Value []byte 10 | Offset int64 11 | Timestamp *time.Time 12 | } 13 | -------------------------------------------------------------------------------- /model/pannel_folder.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type PannelFolder struct { 4 | Id int `db:"id" json:"id"` 5 | FolderName string `db:"folder_name" json:"folder_name"` 6 | FolderType int8 `db:"folder_type" json:"folder_type"` //0为自己创建的 7 | CreateBy int `db:"create_by" json:"create_by"` 8 | CreateTime string `db:"create_time" json:"create_time"` 9 | UpdateTime string `db:"update_time" json:"update_time"` 10 | Appid int `db:"appid" json:"appid"` 11 | } 12 | 13 | type Pannel struct { 14 | Id int `db:"id" json:"id"` 15 | FolderId int `db:"folder_id" json:"folder_id"` 16 | PannelName string `db:"pannel_name" json:"pannel_name"` 17 | Managers string `db:"managers" json:"managers"` 18 | CreateBy int `db:"create_by" json:"create_by"` 19 | CreateTime int64 `db:"create_time" json:"create_time"` 20 | UpdateTime int64 `db:"update_time" json:"update_time"` 21 | ReportTables string `db:"report_tables" json:"report_tables"` 22 | } 23 | -------------------------------------------------------------------------------- /model/report_table.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "github.com/1340691923/xwl_bi/engine/db" 4 | 5 | type ReportTable struct { 6 | Id int `db:"id" json:"id"` 7 | Appid int `db:"appid" json:"appid"` 8 | UserId int `db:"user_id" json:"user_id"` 9 | Name string `db:"name" json:"name"` 10 | RtType int8 `db:"rt_type" json:"rt_type"` 11 | Data string `db:"data" json:"data"` 12 | CreateTime string `db:"create_time" json:"create_time"` 13 | UpdateTime string `db:"update_time" json:"update_time"` 14 | Remark string `db:"remark" json:"remark"` 15 | } 16 | 17 | func (this *ReportTable) InsertOrUpdate() (err error) { 18 | sql := `insert into report_table(appid,user_id,name,rt_type,data,remark)values(?,?,?,?,?,?) on duplicate key update data=?,remark=?` 19 | _, err = db.Sqlx.Exec(sql, this.Appid, this.UserId, this.Name, this.RtType, this.Data, this.Remark, this.Data, this.Remark) 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /platform-basic-libs/jwt/exception.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | // 内置异常 4 | const ( 5 | ERROR_AUTH_TOKEN = 40006 6 | ) 7 | 8 | var TOKEN_ERROR = map[int]string{ 9 | ERROR_AUTH_TOKEN: "Token生成失败", 10 | } 11 | -------------------------------------------------------------------------------- /platform-basic-libs/my_error/my_error.go: -------------------------------------------------------------------------------- 1 | //自定义异常层 2 | package my_error 3 | 4 | //自定义异常结构体 实现Error方法 5 | type MyError struct { 6 | code int 7 | msg string 8 | } 9 | 10 | // 自定义业务异常 11 | func NewBusiness(ErrEnum map[int]string, code int) error { 12 | text := ErrEnum[code] 13 | return &MyError{code, text} 14 | } 15 | 16 | func NewError(text string, code int) error { 17 | return &MyError{code, text} 18 | } 19 | 20 | func (this *MyError) Error() string { 21 | return this.msg 22 | } 23 | 24 | func (this *MyError) Code() int { 25 | return this.code 26 | } 27 | -------------------------------------------------------------------------------- /platform-basic-libs/rbac/index.go: -------------------------------------------------------------------------------- 1 | package rbac 2 | 3 | import ( 4 | "github.com/casbin/casbin" 5 | xormadapter "github.com/casbin/xorm-adapter" 6 | ) 7 | 8 | var Enforcer *casbin.Enforcer 9 | 10 | func Run(driverName string, datasource string) (err error) { 11 | text := ` 12 | [request_definition] 13 | r = sub, obj, act 14 | 15 | [policy_definition] 16 | p = sub, obj, act 17 | 18 | [policy_effect] 19 | e = some(where (p.eft == allow)) 20 | 21 | [matchers] 22 | m = r.sub == p.sub && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") || r.sub == "1" 23 | ` 24 | policy := casbin.NewModel(text) 25 | 26 | model := xormadapter.NewAdapter(driverName, datasource, true) 27 | Enforcer = casbin.NewEnforcer(policy, model) 28 | err = Enforcer.LoadPolicy() 29 | 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /platform-basic-libs/request/Exception.go: -------------------------------------------------------------------------------- 1 | //自定义请求辅助方法层 2 | package request 3 | 4 | //自定义业务异常 5 | const ( 6 | IdNullError = 100002 7 | EmptyParmasError = 100003 8 | EmptyEventError = 100004 9 | ) 10 | 11 | var ErrorMap = map[int]string{ 12 | IdNullError: "id不能为空!", 13 | EmptyParmasError: "请求参数不能为空", 14 | EmptyEventError: "事件名不能为空", 15 | } 16 | -------------------------------------------------------------------------------- /platform-basic-libs/request/Request.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "github.com/tidwall/gjson" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/1340691923/xwl_bi/platform-basic-libs/my_error" 9 | fiber "github.com/gofiber/fiber/v2" 10 | ) 11 | 12 | //自定义请求 辅助方法 13 | type Request struct { 14 | } 15 | 16 | type CheckConfigStruct struct { 17 | Code int 18 | Key string 19 | } 20 | 21 | //检查请求参数 22 | func (this Request) CheckParameter(checkConfig []CheckConfigStruct, ctx *fiber.Ctx) (err error) { 23 | method := strings.ToUpper(ctx.Method()) 24 | for _, config := range checkConfig { 25 | switch method { 26 | case "GET": 27 | if ctx.FormValue(config.Key) == "" { 28 | err = my_error.NewBusiness(ErrorMap, config.Code) 29 | return 30 | } 31 | case "POST": 32 | if !gjson.GetBytes(ctx.Body(), config.Key).Exists() { 33 | err = my_error.NewBusiness(ErrorMap, config.Code) 34 | return 35 | } 36 | } 37 | 38 | } 39 | return 40 | } 41 | 42 | // FormIntDefault 获取Form参数 如果出错则返回默认值 43 | func (this Request) FormIntDefault(ctx *fiber.Ctx, key string, def int) int { 44 | i, err := strconv.Atoi(ctx.FormValue(key)) 45 | if err != nil { 46 | return def 47 | } 48 | return i 49 | } 50 | 51 | //获取用户token信息 52 | func (this Request) GetToken(ctx *fiber.Ctx) (token string) { 53 | return ctx.Get("X-Token") 54 | } 55 | -------------------------------------------------------------------------------- /platform-basic-libs/service/analysis/cache.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "fmt" 5 | "github.com/1340691923/xwl_bi/engine/db" 6 | "github.com/1340691923/xwl_bi/engine/logs" 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 8 | "github.com/garyburd/redigo/redis" 9 | "go.uber.org/zap" 10 | "time" 11 | ) 12 | 13 | type Cache struct { 14 | overTime int `json:"over_time"` 15 | analysisType string `json:"cache_key"` 16 | reqData []byte `json:"req_data"` 17 | } 18 | 19 | func ClearCacheByAppid(key string) (err error) { 20 | conn := db.RedisPool.Get() 21 | defer conn.Close() 22 | _, err = conn.Do("unlink", key) 23 | if err != nil { 24 | _, err = conn.Do("del", key) 25 | if err != nil { 26 | logs.Logger.Error("err", zap.Error(err)) 27 | } 28 | } 29 | return 30 | } 31 | 32 | func NewCache(overTime time.Duration, analysisType string, reqData []byte) *Cache { 33 | return &Cache{overTime: int(overTime.Seconds()), analysisType: analysisType, reqData: reqData} 34 | } 35 | 36 | func (this *Cache) getKey() string { 37 | return fmt.Sprintf("%s_%s", this.analysisType, util.MD5HexHash(this.reqData)) 38 | } 39 | 40 | func (this *Cache) LoadData() (b []byte, err error) { 41 | conn := db.RedisPool.Get() 42 | defer conn.Close() 43 | b, err = redis.Bytes(conn.Do("get", this.getKey())) 44 | return 45 | } 46 | 47 | func (this *Cache) SetData(b []byte) (err error) { 48 | conn := db.RedisPool.Get() 49 | defer conn.Close() 50 | _, err = conn.Do("SETEX", this.getKey(), this.overTime, b) 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /platform-basic-libs/service/analysis/exception.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | // 内置异常 4 | const ( 5 | TimeError int = 60001 6 | ZhiBiaoNumError int = 60002 7 | GroupNumError int = 60003 8 | GroupEmptyError int = 60004 9 | UIEmptyError int = 60005 10 | EventNameEmptyError int = 60006 11 | ) 12 | 13 | // 内置异常表 14 | var ERROR_TABLE = map[int]string{ 15 | TimeError: "筛选时间异常", 16 | ZhiBiaoNumError: "筛选指标个数异常", 17 | GroupNumError: "筛选分组个数异常", 18 | GroupEmptyError: "筛选分组不能为空字段", 19 | UIEmptyError: "用户id列表不能为空", 20 | EventNameEmptyError: "事件名不能为空", 21 | } 22 | -------------------------------------------------------------------------------- /platform-basic-libs/service/analysis/interface.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type Ianalysis interface { 9 | GetList() (interface{}, error) 10 | GetExecSql() (SQL string, allArgs []interface{}, err error) //后续开发 查看执行sql功能 11 | } 12 | 13 | type Command int 14 | 15 | const ( 16 | FunnelComand Command = 1 17 | RetentionComand Command = 2 18 | TraceComand Command = 3 19 | EventComand Command = 4 20 | UserAttrCommand Command = 5 21 | UserListCommand Command = 6 22 | UserEventDetailListCommand Command = 7 23 | UserEventCountCommand Command = 8 24 | ) 25 | 26 | var commandMap = map[Command]func(reqData []byte) (Ianalysis, error){ 27 | FunnelComand: NewFunnel, 28 | RetentionComand: NewRetention, 29 | TraceComand: NewTrace, 30 | EventComand: NewEvent, 31 | UserAttrCommand: NewUserAttr, 32 | UserListCommand: NewUserList, 33 | UserEventDetailListCommand: NewUserEventDetailList, 34 | UserEventCountCommand: NewUserEventCountList, 35 | } 36 | 37 | func NewAnalysisByCommand(command Command, reqData []byte) (i Ianalysis, err error) { 38 | var fn func(reqData []byte) (Ianalysis, error) 39 | var found bool 40 | if fn, found = commandMap[command]; !found { 41 | return nil, errors.New(fmt.Sprintf("没有找到该命令:%v", command)) 42 | } 43 | 44 | return fn(reqData) 45 | } 46 | 47 | func GetAnalysisRes(i Ianalysis) (res interface{}, err error) { 48 | return i.GetList() 49 | } 50 | -------------------------------------------------------------------------------- /platform-basic-libs/service/analysis/utils.go: -------------------------------------------------------------------------------- 1 | package analysis 2 | 3 | import ( 4 | "fmt" 5 | "github.com/1340691923/xwl_bi/engine/logs" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/request" 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/service/analysis/utils" 8 | ) 9 | 10 | func getUserfilterSqlArgs(analysisFilter request.AnalysisFilter, appid int) (userFilterSql string, userFilterArgs []interface{}, err error) { 11 | if len(analysisFilter.Filts) > 0 { 12 | var colArr []string 13 | var sql string 14 | sql, userFilterArgs, colArr, err = utils.GetWhereSql(analysisFilter) 15 | if err != nil { 16 | return 17 | } 18 | userFilterSql = ` and xwl_distinct_id in ( select xwl_distinct_id from ` + utils.GetUserTableView(appid, colArr) + ` where ` + sql + ") " 19 | } 20 | return 21 | } 22 | 23 | func getZhibiaoFilterSqlArgs(zhibiaoArr []request.Zhibiao) (windowSql string, allArgs []interface{}, err error) { 24 | 25 | for _, zhibiao := range zhibiaoArr { 26 | windowSql = windowSql + "," 27 | 28 | windowSql = windowSql + fmt.Sprintf(" xwl_part_event = '%v' ", zhibiao.EventName) 29 | 30 | if len(zhibiao.Relation.Filts) > 0 { 31 | windowSql = windowSql + " and " 32 | sql, args, _, err := utils.GetWhereSql(zhibiao.Relation) 33 | 34 | if err != nil { 35 | logs.Logger.Sugar().Errorf("zhibiao.Relation", zhibiao) 36 | return windowSql, allArgs, err 37 | } 38 | 39 | allArgs = append(allArgs, args...) 40 | 41 | windowSql = windowSql + sql 42 | } 43 | } 44 | 45 | return windowSql, allArgs, err 46 | } 47 | -------------------------------------------------------------------------------- /platform-basic-libs/service/analysis/utils/user_group.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/engine/db" 5 | "github.com/1340691923/xwl_bi/model" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 7 | "github.com/Masterminds/squirrel" 8 | "strings" 9 | ) 10 | 11 | func GetUserGroupSqlAndArgs(ids []int, appid int) (SQL string, Args []interface{}, err error) { 12 | if len(ids) == 0 { 13 | return " and ( 1 = 1 ) ", nil, err 14 | } 15 | 16 | sql, args, err := db. 17 | SqlBuilder. 18 | Select("user_list"). 19 | From("user_group"). 20 | Where(db.Eq{"appid": appid, "id": ids}). 21 | ToSql() 22 | 23 | var userGroupList []model.UserGroup 24 | 25 | err = db.Sqlx.Select(&userGroupList, sql, args...) 26 | 27 | if err != nil { 28 | return "", nil, err 29 | } 30 | 31 | or := squirrel.Or{} 32 | 33 | for index := range userGroupList { 34 | idStr, err := util.GzipUnCompress(userGroupList[index].UserList) 35 | if err != nil { 36 | return "", nil, err 37 | } 38 | id := strings.Split(idStr, ",") 39 | or = append(or, db.Eq{"xwl_distinct_id": [][]string{id}}) 40 | } 41 | 42 | SQL, Args, err = or.ToSql() 43 | SQL = " and " + SQL 44 | return SQL, Args, err 45 | } 46 | -------------------------------------------------------------------------------- /platform-basic-libs/service/debug_data/debug_data.go: -------------------------------------------------------------------------------- 1 | package debug_data 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/engine/db" 5 | "github.com/1340691923/xwl_bi/model" 6 | ) 7 | 8 | type DebugData struct { 9 | } 10 | 11 | func (this *DebugData) AddDebugDeviceID(appid, deviceID, remark string, managerUid int32) (err error) { 12 | 13 | _, err = db. 14 | SqlBuilder. 15 | Insert("debug_device"). 16 | SetMap(map[string]interface{}{ 17 | "remark": remark, 18 | "device_id": deviceID, 19 | "appid": appid, 20 | "create_by": managerUid, 21 | }).RunWith(db.Sqlx).Exec() 22 | 23 | if err != nil { 24 | return 25 | } 26 | 27 | Hash := "DebugDeviceID_" + appid 28 | conn := db.RedisPool.Get() 29 | defer conn.Close() 30 | _, err = conn.Do("sadd", Hash, deviceID) 31 | 32 | if err != nil { 33 | return 34 | } 35 | 36 | return 37 | } 38 | 39 | func (this *DebugData) DelDebugDeviceID(appid, deviceID string, managerUid int32) (err error) { 40 | 41 | _, err = db.SqlBuilder. 42 | Delete("debug_device"). 43 | Where(db.Eq{"device_id": deviceID, "appid": appid, "create_by": managerUid}). 44 | RunWith(db.Sqlx). 45 | Exec() 46 | if err != nil { 47 | return 48 | } 49 | Hash := "DebugDeviceID_" + appid 50 | conn := db.RedisPool.Get() 51 | defer conn.Close() 52 | _, err = conn.Do("srem", Hash, deviceID) 53 | 54 | if err != nil { 55 | return 56 | } 57 | 58 | return 59 | } 60 | 61 | func (this *DebugData) DebugDeviceIDList(appid int, managerUid int32) (res []model.DebugDevice, err error) { 62 | 63 | sql, args, err := db.SqlBuilder. 64 | Select("*"). 65 | From("debug_device"). 66 | Where(db.Eq{"appid": appid, "create_by": managerUid}). 67 | ToSql() 68 | if err != nil { 69 | return 70 | } 71 | 72 | err = db.Sqlx.Select(&res, sql, args...) 73 | if err != nil { 74 | return 75 | } 76 | 77 | return 78 | } 79 | -------------------------------------------------------------------------------- /platform-basic-libs/service/gm_operater_log/gm_operater_log_service.go: -------------------------------------------------------------------------------- 1 | package gm_operater_log 2 | 3 | import ( 4 | "github.com/1340691923/xwl_bi/engine/logs" 5 | "github.com/1340691923/xwl_bi/model" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/request" 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | type GmOperaterLogService struct { 12 | } 13 | 14 | func (this *GmOperaterLogService) List(reqData request.GmOperaterLogList) (list []model.GmOperaterLog, count int, err error) { 15 | if reqData.Page <= 0 { 16 | reqData.Page = 1 17 | } 18 | if reqData.Limit <= 0 { 19 | reqData.Limit = 10 20 | } 21 | 22 | page := reqData.Page 23 | limit := reqData.Limit 24 | 25 | operater_action := reqData.OperaterAction 26 | 27 | gmOperaterModel := &model.GmOperaterLog{ 28 | OperaterRoleId: reqData.RoleId, 29 | OperaterId: reqData.UserId, 30 | OperaterAction: operater_action, 31 | FilterDate: reqData.Date, 32 | } 33 | listP := &list 34 | err = model.SearchList(gmOperaterModel, page, limit, "*", listP) 35 | if err != nil { 36 | return 37 | } 38 | count, err = model.Count(gmOperaterModel) 39 | if err != nil { 40 | return 41 | } 42 | 43 | for index := range list { 44 | 45 | body, err := util.GzipUnCompress(list[index].Body) 46 | if err != nil { 47 | logs.Logger.Error("err", zap.Error(err)) 48 | continue 49 | } 50 | 51 | list[index].BodyStr = body 52 | } 53 | return 54 | } 55 | -------------------------------------------------------------------------------- /platform-basic-libs/service/gm_user/exception.go: -------------------------------------------------------------------------------- 1 | package gm_user 2 | 3 | // 自定义业务异常 4 | const ( 5 | ERROR_AUTH_TOKEN = 40006 6 | ERROR_AUTH = 40007 7 | ) 8 | 9 | var AUTH_ERROR = map[int]string{ 10 | ERROR_AUTH_TOKEN: "Token生成失败", 11 | ERROR_AUTH: "用户验证失败", 12 | } 13 | -------------------------------------------------------------------------------- /platform-basic-libs/service/gm_user/gm_user_service.go: -------------------------------------------------------------------------------- 1 | //BI用户层 2 | package gm_user 3 | 4 | import ( 5 | "errors" 6 | "github.com/1340691923/xwl_bi/engine/db" 7 | "github.com/1340691923/xwl_bi/engine/logs" 8 | "github.com/1340691923/xwl_bi/model" 9 | "github.com/1340691923/xwl_bi/platform-basic-libs/jwt" 10 | "github.com/1340691923/xwl_bi/platform-basic-libs/util" 11 | "go.uber.org/zap" 12 | "time" 13 | ) 14 | 15 | // GmUserService 16 | type GmUserService struct { 17 | } 18 | 19 | func (this GmUserService) CheckLogin(username, password string) (token string, err error) { 20 | var model2 model.GmUserModel 21 | model2.Password = password 22 | model2.Username = username 23 | gmUser, err := model2.GetUserByUP() 24 | 25 | if err != nil { 26 | logs.Logger.Error("登陆失败", zap.Error(err)) 27 | err = errors.New("用户验证失败") 28 | return 29 | } 30 | 31 | if gmUser.IsDel == 1 { 32 | err = errors.New("您的账号已被封禁") 33 | return 34 | } 35 | 36 | db.SqlBuilder. 37 | Update("gm_user"). 38 | SetMap(map[string]interface{}{"last_login_time": time.Now().Format(util.TimeFormat)}). 39 | Where(db.Eq{"id": gmUser.ID}). 40 | RunWith(db.Sqlx). 41 | Exec() 42 | 43 | token, err = jwt.GenerateToken(gmUser) 44 | if err != nil { 45 | return 46 | } 47 | return 48 | } 49 | 50 | func (this GmUserService) GetRoleInfo(roleId int32) (gminfo model.GmRoleModel, err error) { 51 | var model2 model.GmRoleModel 52 | gminfo, err = model2.GetById(int(roleId)) 53 | if err != nil { 54 | return 55 | } 56 | return 57 | } 58 | 59 | func (this GmUserService) IsExitUser(claims *jwt.Claims) bool { 60 | var model2 model.GmUserModel 61 | model2.Username = claims.Username 62 | model2.RoleId = claims.RoleId 63 | return model2.Exsit() 64 | } 65 | -------------------------------------------------------------------------------- /platform-basic-libs/service/myapp/redis.go: -------------------------------------------------------------------------------- 1 | package myapp 2 | 3 | import ( 4 | "fmt" 5 | "github.com/1340691923/xwl_bi/engine/db" 6 | "github.com/1340691923/xwl_bi/engine/logs" 7 | "github.com/garyburd/redigo/redis" 8 | "go.uber.org/zap" 9 | ) 10 | 11 | const AppidToTableidHash = "AppidToTableid" 12 | 13 | func SetAppidToTableid(appid, appkey string, tableID int) (err error) { 14 | conn := db.RedisPool.Get() 15 | defer conn.Close() 16 | _, err = conn.Do("hset", AppidToTableidHash, fmt.Sprintf("%s_xwl_%s", appid, appkey), tableID) 17 | if err != nil { 18 | logs.Logger.Error("SetAppidToTableid err", zap.Error(err)) 19 | } 20 | return 21 | } 22 | 23 | func GetAppidToTableid(conn redis.Conn, key string) (tableID string, err error) { 24 | tableID, err = redis.String(conn.Do("hget", AppidToTableidHash, key)) 25 | return 26 | } 27 | 28 | func DeleteAppidToTableid(appid, appkey string) (err error) { 29 | conn := db.RedisPool.Get() 30 | defer conn.Close() 31 | _, err = conn.Do("hdel", AppidToTableidHash, fmt.Sprintf("%s_xwl_%s", appid, appkey)) 32 | if err != nil { 33 | logs.Logger.Error("DeleteAppidToTableid", zap.Error(err)) 34 | } 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /platform-basic-libs/service/myapp/utils.go: -------------------------------------------------------------------------------- 1 | package myapp 2 | 3 | import ( 4 | "fmt" 5 | "github.com/1340691923/xwl_bi/engine/db" 6 | "github.com/1340691923/xwl_bi/model" 7 | "github.com/1340691923/xwl_bi/platform-basic-libs/jwt" 8 | ) 9 | 10 | func GetAppidsByToken(token string) (list []model.App, err error) { 11 | c, _ := jwt.ParseToken(token) 12 | 13 | selectBuilder := db.SqlBuilder. 14 | Select("id,app_name"). 15 | From("app") 16 | 17 | if c.UserID != 1 { 18 | selectBuilder = selectBuilder.Where(fmt.Sprintf("FIND_IN_SET(%v,app_manager)", c.UserID)).Where(db.Eq{"is_close": 0}) 19 | } 20 | 21 | sql, args, err := selectBuilder.ToSql() 22 | 23 | if err != nil { 24 | return 25 | } 26 | 27 | err = db.Sqlx.Select(&list, sql, args...) 28 | if err != nil { 29 | return 30 | } 31 | 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /platform-basic-libs/service/report/Exception.go: -------------------------------------------------------------------------------- 1 | package report 2 | 3 | // 内置异常 4 | const ( 5 | ServerErr int = 10001 6 | AppParmasErr int = 10002 7 | ReportTypeErr int = 10003 8 | ) 9 | 10 | // 内置异常表 TOKEN_ERROR 11 | var ERROR_TABLE = map[int]string{ 12 | ServerErr: "服务异常", 13 | AppParmasErr: "appid错误或者appkey错误", 14 | ReportTypeErr: "上报类型错误", 15 | } 16 | -------------------------------------------------------------------------------- /platform-basic-libs/sinker/model/metric.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type Metric interface { 8 | GetInt(key string, nullable bool) (val interface{}) 9 | GetFloat(key string, nullable bool) (val interface{}) 10 | GetString(key string, nullable bool) (val interface{}) 11 | GetDateTime(key string, nullable bool) (val interface{}) 12 | GetElasticDateTime(key string, nullable bool) (val interface{}) 13 | GetArray(key string, t int) (val interface{}) 14 | GetNewKeys(knownKeys *sync.Map, newKeys *sync.Map) bool 15 | } 16 | 17 | type DimMetrics struct { 18 | Dims []*ColumnWithType 19 | Fields []*ColumnWithType 20 | } 21 | 22 | type ColumnWithType struct { 23 | Name string 24 | Type int 25 | Nullable bool 26 | SourceName string 27 | } 28 | -------------------------------------------------------------------------------- /platform-basic-libs/sinker/model/topic.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ReportEventProperties = "reportEvent" 4 | const ReportUserProperties = "reportUser" 5 | -------------------------------------------------------------------------------- /platform-basic-libs/util/config.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | // LoadJSONConfig 读取配置文件 json格式 11 | func LoadJSONConfig(filename string, v interface{}) error { 12 | b, err := ioutil.ReadFile(filename) 13 | if err != nil { 14 | return err 15 | } 16 | err = json.Unmarshal(b, v) 17 | if err != nil { 18 | return err 19 | } 20 | return nil 21 | } 22 | 23 | func JoinInt(s []int, sp string) string { 24 | var tmp = make([]string, 0, len(s)) 25 | for i, _ := range s { 26 | tmp = append(tmp, strconv.Itoa(s[i])) 27 | } 28 | return strings.Join(tmp, sp) 29 | } 30 | -------------------------------------------------------------------------------- /platform-basic-libs/util/convert.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import jsoniter "github.com/json-iterator/go" 4 | 5 | func Model2Map(m interface{}, needZeroByInt, needZeroByString bool) (res map[string]interface{}) { 6 | res = map[string]interface{}{} 7 | var json = jsoniter.ConfigCompatibleWithStandardLibrary 8 | b, _ := json.Marshal(m) 9 | json.Unmarshal(b, &res) 10 | for k, v := range res { 11 | switch v.(type) { 12 | case float64: 13 | if v.(float64) == 0 && !needZeroByInt { 14 | delete(res, k) 15 | } 16 | case int64: 17 | if v.(int64) == 0 && !needZeroByInt { 18 | delete(res, k) 19 | } 20 | case int: 21 | if v.(int) == 0 && !needZeroByInt { 22 | delete(res, k) 23 | } 24 | case string: 25 | if v.(string) == "" && !needZeroByString { 26 | delete(res, k) 27 | } 28 | } 29 | } 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /platform-basic-libs/util/datatype.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "sync" 4 | 5 | type Set struct { 6 | m map[interface{}]bool 7 | sync.RWMutex 8 | } 9 | 10 | func NewSet() *Set { 11 | return &Set{ 12 | m: map[interface{}]bool{}, 13 | } 14 | } 15 | 16 | func (s *Set) Add(item interface{}) { 17 | //写锁 18 | s.Lock() 19 | defer s.Unlock() 20 | s.m[item] = true 21 | } 22 | 23 | func (s *Set) Remove(item interface{}) { 24 | //写锁 25 | s.Lock() 26 | defer s.Unlock() 27 | delete(s.m, item) 28 | } 29 | 30 | func (s *Set) Has(item interface{}) bool { 31 | //允许读 32 | s.RLock() 33 | defer s.RUnlock() 34 | _, ok := s.m[item] 35 | return ok 36 | } 37 | 38 | func (s *Set) List() []interface{} { 39 | //允许读 40 | s.RLock() 41 | defer s.RUnlock() 42 | var outList []interface{} 43 | for value := range s.m { 44 | outList = append(outList, value) 45 | } 46 | return outList 47 | } 48 | 49 | func (s *Set) Len() int { 50 | return len(s.List()) 51 | } 52 | 53 | func (s *Set) Clear() { 54 | s.Lock() 55 | defer s.Unlock() 56 | s.m = map[interface{}]bool{} 57 | } 58 | 59 | func (s *Set) IsEmpty() bool { 60 | if s.Len() == 0 { 61 | return true 62 | } 63 | return false 64 | } 65 | -------------------------------------------------------------------------------- /platform-basic-libs/util/dir.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | ) 9 | 10 | func substr(s string, pos, length int) string { 11 | runes := []rune(s) 12 | l := pos + length 13 | if l > len(runes) { 14 | l = len(runes) 15 | } 16 | return string(runes[pos:l]) 17 | } 18 | 19 | func GetParentDirectory(dirctory string) string { 20 | return substr(dirctory, 0, strings.LastIndex(dirctory, "/")) 21 | } 22 | 23 | func GetCurrentDirectory() string { 24 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | return strings.Replace(dir, "\\", "/", -1) 29 | } 30 | -------------------------------------------------------------------------------- /platform-basic-libs/util/errors.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "database/sql" 5 | "strings" 6 | 7 | "github.com/garyburd/redigo/redis" 8 | ) 9 | 10 | func FilterMysqlNilErr(err error) bool { 11 | if err != nil && err != sql.ErrNoRows { 12 | return true 13 | } 14 | return false 15 | } 16 | 17 | func IsMysqlRepeatError(err error) bool { 18 | if err != nil && strings.Contains(err.Error(), "Error 1062") { 19 | return true 20 | } 21 | return false 22 | } 23 | 24 | func FilterRedisNilErr(err error) bool { 25 | if err != nil && err != redis.ErrNil { 26 | return true 27 | } 28 | return false 29 | } 30 | -------------------------------------------------------------------------------- /platform-basic-libs/util/exec.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "log" 5 | "os/exec" 6 | "runtime" 7 | "syscall" 8 | ) 9 | 10 | func OpenWinBrowser(uri string) error { 11 | switch runtime.GOOS { 12 | case "windows": 13 | cmd := exec.Command(`cmd`, `/c`, `start`, uri) 14 | cmd.SysProcAttr = &syscall.SysProcAttr{} 15 | err := cmd.Start() 16 | if err != nil { 17 | log.Println(err) 18 | return err 19 | } 20 | } 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /platform-basic-libs/util/gzip.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "io/ioutil" 7 | ) 8 | 9 | func GzipCompressByte(data []byte) ([]byte, error) { 10 | buf := bytes.NewBuffer(nil) 11 | gzW := gzip.NewWriter(buf) 12 | _, err := gzW.Write(data) 13 | if err != nil { 14 | return nil, err 15 | } 16 | gzW.Close() 17 | return buf.Bytes(), err 18 | } 19 | 20 | func GzipCompress(data string) ([]byte, error) { 21 | buf := bytes.NewBuffer(nil) 22 | gzW := gzip.NewWriter(buf) 23 | _, err := gzW.Write(Str2bytes(data)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | gzW.Close() 28 | return buf.Bytes(), err 29 | } 30 | 31 | func GzipUnCompress(data []byte) (string, error) { 32 | gzR, err := gzip.NewReader(bytes.NewReader(data)) 33 | if err != nil { 34 | return "", err 35 | } 36 | b, err := ioutil.ReadAll(gzR) 37 | return Bytes2str(b), err 38 | } 39 | 40 | func GzipUnCompressByte(data []byte) ([]byte, error) { 41 | gzR, err := gzip.NewReader(bytes.NewReader(data)) 42 | if err != nil { 43 | return nil, err 44 | } 45 | b, err := ioutil.ReadAll(gzR) 46 | return b, err 47 | } 48 | -------------------------------------------------------------------------------- /platform-basic-libs/util/interface.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "reflect" 4 | 5 | // interface{}转为 []interface{} 6 | func CreateAnyTypeSlice(slice interface{}) ([]interface{}, bool) { 7 | val, ok := isSlice(slice) 8 | 9 | if !ok { 10 | return nil, false 11 | } 12 | 13 | sliceLen := val.Len() 14 | 15 | out := make([]interface{}, sliceLen) 16 | 17 | for i := 0; i < sliceLen; i++ { 18 | out[i] = val.Index(i).Interface() 19 | } 20 | 21 | return out, true 22 | } 23 | 24 | // 判断是否为slcie数据 25 | func isSlice(arg interface{}) (val reflect.Value, ok bool) { 26 | val = reflect.ValueOf(arg) 27 | 28 | if val.Kind() == reflect.Slice { 29 | ok = true 30 | } 31 | 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /platform-basic-libs/util/json.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | jsoniter "github.com/json-iterator/go" 5 | ) 6 | 7 | func IsJson(str string) bool { 8 | maps := make(map[string]interface{}) 9 | var json = jsoniter.ConfigCompatibleWithStandardLibrary 10 | err := json.Unmarshal(Str2bytes(str), &maps) 11 | if err != nil { 12 | return false 13 | } 14 | return true 15 | } 16 | -------------------------------------------------------------------------------- /platform-basic-libs/util/t_util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "time" 6 | ) 7 | 8 | type Tutil struct { 9 | startT time.Time 10 | tag string 11 | logFloag bool 12 | logger *zap.Logger 13 | } 14 | 15 | func NewTutil(tagP string, logFloag bool, logger *zap.Logger) *Tutil { 16 | return &Tutil{startT: time.Now(), tag: tagP, logFloag: logFloag, logger: logger} 17 | } 18 | 19 | func (this *Tutil) EndT(tagC string, haveNext ...bool) { 20 | if len(haveNext) == 0 { 21 | this.startT = time.Now() 22 | } else { 23 | if this.logFloag { 24 | this.logger.Sugar().Infof("%s(%s):lost time:%v", this.tag, tagC, time.Now().Sub(this.startT).String()) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /platform-basic-libs/util/time.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "time" 4 | 5 | const ( 6 | TimeFormat = "2006-01-02 15:04:05" 7 | TimeFormatDay = "20060102" 8 | TimeFormatDay2 = "2006-01-02" 9 | TimeFormatDay3 = "2006/01/02" 10 | TimeFormatDay4 = "2006.01.02_15" 11 | ) 12 | 13 | /** 14 | * 二个时间戳是否同一天 15 | * @return true 是 false 不是今天 16 | */ 17 | func IsSameDay(oldDay, anotherDay int64) bool { 18 | tm := time.Unix(oldDay, 0) 19 | tmAnother := time.Unix(anotherDay, 0) 20 | if tm.Format(TimeFormatDay2) == tmAnother.Format(TimeFormatDay2) { 21 | return true 22 | } 23 | return false 24 | } 25 | 26 | /**字符串->时间对象*/ 27 | func Str2Time(formatTimeStr, timeFormat string) time.Time { 28 | loc, _ := time.LoadLocation("Local") 29 | theTime, _ := time.ParseInLocation(timeFormat, formatTimeStr, loc) //使用模板在对应时区转化为time.time类型 30 | return theTime 31 | } 32 | -------------------------------------------------------------------------------- /platform-basic-libs/util/token.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "github.com/sony/sonyflake" 5 | "log" 6 | "strconv" 7 | "sync" 8 | ) 9 | 10 | var TokenBucket sync.Map 11 | 12 | func GetUUid() string { 13 | flake := sonyflake.NewSonyflake(sonyflake.Settings{}) 14 | id, err := flake.NextID() 15 | if err != nil { 16 | log.Println("err", err) 17 | } 18 | return strconv.Itoa(int(id)) 19 | } 20 | -------------------------------------------------------------------------------- /report_start.bat: -------------------------------------------------------------------------------- 1 | set dir = %cd% 2 | 3 | set args = "-configFileDir=%cd%\config" 4 | 5 | gowatch -p cmd/report_server/main.go -args=args -o bin/win/report_server.exe -------------------------------------------------------------------------------- /router/app.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | . "github.com/1340691923/xwl_bi/controller" 5 | "github.com/1340691923/xwl_bi/middleware" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/api_config" 7 | "github.com/gofiber/fiber/v2" 8 | ) 9 | 10 | func runApp(app *fiber.App) { 11 | apiRouterConfig := api_config.NewApiRouterConfig() 12 | const AbsolutePath = "/api/app" 13 | appG := app.Group(AbsolutePath) 14 | { 15 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "查询应用列表", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.List) 16 | 17 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "获取应用下拉选", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.Config) 18 | 19 | appG = appG.Use(middleware.OperaterLog) 20 | 21 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "创建应用", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.Create) 22 | 23 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "重置秘钥", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.ResetAppkey) 24 | 25 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "修改应用成员", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.UpdateManager) 26 | 27 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "修改应用状态", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), AppController{}.StatusAction) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /router/index.go: -------------------------------------------------------------------------------- 1 | //路由层 2 | package router 3 | 4 | import ( 5 | . "github.com/1340691923/xwl_bi/controller" 6 | . "github.com/1340691923/xwl_bi/middleware" 7 | "github.com/1340691923/xwl_bi/views" 8 | . "github.com/gofiber/fiber/v2" 9 | "github.com/gofiber/fiber/v2/middleware/compress" 10 | "github.com/gofiber/fiber/v2/middleware/cors" 11 | "github.com/gofiber/fiber/v2/middleware/filesystem" 12 | "github.com/gofiber/fiber/v2/middleware/pprof" 13 | jsoniter "github.com/json-iterator/go" 14 | ) 15 | 16 | func Init() *App { 17 | var json = jsoniter.ConfigCompatibleWithStandardLibrary 18 | app := New(Config{ 19 | AppName: "铸龙-BI", 20 | JSONDecoder: json.Unmarshal, 21 | JSONEncoder: json.Marshal, 22 | }) 23 | 24 | app.Use(compress.New(compress.Config{ 25 | Level: compress.LevelBestCompression, 26 | })) 27 | 28 | app.Use("/", filesystem.New(filesystem.Config{ 29 | Root: views.GetFileSystem(), 30 | })) 31 | 32 | app.Use( 33 | cors.New(), 34 | pprof.New(), 35 | ) 36 | 37 | app.Post("/api/gm_user/login", ManagerUserController{}.Login) 38 | routerWebsocket(app) 39 | app.Use( 40 | Timer, 41 | JwtMiddleware, 42 | Rbac, 43 | ) 44 | 45 | return runRouterGroupFn( 46 | app, 47 | runOperaterLog, 48 | runGmUser, 49 | runRealData, 50 | runMetaData, 51 | runAnalysis, 52 | runPannel, 53 | runApp, 54 | runUserGroup, 55 | ) 56 | } 57 | 58 | type routerGroupFn func(app *App) 59 | 60 | func runRouterGroupFn(app *App, fns ...routerGroupFn) *App { 61 | for _, fn := range fns { 62 | fn(app) 63 | } 64 | return app 65 | } 66 | -------------------------------------------------------------------------------- /router/operater_log.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | . "github.com/1340691923/xwl_bi/controller" 5 | "github.com/1340691923/xwl_bi/platform-basic-libs/api_config" 6 | "github.com/gofiber/fiber/v2" 7 | ) 8 | 9 | func runOperaterLog(app *fiber.App) { 10 | apiRouterConfig := api_config.NewApiRouterConfig() 11 | const AbsolutePath = "/api/operater_log" 12 | appG := app.Group(AbsolutePath) 13 | { 14 | apiRouterConfig.MountApi(api_config.MountApiBasePramas{Remark: "查看后台操作日志", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), GmOperaterController{}.ListAction) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /router/user_group.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | . "github.com/1340691923/xwl_bi/controller" 5 | "github.com/1340691923/xwl_bi/middleware" 6 | "github.com/1340691923/xwl_bi/platform-basic-libs/api_config" 7 | "github.com/gofiber/fiber/v2" 8 | ) 9 | 10 | func runUserGroup(app *fiber.App) { 11 | c := api_config.NewApiRouterConfig() 12 | const AbsolutePath = "/api/user_group" 13 | appG := app.Group(AbsolutePath).Use(middleware.FilterAppid) 14 | { 15 | 16 | appG = appG.Use(middleware.OperaterLog) 17 | 18 | c.MountApi(api_config.MountApiBasePramas{Remark: "新增用户分群", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), UserGroupController{}.AddUserGroup) 19 | 20 | c.MountApi(api_config.MountApiBasePramas{Remark: "修改用户分群", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), UserGroupController{}.ModifyUserGroup) 21 | 22 | c.MountApi(api_config.MountApiBasePramas{Remark: "删除用户分群", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), UserGroupController{}.DeleteUserGroup) 23 | 24 | c.MountApi(api_config.MountApiBasePramas{Remark: "用户分群列表", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), UserGroupController{}.UserGroupList) 25 | 26 | c.MountApi(api_config.MountApiBasePramas{Remark: "用户分群下拉选", AbsolutePath: AbsolutePath}, appG.(*fiber.Group), UserGroupController{}.UserGroupSelect) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /router/ws.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | . "github.com/1340691923/xwl_bi/controller" 5 | "github.com/gofiber/fiber/v2" 6 | "github.com/gofiber/websocket/v2" 7 | ) 8 | 9 | func routerWebsocket(app *fiber.App) { 10 | app.Use("/ws", func(c *fiber.Ctx) error { 11 | 12 | if websocket.IsWebSocketUpgrade(c) { 13 | c.Locals("allowed", true) 14 | return c.Next() 15 | } 16 | return fiber.ErrUpgradeRequired 17 | }) 18 | 19 | app.Get("/ws", websocket.New(DebugDataWs)) 20 | } 21 | -------------------------------------------------------------------------------- /sdk/cocos-creator/Hello.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | import { _decorator, Component, Node } from 'cc'; 4 | const { ccclass, property } = _decorator; 5 | 6 | 7 | @ccclass('Hello') 8 | export class Hello extends Component { 9 | 10 | start () { 11 | 12 | let parmas = {"appid":"389261007232434486","appkey":"a3f2b1db196e60f2f627358b429d52d7"} 13 | 14 | var foo = new report.EventReport("http://127.0.0.1:8091", parmas["appid"], parmas["appkey"], 0) 15 | 16 | foo.track("test",{}) 17 | 18 | } 19 | 20 | } 21 | */ 22 | -------------------------------------------------------------------------------- /sdk/cocos-creator/report.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace report { 2 | 3 | export class EventReport { 4 | 5 | constructor(serverUrl: string, appid: string, appkey: string, debug: number); 6 | 7 | public identify(uuid :string): void; 8 | 9 | public login(uid :string): void; 10 | 11 | public logout(): void; 12 | 13 | public getDistinctId():string; 14 | 15 | public track(eventName :string,properties :any): void; 16 | 17 | public userSet(properties :any):EventReport; 18 | 19 | public userUnset(key :string):void; 20 | 21 | public userAdd(properties :any):void; 22 | 23 | public userSetOnce(properties :any):void; 24 | 25 | public getSuperProperties():any; 26 | 27 | public getUserProperties():any; 28 | 29 | public setSuperProperties(properties :any):void; 30 | 31 | public unsetSuperProperties(key :string):void; 32 | 33 | public clearSuperProperties():void; 34 | 35 | public getUserProperties():any; 36 | 37 | public trackUserData():void; 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /sdk/egert/report.d.ts: -------------------------------------------------------------------------------- 1 | declare class EventReport { 2 | 3 | constructor(serverUrl: string, appid: string, appkey: string, debug: number); 4 | 5 | public identify(uuid :string): void; 6 | 7 | public login(uid :string): void; 8 | 9 | public logout(): void; 10 | 11 | public track(eventName :string,properties :any): void; 12 | 13 | public userSet(properties :any):EventReport; 14 | 15 | public userUnset(key :string):void; 16 | 17 | public getDistinctId():string; 18 | 19 | public userAdd(properties :any):void; 20 | 21 | public userSetOnce(properties :any):void; 22 | 23 | public getSuperProperties():any; 24 | 25 | public getUserProperties():any; 26 | 27 | public setSuperProperties(properties :any):void; 28 | 29 | public unsetSuperProperties(key :string):void; 30 | 31 | public clearSuperProperties():void; 32 | 33 | public getUserProperties():any; 34 | 35 | public trackUserData():void; 36 | } 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /sinker_start.bat: -------------------------------------------------------------------------------- 1 | set dir = %cd% 2 | 3 | set args = "-configFileDir=%cd%\config" 4 | 5 | gowatch -p cmd/sinker/main.go -args=args -o bin/win/sinker.exe -------------------------------------------------------------------------------- /views/fs.go: -------------------------------------------------------------------------------- 1 | package views 2 | 3 | import ( 4 | "embed" 5 | "io/fs" 6 | "net/http" 7 | ) 8 | 9 | //go:embed dist 10 | var StatisFs embed.FS 11 | 12 | func GetFileSystem() http.FileSystem { 13 | fsys, err := fs.Sub(StatisFs, "dist") 14 | if err != nil { 15 | panic(err) 16 | } 17 | return http.FS(fsys) 18 | } 19 | -------------------------------------------------------------------------------- /vue/.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /vue/.env.development: -------------------------------------------------------------------------------- 1 | # just a flag 2 | ENV = 'development' 3 | 4 | # base api 5 | # 开发环境 6 | VUE_APP_BASE_API = 'http://localhost:8090/' 7 | VUE_APP_BASE_TITLE = '铸龙-埋点数据分析平台(开发)' 8 | # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable, 9 | # to control whether the babel-plugin-dynamic-import-node plugin is enabled. 10 | # It only does one thing by converting all import() to require(). 11 | # This configuration can significantly increase the speed of hot updates, 12 | # when you have a large number of pages. 13 | # Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js 14 | 15 | VUE_CLI_BABEL_TRANSPILE_MODULES = true 16 | 17 | -------------------------------------------------------------------------------- /vue/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | 3 | # just a flag 4 | ENV = 'staging' 5 | 6 | # base api 7 | # 生产环境 8 | VUE_APP_BASE_API = '' 9 | VUE_APP_BASE_TITLE = '铸龙-埋点数据分析平台' 10 | -------------------------------------------------------------------------------- /vue/.env.staging: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | 3 | # just a flag 4 | ENV = 'staging' 5 | 6 | # base api 7 | # 测试环境 8 | VUE_APP_BASE_API = '' 9 | VUE_APP_BASE_TITLE = '铸龙-埋点数据分析平台(测试)' 10 | 11 | -------------------------------------------------------------------------------- /vue/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | src/assets 3 | public 4 | dist 5 | -------------------------------------------------------------------------------- /vue/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 10 3 | script: npm run test 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /vue/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present PanJiaChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /vue/build/index.js: -------------------------------------------------------------------------------- 1 | const { run } = require('runjs') 2 | const chalk = require('chalk') 3 | const config = require('../vue.config.js') 4 | const rawArgv = process.argv.slice(2) 5 | const args = rawArgv.join(' ') 6 | 7 | if (process.env.npm_config_preview || rawArgv.includes('--preview')) { 8 | const report = rawArgv.includes('--report') 9 | 10 | run(`vue-cli-service build ${args}`) 11 | 12 | const port = 9526 13 | const publicPath = config.publicPath 14 | 15 | var connect = require('connect') 16 | var serveStatic = require('serve-static') 17 | const app = connect() 18 | 19 | app.use( 20 | publicPath, 21 | serveStatic('./dist', { 22 | index: ['index.html', '/'] 23 | }) 24 | ) 25 | 26 | app.listen(port, function () { 27 | console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) 28 | if (report) { 29 | console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) 30 | } 31 | 32 | }) 33 | } else { 34 | run(`vue-cli-service build ${args}`) 35 | } 36 | -------------------------------------------------------------------------------- /vue/debug.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1340691923/xwl_bi/9337120b09f855a22c4c5a4e78b84436ef37dc30/vue/debug.log -------------------------------------------------------------------------------- /vue/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest', 5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 6 | 'jest-transform-stub', 7 | '^.+\\.jsx?$': 'babel-jest' 8 | }, 9 | moduleNameMapper: { 10 | '^@/(.*)$': '/src/$1' 11 | }, 12 | snapshotSerializers: ['jest-serializer-vue'], 13 | testMatch: [ 14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 15 | ], 16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], 17 | coverageDirectory: '/tests/unit/coverage', 18 | // 'collectCoverage': true, 19 | 'coverageReporters': [ 20 | 'lcov', 21 | 'text-summary' 22 | ], 23 | testURL: 'http://localhost/' 24 | } 25 | -------------------------------------------------------------------------------- /vue/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["src/*"] 6 | } 7 | }, 8 | "exclude": ["node_modules", "dist"] 9 | } -------------------------------------------------------------------------------- /vue/mock/remote-search.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | 3 | const NameList = [] 4 | const count = 100 5 | 6 | for (let i = 0; i < count; i++) { 7 | NameList.push(Mock.mock({ 8 | name: '@first' 9 | })) 10 | } 11 | NameList.push({ name: 'mock-Pan' }) 12 | 13 | export default [ 14 | // username search 15 | { 16 | url: '/search/user', 17 | type: 'get', 18 | response: config => { 19 | const { name } = config.query 20 | const mockNameList = NameList.filter(item => { 21 | const lowerCaseName = item.name.toLowerCase() 22 | return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) 23 | }) 24 | return { 25 | code: 20000, 26 | data: { items: mockNameList } 27 | } 28 | } 29 | }, 30 | 31 | // transaction list 32 | { 33 | url: '/transaction/list', 34 | type: 'get', 35 | response: _ => { 36 | return { 37 | code: 20000, 38 | data: { 39 | total: 20, 40 | 'items|20': [{ 41 | order_no: '@guid()', 42 | timestamp: +Mock.Random.date('T'), 43 | username: '@name()', 44 | price: '@float(1000, 15000, 0, 2)', 45 | 'status|1': ['success', 'pending'] 46 | }] 47 | } 48 | } 49 | } 50 | } 51 | ] 52 | -------------------------------------------------------------------------------- /vue/plop-templates/component/index.hbs: -------------------------------------------------------------------------------- 1 | {{#if template}} 2 | 5 | {{/if}} 6 | 7 | {{#if script}} 8 | 20 | {{/if}} 21 | 22 | {{#if style}} 23 | 26 | {{/if}} 27 | -------------------------------------------------------------------------------- /vue/plop-templates/component/prompt.js: -------------------------------------------------------------------------------- 1 | const { notEmpty } = require('../utils.js') 2 | 3 | module.exports = { 4 | description: 'generate vue component', 5 | prompts: [{ 6 | type: 'input', 7 | name: 'name', 8 | message: 'component name please', 9 | validate: notEmpty('name') 10 | }, 11 | { 12 | type: 'checkbox', 13 | name: 'blocks', 14 | message: 'Blocks:', 15 | choices: [{ 16 | name: '