diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1fbf887 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* linguist-language=GO \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24dd65d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +.buildpath +.hgignore.swp +.project +.orig +.swp +.idea/ +.settings/ +.vscode/ +vendor/ +composer.lock +gitpush.sh +bin/ +cbuild +**/.DS_Store +.test/ +main +output/ +manifest/output/ +temp/ +resource/log/ +#resource/public/ +logs/ +upload/product_icon/ +config.yaml +extend/log/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..378d7b0 --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +ROOT_DIR = $(shell pwd) +NAMESPACE = "default" +DEPLOY_NAME = "focus-single" +DOCKER_NAME = "focus-single" + +# Install/Update to the latest CLI tool. +.PHONY: cli +cli: + @set -e; \ + wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \ + chmod +x gf && \ + ./gf install -y && \ + rm ./gf + + +# Check and install CLI tool. +.PHONY: cli.install +cli.install: + @set -e; \ + gf -v > /dev/null 2>&1 || if [[ $? -neq 0 ]]; then \ + echo "GoFame CLI is not installed, start proceeding auto installation..."; \ + make cli; \ + fi; + + +# Generate Go files for DAO/DO/Entity. +.PHONY: dao +dao: cli.install + @gf gen dao + + + +# Build image, deploy image and yaml to current kubectl environment and make port forward to local machine. +.PHONY: start +start: + @set -e; \ + make image; \ + make deploy; \ + make port; + +# Build docker image. +.PHONY: image +image: cli.install + $(eval _TAG = $(if ${TAG}, ${TAG}, latest)) + $(eval _PUSH = $(if ${PUSH}, ${PUSH}, )) + @gf docker -p -b "-a amd64 -s linux -p temp" -t $(DOCKER_NAME):${_TAG}; + + +# Build docker image and automatically push to docker repo. +.PHONY: image.push +image.push: + @make image PUSH=-p; + + +# Deploy image and yaml to current kubectl environment. +.PHONY: deploy +deploy: + $(eval _ENV = $(if ${ENV}, ${ENV}, develop-tke)) + + @set -e; \ + mkdir -p $(ROOT_DIR)/temp/kustomize;\ + cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\ + kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\ + kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \ + kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; + + diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..786be46 --- /dev/null +++ b/README.MD @@ -0,0 +1,193 @@ +Sagoo IOT +======== + +SagooIOT是一个基于golang开发的轻量级的物联网平台。支持跨平台的物联网接入及管理方案,平台实现了物联网开发相关的基础功能,基于该功能可以快速的搭建起一整套的IOT相关的业务系统。 + + + + +## 平台简介 +* 基于全新Go Frame 2.0+Vue3+Element Plus开发的全栈前后端分离的管理系统 +* 前端采用vue-next-admin 、Vue、Element UI。 + + + +## 特征 +* 高生产率:几分钟即可搭建一个后台管理系统 +* 模块化:单应用多系统的模式,将一个完整的应用拆分为多个系统,后续扩展更加便捷,增加代码复用性。 +* 认证机制:采用gtoken的用户状态认证及casbin的权限认证 +* 路由模式:得利于goframe2.0提供了规范化的路由注册方式,无需注解自动生成api文档 +* 面向接口开发 +* 支持物模型,多产品、多设备接入管理。 +* 屏蔽网络协议的复杂性,适配多种接入协议(TCP,MQTT,UDP,CoAP,HTTP,GRPC,RPC等),灵活接入不同厂家的不同设备。 +* 支持跨平台运行,可快速实现边缘计算功能,实现离线自动预警,自动执行等相关功能。 +* 支持跨终端展示,可以通过PC,手机,平板等进行设备状态的监控和数据展示 +* 独特的插件系统,支持跨语言接入,可以通过C/C++,Python编写的插件进行快速接入。 +* 插件系统支持热插拔,支持Modbus tcp,modbus rtu,modbus ascii,iec61850,opc等数据采集协议 + + +## 内置功能 + +1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +3. 岗位管理:配置系统用户所属担任职务。 +4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 +5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +7. 参数管理:对系统动态配置常用参数。 +8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +9. 登录日志:系统登录日志记录查询包含登录异常。 +10. 在线用户:当前系统中活跃用户状态监控。 +11. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 +12. 代码生成:前后端代码的生成。 +13. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 +14. 文件上传,缓存标签等。 +15. 产品管理:对设备类产品进行统一管理 +16. 设备管理:对设备进行接入与数据配置管理 +17. 数据中心:对第三方api或是数据库及内部数据进行数据新建模管理,支持规则定义。 + + +## 环境需求 + +**操作系统** + +Linux / macOS /Win + +**Go 编译环境** + +依赖 `Go1.16+` 编译环境,可前往[官方网站](https://golang.org/dl/) 或 [国内镜像](https://golang.google.cn/dl/) 下载安装。 + +**MySQL** + +MySQL 5.6+ + + + +## 技术栈 + +开发语言:golang + +服务端基础架构:[GoFrame](https://github.com/gogf/gf) 【 [中文文档](https://goframe.org/index) 】 + +前端框架 [vue-next-admin](https://gitee.com/lyt-top/vue-next-admin)【[中文文档](https://lyt-top.gitee.io/vue-next-admin-doc-preview/)】 + +swaggo https://github.com/swaggo/swag + +gtoken https://github.com/goflyfox/gtoken + +casbin https://github.com/casbin/casbin + +## 工程目录 + +``` +/ +├── api +├── hack +├── internal +│ ├── cmd +│ ├── consts +│ ├── controller +│ ├── dao +│ ├── logic +│ ├── model +│ | ├── do +│ │ └── entity +│ └── service +├── manifest +├── resource +├── utility +├── go.mod +└── main.go + +``` + +| 目录/文件名称 | 说明 | 描述 | +| :-------------- | :------- | :----------------------------------------------------------- | +| `api` | 对外接口 | 对外提供服务的输入/输出数据结构定义。考虑到版本管理需要,往往以`api/v1...`存在。 | +| `hack` | 工具脚本 | 存放项目开发工具、脚本等内容。例如,`CLI`工具的配置,各种`shell/bat`脚本等文件。 | +| `internal` | 内部逻辑 | 业务逻辑存放目录。通过`Golang internal`特性对外部隐藏可见性。 | +| ` - cmd` | 入口指令 | 命令行管理目录。可以管理维护多个命令行。 | +| ` - consts` | 常量定义 | 项目所有常量定义。 | +| ` - controller` | 接口处理 | 接收/解析用户输入参数的入口/接口层。 | +| ` - dao` | 数据访问 | 数据访问对象,这是一层抽象对象,用于和底层数据库交互,仅包含最基础的 `CURD` 方法 | +| ` - logic` | 业务封装 | 业务逻辑封装管理,特定的业务逻辑实现和封装。往往是项目中最复杂的部分。 | +| ` - model` | 结构模型 | 数据结构管理模块,管理数据实体对象,以及输入与输出数据结构定义。 | +| ` - do` | 领域对象 | 用于`dao`数据操作中业务模型与实例模型转换,由工具维护,用户不能修改。 | +| ` - entity` | 数据模型 | 数据模型是模型与数据集合的一对一关系,由工具维护,用户不能修改。 | +| ` - service` | 业务接口 | 用于业务模块解耦的接口定义层。具体的接口实现在`logic`中进行注入。 | +| `manifest` | 交付清单 | 包含程序编译、部署、运行、配置的文件。常见内容如下: | +| ` - config` | 配置管理 | 配置文件存放目录。 | +| ` - docker` | 镜像文件 | `Docker`镜像相关依赖文件,脚本文件等等。 | +| ` - deploy` | 部署文件 | 部署相关的文件。默认提供了`Kubernetes`集群化部署的`Yaml`模板,通过`kustomize`管理。 | +| `resource` | 静态资源 | 静态资源文件。这些文件往往可以通过 资源打包/镜像编译 的形式注入到发布文件中。 | +| `go.mod` | 依赖管理 | 使用`Go Module`包管理的依赖描述文件。 | +| `main.go` | 入口文件 | 程序入口文件。 | + +## 本地源码运行 + +修改config下的config.toml文件,并配置相关项 + +请跟据注释进行配置修改,包括服务相关配置,日志相关 + +`go run main.go` + +## 关于build.sh编译脚本 + +可以使用build.sh进行程序编译,如果在使用build.sh脚本进行程序编译时,提示 + +``` +fatal: No names found, cannot describe anything. +./build.sh linux|windows|mac + +``` +是因为源码没有进行git版本的标签设置。 + +支持将git的tag编译到程序中。需要创建git的tag。只有创建了tag,编译的程序才会显示版本号。 + +``` +git tag v0.0.1 + +git push origin v0.0.1 +``` + +## 编译后执行脚本 + +编译后生成的可执行文件放在bin目录下,将bin目录下的文件放到目标服务器,执行`./curl.sh start` 运行即可。 + +``` +curl.sh脚本参数: + +start|stop|restart|status|tail + +``` + +分别对应 启动、停止、重启、状态、显示动态日志运行信息 + +## 插件编译 + +如果要使用插件,需要提前将插件进行编译。直接使用plugins下面的编译脚本直接执行就可以。 + + +## 其它问题 + +### 如果在macOS下遇到 Warning :`IOMasterPort`: +``` +warning: ‘IOMasterPort‘ is deprecated: first deprecated in macOS 12.0 [-Wdeprecated-declarations] +``` +**原因** + +依赖包跟MacOS的版本有兼容问题。 + +解决方案 +切换CGO编译方式 +``` +go env -w CGO_ENABLED="0" +``` + +### 如果采用HTTPS方式时SSE不工作,需要如下配置: + +```Nginx + proxy_set_header Connection ''; + proxy_http_version 1.1; + chunked_transfer_encoding off; +``` diff --git a/README.md b/README.md deleted file mode 100644 index 89f548d..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# sagooiot -SagooIOT是一个基于golang开发的开源的企业级物联网基础开发平台。负责设备管理和协议数据管理,支持跨平台的物联网接入及管理方案,平台实现了物联网开发相关的基础功能,基于该功能可以快速的搭建起一整套的IOT相关的业务系统。旨在通过可复用的组件,减少开发工作,简化和加速物联网开发交付。适配多种接入协议(TCP,MQTT,UDP,CoAP,HTTP,GRPC,RPC等) diff --git a/api/v1/alarm/alarm_level.go b/api/v1/alarm/alarm_level.go new file mode 100644 index 0000000..bcc64dd --- /dev/null +++ b/api/v1/alarm/alarm_level.go @@ -0,0 +1,20 @@ +package alarm + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type AlarmLevelReq struct { + g.Meta `path:"/level/all" method:"get" summary:"告警级别" tags:"告警"` +} +type AlarmLevelRes struct { + *model.AlarmLevelListOutput +} + +type AlarmLevelEditReq struct { + g.Meta `path:"/level/edit" method:"put" summary:"告警配置" tags:"告警"` + List []*model.AlarmLevelEditInput `json:"list" dc:"告警级别列表" v:"required#告警级别不能为空"` +} +type AlarmLevelEditRes struct{} diff --git a/api/v1/alarm/alarm_log.go b/api/v1/alarm/alarm_log.go new file mode 100644 index 0000000..e9893a2 --- /dev/null +++ b/api/v1/alarm/alarm_log.go @@ -0,0 +1,29 @@ +package alarm + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type AlarmLogDetailReq struct { + g.Meta `path:"/log/detail" method:"get" summary:"告警日志详情" tags:"告警"` + Id uint64 `json:"id" dc:"告警日志ID" v:"required#告警日志ID不能为空"` +} +type AlarmLogDetailRes struct { + Data *model.AlarmLogOutput `json:"data" dc:"告警日志详情"` +} + +type AlarmLogListReq struct { + g.Meta `path:"/log/list" method:"get" summary:"告警日志" tags:"告警"` + *model.AlarmLogListInput +} +type AlarmLogListRes struct { + *model.AlarmLogListOutput +} + +type AlarmLogHandleReq struct { + g.Meta `path:"/log/handle" method:"post" summary:"告警处理" tags:"告警"` + model.AlarmLogHandleInput +} +type AlarmLogHandleRes struct{} diff --git a/api/v1/alarm/alarm_rule.go b/api/v1/alarm/alarm_rule.go new file mode 100644 index 0000000..10191b4 --- /dev/null +++ b/api/v1/alarm/alarm_rule.go @@ -0,0 +1,76 @@ +package alarm + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type AlarmRuleListReq struct { + g.Meta `path:"/rule/list" method:"get" summary:"告警规则列表" tags:"告警"` + *model.AlarmRuleListInput +} +type AlarmRuleListRes struct { + *model.AlarmRuleListOutput +} + +type AlarmRuleAddReq struct { + g.Meta `path:"/rule/add" method:"post" summary:"新增告警规则" tags:"告警"` + *model.AlarmRuleAddInput +} +type AlarmRuleAddRes struct{} + +type AlarmRuleEditReq struct { + g.Meta `path:"/rule/edit" method:"put" summary:"编辑告警规则" tags:"告警"` + *model.AlarmRuleEditInput +} +type AlarmRuleEditRes struct{} + +type AlarmRuleDeployReq struct { + g.Meta `path:"/rule/deploy" method:"post" summary:"启用" tags:"告警"` + Id uint64 `json:"id" dc:"告警规则ID" v:"required#告警规则ID不能为空"` +} +type AlarmRuleDeployRes struct{} + +type AlarmRuleUndeployReq struct { + g.Meta `path:"/rule/undeploy" method:"post" summary:"禁用" tags:"告警"` + Id uint64 `json:"id" dc:"告警规则ID" v:"required#告警规则ID不能为空"` +} +type AlarmRuleUndeployRes struct{} + +type AlarmRuleDelReq struct { + g.Meta `path:"/rule/del" method:"delete" summary:"删除" tags:"告警"` + Id uint64 `json:"id" dc:"告警规则ID" v:"required#告警规则ID不能为空"` +} +type AlarmRuleDelRes struct{} + +type AlarmRuleDetailReq struct { + g.Meta `path:"/rule/detail" method:"get" summary:"详情" tags:"告警"` + Id uint64 `json:"id" dc:"告警规则ID" v:"required#告警规则ID不能为空"` +} +type AlarmRuleDetailRes struct { + Data *model.AlarmRuleOutput `json:"data" dc:"告警详情"` +} + +type AlarmRuleOperatorReq struct { + g.Meta `path:"/rule/operator" method:"get" summary:"操作符" tags:"告警"` +} +type AlarmRuleOperatorRes struct { + List []model.OperatorOutput `json:"list" dc:"操作符列表"` +} + +type AlarmRuleTriggerTypeReq struct { + g.Meta `path:"/rule/trigger_type" method:"get" summary:"触发类型" tags:"告警"` + ProductKey string `json:"productKey" dc:"产品标识"` +} +type AlarmRuleTriggerTypeRes struct { + List []model.TriggerTypeOutput `json:"list" dc:"触发类型列表"` +} + +type AlarmRuleTriggerParamReq struct { + g.Meta `path:"/rule/trigger_param" method:"get" summary:"触发条件参数" tags:"告警"` + ProductKey string `json:"productKey" dc:"产品标识"` +} +type AlarmRuleTriggerParamRes struct { + List []model.TriggerParamOutput `json:"list" dc:"触发条件参数列表"` +} diff --git a/api/v1/common/api.go b/api/v1/common/api.go new file mode 100644 index 0000000..63fc5a7 --- /dev/null +++ b/api/v1/common/api.go @@ -0,0 +1,14 @@ +package common + +type PaginationReq struct { + KeyWord string `json:"keyWord" dc:"搜索关键字"` //搜索关键字 + DateRange []string `p:"dateRange"` //日期范围 + OrderBy string //排序方式 + PageNum int `json:"pageNum" in:"query" d:"1" v:"min:0#分页号码错误" dc:"分页号码,默认1"` + PageSize int `json:"PageSize" in:"query" d:"10" v:"max:50#分页数量最大50条" dc:"分页数量,最大50"` +} + +type PaginationRes struct { + CurrentPage int `json:"currentPage" dc:"当前页"` + Total int `dc:"总数"` +} diff --git a/api/v1/common/base_db_link.go b/api/v1/common/base_db_link.go new file mode 100644 index 0000000..37df651 --- /dev/null +++ b/api/v1/common/base_db_link.go @@ -0,0 +1,66 @@ +package common + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type BaseDbLinkDoReq struct { + g.Meta `path:"/base/db/list" tags:"数据源管理" method:"get" summary:"数据源列表"` + Name string `p:"name" description:"数据源名称"` + Types string `p:"types" description:"驱动类型 mysql或oracle"` + Host string `p:"host" description:"主机地址"` + Port string `p:"port" description:"端口"` + UserName string `p:"user_name" description:"用户名称"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用"` + *PaginationReq +} +type BaseDbLinkDoRes struct { + Data []*model.BaseDbLinkRes + PaginationRes +} + +type AddBaseDbLinkReq struct { + g.Meta `path:"/base/db/add" tags:"数据源管理" method:"post" summary:"添加数据源"` + Name string `json:"name" description:"名称" v:"required#请输入数据源名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle" v:"required#请输入数据源驱动类型"` + Host string `json:"host" description:"主机地址" v:"required#请输入数据源主机地址"` + Port int `json:"port" description:"端口号" v:"required#请输入数据源端口号"` + UserName string `json:"userName" description:"用户名称" v:"required#请输入数据源用户名称"` + Password string `json:"password" description:"密码" v:"required#请输入数据源密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type AddBaseDbLinkRes struct { +} + +type DetailBaseDbLinkReq struct { + g.Meta `path:"/base/db/detail" tags:"数据源管理" method:"get" summary:"根据ID获取数据源详情"` + Id int `p:"id" description:"数据源ID" v:"required#ID不能为空"` +} +type DetailBaseDbLinkRes struct { + Data *model.DetailBaseDbLinkRes +} + +type EditBaseDbLinkReq struct { + g.Meta `path:"/base/db/edit" method:"put" summary:"编辑数据源" tags:"数据源管理"` + Id int `json:"id" description:"" v:"required#请输入数据源ID"` + Name string `json:"name" description:"名称" v:"required#请输入数据源名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle" v:"required#请输入数据源驱动类型"` + Host string `json:"host" description:"主机地址" v:"required#请输入数据源主机地址"` + Port int `json:"port" description:"端口号" v:"required#请输入数据源端口号"` + UserName string `json:"userName" description:"用户名称" v:"required#请输入数据源用户名称"` + Password string `json:"password" description:"密码" v:"required#请输入数据源密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type EditBaseDbLinkRes struct { +} + +type DelBaseDbLinkReq struct { + g.Meta `path:"/base/db/del" method:"delete" summary:"根据ID删除数据源" tags:"数据源管理"` + Id int `p:"id" description:"数据源ID" v:"required#ID不能为空"` +} +type DelBaseDbLinkRes struct { +} diff --git a/api/v1/common/city_data.go b/api/v1/common/city_data.go new file mode 100644 index 0000000..21906b4 --- /dev/null +++ b/api/v1/common/city_data.go @@ -0,0 +1,45 @@ +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type CityTreeReq struct { + g.Meta `path:"/city/tree" method:"get" summary:"获取城市列表" tags:"城市管理"` + Status int `json:"status" description:"状态:--1为全部,0为禁用,1为正常" ` + Name string `json:"name" description:"城市名" ` + Code string `json:"code" description:"城市编码" ` +} +type CityTreeRes struct { + Data []*model.CityTreeRes +} + +type AddCityReq struct { + g.Meta `path:"/city/add" method:"post" summary:"添加城市" tags:"城市管理"` + *model.AddCityReq +} +type AddCityRes struct { +} + +type EditCityReq struct { + g.Meta `path:"/city/edit" method:"put" summary:"编辑城市" tags:"城市管理"` + *model.EditCityReq +} +type EditCityRes struct { +} + +type GetCityByIdReq struct { + g.Meta `path:"/city/getInfoById" method:"get" summary:"根据ID获取城市信息" tags:"城市管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` +} +type GetCityByIdRes struct { + Data *model.CityRes +} + +type DelCityByIdReq struct { + g.Meta `path:"/city/del" method:"delete" summary:"根据ID删除城市信息" tags:"城市管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` +} +type DelCityByIdRes struct { +} diff --git a/api/v1/common/config_data.go b/api/v1/common/config_data.go new file mode 100644 index 0000000..6c2aecc --- /dev/null +++ b/api/v1/common/config_data.go @@ -0,0 +1,63 @@ +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ConfigSearchReq struct { + g.Meta `path:"/config/list" tags:"系统参数管理" method:"get" summary:"系统参数列表"` + ConfigName string `p:"configName"` //参数名称 + ConfigKey string `p:"configKey"` //参数键名 + ConfigType string `p:"configType"` //状态 + *PaginationReq +} + +type ConfigSearchRes struct { + g.Meta `mime:"application/json"` + List []*model.SysConfigRes `json:"list"` + PaginationRes +} + +type ConfigAddReq struct { + g.Meta `path:"/config/add" tags:"系统参数管理" method:"post" summary:"添加系统参数"` + ConfigName string `p:"configName" v:"required#参数名称不能为空"` + ConfigKey string `p:"configKey" v:"required#参数键名不能为空"` + ConfigValue string `p:"configValue" v:"required#参数键值不能为空"` + ConfigType int `p:"configType" v:"required|in:0,1#系统内置不能为空|系统内置类型只能为0或1"` + Remark string `p:"remark"` +} + +type ConfigAddRes struct { +} + +type ConfigGetReq struct { + g.Meta `path:"/config/get" tags:"系统参数管理" method:"get" summary:"获取系统参数"` + Id int `p:"id"` +} + +type ConfigGetRes struct { + g.Meta `mime:"application/json"` + Data *model.SysConfigRes `json:"data"` +} + +type ConfigEditReq struct { + g.Meta `path:"/config/edit" tags:"系统参数管理" method:"put" summary:"修改系统参数"` + ConfigId int `p:"configId" v:"required|min:1#主键ID不能为空|主键ID参数错误"` + ConfigName string `p:"configName" v:"required#参数名称不能为空"` + ConfigKey string `p:"configKey" v:"required#参数键名不能为空"` + ConfigValue string `p:"configValue" v:"required#参数键值不能为空"` + ConfigType int `p:"configType" v:"required|in:0,1#系统内置不能为空|系统内置类型只能为0或1"` + Remark string `p:"remark"` +} + +type ConfigEditRes struct { +} + +type ConfigDeleteReq struct { + g.Meta `path:"/config/delete" tags:"系统参数管理" method:"delete" summary:"删除系统参数"` + Ids []int `p:"ids"` +} + +type ConfigDeleteRes struct { +} diff --git a/api/v1/common/dict_data.go b/api/v1/common/dict_data.go new file mode 100644 index 0000000..c67e4fb --- /dev/null +++ b/api/v1/common/dict_data.go @@ -0,0 +1,88 @@ +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +// GetDictReq 获取字典信息请求参数 +type GetDictReq struct { + g.Meta `path:"/dict/data/getDictData" tags:"字典管理" method:"get" summary:"获取字典数据公共方法"` + Authorization string `p:"Authorization" in:"header" dc:"Bearer {{token}}"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + DefaultValue string `p:"defaultValue"` +} + +// GetDictRes 完整的一个字典信息 +type GetDictRes struct { + g.Meta `mime:"application/json"` + Data *model.DictTypeRes `json:"info"` + Values []*model.DictDataRes `json:"values"` +} + +// DictDataSearchReq 分页请求参数 +type DictDataSearchReq struct { + g.Meta `path:"/dict/data/list" tags:"字典管理" method:"get" summary:"字典数据列表"` + DictType string `p:"dictType"` //字典类型 + DictLabel string `p:"dictLabel"` //字典标签 + Status string `p:"status"` //状态 + PaginationReq +} + +// DictDataSearchRes 字典数据结果 +type DictDataSearchRes struct { + g.Meta `mime:"application/json"` + List []*model.SysDictDataRes `json:"list"` + PaginationRes +} + +type DictDataAddReq struct { + g.Meta `path:"/dict/data/add" tags:"字典管理" method:"post" summary:"添加字典数据"` + DictLabel string `p:"dictLabel" v:"required#字典标签不能为空"` + DictValue string `p:"dictValue" v:"required#字典键值不能为空"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + DictSort int `p:"dictSort" v:"integer#排序只能为整数"` + CssClass string `p:"cssClass"` + ListClass string `p:"listClass"` + IsDefault int `p:"isDefault" v:"required|in:0,1#系统默认不能为空|默认值只能为0或1"` + Status int `p:"status" v:"required|in:0,1#状态不能为空|状态只能为0或1"` + Remark string `p:"remark"` +} + +type DictDataAddRes struct { +} + +type DictDataGetReq struct { + g.Meta `path:"/dict/data/get" tags:"字典管理" method:"get" summary:"获取字典数据"` + DictCode uint `p:"dictCode"` +} + +type DictDataGetRes struct { + g.Meta `mime:"application/json"` + Dict *model.SysDictDataRes `json:"dict"` +} + +type DictDataEditReq struct { + g.Meta `path:"/dict/data/edit" tags:"字典管理" method:"put" summary:"修改字典数据"` + DictCode int `p:"dictCode" v:"required|min:1#主键ID不能为空|主键ID不能小于1"` + DictLabel string `p:"dictLabel" v:"required#字典标签不能为空"` + DictValue string `p:"dictValue" v:"required#字典键值不能为空"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + DictSort int `p:"dictSort" v:"integer#排序只能为整数"` + CssClass string `p:"cssClass"` + ListClass string `p:"listClass"` + IsDefault int `p:"isDefault" v:"required|in:0,1#系统默认不能为空|默认值只能为0或1"` + Status int `p:"status" v:"required|in:0,1#状态不能为空|状态只能为0或1"` + Remark string `p:"remark"` +} + +type DictDataEditRes struct { +} + +type DictDataDeleteReq struct { + g.Meta `path:"/dict/data/delete" tags:"字典管理" method:"delete" summary:"删除字典数据"` + Ids []int `p:"ids"` +} + +type DictDataDeleteRes struct { +} diff --git a/api/v1/common/dict_type.go b/api/v1/common/dict_type.go new file mode 100644 index 0000000..d39393d --- /dev/null +++ b/api/v1/common/dict_type.go @@ -0,0 +1,61 @@ +package common + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type DictTypeSearchReq struct { + g.Meta `path:"/dict/type/list" tags:"字典管理" method:"get" summary:"字典类型列表"` + DictName string `p:"dictName"` //字典名称 + DictType string `p:"dictType"` //字典类型 + Status string `p:"status"` //字典状态 + *PaginationReq +} + +type DictTypeSearchRes struct { + g.Meta `mime:"application/json"` + DictTypeList []*model.SysDictTypeInfoRes `json:"dictTypeList"` + PaginationRes +} + +type DictTypeAddReq struct { + g.Meta `path:"/dict/type/add" tags:"字典管理" method:"post" summary:"添加字典类型"` + DictName string `p:"dictName" v:"required#字典名称不能为空"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + Status uint `p:"status" v:"required|in:0,1#状态不能为空|状态只能为0或1"` + Remark string `p:"remark"` +} + +type DictTypeAddRes struct { +} + +type DictTypeGetReq struct { + g.Meta `path:"/dict/type/get" tags:"字典管理" method:"get" summary:"获取字典类型"` + DictId uint `p:"dictId" v:"required#类型id不能为空"` +} + +type DictTypeGetRes struct { + g.Meta `mime:"application/json"` + DictType *model.SysDictTypeRes `json:"dictType"` +} + +type DictTypeEditReq struct { + g.Meta `path:"/dict/type/edit" tags:"字典管理" method:"put" summary:"修改字典类型"` + DictId int `p:"dictId" v:"required|min:1#主键ID不能为空|主键ID必须为大于0的值"` + DictName string `p:"dictName" v:"required#字典名称不能为空"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + Status uint `p:"status" v:"required|in:0,1#状态不能为空|状态只能为0或1"` + Remark string `p:"remark"` +} + +type DictTypeEditRes struct { +} + +type DictTypeDeleteReq struct { + g.Meta `path:"/dict/type/delete" tags:"字典管理" method:"delete" summary:"删除字典类型"` + DictIds []int `p:"dictIds" v:"required#字典类型id不能为空"` +} + +type DictTypeDeleteRes struct { +} diff --git a/api/v1/common/notice.go b/api/v1/common/notice.go new file mode 100644 index 0000000..44eca97 --- /dev/null +++ b/api/v1/common/notice.go @@ -0,0 +1,23 @@ +package common + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +type GetNoticeReq struct { + g.Meta `path:"/notice/data" tags:"公共方法" method:"get" summary:"获取实时通知信息"` + Topic string `p:"topic" v:"required#订阅主题不能为空"` +} + +type GetNoticeRes struct { + g.Meta `mime:"application/json"` +} + +type GetNotice2Req struct { + g.Meta `path:"/notice/data2" tags:"公共方法" method:"get" summary:"获取实时通知信息"` + Topic string `p:"topic" v:"required#订阅主题不能为空"` +} + +type GetNotice2Res struct { + g.Meta `mime:"application/json"` +} diff --git a/api/v1/common/sysinfo.go b/api/v1/common/sysinfo.go new file mode 100644 index 0000000..aa420ee --- /dev/null +++ b/api/v1/common/sysinfo.go @@ -0,0 +1,17 @@ +package common + +import "github.com/gogf/gf/v2/frame/g" + +type GetSysInfoReq struct { + g.Meta `path:"/sysinfo" tags:"公共方法" method:"get" summary:"获取系统相关的信息"` +} + +type GetSysInfoRes g.Map + +type IsTokenReq struct { + g.Meta `path:"/isToken" method:"get" summary:"验证token是否正确" tags:"公共方法"` +} +type IsTokenRes struct { + ExpiresAt int64 `json:"expiresAt"` + IsToken bool `json:"isToken"` +} diff --git a/api/v1/common/upload.go b/api/v1/common/upload.go new file mode 100644 index 0000000..4d0f789 --- /dev/null +++ b/api/v1/common/upload.go @@ -0,0 +1,34 @@ +package common + +import "github.com/gogf/gf/v2/frame/g" + +type UploadSingleImgReq struct { + g.Meta `path:"/singleImg" tags:"文件上传下载" method:"post" summary:"上传图片"` +} + +type UploadSingleFileReq struct { + g.Meta `path:"/singleFile" tags:"文件上传下载" method:"post" summary:"上传文件"` +} + +type UploadSingleRes struct { + g.Meta `mime:"application/json"` + UploadResponse +} + +type UploadMultipleImgReq struct { + g.Meta `path:"/multipleImg" tags:"文件上传下载" method:"post" summary:"上传多图片"` +} + +type UploadMultipleFileReq struct { + g.Meta `path:"/multipleFile" tags:"文件上传下载" method:"post" summary:"上传多文件"` +} + +type UploadMultipleRes []*UploadResponse + +type UploadResponse struct { + Size int64 `json:"size"` + Path string `json:"path"` + FullPath string `json:"full_path"` + Name string `json:"name"` + Type string `json:"type"` +} diff --git a/api/v1/envirotronics/env_weather.go b/api/v1/envirotronics/env_weather.go new file mode 100644 index 0000000..13b2b4d --- /dev/null +++ b/api/v1/envirotronics/env_weather.go @@ -0,0 +1,46 @@ +package envirotronics + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type CityWeatherListReq struct { + g.Meta `path:"/weather/cityWeatherList" method:"get" summary:"获取城市的风力及日照时长" tags:"天气监测"` + Name string `json:"name" description:"名字"` +} +type CityWeatherListRes struct { + Info []*model.CityWeatherListRes +} + +type GetCityWeatherByIdReq struct { + g.Meta `path:"/weather/getInfoById" method:"get" summary:"根据ID获取指定城市的天气" tags:"天气监测"` + Id int `json:"id" description:"主键ID" v:"required#ID不能为空"` +} +type GetCityWeatherByIdRes struct { + Info *model.CityWeatherListRes +} + +type GetCityTemperatureByIdReq struct { + g.Meta `path:"/weather/getTemperatureEchartById" method:"get" summary:"根据ID获取指定城市的温度图表" tags:"天气监测"` + Id int `json:"id" description:"主键ID" v:"required#ID不能为空"` + Types int `json:"types" description:"类型 1 日 2周 3月 4年" v:"required#类型不能为空"` +} +type GetCityTemperatureByIdRes struct { + Info []*model.CityWeatherEchartRes + AvgInfo []*model.CityWeatherEchartRes + ForeCastInfo []*model.CityWeatherEchartRes + ForeCastAvgInfo []*model.CityWeatherEchartRes +} + +type GetCityWindpowerByIdReq struct { + g.Meta `path:"/weather/getWindpowerEchartById" method:"get" summary:"根据ID获取指定城市的风力图表" tags:"天气监测"` + Id int `json:"id" description:"主键ID" v:"required#ID不能为空"` + Types int `json:"types" description:"类型 1 日 2周 3月 4年" v:"required#类型不能为空"` +} +type GetCityWindpowerByIdRes struct { + Info []*model.CityWeatherEchartRes + AvgInfo []*model.CityWeatherEchartRes + ForeCastInfo []*model.CityWeatherEchartRes + ForeCastAvgInfo []*model.CityWeatherEchartRes +} diff --git a/api/v1/network/server.go b/api/v1/network/server.go new file mode 100644 index 0000000..7ce5d79 --- /dev/null +++ b/api/v1/network/server.go @@ -0,0 +1,74 @@ +package network + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +// 这里是需要处理的地方,需要在这里调试好下面的几个接口 + +// 获取列表api +type GetNetworkServerListReq struct { + g.Meta `path:"/server/list" method:"get" summary:"获取通讯服务列表" tags:"网络组件管理"` + common.PaginationReq +} +type GetNetworkServerListRes struct { + Data []*model.NetworkServerRes + common.PaginationRes +} + +// 获取指定ID的数据api +type GetNetworkServerByIdReq struct { + g.Meta `path:"/get" method:"get" summary:"获取通讯服务列表" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNetworkServerByIdRes struct { + Data *model.NetworkServerRes +} + +// 添加数据api +type AddNetworkServerReq struct { + g.Meta `path:"/server/add" method:"post" summary:"添加通讯服务" tags:"网络组件管理"` + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:""` +} +type AddNetworkServerRes struct{} + +// 编辑数据api +type EditNetworkServerReq struct { + g.Meta `path:"/server/edit" method:"put" summary:"编辑通讯服务" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Status int `json:"status" description:"状态"` + Remark string `json:"remark" description:"备注"` +} +type EditNetworkServerRes struct{} + +// 删除数据api +type DeleteNetworkServerReq struct { + g.Meta `path:"/server/delete" method:"delete" summary:"删除通讯服务" tags:"网络组件管理"` + Ids []int `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNetworkServerRes struct{} + +// 服务状态api +type SetNetworkServerStatusReq struct { + g.Meta `path:"/server/status" method:"post" summary:"修改服务状态" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` + Status int `json:"status" description:"status" v:"required#status不能为空"` +} +type SetNetworkServerStatusRes struct{} diff --git a/api/v1/network/tunnel.go b/api/v1/network/tunnel.go new file mode 100644 index 0000000..fbdfaf1 --- /dev/null +++ b/api/v1/network/tunnel.go @@ -0,0 +1,77 @@ +package network + +import ( + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +// 获取列表api +type GetNetworkTunnelListReq struct { + g.Meta `path:"/tunnel/list" method:"get" summary:"获取通道列表" tags:"网络组件管理"` + ServiceId int `json:"serviceId" dc:"服务ID"` + DeviceKey string `json:"deviceKey" dc:"设备标识"` + *common.PaginationReq +} +type GetNetworkTunnelListRes struct { + Data []*model.NetworkTunnelRes + common.PaginationRes +} + +// 获取指定ID的数据api +type GetNetworkTunnelByIdReq struct { + g.Meta `path:"/tunnel/get" method:"get" summary:"获取单个通道" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNetworkTunnelByIdRes struct { + Data *model.NetworkTunnelRes +} + +// 添加数据api +type AddNetworkTunnelReq struct { + g.Meta `path:"/tunnel/add" method:"post" summary:"添加通道" tags:"网络组件管理"` + Name string `json:"name" description:"" v:"required#名称不能为空"` + Types string `json:"types" description:"" v:"required#类型不能为空"` + Addr string `json:"addr" description:"" v:"required#地址不能为空"` + Remote string `json:"remote" description:""` + Status string `json:"status" description:""` + Retry string `json:"retry" description:""` + Heartbeat string `json:"heartbeat" description:""` + Serial string `json:"serial" description:""` + Protoccol string `json:"protoccol" description:""` + Remark string `json:"remark" description:"备注"` +} +type AddNetworkTunnelRes struct{} + +// 编辑数据api +type EditNetworkTunnelReq struct { + g.Meta `path:"/tunnel/edit" method:"put" summary:"编辑通道" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` + Name string `json:"name" description:"" v:"required#名称不能为空"` + Types string `json:"types" description:"" v:"required#类型不能为空"` + Addr string `json:"addr" description:"" v:"required#地址不能为空"` + Remote string `json:"remote" description:""` + Status string `json:"status" description:""` + Retry string `json:"retry" description:""` + Heartbeat string `json:"heartbeat" description:""` + Serial string `json:"serial" description:""` + Protoccol string `json:"protoccol" description:""` + Remark string `json:"remark" description:"备注"` +} +type EditNetworkTunnelRes struct{} + +// 删除数据api +type DeleteNetworkTunnelReq struct { + g.Meta `path:"/tunnel/delete" method:"delete" summary:"删除通道" tags:"网络组件管理"` + Ids []int `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNetworkTunnelRes struct{} + +// 通道状态api +type SetNetworkTunnelStatusReq struct { + g.Meta `path:"/tunnel/status" method:"post" summary:"修改通道状态" tags:"网络组件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` + Status int `json:"status" description:"status" v:"required#status不能为空"` +} +type SetNetworkTunnelStatusRes struct{} diff --git a/api/v1/notice/config.go b/api/v1/notice/config.go new file mode 100644 index 0000000..cbf479f --- /dev/null +++ b/api/v1/notice/config.go @@ -0,0 +1,59 @@ +package notice + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" +) + +//GetNoticeConfigListReq 获取数据列表 +type GetNoticeConfigListReq struct { + g.Meta `path:"/config/list" method:"get" summary:"获取通知配置列表" tags:"通知服务管理"` + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + common.PaginationReq +} +type GetNoticeConfigListRes struct { + Data []GetNoticeConfigByIdRes + common.PaginationRes +} + +//GetNoticeConfigByIdReq 获取指定ID的数据 +type GetNoticeConfigByIdReq struct { + g.Meta `path:"/config/get" method:"get" summary:"获取通知配置" tags:"通知服务管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNoticeConfigByIdRes struct { + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + CreatedAt string `json:"createdAt" description:""` + Id string `json:"id" description:""` + Title string `json:"title" description:""` +} + +//AddNoticeConfigReq 添加数据 +type AddNoticeConfigReq struct { + g.Meta `path:"/config/add" method:"post" summary:"添加通知配置" tags:"通知服务管理"` + Title string `json:"title" description:""` + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type AddNoticeConfigRes struct{} + +//EditNoticeConfigReq 编辑数据api +type EditNoticeConfigReq struct { + g.Meta `path:"/config/edit" method:"put" summary:"编辑通知配置" tags:"通知服务管理"` + Id string `json:"id" description:""` + Title string `json:"title" description:""` + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type EditNoticeConfigRes struct{} + +//DeleteNoticeConfigReq 删除数据 +type DeleteNoticeConfigReq struct { + g.Meta `path:"/config/delete" method:"delete" summary:"删除通知配置" tags:"通知服务管理"` + Ids []string `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNoticeConfigRes struct{} diff --git a/api/v1/notice/info.go b/api/v1/notice/info.go new file mode 100644 index 0000000..5182b3b --- /dev/null +++ b/api/v1/notice/info.go @@ -0,0 +1,88 @@ +package notice + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" +) + +//GetNoticeInfoListReq 获取数据列表 +type GetNoticeInfoListReq struct { + g.Meta `path:"/info/list" method:"get" summary:"获取通知信息列表" tags:"通知服务管理"` + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + Status int `json:"status" description:""` + common.PaginationReq +} +type GetNoticeInfoListRes struct { + Data []GetNoticeInfoByIdRes + common.PaginationRes +} + +//GetNoticeInfoByIdReq 获取指定ID的数据 +type GetNoticeInfoByIdReq struct { + g.Meta `path:"/info/get" method:"get" summary:"获取通知信息" tags:"通知服务管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNoticeInfoByIdRes struct { + OrgIds string `json:"orgIds" description:""` + MethodNum string `json:"methodNum" description:""` + CreatedAt string `json:"createdAt" description:""` + MsgTitle string `json:"msgTitle" description:""` + Totag string `json:"totag" description:""` + Status string `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + Id string `json:"id" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + MsgBody string `json:"msgBody" description:""` + MsgUrl string `json:"msgUrl" description:""` + ConfigId string `json:"configId" description:""` + UserIds string `json:"userIds" description:""` +} + +//AddNoticeInfoReq 添加数据 +type AddNoticeInfoReq struct { + g.Meta `path:"/info/add" method:"post" summary:"添加通知信息" tags:"通知服务管理"` + Totag string `json:"totag" description:""` + Status string `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + MsgBody string `json:"msgBody" description:""` + MsgUrl string `json:"msgUrl" description:""` + ConfigId string `json:"configId" description:""` + UserIds string `json:"userIds" description:""` + OrgIds string `json:"orgIds" description:""` + MethodNum string `json:"methodNum" description:""` + CreatedAt string `json:"createdAt" description:""` + MsgTitle string `json:"msgTitle" description:""` +} +type AddNoticeInfoRes struct{} + +//EditNoticeInfoReq 编辑数据api +type EditNoticeInfoReq struct { + g.Meta `path:"/info/edit" method:"put" summary:"编辑通知信息" tags:"通知服务管理"` + UserIds string `json:"userIds" description:""` + MsgTitle string `json:"msgTitle" description:""` + OrgIds string `json:"orgIds" description:""` + MethodNum string `json:"methodNum" description:""` + CreatedAt string `json:"createdAt" description:""` + Id string `json:"id" description:""` + Totag string `json:"totag" description:""` + Status string `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + MsgUrl string `json:"msgUrl" description:""` + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + MsgBody string `json:"msgBody" description:""` +} +type EditNoticeInfoRes struct{} + +//DeleteNoticeInfoReq 删除数据 +type DeleteNoticeInfoReq struct { + g.Meta `path:"/info/delete" method:"delete" summary:"删除通知信息" tags:"通知服务管理"` + Ids []int `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNoticeInfoRes struct{} diff --git a/api/v1/notice/log.go b/api/v1/notice/log.go new file mode 100644 index 0000000..0ef1345 --- /dev/null +++ b/api/v1/notice/log.go @@ -0,0 +1,21 @@ +package notice + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type LogSearchReq struct { + g.Meta `path:"/log/search" method:"get" summary:"通知日志搜索" tags:"通知服务管理"` + *model.NoticeLogSearchInput +} +type LogSearchRes struct { + *model.NoticeLogSearchOutput +} + +type LogDelReq struct { + g.Meta `path:"/log/del" method:"delete" summary:"通知日志删除" tags:"通知服务管理"` + Ids []uint64 `json:"ids" dc:"日志Ids" v:"required#日志ID不能为空"` +} +type LogDelRes struct{} diff --git a/api/v1/notice/template.go b/api/v1/notice/template.go new file mode 100644 index 0000000..97fecfb --- /dev/null +++ b/api/v1/notice/template.go @@ -0,0 +1,95 @@ +package notice + +import ( + "github.com/sagoo-cloud/sagooiot/api/v1/common" + + "github.com/gogf/gf/v2/frame/g" +) + +//GetNoticeTemplateListReq 获取数据列表 +type GetNoticeTemplateListReq struct { + g.Meta `path:"/template/list" method:"get" summary:"获取通知模版列表" tags:"通知服务管理"` + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + common.PaginationReq +} +type GetNoticeTemplateListRes struct { + Data []GetNoticeTemplateByIdRes + common.PaginationRes +} + +//GetNoticeTemplateByIdReq 获取指定ID的数据 +type GetNoticeTemplateByIdReq struct { + g.Meta `path:"/template/get" method:"get" summary:"获取通知模版" tags:"通知服务管理"` + Id string `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNoticeTemplateByIdRes struct { + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + Id string `json:"id" description:""` +} + +//GetNoticeTemplateByConfigIdReq 获取指定ConfigId的数据 +type GetNoticeTemplateByConfigIdReq struct { + g.Meta `path:"/template/getbyconfig" method:"get" summary:"获取通知模版" tags:"通知服务管理"` + ConfigId string `json:"configId" description:"configId" v:"required#通知配置ID不能为空"` +} +type GetNoticeTemplateByConfigIdRes struct { + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + Id string `json:"id" description:""` +} + +//AddNoticeTemplateReq 添加数据 +type AddNoticeTemplateReq struct { + g.Meta `path:"/template/add" method:"post" summary:"添加通知模版" tags:"通知服务管理"` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` +} +type AddNoticeTemplateRes struct{} + +//SaveNoticeTemplateReq 添加数据 +type SaveNoticeTemplateReq struct { + g.Meta `path:"/template/save" method:"post" summary:"直接更新通知模版数据" tags:"通知服务管理"` + Id string `json:"id" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + ConfigId string `json:"configId" description:"configId" v:"required#configId不能为空"` + SendGateway string `json:"sendGateway" description:""` +} +type SaveNoticeTemplateRes struct{} + +//EditNoticeTemplateReq 编辑数据api +type EditNoticeTemplateReq struct { + g.Meta `path:"/template/edit" method:"put" summary:"编辑通知模版" tags:"通知服务管理"` + Id string `json:"id" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + ConfigId string `json:"configId" description:""` +} +type EditNoticeTemplateRes struct{} + +//DeleteNoticeTemplateReq 删除数据 +type DeleteNoticeTemplateReq struct { + g.Meta `path:"/template/delete" method:"delete" summary:"删除通知模版" tags:"通知服务管理"` + Ids []string `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNoticeTemplateRes struct{} diff --git a/api/v1/product/category.go b/api/v1/product/category.go new file mode 100644 index 0000000..f750801 --- /dev/null +++ b/api/v1/product/category.go @@ -0,0 +1,44 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type CategoryListForPageReq struct { + g.Meta `path:"/category/page_list" method:"get" summary:"产品分类列表(分页)" tags:"产品分类"` + Name string `json:"name" dc:"分类名称"` + *common.PaginationReq +} +type CategoryListForPageRes struct { + Category []*model.ProductCategoryTreeOutput `json:"category" dc:"产品分类列表"` + common.PaginationRes +} + +type CategoryListReq struct { + g.Meta `path:"/category/list" method:"get" summary:"产品分类列表" tags:"产品分类"` + Name string `json:"name" dc:"分类名称"` +} +type CategoryListRes struct { + Category []*model.ProductCategoryTreeOutput `json:"category" dc:"产品分类列表"` +} + +type AddCategoryReq struct { + g.Meta `path:"/category/add" method:"post" summary:"添加产品分类" tags:"产品分类"` + *model.AddProductCategoryInput +} +type AddCategoryRes struct{} + +type EditCategoryReq struct { + g.Meta `path:"/category/edit" method:"put" summary:"编辑产品分类" tags:"产品分类"` + *model.EditProductCategoryInput +} +type EditCategoryRes struct{} + +type DelCategoryReq struct { + g.Meta `path:"/category/del" method:"delete" summary:"删除产品分类" tags:"产品分类"` + Id uint `json:"id" dc:"分类ID" v:"required#分类ID不能为空"` +} +type DelCategoryRes struct{} diff --git a/api/v1/product/device.go b/api/v1/product/device.go new file mode 100644 index 0000000..bff5abf --- /dev/null +++ b/api/v1/product/device.go @@ -0,0 +1,120 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type GetDeviceReq struct { + g.Meta `path:"/device/get" method:"get" summary:"设备详情" tags:"设备"` + Key string `json:"key" dc:"设备标识" v:"required#设备标识不能为空"` +} +type GetDeviceRes struct { + Data *model.DeviceOutput `json:"data" dc:"设备详情"` +} + +type DetailDeviceReq struct { + g.Meta `path:"/device/detail" method:"get" summary:"设备详情" tags:"设备"` + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` +} +type DetailDeviceRes struct { + Data *model.DeviceOutput `json:"data" dc:"设备详情"` +} + +type ListDeviceForPageReq struct { + g.Meta `path:"/device/page_list" method:"get" summary:"设备搜索列表(分页)" tags:"设备"` + *model.ListDeviceForPageInput +} +type ListDeviceForPageRes struct { + *model.ListDeviceForPageOutput +} + +type ListDeviceReq struct { + g.Meta `path:"/device/list" method:"get" summary:"设备列表" tags:"设备"` + *model.ListDeviceInput +} +type ListDeviceRes struct { + Device []*model.DeviceOutput `json:"device" dc:"设备列表"` +} + +type AddDeviceReq struct { + g.Meta `path:"/device/add" method:"post" summary:"添加设备" tags:"设备"` + *model.AddDeviceInput +} +type AddDeviceRes struct{} + +type EditDeviceReq struct { + g.Meta `path:"/device/edit" method:"put" summary:"编辑设备" tags:"设备"` + *model.EditDeviceInput +} +type EditDeviceRes struct{} + +type DelDeviceReq struct { + g.Meta `path:"/device/del" method:"delete" summary:"删除设备" tags:"设备"` + Ids []uint `json:"ids" dc:"设备Ids" v:"required#设备ID不能为空"` +} +type DelDeviceRes struct{} + +type DeployDeviceReq struct { + g.Meta `path:"/device/deploy" method:"post" summary:"启用设备" tags:"设备"` + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` +} +type DeployDeviceRes struct{} + +type UndeployDeviceReq struct { + g.Meta `path:"/device/undeploy" method:"post" summary:"禁用设备" tags:"设备"` + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` +} +type UndeployDeviceRes struct{} + +type OnlineDeviceReq struct { + g.Meta `path:"/device/online" method:"post" summary:"上线设备" tags:"设备"` + Key string `json:"key" dc:"设备标识" v:"required#设备标识不能为空"` +} +type OnlineDeviceRes struct{} + +type OfflineDeviceReq struct { + g.Meta `path:"/device/offline" method:"post" summary:"下线设备" tags:"设备"` + Key string `json:"key" dc:"设备标识" v:"required#设备标识不能为空"` +} +type OfflineDeviceRes struct{} + +type DeviceRunStatusReq struct { + g.Meta `path:"/device/run_status" method:"get" summary:"运行状态" tags:"设备"` + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` +} +type DeviceRunStatusRes struct { + *model.DeviceRunStatusOutput +} + +type DeviceGetPropertyReq struct { + g.Meta `path:"/device/property/get" method:"get" summary:"获取指定属性值" tags:"设备"` + *model.DeviceGetPropertyInput +} +type DeviceGetPropertyRes struct { + *model.DevicePropertiy +} + +type DeviceGetPropertyListReq struct { + g.Meta `path:"/device/property/list" method:"get" summary:"属性详情列表" tags:"设备"` + *model.DeviceGetPropertyListInput +} +type DeviceGetPropertyListRes struct { + *model.DeviceGetPropertyListOutput +} + +type DeviceStatisticsReq struct { + g.Meta `path:"/device/statistics" method:"get" summary:"设备相关统计" tags:"设备"` +} +type DeviceStatisticsRes struct { + DeviceTotal model.DeviceTotalOutput `json:"deviceTotal" dc:"设备相关统计"` +} + +type DeviceStatisticsForMonthsReq struct { + g.Meta `path:"/device/statistics/months" method:"get" summary:"设备消息量、告警量月度统计" tags:"设备"` +} +type DeviceStatisticsForMonthsRes struct { + MsgTotal map[int]int `json:"msgTotal" dc:"设备消息量月度统计"` + AlarmTotal map[int]int `json:"alarmTotal" dc:"设备告警量月度统计"` +} diff --git a/api/v1/product/device_log.go b/api/v1/product/device_log.go new file mode 100644 index 0000000..2f3cb99 --- /dev/null +++ b/api/v1/product/device_log.go @@ -0,0 +1,22 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DeviceLogTypeReq struct { + g.Meta `path:"/log/type" method:"get" summary:"日志类型" tags:"时序数据库管理"` +} +type DeviceLogTypeRes struct { + List []string `json:"list" dc:"日志类型列表"` +} + +type DeviceLogSearchReq struct { + g.Meta `path:"/log/search" method:"get" summary:"日志搜索" tags:"时序数据库管理"` + *model.DeviceLogSearchInput +} +type DeviceLogSearchRes struct { + *model.DeviceLogSearchOutput +} diff --git a/api/v1/product/device_tag.go b/api/v1/product/device_tag.go new file mode 100644 index 0000000..cbb1928 --- /dev/null +++ b/api/v1/product/device_tag.go @@ -0,0 +1,25 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type AddTagDeviceReq struct { + g.Meta `path:"/device/tag/add" method:"post" summary:"标签添加" tags:"设备"` + *model.AddTagDeviceInput +} +type AddTagDeviceRes struct{} + +type EditTagDeviceReq struct { + g.Meta `path:"/device/tag/edit" method:"put" summary:"标签编辑" tags:"设备"` + *model.EditTagDeviceInput +} +type EditTagDeviceRes struct{} + +type DelTagDeviceReq struct { + g.Meta `path:"/device/tag/del" method:"delete" summary:"标签删除" tags:"设备"` + Id uint `json:"id" dc:"标签ID" v:"required#标签ID不能为空"` +} +type DelTagDeviceRes struct{} diff --git a/api/v1/product/product.go b/api/v1/product/product.go new file mode 100644 index 0000000..ca003d2 --- /dev/null +++ b/api/v1/product/product.go @@ -0,0 +1,77 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" +) + +type GetProductReq struct { + g.Meta `path:"/get" method:"get" summary:"产品详情" tags:"产品"` + Key string `json:"key" dc:"产品标识" v:"required#产品标识不能为空"` +} +type GetProductRes struct { + Data *model.DetailProductOutput `json:"data" dc:"产品详情"` +} + +type DetailProductReq struct { + g.Meta `path:"/detail" method:"get" summary:"产品详情" tags:"产品"` + Id uint `json:"id" dc:"产品ID" v:"required#产品ID不能为空"` +} +type DetailProductRes struct { + Data *model.DetailProductOutput `json:"data" dc:"产品详情"` +} + +type ListForPageReq struct { + g.Meta `path:"/page_list" method:"get" summary:"产品搜索列表(分页)" tags:"产品"` + model.ListForPageInput +} +type ListForPageRes struct { + model.ListForPageOutput +} + +type ListReq struct { + g.Meta `path:"/list" method:"get" summary:"产品列表" tags:"产品"` +} +type ListRes struct { + Product []*model.ProductOutput `json:"product" dc:"产品列表"` +} + +type AddProductReq struct { + g.Meta `path:"/add" method:"post" summary:"添加产品" tags:"产品"` + *model.AddProductInput +} +type AddProductRes struct{} + +type EditProductReq struct { + g.Meta `path:"/edit" method:"put" summary:"编辑产品" tags:"产品"` + *model.EditProductInput +} +type EditProductRes struct{} + +type DelProductReq struct { + g.Meta `path:"/del" method:"delete" summary:"删除产品" tags:"产品"` + Ids []uint `json:"ids" dc:"产品Ids" v:"required#产品ID不能为空"` +} +type DelProductRes struct{} + +type DeployProductReq struct { + g.Meta `path:"/deploy" method:"post" summary:"发布产品" tags:"产品"` + Id uint `json:"id" dc:"产品ID" v:"required#产品ID不能为空"` +} +type DeployProductRes struct{} + +type UndeployProductReq struct { + g.Meta `path:"/undeploy" method:"post" summary:"停用产品" tags:"产品"` + Id uint `json:"id" dc:"产品ID" v:"required#产品ID不能为空"` +} +type UndeployProductRes struct{} + +type UploadIconReq struct { + g.Meta `path:"/icon/upload" method:"post" mime:"multipart/form-data" summary:"图标上传" tags:"产品"` + Icon *ghttp.UploadFile `json:"icon" type:"file" dc:"选择上传图片"` +} +type UploadIconRes struct { + IconPath string `json:"name" dc:"图标地址"` +} diff --git a/api/v1/product/protocol.go b/api/v1/product/protocol.go new file mode 100644 index 0000000..c1f3c71 --- /dev/null +++ b/api/v1/product/protocol.go @@ -0,0 +1,23 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +// 消息协议 +type ListMessageProtocolReq struct { + g.Meta `path:"/protocol/message_protocol_list" method:"get" summary:"消息协议" tags:"协议"` +} +type ListMessageProtocolRes struct { + Data []*model.MessageProtocolRes `json:"data" dc:"消息协议"` +} + +// 传输协议 +type ListTrunsportProtocolReq struct { + g.Meta `path:"/protocol/trunsport_protocol_list" method:"get" summary:"传输协议" tags:"协议"` +} +type ListTrunsportProtocolRes struct { + Data []*model.TrunsportProtocolRes `json:"data" dc:"传输协议"` +} diff --git a/api/v1/product/tsl.go b/api/v1/product/tsl.go new file mode 100644 index 0000000..268202d --- /dev/null +++ b/api/v1/product/tsl.go @@ -0,0 +1,136 @@ +package product + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +// 数据类型 + +type DateTypeReq struct { + g.Meta `path:"/tsl/data_type" method:"get" summary:"数据类型" tags:"物模型"` +} +type DateTypeRes struct { + DataType *model.DataTypeOutput `json:"dataType" dc:"数据类型"` +} + +// 属性 + +type ListTSLPropertyReq struct { + g.Meta `path:"/tsl/property/list" method:"get" summary:"属性列表" tags:"物模型"` + *model.ListTSLPropertyInput +} +type ListTSLPropertyRes struct { + *model.ListTSLPropertyOutput +} + +type AllTSLPropertyReq struct { + g.Meta `path:"/tsl/property/all" method:"get" summary:"所有属性列表" tags:"物模型"` + Key string `json:"key" dc:"产品标识" v:"required#产品标识不能为空"` +} +type AllTSLPropertyRes struct { + Data []model.TSLProperty +} + +type AddTSLPropertyReq struct { + g.Meta `path:"/tsl/property/add" method:"post" summary:"属性添加" tags:"物模型"` + *model.TSLPropertyInput +} +type AddTSLPropertyRes struct{} + +type EditTSLPropertyReq struct { + g.Meta `path:"/tsl/property/edit" method:"put" summary:"属性编辑" tags:"物模型"` + *model.TSLPropertyInput +} +type EditTSLPropertyRes struct{} + +type DelTSLPropertyReq struct { + g.Meta `path:"/tsl/property/del" method:"delete" summary:"属性删除" tags:"物模型"` + *model.DelTSLPropertyInput +} +type DelTSLPropertyRes struct{} + +// 功能 + +type ListTSLFunctionReq struct { + g.Meta `path:"/tsl/function/list" method:"get" summary:"功能列表" tags:"物模型"` + *model.ListTSLFunctionInput +} +type ListTSLFunctionRes struct { + *model.ListTSLFunctionOutput +} + +type AddTSLFunctionReq struct { + g.Meta `path:"/tsl/function/add" method:"post" summary:"功能添加" tags:"物模型"` + *model.TSLFunctionAddInput +} +type AddTSLFunctionRes struct{} + +type EditTSLFunctionReq struct { + g.Meta `path:"/tsl/function/edit" method:"put" summary:"功能编辑" tags:"物模型"` + *model.TSLFunctionAddInput +} +type EditTSLFunctionRes struct{} + +type DelTSLFunctionReq struct { + g.Meta `path:"/tsl/function/del" method:"delete" summary:"功能删除" tags:"物模型"` + *model.DelTSLFunctionInput +} +type DelTSLFunctionRes struct{} + +// 事件 + +type ListTSLEventReq struct { + g.Meta `path:"/tsl/event/list" method:"get" summary:"事件列表" tags:"物模型"` + *model.ListTSLEventInput +} +type ListTSLEventRes struct { + *model.ListTSLEventOutput +} + +type AddTSLEventReq struct { + g.Meta `path:"/tsl/event/add" method:"post" summary:"事件添加" tags:"物模型"` + *model.TSLEventInput +} +type AddTSLEventRes struct{} + +type EditTSLEventReq struct { + g.Meta `path:"/tsl/event/edit" method:"put" summary:"事件编辑" tags:"物模型"` + *model.TSLEventInput +} +type EditTSLEventRes struct{} + +type DelTSLEventReq struct { + g.Meta `path:"/tsl/event/del" method:"delete" summary:"事件删除" tags:"物模型"` + *model.DelTSLEventInput +} +type DelTSLEventRes struct{} + +// 标签 + +type ListTSLTagReq struct { + g.Meta `path:"/tsl/tag/list" method:"get" summary:"标签列表" tags:"物模型"` + *model.ListTSLTagInput +} +type ListTSLTagRes struct { + *model.ListTSLTagOutput +} + +type AddTSLTagReq struct { + g.Meta `path:"/tsl/tag/add" method:"post" summary:"标签添加" tags:"物模型"` + *model.TSLTagInput +} +type AddTSLTagRes struct{} + +type EditTSLTagReq struct { + g.Meta `path:"/tsl/tag/edit" method:"put" summary:"标签编辑" tags:"物模型"` + *model.TSLTagInput +} +type EditTSLTagRes struct{} + +type DelTSLTagReq struct { + g.Meta `path:"/tsl/tag/del" method:"delete" summary:"标签删除" tags:"物模型"` + *model.DelTSLTagInput +} +type DelTSLTagRes struct{} diff --git a/api/v1/source/node.go b/api/v1/source/node.go new file mode 100644 index 0000000..1963d7f --- /dev/null +++ b/api/v1/source/node.go @@ -0,0 +1,33 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataNodeAddReq struct { + g.Meta `path:"/node/add" method:"post" summary:"添加数据节点" tags:"数据源"` + *model.DataNodeAddInput +} +type DataNodeAddRes struct{} + +type DataNodeEditReq struct { + g.Meta `path:"/node/edit" method:"put" summary:"编辑数据节点" tags:"数据源"` + *model.DataNodeEditInput +} +type DataNodeEditRes struct{} + +type DataNodeDelReq struct { + g.Meta `path:"/node/del" method:"delete" summary:"删除数据节点" tags:"数据源"` + NodeId uint64 `json:"nodeId" dc:"数据节点ID" v:"required#数据节点ID不能为空"` +} +type DataNodeDelRes struct{} + +type DataNodeListReq struct { + g.Meta `path:"/node/list" method:"get" summary:"数据节点列表" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataNodeListRes struct { + List []*model.DataNodeOutput `json:"list" dc:"数据节点列表"` +} diff --git a/api/v1/source/source.go b/api/v1/source/source.go new file mode 100644 index 0000000..ca8db03 --- /dev/null +++ b/api/v1/source/source.go @@ -0,0 +1,83 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataSourceApiAddReq struct { + g.Meta `path:"/api/add" method:"post" summary:"添加API数据源" tags:"数据源"` + *model.DataSourceApiAddInput +} +type DataSourceApiAddRes struct{} + +type DataSourceApiEditReq struct { + g.Meta `path:"/api/edit" method:"put" summary:"编辑API数据源" tags:"数据源"` + *model.DataSourceApiEditInput +} +type DataSourceApiEditRes struct{} + +type DataSourceApiGetReq struct { + g.Meta `path:"/api/get" method:"get" summary:"获取API数据" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceApiGetRes struct { + Data string `json:"data" dc:"api源数据"` +} + +type DataSourceDelReq struct { + g.Meta `path:"/del" method:"delete" summary:"删除数据源" tags:"数据源"` + Ids []uint64 `json:"ids" dc:"数据源Ids" v:"required#数据源ID不能为空"` +} +type DataSourceDelRes struct{} + +type DataSourceSearchReq struct { + g.Meta `path:"/search" method:"get" summary:"搜索数据源" tags:"数据源"` + *model.DataSourceSearchInput +} +type DataSourceSearchRes struct { + *model.DataSourceSearchOutput +} + +type DataSourceListReq struct { + g.Meta `path:"/list" method:"get" summary:"数据源列表" tags:"数据源"` +} +type DataSourceListRes struct { + List []*entity.DataSource `json:"list" dc:"数据源列表"` +} + +type DataSourceReq struct { + g.Meta `path:"/detail" method:"get" summary:"数据源详情" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceRes struct { + Data *model.DataSourceOutput `json:"data" dc:"数据源详情"` +} + +type DataSourceDeployReq struct { + g.Meta `path:"/deploy" method:"post" summary:"发布" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceDeployRes struct{} + +type DataSourceUndeployReq struct { + g.Meta `path:"/undeploy" method:"post" summary:"停用" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceUndeployRes struct{} + +type DataSourceDataReq struct { + g.Meta `path:"/getdata" method:"get" summary:"获取源数据记录" tags:"数据源"` + *model.DataSourceDataInput +} +type DataSourceDataRes struct { + *model.DataSourceDataOutput +} + +type DataSourceCopyReq struct { + g.Meta `path:"/copy" method:"post" summary:"复制数据源" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceCopyRes struct{} diff --git a/api/v1/source/source_db.go b/api/v1/source/source_db.go new file mode 100644 index 0000000..c62fa0c --- /dev/null +++ b/api/v1/source/source_db.go @@ -0,0 +1,35 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataSourceDbAddReq struct { + g.Meta `path:"/db/add" method:"post" summary:"添加数据库数据源" tags:"数据源"` + *model.DataSourceDbAddInput +} +type DataSourceDbAddRes struct{} + +type DataSourceDbEditReq struct { + g.Meta `path:"/db/edit" method:"put" summary:"编辑数据库数据源" tags:"数据源"` + *model.DataSourceDbEditInput +} +type DataSourceDbEditRes struct{} + +type DataSourceDbGetReq struct { + g.Meta `path:"/db/get" method:"get" summary:"获取数据库数据" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceDbGetRes struct { + Data string `json:"data" dc:"数据库源数据"` +} + +type DataSourceDbFieldsReq struct { + g.Meta `path:"/db/fields" method:"get" summary:"获取数据表字段" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceDbFieldsRes struct { + Data g.MapStrAny `json:"data" dc:"数据表字段"` +} diff --git a/api/v1/source/source_device.go b/api/v1/source/source_device.go new file mode 100644 index 0000000..0f173f4 --- /dev/null +++ b/api/v1/source/source_device.go @@ -0,0 +1,27 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataSourceDeviceAddReq struct { + g.Meta `path:"/device/add" method:"post" summary:"添加设备数据源" tags:"数据源"` + *model.DataSourceDeviceAddInput +} +type DataSourceDeviceAddRes struct{} + +type DataSourceDeviceEditReq struct { + g.Meta `path:"/device/edit" method:"put" summary:"编辑设备数据源" tags:"数据源"` + *model.DataSourceDeviceEditInput +} +type DataSourceDeviceEditRes struct{} + +type DataSourceDeviceGetReq struct { + g.Meta `path:"/device/get" method:"get" summary:"获取设备数据" tags:"数据源"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` +} +type DataSourceDeviceGetRes struct { + Data string `json:"data" dc:"设备源数据"` +} diff --git a/api/v1/source/template.go b/api/v1/source/template.go new file mode 100644 index 0000000..8631898 --- /dev/null +++ b/api/v1/source/template.go @@ -0,0 +1,97 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataTemplateAddReq struct { + g.Meta `path:"/template/add" method:"post" summary:"添加数据模型" tags:"数据建模"` + *model.DataTemplateAddInput +} +type DataTemplateAddRes struct{} + +type DataTemplateEditReq struct { + g.Meta `path:"/template/edit" method:"put" summary:"编辑数据模型" tags:"数据建模"` + *model.DataTemplateEditInput +} +type DataTemplateEditRes struct{} + +type DataTemplateDelReq struct { + g.Meta `path:"/template/del" method:"delete" summary:"删除数据模型" tags:"数据建模"` + Ids []uint64 `json:"ids" dc:"数据模型Ids" v:"required#数据模型ID不能为空"` +} +type DataTemplateDelRes struct{} + +type DataTemplateSearchReq struct { + g.Meta `path:"/template/search" method:"get" summary:"搜索数据模型" tags:"数据建模"` + *model.DataTemplateSearchInput +} +type DataTemplateSearchRes struct { + *model.DataTemplateSearchOutput +} + +type DataTemplateListReq struct { + g.Meta `path:"/template/list" method:"get" summary:"已发布数据模型列表" tags:"数据建模"` +} +type DataTemplateListRes struct { + List []*entity.DataTemplate `json:"list" dc:"数据模型列表"` +} + +type DataTemplateReq struct { + g.Meta `path:"/template/detail" method:"get" summary:"数据模型详情" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateRes struct { + Data *model.DataTemplateOutput `json:"data" dc:"数据模型详情"` +} + +type DataTemplateDeployReq struct { + g.Meta `path:"/template/deploy" method:"post" summary:"发布" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateDeployRes struct{} + +type DataTemplateUndeployReq struct { + g.Meta `path:"/template/undeploy" method:"post" summary:"停用" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateUndeployRes struct{} + +type DataTemplateDataReq struct { + g.Meta `path:"/template/getdata" method:"get" summary:"获取模型数据" tags:"数据建模"` + *model.DataTemplateDataInput +} +type DataTemplateDataRes struct { + *model.DataTemplateDataOutput +} + +type DataTemplateCopyReq struct { + g.Meta `path:"/template/copy" method:"post" summary:"复制模型" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateCopyRes struct{} + +type DataTemplateCheckRelationReq struct { + g.Meta `path:"/template/relation_check" method:"get" summary:"检测数据模型是否需要设置关联" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateCheckRelationRes struct { + Yes bool `json:"yes" dc:"是否需要设置关联: true:需要设置, false:不需要"` +} + +type DataTemplateRelationReq struct { + g.Meta `path:"/template/relation" method:"post" summary:"设置主源、关联字段" tags:"数据建模"` + *model.TemplateDataRelationInput +} +type DataTemplateRelationRes struct{} + +type TemplateSourceListReq struct { + g.Meta `path:"/template/source_list" method:"get" summary:"数据模型源列表" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type TemplateSourceListRes struct { + List []*model.DataSourceOutput +} diff --git a/api/v1/source/template_node.go b/api/v1/source/template_node.go new file mode 100644 index 0000000..87868aa --- /dev/null +++ b/api/v1/source/template_node.go @@ -0,0 +1,33 @@ +package source + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DataTemplateNodeAddReq struct { + g.Meta `path:"/template/node/add" method:"post" summary:"添加数据模型节点" tags:"数据建模"` + *model.DataTemplateNodeAddInput +} +type DataTemplateNodeAddRes struct{} + +type DataTemplateNodeEditReq struct { + g.Meta `path:"/template/node/edit" method:"put" summary:"编辑数据模型节点" tags:"数据建模"` + *model.DataTemplateNodeEditInput +} +type DataTemplateNodeEditRes struct{} + +type DataTemplateNodeDelReq struct { + g.Meta `path:"/template/node/del" method:"delete" summary:"删除数据模型节点" tags:"数据建模"` + Id uint64 `json:"id" dc:"数据模型节点ID" v:"required#数据模型节点ID不能为空"` +} +type DataTemplateNodeDelRes struct{} + +type DataTemplateNodeListReq struct { + g.Meta `path:"/template/node/list" method:"get" summary:"数据模型节点列表" tags:"数据建模"` + Tid uint64 `json:"tid" dc:"数据模型ID" v:"required#数据模型ID不能为空"` +} +type DataTemplateNodeListRes struct { + List []*model.DataTemplateNodeOutput `json:"list" dc:"数据模型节点列表"` +} diff --git a/api/v1/system/captcha.go b/api/v1/system/captcha.go new file mode 100644 index 0000000..7328ac9 --- /dev/null +++ b/api/v1/system/captcha.go @@ -0,0 +1,14 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +type CaptchaIndexReq struct { + g.Meta `path:"/captcha" method:"get" tags:"登录" summary:"获取默认的验证码"` +} +type CaptchaIndexRes struct { + g.Meta `mime:"application/json"` + Key string `json:"key" dc:"key"` + Img string `json:"img" dc:"图片"` +} diff --git a/api/v1/system/login.go b/api/v1/system/login.go new file mode 100644 index 0000000..2fe5366 --- /dev/null +++ b/api/v1/system/login.go @@ -0,0 +1,24 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type LoginDoReq struct { + g.Meta `path:"/login" method:"post" summary:"执行登录请求" tags:"登录"` + UserName string `json:"userName" v:"required#请输入账号" dc:"账号"` + Password string `json:"password" v:"required#请输入密码" dc:"密码"` + Captcha string `json:"captcha" v:"required#请输入验证码" dc:"验证码"` + VerifyKey string `json:"verifyKey"` +} +type LoginDoRes struct { + UserInfo *model.LoginUserRes `json:"userInfo"` + Token string `json:"token"` +} + +type LoginOutReq struct { + g.Meta `path:"/loginOut" method:"post" summary:"退出" tags:"登录"` +} +type LoginOutRes struct { +} diff --git a/api/v1/system/sys_api.go b/api/v1/system/sys_api.go new file mode 100644 index 0000000..5dcade8 --- /dev/null +++ b/api/v1/system/sys_api.go @@ -0,0 +1,79 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type GetApiAllReq struct { + g.Meta `path:"/api/GetAll" method:"get" summary:"获取所有接口" tags:"接口API管理"` +} +type GetApiAllRes struct { + Data []*model.SysApiAllRes +} + +type GetApiTreeReq struct { + g.Meta `path:"/api/tree" method:"get" summary:"获取接口列表" tags:"接口API管理"` + Name string `json:"name" description:"名称"` + Address string `json:"address" description:"接口地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Types int `json:"types" description:"类型 1 分类 2接口"` +} +type GetApiTreeRes struct { + Info []*model.SysApiTreeRes +} + +type AddApiReq struct { + g.Meta `path:"/api/add" method:"post" summary:"添加Api" tags:"接口API管理"` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Types int `json:"types" description:"1 分类 2接口" v:"required#请选择类型"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + MenuIds []int `json:"menuIds" description:"菜单Id数组"` +} + +type AddApiRes struct { +} + +type EditApiReq struct { + g.Meta `path:"/api/edit" method:"put" summary:"编辑Api" tags:"接口API管理"` + Id int `json:"id" description:"" v:"required#ApiId不能为空"` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Types int `json:"types" description:"1 分类 2接口" v:"required#请选择类型"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址" ` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + MenuIds []int `json:"menuIds" description:"菜单Id数组"` +} +type EditApiRes struct { +} + +type DetailApiReq struct { + g.Meta `path:"/api/detail" method:"get" summary:"根据ID获取Api详情" tags:"接口API管理"` + Id int `json:"id" description:"ApiID" v:"required#ID不能为空"` +} +type DetailApiRes struct { + Data *model.SysApiRes +} + +type DelApiReq struct { + g.Meta `path:"/api/del" method:"delete" summary:"根据ID删除Api" tags:"接口API管理"` + Id int `json:"id" description:"ApiID" v:"required#ID不能为空"` +} +type DelApiRes struct { +} + +type EditApiStatusReq struct { + g.Meta `path:"/api/editStatus" method:"put" summary:"编辑Api状态" tags:"接口API管理"` + Id int `json:"id" description:"接口ID" v:"required#ID不能为空"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type EditApiStatusRes struct { +} diff --git a/api/v1/system/sys_authorize.go b/api/v1/system/sys_authorize.go new file mode 100644 index 0000000..3c44970 --- /dev/null +++ b/api/v1/system/sys_authorize.go @@ -0,0 +1,34 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type AuthorizeQueryReq struct { + g.Meta `path:"/authorize/query" method:"get" summary:"根据类型获取当前用户的权限" tags:"权限管理"` + ItemsType string `json:"itemsType" description:"类型menu菜单 button按钮 column列表字段 api 接口" v:"required#项目类型不能为空" ` + MenuIds []int `json:"menuIds" description:"菜单ID"` +} +type AuthorizeQueryRes struct { + Data []*model.AuthorizeQueryTreeRes +} + +type AddAuthorizeReq struct { + g.Meta `path:"/authorize/Add" method:"post" summary:"添加权限" tags:"权限管理"` + MenuIds []string `json:"menuIds" description:"菜单ID" v:"required#菜单ID不能为空"` + ButtonIds []string `json:"buttonIds" description:"按钮ID"` + ColumnIds []string `json:"columnIds" description:"列表字段ID"` + ApiIds []string `json:"apiIds" description:"接口Ids"` + RoleId int `json:"roleId" description:"角色ID" v:"required#角色ID不能为空"` +} +type AddAuthorizeRes struct { +} + +type IsAllowAuthorizeReq struct { + g.Meta `path:"/authorize/isAllow" method:"get" summary:"判断是否允许给角色授权" tags:"权限管理"` + RoleId int `json:"roleId" description:"角色ID" v:"required#角色ID不能为空"` +} +type IsAllowAuthorizeRes struct { + IsAllow bool `json:"isAllow" description:"是否允许 true允许 false不允许"` +} diff --git a/api/v1/system/sys_dept.go b/api/v1/system/sys_dept.go new file mode 100644 index 0000000..42d5622 --- /dev/null +++ b/api/v1/system/sys_dept.go @@ -0,0 +1,60 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type DeptDoReq struct { + g.Meta `path:"/dept/tree" method:"get" summary:"获取部门列表" tags:"部门管理"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用" ` + DeptName string `p:"dept_name" description:"部门名称"` +} +type DeptDoRes struct { + Data []*model.DeptRes +} + +type AddDeptReq struct { + g.Meta `path:"/dept/add" method:"post" summary:"添加部门" tags:"部门管理"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + OrganizationId int `json:"organizationId" description:"组织ID" v:"required#请输入选择组织"` + DeptName string `json:"deptName" description:"部门名称" v:"required#请输入部门名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)" v:"required#请选择状态"` + Leader string `json:"leader" description:"负责人" v:"required#请输入部门负责人"` + Phone string `json:"phone" description:"联系电话" v:"phone#请输入联系电话或格式错误"` + Email string `json:"email" description:"邮箱"` +} +type AddDeptRes struct { +} + +type EditDeptReq struct { + g.Meta `path:"/dept/edit" method:"put" summary:"编辑部门" tags:"部门管理"` + DeptId int64 `json:"deptId" description:"部门id"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + OrganizationId int `json:"organizationId" description:"组织ID" v:"required#请输入选择组织"` + DeptName string `json:"deptName" description:"部门名称" v:"required#请输入部门名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)" v:"required#请选择状态"` + Leader string `json:"leader" description:"负责人" v:"required#请输入部门负责人"` + Phone string `json:"phone" description:"联系电话" v:"phone#请输入联系电话或格式错误"` + Email string `json:"email" description:"邮箱"` +} +type EditDeptRes struct { +} + +type DetailDeptReq struct { + g.Meta `path:"/dept/detail" method:"get" summary:"根据ID获取部门详情" tags:"部门管理"` + DeptId int64 `p:"dept_id" description:"部门ID" v:"required#ID不能为空"` +} +type DetailDeptRes struct { + Data *model.DetailDeptRes +} + +type DelDeptReq struct { + g.Meta `path:"/dept/del" method:"delete" summary:"根据ID删除部门" tags:"部门管理"` + DeptId int64 `p:"dept_id" description:"部门ID" v:"required#ID不能为空"` +} +type DelDeptRes struct { +} diff --git a/api/v1/system/sys_job.go b/api/v1/system/sys_job.go new file mode 100644 index 0000000..54b7926 --- /dev/null +++ b/api/v1/system/sys_job.go @@ -0,0 +1,89 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type GetJobListReq struct { + g.Meta `path:"/job/list" method:"get" summary:"获取任务列表" tags:"定时任务管理"` + JobName string `json:"jobName" description:"任务名称"` + JobGroup string `json:"jobGroup" description:"任务组名"` + Status string `json:"status" description:"状态(0正常 1暂停)"` + *common.PaginationReq +} +type GetJobListRes struct { + Data []*model.SysJobRes + common.PaginationRes +} + +type AddJobReq struct { + g.Meta `path:"/job/add" method:"post" summary:"添加定时任务" tags:"定时任务管理"` + JobName string `json:"jobName" description:"任务名称" v:"required#任务名称不能来空"` + JobParams string `json:"jobParams" description:"任务参数"` + JobGroup string `json:"jobGroup" description:"分组"` + InvokeTarget string `json:"invokeTarget" description:"执行方法" v:"required#执行方法不能为空"` + CronExpression string `json:"cronExpression" description:"任务执行表达式" v:"required#任务表达式不能为空"` + MisfirePolicy int `json:"misfirePolicy"` + Concurrent int `json:"concurrent" ` + Status int `json:"status" description:"状态" v:"required#状态(0正常 1暂停)不能为空"` + Remark string `json:"remark" ` + CreateBy uint64 +} +type AddJobRes struct { +} + +type EditJobReq struct { + g.Meta `path:"/job/edit" method:"put" summary:"编辑定时任务" tags:"定时任务管理"` + JobId int64 `json:"job_id" v:"min:1#任务id不能为空"` + JobName string `json:"jobName" description:"任务名称" v:"required#任务名称不能来空"` + JobParams string `json:"jobParams" description:"任务参数"` + JobGroup string `json:"jobGroup" description:"分组"` + InvokeTarget string `json:"invokeTarget" description:"执行方法" v:"required#执行方法不能为空"` + CronExpression string `json:"cronExpression" description:"任务执行表达式" v:"required#任务表达式不能为空"` + MisfirePolicy int `json:"misfirePolicy"` + Concurrent int `json:"concurrent" ` + Status int `json:"status" description:"状态" v:"required#状态(0正常 1暂停)不能为空"` + Remark string `json:"remark" ` + CreateBy uint64 + UpdateBy uint64 +} +type EditJobRes struct { +} + +type DeleteJobByIdReq struct { + g.Meta `path:"/job/delJobById" method:"delete" summary:"根据ID删除任务" tags:"定时任务管理"` + Id []int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type DeleteJobByIdRes struct { +} + +type GetJobByIdReq struct { + g.Meta `path:"/job/getJobById" method:"get" summary:"根据ID获取任务" tags:"定时任务管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type GetJobByIdRes struct { + Data *model.SysJobRes +} + +type StartJobByIdReq struct { + g.Meta `path:"/job/start" method:"put" summary:"开始一个任务" tags:"定时任务管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type StartJobByIdRes struct { +} + +type StopJobByIdReq struct { + g.Meta `path:"/job/stop" method:"put" summary:"结束一个任务" tags:"定时任务管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type StopJobByIdRes struct { +} + +type RunJobByIdReq struct { + g.Meta `path:"/job/run" method:"put" summary:"执行一个任务" tags:"定时任务管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type RunJobByIdRes struct { +} diff --git a/api/v1/system/sys_login_log.go b/api/v1/system/sys_login_log.go new file mode 100644 index 0000000..805d379 --- /dev/null +++ b/api/v1/system/sys_login_log.go @@ -0,0 +1,53 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +type SysLoginLogDoReq struct { + g.Meta `path:"/login/log/list" tags:"访问日志管理" method:"get" summary:"访问日志列表"` + LoginName string `p:"login_name" description:"登录账号"` + Ipaddr string `p:"ipaddr" description:"登录IP地址"` + LoginLocation string `p:"login_location" description:"登录地点"` + Browser string `p:"browser" description:"浏览器类型"` + Os string `p:"os" description:"操作系统"` + Status int `p:"status" description:"登录状态(0失败 1成功)"` + *common.PaginationReq +} +type SysLoginLogDoRes struct { + Data []*model.SysLoginLogOut + common.PaginationRes +} + +type SysLoginLogDoExportReq struct { + g.Meta `path:"/login/log/export" tags:"访问日志管理" method:"get" summary:"访问日志导出"` + LoginName string `p:"login_name" description:"登录账号"` + Ipaddr string `p:"ipaddr" description:"登录IP地址"` + LoginLocation string `p:"login_location" description:"登录地点"` + Browser string `p:"browser" description:"浏览器类型"` + Os string `p:"os" description:"操作系统"` + Status int `p:"status" description:"登录状态(0失败 1成功)"` + common.PaginationReq +} +type SysLoginLogDoExportRes struct { + g.Meta `mime:"text/html" example:"string"` +} + +type DetailSysLoginLogReq struct { + g.Meta `path:"/login/log/detail" tags:"访问日志管理" method:"get" summary:"根据ID获取访问日志详情"` + InfoId int `json:"infoId" description:"访问日志ID" v:"required#日志ID不能为空"` +} +type DetailSysLoginLogRes struct { + Data *entity.SysLoginLog +} + +type DelSysLoginLogReq struct { + g.Meta `path:"/login/log/del" method:"delete" summary:"根据ID删除访问日志" tags:"访问日志管理"` + InfoIds []int `json:"infoIds" description:"访问日志ID" v:"required#ID不能为空"` +} +type DelSysLoginLogRes struct { +} diff --git a/api/v1/system/sys_menu.go b/api/v1/system/sys_menu.go new file mode 100644 index 0000000..1b9894d --- /dev/null +++ b/api/v1/system/sys_menu.go @@ -0,0 +1,210 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type MenuDoReq struct { + g.Meta `path:"/menu/tree" tags:"菜单管理" method:"get" summary:"菜单列表"` + Title string `p:"title" dc:"菜单标题"` + Status int `p:"status" dc:"状态:0为停用,1为正常"` +} +type MenuDoRes struct { + Data []*model.SysMenuRes +} + +type AddMenuReq struct { + g.Meta `path:"/menu/add" tags:"菜单管理" method:"post" summary:"添加菜单"` + MenuType uint `p:"menuType" v:"min:0|max:2#菜单类型最小值为:min|菜单类型最大值为:max" dc:"菜单类型 0目录 1菜单 2按钮"` + ParentId int `p:"parentId" v:"required#请选择上级" dc:"父ID"` + Name string `p:"name" v:"required#请填写规则名称" dc:"规则名称:具有唯一性"` + Title string `p:"title" v:"required|length:1,100#请填写标题|标题长度在:min到:max位" dc:"规则名称"` + Icon string `p:"icon" dc:"图标"` + Weigh int `p:"weigh" dc:"权重"` + Condition string `p:"condition" dc:"条件"` + Remark string `p:"remark" dc:"备注"` + IsHide uint `p:"isHide" dc:"显示状态"` + Path string `p:"path" dc:"路由地址"` + Component string `p:"component" v:"required-if:menuType,1#组件路径不能为空" dc:"组件路径"` + IsLink uint `p:"isLink" dc:"是否外链 1是 0否"` + IsIframe uint `p:"isIframe" dc:"是否内嵌iframe"` + IsCached uint `p:"isKeepAlive" dc:"是否缓存"` + IsAffix uint `p:"isAffix" dc:"是否固定"` + LinkUrl string `p:"linkUrl" dc:"链接地址"` + Status int `p:"status" dc:"状态 0 停用 1启用"` + ModuleType string `p:"moduleType" dc:"所属模块 system 运维 company企业"` +} +type AddMenuRes struct { +} + +type DetailMenuReq struct { + g.Meta `path:"/menu/detail" tags:"菜单管理" method:"get" summary:"根据ID获取菜单详情"` + Id int64 `p:"id" description:"菜单ID" v:"required#ID不能为空"` +} +type DetailMenuRes struct { + Data *model.DetailMenuRes +} + +type EditMenuReq struct { + g.Meta `path:"/menu/edit" method:"put" summary:"编辑菜单" tags:"菜单管理"` + Id int64 `json:"id" description:"菜单ID" v:"required#菜单ID不能为空"` + MenuType uint `p:"menuType" v:"min:0|max:2#菜单类型最小值为:min|菜单类型最大值为:max" dc:"菜单类型 0目录 1菜单 2按钮"` + ParentId int `p:"parentId" v:"required#请选择上级" dc:"父ID"` + Name string `p:"name" v:"required#请填写规则名称" dc:"规则名称:具有唯一性"` + Title string `p:"title" v:"required|length:1,100#请填写标题|标题长度在:min到:max位" dc:"规则名称"` + Icon string `p:"icon" dc:"图标"` + Weigh int `p:"weigh" dc:"权重"` + Condition string `p:"condition" dc:"条件"` + Remark string `p:"remark" dc:"备注"` + IsHide uint `p:"isHide" dc:"显示状态"` + Path string `p:"path" dc:"路由地址"` + Component string `p:"component" v:"required-if:menuType,1#组件路径不能为空" dc:"组件路径"` + IsLink uint `p:"isLink" dc:"是否外链 1是 0否"` + IsIframe uint `p:"isIframe" dc:"是否内嵌iframe"` + IsCached uint `p:"isKeepAlive" dc:"是否缓存"` + IsAffix uint `p:"isAffix" dc:"是否固定"` + LinkUrl string `p:"linkUrl" dc:"链接地址"` + Status int `p:"status" dc:"状态 0 停用 1启用"` + ModuleType string `p:"moduleType" dc:"所属模块 system 运维 company企业"` +} +type EditMenuRes struct { +} + +type DelMenuReq struct { + g.Meta `path:"/menu/del" method:"delete" summary:"根据ID删除菜单" tags:"菜单管理"` + Id int64 `p:"id" description:"菜单ID" v:"required#ID不能为空"` +} +type DelMenuRes struct { +} + +//********** 菜单按钮关联开始 ********** + +type MenuButtonDoReq struct { + g.Meta `path:"/menu/button/tree" tags:"菜单管理" method:"get" summary:"菜单与按钮树列表"` + MenuId int `json:"menuId" dc:"菜单ID" v:"required#菜单ID不能为空"` + ParentId int `json:"parentId" dc:"父ID"` + Status int `json:"status" dc:"状态:-1为全部,0为正常,1为停用"` + Name string `json:"name" dc:"名称"` +} +type MenuButtonDoRes struct { + Data []*model.UserMenuButtonRes +} + +type AddMenuButtonReq struct { + g.Meta `path:"/menu/button/add" tags:"菜单管理" method:"post" summary:"添加菜单与按钮相关关联"` + ParentId int `json:"parentId" description:"父ID" v:"required#请选择上级"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择菜单ID"` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除" v:"required#请选择类型"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type AddMenuButtonRes struct { +} + +type DetailMenuButtonReq struct { + g.Meta `path:"/menu/button/detail" tags:"菜单管理" method:"get" summary:"根据ID获取菜单按钮详情"` + Id int64 `p:"id" description:"菜单按钮ID" v:"required#ID不能为空"` +} +type DetailMenuButtonRes struct { + Data *model.DetailMenuButtonRes +} + +type EditMenuButtonReq struct { + g.Meta `path:"/menu/button/edit" method:"put" summary:"编辑菜单按钮" tags:"菜单管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` + ParentId int `json:"parentId" description:"父ID" v:"required#请选择上级"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择关联菜单"` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除" v:"required#请选择类型"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type EditMenuButtonRes struct { +} + +type DelMenuButtonReq struct { + g.Meta `path:"/menu/button/del" method:"delete" summary:"根据ID删除菜单按钮" tags:"菜单管理"` + Id int64 `json:"id" description:"菜单按钮ID" v:"required#ID不能为空"` +} +type DelMenuButtonRes struct { +} + +type EditMenuButtonStatusReq struct { + g.Meta `path:"/menu/button/editStatus" method:"put" summary:"编辑菜单按钮状态" tags:"菜单管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择关联菜单"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} + +type EditMenuButtonStatusRes struct { +} + +//********** 菜单按钮关联结束 ********** + +//********** 菜单列表关联开始 ********** + +type MenuColumnDoReq struct { + g.Meta `path:"/menu/column/tree" tags:"菜单管理" method:"get" summary:"菜单与列表树列表"` + MenuId string `json:"menuId" dc:"菜单ID" v:"required#菜单ID不能为空"` + ParentId string `json:"parentId" dc:"父ID"` + Status int `json:"status" dc:"状态:-1为全部,0为正常,1为停用"` + Name string `json:"name" dc:"名称"` +} +type MenuColumnDoRes struct { + Data []*model.UserMenuColumnRes +} + +type AddMenuColumnReq struct { + g.Meta `path:"/menu/column/add" tags:"菜单管理" method:"post" summary:"添加菜单与列表相关关联"` + ParentId int `json:"parentId" description:"父ID" v:"required#请选择上级"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择菜单ID"` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type AddMenuColumnRes struct { +} + +type DetailMenuColumnReq struct { + g.Meta `path:"/menu/column/detail" tags:"菜单管理" method:"get" summary:"根据ID获取菜单列表详情"` + Id int64 `p:"id" description:"菜单列表ID" v:"required#ID不能为空"` +} +type DetailMenuColumnRes struct { + Data *model.DetailMenuColumnRes +} + +type EditMenuColumnReq struct { + g.Meta `path:"/menu/column/edit" method:"put" summary:"编辑菜单列表" tags:"菜单管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` + ParentId int `json:"parentId" description:"父ID" v:"required#请选择上级"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择关联菜单"` + Name string `json:"name" description:"名称" v:"required#请输入名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} +type EditMenuColumnRes struct { +} + +type DelMenuColumnReq struct { + g.Meta `path:"/menu/column/del" method:"delete" summary:"根据ID删除菜单列表" tags:"菜单管理"` + Id int64 `p:"id" description:"菜单列表ID" v:"required#ID不能为空"` +} +type DelMenuColumnRes struct { +} + +type EditMenuColumnStatusReq struct { + g.Meta `path:"/menu/column/editStatus" method:"put" summary:"编辑菜单列表状态" tags:"菜单管理"` + Id int `json:"id" description:"" v:"required#ID不能为空"` + MenuId int `json:"menuId" description:"菜单ID" v:"required#请选择关联菜单"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} + +type EditMenuColumnStatusRes struct { +} + +//********** 菜单列表关联结束 ********** diff --git a/api/v1/system/sys_monitor.go b/api/v1/system/sys_monitor.go new file mode 100644 index 0000000..5205cec --- /dev/null +++ b/api/v1/system/sys_monitor.go @@ -0,0 +1,9 @@ +package system + +import "github.com/gogf/gf/v2/frame/g" + +type MonitorSearchReq struct { + g.Meta `path:"/monitor/server" tags:"服务监控" method:"get" summary:"服务监控"` +} + +type MonitorSearchRes g.Map diff --git a/api/v1/system/sys_notifications.go b/api/v1/system/sys_notifications.go new file mode 100644 index 0000000..278b825 --- /dev/null +++ b/api/v1/system/sys_notifications.go @@ -0,0 +1,58 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +//获取列表api +type GetNotificationsListReq struct { + g.Meta `path:"/notifications/list" method:"get" summary:"获取消息列表" tags:"通知中心管理"` + common.PaginationReq +} +type GetNotificationsListRes struct { + Data []*model.NotificationsRes + common.PaginationRes +} + +//获取指定ID的数据api +type GetNotificationsByIdReq struct { + g.Meta `path:"/notifications/get" method:"get" summary:"获取消息列表" tags:"通知中心管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetNotificationsByIdRes struct { + Data *model.NotificationsRes +} + +//添加数据api +type AddNotificationsReq struct { + g.Meta `path:"/notifications/add" method:"post" summary:"添加消息" tags:"通知中心管理"` + Types string `json:"types" description:"类型"` + CreatedAt string `json:"createdAt" description:"发送时间"` + Status string `json:"status" description:"0,未读,1,已读"` + Title string `json:"title" description:"标题"` + Doc string `json:"doc" description:"描述"` + Source string `json:"source" description:"消息来源"` +} +type AddNotificationsRes struct{} + +//编辑数据api +type EditNotificationsReq struct { + g.Meta `path:"/notifications/edit" method:"put" summary:"编辑消息" tags:"通知中心管理"` + Id string `json:"id" description:""` + Title string `json:"title" description:"标题"` + Doc string `json:"doc" description:"描述"` + Source string `json:"source" description:"消息来源"` + Types string `json:"types" description:"类型"` + CreatedAt string `json:"createdAt" description:"发送时间"` + Status string `json:"status" description:"0,未读,1,已读"` +} +type EditNotificationsRes struct{} + +//删除数据api +type DeleteNotificationsReq struct { + g.Meta `path:"/notifications/delete" method:"delete" summary:"删除消息" tags:"通知中心管理"` + Ids []int `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeleteNotificationsRes struct{} diff --git a/api/v1/system/sys_oper_log.go b/api/v1/system/sys_oper_log.go new file mode 100644 index 0000000..3861062 --- /dev/null +++ b/api/v1/system/sys_oper_log.go @@ -0,0 +1,53 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +type SysOperLogDoReq struct { + g.Meta `path:"/oper/log/list" tags:"操作日志管理" method:"get" summary:"操作日志列表"` + Title string `p:"title" description:"模块标题"` + BusinessType string `p:"business_type" description:"业务类型(0其它 1新增 2修改 3删除)"` + Method string `p:"method" description:"方法名称"` + RequestMethod string `p:"request_method" description:"请求方式"` + OperatorType string `p:"operator_type" description:"操作类别(0其它 1后台用户 2手机端用户)"` + OperName string `p:"oper_name" description:"操作人员"` + DeptName string `p:"dept_name" description:"部门名称"` + OperUrl string `p:"oper_url" description:"请求URL"` + OperIp string `p:"oper_ip" description:"主机地址"` + OperLocation string `p:"oper_location" description:"操作地点"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用"` + *common.PaginationReq +} +type SysOperLogDoRes struct { + Data []*model.SysOperLogRes + common.PaginationRes +} + +/** +type AddSysOperLogReq struct { + g.Meta `path:"/oper/log/add" tags:"操作日志管理" method:"post" summary:"添加操作日志"` + *entity.SysOperLog +} +type AddSysOperLogRes struct { +} +*/ + +type DetailSysOperLogReq struct { + g.Meta `path:"/oper/log/detail" tags:"操作日志管理" method:"get" summary:"根据ID获取操作日志详情"` + OperId int `json:"operId" description:"操作日志ID" v:"required#日志ID不能为空"` +} +type DetailSysOperLogRes struct { + Data *entity.SysOperLog +} + +type DelSysOperLogReq struct { + g.Meta `path:"/oper/log/del" method:"delete" summary:"根据ID删除操作日志" tags:"操作日志管理"` + OperIds []int `json:"operIds" description:"操作日志ID" v:"required#ID不能为空"` +} +type DelSysOperLogRes struct { +} diff --git a/api/v1/system/sys_organization.go b/api/v1/system/sys_organization.go new file mode 100644 index 0000000..dd5ead8 --- /dev/null +++ b/api/v1/system/sys_organization.go @@ -0,0 +1,65 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type OrganizationDoReq struct { + g.Meta `path:"/organization/tree" method:"get" summary:"获取组织列表" tags:"组织管理"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用" ` + Name string `p:"name" description:"组织名称"` +} +type OrganizationDoRes struct { + Data []*model.OrganizationRes +} + +type AddOrganizationReq struct { + g.Meta `path:"/organization/add" method:"post" summary:"添加组织" tags:"组织管理"` + ParentId int64 `json:"parentId" description:"父组织id"` + Name string `json:"name" description:"组织名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)" v:"required#请选择状态"` + Leader string `json:"leader" description:"负责人" v:"required#请输入部门负责人"` + Phone string `json:"phone" description:"联系电话" v:"phone#请输入联系电话或格式错误"` + Email string `json:"email" description:"邮箱"` +} +type AddOrganizationRes struct { +} + +type EditOrganizationReq struct { + g.Meta `path:"/organization/edit" method:"put" summary:"编辑组织" tags:"组织管理"` + Id int64 `json:"id" description:"组织id"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + Name string `json:"name" description:"组织名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)" v:"required#请选择状态"` + Leader string `json:"leader" description:"负责人" v:"required#请输入部门负责人"` + Phone string `json:"phone" description:"联系电话" v:"phone#请输入联系电话或格式错误"` + Email string `json:"email" description:"邮箱"` +} +type EditOrganizationRes struct { +} + +type DetailOrganizationReq struct { + g.Meta `path:"/organization/detail" method:"get" summary:"根据ID获取组织详情" tags:"组织管理"` + Id int64 `p:"id" description:"组织ID" v:"required#ID不能为空"` +} +type DetailOrganizationRes struct { + Data *model.DetailOrganizationRes +} + +type DelOrganizationReq struct { + g.Meta `path:"/organization/del" method:"delete" summary:"根据ID删除组织" tags:"组织管理"` + Id int64 `p:"id" description:"组织ID" v:"required#ID不能为空"` +} +type DelOrganizationRes struct { +} + +type GetOrganizationCountReq struct { + g.Meta `path:"/organization/count" method:"get" summary:"获取组织数量" tags:"组织管理"` +} +type GetOrganizationCountRes struct { + Count int +} diff --git a/api/v1/system/sys_plugins.go b/api/v1/system/sys_plugins.go new file mode 100644 index 0000000..f205721 --- /dev/null +++ b/api/v1/system/sys_plugins.go @@ -0,0 +1,40 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" +) + +//GetSysPluginsListReq 获取数据列表 +type GetSysPluginsListReq struct { + g.Meta `path:"/plugins/list" method:"get" summary:"获取插件列表" tags:"插件管理"` + common.PaginationReq +} +type GetSysPluginsListRes struct { + Data []GetSysPluginsByIdRes + common.PaginationRes +} + +//GetSysPluginsByIdReq 获取指定ID的数据 +type GetSysPluginsByIdReq struct { + g.Meta `path:"/plugins/get" method:"get" summary:"获取插件" tags:"插件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetSysPluginsByIdRes struct { + Version string `json:"version" description:"版本"` + Author string `json:"author" description:""` + StartTime string `json:"startTime" description:""` + Id int `json:"id" description:"ID"` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Intro string `json:"intro" description:"介绍"` + Status int `json:"status" description:"状态"` + Types string `json:"types" description:"插件类型"` +} + +type EditSysPluginsStatusReq struct { + g.Meta `path:"/plugins/set" method:"post" summary:"设置插件状态" tags:"插件管理"` + Id int `json:"id" description:"ID"` + Status int `json:"status" description:"状态,0停用,1启用"` +} +type EditSysPluginsStatusRes struct{} diff --git a/api/v1/system/sys_plugins_config.go b/api/v1/system/sys_plugins_config.go new file mode 100644 index 0000000..58d79ca --- /dev/null +++ b/api/v1/system/sys_plugins_config.go @@ -0,0 +1,81 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" +) + +//GetPluginsConfigListReq 获取数据列表 +type GetPluginsConfigListReq struct { + g.Meta `path:"/plugins_config/list" method:"get" summary:"获取插件配置列表" tags:"插件管理"` + common.PaginationReq +} +type GetPluginsConfigListRes struct { + Data []GetPluginsConfigByIdRes + common.PaginationRes +} + +//GetPluginsConfigByIdReq 获取指定ID的数据 +type GetPluginsConfigByIdReq struct { + g.Meta `path:"/plugins_config/get" method:"get" summary:"获取插件配置" tags:"插件管理"` + Id int `json:"id" description:"id" v:"required#id不能为空"` +} +type GetPluginsConfigByIdRes struct { + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` + Id string `json:"id" description:""` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` +} + +//GetPluginsConfigByNameReq 获取指定类型与名称的的插件数据 +type GetPluginsConfigByNameReq struct { + g.Meta `path:"/plugins_config/getbyname" method:"get" summary:"获取指定类型与名称的的插件数据" tags:"插件管理"` + Type string `json:"type" description:"type" v:"required#类型不能为空"` + Name string `json:"name" description:"name" v:"required#名称不能为空"` +} +type GetPluginsConfigByNameRes struct { + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` + Id string `json:"id" description:""` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` +} + +//AddPluginsConfigReq 添加数据 +type AddPluginsConfigReq struct { + g.Meta `path:"/plugins_config/add" method:"post" summary:"添加插件配置" tags:"插件管理"` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` +} +type AddPluginsConfigRes struct{} + +//SavePluginsConfigReq 直接更新配置数据 +type SavePluginsConfigReq struct { + g.Meta `path:"/plugins_config/save" method:"post" summary:"直接更新配置数据" tags:"插件管理"` + Type string `json:"type" description:"type" v:"required#插件类型不能为空"` + Name string `json:"name" description:"name" v:"required#插件名称不能为空"` + Value string `json:"value" description:"配置内容,一行一条"` + Doc string `json:"doc" description:"配置说明"` +} +type SavePluginsConfigRes struct{} + +//EditPluginsConfigReq 编辑数据api +type EditPluginsConfigReq struct { + g.Meta `path:"/plugins_config/edit" method:"put" summary:"编辑插件配置" tags:"插件管理"` + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` + Id string `json:"id" description:""` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` +} +type EditPluginsConfigRes struct{} + +//DeletePluginsConfigReq 删除数据 +type DeletePluginsConfigReq struct { + g.Meta `path:"/plugins_config/delete" method:"delete" summary:"删除插件配置" tags:"插件管理"` + Ids []int `json:"ids" description:"ids" v:"required#ids不能为空"` +} +type DeletePluginsConfigRes struct{} diff --git a/api/v1/system/sys_post.go b/api/v1/system/sys_post.go new file mode 100644 index 0000000..d5f6341 --- /dev/null +++ b/api/v1/system/sys_post.go @@ -0,0 +1,55 @@ +package system + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type PostDoReq struct { + g.Meta `path:"/post/tree" method:"get" summary:"获取岗位列表" tags:"岗位管理"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用" ` + PostName string `p:"postName" description:"岗位名称"` + PostCode string `p:"postCode" description:"岗位编码"` +} +type PostDoRes struct { + Data []*model.PostRes +} + +type AddPostReq struct { + g.Meta `path:"/post/add" method:"post" summary:"添加岗位" tags:"岗位管理"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + PostName string `json:"postName" description:"岗位名称" v:"required#请输入岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} +type AddPostRes struct { +} + +type EditPostReq struct { + g.Meta `path:"/post/edit" method:"put" summary:"编辑岗位" tags:"岗位管理"` + PostId int64 `json:"postId" description:"岗位ID" v:"required#岗位ID不能为空"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + PostName string `json:"postName" description:"岗位名称" v:"required#请输入岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} +type EditPostRes struct { +} + +type DetailPostReq struct { + g.Meta `path:"/post/detail" method:"get" summary:"根据ID获取岗位详情" tags:"岗位管理"` + PostId int64 `p:"post_id" description:"岗位ID" v:"required#ID不能为空"` +} +type DetailPostRes struct { + Data *model.DetailPostRes +} + +type DelPostReq struct { + g.Meta `path:"/post/del" method:"delete" summary:"根据ID删除岗位" tags:"岗位管理"` + PostId int64 `p:"post_id" description:"岗位ID" v:"required#ID不能为空"` +} +type DelPostRes struct { +} diff --git a/api/v1/system/sys_role.go b/api/v1/system/sys_role.go new file mode 100644 index 0000000..8d884f6 --- /dev/null +++ b/api/v1/system/sys_role.go @@ -0,0 +1,74 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type RoleTreeReq struct { + g.Meta `path:"/role/tree" method:"get" summary:"角色树状列表" tags:"角色管理"` + Name string `json:"name" description:"角色名称"` + Status int `json:"status" description:"状态;0:禁用;1:正常"` +} +type RoleTreeRes struct { + Data []*model.RoleTreeRes +} + +type AddRoleReq struct { + g.Meta `path:"/role/add" method:"post" summary:"添加角色" tags:"角色管理"` + ParentId int `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + Name string `json:"name" description:"角色名称" v:"required#请输入名称"` + ListOrder uint `json:"listOrder" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} +type AddRoleRes struct { +} + +type EditRoleReq struct { + g.Meta `path:"/role/edit" method:"put" summary:"编辑角色" tags:"角色管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` + ParentId int `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + Name string `json:"name" description:"角色名称" v:"required#请输入名称"` + ListOrder uint `json:"listOrder" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} +type EditRoleRes struct { +} + +type GetRoleByIdReq struct { + g.Meta `path:"/role/getInfoById" method:"get" summary:"根据ID获取角色" tags:"角色管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` +} +type GetRoleByIdRes struct { + Data *model.RoleInfoRes +} + +type DeleteRoleByIdReq struct { + g.Meta `path:"/role/delInfoById" method:"delete" summary:"根据ID删除角色" tags:"角色管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` +} +type DeleteRoleByIdRes struct { +} + +type DataScopeReq struct { + g.Meta `path:"/role/dataScope" method:"post" summary:"角色数据权限授权" tags:"角色管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` + DataScope uint `json:"dataScope" description:"数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)" v:"required#数据权限范围不能为空不能为空"` + DeptIds []int64 `json:"deptIds"` +} + +type DataScopeRes struct { +} + +type GetAuthorizeByIdReq struct { + g.Meta `path:"/role/getAuthorizeById" method:"get" summary:"根据ID获取权限信息" tags:"角色管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type GetAuthorizeByIdRes struct { + MenuIds []string `json:"menuIds" description:"菜单ID"` + ButtonIds []string `json:"buttonIds" description:"按钮ID"` + ColumnIds []string `json:"columnIds" description:"列表字段ID"` + ApiIds []string `json:"apiIds" description:"接口Ids"` +} diff --git a/api/v1/system/sys_user.go b/api/v1/system/sys_user.go new file mode 100644 index 0000000..b154d6d --- /dev/null +++ b/api/v1/system/sys_user.go @@ -0,0 +1,133 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type UserListReq struct { + g.Meta `path:"/user/list" method:"get" summary:"用户列表" tags:"用户管理"` + KeyWords string `json:"keyWords" description:"关键词(可根据账号或者用户昵称查询)"` + DeptId int `json:"deptId" description:"部门ID"` + UserName string `json:"userName" description:"用户名"` + Mobile string `json:"mobile" description:"手机号"` + Status int `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + *common.PaginationReq +} +type UserListRes struct { + Data []*model.UserListRes + common.PaginationRes +} + +type AddUserReq struct { + g.Meta `path:"/user/add" method:"post" summary:"添加用户" tags:"用户管理"` + UserName string `json:"userName" description:"用户名" v:"required#用户名不能为空"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号" v:"required#手机号不能为空"` + UserNickname string `json:"userNickname" description:"用户昵称" v:"required#用户昵称不能为空"` + Birthday int `json:"birthday" description:"生日"` + UserPassword string `json:"userPassword" description:"登录密码;cmf_password加密"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id" v:"required#部门不能为空"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} +type AddUserRes struct { +} + +type EditUserReq struct { + g.Meta `path:"/user/edit" method:"put" summary:"编辑用户" tags:"用户管理"` + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名" v:"required#用户名不能为空"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号" v:"required#手机号不能为空"` + UserNickname string `json:"userNickname" description:"用户昵称" v:"required#用户昵称不能为空"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id" v:"required#部门不能为空"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} +type EditUserRes struct { +} + +type GetUserByIdReq struct { + g.Meta `path:"/user/getInfoById" method:"get" summary:"根据ID获取用户" tags:"用户管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` +} +type GetUserByIdRes struct { + Data *model.UserInfoRes +} + +type DeleteUserByIdReq struct { + g.Meta `path:"/user/delInfoById" method:"delete" summary:"根据ID删除用户" tags:"用户管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` +} +type DeleteUserByIdRes struct { +} + +type ResetPasswordReq struct { + g.Meta `path:"/user/resetPassword" method:"post" summary:"重置用户密码" tags:"用户管理"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` + UserPassword string `json:"userPassword" description:"登录密码;cmf_password加密"` +} +type ResetPasswordRes struct { +} + +type CurrentUserReq struct { + g.Meta `path:"/user/currentUser" method:"get" summary:"获取登录用户信息" tags:"用户管理"` +} +type CurrentUserRes struct { + Info *model.UserInfoRes + Data []*model.UserMenuTreeRes +} + +type UserGetParamsReq struct { + g.Meta `path:"/user/params" tags:"用户管理" method:"get" summary:"用户维护参数获取"` +} + +type UserGetParamsRes struct { + g.Meta `mime:"application/json"` + RoleList []*model.RoleInfoRes `json:"roleList"` + Posts []*model.DetailPostRes `json:"posts"` +} + +type EditUserStatusReq struct { + g.Meta `path:"/user/editStatus" tags:"用户管理" method:"put" summary:"修改用户状态"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` +} + +type EditUserStatusRes struct { +} + +type GetUserAllReq struct { + g.Meta `path:"/user/getAll" method:"get" summary:"所有用户列表" tags:"用户管理"` +} +type GetUserAllRes struct { + Data []*model.UserRes +} + +type EditUserAvatarReq struct { + g.Meta `path:"/user/editAvatar" tags:"用户管理" method:"put" summary:"修改用户头像"` + Id uint `json:"id" description:"ID" v:"required#ID不能为空"` + Avatar string `json:"avatar" description:"头像" v:"required#头像不能为空"` +} + +type EditUserAvatarRes struct { +} diff --git a/api/v1/system/sys_user_online.go b/api/v1/system/sys_user_online.go new file mode 100644 index 0000000..79c0853 --- /dev/null +++ b/api/v1/system/sys_user_online.go @@ -0,0 +1,23 @@ +package system + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type UserOnlineListReq struct { + g.Meta `path:"/userOnline/list" method:"get" summary:"列表" tags:"在线用户管理"` + *common.PaginationReq +} +type UserOnlineListRes struct { + Data []*model.UserOnlineListRes + common.PaginationRes +} + +type UserOnlineStrongBackReq struct { + g.Meta `path:"/userOnline/strongBack" method:"delete" summary:"强退" tags:"在线用户管理"` + Id int `json:"id" description:"ID" v:"required#ID不能为空"` +} +type UserOnlineStrongBackRes struct { +} diff --git a/api/v1/tdengine/td_engine.go b/api/v1/tdengine/td_engine.go new file mode 100644 index 0000000..60ed4f3 --- /dev/null +++ b/api/v1/tdengine/td_engine.go @@ -0,0 +1,43 @@ +package tdengine + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type GetTdEngineAllDbReq struct { + g.Meta `path:"/getAllDb" method:"get" summary:"获取所有数据库" tags:"时序数据库管理"` +} + +type GetTdEngineAllDbRes struct { + Info []string +} + +type GetTdEngineListTableByDatabasesReq struct { + g.Meta `path:"/getListTablesByDatabases" method:"get" summary:"获取指定数据库下所有的表列表" tags:"时序数据库管理"` + DbName string `json:"dbName" description:"数据库名称" v:"required#数据库名称不能为空"` +} + +type GetTdEngineListTableByDatabasesRes struct { + Info []*model.TDEngineTablesList +} + +type GetTdEngineTableInfoByTableReq struct { + g.Meta `path:"/getTdEngineTableInfoByTable" method:"get" summary:"获取指定数据表结构信息" tags:"时序数据库管理"` + DbName string `json:"dbName" description:"数据库名称" v:"required#数据库名称不能为空"` + TableName string `json:"tableName" description:"数据库名称" v:"required#表名称不能为空"` +} + +type GetTdEngineTableInfoByTableRes struct { + Info []*model.TDEngineTableInfo +} + +type GetTdEngineTableDataByTableReq struct { + g.Meta `path:"/getTdEngineTableDataByTable" method:"get" summary:"获取指定数据表数据信息" tags:"时序数据库管理"` + DbName string `json:"dbName" description:"数据库名称" v:"required#数据库名称不能为空"` + TableName string `json:"tableName" description:"数据库名称" v:"required#表名称不能为空"` +} + +type GetTdEngineTableDataByTableRes struct { + *model.TableDataInfo +} diff --git a/api/v1/websocket/websocket.go b/api/v1/websocket/websocket.go new file mode 100644 index 0000000..52a3279 --- /dev/null +++ b/api/v1/websocket/websocket.go @@ -0,0 +1,19 @@ +package websocket + +import "github.com/gogf/gf/v2/frame/g" + +type ConfigureDiagramWebsocketReq struct { + g.Meta `path:"/configureDiagram/ws" method:"get" tags:"websocket管理" summary:"组态拓扑图发送消息"` + Id string `v:"required"` +} +type ConfigureDiagramWebsocketRes struct { + g.Meta `mime:"text/html" type:"string" example:"
" dc:"组态拓扑图"` +} + +type MonitorSearchReq struct { + g.Meta `path:"/monitorServer/ws" method:"get" tags:"websocket管理" summary:"服务监控"` +} + +type MonitorSearchRes struct { + g.Meta `mime:"text/html" type:"string" example:" +" dc:"服务监控"` +} diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4b2b37b --- /dev/null +++ b/build.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +#应用的名称 +AppName=sagoo-admin + +BuildVersion=$(git describe --abbrev=0 --tags) +BuildTime=$(date +%FT%T%z) +CommitID=$(git rev-parse HEAD) + +help() { + echo "Usage: $0 [option]" + echo "Options:" + echo " linux build for Linux" + echo " windows build for Windows" + echo " mac build for macOS" + echo " macOld build for macOS (old version)" +} + + +linux(){ + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $AppName -a -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}" + copyFile + cp curl.sh bin/ + + cp $AppName bin/ + + rm -f $AppName + +} +windows(){ + CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o $AppName.exe -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}" + + copyFile + + cp $AppName.exe bin/ + + rm -f $AppName.exe + +} +mac(){ + go build -o $AppName -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}" + + copyFile + cp curl.sh bin/ + + cp $AppName bin/ + + rm -f $AppName + +} + +macOld(){ + + GOARCH=amd64 go build -ldflags "-w -s -X main.BuildVersion=${BuildVersion} -X main.CommitID=${CommitID} -X main.BuildTime=${BuildTime}" + + copyFile + cp curl.sh bin/ + + cp $AppName bin/ + + rm -f $AppName +} + +copyFile() { + rm -rf bin + mkdir bin + mkdir bin/resource + mkdir bin/resource/public + + cp -r ./manifest/config/. bin/config/ + + echo "${BuildVersion} $(date +%T)" +} + +case "$1" in + "linux") + linux + ;; + "windows") + windows + ;; + "macOld") + macOld + ;; + "mac") + mac + ;; + *) + help + ;; +esac \ No newline at end of file diff --git a/curl.sh b/curl.sh new file mode 100755 index 0000000..b5afe9f --- /dev/null +++ b/curl.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +WORKSPACE=$(cd $(dirname $0)/ || exit; pwd) +cd "$WORKSPACE" || exit + +mkdir -p var + +app=sagoo-admin +pidfile=var/$app.pid +logfile=var/$app.log + +function check_pid() { + if [ -f $pidfile ];then + pid=$(cat $pidfile) + if [[ -n $pid ]]; then + running=$(ps -p "$pid"|grep -c -v "PID TTY") + return "$running" + fi + fi + return 0 +} + + + function start(){ + check_pid + running=$? + if [ $running -gt 0 ]; then + echo -n "$app now is running already,pid=" + cat $pidfile + return + fi + + nohup ./$app &> $logfile & + sleep 1 + running=$(ps -p $! | grep -c -v "PID TTY") + if [ "$running" -gt 0 ];then + echo $! > $pidfile + echo "$app started..., pid=$!" + else + echo "$app failed to start" + return 1 + fi + + } + +function stop() { + check_pid + running=$? + if [ $running -gt 0 ];then + pid=$(cat $pidfile) + kill "$pid" + rm -f $pidfile + echo "$app stoped" + else + echo "$app already stoped" + fi +} + +function restart() { + stop + sleep 1 + start +} + +function status() { + check_pid + running=$? + if [ $running -gt 0 ];then + echo "started" + else + echo "stoped" + fi +} + +function tailf() { + tail -f var/* +} + +function help() { + echo "$0 pid|start|stop|restart|status|tail" +} + +function pid() { + cat $pidfile +} + +if [ "$1" == "" ]; then + help +elif [ "$1" == "stop" ];then + stop +elif [ "$1" == "start" ];then + start +elif [ "$1" == "restart" ];then + restart +elif [ "$1" == "status" ];then + status +elif [ "$1" == "tail" ];then + tailf +elif [ "$1" == "pid" ];then + pid +else + help +fi diff --git a/extend/extend.go b/extend/extend.go new file mode 100644 index 0000000..217cdd7 --- /dev/null +++ b/extend/extend.go @@ -0,0 +1,133 @@ +package extend + +import ( + "context" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/extend/model" + "github.com/sagoo-cloud/sagooiot/extend/module" + "sync" +) + +type SysPlugin struct { + pluginManager *Manager +} + +const ( + NoticePluginName = "notice" + ProtocolPluginName = "protocol" +) + +var ins *SysPlugin +var once sync.Once + +//GetNoticePlugin 构造方法 +func GetNoticePlugin() *SysPlugin { + once.Do(func() { + ins = &SysPlugin{} + pm, err := pluginInit("notice") + if err != nil { + g.Log().Error(context.TODO(), err.Error()) + } + ins.pluginManager = pm + }) + + return ins +} + +//GetProtocolPlugin 构造方法 +func GetProtocolPlugin() *SysPlugin { + once.Do(func() { + ins = &SysPlugin{} + pm, err := pluginInit("protocol") + if err != nil { + g.Log().Error(context.TODO(), err.Error()) + } + ins.pluginManager = pm + }) + + return ins +} + +//初始化处理协议插件 +func pluginInit(sysPluginType string) (pm *Manager, err error) { + // 静态目录设置 + pluginsPath := g.Cfg().MustGet(context.TODO(), "system.pluginsPath").String() + //pluginsPath := "../plugins/built" + switch sysPluginType { + case "notice": + pm = NewManager(sysPluginType, "notice-*", pluginsPath, &module.NoticePlugin{}) + defer pm.Dispose() + + break + case "protocol": + pm = NewManager(sysPluginType, "protocol-*", pluginsPath, &module.ProtocolPlugin{}) + defer pm.Dispose() + + break + default: + err = gerror.New("无效的插件类型") + return + } + + //defer ProtocolPlugin.Dispose() + //初始化管理器 + err = pm.Init() + //重启所有插件 + err = pm.Launch() + //if len(pm.Plugins) > 0 { + // for key, _ := range pm.Plugins { + // data, e := pm.GetInterface(key) + // if e != nil { + // return + // } + // //将插件启动的信息存入数据库 + // res := data.(module.Notice).Info() + // var pluginData sysModel.SysPluginsAddInput + // err = gconv.Scan(res, &pluginData) + // pluginData.Status = 1 + // pluginData.Types = sysPluginType + // pluginData.StartTime = gtime.Datetime() + // //go service.SysPlugins().SaveSysPlugins(context.TODO(), pluginData) + // } + //} + + return +} + +// GetProtocolUnpackData 通过协议解析插件处理后,获取解析数据。protocolType 为协议名称 +func (pm *SysPlugin) GetProtocolUnpackData(protocolType string, data []byte) (res string, err error) { + //获取插件 + p, err := pm.pluginManager.GetInterface(protocolType) + if err != nil { + return + } + res = p.(module.Protocol).Read(data) + return +} + +// NoticeSend 通过插件发送通知信息。noticeType 为通知插件名称;msg为通知内容 +func (pm *SysPlugin) NoticeSend(noticeType string, msg model.NoticeInfoData) (res string, err error) { + //获取插件 + p, err := pm.pluginManager.GetInterface(noticeType) + if err != nil { + return + } + + var nd = new(model.NoticeData) + nd.Msg = msg + cfgData, err := getPluginsConfigData("notice", noticeType) + if err != nil { + return + } + nd.Config = cfgData + ndJson := gjson.New(nd) + //转为byte + byteData := ndJson.MustToJson() + + sendRes := p.(module.Notice).Send(byteData) + res, err = gjson.New(sendRes).ToJsonString() + g.Log().Debug(context.TODO(), "通知发送结果:", res) + return +} diff --git a/extend/manager.go b/extend/manager.go new file mode 100644 index 0000000..60478c6 --- /dev/null +++ b/extend/manager.go @@ -0,0 +1,159 @@ +package extend + +import ( + "context" + "errors" + "fmt" + "github.com/gogf/gf/v2/encoding/gyaml" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/extend/module" + "os/exec" + "path/filepath" + "strings" + "sync" + + "github.com/hashicorp/go-plugin" +) + +type PluginInfo struct { + ID string + Path string + Client *plugin.Client +} + +func NewManager(ptype, glob, dir string, pluginImpl plugin.Plugin) *Manager { + + manager := &Manager{ + Type: ptype, + Glob: glob, + Path: dir, + Plugins: map[string]*PluginInfo{}, + pluginImpl: pluginImpl, + } + + return manager +} + +// Manager 为不同类型的插件,管理的生命周期 +type Manager struct { + Type string // 管理器处理的插件类型的id + Glob string // 全局的插件文件名 + Path string // 插件路径 + Plugins map[string]*PluginInfo // 插件信息列表 + initialized bool // 是否初始化 + pluginImpl plugin.Plugin // 插件实现虚拟接口 +} + +func (m *Manager) Init() error { + + //发现插件绝对路径 + plugins, err := plugin.Discover(m.Glob, m.Path) + if err != nil { + return err + } + + //获取所有插件信息 + for _, p := range plugins { + _, file := filepath.Split(p) + globAsterix := strings.LastIndex(m.Glob, "*") + trim := m.Glob[0:globAsterix] + id := strings.TrimPrefix(file, trim) + + //添加到插件信息 + m.Plugins[id] = &PluginInfo{ + ID: id, + Path: p, + } + } + + m.initialized = true + + return nil +} + +func (m *Manager) Launch() error { + + for id, info := range m.Plugins { + + fmt.Printf("注册插件 type=%s, id=%s, impl=%s \n", m.Type, id, info.Path) + // 创建新的客户端 + // 两种方式选其一 + // 以exec.Command方式启动插件进程,并创建宿主机进程和插件进程的连接 + // 或者使用Reattach连接到现有进程,需提供Reattach信息 + client := plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: module.HandshakeConfig, + Plugins: m.pluginMap(id), + //创建新进程,或使用Reattach连接到现有进程中 + Cmd: exec.Command(info.Path), + }) + + if _, ok := m.Plugins[id]; !ok { + // 如果没有找到,忽略? + continue + } + pinfo := m.Plugins[id] + pinfo.Client = client + + } + + return nil +} + +func (m *Manager) Dispose() { + var wg sync.WaitGroup + for _, pinfo := range m.Plugins { + wg.Add(1) + + go func(client *plugin.Client) { + // 关闭client,释放相关资源,终止插件子程序的运行 + client.Kill() + wg.Done() + }(pinfo.Client) + } + + wg.Wait() + +} + +func (m *Manager) GetInterface(id string) (interface{}, error) { + + if _, ok := m.Plugins[id]; !ok { + return nil, errors.New("在注册的插件中找不到插件ID!") + } + + //获取注册插件客户端 plugin.Client + client := m.Plugins[id].Client + + // 返回协议客户端,如rpc客户端或grpc客户端,用于后续通信 + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + // 根据指定插件名称分配新实例 + raw, err := rpcClient.Dispense(id) + if err != nil { + return nil, err + } + + return raw, nil +} + +// pluginMap //插件名称到插件对象的映射关系 +func (m *Manager) pluginMap(id string) map[string]plugin.Plugin { + pMap := map[string]plugin.Plugin{} + + pMap[id] = m.pluginImpl + + return pMap +} + +func getPluginsConfigData(pluginType, pluginName string) (res map[interface{}]interface{}, err error) { + key := "plugins" + pluginType + pluginName + fmt.Println(key) + pcgData, err := g.Redis().Do(context.TODO(), "GET", key) + + err = gyaml.DecodeTo([]byte(pcgData.String()), &res) + + return +} diff --git a/extend/model/base.go b/extend/model/base.go new file mode 100644 index 0000000..01c2e42 --- /dev/null +++ b/extend/model/base.go @@ -0,0 +1,14 @@ +package model + +// JsonRes 数据返回通用JSON数据结构 +type JsonRes struct { + Code int `json:"code"` // 错误码((0:成功, 1:失败, >1:错误码)) + Message string `json:"message"` // 提示信息 + Data interface{} `json:"data"` // 返回数据(业务接口定义具体数据结构) +} + +type SagooMqttData struct { + Attr map[string]any `json:"attr"` + DeviceID string `json:"device_id"` + ReturnTime int64 `json:"return_time"` +} diff --git a/extend/model/info.go b/extend/model/info.go new file mode 100644 index 0000000..a2a4263 --- /dev/null +++ b/extend/model/info.go @@ -0,0 +1,9 @@ +package model + +type ModuleInfo struct { + Name string //插件英文名称 + Title string //插件标题 + Intro string //插件介绍 + Author string //作者 + Version string //版本 +} diff --git a/extend/model/notice.go b/extend/model/notice.go new file mode 100644 index 0000000..a4dfc08 --- /dev/null +++ b/extend/model/notice.go @@ -0,0 +1,26 @@ +package model + +type NoticeSendObject struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type NoticeInfoData struct { + ConfigId string `orm:"config_id" json:"config_id"` // + ComeFrom string `orm:"come_from" json:"come_from"` // + Method string `orm:"method" json:"method"` // + MethodCron string `orm:"method_cron" json:"method_cron"` // + MethodNum int `orm:"method_num" json:"method_num"` // + MsgTitle string `orm:"msg_title" json:"msg_title"` // + MsgBody string `orm:"msg_body" json:"msg_body"` // + MsgUrl string `orm:"msg_url" json:"msg_url"` // + UserIds string `orm:"user_ids" json:"user_ids"` // + PartyIds string `orm:"party_ids" json:"party_ids"` // + Totag string `orm:"totag" json:"totag"` // +} + +type NoticeData struct { + Config map[interface{}]interface{} + SendParam map[string]interface{} + Msg NoticeInfoData +} diff --git a/extend/module/module.go b/extend/module/module.go new file mode 100644 index 0000000..db396e2 --- /dev/null +++ b/extend/module/module.go @@ -0,0 +1,24 @@ +package module + +import ( + "encoding/json" + "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" +) + +//HandshakeConfig 握手配置,插件进程和宿主机进程,都需要保持一致 +var HandshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "SAGOO_PLUGIN", + MagicCookieValue: "sagoo_plugin", +} + +//OutJsonRes 输出json字符串结果 +func OutJsonRes(code int, message string, data interface{}) string { + var res = model.JsonRes{} + res.Code = code + res.Message = message + res.Data = data + jsonByte, _ := json.Marshal(res) + return string(jsonByte) +} diff --git a/extend/module/notice.go b/extend/module/notice.go new file mode 100644 index 0000000..b1ffab2 --- /dev/null +++ b/extend/module/notice.go @@ -0,0 +1,63 @@ +package module + +import ( + gplugin "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" + "net/rpc" +) + +// Notice 通知服务插件接口 +type Notice interface { + Info() model.ModuleInfo + Send(data []byte) model.JsonRes +} + +//NoticeRPC 基于RPC实现 +type NoticeRPC struct { + Client *rpc.Client +} + +func (g *NoticeRPC) Info() model.ModuleInfo { + var resp model.ModuleInfo + err := g.Client.Call("Plugin.Info", new(interface{}), &resp) + if err != nil { + panic(err) + } + return resp +} +func (g *NoticeRPC) Send(data []byte) model.JsonRes { + var resp model.JsonRes + err := g.Client.Call("Plugin.Send", data, &resp) + if err != nil { + panic(err) + } + + return resp +} + +//NoticeRPCServer GreeterRPC的RPC服务器,符合 net/rpc的要求 +type NoticeRPCServer struct { + Impl Notice +} + +func (s *NoticeRPCServer) Info(args interface{}, resp *model.ModuleInfo) error { + *resp = s.Impl.Info() + return nil +} +func (s *NoticeRPCServer) Send(data []byte, resp *model.JsonRes) error { + *resp = s.Impl.Send(data) + return nil +} + +//NoticePlugin 插件的虚拟实现。用于PluginMap的插件接口。在运行时,来自插件实现的实际实现会覆盖 +type NoticePlugin struct{} + +//Server 此方法由插件进程延迟的调用 +func (NoticePlugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &NoticeRPCServer{}, nil +} + +//Client 此方法由宿主进程调用 +func (NoticePlugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &NoticeRPC{Client: c}, nil +} diff --git a/extend/module/protocol.go b/extend/module/protocol.go new file mode 100644 index 0000000..bbbcac1 --- /dev/null +++ b/extend/module/protocol.go @@ -0,0 +1,87 @@ +package module + +import ( + "fmt" + gplugin "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" + "net/rpc" +) + +// Protocol 协议解析插件接口 +type Protocol interface { + Info() model.ModuleInfo + Read(data []byte) string + Write(args interface{}) error +} + +//ProtocolRPC 基于RPC实现 +type ProtocolRPC struct { + Client *rpc.Client +} + +func (g *ProtocolRPC) Info() model.ModuleInfo { + var resp model.ModuleInfo + err := g.Client.Call("Plugin.Info", new(interface{}), &resp) + if err != nil { + //希望接口返回错误 + //这里没有太多其他选择。 + fmt.Println("==========") + panic(err) + } + return resp +} +func (g *ProtocolRPC) Write(args interface{}) error { + var resp string + err := g.Client.Call("Plugin.Write", args, &resp) + if err != nil { + //希望接口返回错误 + //这里没有太多其他选择。 + //panic(err) + } + + return nil +} +func (g *ProtocolRPC) Read(data []byte) string { + var resp string + err := g.Client.Call("Plugin.Read", data, &resp) + if err != nil { + //希望接口返回错误 + //这里没有太多其他选择。 + panic(err) + } + return resp +} + +//ProtocolRPCServer GreeterRPC的RPC服务器,符合 net/rpc的要求 +type ProtocolRPCServer struct { + // 内嵌业务接口 + // 插件进程会将实现业务接口的对象赋值给Impl + Impl Protocol +} + +func (s *ProtocolRPCServer) Info(args interface{}, resp *model.ModuleInfo) error { + *resp = s.Impl.Info() + return nil +} +func (s *ProtocolRPCServer) Write(args interface{}, resp *string) error { + return s.Impl.Write(args) +} +func (s *ProtocolRPCServer) Read(args []byte, resp *string) error { + *resp = s.Impl.Read(args) + return nil +} + +//ProtocolPlugin 插件的虚拟实现。用于PluginMap的插件接口。在运行时,来自插件实现的实际实现会覆盖 +type ProtocolPlugin struct{} + +//Server 此方法由插件进程延迟的调用 +func (ProtocolPlugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &ProtocolRPCServer{}, nil + //return interface{}, nil +} + +//Client 此方法由宿主进程调用 +func (ProtocolPlugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &ProtocolRPC{Client: c}, nil + //return interface{}, nil +} diff --git a/extend/sdk/sdk.go b/extend/sdk/sdk.go new file mode 100644 index 0000000..eff669d --- /dev/null +++ b/extend/sdk/sdk.go @@ -0,0 +1,29 @@ +package sdk + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/encoding/gyaml" + "github.com/sagoo-cloud/sagooiot/extend/model" +) + +func DecodeNoticeData(data []byte) (res model.NoticeData, err error) { + dataJson := gjson.New(string(data)) + configJson := dataJson.Get("Config") + sendParamJson := dataJson.Get("SendParam") + msgJson := dataJson.Get("Msg") + + //解析通知内容数据 + if err = gjson.Unmarshal(msgJson.Bytes(), &res.Msg); err != nil { + return + } + + //解析配置数据 + if err = gyaml.DecodeTo(configJson.Bytes(), &res.Config); err != nil { + return + } + + //解析参数数据 + res.SendParam = sendParamJson.MapStrAny() + + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e56bb10 --- /dev/null +++ b/go.mod @@ -0,0 +1,90 @@ +module github.com/sagoo-cloud/sagooiot + +go 1.18 + +require ( + github.com/eclipse/paho.mqtt.golang v1.4.1 + github.com/fastwego/wxwork v1.0.0-beta.8 + github.com/go-co-op/gocron v1.17.0 + github.com/go-gota/gota v0.12.0 + github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0 + github.com/gogf/gf/v2 v2.2.0 + github.com/gorilla/websocket v1.5.0 + github.com/hashicorp/go-plugin v1.4.5 + github.com/mojocn/base64Captcha v1.3.5 + github.com/mssola/user_agent v0.5.3 + github.com/robfig/cron/v3 v3.0.1 + github.com/russross/blackfriday/v2 v2.1.0 + github.com/shirou/gopsutil/v3 v3.22.9 + github.com/taosdata/driver-go/v3 v3.0.0 + github.com/tealeg/xlsx v1.0.5 + github.com/tencentyun/cos-go-sdk-v5 v0.7.34 + github.com/tiger1103/gfast-cache v0.0.7 + github.com/tiger1103/gfast-token v0.1.1 + github.com/xinjiayu/sse v0.0.0-20221022122111-e702197c579c + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df +) + +require ( + github.com/denisenkom/go-mssqldb v0.11.0 // indirect + github.com/faabiosr/cachego v0.15.0 // indirect + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/hashicorp/go-hclog v0.14.1 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect +) + +require ( + github.com/BurntSushi/toml v1.1.0 // indirect + github.com/Knetic/govaluate v3.0.0+incompatible + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/gogf/gf/contrib/drivers/mssql/v2 v2.2.1 + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/grokify/html-strip-tags-go v0.0.1 // indirect + github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mozillazg/go-httpheader v0.2.1 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.2 // indirect + github.com/tklauser/go-sysconf v0.3.10 // indirect + github.com/tklauser/numcpus v0.4.0 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + go.opentelemetry.io/otel v1.7.0 // indirect + go.opentelemetry.io/otel/sdk v1.7.0 // indirect + go.opentelemetry.io/otel/trace v1.7.0 // indirect + golang.org/x/image v0.0.0-20210216034530-4410531fe030 // indirect + golang.org/x/net v0.4.0 // indirect + golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect + gonum.org/v1/gonum v0.9.1 // indirect + google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect + google.golang.org/grpc v1.51.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c9a2900 --- /dev/null +++ b/go.sum @@ -0,0 +1,397 @@ +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4= +github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= +github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI= +github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA= +github.com/faabiosr/cachego v0.15.0 h1:IqcDhvzMbL4a1c9Dek88DIWJYQ5HG//L0PKCReneOA4= +github.com/faabiosr/cachego v0.15.0/go.mod h1:L2EomlU3/rUWjzFavY9Fwm8B4zZmX2X6u8kTMkETrwI= +github.com/fastwego/wxwork v1.0.0-beta.8 h1:TJaAMwby7s3oKTPDawokYKAdSbnUUHJjMBsTk7eFEU0= +github.com/fastwego/wxwork v1.0.0-beta.8/go.mod h1:BzD2YB7T/1dPzKyavIcqJxn+n9eWFpUTwhgriabBWi8= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/go-co-op/gocron v1.17.0 h1:IixLXsti+Qo0wMvmn6Kmjp2csk2ykpkcL+EmHmST18w= +github.com/go-co-op/gocron v1.17.0/go.mod h1:IpDBSaJOVfFw7hXZuTag3SCSkqazXBBUkbQ1m1aesBs= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gota/gota v0.12.0 h1:T5BDg1hTf5fZ/CO+T/N0E+DDqUhvoKBl+UVckgcAAQg= +github.com/go-gota/gota v0.12.0/go.mod h1:UT+NsWpZC/FhaOyWb9Hui0jXg0Iq8e/YugZHTbyW/34= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gogf/gf/contrib/drivers/mssql/v2 v2.2.1 h1:AhLJkS0Py0wx095bLJkGWwgTI7dBkzj2oFx0f35M31U= +github.com/gogf/gf/contrib/drivers/mssql/v2 v2.2.1/go.mod h1:0e6a31p3gl7fXOT48EzpkDcUHLXYUyIEntczX/wIx5g= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0 h1:uRF+lXyUPBNxvhMGdUWxxfEtLM7mNbrb+8AqQBAXgcQ= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0/go.mod h1:z+/0qiOwMroAnj5ESuobTv0l5P83rf+XR3r6Fj8WJyk= +github.com/gogf/gf/v2 v2.0.0-rc.0.20220117131058-9345eb5e946f/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM= +github.com/gogf/gf/v2 v2.0.0/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM= +github.com/gogf/gf/v2 v2.1.0-rc4/go.mod h1:thvkyb43RWUu/m05sRm4CbH9r7t7/FrW2M56L9Ystwk= +github.com/gogf/gf/v2 v2.2.0 h1:J1b+ORVr9GQyuvb7PlQq07IfU2Qe89zN2gJXXu8nBb0= +github.com/gogf/gf/v2 v2.2.0/go.mod h1:thvkyb43RWUu/m05sRm4CbH9r7t7/FrW2M56L9Ystwk= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= +github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= +github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= +github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0= +github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= +github.com/mssola/user_agent v0.5.3 h1:lBRPML9mdFuIZgI2cmlQ+atbpJdLdeVl2IDodjBR578= +github.com/mssola/user_agent v0.5.3/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= +github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/shirou/gopsutil/v3 v3.22.9 h1:yibtJhIVEMcdw+tCTbOPiF1VcsuDeTE4utJ8Dm4c5eA= +github.com/shirou/gopsutil/v3 v3.22.9/go.mod h1:bBYl1kjgEJpWpxeHmLI+dVHWtyAwfcmSBLDsp2TNT8A= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/taosdata/driver-go/v3 v3.0.0 h1:hJScQiBB+ks671kz7r+VYo1J8aF8MDCQzA9uYeby64U= +github.com/taosdata/driver-go/v3 v3.0.0/go.mod h1:lT4lpI3wo3hXRwP3nzm7xDs/YgYbw5YU58XingVlfsY= +github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE= +github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= +github.com/tencentyun/cos-go-sdk-v5 v0.7.34 h1:xm+Pg+6m486y4eugRI7/E4WasbVmpY1hp9QBSRErgp8= +github.com/tencentyun/cos-go-sdk-v5 v0.7.34/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= +github.com/tiger1103/gfast-cache v0.0.7 h1:YRuSFxFdvNlIsHAndS7XjYRLd4tmXGWhvHt9rK0LVT0= +github.com/tiger1103/gfast-cache v0.0.7/go.mod h1:s6cRWyr87wz6IJNGKRV6Ahq9hcuVz8h2PAtGrO66JO8= +github.com/tiger1103/gfast-token v0.1.1 h1:NKf/Zd1SWWimSmiJsT/fSzINTlN8PR+x0Hns7ejqF0E= +github.com/tiger1103/gfast-token v0.1.1/go.mod h1:O0o947d4lwJwSHdwgsRc0YsQ/MLdN7/rn2nR9aeGGow= +github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= +github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/xinjiayu/sse v0.0.0-20221022122111-e702197c579c h1:ZYV7ubpsRHKje5z9Uy9SIZaSHL3p8VF33gxwtjlk8QU= +github.com/xinjiayu/sse v0.0.0-20221022122111-e702197c579c/go.mod h1:+PHaZosXaDmfak+L6jBbo8vPdZ4JB6BvCjrNVwFml6Q= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= +go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM= +go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= +go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= +go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 h1:n9HxLrNxWWtEb1cA950nuEEj3QnKbtsCJ6KjcgisNUs= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030 h1:lP9pYkih3DUSC641giIXa2XqfTIbbbRr0w2EOTA7wHA= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.1 h1:HCWmqqNoELL0RAQeKBXWtkp04mGk8koafcB4He6+uhc= +gonum.org/v1/gonum v0.9.1/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..44bae72 --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,116 @@ +package cmd + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/cmd/router" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network" + "github.com/sagoo-cloud/sagooiot/utility/notifier" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/net/goai" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/util/gmode" +) + +var ( + Main = gcmd.Command{ + Name: "main", + Usage: "main", + Brief: "start sagoo-iot server", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + var ( + s = g.Server() + ) + + // 静态目录设置 + uploadPath := g.Cfg().MustGet(ctx, "upload.path").String() + if uploadPath == "" { + g.Log().Fatal(ctx, "文件上传配置路径不能为空") + } + //s.AddStaticPath("/upload", uploadPath) + + // HOOK, 开发阶段禁止浏览器缓存,方便调试 + if gmode.IsDevelop() { + s.BindHookHandler("/*", ghttp.HookBeforeServe, func(r *ghttp.Request) { + r.Response.Header().Set("Cache-Control", "no-store") + }) + } + + //操作日志 + s.BindHookHandler("/*", ghttp.HookAfterOutput, func(r *ghttp.Request) { + service.Middleware().OperationLog(r) + }) + + //sse 实时数据推送 + s.Group("/subscribe", func(group *ghttp.RouterGroup) { + group.GET("/sysenv", notifier.SysenvMessageEvent) + }) + + s.Group("/api/v1", func(group *ghttp.RouterGroup) { + + group.Middleware( + service.Middleware().Ctx, + service.Middleware().ResponseHandler, + service.Middleware().MiddlewareCORS, + ) + + router.System(ctx, group) //系统默认功能的路由 + router.Business(ctx, group) //业务专属功能的路由 + + }) + + // 初始化插件配置数据 + if err := service.SystemPluginsConfig().UpdateAllPluginsConfigCache(); err != nil { + g.Log().Error(ctx, "初始化插件配置数据失败:", err) + } + + // TDengine 初始化 + if err := service.TSLTable().CreateDatabase(ctx); err != nil { + g.Log().Fatal(ctx, "TDengine 数据库创建失败:", err) + } + if err := service.TdLogTable().CreateStable(ctx); err != nil { + g.Log().Fatal(ctx, "TDengine 日志超级表创建失败:", err) + } + if err := mqtt.InitSystemMqtt(); err != nil { + g.Log().Errorf(ctx, "MQTT 初始化mqtt客户端失败,失败原因:%+#v", err) + } + defer mqtt.Close() + // 启动失败的话请注释掉 + if err := network.ReloadNetwork(context.Background()); err != nil { + g.Log().Errorf(ctx, "载入网络错误,错误原因:%+#v", err) + } + // 自定义丰富文档 + enhanceOpenAPIDoc(s) + // 启动Http Server + s.Run() + return + }, + } +) + +func enhanceOpenAPIDoc(s *ghttp.Server) { + openapi := s.GetOpenApi() + openapi.Config.CommonResponse = ghttp.DefaultHandlerResponse{} + openapi.Config.CommonResponseDataField = `Data` + + // API description. + openapi.Info.Title = `sagooAdmin Project` + openapi.Info.Description = `` + + // Sort the tags in custom sequence. + openapi.Tags = &goai.Tags{ + {Name: consts.OpenAPITagNameLogin}, + {Name: consts.OpenAPITagNameOrganization}, + {Name: consts.OpenAPITagNameDept}, + {Name: consts.OpenAPITagNamePost}, + {Name: consts.OpenAPITagNameRole}, + {Name: consts.OpenAPITagNameUser}, + {Name: consts.OpenAPITagNameMenu}, + {Name: consts.OpenAPITagNameApi}, + {Name: consts.OpenAPITagNameAuthorize}, + } +} diff --git a/internal/cmd/router/business.go b/internal/cmd/router/business.go new file mode 100644 index 0000000..7ad781a --- /dev/null +++ b/internal/cmd/router/business.go @@ -0,0 +1,20 @@ +package router + +import ( + "context" + envirotronicsController "github.com/sagoo-cloud/sagooiot/internal/controller/envirotronics" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/net/ghttp" +) + +// Business 业务相关功能的路由 +func Business(ctx context.Context, group *ghttp.RouterGroup) { + //环测相关路由 + group.Group("/envirotronics", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + envirotronicsController.Weather, // 天气监测 + ) + }) +} diff --git a/internal/cmd/router/system.go b/internal/cmd/router/system.go new file mode 100644 index 0000000..45282a6 --- /dev/null +++ b/internal/cmd/router/system.go @@ -0,0 +1,138 @@ +package router + +import ( + "context" + alarmController "github.com/sagoo-cloud/sagooiot/internal/controller/alarm" + commonController "github.com/sagoo-cloud/sagooiot/internal/controller/common" + networkController "github.com/sagoo-cloud/sagooiot/internal/controller/network" + noticeController "github.com/sagoo-cloud/sagooiot/internal/controller/notice" + productController "github.com/sagoo-cloud/sagooiot/internal/controller/product" + sourceController "github.com/sagoo-cloud/sagooiot/internal/controller/source" + systemController "github.com/sagoo-cloud/sagooiot/internal/controller/system" + tdengineController "github.com/sagoo-cloud/sagooiot/internal/controller/tdengine" + + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/net/ghttp" +) + +// System 系统默认功能的路由,不含业务属性的 +func System(ctx context.Context, group *ghttp.RouterGroup) { + //系统登录路由 + group.Group("/", func(group *ghttp.RouterGroup) { + group.Bind( + systemController.Login, // 登录 + systemController.Captcha, // 验证码 + commonController.SysInfo, //系统信息 + + ) + }) + + // 公共接口相关路由 + group.Group("/common", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + commonController.Upload, + commonController.ConfigData, + commonController.DictType, + commonController.DictData, + commonController.BaseDbLink, //数据源管理 + commonController.CityData, //城市管理 + ) + }) + + // 产品设备相关路由 + group.Group("/product", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + productController.Category, // 产品分类 + productController.Product, // 产品 + productController.Device, // 设备 + productController.DeviceTag, // 设备标签 + productController.DeviceLog, // 设备日志 + productController.TSLDataType, // 物模型:数据类型 + productController.TSLProperty, // 物模型:属性 + productController.TSLFunction, // 物模型:功能 + productController.TSLEvent, // 物模型:事件 + productController.TSLTag, // 物模型:标签 + ) + }) + + // 告警相关路由 + group.Group("/alarm", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + alarmController.AlarmLevel, // 告警级别 + alarmController.AlarmRule, // 告警规则 + alarmController.AlarmLog, // 告警日志 + ) + }) + + // 数据源相关路由 + group.Group("/source", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + sourceController.DataSource, // 数据源 + sourceController.DataNode, // 数据节点 + sourceController.DataTemplate, // 数据模型 + sourceController.DataTemplateNode, // 数据模型节点 + ) + }) + + // 网络通道相关路由 + group.Group("/network", func(group *ghttp.RouterGroup) { + //group.Middleware(service.Middleware().Auth) + group.Bind( + networkController.Tunnel, // 通讯通道管理 + networkController.Server, // 通讯服务管理 + + ) + }) + + //系统权限控制路由 + group.Group("/system", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + systemController.SysRole, // 角色 + systemController.SysDept, // 部门 + systemController.SysPost, // 岗位 + systemController.SysUser, // 用户 + systemController.SysMenu, // 菜单 + systemController.SysApi, // 接口 + systemController.SysAuthorize, //权限管理 + systemController.SysOrganization, //组织管理 + systemController.SysOperLog, //操作日志管理 + systemController.SysLoginLog, //访问日志管理 + + systemController.SysJob, //定时任务管理 + + systemController.SysMonitor, //服务监控 + systemController.SysUserOnline, //在线用户 + + systemController.SysNotifications, //消息中心 + systemController.SysPlugins, //插件管理 + systemController.SysPluginsConfig, //插件配置管理 + + ) + }) + + //时序数据库相关路由 + group.Group("/tdengine", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + tdengineController.TdEngine, //websocket + ) + }) + + //通知服务相关路由 + group.Group("/notice", func(group *ghttp.RouterGroup) { + group.Middleware(service.Middleware().Auth) + group.Bind( + noticeController.NoticeInfo, + noticeController.NoticeConfig, + noticeController.NoticeTemplate, + noticeController.NoticeLog, + ) + }) + +} diff --git a/internal/consts/cache.go b/internal/consts/cache.go new file mode 100644 index 0000000..16a9704 --- /dev/null +++ b/internal/consts/cache.go @@ -0,0 +1,27 @@ +/* +* @desc:缓存相关 + */ + +package consts + +const ( + CacheModelMem = "memory" + CacheModelRedis = "redis" + + // CacheSysDict 字典缓存菜单KEY + CacheSysDict = "sysDict" + + // CacheSysRole 角色缓存key + CacheSysRole = "sysRole" + + // CacheSysDept 部门缓存key + CacheSysDept = "sysDept" + + // CacheSysAuthTag 权限缓存TAG标签 + CacheSysAuthTag = "sysAuthTag" + + // CacheSysDictTag 字典缓存标签 + CacheSysDictTag = "sysDictTag" + // CacheSysConfigTag 系统参数配置 + CacheSysConfigTag = "sysConfigTag" +) diff --git a/internal/consts/config.go b/internal/consts/config.go new file mode 100644 index 0000000..c0c0da5 --- /dev/null +++ b/internal/consts/config.go @@ -0,0 +1,5 @@ +package consts + +const ( + PageSize = 10 //分页长度 +) diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 0000000..2e6ad28 --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1,76 @@ +package consts + +const ( + Version = "v0.2.0" // 当前服务版本(用于模板展示) + CaptchaDefaultName = "CaptchaDefaultName" // 验证码默认存储空间名称 + ContextKey = "ContextKey" // 上下文变量存储键名,前后端系统共享 + FileMaxUploadCountMinute = 10 // 同一用户1分钟之内最大上传数量 + DefaultPageSize = 10 //默认分页条数 +) + +// 系统启动OR禁用常量 +const ( + Start = 1 //启动 + Disabled = 0 //禁用 +) + +// 权限类型常量 +const ( + Menu = "menu" + Button = "button" + Column = "column" + Api = "api" +) + +// 组态图常量 +const ( + FolderTypesTopology = "topology" //图纸文件夹类型 + FolderTypesComponents = "components" //自定义组件文件夹类型 +) + +// WebSocket +const ( + ConfigureDiagram = "configureDiagram" //组态拓扑图 + MonitorServer = "monitorServer" //服务监控 +) + +// 错误代码 +const ( + ErrorInvalidFunction = 1 //功能不正确 + ErrorAccessDenied = 2 //访问被拒绝 + ErrorInvalidData = 3 //数据无效 + ErrorGetApiData = 4 //获取接口错误 + ErrorInvalidRole = 5 //未设置角色 + ErrorNotLogged = 401 //未登录,或是token失效 +) + +const ( + Weather = 1 //天气 + LoopRegulation = 2 //环路监管 + LoopMap = 3 //分布图 + Energy = 4 //能耗分析 +) + +// 服务状态 +const ( + ServerStatusOffline = 0 + ServerStatusOnline = 1 +) + +// ServerListLimit 服务限制 +const ( + ServerListLimit = 10000 +) + +// 业务单元 +const ( + PLOT = "plot" + Floor = "floor" + Unit = "unit" +) + +// 系统参数KEY常量 +const ( + IsAutoRunJob = "sys.auto.run.job" + IsOpenAccessControl = "sys.access.control" +) diff --git a/internal/consts/content.go b/internal/consts/content.go new file mode 100644 index 0000000..df2ecce --- /dev/null +++ b/internal/consts/content.go @@ -0,0 +1,13 @@ +package consts + +const ( + ContentListDefaultSize = 10 + ContentListMaxSize = 50 + ContentSortDefault = 0 // 排序:按照创建时间 + ContentSortActive = 1 // 排序:按照更新时间 + ContentSortHot = 2 // 排序:按照浏览量 + ContentSortScore = 3 // 排序:按照搜索结果关联性 + ContentTypeArticle = "article" + ContentTypeAsk = "ask" + ContentTypeTopic = "topic" +) diff --git a/internal/consts/device.go b/internal/consts/device.go new file mode 100644 index 0000000..797630e --- /dev/null +++ b/internal/consts/device.go @@ -0,0 +1,7 @@ +package consts + +const ( + DeviceStatueDisable = 0 + DeviceStatueOffline = 1 + DeviceStatueOnline = 2 +) diff --git a/internal/consts/energy.go b/internal/consts/energy.go new file mode 100644 index 0000000..537781a --- /dev/null +++ b/internal/consts/energy.go @@ -0,0 +1,7 @@ +package consts + +const ( + LossWaterId = "energy.loss.water" + StationInfos = "energy.station.infos" + StationLists = "energy.station.lists" +) diff --git a/internal/consts/interact.go b/internal/consts/interact.go new file mode 100644 index 0000000..0b66872 --- /dev/null +++ b/internal/consts/interact.go @@ -0,0 +1,8 @@ +package consts + +const ( + InteractTypeZan = 0 + InteractTypeCai = 1 + InteractTargetTypeContent = "content" + InteractTargetTypeReply = "reply" +) diff --git a/internal/consts/openapi.go b/internal/consts/openapi.go new file mode 100644 index 0000000..33c40a3 --- /dev/null +++ b/internal/consts/openapi.go @@ -0,0 +1,13 @@ +package consts + +const ( + OpenAPITagNameLogin = `登录` + OpenAPITagNameOrganization = `组织管理` + OpenAPITagNameDept = `部门管理` + OpenAPITagNamePost = `岗位管理` + OpenAPITagNameRole = `角色管理` + OpenAPITagNameUser = `用户管理` + OpenAPITagNameMenu = `菜单管理` + OpenAPITagNameApi = `接口管理` + OpenAPITagNameAuthorize = `权限管理` +) diff --git a/internal/consts/session.go b/internal/consts/session.go new file mode 100644 index 0000000..c2bb2fd --- /dev/null +++ b/internal/consts/session.go @@ -0,0 +1,8 @@ +package consts + +const ( + SessionNoticeTypeSuccess = "success" + SessionNoticeTypeInfo = "primary" + SessionNoticeTypeWarn = "warning" + SessionNoticeTypeError = "danger" +) diff --git a/internal/consts/topic.go b/internal/consts/topic.go new file mode 100644 index 0000000..a953791 --- /dev/null +++ b/internal/consts/topic.go @@ -0,0 +1,123 @@ +package consts + +import "fmt" + +type ( + Topic string + Action string +) + +const ( + TopicDeviceData Topic = "device/+/#" +) + +const ( + ActionError Action = "error" + ActionOnline Action = "online" + ActionOffline Action = "offline" + ActionOpen Action = "open" + ActionClose Action = "close" + ActionTunnel Action = "tunnel" +) + +func GetWrapperTopic(topic Topic, action Action, id int) string { + return fmt.Sprintf(string(topic), id, action) +} + +func GetDataBusWrapperTopic(productKey, deviceKey string, topic Topic) string { + return fmt.Sprintf("/device/%s/%s%s", productKey, deviceKey, topic) +} + +const CommonDataBusPrefix = "/device/+/+" + +const ( + DataBusOnline Topic = "/online" + DataBusOffline Topic = "/offline" + + DataBusEvent Topic = "/message/event/{eventId}" + + DataBusPropertyReport Topic = "/message/property/report" + + DataBusPropertyRead Topic = "/message/send/property/read" + DataBusPropertyReadReply Topic = "/message/property/read/reply" + + DataBusPropertyWrite Topic = "/message/send/property/write" + DataBusPropertyWriteReply Topic = "/message/property/write/reply" + + DataBusFunctionSend Topic = "/message/send/function" + DataBusFunctionReply Topic = "/message/function/reply" + + DataBusRegister Topic = "/register" + DataBusUnRegister Topic = "/unregister" + + DataBusChildDeviceMessage Topic = "/message/children/{childrenDeviceId}/{topic}" + DataBusChildDeviceMessageReply Topic = "/message/children/reply/{childrenDeviceId}/{topic}" + + DataBusDirect Topic = "/message/direct" + DataBusUpdate Topic = "/message/tags/update" + + DataBusFirmwarePull Topic = "/firmware/pull" + DataBusFirmwarePullReply Topic = "/firmware/pull/reply" + + DataBusFirmwarePush Topic = "/firmware/push" + DataBusFirmwarePushReply Topic = "/firmware/push/reply" + + DataBusFirmwareReport Topic = "/firmware/report" + + DataBusFirmwareProgress Topic = "/firmware/progress" + + DataBusLog Topic = "/message/log" + + DataBusMetadataDerived Topic = "/metadata/derived" +) + +const ( + DataBusServer Topic = "/system/server/%d/%s" + DataBusTunnel Topic = "/system/tunnel/%d/%s" +) + +var topicToDescMap = map[Topic]string{ + DataBusOnline: "设备上线", + DataBusOffline: "设备下线", + DataBusEvent: "事件上报", + DataBusPropertyRead: "读取属性", + DataBusPropertyReadReply: "读取属性回复", + DataBusPropertyWrite: "修改属性", + DataBusPropertyWriteReply: "修改属性回复", + DataBusFunctionSend: "方法调用", + DataBusFunctionReply: "方法调用回复", + DataBusPropertyReport: "属性上报", + DataBusChildDeviceMessage: "子设备消息", + DataBusChildDeviceMessageReply: "子设备消息回复", + DataBusRegister: "设备注册", + DataBusUnRegister: "设备解除注册", +} + +const ( + Online = "online" + Offline = "offline" + Event = "event" + PropertyRead = "property_read" + PropertyReadReply = "property_read_reply" + PropertyWrite = "property_write" + PropertyWriteReply = "property_write_reply" + FunctionSend = "function_send" + FunctionReply = "function_reply" + PropertyReport = "property_report" + ChildDeviceMessage = "child_device_message" + ChildDeviceMessageReply = "child_device_message_reply" + Register = "register" + UnRegister = "un_register" +) + +func GetTopicType(topic Topic) string { + return topicToDescMap[topic] +} + +func GetTopicTypes() []string { + var topicTypes = make([]string, 0) + for _, t := range topicToDescMap { + topicTypes = append(topicTypes, t) + } + return topicTypes +} diff --git a/internal/consts/tsl_type.go b/internal/consts/tsl_type.go new file mode 100644 index 0000000..49ab6e7 --- /dev/null +++ b/internal/consts/tsl_type.go @@ -0,0 +1,14 @@ +package consts + +const ( + TypeInt = "int" + TypeLong = "long" + TypeFloat = "float" + TypeDouble = "double" + TypeText = "text" + TypeBool = "boolean" + TypeDate = "date" + TypeEnum = "enum" + TypeArray = "array" + TypeObject = "object" +) diff --git a/internal/consts/upload.go b/internal/consts/upload.go new file mode 100644 index 0000000..ddfbae2 --- /dev/null +++ b/internal/consts/upload.go @@ -0,0 +1,18 @@ +package consts + +const ( + UploadPath = "upload_file" + ImgTypeKey = "sys.uploadFile.imageType" + ImgSizeKey = "sys.uploadFile.imageSize" + FileTypeKey = "sys.uploadFile.fileType" + FileSizeKey = "sys.uploadFile.fileSize" + CheckFileTypeImg = "img" // 文件类型(图片) + CheckFileTypeFile = "file" // 文件类型(任意) +) + +const ( + SourceLocal = iota // 上传到本地 + SourceTencent // 上传至腾讯云 + SourceAli // 上传到阿里云 + SourceQiniu // 上传到七牛云 +) diff --git a/internal/consts/user.go b/internal/consts/user.go new file mode 100644 index 0000000..c1564d4 --- /dev/null +++ b/internal/consts/user.go @@ -0,0 +1,10 @@ +package consts + +const ( + UserStatusOk = 0 // 用户状态正常 + UserStatusDisabled = 1 // 用户状态禁用 + UserGenderUnknown = 0 // 性别: 未知 + UserGenderMale = 1 // 性别: 男 + UserGenderFemale = 2 // 性别: 女 + UserLoginUrl = "/login" +) diff --git a/internal/controller/alarm/alarm_level.go b/internal/controller/alarm/alarm_level.go new file mode 100644 index 0000000..bd92c05 --- /dev/null +++ b/internal/controller/alarm/alarm_level.go @@ -0,0 +1,26 @@ +package alarm + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/alarm" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var AlarmLevel = cAlarmLevel{} + +type cAlarmLevel struct{} + +func (c *cAlarmLevel) All(ctx context.Context, req *alarm.AlarmLevelReq) (res *alarm.AlarmLevelRes, err error) { + list, err := service.AlarmLevel().All(ctx) + if err != nil || list == nil { + return + } + res = new(alarm.AlarmLevelRes) + res.AlarmLevelListOutput = list + return +} + +func (c *cAlarmLevel) Edit(ctx context.Context, req *alarm.AlarmLevelEditReq) (res *alarm.AlarmLevelEditRes, err error) { + err = service.AlarmLevel().Edit(ctx, req.List) + return +} diff --git a/internal/controller/alarm/alarm_log.go b/internal/controller/alarm/alarm_log.go new file mode 100644 index 0000000..de443ba --- /dev/null +++ b/internal/controller/alarm/alarm_log.go @@ -0,0 +1,34 @@ +package alarm + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/alarm" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var AlarmLog = cAlarmLog{} + +type cAlarmLog struct{} + +func (c *cAlarmLog) Detail(ctx context.Context, req *alarm.AlarmLogDetailReq) (res *alarm.AlarmLogDetailRes, err error) { + out, err := service.AlarmLog().Detail(ctx, req.Id) + if err != nil || out == nil { + return + } + res = new(alarm.AlarmLogDetailRes) + res.Data = out + return +} + +func (c *cAlarmLog) List(ctx context.Context, req *alarm.AlarmLogListReq) (res *alarm.AlarmLogListRes, err error) { + out, err := service.AlarmLog().List(ctx, req.AlarmLogListInput) + res = &alarm.AlarmLogListRes{ + AlarmLogListOutput: out, + } + return +} + +func (c *cAlarmLog) Handle(ctx context.Context, req *alarm.AlarmLogHandleReq) (res *alarm.AlarmLogHandleRes, err error) { + err = service.AlarmLog().Handle(ctx, &req.AlarmLogHandleInput) + return +} diff --git a/internal/controller/alarm/alarm_rule.go b/internal/controller/alarm/alarm_rule.go new file mode 100644 index 0000000..36f08f1 --- /dev/null +++ b/internal/controller/alarm/alarm_rule.go @@ -0,0 +1,84 @@ +package alarm + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/alarm" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var AlarmRule = cAlarmRule{} + +type cAlarmRule struct{} + +func (c *cAlarmRule) List(ctx context.Context, req *alarm.AlarmRuleListReq) (res *alarm.AlarmRuleListRes, err error) { + out, err := service.AlarmRule().List(ctx, req.AlarmRuleListInput) + res = &alarm.AlarmRuleListRes{ + AlarmRuleListOutput: out, + } + return +} + +func (c *cAlarmRule) Add(ctx context.Context, req *alarm.AlarmRuleAddReq) (res *alarm.AlarmRuleAddRes, err error) { + err = service.AlarmRule().Add(ctx, req.AlarmRuleAddInput) + return +} + +func (c *cAlarmRule) Edit(ctx context.Context, req *alarm.AlarmRuleEditReq) (res *alarm.AlarmRuleEditRes, err error) { + err = service.AlarmRule().Edit(ctx, req.AlarmRuleEditInput) + return +} + +func (c *cAlarmRule) Deploy(ctx context.Context, req *alarm.AlarmRuleDeployReq) (res *alarm.AlarmRuleDeployRes, err error) { + err = service.AlarmRule().Deploy(ctx, req.Id) + return +} + +func (c *cAlarmRule) Undeploy(ctx context.Context, req *alarm.AlarmRuleUndeployReq) (res *alarm.AlarmRuleUndeployRes, err error) { + err = service.AlarmRule().Undeploy(ctx, req.Id) + return +} + +func (c *cAlarmRule) Del(ctx context.Context, req *alarm.AlarmRuleDelReq) (res *alarm.AlarmRuleDelRes, err error) { + err = service.AlarmRule().Del(ctx, req.Id) + return +} + +func (c *cAlarmRule) Detail(ctx context.Context, req *alarm.AlarmRuleDetailReq) (res *alarm.AlarmRuleDetailRes, err error) { + out, err := service.AlarmRule().Detail(ctx, req.Id) + if err != nil || out == nil { + return + } + res = new(alarm.AlarmRuleDetailRes) + res.Data = out + return +} + +func (c *cAlarmRule) Operator(ctx context.Context, req *alarm.AlarmRuleOperatorReq) (res *alarm.AlarmRuleOperatorRes, err error) { + out, err := service.AlarmRule().Operator(ctx) + if err != nil || out == nil { + return + } + res = new(alarm.AlarmRuleOperatorRes) + res.List = out + return +} + +func (c *cAlarmRule) TriggerType(ctx context.Context, req *alarm.AlarmRuleTriggerTypeReq) (res *alarm.AlarmRuleTriggerTypeRes, err error) { + out, err := service.AlarmRule().TriggerType(ctx, req.ProductKey) + if err != nil || out == nil { + return + } + res = new(alarm.AlarmRuleTriggerTypeRes) + res.List = out + return +} + +func (c *cAlarmRule) TriggerParam(ctx context.Context, req *alarm.AlarmRuleTriggerParamReq) (res *alarm.AlarmRuleTriggerParamRes, err error) { + out, err := service.AlarmRule().TriggerParam(ctx, req.ProductKey) + if err != nil || out == nil { + return + } + res = new(alarm.AlarmRuleTriggerParamRes) + res.List = out + return +} diff --git a/internal/controller/common/base_db_link.go b/internal/controller/common/base_db_link.go new file mode 100644 index 0000000..be8d6e9 --- /dev/null +++ b/internal/controller/common/base_db_link.go @@ -0,0 +1,80 @@ +package common + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/util/gconv" +) + +var BaseDbLink = cBaseDbLink{} + +type cBaseDbLink struct{} + +// GetList 获取数据源列表 +func (a *cBaseDbLink) GetList(ctx context.Context, req *common.BaseDbLinkDoReq) (res *common.BaseDbLinkDoRes, err error) { + var input *model.BaseDbLinkDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + total, out, err := service.BaseDbLink().GetList(ctx, input) + if err != nil { + return + } + res = new(common.BaseDbLinkDoRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// AddBaseDbLink 添加数据源 +func (a *cBaseDbLink) AddBaseDbLink(ctx context.Context, req *common.AddBaseDbLinkReq) (res *common.AddBaseDbLinkRes, err error) { + var input *model.AddBaseDbLinkInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.BaseDbLink().Add(ctx, input) + return +} + +// DetailBaseDbLink 获取数据源详情 +func (a *cBaseDbLink) DetailBaseDbLink(ctx context.Context, req *common.DetailBaseDbLinkReq) (res *common.DetailBaseDbLinkRes, err error) { + data, err := service.BaseDbLink().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailBaseDbLinkRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &common.DetailBaseDbLinkRes{ + Data: detailRes, + } + } + return +} + +// EditBaseDbLink 编辑数据源 +func (a *cBaseDbLink) EditBaseDbLink(ctx context.Context, req *common.EditBaseDbLinkReq) (res *common.EditBaseDbLinkRes, err error) { + var input *model.EditBaseDbLinkInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.BaseDbLink().Edit(ctx, input) + return +} + +// DelBaseDbLink 根据ID删除数据源 +func (a *cBaseDbLink) DelBaseDbLink(ctx context.Context, req *common.DelBaseDbLinkReq) (res *common.DelBaseDbLinkRes, err error) { + err = service.BaseDbLink().Del(ctx, req.Id) + return +} diff --git a/internal/controller/common/city_data.go b/internal/controller/common/city_data.go new file mode 100644 index 0000000..a84080f --- /dev/null +++ b/internal/controller/common/city_data.go @@ -0,0 +1,127 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var CityData = cCityData{} + +type cCityData struct{} + +// CityTree 获取列表 +func (a *cCityData) CityTree(ctx context.Context, req *common.CityTreeReq) (res *common.CityTreeRes, err error) { + info, err := service.CityData().GetList(ctx, req.Status, req.Name, req.Code) + if err != nil { + return + } + if info != nil { + var dataTree []*model.CityTreeRes + if err = gconv.Scan(info, &dataTree); err != nil { + return + } + treeData, er := GetCityTreeRes(dataTree) + if er != nil { + return + } + + res = &common.CityTreeRes{ + Data: treeData, + } + } + + return +} + +func GetCityTreeRes(heatStationInfo []*model.CityTreeRes) (dataTree []*model.CityTreeRes, err error) { + var parentNodeRes []*model.CityTreeRes + if heatStationInfo != nil { + //获取所有的根节点 + for _, v := range heatStationInfo { + var parentNode *model.CityTreeRes + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeRes = append(parentNodeRes, parentNode) + } + } + } + treeData := GetCityChildrenTree(parentNodeRes, heatStationInfo) + return treeData, nil +} + +func GetCityChildrenTree(parentNodeRes []*model.CityTreeRes, data []*model.CityTreeRes) (dataTree []*model.CityTreeRes) { + //循环所有一级节点 + for k, v := range parentNodeRes { + //查询所有该节点下的所有子节点 + for _, j := range data { + var node *model.CityTreeRes + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeRes[k].Children = append(parentNodeRes[k].Children, node) + } + } + GetCityChildrenTree(v.Children, data) + } + return parentNodeRes +} + +// AddCity 添加城市 +func (a *cCityData) AddCity(ctx context.Context, req *common.AddCityReq) (res *common.AddCityRes, err error) { + var city *entity.CityData + if err = gconv.Scan(req.AddCityReq, &city); err != nil { + return + } + err = service.CityData().Add(ctx, city) + if err != nil { + return + } + return +} + +// EditCity 编辑城市 +func (a *cCityData) EditCity(ctx context.Context, req *common.EditCityReq) (res *common.EditCityRes, err error) { + var city *entity.CityData + if err = gconv.Scan(req.EditCityReq, &city); err != nil { + return + } + err = service.CityData().Edit(ctx, city) + if err != nil { + return + } + return +} + +// GetCityById 根据ID获取城市 +func (a *cCityData) GetCityById(ctx context.Context, req *common.GetCityByIdReq) (res *common.GetCityByIdRes, err error) { + data, err := service.CityData().GetInfoById(ctx, req.Id) + if err != nil { + return + } + var city *model.CityRes + if data != nil { + if err = gconv.Scan(data, &city); err != nil { + return + } + } + res = &common.GetCityByIdRes{ + Data: city, + } + return +} + +// DelCityById 根据ID删除城市 +func (a *cCityData) DelCityById(ctx context.Context, req *common.DelCityByIdReq) (res *common.DelCityByIdRes, err error) { + err = service.CityData().DelById(ctx, req.Id) + if err != nil { + return + } + return +} diff --git a/internal/controller/common/config_data.go b/internal/controller/common/config_data.go new file mode 100644 index 0000000..6ea17d8 --- /dev/null +++ b/internal/controller/common/config_data.go @@ -0,0 +1,78 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type cConfigData struct{} + +var ConfigData = cConfigData{} + +// List 系统参数列表 +func (c *cConfigData) List(ctx context.Context, req *common.ConfigSearchReq) (res *common.ConfigSearchRes, err error) { + var input *model.ConfigDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.ConfigData().List(ctx, input) + if err != nil { + return + } + res = new(common.ConfigSearchRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.List); err != nil { + return + } + } + return +} + +// Add 添加系统参数 +func (c *cConfigData) Add(ctx context.Context, req *common.ConfigAddReq) (res *common.ConfigAddRes, err error) { + var input *model.AddConfigInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.ConfigData().Add(ctx, input, service.Context().GetUserId(ctx)) + return +} + +// Get 获取系统参数 +func (c *cConfigData) Get(ctx context.Context, req *common.ConfigGetReq) (res *common.ConfigGetRes, err error) { + out, err := service.ConfigData().Get(ctx, req.Id) + if err != nil { + return + } + var data *model.SysConfigRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &common.ConfigGetRes{ + Data: data, + } + return +} + +// Edit 修改系统参数 +func (c *cConfigData) Edit(ctx context.Context, req *common.ConfigEditReq) (res *common.ConfigEditRes, err error) { + var input *model.EditConfigInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.ConfigData().Edit(ctx, input, service.Context().GetUserId(ctx)) + return +} + +// Delete 删除系统参数 +func (c *cConfigData) Delete(ctx context.Context, req *common.ConfigDeleteReq) (res *common.ConfigDeleteRes, err error) { + err = service.ConfigData().Delete(ctx, req.Ids) + return +} diff --git a/internal/controller/common/dict_data.go b/internal/controller/common/dict_data.go new file mode 100644 index 0000000..d320f02 --- /dev/null +++ b/internal/controller/common/dict_data.go @@ -0,0 +1,97 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type cDictData struct{} + +var DictData = cDictData{} + +// GetDictData 获取字典数据 +func (c *cDictData) GetDictData(ctx context.Context, req *common.GetDictReq) (res *common.GetDictRes, err error) { + var input *model.GetDictInput + if err = gconv.Scan(req, &input); err != nil { + return + } + out, err := service.DictData().GetDictWithDataByType(ctx, input) + if err != nil { + return + } + var data *model.GetDictRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &common.GetDictRes{ + Data: data.Data, + Values: data.Values, + } + return +} + +// List 获取字典数据列表 +func (c *cDictData) List(ctx context.Context, req *common.DictDataSearchReq) (res *common.DictDataSearchRes, err error) { + var input *model.SysDictSearchInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.DictData().List(ctx, input) + if err != nil { + return + } + res = new(common.DictDataSearchRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.List); err != nil { + return + } + } + return +} + +// Add 添加字典数据 +func (c *cDictData) Add(ctx context.Context, req *common.DictDataAddReq) (res *common.DictDataAddRes, err error) { + var input *model.AddDictDataInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.DictData().Add(ctx, input, service.Context().GetUserId(ctx)) + return +} + +// Get 获取对应的字典数据 +func (c *cDictData) Get(ctx context.Context, req *common.DictDataGetReq) (res *common.DictDataGetRes, err error) { + out, err := service.DictData().Get(ctx, req.DictCode) + var data *model.SysDictDataRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &common.DictDataGetRes{ + Dict: data, + } + return +} + +// Edit 修改字典数据 +func (c *cDictData) Edit(ctx context.Context, req *common.DictDataEditReq) (res *common.DictDataEditRes, err error) { + var input *model.EditDictDataInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.DictData().Edit(ctx, input, service.Context().GetUserId(ctx)) + return +} + +func (c *cDictData) Delete(ctx context.Context, req *common.DictDataDeleteReq) (res *common.DictDataDeleteRes, err error) { + err = service.DictData().Delete(ctx, req.Ids) + return +} diff --git a/internal/controller/common/dict_type.go b/internal/controller/common/dict_type.go new file mode 100644 index 0000000..e45e1dd --- /dev/null +++ b/internal/controller/common/dict_type.go @@ -0,0 +1,78 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type cDictType struct{} + +var DictType = cDictType{} + +// List 字典类型列表 +func (c *cDictType) List(ctx context.Context, req *common.DictTypeSearchReq) (res *common.DictTypeSearchRes, err error) { + var input *model.DictTypeDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.DictType().List(ctx, input) + if err != nil { + return + } + res = new(common.DictTypeSearchRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.DictTypeList); err != nil { + return + } + } + + return +} + +// Add 添加字典类型 +func (c *cDictType) Add(ctx context.Context, req *common.DictTypeAddReq) (res *common.DictTypeAddRes, err error) { + var input *model.AddDictTypeInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.DictType().Add(ctx, input, service.Context().GetUserId(ctx)) + return +} + +// Get 获取字典类型 +func (c *cDictType) Get(ctx context.Context, req *common.DictTypeGetReq) (res *common.DictTypeGetRes, err error) { + out, err := service.DictType().Get(ctx, req) + if err != nil { + return + } + var data *model.SysDictTypeRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &common.DictTypeGetRes{ + DictType: data, + } + return +} + +// Edit 修改字典数据 +func (c *cDictType) Edit(ctx context.Context, req *common.DictTypeEditReq) (res *common.DictTypeEditRes, err error) { + var input *model.EditDictTypeInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.DictType().Edit(ctx, input, service.Context().GetUserId(ctx)) + return +} + +func (c *cDictType) Delete(ctx context.Context, req *common.DictTypeDeleteReq) (res *common.DictTypeDeleteRes, err error) { + err = service.DictType().Delete(ctx, req.DictIds) + return +} diff --git a/internal/controller/common/sysinfo.go b/internal/controller/common/sysinfo.go new file mode 100644 index 0000000..d98188b --- /dev/null +++ b/internal/controller/common/sysinfo.go @@ -0,0 +1,60 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/version" +) + +type cSysInfo struct{} + +var SysInfo = cSysInfo{} + +func (s *cSysInfo) GetSysInfo(ctx context.Context, req *common.GetSysInfoReq) (res *common.GetSysInfoRes, err error) { + + cfgSystemName, err := service.ConfigData().GetConfigByKey(ctx, "sys.system.name") + systemName := "沙果IOT" + if cfgSystemName != nil { + systemName = cfgSystemName.ConfigValue + } + + cfgSystemCopyright, err := service.ConfigData().GetConfigByKey(ctx, "sys.system.copyright") + systemCopyright := "Sagoo inc." + if cfgSystemName != nil { + systemCopyright = cfgSystemCopyright.ConfigValue + } + + res = &common.GetSysInfoRes{ + "systemName": systemName, + "systemCopyright": systemCopyright, + "buildVersion": version.BuildVersion, + "buildTime": version.BuildTime, + } + + return +} + +// IsToken 验证token是否正确 +func (s *cSysInfo) IsToken(ctx context.Context, req *common.IsTokenReq) (res *common.IsTokenRes, err error) { + authorization := ghttp.RequestFromCtx(ctx).Header.Get("Authorization") + if authorization == "" { + err = gerror.New("请先登录!") + return + } + var isToken = false + var expiresAt int64 + //验证TOKEN是否正确 + data, _ := service.SysToken().ParseToken(ghttp.RequestFromCtx(ctx)) + if data != nil { + isToken = true + expiresAt = data.ExpiresAt + } + res = &common.IsTokenRes{ + IsToken: isToken, + ExpiresAt: expiresAt, + } + return +} diff --git a/internal/controller/common/upload.go b/internal/controller/common/upload.go new file mode 100644 index 0000000..8e508c4 --- /dev/null +++ b/internal/controller/common/upload.go @@ -0,0 +1,87 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type cUpload struct{} + +var Upload = cUpload{} + +//SingleImg 上传单图 +func (c *cUpload) SingleImg(ctx context.Context, req *common.UploadSingleImgReq) (res *common.UploadSingleRes, err error) { + r := g.RequestFromCtx(ctx) + file := r.GetUploadFile("file") + if file == nil { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeImg, v.Int()) + if err != nil { + return + } + res = &common.UploadSingleRes{ + UploadResponse: response, + } + // 上传第三方 + return +} + +//MultipleImg 上传多图 +func (c *cUpload) MultipleImg(ctx context.Context, req *common.UploadMultipleImgReq) (res *common.UploadMultipleRes, err error) { + r := g.RequestFromCtx(ctx) + files := r.GetUploadFiles("file") + if len(files) == 0 { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeImg, v.Int()) + if err != nil { + return + } + res = &mf + return +} + +//SingleFile 上传单文件 +func (c *cUpload) SingleFile(ctx context.Context, req *common.UploadSingleFileReq) (res *common.UploadSingleRes, err error) { + r := g.RequestFromCtx(ctx) + file := r.GetUploadFile("file") + if file == nil { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeFile, v.Int()) + if err != nil { + return + } + res = &common.UploadSingleRes{ + UploadResponse: response, + } + return +} + +//MultipleFile 上传多文件 +func (c *cUpload) MultipleFile(ctx context.Context, req *common.UploadMultipleFileReq) (res *common.UploadMultipleRes, err error) { + r := g.RequestFromCtx(ctx) + files := r.GetUploadFiles("file") + if len(files) == 0 { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeFile, v.Int()) + if err != nil { + return + } + res = &mf + return +} diff --git a/internal/controller/envirotronics/env_weather.go b/internal/controller/envirotronics/env_weather.go new file mode 100644 index 0000000..89962a1 --- /dev/null +++ b/internal/controller/envirotronics/env_weather.go @@ -0,0 +1,128 @@ +package envirotronics + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/envirotronics" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var Weather = cWeather{} + +type cWeather struct{} + +// CityWeatherList 获取城市的风力及日照时长 +func (a *cWeather) CityWeatherList(ctx context.Context, req *envirotronics.CityWeatherListReq) (res *envirotronics.CityWeatherListRes, err error) { + out, err := service.EnvWeather().CityWeatherList(ctx) + if err != nil { + return + } + var cityWeatherListRes []*model.CityWeatherListRes + if out != nil { + if err = gconv.Scan(out, &cityWeatherListRes); err != nil { + return + } + } + res = &envirotronics.CityWeatherListRes{ + Info: cityWeatherListRes, + } + return +} + +// GetCityWeatherById 根据ID获取指定城市的天气 +func (a *cWeather) GetCityWeatherById(ctx context.Context, req *envirotronics.GetCityWeatherByIdReq) (res *envirotronics.GetCityWeatherByIdRes, err error) { + out, err := service.EnvWeather().GetCityWeatherById(ctx, req.Id) + if err != nil { + return + } + var cityWeatherListRes *model.CityWeatherListRes + if out != nil { + if err = gconv.Scan(out, &cityWeatherListRes); err != nil { + return + } + } + + res = &envirotronics.GetCityWeatherByIdRes{ + Info: cityWeatherListRes, + } + return +} + +// GetCityTemperatureById 根据ID获取指定城市的温度图表 +func (a *cWeather) GetCityTemperatureById(ctx context.Context, req *envirotronics.GetCityTemperatureByIdReq) (res *envirotronics.GetCityTemperatureByIdRes, err error) { + cityWeatherEchartOut, avgCityWeatherEchartOut, foreCastCityWeatherEchartOut, foreCastAvgCityWeatherEchartOut, err := service.EnvWeather().GetCityTemperatureById(ctx, req.Id, req.Types) + if err != nil { + return + } + var cityWeatherEchartRes []*model.CityWeatherEchartRes + if cityWeatherEchartOut != nil { + if err = gconv.Scan(cityWeatherEchartOut, &cityWeatherEchartRes); err != nil { + return + } + } + var avgCityWeatherEchartRes []*model.CityWeatherEchartRes + if avgCityWeatherEchartOut != nil { + if err = gconv.Scan(avgCityWeatherEchartOut, &avgCityWeatherEchartRes); err != nil { + return + } + } + var foreCastCityWeatherEchartRes []*model.CityWeatherEchartRes + if foreCastCityWeatherEchartOut != nil { + if err = gconv.Scan(foreCastCityWeatherEchartOut, &foreCastCityWeatherEchartRes); err != nil { + return + } + } + var foreCastAvgCityWeatherEchartRes []*model.CityWeatherEchartRes + if foreCastAvgCityWeatherEchartOut != nil { + if err = gconv.Scan(foreCastAvgCityWeatherEchartOut, &foreCastAvgCityWeatherEchartRes); err != nil { + return + } + } + res = &envirotronics.GetCityTemperatureByIdRes{ + Info: cityWeatherEchartRes, + AvgInfo: avgCityWeatherEchartRes, + ForeCastInfo: foreCastCityWeatherEchartRes, + ForeCastAvgInfo: foreCastAvgCityWeatherEchartRes, + } + return +} + +// GetCityWindpowerById 根据ID获取指定城市的风力图表 +func (a *cWeather) GetCityWindpowerById(ctx context.Context, req *envirotronics.GetCityWindpowerByIdReq) (res *envirotronics.GetCityWindpowerByIdRes, err error) { + cityWeatherEchartOut, avgCityWeatherEchartOut, foreCastCityWeatherEchartOut, foreCastAvgCityWeatherEchartOut, err := service.EnvWeather().GetCityWindpowerById(ctx, req.Id, req.Types) + if err != nil { + return + } + var cityWeatherEchartRes []*model.CityWeatherEchartRes + if cityWeatherEchartOut != nil { + if err = gconv.Scan(cityWeatherEchartOut, &cityWeatherEchartRes); err != nil { + return + } + } + var avgCityWeatherEchartRes []*model.CityWeatherEchartRes + if avgCityWeatherEchartOut != nil { + if err = gconv.Scan(avgCityWeatherEchartOut, &avgCityWeatherEchartRes); err != nil { + return + } + } + var foreCastCityWeatherEchartRes []*model.CityWeatherEchartRes + if foreCastCityWeatherEchartOut != nil { + if err = gconv.Scan(foreCastCityWeatherEchartOut, &foreCastCityWeatherEchartRes); err != nil { + return + } + } + var foreCastAvgCityWeatherEchartRes []*model.CityWeatherEchartRes + if foreCastAvgCityWeatherEchartOut != nil { + if err = gconv.Scan(foreCastAvgCityWeatherEchartOut, &foreCastAvgCityWeatherEchartRes); err != nil { + return + } + } + res = &envirotronics.GetCityWindpowerByIdRes{ + Info: cityWeatherEchartRes, + AvgInfo: avgCityWeatherEchartRes, + ForeCastInfo: foreCastCityWeatherEchartRes, + ForeCastAvgInfo: foreCastAvgCityWeatherEchartRes, + } + return +} diff --git a/internal/controller/network/server.go b/internal/controller/network/server.go new file mode 100644 index 0000000..35b4147 --- /dev/null +++ b/internal/controller/network/server.go @@ -0,0 +1,81 @@ +package network + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/network" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var Server = cNetworkServer{} + +type cNetworkServer struct{} + +// 获取列表 +func (u *cNetworkServer) GetNetworkServerList(ctx context.Context, req *network.GetNetworkServerListReq) (res *network.GetNetworkServerListRes, err error) { + var input *model.GetNetworkServerListInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.NetworkServer().GetServerList(ctx, input) + if err != nil { + return + } + res = new(network.GetNetworkServerListRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// 获取指定ID数据 +func (u *cNetworkServer) GetServerById(ctx context.Context, req *network.GetNetworkServerByIdReq) (res *network.GetNetworkServerByIdRes, err error) { + out, err := service.NetworkServer().GetServerById(ctx, req.Id) + var data *model.NetworkServerRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &network.GetNetworkServerByIdRes{ + Data: data, + } + return +} + +// 添加数据 +func (u *cNetworkServer) AddServer(ctx context.Context, req *network.AddNetworkServerReq) (res *network.AddNetworkServerRes, err error) { + var data = model.NetworkServerAddInput{} + err = gconv.Scan(req, &data) + err = service.NetworkServer().AddServer(ctx, data) + return +} + +// 修改数据 +func (u *cNetworkServer) EditServer(ctx context.Context, req *network.EditNetworkServerReq) (res *network.EditNetworkServerRes, err error) { + var data = model.NetworkServerEditInput{} + err = gconv.Scan(req, &data) + err = service.NetworkServer().EditServer(ctx, data) + return +} + +// 删除数据 +func (u *cNetworkServer) DeleteServer(ctx context.Context, req *network.DeleteNetworkServerReq) (res *network.DeleteNetworkServerRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.NetworkServer().DeleteServer(ctx, req.Ids) + return +} + +// 修改数据 +func (u *cNetworkServer) SetServerStatus(ctx context.Context, req *network.SetNetworkServerStatusReq) (res *network.SetNetworkServerStatusRes, err error) { + err = service.NetworkServer().SetServerStatus(ctx, req.Id, req.Status) + return +} diff --git a/internal/controller/network/tunnel.go b/internal/controller/network/tunnel.go new file mode 100644 index 0000000..4238b7c --- /dev/null +++ b/internal/controller/network/tunnel.go @@ -0,0 +1,86 @@ +package network + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/network" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" +) + +var Tunnel = cNetworkTunnel{} + +type cNetworkTunnel struct{} + +// 获取列表 +func (u *cNetworkTunnel) GetNetworkTunnelList(ctx context.Context, req *network.GetNetworkTunnelListReq) (res *network.GetNetworkTunnelListRes, err error) { + var input *model.GetNetworkTunnelListInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.NetworkTunnel().GetTunnelList(ctx, input) + if err != nil { + return + } + res = new(network.GetNetworkTunnelListRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// 获取指定ID数据 +func (u *cNetworkTunnel) GetTunnelById(ctx context.Context, req *network.GetNetworkTunnelByIdReq) (res *network.GetNetworkTunnelByIdRes, err error) { + out, err := service.NetworkTunnel().GetTunnelById(ctx, req.Id) + if err != nil { + return + } + var data *model.NetworkTunnelRes + if out != nil { + if err = gconv.Scan(out, &data); err != nil { + return + } + } + res = &network.GetNetworkTunnelByIdRes{ + Data: data, + } + return +} + +// 添加数据 +func (u *cNetworkTunnel) AddTunnel(ctx context.Context, req *network.AddNetworkTunnelReq) (res *network.AddNetworkTunnelRes, err error) { + + var data = model.NetworkTunnelAddInput{} + err = gconv.Scan(req, &data) + _, err = service.NetworkTunnel().AddTunnel(ctx, data) + return +} + +// 修改数据 +func (u *cNetworkTunnel) EditTunnel(ctx context.Context, req *network.EditNetworkTunnelReq) (res *network.EditNetworkTunnelRes, err error) { + var data = model.NetworkTunnelEditInput{} + err = gconv.Scan(req, &data) + err = service.NetworkTunnel().EditTunnel(ctx, data) + return +} + +// 删除数据 +func (u *cNetworkTunnel) DeleteTunnel(ctx context.Context, req *network.DeleteNetworkTunnelReq) (res *network.DeleteNetworkTunnelRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.NetworkTunnel().DeleteTunnel(ctx, req.Ids) + return +} + +// 修改数据 +func (u *cNetworkTunnel) SetTunnelStatus(ctx context.Context, req *network.SetNetworkTunnelStatusReq) (res *network.SetNetworkTunnelStatusRes, err error) { + err = service.NetworkTunnel().SetTunnelStatus(ctx, req.Id, req.Status) + return +} diff --git a/internal/controller/notice/Log.go b/internal/controller/notice/Log.go new file mode 100644 index 0000000..339e257 --- /dev/null +++ b/internal/controller/notice/Log.go @@ -0,0 +1,26 @@ +package notice + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/notice" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var NoticeLog = cNoticeNoticeLog{} + +type cNoticeNoticeLog struct{} + +// 删除日志 +func (u *cNoticeNoticeLog) Del(ctx context.Context, req *notice.LogDelReq) (res *notice.LogDelRes, err error) { + err = service.NoticeLog().Del(ctx, req.Ids) + return +} + +// 通知日志搜索 +func (u *cNoticeNoticeLog) Search(ctx context.Context, req *notice.LogSearchReq) (res *notice.LogSearchRes, err error) { + out, err := service.NoticeLog().Search(ctx, req.NoticeLogSearchInput) + res = ¬ice.LogSearchRes{ + NoticeLogSearchOutput: out, + } + return +} diff --git a/internal/controller/notice/config.go b/internal/controller/notice/config.go new file mode 100644 index 0000000..f26e4a3 --- /dev/null +++ b/internal/controller/notice/config.go @@ -0,0 +1,64 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" + "github.com/sagoo-cloud/sagooiot/api/v1/notice" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var NoticeConfig = cNoticeNoticeConfig{} + +type cNoticeNoticeConfig struct{} + +//GetNoticeConfigList 获取列表 +func (u *cNoticeNoticeConfig) GetNoticeConfigList(ctx context.Context, req *notice.GetNoticeConfigListReq) (res *notice.GetNoticeConfigListRes, err error) { + var reqData = new(model.GetNoticeConfigListInput) + err = gconv.Scan(req, &reqData) + total, currentPage, dataList, err := service.NoticeConfig().GetNoticeConfigList(ctx, reqData) + res = new(notice.GetNoticeConfigListRes) + err = gconv.Scan(dataList, &res.Data) + res.PaginationRes.Total = total + res.PaginationRes.CurrentPage = currentPage + return +} + +//GetNoticeConfigById 获取指定ID数据 +func (u *cNoticeNoticeConfig) GetNoticeConfigById(ctx context.Context, req *notice.GetNoticeConfigByIdReq) (res *notice.GetNoticeConfigByIdRes, err error) { + data, err := service.NoticeConfig().GetNoticeConfigById(ctx, req.Id) + res = new(notice.GetNoticeConfigByIdRes) + err = gconv.Scan(data, &res) + return +} + +//AddNoticeConfig 添加数据 +func (u *cNoticeNoticeConfig) AddNoticeConfig(ctx context.Context, req *notice.AddNoticeConfigReq) (res *notice.AddNoticeConfigRes, err error) { + var data = model.NoticeConfigAddInput{} + err = gconv.Scan(req, &data) + data.Id = guid.S() + err = service.NoticeConfig().AddNoticeConfig(ctx, data) + return +} + +//EditNoticeConfig 修改数据 +func (u *cNoticeNoticeConfig) EditNoticeConfig(ctx context.Context, req *notice.EditNoticeConfigReq) (res *notice.EditNoticeConfigRes, err error) { + var data = model.NoticeConfigEditInput{} + err = gconv.Scan(req, &data) + if err != nil { + return + } + err = service.NoticeConfig().EditNoticeConfig(ctx, data) + return +} + +//DeleteNoticeConfig 删除数据 +func (u *cNoticeNoticeConfig) DeleteNoticeConfig(ctx context.Context, req *notice.DeleteNoticeConfigReq) (res *notice.DeleteNoticeConfigRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.NoticeConfig().DeleteNoticeConfig(ctx, req.Ids) + return +} diff --git a/internal/controller/notice/info.go b/internal/controller/notice/info.go new file mode 100644 index 0000000..4006e37 --- /dev/null +++ b/internal/controller/notice/info.go @@ -0,0 +1,67 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/notice" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var NoticeInfo = cNoticeNoticeInfo{} + +type cNoticeNoticeInfo struct{} + +//GetNoticeInfoList 获取列表 +func (u *cNoticeNoticeInfo) GetNoticeInfoList(ctx context.Context, req *notice.GetNoticeInfoListReq) (res *notice.GetNoticeInfoListRes, err error) { + var reqData = new(model.GetNoticeInfoListInput) + if err = gconv.Scan(req, &reqData); err != nil { + return + } + total, currentPage, dataList, err := service.NoticeInfo().GetNoticeInfoList(ctx, reqData) + res = new(notice.GetNoticeInfoListRes) + if err = gconv.Scan(dataList, &res.Data); err != nil { + return + } + res.PaginationRes.Total = total + res.PaginationRes.CurrentPage = currentPage + return +} + +//GetNoticeInfoById 获取指定ID数据 +func (u *cNoticeNoticeInfo) GetNoticeInfoById(ctx context.Context, req *notice.GetNoticeInfoByIdReq) (res *notice.GetNoticeInfoByIdRes, err error) { + data, err := service.NoticeInfo().GetNoticeInfoById(ctx, req.Id) + res = new(notice.GetNoticeInfoByIdRes) + err = gconv.Scan(data, &res) + return +} + +//AddNoticeInfo 添加数据 +func (u *cNoticeNoticeInfo) AddNoticeInfo(ctx context.Context, req *notice.AddNoticeInfoReq) (res *notice.AddNoticeInfoRes, err error) { + var data = model.NoticeInfoAddInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + err = service.NoticeInfo().AddNoticeInfo(ctx, data) + return +} + +//EditNoticeInfo 修改数据 +func (u *cNoticeNoticeInfo) EditNoticeInfo(ctx context.Context, req *notice.EditNoticeInfoReq) (res *notice.EditNoticeInfoRes, err error) { + var data = model.NoticeInfoEditInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + err = service.NoticeInfo().EditNoticeInfo(ctx, data) + return +} + +//DeleteNoticeInfo 删除数据 +func (u *cNoticeNoticeInfo) DeleteNoticeInfo(ctx context.Context, req *notice.DeleteNoticeInfoReq) (res *notice.DeleteNoticeInfoRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.NoticeInfo().DeleteNoticeInfo(ctx, req.Ids) + return +} diff --git a/internal/controller/notice/template.go b/internal/controller/notice/template.go new file mode 100644 index 0000000..008048d --- /dev/null +++ b/internal/controller/notice/template.go @@ -0,0 +1,92 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" + "github.com/sagoo-cloud/sagooiot/api/v1/notice" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var NoticeTemplate = cNoticeNoticeTemplate{} + +type cNoticeNoticeTemplate struct{} + +//GetNoticeTemplateList 获取列表 +func (u *cNoticeNoticeTemplate) GetNoticeTemplateList(ctx context.Context, req *notice.GetNoticeTemplateListReq) (res *notice.GetNoticeTemplateListRes, err error) { + var reqData = new(model.GetNoticeTemplateListInput) + if err = gconv.Scan(req, &reqData); err != nil { + return + } + total, currentPage, dataList, err := service.NoticeTemplate().GetNoticeTemplateList(ctx, reqData) + res = new(notice.GetNoticeTemplateListRes) + err = gconv.Scan(dataList, &res.Data) + res.PaginationRes.Total = total + res.PaginationRes.CurrentPage = currentPage + return +} + +//GetNoticeTemplateById 获取指定ID数据 +func (u *cNoticeNoticeTemplate) GetNoticeTemplateById(ctx context.Context, req *notice.GetNoticeTemplateByIdReq) (res *notice.GetNoticeTemplateByIdRes, err error) { + data, err := service.NoticeTemplate().GetNoticeTemplateById(ctx, req.Id) + res = new(notice.GetNoticeTemplateByIdRes) + err = gconv.Scan(data, &res) + return +} + +//GetNoticeTemplateByConfigId 获取指定ConfigID数据 +func (u *cNoticeNoticeTemplate) GetNoticeTemplateByConfigId(ctx context.Context, req *notice.GetNoticeTemplateByConfigIdReq) (res *notice.GetNoticeTemplateByConfigIdRes, err error) { + data, err := service.NoticeTemplate().GetNoticeTemplateByConfigId(ctx, req.ConfigId) + res = new(notice.GetNoticeTemplateByConfigIdRes) + if data == nil { + return + } + err = gconv.Scan(data, &res) + return +} + +//AddNoticeTemplate 添加数据 +func (u *cNoticeNoticeTemplate) AddNoticeTemplate(ctx context.Context, req *notice.AddNoticeTemplateReq) (res *notice.AddNoticeTemplateRes, err error) { + var data = model.NoticeTemplateAddInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + data.Id = guid.S() + err = service.NoticeTemplate().AddNoticeTemplate(ctx, data) + return +} + +//EditNoticeTemplate 修改数据 +func (u *cNoticeNoticeTemplate) EditNoticeTemplate(ctx context.Context, req *notice.EditNoticeTemplateReq) (res *notice.EditNoticeTemplateRes, err error) { + var data = model.NoticeTemplateEditInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + //data.UpdateBy = userInfo.Id //如果需要保存信息,把这个打开 + err = service.NoticeTemplate().EditNoticeTemplate(ctx, data) + return +} + +//SaveNoticeTemplate 直接更新数据 +func (u *cNoticeNoticeTemplate) SaveNoticeTemplate(ctx context.Context, req *notice.SaveNoticeTemplateReq) (res *notice.SaveNoticeTemplateRes, err error) { + var data = model.NoticeTemplateAddInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + if data.Id == "" { + data.Id = guid.S() + } + err = service.NoticeTemplate().SaveNoticeTemplate(ctx, data) + return +} + +//DeleteNoticeTemplate 删除数据 +func (u *cNoticeNoticeTemplate) DeleteNoticeTemplate(ctx context.Context, req *notice.DeleteNoticeTemplateReq) (res *notice.DeleteNoticeTemplateRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.NoticeTemplate().DeleteNoticeTemplate(ctx, req.Ids) + return +} diff --git a/internal/controller/product/category.go b/internal/controller/product/category.go new file mode 100644 index 0000000..cc45afe --- /dev/null +++ b/internal/controller/product/category.go @@ -0,0 +1,44 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var Category = cCategory{} + +type cCategory struct{} + +func (c *cCategory) ListForPage(ctx context.Context, req *product.CategoryListForPageReq) (res *product.CategoryListForPageRes, err error) { + list, total, err := service.DevCategory().ListForPage(ctx, req.PageNum, req.PageSize, req.Name) + res = &product.CategoryListForPageRes{ + Category: list, + } + res.Total = total + res.CurrentPage = req.PageNum + return +} + +func (c *cCategory) List(ctx context.Context, req *product.CategoryListReq) (res *product.CategoryListRes, err error) { + list, err := service.DevCategory().List(ctx, req.Name) + res = &product.CategoryListRes{ + Category: list, + } + return +} + +func (c *cCategory) Add(ctx context.Context, req *product.AddCategoryReq) (res *product.AddCategoryRes, err error) { + err = service.DevCategory().Add(ctx, req.AddProductCategoryInput) + return +} + +func (c *cCategory) Edit(ctx context.Context, req *product.EditCategoryReq) (res *product.EditCategoryRes, err error) { + err = service.DevCategory().Edit(ctx, req.EditProductCategoryInput) + return +} + +func (c *cCategory) Del(ctx context.Context, req *product.DelCategoryReq) (res *product.DelCategoryRes, err error) { + err = service.DevCategory().Del(ctx, req.Id) + return +} diff --git a/internal/controller/product/device.go b/internal/controller/product/device.go new file mode 100644 index 0000000..f051cd2 --- /dev/null +++ b/internal/controller/product/device.go @@ -0,0 +1,119 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var Device = cDevice{} + +type cDevice struct{} + +func (c *cDevice) Get(ctx context.Context, req *product.GetDeviceReq) (res *product.GetDeviceRes, err error) { + p, err := service.DevDevice().Get(ctx, req.Key) + res = &product.GetDeviceRes{ + Data: p, + } + return +} + +func (c *cDevice) Detail(ctx context.Context, req *product.DetailDeviceReq) (res *product.DetailDeviceRes, err error) { + p, err := service.DevDevice().Detail(ctx, req.Id) + res = &product.DetailDeviceRes{ + Data: p, + } + return +} + +func (c *cDevice) ListForPage(ctx context.Context, req *product.ListDeviceForPageReq) (res *product.ListDeviceForPageRes, err error) { + out, err := service.DevDevice().ListForPage(ctx, req.ListDeviceForPageInput) + res = &product.ListDeviceForPageRes{ + ListDeviceForPageOutput: out, + } + return +} + +func (c *cDevice) List(ctx context.Context, req *product.ListDeviceReq) (res *product.ListDeviceRes, err error) { + out, err := service.DevDevice().List(ctx, req.ListDeviceInput) + res = &product.ListDeviceRes{ + Device: out, + } + return +} + +func (c *cDevice) Add(ctx context.Context, req *product.AddDeviceReq) (res *product.AddDeviceRes, err error) { + _, err = service.DevDevice().Add(ctx, req.AddDeviceInput) + return +} + +func (c *cDevice) Edit(ctx context.Context, req *product.EditDeviceReq) (res *product.EditDeviceRes, err error) { + err = service.DevDevice().Edit(ctx, req.EditDeviceInput) + return +} + +func (c *cDevice) Del(ctx context.Context, req *product.DelDeviceReq) (res *product.DelDeviceRes, err error) { + err = service.DevDevice().Del(ctx, req.Ids) + return +} + +func (c *cDevice) Deploy(ctx context.Context, req *product.DeployDeviceReq) (res *product.DeployDeviceRes, err error) { + err = service.DevDevice().Deploy(ctx, req.Id) + return +} + +func (c *cDevice) Undeploy(ctx context.Context, req *product.UndeployDeviceReq) (res *product.UndeployDeviceRes, err error) { + err = service.DevDevice().Undeploy(ctx, req.Id) + return +} + +func (c *cDevice) Online(ctx context.Context, req *product.OnlineDeviceReq) (res *product.OnlineDeviceRes, err error) { + err = service.DevDevice().Online(ctx, req.Key) + return +} + +func (c *cDevice) Offline(ctx context.Context, req *product.OfflineDeviceReq) (res *product.OfflineDeviceRes, err error) { + err = service.DevDevice().Offline(ctx, req.Key) + return +} + +func (c *cDevice) RunStatus(ctx context.Context, req *product.DeviceRunStatusReq) (res *product.DeviceRunStatusRes, err error) { + out, err := service.DevDevice().RunStatus(ctx, req.Id) + if err != nil { + return + } + res = &product.DeviceRunStatusRes{ + DeviceRunStatusOutput: out, + } + return +} + +func (c *cDevice) GetProperty(ctx context.Context, req *product.DeviceGetPropertyReq) (res *product.DeviceGetPropertyRes, err error) { + out, err := service.DevDevice().GetProperty(ctx, req.DeviceGetPropertyInput) + res = &product.DeviceGetPropertyRes{ + DevicePropertiy: out, + } + return +} + +func (c *cDevice) GetPropertyList(ctx context.Context, req *product.DeviceGetPropertyListReq) (res *product.DeviceGetPropertyListRes, err error) { + out, err := service.DevDevice().GetPropertyList(ctx, req.DeviceGetPropertyListInput) + res = &product.DeviceGetPropertyListRes{ + DeviceGetPropertyListOutput: out, + } + return +} + +func (c *cDevice) Statistics(ctx context.Context, req *product.DeviceStatisticsReq) (res product.DeviceStatisticsRes, err error) { + res.DeviceTotal, err = service.DevDevice().Total(ctx) + return +} + +func (c *cDevice) StatisticsForMonths(ctx context.Context, req *product.DeviceStatisticsForMonthsReq) (res product.DeviceStatisticsForMonthsRes, err error) { + res.MsgTotal, err = service.DevDevice().TotalForMonths(ctx) + if err != nil { + return + } + res.AlarmTotal, err = service.DevDevice().AlarmTotalForMonths(ctx) + return +} diff --git a/internal/controller/product/device_log.go b/internal/controller/product/device_log.go new file mode 100644 index 0000000..b4bc10e --- /dev/null +++ b/internal/controller/product/device_log.go @@ -0,0 +1,27 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DeviceLog = cDeviceLog{} + +type cDeviceLog struct{} + +// 日志类型 +func (c *cDeviceLog) LogType(ctx context.Context, req *product.DeviceLogTypeReq) (res *product.DeviceLogTypeRes, err error) { + res = new(product.DeviceLogTypeRes) + res.List = service.DevDeviceLog().LogType(ctx) + return +} + +// 日志搜索 +func (c *cDeviceLog) Search(ctx context.Context, req *product.DeviceLogSearchReq) (res *product.DeviceLogSearchRes, err error) { + out, err := service.DevDeviceLog().Search(ctx, req.DeviceLogSearchInput) + res = &product.DeviceLogSearchRes{ + DeviceLogSearchOutput: out, + } + return +} diff --git a/internal/controller/product/device_tag.go b/internal/controller/product/device_tag.go new file mode 100644 index 0000000..984f368 --- /dev/null +++ b/internal/controller/product/device_tag.go @@ -0,0 +1,26 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DeviceTag = cDeviceTag{} + +type cDeviceTag struct{} + +func (c *cDeviceTag) Add(ctx context.Context, req *product.AddTagDeviceReq) (res *product.AddTagDeviceRes, err error) { + err = service.DevDeviceTag().Add(ctx, req.AddTagDeviceInput) + return +} + +func (c *cDeviceTag) Edit(ctx context.Context, req *product.EditTagDeviceReq) (res *product.EditTagDeviceRes, err error) { + err = service.DevDeviceTag().Edit(ctx, req.EditTagDeviceInput) + return +} + +func (c *cDeviceTag) Del(ctx context.Context, req *product.DelTagDeviceReq) (res *product.DelTagDeviceRes, err error) { + err = service.DevDeviceTag().Del(ctx, req.Id) + return +} diff --git a/internal/controller/product/product.go b/internal/controller/product/product.go new file mode 100644 index 0000000..3cbb2e6 --- /dev/null +++ b/internal/controller/product/product.go @@ -0,0 +1,92 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +var Product = cProduct{} + +type cProduct struct{} + +func (c *cProduct) Get(ctx context.Context, req *product.GetProductReq) (res *product.GetProductRes, err error) { + p, err := service.DevProduct().Get(ctx, req.Key) + res = &product.GetProductRes{ + Data: p, + } + return +} + +func (c *cProduct) Detail(ctx context.Context, req *product.DetailProductReq) (res *product.DetailProductRes, err error) { + p, err := service.DevProduct().Detail(ctx, req.Id) + res = &product.DetailProductRes{ + Data: p, + } + return +} + +func (c *cProduct) ListForPage(ctx context.Context, req *product.ListForPageReq) (res *product.ListForPageRes, err error) { + out, err := service.DevProduct().ListForPage(ctx, &req.ListForPageInput) + res = &product.ListForPageRes{ + ListForPageOutput: *out, + } + return +} + +func (c *cProduct) List(ctx context.Context, req *product.ListReq) (res *product.ListRes, err error) { + list, err := service.DevProduct().List(ctx) + res = &product.ListRes{ + Product: list, + } + return +} + +func (c *cProduct) Add(ctx context.Context, req *product.AddProductReq) (res *product.AddProductRes, err error) { + err = service.DevProduct().Add(ctx, req.AddProductInput) + return +} + +func (c *cProduct) Edit(ctx context.Context, req *product.EditProductReq) (res *product.EditProductRes, err error) { + err = service.DevProduct().Edit(ctx, req.EditProductInput) + return +} + +func (c *cProduct) Del(ctx context.Context, req *product.DelProductReq) (res *product.DelProductRes, err error) { + err = service.DevProduct().Del(ctx, req.Ids) + return +} + +func (c *cProduct) Deploy(ctx context.Context, req *product.DeployProductReq) (res *product.DeployProductRes, err error) { + err = service.DevProduct().Deploy(ctx, req.Id) + return +} + +func (c *cProduct) Undeploy(ctx context.Context, req *product.UndeployProductReq) (res *product.UndeployProductRes, err error) { + err = service.DevProduct().Undeploy(ctx, req.Id) + return +} + +func (c *cProduct) UploadIcon(ctx context.Context, req *product.UploadIconReq) (res *product.UploadIconRes, err error) { + if req.Icon == nil { + return nil, gerror.NewCode(gcode.CodeMissingParameter, "请选择上传的图片") + } + + uploadPath := g.Cfg().MustGet(ctx, "upload.path").String() + + filename, err := req.Icon.Save(uploadPath+"/product_icon", true) + if err != nil { + err = gerror.New("图片上传失败") + return + } + + res = &product.UploadIconRes{ + IconPath: uploadPath + "/product_icon/" + filename, + } + + return +} diff --git a/internal/controller/product/protocol.go b/internal/controller/product/protocol.go new file mode 100644 index 0000000..c5d1d07 --- /dev/null +++ b/internal/controller/product/protocol.go @@ -0,0 +1,35 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +var Protocol = cProtocol{} + +type cProtocol struct{} + +// ListMessageProtocol 消息协议列表 +func (c *cProtocol) ListMessageProtocol(ctx context.Context, req *product.ListMessageProtocolReq) (res *product.ListMessageProtocolRes, err error) { + res = &product.ListMessageProtocolRes{ + Data: []*model.MessageProtocolRes{ + {Key: "modbus", Name: "modbus"}, + }, + } + return +} + +// ListTrunsportProtocol 传输协议列表 +func (c *cProtocol) ListTrunsportProtocol(ctx context.Context, req *product.ListTrunsportProtocolReq) (res *product.ListTrunsportProtocolRes, err error) { + res = &product.ListTrunsportProtocolRes{ + Data: []*model.TrunsportProtocolRes{ + {Key: "tcp-server", Name: "tcp服务端"}, + {Key: "tcp-client", Name: "tcp客户端"}, + {Key: "udp-server", Name: "udp服务端"}, + {Key: "udp-client", Name: "udp客户端"}, + {Key: "serial", Name: "serial"}, + }, + } + return +} diff --git a/internal/controller/product/tsl_data_type.go b/internal/controller/product/tsl_data_type.go new file mode 100644 index 0000000..0c88a00 --- /dev/null +++ b/internal/controller/product/tsl_data_type.go @@ -0,0 +1,17 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TSLDataType = cTSLDataType{} + +type cTSLDataType struct{} + +func (c *cTSLDataType) DataTypeValueList(ctx context.Context, req *product.DateTypeReq) (res *product.DateTypeRes, err error) { + res = new(product.DateTypeRes) + res.DataType, err = service.DevTSLDataType().DataTypeValueList(ctx) + return +} diff --git a/internal/controller/product/tsl_event.go b/internal/controller/product/tsl_event.go new file mode 100644 index 0000000..294d119 --- /dev/null +++ b/internal/controller/product/tsl_event.go @@ -0,0 +1,34 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TSLEvent = cTSLEvent{} + +type cTSLEvent struct{} + +func (c *cTSLEvent) ListEvent(ctx context.Context, req *product.ListTSLEventReq) (res *product.ListTSLEventRes, err error) { + out, err := service.DevTSLEvent().ListEvent(ctx, req.ListTSLEventInput) + res = &product.ListTSLEventRes{ + ListTSLEventOutput: out, + } + return +} + +func (c *cTSLEvent) AddEvent(ctx context.Context, req *product.AddTSLEventReq) (res *product.AddTSLEventRes, err error) { + err = service.DevTSLEvent().AddEvent(ctx, req.TSLEventInput) + return +} + +func (c *cTSLEvent) EditEvent(ctx context.Context, req *product.EditTSLEventReq) (res *product.EditTSLEventRes, err error) { + err = service.DevTSLEvent().EditEvent(ctx, req.TSLEventInput) + return +} + +func (c *cTSLEvent) DelEvent(ctx context.Context, req *product.DelTSLEventReq) (res *product.DelTSLEventRes, err error) { + err = service.DevTSLEvent().DelEvent(ctx, req.DelTSLEventInput) + return +} diff --git a/internal/controller/product/tsl_function.go b/internal/controller/product/tsl_function.go new file mode 100644 index 0000000..fbdb879 --- /dev/null +++ b/internal/controller/product/tsl_function.go @@ -0,0 +1,34 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TSLFunction = cTSLFunction{} + +type cTSLFunction struct{} + +func (c *cTSLFunction) ListFunction(ctx context.Context, req *product.ListTSLFunctionReq) (res *product.ListTSLFunctionRes, err error) { + out, err := service.DevTSLFunction().ListFunction(ctx, req.ListTSLFunctionInput) + res = &product.ListTSLFunctionRes{ + ListTSLFunctionOutput: out, + } + return +} + +func (c *cTSLFunction) AddFunction(ctx context.Context, req *product.AddTSLFunctionReq) (res *product.AddTSLFunctionRes, err error) { + err = service.DevTSLFunction().AddFunction(ctx, req.TSLFunctionAddInput) + return +} + +func (c *cTSLFunction) EditFunction(ctx context.Context, req *product.EditTSLFunctionReq) (res *product.EditTSLFunctionRes, err error) { + err = service.DevTSLFunction().EditFunction(ctx, req.TSLFunctionAddInput) + return +} + +func (c *cTSLFunction) DelFunction(ctx context.Context, req *product.DelTSLFunctionReq) (res *product.DelTSLFunctionRes, err error) { + err = service.DevTSLFunction().DelFunction(ctx, req.DelTSLFunctionInput) + return +} diff --git a/internal/controller/product/tsl_property.go b/internal/controller/product/tsl_property.go new file mode 100644 index 0000000..217c054 --- /dev/null +++ b/internal/controller/product/tsl_property.go @@ -0,0 +1,42 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TSLProperty = cTSLProperty{} + +type cTSLProperty struct{} + +func (c *cTSLProperty) ListProperty(ctx context.Context, req *product.ListTSLPropertyReq) (res *product.ListTSLPropertyRes, err error) { + out, err := service.DevTSLProperty().ListProperty(ctx, req.ListTSLPropertyInput) + res = &product.ListTSLPropertyRes{ + ListTSLPropertyOutput: out, + } + return +} + +func (c *cTSLProperty) AllProperty(ctx context.Context, req *product.AllTSLPropertyReq) (res *product.AllTSLPropertyRes, err error) { + list, err := service.DevTSLProperty().AllProperty(ctx, req.Key) + res = &product.AllTSLPropertyRes{ + Data: list, + } + return +} + +func (c *cTSLProperty) AddProperty(ctx context.Context, req *product.AddTSLPropertyReq) (res *product.AddTSLPropertyRes, err error) { + err = service.DevTSLProperty().AddProperty(ctx, req.TSLPropertyInput) + return +} + +func (c *cTSLProperty) EditProperty(ctx context.Context, req *product.EditTSLPropertyReq) (res *product.EditTSLPropertyRes, err error) { + err = service.DevTSLProperty().EditProperty(ctx, req.TSLPropertyInput) + return +} + +func (c *cTSLProperty) DelProperty(ctx context.Context, req *product.DelTSLPropertyReq) (res *product.DelTSLPropertyRes, err error) { + err = service.DevTSLProperty().DelProperty(ctx, req.DelTSLPropertyInput) + return +} diff --git a/internal/controller/product/tsl_tag.go b/internal/controller/product/tsl_tag.go new file mode 100644 index 0000000..5367489 --- /dev/null +++ b/internal/controller/product/tsl_tag.go @@ -0,0 +1,34 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/product" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TSLTag = cTSLTag{} + +type cTSLTag struct{} + +func (c *cTSLTag) ListTag(ctx context.Context, req *product.ListTSLTagReq) (res *product.ListTSLTagRes, err error) { + out, err := service.DevTSLTag().ListTag(ctx, req.ListTSLTagInput) + res = &product.ListTSLTagRes{ + ListTSLTagOutput: out, + } + return +} + +func (c *cTSLTag) AddTag(ctx context.Context, req *product.AddTSLTagReq) (res *product.AddTSLTagRes, err error) { + err = service.DevTSLTag().AddTag(ctx, req.TSLTagInput) + return +} + +func (c *cTSLTag) EditTag(ctx context.Context, req *product.EditTSLTagReq) (res *product.EditTSLTagRes, err error) { + err = service.DevTSLTag().EditTag(ctx, req.TSLTagInput) + return +} + +func (c *cTSLTag) DelTag(ctx context.Context, req *product.DelTSLTagReq) (res *product.DelTSLTagRes, err error) { + err = service.DevTSLTag().DelTag(ctx, req.DelTSLTagInput) + return +} diff --git a/internal/controller/source/node.go b/internal/controller/source/node.go new file mode 100644 index 0000000..682ff2f --- /dev/null +++ b/internal/controller/source/node.go @@ -0,0 +1,38 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DataNode = cDataNode{} + +type cDataNode struct{} + +// 添加数据节点 +func (c *cDataNode) Add(ctx context.Context, req *source.DataNodeAddReq) (res *source.DataNodeAddRes, err error) { + err = service.DataNode().Add(ctx, req.DataNodeAddInput) + return +} + +// 编辑数据节点 +func (c *cDataNode) Edit(ctx context.Context, req *source.DataNodeEditReq) (res *source.DataNodeEditRes, err error) { + err = service.DataNode().Edit(ctx, req.DataNodeEditInput) + return +} + +// 删除数据节点 +func (c *cDataNode) Del(ctx context.Context, req *source.DataNodeDelReq) (res *source.DataNodeDelRes, err error) { + err = service.DataNode().Del(ctx, req.NodeId) + return +} + +// 数据节点列表 +func (c *cDataNode) List(ctx context.Context, req *source.DataNodeListReq) (res *source.DataNodeListRes, err error) { + list, err := service.DataNode().List(ctx, req.SourceId) + res = &source.DataNodeListRes{ + List: list, + } + return +} diff --git a/internal/controller/source/source.go b/internal/controller/source/source.go new file mode 100644 index 0000000..7f962d3 --- /dev/null +++ b/internal/controller/source/source.go @@ -0,0 +1,94 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DataSource = cDataSource{} + +type cDataSource struct{} + +// 添加 api 数据源 +func (c *cDataSource) Add(ctx context.Context, req *source.DataSourceApiAddReq) (res *source.DataSourceApiAddRes, err error) { + _, err = service.DataSource().Add(ctx, req.DataSourceApiAddInput) + return +} + +// 编辑 api 数据源 +func (c *cDataSource) Edit(ctx context.Context, req *source.DataSourceApiEditReq) (res *source.DataSourceApiEditRes, err error) { + err = service.DataSource().Edit(ctx, req.DataSourceApiEditInput) + return +} + +// 获取 api 数据 +func (c *cDataSource) GetApiData(ctx context.Context, req *source.DataSourceApiGetReq) (res *source.DataSourceApiGetRes, err error) { + res = new(source.DataSourceApiGetRes) + data, err := service.DataSource().GetApiData(ctx, req.SourceId) + if err != nil { + return + } + if len(data) > 0 { + res.Data = data[0] + } + return +} + +// 批量删除数据源 +func (c *cDataSource) Del(ctx context.Context, req *source.DataSourceDelReq) (res *source.DataSourceDelRes, err error) { + err = service.DataSource().Del(ctx, req.Ids) + return +} + +// 搜索数据源 +func (c *cDataSource) Search(ctx context.Context, req *source.DataSourceSearchReq) (res *source.DataSourceSearchRes, err error) { + out, err := service.DataSource().Search(ctx, req.DataSourceSearchInput) + res = &source.DataSourceSearchRes{ + DataSourceSearchOutput: out, + } + return +} + +// 数据源列表 +func (c *cDataSource) List(ctx context.Context, req *source.DataSourceListReq) (res *source.DataSourceListRes, err error) { + list, err := service.DataSource().List(ctx) + res = &source.DataSourceListRes{ + List: list, + } + return +} + +// 详情 +func (c *cDataSource) Detail(ctx context.Context, req *source.DataSourceReq) (res *source.DataSourceRes, err error) { + res = new(source.DataSourceRes) + res.Data, err = service.DataSource().Detail(ctx, req.SourceId) + return +} + +// 发布 +func (c *cDataSource) Deploy(ctx context.Context, req *source.DataSourceDeployReq) (res *source.DataSourceDeployRes, err error) { + err = service.DataSource().Deploy(ctx, req.SourceId) + return +} + +// 停用 +func (c *cDataSource) Undeploy(ctx context.Context, req *source.DataSourceUndeployReq) (res *source.DataSourceUndeployRes, err error) { + err = service.DataSource().Undeploy(ctx, req.SourceId) + return +} + +// 获取源数据记录 +func (c *cDataSource) GetData(ctx context.Context, req *source.DataSourceDataReq) (res *source.DataSourceDataRes, err error) { + out, err := service.DataSource().GetData(ctx, req.DataSourceDataInput) + res = &source.DataSourceDataRes{ + DataSourceDataOutput: out, + } + return +} + +// 复制数据源 +func (c *cDataSource) Copy(ctx context.Context, req *source.DataSourceCopyReq) (res *source.DataSourceCopyRes, err error) { + err = service.DataSource().CopeSource(ctx, req.SourceId) + return +} diff --git a/internal/controller/source/source_db.go b/internal/controller/source/source_db.go new file mode 100644 index 0000000..0e1913f --- /dev/null +++ b/internal/controller/source/source_db.go @@ -0,0 +1,33 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +// 添加 数据库 数据源 +func (c *cDataSource) AddDb(ctx context.Context, req *source.DataSourceDbAddReq) (res *source.DataSourceDbAddRes, err error) { + _, err = service.DataSource().AddDb(ctx, req.DataSourceDbAddInput) + return +} + +// 编辑 数据库 数据源 +func (c *cDataSource) EditDb(ctx context.Context, req *source.DataSourceDbEditReq) (res *source.DataSourceDbEditRes, err error) { + err = service.DataSource().EditDb(ctx, req.DataSourceDbEditInput) + return +} + +// 获取 数据库 数据 +func (c *cDataSource) GetDbData(ctx context.Context, req *source.DataSourceDbGetReq) (res *source.DataSourceDbGetRes, err error) { + res = new(source.DataSourceDbGetRes) + res.Data, err = service.DataSource().GetDbData(ctx, req.SourceId) + return +} + +// 获取 数据表 字段 +func (c *cDataSource) GetDbFields(ctx context.Context, req *source.DataSourceDbFieldsReq) (res *source.DataSourceDbFieldsRes, err error) { + res = new(source.DataSourceDbFieldsRes) + res.Data, err = service.DataSource().GetDbFields(ctx, req.SourceId) + return +} diff --git a/internal/controller/source/source_device.go b/internal/controller/source/source_device.go new file mode 100644 index 0000000..c600437 --- /dev/null +++ b/internal/controller/source/source_device.go @@ -0,0 +1,26 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +// 添加 设备 数据源 +func (c *cDataSource) AddDevice(ctx context.Context, req *source.DataSourceDeviceAddReq) (res *source.DataSourceDeviceAddRes, err error) { + _, err = service.DataSource().AddDevice(ctx, req.DataSourceDeviceAddInput) + return +} + +// 编辑 设备 数据源 +func (c *cDataSource) EditDevice(ctx context.Context, req *source.DataSourceDeviceEditReq) (res *source.DataSourceDeviceEditRes, err error) { + err = service.DataSource().EditDevice(ctx, req.DataSourceDeviceEditInput) + return +} + +// 获取 设备 数据 +func (c *cDataSource) GetDeviceData(ctx context.Context, req *source.DataSourceDeviceGetReq) (res *source.DataSourceDeviceGetRes, err error) { + res = new(source.DataSourceDeviceGetRes) + res.Data, err = service.DataSource().GetDeviceData(ctx, req.SourceId) + return +} diff --git a/internal/controller/source/template.go b/internal/controller/source/template.go new file mode 100644 index 0000000..afdb0a2 --- /dev/null +++ b/internal/controller/source/template.go @@ -0,0 +1,99 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DataTemplate = cDataTemplate{} + +type cDataTemplate struct{} + +// 添加数据模型 +func (c *cDataTemplate) Add(ctx context.Context, req *source.DataTemplateAddReq) (res *source.DataTemplateAddRes, err error) { + _, err = service.DataTemplate().Add(ctx, req.DataTemplateAddInput) + return +} + +// 编辑数据模型 +func (c *cDataTemplate) Edit(ctx context.Context, req *source.DataTemplateEditReq) (res *source.DataTemplateEditRes, err error) { + err = service.DataTemplate().Edit(ctx, req.DataTemplateEditInput) + return +} + +// 批量删除数据模型 +func (c *cDataTemplate) Del(ctx context.Context, req *source.DataTemplateDelReq) (res *source.DataTemplateDelRes, err error) { + err = service.DataTemplate().Del(ctx, req.Ids) + return +} + +// 搜索数据模型 +func (c *cDataTemplate) Search(ctx context.Context, req *source.DataTemplateSearchReq) (res *source.DataTemplateSearchRes, err error) { + out, err := service.DataTemplate().Search(ctx, req.DataTemplateSearchInput) + res = &source.DataTemplateSearchRes{ + DataTemplateSearchOutput: out, + } + return +} + +// 已发布数据模型列表 +func (c *cDataTemplate) List(ctx context.Context, req *source.DataTemplateListReq) (res *source.DataTemplateListRes, err error) { + list, err := service.DataTemplate().List(ctx) + res = &source.DataTemplateListRes{ + List: list, + } + return +} + +// 详情 +func (c *cDataTemplate) Detail(ctx context.Context, req *source.DataTemplateReq) (res *source.DataTemplateRes, err error) { + res = new(source.DataTemplateRes) + res.Data, err = service.DataTemplate().Detail(ctx, req.Id) + return +} + +// 发布 +func (c *cDataTemplate) Deploy(ctx context.Context, req *source.DataTemplateDeployReq) (res *source.DataTemplateDeployRes, err error) { + err = service.DataTemplate().Deploy(ctx, req.Id) + return +} + +// 停用 +func (c *cDataTemplate) Undeploy(ctx context.Context, req *source.DataTemplateUndeployReq) (res *source.DataTemplateUndeployRes, err error) { + err = service.DataTemplate().Undeploy(ctx, req.Id) + return +} + +// 获取模型数据 +func (c *cDataTemplate) GetData(ctx context.Context, req *source.DataTemplateDataReq) (res *source.DataTemplateDataRes, err error) { + out, err := service.DataTemplate().GetData(ctx, req.DataTemplateDataInput) + res = &source.DataTemplateDataRes{ + DataTemplateDataOutput: out, + } + return +} + +// 复制模型 +func (c *cDataTemplate) Copy(ctx context.Context, req *source.DataTemplateCopyReq) (res *source.DataTemplateCopyRes, err error) { + err = service.DataTemplate().CopeTemplate(ctx, req.Id) + return +} + +// 检测数据模型是否需要设置关联 +func (c *cDataTemplate) CheckRelation(ctx context.Context, req *source.DataTemplateCheckRelationReq) (res source.DataTemplateCheckRelationRes, err error) { + res.Yes, err = service.DataTemplate().CheckRelation(ctx, req.Id) + return +} + +// 设置主源、关联字段 +func (c *cDataTemplate) SetRelation(ctx context.Context, req *source.DataTemplateRelationReq) (res *source.DataTemplateRelationRes, err error) { + err = service.DataTemplate().SetRelation(ctx, req.TemplateDataRelationInput) + return +} + +// 数据源列表 +func (c *cDataTemplate) SourceList(ctx context.Context, req *source.TemplateSourceListReq) (res source.TemplateSourceListRes, err error) { + res.List, err = service.DataTemplate().SourceList(ctx, req.Id) + return +} diff --git a/internal/controller/source/template_node.go b/internal/controller/source/template_node.go new file mode 100644 index 0000000..404cfd2 --- /dev/null +++ b/internal/controller/source/template_node.go @@ -0,0 +1,38 @@ +package source + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/source" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var DataTemplateNode = cDataTemplateNode{} + +type cDataTemplateNode struct{} + +// 添加数据模型节点 +func (c *cDataTemplateNode) Add(ctx context.Context, req *source.DataTemplateNodeAddReq) (res *source.DataTemplateNodeAddRes, err error) { + err = service.DataTemplateNode().Add(ctx, req.DataTemplateNodeAddInput) + return +} + +// 编辑数据模型节点 +func (c *cDataTemplateNode) Edit(ctx context.Context, req *source.DataTemplateNodeEditReq) (res *source.DataTemplateNodeEditRes, err error) { + err = service.DataTemplateNode().Edit(ctx, req.DataTemplateNodeEditInput) + return +} + +// 删除数据模型节点 +func (c *cDataTemplateNode) Del(ctx context.Context, req *source.DataTemplateNodeDelReq) (res *source.DataTemplateNodeDelRes, err error) { + err = service.DataTemplateNode().Del(ctx, req.Id) + return +} + +// 数据模型节点列表 +func (c *cDataTemplateNode) List(ctx context.Context, req *source.DataTemplateNodeListReq) (res *source.DataTemplateNodeListRes, err error) { + list, err := service.DataTemplateNode().List(ctx, req.Tid) + res = &source.DataTemplateNodeListRes{ + List: list, + } + return +} diff --git a/internal/controller/system/captcha.go b/internal/controller/system/captcha.go new file mode 100644 index 0000000..ec34264 --- /dev/null +++ b/internal/controller/system/captcha.go @@ -0,0 +1,26 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" +) + +// 图形验证码 +var Captcha = cCaptcha{} + +type cCaptcha struct{} + +func (a *cCaptcha) Index(ctx context.Context, req *systemV1.CaptchaIndexReq) (res *systemV1.CaptchaIndexRes, err error) { + var ( + idKeyC, base64stringC string + ) + idKeyC, base64stringC, err = service.Captcha().GetVerifyImgString(ctx) + res = &systemV1.CaptchaIndexRes{ + Key: idKeyC, + Img: base64stringC, + } + + return +} diff --git a/internal/controller/system/login.go b/internal/controller/system/login.go new file mode 100644 index 0000000..180b133 --- /dev/null +++ b/internal/controller/system/login.go @@ -0,0 +1,39 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +// Login 登录管理 +var Login = cLogin{} + +type cLogin struct{} + +// Login 登录 +func (a *cLogin) Login(ctx context.Context, req *system.LoginDoReq) (res *system.LoginDoRes, err error) { + out, token, err := service.Login().Login(ctx, req.VerifyKey, req.Captcha, req.UserName, req.Password) + if err != nil { + return + } + var loginUserRes *model.LoginUserRes + if out != nil { + if err = gconv.Scan(out, &loginUserRes); err != nil { + return + } + } + res = &system.LoginDoRes{ + UserInfo: loginUserRes, + Token: token, + } + return +} + +// LoginOut 退出登录 +func (a *cLogin) LoginOut(ctx context.Context, req *system.LoginOutReq) (res *system.LoginOutRes, err error) { + err = service.Login().LoginOut(ctx) + return +} diff --git a/internal/controller/system/sys_api.go b/internal/controller/system/sys_api.go new file mode 100644 index 0000000..d51c60c --- /dev/null +++ b/internal/controller/system/sys_api.go @@ -0,0 +1,99 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysApi = cApi{} + +type cApi struct{} + +// GetApiAll 获取所有接口 +func (a *cApi) GetApiAll(ctx context.Context, req *system.GetApiAllReq) (res *system.GetApiAllRes, err error) { + apiInfo, err := service.SysApi().GetApiAll(ctx) + if err != nil { + return + } + var apiInfoRes []*model.SysApiAllRes + if apiInfo != nil { + if err = gconv.Scan(apiInfo, &apiInfoRes); err != nil { + return + } + } + res = &system.GetApiAllRes{ + Data: apiInfoRes, + } + return +} + +// GetApiTree 获取接口树状结构 +func (a *cApi) GetApiTree(ctx context.Context, req *system.GetApiTreeReq) (res *system.GetApiTreeRes, err error) { + out, err := service.SysApi().GetApiTree(ctx, req.Name, req.Address, req.Status, req.Types) + if err != nil { + return nil, err + } + var treeData []*model.SysApiTreeRes + if out != nil { + if err = gconv.Scan(out, &treeData); err != nil { + return + } + } + res = &system.GetApiTreeRes{ + Info: treeData, + } + return +} + +// AddApi 添加Api列表 +func (a *cApi) AddApi(ctx context.Context, req *system.AddApiReq) (res *system.AddApiRes, err error) { + var input *model.AddApiInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysApi().Add(ctx, input) + return +} + +// DetailApi 获取Api列表详情 +func (a *cApi) DetailApi(ctx context.Context, req *system.DetailApiReq) (res *system.DetailApiRes, err error) { + out, err := service.SysApi().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if out != nil { + var detailRes *model.SysApiRes + if err = gconv.Scan(out, &detailRes); err != nil { + return nil, err + } + res = &system.DetailApiRes{ + Data: detailRes, + } + } + return +} + +// EditApi 编辑Api +func (a *cApi) EditApi(ctx context.Context, req *system.EditApiReq) (res *system.EditApiRes, err error) { + var input *model.EditApiInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysApi().Edit(ctx, input) + return +} + +// DelApi 根据ID删除Api +func (a *cApi) DelApi(ctx context.Context, req *system.DelApiReq) (res *system.DelApiRes, err error) { + err = service.SysApi().Del(ctx, req.Id) + return +} + +// EditApiStatus 编辑API状态 +func (a *cApi) EditApiStatus(ctx context.Context, req *system.EditApiStatusReq) (res *system.EditApiStatusRes, err error) { + err = service.SysApi().EditStatus(ctx, req.Id, req.Status) + return +} diff --git a/internal/controller/system/sys_authorize.go b/internal/controller/system/sys_authorize.go new file mode 100644 index 0000000..332e6f5 --- /dev/null +++ b/internal/controller/system/sys_authorize.go @@ -0,0 +1,49 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysAuthorize = cSysAuthorize{} + +type cSysAuthorize struct{} + +// AuthorizeQuery 权限查询 +func (c *cSysAuthorize) AuthorizeQuery(ctx context.Context, req *system.AuthorizeQueryReq) (res *system.AuthorizeQueryRes, err error) { + out, err := service.SysAuthorize().AuthorizeQuery(ctx, req.ItemsType, req.MenuIds) + if err != nil { + return + } + var authorizeQueryTree []*model.AuthorizeQueryTreeRes + if out != nil { + if err = gconv.Scan(out, &authorizeQueryTree); err != nil { + return + } + } + res = &system.AuthorizeQueryRes{ + Data: authorizeQueryTree, + } + return +} + +// AddAuthorize 授权 +func (c *cSysAuthorize) AddAuthorize(ctx context.Context, req *system.AddAuthorizeReq) (res *system.AddAuthorizeRes, err error) { + err = service.SysAuthorize().AddAuthorize(ctx, req.RoleId, req.MenuIds, req.ButtonIds, req.ColumnIds, req.ApiIds) + return +} + +// IsAllowAuthorize 判断是否允许授权 +func (c *cSysAuthorize) IsAllowAuthorize(ctx context.Context, req *system.IsAllowAuthorizeReq) (res *system.IsAllowAuthorizeRes, err error) { + isAllow, err := service.SysAuthorize().IsAllowAuthorize(ctx, req.RoleId) + if err != nil { + return + } + res = &system.IsAllowAuthorizeRes{ + IsAllow: isAllow, + } + return +} diff --git a/internal/controller/system/sys_dept.go b/internal/controller/system/sys_dept.go new file mode 100644 index 0000000..b608f1a --- /dev/null +++ b/internal/controller/system/sys_dept.go @@ -0,0 +1,75 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysDept = cDept{} + +type cDept struct{} + +func (a *cDept) DeptTree(ctx context.Context, req *systemV1.DeptDoReq) (res *systemV1.DeptDoRes, err error) { + //获取所有的部门 + out, err := service.SysDept().GetTree(ctx, req.DeptName, req.Status) + if err != nil { + return nil, err + } + var treeData []*model.DeptRes + if out != nil { + if err = gconv.Scan(out, &treeData); err != nil { + return + } + } + res = &systemV1.DeptDoRes{ + Data: treeData, + } + return +} + +// AddDept 添加部门 +func (a *cDept) AddDept(ctx context.Context, req *systemV1.AddDeptReq) (res *systemV1.AddDeptRes, err error) { + var input *model.AddDeptInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysDept().Add(ctx, input) + return +} + +// EditDept 编辑部门 +func (a *cDept) EditDept(ctx context.Context, req *systemV1.EditDeptReq) (res *systemV1.EditDeptRes, err error) { + var input *model.EditDeptInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysDept().Edit(ctx, input) + return +} + +// DetailDept 获取部门详情 +func (a *cDept) DetailDept(ctx context.Context, req *systemV1.DetailDeptReq) (res *systemV1.DetailDeptRes, err error) { + data, err := service.SysDept().Detail(ctx, req.DeptId) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailDeptRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &systemV1.DetailDeptRes{ + Data: detailRes, + } + } + return +} + +// DelDept 根据ID删除部门 +func (a *cDept) DelDept(ctx context.Context, req *systemV1.DelDeptReq) (res *systemV1.DelDeptRes, err error) { + err = service.SysDept().Del(ctx, req.DeptId) + return +} diff --git a/internal/controller/system/sys_job.go b/internal/controller/system/sys_job.go new file mode 100644 index 0000000..3a0a872 --- /dev/null +++ b/internal/controller/system/sys_job.go @@ -0,0 +1,126 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysJob = cSysJob{} + +type cSysJob struct{} + +// List 任务列表 +func (a *cSysJob) List(ctx context.Context, req *system.GetJobListReq) (res *system.GetJobListRes, err error) { + + var input *model.GetJobListInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + total, out, err := service.SysJob().JobList(ctx, input) + + if err != nil { + return + } + res = new(system.GetJobListRes) + res.Total = total + res.CurrentPage = req.PageNum + + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + + return +} + +func (a *cSysJob) Add(ctx context.Context, req *system.AddJobReq) (res *system.AddJobRes, err error) { + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if loginUserId == 0 { + err = gerror.New("未登录或TOKEN失效,请重新登录") + return + } + + req.CreateBy = gconv.Uint64(loginUserId) + var input *model.SysJobAddInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + err = service.SysJob().AddJob(ctx, input) + return +} + +func (a *cSysJob) Get(ctx context.Context, req *system.GetJobByIdReq) (res *system.GetJobByIdRes, err error) { + job, err := service.SysJob().GetJobInfoById(ctx, req.Id) + if err != nil { + return + } + var jobRes *model.SysJobRes + if job != nil { + if err = gconv.Scan(job, &jobRes); err != nil { + return + } + } + res = &system.GetJobByIdRes{ + Data: jobRes, + } + return +} + +func (a *cSysJob) Edit(ctx context.Context, req *system.EditJobReq) (res *system.EditJobRes, err error) { + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if loginUserId == 0 { + err = gerror.New("未登录或TOKEN失效,请重新登录") + return + } + + req.UpdateBy = gconv.Uint64(loginUserId) //获取登陆用户id + + var input *model.SysJobEditInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + err = service.SysJob().EditJob(ctx, input) + return +} + +// Start 启动任务 +func (a *cSysJob) Start(ctx context.Context, req *system.StartJobByIdReq) (res *system.StartJobByIdRes, err error) { + + job, err := service.SysJob().GetJobInfoById(ctx, req.Id) + err = service.SysJob().JobStart(ctx, job) + return +} + +// Stop 停止任务 +func (a *cSysJob) Stop(ctx context.Context, req *system.StopJobByIdReq) (res *system.StopJobByIdRes, err error) { + + job, err := service.SysJob().GetJobInfoById(ctx, req.Id) + err = service.SysJob().JobStop(ctx, job) + return +} + +// Run 执行任务 +func (a *cSysJob) Run(ctx context.Context, req *system.RunJobByIdReq) (res *system.RunJobByIdRes, err error) { + + job, err := service.SysJob().GetJobInfoById(ctx, req.Id) + err = service.SysJob().JobRun(ctx, job) + return +} + +// Delete 删除任务 +func (a *cSysJob) Delete(ctx context.Context, req *system.DeleteJobByIdReq) (res *system.DeleteJobByIdRes, err error) { + err = service.SysJob().DeleteJobByIds(ctx, req.Id) + return +} diff --git a/internal/controller/system/sys_login_log.go b/internal/controller/system/sys_login_log.go new file mode 100644 index 0000000..bab1c1a --- /dev/null +++ b/internal/controller/system/sys_login_log.go @@ -0,0 +1,88 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility" + "github.com/sagoo-cloud/sagooiot/utility/response" + + "github.com/gogf/gf/v2/util/gconv" +) + +var SysLoginLog = cSysLoginLog{} + +type cSysLoginLog struct{} + +// GetList 获取访问日志列表 +func (a *cSysLoginLog) GetList(ctx context.Context, req *systemV1.SysLoginLogDoReq) (res *systemV1.SysLoginLogDoRes, err error) { + var reqData = new(model.SysLoginLogInput) + err = gconv.Scan(req, &reqData) + if err != nil { + return + } + total, page, outData, err := service.SysLoginLog().GetList(ctx, reqData) + if err != nil { + return + } + res = new(systemV1.SysLoginLogDoRes) + res.Total = total + res.CurrentPage = page + if outData != nil { + if err = gconv.Scan(outData, &res.Data); err != nil { + return + } + } + return +} + +// Export 导出登录访问日志 +func (a *cSysLoginLog) Export(ctx context.Context, req *systemV1.SysLoginLogDoExportReq) (res *systemV1.SysLoginLogDoExportRes, err error) { + var reqData = new(model.SysLoginLogInput) + err = gconv.Scan(req, &reqData) + if err != nil { + return + } + _, _, outList, err := service.SysLoginLog().GetList(ctx, reqData) + if err != nil { + return + } + + //处理数据并导出 + var resData []interface{} + for _, d := range outList { + resData = append(resData, d) + } + data := utility.ToExcel(resData) + var request = g.RequestFromCtx(ctx) + response.ToXls(request, data, "SysLoginLog") + + return +} + +// DetailSysLoginLog 获取访问日志详情 +func (a *cSysLoginLog) DetailSysLoginLog(ctx context.Context, req *systemV1.DetailSysLoginLogReq) (res *systemV1.DetailSysLoginLogRes, err error) { + data, err := service.SysLoginLog().Detail(ctx, req.InfoId) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *entity.SysLoginLog + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &systemV1.DetailSysLoginLogRes{ + Data: detailRes, + } + } + return +} + +// DelSysLoginLog 根据ID删除访问日志 +func (a *cSysLoginLog) DelSysLoginLog(ctx context.Context, req *systemV1.DelSysLoginLogReq) (res *systemV1.DelSysLoginLogRes, err error) { + err = service.SysLoginLog().Del(ctx, req.InfoIds) + return +} diff --git a/internal/controller/system/sys_menu.go b/internal/controller/system/sys_menu.go new file mode 100644 index 0000000..f4ef1bf --- /dev/null +++ b/internal/controller/system/sys_menu.go @@ -0,0 +1,271 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysMenu = cMenu{} + +type cMenu struct{} + +func (a *cMenu) MenuTree(ctx context.Context, req *system.MenuDoReq) (res *system.MenuDoRes, err error) { + //获取所有的菜单 + menuInfo, err := service.SysMenu().GetTree(ctx, req.Title, req.Status) + if err != nil { + return nil, err + } + var treeData []*model.SysMenuRes + if menuInfo != nil { + if err = gconv.Scan(menuInfo, &treeData); err != nil { + return + } + } + res = &system.MenuDoRes{ + Data: treeData, + } + return +} + +// AddMenu 添加菜单 +func (a *cMenu) AddMenu(ctx context.Context, req *system.AddMenuReq) (res *system.AddMenuRes, err error) { + var input *model.AddMenuInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenu().Add(ctx, input) + return +} + +// DetailMenu 获取菜单详情 +func (a *cMenu) DetailMenu(ctx context.Context, req *system.DetailMenuReq) (res *system.DetailMenuRes, err error) { + data, err := service.SysMenu().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailMenuRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &system.DetailMenuRes{ + Data: detailRes, + } + } + return +} + +// EditMenu 编辑菜单 +func (a *cMenu) EditMenu(ctx context.Context, req *system.EditMenuReq) (res *system.EditMenuRes, err error) { + var input *model.EditMenuInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenu().Edit(ctx, input) + return +} + +// DelMenu 根据ID删除菜单 +func (a *cMenu) DelMenu(ctx context.Context, req *system.DelMenuReq) (res *system.DelMenuRes, err error) { + err = service.SysMenu().Del(ctx, req.Id) + return +} + +// MenuButtonTree 获取菜单按钮树结构列表 +func (a *cMenu) MenuButtonTree(ctx context.Context, req *system.MenuButtonDoReq) (res *system.MenuButtonDoRes, err error) { + //获取所有的菜单 + menuButtonInfo, err := service.SysMenuButton().GetList(ctx, req.Status, req.Name, req.MenuId) + if err != nil { + return nil, err + } + var parentNodeRes []*model.UserMenuButtonRes + if menuButtonInfo != nil { + //获取所有的根节点 + for _, v := range menuButtonInfo { + var parentNode *model.UserMenuButtonRes + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeRes = append(parentNodeRes, parentNode) + } + } + } + treeData := buttonTree(parentNodeRes, menuButtonInfo) + res = &system.MenuButtonDoRes{ + Data: treeData, + } + return +} + +// buttonTree MenuButtonTree 生成菜单按钮树结构 +func buttonTree(parentNodeRes []*model.UserMenuButtonRes, data []model.UserMenuButtonRes) (dataTree []*model.UserMenuButtonRes) { + //循环所有一级菜单 + for k, v := range parentNodeRes { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.UserMenuButtonRes + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeRes[k].Children = append(parentNodeRes[k].Children, node) + } + } + buttonTree(v.Children, data) + } + return parentNodeRes +} + +// AddMenuButton AddMenu 添加菜单按钮 +func (a *cMenu) AddMenuButton(ctx context.Context, req *system.AddMenuButtonReq) (res *system.AddMenuButtonRes, err error) { + var input *model.AddMenuButtonInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenuButton().Add(ctx, input) + return +} + +// DetailMenuButton DetailMenu 获取菜单按钮详情 +func (a *cMenu) DetailMenuButton(ctx context.Context, req *system.DetailMenuButtonReq) (res *system.DetailMenuButtonRes, err error) { + data, err := service.SysMenuButton().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailMenuButtonRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &system.DetailMenuButtonRes{ + Data: detailRes, + } + } + return +} + +// EditMenuButton 编辑菜单按钮 +func (a *cMenu) EditMenuButton(ctx context.Context, req *system.EditMenuButtonReq) (res *system.EditMenuButtonRes, err error) { + var input *model.EditMenuButtonInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenuButton().Edit(ctx, input) + return +} + +// DelMenuButton 根据ID删除菜单按钮 +func (a *cMenu) DelMenuButton(ctx context.Context, req *system.DelMenuButtonReq) (res *system.DelMenuButtonRes, err error) { + err = service.SysMenuButton().Del(ctx, req.Id) + return +} + +// EditMenuButtonStatus 编辑菜单按钮状态 +func (a *cMenu) EditMenuButtonStatus(ctx context.Context, req *system.EditMenuButtonStatusReq) (res *system.EditMenuButtonStatusRes, err error) { + err = service.SysMenuButton().EditStatus(ctx, req.Id, req.MenuId, req.Status) + return +} + +// MenuColumnTree 获取菜单列表树结构列表 +func (a *cMenu) MenuColumnTree(ctx context.Context, req *system.MenuColumnDoReq) (res *system.MenuColumnDoRes, err error) { + var input *model.MenuColumnDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + //获取所有的菜单 + menuColumnInfo, err := service.SysMenuColumn().GetList(ctx, input) + if err != nil { + return nil, err + } + var parentNodeRes []*model.UserMenuColumnRes + if menuColumnInfo != nil { + //获取所有的根节点 + for _, v := range menuColumnInfo { + var parentNode *model.UserMenuColumnRes + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeRes = append(parentNodeRes, parentNode) + } + } + } + treeData := columnTree(parentNodeRes, menuColumnInfo) + res = &system.MenuColumnDoRes{ + Data: treeData, + } + return +} + +// columnTree MenuColumnTree 生成菜单列表树结构 +func columnTree(parentNodeRes []*model.UserMenuColumnRes, data []model.UserMenuColumnRes) (dataTree []*model.UserMenuColumnRes) { + //循环所有一级菜单 + for k, v := range parentNodeRes { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.UserMenuColumnRes + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeRes[k].Children = append(parentNodeRes[k].Children, node) + } + } + columnTree(v.Children, data) + } + return parentNodeRes +} + +// AddMenuColumn AddMenu 添加菜单列表 +func (a *cMenu) AddMenuColumn(ctx context.Context, req *system.AddMenuColumnReq) (res *system.AddMenuColumnRes, err error) { + var input *model.AddMenuColumnInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenuColumn().Add(ctx, input) + return +} + +// DetailMenuColumn DetailMenu 获取菜单列表详情 +func (a *cMenu) DetailMenuColumn(ctx context.Context, req *system.DetailMenuColumnReq) (res *system.DetailMenuColumnRes, err error) { + data, err := service.SysMenuColumn().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailMenuColumnRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &system.DetailMenuColumnRes{ + Data: detailRes, + } + } + return +} + +// EditMenuColumn EditMenu 编辑菜单列表 +func (a *cMenu) EditMenuColumn(ctx context.Context, req *system.EditMenuColumnReq) (res *system.EditMenuColumnRes, err error) { + var input *model.EditMenuColumnInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysMenuColumn().Edit(ctx, input) + return +} + +// DelMenuColumn DelMenu 根据ID删除菜单列表 +func (a *cMenu) DelMenuColumn(ctx context.Context, req *system.DelMenuColumnReq) (res *system.DelMenuColumnRes, err error) { + err = service.SysMenuColumn().Del(ctx, req.Id) + return +} + +// EditMenuColumnStatus 编辑菜单列表状态 +func (a *cMenu) EditMenuColumnStatus(ctx context.Context, req *system.EditMenuColumnStatusReq) (res *system.EditMenuColumnStatusRes, err error) { + err = service.SysMenuColumn().EditStatus(ctx, req.Id, req.MenuId, req.Status) + return +} diff --git a/internal/controller/system/sys_monitor.go b/internal/controller/system/sys_monitor.go new file mode 100644 index 0000000..29f7896 --- /dev/null +++ b/internal/controller/system/sys_monitor.go @@ -0,0 +1,150 @@ +package system + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/host" + "github.com/shirou/gopsutil/v3/load" + "github.com/shirou/gopsutil/v3/mem" + "os" + "runtime" + "strconv" + "time" +) + +var SysMonitor = cMonitor{ + startTime: gtime.Now(), +} + +type cMonitor struct { + startTime *gtime.Time +} + +func (c *cMonitor) List(ctx context.Context, req *system.MonitorSearchReq) (res *system.MonitorSearchRes, err error) { + cpuNum := runtime.NumCPU() //核心数 + var cpuUsed float64 = 0 //用户使用率 + var cpuAvg5 float64 = 0 //CPU负载5 + var cpuAvg15 float64 = 0 //当前空闲率 + + cpuInfo, err := cpu.Percent(time.Second, false) + if err == nil { + cpuUsed, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", cpuInfo[0]), 64) + } + + loadInfo, err := load.Avg() + if err == nil { + cpuAvg5, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", loadInfo.Load5), 64) + cpuAvg15, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", loadInfo.Load5), 64) + } + + var memTotal uint64 = 0 //总内存 + var memUsed uint64 = 0 //总内存 := 0 //已用内存 + var memFree uint64 = 0 //剩余内存 + var memUsage float64 = 0 //使用率 + + v, err := mem.VirtualMemory() + if err == nil { + memTotal = v.Total + memUsed = v.Used + memFree = memTotal - memUsed + memUsage, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", v.UsedPercent), 64) + } + + var goTotal uint64 = 0 //go分配的总内存数 + var goUsed uint64 = 0 //go使用的内存数 + var goFree uint64 = 0 //go剩余的内存数 + var goUsage float64 = 0 //使用率 + + var gomem runtime.MemStats + runtime.ReadMemStats(&gomem) + goUsed = gomem.Sys + goUsage = gconv.Float64(fmt.Sprintf("%.2f", gconv.Float64(goUsed)/gconv.Float64(memTotal)*100)) + sysComputerIp := "" //服务器IP + + ip, err := utils.GetLocalIP() + if err == nil { + sysComputerIp = ip + } + + sysComputerName := "" //服务器名称 + sysOsName := "" //操作系统 + sysOsArch := "" //系统架构 + + sysInfo, err := host.Info() + + if err == nil { + sysComputerName = sysInfo.Hostname + sysOsName = sysInfo.OS + sysOsArch = sysInfo.KernelArch + } + + goName := "GoLang" //语言环境 + goVersion := runtime.Version() //版本 + gtime.Date() + goStartTime := c.startTime //启动时间 + + goRunTime := gtime.Now().Timestamp() - c.startTime.Timestamp() //运行时长(秒) + goHome := runtime.GOROOT() //安装路径 + goUserDir := "" //项目路径 + + curDir, err := os.Getwd() + + if err == nil { + goUserDir = curDir + } + + //服务器磁盘信息 + diskList := make([]disk.UsageStat, 0) + diskInfo, err := disk.Partitions(true) //所有分区 + if err == nil { + for _, p := range diskInfo { + diskDetail, err := disk.Usage(p.Mountpoint) + if err == nil { + diskDetail.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", diskDetail.UsedPercent), 64) + diskList = append(diskList, *diskDetail) + } + } + } + + d, _ := disk.Usage("/") + diskTotal := d.Total / 1024 / 1024 / 1024 //磁盘空间总数 + diskUsed := d.Used / 1024 / 1024 / 1024 //磁盘使用数 + diskUsedPercent := d.UsedPercent //磁盘使用率 + + res = new(system.MonitorSearchRes) + res = &system.MonitorSearchRes{ + "cpuNum": cpuNum, + "cpuUsed": cpuUsed, + "cpuAvg5": gconv.String(cpuAvg5), + "cpuAvg15": gconv.String(cpuAvg15), + "memTotal": memTotal, + "goTotal": goTotal, + "memUsed": memUsed, + "goUsed": goUsed, + "memFree": memFree, + "goFree": goFree, + "memUsage": memUsage, + "goUsage": goUsage, + "sysComputerName": sysComputerName, + "sysOsName": sysOsName, + "sysComputerIp": sysComputerIp, + "sysOsArch": sysOsArch, + "goName": goName, + "goVersion": goVersion, + "goStartTime": goStartTime, + "goRunTime": goRunTime, + "goHome": goHome, + "goUserDir": goUserDir, + "diskList": diskList, + "diskTotal": diskTotal, + "diskUsed": diskUsed, + "diskUsedPercent": diskUsedPercent, + } + return +} diff --git a/internal/controller/system/sys_notifications.go b/internal/controller/system/sys_notifications.go new file mode 100644 index 0000000..43e50dd --- /dev/null +++ b/internal/controller/system/sys_notifications.go @@ -0,0 +1,68 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysNotifications = cSysNotifications{} + +type cSysNotifications struct{} + +// 获取列表 +func (u *cSysNotifications) GetNotificationsList(ctx context.Context, req *system.GetNotificationsListReq) (res *system.GetNotificationsListRes, err error) { + var input *model.GetNotificationsListInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, currentPage, out, err := service.SysNotifications().GetSysNotificationsList(ctx, input) + if err != nil { + return + } + res = new(system.GetNotificationsListRes) + res.Total = total + res.CurrentPage = currentPage + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// 获取指定ID数据 +func (u *cSysNotifications) GetNotificationsById(ctx context.Context, req *system.GetNotificationsByIdReq) (res *system.GetNotificationsByIdRes, err error) { + data, err := service.SysNotifications().GetSysNotificationsById(ctx, req.Id) + res = new(system.GetNotificationsByIdRes) + err = gconv.Scan(data, &res.Data) + return +} + +// 添加数据 +func (u *cSysNotifications) AddSysNotifications(ctx context.Context, req *system.AddNotificationsReq) (res *system.AddNotificationsRes, err error) { + var data = model.NotificationsAddInput{} + err = gconv.Scan(req, &data) + err = service.SysNotifications().AddSysNotifications(ctx, data) + return +} + +// 修改数据 +func (u *cSysNotifications) EditSysNotifications(ctx context.Context, req *system.EditNotificationsReq) (res *system.EditNotificationsRes, err error) { + var data = model.NotificationsEditInput{} + err = gconv.Scan(req, &data) + err = service.SysNotifications().EditSysNotifications(ctx, data) + return +} + +// 删除数据 +func (u *cSysNotifications) DeleteSysNotifications(ctx context.Context, req *system.DeleteNotificationsReq) (res *system.DeleteNotificationsRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.SysNotifications().DeleteSysNotifications(ctx, req) + return +} diff --git a/internal/controller/system/sys_oper_log.go b/internal/controller/system/sys_oper_log.go new file mode 100644 index 0000000..bd909b8 --- /dev/null +++ b/internal/controller/system/sys_oper_log.go @@ -0,0 +1,69 @@ +package system + +import ( + "context" + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/util/gconv" +) + +var SysOperLog = cSysOperLog{} + +type cSysOperLog struct{} + +// GetList 获取操作日志列表 +func (a *cSysOperLog) GetList(ctx context.Context, req *systemV1.SysOperLogDoReq) (res *systemV1.SysOperLogDoRes, err error) { + var input *model.SysOperLogDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + total, out, err := service.SysOperLog().GetList(ctx, input) + if err != nil { + return + } + res = new(systemV1.SysOperLogDoRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +/** +// AddSysOperLog 添加操作日志 +func (a *cSysOperLog) AddSysOperLog(ctx context.Context, req *systemV1.AddSysOperLogReq) (res *systemV1.AddSysOperLogRes, err error) { + err = service.SysOperLog().Add(ctx, req.SysOperLog) + return +} +*/ + +// DetailSysOperLog 获取操作日志详情 +func (a *cSysOperLog) DetailSysOperLog(ctx context.Context, req *systemV1.DetailSysOperLogReq) (res *systemV1.DetailSysOperLogRes, err error) { + data, err := service.SysOperLog().Detail(ctx, req.OperId) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *entity.SysOperLog + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &systemV1.DetailSysOperLogRes{ + Data: detailRes, + } + } + return +} + +// DelSysOperLog 根据ID删除访问日志 +func (a *cSysOperLog) DelSysOperLog(ctx context.Context, req *systemV1.DelSysOperLogReq) (res *systemV1.DelSysOperLogRes, err error) { + err = service.SysOperLog().Del(ctx, req.OperIds) + return +} diff --git a/internal/controller/system/sys_organization.go b/internal/controller/system/sys_organization.go new file mode 100644 index 0000000..9024292 --- /dev/null +++ b/internal/controller/system/sys_organization.go @@ -0,0 +1,87 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysOrganization = cOrganization{} + +type cOrganization struct{} + +func (a *cOrganization) OrganizationTree(ctx context.Context, req *systemV1.OrganizationDoReq) (res *systemV1.OrganizationDoRes, err error) { + //获取所有的组织 + out, err := service.SysOrganization().GetTree(ctx, req.Name, req.Status) + if err != nil { + return nil, err + } + var treeData []*model.OrganizationRes + if out != nil { + if err = gconv.Scan(out, &treeData); err != nil { + return + } + } + res = &systemV1.OrganizationDoRes{ + Data: treeData, + } + return +} + +// AddOrganization 添加组织 +func (a *cOrganization) AddOrganization(ctx context.Context, req *systemV1.AddOrganizationReq) (res *systemV1.AddOrganizationRes, err error) { + var input *model.AddOrganizationInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysOrganization().Add(ctx, input) + return +} + +// EditOrganization 编辑组织 +func (a *cOrganization) EditOrganization(ctx context.Context, req *systemV1.EditOrganizationReq) (res *systemV1.EditOrganizationRes, err error) { + var input *model.EditOrganizationInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysOrganization().Edit(ctx, input) + return +} + +// DetailOrganization 获取组织详情 +func (a *cOrganization) DetailOrganization(ctx context.Context, req *systemV1.DetailOrganizationReq) (res *systemV1.DetailOrganizationRes, err error) { + data, err := service.SysOrganization().Detail(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailOrganizationRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &systemV1.DetailOrganizationRes{ + Data: detailRes, + } + } + return +} + +// DelOrganization 根据ID删除组织 +func (a *cOrganization) DelOrganization(ctx context.Context, req *systemV1.DelOrganizationReq) (res *systemV1.DelOrganizationRes, err error) { + err = service.SysOrganization().Del(ctx, req.Id) + return +} + +// GetCount 获取组织数量 +func (a *cOrganization) GetCount(ctx context.Context, req *systemV1.GetOrganizationCountReq) (res *systemV1.GetOrganizationCountRes, err error) { + count, err := service.SysOrganization().Count(ctx) + if err != nil { + return + } + res = &systemV1.GetOrganizationCountRes{ + Count: count, + } + return +} diff --git a/internal/controller/system/sys_plugins.go b/internal/controller/system/sys_plugins.go new file mode 100644 index 0000000..bf28239 --- /dev/null +++ b/internal/controller/system/sys_plugins.go @@ -0,0 +1,41 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysPlugins = cSystemSysPlugins{} + +type cSystemSysPlugins struct{} + +// GetSysPluginsList 获取列表 +func (u *cSystemSysPlugins) GetSysPluginsList(ctx context.Context, req *system.GetSysPluginsListReq) (res *system.GetSysPluginsListRes, err error) { + var inputData = new(model.GetSysPluginsListInput) + if err = gconv.Scan(req, &inputData); err != nil { + return + } + total, currentPage, dataList, err := service.SysPlugins().GetSysPluginsList(ctx, inputData) + res = new(system.GetSysPluginsListRes) + err = gconv.Scan(dataList, &res.Data) + res.PaginationRes.Total = total + res.PaginationRes.CurrentPage = currentPage + return +} + +// GetSysPluginsById 获取指定ID数据 +func (u *cSystemSysPlugins) GetSysPluginsById(ctx context.Context, req *system.GetSysPluginsByIdReq) (res *system.GetSysPluginsByIdRes, err error) { + data, err := service.SysPlugins().GetSysPluginsById(ctx, req.Id) + res = new(system.GetSysPluginsByIdRes) + err = gconv.Scan(data, &res) + return +} + +// EditSysPluginsStatus 修改插件的状态 +func (a *cMenu) EditSysPluginsStatus(ctx context.Context, req *system.EditSysPluginsStatusReq) (res *system.EditSysPluginsStatusRes, err error) { + err = service.SysPlugins().EditStatus(ctx, req.Id, req.Status) + return +} diff --git a/internal/controller/system/sys_plugins_config.go b/internal/controller/system/sys_plugins_config.go new file mode 100644 index 0000000..55514c8 --- /dev/null +++ b/internal/controller/system/sys_plugins_config.go @@ -0,0 +1,83 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysPluginsConfig = cSystemPlugins_config{} + +type cSystemPlugins_config struct{} + +// GetPluginsConfigList 获取列表 +func (u *cSystemPlugins_config) GetPluginsConfigList(ctx context.Context, req *system.GetPluginsConfigListReq) (res *system.GetPluginsConfigListRes, err error) { + var inputData = new(model.GetPluginsConfigListInput) + if err = gconv.Scan(req, &inputData); err != nil { + return + } + total, currentPage, dataList, err := service.SystemPluginsConfig().GetPluginsConfigList(ctx, inputData) + res = new(system.GetPluginsConfigListRes) + err = gconv.Scan(dataList, &res.Data) + res.PaginationRes.Total = total + res.PaginationRes.CurrentPage = currentPage + return +} + +// GetPluginsConfigById 获取指定ID数据 +func (u *cSystemPlugins_config) GetPluginsConfigById(ctx context.Context, req *system.GetPluginsConfigByIdReq) (res *system.GetPluginsConfigByIdRes, err error) { + data, err := service.SystemPluginsConfig().GetPluginsConfigById(ctx, req.Id) + res = new(system.GetPluginsConfigByIdRes) + err = gconv.Scan(data, &res) + return +} + +// GetPluginsConfigByName 获取指定类型与名称的插件配置数据 +func (u *cSystemPlugins_config) GetPluginsConfigByName(ctx context.Context, req *system.GetPluginsConfigByNameReq) (res *system.GetPluginsConfigByNameRes, err error) { + data, err := service.SystemPluginsConfig().GetPluginsConfigByName(ctx, req.Type, req.Name) + res = new(system.GetPluginsConfigByNameRes) + err = gconv.Scan(data, &res) + return +} + +// AddPluginsConfig 添加数据 +func (u *cSystemPlugins_config) AddPluginsConfig(ctx context.Context, req *system.AddPluginsConfigReq) (res *system.AddPluginsConfigRes, err error) { + var data = model.PluginsConfigAddInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + err = service.SystemPluginsConfig().AddPluginsConfig(ctx, data) + return +} + +// EditPluginsConfig 修改数据 +func (u *cSystemPlugins_config) EditPluginsConfig(ctx context.Context, req *system.EditPluginsConfigReq) (res *system.EditPluginsConfigRes, err error) { + var data = model.PluginsConfigEditInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + err = service.SystemPluginsConfig().EditPluginsConfig(ctx, data) + return +} + +// SavePluginsConfig 修改数据 +func (u *cSystemPlugins_config) SavePluginsConfig(ctx context.Context, req *system.SavePluginsConfigReq) (res *system.SavePluginsConfigRes, err error) { + var data = model.PluginsConfigAddInput{} + if err = gconv.Scan(req, &data); err != nil { + return + } + err = service.SystemPluginsConfig().SavePluginsConfig(ctx, data) + return +} + +// DeletePluginsConfig 删除数据 +func (u *cSystemPlugins_config) DeletePluginsConfig(ctx context.Context, req *system.DeletePluginsConfigReq) (res *system.DeletePluginsConfigRes, err error) { + if len(req.Ids) == 0 { + err = gerror.New("ID参数错误") + } + err = service.SystemPluginsConfig().DeletePluginsConfig(ctx, req.Ids) + return +} diff --git a/internal/controller/system/sys_post.go b/internal/controller/system/sys_post.go new file mode 100644 index 0000000..495ebd1 --- /dev/null +++ b/internal/controller/system/sys_post.go @@ -0,0 +1,75 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + systemV1 "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysPost = cPost{} + +type cPost struct{} + +func (a *cPost) PostTree(ctx context.Context, req *systemV1.PostDoReq) (res *systemV1.PostDoRes, err error) { + //获取所有的岗位 + out, err := service.SysPost().GetTree(ctx, req.PostName, req.PostCode, req.Status) + if err != nil { + return nil, err + } + var treeData []*model.PostRes + if out != nil { + if err = gconv.Scan(out, &treeData); err != nil { + return + } + } + res = &systemV1.PostDoRes{ + Data: treeData, + } + return +} + +// AddPost 添加岗位 +func (a *cPost) AddPost(ctx context.Context, req *systemV1.AddPostReq) (res *systemV1.AddPostRes, err error) { + var input *model.AddPostInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysPost().Add(ctx, input) + return +} + +// EditPost 编辑岗位 +func (a *cPost) EditPost(ctx context.Context, req *systemV1.EditPostReq) (res *systemV1.EditPostRes, err error) { + var input *model.EditPostInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysPost().Edit(ctx, input) + return +} + +// DetailPost 获取岗位详情 +func (a *cPost) DetailPost(ctx context.Context, req *systemV1.DetailPostReq) (res *systemV1.DetailPostRes, err error) { + data, err := service.SysPost().Detail(ctx, req.PostId) + if err != nil { + return nil, err + } + if data != nil { + var detailRes *model.DetailPostRes + if err = gconv.Scan(data, &detailRes); err != nil { + return nil, err + } + res = &systemV1.DetailPostRes{ + Data: detailRes, + } + } + return +} + +// DelPost 根据ID删除岗位 +func (a *cPost) DelPost(ctx context.Context, req *systemV1.DelPostReq) (res *systemV1.DelPostRes, err error) { + err = service.SysPost().Del(ctx, req.PostId) + return +} diff --git a/internal/controller/system/sys_role.go b/internal/controller/system/sys_role.go new file mode 100644 index 0000000..40b5d61 --- /dev/null +++ b/internal/controller/system/sys_role.go @@ -0,0 +1,111 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +// SysRole 角色 +var SysRole = cSysRole{} + +type cSysRole struct{} + +// RoleTree 角色树状列表 +func (a *cSysRole) RoleTree(ctx context.Context, req *system.RoleTreeReq) (res *system.RoleTreeRes, err error) { + //获取所有的角色 + out, err := service.SysRole().GetTree(ctx, req.Name, req.Status) + if err != nil { + return nil, err + } + var treeData []*model.RoleTreeRes + if out != nil { + if err = gconv.Scan(out, &treeData); err != nil { + return + } + } + res = &system.RoleTreeRes{ + Data: treeData, + } + return +} + +// AddRole 添加 +func (a *cSysRole) AddRole(ctx context.Context, req *system.AddRoleReq) (res *system.AddRoleRes, err error) { + var input *model.AddRoleInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysRole().Add(ctx, input) + return +} + +// EditRole 编辑 +func (a *cSysRole) EditRole(ctx context.Context, req *system.EditRoleReq) (res *system.EditRoleRes, err error) { + var input *model.EditRoleInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysRole().Edit(ctx, input) + return +} + +// GetRoleById 根据ID获取角色信息 +func (a *cSysRole) GetRoleById(ctx context.Context, req *system.GetRoleByIdReq) (res *system.GetRoleByIdRes, err error) { + data, err := service.SysRole().GetInfoById(ctx, req.Id) + if err != nil { + return nil, err + } + if data != nil { + var roleInfoRes *model.RoleInfoRes + if err = gconv.Scan(data, &roleInfoRes); err != nil { + return nil, err + } + if roleInfoRes.DataScope == 2 { + //获取部门ID + roleDeptInfo, _ := service.SysRoleDept().GetInfoByRoleId(ctx, int(roleInfoRes.Id)) + var deptIds []int64 + if roleDeptInfo != nil { + for _, roleDept := range roleDeptInfo { + deptIds = append(deptIds, roleDept.DeptId) + } + } + roleInfoRes.DeptIds = append(roleInfoRes.DeptIds, deptIds...) + } + res = &system.GetRoleByIdRes{ + Data: roleInfoRes, + } + } + return +} + +// DelRoleById 根据ID删除角色 +func (a *cSysRole) DelRoleById(ctx context.Context, req *system.DeleteRoleByIdReq) (res *system.DeleteRoleByIdRes, err error) { + err = service.SysRole().DelInfoById(ctx, req.Id) + return +} + +// DataScope 角色数据权限授权 +func (a *cSysRole) DataScope(ctx context.Context, req *system.DataScopeReq) (res *system.DataScopeRes, err error) { + err = service.SysRole().DataScope(ctx, req.Id, req.DataScope, req.DeptIds) + return +} + +// GetAuthorizeById 根据ID获取权限信息 +func (c *cSysAuthorize) GetAuthorizeById(ctx context.Context, req *system.GetAuthorizeByIdReq) (res *system.GetAuthorizeByIdRes, err error) { + menuIds, menuButtonIds, menuColumnIds, menuApiIds, err := service.SysRole().GetAuthorizeById(ctx, req.Id) + if err != nil { + return + } + + res = &system.GetAuthorizeByIdRes{ + MenuIds: menuIds, + ButtonIds: menuButtonIds, + ColumnIds: menuColumnIds, + ApiIds: menuApiIds, + } + return + +} diff --git a/internal/controller/system/sys_user.go b/internal/controller/system/sys_user.go new file mode 100644 index 0000000..9174df4 --- /dev/null +++ b/internal/controller/system/sys_user.go @@ -0,0 +1,150 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +// SysUser 用户 +var SysUser = cSysUser{} + +type cSysUser struct{} + +// UserList 用户列表 +func (u *cSysUser) UserList(ctx context.Context, req *system.UserListReq) (res *system.UserListRes, err error) { + //获取所有用户列表 + var input *model.UserListDoInput + if err = gconv.Scan(req, &input); err != nil { + return + } + total, out, err := service.SysUser().UserList(ctx, input) + if err != nil { + return + } + res = new(system.UserListRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// AddUser 用户添加 +func (u *cSysUser) AddUser(ctx context.Context, req *system.AddUserReq) (res *system.AddUserRes, err error) { + var input *model.AddUserInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysUser().Add(ctx, input) + return +} + +// EditUser 用户编辑 +func (u *cSysUser) EditUser(ctx context.Context, req *system.EditUserReq) (res *system.EditUserRes, err error) { + var input *model.EditUserInput + if err = gconv.Scan(req, &input); err != nil { + return + } + err = service.SysUser().Edit(ctx, input) + return +} + +// GetUserById 根据ID获取用户信息 +func (u *cSysUser) GetUserById(ctx context.Context, req *system.GetUserByIdReq) (res *system.GetUserByIdRes, err error) { + out, err := service.SysUser().GetUserById(ctx, req.Id) + if err != nil { + return + } + var userInfoRes *model.UserInfoRes + if out != nil { + if err = gconv.Scan(out, &userInfoRes); err != nil { + return + } + } + res = &system.GetUserByIdRes{ + Data: userInfoRes, + } + return +} + +// DelUserById 根据ID删除用户 +func (u *cSysUser) DelUserById(ctx context.Context, req *system.DeleteUserByIdReq) (res *system.DeleteUserByIdRes, err error) { + err = service.SysUser().DelInfoById(ctx, req.Id) + return +} + +// ResetPassword 重置密码 +func (u *cSysUser) ResetPassword(ctx context.Context, req *system.ResetPasswordReq) (res *system.ResetPasswordRes, err error) { + err = service.SysUser().ResetPassword(ctx, req.Id, req.UserPassword) + return +} + +// CurrentUser 获取登录用户信息 +func (u *cSysUser) CurrentUser(ctx context.Context, req *system.CurrentUserReq) (res *system.CurrentUserRes, err error) { + userInfoOut, menuTreeOur, err := service.SysUser().CurrentUser(ctx) + if err != nil { + return + } + var userInfoRes *model.UserInfoRes + if userInfoOut != nil { + if err = gconv.Scan(userInfoOut, &userInfoRes); err != nil { + return + } + } + var userMenuTreeRes []*model.UserMenuTreeRes + if menuTreeOur != nil { + if err = gconv.Scan(menuTreeOur, &userMenuTreeRes); err != nil { + return + } + } + res = &system.CurrentUserRes{ + Info: userInfoRes, + Data: userMenuTreeRes, + } + return +} + +// GetParams 获取用户维护相关参数 +func (u *cSysUser) GetParams(ctx context.Context, req *system.UserGetParamsReq) (res *system.UserGetParamsRes, err error) { + res = new(system.UserGetParamsRes) + res.RoleList, err = service.SysRole().GetRoleList(ctx) + if err != nil { + return + } + res.Posts, err = service.SysPost().GetUsedPost(ctx) + return +} + +// EditUserStatus 修改用户状态 +func (u *cSysUser) EditUserStatus(ctx context.Context, req *system.EditUserStatusReq) (res *system.EditUserStatusRes, err error) { + err = service.SysUser().EditUserStatus(ctx, req.Id, req.Status) + return +} + +// GetUserAll 所有用户列表 +func (u *cSysUser) GetUserAll(ctx context.Context, req *system.GetUserAllReq) (res *system.GetUserAllRes, err error) { + //获取所有用户列表 + data, err := service.SysUser().GetAll(ctx) + var userRes []*model.UserRes + if data != nil { + if err = gconv.Scan(data, &userRes); err != nil { + return + } + } + res = &system.GetUserAllRes{ + Data: userRes, + } + return +} + +// EditUserAvatar 修改用户头像 +func (u *cSysUser) EditUserAvatar(ctx context.Context, req *system.EditUserAvatarReq) (res *system.EditUserAvatarRes, err error) { + err = service.SysUser().EditUserAvatar(ctx, req.Id, req.Avatar) + return +} diff --git a/internal/controller/system/sys_user_online.go b/internal/controller/system/sys_user_online.go new file mode 100644 index 0000000..08a1ec5 --- /dev/null +++ b/internal/controller/system/sys_user_online.go @@ -0,0 +1,44 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var SysUserOnline = cSysUserOnline{} + +type cSysUserOnline struct{} + +// UserOnlineListReq 在线用户列表 +func (c *cSysUserOnline) UserOnlineListReq(ctx context.Context, req *system.UserOnlineListReq) (res *system.UserOnlineListRes, err error) { + var input *model.UserOnlineDoListInput + if err = gconv.Scan(req, &input); err != nil { + return + } + + total, out, err := service.SysUserOnline().UserOnlineList(ctx, input) + if err != nil { + return + } + res = new(system.UserOnlineListRes) + res.Total = total + res.CurrentPage = req.PageNum + if out != nil { + if err = gconv.Scan(out, &res.Data); err != nil { + return + } + } + return +} + +// UserOnlineStrongBack 强退 +func (c *cSysUserOnline) UserOnlineStrongBack(ctx context.Context, req *system.UserOnlineStrongBackReq) (res *system.UserOnlineStrongBackRes, err error) { + err = service.SysUserOnline().UserOnlineStrongBack(ctx, req.Id) + if err != nil { + return + } + return +} diff --git a/internal/controller/tdengine/td_engine.go b/internal/controller/tdengine/td_engine.go new file mode 100644 index 0000000..0eae4f7 --- /dev/null +++ b/internal/controller/tdengine/td_engine.go @@ -0,0 +1,55 @@ +package tdengine + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/tdengine" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +var TdEngine = cTdEngine{} + +type cTdEngine struct{} + +// GetTdEngineAllDb 获取所有数据库 +func (a *cTdEngine) GetTdEngineAllDb(ctx context.Context, req *tdengine.GetTdEngineAllDbReq) (res *tdengine.GetTdEngineAllDbRes, err error) { + data, err := service.TdEngine().GetTdEngineAllDb(ctx) + if data != nil { + res = &tdengine.GetTdEngineAllDbRes{ + Info: data, + } + } + return +} + +// GetListTableByDatabases 获取指定数据库下所有的表列表 +func (a *cTdEngine) GetListTableByDatabases(ctx context.Context, req *tdengine.GetTdEngineListTableByDatabasesReq) (res *tdengine.GetTdEngineListTableByDatabasesRes, err error) { + data, err := service.TdEngine().GetListTableByDatabases(ctx, req.DbName) + if data != nil { + res = &tdengine.GetTdEngineListTableByDatabasesRes{ + Info: data, + } + } + return +} + +// GetTdEngineTableInfoByTable 获取指定数据表结构信息 +func (a *cTdEngine) GetTdEngineTableInfoByTable(ctx context.Context, req *tdengine.GetTdEngineTableInfoByTableReq) (res *tdengine.GetTdEngineTableInfoByTableRes, err error) { + data, err := service.TdEngine().GetTdEngineTableInfoByTable(ctx, req.DbName, req.TableName) + if data != nil { + res = &tdengine.GetTdEngineTableInfoByTableRes{ + Info: data, + } + } + return +} + +// GetTdEngineTableDataByTable 获取指定表数据信息 +func (a *cTdEngine) GetTdEngineTableDataByTable(ctx context.Context, req *tdengine.GetTdEngineTableDataByTableReq) (res *tdengine.GetTdEngineTableDataByTableRes, err error) { + data, err := service.TdEngine().GetTdEngineTableDataByTable(ctx, req.DbName, req.TableName) + if data != nil { + res = &tdengine.GetTdEngineTableDataByTableRes{ + TableDataInfo: data, + } + } + return +} diff --git a/internal/dao/alarm_level.go b/internal/dao/alarm_level.go new file mode 100644 index 0000000..597c091 --- /dev/null +++ b/internal/dao/alarm_level.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalAlarmLevelDao is internal type for wrapping internal DAO implements. +type internalAlarmLevelDao = *internal.AlarmLevelDao + +// alarmLevelDao is the data access object for table alarm_level. +// You can define custom methods on it to extend its functionality as you wish. +type alarmLevelDao struct { + internalAlarmLevelDao +} + +var ( + // AlarmLevel is globally public accessible object for table alarm_level operations. + AlarmLevel = alarmLevelDao{ + internal.NewAlarmLevelDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/alarm_log.go b/internal/dao/alarm_log.go new file mode 100644 index 0000000..0ce64ed --- /dev/null +++ b/internal/dao/alarm_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalAlarmLogDao is internal type for wrapping internal DAO implements. +type internalAlarmLogDao = *internal.AlarmLogDao + +// alarmLogDao is the data access object for table alarm_log. +// You can define custom methods on it to extend its functionality as you wish. +type alarmLogDao struct { + internalAlarmLogDao +} + +var ( + // AlarmLog is globally public accessible object for table alarm_log operations. + AlarmLog = alarmLogDao{ + internal.NewAlarmLogDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/alarm_rule.go b/internal/dao/alarm_rule.go new file mode 100644 index 0000000..9f06b15 --- /dev/null +++ b/internal/dao/alarm_rule.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalAlarmRuleDao is internal type for wrapping internal DAO implements. +type internalAlarmRuleDao = *internal.AlarmRuleDao + +// alarmRuleDao is the data access object for table alarm_rule. +// You can define custom methods on it to extend its functionality as you wish. +type alarmRuleDao struct { + internalAlarmRuleDao +} + +var ( + // AlarmRule is globally public accessible object for table alarm_rule operations. + AlarmRule = alarmRuleDao{ + internal.NewAlarmRuleDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/base_db_link.go b/internal/dao/base_db_link.go new file mode 100644 index 0000000..a09c095 --- /dev/null +++ b/internal/dao/base_db_link.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalBaseDbLinkDao is internal type for wrapping internal DAO implements. +type internalBaseDbLinkDao = *internal.BaseDbLinkDao + +// baseDbLinkDao is the data access object for table base_db_link. +// You can define custom methods on it to extend its functionality as you wish. +type baseDbLinkDao struct { + internalBaseDbLinkDao +} + +var ( + // BaseDbLink is globally public accessible object for table base_db_link operations. + BaseDbLink = baseDbLinkDao{ + internal.NewBaseDbLinkDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/city_data.go b/internal/dao/city_data.go new file mode 100644 index 0000000..5afe0ca --- /dev/null +++ b/internal/dao/city_data.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalCityDataDao is internal type for wrapping internal DAO implements. +type internalCityDataDao = *internal.CityDataDao + +// cityDataDao is the data access object for table city_data. +// You can define custom methods on it to extend its functionality as you wish. +type cityDataDao struct { + internalCityDataDao +} + +var ( + // CityData is globally public accessible object for table city_data operations. + CityData = cityDataDao{ + internal.NewCityDataDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/data_node.go b/internal/dao/data_node.go new file mode 100644 index 0000000..8cee1ef --- /dev/null +++ b/internal/dao/data_node.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDataNodeDao is internal type for wrapping internal DAO implements. +type internalDataNodeDao = *internal.DataNodeDao + +// dataNodeDao is the data access object for table data_node. +// You can define custom methods on it to extend its functionality as you wish. +type dataNodeDao struct { + internalDataNodeDao +} + +var ( + // DataNode is globally public accessible object for table data_node operations. + DataNode = dataNodeDao{ + internal.NewDataNodeDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/data_source.go b/internal/dao/data_source.go new file mode 100644 index 0000000..091e066 --- /dev/null +++ b/internal/dao/data_source.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDataSourceDao is internal type for wrapping internal DAO implements. +type internalDataSourceDao = *internal.DataSourceDao + +// dataSourceDao is the data access object for table data_source. +// You can define custom methods on it to extend its functionality as you wish. +type dataSourceDao struct { + internalDataSourceDao +} + +var ( + // DataSource is globally public accessible object for table data_source operations. + DataSource = dataSourceDao{ + internal.NewDataSourceDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/data_template.go b/internal/dao/data_template.go new file mode 100644 index 0000000..5a8b654 --- /dev/null +++ b/internal/dao/data_template.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDataTemplateDao is internal type for wrapping internal DAO implements. +type internalDataTemplateDao = *internal.DataTemplateDao + +// dataTemplateDao is the data access object for table data_template. +// You can define custom methods on it to extend its functionality as you wish. +type dataTemplateDao struct { + internalDataTemplateDao +} + +var ( + // DataTemplate is globally public accessible object for table data_template operations. + DataTemplate = dataTemplateDao{ + internal.NewDataTemplateDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/data_template_busi.go b/internal/dao/data_template_busi.go new file mode 100644 index 0000000..303bd51 --- /dev/null +++ b/internal/dao/data_template_busi.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDataTemplateBusiDao is internal type for wrapping internal DAO implements. +type internalDataTemplateBusiDao = *internal.DataTemplateBusiDao + +// dataTemplateBusiDao is the data access object for table data_template_busi. +// You can define custom methods on it to extend its functionality as you wish. +type dataTemplateBusiDao struct { + internalDataTemplateBusiDao +} + +var ( + // DataTemplateBusi is globally public accessible object for table data_template_busi operations. + DataTemplateBusi = dataTemplateBusiDao{ + internal.NewDataTemplateBusiDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/data_template_node.go b/internal/dao/data_template_node.go new file mode 100644 index 0000000..8b80247 --- /dev/null +++ b/internal/dao/data_template_node.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDataTemplateNodeDao is internal type for wrapping internal DAO implements. +type internalDataTemplateNodeDao = *internal.DataTemplateNodeDao + +// dataTemplateNodeDao is the data access object for table data_template_node. +// You can define custom methods on it to extend its functionality as you wish. +type dataTemplateNodeDao struct { + internalDataTemplateNodeDao +} + +var ( + // DataTemplateNode is globally public accessible object for table data_template_node operations. + DataTemplateNode = dataTemplateNodeDao{ + internal.NewDataTemplateNodeDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/dev_device.go b/internal/dao/dev_device.go new file mode 100644 index 0000000..a1c95e6 --- /dev/null +++ b/internal/dao/dev_device.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDevDeviceDao is internal type for wrapping internal DAO implements. +type internalDevDeviceDao = *internal.DevDeviceDao + +// devDeviceDao is the data access object for table dev_device. +// You can define custom methods on it to extend its functionality as you wish. +type devDeviceDao struct { + internalDevDeviceDao +} + +var ( + // DevDevice is globally public accessible object for table dev_device operations. + DevDevice = devDeviceDao{ + internal.NewDevDeviceDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/dev_device_tag.go b/internal/dao/dev_device_tag.go new file mode 100644 index 0000000..625e7f4 --- /dev/null +++ b/internal/dao/dev_device_tag.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDevDeviceTagDao is internal type for wrapping internal DAO implements. +type internalDevDeviceTagDao = *internal.DevDeviceTagDao + +// devDeviceTagDao is the data access object for table dev_device_tag. +// You can define custom methods on it to extend its functionality as you wish. +type devDeviceTagDao struct { + internalDevDeviceTagDao +} + +var ( + // DevDeviceTag is globally public accessible object for table dev_device_tag operations. + DevDeviceTag = devDeviceTagDao{ + internal.NewDevDeviceTagDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/dev_product.go b/internal/dao/dev_product.go new file mode 100644 index 0000000..005fe8e --- /dev/null +++ b/internal/dao/dev_product.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDevProductDao is internal type for wrapping internal DAO implements. +type internalDevProductDao = *internal.DevProductDao + +// devProductDao is the data access object for table dev_product. +// You can define custom methods on it to extend its functionality as you wish. +type devProductDao struct { + internalDevProductDao +} + +var ( + // DevProduct is globally public accessible object for table dev_product operations. + DevProduct = devProductDao{ + internal.NewDevProductDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/dev_product_category.go b/internal/dao/dev_product_category.go new file mode 100644 index 0000000..f809ca7 --- /dev/null +++ b/internal/dao/dev_product_category.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalDevProductCategoryDao is internal type for wrapping internal DAO implements. +type internalDevProductCategoryDao = *internal.DevProductCategoryDao + +// devProductCategoryDao is the data access object for table dev_product_category. +// You can define custom methods on it to extend its functionality as you wish. +type devProductCategoryDao struct { + internalDevProductCategoryDao +} + +var ( + // DevProductCategory is globally public accessible object for table dev_product_category operations. + DevProductCategory = devProductCategoryDao{ + internal.NewDevProductCategoryDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/internal/alarm_level.go b/internal/dao/internal/alarm_level.go new file mode 100644 index 0000000..7e801d2 --- /dev/null +++ b/internal/dao/internal/alarm_level.go @@ -0,0 +1,75 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AlarmLevelDao is the data access object for table alarm_level. +type AlarmLevelDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AlarmLevelColumns // columns contains all the column names of Table for convenient usage. +} + +// AlarmLevelColumns defines and stores column names for table alarm_level. +type AlarmLevelColumns struct { + Level string // 告警级别 + Name string // 名称 +} + +// alarmLevelColumns holds the columns for table alarm_level. +var alarmLevelColumns = AlarmLevelColumns{ + Level: "level", + Name: "name", +} + +// NewAlarmLevelDao creates and returns a new DAO object for table data access. +func NewAlarmLevelDao() *AlarmLevelDao { + return &AlarmLevelDao{ + group: "default", + table: "alarm_level", + columns: alarmLevelColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AlarmLevelDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AlarmLevelDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AlarmLevelDao) Columns() AlarmLevelColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AlarmLevelDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AlarmLevelDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AlarmLevelDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/alarm_log.go b/internal/dao/internal/alarm_log.go new file mode 100644 index 0000000..d0336cb --- /dev/null +++ b/internal/dao/internal/alarm_log.go @@ -0,0 +1,97 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AlarmLogDao is the data access object for table alarm_log. +type AlarmLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AlarmLogColumns // columns contains all the column names of Table for convenient usage. +} + +// AlarmLogColumns defines and stores column names for table alarm_log. +type AlarmLogColumns struct { + Id string // + Type string // 告警类型:1=规则告警,2=设备自主告警 + RuleId string // 规则id + RuleName string // 规则名称 + Level string // 告警级别 + Data string // 触发告警的数据 + ProductKey string // 产品标识 + DeviceKey string // 设备标识 + Status string // 告警状态:0=未处理,1=已处理 + CreatedAt string // 告警时间 + UpdateBy string // 告警处理人员 + UpdatedAt string // 处理时间 + Content string // 处理意见 +} + +// alarmLogColumns holds the columns for table alarm_log. +var alarmLogColumns = AlarmLogColumns{ + Id: "id", + Type: "type", + RuleId: "rule_id", + RuleName: "rule_name", + Level: "level", + Data: "data", + ProductKey: "product_key", + DeviceKey: "device_key", + Status: "status", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + Content: "content", +} + +// NewAlarmLogDao creates and returns a new DAO object for table data access. +func NewAlarmLogDao() *AlarmLogDao { + return &AlarmLogDao{ + group: "default", + table: "alarm_log", + columns: alarmLogColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AlarmLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AlarmLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AlarmLogDao) Columns() AlarmLogColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AlarmLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AlarmLogDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AlarmLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/alarm_rule.go b/internal/dao/internal/alarm_rule.go new file mode 100644 index 0000000..4a08638 --- /dev/null +++ b/internal/dao/internal/alarm_rule.go @@ -0,0 +1,101 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// AlarmRuleDao is the data access object for table alarm_rule. +type AlarmRuleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns AlarmRuleColumns // columns contains all the column names of Table for convenient usage. +} + +// AlarmRuleColumns defines and stores column names for table alarm_rule. +type AlarmRuleColumns struct { + Id string // + Name string // 告警规则名称 + Level string // 告警级别,默认:4(一般) + ProductKey string // 产品标识 + DeviceKey string // 设备标识 + TriggerType string // 触发类型:1=上线,2=离线,3=属性上报 + TriggerCondition string // 触发条件 + Action string // 执行动作 + Status string // 状态:0=未启用,1=已启用 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// alarmRuleColumns holds the columns for table alarm_rule. +var alarmRuleColumns = AlarmRuleColumns{ + Id: "id", + Name: "name", + Level: "level", + ProductKey: "product_key", + DeviceKey: "device_key", + TriggerType: "trigger_type", + TriggerCondition: "trigger_condition", + Action: "action", + Status: "status", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewAlarmRuleDao creates and returns a new DAO object for table data access. +func NewAlarmRuleDao() *AlarmRuleDao { + return &AlarmRuleDao{ + group: "default", + table: "alarm_rule", + columns: alarmRuleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *AlarmRuleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *AlarmRuleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *AlarmRuleDao) Columns() AlarmRuleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *AlarmRuleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *AlarmRuleDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *AlarmRuleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/base_db_link.go b/internal/dao/internal/base_db_link.go new file mode 100644 index 0000000..01e8493 --- /dev/null +++ b/internal/dao/internal/base_db_link.go @@ -0,0 +1,103 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// BaseDbLinkDao is the data access object for table base_db_link. +type BaseDbLinkDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns BaseDbLinkColumns // columns contains all the column names of Table for convenient usage. +} + +// BaseDbLinkColumns defines and stores column names for table base_db_link. +type BaseDbLinkColumns struct { + Id string // + Name string // 名称 + Types string // 驱动类型 mysql或oracle + Host string // 主机地址 + Port string // 端口号 + UserName string // 用户名称 + Password string // 密码 + Description string // 描述 + Status string // 状态 0 停用 1启用 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + UpdatedBy string // 修改人 + UpdatedAt string // 更新时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// baseDbLinkColumns holds the columns for table base_db_link. +var baseDbLinkColumns = BaseDbLinkColumns{ + Id: "id", + Name: "name", + Types: "types", + Host: "host", + Port: "port", + UserName: "user_name", + Password: "password", + Description: "description", + Status: "status", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewBaseDbLinkDao creates and returns a new DAO object for table data access. +func NewBaseDbLinkDao() *BaseDbLinkDao { + return &BaseDbLinkDao{ + group: "default", + table: "base_db_link", + columns: baseDbLinkColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *BaseDbLinkDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *BaseDbLinkDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *BaseDbLinkDao) Columns() BaseDbLinkColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *BaseDbLinkDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *BaseDbLinkDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *BaseDbLinkDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/city_data.go b/internal/dao/internal/city_data.go new file mode 100644 index 0000000..0e39c2c --- /dev/null +++ b/internal/dao/internal/city_data.go @@ -0,0 +1,97 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// CityDataDao is the data access object for table city_data. +type CityDataDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns CityDataColumns // columns contains all the column names of Table for convenient usage. +} + +// CityDataColumns defines and stores column names for table city_data. +type CityDataColumns struct { + Id string // + Name string // 名字 + Code string // 编码 + ParentId string // 父ID + Sort string // 排序 + Status string // 状态;0:禁用;1:正常 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建者 + CreatedAt string // 创建日期 + UpdatedBy string // 更新者 + UpdatedAt string // 修改日期 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// cityDataColumns holds the columns for table city_data. +var cityDataColumns = CityDataColumns{ + Id: "id", + Name: "name", + Code: "code", + ParentId: "parent_id", + Sort: "sort", + Status: "status", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewCityDataDao creates and returns a new DAO object for table data access. +func NewCityDataDao() *CityDataDao { + return &CityDataDao{ + group: "default", + table: "city_data", + columns: cityDataColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *CityDataDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *CityDataDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *CityDataDao) Columns() CityDataColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *CityDataDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *CityDataDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *CityDataDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/data_node.go b/internal/dao/internal/data_node.go new file mode 100644 index 0000000..88a5090 --- /dev/null +++ b/internal/dao/internal/data_node.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DataNodeDao is the data access object for table data_node. +type DataNodeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DataNodeColumns // columns contains all the column names of Table for convenient usage. +} + +// DataNodeColumns defines and stores column names for table data_node. +type DataNodeColumns struct { + NodeId string // + SourceId string // 数据源ID + Name string // 数据节点名称 + Key string // 数据节点标识 + DataType string // 数据类型 + Value string // 取值项 + IsPk string // 是否主键:0=否,1=是 + Rule string // 规则配置json + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// dataNodeColumns holds the columns for table data_node. +var dataNodeColumns = DataNodeColumns{ + NodeId: "node_id", + SourceId: "source_id", + Name: "name", + Key: "key", + DataType: "data_type", + Value: "value", + IsPk: "is_pk", + Rule: "rule", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDataNodeDao creates and returns a new DAO object for table data access. +func NewDataNodeDao() *DataNodeDao { + return &DataNodeDao{ + group: "default", + table: "data_node", + columns: dataNodeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DataNodeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DataNodeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DataNodeDao) Columns() DataNodeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DataNodeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DataNodeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DataNodeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/data_source.go b/internal/dao/internal/data_source.go new file mode 100644 index 0000000..0b47074 --- /dev/null +++ b/internal/dao/internal/data_source.go @@ -0,0 +1,103 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DataSourceDao is the data access object for table data_source. +type DataSourceDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DataSourceColumns // columns contains all the column names of Table for convenient usage. +} + +// DataSourceColumns defines and stores column names for table data_source. +type DataSourceColumns struct { + SourceId string // + Name string // 数据源名称 + Key string // 数据源标识 + Desc string // 描述 + From string // 数据来源:1=api导入,2=数据库,3=文件,4=设备 + Config string // 数据源配置json:api配置、数据库配置、文件配置 + Rule string // 规则配置json + LockKey string // 锁定key标识:0=未锁定,1=锁定,不允许修改 + Status string // 状态:0=未发布,1=已发布 + DataTable string // 数据表名称 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// dataSourceColumns holds the columns for table data_source. +var dataSourceColumns = DataSourceColumns{ + SourceId: "source_id", + Name: "name", + Key: "key", + Desc: "desc", + From: "from", + Config: "config", + Rule: "rule", + LockKey: "lock_key", + Status: "status", + DataTable: "data_table", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDataSourceDao creates and returns a new DAO object for table data access. +func NewDataSourceDao() *DataSourceDao { + return &DataSourceDao{ + group: "default", + table: "data_source", + columns: dataSourceColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DataSourceDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DataSourceDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DataSourceDao) Columns() DataSourceColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DataSourceDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DataSourceDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DataSourceDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/data_template.go b/internal/dao/internal/data_template.go new file mode 100644 index 0000000..1e80c9d --- /dev/null +++ b/internal/dao/internal/data_template.go @@ -0,0 +1,107 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DataTemplateDao is the data access object for table data_template. +type DataTemplateDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DataTemplateColumns // columns contains all the column names of Table for convenient usage. +} + +// DataTemplateColumns defines and stores column names for table data_template. +type DataTemplateColumns struct { + Id string // ID + Name string // 名称 + Key string // 标识 + Desc string // 描述 + Status string // 状态:0=未发布,1=已发布 + CronExpression string // cron执行表达式 + SortNodeKey string // 排序节点标识 + SortDesc string // 排序方式:1=倒序,2=正序 + DataTable string // 数据表名称 + LockKey string // 锁定key标识:0=未锁定,1=锁定,不允许修改 + MainSourceId string // 主数据源 + SourceNodeKey string // 数据源关联节点 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// dataTemplateColumns holds the columns for table data_template. +var dataTemplateColumns = DataTemplateColumns{ + Id: "id", + Name: "name", + Key: "key", + Desc: "desc", + Status: "status", + CronExpression: "cron_expression", + SortNodeKey: "sort_node_key", + SortDesc: "sort_desc", + DataTable: "data_table", + LockKey: "lock_key", + MainSourceId: "main_source_id", + SourceNodeKey: "source_node_key", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDataTemplateDao creates and returns a new DAO object for table data access. +func NewDataTemplateDao() *DataTemplateDao { + return &DataTemplateDao{ + group: "default", + table: "data_template", + columns: dataTemplateColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DataTemplateDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DataTemplateDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DataTemplateDao) Columns() DataTemplateColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DataTemplateDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DataTemplateDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DataTemplateDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/data_template_busi.go b/internal/dao/internal/data_template_busi.go new file mode 100644 index 0000000..e4f435c --- /dev/null +++ b/internal/dao/internal/data_template_busi.go @@ -0,0 +1,87 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DataTemplateBusiDao is the data access object for table data_template_busi. +type DataTemplateBusiDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DataTemplateBusiColumns // columns contains all the column names of Table for convenient usage. +} + +// DataTemplateBusiColumns defines and stores column names for table data_template_busi. +type DataTemplateBusiColumns struct { + Id string // + DataTemplateId string // 数据建模ID + BusiTypes string // 业务单元 + IsDeleted string // 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// dataTemplateBusiColumns holds the columns for table data_template_busi. +var dataTemplateBusiColumns = DataTemplateBusiColumns{ + Id: "id", + DataTemplateId: "data_template_id", + BusiTypes: "busi_types", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewDataTemplateBusiDao creates and returns a new DAO object for table data access. +func NewDataTemplateBusiDao() *DataTemplateBusiDao { + return &DataTemplateBusiDao{ + group: "default", + table: "data_template_busi", + columns: dataTemplateBusiColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DataTemplateBusiDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DataTemplateBusiDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DataTemplateBusiDao) Columns() DataTemplateBusiColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DataTemplateBusiDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DataTemplateBusiDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DataTemplateBusiDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/data_template_node.go b/internal/dao/internal/data_template_node.go new file mode 100644 index 0000000..95d27f8 --- /dev/null +++ b/internal/dao/internal/data_template_node.go @@ -0,0 +1,107 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DataTemplateNodeDao is the data access object for table data_template_node. +type DataTemplateNodeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DataTemplateNodeColumns // columns contains all the column names of Table for convenient usage. +} + +// DataTemplateNodeColumns defines and stores column names for table data_template_node. +type DataTemplateNodeColumns struct { + Id string // ID + Tid string // 模型ID + From string // 字段生成方式:1=自动生成,2=数据源 + SourceId string // 数据源ID + NodeId string // 数据源ID + Name string // 节点名称 + Key string // 节点标识 + DataType string // 数据类型 + Default string // 默认值 + Method string // 数值类型,取值方式 + IsPk string // 是否主键:0=否,1=是 + Desc string // 描述 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// dataTemplateNodeColumns holds the columns for table data_template_node. +var dataTemplateNodeColumns = DataTemplateNodeColumns{ + Id: "id", + Tid: "tid", + From: "from", + SourceId: "source_id", + NodeId: "node_id", + Name: "name", + Key: "key", + DataType: "data_type", + Default: "default", + Method: "method", + IsPk: "is_pk", + Desc: "desc", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDataTemplateNodeDao creates and returns a new DAO object for table data access. +func NewDataTemplateNodeDao() *DataTemplateNodeDao { + return &DataTemplateNodeDao{ + group: "default", + table: "data_template_node", + columns: dataTemplateNodeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DataTemplateNodeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DataTemplateNodeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DataTemplateNodeDao) Columns() DataTemplateNodeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DataTemplateNodeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DataTemplateNodeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DataTemplateNodeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/dev_device.go b/internal/dao/internal/dev_device.go new file mode 100644 index 0000000..a817f2f --- /dev/null +++ b/internal/dao/internal/dev_device.go @@ -0,0 +1,109 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DevDeviceDao is the data access object for table dev_device. +type DevDeviceDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DevDeviceColumns // columns contains all the column names of Table for convenient usage. +} + +// DevDeviceColumns defines and stores column names for table dev_device. +type DevDeviceColumns struct { + Id string // + Key string // 设备标识 + Name string // 设备名称 + ProductId string // 所属产品 + Desc string // 描述 + MetadataTable string // 是否生成物模型子表:0=否,1=是 + Status string // 状态:0=未启用,1=离线,2=在线 + RegistryTime string // 激活时间 + LastOnlineTime string // 最后上线时间 + Certificate string // 设备证书 + SecureKey string // 设备密钥 + Version string // 固件版本号 + TunnelId string // tunnelId + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// devDeviceColumns holds the columns for table dev_device. +var devDeviceColumns = DevDeviceColumns{ + Id: "id", + Key: "key", + Name: "name", + ProductId: "product_id", + Desc: "desc", + MetadataTable: "metadata_table", + Status: "status", + RegistryTime: "registry_time", + LastOnlineTime: "last_online_time", + Certificate: "certificate", + SecureKey: "secure_key", + Version: "version", + TunnelId: "tunnel_id", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDevDeviceDao creates and returns a new DAO object for table data access. +func NewDevDeviceDao() *DevDeviceDao { + return &DevDeviceDao{ + group: "default", + table: "dev_device", + columns: devDeviceColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DevDeviceDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DevDeviceDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DevDeviceDao) Columns() DevDeviceColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DevDeviceDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DevDeviceDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DevDeviceDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/dev_device_tag.go b/internal/dao/internal/dev_device_tag.go new file mode 100644 index 0000000..56fe97c --- /dev/null +++ b/internal/dao/internal/dev_device_tag.go @@ -0,0 +1,95 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DevDeviceTagDao is the data access object for table dev_device_tag. +type DevDeviceTagDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DevDeviceTagColumns // columns contains all the column names of Table for convenient usage. +} + +// DevDeviceTagColumns defines and stores column names for table dev_device_tag. +type DevDeviceTagColumns struct { + Id string // + DeviceId string // 设备ID + DeviceKey string // 设备标识 + Key string // 标签标识 + Name string // 标签名称 + Value string // 标签值 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// devDeviceTagColumns holds the columns for table dev_device_tag. +var devDeviceTagColumns = DevDeviceTagColumns{ + Id: "id", + DeviceId: "device_id", + DeviceKey: "device_key", + Key: "key", + Name: "name", + Value: "value", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDevDeviceTagDao creates and returns a new DAO object for table data access. +func NewDevDeviceTagDao() *DevDeviceTagDao { + return &DevDeviceTagDao{ + group: "default", + table: "dev_device_tag", + columns: devDeviceTagColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DevDeviceTagDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DevDeviceTagDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DevDeviceTagDao) Columns() DevDeviceTagColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DevDeviceTagDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DevDeviceTagDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DevDeviceTagDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/dev_product.go b/internal/dao/internal/dev_product.go new file mode 100644 index 0000000..431a251 --- /dev/null +++ b/internal/dao/internal/dev_product.go @@ -0,0 +1,111 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DevProductDao is the data access object for table dev_product. +type DevProductDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DevProductColumns // columns contains all the column names of Table for convenient usage. +} + +// DevProductColumns defines and stores column names for table dev_product. +type DevProductColumns struct { + Id string // + Key string // 产品标识 + Name string // 产品名称 + CategoryId string // 所属品类 + MessageProtocol string // 消息协议 + TransportProtocol string // 传输协议: MQTT,COAP,UDP + ProtocolId string // 协议id + DeviceType string // 设备类型: 网关,设备 + Desc string // 描述 + Icon string // 图片地址 + Metadata string // 物模型 + MetadataTable string // 是否生成物模型表:0=否,1=是 + Policy string // 采集策略 + Status string // 发布状态:0=未发布,1=已发布 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// devProductColumns holds the columns for table dev_product. +var devProductColumns = DevProductColumns{ + Id: "id", + Key: "key", + Name: "name", + CategoryId: "category_id", + MessageProtocol: "message_protocol", + TransportProtocol: "transport_protocol", + ProtocolId: "protocol_id", + DeviceType: "device_type", + Desc: "desc", + Icon: "icon", + Metadata: "metadata", + MetadataTable: "metadata_table", + Policy: "policy", + Status: "status", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDevProductDao creates and returns a new DAO object for table data access. +func NewDevProductDao() *DevProductDao { + return &DevProductDao{ + group: "default", + table: "dev_product", + columns: devProductColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DevProductDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DevProductDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DevProductDao) Columns() DevProductColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DevProductDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DevProductDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DevProductDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/dev_product_category.go b/internal/dao/internal/dev_product_category.go new file mode 100644 index 0000000..c35d1a5 --- /dev/null +++ b/internal/dao/internal/dev_product_category.go @@ -0,0 +1,93 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// DevProductCategoryDao is the data access object for table dev_product_category. +type DevProductCategoryDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns DevProductCategoryColumns // columns contains all the column names of Table for convenient usage. +} + +// DevProductCategoryColumns defines and stores column names for table dev_product_category. +type DevProductCategoryColumns struct { + Id string // + ParentId string // 父ID + Key string // 分类标识 + Name string // 分类名称 + Desc string // 描述 + CreateBy string // 创建者 + UpdateBy string // 更新者 + DeletedBy string // 删除者 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// devProductCategoryColumns holds the columns for table dev_product_category. +var devProductCategoryColumns = DevProductCategoryColumns{ + Id: "id", + ParentId: "parent_id", + Key: "key", + Name: "name", + Desc: "desc", + CreateBy: "create_by", + UpdateBy: "update_by", + DeletedBy: "deleted_by", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewDevProductCategoryDao creates and returns a new DAO object for table data access. +func NewDevProductCategoryDao() *DevProductCategoryDao { + return &DevProductCategoryDao{ + group: "default", + table: "dev_product_category", + columns: devProductCategoryColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *DevProductCategoryDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *DevProductCategoryDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *DevProductCategoryDao) Columns() DevProductCategoryColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *DevProductCategoryDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *DevProductCategoryDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *DevProductCategoryDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/network_server.go b/internal/dao/internal/network_server.go new file mode 100644 index 0000000..91e7d6e --- /dev/null +++ b/internal/dao/internal/network_server.go @@ -0,0 +1,97 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NetworkServerDao is the data access object for table network_server. +type NetworkServerDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NetworkServerColumns // columns contains all the column names of Table for convenient usage. +} + +// NetworkServerColumns defines and stores column names for table network_server. +type NetworkServerColumns struct { + Id string // + Name string // + Types string // tcp/udp + Addr string // + Register string // 注册包 + Heartbeat string // 心跳包 + Protocol string // 协议 + Devices string // 默认设备 + Status string // + CreatedAt string // + UpdatedAt string // + CreateBy string // + Remark string // 备注 +} + +// networkServerColumns holds the columns for table network_server. +var networkServerColumns = NetworkServerColumns{ + Id: "id", + Name: "name", + Types: "types", + Addr: "addr", + Register: "register", + Heartbeat: "heartbeat", + Protocol: "protocol", + Devices: "devices", + Status: "status", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + CreateBy: "create_by", + Remark: "remark", +} + +// NewNetworkServerDao creates and returns a new DAO object for table data access. +func NewNetworkServerDao() *NetworkServerDao { + return &NetworkServerDao{ + group: "default", + table: "network_server", + columns: networkServerColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NetworkServerDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NetworkServerDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NetworkServerDao) Columns() NetworkServerColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NetworkServerDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NetworkServerDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NetworkServerDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/network_tunnel.go b/internal/dao/internal/network_tunnel.go new file mode 100644 index 0000000..f8753d3 --- /dev/null +++ b/internal/dao/internal/network_tunnel.go @@ -0,0 +1,103 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NetworkTunnelDao is the data access object for table network_tunnel. +type NetworkTunnelDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NetworkTunnelColumns // columns contains all the column names of Table for convenient usage. +} + +// NetworkTunnelColumns defines and stores column names for table network_tunnel. +type NetworkTunnelColumns struct { + Id string // + ServerId string // 服务ID + Name string // + Types string // + Addr string // + Remote string // + Retry string // 断线重连 + Heartbeat string // 心跳包 + Serial string // 串口参数 + Protoccol string // 适配协议 + DeviceKey string // 设备标识 + Status string // + Last string // + CreatedAt string // + UpdatedAt string // + Remark string // 备注 +} + +// networkTunnelColumns holds the columns for table network_tunnel. +var networkTunnelColumns = NetworkTunnelColumns{ + Id: "id", + ServerId: "server_id", + Name: "name", + Types: "types", + Addr: "addr", + Remote: "remote", + Retry: "retry", + Heartbeat: "heartbeat", + Serial: "serial", + Protoccol: "protoccol", + DeviceKey: "device_key", + Status: "status", + Last: "last", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + Remark: "remark", +} + +// NewNetworkTunnelDao creates and returns a new DAO object for table data access. +func NewNetworkTunnelDao() *NetworkTunnelDao { + return &NetworkTunnelDao{ + group: "default", + table: "network_tunnel", + columns: networkTunnelColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NetworkTunnelDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NetworkTunnelDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NetworkTunnelDao) Columns() NetworkTunnelColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NetworkTunnelDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NetworkTunnelDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NetworkTunnelDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/notice_config.go b/internal/dao/internal/notice_config.go new file mode 100644 index 0000000..44044e1 --- /dev/null +++ b/internal/dao/internal/notice_config.go @@ -0,0 +1,81 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NoticeConfigDao is the data access object for table notice_config. +type NoticeConfigDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NoticeConfigColumns // columns contains all the column names of Table for convenient usage. +} + +// NoticeConfigColumns defines and stores column names for table notice_config. +type NoticeConfigColumns struct { + Id string // + Title string // + SendGateway string // + Types string // + CreatedAt string // +} + +// noticeConfigColumns holds the columns for table notice_config. +var noticeConfigColumns = NoticeConfigColumns{ + Id: "id", + Title: "title", + SendGateway: "send_gateway", + Types: "types", + CreatedAt: "created_at", +} + +// NewNoticeConfigDao creates and returns a new DAO object for table data access. +func NewNoticeConfigDao() *NoticeConfigDao { + return &NoticeConfigDao{ + group: "default", + table: "notice_config", + columns: noticeConfigColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NoticeConfigDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NoticeConfigDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NoticeConfigDao) Columns() NoticeConfigColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NoticeConfigDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NoticeConfigDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NoticeConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/notice_info.go b/internal/dao/internal/notice_info.go new file mode 100644 index 0000000..cbb2a6b --- /dev/null +++ b/internal/dao/internal/notice_info.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NoticeInfoDao is the data access object for table notice_info. +type NoticeInfoDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NoticeInfoColumns // columns contains all the column names of Table for convenient usage. +} + +// NoticeInfoColumns defines and stores column names for table notice_info. +type NoticeInfoColumns struct { + Id string // + ConfigId string // + ComeFrom string // + Method string // + MsgTitle string // + MsgBody string // + MsgUrl string // + UserIds string // + OrgIds string // + Totag string // + Status string // + MethodCron string // + MethodNum string // + CreatedAt string // +} + +// noticeInfoColumns holds the columns for table notice_info. +var noticeInfoColumns = NoticeInfoColumns{ + Id: "id", + ConfigId: "config_id", + ComeFrom: "come_from", + Method: "method", + MsgTitle: "msg_title", + MsgBody: "msg_body", + MsgUrl: "msg_url", + UserIds: "user_ids", + OrgIds: "org_ids", + Totag: "totag", + Status: "status", + MethodCron: "method_cron", + MethodNum: "method_num", + CreatedAt: "created_at", +} + +// NewNoticeInfoDao creates and returns a new DAO object for table data access. +func NewNoticeInfoDao() *NoticeInfoDao { + return &NoticeInfoDao{ + group: "default", + table: "notice_info", + columns: noticeInfoColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NoticeInfoDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NoticeInfoDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NoticeInfoDao) Columns() NoticeInfoColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NoticeInfoDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NoticeInfoDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NoticeInfoDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/notice_log.go b/internal/dao/internal/notice_log.go new file mode 100644 index 0000000..ab40503 --- /dev/null +++ b/internal/dao/internal/notice_log.go @@ -0,0 +1,89 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NoticeLogDao is the data access object for table notice_log. +type NoticeLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NoticeLogColumns // columns contains all the column names of Table for convenient usage. +} + +// NoticeLogColumns defines and stores column names for table notice_log. +type NoticeLogColumns struct { + Id string // + SendGateway string // 通知渠道 + TemplateId string // 通知模板ID + Addressee string // 收信人列表 + Title string // 通知标题 + Content string // 通知内容 + Status string // 发送状态:0=失败,1=成功 + FailMsg string // 失败信息 + SendTime string // 发送时间 +} + +// noticeLogColumns holds the columns for table notice_log. +var noticeLogColumns = NoticeLogColumns{ + Id: "id", + SendGateway: "send_gateway", + TemplateId: "template_id", + Addressee: "addressee", + Title: "title", + Content: "content", + Status: "status", + FailMsg: "fail_msg", + SendTime: "send_time", +} + +// NewNoticeLogDao creates and returns a new DAO object for table data access. +func NewNoticeLogDao() *NoticeLogDao { + return &NoticeLogDao{ + group: "default", + table: "notice_log", + columns: noticeLogColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NoticeLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NoticeLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NoticeLogDao) Columns() NoticeLogColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NoticeLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NoticeLogDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NoticeLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/notice_template.go b/internal/dao/internal/notice_template.go new file mode 100644 index 0000000..8fa4f20 --- /dev/null +++ b/internal/dao/internal/notice_template.go @@ -0,0 +1,85 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// NoticeTemplateDao is the data access object for table notice_template. +type NoticeTemplateDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns NoticeTemplateColumns // columns contains all the column names of Table for convenient usage. +} + +// NoticeTemplateColumns defines and stores column names for table notice_template. +type NoticeTemplateColumns struct { + Id string // + ConfigId string // + SendGateway string // + Code string // + Title string // + Content string // + CreatedAt string // +} + +// noticeTemplateColumns holds the columns for table notice_template. +var noticeTemplateColumns = NoticeTemplateColumns{ + Id: "id", + ConfigId: "config_id", + SendGateway: "send_gateway", + Code: "code", + Title: "title", + Content: "content", + CreatedAt: "created_at", +} + +// NewNoticeTemplateDao creates and returns a new DAO object for table data access. +func NewNoticeTemplateDao() *NoticeTemplateDao { + return &NoticeTemplateDao{ + group: "default", + table: "notice_template", + columns: noticeTemplateColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *NoticeTemplateDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *NoticeTemplateDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *NoticeTemplateDao) Columns() NoticeTemplateColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *NoticeTemplateDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *NoticeTemplateDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *NoticeTemplateDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_api.go b/internal/dao/internal/sys_api.go new file mode 100644 index 0000000..6ba1102 --- /dev/null +++ b/internal/dao/internal/sys_api.go @@ -0,0 +1,103 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysApiDao is the data access object for table sys_api. +type SysApiDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysApiColumns // columns contains all the column names of Table for convenient usage. +} + +// SysApiColumns defines and stores column names for table sys_api. +type SysApiColumns struct { + Id string // + ParentId string // + Name string // 名称 + Types string // 1 分类 2接口 + Method string // 请求方式(数据字典维护) + Address string // 接口地址 + Remark string // 备注 + Status string // 状态 0 停用 1启用 + Sort string // 排序 + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建时间 + UpdatedBy string // 更新者 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysApiColumns holds the columns for table sys_api. +var sysApiColumns = SysApiColumns{ + Id: "id", + ParentId: "parent_id", + Name: "name", + Types: "types", + Method: "method", + Address: "address", + Remark: "remark", + Status: "status", + Sort: "sort", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysApiDao creates and returns a new DAO object for table data access. +func NewSysApiDao() *SysApiDao { + return &SysApiDao{ + group: "default", + table: "sys_api", + columns: sysApiColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysApiDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysApiDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysApiDao) Columns() SysApiColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysApiDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysApiDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysApiDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_authorize.go b/internal/dao/internal/sys_authorize.go new file mode 100644 index 0000000..d5a4b75 --- /dev/null +++ b/internal/dao/internal/sys_authorize.go @@ -0,0 +1,91 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysAuthorizeDao is the data access object for table sys_authorize. +type SysAuthorizeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysAuthorizeColumns // columns contains all the column names of Table for convenient usage. +} + +// SysAuthorizeColumns defines and stores column names for table sys_authorize. +type SysAuthorizeColumns struct { + Id string // + RoleId string // 角色ID + ItemsType string // 项目类型 menu菜单 button按钮 column列表字段 api接口 + ItemsId string // 项目ID + IsCheckAll string // 是否全选 1是 0否 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysAuthorizeColumns holds the columns for table sys_authorize. +var sysAuthorizeColumns = SysAuthorizeColumns{ + Id: "id", + RoleId: "role_id", + ItemsType: "items_type", + ItemsId: "items_id", + IsCheckAll: "is_check_all", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysAuthorizeDao creates and returns a new DAO object for table data access. +func NewSysAuthorizeDao() *SysAuthorizeDao { + return &SysAuthorizeDao{ + group: "default", + table: "sys_authorize", + columns: sysAuthorizeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysAuthorizeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysAuthorizeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysAuthorizeDao) Columns() SysAuthorizeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysAuthorizeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysAuthorizeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysAuthorizeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_config.go b/internal/dao/internal/sys_config.go new file mode 100644 index 0000000..1775a9e --- /dev/null +++ b/internal/dao/internal/sys_config.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysConfigDao is the data access object for table sys_config. +type SysConfigDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysConfigColumns // columns contains all the column names of Table for convenient usage. +} + +// SysConfigColumns defines and stores column names for table sys_config. +type SysConfigColumns struct { + ConfigId string // 参数主键 + ConfigName string // 参数名称 + ConfigKey string // 参数键名 + ConfigValue string // 参数键值 + ConfigType string // 系统内置(1是 2否) + Remark string // 备注 + Status string // 状态 0 停用 1启用 + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建时间 + UpdateBy string // 更新者 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysConfigColumns holds the columns for table sys_config. +var sysConfigColumns = SysConfigColumns{ + ConfigId: "config_id", + ConfigName: "config_name", + ConfigKey: "config_key", + ConfigValue: "config_value", + ConfigType: "config_type", + Remark: "remark", + Status: "status", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysConfigDao creates and returns a new DAO object for table data access. +func NewSysConfigDao() *SysConfigDao { + return &SysConfigDao{ + group: "default", + table: "sys_config", + columns: sysConfigColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysConfigDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysConfigDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysConfigDao) Columns() SysConfigColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysConfigDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysConfigDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_dept.go b/internal/dao/internal/sys_dept.go new file mode 100644 index 0000000..2701389 --- /dev/null +++ b/internal/dao/internal/sys_dept.go @@ -0,0 +1,105 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysDeptDao is the data access object for table sys_dept. +type SysDeptDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysDeptColumns // columns contains all the column names of Table for convenient usage. +} + +// SysDeptColumns defines and stores column names for table sys_dept. +type SysDeptColumns struct { + DeptId string // 部门id + OrganizationId string // 组织ID + ParentId string // 父部门id + Ancestors string // 祖级列表 + DeptName string // 部门名称 + OrderNum string // 显示顺序 + Leader string // 负责人 + Phone string // 联系电话 + Email string // 邮箱 + Status string // 部门状态(0停用 1正常) + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedAt string // 创建时间 + CreatedBy string // 创建人 + UpdatedBy string // 修改人 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysDeptColumns holds the columns for table sys_dept. +var sysDeptColumns = SysDeptColumns{ + DeptId: "dept_id", + OrganizationId: "organization_id", + ParentId: "parent_id", + Ancestors: "ancestors", + DeptName: "dept_name", + OrderNum: "order_num", + Leader: "leader", + Phone: "phone", + Email: "email", + Status: "status", + IsDeleted: "is_deleted", + CreatedAt: "created_at", + CreatedBy: "created_by", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysDeptDao creates and returns a new DAO object for table data access. +func NewSysDeptDao() *SysDeptDao { + return &SysDeptDao{ + group: "default", + table: "sys_dept", + columns: sysDeptColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysDeptDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysDeptDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysDeptDao) Columns() SysDeptColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysDeptDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysDeptDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysDeptDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_dict_data.go b/internal/dao/internal/sys_dict_data.go new file mode 100644 index 0000000..07defb4 --- /dev/null +++ b/internal/dao/internal/sys_dict_data.go @@ -0,0 +1,105 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysDictDataDao is the data access object for table sys_dict_data. +type SysDictDataDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysDictDataColumns // columns contains all the column names of Table for convenient usage. +} + +// SysDictDataColumns defines and stores column names for table sys_dict_data. +type SysDictDataColumns struct { + DictCode string // 字典编码 + DictSort string // 字典排序 + DictLabel string // 字典标签 + DictValue string // 字典键值 + DictType string // 字典类型 + CssClass string // 样式属性(其他样式扩展) + ListClass string // 表格回显样式 + IsDefault string // 是否默认(1是 0否) + Remark string // 备注 + Status string // 状态(0正常 1停用) + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建时间 + UpdateBy string // 更新者 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysDictDataColumns holds the columns for table sys_dict_data. +var sysDictDataColumns = SysDictDataColumns{ + DictCode: "dict_code", + DictSort: "dict_sort", + DictLabel: "dict_label", + DictValue: "dict_value", + DictType: "dict_type", + CssClass: "css_class", + ListClass: "list_class", + IsDefault: "is_default", + Remark: "remark", + Status: "status", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysDictDataDao creates and returns a new DAO object for table data access. +func NewSysDictDataDao() *SysDictDataDao { + return &SysDictDataDao{ + group: "default", + table: "sys_dict_data", + columns: sysDictDataColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysDictDataDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysDictDataDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysDictDataDao) Columns() SysDictDataColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysDictDataDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysDictDataDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysDictDataDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_dict_type.go b/internal/dao/internal/sys_dict_type.go new file mode 100644 index 0000000..5f57fe0 --- /dev/null +++ b/internal/dao/internal/sys_dict_type.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysDictTypeDao is the data access object for table sys_dict_type. +type SysDictTypeDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysDictTypeColumns // columns contains all the column names of Table for convenient usage. +} + +// SysDictTypeColumns defines and stores column names for table sys_dict_type. +type SysDictTypeColumns struct { + DictId string // 字典主键 + ParentId string // 父主键ID + DictName string // 字典名称 + DictType string // 字典类型 + ModuleClassify string // 模块分类 + Remark string // 备注 + Status string // 状态(0正常 1停用) + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建日期 + UpdateBy string // 更新者 + UpdatedAt string // 修改日期 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysDictTypeColumns holds the columns for table sys_dict_type. +var sysDictTypeColumns = SysDictTypeColumns{ + DictId: "dict_id", + ParentId: "parent_id", + DictName: "dict_name", + DictType: "dict_type", + ModuleClassify: "module_classify", + Remark: "remark", + Status: "status", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysDictTypeDao creates and returns a new DAO object for table data access. +func NewSysDictTypeDao() *SysDictTypeDao { + return &SysDictTypeDao{ + group: "default", + table: "sys_dict_type", + columns: sysDictTypeColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysDictTypeDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysDictTypeDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysDictTypeDao) Columns() SysDictTypeColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysDictTypeDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysDictTypeDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysDictTypeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_job.go b/internal/dao/internal/sys_job.go new file mode 100644 index 0000000..6336c94 --- /dev/null +++ b/internal/dao/internal/sys_job.go @@ -0,0 +1,101 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysJobDao is the data access object for table sys_job. +type SysJobDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysJobColumns // columns contains all the column names of Table for convenient usage. +} + +// SysJobColumns defines and stores column names for table sys_job. +type SysJobColumns struct { + JobId string // 任务ID + JobName string // 任务名称 + JobParams string // 参数 + JobGroup string // 任务组名 + InvokeTarget string // 调用目标字符串 + CronExpression string // cron执行表达式 + MisfirePolicy string // 计划执行策略(1多次执行 2执行一次) + Concurrent string // 是否并发执行(0允许 1禁止) + Status string // 状态(0正常 1暂停) + CreateBy string // 创建者 + UpdateBy string // 更新者 + Remark string // 备注信息 + CreatedAt string // 创建时间 + UpdatedAt string // 更新时间 + DeletedAt string // 删除时间 +} + +// sysJobColumns holds the columns for table sys_job. +var sysJobColumns = SysJobColumns{ + JobId: "job_id", + JobName: "job_name", + JobParams: "job_params", + JobGroup: "job_group", + InvokeTarget: "invoke_target", + CronExpression: "cron_expression", + MisfirePolicy: "misfire_policy", + Concurrent: "concurrent", + Status: "status", + CreateBy: "create_by", + UpdateBy: "update_by", + Remark: "remark", + CreatedAt: "created_at", + UpdatedAt: "updated_at", + DeletedAt: "deleted_at", +} + +// NewSysJobDao creates and returns a new DAO object for table data access. +func NewSysJobDao() *SysJobDao { + return &SysJobDao{ + group: "default", + table: "sys_job", + columns: sysJobColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysJobDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysJobDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysJobDao) Columns() SysJobColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysJobDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysJobDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysJobDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_login_log.go b/internal/dao/internal/sys_login_log.go new file mode 100644 index 0000000..b80ed47 --- /dev/null +++ b/internal/dao/internal/sys_login_log.go @@ -0,0 +1,91 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysLoginLogDao is the data access object for table sys_login_log. +type SysLoginLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysLoginLogColumns // columns contains all the column names of Table for convenient usage. +} + +// SysLoginLogColumns defines and stores column names for table sys_login_log. +type SysLoginLogColumns struct { + InfoId string // 访问ID + LoginName string // 登录账号 + Ipaddr string // 登录IP地址 + LoginLocation string // 登录地点 + Browser string // 浏览器类型 + Os string // 操作系统 + Status string // 登录状态(0成功 1失败) + Msg string // 提示消息 + LoginTime string // 登录时间 + Module string // 登录模块 +} + +// sysLoginLogColumns holds the columns for table sys_login_log. +var sysLoginLogColumns = SysLoginLogColumns{ + InfoId: "info_id", + LoginName: "login_name", + Ipaddr: "ipaddr", + LoginLocation: "login_location", + Browser: "browser", + Os: "os", + Status: "status", + Msg: "msg", + LoginTime: "login_time", + Module: "module", +} + +// NewSysLoginLogDao creates and returns a new DAO object for table data access. +func NewSysLoginLogDao() *SysLoginLogDao { + return &SysLoginLogDao{ + group: "default", + table: "sys_login_log", + columns: sysLoginLogColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysLoginLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysLoginLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysLoginLogDao) Columns() SysLoginLogColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysLoginLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysLoginLogDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysLoginLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_menu.go b/internal/dao/internal/sys_menu.go new file mode 100644 index 0000000..7a8e53e --- /dev/null +++ b/internal/dao/internal/sys_menu.go @@ -0,0 +1,127 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysMenuDao is the data access object for table sys_menu. +type SysMenuDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysMenuColumns // columns contains all the column names of Table for convenient usage. +} + +// SysMenuColumns defines and stores column names for table sys_menu. +type SysMenuColumns struct { + Id string // + ParentId string // 父ID + Name string // 规则名称 + Title string // 规则名称 + Icon string // 图标 + Condition string // 条件 + Remark string // 备注 + MenuType string // 类型 0目录 1菜单 2按钮 + Weigh string // 权重 + IsHide string // 显示状态 + Path string // 路由地址 + Component string // 组件路径 + IsLink string // 是否外链 1是 0否 + ModuleType string // 所属模块 system 运维 company企业 + ModelId string // 模型ID + IsIframe string // 是否内嵌iframe + IsCached string // 是否缓存 + Redirect string // 路由重定向地址 + IsAffix string // 是否固定 + LinkUrl string // 链接地址 + Status string // 状态 0 停用 1启用 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + UpdatedBy string // 修改人 + UpdatedAt string // 更新时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysMenuColumns holds the columns for table sys_menu. +var sysMenuColumns = SysMenuColumns{ + Id: "id", + ParentId: "parent_id", + Name: "name", + Title: "title", + Icon: "icon", + Condition: "condition", + Remark: "remark", + MenuType: "menu_type", + Weigh: "weigh", + IsHide: "is_hide", + Path: "path", + Component: "component", + IsLink: "is_link", + ModuleType: "module_type", + ModelId: "model_id", + IsIframe: "is_iframe", + IsCached: "is_cached", + Redirect: "redirect", + IsAffix: "is_affix", + LinkUrl: "link_url", + Status: "status", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysMenuDao creates and returns a new DAO object for table data access. +func NewSysMenuDao() *SysMenuDao { + return &SysMenuDao{ + group: "default", + table: "sys_menu", + columns: sysMenuColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysMenuDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysMenuDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysMenuDao) Columns() SysMenuColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysMenuDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysMenuDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysMenuDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_menu_api.go b/internal/dao/internal/sys_menu_api.go new file mode 100644 index 0000000..c849b27 --- /dev/null +++ b/internal/dao/internal/sys_menu_api.go @@ -0,0 +1,87 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysMenuApiDao is the data access object for table sys_menu_api. +type SysMenuApiDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysMenuApiColumns // columns contains all the column names of Table for convenient usage. +} + +// SysMenuApiColumns defines and stores column names for table sys_menu_api. +type SysMenuApiColumns struct { + Id string // id + MenuId string // 菜单ID + ApiId string // apiId + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysMenuApiColumns holds the columns for table sys_menu_api. +var sysMenuApiColumns = SysMenuApiColumns{ + Id: "id", + MenuId: "menu_id", + ApiId: "api_id", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysMenuApiDao creates and returns a new DAO object for table data access. +func NewSysMenuApiDao() *SysMenuApiDao { + return &SysMenuApiDao{ + group: "default", + table: "sys_menu_api", + columns: sysMenuApiColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysMenuApiDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysMenuApiDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysMenuApiDao) Columns() SysMenuApiColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysMenuApiDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysMenuApiDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysMenuApiDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_menu_button.go b/internal/dao/internal/sys_menu_button.go new file mode 100644 index 0000000..afdc92c --- /dev/null +++ b/internal/dao/internal/sys_menu_button.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysMenuButtonDao is the data access object for table sys_menu_button. +type SysMenuButtonDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysMenuButtonColumns // columns contains all the column names of Table for convenient usage. +} + +// SysMenuButtonColumns defines and stores column names for table sys_menu_button. +type SysMenuButtonColumns struct { + Id string // + ParentId string // 父ID + MenuId string // 菜单ID + Name string // 名称 + Types string // 类型 自定义 add添加 edit编辑 del 删除 + Description string // 描述 + Status string // 状态 0 停用 1启用 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + UpdatedBy string // 修改人 + UpdatedAt string // 更新时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysMenuButtonColumns holds the columns for table sys_menu_button. +var sysMenuButtonColumns = SysMenuButtonColumns{ + Id: "id", + ParentId: "parent_id", + MenuId: "menu_id", + Name: "name", + Types: "types", + Description: "description", + Status: "status", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysMenuButtonDao creates and returns a new DAO object for table data access. +func NewSysMenuButtonDao() *SysMenuButtonDao { + return &SysMenuButtonDao{ + group: "default", + table: "sys_menu_button", + columns: sysMenuButtonColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysMenuButtonDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysMenuButtonDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysMenuButtonDao) Columns() SysMenuButtonColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysMenuButtonDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysMenuButtonDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysMenuButtonDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_menu_column.go b/internal/dao/internal/sys_menu_column.go new file mode 100644 index 0000000..6838ced --- /dev/null +++ b/internal/dao/internal/sys_menu_column.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysMenuColumnDao is the data access object for table sys_menu_column. +type SysMenuColumnDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysMenuColumnColumns // columns contains all the column names of Table for convenient usage. +} + +// SysMenuColumnColumns defines and stores column names for table sys_menu_column. +type SysMenuColumnColumns struct { + Id string // + ParentId string // 父ID + MenuId string // 菜单ID + Name string // 名称 + Code string // 代表字段 + Description string // 描述 + Status string // 状态 0 停用 1启用 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + UpdatedBy string // 修改人 + UpdatedAt string // 更新时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysMenuColumnColumns holds the columns for table sys_menu_column. +var sysMenuColumnColumns = SysMenuColumnColumns{ + Id: "id", + ParentId: "parent_id", + MenuId: "menu_id", + Name: "name", + Code: "code", + Description: "description", + Status: "status", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysMenuColumnDao creates and returns a new DAO object for table data access. +func NewSysMenuColumnDao() *SysMenuColumnDao { + return &SysMenuColumnDao{ + group: "default", + table: "sys_menu_column", + columns: sysMenuColumnColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysMenuColumnDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysMenuColumnDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysMenuColumnDao) Columns() SysMenuColumnColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysMenuColumnDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysMenuColumnDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysMenuColumnDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_notifications.go b/internal/dao/internal/sys_notifications.go new file mode 100644 index 0000000..5781852 --- /dev/null +++ b/internal/dao/internal/sys_notifications.go @@ -0,0 +1,85 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysNotificationsDao is the data access object for table sys_notifications. +type SysNotificationsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysNotificationsColumns // columns contains all the column names of Table for convenient usage. +} + +// SysNotificationsColumns defines and stores column names for table sys_notifications. +type SysNotificationsColumns struct { + Id string // + Title string // 标题 + Doc string // 描述 + Source string // 消息来源 + Types string // 类型 + CreatedAt string // 发送时间 + Status string // 0,未读,1,已读 +} + +// sysNotificationsColumns holds the columns for table sys_notifications. +var sysNotificationsColumns = SysNotificationsColumns{ + Id: "id", + Title: "title", + Doc: "doc", + Source: "source", + Types: "types", + CreatedAt: "created_at", + Status: "status", +} + +// NewSysNotificationsDao creates and returns a new DAO object for table data access. +func NewSysNotificationsDao() *SysNotificationsDao { + return &SysNotificationsDao{ + group: "default", + table: "sys_notifications", + columns: sysNotificationsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysNotificationsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysNotificationsDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysNotificationsDao) Columns() SysNotificationsColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysNotificationsDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysNotificationsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysNotificationsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_oper_log.go b/internal/dao/internal/sys_oper_log.go new file mode 100644 index 0000000..6f2b015 --- /dev/null +++ b/internal/dao/internal/sys_oper_log.go @@ -0,0 +1,103 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysOperLogDao is the data access object for table sys_oper_log. +type SysOperLogDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysOperLogColumns // columns contains all the column names of Table for convenient usage. +} + +// SysOperLogColumns defines and stores column names for table sys_oper_log. +type SysOperLogColumns struct { + OperId string // 日志主键 + Title string // 模块标题 + BusinessType string // 业务类型(0其它 1新增 2修改 3删除) + Method string // 方法名称 + RequestMethod string // 请求方式 + OperatorType string // 操作类别(0其它 1后台用户 2手机端用户) + OperName string // 操作人员 + DeptName string // 部门名称 + OperUrl string // 请求URL + OperIp string // 主机地址 + OperLocation string // 操作地点 + OperParam string // 请求参数 + JsonResult string // 返回参数 + Status string // 操作状态(0正常 1异常) + ErrorMsg string // 错误消息 + OperTime string // 操作时间 +} + +// sysOperLogColumns holds the columns for table sys_oper_log. +var sysOperLogColumns = SysOperLogColumns{ + OperId: "oper_id", + Title: "title", + BusinessType: "business_type", + Method: "method", + RequestMethod: "request_method", + OperatorType: "operator_type", + OperName: "oper_name", + DeptName: "dept_name", + OperUrl: "oper_url", + OperIp: "oper_ip", + OperLocation: "oper_location", + OperParam: "oper_param", + JsonResult: "json_result", + Status: "status", + ErrorMsg: "error_msg", + OperTime: "oper_time", +} + +// NewSysOperLogDao creates and returns a new DAO object for table data access. +func NewSysOperLogDao() *SysOperLogDao { + return &SysOperLogDao{ + group: "default", + table: "sys_oper_log", + columns: sysOperLogColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysOperLogDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysOperLogDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysOperLogDao) Columns() SysOperLogColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysOperLogDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysOperLogDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysOperLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_organization.go b/internal/dao/internal/sys_organization.go new file mode 100644 index 0000000..67226c6 --- /dev/null +++ b/internal/dao/internal/sys_organization.go @@ -0,0 +1,105 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysOrganizationDao is the data access object for table sys_organization. +type SysOrganizationDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysOrganizationColumns // columns contains all the column names of Table for convenient usage. +} + +// SysOrganizationColumns defines and stores column names for table sys_organization. +type SysOrganizationColumns struct { + Id string // 组织ID + ParentId string // 父组织id + Ancestors string // 祖级列表 + Name string // 组织名称 + Number string // 组织编号 + OrderNum string // 显示顺序 + Leader string // 负责人 + Phone string // 联系电话 + Email string // 邮箱 + Status string // 组织状态(0停用 1正常) + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedAt string // 创建时间 + CreatedBy string // 创建人 + UpdatedBy string // 修改人 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysOrganizationColumns holds the columns for table sys_organization. +var sysOrganizationColumns = SysOrganizationColumns{ + Id: "id", + ParentId: "parent_id", + Ancestors: "ancestors", + Name: "name", + Number: "number", + OrderNum: "order_num", + Leader: "leader", + Phone: "phone", + Email: "email", + Status: "status", + IsDeleted: "is_deleted", + CreatedAt: "created_at", + CreatedBy: "created_by", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysOrganizationDao creates and returns a new DAO object for table data access. +func NewSysOrganizationDao() *SysOrganizationDao { + return &SysOrganizationDao{ + group: "default", + table: "sys_organization", + columns: sysOrganizationColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysOrganizationDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysOrganizationDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysOrganizationDao) Columns() SysOrganizationColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysOrganizationDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysOrganizationDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysOrganizationDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_plugins.go b/internal/dao/internal/sys_plugins.go new file mode 100644 index 0000000..7095778 --- /dev/null +++ b/internal/dao/internal/sys_plugins.go @@ -0,0 +1,89 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysPluginsDao is the data access object for table sys_plugins. +type SysPluginsDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysPluginsColumns // columns contains all the column names of Table for convenient usage. +} + +// SysPluginsColumns defines and stores column names for table sys_plugins. +type SysPluginsColumns struct { + Id string // ID + Name string // 名称 + Title string // 标题 + Intro string // 介绍 + Version string // 版本 + Status string // 状态 + Types string // 插件类型 + Author string // + StartTime string // +} + +// sysPluginsColumns holds the columns for table sys_plugins. +var sysPluginsColumns = SysPluginsColumns{ + Id: "id", + Name: "name", + Title: "title", + Intro: "intro", + Version: "version", + Status: "status", + Types: "types", + Author: "author", + StartTime: "start_time", +} + +// NewSysPluginsDao creates and returns a new DAO object for table data access. +func NewSysPluginsDao() *SysPluginsDao { + return &SysPluginsDao{ + group: "default", + table: "sys_plugins", + columns: sysPluginsColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysPluginsDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysPluginsDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysPluginsDao) Columns() SysPluginsColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysPluginsDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysPluginsDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysPluginsDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_plugins_config.go b/internal/dao/internal/sys_plugins_config.go new file mode 100644 index 0000000..9f921cf --- /dev/null +++ b/internal/dao/internal/sys_plugins_config.go @@ -0,0 +1,81 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysPluginsConfigDao is the data access object for table sys_plugins_config. +type SysPluginsConfigDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysPluginsConfigColumns // columns contains all the column names of Table for convenient usage. +} + +// SysPluginsConfigColumns defines and stores column names for table sys_plugins_config. +type SysPluginsConfigColumns struct { + Id string // + Type string // 插件类型 + Name string // 插件名称 + Value string // 配置内容 + Doc string // 配置说明 +} + +// sysPluginsConfigColumns holds the columns for table sys_plugins_config. +var sysPluginsConfigColumns = SysPluginsConfigColumns{ + Id: "id", + Type: "type", + Name: "name", + Value: "value", + Doc: "doc", +} + +// NewSysPluginsConfigDao creates and returns a new DAO object for table data access. +func NewSysPluginsConfigDao() *SysPluginsConfigDao { + return &SysPluginsConfigDao{ + group: "default", + table: "sys_plugins_config", + columns: sysPluginsConfigColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysPluginsConfigDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysPluginsConfigDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysPluginsConfigDao) Columns() SysPluginsConfigColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysPluginsConfigDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysPluginsConfigDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysPluginsConfigDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_post.go b/internal/dao/internal/sys_post.go new file mode 100644 index 0000000..b766fcb --- /dev/null +++ b/internal/dao/internal/sys_post.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysPostDao is the data access object for table sys_post. +type SysPostDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysPostColumns // columns contains all the column names of Table for convenient usage. +} + +// SysPostColumns defines and stores column names for table sys_post. +type SysPostColumns struct { + PostId string // 岗位ID + ParentId string // 父ID + PostCode string // 岗位编码 + PostName string // 岗位名称 + PostSort string // 显示顺序 + Status string // 状态(0正常 1停用) + Remark string // 备注 + IsDeleted string // 是否删除 0未删除 1已删除 + CreatedBy string // 创建人 + CreatedAt string // 创建时间 + UpdatedBy string // 修改人 + UpdatedAt string // 修改时间 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysPostColumns holds the columns for table sys_post. +var sysPostColumns = SysPostColumns{ + PostId: "post_id", + ParentId: "parent_id", + PostCode: "post_code", + PostName: "post_name", + PostSort: "post_sort", + Status: "status", + Remark: "remark", + IsDeleted: "is_deleted", + CreatedBy: "created_by", + CreatedAt: "created_at", + UpdatedBy: "updated_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysPostDao creates and returns a new DAO object for table data access. +func NewSysPostDao() *SysPostDao { + return &SysPostDao{ + group: "default", + table: "sys_post", + columns: sysPostColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysPostDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysPostDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysPostDao) Columns() SysPostColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysPostDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysPostDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysPostDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_role.go b/internal/dao/internal/sys_role.go new file mode 100644 index 0000000..5801533 --- /dev/null +++ b/internal/dao/internal/sys_role.go @@ -0,0 +1,99 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysRoleDao is the data access object for table sys_role. +type SysRoleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysRoleColumns // columns contains all the column names of Table for convenient usage. +} + +// SysRoleColumns defines and stores column names for table sys_role. +type SysRoleColumns struct { + Id string // + ParentId string // 父ID + ListOrder string // 排序 + Name string // 角色名称 + DataScope string // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + Remark string // 备注 + Status string // 状态;0:禁用;1:正常 + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建日期 + UpdateBy string // 更新者 + UpdatedAt string // 修改日期 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysRoleColumns holds the columns for table sys_role. +var sysRoleColumns = SysRoleColumns{ + Id: "id", + ParentId: "parent_id", + ListOrder: "list_order", + Name: "name", + DataScope: "data_scope", + Remark: "remark", + Status: "status", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysRoleDao creates and returns a new DAO object for table data access. +func NewSysRoleDao() *SysRoleDao { + return &SysRoleDao{ + group: "default", + table: "sys_role", + columns: sysRoleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysRoleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysRoleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysRoleDao) Columns() SysRoleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysRoleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysRoleDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysRoleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_role_dept.go b/internal/dao/internal/sys_role_dept.go new file mode 100644 index 0000000..b61dbcc --- /dev/null +++ b/internal/dao/internal/sys_role_dept.go @@ -0,0 +1,75 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysRoleDeptDao is the data access object for table sys_role_dept. +type SysRoleDeptDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysRoleDeptColumns // columns contains all the column names of Table for convenient usage. +} + +// SysRoleDeptColumns defines and stores column names for table sys_role_dept. +type SysRoleDeptColumns struct { + RoleId string // 角色ID + DeptId string // 部门ID +} + +// sysRoleDeptColumns holds the columns for table sys_role_dept. +var sysRoleDeptColumns = SysRoleDeptColumns{ + RoleId: "role_id", + DeptId: "dept_id", +} + +// NewSysRoleDeptDao creates and returns a new DAO object for table data access. +func NewSysRoleDeptDao() *SysRoleDeptDao { + return &SysRoleDeptDao{ + group: "default", + table: "sys_role_dept", + columns: sysRoleDeptColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysRoleDeptDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysRoleDeptDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysRoleDeptDao) Columns() SysRoleDeptColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysRoleDeptDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysRoleDeptDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysRoleDeptDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_user.go b/internal/dao/internal/sys_user.go new file mode 100644 index 0000000..fb41dd5 --- /dev/null +++ b/internal/dao/internal/sys_user.go @@ -0,0 +1,123 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserDao is the data access object for table sys_user. +type SysUserDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysUserColumns // columns contains all the column names of Table for convenient usage. +} + +// SysUserColumns defines and stores column names for table sys_user. +type SysUserColumns struct { + Id string // + UserName string // 用户名 + UserTypes string // 系统 system 企业 company + Mobile string // 中国手机不带国家代码,国际手机号格式为:国家代码-手机号 + UserNickname string // 用户昵称 + Birthday string // 生日 + UserPassword string // 登录密码;cmf_password加密 + UserSalt string // 加密盐 + UserEmail string // 用户登录邮箱 + Sex string // 性别;0:保密,1:男,2:女 + Avatar string // 用户头像 + DeptId string // 部门id + Remark string // 备注 + IsAdmin string // 是否后台管理员 1 是 0 否 + Address string // 联系地址 + Describe string // 描述信息 + LastLoginIp string // 最后登录ip + LastLoginTime string // 最后登录时间 + Status string // 用户状态;0:禁用,1:正常,2:未验证 + IsDeleted string // 是否删除 0未删除 1已删除 + CreateBy string // 创建者 + CreatedAt string // 创建日期 + UpdateBy string // 更新者 + UpdatedAt string // 修改日期 + DeletedBy string // 删除人 + DeletedAt string // 删除时间 +} + +// sysUserColumns holds the columns for table sys_user. +var sysUserColumns = SysUserColumns{ + Id: "id", + UserName: "user_name", + UserTypes: "user_types", + Mobile: "mobile", + UserNickname: "user_nickname", + Birthday: "birthday", + UserPassword: "user_password", + UserSalt: "user_salt", + UserEmail: "user_email", + Sex: "sex", + Avatar: "avatar", + DeptId: "dept_id", + Remark: "remark", + IsAdmin: "is_admin", + Address: "address", + Describe: "describe", + LastLoginIp: "last_login_ip", + LastLoginTime: "last_login_time", + Status: "status", + IsDeleted: "is_deleted", + CreateBy: "create_by", + CreatedAt: "created_at", + UpdateBy: "update_by", + UpdatedAt: "updated_at", + DeletedBy: "deleted_by", + DeletedAt: "deleted_at", +} + +// NewSysUserDao creates and returns a new DAO object for table data access. +func NewSysUserDao() *SysUserDao { + return &SysUserDao{ + group: "default", + table: "sys_user", + columns: sysUserColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysUserDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysUserDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysUserDao) Columns() SysUserColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysUserDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysUserDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_user_online.go b/internal/dao/internal/sys_user_online.go new file mode 100644 index 0000000..741adab --- /dev/null +++ b/internal/dao/internal/sys_user_online.go @@ -0,0 +1,89 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserOnlineDao is the data access object for table sys_user_online. +type SysUserOnlineDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysUserOnlineColumns // columns contains all the column names of Table for convenient usage. +} + +// SysUserOnlineColumns defines and stores column names for table sys_user_online. +type SysUserOnlineColumns struct { + Id string // + Uuid string // 用户标识 + Key string // + Token string // 用户token + CreatedAt string // 登录时间 + UserName string // 用户名 + Ip string // 登录ip + Explorer string // 浏览器 + Os string // 操作系统 +} + +// sysUserOnlineColumns holds the columns for table sys_user_online. +var sysUserOnlineColumns = SysUserOnlineColumns{ + Id: "id", + Uuid: "uuid", + Key: "key", + Token: "token", + CreatedAt: "created_at", + UserName: "user_name", + Ip: "ip", + Explorer: "explorer", + Os: "os", +} + +// NewSysUserOnlineDao creates and returns a new DAO object for table data access. +func NewSysUserOnlineDao() *SysUserOnlineDao { + return &SysUserOnlineDao{ + group: "default", + table: "sys_user_online", + columns: sysUserOnlineColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysUserOnlineDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysUserOnlineDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysUserOnlineDao) Columns() SysUserOnlineColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysUserOnlineDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysUserOnlineDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysUserOnlineDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_user_post.go b/internal/dao/internal/sys_user_post.go new file mode 100644 index 0000000..cb4a170 --- /dev/null +++ b/internal/dao/internal/sys_user_post.go @@ -0,0 +1,75 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserPostDao is the data access object for table sys_user_post. +type SysUserPostDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysUserPostColumns // columns contains all the column names of Table for convenient usage. +} + +// SysUserPostColumns defines and stores column names for table sys_user_post. +type SysUserPostColumns struct { + UserId string // 用户ID + PostId string // 岗位ID +} + +// sysUserPostColumns holds the columns for table sys_user_post. +var sysUserPostColumns = SysUserPostColumns{ + UserId: "user_id", + PostId: "post_id", +} + +// NewSysUserPostDao creates and returns a new DAO object for table data access. +func NewSysUserPostDao() *SysUserPostDao { + return &SysUserPostDao{ + group: "default", + table: "sys_user_post", + columns: sysUserPostColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysUserPostDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysUserPostDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysUserPostDao) Columns() SysUserPostColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysUserPostDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysUserPostDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysUserPostDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/internal/sys_user_role.go b/internal/dao/internal/sys_user_role.go new file mode 100644 index 0000000..d0cb3c6 --- /dev/null +++ b/internal/dao/internal/sys_user_role.go @@ -0,0 +1,75 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserRoleDao is the data access object for table sys_user_role. +type SysUserRoleDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns SysUserRoleColumns // columns contains all the column names of Table for convenient usage. +} + +// SysUserRoleColumns defines and stores column names for table sys_user_role. +type SysUserRoleColumns struct { + UserId string // + RoleId string // +} + +// sysUserRoleColumns holds the columns for table sys_user_role. +var sysUserRoleColumns = SysUserRoleColumns{ + UserId: "user_id", + RoleId: "role_id", +} + +// NewSysUserRoleDao creates and returns a new DAO object for table data access. +func NewSysUserRoleDao() *SysUserRoleDao { + return &SysUserRoleDao{ + group: "default", + table: "sys_user_role", + columns: sysUserRoleColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *SysUserRoleDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *SysUserRoleDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *SysUserRoleDao) Columns() SysUserRoleColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *SysUserRoleDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *SysUserRoleDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *SysUserRoleDao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/internal/dao/network_server.go b/internal/dao/network_server.go new file mode 100644 index 0000000..c7c5cb0 --- /dev/null +++ b/internal/dao/network_server.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNetworkServerDao is internal type for wrapping internal DAO implements. +type internalNetworkServerDao = *internal.NetworkServerDao + +// networkServerDao is the data access object for table network_server. +// You can define custom methods on it to extend its functionality as you wish. +type networkServerDao struct { + internalNetworkServerDao +} + +var ( + // NetworkServer is globally public accessible object for table network_server operations. + NetworkServer = networkServerDao{ + internal.NewNetworkServerDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/network_tunnel.go b/internal/dao/network_tunnel.go new file mode 100644 index 0000000..a86c28e --- /dev/null +++ b/internal/dao/network_tunnel.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNetworkTunnelDao is internal type for wrapping internal DAO implements. +type internalNetworkTunnelDao = *internal.NetworkTunnelDao + +// networkTunnelDao is the data access object for table network_tunnel. +// You can define custom methods on it to extend its functionality as you wish. +type networkTunnelDao struct { + internalNetworkTunnelDao +} + +var ( + // NetworkTunnel is globally public accessible object for table network_tunnel operations. + NetworkTunnel = networkTunnelDao{ + internal.NewNetworkTunnelDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/notice_config.go b/internal/dao/notice_config.go new file mode 100644 index 0000000..24837df --- /dev/null +++ b/internal/dao/notice_config.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNoticeConfigDao is internal type for wrapping internal DAO implements. +type internalNoticeConfigDao = *internal.NoticeConfigDao + +// noticeConfigDao is the data access object for table notice_config. +// You can define custom methods on it to extend its functionality as you wish. +type noticeConfigDao struct { + internalNoticeConfigDao +} + +var ( + // NoticeConfig is globally public accessible object for table notice_config operations. + NoticeConfig = noticeConfigDao{ + internal.NewNoticeConfigDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/notice_info.go b/internal/dao/notice_info.go new file mode 100644 index 0000000..77584cd --- /dev/null +++ b/internal/dao/notice_info.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNoticeInfoDao is internal type for wrapping internal DAO implements. +type internalNoticeInfoDao = *internal.NoticeInfoDao + +// noticeInfoDao is the data access object for table notice_info. +// You can define custom methods on it to extend its functionality as you wish. +type noticeInfoDao struct { + internalNoticeInfoDao +} + +var ( + // NoticeInfo is globally public accessible object for table notice_info operations. + NoticeInfo = noticeInfoDao{ + internal.NewNoticeInfoDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/notice_log.go b/internal/dao/notice_log.go new file mode 100644 index 0000000..8782023 --- /dev/null +++ b/internal/dao/notice_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNoticeLogDao is internal type for wrapping internal DAO implements. +type internalNoticeLogDao = *internal.NoticeLogDao + +// noticeLogDao is the data access object for table notice_log. +// You can define custom methods on it to extend its functionality as you wish. +type noticeLogDao struct { + internalNoticeLogDao +} + +var ( + // NoticeLog is globally public accessible object for table notice_log operations. + NoticeLog = noticeLogDao{ + internal.NewNoticeLogDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/notice_template.go b/internal/dao/notice_template.go new file mode 100644 index 0000000..76eff91 --- /dev/null +++ b/internal/dao/notice_template.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalNoticeTemplateDao is internal type for wrapping internal DAO implements. +type internalNoticeTemplateDao = *internal.NoticeTemplateDao + +// noticeTemplateDao is the data access object for table notice_template. +// You can define custom methods on it to extend its functionality as you wish. +type noticeTemplateDao struct { + internalNoticeTemplateDao +} + +var ( + // NoticeTemplate is globally public accessible object for table notice_template operations. + NoticeTemplate = noticeTemplateDao{ + internal.NewNoticeTemplateDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_api.go b/internal/dao/sys_api.go new file mode 100644 index 0000000..9485708 --- /dev/null +++ b/internal/dao/sys_api.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysApiDao is internal type for wrapping internal DAO implements. +type internalSysApiDao = *internal.SysApiDao + +// sysApiDao is the data access object for table sys_api. +// You can define custom methods on it to extend its functionality as you wish. +type sysApiDao struct { + internalSysApiDao +} + +var ( + // SysApi is globally public accessible object for table sys_api operations. + SysApi = sysApiDao{ + internal.NewSysApiDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_authorize.go b/internal/dao/sys_authorize.go new file mode 100644 index 0000000..7b340a2 --- /dev/null +++ b/internal/dao/sys_authorize.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysAuthorizeDao is internal type for wrapping internal DAO implements. +type internalSysAuthorizeDao = *internal.SysAuthorizeDao + +// sysAuthorizeDao is the data access object for table sys_authorize. +// You can define custom methods on it to extend its functionality as you wish. +type sysAuthorizeDao struct { + internalSysAuthorizeDao +} + +var ( + // SysAuthorize is globally public accessible object for table sys_authorize operations. + SysAuthorize = sysAuthorizeDao{ + internal.NewSysAuthorizeDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_config.go b/internal/dao/sys_config.go new file mode 100644 index 0000000..ac26bf0 --- /dev/null +++ b/internal/dao/sys_config.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysConfigDao is internal type for wrapping internal DAO implements. +type internalSysConfigDao = *internal.SysConfigDao + +// sysConfigDao is the data access object for table sys_config. +// You can define custom methods on it to extend its functionality as you wish. +type sysConfigDao struct { + internalSysConfigDao +} + +var ( + // SysConfig is globally public accessible object for table sys_config operations. + SysConfig = sysConfigDao{ + internal.NewSysConfigDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_dept.go b/internal/dao/sys_dept.go new file mode 100644 index 0000000..0b64899 --- /dev/null +++ b/internal/dao/sys_dept.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysDeptDao is internal type for wrapping internal DAO implements. +type internalSysDeptDao = *internal.SysDeptDao + +// sysDeptDao is the data access object for table sys_dept. +// You can define custom methods on it to extend its functionality as you wish. +type sysDeptDao struct { + internalSysDeptDao +} + +var ( + // SysDept is globally public accessible object for table sys_dept operations. + SysDept = sysDeptDao{ + internal.NewSysDeptDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_dict_data.go b/internal/dao/sys_dict_data.go new file mode 100644 index 0000000..d130179 --- /dev/null +++ b/internal/dao/sys_dict_data.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysDictDataDao is internal type for wrapping internal DAO implements. +type internalSysDictDataDao = *internal.SysDictDataDao + +// sysDictDataDao is the data access object for table sys_dict_data. +// You can define custom methods on it to extend its functionality as you wish. +type sysDictDataDao struct { + internalSysDictDataDao +} + +var ( + // SysDictData is globally public accessible object for table sys_dict_data operations. + SysDictData = sysDictDataDao{ + internal.NewSysDictDataDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_dict_type.go b/internal/dao/sys_dict_type.go new file mode 100644 index 0000000..291bc48 --- /dev/null +++ b/internal/dao/sys_dict_type.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysDictTypeDao is internal type for wrapping internal DAO implements. +type internalSysDictTypeDao = *internal.SysDictTypeDao + +// sysDictTypeDao is the data access object for table sys_dict_type. +// You can define custom methods on it to extend its functionality as you wish. +type sysDictTypeDao struct { + internalSysDictTypeDao +} + +var ( + // SysDictType is globally public accessible object for table sys_dict_type operations. + SysDictType = sysDictTypeDao{ + internal.NewSysDictTypeDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_job.go b/internal/dao/sys_job.go new file mode 100644 index 0000000..068b6b0 --- /dev/null +++ b/internal/dao/sys_job.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysJobDao is internal type for wrapping internal DAO implements. +type internalSysJobDao = *internal.SysJobDao + +// sysJobDao is the data access object for table sys_job. +// You can define custom methods on it to extend its functionality as you wish. +type sysJobDao struct { + internalSysJobDao +} + +var ( + // SysJob is globally public accessible object for table sys_job operations. + SysJob = sysJobDao{ + internal.NewSysJobDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_login_log.go b/internal/dao/sys_login_log.go new file mode 100644 index 0000000..e933962 --- /dev/null +++ b/internal/dao/sys_login_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysLoginLogDao is internal type for wrapping internal DAO implements. +type internalSysLoginLogDao = *internal.SysLoginLogDao + +// sysLoginLogDao is the data access object for table sys_login_log. +// You can define custom methods on it to extend its functionality as you wish. +type sysLoginLogDao struct { + internalSysLoginLogDao +} + +var ( + // SysLoginLog is globally public accessible object for table sys_login_log operations. + SysLoginLog = sysLoginLogDao{ + internal.NewSysLoginLogDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_menu.go b/internal/dao/sys_menu.go new file mode 100644 index 0000000..3ef8f89 --- /dev/null +++ b/internal/dao/sys_menu.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysMenuDao is internal type for wrapping internal DAO implements. +type internalSysMenuDao = *internal.SysMenuDao + +// sysMenuDao is the data access object for table sys_menu. +// You can define custom methods on it to extend its functionality as you wish. +type sysMenuDao struct { + internalSysMenuDao +} + +var ( + // SysMenu is globally public accessible object for table sys_menu operations. + SysMenu = sysMenuDao{ + internal.NewSysMenuDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_menu_api.go b/internal/dao/sys_menu_api.go new file mode 100644 index 0000000..2de9297 --- /dev/null +++ b/internal/dao/sys_menu_api.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysMenuApiDao is internal type for wrapping internal DAO implements. +type internalSysMenuApiDao = *internal.SysMenuApiDao + +// sysMenuApiDao is the data access object for table sys_menu_api. +// You can define custom methods on it to extend its functionality as you wish. +type sysMenuApiDao struct { + internalSysMenuApiDao +} + +var ( + // SysMenuApi is globally public accessible object for table sys_menu_api operations. + SysMenuApi = sysMenuApiDao{ + internal.NewSysMenuApiDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_menu_button.go b/internal/dao/sys_menu_button.go new file mode 100644 index 0000000..eb83dcb --- /dev/null +++ b/internal/dao/sys_menu_button.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysMenuButtonDao is internal type for wrapping internal DAO implements. +type internalSysMenuButtonDao = *internal.SysMenuButtonDao + +// sysMenuButtonDao is the data access object for table sys_menu_button. +// You can define custom methods on it to extend its functionality as you wish. +type sysMenuButtonDao struct { + internalSysMenuButtonDao +} + +var ( + // SysMenuButton is globally public accessible object for table sys_menu_button operations. + SysMenuButton = sysMenuButtonDao{ + internal.NewSysMenuButtonDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_menu_column.go b/internal/dao/sys_menu_column.go new file mode 100644 index 0000000..5f6dcc4 --- /dev/null +++ b/internal/dao/sys_menu_column.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysMenuColumnDao is internal type for wrapping internal DAO implements. +type internalSysMenuColumnDao = *internal.SysMenuColumnDao + +// sysMenuColumnDao is the data access object for table sys_menu_column. +// You can define custom methods on it to extend its functionality as you wish. +type sysMenuColumnDao struct { + internalSysMenuColumnDao +} + +var ( + // SysMenuColumn is globally public accessible object for table sys_menu_column operations. + SysMenuColumn = sysMenuColumnDao{ + internal.NewSysMenuColumnDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_notifications.go b/internal/dao/sys_notifications.go new file mode 100644 index 0000000..58e2f71 --- /dev/null +++ b/internal/dao/sys_notifications.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysNotificationsDao is internal type for wrapping internal DAO implements. +type internalSysNotificationsDao = *internal.SysNotificationsDao + +// sysNotificationsDao is the data access object for table sys_notifications. +// You can define custom methods on it to extend its functionality as you wish. +type sysNotificationsDao struct { + internalSysNotificationsDao +} + +var ( + // SysNotifications is globally public accessible object for table sys_notifications operations. + SysNotifications = sysNotificationsDao{ + internal.NewSysNotificationsDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_oper_log.go b/internal/dao/sys_oper_log.go new file mode 100644 index 0000000..798abf4 --- /dev/null +++ b/internal/dao/sys_oper_log.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysOperLogDao is internal type for wrapping internal DAO implements. +type internalSysOperLogDao = *internal.SysOperLogDao + +// sysOperLogDao is the data access object for table sys_oper_log. +// You can define custom methods on it to extend its functionality as you wish. +type sysOperLogDao struct { + internalSysOperLogDao +} + +var ( + // SysOperLog is globally public accessible object for table sys_oper_log operations. + SysOperLog = sysOperLogDao{ + internal.NewSysOperLogDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_organization.go b/internal/dao/sys_organization.go new file mode 100644 index 0000000..b8cffaf --- /dev/null +++ b/internal/dao/sys_organization.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysOrganizationDao is internal type for wrapping internal DAO implements. +type internalSysOrganizationDao = *internal.SysOrganizationDao + +// sysOrganizationDao is the data access object for table sys_organization. +// You can define custom methods on it to extend its functionality as you wish. +type sysOrganizationDao struct { + internalSysOrganizationDao +} + +var ( + // SysOrganization is globally public accessible object for table sys_organization operations. + SysOrganization = sysOrganizationDao{ + internal.NewSysOrganizationDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_plugins.go b/internal/dao/sys_plugins.go new file mode 100644 index 0000000..4f80d32 --- /dev/null +++ b/internal/dao/sys_plugins.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysPluginsDao is internal type for wrapping internal DAO implements. +type internalSysPluginsDao = *internal.SysPluginsDao + +// sysPluginsDao is the data access object for table sys_plugins. +// You can define custom methods on it to extend its functionality as you wish. +type sysPluginsDao struct { + internalSysPluginsDao +} + +var ( + // SysPlugins is globally public accessible object for table sys_plugins operations. + SysPlugins = sysPluginsDao{ + internal.NewSysPluginsDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_plugins_config.go b/internal/dao/sys_plugins_config.go new file mode 100644 index 0000000..99fcbd1 --- /dev/null +++ b/internal/dao/sys_plugins_config.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysPluginsConfigDao is internal type for wrapping internal DAO implements. +type internalSysPluginsConfigDao = *internal.SysPluginsConfigDao + +// sysPluginsConfigDao is the data access object for table sys_plugins_config. +// You can define custom methods on it to extend its functionality as you wish. +type sysPluginsConfigDao struct { + internalSysPluginsConfigDao +} + +var ( + // SysPluginsConfig is globally public accessible object for table sys_plugins_config operations. + SysPluginsConfig = sysPluginsConfigDao{ + internal.NewSysPluginsConfigDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_post.go b/internal/dao/sys_post.go new file mode 100644 index 0000000..62eceda --- /dev/null +++ b/internal/dao/sys_post.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysPostDao is internal type for wrapping internal DAO implements. +type internalSysPostDao = *internal.SysPostDao + +// sysPostDao is the data access object for table sys_post. +// You can define custom methods on it to extend its functionality as you wish. +type sysPostDao struct { + internalSysPostDao +} + +var ( + // SysPost is globally public accessible object for table sys_post operations. + SysPost = sysPostDao{ + internal.NewSysPostDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_role.go b/internal/dao/sys_role.go new file mode 100644 index 0000000..599985f --- /dev/null +++ b/internal/dao/sys_role.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysRoleDao is internal type for wrapping internal DAO implements. +type internalSysRoleDao = *internal.SysRoleDao + +// sysRoleDao is the data access object for table sys_role. +// You can define custom methods on it to extend its functionality as you wish. +type sysRoleDao struct { + internalSysRoleDao +} + +var ( + // SysRole is globally public accessible object for table sys_role operations. + SysRole = sysRoleDao{ + internal.NewSysRoleDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_role_dept.go b/internal/dao/sys_role_dept.go new file mode 100644 index 0000000..ce95807 --- /dev/null +++ b/internal/dao/sys_role_dept.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysRoleDeptDao is internal type for wrapping internal DAO implements. +type internalSysRoleDeptDao = *internal.SysRoleDeptDao + +// sysRoleDeptDao is the data access object for table sys_role_dept. +// You can define custom methods on it to extend its functionality as you wish. +type sysRoleDeptDao struct { + internalSysRoleDeptDao +} + +var ( + // SysRoleDept is globally public accessible object for table sys_role_dept operations. + SysRoleDept = sysRoleDeptDao{ + internal.NewSysRoleDeptDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_user.go b/internal/dao/sys_user.go new file mode 100644 index 0000000..69f16cc --- /dev/null +++ b/internal/dao/sys_user.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysUserDao is internal type for wrapping internal DAO implements. +type internalSysUserDao = *internal.SysUserDao + +// sysUserDao is the data access object for table sys_user. +// You can define custom methods on it to extend its functionality as you wish. +type sysUserDao struct { + internalSysUserDao +} + +var ( + // SysUser is globally public accessible object for table sys_user operations. + SysUser = sysUserDao{ + internal.NewSysUserDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_user_online.go b/internal/dao/sys_user_online.go new file mode 100644 index 0000000..874be5d --- /dev/null +++ b/internal/dao/sys_user_online.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysUserOnlineDao is internal type for wrapping internal DAO implements. +type internalSysUserOnlineDao = *internal.SysUserOnlineDao + +// sysUserOnlineDao is the data access object for table sys_user_online. +// You can define custom methods on it to extend its functionality as you wish. +type sysUserOnlineDao struct { + internalSysUserOnlineDao +} + +var ( + // SysUserOnline is globally public accessible object for table sys_user_online operations. + SysUserOnline = sysUserOnlineDao{ + internal.NewSysUserOnlineDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_user_post.go b/internal/dao/sys_user_post.go new file mode 100644 index 0000000..188c6d5 --- /dev/null +++ b/internal/dao/sys_user_post.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysUserPostDao is internal type for wrapping internal DAO implements. +type internalSysUserPostDao = *internal.SysUserPostDao + +// sysUserPostDao is the data access object for table sys_user_post. +// You can define custom methods on it to extend its functionality as you wish. +type sysUserPostDao struct { + internalSysUserPostDao +} + +var ( + // SysUserPost is globally public accessible object for table sys_user_post operations. + SysUserPost = sysUserPostDao{ + internal.NewSysUserPostDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/dao/sys_user_role.go b/internal/dao/sys_user_role.go new file mode 100644 index 0000000..1f6dc15 --- /dev/null +++ b/internal/dao/sys_user_role.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "github.com/sagoo-cloud/sagooiot/internal/dao/internal" +) + +// internalSysUserRoleDao is internal type for wrapping internal DAO implements. +type internalSysUserRoleDao = *internal.SysUserRoleDao + +// sysUserRoleDao is the data access object for table sys_user_role. +// You can define custom methods on it to extend its functionality as you wish. +type sysUserRoleDao struct { + internalSysUserRoleDao +} + +var ( + // SysUserRole is globally public accessible object for table sys_user_role operations. + SysUserRole = sysUserRoleDao{ + internal.NewSysUserRoleDao(), + } +) + +// Fill with you ideas below. diff --git a/internal/logic/alarm/alarm_level.go b/internal/logic/alarm/alarm_level.go new file mode 100644 index 0000000..ecb8897 --- /dev/null +++ b/internal/logic/alarm/alarm_level.go @@ -0,0 +1,55 @@ +package alarm + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/frame/g" +) + +type sAlarmLevel struct{} + +func init() { + service.RegisterAlarmLevel(alarmLevelNew()) +} + +func alarmLevelNew() *sAlarmLevel { + return &sAlarmLevel{} +} + +func (s *sAlarmLevel) Detail(ctx context.Context, level uint) (out model.AlarmLevelOutput, err error) { + err = dao.AlarmLevel.Ctx(ctx).Where(dao.AlarmLevel.Columns().Level, level).Scan(&out) + return +} + +func (s *sAlarmLevel) All(ctx context.Context) (out *model.AlarmLevelListOutput, err error) { + var p []*entity.AlarmLevel + + err = dao.AlarmLevel.Ctx(ctx).Scan(&p) + if err != nil || p == nil { + return + } + + out = new(model.AlarmLevelListOutput) + out.List = p + + return +} + +func (s *sAlarmLevel) Edit(ctx context.Context, in []*model.AlarmLevelEditInput) (err error) { + for _, v := range in { + _, err = dao.AlarmLevel.Ctx(ctx).Data(g.Map{ + "name": v.Name, + }). + Where(dao.AlarmLevel.Columns().Level, v.Level). + Update() + if err != nil { + return + } + } + + return +} diff --git a/internal/logic/alarm/alarm_log.go b/internal/logic/alarm/alarm_log.go new file mode 100644 index 0000000..86f9fe0 --- /dev/null +++ b/internal/logic/alarm/alarm_log.go @@ -0,0 +1,106 @@ +package alarm + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + + "github.com/gogf/gf/v2/frame/g" +) + +type sAlarmLog struct{} + +func init() { + service.RegisterAlarmLog(alarmLogNew()) +} + +func alarmLogNew() *sAlarmLog { + return &sAlarmLog{} +} + +func (s *sAlarmLog) Detail(ctx context.Context, id uint64) (out *model.AlarmLogOutput, err error) { + err = dao.AlarmLog.Ctx(ctx).WithAll().Where(dao.AlarmLog.Columns().Id, id).Scan(&out) + return +} + +func (s *sAlarmLog) Add(ctx context.Context, in *model.AlarmLogAddInput) (id uint64, err error) { + rs, err := dao.AlarmLog.Ctx(ctx).Data(in).Insert() + if err != nil { + return + } + newId, err := rs.LastInsertId() + id = uint64(newId) + return +} + +func (s *sAlarmLog) List(ctx context.Context, in *model.AlarmLogListInput) (out *model.AlarmLogListOutput, err error) { + out = new(model.AlarmLogListOutput) + c := dao.AlarmLog.Columns() + m := dao.AlarmLog.Ctx(ctx).WithAll().OrderDesc(c.Id) + + if len(in.DateRange) > 0 { + m = m.WhereBetween(c.CreatedAt, in.DateRange[0], in.DateRange[1]) + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + err = m.Page(in.PageNum, in.PageSize).Scan(&out.List) + return +} + +func (s *sAlarmLog) Handle(ctx context.Context, in *model.AlarmLogHandleInput) (err error) { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + c := dao.AlarmLog.Columns() + _, err = dao.AlarmLog.Ctx(ctx).Data(g.Map{ + c.Status: in.Status, + c.UpdateBy: loginUserId, + c.Content: in.Content, + }).Where(c.Id, in.Id).Update() + + return +} + +func (s *sAlarmLog) TotalForLevel(ctx context.Context) (total []model.AlarmLogLevelTotal, err error) { + rs, err := dao.AlarmLog.Ctx(ctx).Fields("level, count(*) as num").Group(dao.AlarmLevel.Columns().Level).All() + if err != nil || rs.Len() == 0 { + return + } + + level, err := service.AlarmLevel().All(ctx) + if err != nil { + return + } + l := make(map[uint]string, len(level.List)) + for _, v := range level.List { + l[v.Level] = v.Name + } + + logTotal := 0 + for _, v := range rs { + logTotal += v["num"].Int() + + total = append(total, model.AlarmLogLevelTotal{ + Level: v["level"].Uint(), + Name: l[v["level"].Uint()], + Num: v["num"].Int(), + }) + } + + for k, v := range total { + n, _ := strconv.ParseFloat(fmt.Sprintf("%.0f", float64(v.Num)/float64(logTotal)*100), 64) + total[k].Ratio = n + } + + return +} + +//ClearLogByDays 按日期删除日志 +func (s *sAlarmLog) ClearLogByDays(ctx context.Context, days int) (err error) { + _, err = dao.AlarmLog.Ctx(ctx).Delete("to_days(now())-to_days(`created_at`) > ?", days+1) + return +} diff --git a/internal/logic/alarm/alarm_log_test.go b/internal/logic/alarm/alarm_log_test.go new file mode 100644 index 0000000..7556916 --- /dev/null +++ b/internal/logic/alarm/alarm_log_test.go @@ -0,0 +1,26 @@ +package alarm + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" +) + +func TestAddLog(t *testing.T) { + log := &model.AlarmLogAddInput{ + Type: 1, + RuleId: 1, + RuleName: "告警规则1--", + Level: 4, + Data: `{"ts":"2022-11-06 11:00:00","pr1":92,"pr2":98,"pr3":89}`, + ProductKey: "aoxiang", + DeviceKey: "device1", + } + _, err := service.AlarmLog().Add(context.TODO(), log) + if err != nil { + t.Fatal(err) + } +} diff --git a/internal/logic/alarm/alarm_rule.go b/internal/logic/alarm/alarm_rule.go new file mode 100644 index 0000000..4954dfa --- /dev/null +++ b/internal/logic/alarm/alarm_rule.go @@ -0,0 +1,303 @@ +package alarm + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sAlarmRule struct{} + +func init() { + service.RegisterAlarmRule(alarmRuleNew()) +} + +func alarmRuleNew() *sAlarmRule { + return &sAlarmRule{} +} + +func (s *sAlarmRule) List(ctx context.Context, in *model.AlarmRuleListInput) (out *model.AlarmRuleListOutput, err error) { + out = new(model.AlarmRuleListOutput) + c := dao.AlarmRule.Columns() + m := dao.AlarmRule.Ctx(ctx).WithAll().OrderDesc(c.Id) + + if len(in.DateRange) > 0 { + m = m.WhereBetween(c.CreatedAt, in.DateRange[0], in.DateRange[1]) + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + err = m.Page(in.PageNum, in.PageSize).Scan(&out.List) + if err != nil { + return + } + for i, v := range out.List { + out.List[i].TriggerTypeName = model.AlarmTriggerType[v.TriggerType] + } + + return +} + +func (s *sAlarmRule) Cache(ctx context.Context) (rs map[string][]model.AlarmRuleOutput, err error) { + key := "alarm:rule" + tag := "alarm" + value := common.Cache().GetOrSetFunc(ctx, key, func(ctx context.Context) (value interface{}, err error) { + var list []model.AlarmRuleOutput + err = dao.AlarmRule.Ctx(ctx).WithAll(). + Where(dao.AlarmRule.Columns().Status, 1). + OrderDesc(dao.AlarmRule.Columns().Id). + Scan(&list) + if err != nil || len(list) == 0 { + return + } + + rs := make(map[string][]model.AlarmRuleOutput) + for _, v := range list { + if v.TriggerCondition != "" { + err = json.Unmarshal([]byte(v.TriggerCondition), &v.Condition) + } + if v.Action != "" { + err = json.Unmarshal([]byte(v.Action), &v.PerformAction) + } + rs[v.ProductKey] = append(rs[v.ProductKey], v) + } + value = rs + return + }, 0, tag) + + data := gconv.Map(value) + rs = make(map[string][]model.AlarmRuleOutput, len(data)) + for k, v := range data { + var t []model.AlarmRuleOutput + if err = gconv.Scan(v, &t); err == nil { + rs[k] = t + } + } + return +} +func (s *sAlarmRule) delCache(ctx context.Context) { + key := "alarm:rule" + common.Cache().Remove(ctx, key) +} + +func (s *sAlarmRule) Detail(ctx context.Context, id uint64) (out *model.AlarmRuleOutput, err error) { + err = dao.AlarmRule.Ctx(ctx).WithAll().Where(dao.AlarmRule.Columns().Id, id).Scan(&out) + if err != nil || out == nil { + return + } + out.TriggerTypeName = model.AlarmTriggerType[out.TriggerType] + + if out.TriggerCondition != "" { + err = json.Unmarshal([]byte(out.TriggerCondition), &out.Condition) + } + if out.Action != "" { + err = json.Unmarshal([]byte(out.Action), &out.PerformAction) + } + return +} + +func (s *sAlarmRule) Add(ctx context.Context, in *model.AlarmRuleAddInput) (err error) { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.AlarmRule + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + param.TriggerCondition, _ = json.Marshal(in.AlarmTriggerCondition) + param.Action, _ = json.Marshal(in.AlarmPerformAction) + + _, err = dao.AlarmRule.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + s.delCache(ctx) + + return +} + +func (s *sAlarmRule) Edit(ctx context.Context, in *model.AlarmRuleEditInput) (err error) { + p, err := s.Detail(ctx, in.Id) + if err != nil { + return err + } + if p == nil { + err = gerror.New("告警规则不存在") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.AlarmRule + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.Id = nil + param.TriggerCondition, _ = json.Marshal(in.AlarmTriggerCondition) + param.Action, _ = json.Marshal(in.AlarmPerformAction) + + _, err = dao.AlarmRule.Ctx(ctx).Data(param).Where(dao.AlarmRule.Columns().Id, in.Id).Update() + if err != nil { + return + } + s.delCache(ctx) + + return +} + +func (s *sAlarmRule) Deploy(ctx context.Context, id uint64) (err error) { + var p *entity.AlarmRule + err = dao.AlarmRule.Ctx(ctx).Where(dao.AlarmRule.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil || p.Status == model.AlarmRuleStatusOn { + err = gerror.New("告警规则不存在,或已启用") + return + } + + _, err = dao.AlarmRule.Ctx(ctx). + Data(g.Map{dao.AlarmRule.Columns().Status: model.AlarmRuleStatusOn}). + Where(dao.AlarmRule.Columns().Id, id). + Update() + if err != nil { + return + } + s.delCache(ctx) + + return +} + +func (s *sAlarmRule) Undeploy(ctx context.Context, id uint64) (err error) { + var p *entity.AlarmRule + err = dao.AlarmRule.Ctx(ctx).Where(dao.AlarmRule.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil || p.Status == model.AlarmRuleStatusOff { + err = gerror.New("告警规则不存在,或已禁用") + return + } + + _, err = dao.AlarmRule.Ctx(ctx). + Data(g.Map{dao.AlarmRule.Columns().Status: model.AlarmRuleStatusOff}). + Where(dao.AlarmRule.Columns().Id, id). + Update() + if err != nil { + return + } + s.delCache(ctx) + + return +} + +func (s *sAlarmRule) Del(ctx context.Context, id uint64) (err error) { + var p *entity.AlarmRule + err = dao.AlarmRule.Ctx(ctx).Where(dao.AlarmRule.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil { + err = gerror.New("告警规则不存在") + return + } + if p.Status == model.AlarmRuleStatusOn { + err = gerror.New("告警规则已启用,请先禁用,再删除") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + _, err = dao.AlarmRule.Ctx(ctx). + Data(do.AlarmRule{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.AlarmRule.Columns().Id, id). + Where(dao.AlarmRule.Columns().Status, model.AlarmRuleStatusOff). + Unscoped(). + Update() + if err != nil { + return + } + s.delCache(ctx) + + return +} + +func (s *sAlarmRule) Operator(ctx context.Context) (out []model.OperatorOutput, err error) { + out = []model.OperatorOutput{ + {Title: "等于", Type: model.OperatorEq}, + {Title: "不等于", Type: model.OperatorNe}, + {Title: "大于", Type: model.OperatorGt}, + {Title: "大于等于", Type: model.OperatorGte}, + {Title: "小于", Type: model.OperatorLt}, + {Title: "小于等于", Type: model.OperatorLte}, + {Title: "在...之间", Type: model.OperatorBet}, + {Title: "不在...之间", Type: model.OperatorNbet}, + } + return +} + +func (s *sAlarmRule) TriggerType(ctx context.Context, productKey string) (out []model.TriggerTypeOutput, err error) { + out = []model.TriggerTypeOutput{ + {Title: model.AlarmTriggerType[model.AlarmTriggerTypeOnline], Type: model.AlarmTriggerTypeOnline}, + {Title: model.AlarmTriggerType[model.AlarmTriggerTypeOffline], Type: model.AlarmTriggerTypeOffline}, + } + + product, err := service.DevProduct().Get(ctx, productKey) + if err != nil || product == nil { + return + } + if product.TSL != nil { + switch { + case len(product.TSL.Properties) > 0: + out = append(out, model.TriggerTypeOutput{ + Title: model.AlarmTriggerType[model.AlarmTriggerTypeProperty], Type: model.AlarmTriggerTypeProperty, + }) + } + } + + return +} + +func (s *sAlarmRule) TriggerParam(ctx context.Context, productKey string) (out []model.TriggerParamOutput, err error) { + out = []model.TriggerParamOutput{ + // {Title: "系统时间", ParamKey: "sysTime"}, + {Title: "上报时间", ParamKey: "sysReportTime"}, + } + + product, err := service.DevProduct().Get(ctx, productKey) + if err != nil || product == nil { + return + } + if product.TSL != nil { + switch { + case len(product.TSL.Properties) > 0: + for _, v := range product.TSL.Properties { + out = append(out, model.TriggerParamOutput{ + Title: v.Name, ParamKey: v.Key, + }) + } + } + } + + return +} diff --git a/internal/logic/alarm/alarm_rule_check.go b/internal/logic/alarm/alarm_rule_check.go new file mode 100644 index 0000000..b555611 --- /dev/null +++ b/internal/logic/alarm/alarm_rule_check.go @@ -0,0 +1,298 @@ +package alarm + +import ( + "context" + "encoding/json" + "fmt" + "github.com/sagoo-cloud/sagooiot/extend" + extModel "github.com/sagoo-cloud/sagooiot/extend/model" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/notifier" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "strconv" + "time" + + "github.com/Knetic/govaluate" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// 告警匹配检测 +func (s *sAlarmRule) Check(ctx context.Context, productKey string, deviceKey string, data map[string]any) (err error) { + list, err := s.Cache(ctx) + if err != nil { + g.Log().Errorf(ctx, "告警规则缓存获取 - %s - %s:%s", productKey, deviceKey, err) + return + } + if len(list) == 0 { + return + } + pList, ok := list[productKey] + if !ok { + return + } + + logData, err := json.Marshal(data) + if err != nil { + g.Log().Errorf(ctx, "告警规则数据 - %s - %s:%s", productKey, deviceKey, err) + return + } + + // 填充告警触发时间 + if ts, ok := data["ts"]; ok { + if t, err := time.Parse("2006-01-02 15:04:05", ts.(string)); err == nil { + data["ts"] = t.Unix() + } + } else { + data["ts"] = time.Now().Unix() + } + + for _, rule := range pList { + if rule.DeviceKey == deviceKey { + go func(rule model.AlarmRuleOutput) { + exp := s.expression(ctx, rule) + if exp != "" { + gov, err := govaluate.NewEvaluableExpression(exp) + if err != nil { + g.Log().Errorf(ctx, "告警表达式 - %s - %s - %s:%s", productKey, deviceKey, exp, err) + return + } + if gov == nil { + return + } + rs, err := gov.Evaluate(data) + if err != nil { + g.Log().Errorf(ctx, "告警表达式参数 - %s - %s:%s - %v", productKey, deviceKey, err, data) + return + } + if rs == nil { + return + } + if y, ok := rs.(bool); ok && y { + log := &model.AlarmLogAddInput{ + Type: 1, + RuleId: rule.Id, + RuleName: rule.Name, + Level: rule.Level, + Data: string(logData), + ProductKey: productKey, + DeviceKey: deviceKey, + } + logId, err := service.AlarmLog().Add(ctx, log) + if err != nil { + g.Log().Errorf(ctx, "告警日志写入 - %s - %s:%s", productKey, deviceKey, err) + return + } + + // 触发告警通知 + nt := notifier.NewNotifier(3 * time.Second) + nt.SetCallbacks( + func(state notifier.State) { + s.doAction(ctx, rule, exp) + }, + func(state notifier.State) { + s.doAction(ctx, rule, exp) + }, + func(state notifier.State) { + s.doAction(ctx, rule, exp) + }) + // 频率控制 + i := 0 + for { + i++ + if i == 6 || i == 12 { + alarmLog, _ := service.AlarmLog().Detail(ctx, logId) + if alarmLog == nil { + break + } + // 告警未处理,触发通知 + if alarmLog.Status == model.AlarmLogStatusUnhandle { + nt.Trigger(true) + } + } + if i == 9 || i == 15 { + alarmLog, _ := service.AlarmLog().Detail(ctx, logId) + if alarmLog == nil { + break + } + // 告警已处理或忽略,停止触发通知 + if alarmLog.Status == model.AlarmLogStatusHandle || + alarmLog.Status == model.AlarmLogStatusIgnore { + nt.Trigger(false) + } + } + + time.Sleep(1 * time.Second) + if i > 20 { + break + } + } + } + } + }(rule) + } + } + return +} + +// 告警执行动作 +func (s *sAlarmRule) doAction(ctx context.Context, rule model.AlarmRuleOutput, expression string) { + if len(rule.PerformAction.Action) == 0 { + return + } + + for _, v := range rule.PerformAction.Action { + if v.NoticeTemplate == "" { + continue + } + + // 获取告警模板 + tpl, err := service.NoticeTemplate().GetNoticeTemplateById(ctx, v.NoticeTemplate) + if err != nil { + g.Log().Errorf(ctx, "告警获取通知模板 - %s :%s", v.NoticeTemplate, err) + continue + } + if tpl == nil { + continue + } + + // 获取告警级别名称 + level, err := service.AlarmLevel().Detail(ctx, rule.Level) + if err != nil { + g.Log().Errorf(ctx, "告警获取级别名称 - %s :%s", v.NoticeTemplate, err) + } + + // 获取设备、产品名称 + var ( + pname string + dname string + ) + d, err := service.DevDevice().Get(ctx, rule.DeviceKey) + if err != nil { + g.Log().Errorf(ctx, "告警获取设备信息 - %s :%s", rule.DeviceKey, err) + } + if d != nil { + pname = d.Product.Name + dname = d.Name + } + + // 模板解析 + content, err := utils.ReplaceTemplate(tpl.Content, map[string]any{ + "Level": level.Name, + "Product": pname, + "Device": dname, + "Rule": rule.Name + " " + expression, + }) + if err != nil { + g.Log().Errorf(ctx, "告警模板解析 - %s :%s", v.NoticeTemplate, err) + } + + // 告警消息发送 + var msg = extModel.NoticeInfoData{} + msg.MsgTitle = tpl.Title + msg.MsgBody = content + + for _, u := range v.Addressee { + if extend.GetNoticePlugin() != nil { + msg.Totag = fmt.Sprintf(`[{"name":"%s","value":"%s"}]`, tpl.SendGateway, u) + noticeStatus := 1 + noticeFail := "" + _, err = extend.GetNoticePlugin().NoticeSend(tpl.SendGateway, msg) + if err != nil { + noticeStatus = 0 + noticeFail = err.Error() + g.Log().Errorf(ctx, "告警通知发送 - %s :%s", tpl.SendGateway, err) + } + + // 通知日志记录 + if err = service.NoticeLog().Add(ctx, &model.NoticeLogAddInput{ + TemplateId: tpl.Id, + SendGateway: tpl.SendGateway, + Addressee: u, + Title: tpl.Title, + Content: content, + Status: noticeStatus, + FailMsg: noticeFail, + SendTime: gtime.Now().String(), + }); err != nil { + g.Log().Errorf(ctx, "告警通知日志记录:%v", err) + } + } + } + } +} + +// 告警条件表达式生成 +func (s *sAlarmRule) expression(ctx context.Context, rule model.AlarmRuleOutput) string { + glen := len(rule.Condition.TriggerCondition) + var exp string + for _, group := range rule.Condition.TriggerCondition { + flen := len(group.Filters) + var gexp string + for _, v := range group.Filters { + if (v.Operator == model.OperatorBet || + v.Operator == model.OperatorNbet) && len(v.Value) < 2 { + continue + } + + // 如果条件参数是上报时间,则将参数值转换成时间戳 + if v.Key == "sysReportTime" { + v.Key = "ts" + if v.Value[0] != "" { + if t, err := time.Parse("2006-01-02 15:04:05", v.Value[0]); err == nil { + v.Value[0] = strconv.FormatInt(t.Unix(), 10) + } + } + if len(v.Value) > 1 && v.Value[1] != "" { + if t, err := time.Parse("2006-01-02 15:04:05", v.Value[1]); err == nil { + v.Value[1] = strconv.FormatInt(t.Unix(), 10) + } + } + } + + // 表达式生成 + var fexp string + switch v.Operator { + case model.OperatorEq: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, "=", v.Value[0]) + case model.OperatorNe: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, "!=", v.Value[0]) + case model.OperatorGt: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, ">", v.Value[0]) + case model.OperatorGte: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, ">=", v.Value[0]) + case model.OperatorLt: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, "<", v.Value[0]) + case model.OperatorLte: + fexp = fmt.Sprintf("(%s %s %s)", v.Key, "<=", v.Value[0]) + case model.OperatorBet: + fexp = fmt.Sprintf("(%s >= %s && %s <= %s)", v.Key, v.Value[0], v.Key, v.Value[1]) + case model.OperatorNbet: + fexp = fmt.Sprintf("(%s < %s && %s > %s)", v.Key, v.Value[0], v.Key, v.Value[1]) + } + if flen > 1 { + switch v.AndOr { + case 1: + fexp = " && " + fexp + case 2: + fexp = " || " + fexp + } + } + gexp += fexp + } + if flen > 1 { + gexp = "(" + gexp + ")" + } + if glen > 1 { + switch group.AndOr { + case 1: + gexp = " && " + gexp + case 2: + gexp = " || " + gexp + } + } + exp += gexp + } + return exp +} diff --git a/internal/logic/alarm/alarm_rule_check_test.go b/internal/logic/alarm/alarm_rule_check_test.go new file mode 100644 index 0000000..cfe9d05 --- /dev/null +++ b/internal/logic/alarm/alarm_rule_check_test.go @@ -0,0 +1,35 @@ +package alarm + +import ( + "context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/notice" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/product" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + "time" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + "github.com/gogf/gf/v2/os/gtime" +) + +func TestCheck(t *testing.T) { + productKey := "monipower20221103" + deviceKey := "t20221333" + data := map[string]any{ + "ts": gtime.Datetime(), + "va": 92.12, + } + err := service.AlarmRule().Check(context.TODO(), productKey, deviceKey, data) + if err != nil { + t.Fatal(err) + } + time.Sleep(10 * time.Second) +} + +func TestCache(t *testing.T) { + rs, err := service.AlarmRule().Cache(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(rs) +} diff --git a/internal/logic/common/base_db_link.go b/internal/logic/common/base_db_link.go new file mode 100644 index 0000000..5a8dac1 --- /dev/null +++ b/internal/logic/common/base_db_link.go @@ -0,0 +1,170 @@ +package common + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sBaseDbLink struct { +} + +func BaseDbLink() *sBaseDbLink { + return &sBaseDbLink{} +} + +func init() { + service.RegisterBaseDbLink(BaseDbLink()) +} + +// GetList 获取数据源数据列表 +func (s *sBaseDbLink) GetList(ctx context.Context, input *model.BaseDbLinkDoInput) (total int, out []*model.BaseDbLinkOut, err error) { + m := dao.BaseDbLink.Ctx(ctx) + if input.Host != "" { + m = m.WhereLike(dao.BaseDbLink.Columns().Host, "%"+input.Host+"%") + } + if input.Name != "" { + m = m.WhereLike(dao.BaseDbLink.Columns().Name, "%"+input.Name+"%") + } + if input.Types != "" { + m = m.WhereLike(dao.BaseDbLink.Columns().Types, "%"+input.Types+"%") + } + if input.Port != "" { + m = m.WhereLike(dao.BaseDbLink.Columns().Port, "%"+input.Port+"%") + } + if input.UserName != "" { + m = m.WhereLike(dao.BaseDbLink.Columns().UserName, "%"+input.UserName+"%") + } + if input.Status != -1 { + m = m.Where(dao.BaseDbLink.Columns().Status, input.Status) + } + m = m.Where(dao.BaseDbLink.Columns().IsDeleted, 0) + //获取总数 + total, err = m.Count() + if err != nil { + err = gerror.New("获取数据源列表数据失败") + return + } + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.DefaultPageSize + } + //获取数据源列表信息 + err = m.Page(input.PageNum, input.PageSize).OrderDesc(dao.BaseDbLink.Columns().CreatedAt).Scan(&out) + if err != nil { + err = gerror.New("获取数据源列表失败") + return + } + return +} + +// Add 添加数据源 +func (s *sBaseDbLink) Add(ctx context.Context, input *model.AddBaseDbLinkInput) (err error) { + var baseDbLink *entity.BaseDbLink + //根据名称查看角色是否存在 + baseDbLink = checkBaseDbLinkName(ctx, input.Name, baseDbLink, 0) + if baseDbLink != nil { + return gerror.New("数据源已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + baseDbLink = new(entity.BaseDbLink) + if err := gconv.Scan(input, &baseDbLink); err != nil { + return err + } + baseDbLink.IsDeleted = 0 + baseDbLink.CreatedBy = uint(loginUserId) + _, err = dao.BaseDbLink.Ctx(ctx).Data(baseDbLink).Insert() + if err != nil { + return err + } + return +} + +// Detail 数据源详情 +func (s *sBaseDbLink) Detail(ctx context.Context, baseDbLinkId int) (entity *entity.BaseDbLink, err error) { + _ = dao.BaseDbLink.Ctx(ctx).Where(g.Map{ + dao.BaseDbLink.Columns().Id: baseDbLinkId, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// Edit 修改数据源 +func (s *sBaseDbLink) Edit(ctx context.Context, input *model.EditBaseDbLinkInput) (err error) { + var baseDbLink, BaseDbLink2 *entity.BaseDbLink + //根据ID查看数据源是否存在 + baseDbLink = checkBaseDbLinkId(ctx, input.Id, baseDbLink) + if baseDbLink == nil { + return gerror.New("数据源不存在") + } + BaseDbLink2 = checkBaseDbLinkName(ctx, input.Name, BaseDbLink2, input.Id) + if BaseDbLink2 != nil { + return gerror.New("相同数据源已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &baseDbLink); err != nil { + return err + } + baseDbLink.UpdatedBy = int(uint(loginUserId)) + _, err = dao.BaseDbLink.Ctx(ctx).Data(baseDbLink). + Where(dao.BaseDbLink.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + return +} + +// 检查相同数据源名称的数据是否存在 +func checkBaseDbLinkName(ctx context.Context, BaseDbLinkName string, BaseDbLink *entity.BaseDbLink, tag int) *entity.BaseDbLink { + m := dao.BaseDbLink.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.BaseDbLink.Columns().Id, tag) + } + _ = m.Where(g.Map{ + dao.BaseDbLink.Columns().Name: BaseDbLinkName, + dao.BaseDbLink.Columns().IsDeleted: 0, + }).Scan(&BaseDbLink) + return BaseDbLink +} + +// 检查指定ID的数据是否存在 +func checkBaseDbLinkId(ctx context.Context, BaseDbLinkId int, BaseDbLink *entity.BaseDbLink) *entity.BaseDbLink { + _ = dao.BaseDbLink.Ctx(ctx).Where(g.Map{ + dao.BaseDbLink.Columns().Id: BaseDbLinkId, + dao.BaseDbLink.Columns().IsDeleted: 0, + }).Scan(&BaseDbLink) + return BaseDbLink +} + +// Del 根据ID删除数据源信息 +func (s *sBaseDbLink) Del(ctx context.Context, BaseDbLinkId int) (err error) { + var BaseDbLink *entity.BaseDbLink + _ = dao.BaseDbLink.Ctx(ctx).Where(g.Map{ + dao.BaseDbLink.Columns().Id: BaseDbLinkId, + }).Scan(&BaseDbLink) + if BaseDbLink == nil { + return gerror.New("ID错误") + } + loginUserId := service.Context().GetUserId(ctx) + //删除数据源信息 + _, err = dao.BaseDbLink.Ctx(ctx). + Data(g.Map{ + dao.BaseDbLink.Columns().DeletedBy: uint(loginUserId), + dao.BaseDbLink.Columns().IsDeleted: 1, + }).Where(dao.BaseDbLink.Columns().Id, BaseDbLinkId). + Delete() + return +} diff --git a/internal/logic/common/cache.go b/internal/logic/common/cache.go new file mode 100644 index 0000000..e349c19 --- /dev/null +++ b/internal/logic/common/cache.go @@ -0,0 +1,53 @@ +/* +* @desc:缓存处理 + */ + +package common + +import ( + "github.com/sagoo-cloud/sagooiot/internal/consts" + "sync" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/tiger1103/gfast-cache/cache" +) + +type ICache interface { + cache.IGCache +} + +type cacheImpl struct { + *cache.GfCache + prefix string +} + +var ( + c = cacheImpl{} + cacheContainer *cache.GfCache + lock = &sync.Mutex{} +) + +func Cache() ICache { + var ( + ch = c + ctx = gctx.New() + ) + prefix := g.Cfg().MustGet(ctx, "system.cache.prefix").String() + model := g.Cfg().MustGet(ctx, "system.cache.model").String() + if cacheContainer == nil { + lock.Lock() + if cacheContainer == nil { + if model == consts.CacheModelRedis { + // redis + cacheContainer = cache.NewRedis(prefix) + } else { + // memory + cacheContainer = cache.New(prefix) + } + } + lock.Unlock() + } + ch.GfCache = cacheContainer + return &ch +} diff --git a/internal/logic/common/city_data.go b/internal/logic/common/city_data.go new file mode 100644 index 0000000..1f90ceb --- /dev/null +++ b/internal/logic/common/city_data.go @@ -0,0 +1,178 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sCityData struct { +} + +func CityData() *sCityData { + return &sCityData{} +} + +func init() { + service.RegisterCityData(CityData()) +} + +// GetList 获取城市列表 +func (s *sCityData) GetList(ctx context.Context, status int, name string, code string) (data []*entity.CityData, err error) { + m := dao.CityData.Ctx(ctx) + if status != -1 { + m = m.Where(dao.CityData.Columns().Status, status) + } + if name != "" { + m = m.Where(dao.CityData.Columns().Name, name) + } + if code != "" { + m = m.Where(dao.CityData.Columns().Code, code) + } + m = m.Where(dao.CityData.Columns().IsDeleted, 0).OrderAsc(dao.CityData.Columns().Sort) + + //获取城市列表信息 + err = m.Scan(&data) + if err != nil { + err = gerror.New("获取城市列表失败") + return + } + return +} + +// Add 添加城市 +func (s *sCityData) Add(ctx context.Context, city *entity.CityData) (err error) { + err = dao.CityData.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + //根据名字查询城市是否存在 + num, _ := dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Name: city.Name, + dao.CityData.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return gerror.New("城市已存在") + } + //根据Code查询城市是否存在 + codeNum, _ := dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Code: city.Code, + dao.CityData.Columns().IsDeleted: 0, + }).Count() + if codeNum > 0 { + return gerror.New("编码已存在") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + city.CreatedBy = uint(loginUserId) + city.IsDeleted = 0 + _, addErr := dao.CityData.Ctx(ctx).Data(city).Insert() + if addErr != nil { + err = gerror.New("添加失败") + return err + } + return err + }) + + return +} + +// Edit 编辑城市 +func (s *sCityData) Edit(ctx context.Context, city *entity.CityData) (err error) { + //根据ID查询城市是否存在 + var cityInfo *entity.CityData + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Id: city.Id, + dao.CityData.Columns().IsDeleted: 0, + }).Scan(&cityInfo) + if cityInfo == nil { + return gerror.New("ID错误") + } + var cityInfoByName *entity.CityData + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Name: city.Name, + dao.CityData.Columns().IsDeleted: 0, + }).Scan(&cityInfoByName) + if cityInfoByName != nil && cityInfoByName.Id != city.Id { + return gerror.New("编码已存在") + } + var cityInfoByCode *entity.CityData + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Code: city.Code, + dao.CityData.Columns().IsDeleted: 0, + }).Scan(&cityInfoByCode) + if cityInfoByCode != nil && cityInfoByCode.Id != city.Id { + return gerror.New("编码已存在") + } + + err = dao.CityData.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + cityInfo.UpdatedBy = uint(loginUserId) + cityInfo.Status = city.Status + cityInfo.Sort = city.Sort + cityInfo.ParentId = city.ParentId + cityInfo.Name = city.Name + cityInfo.Code = city.Code + _, err = dao.CityData.Ctx(ctx).Data(cityInfo).Where(dao.CityData.Columns().Id, city.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + return err + }) + + return +} + +// GetInfoById 根据ID获取城市 +func (s *sCityData) GetInfoById(ctx context.Context, id int) (cityInfo *entity.CityData, err error) { + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Id: id, + }).Scan(&cityInfo) + return +} + +// DelById 删除城市 +func (s *sCityData) DelById(ctx context.Context, id int) (err error) { + //根据ID查询城市是否存在 + var cityInfo *entity.CityData + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Id: id, + dao.CityData.Columns().IsDeleted: 0, + }).Scan(&cityInfo) + if cityInfo == nil { + return gerror.New("ID错误") + } + //判断是否存在子节点 + childrenNum, err := dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().ParentId: id, + dao.CityData.Columns().IsDeleted: 0, + }).Count() + if childrenNum > 0 { + return gerror.New("请先删除子节点") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + cityInfo.DeletedBy = loginUserId + cityInfo.IsDeleted = 1 + //获取当前时间 + t, err := gtime.StrToTimeFormat(gtime.Datetime(), "2006-01-02 15:04:05") + cityInfo.DeletedAt = t + _, err = dao.CityData.Ctx(ctx).Data(cityInfo).Where(dao.CityData.Columns().Id, id).Update() + if err != nil { + return gerror.New("删除失败") + } + return +} + +// GetAll 获取所有城市 +func (s *sCityData) GetAll(ctx context.Context) (data []*entity.CityData, err error) { + err = dao.CityData.Ctx(ctx).Where(g.Map{ + dao.CityData.Columns().Status: 1, + dao.CityData.Columns().IsDeleted: 0, + }).OrderAsc(dao.CityData.Columns().Sort).Scan(&data) + return +} diff --git a/internal/logic/common/config_data.go b/internal/logic/common/config_data.go new file mode 100644 index 0000000..99c7a98 --- /dev/null +++ b/internal/logic/common/config_data.go @@ -0,0 +1,165 @@ +package common + +import ( + "context" + "errors" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sConfigData struct { +} + +func sysConfigDataNew() *sConfigData { + return &sConfigData{} +} + +func init() { + service.RegisterConfigData(sysConfigDataNew()) +} + +// List 系统参数列表 +func (s *sConfigData) List(ctx context.Context, input *model.ConfigDoInput) (total int, out []*model.SysConfigOut, err error) { + m := dao.SysConfig.Ctx(ctx) + if input != nil { + if input.ConfigName != "" { + m = m.Where("config_name like ?", "%"+input.ConfigName+"%") + } + if input.ConfigType != "" { + m = m.Where("config_type = ", gconv.Int(input.ConfigType)) + } + if input.ConfigKey != "" { + m = m.Where("config_key like ?", "%"+input.ConfigKey+"%") + } + if len(input.DateRange) > 0 { + m = m.Where("created_at >= ? AND created_at<=?", input.DateRange[0], input.DateRange[1]) + } + } + total, err = m.Count() + liberr.ErrIsNil(ctx, err, "获取数据失败") + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.PageSize + } + err = m.Page(input.PageNum, input.PageSize).Order("config_id desc").Scan(&out) + liberr.ErrIsNil(ctx, err, "获取数据失败") + return +} + +func (s *sConfigData) Add(ctx context.Context, input *model.AddConfigInput, userId int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = s.CheckConfigKeyUnique(ctx, input.ConfigKey) + liberr.ErrIsNil(ctx, err) + _, err = dao.SysConfig.Ctx(ctx).Insert(do.SysConfig{ + ConfigName: input.ConfigName, + ConfigKey: input.ConfigKey, + ConfigValue: input.ConfigValue, + ConfigType: input.ConfigType, + CreateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, err, "添加系统参数失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysConfigTag) + }) + return +} + +// CheckConfigKeyUnique 验证参数键名是否存在 +func (s *sConfigData) CheckConfigKeyUnique(ctx context.Context, configKey string, configId ...int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + data := (*entity.SysConfig)(nil) + m := dao.SysConfig.Ctx(ctx).Fields(dao.SysConfig.Columns().ConfigId).Where(dao.SysConfig.Columns().ConfigKey, configKey) + if len(configId) > 0 { + m = m.Where(dao.SysConfig.Columns().ConfigId+" != ?", configId[0]) + } + err = m.Scan(&data) + liberr.ErrIsNil(ctx, err, "校验失败") + if data != nil { + liberr.ErrIsNil(ctx, errors.New("参数键名重复")) + } + }) + return +} + +// Get 获取系统参数 +func (s *sConfigData) Get(ctx context.Context, id int) (out *model.SysConfigOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = dao.SysConfig.Ctx(ctx).WherePri(id).Scan(&out) + liberr.ErrIsNil(ctx, err, "获取系统参数失败") + }) + return +} + +// Edit 修改系统参数 +func (s *sConfigData) Edit(ctx context.Context, input *model.EditConfigInput, userId int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = s.CheckConfigKeyUnique(ctx, input.ConfigKey, input.ConfigId) + liberr.ErrIsNil(ctx, err) + _, err = dao.SysConfig.Ctx(ctx).WherePri(input.ConfigId).Update(do.SysConfig{ + ConfigName: input.ConfigName, + ConfigKey: input.ConfigKey, + ConfigValue: input.ConfigValue, + ConfigType: input.ConfigType, + UpdateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, err, "修改系统参数失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysConfigTag) + }) + return +} + +// Delete 删除系统参数 +func (s *sConfigData) Delete(ctx context.Context, ids []int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.SysConfig.Ctx(ctx).Delete(dao.SysConfig.Columns().ConfigId+" in (?)", ids) + liberr.ErrIsNil(ctx, err, "删除失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysConfigTag) + }) + return +} + +// GetConfigByKey 通过key获取参数(从缓存获取) +func (s *sConfigData) GetConfigByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) { + if key == "" { + err = gerror.New("参数key不能为空") + return + } + cache := Cache() + cf := cache.Get(ctx, consts.CacheSysConfigTag+key) + if cf != nil && !cf.IsEmpty() { + err = gconv.Struct(cf, &config) + return + } + config, err = s.GetByKey(ctx, key) + if err != nil { + return + } + if config != nil { + cache.Set(ctx, consts.CacheSysConfigTag+key, config, 0, consts.CacheSysConfigTag) + } + return +} + +// GetByKey 通过key获取参数(从数据库获取) +func (s *sConfigData) GetByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) { + err = dao.SysConfig.Ctx(ctx).Where("config_key", key).Scan(&config) + if err != nil { + g.Log().Error(ctx, err) + err = gerror.New("获取配置失败") + } + return +} diff --git a/internal/logic/common/dict_data.go b/internal/logic/common/dict_data.go new file mode 100644 index 0000000..f7469b3 --- /dev/null +++ b/internal/logic/common/dict_data.go @@ -0,0 +1,160 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sDictData struct { +} + +func DictData() *sDictData { + return &sDictData{} +} + +func init() { + service.RegisterDictData(DictData()) +} + +// GetDictWithDataByType 通过字典键类型获取选项 +func (s *sDictData) GetDictWithDataByType(ctx context.Context, input *model.GetDictInput) (dict *model.GetDictOut, err error) { + cache := Cache() + cacheKey := consts.CacheSysDict + "_" + input.DictType + //从缓存获取 + iDict := cache.GetOrSetFuncLock(ctx, cacheKey, func(ctx context.Context) (value interface{}, err error) { + err = g.Try(ctx, func(ctx context.Context) { + //从数据库获取 + dict = &model.GetDictOut{} + //获取类型数据 + err = dao.SysDictType.Ctx(ctx).Where(dao.SysDictType.Columns().DictType, input.DictType). + Where(dao.SysDictType.Columns().Status, 1).Fields(model.DictTypeOut{}).Scan(&dict.Data) + liberr.ErrIsNil(ctx, err, "获取字典类型失败") + err = dao.SysDictData.Ctx(ctx).Fields(model.DictDataOut{}). + Where(dao.SysDictData.Columns().DictType, input.DictType). + Order(dao.SysDictData.Columns().DictSort + " asc," + + dao.SysDictData.Columns().DictCode + " asc"). + Scan(&dict.Values) + liberr.ErrIsNil(ctx, err, "获取字典数据失败") + }) + value = dict + return + }, 0, consts.CacheSysDictTag) + if iDict != nil { + err = gconv.Struct(iDict, &dict) + if err != nil { + return + } + } + //设置给定的默认值 + for _, v := range dict.Values { + if input.DefaultValue != "" { + if gstr.Equal(input.DefaultValue, v.DictValue) { + v.IsDefault = 1 + } else { + v.IsDefault = 0 + } + } + } + return +} + +// List 获取字典数据 +func (s *sDictData) List(ctx context.Context, input *model.SysDictSearchInput) (total int, out []*model.SysDictDataOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysDictData.Ctx(ctx) + if input != nil { + if input.DictLabel != "" { + m = m.Where(dao.SysDictData.Columns().DictLabel+" like ?", "%"+input.DictLabel+"%") + } + if input.Status != "-1" { + m = m.Where(dao.SysDictData.Columns().Status+" = ", gconv.Int(input.Status)) + } + if input.DictType != "" { + m = m.Where(dao.SysDictData.Columns().DictType+" = ?", input.DictType) + } + total, err = m.Count() + liberr.ErrIsNil(ctx, err, "获取字典数据失败") + if input.PageNum == 0 { + input.PageNum = 1 + } + } + if input.PageSize == 0 { + input.PageSize = consts.PageSize + } + err = m.Page(input.PageNum, input.PageSize).Order(dao.SysDictData.Columns().DictSort + " asc," + + dao.SysDictData.Columns().DictCode + " asc").Scan(&out) + liberr.ErrIsNil(ctx, err, "获取字典数据失败") + }) + return +} + +func (s *sDictData) Add(ctx context.Context, input *model.AddDictDataInput, userId int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.SysDictData.Ctx(ctx).Insert(do.SysDictData{ + DictSort: input.DictSort, + DictLabel: input.DictLabel, + DictValue: input.DictValue, + DictType: input.DictType, + CssClass: input.CssClass, + ListClass: input.ListClass, + IsDefault: input.IsDefault, + Status: input.Status, + CreateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, err, "添加字典数据失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return +} + +// Get 获取字典数据 +func (s *sDictData) Get(ctx context.Context, dictCode uint) (out *model.SysDictDataOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = dao.SysDictData.Ctx(ctx).WherePri(dictCode).Scan(&out) + liberr.ErrIsNil(ctx, err, "获取字典数据失败") + }) + return +} + +// Edit 修改字典数据 +func (s *sDictData) Edit(ctx context.Context, input *model.EditDictDataInput, userId int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.SysDictData.Ctx(ctx).WherePri(input.DictCode).Update(do.SysDictData{ + DictSort: input.DictSort, + DictLabel: input.DictLabel, + DictValue: input.DictValue, + DictType: input.DictType, + CssClass: input.CssClass, + ListClass: input.ListClass, + IsDefault: input.IsDefault, + Status: input.Status, + UpdateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, err, "修改字典数据失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return +} + +// Delete 删除字典数据 +func (s *sDictData) Delete(ctx context.Context, ids []int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.SysDictData.Ctx(ctx).Where(dao.SysDictData.Columns().DictCode+" in(?)", ids).Delete() + liberr.ErrIsNil(ctx, err, "删除字典数据失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return +} diff --git a/internal/logic/common/dict_type.go b/internal/logic/common/dict_type.go new file mode 100644 index 0000000..f62cd5e --- /dev/null +++ b/internal/logic/common/dict_type.go @@ -0,0 +1,158 @@ +package common + +import ( + "context" + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sDictType struct { +} + +func DictType() *sDictType { + return &sDictType{} +} + +func init() { + service.RegisterDictType(DictType()) +} + +// List 字典类型列表 +func (s *sDictType) List(ctx context.Context, input *model.DictTypeDoInput) (total int, out []*model.SysDictTypeInfoOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysDictType.Ctx(ctx) + if input.DictName != "" { + m = m.Where(dao.SysDictType.Columns().DictName+" like ?", "%"+input.DictName+"%") + } + if input.DictType != "" { + m = m.Where(dao.SysDictType.Columns().DictType+" like ?", "%"+input.DictType+"%") + } + if input.Status != "" { + m = m.Where(dao.SysDictType.Columns().Status+" = ", gconv.Int(input.Status)) + } + total, err = m.Count() + liberr.ErrIsNil(ctx, err, "获取字典类型失败") + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.PageSize + } + err = m.Fields(model.SysDictTypeInfoRes{}).Page(input.PageNum, input.PageSize). + Order(dao.SysDictType.Columns().DictId + " asc").Scan(&out) + liberr.ErrIsNil(ctx, err, "获取字典类型失败") + }) + return +} + +// Add 添加字典类型 +func (s *sDictType) Add(ctx context.Context, input *model.AddDictTypeInput, userId int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = s.ExistsDictType(ctx, input.DictType) + liberr.ErrIsNil(ctx, err) + _, err = dao.SysDictType.Ctx(ctx).Insert(do.SysDictType{ + DictName: input.DictName, + DictType: input.DictType, + Status: input.Status, + CreateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, err, "添加字典类型失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return +} + +// Edit 修改字典类型 +func (s *sDictType) Edit(ctx context.Context, input *model.EditDictTypeInput, userId int) (err error) { + err = g.DB().Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + err = g.Try(ctx, func(ctx context.Context) { + err = s.ExistsDictType(ctx, input.DictType, input.DictId) + liberr.ErrIsNil(ctx, err) + dictType := (*entity.SysDictType)(nil) + e := dao.SysDictType.Ctx(ctx).Fields(dao.SysDictType.Columns().DictType).WherePri(input.DictId).Scan(&dictType) + liberr.ErrIsNil(ctx, e, "获取字典类型失败") + liberr.ValueIsNil(dictType, "字典类型不存在") + //修改字典类型 + _, e = dao.SysDictType.Ctx(ctx).TX(tx).WherePri(input.DictId).Update(do.SysDictType{ + DictName: input.DictName, + DictType: input.DictType, + Status: input.Status, + UpdateBy: userId, + Remark: input.Remark, + }) + liberr.ErrIsNil(ctx, e, "修改字典类型失败") + //修改字典数据 + _, e = dao.SysDictData.Ctx(ctx).TX(tx).Data(do.SysDictData{DictType: input.DictType}). + Where(dao.SysDictData.Columns().DictType, dictType.DictType).Update() + liberr.ErrIsNil(ctx, e, "修改字典数据失败") + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return err + }) + return +} + +func (s *sDictType) Get(ctx context.Context, req *common.DictTypeGetReq) (dictType *model.SysDictTypeOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = dao.SysDictType.Ctx(ctx).Where(dao.SysDictType.Columns().DictId, req.DictId).Scan(&dictType) + liberr.ErrIsNil(ctx, err, "获取字典类型失败") + }) + return +} + +// ExistsDictType 检查类型是否已经存在 +func (s *sDictType) ExistsDictType(ctx context.Context, dictType string, dictId ...int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysDictType.Ctx(ctx).Fields(dao.SysDictType.Columns().DictId). + Where(dao.SysDictType.Columns().DictType, dictType) + if len(dictId) > 0 { + m = m.Where(dao.SysDictType.Columns().DictId+" !=? ", dictId[0]) + } + res, e := m.One() + liberr.ErrIsNil(ctx, e, "sql err") + if !res.IsEmpty() { + liberr.ErrIsNil(ctx, gerror.New("字典类型已存在")) + } + }) + return +} + +// Delete 删除字典类型 +func (s *sDictType) Delete(ctx context.Context, dictIds []int) (err error) { + err = g.DB().Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + err = g.Try(ctx, func(ctx context.Context) { + discs := ([]*entity.SysDictType)(nil) + err = dao.SysDictType.Ctx(ctx).Fields(dao.SysDictType.Columns().DictType). + Where(dao.SysDictType.Columns().DictId+" in (?) ", dictIds).Scan(&discs) + liberr.ErrIsNil(ctx, err, "删除失败") + types := garray.NewStrArray() + for _, dt := range discs { + types.Append(dt.DictType) + } + if types.Len() > 0 { + _, err = dao.SysDictType.Ctx(ctx).TX(tx).Delete(dao.SysDictType.Columns().DictId+" in (?) ", dictIds) + liberr.ErrIsNil(ctx, err, "删除类型失败") + _, err = dao.SysDictData.Ctx(ctx).TX(tx).Delete(dao.SysDictData.Columns().DictType+" in (?) ", types.Slice()) + liberr.ErrIsNil(ctx, err, "删除字典数据失败") + } + //清除缓存 + Cache().RemoveByTag(ctx, consts.CacheSysDictTag) + }) + return err + }) + return +} diff --git a/internal/logic/common/upload.go b/internal/logic/common/upload.go new file mode 100644 index 0000000..fbb3e01 --- /dev/null +++ b/internal/logic/common/upload.go @@ -0,0 +1,307 @@ +package common + +import ( + "context" + "errors" + "fmt" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/grand" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +type sUpload struct { +} + +func upload() *sUpload { + return &sUpload{} +} + +func init() { + service.RegisterUpload(upload()) +} + +//UploadFiles 上传多文件 +func (s *sUpload) UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result common.UploadMultipleRes, err error) { + for _, item := range files { + f, e := s.UploadFile(ctx, item, checkFileType, source) + if e != nil { + return + } + result = append(result, &f) + } + return +} + +//UploadFile 上传单文件 +func (s *sUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result common.UploadResponse, err error) { + + // 检查文件类型 + err = s.CheckType(ctx, checkFileType, file) + if err != nil { + return + } + + // 检查文件大小 + err = s.CheckSize(ctx, checkFileType, file) + if err != nil { + return + } + + // 非图片文件只能上传至本地 + if checkFileType == consts.CheckFileTypeFile { + source = consts.SourceLocal + } + + switch source { + // 上传至本地 + case consts.SourceLocal: + result, err = s.UploadLocal(ctx, file) + // 上传至腾讯云 + case consts.SourceTencent: + result, err = s.UploadTencent(ctx, file) + default: + err = errors.New("source参数错误") + } + + if err != nil { + return + } + return +} + +//UploadTencent 上传至腾讯云 +func (s *sUpload) UploadTencent(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) { + v, err := g.Cfg().Get(ctx, "upload.tencentCOS") + if err != nil { + return + } + m := v.MapStrVar() + var ( + upPath = m["upPath"].String() + rawUrl = m["rawUrl"].String() + secretID = m["secretID"].String() + secretKey = m["secretKey"].String() + ) + name := gfile.Basename(file.Filename) + name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6)) + name = name + gfile.Ext(file.Filename) + + path := upPath + name + + urlAdd, _ := url.Parse(rawUrl) + b := &cos.BaseURL{BucketURL: urlAdd} + client := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: secretID, + SecretKey: secretKey, + Transport: &debug.DebugRequestTransport{ + RequestHeader: false, + RequestBody: false, + ResponseHeader: false, + ResponseBody: false, + }, + }, + }) + opt := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentLength: file.Size, + }, + } + var f io.ReadCloser + f, err = file.Open() + if err != nil { + return + } + defer f.Close() + _, err = client.Object.Put(context.Background(), path, f, opt) + result = common.UploadResponse{ + Size: file.Size, + Path: rawUrl + path, + FullPath: rawUrl + path, + Name: file.Filename, + Type: file.Header.Get("Content-type"), + } + return +} + +//UploadLocal 上传本地 +func (s *sUpload) UploadLocal(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) { + if file == nil { + err = errors.New("文件必须") + return + } + r := g.RequestFromCtx(ctx) + urlPerfix := fmt.Sprintf("http://%s/", r.Host) + p := strings.Trim(consts.UploadPath, "/") + sp := s.getStaticPath(ctx) + if sp != "" { + sp = strings.Trim(sp, "/") + } + nowData := time.Now().Format("2006-01-02") + // 包含静态文件夹的路径 + fullDirPath := sp + "/" + p + "/" + nowData + fileName, err := file.Save(fullDirPath, true) + if err != nil { + return + } + // 不含静态文件夹的路径 + fullPath := p + "/" + nowData + "/" + fileName + + result = common.UploadResponse{ + Size: file.Size, + Path: fullPath, + FullPath: urlPerfix + fullPath, + Name: file.Filename, + Type: file.Header.Get("Content-type"), + } + return +} + +//CheckSize 检查上传文件大小 +func (s *sUpload) CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) { + + var ( + configSize *entity.SysConfig + ) + + if checkFileType == consts.CheckFileTypeFile { + + //获取上传大小配置 + configSize, err = s.getUpConfig(ctx, consts.FileSizeKey) + if err != nil { + return + } + } else if checkFileType == consts.CheckFileTypeImg { + + //获取上传大小配置 + configSize, err = s.getUpConfig(ctx, consts.ImgSizeKey) + if err != nil { + return + } + } else { + return errors.New(fmt.Sprintf("文件检查类型错误:%s|%s", consts.CheckFileTypeFile, consts.CheckFileTypeImg)) + } + + var rightSize bool + rightSize, err = s.checkSize(configSize.ConfigValue, file.Size) + if err != nil { + return + } + if !rightSize { + err = gerror.New("上传文件超过最大尺寸:" + configSize.ConfigValue) + return + } + return +} + +//CheckType 检查上传文件类型 +func (s *sUpload) CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) { + + var ( + configType *entity.SysConfig + ) + + if checkFileType == consts.CheckFileTypeFile { + //获取上传类型配置 + configType, err = s.getUpConfig(ctx, consts.FileTypeKey) + if err != nil { + return + } + + } else if checkFileType == consts.CheckFileTypeImg { + //获取上传类型配置 + configType, err = s.getUpConfig(ctx, consts.ImgTypeKey) + if err != nil { + return + } + } else { + return errors.New(fmt.Sprintf("文件检查类型错误:%s|%s", consts.CheckFileTypeFile, consts.CheckFileTypeImg)) + } + + rightType := s.checkFileType(file.Filename, configType.ConfigValue) + if !rightType { + err = gerror.New("上传文件类型错误,只能包含后缀为:" + configType.ConfigValue + "的文件。") + return + } + return +} + +//getUpConfig 获取上传配置 +func (s *sUpload) getUpConfig(ctx context.Context, key string) (config *entity.SysConfig, err error) { + config, err = sysConfigDataNew().GetConfigByKey(ctx, key) + if err != nil { + return + } + if config == nil { + err = gerror.New("上传文件类型未设置,请在后台配置") + return + } + return +} + +//checkFileType 判断上传文件类型是否合法 +func (s *sUpload) checkFileType(fileName, typeString string) bool { + suffix := gstr.SubStrRune(fileName, gstr.PosRRune(fileName, ".")+1, gstr.LenRune(fileName)-1) + imageType := gstr.Split(typeString, ",") + rightType := false + for _, v := range imageType { + if gstr.Equal(suffix, v) { + rightType = true + break + } + } + return rightType +} + +//checkSize 检查文件大小是否合法 +func (s *sUpload) checkSize(configSize string, fileSize int64) (bool, error) { + match, err := gregex.MatchString(`^([0-9]+)(?i:([a-z]*))$`, configSize) + if err != nil { + return false, err + } + if len(match) == 0 { + err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB)") + return false, err + } + var cfSize int64 + switch gstr.ToUpper(match[2]) { + case "MB", "M": + cfSize = gconv.Int64(match[1]) * 1024 * 1024 + case "KB", "K": + cfSize = gconv.Int64(match[1]) * 1024 + case "": + cfSize = gconv.Int64(match[1]) + } + if cfSize == 0 { + err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB),最大单位为MB") + return false, err + } + return cfSize >= fileSize, nil +} + +//getStaticPath 静态文件夹目录 +func (s *sUpload) getStaticPath(ctx context.Context) string { + value, _ := g.Cfg().Get(ctx, "server.serverRoot") + if !value.IsEmpty() { + return value.String() + } + return "" +} diff --git a/internal/logic/context/context.go b/internal/logic/context/context.go new file mode 100644 index 0000000..7b7daf6 --- /dev/null +++ b/internal/logic/context/context.go @@ -0,0 +1,69 @@ +package context + +import ( + "context" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sContext struct { +} + +func init() { + service.RegisterContext(New()) +} + +func New() *sContext { + return &sContext{} +} + +// Init 初始化上下文对象指针到上下文对象中,以便后续的请求流程中可以修改。 +func (s *sContext) Init(r *ghttp.Request, customCtx *model.Context) { + r.SetCtxVar(consts.ContextKey, customCtx) +} + +// Get 获得上下文变量,如果没有设置,那么返回nil +func (s *sContext) Get(ctx context.Context) *model.Context { + value := ctx.Value(consts.ContextKey) + if value == nil { + return nil + } + if localCtx, ok := value.(*model.Context); ok { + return localCtx + } + return nil +} + +// SetUser 将上下文信息设置到上下文请求中,注意是完整覆盖 +func (s *sContext) SetUser(ctx context.Context, ctxUser *model.ContextUser) { + s.Get(ctx).User = ctxUser +} + +// GetLoginUser 获取当前登陆用户信息 +func (s *sContext) GetLoginUser(ctx context.Context) *model.ContextUser { + sysContext := s.Get(ctx) + if sysContext == nil { + return nil + } + return sysContext.User +} + +// GetUserId 获取当前登录用户id +func (s *sContext) GetUserId(ctx context.Context) int { + user := s.GetLoginUser(ctx) + if user != nil { + return user.Id + } + return 0 +} + +// GetUserDeptId 获取当前登录用户部门ID +func (s *sContext) GetUserDeptId(ctx context.Context) int { + user := s.GetLoginUser(ctx) + if user != nil { + return user.DeptId + } + return 0 +} diff --git a/internal/logic/datahub/data_node.go b/internal/logic/datahub/data_node.go new file mode 100644 index 0000000..003046c --- /dev/null +++ b/internal/logic/datahub/data_node.go @@ -0,0 +1,196 @@ +package datahub + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDataNode struct{} + +func init() { + service.RegisterDataNode(dataNodeNew()) +} + +func dataNodeNew() *sDataNode { + return &sDataNode{} +} + +func (s *sDataNode) Add(ctx context.Context, in *model.DataNodeAddInput) (err error) { + id, _ := dao.DataNode.Ctx(ctx). + Fields(dao.DataNode.Columns().NodeId). + Where(dao.DataNode.Columns().SourceId, in.SourceId). + Where(dao.DataNode.Columns().Key, in.Key). + Value() + if id.Int64() > 0 { + return gerror.New("数据节点标识重复") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataNode + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + err = dao.DataNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + rs, err := dao.DataNode.Ctx(ctx).Data(param).Insert() + if err != nil { + return err + } + + nodeId, _ := rs.LastInsertId() + + dataSource, _ := service.DataSource().Detail(ctx, in.SourceId) + if dataSource != nil && dataSource.DataTable != "" { + // 表结构已存在,字段新增 + err = addColumn(ctx, uint64(nodeId)) + if err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataNode) Edit(ctx context.Context, in *model.DataNodeEditInput) (err error) { + id, _ := dao.DataNode.Ctx(ctx). + Fields(dao.DataNode.Columns().NodeId). + Where(dao.DataNode.Columns().NodeId, in.NodeId). + Value() + if id.Int64() == 0 { + return gerror.New("数据节点不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataNode + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.NodeId = nil + + _, err = dao.DataNode.Ctx(ctx).Data(param).Where(dao.DataNode.Columns().NodeId, in.NodeId).Update() + + return +} + +func (s *sDataNode) Del(ctx context.Context, nodeId uint64) (err error) { + var p *entity.DataNode + err = dao.DataNode.Ctx(ctx).Where(dao.DataNode.Columns().NodeId, nodeId).Scan(&p) + if p == nil { + return gerror.New("数据节点不存在") + } + + var ds *entity.DataSource + err = dao.DataSource.Ctx(ctx).Where(dao.DataSource.Columns().SourceId, p.SourceId).Scan(&ds) + if err != nil { + return + } + if ds != nil && ds.Status != model.DataSourceStatusOff { + return gerror.New("数据源已发布,请先撤回,再删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + if ds != nil && ds.DataTable != "" { + // 表结构已存在,字段须删除处理 + if err = dropColumn(ctx, nodeId); err != nil { + return err + } + } + + _, err = dao.DataNode.Ctx(ctx). + Data(do.DataNode{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataNode.Columns().NodeId, nodeId). + Unscoped(). + Update() + return err + }) + + return +} + +func (s *sDataNode) List(ctx context.Context, sourceId uint64) (list []*model.DataNodeOutput, err error) { + var p []*entity.DataNode + err = dao.DataNode.Ctx(ctx).OrderAsc(dao.DataNode.Columns().NodeId).Where(dao.DataNode.Columns().SourceId, sourceId).Scan(&p) + if err != nil || p == nil { + return + } + + list = make([]*model.DataNodeOutput, len(p)) + for i, v := range p { + // 规则配置 + var rule []*model.DataSourceRule + if v.Rule != "" { + j, _ := gjson.DecodeToJson(v.Rule) + if err = j.Scan(&rule); err != nil { + return nil, err + } + } + + out := new(model.DataNodeOutput) + out.DataNode = v + out.NodeRule = rule + + list[i] = out + } + + return +} + +// 详情 +func (s *sDataNode) Detail(ctx context.Context, nodeId uint64) (out *model.DataNodeOutput, err error) { + var p *entity.DataNode + err = dao.DataNode.Ctx(ctx).Where(dao.DataNode.Columns().NodeId, nodeId).Scan(&p) + if err != nil || p == nil { + return + } + + // 规则配置 + var rule []*model.DataSourceRule + if p.Rule != "" { + j, _ := gjson.DecodeToJson(p.Rule) + if err = j.Scan(&rule); err != nil { + return nil, err + } + } + + out = new(model.DataNodeOutput) + out.DataNode = p + out.NodeRule = rule + + return +} diff --git a/internal/logic/datahub/data_source.go b/internal/logic/datahub/data_source.go new file mode 100644 index 0000000..6af9a81 --- /dev/null +++ b/internal/logic/datahub/data_source.go @@ -0,0 +1,624 @@ +package datahub + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDataSource struct{} + +func init() { + service.RegisterDataSource(dataSourceNew()) +} + +func dataSourceNew() *sDataSource { + return &sDataSource{} +} + +func (s *sDataSource) Add(ctx context.Context, in *model.DataSourceApiAddInput) (sourceId uint64, err error) { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + param.LockKey = 0 + + in.Config.Url = gstr.TrimAll(in.Config.Url) + + param.Config, err = json.Marshal(in.Config) + if err != nil { + err = gerror.New("数据源配置格式错误") + return + } + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return 0, gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + rs, err := dao.DataSource.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + + newId, _ := rs.LastInsertId() + sourceId = uint64(newId) + + return +} + +func (s *sDataSource) Edit(ctx context.Context, in *model.DataSourceApiEditInput) (err error) { + out, err := s.Detail(ctx, in.SourceId) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据源不存在") + } + if out.Status == model.DataSourceStatusOn { + return gerror.New("数据源已发布") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.SourceId = nil + if out.LockKey == 1 { + param.Key = nil + } else { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + WhereNot(dao.DataSource.Columns().SourceId, in.SourceId). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + } + + in.Config.Url = gstr.TrimAll(in.Config.Url) + + param.Config, err = json.Marshal(in.Config) + if err != nil { + return gerror.New("数据源配置格式错误") + } + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + err = dao.DataSource.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DataSource.Ctx(ctx). + Data(param). + Where(dao.DataSource.Columns().SourceId, in.SourceId). + Update() + if err != nil { + return err + } + + // 同步聚合时间到定时任务管理 + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataSource-" + gconv.String(out.SourceId) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) > 0 { + editJob := new(model.SysJobEditInput) + editJob.JobName = list[0].JobName + editJob.JobParams = list[0].JobParams + editJob.JobGroup = list[0].JobGroup + editJob.InvokeTarget = list[0].InvokeTarget + editJob.CronExpression = in.Config.CronExpression + editJob.MisfirePolicy = list[0].MisfirePolicy + editJob.Concurrent = list[0].Concurrent + editJob.Status = list[0].Status + editJob.Remark = list[0].Remark + + editJob.JobId = list[0].JobId + editJob.UpdateBy = uint64(loginUserId) + err = service.SysJob().EditJob(ctx, editJob) + if err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataSource) Del(ctx context.Context, ids []uint64) (err error) { + var p []*entity.DataSource + err = dao.DataSource.Ctx(ctx).WhereIn(dao.DataSource.Columns().SourceId, ids).Scan(&p) + if len(p) == 0 { + return gerror.New("数据源不存在") + } + if len(p) == 1 && p[0].Status == model.DataSourceStatusOn { + return gerror.New("数据源已发布,请先撤回,再删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 删除数据源 + var delIds []uint64 + for _, id := range ids { + rs, err := dao.DataSource.Ctx(ctx). + Data(do.DataSource{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataSource.Columns().SourceId, id). + Where(dao.DataSource.Columns().Status, model.DataSourceStatusOff). + Unscoped(). + Update() + if err != nil { + return err + } + + num, _ := rs.RowsAffected() + if num > 0 { + delIds = append(delIds, id) + } + } + + // 删除数据节点 + for _, id := range delIds { + _, err = dao.DataNode.Ctx(ctx). + Data(do.DataNode{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataNode.Columns().SourceId, id). + Unscoped(). + Update() + if err != nil { + return err + } + } + + // 删除定时任务、删除数据表 + for _, id := range delIds { + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataSource-" + gconv.String(id) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) != 0 { + err = service.SysJob().DeleteJobByIds(ctx, []int{int(list[0].JobId)}) + } + + err = dropTable(ctx, id) + if err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataSource) Search(ctx context.Context, in *model.DataSourceSearchInput) (out *model.DataSourceSearchOutput, err error) { + out = new(model.DataSourceSearchOutput) + c := dao.DataSource.Columns() + m := dao.DataSource.Ctx(ctx).OrderDesc(c.SourceId) + + if in.Key != "" { + m = m.Where(c.Key, in.Key) + } + if in.Name != "" { + m = m.WhereLike(c.Name, "%"+in.Name+"%") + } + if in.From > 0 { + m = m.Where(c.From, in.From) + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + err = m.Page(in.PageNum, in.PageSize).Scan(&out.List) + + return +} + +// 已发布源列表 +func (s *sDataSource) List(ctx context.Context) (list []*entity.DataSource, err error) { + err = dao.DataSource.Ctx(ctx). + Where(dao.DataSource.Columns().Status, model.DataSourceStatusOn). + OrderDesc(dao.DataSource.Columns().SourceId). + Scan(&list) + return +} + +func (s *sDataSource) Detail(ctx context.Context, sourceId uint64) (out *model.DataSourceOutput, err error) { + var p *entity.DataSource + err = dao.DataSource.Ctx(ctx).Where(dao.DataSource.Columns().SourceId, sourceId).Scan(&p) + if err != nil { + return + } + if p == nil { + return + } + + // 规则配置 + var rule []*model.DataSourceRule + if p.Rule != "" { + j, _ := gjson.DecodeToJson(p.Rule) + if err = j.Scan(&rule); err != nil { + return nil, err + } + } + + out = new(model.DataSourceOutput) + out.DataSource = p + out.SourceRule = rule + + // 数据源配置 + if p.Config != "" { + j, _ := gjson.DecodeToJson(p.Config) + switch p.From { + case model.DataSourceFromApi: + // api 配置 + out.ApiConfig = &model.DataSourceConfigApi{} + err = j.Scan(out.ApiConfig) + case model.DataSourceFromDevice: + // 设备配置 + out.DeviceConfig = &model.DataSourceConfigDevice{} + err = j.Scan(out.DeviceConfig) + case model.DataSourceFromDb: + // 数据库配置 + out.DbConfig = &model.DataSourceConfigDb{} + err = j.Scan(out.DbConfig) + } + } + + return +} + +func (s *sDataSource) Deploy(ctx context.Context, sourceId uint64) (err error) { + out, err := s.Detail(ctx, sourceId) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据源不存在") + } + if out.Status == model.DataSourceStatusOn { + return gerror.New("数据源已发布") + } + + // 获取节点 + nodeList, err := service.DataNode().List(ctx, sourceId) + if err != nil { + return + } + if len(nodeList) == 0 { + err = gerror.New("该数据源还未创建数据节点") + return + } + + // 获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataSource.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 创建表结构 + table := "" + if out.From == model.DataSourceFromApi || out.From == model.DataSourceFromDb { + if out.DataTable == "" { + table, err = createTable(ctx, sourceId) + if err != nil { + return err + } + } + } + + m := g.Map{ + dao.DataSource.Columns().Status: model.DataSourceStatusOn, + dao.DataSource.Columns().LockKey: 1, + } + if table != "" { + m[dao.DataSource.Columns().DataTable] = table + } + + _, err = dao.DataSource.Ctx(ctx). + Data(m). + Where(dao.DataSource.Columns().SourceId, sourceId). + Update() + + return err + }) + if err != nil { + return err + } + + if out.From != model.DataSourceFromApi && out.From != model.DataSourceFromDb { + return + } + + var cron string + switch out.From { + case model.DataSourceFromApi: + cron = out.ApiConfig.CronExpression + case model.DataSourceFromDb: + cron = out.DbConfig.CronExpression + } + + // 开启数据更新任务,任务排重 +Job: + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataSource-" + gconv.String(sourceId) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) == 0 { + sysJob := new(model.SysJobAddInput) + sysJob.JobName = "dataSource-" + gconv.String(sourceId) + sysJob.JobParams = gconv.String(sourceId) + sysJob.JobGroup = "dataSourceJob" + sysJob.InvokeTarget = "dataSource" + sysJob.CronExpression = cron + sysJob.MisfirePolicy = 1 + sysJob.Concurrent = 0 + sysJob.Status = 0 + sysJob.Remark = out.Name + sysJob.CreateBy = uint64(loginUserId) + err = service.SysJob().AddJob(ctx, sysJob) + goto Job + } + err = service.SysJob().JobStart(ctx, list[0]) + // 初始执行一次 + err = service.SysJob().JobRun(ctx, list[0]) + + return +} + +func (s *sDataSource) Undeploy(ctx context.Context, sourceId uint64) (err error) { + out, err := s.Detail(ctx, sourceId) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据源不存在") + } + if out.Status == model.DataSourceStatusOff { + return gerror.New("数据源已停用") + } + + _, err = dao.DataSource.Ctx(ctx). + Data(g.Map{dao.DataSource.Columns().Status: model.DataSourceStatusOff}). + Where(dao.DataSource.Columns().SourceId, sourceId). + Update() + if err != nil { + return err + } + + if out.From != model.DataSourceFromApi && out.From != model.DataSourceFromDb { + return + } + + // 关闭数据更新任务 + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataSource-" + gconv.String(sourceId) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) == 0 { + return + } + err = service.SysJob().JobStop(ctx, list[0]) + + return +} + +// 更新数据记录,定时任务触发 +func (s *sDataSource) UpdateData(ctx context.Context, sourceId uint64) (err error) { + out, err := s.Detail(ctx, sourceId) + if err != nil { + return + } + if out == nil { + err = gerror.New("数据源不存在") + return + } + + switch out.From { + case model.DataSourceFromApi: + err = s.updateDataForApi(ctx, sourceId) + case model.DataSourceFromDb: + err = s.updateDataForDb(ctx, sourceId) + } + return +} + +// 获取数据源的聚合数据 +func (s *sDataSource) GetData(ctx context.Context, in *model.DataSourceDataInput) (out *model.DataSourceDataOutput, err error) { + src, err := s.Detail(ctx, in.SourceId) + if err != nil { + return + } + if src == nil { + err = gerror.New("数据源不存在") + return + } + if src.Status == model.DataSourceStatusOff { + err = gerror.New("数据源已停用") + return + } + + switch src.From { + case model.DataSourceFromApi: + out, err = s.getApiDataRecord(ctx, in, src) + case model.DataSourceFromDevice: + out, err = s.getDeviceDataRecord(ctx, in, src) + case model.DataSourceFromDb: + out, err = s.getDbDataRecord(ctx, in, src) + } + + return +} + +// 获取数据源的聚合数据,非分页 +func (s *sDataSource) GetAllData(ctx context.Context, in *model.SourceDataAllInput) (out *model.SourceDataAllOutput, err error) { + ds, err := s.Detail(ctx, in.SourceId) + if err != nil { + return + } + if ds == nil { + err = gerror.New("数据源不存在") + return + } + if ds.Status == model.DataSourceStatusOff { + err = gerror.New("数据源已停用") + return + } + + switch ds.From { + case model.DataSourceFromApi: + out, err = s.getApiDataAllRecord(ctx, in, ds) + case model.DataSourceFromDevice: + out, err = s.getDeviceDataAllRecord(ctx, in, ds) + case model.DataSourceFromDb: + out, err = s.getDbDataAllRecord(ctx, in, ds) + } + + return +} + +// 数据源获取数据的内网方法列表,供大屏使用 +func (s *sDataSource) AllSource(ctx context.Context) (out []*model.AllSourceOut, err error) { + err = dao.DataSource.Ctx(ctx). + Where(dao.DataSource.Columns().Status, model.DataSourceStatusOn). + OrderDesc(dao.DataSource.Columns().SourceId). + Scan(&out) + if err != nil { + return + } + + for _, v := range out { + v.Path = "GetAllData?pageNum=1&pageSize=10&sourceId=" + gconv.String(v.SourceId) + } + + return +} + +// 复制数据源 +func (s *sDataSource) CopeSource(ctx context.Context, sourceId uint64) (err error) { + out, err := s.Detail(ctx, sourceId) + if err != nil { + return + } + if out == nil { + err = gerror.New("数据源不存在") + return + } + + switch out.From { + case model.DataSourceFromApi: + _, err = s.copeApiSource(ctx, out) + case model.DataSourceFromDevice: + _, err = s.copeDeviceSource(ctx, out) + case model.DataSourceFromDb: + _, err = s.copeDbSource(ctx, out) + } + + return +} + +// 复制数据源节点 +func (s *sDataSource) copeNode(ctx context.Context, sourceId, newSourceId uint64) (err error) { + nodes, err := service.DataNode().List(ctx, sourceId) + if err != nil || len(nodes) == 0 { + return + } + + for _, v := range nodes { + var in *model.DataNodeAddInput + err = gconv.Scan(v.DataNode, &in) + if err != nil { + return + } + in.SourceId = newSourceId + + err = gconv.Scan(v.NodeRule, &in.Rule) + if err != nil { + return + } + + err = service.DataNode().Add(ctx, in) + if err != nil { + return + } + } + return +} + +// 更新数据聚合时长 +func (s *sDataSource) UpdateInterval(ctx context.Context, sourceId uint64, cronExpression string) (err error) { + out, _ := s.Detail(ctx, sourceId) + + var c []byte + + switch out.From { + case model.DataSourceFromApi: + conf := out.ApiConfig + conf.CronExpression = cronExpression + c, _ = json.Marshal(conf) + case model.DataSourceFromDb: + conf := out.DbConfig + conf.CronExpression = cronExpression + c, _ = json.Marshal(conf) + } + + _, err = dao.DataSource.Ctx(ctx). + Data(g.Map{ + dao.DataSource.Columns().Config: c, + }). + Where(dao.DataSource.Columns().SourceId, sourceId). + Update() + + return +} diff --git a/internal/logic/datahub/data_source_api.go b/internal/logic/datahub/data_source_api.go new file mode 100644 index 0000000..298d85e --- /dev/null +++ b/internal/logic/datahub/data_source_api.go @@ -0,0 +1,262 @@ +package datahub + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "reflect" + "strings" + "sync" + + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/util/gconv" +) + +func (s *sDataSource) updateDataForApi(ctx context.Context, sourceId uint64) error { + // 数据节点 + nodeList, err := service.DataNode().List(ctx, sourceId) + if err != nil { + return err + } + if len(nodeList) == 0 { + return gerror.New("数据源未添加数据节点") + } + + // 获取api数据 + apiDataArr, err := s.GetApiData(ctx, sourceId) + if err != nil { + return err + } + + // 数据映射 + var insertData []*gmap.AnyAnyMap + for _, apiData := range apiDataArr { + j := gjson.New(apiData) + m := gmap.New(true) + + var wg sync.WaitGroup + for _, v := range nodeList { + wg.Add(1) + go func(v *model.DataNodeOutput) { + defer wg.Done() + + // 规则过滤,启用节点规则 + var rule *model.DataSourceRule + if len(v.NodeRule) > 0 { + rule = v.NodeRule[0] + } + + rs := getValue(v.Value, j, rule) + if rs != "" { + m.Set(v.Key, rs) + } + }(v) + } + wg.Wait() + insertData = append(insertData, m) + } + + // 入库 + if len(insertData) > 0 { + table := getTableName(sourceId) + err = g.DB(DataCenter()).GetCore().ClearTableFields(ctx, table) + if err != nil { + return err + } + _, err = g.DB(DataCenter()).Save(ctx, table, insertData) + if err != nil { + return err + } + } + + return nil +} + +// 获取api数据 +func (s *sDataSource) GetApiData(ctx context.Context, sourceId uint64) (apiData []string, err error) { + p, _ := s.Detail(ctx, sourceId) + if p == nil || p.ApiConfig == nil { + err = gerror.New("数据源不存在或未进行配置") + return + } + + // api配置 + config := p.ApiConfig + + // api数据获取 + get := func(header, data g.MapStrStr) (string, error) { + client := g.Client() + client.Header(header) + res, err := client.DoRequest(ctx, config.Method, config.Url, data) + if err != nil { + return "", err + } + defer res.Close() + return res.ReadAllString(), nil + } + + if len(config.RequestParams) > 0 { + for _, param := range config.RequestParams { + header := g.MapStrStr{} + data := g.MapStrStr{} + for _, v := range param { + if v.Type == "header" { + header[v.Key] = v.Value + } else { + data[v.Key] = v.Value + } + } + rs, err := get(header, data) + if err != nil { + return nil, err + } + apiData = append(apiData, rs) + } + } else { + rs, err := get(nil, nil) + if err != nil { + return nil, err + } + apiData = append(apiData, rs) + } + + return +} + +// api数据提取值 +func getValue(value string, apiData *gjson.Json, rule *model.DataSourceRule) string { + sv := apiData.Get(value) + if sv == nil { + return "" + } + + s := sv.String() + + if rule != nil && rule.Expression != "" { + // 正则过滤数据 + rs, _ := gregex.ReplaceString(rule.Expression, rule.Replace, s) + return gconv.String(rs) + } + + return s +} + +// api源数据记录列表 +func (s *sDataSource) getApiDataRecord(ctx context.Context, in *model.DataSourceDataInput, ds *model.DataSourceOutput) (out *model.DataSourceDataOutput, err error) { + out = new(model.DataSourceDataOutput) + + table := getTableName(in.SourceId) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " where " + strings.Join(exp, " and ") + } + sql := "select * from " + table + where + " order by created_at desc" + + out.Total, _ = g.DB(DataCenter()).GetCount(ctx, sql, value...) + out.CurrentPage = in.PageNum + + sql += fmt.Sprintf(" limit %d, %d", (in.PageNum-1)*in.PageSize, in.PageSize) + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + out.List = rs.Json() + + return +} + +// api源数据记录列表,非分页 +func (s *sDataSource) getApiDataAllRecord(ctx context.Context, in *model.SourceDataAllInput, ds *model.DataSourceOutput) (out *model.SourceDataAllOutput, err error) { + out = new(model.SourceDataAllOutput) + + table := getTableName(in.SourceId) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " where " + strings.Join(exp, " and ") + } + sql := "select * from " + table + where + " order by created_at desc" + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + out.List = rs.Json() + + return +} + +// 复制API数据源 +func (s *sDataSource) copeApiSource(ctx context.Context, ds *model.DataSourceOutput) (newSourceId uint64, err error) { + err = dao.DataSource.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 复制源 + in := new(model.DataSourceApiAddInput) + in.DataSource = model.DataSource{} + in.Config = model.DataSourceConfigApi{} + + err = gconv.Scan(ds.DataSource, &in.DataSource) + if err != nil { + return err + } + in.DataSource.Key += "_" + gtime.Now().Format("YmdHis") + + err = gconv.Scan(ds.ApiConfig, &in.Config) + if err != nil { + return err + } + + newSourceId, err = s.Add(ctx, in) + if err != nil { + return err + } + + // 复制节点 + err = s.copeNode(ctx, ds.SourceId, newSourceId) + + return err + }) + + return +} diff --git a/internal/logic/datahub/data_source_db.go b/internal/logic/datahub/data_source_db.go new file mode 100644 index 0000000..ef060f7 --- /dev/null +++ b/internal/logic/datahub/data_source_db.go @@ -0,0 +1,495 @@ +package datahub + +import ( + "context" + "encoding/json" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/service" + "reflect" + "strings" + "sync" + + _ "github.com/gogf/gf/contrib/drivers/mssql/v2" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/util/gconv" +) + +// 添加数据库数据源 +func (s *sDataSource) AddDb(ctx context.Context, in *model.DataSourceDbAddInput) (sourceId uint64, err error) { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + param.LockKey = 0 + + conf, err := json.Marshal(in.Config) + if err != nil { + err = gerror.New("数据源配置格式错误") + return + } + param.Config = conf + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return 0, gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + rs, err := dao.DataSource.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + + newId, _ := rs.LastInsertId() + sourceId = uint64(newId) + + return +} + +// 编辑数据库数据源 +func (s *sDataSource) EditDb(ctx context.Context, in *model.DataSourceDbEditInput) (err error) { + out, err := s.Detail(ctx, in.SourceId) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据源不存在") + } + if out.Status == model.DataSourceStatusOn { + return gerror.New("数据源已发布") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.SourceId = nil + if out.LockKey == 1 { + param.Key = nil + } else { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + WhereNot(dao.DataSource.Columns().SourceId, in.SourceId). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + } + + conf, err := json.Marshal(in.Config) + if err != nil { + return gerror.New("数据源配置格式错误") + } + param.Config = conf + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + _, err = dao.DataSource.Ctx(ctx).Data(param).Where(dao.DataSource.Columns().SourceId, in.SourceId).Update() + + return +} + +// 获取数据库表结构 +func (s *sDataSource) GetDbFields(ctx context.Context, sourceId uint64) (g.MapStrAny, error) { + p, _ := s.Detail(ctx, sourceId) + if p == nil || p.DbConfig == nil { + return nil, gerror.New("数据源不存在或未进行配置") + } + + // 数据库配置 + conf := p.DbConfig + + db, err := gdb.New(gdb.ConfigNode{ + Host: conf.Host, + Port: gconv.String(conf.Port), + User: conf.User, + Pass: conf.Passwd, + Name: conf.DbName, + Type: conf.Type, + }) + if err != nil { + return nil, err + } + + if conf.QueryType == model.DataSourceDbQueryTypeSql { + rs, err := db.GetOne(ctx, conf.TableName) + if err != nil { + return nil, err + } + + tmp := rs.GMap() + data := make(g.MapStrAny) + for k := range tmp.Map() { + tf := new(gdb.TableField) + tf.Name = k + tf.Comment = k + + switch (tmp.GetVar(k).Interface()).(type) { + case int: + tf.Type = "int" + case string: + tf.Type = "string" + case float64: + tf.Type = "double" + case *gtime.Time: + tf.Type = "date" + default: + tf.Type = "string" + } + data[k] = tf + } + return data, nil + } + + fields, err := db.TableFields(ctx, conf.TableName) + if err != nil { + return nil, err + } + + // 字段类型转换 + data := make(g.MapStrAny, len(fields)) + for k, v := range fields { + p := *v + vtype := strings.Split(p.Type, "(") + p.Type = mappingFieldType(vtype[0]) + data[k] = p + } + return data, nil +} + +// mssql字段类型映射 +func mappingFieldType(t string) (netT string) { + switch t { + case "int", "smallint", "tinyint", "timestamp": + netT = "int" + case "bigint": + netT = "long" + case "float", "decimal", "numeric": + netT = "float" + case "real": + netT = "double" + case "varchar", "char", "nvarchar", "nchar", "bit": + netT = "string" + case "text", "ntext": + netT = "text" + case "datetime", "smalldatetime": + netT = "date" + default: + netT = "string" + } + return +} + +// 获取数据库单条数据 +func (s *sDataSource) GetDbData(ctx context.Context, sourceId uint64) (string, error) { + rs, _, err := s.getDbData(ctx, sourceId, 1) + if err != nil || rs.Len() == 0 { + return "", err + } + return rs[0].Json(), nil +} + +func (s *sDataSource) getDbData(ctx context.Context, sourceId uint64, limit int) (rs gdb.Result, ds *model.DataSourceOutput, err error) { + p, _ := s.Detail(ctx, sourceId) + if p == nil || p.DbConfig == nil { + err = gerror.New("数据源不存在或未进行配置") + return + } + ds = p + + // 数据库配置 + conf := p.DbConfig + + dbDebug, _ := g.Cfg().Get(context.TODO(), "database.default.debug") + + db, err := gdb.New(gdb.ConfigNode{ + Host: conf.Host, + Port: gconv.String(conf.Port), + User: conf.User, + Pass: conf.Passwd, + Name: conf.DbName, + Type: conf.Type, + Debug: dbDebug.Bool(), + }) + if err != nil { + return + } + + if conf.QueryType == model.DataSourceDbQueryTypeSql { + sql := conf.TableName + if strings.Contains(sql, "%d") { + sql = fmt.Sprintf(conf.TableName, conf.PkMax) + } + rs, err = db.GetAll(ctx, sql) + return + } + + where := "" + if limit <= 0 { + limit = conf.Num + + if conf.Pk != "" { + // 判断主键类型 + var tmap g.MapStrAny + tmap, err = s.GetDbFields(ctx, sourceId) + if err != nil { + return + } + if t, ok := tmap[conf.Pk]; ok { + tf := t.(gdb.TableField) + switch tf.Type { + case "int", "long": + where = fmt.Sprintf("where %s > %d", conf.Pk, conf.PkMax) + } + } + } + } + order := "" + if conf.Pk != "" { + order = fmt.Sprintf("order by %s asc", conf.Pk) + } + sql := fmt.Sprintf("select * from %s %s %s limit %d", conf.TableName, where, order, limit) + if conf.Type == "mssql" { + sql = fmt.Sprintf("select top %d * from %s %s %s", limit, conf.TableName, where, order) + } + rs, err = db.GetAll(ctx, sql) + return +} + +// 数据库源数据记录列表 +func (s *sDataSource) getDbDataRecord(ctx context.Context, in *model.DataSourceDataInput, ds *model.DataSourceOutput) (out *model.DataSourceDataOutput, err error) { + out = new(model.DataSourceDataOutput) + + table := getTableName(in.SourceId) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " where " + strings.Join(exp, " and ") + } + sql := "select * from " + table + where + " order by created_at desc" + + out.Total, _ = g.DB(DataCenter()).GetCount(ctx, sql, value...) + out.CurrentPage = in.PageNum + + sql += fmt.Sprintf(" limit %d, %d", (in.PageNum-1)*in.PageSize, in.PageSize) + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + out.List = rs.Json() + + return +} + +// 数据库源数据记录列表,非分页 +func (s *sDataSource) getDbDataAllRecord(ctx context.Context, in *model.SourceDataAllInput, ds *model.DataSourceOutput) (out *model.SourceDataAllOutput, err error) { + out = new(model.SourceDataAllOutput) + + table := getTableName(in.SourceId) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " where " + strings.Join(exp, " and ") + } + sql := "select * from " + table + where + " order by created_at desc" + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + out.List = rs.Json() + + return +} + +// 复制数据库数据源 +func (s *sDataSource) copeDbSource(ctx context.Context, ds *model.DataSourceOutput) (newSourceId uint64, err error) { + err = dao.DataSource.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 复制源 + in := new(model.DataSourceDbAddInput) + in.DataSource = model.DataSource{} + in.Config = model.DataSourceConfigDb{} + + err = gconv.Scan(ds.DataSource, &in.DataSource) + if err != nil { + return err + } + in.DataSource.Key += "_" + gtime.Now().Format("YmdHis") + + err = gconv.Scan(ds.DbConfig, &in.Config) + if err != nil { + return err + } + + newSourceId, err = s.AddDb(ctx, in) + if err != nil { + return err + } + + // 复制节点 + err = s.copeNode(ctx, ds.SourceId, newSourceId) + + return err + }) + + return +} + +func (s *sDataSource) updateDataForDb(ctx context.Context, sourceId uint64) error { + // 数据节点 + nodeList, err := service.DataNode().List(ctx, sourceId) + if err != nil { + return err + } + if len(nodeList) == 0 { + return gerror.New("数据源未添加数据节点") + } + + // 获取数据库数据 + rs, ds, err := s.getDbData(ctx, sourceId, -1) + if err != nil { + return err + } + + var pkMax uint64 = 0 + + // 数据映射 + var insertData []*gmap.AnyAnyMap + for _, row := range rs { + pk := row[ds.DbConfig.Pk] + if pk.Uint64() > pkMax { + pkMax = pk.Uint64() + } + + m := gmap.New(true) + + var wg sync.WaitGroup + for _, v := range nodeList { + wg.Add(1) + go func(v *model.DataNodeOutput) { + defer wg.Done() + + // 规则过滤,启用节点规则 + var rule *model.DataSourceRule + if len(v.NodeRule) > 0 { + rule = v.NodeRule[0] + } + + sv, ok := row[v.Value] + if !ok { + return + } + + rs := sv.String() + if rule != nil && rule.Expression != "" { + // 正则过滤数据 + rs, err = gregex.ReplaceString(rule.Expression, rule.Replace, rs) + if err != nil { + return + } + } + m.Set(v.Key, rs) + }(v) + } + wg.Wait() + insertData = append(insertData, m) + } + + // 入库 + if len(insertData) > 0 { + table := getTableName(sourceId) + err = g.DB(DataCenter()).GetCore().ClearTableFields(ctx, table) + if err != nil { + return err + } + _, err = g.DB(DataCenter()).Save(ctx, table, insertData) + if err != nil { + return err + } + } + + // 主键最大值存储 + if pkMax > 0 { + conf := ds.DbConfig + conf.PkMax = pkMax + c, _ := json.Marshal(conf) + _, err = dao.DataSource.Ctx(ctx). + Data(g.Map{ + dao.DataSource.Columns().Config: c, + }). + Where(dao.DataSource.Columns().SourceId, sourceId). + Update() + } + return err +} diff --git a/internal/logic/datahub/data_source_device.go b/internal/logic/datahub/data_source_device.go new file mode 100644 index 0000000..66360cd --- /dev/null +++ b/internal/logic/datahub/data_source_device.go @@ -0,0 +1,300 @@ +package datahub + +import ( + "context" + "encoding/json" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/service" + "reflect" + "strings" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +// 添加设备数据源 +func (s *sDataSource) AddDevice(ctx context.Context, in *model.DataSourceDeviceAddInput) (sourceId uint64, err error) { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + param.LockKey = 0 + + conf, err := json.Marshal(in.Config) + if err != nil { + err = gerror.New("数据源配置格式错误") + return + } + param.Config = conf + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return 0, gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + rs, err := dao.DataSource.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + + newId, _ := rs.LastInsertId() + sourceId = uint64(newId) + + return +} + +// 编辑设备数据源 +func (s *sDataSource) EditDevice(ctx context.Context, in *model.DataSourceDeviceEditInput) (err error) { + out, err := s.Detail(ctx, in.SourceId) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据源不存在") + } + if out.Status == model.DataSourceStatusOn { + return gerror.New("数据源已发布") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataSource + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.SourceId = nil + if out.LockKey == 1 { + param.Key = nil + } else { + id, _ := dao.DataSource.Ctx(ctx). + Fields(dao.DataSource.Columns().SourceId). + Where(dao.DataSource.Columns().Key, in.Key). + WhereNot(dao.DataSource.Columns().SourceId, in.SourceId). + Value() + if id.Int64() > 0 { + err = gerror.New("数据源标识重复") + return + } + } + + conf, err := json.Marshal(in.Config) + if err != nil { + return gerror.New("数据源配置格式错误") + } + param.Config = conf + + if in.Rule != nil { + rule, err := json.Marshal(in.Rule) + if err != nil { + return gerror.New("规则配置格式错误") + } + param.Rule = rule + } + + _, err = dao.DataSource.Ctx(ctx).Data(param).Where(dao.DataSource.Columns().SourceId, in.SourceId).Update() + + return +} + +// 获取设备源数据,源配置测试使用 +func (s *sDataSource) GetDeviceData(ctx context.Context, sourceId uint64) (string, error) { + p, _ := s.Detail(ctx, sourceId) + if p == nil || p.DeviceConfig == nil { + return "", gerror.New("数据源不存在或未进行配置") + } + + // 设备配置 + conf := p.DeviceConfig + + // TDengine + sql := "select * from ? where device='?' order by ts desc limit 1" + rs, err := service.TdEngine().GetOne(ctx, sql, conf.ProductKey, conf.DeviceKey) + if err != nil { + return "", err + } + data, _ := json.Marshal(rs) + + return string(data), nil +} + +// 设备源数据记录列表 +func (s *sDataSource) getDeviceDataRecord(ctx context.Context, in *model.DataSourceDataInput, ds *model.DataSourceOutput) (out *model.DataSourceDataOutput, err error) { + out = new(model.DataSourceDataOutput) + + // 设备配置 + conf := ds.DeviceConfig + + // 搜索条件 + var exp []string + if in.Param != nil { + for k, v := range in.Param { + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + tmp := k + for i := 0; i < s.Len(); i++ { + s := fmt.Sprintf("'%v'", v) + tmp = strings.Replace(tmp, "?", s, 1) + } + exp = append(exp, tmp) + } else { + s := fmt.Sprintf("'%v'", v) + exp = append(exp, strings.Replace(k, "?", s, 1)) + } + } + } + where := "" + if len(exp) > 0 { + where = " and " + strings.Join(exp, " and ") + } + + // TDengine + sql := fmt.Sprintf("select count(*) as num from %s where device='%s' %s limit 100", conf.ProductKey, conf.DeviceKey, where) + rs, err := service.TdEngine().GetOne(ctx, sql) + if err != nil { + return + } + out.Total = rs["num"].Int() + out.CurrentPage = in.PageNum + if in.PageNum*in.PageSize > 100 { + return + } + + // 获取节点字段 + var fileds []string + nodeList, err := service.DataNode().List(ctx, ds.SourceId) + if err != nil { + return + } + for _, v := range nodeList { + fileds = append(fileds, v.Value) + } + + sql = fmt.Sprintf("select %s from %s where device='%s' %s order by ts desc limit %d, %d", strings.Join(fileds, ","), conf.ProductKey, conf.DeviceKey, where, (in.PageNum-1)*in.PageSize, in.PageSize) + data, err := service.TdEngine().GetAll(ctx, sql) + if err != nil { + return + } + + var nr gdb.Result + r := make(gdb.Record, len(nodeList)) + for _, row := range data { + for _, v := range nodeList { + r[v.Key] = row[v.Value] + } + nr = append(nr, r) + } + + out.List = nr.Json() + + return +} + +// 设备源数据记录列表,非分页 +func (s *sDataSource) getDeviceDataAllRecord(ctx context.Context, in *model.SourceDataAllInput, ds *model.DataSourceOutput) (out *model.SourceDataAllOutput, err error) { + out = new(model.SourceDataAllOutput) + + // 设备配置 + conf := ds.DeviceConfig + + // 搜索条件 + var exp []string + if in.Param != nil { + for k, v := range in.Param { + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + tmp := k + for i := 0; i < s.Len(); i++ { + s := fmt.Sprintf("'%v'", v) + tmp = strings.Replace(tmp, "?", s, 1) + } + exp = append(exp, tmp) + } else { + s := fmt.Sprintf("'%v'", v) + exp = append(exp, strings.Replace(k, "?", s, 1)) + } + } + } + where := "" + if len(exp) > 0 { + where = " and " + strings.Join(exp, " and ") + } + + // 获取节点字段 + var fileds []string + nodeList, err := service.DataNode().List(ctx, ds.SourceId) + if err != nil { + return + } + for _, v := range nodeList { + fileds = append(fileds, v.Value) + } + + // TDengine + sql := fmt.Sprintf("select %s from %s where device='%s' %s order by ts desc", strings.Join(fileds, ","), conf.ProductKey, conf.DeviceKey, where) + data, err := service.TdEngine().GetAll(ctx, sql) + if err != nil { + return + } + out.List = data.Json() + + return +} + +// 复制设备数据源 +func (s *sDataSource) copeDeviceSource(ctx context.Context, ds *model.DataSourceOutput) (newSourcId uint64, err error) { + err = dao.DataSource.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 复制源 + in := new(model.DataSourceDeviceAddInput) + in.DataSource = model.DataSource{} + in.Config = model.DataSourceConfigDevice{} + + err = gconv.Scan(ds.DataSource, &in.DataSource) + if err != nil { + return err + } + in.DataSource.Key += "_" + gtime.Now().Format("YmdHis") + + err = gconv.Scan(ds.DeviceConfig, &in.Config) + if err != nil { + return err + } + + newSourcId, err = s.AddDevice(ctx, in) + if err != nil { + return err + } + + // 复制节点 + err = s.copeNode(ctx, ds.SourceId, newSourcId) + + return err + }) + + return +} diff --git a/internal/logic/datahub/data_source_record.go b/internal/logic/datahub/data_source_record.go new file mode 100644 index 0000000..cfe55b3 --- /dev/null +++ b/internal/logic/datahub/data_source_record.go @@ -0,0 +1,115 @@ +package datahub + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +type sDataSourceRecord struct{} + +func init() { + service.RegisterDataSourceRecord(dataSourceRecordNew()) +} + +func dataSourceRecordNew() *sDataSourceRecord { + return &sDataSourceRecord{} +} + +func (s *sDataSourceRecord) GetForTpl(ctx context.Context, sourceId uint64, tid uint64) (rs gdb.Result, err error) { + ds, err := service.DataSource().Detail(ctx, sourceId) + if err != nil { + return + } + if ds == nil { + err = gerror.New("数据源不存在") + return + } + + dsNodes, err := service.DataNode().List(ctx, sourceId) + if err != nil { + return + } + if len(dsNodes) == 0 { + err = gerror.New("数据源未创建节点") + return + } + + dt, err := service.DataTemplate().Detail(ctx, tid) + if err != nil { + return + } + if dt == nil { + err = gerror.New("数据模型不存在") + return + } + + tplNodes, err := service.DataTemplateNode().List(ctx, tid) + if err != nil { + return + } + if len(tplNodes) == 0 { + err = gerror.New("数据模型未创建模型节点") + return + } + + switch ds.From { + case model.DataSourceFromApi: + rs, err = s.getFromApi(ctx, ds, dsNodes, dt, tplNodes) + case model.DataSourceFromDb: + rs, err = s.getFromDb(ctx, ds, dsNodes, dt, tplNodes) + case model.DataSourceFromDevice: + rs, err = s.getFromDevice(ctx, ds, dsNodes, dt, tplNodes) + } + + return +} + +func (s *sDataSourceRecord) getFromDevice(ctx context.Context, ds *model.DataSourceOutput, dsNodes []*model.DataNodeOutput, dt *model.DataTemplateOutput, tplNodes []*model.DataTemplateNodeOutput) (rs gdb.Result, err error) { + table := ds.DeviceConfig.ProductKey + where := "where device='" + ds.DeviceConfig.DeviceKey + "'" + + // TDengine + sql := fmt.Sprintf("select * from %s %s order by ts desc limit 1", table, where) + data, err := service.TdEngine().GetAll(ctx, sql) + if err != nil || data.Len() == 0 { + return + } + + r := make(gdb.Record, len(dsNodes)) + for _, v := range dsNodes { + r[v.Key] = data[0][v.Value] + } + rs = append(rs, r) + + return +} + +func (s *sDataSourceRecord) getFromApi(ctx context.Context, ds *model.DataSourceOutput, dsNodes []*model.DataNodeOutput, dt *model.DataTemplateOutput, tplNodes []*model.DataTemplateNodeOutput) (rs gdb.Result, err error) { + table := getTableName(ds.SourceId) + + groupNum := len(ds.ApiConfig.RequestParams) + if groupNum > 1 { + // 多组数据 + sql := fmt.Sprintf("select * from %s order by created_at desc limit %d", table, groupNum) + rs, err = g.DB(DataCenter()).GetAll(ctx, sql) + return + } + + sql := fmt.Sprintf("select * from %s order by created_at desc limit 1", table) + rs, err = g.DB(DataCenter()).GetAll(ctx, sql) + return +} + +func (s *sDataSourceRecord) getFromDb(ctx context.Context, ds *model.DataSourceOutput, dsNodes []*model.DataNodeOutput, dt *model.DataTemplateOutput, tplNodes []*model.DataTemplateNodeOutput) (rs gdb.Result, err error) { + table := getTableName(ds.SourceId) + + sql := fmt.Sprintf("select * from %s order by created_at desc limit %d", table, ds.DbConfig.Num) + rs, err = g.DB(DataCenter()).GetAll(ctx, sql) + return +} diff --git a/internal/logic/datahub/data_source_record_test.go b/internal/logic/datahub/data_source_record_test.go new file mode 100644 index 0000000..bb81d84 --- /dev/null +++ b/internal/logic/datahub/data_source_record_test.go @@ -0,0 +1,19 @@ +package datahub + +import ( + "context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/tdengine" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + _ "github.com/taosdata/driver-go/v3/taosRestful" +) + +func TestGetForTpl(t *testing.T) { + out, err := service.DataSourceRecord().GetForTpl(context.TODO(), 43, 9) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} diff --git a/internal/logic/datahub/data_source_test.go b/internal/logic/datahub/data_source_test.go new file mode 100644 index 0000000..d26a425 --- /dev/null +++ b/internal/logic/datahub/data_source_test.go @@ -0,0 +1,49 @@ +package datahub + +import ( + "context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/tdengine" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + _ "github.com/taosdata/driver-go/v3/taosRestful" +) + +func TestAllSource(t *testing.T) { + out, err := service.DataSource().AllSource(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestGetAllDataS(t *testing.T) { + in := &model.SourceDataAllInput{ + SourceId: 45, + Param: map[string]interface{}{ + "pr1=?": "aaa", + }, + } + out, err := service.DataSource().GetAllData(context.TODO(), in) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestUpdateDataS(t *testing.T) { + err := service.DataSource().UpdateData(context.TODO(), 84) + if err != nil { + t.Fatal(err) + } +} + +func TestGetDbData(t *testing.T) { + out, err := service.DataSource().GetDbData(context.TODO(), 77) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} diff --git a/internal/logic/datahub/data_table.go b/internal/logic/datahub/data_table.go new file mode 100644 index 0000000..0f0e574 --- /dev/null +++ b/internal/logic/datahub/data_table.go @@ -0,0 +1,180 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + "strings" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +// 数据表名称 +func getTableName(sourceId uint64) string { + return "data_source_" + strconv.FormatUint(sourceId, 10) +} + +// 生成数据表结构 +func createTable(ctx context.Context, sourceId uint64) (table string, err error) { + table = getTableName(sourceId) + + isExsit := checkTableExsit(ctx, table) + if isExsit { + err = gerror.New("数据表" + table + "已存在") + return + } + + // 获取节点 + nodeList, err := service.DataNode().List(ctx, sourceId) + if err != nil { + return + } + if len(nodeList) == 0 { + err = gerror.New("该数据源还未创建数据节点") + return + } + + pk := "" + columns := make([]string, len(nodeList)+1) + for i, v := range nodeList { + switch v.DataType { + case "int": + columns[i] = "`" + v.Key + "` int(11) DEFAULT 0 COMMENT '" + v.Name + "'" + case "long": + columns[i] = "`" + v.Key + "` bigint(20) DEFAULT 0 COMMENT '" + v.Name + "'" + case "float": + columns[i] = "`" + v.Key + "` float DEFAULT 0 COMMENT '" + v.Name + "'" + case "double": + columns[i] = "`" + v.Key + "` double DEFAULT 0 COMMENT '" + v.Name + "'" + case "string": + columns[i] = "`" + v.Key + "` varchar(255) DEFAULT '' COMMENT '" + v.Name + "'" + case "boolean": + columns[i] = "`" + v.Key + "` tinyint DEFAULT 0 COMMENT '" + v.Name + "'" + case "date": + columns[i] = "`" + v.Key + "` datetime DEFAULT NULL COMMENT '" + v.Name + "'" + default: + columns[i] = "`" + v.Key + "` varchar(255) DEFAULT '' COMMENT '" + v.Name + "'" + } + + // 主键 + if v.IsPk == 1 { + pk = ", primary key (`" + v.Key + "`)" + } + } + columns[len(nodeList)] = "`created_at` datetime DEFAULT NULL COMMENT '创建时间'" + + sql := "CREATE TABLE " + table + " ( " + strings.Join(columns, ",") + pk + " );" + _, err = g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return + } + + return +} + +// 表删除 +func dropTable(ctx context.Context, sourceId uint64) error { + table := getTableName(sourceId) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return nil + } + + sql := "DROP TABLE " + table + _, err := g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return err + } + return nil +} + +// 字段增加 +func addColumn(ctx context.Context, nodeId uint64) (err error) { + var p *entity.DataNode + err = dao.DataNode.Ctx(ctx).Where(dao.DataNode.Columns().NodeId, nodeId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("数据节点不存在") + } + + table := getTableName(p.SourceId) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return gerror.New("数据表" + table + "不存在") + } + + column := "" + + switch p.DataType { + case "int": + column = "`" + p.Key + "` int(11) DEFAULT 0 COMMENT '" + p.Name + "'" + case "long": + column = "`" + p.Key + "` bigint(20) DEFAULT 0 COMMENT '" + p.Name + "'" + case "float": + column = "`" + p.Key + "` float DEFAULT 0 COMMENT '" + p.Name + "'" + case "double": + column = "`" + p.Key + "` double DEFAULT 0 COMMENT '" + p.Name + "'" + case "string": + column = "`" + p.Key + "` varchar(255) DEFAULT '' COMMENT '" + p.Name + "'" + case "boolean": + column = "`" + p.Key + "` tinyint DEFAULT 0 COMMENT '" + p.Name + "'" + case "date": + column = "`" + p.Key + "` datetime DEFAULT NULL COMMENT '" + p.Name + "'" + default: + column = "`" + p.Key + "` varchar(255) DEFAULT '' COMMENT '" + p.Name + "'" + } + + sql := "ALTER TABLE " + table + " ADD COLUMN " + column + _, err = g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return err + } + return nil +} + +// 字段删除 +func dropColumn(ctx context.Context, nodeId uint64) (err error) { + var p *entity.DataNode + err = dao.DataNode.Ctx(ctx).Where(dao.DataNode.Columns().NodeId, nodeId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("数据节点不存在") + } + + table := getTableName(p.SourceId) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return gerror.New("数据表" + table + "不存在") + } + + sql := "ALTER TABLE " + table + " DROP `" + p.Key + "`" + _, err = g.DB(DataCenter()).Exec(ctx, sql) + + return err +} + +// 检查表是否存在, true:已存在,false:不存在 +func checkTableExsit(ctx context.Context, table string) bool { + sql := "select * from information_schema.tables where table_name = ? and table_schema = (select database()) limit 1" + one, _ := g.DB(DataCenter()).GetOne(ctx, sql, table) + return one != nil +} + +// 获取数据库分组 +func DataCenter() string { + name, _ := g.Cfg().Get(context.TODO(), "database.dataCenter.link") + if name.String() != "" { + return "dataCenter" + } + return "" +} diff --git a/internal/logic/datahub/data_table_test.go b/internal/logic/datahub/data_table_test.go new file mode 100644 index 0000000..3fe9adf --- /dev/null +++ b/internal/logic/datahub/data_table_test.go @@ -0,0 +1,16 @@ +package datahub + +import ( + "context" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" +) + +func TestCreateTable(t *testing.T) { + table, err := createTable(context.TODO(), 1) + if err != nil { + t.Fatal(err) + } + t.Log(table) +} diff --git a/internal/logic/datahub/data_template.go b/internal/logic/datahub/data_template.go new file mode 100644 index 0000000..221d24f --- /dev/null +++ b/internal/logic/datahub/data_template.go @@ -0,0 +1,720 @@ +package datahub + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "reflect" + "strings" + + "github.com/go-gota/gota/dataframe" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDataTemplate struct{} + +func init() { + service.RegisterDataTemplate(dataTemplateNew()) +} + +func dataTemplateNew() *sDataTemplate { + return &sDataTemplate{} +} + +func (s *sDataTemplate) Add(ctx context.Context, in *model.DataTemplateAddInput) (id uint64, err error) { + tid, _ := dao.DataTemplate.Ctx(ctx). + Fields(dao.DataTemplate.Columns().Id). + Where(dao.DataTemplate.Columns().Key, in.Key). + Value() + if tid.Int64() > 0 { + err = gerror.New("数据模型标识重复") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataTemplate + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + param.LockKey = 0 + + rs, err := dao.DataTemplate.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + + newId, _ := rs.LastInsertId() + id = uint64(newId) + + return +} + +func (s *sDataTemplate) Edit(ctx context.Context, in *model.DataTemplateEditInput) (err error) { + out, err := s.Detail(ctx, in.Id) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据模型不存在") + } + if out.Status == model.DataTemplateStatusOn { + return gerror.New("数据模型已发布,请先撤回") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataTemplate + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.Id = nil + if out.LockKey == 1 { + param.Key = nil + } else { + id, _ := dao.DataTemplate.Ctx(ctx). + Fields(dao.DataTemplate.Columns().Id). + Where(dao.DataTemplate.Columns().Key, in.Key). + WhereNot(dao.DataTemplate.Columns().Id, in.Id). + Value() + if id.Int64() > 0 { + err = gerror.New("数据模型标识重复") + return + } + } + + err = dao.DataTemplate.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DataTemplate.Ctx(ctx). + Data(param). + Where(dao.DataTemplate.Columns().Id, in.Id). + Update() + if err != nil { + return err + } + + // 同步聚合时间到定时任务管理 + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataTemplate-" + gconv.String(out.Id) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) > 0 { + editJob := new(model.SysJobEditInput) + editJob.JobName = list[0].JobName + editJob.JobParams = list[0].JobParams + editJob.JobGroup = list[0].JobGroup + editJob.InvokeTarget = list[0].InvokeTarget + editJob.CronExpression = in.CronExpression + editJob.MisfirePolicy = list[0].MisfirePolicy + editJob.Concurrent = list[0].Concurrent + editJob.Status = list[0].Status + editJob.Remark = list[0].Remark + editJob.JobId = list[0].JobId + editJob.UpdateBy = uint64(loginUserId) + err = service.SysJob().EditJob(ctx, editJob) + if err != nil { + return err + } + } + + // 绑定业务 + err = service.DataTemplateBusi().Add(ctx, &model.DataTemplateBusiAddInput{ + DataTemplateId: in.Id, + BusiTypes: in.BusiTypes, + }) + + return err + }) + + return +} + +func (s *sDataTemplate) Del(ctx context.Context, ids []uint64) (err error) { + var p []*entity.DataTemplate + err = dao.DataTemplate.Ctx(ctx).WhereIn(dao.DataTemplate.Columns().Id, ids).Scan(&p) + if len(p) == 0 { + return gerror.New("数据模型不存在") + } + if len(p) == 1 && p[0].Status == model.DataTemplateStatusOn { + return gerror.New("数据模型已发布,请先撤回,再删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataTemplate.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 删除数据模型 + var delIds []uint64 + for _, id := range ids { + rs, err := dao.DataTemplate.Ctx(ctx). + Data(do.DataTemplate{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataTemplate.Columns().Id, id). + Where(dao.DataTemplate.Columns().Status, model.DataTemplateStatusOff). + Unscoped(). + Update() + if err != nil { + return err + } + + num, _ := rs.RowsAffected() + if num > 0 { + delIds = append(delIds, id) + } + } + + // 删除数据模型节点 + for _, id := range delIds { + _, err = dao.DataTemplateNode.Ctx(ctx). + Data(do.DataTemplateNode{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataTemplateNode.Columns().Tid, id). + Unscoped(). + Update() + if err != nil { + return err + } + } + + // 删除定时任务、删除数据表 + for _, id := range delIds { + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataTemplate-" + gconv.String(id) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) != 0 { + err = service.SysJob().DeleteJobByIds(ctx, []int{int(list[0].JobId)}) + } + + if err = dropTplTable(ctx, id); err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataTemplate) Search(ctx context.Context, in *model.DataTemplateSearchInput) (out *model.DataTemplateSearchOutput, err error) { + out = new(model.DataTemplateSearchOutput) + c := dao.DataTemplate.Columns() + m := dao.DataTemplate.Ctx(ctx).WithAll().OrderDesc(c.Id) + + if in.Key != "" { + m = m.Where(c.Key, in.Key) + } + if in.Name != "" { + m = m.WhereLike(c.Name, "%"+in.Name+"%") + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + if err = m.Page(in.PageNum, in.PageSize).Scan(&out.List); err != nil { + return + } + + for k, v := range out.List { + if len(v.DataTemplateBusi) > 0 { + for _, bs := range v.DataTemplateBusi { + out.List[k].BusiTypes = append(out.List[k].BusiTypes, bs.BusiTypes) + } + } + } + + return +} + +func (s *sDataTemplate) List(ctx context.Context) (list []*entity.DataTemplate, err error) { + c := dao.DataTemplate.Columns() + err = dao.DataTemplate.Ctx(ctx).Where(c.Status, model.DataTemplateStatusOn).OrderDesc(c.Id).Scan(&list) + return +} + +func (s *sDataTemplate) Detail(ctx context.Context, id uint64) (out *model.DataTemplateOutput, err error) { + err = dao.DataTemplate.Ctx(ctx).Where(dao.DataTemplate.Columns().Id, id).Scan(&out) + return +} + +func (s *sDataTemplate) Deploy(ctx context.Context, id uint64) (err error) { + out, err := s.Detail(ctx, id) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据模型不存在") + } + if out.Status == model.DataTemplateStatusOn { + return gerror.New("数据模型已发布") + } + + // 获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataTemplate.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 创建表结构 + table := "" + if out.DataTable == "" { + table, err = createTplTable(ctx, id) + if err != nil { + return err + } + } + + m := g.Map{ + dao.DataTemplate.Columns().Status: model.DataTemplateStatusOn, + dao.DataTemplate.Columns().LockKey: 1, + } + if table != "" { + m[dao.DataTemplate.Columns().DataTable] = table + } + + _, err = dao.DataTemplate.Ctx(ctx). + Data(m). + Where(dao.DataTemplate.Columns().Id, id). + Update() + + return err + }) + if err != nil { + return err + } + + // 开启数据更新任务,任务排重 +Job: + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataTemplate-" + gconv.String(id) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) == 0 { + sysJob := new(model.SysJobAddInput) + sysJob.JobName = "dataTemplate-" + gconv.String(id) + sysJob.JobParams = gconv.String(id) + sysJob.JobGroup = "dataSourceJob" + sysJob.InvokeTarget = "dataTemplate" + sysJob.CronExpression = out.CronExpression + sysJob.MisfirePolicy = 1 + sysJob.Concurrent = 0 + sysJob.Status = 0 + sysJob.Remark = out.Name + sysJob.CreateBy = uint64(loginUserId) + err = service.SysJob().AddJob(ctx, sysJob) + goto Job + } + err = service.SysJob().JobStart(ctx, list[0]) + // 初始执行一次 + err = service.SysJob().JobRun(ctx, list[0]) + + return +} + +func (s *sDataTemplate) Undeploy(ctx context.Context, id uint64) (err error) { + out, err := s.Detail(ctx, id) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据模型不存在") + } + if out.Status == model.DataTemplateStatusOff { + return gerror.New("数据模型已停用") + } + + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{dao.DataTemplate.Columns().Status: model.DataTemplateStatusOff}). + Where(dao.DataTemplate.Columns().Id, id). + Update() + if err != nil { + return err + } + + // 关闭数据更新任务 + job := new(model.GetJobListInput) + job.JobGroup = "dataSourceJob" + job.JobName = "dataTemplate-" + gconv.String(id) + job.PaginationInput = &model.PaginationInput{PageNum: 1, PageSize: 1} + _, list, _ := service.SysJob().JobList(ctx, job) + if len(list) == 0 { + return + } + err = service.SysJob().JobStop(ctx, list[0]) + + return +} + +// GetData 获取数据模型的聚合数据 +func (s *sDataTemplate) GetData(ctx context.Context, in *model.DataTemplateDataInput) (out *model.DataTemplateDataOutput, err error) { + dt, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if dt == nil { + err = gerror.New("数据模型不存在") + return + } + + sortNode := "created_at desc" + if dt.SortNodeKey != "" { + sortDesc := "desc" + if dt.SortDesc == 2 { + sortDesc = "asc" + } + sortNode = dt.SortNodeKey + " " + sortDesc + } + + out = new(model.DataTemplateDataOutput) + + table := getTplTableName(in.Id) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " where " + strings.Join(exp, " and ") + } + + sql := "select * from " + table + where + " order by " + sortNode + + out.Total, _ = g.DB(DataCenter()).GetCount(ctx, sql, value...) + out.CurrentPage = in.PageNum + + sql += fmt.Sprintf(" limit %d, %d", (in.PageNum-1)*in.PageSize, in.PageSize) + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + out.List = rs.Json() + + return +} + +// 获取数据模型的聚合数据,不分页 +func (s *sDataTemplate) GetAllData(ctx context.Context, in *model.TemplateDataAllInput) (out *model.TemplateDataAllOutput, err error) { + dt, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if dt == nil { + err = gerror.New("数据模型不存在") + return + } + + sortNode := "CREATED_AT ASC" + if dt.SortNodeKey != "" { + sortDesc := "DESC" + if dt.SortDesc == 2 { + sortDesc = "ASC" + } + sortNode = dt.SortNodeKey + " " + sortDesc + } + + out = new(model.TemplateDataAllOutput) + + table := getTplTableName(in.Id) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " WHERE " + strings.Join(exp, " AND ") + } + + sql := "SELECT * FROM " + table + where + " ORDER BY " + sortNode + rs, err := g.DB(DataCenter()).GetAll(ctx, sql, value...) + if err != nil { + return + } + err = gconv.Scan(rs.List(), &out.List) + + return +} + +// 获取数据,返回dataframe +func (s *sDataTemplate) GetDataBySql(ctx context.Context, sql string) (df dataframe.DataFrame, err error) { + rs, err := g.DB(DataCenter()).GetAll(ctx, sql) + if err != nil { + return + } + df = dataframe.LoadMaps(rs.List()) + return +} + +// GetDataByTableName 获取数据,返回dataframe +func (s *sDataTemplate) GetDataByTableName(ctx context.Context, tableName string) (df dataframe.DataFrame, err error) { + rs, err := g.DB(DataCenter()).Model(tableName).All() + if err != nil { + return + } + df = dataframe.LoadMaps(rs.List()) + return +} + +// 获取最后一条记录 +func (s *sDataTemplate) GetLastData(ctx context.Context, in *model.TemplateDataLastInput) (out *model.TemplateDataLastOutput, err error) { + dt, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if dt == nil { + err = gerror.New("数据模型不存在") + return + } + + sortNode := "CREATED_AT DESC" + + out = new(model.TemplateDataLastOutput) + + table := getTplTableName(in.Id) + + // 搜索条件 + var exp []string + var value []any + if in.Param != nil { + for k, v := range in.Param { + exp = append(exp, k) + if reflect.TypeOf(v).Kind() == reflect.Slice { + s := reflect.ValueOf(v) + for i := 0; i < s.Len(); i++ { + ele := s.Index(i) + value = append(value, ele.Interface()) + } + } else { + value = append(value, v) + } + } + } + where := "" + if len(exp) > 0 { + where = " WHERE " + strings.Join(exp, " AND ") + } + + sql := "SELECT * FROM " + table + where + " ORDER BY " + sortNode + " LIMIT 1" + rs, err := g.DB(DataCenter()).GetOne(ctx, sql, value...) + if err != nil { + return + } + err = gconv.Scan(rs, &out.Data) + + return +} + +// 更新数据记录,定时任务触发 +func (s *sDataTemplate) UpdateData(ctx context.Context, id uint64) error { + err := service.DataTemplateRecord().UpdateData(ctx, id) + return err +} + +func (s *sDataTemplate) GetInfoByIds(ctx context.Context, ids []uint64) (data []*entity.DataTemplate, err error) { + var p []*entity.DataTemplate + err = dao.DataTemplate.Ctx(ctx).WhereIn(dao.DataTemplate.Columns().Id, ids).Where(g.Map{ + dao.DataTemplate.Columns().Status: 1, + }).Scan(&p) + if err != nil { + return + } + if p == nil { + return + } + return p, err +} + +// 数据模型获取数据的内网方法列表,供大屏使用 +func (s *sDataTemplate) AllTemplate(ctx context.Context) (out []*model.AllTemplateOut, err error) { + err = dao.DataTemplate.Ctx(ctx). + Where(dao.DataTemplate.Columns().Status, model.DataTemplateStatusOn). + OrderDesc(dao.DataTemplate.Columns().Id). + Scan(&out) + if err != nil { + return + } + + for _, v := range out { + v.Path = "GetAllData?pageNum=1&pageSize=10&id=" + gconv.String(v.Id) + } + + return +} + +// 更新数据聚合时长 +func (s *sDataTemplate) UpdateInterval(ctx context.Context, id uint64, cronExpression string) (err error) { + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{ + dao.DataTemplate.Columns().CronExpression: cronExpression, + }). + Where(dao.DataTemplate.Columns().Id, id). + Update() + + return +} + +// 复制数据模型 +func (s *sDataTemplate) CopeTemplate(ctx context.Context, id uint64) (err error) { + out, err := s.Detail(ctx, id) + if err != nil { + return err + } + if out == nil { + return gerror.New("数据模型不存在") + } + + err = dao.DataTemplate.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + // 复制模型 + in := new(model.DataTemplateAddInput) + + err = gconv.Scan(out, &in) + if err != nil { + return err + } + in.Key += "_" + gtime.Now().Format("YmdHis") + + newId, err := s.Add(ctx, in) + if err != nil { + return err + } + + // 复制节点 + tplNodes, err := service.DataTemplateNode().List(ctx, id) + if err != nil || len(tplNodes) == 0 { + return err + } + + for _, v := range tplNodes { + var in *model.DataTemplateNodeAddInput + err = gconv.Scan(v.DataTemplateNode, &in) + if err != nil { + return err + } + in.Tid = newId + in.IsSorting = v.IsSorting + in.IsDesc = v.IsDesc + + err = service.DataTemplateNode().Add(ctx, in) + if err != nil { + return err + } + } + + return nil + }) + + return +} + +// 检测数据模型是否需要设置关联 +func (s *sDataTemplate) CheckRelation(ctx context.Context, id uint64) (yes bool, err error) { + rs, err := dao.DataTemplateNode.Ctx(ctx).Fields("count(distinct source_id)").Where(dao.DataTemplateNode.Columns().Tid, id).Value() + if err != nil || rs.Int() <= 1 { + return + } + + dt, err := s.Detail(ctx, id) + if err != nil { + return + } + if dt == nil { + err = gerror.New("数据模型不存在") + return + } + + if dt.MainSourceId == 0 || dt.SourceNodeKey == "" { + yes = true + } + + return +} + +// 设置主源、关联字段 +func (s *sDataTemplate) SetRelation(ctx context.Context, in *model.TemplateDataRelationInput) (err error) { + dt, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if dt == nil { + return gerror.New("数据模型不存在") + } + if dt.Status == model.DataTemplateStatusOn { + return gerror.New("数据模型已发布,请先撤回") + } + + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{ + dao.DataTemplate.Columns().MainSourceId: in.MainSourceId, + dao.DataTemplate.Columns().SourceNodeKey: in.SourceNodeKey, + }). + Where(dao.DataTemplate.Columns().Id, in.Id). + Update() + return +} + +// 数据源列表 +func (s *sDataTemplate) SourceList(ctx context.Context, id uint64) (list []*model.DataSourceOutput, err error) { + rs, err := dao.DataTemplateNode.Ctx(ctx).Fields("source_id"). + Where(dao.DataTemplateNode.Columns().Tid, id). + Group(dao.DataTemplateNode.Columns().SourceId). + Array() + if err != nil || len(rs) == 0 { + return + } + + for _, v := range rs { + ds, err := service.DataSource().Detail(ctx, v.Uint64()) + if err != nil { + return nil, err + } + list = append(list, ds) + } + + return +} diff --git a/internal/logic/datahub/data_template_busi.go b/internal/logic/datahub/data_template_busi.go new file mode 100644 index 0000000..89ae482 --- /dev/null +++ b/internal/logic/datahub/data_template_busi.go @@ -0,0 +1,81 @@ +package datahub + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +type sDataTemplateBusi struct{} + +func init() { + service.RegisterDataTemplateBusi(dataTemplateBusiNew()) +} + +func dataTemplateBusiNew() *sDataTemplateBusi { + return &sDataTemplateBusi{} +} + +func (s *sDataTemplateBusi) Add(ctx context.Context, in *model.DataTemplateBusiAddInput) (err error) { + if len(in.BusiTypes) == 0 { + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + c := dao.DataTemplateBusi.Columns() + for _, v := range in.BusiTypes { + id, _ := dao.DataTemplateBusi.Ctx(ctx). + Where(c.BusiTypes, v). + Value("id") + if id.Int() > 0 { + continue + } + + param := do.DataTemplateBusi{ + DataTemplateId: in.DataTemplateId, + BusiTypes: v, + CreatedBy: uint(loginUserId), + } + _, err = dao.DataTemplateBusi.Ctx(ctx).Data(param).Insert() + } + + return +} + +func (s *sDataTemplateBusi) GetInfos(ctx context.Context, busiTypes int) (data *entity.DataTemplateBusi, err error) { + err = dao.DataTemplateBusi.Ctx(ctx).Where(g.Map{ + dao.DataTemplateBusi.Columns().BusiTypes: busiTypes, + dao.DataTemplateBusi.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +func (s *sDataTemplateBusi) GetInfo(ctx context.Context, busiTypes int) (data *entity.DataTemplateBusi, err error) { + err = dao.DataTemplateBusi.Ctx(ctx).Where(g.Map{ + dao.DataTemplateBusi.Columns().BusiTypes: busiTypes, + dao.DataTemplateBusi.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +func (s *sDataTemplateBusi) GetTable(ctx context.Context, busiTypes int) (table string, err error) { + busi, err := s.GetInfos(ctx, busiTypes) + if err != nil { + return + } + if busi == nil { + err = gerror.New("未绑定数据模型") + return + } + table = fmt.Sprintf("data_template_%d", busi.DataTemplateId) + return +} diff --git a/internal/logic/datahub/data_template_node.go b/internal/logic/datahub/data_template_node.go new file mode 100644 index 0000000..68c1995 --- /dev/null +++ b/internal/logic/datahub/data_template_node.go @@ -0,0 +1,209 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDataTemplateNode struct{} + +func init() { + service.RegisterDataTemplateNode(dataTemplateNodeNew()) +} + +func dataTemplateNodeNew() *sDataTemplateNode { + return &sDataTemplateNode{} +} + +func (s *sDataTemplateNode) Add(ctx context.Context, in *model.DataTemplateNodeAddInput) (err error) { + id, _ := dao.DataTemplateNode.Ctx(ctx). + Fields(dao.DataTemplateNode.Columns().Id). + Where(dao.DataTemplateNode.Columns().Tid, in.Tid). + Where(dao.DataTemplateNode.Columns().Key, in.Key). + Value() + if id.Int64() > 0 { + return gerror.New("数据模型节点标识重复") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataTemplateNode + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + if in.Method == "" { + param.Method = nil + } + + err = dao.DataTemplateNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + rs, err := dao.DataTemplateNode.Ctx(ctx).Data(param).Insert() + if err != nil { + return err + } + + nodeId, _ := rs.LastInsertId() + + dataTemplate, _ := service.DataTemplate().Detail(ctx, in.Tid) + if dataTemplate != nil && dataTemplate.DataTable != "" { + // 表结构已存在,字段新增 + err = addTplColumn(ctx, uint64(nodeId)) + if err != nil { + return err + } + } + + // 处理排序字段 + if in.IsSorting == 1 { + c := dao.DataTemplate.Columns() + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{c.SortNodeKey: in.Key, c.SortDesc: in.IsDesc}). + Where(c.Id, in.Tid). + Update() + if err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataTemplateNode) Edit(ctx context.Context, in *model.DataTemplateNodeEditInput) (err error) { + var p *entity.DataTemplateNode + err = dao.DataTemplateNode.Ctx(ctx).Where(dao.DataTemplateNode.Columns().Id, in.Id).Scan(&p) + if p == nil { + return gerror.New("数据模型节点不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DataTemplateNode + err = gconv.Scan(in, ¶m) + param.UpdateBy = uint(loginUserId) + param.Id = nil + if in.SourceId == p.SourceId { + param.SourceId = nil + if in.NodeId == p.NodeId { + param.NodeId = nil + } + } + + err = dao.DataTemplateNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DataTemplateNode.Ctx(ctx).Data(param).Where(dao.DataTemplateNode.Columns().Id, in.Id).Update() + if err != nil { + return err + } + + // 处理排序字段 + sortNode := "" + sortDesc := 0 + if in.IsSorting == 1 { + sortNode = p.Key + sortDesc = in.IsDesc + } + c := dao.DataTemplate.Columns() + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{c.SortNodeKey: sortNode, c.SortDesc: sortDesc}). + Where(c.Id, p.Tid). + WhereNot(c.SortNodeKey, sortNode). + Update() + return err + }) + + return +} + +func (s *sDataTemplateNode) Del(ctx context.Context, id uint64) (err error) { + var p *entity.DataTemplateNode + err = dao.DataTemplateNode.Ctx(ctx).Where(dao.DataTemplateNode.Columns().Id, id).Scan(&p) + if p == nil { + return gerror.New("数据模型节点不存在") + } + + var dt *entity.DataTemplate + err = dao.DataTemplate.Ctx(ctx).Where(dao.DataTemplate.Columns().Id, p.Tid).Scan(&dt) + if err != nil { + return + } + if dt != nil && dt.Status != model.DataTemplateStatusOff { + return gerror.New("数据模型已发布,请先撤回,再删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + err = dao.DataTemplateNode.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + if dt != nil && dt.DataTable != "" { + // 表结构已存在,字段须删除处理 + if err = dropTplColumn(ctx, id); err != nil { + return err + } + } + + _, err = dao.DataTemplateNode.Ctx(ctx). + Data(do.DataTemplateNode{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DataTemplateNode.Columns().Id, id). + Unscoped(). + Update() + if err != nil { + return err + } + + // 处理排序字段 + if dt.SortNodeKey == p.Key { + c := dao.DataTemplate.Columns() + _, err = dao.DataTemplate.Ctx(ctx). + Data(g.Map{c.SortNodeKey: "", c.SortDesc: 0}). + Where(c.Id, p.Tid). + Update() + if err != nil { + return err + } + } + + return nil + }) + + return +} + +func (s *sDataTemplateNode) List(ctx context.Context, tid uint64) (list []*model.DataTemplateNodeOutput, err error) { + err = dao.DataTemplateNode.Ctx(ctx).WithAll().OrderAsc(dao.DataTemplateNode.Columns().Id).Where(dao.DataTemplateNode.Columns().Tid, tid).Scan(&list) + if err != nil || len(list) == 0 { + return + } + + dt, err := service.DataTemplate().Detail(ctx, tid) + if err != nil || dt == nil { + return + } + + for _, v := range list { + if dt.SortNodeKey == v.Key { + v.IsSorting = 1 + v.IsDesc = dt.SortDesc + break + } + } + + return +} diff --git a/internal/logic/datahub/data_template_record.go b/internal/logic/datahub/data_template_record.go new file mode 100644 index 0000000..e2ace02 --- /dev/null +++ b/internal/logic/datahub/data_template_record.go @@ -0,0 +1,230 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/guid" +) + +type sDataTemplateRecord struct{} + +func init() { + service.RegisterDataTemplateRecord(dataTemplateRecordNew()) +} + +func dataTemplateRecordNew() *sDataTemplateRecord { + return &sDataTemplateRecord{} +} + +// 更新数据记录,定时任务触发 +func (s *sDataTemplateRecord) UpdateData(ctx context.Context, tid uint64) error { + dt, err := service.DataTemplate().Detail(ctx, tid) + if err != nil { + return err + } + if dt == nil { + return gerror.New("数据模型不存在") + } + + // 获取节点 + tplNodes, err := service.DataTemplateNode().List(ctx, tid) + if err != nil { + return err + } + if len(tplNodes) == 0 { + return gerror.New("数据模型未创建模型节点") + } + + // 合并数据 + var insertData []*gmap.AnyAnyMap + if dt.MainSourceId > 0 && dt.SourceNodeKey != "" { + if insertData, err = s.mergeForRelation(ctx, dt, tplNodes); err != nil { + return err + } + } else { + if insertData, err = s.merge(ctx, dt, tplNodes); err != nil { + return err + } + } + + // 入库 + if len(insertData) > 0 { + table := getTplTableName(tid) + if err = g.DB(DataCenter()).GetCore().ClearTableFields(ctx, table); err != nil { + return err + } + for i := 0; i < len(insertData); i = i + 1000 { + s := 1000 + i + if len(insertData)-i < 1000 { + s = len(insertData) + } + d := insertData[i:s] + if _, err = g.DB(DataCenter()).Save(ctx, table, d); err != nil { + return err + } + } + } + + return nil +} + +// 按关联字段合并 +func (s *sDataTemplateRecord) mergeForRelation(ctx context.Context, dt *model.DataTemplateOutput, nodes []*model.DataTemplateNodeOutput) (data []*gmap.AnyAnyMap, err error) { + // 统计数据源 + sourceIds := make(map[uint64]struct{}) + for _, node := range nodes { + if node.SourceId > 0 { + sourceIds[node.SourceId] = struct{}{} + } + } + if len(sourceIds) == 0 { + err = gerror.New("数据模型未关联数据源节点") + return + } + + // 获取数据源数据 + var mainSource map[string]*gmap.StrAnyMap + recordData := make(map[uint64]map[string]*gmap.StrAnyMap) + for sid := range sourceIds { + rs, err := s.getSourceRecordForRelation(ctx, sid, dt, nodes) + if err != nil { + return nil, err + } + recordData[sid] = rs + + if sid == dt.MainSourceId || len(sourceIds) == 1 { + mainSource = rs + } + } + + // 合并数据 + for rKey, row := range mainSource { + m := gmap.New() + for _, node := range nodes { + if node.From == 2 { + // 数据源关联节点 + if node.SourceId == dt.MainSourceId { + m.Set(node.Key, row.Get(node.Key)) + } else { + if row, ok := recordData[node.SourceId]; ok { + if rowD, ok := row[rKey]; ok { + m.Set(node.Key, rowD.Get(node.Key)) + } else { + m.Set(node.Key, "") + } + } + } + } else { + // 自定义节点 + if node.Default != "" { + m.Set(node.Key, node.Default) + } else { + m.Set(node.Key, guid.S()) + } + } + } + data = append(data, m) + } + return +} + +func (s *sDataTemplateRecord) getSourceRecordForRelation(ctx context.Context, sourceId uint64, dt *model.DataTemplateOutput, nodes []*model.DataTemplateNodeOutput) (rs map[string]*gmap.StrAnyMap, err error) { + data, err := service.DataSourceRecord().GetForTpl(ctx, sourceId, dt.Id) + if err != nil { + return + } + + rs = make(map[string]*gmap.StrAnyMap, data.Len()) + for i, row := range data { + m := gmap.NewStrAnyMap() + for _, node := range nodes { + if node.From == 2 && node.SourceId == sourceId { + m.Set(node.Key, row[node.Node.Key]) + } + } + + relationKey := row[dt.SourceNodeKey].String() + if relationKey == "" { + relationKey = strconv.Itoa(i) + } + rs[relationKey] = m + } + + return +} + +// 按索引行合并 +func (s *sDataTemplateRecord) merge(ctx context.Context, dt *model.DataTemplateOutput, nodes []*model.DataTemplateNodeOutput) (data []*gmap.AnyAnyMap, err error) { + // 统计数据源 + sourceIds := make(map[uint64]struct{}) + for _, node := range nodes { + if node.SourceId > 0 { + sourceIds[node.SourceId] = struct{}{} + } + } + if len(sourceIds) == 0 { + err = gerror.New("数据模型未关联数据源节点") + return + } + + // 聚合数据源数据 + recordNum := 0 + recordData := make(map[uint64][]*gmap.StrAnyMap) + for sid := range sourceIds { + rs, err := s.getSourceRecord(ctx, sid, dt.Id, nodes) + if err != nil { + return nil, err + } + if recordNum == 0 { + recordNum = len(rs) + } + recordData[sid] = rs + } + + // 合并数据 + for i := 0; i < recordNum; i++ { + m := gmap.New() + for _, node := range nodes { + if node.From == 2 { + // 数据源关联节点 + if row, ok := recordData[node.SourceId]; ok { + m.Set(node.Key, row[i].Get(node.Key)) + } + } else { + // 自定义节点 + if node.Default != "" { + m.Set(node.Key, node.Default) + } else { + m.Set(node.Key, guid.S()) + } + } + } + data = append(data, m) + } + return +} + +func (s *sDataTemplateRecord) getSourceRecord(ctx context.Context, sourceId uint64, tid uint64, nodes []*model.DataTemplateNodeOutput) (rs []*gmap.StrAnyMap, err error) { + data, err := service.DataSourceRecord().GetForTpl(ctx, sourceId, tid) + if err != nil { + return + } + + for _, row := range data { + m := gmap.NewStrAnyMap() + for _, node := range nodes { + if node.From == 2 && node.SourceId == sourceId { + m.Set(node.Key, row[node.Node.Key]) + } + } + rs = append(rs, m) + } + + return +} diff --git a/internal/logic/datahub/data_template_record_test.go b/internal/logic/datahub/data_template_record_test.go new file mode 100644 index 0000000..a9de093 --- /dev/null +++ b/internal/logic/datahub/data_template_record_test.go @@ -0,0 +1,16 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" +) + +func TestUpdateDataRecord(t *testing.T) { + err := service.DataTemplateRecord().UpdateData(context.TODO(), 10) + if err != nil { + t.Fatal(err) + } +} diff --git a/internal/logic/datahub/data_template_table.go b/internal/logic/datahub/data_template_table.go new file mode 100644 index 0000000..711f98b --- /dev/null +++ b/internal/logic/datahub/data_template_table.go @@ -0,0 +1,181 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + "strings" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" +) + +// 数据表名称 +func getTplTableName(id uint64) string { + return "data_template_" + strconv.FormatUint(id, 10) +} + +// 生成数据表结构 +func createTplTable(ctx context.Context, id uint64) (table string, err error) { + table = getTplTableName(id) + + isExsit := checkTableExsit(ctx, table) + if isExsit { + err = gerror.New("数据表" + table + "已存在") + return + } + + // 获取节点 + tplNodes, err := service.DataTemplateNode().List(ctx, id) + if err != nil { + return + } + if len(tplNodes) == 0 { + err = gerror.New("该数据模型还未创建模型节点") + return + } + + pk := "" + columns := make([]string, len(tplNodes)+1) + for i, v := range tplNodes { + // 节点默认值,主要处理自动生成的节点 + df := "DEFAULT 0" + if v.DataType == "string" { + df = "DEFAULT ''" + } + if v.From == 1 && v.Default != "" { + df = "DEFAULT '" + v.Default + "'" + } + + switch v.DataType { + case "int": + columns[i] = "`" + v.Key + "` int(11) " + df + " COMMENT '" + v.Name + "'" + case "long": + columns[i] = "`" + v.Key + "` bigint(20) " + df + " COMMENT '" + v.Name + "'" + case "float": + columns[i] = "`" + v.Key + "` float " + df + " COMMENT '" + v.Name + "'" + case "double": + columns[i] = "`" + v.Key + "` double " + df + " COMMENT '" + v.Name + "'" + case "string": + columns[i] = "`" + v.Key + "` varchar(255) " + df + " COMMENT '" + v.Name + "'" + case "boolean": + columns[i] = "`" + v.Key + "` tinyint " + df + " COMMENT '" + v.Name + "'" + case "date": + columns[i] = "`" + v.Key + "` datetime DEFAULT NULL COMMENT '" + v.Name + "'" + default: + columns[i] = "`" + v.Key + "` varchar(255) " + df + " COMMENT '" + v.Name + "'" + } + + // 主键 + if v.IsPk == 1 { + pk = ", primary key (`" + v.Key + "`)" + } + } + columns[len(tplNodes)] = "`created_at` datetime DEFAULT NULL COMMENT '创建时间'" + + sql := "CREATE TABLE " + table + " ( " + strings.Join(columns, ",") + pk + " );" + _, err = g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return + } + + return +} + +// 表删除 +func dropTplTable(ctx context.Context, id uint64) error { + table := getTplTableName(id) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return nil + } + + sql := "DROP TABLE " + table + _, err := g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return err + } + return nil +} + +// 字段增加 +func addTplColumn(ctx context.Context, nodeId uint64) (err error) { + var p *entity.DataTemplateNode + err = dao.DataTemplateNode.Ctx(ctx).Where(dao.DataTemplateNode.Columns().Id, nodeId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("模型节点不存在") + } + + table := getTplTableName(p.Tid) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return gerror.New("数据表" + table + "不存在") + } + + // 节点默认值,主要处理自动生成的节点 + df := "DEFAULT 0" + if p.DataType == "string" { + df = "DEFAULT ''" + } + if p.From == 1 && p.Default != "" { + df = "DEFAULT '" + p.Default + "'" + } + + column := "" + switch p.DataType { + case "int": + column = "`" + p.Key + "` int(11) " + df + " COMMENT '" + p.Name + "'" + case "long": + column = "`" + p.Key + "` bigint(20) " + df + " COMMENT '" + p.Name + "'" + case "float": + column = "`" + p.Key + "` float " + df + " COMMENT '" + p.Name + "'" + case "double": + column = "`" + p.Key + "` double " + df + " COMMENT '" + p.Name + "'" + case "string": + column = "`" + p.Key + "` varchar(255) " + df + " COMMENT '" + p.Name + "'" + case "boolean": + column = "`" + p.Key + "` tinyint " + df + " COMMENT '" + p.Name + "'" + case "date": + column = "`" + p.Key + "` datetime DEFAULT NULL COMMENT '" + p.Name + "'" + default: + column = "`" + p.Key + "` varchar(255) " + df + " COMMENT '" + p.Name + "'" + } + + sql := "ALTER TABLE " + table + " ADD COLUMN " + column + _, err = g.DB(DataCenter()).Exec(ctx, sql) + if err != nil { + return err + } + return nil +} + +// 字段删除 +func dropTplColumn(ctx context.Context, nodeId uint64) (err error) { + var p *entity.DataTemplateNode + err = dao.DataTemplateNode.Ctx(ctx).Where(dao.DataTemplateNode.Columns().Id, nodeId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("数据节点不存在") + } + + table := getTplTableName(p.Tid) + + isExsit := checkTableExsit(ctx, table) + if !isExsit { + return gerror.New("数据表" + table + "不存在") + } + + sql := "ALTER TABLE " + table + " DROP `" + p.Key + "`" + _, err = g.DB(DataCenter()).Exec(ctx, sql) + + return err +} diff --git a/internal/logic/datahub/data_template_test.go b/internal/logic/datahub/data_template_test.go new file mode 100644 index 0000000..38525fd --- /dev/null +++ b/internal/logic/datahub/data_template_test.go @@ -0,0 +1,76 @@ +package datahub + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" +) + +func TestAllTemplate(t *testing.T) { + out, err := service.DataTemplate().AllTemplate(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestGetAllData(t *testing.T) { + in := &model.TemplateDataAllInput{ + Id: 4, + Param: map[string]interface{}{ + "city like ?": "%北京%", + }, + } + out, err := service.DataTemplate().GetAllData(context.TODO(), in) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestGetLastData(t *testing.T) { + in := &model.TemplateDataLastInput{ + Id: 18, + } + out, err := service.DataTemplate().GetLastData(context.TODO(), in) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestUpdateDataTpl(t *testing.T) { + err := service.DataTemplate().UpdateData(context.TODO(), 15) + if err != nil { + t.Fatal(err) + } +} + +func TestGetAllBySql(t *testing.T) { + sql := "select * from data_template_20 order by created_at desc limit 2" + out, err := service.DataTemplate().GetDataBySql(context.TODO(), sql) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestGetAllByTableName(t *testing.T) { + tableName := "data_template_20" + out, err := service.DataTemplate().GetDataByTableName(context.TODO(), tableName) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestCheckRelation(t *testing.T) { + out, err := service.DataTemplate().CheckRelation(context.TODO(), 31) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} diff --git a/internal/logic/envirotronics/env_weather.go b/internal/logic/envirotronics/env_weather.go new file mode 100644 index 0000000..45c5748 --- /dev/null +++ b/internal/logic/envirotronics/env_weather.go @@ -0,0 +1,477 @@ +package envirotronics + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "regexp" + "strconv" + "strings" + + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sEnvWeather struct { +} + +func EnvWeather() *sEnvWeather { + return &sEnvWeather{} +} + +func init() { + service.RegisterEnvWeather(EnvWeather()) +} + +// CityWeatherList 获取城市的风力及日照时长 +func (a *sEnvWeather) CityWeatherList(ctx context.Context) (cityWeatherListOut []*model.CityWeatherListOut, err error) { + info, err := service.CityData().GetAll(ctx) + if err != nil { + return + } + if info != nil { + var cityIds []int + for _, city := range info { + cityIds = append(cityIds, city.Id) + } + if len(cityIds) > 0 { + //绑定的数据建模 + dataInfo, _ := service.DataTemplateBusi().GetInfos(ctx, consts.Weather) + if dataInfo != nil { + //查询数据建模数据 + var in = new(model.TemplateDataAllInput) + in.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + params := map[string]interface{}{ + "CREATED_AT >= ? ": gtime.Now().Format("Y-m-d 00:00:00"), + "CREATED_AT < ? ": gtime.Now().Format("Y-m-d H:i:s"), + } + in.Param = params + out, _ := service.DataTemplate().GetAllData(ctx, in) + + for _, city := range info { + var cityWeather = new(model.CityWeatherListOut) + cityWeather.Id = city.Id + cityWeather.Name = city.Name + cityWeather.Code = city.Code + //获取当前城市当天城市数据 + var cityOut g.List + for _, v := range out.List { + if strings.EqualFold(city.Code, v["adcode"].(string)) { + cityOut = append(cityOut, v) + } + } + if len(cityOut) > 0 { + if err = gconv.Scan(cityOut[len(cityOut)-1], &cityWeather); err != nil { + return + } + } + //计算日照时长 + if cityWeather.Sunrise != "" && cityWeather.Sunset != "" { + cityWeather.SunshineDuration = int(gtime.New(gtime.Now().Format("Y-m-d ") + cityWeather.Sunset + ":00").Sub(gtime.New(gtime.Now().Format("Y-m-d ") + cityWeather.Sunrise + ":00")).Hours()) + } + + cityWeatherListOut = append(cityWeatherListOut, cityWeather) + } + } + } + } + return +} + +// GetCityWeatherById 根据ID获取指定城市的天气 +func (a *sEnvWeather) GetCityWeatherById(ctx context.Context, id int) (cityWeatherListOut *model.CityWeatherListOut, err error) { + info, err := service.CityData().GetInfoById(ctx, id) + if err != nil { + return + } + cityWeatherListOut = new(model.CityWeatherListOut) + if info != nil { + //绑定的数据建模 + dataInfo, _ := service.DataTemplateBusi().GetInfo(ctx, consts.Weather) + if dataInfo != nil { + cityWeatherListOut.Id = info.Id + cityWeatherListOut.Name = info.Name + cityWeatherListOut.Code = info.Code + + var in = new(model.TemplateDataLastInput) + in.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + params := map[string]interface{}{ + "CREATED_AT >= ? ": gtime.Now().Format("Y-m-d 00:00:00"), + "CREATED_AT < ? ": gtime.Now().Format("Y-m-d H:i:s"), + "ADCODE = ? ": info.Code, + } + in.Param = params + //获取数据建模数据 + out, _ := service.DataTemplate().GetLastData(ctx, in) + if out.Data != nil { + if err = gconv.Scan(out.Data, &cityWeatherListOut); err != nil { + return + } + } + + //计算日照时长 + if cityWeatherListOut.Sunrise != "" && cityWeatherListOut.Sunset != "" { + cityWeatherListOut.SunshineDuration = int(gtime.New(gtime.Now().Format("Y-m-d ") + cityWeatherListOut.Sunset + ":00").Sub(gtime.New(gtime.Now().Format("Y-m-d ") + cityWeatherListOut.Sunrise + ":00")).Hours()) + } + } + } + return +} + +// GetCityTemperatureById 根据ID获取指定城市的温度图表 +func (a *sEnvWeather) GetCityTemperatureById(ctx context.Context, id int, types int) (cityWeatherEchartOut []*model.CityWeatherEchartOut, avgCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastAvgCityWeatherEchartOut []*model.CityWeatherEchartOut, err error) { + info, err := service.CityData().GetInfoById(ctx, id) + if err != nil { + return + } + if info != nil { + //绑定的数据建模 + dataInfo, _ := service.DataTemplateBusi().GetInfo(ctx, consts.Weather) + if dataInfo != nil { + //根据类型获取时间差、开始时间、结束时间 + index, begin, end := utils.GetTimeByType(types) + + //封装数据建模 + var in = new(model.TemplateDataAllInput) + //数据建模ID + in.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + params := map[string]interface{}{ + "CREATED_AT >= ? ": begin, + "CREATED_AT < ? ": end, + "ADCODE = ? ": info.Code, + } + in.Param = params + + //获取数据建模数据 + out, _ := service.DataTemplate().GetAllData(ctx, in) + + var sumValue float64 + var foreCastSumValue float64 + for i := 0; i < index; i++ { + //实时天气 + var cityWeatherEchart = new(model.CityWeatherEchartOut) + startTime, endTime, duration, unit := utils.GetTime(i, types, begin) + cityWeatherEchart.Time = strconv.Itoa(duration) + unit + var value float64 + var num float64 + for _, m := range out.List { + if gtime.New(startTime).Before(m["created_at"].(*gtime.Time)) && m["created_at"].(*gtime.Time).Before(gtime.New(endTime)) { + parseValue, _ := strconv.ParseFloat(m["temperature"].(string), 64) + value += parseValue + num++ + } + } + if value != 0 && num != 0 { + + cityWeatherEchart.Value = fmt.Sprintf("%.2f", value/num) + sumValue += value / num + } else { + cityWeatherEchart.Value = "0.00" + } + cityWeatherEchartOut = append(cityWeatherEchartOut, cityWeatherEchart) + + if types == 2 || types == 3 { + //预报天气 + var foreCastCityWeatherEchart = new(model.CityWeatherEchartOut) + foreCastCityWeatherEchart.Time = strconv.Itoa(duration) + unit + + var foreCastValue float64 + var foreCastNum float64 + //开始时间-1天 + startTime = gtime.New(startTime).AddDate(0, 0, -1).Format("Y-m-d H:i:s") + //结束时间-1天 + endTime = gtime.New(endTime).AddDate(0, 0, -1).Format("Y-m-d H:i:s") + for _, m := range out.List { + if gtime.New(startTime).Before(m["created_at"].(*gtime.Time)) && m["created_at"].(*gtime.Time).Before(gtime.New(endTime)) { + parseValue, _ := strconv.ParseFloat(m["next_day_temp"].(string), 64) + foreCastValue += parseValue + foreCastNum++ + } + } + if foreCastValue != 0 && foreCastNum != 0 { + foreCastCityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastValue/foreCastNum) + foreCastSumValue += foreCastValue / foreCastNum + } else { + foreCastCityWeatherEchart.Value = "0.00" + } + foreCastCityWeatherEchartOut = append(foreCastCityWeatherEchartOut, foreCastCityWeatherEchart) + } + } + + //获取未来一周的时间 + if types == 2 || types == 3 { + //获取最后一条数据 + var lastIn = new(model.TemplateDataLastInput) + lastIn.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + lastParams := map[string]interface{}{ + "CREATED_AT >= ? ": gtime.Now().Format("Y-m-d 00:00:00"), + "CREATED_AT < ? ": gtime.Now().Format("Y-m-d H:i:s"), + "ADCODE = ? ": info.Code, + } + lastIn.Param = lastParams + + lastOut, _ := service.DataTemplate().GetLastData(ctx, lastIn) + if lastOut.Data != nil { + for i := 1; i < 7; i++ { + //获取字段名称 + var field string + switch i { + case 1: + field = "next_day_temp" + break + case 2: + field = "next_three_day_temp" + break + case 3: + field = "next_four_day_temp" + break + case 4: + field = "next_five_day_temp" + break + case 5: + field = "next_six_day_temp" + break + case 6: + field = "next_seven_day_temp" + break + } + parseValue, _ := strconv.ParseFloat(gconv.String(lastOut.Data[field]), 64) + var cityWeatherEchart = new(model.CityWeatherEchartOut) + cityWeatherEchart.Time = strconv.Itoa(gtime.New(gtime.Now()).AddDate(0, 0, i).Day()) + "日" + cityWeatherEchart.Value = fmt.Sprintf("%.2f", parseValue) + foreCastCityWeatherEchartOut = append(foreCastCityWeatherEchartOut, cityWeatherEchart) + foreCastSumValue += parseValue + } + } + } + + //获取实时天气平均值 + for i := 0; i < index; i++ { + var cityWeatherEchart = new(model.CityWeatherEchartOut) + _, _, duration, unit := utils.GetTime(i, types, begin) + cityWeatherEchart.Time = strconv.Itoa(duration) + unit + if sumValue != 0 { + cityWeatherEchart.Value = fmt.Sprintf("%.2f", sumValue/float64(index)) + } else { + cityWeatherEchart.Value = "0.00" + } + avgCityWeatherEchartOut = append(avgCityWeatherEchartOut, cityWeatherEchart) + //获取预报天气值 + if types == 2 || types == 3 { + var foreCastCityWeatherEchart = new(model.CityWeatherEchartOut) + foreCastCityWeatherEchart.Time = strconv.Itoa(duration) + unit + if foreCastSumValue != 0 { + foreCastCityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastSumValue/float64(index+6)) + } else { + foreCastCityWeatherEchart.Value = "0.00" + } + foreCastAvgCityWeatherEchartOut = append(foreCastAvgCityWeatherEchartOut, foreCastCityWeatherEchart) + } + } + //获取未来一周的平均天气 + if types == 2 || types == 3 { + for i := 1; i < 7; i++ { + var cityWeatherEchart = new(model.CityWeatherEchartOut) + cityWeatherEchart.Time = strconv.Itoa(gtime.New(gtime.Now()).AddDate(0, 0, i).Day()) + "日" + cityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastSumValue/float64(gtime.Now().Day()+6)) + foreCastAvgCityWeatherEchartOut = append(foreCastAvgCityWeatherEchartOut, cityWeatherEchart) + } + } + } + } + return +} + +// GetCityWindpowerById 根据ID获取指定城市的风力图表 +func (a *sEnvWeather) GetCityWindpowerById(ctx context.Context, id int, types int) (cityWeatherEchartOut []*model.CityWeatherEchartOut, avgCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastAvgCityWeatherEchartOut []*model.CityWeatherEchartOut, err error) { + info, err := service.CityData().GetInfoById(ctx, id) + if err != nil { + return + } + if info != nil { + //绑定的数据建模 + dataInfo, _ := service.DataTemplateBusi().GetInfo(ctx, consts.Weather) + if dataInfo != nil { + //根据类型获取时间差、开始时间、结束时间 + index, begin, end := utils.GetTimeByType(types) + + //封装数据建模 + var in = new(model.TemplateDataAllInput) + //数据建模ID + in.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + params := map[string]interface{}{ + "CREATED_AT >= ? ": begin, + "CREATED_AT < ? ": end, + "ADCODE = ? ": info.Code, + } + in.Param = params + + //获取数据建模数据 + out, _ := service.DataTemplate().GetAllData(ctx, in) + + var sumValue float64 + var foreCastSumValue float64 + //获取当前数据 + for i := 0; i < index; i++ { + var cityWeatherEchart = new(model.CityWeatherEchartOut) + startTime, endTime, duration, unit := utils.GetTime(i, types, begin) + cityWeatherEchart.Time = strconv.Itoa(duration) + unit + var value float64 + var num float64 + + for _, m := range out.List { + if gtime.New(startTime).Before(m["created_at"].(*gtime.Time)) && m["created_at"].(*gtime.Time).Before(gtime.New(endTime)) { + re := regexp.MustCompile("[0-9]+") + if re.FindAllString(m["windpower"].(string), -1) != nil { + parseValue, _ := strconv.ParseFloat(re.FindAllString(m["windpower"].(string), -1)[0], 64) + value += parseValue + } else { + value += 0.5 + } + num++ + } + } + if value != 0 && num != 0 { + cityWeatherEchart.Value = fmt.Sprintf("%.2f", value/num) + sumValue += value / num + } else { + cityWeatherEchart.Value = "0.00" + } + cityWeatherEchartOut = append(cityWeatherEchartOut, cityWeatherEchart) + + if types == 2 || types == 3 { + //预报天气 + var foreCastCityWeatherEchart = new(model.CityWeatherEchartOut) + foreCastCityWeatherEchart.Time = strconv.Itoa(duration) + unit + + var foreCastValue float64 + var foreCastNum float64 + //开始时间-1天 + startTime = gtime.New(startTime).AddDate(0, 0, -1).Format("Y-m-d H:i:s") + //结束时间-1天 + endTime = gtime.New(endTime).AddDate(0, 0, -1).Format("Y-m-d H:i:s") + for _, m := range out.List { + if gtime.New(startTime).Before(m["created_at"].(*gtime.Time)) && m["created_at"].(*gtime.Time).Before(gtime.New(endTime)) { + re := regexp.MustCompile("[0-9]+") + if re.FindAllString(m["next_day_windpower"].(string), -1) != nil { + parseValue, _ := strconv.ParseFloat(re.FindAllString(m["next_day_windpower"].(string), -1)[0], 64) + foreCastValue += parseValue + } else { + foreCastValue += 0.5 + } + foreCastNum++ + } + } + if foreCastValue != 0 && foreCastNum != 0 { + foreCastCityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastValue/foreCastNum) + foreCastSumValue += foreCastValue / foreCastNum + } else { + foreCastCityWeatherEchart.Value = "0.00" + } + foreCastCityWeatherEchartOut = append(foreCastCityWeatherEchartOut, foreCastCityWeatherEchart) + } + } + + //获取未来一周的时间 + if types == 2 || types == 3 { + //获取最后一条数据 + var lastIn = new(model.TemplateDataLastInput) + lastIn.Id = uint64(dataInfo.DataTemplateId) + //查询条件 + lastParams := map[string]interface{}{ + "CREATED_AT >= ? ": gtime.Now().Format("Y-m-d 00:00:00"), + "CREATED_AT < ? ": gtime.Now().Format("Y-m-d H:i:s"), + "ADCODE = ? ": info.Code, + } + lastIn.Param = lastParams + + lastOut, _ := service.DataTemplate().GetLastData(ctx, lastIn) + if lastOut.Data != nil { + for i := 1; i < 7; i++ { + //获取字段名称 + var field string + switch i { + case 1: + field = "next_day_windpower" + break + case 2: + field = "next_three_day_windpower" + break + case 3: + field = "next_four_day_windpower" + break + case 4: + field = "next_five_day_windpower" + break + case 5: + field = "next_six_day_windpower" + break + case 6: + field = "next_seven_day_windpower" + break + } + var cityWeatherEchart = new(model.CityWeatherEchartOut) + cityWeatherEchart.Time = strconv.Itoa(gtime.New(gtime.Now()).AddDate(0, 0, i).Day()) + "日" + re := regexp.MustCompile("[0-9]+") + var parseValue float64 + if re.FindAllString(gconv.String(lastOut.Data[field]), -1) != nil { + parseValue, _ = strconv.ParseFloat(re.FindAllString(gconv.String(lastOut.Data[field]), -1)[0], 64) + } else { + parseValue += 0.5 + } + cityWeatherEchart.Value = fmt.Sprintf("%.2f", parseValue) + foreCastCityWeatherEchartOut = append(foreCastCityWeatherEchartOut, cityWeatherEchart) + foreCastSumValue += parseValue + } + } + } + + //获取平均值 + for i := 0; i < index; i++ { + var cityWeatherEchart = new(model.CityWeatherEchartOut) + + _, _, duration, unit := utils.GetTime(i, types, begin) + cityWeatherEchart.Time = strconv.Itoa(duration) + unit + + if sumValue != 0 { + cityWeatherEchart.Value = fmt.Sprintf("%.2f", sumValue/float64(index)) + } else { + cityWeatherEchart.Value = "0.00" + } + avgCityWeatherEchartOut = append(avgCityWeatherEchartOut, cityWeatherEchart) + + //获取预报天气值 + if types == 2 || types == 3 { + var foreCastCityWeatherEchart = new(model.CityWeatherEchartOut) + foreCastCityWeatherEchart.Time = strconv.Itoa(duration) + unit + if sumValue != 0 { + foreCastCityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastSumValue/float64(index+6)) + } else { + foreCastCityWeatherEchart.Value = "0.00" + } + foreCastAvgCityWeatherEchartOut = append(foreCastAvgCityWeatherEchartOut, foreCastCityWeatherEchart) + } + } + + //获取未来一周的平均天气 + if types == 2 || types == 3 { + for i := 1; i < 7; i++ { + var cityWeatherEchart = new(model.CityWeatherEchartOut) + cityWeatherEchart.Time = strconv.Itoa(gtime.New(gtime.Now()).AddDate(0, 0, i).Day()) + "日" + cityWeatherEchart.Value = fmt.Sprintf("%.2f", foreCastSumValue/float64(gtime.Now().Day()+6)) + foreCastAvgCityWeatherEchartOut = append(foreCastAvgCityWeatherEchartOut, cityWeatherEchart) + } + } + } + } + return +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go new file mode 100644 index 0000000..ea7ddb4 --- /dev/null +++ b/internal/logic/logic.go @@ -0,0 +1,19 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package logic + +import ( + _ "github.com/sagoo-cloud/sagooiot/internal/logic/alarm" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/common" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/datahub" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/envirotronics" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/middleware" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/network" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/notice" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/product" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/system" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/tdengine" +) diff --git a/internal/logic/middleware/middleware.go b/internal/logic/middleware/middleware.go new file mode 100644 index 0000000..301d905 --- /dev/null +++ b/internal/logic/middleware/middleware.go @@ -0,0 +1,227 @@ +package middleware + +import ( + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/response" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "strings" +) + +type sMiddleware struct { + LoginUrl string // 登录路由地址 +} + +func init() { + service.RegisterMiddleware(New()) +} + +func New() *sMiddleware { + return &sMiddleware{ + LoginUrl: "/login", + } +} + +// ResponseHandler 返回处理中间件 +func (s *sMiddleware) ResponseHandler(r *ghttp.Request) { + r.Middleware.Next() + + // 如果已经有返回内容,那么该中间件什么也不做 + if r.Response.BufferLength() > 0 { + return + } + + var ( + err = r.GetError() + res = r.GetHandlerResponse() + code gcode.Code = gcode.CodeOK + ) + if err != nil { + code = gerror.Code(err) + if code == gcode.CodeNil { + code = gcode.CodeInternalError + } + if r.IsAjaxRequest() { + response.JsonExit(r, code.Code(), err.Error()) + } else { + /*service.View().Render500(r.Context(), model.View{ + Error: err.Error(), + })*/ + response.JsonExit(r, code.Code(), err.Error()) + } + } else { + if r.IsAjaxRequest() { + response.JsonExit(r, code.Code(), "", res) + } else { + // 什么都不做,业务API自行处理模板渲染的成功逻辑。 + response.JsonExit(r, code.Code(), "", res) + } + } +} + +// Ctx 自定义上下文对象 +func (s *sMiddleware) Ctx(r *ghttp.Request) { + ctx := r.GetCtx() + // 初始化登录用户信息 + data, err := service.SysToken().ParseToken(r) + if err != nil { + // 执行下一步请求逻辑 + r.Middleware.Next() + } + if data != nil { + context := new(model.Context) + err = gconv.Struct(data.Data, &context.User) + if err != nil { + g.Log().Error(ctx, err) + // 执行下一步请求逻辑 + r.Middleware.Next() + } + service.Context().Init(r, context) + } + // 执行下一步请求逻辑 + r.Middleware.Next() +} + +// Auth 前台系统权限控制,用户必须登录才能访问 +func (s *sMiddleware) Auth(r *ghttp.Request) { + userId := service.Context().GetUserId(r.Context()) + if userId == 0 { + response.JsonRedirectExit(r, consts.ErrorNotLogged, "未登录或会话已过期,请您登录后再继续", s.LoginUrl) + return + } else { + //查询系统参数 + sysConfigInfo, err := service.ConfigData().GetConfigByKey(r.Context(), consts.IsOpenAccessControl) + if err != nil { + return + } + if sysConfigInfo != nil { + if strings.EqualFold(sysConfigInfo.ConfigValue, "1") { + //判断用户是否有访问权限 + url := r.Request.URL.Path + if !strings.EqualFold(url, "/api/v1/system/user/currentUser") { + //获取用户角色信息 + userRoleInfo, err := service.SysUserRole().GetInfoByUserId(r.Context(), userId) + if err != nil { + response.JsonRedirectExit(r, consts.ErrorInvalidRole, "获取用户角色失败", "") + return + } + if userRoleInfo != nil { + var roleIds []int + //判断是否为超级管理员 + var isSuperAdmin = false + for _, userRole := range userRoleInfo { + //获取角色ID + if userRole.RoleId == 1 { + isSuperAdmin = true + } + roleIds = append(roleIds, userRole.RoleId) + } + if !isSuperAdmin { + //获取角色ID下所有的请求API + authorizeInfo, authorizeErr := service.SysAuthorize().GetInfoByRoleIdsAndItemsType(r.Context(), roleIds, consts.Api) + if authorizeErr != nil { + response.JsonRedirectExit(r, consts.ErrorInvalidData, "获取用户权限失败", "") + return + } + if authorizeInfo != nil { + //判断是否与当前访问接口一致 + var menuApiIds []int + for _, authorize := range authorizeInfo { + menuApiIds = append(menuApiIds, authorize.ItemsId) + } + //获取所有的接口API + menuApiInfo, menuApiErr := service.SysMenuApi().GetInfoByIds(r.Context(), menuApiIds) + if menuApiErr != nil { + response.JsonRedirectExit(r, consts.ErrorInvalidData, "相关接口未配置", "") + return + } + if menuApiInfo != nil { + var apiIds []int + for _, menuApi := range menuApiInfo { + apiIds = append(apiIds, menuApi.ApiId) + } + //获取所有的接口 + apiInfo, apiErr := service.SysApi().GetInfoByIds(r.Context(), apiIds) + if apiErr != nil { + response.JsonRedirectExit(r, consts.ErrorInvalidData, "获取接口失败", "") + return + } + if apiInfo != nil { + var isExist = false + //获取请求路径 + for _, api := range apiInfo { + if strings.EqualFold(url, api.Address) { + isExist = true + break + } + } + if !isExist { + response.JsonRedirectExit(r, consts.ErrorAccessDenied, "无权限访问", "") + return + } + } else { + response.JsonRedirectExit(r, consts.ErrorInvalidData, "相关接口未配置", "") + return + } + + } else { + response.JsonRedirectExit(r, consts.ErrorAccessDenied, "接口未绑定菜单,请联系管理员!", "") + return + } + + } else { + response.JsonRedirectExit(r, consts.ErrorAccessDenied, "未授权接口,无访问权限!", "") + return + } + } + } else { + response.JsonRedirectExit(r, consts.ErrorInvalidRole, "用户未配置角色信息,请联系管理员", "") + return + } + } + } + } + + } + r.Middleware.Next() +} + +// MiddlewareCORS 跨域处理 +func (s *sMiddleware) MiddlewareCORS(r *ghttp.Request) { + + //自定义跨域限制 + //corsOptions := r.Response.DefaultCORSOptions() + // you can set options + //corsOptions.AllowDomain = []string{"goframe.org", "baidu.com"} + //r.Response.CORS(corsOptions) + + //采用默认接受所有跨域 + r.Response.CORSDefault() + + r.Middleware.Next() +} + +// OperationLog 操作日志 +func (s *sMiddleware) OperationLog(r *ghttp.Request) { + //获取当前登录用户信息 + loginUserId := service.Context().GetUserId(r.GetCtx()) + if loginUserId == 0 { + return + } + var ( + url = r.Request.URL //请求地址 + err = r.GetError() + handlerResponse = r.GetHandlerResponse() + body = r.GetMap() + ) + + res := gconv.Map(handlerResponse) + + service.SysOperLog().Invoke(r.GetCtx(), loginUserId, url, body, r.Method, utils.GetClientIp(r.GetCtx()), res, err) +} diff --git a/internal/logic/network/network_server.go b/internal/logic/network/network_server.go new file mode 100644 index 0000000..9f389c8 --- /dev/null +++ b/internal/logic/network/network_server.go @@ -0,0 +1,140 @@ +package network + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/core" +) + +type sNetworkServer struct{} + +func sNetworkServerNew() *sNetworkServer { + return &sNetworkServer{} +} +func init() { + service.RegisterNetworkServer(sNetworkServerNew()) +} + +const ( + ServerStatusOnline = "online" + ServerStatusOffline = "offline" +) + +// GetServerList 获取列表数据 +func (s *sNetworkServer) GetServerList(ctx context.Context, in *model.GetNetworkServerListInput) (total int, out []*model.NetworkServerOut, err error) { + //g.Log().Debug(ctx, in) + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NetworkServer.Ctx(ctx) + + if in.KeyWord != "" { + m = m.WhereLike(dao.NetworkServer.Columns().Name, "%"+in.KeyWord+"%") + } + + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + if in.PageNum == 0 { + in.PageNum = 1 + } + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(in.PageNum, in.PageSize).Order("created_at desc").Scan(&out) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + + return +} + +// GetServerRunList 获取可运行的服务列表数据 +func (s *sNetworkServer) GetServerRunList(ctx context.Context) (list []*model.NetworkServerRes, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NetworkServer.Ctx(ctx) + err = m.Where(dao.NetworkServer.Columns().Status, 1).Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// GetServerById 获取指定ID数据 +func (s *sNetworkServer) GetServerById(ctx context.Context, id int) (out *model.NetworkServerOut, err error) { + err = dao.NetworkServer.Ctx(ctx).Where("id", id).Scan(&out) + return +} + +// AddServer 添加数据 todo 需要处理 +func (s *sNetworkServer) AddServer(ctx context.Context, in model.NetworkServerAddInput) (err error) { + insertResult, insertResultErr := dao.NetworkServer.Ctx(ctx).Insert(in) + if insertResultErr != nil { + return insertResultErr + } + lastId, lastIdErr := insertResult.LastInsertId() + if lastIdErr != nil { + return lastIdErr + } + if err == nil && in.Status == consts.ServerStatusOnline { + return core.LoadServer(ctx, int(lastId)) + } + return +} + +// EditServer 修改数据 todo 需要处理 +func (s *sNetworkServer) EditServer(ctx context.Context, in model.NetworkServerEditInput) (err error) { + _, err = dao.NetworkServer.Ctx(ctx).FieldsEx(dao.NetworkServer.Columns().Id, dao.NetworkServer.Columns().CreateBy).Where(dao.NetworkServer.Columns().Id, in.Id).Update(in) + if err = core.RemoveServer(in.Id); err != nil { + return err + } + if in.Status == 1 { + if err = core.LoadServer(ctx, in.Id); err != nil { + return err + } + } + return +} + +// 删除数据 +// todo 需要处理 +func (s *sNetworkServer) DeleteServer(ctx context.Context, ids []int) (err error) { + _, err = dao.NetworkServer.Ctx(ctx).Delete(dao.NetworkServer.Columns().Id+" in (?)", ids) + if err == nil { + for _, node := range ids { + if err = core.RemoveServer(node); err != nil { + return err + } + } + } + return +} + +// SetServerStatus 修改状态数据 todo 需要处理 +func (s *sNetworkServer) SetServerStatus(ctx context.Context, id, status int) (err error) { + + var data = g.Map{ + dao.NetworkServer.Columns().Status: status, + } + _, err = dao.NetworkServer.Ctx(ctx).Where(dao.NetworkServer.Columns().Id, id).Update(data) + if err != nil { + return err + } + if status == 1 { + if err = core.LoadServer(ctx, id); err != nil { + return err + } + } else { + if err = core.RemoveServer(id); err != nil { + return err + } + } + return +} diff --git a/internal/logic/network/network_tunnel.go b/internal/logic/network/network_tunnel.go new file mode 100644 index 0000000..d19501b --- /dev/null +++ b/internal/logic/network/network_tunnel.go @@ -0,0 +1,170 @@ +package network + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/core" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sNetworkTunnel struct{} + +func sNetworkTunnelNew() *sNetworkTunnel { + return &sNetworkTunnel{} +} +func init() { + service.RegisterNetworkTunnel(sNetworkTunnelNew()) +} + +const ( + TunnelIsOffline = iota + TunnelIsOnLine +) + +// 获取列表数据 +func (s *sNetworkTunnel) GetTunnelList(ctx context.Context, in *model.GetNetworkTunnelListInput) (total int, out []*model.NetworkTunnelOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NetworkTunnel.Ctx(ctx) + + if in.ServiceId > 0 { + m = m.Where(dao.NetworkTunnel.Columns().ServerId, in.ServiceId) + } + if in.DeviceKey != "" { + m = m.Where(dao.NetworkTunnel.Columns().DeviceKey, in.DeviceKey) + } + if in.KeyWord != "" { + m = m.WhereLike(dao.NetworkTunnel.Columns().Name, "%"+in.KeyWord+"%") + } + + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + if in.PageNum == 0 { + in.PageNum = 1 + } + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + + err = m.Page(in.PageNum, in.PageSize).Order("created_at desc").Scan(&out) + + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// 获取列表数据 +func (s *sNetworkTunnel) GetTunnelRunList(ctx context.Context) (out []*model.NetworkTunnelOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NetworkTunnel.Ctx(ctx) + err = m.Where(dao.NetworkTunnel.Columns().Status, 1).Scan(&out) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// 获取指定ID数据 +func (s *sNetworkTunnel) GetTunnelById(ctx context.Context, id int) (out *model.NetworkTunnelOut, err error) { + err = dao.NetworkTunnel.Ctx(ctx).Where("id", id).Scan(&out) + return +} + +// TODO 这里更改了请求参数,需要确认是否ok +// 添加数据 +func (s *sNetworkTunnel) AddTunnel(ctx context.Context, in model.NetworkTunnelAddInput) (id int, err error) { + rs, err := dao.NetworkTunnel.Ctx(ctx).Insert(in) + if err != nil { + return + } + newId, _ := rs.LastInsertId() + id = int(newId) + + if err == nil && in.Status == TunnelIsOnLine { + var networkTunnelEditInput model.NetworkTunnelEditInput + if err = dao.NetworkTunnel.Ctx(ctx).Where("name", in.Name).Scan(&networkTunnelEditInput); err != nil { + return + } else { + err = core.LoadTunnel(ctx, networkTunnelEditInput.Id) + return + } + } + return +} + +// 修改数据 +func (s *sNetworkTunnel) EditTunnel(ctx context.Context, in model.NetworkTunnelEditInput) (err error) { + var param do.NetworkTunnel + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.Id = nil + if in.Remote == "" { + param.Remote = nil + } + + _, err = dao.NetworkTunnel.Ctx(ctx).FieldsEx(dao.NetworkTunnel.Columns().Id).Where(dao.NetworkTunnel.Columns().Id, in.Id).Update(param) + if err != nil { + return + } + if err = core.RemoveTunnel(in.Id); err != nil { + return err + } + if in.Status == TunnelIsOnLine { + if err = core.LoadTunnel(ctx, in.Id); err != nil { + return err + } + } + return +} + +// 删除数据 +func (s *sNetworkTunnel) DeleteTunnel(ctx context.Context, ids []int) (err error) { + _, err = dao.NetworkTunnel.Ctx(ctx).Delete(dao.NetworkTunnel.Columns().Id+" in (?)", ids) + //TODO 这里需要注意中间删除失败的情况 + if err == nil { + for _, node := range ids { + if err = core.RemoveTunnel(node); err != nil { + return err + } + } + } + return +} + +// 修改状态数据 +func (s *sNetworkTunnel) SetTunnelStatus(ctx context.Context, id, status int) (err error) { + var data = g.Map{ + dao.NetworkTunnel.Columns().Status: status, + } + + //TODO 这儿里还需要进行通道的启用处理,启用成功更新数据状态 + + _, err = dao.NetworkTunnel.Ctx(ctx).Where(dao.NetworkTunnel.Columns().Id, id).Update(data) + if err != nil { + return + } + if status == 0 { + if err = core.LoadTunnel(ctx, id); err != nil { + return err + } + } else { + if err = core.RemoveTunnel(id); err != nil { + return err + } + } + return +} diff --git a/internal/logic/notice/notice_config.go b/internal/logic/notice/notice_config.go new file mode 100644 index 0000000..a41ed7b --- /dev/null +++ b/internal/logic/notice/notice_config.go @@ -0,0 +1,80 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sNoticeConfig struct{} + +func sNoticeConfigNew() *sNoticeConfig { + return &sNoticeConfig{} +} +func init() { + service.RegisterNoticeConfig(sNoticeConfigNew()) +} + +//GetNoticeConfigList 获取列表数据 +func (s *sNoticeConfig) GetNoticeConfigList(ctx context.Context, in *model.GetNoticeConfigListInput) (total, page int, list []*model.NoticeConfigOutput, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NoticeConfig.Ctx(ctx) + + if in.KeyWord != "" { + m = m.WhereLike(dao.NoticeConfig.Columns().Title, "%"+in.KeyWord+"%") + } + if in.Types != "" { + m = m.Where(dao.NoticeConfig.Columns().Types, in.Types) + } + if in.SendGateway != "" { + m = m.Where(dao.NoticeConfig.Columns().SendGateway, in.SendGateway) + } + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = in.PageNum + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +//GetNoticeConfigById 获取指定ID数据 +func (s *sNoticeConfig) GetNoticeConfigById(ctx context.Context, id int) (out *model.NoticeConfigOutput, err error) { + err = dao.NoticeConfig.Ctx(ctx).Where(dao.NoticeConfig.Columns().Id, id).Scan(&out) + return +} + +//AddNoticeConfig 添加数据 +func (s *sNoticeConfig) AddNoticeConfig(ctx context.Context, in model.NoticeConfigAddInput) (err error) { + _, err = dao.NoticeConfig.Ctx(ctx).Insert(in) + return +} + +//EditNoticeConfig 修改数据 +func (s *sNoticeConfig) EditNoticeConfig(ctx context.Context, in model.NoticeConfigEditInput) (err error) { + _, err = dao.NoticeConfig.Ctx(ctx).FieldsEx(dao.NoticeConfig.Columns().Id).Where(dao.NoticeConfig.Columns().Id, in.Id).Update(in) + return +} + +//DeleteNoticeConfig 删除数据 +func (s *sNoticeConfig) DeleteNoticeConfig(ctx context.Context, Ids []string) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.NoticeConfig.Ctx(ctx).Where(dao.NoticeConfig.Columns().Id+" in(?)", Ids).Delete() + liberr.ErrIsNil(ctx, err, "删除配置数据失败") + }) + return + +} diff --git a/internal/logic/notice/notice_info.go b/internal/logic/notice/notice_info.go new file mode 100644 index 0000000..5e6bef3 --- /dev/null +++ b/internal/logic/notice/notice_info.go @@ -0,0 +1,89 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sNoticeInfo struct{} + +func sNoticeInfoNew() *sNoticeInfo { + return &sNoticeInfo{} +} +func init() { + service.RegisterNoticeInfo(sNoticeInfoNew()) +} + +//GetNoticeInfoList 获取列表数据 +func (s *sNoticeInfo) GetNoticeInfoList(ctx context.Context, in *model.GetNoticeInfoListInput) (total, page int, list []*model.NoticeInfoOutput, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NoticeInfo.Ctx(ctx) + + if in.KeyWord != "" { + m = m.WhereLike(dao.NoticeInfo.Columns().MsgTitle, "%"+in.KeyWord+"%") + m = m.WhereOrLike(dao.NoticeInfo.Columns().MsgBody, "%"+in.KeyWord+"%") + } + if in.Method != "" { + m = m.Where(dao.NoticeInfo.Columns().Method, in.Method) + } + if in.ConfigId != "" { + m = m.Where(dao.NoticeInfo.Columns().ConfigId, in.ConfigId) + } + + if in.ComeFrom != "" { + m = m.Where(dao.NoticeInfo.Columns().ComeFrom, in.ComeFrom) + } + + if in.Status != -1 { + m = m.Where(dao.NoticeInfo.Columns().Status, in.Status) + } + + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = in.PageNum + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +//GetNoticeInfoById 获取指定ID数据 +func (s *sNoticeInfo) GetNoticeInfoById(ctx context.Context, id int) (out *model.NoticeInfoOutput, err error) { + err = dao.NoticeInfo.Ctx(ctx).Where(dao.NoticeInfo.Columns().Id, id).Scan(&out) + return +} + +//AddNoticeInfo 添加数据 +func (s *sNoticeInfo) AddNoticeInfo(ctx context.Context, in model.NoticeInfoAddInput) (err error) { + _, err = dao.NoticeInfo.Ctx(ctx).Insert(in) + return +} + +//EditNoticeInfo 修改数据 +func (s *sNoticeInfo) EditNoticeInfo(ctx context.Context, in model.NoticeInfoEditInput) (err error) { + _, err = dao.NoticeInfo.Ctx(ctx).FieldsEx(dao.NoticeInfo.Columns().Id).Where(dao.NoticeInfo.Columns().Id, in.Id).Update(in) + return +} + +//DeleteNoticeInfo 删除数据 +func (s *sNoticeInfo) DeleteNoticeInfo(ctx context.Context, Ids []int) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.NoticeInfo.Ctx(ctx).Where(dao.NoticeInfo.Columns().Id+" in(?)", Ids).Delete() + liberr.ErrIsNil(ctx, err, "删除通知数据失败") + }) + return +} diff --git a/internal/logic/notice/notice_log.go b/internal/logic/notice/notice_log.go new file mode 100644 index 0000000..180e6e5 --- /dev/null +++ b/internal/logic/notice/notice_log.go @@ -0,0 +1,72 @@ +package notice + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sNoticeLog struct{} + +func init() { + service.RegisterNoticeLog(noticeLogNew()) +} + +func noticeLogNew() *sNoticeLog { + return &sNoticeLog{} +} + +// 通知日志记录 +func (s *sNoticeLog) Add(ctx context.Context, in *model.NoticeLogAddInput) (err error) { + _, err = dao.NoticeLog.Ctx(ctx).Data(in).Insert() + return +} + +// 删除日志 +func (s *sNoticeLog) Del(ctx context.Context, ids []uint64) (err error) { + _, err = dao.NoticeLog.Ctx(ctx).WhereIn(dao.NoticeLog.Columns().Id, ids).Delete() + return +} + +// 搜索 +func (s *sNoticeLog) Search(ctx context.Context, in *model.NoticeLogSearchInput) (out *model.NoticeLogSearchOutput, err error) { + out = new(model.NoticeLogSearchOutput) + m := dao.NoticeLog.Ctx(ctx) + if in.Status != -1 { + m = m.Where(dao.NoticeLog.Columns().Status, in.Status) + } + if len(in.DateRange) > 0 { + m = m.WhereBetween(dao.NoticeLog.Columns().SendTime, in.DateRange[0], in.DateRange[1]) + } + + out.CurrentPage = in.PageNum + if out.Total, err = m.Count(); err != nil || out.Total == 0 { + return + } + var list []model.NoticeLogList + if err = m.Page(in.PageNum, in.PageSize).OrderDesc(dao.NoticeLog.Columns().Id).Scan(&list); err != nil { + return + } + + // 获取发送通道中文配置 + var dtList []model.SysDictDataOut + err = dao.SysDictData.Ctx(ctx).Where(dao.SysDictType.Columns().DictType, "notice_send_gateway").Scan(&dtList) + + for i, v := range list { + for _, t := range dtList { + if v.SendGateway == t.DictValue { + list[i].Gateway = t.DictLabel + } + } + } + out.List = list + + return +} + +//ClearLogByDays 按日期删除日志 +func (s *sNoticeLog) ClearLogByDays(ctx context.Context, days int) (err error) { + _, err = dao.NoticeLog.Ctx(ctx).Delete("to_days(now())-to_days(`send_time`) > ?", days+1) + return +} diff --git a/internal/logic/notice/notice_template.go b/internal/logic/notice/notice_template.go new file mode 100644 index 0000000..260a69e --- /dev/null +++ b/internal/logic/notice/notice_template.go @@ -0,0 +1,97 @@ +package notice + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" +) + +type sNoticeTemplate struct{} + +func sNoticeTemplateNew() *sNoticeTemplate { + return &sNoticeTemplate{} +} +func init() { + service.RegisterNoticeTemplate(sNoticeTemplateNew()) +} + +//GetNoticeTemplateList 获取列表数据 +func (s *sNoticeTemplate) GetNoticeTemplateList(ctx context.Context, in *model.GetNoticeTemplateListInput) (total, page int, list []*model.NoticeTemplateOutput, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.NoticeTemplate.Ctx(ctx) + + if in.KeyWord != "" { + m = m.WhereLike(dao.NoticeTemplate.Columns().Title, "%"+in.KeyWord+"%") + m = m.WhereOrLike(dao.NoticeTemplate.Columns().Content, "%"+in.KeyWord+"%") + } + if in.Code != "" { + m = m.Where(dao.NoticeTemplate.Columns().Content, in.Code) + } + if in.ConfigId != "" { + m = m.Where(dao.NoticeTemplate.Columns().ConfigId, in.ConfigId) + } + + if in.SendGateway != "" { + m = m.Where(dao.NoticeTemplate.Columns().SendGateway, in.SendGateway) + } + + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = in.PageNum + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +//GetNoticeTemplateById 获取指定ID数据 +func (s *sNoticeTemplate) GetNoticeTemplateById(ctx context.Context, id string) (out *model.NoticeTemplateOutput, err error) { + err = dao.NoticeTemplate.Ctx(ctx).Where(dao.NoticeTemplate.Columns().Id, id).Scan(&out) + return +} + +//GetNoticeTemplateByConfigId 获取指定ConfigID数据 +func (s *sNoticeTemplate) GetNoticeTemplateByConfigId(ctx context.Context, configId string) (out *model.NoticeTemplateOutput, err error) { + err = dao.NoticeTemplate.Ctx(ctx).Where(dao.NoticeTemplate.Columns().ConfigId, configId).Scan(&out) + return +} + +//AddNoticeTemplate 添加数据 +func (s *sNoticeTemplate) AddNoticeTemplate(ctx context.Context, in model.NoticeTemplateAddInput) (err error) { + _, err = dao.NoticeTemplate.Ctx(ctx).Insert(in) + return +} + +//EditNoticeTemplate 修改数据 +func (s *sNoticeTemplate) EditNoticeTemplate(ctx context.Context, in model.NoticeTemplateEditInput) (err error) { + _, err = dao.NoticeTemplate.Ctx(ctx).Where(dao.NoticeTemplate.Columns().Id, in.Id).Update(in) + return +} + +//SaveNoticeTemplate 直接更新数据 +func (s *sNoticeTemplate) SaveNoticeTemplate(ctx context.Context, in model.NoticeTemplateAddInput) (err error) { + _, err = dao.NoticeTemplate.Ctx(ctx).Where(dao.NoticeTemplate.Columns().ConfigId, in.ConfigId).Save(in) + return +} + +//DeleteNoticeTemplate 删除数据 +func (s *sNoticeTemplate) DeleteNoticeTemplate(ctx context.Context, Ids []string) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.NoticeTemplate.Ctx(ctx).Where(dao.NoticeTemplate.Columns().Id+" in(?)", Ids).Delete() + liberr.ErrIsNil(ctx, err, "删除模版数据失败") + }) + return +} diff --git a/internal/logic/product/dev_category.go b/internal/logic/product/dev_category.go new file mode 100644 index 0000000..e879db2 --- /dev/null +++ b/internal/logic/product/dev_category.go @@ -0,0 +1,209 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDevCategory struct{} + +func init() { + service.RegisterDevCategory(categoryNew()) +} + +func categoryNew() *sDevCategory { + return &sDevCategory{} +} + +func (s *sDevCategory) Detail(ctx context.Context, id uint) (out *model.ProductCategoryOutput, err error) { + var p *entity.DevProductCategory + + err = dao.DevProductCategory.Ctx(ctx).Where(dao.DevProductCategory.Columns().Id, id).Scan(&p) + if err != nil || p == nil { + return + } + + out = &model.ProductCategoryOutput{ + DevProductCategory: p, + } + + return +} + +func (s *sDevCategory) GetNameByIds(ctx context.Context, categoryIds []uint) (names map[uint]string, err error) { + var categorys []*entity.DevProductCategory + c := dao.DevProductCategory.Columns() + err = dao.DevProductCategory.Ctx(ctx). + Fields(c.Id, c.Name). + WhereIn(c.Id, categoryIds). + OrderDesc(c.Id). + Scan(&categorys) + if err != nil || len(categorys) == 0 { + return + } + + names = make(map[uint]string, len(categorys)) + for _, v := range categorys { + names[v.Id] = v.Name + } + + for _, id := range categoryIds { + if _, ok := names[id]; !ok { + names[id] = "" + } + } + + return +} + +func (s *sDevCategory) ListForPage(ctx context.Context, page, limit int, name string) (out []*model.ProductCategoryTreeOutput, total int, err error) { + if page < 1 { + page = 1 + } + if limit < 1 { + limit = consts.DefaultPageSize + } + + m := dao.DevProductCategory.Ctx(ctx).Fields("id"). + Where(dao.DevProductCategory.Columns().ParentId, 0). + OrderDesc(dao.DevProductCategory.Columns().Id) + + if name != "" { + m = m.WhereLike(dao.DevProductCategory.Columns().Name, "%"+name+"%") + } + + total, _ = m.Count() + if total > 0 { + ids, _ := m.Page(page, limit).Array() + + var categorys []*entity.DevProductCategory + + err = dao.DevProductCategory.Ctx(ctx). + WhereIn(dao.DevProductCategory.Columns().Id, ids). + WhereOr(dao.DevProductCategory.Columns().ParentId, ids). + OrderDesc(dao.DevProductCategory.Columns().Id). + Scan(&categorys) + if err != nil || len(categorys) == 0 { + return + } + + out = Tree(categorys, 0) + } + + return +} + +func (s *sDevCategory) List(ctx context.Context, name string) (out []*model.ProductCategoryTreeOutput, err error) { + var categorys []*entity.DevProductCategory + m := dao.DevProductCategory.Ctx(ctx).OrderDesc(dao.DevProductCategory.Columns().Id) + if name != "" { + m = m.WhereLike(dao.DevProductCategory.Columns().Name, "%"+name+"%") + } + + err = m.Scan(&categorys) + if err != nil || len(categorys) == 0 { + return + } + + out = Tree(categorys, 0) + + return +} + +func Tree(all []*entity.DevProductCategory, pid uint) (rs []*model.ProductCategoryTreeOutput) { + for _, v := range all { + if v.ParentId == pid { + var treeRes *model.ProductCategoryTreeOutput + if err := gconv.Scan(v, &treeRes); err != nil { + return + } + treeRes.Children = Tree(all, v.Id) + + rs = append(rs, treeRes) + } + } + return +} + +func (s *sDevCategory) Add(ctx context.Context, in *model.AddProductCategoryInput) (err error) { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + _, err = dao.DevProductCategory.Ctx(ctx).Data(do.DevProductCategory{ + ParentId: in.ParentId, + Key: in.Key, + Name: in.Name, + Desc: in.Desc, + CreateBy: uint(loginUserId), + }).Insert() + if err != nil { + return + } + + return +} + +func (s *sDevCategory) Edit(ctx context.Context, in *model.EditProductCategoryInput) (err error) { + var category *entity.DevProductCategory + + err = dao.DevProductCategory.Ctx(ctx).Where(dao.DevProductCategory.Columns().Id, in.Id).Scan(&category) + if err != nil { + return + } + if category == nil { + return gerror.New("分类不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + _, err = dao.DevProductCategory.Ctx(ctx).Data(do.DevProductCategory{ + Key: in.Key, + Name: in.Name, + Desc: in.Desc, + UpdateBy: uint(loginUserId), + }).Where(dao.DevProductCategory.Columns().Id, in.Id).Update() + + return +} + +func (s *sDevCategory) Del(ctx context.Context, id uint) (err error) { + var categorys []*entity.DevProductCategory + + err = dao.DevProductCategory.Ctx(ctx). + Where(dao.DevProductCategory.Columns().Id, id). + WhereOr(dao.DevProductCategory.Columns().ParentId, id). + Scan(&categorys) + if err != nil { + return + } + if len(categorys) == 0 { + return gerror.New("分类不存在") + } + if len(categorys) > 1 { + return gerror.New("请先删除子分类") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + _, err = dao.DevProductCategory.Ctx(ctx). + Data(do.DevProductCategory{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DevProductCategory.Columns().Id, id). + Unscoped(). + Update() + + return +} diff --git a/internal/logic/product/dev_device.go b/internal/logic/product/dev_device.go new file mode 100644 index 0000000..463fe99 --- /dev/null +++ b/internal/logic/product/dev_device.go @@ -0,0 +1,654 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "time" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDevDevice struct{} + +func init() { + service.RegisterDevDevice(deviceNew()) +} + +func deviceNew() *sDevDevice { + return &sDevDevice{} +} + +func (s *sDevDevice) Get(ctx context.Context, key string) (out *model.DeviceOutput, err error) { + err = dao.DevDevice.Ctx(ctx).WithAll().Where(dao.DevDevice.Columns().Key, key).Scan(&out) + if err != nil { + return + } + if out == nil { + err = gerror.New("设备不存在") + return + } + if out.Product != nil { + out.ProductName = out.Product.Name + if out.Product.Metadata != "" { + err = json.Unmarshal([]byte(out.Product.Metadata), &out.TSL) + } + } + return +} + +func (s *sDevDevice) Detail(ctx context.Context, id uint) (out *model.DeviceOutput, err error) { + err = dao.DevDevice.Ctx(ctx).WithAll().Where(dao.DevDevice.Columns().Id, id).Scan(&out) + if err != nil { + return + } + if out == nil { + err = gerror.New("设备不存在") + return + } + if out.Product != nil { + out.ProductName = out.Product.Name + if out.Product.Metadata != "" { + err = json.Unmarshal([]byte(out.Product.Metadata), &out.TSL) + } + } + return +} + +func (s *sDevDevice) ListForPage(ctx context.Context, in *model.ListDeviceForPageInput) (out *model.ListDeviceForPageOutput, err error) { + out = new(model.ListDeviceForPageOutput) + c := dao.DevDevice.Columns() + m := dao.DevDevice.Ctx(ctx).OrderDesc(c.Id) + + if in.Status != "" { + m = m.Where(c.Status+" = ", gconv.Int(in.Status)) + } + if in.Key != "" { + m = m.Where(c.Key, in.Key) + } + if in.ProductId > 0 { + m = m.Where(c.ProductId, in.ProductId) + } + if in.TunnelId > 0 { + m = m.Where(c.TunnelId, in.TunnelId) + } + if in.Name != "" { + m = m.WhereLike(c.Name, "%"+in.Name+"%") + } + if len(in.DateRange) > 0 { + m = m.WhereBetween(c.CreatedAt, in.DateRange[0], in.DateRange[1]) + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + err = m.WithAll().Page(in.PageNum, in.PageSize).Scan(&out.Device) + if err != nil { + return + } + + for i, v := range out.Device { + if v.Product != nil { + out.Device[i].ProductName = v.Product.Name + } + } + + return +} + +// List 已发布产品的设备列表 +func (s *sDevDevice) List(ctx context.Context, in *model.ListDeviceInput) (list []*model.DeviceOutput, err error) { + m := dao.DevDevice.Ctx(ctx). + Where(dao.DevDevice.Columns().Status+" > ?", model.DeviceStatusNoEnable) + if in.ProductId > 0 { + m = m.Where(dao.DevDevice.Columns().ProductId, in.ProductId) + } + err = m.WhereIn(dao.DevDevice.Columns().ProductId, + dao.DevProduct.Ctx(ctx). + Fields(dao.DevProduct.Columns().Id). + Where(dao.DevProduct.Columns().Status, model.ProductStatusOn)). + WithAll(). + OrderDesc(dao.DevDevice.Columns().Id). + Scan(&list) + if err != nil { + return + } + + for i, v := range list { + if v.Product != nil { + list[i].ProductName = v.Product.Name + } + } + + return +} + +func (s *sDevDevice) Add(ctx context.Context, in *model.AddDeviceInput) (deviceId uint, err error) { + id, _ := dao.DevDevice.Ctx(ctx). + Fields(dao.DevDevice.Columns().Id). + Where(dao.DevDevice.Columns().Key, in.Key). + Value() + if id.Uint() > 0 { + err = gerror.New("设备标识重复") + return + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevDevice + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + + rs, err := dao.DevDevice.Ctx(ctx).Data(param).Insert() + if err != nil { + return + } + newId, err := rs.LastInsertId() + deviceId = uint(newId) + + return +} + +func (s *sDevDevice) Edit(ctx context.Context, in *model.EditDeviceInput) (err error) { + total, err := dao.DevDevice.Ctx(ctx).Where(dao.DevDevice.Columns().Id, in.Id).Count() + if err != nil { + return + } + if total == 0 { + return gerror.New("设备不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevDevice + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.Id = nil + + _, err = dao.DevDevice.Ctx(ctx).Data(param).Where(dao.DevDevice.Columns().Id, in.Id).Update() + return +} + +func (s *sDevDevice) Del(ctx context.Context, ids []uint) (err error) { + var p []*entity.DevDevice + err = dao.DevDevice.Ctx(ctx).WhereIn(dao.DevDevice.Columns().Id, ids).Scan(&p) + if err != nil { + return + } + if len(p) == 0 { + return gerror.New("设备不存在") + } + if len(p) == 1 && p[0].Status > model.DeviceStatusNoEnable { + return gerror.New("设备已启用,不能删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + for _, id := range ids { + res, _ := s.Detail(ctx, id) + + rs, err := dao.DevDevice.Ctx(ctx). + Data(do.DevDevice{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DevDevice.Columns().Status, model.DeviceStatusNoEnable). + Where(dao.DevDevice.Columns().Id, id). + Unscoped(). + Update() + if err != nil { + return err + } + + num, _ := rs.RowsAffected() + if num > 0 { + // 删除TD子表 + err = service.TSLTable().DropTable(ctx, res.Key) + if err != nil { + return err + } + } + } + + return +} + +// Deploy 设备启用 +func (s *sDevDevice) Deploy(ctx context.Context, id uint) (err error) { + out, err := s.Detail(ctx, id) + if err != nil { + return + } + if out.Status > model.DeviceStatusNoEnable { + return gerror.New("设备已启用") + } + + pd, err := service.DevProduct().Detail(ctx, out.ProductId) + if err != nil { + return err + } + if pd == nil { + return gerror.New("产品不存在") + } + + err = dao.DevDevice.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().Status: model.DeviceStatusOff}). + Where(dao.DevDevice.Columns().Id, id). + Update() + if err != nil { + return err + } + + // 建立TD子表 + if out.MetadataTable == 0 { + err = service.TSLTable().CreateTable(ctx, out.Product.Key, out.Key) + if err != nil { + return err + } + + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().MetadataTable: 1}). + Where(dao.DevDevice.Columns().Id, id). + Update() + } + return err + }) + + return +} + +// Undeploy 设备禁用 +func (s *sDevDevice) Undeploy(ctx context.Context, id uint) (err error) { + var p *entity.DevDevice + + err = dao.DevDevice.Ctx(ctx).Where(dao.DevDevice.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("设备不存在") + } + if p.Status == model.DeviceStatusNoEnable { + return gerror.New("设备已禁用") + } + + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().Status: model.DeviceStatusNoEnable}). + Where(dao.DevDevice.Columns().Id, id). + Update() + + return +} + +// Online 设备上线 +func (s *sDevDevice) Online(ctx context.Context, key string) (err error) { + out, err := s.Get(ctx, key) + if err != nil { + return + } + if out.Status == model.DeviceStatusOn { + return gerror.New("设备已上线") + } + + err = dao.DevDevice.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().Status: model.DeviceStatusOn}). + Where(dao.DevDevice.Columns().Id, out.Id). + Update() + if err != nil { + return err + } + + // 建立TD子表 + if out.MetadataTable == 0 { + err = service.TSLTable().CreateTable(ctx, out.Product.Key, out.Key) + if err != nil { + return err + } + + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().MetadataTable: 1}). + Where(dao.DevDevice.Columns().Id, out.Id). + Update() + } + return err + }) + + return +} + +// Offline 设备下线 +func (s *sDevDevice) Offline(ctx context.Context, key string) (err error) { + out, err := s.Get(ctx, key) + if err != nil { + return + } + if out.Status == model.DeviceStatusOff { + return gerror.New("设备已离线") + } + + _, err = dao.DevDevice.Ctx(ctx). + Data(g.Map{dao.DevDevice.Columns().Status: model.DeviceStatusOff}). + Where(dao.DevDevice.Columns().Id, out.Id). + Update() + + return +} + +// 统计产品下的设备数量 +func (s *sDevDevice) TotalByProductId(ctx context.Context, productIds []uint) (totals map[uint]int, err error) { + r, err := dao.DevDevice.Ctx(ctx).Fields(dao.DevDevice.Columns().ProductId+", count(*) as total"). + WhereIn(dao.DevDevice.Columns().ProductId, productIds). + Group(dao.DevDevice.Columns().ProductId). + All() + if err != nil || r.Len() == 0 { + return + } + + totals = make(map[uint]int, r.Len()) + for _, v := range r { + t := gconv.Int(v["total"]) + id := gconv.Uint(v[dao.DevDevice.Columns().ProductId]) + totals[id] = t + } + + for _, id := range productIds { + if _, ok := totals[id]; !ok { + totals[id] = 0 + } + } + + return +} + +// 统计设备数量 +func (s *sDevDevice) Total(ctx context.Context) (data model.DeviceTotalOutput, err error) { + key := "device:total" + tag := "device" + value := common.Cache().GetOrSetFunc(ctx, key, func(ctx context.Context) (value interface{}, err error) { + var rs model.DeviceTotalOutput + // 设备总量 + rs.DeviceTotal, err = dao.DevDevice.Ctx(ctx).Count() + if err != nil { + return + } + + // 离线设备数量 + rs.DeviceOffline, err = dao.DevDevice.Ctx(ctx).Where(dao.DevDevice.Columns().Status, model.DeviceStatusOff).Count() + if err != nil { + return + } + + // 产品总量 + rs.ProductTotal, err = dao.DevProduct.Ctx(ctx).Count() + if err != nil { + return + } + + // 产品新增数量 + rs.ProductAdded, err = dao.DevProduct.Ctx(ctx). + Where(dao.DevProduct.Columns().CreatedAt+">=?", gtime.Now().Format("Y-m-d")). + Count() + if err != nil { + return + } + + // 设备消息总量 TDengine + sql := "select count(*) as num from device_log" + data, err := service.TdEngine().GetOne(ctx, sql) + if err != nil { + return + } + rs.MsgTotal = data["num"].Int() + + // 设备消息新增数量 TDengine + sql = "select count(*) as num from device_log where ts >= '?'" + data, err = service.TdEngine().GetOne(ctx, sql, gtime.Now().Format("Y-m-d")) + if err != nil { + return + } + rs.MsgAdded = data["num"].Int() + + // 设备报警总量 + rs.AlarmTotal, err = dao.AlarmLog.Ctx(ctx).Count() + if err != nil { + return + } + + // 设备报警增量 + rs.AlarmAdded, err = dao.AlarmLog.Ctx(ctx). + Where(dao.AlarmLog.Columns().CreatedAt+">=?", gtime.Now().Format("Y-m-d")). + Count() + if err != nil { + return + } + + value = rs + return + }, 7200*time.Second, tag) + + err = gconv.Struct(value, &data) + return +} + +// 统计设备月度数量 +func (s *sDevDevice) TotalForMonths(ctx context.Context) (data map[int]int, err error) { + key := "device:totalForMonths" + tag := "device" + value := common.Cache().GetOrSetFunc(ctx, key, func(ctx context.Context) (value interface{}, err error) { + rs := make(map[int]int, 12) + for i := 0; i < 12; i++ { + rs[i+1] = 0 + } + + // 设备消息总量 TDengine + sql := "select substr(to_iso8601(ts), 1, 7) as ym, count(*) as num from device_log where ts >= '?' group by substr(to_iso8601(ts), 1, 7)" + list, err := service.TdEngine().GetAll(ctx, sql, gtime.Now().Format("Y-01-01 00:00:00")) + if err != nil { + return + } + + for _, v := range list { + m := gstr.SubStr(v["ym"].String(), 5) + rs[gconv.Int(m)] = v["num"].Int() + } + + value = rs + return + }, 7200*time.Second, tag) + + err = gconv.Scan(value, &data) + return +} + +// 统计设备月度告警数量 +func (s *sDevDevice) AlarmTotalForMonths(ctx context.Context) (data map[int]int, err error) { + key := "device:alarmTotalForMonths" + tag := "device" + value := common.Cache().GetOrSetFunc(ctx, key, func(ctx context.Context) (value interface{}, err error) { + rs := make(map[int]int, 12) + for i := 0; i < 12; i++ { + rs[i+1] = 0 + } + + at := dao.AlarmLog.Columns().CreatedAt + list, err := dao.AlarmLog.Ctx(ctx). + Fields("date_format("+at+", '%Y%m') as ym, count(*) as num"). + Where(at+">=?", gtime.Now().Format("Y-01-01 00:00:00")). + Group("date_format(" + at + ", '%Y%m')"). + All() + if err != nil { + return + } + + for _, v := range list { + m := gstr.SubStr(v["ym"].String(), 4) + rs[gconv.Int(m)] = v["num"].Int() + } + + value = rs + return + }, 7200*time.Second, tag) + + err = gconv.Scan(value, &data) + return +} + +// RunStatus 运行状态 +func (s *sDevDevice) RunStatus(ctx context.Context, id uint) (out *model.DeviceRunStatusOutput, err error) { + p, err := s.Detail(ctx, id) + if err != nil { + return + } + + out = new(model.DeviceRunStatusOutput) + out.Status = p.Status + // out.LastOnlineTime = p.LastOnlineTime + + if p.Status == model.DeviceStatusNoEnable { + return + } + + // 属性值获取 + sql := "select * from ? order by ts desc limit 1" + rs, err := service.TdEngine().GetOne(ctx, sql, p.Key) + if err != nil { + return + } + out.LastOnlineTime = rs["ts"].GTime() + + var properties []model.DevicePropertiy + for _, v := range p.TSL.Properties { + // 获取当天属性值列表 + var ls gdb.Result + if _, ok := rs[v.Key]; ok { + sql := "select ? from ? where ts >= '?' order by ts desc" + ls, _ = service.TdEngine().GetAll(ctx, sql, v.Key, p.Key, gtime.Now().Format("Y-m-d")) + } + + unit := "" + if v.ValueType.Unit != nil { + unit = *v.ValueType.Unit + } + pro := model.DevicePropertiy{ + Key: v.Key, + Name: v.Name, + Type: v.ValueType.Type, + Unit: unit, + Value: rs[v.Key], + List: ls.Array(v.Key), + } + properties = append(properties, pro) + } + out.Properties = properties + + return +} + +// GetProperty 获取指定属性值 +func (s *sDevDevice) GetProperty(ctx context.Context, in *model.DeviceGetPropertyInput) (out *model.DevicePropertiy, err error) { + p, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if p.Status == model.DeviceStatusNoEnable { + err = gerror.New("设备未启用") + return + } + + // 属性值获取 + sql := "select ? from ? order by ts desc limit 1" + rs, err := service.TdEngine().GetOne(ctx, sql, in.PropertyKey, p.Key) + if err != nil { + return + } + + var name string + var valueType string + for _, v := range p.TSL.Properties { + if v.Key == in.PropertyKey { + name = v.Name + valueType = v.ValueType.Type + break + } + } + + out = new(model.DevicePropertiy) + out.Key = in.PropertyKey + out.Name = name + out.Type = valueType + out.Value = rs[in.PropertyKey] + + // 获取当天属性值列表 + sql = "select ? from ? where ts >= '?' order by ts desc" + ls, _ := service.TdEngine().GetAll(ctx, sql, in.PropertyKey, p.Key, gtime.Now().Format("Y-m-d")) + out.List = ls.Array(in.PropertyKey) + + return +} + +// GetPropertyList 设备属性详情列表 +func (s *sDevDevice) GetPropertyList(ctx context.Context, in *model.DeviceGetPropertyListInput) (out *model.DeviceGetPropertyListOutput, err error) { + p, err := s.Detail(ctx, in.Id) + if err != nil { + return + } + if p.Status == model.DeviceStatusNoEnable { + err = gerror.New("设备未启用") + return + } + + out = new(model.DeviceGetPropertyListOutput) + + // TDengine + sql := "select count(*) as num from ? where ts >= '?'" + rs, err := service.TdEngine().GetOne(ctx, sql, p.Key, gtime.Now().Format("Y-m-d")) + if err != nil { + return + } + out.Total = rs["num"].Int() + out.CurrentPage = in.PageNum + + sql = "select ts, ? from ? where ts >= '?' order by ts desc limit ?, ?" + ls, _ := service.TdEngine().GetAll( + ctx, sql, + in.PropertyKey, + p.Key, + gtime.Now().Format("Y-m-d"), + (in.PageNum-1)*in.PageSize, + in.PageSize, + ) + + var pro []*model.DevicePropertiyOut + for _, v := range ls.List() { + + pro = append(pro, &model.DevicePropertiyOut{ + Ts: gvar.New(v["ts"]).GTime(), + Value: gvar.New(v[in.PropertyKey]), + }) + } + out.List = pro + + return +} diff --git a/internal/logic/product/dev_device_log.go b/internal/logic/product/dev_device_log.go new file mode 100644 index 0000000..168a8cc --- /dev/null +++ b/internal/logic/product/dev_device_log.go @@ -0,0 +1,57 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strings" +) + +type sDevDeviceLog struct{} + +func init() { + service.RegisterDevDeviceLog(devDeviceLog()) +} + +func devDeviceLog() *sDevDeviceLog { + return &sDevDeviceLog{} +} + +// 日志类型 +func (s *sDevDeviceLog) LogType(ctx context.Context) (list []string) { + list = consts.GetTopicTypes() + return +} + +// 日志搜索 +func (s *sDevDeviceLog) Search(ctx context.Context, in *model.DeviceLogSearchInput) (out *model.DeviceLogSearchOutput, err error) { + out = new(model.DeviceLogSearchOutput) + + var whereOr []string + for _, v := range in.Types { + whereOr = append(whereOr, "type='"+v+"'") + } + + where := "" + if len(whereOr) > 0 { + where = " and (" + strings.Join(whereOr, " or ") + ") " + } + + if len(in.DateRange) > 0 { + where += " and (ts >= '" + in.DateRange[0] + "' and ts <= '" + in.DateRange[1] + "') " + } + + // TDengine + sql := "select count(*) as num from device_log where device='?'" + where + rs, err := service.TdEngine().GetOne(ctx, sql, in.DeviceKey) + if err != nil { + return + } + out.Total = rs["num"].Int() + out.CurrentPage = in.PageNum + + sql = "select * from device_log where device='?'" + where + " order by ts desc limit ?, ?" + out.List, err = service.TdLogTable().GetAll(ctx, sql, in.DeviceKey, (in.PageNum-1)*in.PageSize, in.PageSize) + return +} diff --git a/internal/logic/product/dev_device_tag.go b/internal/logic/product/dev_device_tag.go new file mode 100644 index 0000000..6861586 --- /dev/null +++ b/internal/logic/product/dev_device_tag.go @@ -0,0 +1,79 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDevDeviceTag struct{} + +func init() { + service.RegisterDevDeviceTag(deviceTagNew()) +} + +func deviceTagNew() *sDevDeviceTag { + return &sDevDeviceTag{} +} + +func (s *sDevDeviceTag) Add(ctx context.Context, in *model.AddTagDeviceInput) (err error) { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevDeviceTag + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + + _, err = dao.DevDeviceTag.Ctx(ctx).Data(param).Insert() + return +} + +func (s *sDevDeviceTag) Edit(ctx context.Context, in *model.EditTagDeviceInput) (err error) { + total, _ := dao.DevDeviceTag.Ctx(ctx).Where(dao.DevDeviceTag.Columns().Id, in.Id).Count() + if total == 0 { + return gerror.New("标签不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevDeviceTag + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.Id = nil + + _, err = dao.DevDeviceTag.Ctx(ctx).Data(param).Where(dao.DevDeviceTag.Columns().Id, in.Id).Update() + return +} + +func (s *sDevDeviceTag) Del(ctx context.Context, id uint) (err error) { + total, _ := dao.DevDeviceTag.Ctx(ctx).Where(dao.DevDeviceTag.Columns().Id, id).Count() + if total == 0 { + return gerror.New("标签不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + _, err = dao.DevDeviceTag.Ctx(ctx). + Data(do.DevDeviceTag{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DevDeviceTag.Columns().Id, id). + Unscoped(). + Update() + return +} diff --git a/internal/logic/product/dev_device_test.go b/internal/logic/product/dev_device_test.go new file mode 100644 index 0000000..dc93a69 --- /dev/null +++ b/internal/logic/product/dev_device_test.go @@ -0,0 +1,34 @@ +package product + +import ( + "context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/tdengine" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" +) + +func TestTotal(t *testing.T) { + out, err := service.DevDevice().Total(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestTotalForMonths(t *testing.T) { + out, err := service.DevDevice().TotalForMonths(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestAlarmTotalForMonths(t *testing.T) { + out, err := service.DevDevice().AlarmTotalForMonths(context.TODO()) + if err != nil { + t.Fatal(err) + } + t.Log(out) +} diff --git a/internal/logic/product/dev_product.go b/internal/logic/product/dev_product.go new file mode 100644 index 0000000..77af175 --- /dev/null +++ b/internal/logic/product/dev_product.go @@ -0,0 +1,367 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +type sDevProduct struct{} + +func init() { + service.RegisterDevProduct(productNew()) +} + +func productNew() *sDevProduct { + return &sDevProduct{} +} + +func (s *sDevProduct) Get(ctx context.Context, key string) (out *model.DetailProductOutput, err error) { + err = dao.DevProduct.Ctx(ctx).WithAll().Where(dao.DevProduct.Columns().Key, key).Scan(&out) + if err != nil || out == nil { + return + } + + if out.Metadata != "" { + err = json.Unmarshal([]byte(out.Metadata), &out.TSL) + if err != nil { + return + } + } + + if out.Category != nil { + out.CategoryName = out.Category.Name + } + + // 获取产品的设备数量 + totals, err := service.DevDevice().TotalByProductId(ctx, []uint{out.Id}) + if err != nil { + return + } + out.DeviceTotal = totals[out.Id] + + return +} + +func (s *sDevProduct) Detail(ctx context.Context, id uint) (out *model.DetailProductOutput, err error) { + err = dao.DevProduct.Ctx(ctx).WithAll().Where(dao.DevProduct.Columns().Id, id).Scan(&out) + if err != nil || out == nil { + return + } + + if out.Metadata != "" { + err = json.Unmarshal([]byte(out.Metadata), &out.TSL) + if err != nil { + return + } + } + + if out.Category != nil { + out.CategoryName = out.Category.Name + } + + // 获取产品的设备数量 + totals, err := service.DevDevice().TotalByProductId(ctx, []uint{out.Id}) + if err != nil { + return + } + out.DeviceTotal = totals[out.Id] + + return +} + +func (s *sDevProduct) GetNameByIds(ctx context.Context, productIds []uint) (names map[uint]string, err error) { + var products []*entity.DevProduct + c := dao.DevProduct.Columns() + err = dao.DevProduct.Ctx(ctx). + Fields(c.Id, c.Name). + WhereIn(c.Id, productIds). + Scan(&products) + if err != nil || len(products) == 0 { + return + } + + names = make(map[uint]string, len(products)) + for _, v := range products { + names[v.Id] = v.Name + } + + for _, id := range productIds { + if _, ok := names[id]; !ok { + names[id] = "" + } + } + + return +} + +func (s *sDevProduct) ListForPage(ctx context.Context, in *model.ListForPageInput) (out *model.ListForPageOutput, err error) { + out = new(model.ListForPageOutput) + c := dao.DevProduct.Columns() + m := dao.DevProduct.Ctx(ctx).OrderDesc(c.Id) + + if in.Status != "" { + m = m.Where(c.Status+" = ", gconv.Int(in.Status)) + } + if in.CategoryId > 0 { + m = m.Where(c.CategoryId, in.CategoryId) + } + if in.Name != "" { + m = m.WhereLike(c.Name, "%"+in.Name+"%") + } + if len(in.MessageProtocols) > 0 { + m = m.WhereIn(c.MessageProtocol, in.MessageProtocols) + } + if len(in.DeviceTypes) > 0 { + m = m.WhereIn(c.DeviceType, in.DeviceTypes) + } + if len(in.DateRange) > 0 { + m = m.WhereBetween(c.CreatedAt, in.DateRange[0], in.DateRange[1]) + } + + out.Total, _ = m.Count() + out.CurrentPage = in.PageNum + err = m.WithAll().Page(in.PageNum, in.PageSize).Scan(&out.Product) + if err != nil || len(out.Product) == 0 { + return + } + + dLen := len(out.Product) + var productIds = make([]uint, dLen) + for i, v := range out.Product { + productIds[i] = v.Id + + if v.Category != nil { + out.Product[i].CategoryName = v.Category.Name + } + } + + // 获取产品的设备数量 + totals, err := service.DevDevice().TotalByProductId(ctx, productIds) + if err != nil { + return + } + for i, v := range out.Product { + out.Product[i].DeviceTotal = totals[v.Id] + } + + return +} + +func (s *sDevProduct) List(ctx context.Context) (list []*model.ProductOutput, err error) { + err = dao.DevProduct.Ctx(ctx).WithAll(). + Where(dao.DevProduct.Columns().Status, model.ProductStatusOn). + OrderDesc(dao.DevProduct.Columns().Id). + Scan(&list) + if err != nil || len(list) == 0 { + return + } + + dLen := len(list) + var productIds = make([]uint, dLen) + for i, v := range list { + productIds[i] = v.Id + + if v.Category != nil { + list[i].CategoryName = v.Category.Name + } + } + + // 获取产品的设备数量 + totals, err := service.DevDevice().TotalByProductId(ctx, productIds) + if err != nil { + return + } + for i, v := range list { + list[i].DeviceTotal = totals[v.Id] + } + + return +} + +func (s *sDevProduct) Add(ctx context.Context, in *model.AddProductInput) (err error) { + id, _ := dao.DevProduct.Ctx(ctx). + Fields(dao.DevProduct.Columns().Id). + Where(dao.DevProduct.Columns().Key, in.Key). + Value() + if id.Uint() > 0 { + return gerror.New("产品标识重复") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevProduct + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.CreateBy = uint(loginUserId) + param.Status = 0 + + tsl := &model.TSL{ + Key: in.Key, + Name: in.Name, + } + param.Metadata, err = json.Marshal(tsl) + if err != nil { + return + } + + _, err = dao.DevProduct.Ctx(ctx).Data(param).Insert() + + return +} + +func (s *sDevProduct) Edit(ctx context.Context, in *model.EditProductInput) (err error) { + total, err := dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.Id).Count() + if err != nil { + return + } + if total == 0 { + return gerror.New("产品不存在") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + var param *do.DevProduct + err = gconv.Scan(in, ¶m) + if err != nil { + return + } + param.UpdateBy = uint(loginUserId) + param.Id = nil + + _, err = dao.DevProduct.Ctx(ctx).Data(param).Where(dao.DevProduct.Columns().Id, in.Id).Update() + + return +} + +func (s *sDevProduct) Del(ctx context.Context, ids []uint) (err error) { + var p []*entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).WhereIn(dao.DevProduct.Columns().Id, ids).Scan(&p) + if err != nil { + return + } + if len(p) == 0 { + return gerror.New("产品不存在") + } + if len(p) == 1 && p[0].Status == model.ProductStatusOn { + return gerror.New("产品已发布,不能删除") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + for _, id := range ids { + res, _ := s.Detail(ctx, id) + + rs, err := dao.DevProduct.Ctx(ctx). + Data(do.DevProduct{ + DeletedBy: uint(loginUserId), + DeletedAt: gtime.Now(), + }). + Where(dao.DevProduct.Columns().Status, model.ProductStatusOff). + Where(dao.DevProduct.Columns().Id, id). + Unscoped(). + Update() + if err != nil { + return err + } + + num, _ := rs.RowsAffected() + if num > 0 { + // 删除TD表 + err = service.TSLTable().DropStable(ctx, res.Key) + if err != nil { + return err + } + } + } + + return +} + +func (s *sDevProduct) Deploy(ctx context.Context, id uint) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + if p.Status == model.ProductStatusOn { + return gerror.New("产品已发布") + } + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(g.Map{dao.DevProduct.Columns().Status: model.ProductStatusOn}). + Where(dao.DevProduct.Columns().Id, id). + Update() + if err != nil { + return err + } + + // 建立TD表 + if p.Metadata != "" && p.MetadataTable == 0 { + var tsl *model.TSL + err = json.Unmarshal([]byte(p.Metadata), &tsl) + if err != nil { + return err + } + + err = service.TSLTable().CreateStable(ctx, tsl) + if err != nil { + return err + } + + _, err = dao.DevProduct.Ctx(ctx). + Data(g.Map{dao.DevProduct.Columns().MetadataTable: 1}). + Where(dao.DevProduct.Columns().Id, id). + Update() + if err != nil { + return err + } + } + return nil + }) + + return +} + +func (s *sDevProduct) Undeploy(ctx context.Context, id uint) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, id).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + if p.Status == model.ProductStatusOff { + return gerror.New("产品已停用") + } + + _, err = dao.DevProduct.Ctx(ctx). + Data(g.Map{dao.DevProduct.Columns().Status: model.ProductStatusOff}). + Where(dao.DevProduct.Columns().Id, id). + Update() + + return +} diff --git a/internal/logic/product/dev_tsl_data_type.go b/internal/logic/product/dev_tsl_data_type.go new file mode 100644 index 0000000..40a943d --- /dev/null +++ b/internal/logic/product/dev_tsl_data_type.go @@ -0,0 +1,62 @@ +package product + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sDevTSLDataType struct{} + +func init() { + service.RegisterDevTSLDataType(devTSLDataTypeNew()) +} + +func devTSLDataTypeNew() *sDevTSLDataType { + return &sDevTSLDataType{} +} + +func (s *sDevTSLDataType) DataTypeValueList(ctx context.Context) (out *model.DataTypeOutput, err error) { + tMax := 0 + tString := "" + tDecimals := 2 + tTrueText := "是" + tFalseText := "否" + tTrueValue := true + tFalseValue := false + + // 基础类型 + baseType := []model.DataTypeValueBase{ + {Title: "int(整数型)", Type: "int", TSLParamBase: model.TSLParamBase{Max: &tMax, Min: &tMax, Unit: &tString}}, + {Title: "long(长整数型)", Type: "long", TSLParamBase: model.TSLParamBase{Max: &tMax, Min: &tMax, Unit: &tString}}, + {Title: "float(单精度浮点型)", Type: "float", TSLParamBase: model.TSLParamBase{Decimals: &tDecimals, Max: &tMax, Min: &tMax, Unit: &tString}}, + {Title: "double(双精度浮点型)", Type: "double", TSLParamBase: model.TSLParamBase{Decimals: &tDecimals, Max: &tMax, Min: &tMax, Unit: &tString}}, + {Title: "text(字符串)", Type: "string", TSLParamBase: model.TSLParamBase{MaxLength: &tMax}}, + {Title: "bool(布尔型)", Type: "boolean", TSLParamBase: model.TSLParamBase{TrueText: &tTrueText, FalseText: &tFalseText, TrueValue: &tTrueValue, FalseValue: &tFalseValue}}, + } + + tEnum := []model.TSLEnumType{ + {Value: "枚举值", Text: "枚举文本"}, + } + + tArray := &model.TSLArrayType{TSLValueType: model.TSLValueType{Type: "int", TSLParam: model.TSLParam{TSLParamBase: model.TSLParamBase{Max: &tMax, Min: &tMax, Unit: &tString}}}} + + tObject := []model.TSLObjectType{ + {Key: "参数标识", Name: "参数名称", Desc: "描述", ValueType: model.TSLValueType{Type: "int", TSLParam: model.TSLParam{TSLParamBase: model.TSLParamBase{Max: &tMax, Min: &tMax, Unit: &tString}}}}, + } + + // 扩展类型 + extensionType := []model.DataTypeValueExtension{ + {Title: "date(时间戳)", Type: "date"}, + {Title: "enum(枚举)", Type: "enum", TSLParamExtension: model.TSLParamExtension{Elements: tEnum}}, + {Title: "array(数组)", Type: "array", TSLParamExtension: model.TSLParamExtension{ElementType: tArray}}, + {Title: "object(结构体)", Type: "object", TSLParamExtension: model.TSLParamExtension{Properties: tObject}}, + } + + out = &model.DataTypeOutput{ + BaseType: baseType, + ExtensionType: extensionType, + } + + return +} diff --git a/internal/logic/product/dev_tsl_event.go b/internal/logic/product/dev_tsl_event.go new file mode 100644 index 0000000..f2cf53e --- /dev/null +++ b/internal/logic/product/dev_tsl_event.go @@ -0,0 +1,195 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "math" + + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" +) + +type sDevTSLEvent struct{} + +func init() { + service.RegisterDevTSLEvent(devTSLEventNew()) +} + +func devTSLEventNew() *sDevTSLEvent { + return &sDevTSLEvent{} +} + +func (s *sDevTSLEvent) ListEvent(ctx context.Context, in *model.ListTSLEventInput) (out *model.ListTSLEventOutput, err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return nil, gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + out = new(model.ListTSLEventOutput) + out.CurrentPage = in.PageNum + + if len(tsl.Events) == 0 { + return + } + + length := len(tsl.Events) + out.Total = length + + if in.PageNum > int(math.Ceil(float64(length)/float64(in.PageSize))) { + return + } + start := (in.PageNum - 1) * in.PageSize + end := in.PageSize + start + if end > length { + end = length + } + out.Data = tsl.Events[start:end] + + return +} + +func (s *sDevTSLEvent) AddEvent(ctx context.Context, in *model.TSLEventInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + tsl := new(model.TSL) + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := checkExistKey(in.Key, *tsl) + if existKey { + return gerror.New("标识已存在,物模型模块下唯一") + } + + tsl.Events = append(tsl.Events, in.TSLEvent) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} + +func (s *sDevTSLEvent) EditEvent(ctx context.Context, in *model.TSLEventInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Events { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("事件不存在") + } + + newEvents := append(tsl.Events[:existIndex], in.TSLEvent) + tsl.Events = append(newEvents, tsl.Events[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} + +func (s *sDevTSLEvent) DelEvent(ctx context.Context, in *model.DelTSLEventInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Events { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("事件不存在") + } + + tsl.Events = append(tsl.Events[:existIndex], tsl.Events[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} diff --git a/internal/logic/product/dev_tsl_function.go b/internal/logic/product/dev_tsl_function.go new file mode 100644 index 0000000..37af010 --- /dev/null +++ b/internal/logic/product/dev_tsl_function.go @@ -0,0 +1,195 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "math" + + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" +) + +type sDevTSLFunction struct{} + +func init() { + service.RegisterDevTSLFunction(devTSLFunctionNew()) +} + +func devTSLFunctionNew() *sDevTSLFunction { + return &sDevTSLFunction{} +} + +func (s *sDevTSLFunction) ListFunction(ctx context.Context, in *model.ListTSLFunctionInput) (out *model.ListTSLFunctionOutput, err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return nil, gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + out = new(model.ListTSLFunctionOutput) + out.CurrentPage = in.PageNum + + if len(tsl.Functions) == 0 { + return + } + + length := len(tsl.Functions) + out.Total = length + + if in.PageNum > int(math.Ceil(float64(length)/float64(in.PageSize))) { + return + } + start := (in.PageNum - 1) * in.PageSize + end := in.PageSize + start + if end > length { + end = length + } + out.Data = tsl.Functions[start:end] + + return +} + +func (s *sDevTSLFunction) AddFunction(ctx context.Context, in *model.TSLFunctionAddInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + tsl := new(model.TSL) + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := checkExistKey(in.Key, *tsl) + if existKey { + return gerror.New("标识已存在,物模型模块下唯一") + } + + tsl.Functions = append(tsl.Functions, in.TSLFunction) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} + +func (s *sDevTSLFunction) EditFunction(ctx context.Context, in *model.TSLFunctionAddInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Functions { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("功能不存在") + } + + newFunctions := append(tsl.Functions[:existIndex], in.TSLFunction) + tsl.Functions = append(newFunctions, tsl.Functions[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} + +func (s *sDevTSLFunction) DelFunction(ctx context.Context, in *model.DelTSLFunctionInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Functions { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("功能不存在") + } + + tsl.Functions = append(tsl.Functions[:existIndex], tsl.Functions[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} diff --git a/internal/logic/product/dev_tsl_property.go b/internal/logic/product/dev_tsl_property.go new file mode 100644 index 0000000..bfacebc --- /dev/null +++ b/internal/logic/product/dev_tsl_property.go @@ -0,0 +1,301 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "math" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/text/gstr" +) + +type sDevTSLProperty struct{} + +func init() { + service.RegisterDevTSLProperty(devTSLPropertyNew()) +} + +func devTSLPropertyNew() *sDevTSLProperty { + return &sDevTSLProperty{} +} + +func (s *sDevTSLProperty) ListProperty(ctx context.Context, in *model.ListTSLPropertyInput) (out *model.ListTSLPropertyOutput, err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return nil, gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + out = new(model.ListTSLPropertyOutput) + out.CurrentPage = in.PageNum + + if len(tsl.Properties) == 0 { + return + } + + if in.Name != "" { + j := 0 + for _, v := range tsl.Properties { + if gstr.Contains(v.Name, in.Name) { + tsl.Properties[j] = v + j++ + } + } + tsl.Properties = tsl.Properties[:j] + } + + if in.DateType != "" { + j := 0 + for _, v := range tsl.Properties { + if gstr.Contains(v.ValueType.Type, in.DateType) { + tsl.Properties[j] = v + j++ + } + } + tsl.Properties = tsl.Properties[:j] + } + + length := len(tsl.Properties) + out.Total = length + + if in.PageNum > int(math.Ceil(float64(length)/float64(in.PageSize))) { + return + } + start := (in.PageNum - 1) * in.PageSize + end := in.PageSize + start + if end > length { + end = length + } + out.Data = tsl.Properties[start:end] + + return +} + +func (s *sDevTSLProperty) AllProperty(ctx context.Context, key string) (list []model.TSLProperty, err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Key, key).Scan(&p) + if err != nil { + return + } + if p == nil { + return nil, gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + list = tsl.Properties + + return +} + +func (s *sDevTSLProperty) AddProperty(ctx context.Context, in *model.TSLPropertyInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if p == nil { + return gerror.New("产品不存在") + } + + tsl := new(model.TSL) + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + if err = j.Scan(tsl); err != nil { + return + } + + // 检查属性标识Key是否存在 + existKey := checkExistKey(in.Key, *tsl) + if existKey { + return gerror.New("标识已存在,物模型模块下唯一") + } + + tsl.Properties = append(tsl.Properties, in.TSLProperty) + metaData, _ := json.Marshal(tsl) + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + if err != nil { + return err + } + + // 增加TD表字段 + if p.MetadataTable == 1 { + maxLength := 0 + if in.ValueType.TSLParamBase.MaxLength != nil { + maxLength = *in.ValueType.TSLParamBase.MaxLength + } + err = service.TSLTable().AddDatabaseField(ctx, p.Key, in.Key, in.ValueType.Type, maxLength) + if err != nil { + return err + } + } + return nil + }) + + return +} + +func (s *sDevTSLProperty) EditProperty(ctx context.Context, in *model.TSLPropertyInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查属性标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Properties { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("属性不存在") + } + + old := tsl.Properties[existIndex] + old.Name = in.Name + old.AccessMode = in.AccessMode + old.Desc = in.Desc + in.ValueType.Type = old.ValueType.Type + old.ValueType = in.ValueType + + newProperties := append(tsl.Properties[:existIndex], old) + tsl.Properties = append(newProperties, tsl.Properties[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + + return +} + +func (s *sDevTSLProperty) DelProperty(ctx context.Context, in *model.DelTSLPropertyInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查属性标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Properties { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("属性不存在") + } + + tsl.Properties = append(tsl.Properties[:existIndex], tsl.Properties[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + if err != nil { + return err + } + + // 删除TD表字段 + if p.MetadataTable == 1 { + err = service.TSLTable().DelDatabaseField(ctx, p.Key, in.Key) + if err != nil { + return err + } + } + return nil + }) + + return +} + +// 检查标识Key是否存在,物模型模块下唯一 +func checkExistKey(key string, tsl model.TSL) bool { + for _, v := range tsl.Properties { + if v.Key == key { + return true + } + } + for _, v := range tsl.Functions { + if v.Key == key { + return true + } + } + for _, v := range tsl.Events { + if v.Key == key { + return true + } + } + for _, v := range tsl.Tags { + if v.Key == key { + return true + } + } + return false +} diff --git a/internal/logic/product/dev_tsl_tag.go b/internal/logic/product/dev_tsl_tag.go new file mode 100644 index 0000000..6d5071f --- /dev/null +++ b/internal/logic/product/dev_tsl_tag.go @@ -0,0 +1,237 @@ +package product + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "math" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" +) + +type sDevTSLTag struct{} + +func init() { + service.RegisterDevTSLTag(devTSLTagNew()) +} + +func devTSLTagNew() *sDevTSLTag { + return &sDevTSLTag{} +} + +func (s *sDevTSLTag) ListTag(ctx context.Context, in *model.ListTSLTagInput) (out *model.ListTSLTagOutput, err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if err != nil { + return + } + if p == nil { + return nil, gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + out = new(model.ListTSLTagOutput) + out.CurrentPage = in.PageNum + + if len(tsl.Tags) == 0 { + return + } + + length := len(tsl.Tags) + out.Total = length + + if in.PageNum > int(math.Ceil(float64(length)/float64(in.PageSize))) { + return + } + start := (in.PageNum - 1) * in.PageSize + end := in.PageSize + start + if end > length { + end = length + } + out.Data = tsl.Tags[start:end] + + return +} + +func (s *sDevTSLTag) AddTag(ctx context.Context, in *model.TSLTagInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if p == nil { + return gerror.New("产品不存在") + } + + tsl := new(model.TSL) + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := checkExistKey(in.Key, *tsl) + if existKey { + return gerror.New("标识已存在,物模型模块下唯一") + } + + tsl.Tags = append(tsl.Tags, in.TSLTag) + metaData, _ := json.Marshal(tsl) + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + if err != nil { + return err + } + + // 增加TD表标签 + if p.MetadataTable == 1 { + maxLength := 0 + if in.ValueType.TSLParamBase.MaxLength != nil { + maxLength = *in.ValueType.TSLParamBase.MaxLength + } + err = service.TSLTable().AddTag(ctx, p.Key, in.Key, in.ValueType.Type, maxLength) + if err != nil { + return err + } + } + return nil + }) + + return +} + +func (s *sDevTSLTag) EditTag(ctx context.Context, in *model.TSLTagInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Tags { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("标签不存在") + } + + newTags := append(tsl.Tags[:existIndex], in.TSLTag) + tsl.Tags = append(newTags, tsl.Tags[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + if err != nil { + return err + } + + // 更新TD表结构 + if p.MetadataTable == 1 { + maxLength := 0 + if in.ValueType.TSLParamBase.MaxLength != nil { + maxLength = *in.ValueType.TSLParamBase.MaxLength + } + err = service.TSLTable().ModifyTag(ctx, p.Key, in.Key, in.ValueType.Type, maxLength) + if err != nil { + return err + } + } + return nil + }) + + return +} + +func (s *sDevTSLTag) DelTag(ctx context.Context, in *model.DelTSLTagInput) (err error) { + var p *entity.DevProduct + + err = dao.DevProduct.Ctx(ctx).Where(dao.DevProduct.Columns().Id, in.ProductId).Scan(&p) + if p == nil { + return gerror.New("产品不存在") + } + + j, err := gjson.DecodeToJson(p.Metadata) + if err != nil { + return + } + tsl := new(model.TSL) + if err = j.Scan(tsl); err != nil { + return + } + + // 检查标识Key是否存在 + existKey := false + existIndex := 0 + for i, v := range tsl.Tags { + if v.Key == in.Key { + existKey = true + existIndex = i + break + } + } + if !existKey { + return gerror.New("标签不存在") + } + + tsl.Tags = append(tsl.Tags[:existIndex], tsl.Tags[existIndex+1:]...) + metaData, _ := json.Marshal(tsl) + + err = dao.DevProduct.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { + _, err = dao.DevProduct.Ctx(ctx). + Data(dao.DevProduct.Columns().Metadata, metaData). + Where(dao.DevProduct.Columns().Id, in.ProductId). + Update() + if err != nil { + return err + } + + // 删除TD表字段 + if p.MetadataTable == 1 { + err = service.TSLTable().DelTag(ctx, p.Key, in.Key) + if err != nil { + return err + } + } + return nil + }) + + return +} diff --git a/internal/logic/system/captcha.go b/internal/logic/system/captcha.go new file mode 100644 index 0000000..4e1f8e7 --- /dev/null +++ b/internal/logic/system/captcha.go @@ -0,0 +1,50 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/text/gstr" + "github.com/sagoo-cloud/sagooiot/internal/service" + "image/color" + + "github.com/mojocn/base64Captcha" +) + +type sCaptcha struct{} + +var ( + captchaStore = base64Captcha.DefaultMemStore + captchaDriver = &base64Captcha.DriverString{ + Height: 80, + Width: 240, + NoiseCount: 50, + ShowLineOptions: 20, + Length: 4, + Source: "abcdefghjkmnpqrstuvwxyz23456789", + Fonts: []string{"chromohv.ttf"}, + BgColor: &color.RGBA{R: 209, G: 205, B: 205, A: 90}, + } +) + +func init() { + service.RegisterCaptcha(New()) +} + +// Captcha 验证码管理服务 +func New() *sCaptcha { + return &sCaptcha{} +} + +// GetVerifyImgString 获取字母数字混合验证码 +func (s *sCaptcha) GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string, err error) { + driver := captchaDriver.ConvertFonts() + c := base64Captcha.NewCaptcha(driver, captchaStore) + idKeyC, base64stringC, err = c.Generate() + return +} + +// VerifyString 验证输入的验证码是否正确 +func (s *sCaptcha) VerifyString(id, answer string) bool { + c := base64Captcha.NewCaptcha(captchaDriver, captchaStore) + answer = gstr.ToLower(answer) + return c.Verify(id, answer, true) +} diff --git a/internal/logic/system/login.go b/internal/logic/system/login.go new file mode 100644 index 0000000..6948351 --- /dev/null +++ b/internal/logic/system/login.go @@ -0,0 +1,137 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/crypto/gmd5" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" + "github.com/mssola/user_agent" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "strings" +) + +type sLogin struct { +} + +func loginNew() *sLogin { + return &sLogin{} +} + +func init() { + service.RegisterLogin(loginNew()) +} + +// Login 登录 +func (s *sLogin) Login(ctx context.Context, verifyKey string, captcha string, userName string, password string) (loginUserOut *model.LoginUserOut, token string, err error) { + //判断验证码是否正确 + if !service.Captcha().VerifyString(verifyKey, captcha) { + err = gerror.New("验证码输入错误") + return + } + //获取IP地址 + ip := utils.GetClientIp(ctx) + //获取user-agent + userAgent := utils.GetUserAgent(ctx) + //根据账号密码获取用户信息 + userInfo, err := service.SysUser().GetAdminUserByUsernamePassword(ctx, userName, password) + if err != nil { + // 保存登录失败的日志信息 + service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{ + Status: 0, + Username: userName, + Ip: ip, + UserAgent: userAgent, + Msg: err.Error(), + Module: "系统后台", + }) + return + } + //生成token + key := gconv.String(userInfo.Id) + "-" + gmd5.MustEncryptString(userInfo.UserName) + gmd5.MustEncryptString(userInfo.UserPassword) + if g.Cfg().MustGet(ctx, "gfToken.multiLogin").Bool() { + key = gconv.String(userInfo.Id) + "-" + gmd5.MustEncryptString(userInfo.UserName) + "-" + gmd5.MustEncryptString(userInfo.UserPassword+ip+userAgent) + } + userInfo.UserPassword = "" + token, err = service.SysToken().GenerateToken(ctx, key, userInfo) + if err != nil { + return + } + //转换用户信息 + if err = gconv.Scan(userInfo, &loginUserOut); err != nil { + return + } + //修改用户信息 + err = service.SysUser().UpdateLoginInfo(ctx, userInfo.Id, ip) + if err != nil { + return + } + // 保存登录成功的日志信息 + service.SysLoginLog().Invoke(ctx, &model.LoginLogParams{ + Status: 1, + Username: userName, + Ip: ip, + UserAgent: userAgent, + Msg: "登录成功", + Module: "系统后台", + }) + + //查看是否在线用户信息是否都存在不存在则删除 + userOnlines, _ := service.SysUserOnline().GetAll(ctx) + if len(userOnlines) > 0 { + var onlineIds []uint + for _, online := range userOnlines { + if !common.Cache().Get(ctx, online.Key).Bool() { + onlineIds = append(onlineIds, online.Id) + } + } + if len(onlineIds) > 0 { + err = service.SysUserOnline().DelByIds(ctx, onlineIds) + } + } + + //保存在线用户信息 + ua := user_agent.New(userAgent) + os := ua.OS() + explorer, _ := ua.Browser() + service.SysUserOnline().Invoke(ctx, &entity.SysUserOnline{ + Uuid: guid.S(), + UserName: userName, + Key: key, + Token: token, + Ip: ip, + Os: os, + Explorer: explorer, + }) + return +} + +func (s *sLogin) LoginOut(ctx context.Context) (err error) { + authorization := ghttp.RequestFromCtx(ctx).Header.Get("Authorization") + if authorization == "" { + err = gerror.New("请先登录!") + return + } + //查看是否已经登录 + token := strings.Split(authorization, " ") + if len(token) < 2 || len(token) >= 2 && token[1] == "" { + err = gerror.New("TOKEN错误!") + return + } + userOnline, _ := service.SysUserOnline().GetInfoByToken(ctx, token[1]) + if userOnline == nil { + err = gerror.New("未登录,无法退出!") + return + } + //增加删除缓存信息 + common.Cache().Remove(ctx, userOnline.Key) + + err = service.SysUserOnline().DelByToken(ctx, token[1]) + return +} diff --git a/internal/logic/system/sys_api.go b/internal/logic/system/sys_api.go new file mode 100644 index 0000000..f79807b --- /dev/null +++ b/internal/logic/system/sys_api.go @@ -0,0 +1,419 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysApi struct { +} + +func sysApiNew() *sSysApi { + return &sSysApi{} +} + +func init() { + service.RegisterSysApi(sysApiNew()) +} + +// GetInfoByIds 根据接口APIID数组获取接口信息 +func (s *sSysApi) GetInfoByIds(ctx context.Context, ids []int) (data []*entity.SysApi, err error) { + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().IsDeleted: 0, + dao.SysApi.Columns().Status: 1, + }).WhereIn(dao.SysApi.Columns().Id, ids).Scan(&data) + return +} + +// GetApiByMenuId 根据ApiID获取接口信息 +func (s *sSysApi) GetApiByMenuId(ctx context.Context, apiId int) (data []*entity.SysApi, err error) { + var apiApi []*entity.SysMenuApi + err = dao.SysMenuApi.Ctx(ctx).Where(g.Map{ + dao.SysMenuApi.Columns().MenuId: apiId, + dao.SysMenuApi.Columns().IsDeleted: 0, + }).Scan(&apiApi) + //获取接口ID数组 + if apiApi != nil { + var ids []int + for _, api := range apiApi { + ids = append(ids, api.ApiId) + } + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().IsDeleted: 0, + dao.SysApi.Columns().Status: 1, + }).WhereIn(dao.SysApi.Columns().Id, ids).Scan(&data) + } + return +} + +// GetInfoById 根据ID获取API +func (s *sSysApi) GetInfoById(ctx context.Context, id int) (entity *entity.SysApi, err error) { + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: id, + }).Scan(&entity) + return +} + +// GetApiAll 获取所有接口 +func (s *sSysApi) GetApiAll(ctx context.Context) (data []*entity.SysApi, err error) { + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().IsDeleted: 0, + dao.SysApi.Columns().Status: 1, + dao.SysApi.Columns().Types: 2, + }).Scan(&data) + return +} + +// GetApiTree 获取Api数结构数据 +func (s *sSysApi) GetApiTree(ctx context.Context, name string, address string, status int, types int) (out []*model.SysApiTreeOut, err error) { + var e []*entity.SysApi + m := dao.SysApi.Ctx(ctx) + if name != "" { + m = m.WhereLike(dao.SysApi.Columns().Name, "%"+name+"%") + } + if address != "" { + m = m.WhereLike(dao.SysApi.Columns().Address, "%"+address+"%") + } + if status != -1 { + m = m.Where(dao.SysApi.Columns().Status, status) + } + if types != -1 { + m = m.Where(dao.SysApi.Columns().Types, types) + } + m = m.Where(dao.SysApi.Columns().IsDeleted, 0) + + err = m.OrderAsc(dao.SysApi.Columns().Sort).Scan(&e) + + if len(e) > 0 { + out, err = GetApiTree(e) + if err != nil { + return + } + } + return +} + +// Add 添加Api列表 +func (s *sSysApi) Add(ctx context.Context, input *model.AddApiInput) (err error) { + if input.Types == 2 { + if input.Address == "" || len(input.MenuIds) == 0 { + err = gerror.New("参数错误") + return + } + if input.ParentId == -1 { + err = gerror.New("接口不能为根节点") + return + } + } else { + if input.Address != "" || len(input.MenuIds) > 0 { + err = gerror.New("参数错误") + return + } + } + if input.ParentId != -1 { + var parentApiInfo *entity.SysApi + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: input.ParentId, + }).Scan(&parentApiInfo) + if parentApiInfo.IsDeleted != 0 { + return gerror.New("上级节点已删除,无法新增") + } + if parentApiInfo.Status != 1 { + return gerror.New("上级节点未启用,无法新增") + } + if parentApiInfo.Types != 1 { + return gerror.New("上级节点不是分类,无法新增") + } + } + err = dao.SysUser.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + var apiInfo *entity.SysApi + //根据名称查看是否存在 + apiInfo = checkApiName(ctx, input.Name, 0) + if apiInfo != nil { + return gerror.New("Api名字已存在,无法添加") + } + if input.Types == 2 { + //根据名称查看是否存在 + apiInfo = checkApiAddress(ctx, input.Address, 0) + if apiInfo != nil { + return gerror.New("Api地址,无法添加") + } + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + apiInfo = new(entity.SysApi) + if apiInfoErr := gconv.Scan(input, &apiInfo); apiInfoErr != nil { + return + } + apiInfo.IsDeleted = 0 + apiInfo.CreateBy = uint(loginUserId) + apiInfoId, err := dao.SysApi.Ctx(ctx).Data(apiInfo).InsertAndGetId() + if err != nil { + return err + } + //绑定菜单 + err = AddMenuApi(ctx, int(apiInfoId), input.MenuIds, loginUserId) + return + }) + return +} + +// Detail Api列表详情 +func (s *sSysApi) Detail(ctx context.Context, id int) (out *model.SysApiOut, err error) { + var e *entity.SysApi + _ = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: id, + }).Scan(&e) + if e != nil { + if err = gconv.Scan(e, &out); err != nil { + return nil, err + } + menuApiInfo, _ := service.SysMenuApi().GetInfoByApiId(ctx, out.Id) + var menuIds []int + for _, menuApi := range menuApiInfo { + menuIds = append(menuIds, menuApi.MenuId) + } + out.MenuIds = append(out.MenuIds, menuIds...) + } + return +} + +func AddMenuApi(ctx context.Context, id int, menuIds []int, loginUserId int) (err error) { + //添加菜单 + var sysMenuApis []*entity.SysMenuApi + for _, menuId := range menuIds { + var menuInfo *entity.SysMenu + err = dao.SysMenu.Ctx(ctx).Where(dao.SysMenu.Columns().Id, menuId).Scan(&menuInfo) + if menuInfo == nil { + err = gerror.New("菜单ID错误") + return + } + if menuInfo != nil && menuInfo.IsDeleted == 1 { + err = gerror.New(menuInfo.Name + "已删除,无法绑定") + return + } + if menuInfo != nil && menuInfo.Status == 0 { + err = gerror.New(menuInfo.Name + "已禁用,无法绑定") + return + } + + //解除旧绑定关系 + _, err = dao.SysMenuApi.Ctx(ctx).Data(g.Map{ + dao.SysMenuApi.Columns().IsDeleted: 1, + dao.SysMenuApi.Columns().DeletedBy: loginUserId, + }).Where(dao.SysMenuApi.Columns().ApiId, id).Update() + _, err = dao.SysMenuApi.Ctx(ctx).Where(dao.SysMenuApi.Columns().ApiId, id).Delete() + + var sysMenuApi = new(entity.SysMenuApi) + sysMenuApi.MenuId = menuId + sysMenuApi.ApiId = id + sysMenuApi.IsDeleted = 0 + sysMenuApi.CreatedBy = uint(loginUserId) + sysMenuApis = append(sysMenuApis, sysMenuApi) + } + if sysMenuApis != nil { + //添加 + _, addErr := dao.SysMenuApi.Ctx(ctx).Data(sysMenuApis).Insert() + if addErr != nil { + err = gerror.New("添加失败") + return + } + } + return +} + +// Edit 修改Api列表 +func (s *sSysApi) Edit(ctx context.Context, input *model.EditApiInput) (err error) { + if input.Types == 2 { + if input.Address == "" || len(input.MenuIds) == 0 { + err = gerror.New("参数错误") + return + } + if input.ParentId == -1 { + err = gerror.New("接口不能为根节点") + return + } + } else { + if input.Address != "" || len(input.MenuIds) > 0 { + err = gerror.New("参数错误") + return + } + } + if input.ParentId != -1 { + var parentApiInfo *entity.SysApi + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: input.ParentId, + }).Scan(&parentApiInfo) + if parentApiInfo.IsDeleted != 0 { + return gerror.New("上级节点已删除,无法新增") + } + if parentApiInfo.Status != 1 { + return gerror.New("上级节点已启用,无法新增") + } + if parentApiInfo.Types != 1 { + return gerror.New("上级节点不是分类,无法新增") + } + } + err = dao.SysUser.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + var apiInfo, apiInfo2 *entity.SysApi + //根据ID查看Api列表是否存在 + apiInfo = checkApiId(ctx, input.Id, apiInfo) + if apiInfo == nil { + return gerror.New("Api列表不存在") + } + apiInfo2 = checkApiName(ctx, input.Name, input.Id) + if apiInfo2 != nil { + return gerror.New("相同Api名称已存在,无法修改") + } + if input.Types == 2 { + apiInfo2 = checkApiAddress(ctx, input.Address, input.Id) + if apiInfo2 != nil { + return gerror.New("Api地址已存在,无法修改") + } + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if apiInfoErr := gconv.Scan(input, &apiInfo); apiInfoErr != nil { + return + } + apiInfo.UpdatedBy = uint(loginUserId) + _, err = dao.SysApi.Ctx(ctx).Data(apiInfo). + Where(dao.SysApi.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + //绑定菜单 + err = AddMenuApi(ctx, input.Id, input.MenuIds, loginUserId) + return + }) + + return +} + +// Del 根据ID删除Api列表信息 +func (s *sSysApi) Del(ctx context.Context, Id int) (err error) { + var apiColumn *entity.SysApi + _ = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: Id, + }).Scan(&apiColumn) + if apiColumn == nil { + return gerror.New("ID错误") + } + //判断是否为分类 + if apiColumn.Types == 1 { + //判断是否存在子节点 + num, _ := dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().ParentId: Id, + dao.SysApi.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return gerror.New("存在子节点,无法删除") + } + } + loginUserId := service.Context().GetUserId(ctx) + //获取当前时间 + time, err := gtime.StrToTimeFormat(gtime.Datetime(), "2006-01-02 15:04:05") + if err != nil { + return + } + //开启事务管理 + err = dao.SysApi.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + //更新Api列表信息 + _, err = dao.SysApi.Ctx(ctx). + Data(g.Map{ + dao.SysApi.Columns().DeletedBy: uint(loginUserId), + dao.SysApi.Columns().IsDeleted: 1, + dao.SysApi.Columns().DeletedAt: time, + }).Where(dao.SysApi.Columns().Id, Id). + Update() + //删除于菜单关系绑定 + _, err = dao.SysMenuApi.Ctx(ctx).Data(g.Map{ + dao.SysMenuApi.Columns().IsDeleted: 0, + dao.SysMenuApi.Columns().DeletedBy: loginUserId, + dao.SysMenuApi.Columns().DeletedAt: time, + }).Where(dao.SysMenuApi.Columns().ApiId, Id).Update() + return + }) + return +} + +// EditStatus 修改状态 +func (s *sSysApi) EditStatus(ctx context.Context, id int, status int) (err error) { + var apiInfo *entity.SysApi + _ = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: id, + }).Scan(&apiInfo) + if apiInfo == nil { + return gerror.New("ID错误") + } + if apiInfo != nil && apiInfo.IsDeleted == 1 { + return gerror.New("列表字段已删除,无法修改") + } + if apiInfo != nil && apiInfo.Status == status { + return gerror.New("API已禁用或启用,无须重复修改") + } + loginUserId := service.Context().GetUserId(ctx) + apiInfo.Status = status + apiInfo.UpdatedBy = uint(loginUserId) + + _, err = dao.SysApi.Ctx(ctx).Data(apiInfo).Where(g.Map{ + dao.SysApi.Columns().Id: id, + }).Update() + return +} + +// GetInfoByAddress 根据Address获取API +func (s *sSysApi) GetInfoByAddress(ctx context.Context, address string) (entity *entity.SysApi, err error) { + err = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Address: address, + dao.SysApi.Columns().IsDeleted: 0, + dao.SysApi.Columns().Status: 1, + }).Scan(&entity) + return +} + +// 检查指定ID的数据是否存在 +func checkApiId(ctx context.Context, Id int, apiColumn *entity.SysApi) *entity.SysApi { + _ = dao.SysApi.Ctx(ctx).Where(g.Map{ + dao.SysApi.Columns().Id: Id, + dao.SysApi.Columns().IsDeleted: 0, + }).Scan(&apiColumn) + return apiColumn +} + +// 检查相同Api名称的数据是否存在 +func checkApiName(ctx context.Context, name string, tag int) *entity.SysApi { + var apiInfo *entity.SysApi + m := dao.SysApi.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysApi.Columns().Id, tag) + } + _ = m.Where(g.Map{ + dao.SysApi.Columns().Name: name, + dao.SysApi.Columns().IsDeleted: 0, + }).Scan(&apiInfo) + return apiInfo +} + +// 检查相同Api地址的数据是否存在 +func checkApiAddress(ctx context.Context, address string, tag int) *entity.SysApi { + var apiInfo *entity.SysApi + m := dao.SysApi.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysApi.Columns().Id, tag) + } + _ = m.Where(g.Map{ + dao.SysApi.Columns().Address: address, + dao.SysApi.Columns().IsDeleted: 0, + }).Scan(&apiInfo) + return apiInfo +} diff --git a/internal/logic/system/sys_authorize.go b/internal/logic/system/sys_authorize.go new file mode 100644 index 0000000..e77d0cf --- /dev/null +++ b/internal/logic/system/sys_authorize.go @@ -0,0 +1,456 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strings" +) + +type sSysAuthorize struct { +} + +func init() { + service.RegisterSysAuthorize(sysAuthorizeNew()) +} + +func sysAuthorizeNew() *sSysAuthorize { + return &sSysAuthorize{} +} + +func (s *sSysAuthorize) AuthorizeQuery(ctx context.Context, itemsType string, menuIds []int) (out []*model.AuthorizeQueryTreeOut, err error) { + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if loginUserId == 0 { + err = gerror.New("未登录或TOKEN失效,请重新登录") + return + } + //查询用户角色信息 + userRoleInfo, err := service.SysUserRole().GetInfoByUserId(ctx, loginUserId) + if err != nil { + return + } + //判断是否为超级管理员 + if userRoleInfo == nil { + err = gerror.New("无权限,请联系管理员") + return + } + var isSuperAdmin = false + var roleIds []int + for _, userRole := range userRoleInfo { + if userRole.RoleId == 1 { + isSuperAdmin = true + } + roleIds = append(roleIds, userRole.RoleId) + } + if isSuperAdmin { + var userMenuTreeOut []*model.UserMenuTreeOut + if strings.EqualFold(itemsType, consts.Menu) { + userMenuTreeOut, _ = GetMenuInfo(ctx, nil) + } else { + userMenuTreeOut, _ = GetMenuInfo(ctx, menuIds) + } + if userMenuTreeOut == nil { + err = gerror.New("无可用菜单") + return + } + + var authorizeQueryTreeRes []*model.AuthorizeQueryTreeOut + if err = gconv.Scan(userMenuTreeOut, &authorizeQueryTreeRes); err != nil { + return + } + + if !strings.EqualFold(itemsType, consts.Menu) { + if len(menuIds) == 0 { + err = gerror.New("请选择菜单") + return + } + //根据项目类型 菜单ID封装菜单的按钮,列表字段,API接口 + authorizeItemsTypeTreeOut, userItemsTypeTreeErr := GetAuthorizeItemsTypeTreeOut(ctx, menuIds, itemsType, authorizeQueryTreeRes) + if userItemsTypeTreeErr != nil { + return nil, userItemsTypeTreeErr + } + + //获取所有的子节点 + /*childrenMenuTreeOut := GetAllAuthorizeQueryChildrenTree(authorizeItemsTypeTreeOut) + if childrenMenuTreeOut != nil { + //查找所有的上级ID + childrenMenuTreeOut = GetAllAuthorizeQueryParentTree(childrenMenuTreeOut, authorizeItemsTypeTreeOut) + }*/ + + //out = GetAuthorizeMenuTree(childrenMenuTreeOut) + out = authorizeItemsTypeTreeOut + return + } + out = GetAuthorizeMenuTree(authorizeQueryTreeRes) + + return + } else { + var userMenuTreeOut []*model.UserMenuTreeOut + if strings.EqualFold(itemsType, consts.Menu) { + //根据角色ID获取角色下配置的菜单信息 + authorizeItemsInfo, authorizeItemsErr := service.SysAuthorize().GetInfoByRoleIdsAndItemsType(ctx, roleIds, consts.Menu) + if authorizeItemsErr != nil { + return nil, authorizeItemsErr + } + if authorizeItemsInfo == nil { + err = gerror.New("菜单未配置,请联系管理员") + return + } + //获取菜单ID + var authorizeItemsIds []int + for _, authorizeItems := range authorizeItemsInfo { + authorizeItemsIds = append(authorizeItemsIds, authorizeItems.ItemsId) + } + //根据菜单ID获取菜单信息 + userMenuTreeOut, _ = GetMenuInfo(ctx, authorizeItemsIds) + } else { + userMenuTreeOut, _ = GetMenuInfo(ctx, menuIds) + } + if userMenuTreeOut == nil { + err = gerror.New("无可用菜单") + return + } + var authorizeQueryTreeOut []*model.AuthorizeQueryTreeOut + if err = gconv.Scan(userMenuTreeOut, &authorizeQueryTreeOut); err != nil { + return + } + + //根据项目类型 菜单ID封装菜单的按钮,列表字段,API接口 + if !strings.EqualFold(itemsType, consts.Menu) { + if len(menuIds) == 0 { + err = gerror.New("请选择菜单") + return + } + //根据项目类型 菜单ID封装菜单的按钮,列表字段,API接口 + authorizeItemsTypeTreeOut, userItemsTypeTreeErr := GetAuthorizeItemsTypeTreeOut(ctx, menuIds, itemsType, authorizeQueryTreeOut) + if userItemsTypeTreeErr != nil { + return nil, userItemsTypeTreeErr + } + + //获取所有的子节点 + /*childrenMenuTreeOut := GetAllAuthorizeQueryChildrenTree(authorizeItemsTypeTreeOut) + if childrenMenuTreeOut != nil { + //查找所有的上级ID + childrenMenuTreeOut = GetAllAuthorizeQueryParentTree(childrenMenuTreeOut, authorizeItemsTypeTreeOut) + }*/ + + //out = GetAuthorizeMenuTree(childrenMenuTreeOut) + out = authorizeItemsTypeTreeOut + return + } + out = GetAuthorizeMenuTree(authorizeQueryTreeOut) + return + } +} + +// GetInfoByRoleId 根据角色ID获取权限信息 +func (s *sSysAuthorize) GetInfoByRoleId(ctx context.Context, roleId int) (data []*entity.SysAuthorize, err error) { + err = dao.SysAuthorize.Ctx(ctx).Where(g.Map{ + dao.SysAuthorize.Columns().RoleId: roleId, + dao.SysAuthorize.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +// GetInfoByRoleIds 根据角色ID数组获取权限信息 +func (s *sSysAuthorize) GetInfoByRoleIds(ctx context.Context, roleIds []int) (data []*entity.SysAuthorize, err error) { + err = dao.SysAuthorize.Ctx(ctx).Where(g.Map{ + dao.SysAuthorize.Columns().IsDeleted: 0, + }).WhereIn(dao.SysAuthorize.Columns().RoleId, roleIds).Scan(&data) + return +} + +// GetInfoByRoleIdsAndItemsType 根据角色ID和项目类型获取权限信息 +func (s *sSysAuthorize) GetInfoByRoleIdsAndItemsType(ctx context.Context, roleIds []int, itemsType string) (data []*entity.SysAuthorize, err error) { + err = dao.SysAuthorize.Ctx(ctx).Where(g.Map{ + dao.SysAuthorize.Columns().IsDeleted: 0, + dao.SysAuthorize.Columns().ItemsType: itemsType, + }).WhereIn(dao.SysAuthorize.Columns().RoleId, roleIds).Scan(&data) + return +} + +func (s *sSysAuthorize) DelByRoleId(ctx context.Context, roleId int) (err error) { + loginUserId := service.Context().GetUserId(ctx) + _, err = dao.SysAuthorize.Ctx(ctx).Data(g.Map{ + dao.SysAuthorize.Columns().DeletedBy: uint(loginUserId), + dao.SysAuthorize.Columns().IsDeleted: 1, + }).Where(dao.SysAuthorize.Columns().RoleId, roleId).Update() + _, err = dao.SysAuthorize.Ctx(ctx).Where(dao.SysAuthorize.Columns().RoleId, roleId).Delete() + return +} + +func (s *sSysAuthorize) Add(ctx context.Context, authorize []*entity.SysAuthorize) (err error) { + _, err = dao.SysAuthorize.Ctx(ctx).Data(authorize).Insert() + return +} + +func (s *sSysAuthorize) AddAuthorize(ctx context.Context, roleId int, menuIds []string, buttonIds []string, columnIds []string, apiIds []string) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + //删除原有权限 + err = service.SysAuthorize().DelByRoleId(ctx, roleId) + var isTrue = true + //封装菜单权限 + var authorizeInfo []*entity.SysAuthorize + for _, id := range menuIds { + var authorize = new(entity.SysAuthorize) + split := strings.Split(id, "_") + if len(split) < 2 { + isTrue = false + break + } + authorize.ItemsId = gconv.Int(split[0]) + authorize.ItemsType = consts.Menu + authorize.RoleId = roleId + authorize.IsCheckAll = gconv.Int(split[1]) + authorize.IsDeleted = 0 + authorizeInfo = append(authorizeInfo, authorize) + } + if !isTrue { + err = gerror.New("菜单权限参数错误") + return + } + //封装按钮权限 + for _, id := range buttonIds { + var authorize = new(entity.SysAuthorize) + split := strings.Split(id, "_") + if len(split) < 2 { + isTrue = false + break + } + authorize.ItemsId = gconv.Int(split[0]) + authorize.ItemsType = consts.Button + authorize.RoleId = roleId + authorize.IsCheckAll = gconv.Int(split[1]) + authorize.IsDeleted = 0 + authorizeInfo = append(authorizeInfo, authorize) + } + if !isTrue { + err = gerror.New("按钮权限参数错误") + return + } + //封装列表权限 + for _, id := range columnIds { + var authorize = new(entity.SysAuthorize) + split := strings.Split(id, "_") + if len(split) < 2 { + isTrue = false + break + } + authorize.ItemsId = gconv.Int(split[0]) + authorize.ItemsType = consts.Column + authorize.RoleId = roleId + authorize.IsCheckAll = gconv.Int(split[1]) + authorize.IsDeleted = 0 + authorizeInfo = append(authorizeInfo, authorize) + } + if !isTrue { + err = gerror.New("列表权限参数错误") + return + } + //封装接口权限 + for _, id := range apiIds { + var authorize = new(entity.SysAuthorize) + split := strings.Split(id, "_") + if len(split) < 2 { + isTrue = false + break + } + authorize.ItemsId = gconv.Int(split[0]) + authorize.ItemsType = consts.Api + authorize.RoleId = roleId + authorize.IsCheckAll = gconv.Int(split[1]) + authorize.IsDeleted = 0 + authorizeInfo = append(authorizeInfo, authorize) + } + if !isTrue { + err = gerror.New("接口权限参数错误") + return + } + err = s.Add(ctx, authorizeInfo) + if err != nil { + err = gerror.New("添加权限失败") + return + } + }) + return +} +func (s *sSysAuthorize) IsAllowAuthorize(ctx context.Context, roleId int) (isAllow bool, err error) { + //判断角色ID是否为1 + if roleId == 1 { + err = gerror.New("无法更改超级管理员权限") + return + } + + isAllow = false + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + //查看当前登录用户所有的角色 + //查询用户角色信息 + userRoleInfo, err := service.SysUserRole().GetInfoByUserId(ctx, loginUserId) + if err != nil { + return + } + //判断是否为超级管理员 + if userRoleInfo == nil { + err = gerror.New("无权限,请联系管理员") + return + } + var isSuperAdmin = false + var roleIds []int + for _, userRole := range userRoleInfo { + if userRole.RoleId == 1 { + isSuperAdmin = true + } + roleIds = append(roleIds, userRole.RoleId) + } + //判断当前用户是否为超级管理员 + if isSuperAdmin { + //如果是超级管理员则可以对所有角色授权 + isAllow = true + } else { + //根据角色ID获取菜单配置 + authorizeInfo, authorizeErr := s.GetInfoByRoleId(ctx, roleId) + if authorizeErr != nil { + return + } + //如果需要授权的角色ID无任何权限,则当前用户可以对其授权 + if authorizeInfo == nil { + isAllow = true + } else { + //菜单Ids + var menuIds []int + //按钮Ids + var menuButtonIds []int + //列表Ids + var menuColumnIds []int + //API Ids + var menuApiIds []int + for _, authorize := range authorizeInfo { + if strings.EqualFold(authorize.ItemsType, consts.Menu) { + menuIds = append(menuIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Button) { + menuButtonIds = append(menuButtonIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Column) { + menuColumnIds = append(menuColumnIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Api) { + menuApiIds = append(menuApiIds, authorize.ItemsId) + } + } + //获取当前用户所有的权限 + nowUserAuthorizeInfo, nowUserAuthorizeErr := s.GetInfoByRoleIds(ctx, roleIds) + if nowUserAuthorizeErr != nil { + return + } + //菜单Ids + var nowUserMenuIds []int + //按钮Ids + var nowUserMenuButtonIds []int + //列表Ids + var nowUserMenuColumnIds []int + //API Ids + var nowUserMenuApiIds []int + for _, authorize := range nowUserAuthorizeInfo { + if strings.EqualFold(authorize.ItemsType, consts.Menu) { + nowUserMenuIds = append(nowUserMenuIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Button) { + nowUserMenuButtonIds = append(nowUserMenuButtonIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Column) { + nowUserMenuColumnIds = append(nowUserMenuColumnIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Api) { + nowUserMenuApiIds = append(nowUserMenuApiIds, authorize.ItemsId) + } + } + //判断当前登录用户是否大于授权角色的权限 + //获取当前登录用户的菜单信息 + nowUserMenuInfo, _ := service.SysMenu().GetInfoByMenuIds(ctx, nowUserMenuIds) + //获取授权角色的菜单信息 + menuInfo, _ := service.SysMenu().GetInfoByMenuIds(ctx, menuIds) + if len(menuInfo) == 0 { + isAllow = true + } else { + var menuInfoIsAllow = true + //判断当前登录用户所拥有的菜单是包含授权角色的菜单 + for _, menu := range menuInfo { + var nowMenuIsAllow = false + for _, nowUserMenu := range nowUserMenuInfo { + if menu.Id == nowUserMenu.Id { + nowMenuIsAllow = true + break + } + } + if !nowMenuIsAllow { + menuInfoIsAllow = false + break + } + } + //判断是否都包含 + if menuInfoIsAllow { + //判断按钮是否都包含 + //获取当前登录用户按钮单信息 + nowUserMenuButtonInfo, _ := service.SysMenuButton().GetInfoByMenuIds(ctx, nowUserMenuButtonIds) + //获取授权角色的按钮信息 + menuButtonInfo, _ := service.SysMenuButton().GetInfoByMenuIds(ctx, menuButtonIds) + var menuButtonInfoIsAllow = true + if len(menuButtonInfo) != 0 { + //判断当前登录用户所拥有的按钮是包含授权角色的按钮 + for _, menuButton := range menuButtonInfo { + var nowMenuButtonIsAllow = false + for _, nowUserMenuButton := range nowUserMenuButtonInfo { + if menuButton.Id == nowUserMenuButton.Id { + nowMenuButtonIsAllow = true + break + } + } + if !nowMenuButtonIsAllow { + menuButtonInfoIsAllow = false + break + } + } + if menuButtonInfoIsAllow { + //判断列表是否都包含 + //获取当前登录用户的列表信息 + nowUserMenuColumnInfo, _ := service.SysMenuColumn().GetInfoByMenuIds(ctx, nowUserMenuColumnIds) + //获取授权角色的列表信息 + menuColumnInfo, _ := service.SysMenuColumn().GetInfoByMenuIds(ctx, menuColumnIds) + var menuColumnInfoIsAllow = true + if len(menuColumnInfo) == 0 { + //判断当前登录用户所拥有的列表是包含授权角色的列表 + for _, menuColumn := range menuColumnInfo { + var nowMenuColumnIsAllow = false + for _, nowUserMenuColumn := range nowUserMenuColumnInfo { + if menuColumn.Id == nowUserMenuColumn.Id { + nowMenuColumnIsAllow = true + break + } + } + if !nowMenuColumnIsAllow { + menuColumnInfoIsAllow = false + break + } + } + + if menuColumnInfoIsAllow { + isAllow = true + } + } else { + isAllow = true + } + } + + } else { + isAllow = true + } + + } + } + } + } + return +} diff --git a/internal/logic/system/sys_authorize_utils.go b/internal/logic/system/sys_authorize_utils.go new file mode 100644 index 0000000..f3f4b91 --- /dev/null +++ b/internal/logic/system/sys_authorize_utils.go @@ -0,0 +1,651 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "reflect" + "strings" +) + +// GetAllAuthorizeQueryChildrenTree 获取所有的子节点 +func GetAllAuthorizeQueryChildrenTree(userMenuTreeRes []*model.AuthorizeQueryTreeOut) (childrenMenuTreeRes []*model.AuthorizeQueryTreeOut) { + for k := range userMenuTreeRes { + var isExistChildren = false + for j := range userMenuTreeRes { + if userMenuTreeRes[k].Id == uint(userMenuTreeRes[j].ParentId) { + isExistChildren = true + } + } + if !isExistChildren { + if len(userMenuTreeRes[k].Children) > 0 { + childrenMenuTreeRes = append(childrenMenuTreeRes, userMenuTreeRes[k]) + } + } + } + return +} + +// GetAllAuthorizeQueryParentTree 获取所有的父节点 +func GetAllAuthorizeQueryParentTree(childrenMenuTreeRes []*model.AuthorizeQueryTreeOut, userMenuTreeRes []*model.AuthorizeQueryTreeOut) (data []*model.AuthorizeQueryTreeOut) { + var parentMenuTreeRes []*model.AuthorizeQueryTreeOut + for k := range childrenMenuTreeRes { + for j := range userMenuTreeRes { + if uint(childrenMenuTreeRes[k].ParentId) == userMenuTreeRes[j].Id { + //判断父节点是否已存在 + var parentMenuIsExsit = false + for _, p := range parentMenuTreeRes { + if p.Id == userMenuTreeRes[j].Id { + parentMenuIsExsit = true + } + } + if !parentMenuIsExsit { + parentMenuTreeRes = append(parentMenuTreeRes, userMenuTreeRes[j]) + childrenMenuTreeRes = append(childrenMenuTreeRes, userMenuTreeRes[j]) + } + } + } + } + if parentMenuTreeRes != nil { + GetAllAuthorizeQueryParentTree(parentMenuTreeRes, userMenuTreeRes) + } + return childrenMenuTreeRes +} + +// GetRoleTree 获取角色树 +func GetRoleTree(roleInfo []*entity.SysRole) (dataTree []*model.RoleTreeOut, err error) { + var parentNodeRes []*model.RoleTreeOut + if roleInfo != nil { + //获取所有的根节点 + for _, v := range roleInfo { + var parentNode *model.RoleTreeOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeRes = append(parentNodeRes, parentNode) + } + } + } + treeData := RoleTree(parentNodeRes, roleInfo) + return treeData, nil +} + +// RoleTree 生成角色树结构 +func RoleTree(parentNodeRes []*model.RoleTreeOut, data []*entity.SysRole) (dataTree []*model.RoleTreeOut) { + //循环所有一级菜单 + for k, v := range parentNodeRes { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.RoleTreeOut + if j.ParentId == int(v.Id) { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeRes[k].Children = append(parentNodeRes[k].Children, node) + } + } + RoleTree(v.Children, data) + } + return parentNodeRes +} + +func GetApiTree(apiInfo []*entity.SysApi) (dataTree []*model.SysApiTreeOut, err error) { + var parentNodeRes []*model.SysApiTreeOut + if apiInfo != nil { + //获取所有的根节点 + for _, v := range apiInfo { + var parentNode *model.SysApiTreeOut + if v.ParentId == -1 && v.Types == 1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeRes = append(parentNodeRes, parentNode) + } + } + } + treeData := ApiTree(parentNodeRes, apiInfo) + if len(parentNodeRes) == 0 { + if err = gconv.Scan(apiInfo, &treeData); err != nil { + return + } + } + return treeData, nil +} + +// ApiTree 生成接口树结构 +func ApiTree(parentNodeRes []*model.SysApiTreeOut, data []*entity.SysApi) (dataTree []*model.SysApiTreeOut) { + //循环所有一级菜单 + for k, v := range parentNodeRes { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.SysApiTreeOut + if j.ParentId == int(v.Id) { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeRes[k].Children = append(parentNodeRes[k].Children, node) + } + } + ApiTree(v.Children, data) + } + return parentNodeRes +} + +// GetMenuInfo 根据菜单ID获取指定菜单信息或者获取所有菜单信息 +func GetMenuInfo(ctx context.Context, menuIds []int) (userMenuTreeRes []*model.UserMenuTreeOut, err error) { + var menuInfo []*entity.SysMenu + if menuIds != nil { + //根据菜单ID获取菜单信息 + menuInfo, _ = service.SysMenu().GetInfoByMenuIds(ctx, menuIds) + if err != nil { + return + } + } else { + //获取所有的菜单 + menuInfo, _ = service.SysMenu().GetAll(ctx) + if err != nil { + return + } + } + + //获取所有的菜单信息 + if menuInfo != nil { + var userMenuTreeInfo []*model.UserMenuTreeOut + if err = gconv.Scan(menuInfo, &userMenuTreeInfo); err != nil { + return nil, err + } + //封装菜单数据 + //userMenuTreeInfoRes := GetUserMenuTree(userMenuTreeInfo) + + return userMenuTreeInfo, nil + } else { + err = gerror.New("无菜单,请先配置菜单") + return + } +} + +// GetUserItemsTypeTreeOut 根据项目类型 菜单ID封装菜单的按钮,列表字段,API接口 +func GetUserItemsTypeTreeOut(ctx context.Context, menuIds []int, itemsType string, userMenuTreeInfo []*model.UserMenuTreeOut) (userMenuTreeRes []*model.UserMenuTreeOut, err error) { + if strings.EqualFold(itemsType, consts.Button) { + //根据菜单ID获取按钮列表 + menuButtonInfo, er := service.SysMenuButton().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + if menuButtonInfo != nil { + for _, menu := range userMenuTreeInfo { + menuButtonTreeData, _ := GetUserMenuButton(int(menu.Id), menuButtonInfo) + menu.Button = append(menu.Button, menuButtonTreeData...) + } + } + } else if strings.EqualFold(itemsType, consts.Column) { + //根据菜单ID获取列表字段 + menuColumnInfo, er := service.SysMenuColumn().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + if menuColumnInfo != nil { + for _, menu := range userMenuTreeInfo { + menuColumnTreeData, _ := GetUserMenuColumn(int(menu.Id), menuColumnInfo) + menu.Column = append(menu.Column, menuColumnTreeData...) + } + } + + } else if strings.EqualFold(itemsType, consts.Api) { + //根据菜单ID获取列表字段 + menuApiInfo, er := service.SysMenuApi().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + + //获取相关接口ID + var apiIds []int + for _, menuApi := range menuApiInfo { + apiIds = append(apiIds, menuApi.ApiId) + } + + //获取相关接口信息 + apiInfo, _ := service.SysApi().GetInfoByIds(ctx, apiIds) + + if apiInfo != nil { + for _, menu := range userMenuTreeInfo { + var apiId = 0 + var menuApiId = 0 + var apiInfoOut []*model.UserApiOut + if err = gconv.Scan(apiInfo, &apiInfoOut); err != nil { + return + } + for _, menuApi := range menuApiInfo { + if menuApi.MenuId == int(menu.Id) { + apiId = menuApi.ApiId + menuApiId = int(menuApi.Id) + break + } + } + if apiId != 0 { + for _, api := range apiInfoOut { + if apiId == api.Id { + api.MenuApiId = menuApiId + menu.Api = append(menu.Api, api) + break + } + } + } + } + } + + } else { + err = gerror.New("itemsType参数错误") + return + } + return userMenuTreeInfo, nil +} + +// GetAuthorizeMenuTree 获取用户菜单树结构 +func GetAuthorizeMenuTree(userMenuTreeOut []*model.AuthorizeQueryTreeOut) (dataTree []*model.AuthorizeQueryTreeOut) { + var userMenuParentNodeTreeOut []*model.AuthorizeQueryTreeOut + if userMenuTreeOut != nil { + //获取所有的根节点 + for _, v := range userMenuTreeOut { + if v.ParentId == -1 { + userMenuParentNodeTreeOut = append(userMenuParentNodeTreeOut, v) + } + } + } + treeData := AuthorizeMenuTree(userMenuParentNodeTreeOut, userMenuTreeOut) + return treeData +} + +// AuthorizeMenuTree 重组菜单子节点 +func AuthorizeMenuTree(userMenuParentNodeTreeOut []*model.AuthorizeQueryTreeOut, data []*model.AuthorizeQueryTreeOut) (dataTree []*model.AuthorizeQueryTreeOut) { + //循环所有一级菜单 + for k, v := range userMenuParentNodeTreeOut { + var childrenNodeTreeOut []*model.AuthorizeQueryTreeOut + //查询所有该菜单下的所有子菜单 + for _, j := range data { + if j.ParentId == int(v.Id) { + //判断有无子节点 + childrenData := CheckChildrenAuthorizeMenuTree(j, data) + if len(childrenData) > 0 { + j.Children = append(j.Children, childrenData...) + } + var childrenMap g.Map + if err := gconv.Scan(j, &childrenMap); err != nil { + return + } + childrenNodeTreeOut = append(childrenNodeTreeOut, j) + userMenuParentNodeTreeOut[k].Children = append(userMenuParentNodeTreeOut[k].Children, childrenMap) + } + } + } + return userMenuParentNodeTreeOut +} + +func CheckChildrenAuthorizeMenuTree(children *model.AuthorizeQueryTreeOut, data []*model.AuthorizeQueryTreeOut) (childrenData []g.Map) { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + if j.ParentId == int(children.Id) { + j.Children = append(j.Children, CheckChildrenAuthorizeMenuTree(j, data)...) + //判断有无子节点 + var childrenMap g.Map + if err := gconv.Scan(j, &childrenMap); err != nil { + return + } + childrenData = append(childrenData, childrenMap) + + } + } + return +} + +// GetAuthorizeItemsTypeTreeOut 根据项目类型 菜单ID封装菜单的按钮,列表字段,API接口 +func GetAuthorizeItemsTypeTreeOut(ctx context.Context, menuIds []int, itemsType string, authorizeMenuTreeInfo []*model.AuthorizeQueryTreeOut) (authorizeMenuTreeOut []*model.AuthorizeQueryTreeOut, err error) { + if strings.EqualFold(itemsType, consts.Button) { + //根据菜单ID获取按钮列表 + menuButtonInfo, er := service.SysMenuButton().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + if menuButtonInfo != nil { + for _, menu := range authorizeMenuTreeInfo { + menuButtonTreeData, _ := GetUserMenuButton(int(menu.Id), menuButtonInfo) + var childrenMaps []g.Map + if err = gconv.Scan(menuButtonTreeData, &childrenMaps); err != nil { + return + } + menu.Children = append(menu.Children, childrenMaps...) + } + } + } else if strings.EqualFold(itemsType, consts.Column) { + //根据菜单ID获取列表字段 + menuColumnInfo, er := service.SysMenuColumn().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + if menuColumnInfo != nil { + for _, menu := range authorizeMenuTreeInfo { + menuColumnTreeData, _ := GetUserMenuColumn(int(menu.Id), menuColumnInfo) + var childrenMaps []g.Map + if err = gconv.Scan(menuColumnTreeData, &childrenMaps); err != nil { + return + } + menu.Children = append(menu.Children, childrenMaps...) + } + } + + } else if strings.EqualFold(itemsType, consts.Api) { + //根据菜单ID获取列表字段 + menuApiInfo, er := service.SysMenuApi().GetInfoByMenuIds(ctx, menuIds) + if er != nil { + return + } + + //获取相关接口ID + var apiIds []int + for _, menuApi := range menuApiInfo { + apiIds = append(apiIds, menuApi.ApiId) + } + + //获取相关接口信息 + apiInfo, _ := service.SysApi().GetInfoByIds(ctx, apiIds) + + if apiInfo != nil { + for _, menu := range authorizeMenuTreeInfo { + var apiInfoOut []*model.AuthorizeQueryApiOut + if err = gconv.Scan(apiInfo, &apiInfoOut); err != nil { + return + } + for _, menuApi := range menuApiInfo { + if menuApi.MenuId == int(menu.Id) { + for _, api := range apiInfoOut { + if menuApi.ApiId == api.Id { + //菜单与接口绑定ID + api.Id = int(menuApi.Id) + //接口ID + api.ApiId = api.Id + api.Title = api.Name + var childrenMap g.Map + if err = gconv.Scan(api, &childrenMap); err != nil { + return + } + menu.Children = append(menu.Children, childrenMap) + } + } + } + } + } + } + + } else { + err = gerror.New("itemsType参数错误") + return + } + return authorizeMenuTreeInfo, nil +} + +// GetUserMenuTree 获取用户菜单树结构 +func GetUserMenuTree(userMenuTreeRes []*model.UserMenuTreeOut) (dataTree []*model.UserMenuTreeOut) { + var userMenuParentNodeTreeRes []*model.UserMenuTreeOut + if userMenuTreeRes != nil { + //获取所有的根节点 + for _, v := range userMenuTreeRes { + if v.ParentId == -1 { + userMenuParentNodeTreeRes = append(userMenuParentNodeTreeRes, v) + } + } + } + treeData := UserMenuTree(userMenuParentNodeTreeRes, userMenuTreeRes) + return treeData +} + +// UserMenuTree 重组菜单子节点 +func UserMenuTree(userMenuParentNodeTreeRes []*model.UserMenuTreeOut, data []*model.UserMenuTreeOut) (dataTree []*model.UserMenuTreeOut) { + //循环所有一级菜单 + for k, v := range userMenuParentNodeTreeRes { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + if j.ParentId == int(v.Id) { + userMenuParentNodeTreeRes[k].Children = append(userMenuParentNodeTreeRes[k].Children, j) + } + } + UserMenuTree(v.Children, data) + } + return userMenuParentNodeTreeRes +} + +// GetUserMenuButton 获取用户可操作按钮 +func GetUserMenuButton(menuId int, menuButtonInfo []*entity.SysMenuButton) (dataTree []*model.UserMenuButtonOut, err error) { + var menuButton []*entity.SysMenuButton + for _, button := range menuButtonInfo { + if menuId == button.MenuId { + menuButton = append(menuButton, button) + } + } + //获取所有按钮根节点 + var parentMenuButtonNodeRes []*model.UserMenuButtonOut + if menuButton != nil { + //获取所有的根节点 + for _, v := range menuButton { + var parentMenuButtonNode *model.UserMenuButtonOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentMenuButtonNode); err != nil { + return + } + parentMenuButtonNode.Title = v.Name + parentMenuButtonNodeRes = append(parentMenuButtonNodeRes, parentMenuButtonNode) + } + } + } + //获取按钮树状结构 + menuButtonTreeData := UserMenuButtonTree(parentMenuButtonNodeRes, menuButton) + return menuButtonTreeData, nil +} + +// UserMenuButtonTree 生成树结构 +func UserMenuButtonTree(parentMenuButtonNodeRes []*model.UserMenuButtonOut, data []*entity.SysMenuButton) (dataTree []*model.UserMenuButtonOut) { + //循环所有一级菜单 + for k, v := range parentMenuButtonNodeRes { + //查询所有该按钮下的所有子按钮 + for _, j := range data { + var node *model.UserMenuButtonOut + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + node.Title = node.Name + parentMenuButtonNodeRes[k].Children = append(parentMenuButtonNodeRes[k].Children, node) + } + } + UserMenuButtonTree(v.Children, data) + } + return parentMenuButtonNodeRes +} + +// GetUserMenuColumn 获取用户可查看列表 +func GetUserMenuColumn(menuId int, menuColumnInfo []*entity.SysMenuColumn) (dataTree []*model.UserMenuColumnOut, err error) { + var menuColumn []*entity.SysMenuColumn + for _, column := range menuColumnInfo { + if menuId == column.MenuId { + menuColumn = append(menuColumn, column) + } + } + //获取所有按钮根节点 + var parentMenuColumnNodeRes []*model.UserMenuColumnOut + if menuColumn != nil { + //获取所有的根节点 + for _, v := range menuColumn { + var parentColumnButtonNode *model.UserMenuColumnOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentColumnButtonNode); err != nil { + return + } + parentColumnButtonNode.Title = parentColumnButtonNode.Name + parentMenuColumnNodeRes = append(parentMenuColumnNodeRes, parentColumnButtonNode) + } + } + } + //获取列表树状结构 + menuColumnTreeData := UserMenuColumnTree(parentMenuColumnNodeRes, menuColumn) + return menuColumnTreeData, nil +} + +// UserMenuColumnTree 生成树结构 +func UserMenuColumnTree(parentMenuColumnNodeRes []*model.UserMenuColumnOut, data []*entity.SysMenuColumn) (dataTree []*model.UserMenuColumnOut) { + //循环所有一级菜单 + for k, v := range parentMenuColumnNodeRes { + //查询所有该按钮下的所有子按钮 + for _, j := range data { + var node *model.UserMenuColumnOut + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + node.Title = node.Name + parentMenuColumnNodeRes[k].Children = append(parentMenuColumnNodeRes[k].Children, node) + } + } + UserMenuColumnTree(v.Children, data) + } + return parentMenuColumnNodeRes +} + +// GetDataWhere 获取数据权限条件查询 +func GetDataWhere(ctx context.Context, loginUserId int, entity interface{}) (where g.Map, err error) { + //获取当前登录用户信息 + userInfo, err := service.SysUser().GetUserById(ctx, uint(loginUserId)) + if err != nil { + err = gerror.New("登录用户信息错误") + return + } + if userInfo == nil { + err = gerror.New("登录用户不存在无法访问") + return + } + if userInfo != nil && userInfo.Status == 0 { + err = gerror.New("登录用户已禁用无法访问") + return + } + if userInfo != nil && userInfo.Status == 2 { + err = gerror.New("登录用户未验证无法访问") + return + } + t := reflect.TypeOf(entity) + for i := 0; i < t.Elem().NumField(); i++ { + if t.Elem().Field(i).Name == "CreatedBy" { + //若存在用户id的字段,则生成判断数据权限的条件 + //1、获取当前用户所属角色 + userRoleInfo, userRoleErr := service.SysUserRole().GetInfoByUserId(ctx, loginUserId) + if userRoleErr != nil { + err = gerror.New("获取用户角色失败") + return + } + if userRoleInfo == nil { + err = gerror.New("用户无权限访问") + return + } + //判断用户是否为超级管理员 + var isSuperAdmin = false + var roleIds []int + for _, userRole := range userRoleInfo { + if userRole.RoleId == 1 { + isSuperAdmin = true + } + roleIds = append(roleIds, userRole.RoleId) + } + if isSuperAdmin { + //超级管理员可以访问所有的数据 + return + } + //不是超级管理员则获取所有角色信息 + roleInfo, roleInfoErr := service.SysRole().GetInfoByIds(ctx, roleIds) + if roleInfoErr != nil { + err = gerror.New("获取用户角色失败") + return + } + //2获取角色对应数据权限 + deptIdArr := gset.New() + for _, role := range roleInfo { + switch role.DataScope { + case 1: //全部数据权限 + return + case 2: //自定数据权限 + //获取角色所有的部门信息 + roleDeptInfo, _ := service.SysRoleDept().GetInfoByRoleId(ctx, int(role.Id)) + if roleDeptInfo == nil { + err = gerror.New(role.Name + "自定义数据范围,请先配置部门!") + return + } + var deptIds []int64 + for _, roleDept := range roleDeptInfo { + deptIds = append(deptIds, roleDept.DeptId) + } + deptIdArr.Add(gconv.Interfaces(deptIds)...) + case 3: //本部门数据权限 + deptIdArr.Add(gconv.Int64(userInfo.DeptId)) + case 4: //本部门及以下数据权限 + deptIdArr.Add(gconv.Int64(userInfo.DeptId)) + //获取所有的部门信息 + deptInfo, _ := service.SysDept().GetAll(ctx) + if deptInfo != nil { + //获取当前部门所有的下级部门信息 + childrenDeptInfo := GetNextDeptInfoByNowDeptId(int64(userInfo.DeptId), deptInfo) + if childrenDeptInfo != nil { + allChildrenDeptInfo := GetAllNextDeptInfoByChildrenDept(childrenDeptInfo, deptInfo, childrenDeptInfo) + if allChildrenDeptInfo != nil { + for _, allChildrenDept := range allChildrenDeptInfo { + deptIdArr.Add(gconv.Int64(allChildrenDept.DeptId)) + } + } + } + } + case 5: //仅限于自己的数据 + where = g.Map{"created_by": userInfo.Id} + return + } + } + if deptIdArr.Size() > 0 { + where = g.Map{"dept_id": deptIdArr.Slice()} + } + } + } + return +} + +// GetNextDeptInfoByNowDeptId 获取当前部门ID下一层级的部门信息 +func GetNextDeptInfoByNowDeptId(id int64, deptInfo []*entity.SysDept) (data []*entity.SysDept) { + //循环所有的部门信息 + var childrenDept []*entity.SysDept + for _, dept := range deptInfo { + if dept.ParentId == id { + //获取子部门信息 + childrenDept = append(childrenDept, dept) + } + } + return childrenDept +} + +// GetAllNextDeptInfoByChildrenDept 根据所有的子部门获取所有下级部门信息 +func GetAllNextDeptInfoByChildrenDept(childrenDept []*entity.SysDept, deptInfo []*entity.SysDept, resultChildrenAll []*entity.SysDept) (data []*entity.SysDept) { + var newChildrenDept []*entity.SysDept + //循环所有的子部门信息 + for _, v := range childrenDept { + //查询所有该按钮下的所有子按钮 + for _, j := range deptInfo { + if j.ParentId == v.DeptId { + newChildrenDept = append(newChildrenDept, j) + resultChildrenAll = append(resultChildrenAll, j) + } + } + } + if newChildrenDept != nil { + GetAllNextDeptInfoByChildrenDept(newChildrenDept, deptInfo, resultChildrenAll) + } + return resultChildrenAll +} diff --git a/internal/logic/system/sys_dept.go b/internal/logic/system/sys_dept.go new file mode 100644 index 0000000..7c1f97c --- /dev/null +++ b/internal/logic/system/sys_dept.go @@ -0,0 +1,323 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" + "strconv" + "strings" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysDept struct { +} + +func sysDeptNew() *sSysDept { + return &sSysDept{} +} + +func init() { + service.RegisterSysDept(sysDeptNew()) +} + +// GetTree 获取全部部门数据 +func (s *sSysDept) GetTree(ctx context.Context, deptName string, status int) (out []*model.DeptOut, err error) { + dept, err := s.GetData(ctx, deptName, status) + var parentNodeOut []*model.DeptOut + if dept != nil { + //获取所有的根节点 + for _, v := range dept { + var parentNode *model.DeptOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeOut = append(parentNodeOut, parentNode) + } + } + } + out = deptTree(parentNodeOut, dept) + return +} + +// Trees Tree 生成树结构 +func deptTree(parentNodeOut []*model.DeptOut, data []*model.DeptOut) (dataTree []*model.DeptOut) { + //循环所有一级菜单 + for k, v := range parentNodeOut { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.DeptOut + if j.ParentId == v.DeptId { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeOut[k].Children = append(parentNodeOut[k].Children, node) + } + } + deptTree(v.Children, data) + } + return parentNodeOut +} + +// GetData 执行获取数据操作 +func (s *sSysDept) GetData(ctx context.Context, deptName string, status int) (data []*model.DeptOut, err error) { + m := dao.SysDept.Ctx(ctx) + if status != -1 { + m = m.Where(dao.SysDept.Columns().Status, status) + } + //模糊查询部门名称 + if deptName != "" { + m = m.WhereLike(dao.SysDept.Columns().DeptName, "%"+deptName+"%") + } + err = m.Where(dao.SysDept.Columns().IsDeleted, 0). + OrderDesc(dao.SysDept.Columns().OrderNum). + Scan(&data) + if err != nil { + return + } + return +} + +// Add 添加 +func (s *sSysDept) Add(ctx context.Context, input *model.AddDeptInput) (err error) { + var dept *entity.SysDept + //根据名称查看部门是否存在 + dept = checkDeptName(ctx, input.DeptName, dept, 0) + if dept != nil { + return gerror.New("部门已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + dept = new(entity.SysDept) + if err := gconv.Scan(input, &dept); err != nil { + return err + } + dept.IsDeleted = 0 + dept.CreatedBy = uint(loginUserId) + //开启事务管理 + err = dao.SysDept.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + lastId, err1 := dao.SysDept.Ctx(ctx).Data(dept).InsertAndGetId() + if err1 != nil { + return err1 + } + err = setAncestors(ctx, input.ParentId, lastId) + if err != nil { + return err + } + return err + }) + return +} + +// Edit 修改部门 +func (s *sSysDept) Edit(ctx context.Context, input *model.EditDeptInput) (err error) { + var dept1, dept2 *entity.SysDept + //根据ID查看部门是否存在 + dept1 = checkDeptId(ctx, input.DeptId, dept1) + dept := dept1.ParentId + deptAnces := dept1.Ancestors + if dept1 == nil { + return gerror.New("部门不存在") + } + dept2 = checkDeptName(ctx, input.DeptName, dept2, input.DeptId) + if dept2 != nil { + return gerror.New("相同部门已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &dept1); err != nil { + return err + } + dept1.UpdatedBy = loginUserId + //开启事务管理 + err = dao.SysDept.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + _, err = dao.SysDept.Ctx(ctx).Data(dept1). + Where(dao.SysDept.Columns().DeptId, input.DeptId).Update() + if err != nil { + return gerror.New("修改失败") + } + //修改祖籍字段 + if dept != input.ParentId { + err := setAncestors(ctx, input.ParentId, input.DeptId) + if err != nil { + return gerror.New("祖籍修改失败") + } + lId := strconv.FormatInt(input.DeptId, 10) + value, _ := dao.SysDept.Ctx(ctx). + Fields(dao.SysDept.Columns().Ancestors). + WhereLike(dao.SysDept.Columns().Ancestors, "%"+lId+"%").Array() + if input.ParentId == -1 { + for _, v := range value { + newAncestors := strings.Replace(v.String(), deptAnces, lId, -1) + //修改相关祖籍字段 + _, err := dao.SysDept.Ctx(ctx). + Data(dao.SysDept.Columns().Ancestors, newAncestors). + Where(dao.SysDept.Columns().Ancestors, v.String()).Update() + if err != nil { + return gerror.New("关联祖籍修改失败") + } + } + } else { + //查询现有的进行拼接 + ancestors, _ := dao.SysDept.Ctx(ctx). + Fields(dao.SysDept.Columns().Ancestors). + Where(dao.SysDept.Columns().DeptId, input.DeptId).Value() + for _, v := range value { + newAncestors := strings.Replace(ancestors.String(), lId, "", -1) + newAncestor := newAncestors + v.String() + //修改相关祖籍字段 + _, err := dao.SysDept.Ctx(ctx). + Data(dao.SysDept.Columns().Ancestors, newAncestor). + Where(dao.SysDept.Columns().Ancestors, v.String()). + WhereNot(dao.SysDept.Columns().DeptId, input.DeptId). + Update() + if err != nil { + return gerror.New("关联祖籍修改失败") + } + } + } + } + return nil + }) + return +} + +// Detail 部门详情 +func (s *sSysDept) Detail(ctx context.Context, deptId int64) (entity *entity.SysDept, err error) { + _ = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().DeptId: deptId, + }).Scan(&entity) + return +} + +// Del 根据ID删除部门信息 +func (s *sSysDept) Del(ctx context.Context, deptId int64) (err error) { + var dept *entity.SysDept + _ = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().DeptId: deptId, + }).Scan(&dept) + if dept == nil { + return gerror.New("ID错误") + } + //查询是否有子节点 + num, err := dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().ParentId: deptId, + dao.SysDept.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //更新部门信息 + _, err = dao.SysDept.Ctx(ctx). + Data(g.Map{ + dao.SysDept.Columns().DeletedBy: uint(loginUserId), + dao.SysDept.Columns().IsDeleted: 1, + }). + Where(dao.SysDept.Columns().DeptId, deptId). + Update() + //删除部门信息 + _, err = dao.SysDept.Ctx(ctx). + Where(dao.SysDept.Columns().DeptId, deptId). + Delete() + return +} + +// 修改祖籍字段 +func setAncestors(ctx context.Context, ParentId int64, lastId int64) (err error) { + lId := strconv.FormatInt(lastId, 10) + if ParentId == -1 { //根级别,修改祖籍为自己 + _, err := dao.SysDept.Ctx(ctx). + Data(dao.SysDept.Columns().Ancestors, lId). + Where(dao.SysDept.Columns().DeptId, lastId). + Update() + if err != nil { + return gerror.New("祖籍修改失败") + } + } else { + var oldDept *entity.SysDept + _ = dao.SysDept.Ctx(ctx). + Where(dao.SysDept.Columns().DeptId, ParentId). + Scan(&oldDept) + _, err := dao.SysDept.Ctx(ctx). + Data(dao.SysDept.Columns().Ancestors, oldDept.Ancestors+","+lId). + Where(dao.SysDept.Columns().DeptId, lastId). + Update() + if err != nil { + return gerror.New("祖籍修改失败") + } + } + return +} + +// 检查相同部门名称的数据是否存在 +func checkDeptName(ctx context.Context, deptName string, dept *entity.SysDept, tag int64) *entity.SysDept { + m := dao.SysDept.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysDept.Columns().DeptId, tag) + } + _ = m.Where(g.Map{ + dao.SysDept.Columns().DeptName: deptName, + dao.SysDept.Columns().IsDeleted: 0, + }).Scan(&dept) + return dept +} + +// 检查指定ID的数据是否存在 +func checkDeptId(ctx context.Context, DeptId int64, dept *entity.SysDept) *entity.SysDept { + _ = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().DeptId: DeptId, + dao.SysDept.Columns().IsDeleted: 0, + }).Scan(&dept) + return dept +} + +// GetAll 获取全部部门数据 +func (s *sSysDept) GetAll(ctx context.Context) (data []*entity.SysDept, err error) { + _ = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().Status: 1, + dao.SysDept.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +func (s *sSysDept) GetFromCache(ctx context.Context) (list []*entity.SysDept, err error) { + err = g.Try(ctx, func(ctx context.Context) { + cache := common.Cache() + //从缓存获取 + iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysDept, func(ctx context.Context) (value interface{}, err error) { + err = dao.SysDept.Ctx(ctx).Scan(&list) + liberr.ErrIsNil(ctx, err, "获取部门列表失败") + value = list + return + }, 0, consts.CacheSysAuthTag) + if iList != nil { + err = gconv.Struct(iList, &list) + liberr.ErrIsNil(ctx, err) + } + }) + return +} +func (s *sSysDept) FindSonByParentId(deptList []*entity.SysDept, deptId int64) []*entity.SysDept { + children := make([]*entity.SysDept, 0, len(deptList)) + for _, v := range deptList { + if v.ParentId == deptId { + children = append(children, v) + fChildren := s.FindSonByParentId(deptList, v.DeptId) + children = append(children, fChildren...) + } + } + return children +} diff --git a/internal/logic/system/sys_job.go b/internal/logic/system/sys_job.go new file mode 100644 index 0000000..846277b --- /dev/null +++ b/internal/logic/system/sys_job.go @@ -0,0 +1,284 @@ +package system + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" + "strings" + + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcron" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysJob struct { +} + +func sysJobNew() *sSysJob { + return &sSysJob{} +} + +func init() { + service.RegisterSysJob(sysJobNew()) +} + +// JobList 获取任务列表 +func (s *sSysJob) JobList(ctx context.Context, input *model.GetJobListInput) (total int, out []*model.SysJobOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysJob.Ctx(ctx) + if input != nil { + if input.Status != "" { + m = m.Where("status", gconv.Int(input.Status)) + } + if input.JobGroup != "" { + m = m.Where("job_group", input.JobGroup) + } + if input.JobName != "" { + m = m.Where("job_name like ?", "%"+input.JobName+"%") + } + } + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.PageSize + } + err = m.Page(input.PageNum, input.PageSize).Order("job_id asc").Scan(&out) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// GetJobs 获取已开启执行的任务 +func (s *sSysJob) GetJobs(ctx context.Context) (jobs []*model.SysJobOut, err error) { + err = dao.SysJob.Ctx(ctx).Where(dao.SysJob.Columns().Status, 0).Scan(&jobs) + return +} + +func (s *sSysJob) AddJob(ctx context.Context, input *model.SysJobAddInput) (err error) { + _, err = dao.SysJob.Ctx(ctx).Insert(input) + return +} + +func (s *sSysJob) GetJobInfoById(ctx context.Context, id int) (job *model.SysJobOut, err error) { + if id == 0 { + err = gerror.New("参数错误") + return + } + err = dao.SysJob.Ctx(ctx).Where("job_id", id).Scan(&job) + if err != nil { + g.Log().Error(ctx, err) + } + if job == nil || err != nil { + err = gerror.New("获取任务信息失败") + } + return +} + +func (s *sSysJob) EditJob(ctx context.Context, input *model.SysJobEditInput) error { + _, err := dao.SysJob.Ctx(ctx).FieldsEx(dao.SysJob.Columns().JobId, dao.SysJob.Columns().CreateBy).Where(dao.SysJob.Columns().JobId, input.JobId). + Update(input) + + // 同步定时任务到数据源和数据模型 + if input.JobGroup == "dataSourceJob" { + if input.InvokeTarget == "dataSource" { + err = service.DataSource().UpdateInterval(ctx, gconv.Uint64(input.JobParams), input.CronExpression) + } else if input.InvokeTarget == "dataTemplate" { + err = service.DataTemplate().UpdateInterval(ctx, gconv.Uint64(input.JobParams), input.CronExpression) + } + } + return err +} + +// JobStart 启动任务 +func (s *sSysJob) JobStart(ctx context.Context, job *model.SysJobOut) error { + //获取task目录下是否绑定对应的方法 + f := jobTask.TimeTaskList.GetByName(job.InvokeTarget) + if f == nil { + return gerror.New("没有绑定对应的方法") + } + //传参 + paramArr := strings.Split(job.JobParams, "|") + jobTask.TimeTaskList.EditParams(f.FuncName, paramArr) + + jname := fmt.Sprintf("%s-job-%d", job.InvokeTarget, job.JobId) + + rs := gcron.Search(jname) + if rs == nil { + newCtx := ctx + if job.JobGroup == "dataSourceJob" { + newCtx = s.WithValue(ctx, paramArr[0]) + } + if job.MisfirePolicy == 1 { + t, err := gcron.AddSingleton(newCtx, job.CronExpression, f.Run, jname) + if err != nil { + return err + } + if t == nil { + return gerror.New("启动任务失败") + } + } else { + t, err := gcron.AddOnce(newCtx, job.CronExpression, f.Run, jname) + if err != nil { + return err + } + if t == nil { + return gerror.New("启动任务失败") + } + } + } + gcron.Start(jname) + if job.MisfirePolicy == 1 { + job.Status = 0 + _, err := dao.SysJob.Ctx(ctx).Where(dao.SysJob.Columns().JobId, job.JobId).Unscoped().Update(g.Map{ + dao.SysJob.Columns().Status: job.Status, + }) + return err + } + return nil +} + +// JobStartMult 批量启动任务 +func (s *sSysJob) JobStartMult(ctx context.Context, jobs []*model.SysJobOut) error { + + var jobIds = g.Slice{} + for _, job := range jobs { + //获取task目录下是否绑定对应的方法 + f := jobTask.TimeTaskList.GetByName(job.InvokeTarget) + if f == nil { + return gerror.New("没有绑定对应的方法") + } + //传参 + paramArr := strings.Split(job.JobParams, "|") + jobTask.TimeTaskList.EditParams(f.FuncName, paramArr) + + jname := fmt.Sprintf("%s-job-%d", job.InvokeTarget, job.JobId) + + rs := gcron.Search(jname) + if rs == nil { + newCtx := ctx + if job.JobGroup == "dataSourceJob" { + newCtx = s.WithValue(ctx, paramArr[0]) + } + if job.MisfirePolicy == 1 { + t, err := gcron.AddSingleton(newCtx, job.CronExpression, f.Run, jname) + if err != nil { + return err + } + if t == nil { + return gerror.New("启动任务失败") + } + } else { + t, err := gcron.AddOnce(newCtx, job.CronExpression, f.Run, jname) + if err != nil { + return err + } + if t == nil { + return gerror.New("启动任务失败") + } + } + } + gcron.Start(jname) + if job.MisfirePolicy == 1 { + jobIds = append(jobIds, job.JobId) + } + } + + _, err := dao.SysJob.Ctx(ctx).WhereIn(dao.SysJob.Columns().JobId, jobIds).Unscoped().Update(g.Map{ + dao.SysJob.Columns().Status: 0, + }) + return err +} + +// JobStop 停止任务 +func (s *sSysJob) JobStop(ctx context.Context, job *model.SysJobOut) error { + //获取task目录下是否绑定对应的方法 + f := jobTask.TimeTaskList.GetByName(job.InvokeTarget) + if f == nil { + return gerror.New("没有绑定对应的方法") + } + + jname := fmt.Sprintf("%s-job-%d", job.InvokeTarget, job.JobId) + + rs := gcron.Search(jname) + if rs != nil { + gcron.Remove(jname) + } + job.Status = 1 + _, err := dao.SysJob.Ctx(ctx).Where(dao.SysJob.Columns().JobId, job.JobId).Unscoped().Update(g.Map{ + dao.SysJob.Columns().Status: job.Status, + }) + return err +} + +// JobRun 执行任务 +func (s *sSysJob) JobRun(ctx context.Context, job *model.SysJobOut) error { + //可以task目录下是否绑定对应的方法 + f := jobTask.TimeTaskList.GetByName(job.InvokeTarget) + if f == nil { + return gerror.New("当前task目录下没有绑定这个方法") + } + //传参 + paramArr := strings.Split(job.JobParams, "|") + jobTask.TimeTaskList.EditParams(f.FuncName, paramArr) + newCtx := ctx + if job.JobGroup == "dataSourceJob" { + newCtx = s.WithValue(ctx, paramArr[0]) + } + task, err := gcron.AddOnce(newCtx, "@every 1s", f.Run) + if err != nil || task == nil { + return gerror.New("启动执行失败") + } + return nil +} + +// DeleteJobByIds 删除任务 +func (s *sSysJob) DeleteJobByIds(ctx context.Context, ids []int) (err error) { + if len(ids) == 0 { + err = gerror.New("参数错误") + return + } + gst := gset.NewFrom(ids) + var jobs []*model.SysJobOut + jobs, err = s.GetJobs(ctx) + if err != nil { + return + } + for _, job := range jobs { + if gst.Contains(int(job.JobId)) { + err = gerror.New("运行中的任务不能删除") + return + } + } + _, err = dao.SysJob.Ctx(ctx).Delete(dao.SysJob.Columns().JobId+" in (?)", ids) + if err != nil { + g.Log().Error(ctx, err) + err = gerror.New("删除失败") + } + return +} + +// 数据源、数据模型使用 +type contextKey string + +func (s *sSysJob) WithValue(ctx context.Context, value string) context.Context { + return context.WithValue(ctx, contextKey("id"), value) +} + +func (s *sSysJob) Value(ctx context.Context) uint64 { + value := ctx.Value(contextKey("id")) + return gconv.Uint64(value) +} diff --git a/internal/logic/system/sys_login_log.go b/internal/logic/system/sys_login_log.go new file mode 100644 index 0000000..f9e6515 --- /dev/null +++ b/internal/logic/system/sys_login_log.go @@ -0,0 +1,140 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/do" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/utils" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/grpool" + "github.com/gogf/gf/v2/os/gtime" + "github.com/mssola/user_agent" +) + +type sSysLoginLog struct { +} + +func init() { + service.RegisterSysLoginLog(sysLoginLogNew()) +} + +func sysLoginLogNew() *sSysLoginLog { + return &sSysLoginLog{} +} + +func (s *sSysLoginLog) Invoke(ctx context.Context, data *model.LoginLogParams) { + pool := grpool.New(100) + if err := pool.Add(ctx, func(ctx context.Context) { + //写入日志数据 + s.Add(ctx, data) + }, + ); err != nil { + g.Log().Error(ctx, err.Error()) + } + +} + +// Add 记录登录日志 +func (s *sSysLoginLog) Add(ctx context.Context, params *model.LoginLogParams) { + ua := user_agent.New(params.UserAgent) + browser, _ := ua.Browser() + loginData := &do.SysLoginLog{ + LoginName: params.Username, + Ipaddr: params.Ip, + LoginLocation: utils.GetCityByIp(params.Ip), + Browser: browser, + Os: ua.OS(), + Status: params.Status, + Msg: params.Msg, + LoginTime: gtime.Now(), + Module: params.Module, + } + _, err := dao.SysLoginLog.Ctx(ctx).Insert(loginData) + if err != nil { + g.Log().Error(ctx, err) + } +} + +// GetList 获取访问日志数据列表 +func (s *sSysLoginLog) GetList(ctx context.Context, req *model.SysLoginLogInput) (total, page int, list []*model.SysLoginLogOut, err error) { + m := dao.SysLoginLog.Ctx(ctx) + if req.LoginName != "" { + m = m.WhereLike(dao.SysLoginLog.Columns().LoginName, "%"+req.LoginName+"%") + } + if req.Ipaddr != "" { + m = m.WhereLike(dao.SysLoginLog.Columns().Ipaddr, "%"+req.Ipaddr+"%") + } + if req.LoginLocation != "" { + m = m.WhereLike(dao.SysLoginLog.Columns().LoginLocation, "%"+req.LoginLocation+"%") + } + if req.Browser != "" { + m = m.WhereLike(dao.SysLoginLog.Columns().Browser, "%"+req.Browser+"%") + } + if req.Os != "" { + m = m.WhereLike(dao.SysLoginLog.Columns().Os, "%"+req.Os+"%") + } + if req.Status != -1 { + m = m.Where(dao.SysLoginLog.Columns().Status, req.Status) + } + /*where,err := GetDataWhere(ctx, service.Context().GetUserId(ctx), new(entity.SysLoginLog)) + if err != nil { + return + } + if len(where) > 0 { + m = m.Where(where) + }*/ + //获取总数 + total, err = m.Count() + if err != nil { + err = gerror.New("获取访问日志列表数据失败") + return + } + page = req.PageNum + if req.PageNum == 0 { + req.PageNum = 1 + } + if req.PageSize == 0 { + req.PageSize = consts.DefaultPageSize + } + //获取访问日志列表信息 + err = m.Page(req.PageNum, req.PageSize).OrderDesc(dao.SysLoginLog.Columns().InfoId).Scan(&list) + if err != nil { + err = gerror.New("获取访问日志列表失败") + return + } + return +} + +// Detail 访问日志详情 +func (s *sSysLoginLog) Detail(ctx context.Context, infoId int) (entity *entity.SysLoginLog, err error) { + _ = dao.SysLoginLog.Ctx(ctx).Where(g.Map{ + dao.SysLoginLog.Columns().InfoId: infoId, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("日志ID错误") + } + return +} + +// Del 根据ID删除访问日志 +func (s *sSysLoginLog) Del(ctx context.Context, infoIds []int) (err error) { + for _, infoId := range infoIds { + var SysLoginLog *entity.BaseDbLink + _ = dao.SysLoginLog.Ctx(ctx).Where(g.Map{ + dao.SysLoginLog.Columns().InfoId: infoId, + }).Scan(&SysLoginLog) + if SysLoginLog == nil { + return gerror.New("ID错误") + } + } + //删除访问日志 + _, err = dao.SysLoginLog.Ctx(ctx).WhereIn(dao.SysLoginLog.Columns().InfoId, infoIds). + Delete() + return +} diff --git a/internal/logic/system/sys_menu.go b/internal/logic/system/sys_menu.go new file mode 100644 index 0000000..6375f71 --- /dev/null +++ b/internal/logic/system/sys_menu.go @@ -0,0 +1,252 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysMenu struct { +} + +func sysMenuNew() *sSysMenu { + return &sSysMenu{} +} + +func init() { + service.RegisterSysMenu(sysMenuNew()) +} + +// GetAll 获取全部菜单数据 +func (s *sSysMenu) GetAll(ctx context.Context) (data []*entity.SysMenu, err error) { + err = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().Status: 1, + dao.SysMenu.Columns().IsDeleted: 0, + }).OrderDesc(dao.SysMenu.Columns().Weigh).Scan(&data) + return +} + +// GetTree 获取菜单数据 +func (s *sSysMenu) GetTree(ctx context.Context, title string, status int) (data []*model.SysMenuOut, err error) { + menuInfo, err := s.GetData(ctx, title, status) + var parentNodeOut []*model.SysMenuOut + if menuInfo != nil { + //获取所有的根节点 + for _, v := range menuInfo { + var parentNode *model.SysMenuOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeOut = append(parentNodeOut, parentNode) + } + } + data = MenuTree(parentNodeOut, menuInfo) + } + + return +} + +// MenuTree 生成树结构 +func MenuTree(parentNodeOut []*model.SysMenuOut, data []*model.SysMenuOut) (dataTree []*model.SysMenuOut) { + //循环所有一级菜单 + for k, v := range parentNodeOut { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.SysMenuOut + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeOut[k].Children = append(parentNodeOut[k].Children, node) + } + } + MenuTree(v.Children, data) + } + return parentNodeOut +} + +// Add 添加菜单 +func (s *sSysMenu) Add(ctx context.Context, input *model.AddMenuInput) (err error) { + var menu *entity.SysMenu + //根据名称查看角色是否存在 + menu = checkMenuName(ctx, input.Name, menu, 0) + if menu != nil { + return gerror.New("菜单已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + menu = new(entity.SysMenu) + if err := gconv.Scan(input, &menu); err != nil { + return err + } + menu.IsDeleted = 0 + menu.CreatedBy = uint(loginUserId) + _, err = dao.SysMenu.Ctx(ctx).Data(menu).Insert() + if err != nil { + return err + } + return +} + +// Detail 菜单详情 +func (s *sSysMenu) Detail(ctx context.Context, menuId int64) (entity *entity.SysMenu, err error) { + _ = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().Id: menuId, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// Edit 修改菜单 +func (s *sSysMenu) Edit(ctx context.Context, input *model.EditMenuInput) (err error) { + var menu, menu2 *entity.SysMenu + //根据ID查看菜单是否存在 + menu = checkMenuId(ctx, input.Id, menu) + if menu == nil { + return gerror.New("菜单不存在") + } + menu2 = checkMenuName(ctx, input.Name, menu2, input.Id) + if menu2 != nil { + return gerror.New("相同菜单已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &menu); err != nil { + return err + } + menu.UpdatedBy = int(uint(loginUserId)) + _, err = dao.SysMenu.Ctx(ctx).Data(menu). + Where(dao.SysMenu.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + return +} + +// 检查相同菜单名称的数据是否存在 +func checkMenuName(ctx context.Context, menuName string, menu *entity.SysMenu, tag int64) *entity.SysMenu { + m := dao.SysMenu.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysMenu.Columns().Id, tag) + } + _ = m.Where(g.Map{ + dao.SysMenu.Columns().Name: menuName, + dao.SysMenu.Columns().IsDeleted: 0, + }).Scan(&menu) + return menu +} + +// Del 根据ID删除菜单信息 +func (s *sSysMenu) Del(ctx context.Context, menuId int64) (err error) { + var menu *entity.SysMenu + _ = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().Id: menuId, + }).Scan(&menu) + if menu == nil { + return gerror.New("ID错误") + } + errorString := checkMenuJoin(ctx, menuId) + if errorString != "" { + return gerror.New(errorString) + } + loginUserId := service.Context().GetUserId(ctx) + _, err = dao.SysMenu.Ctx(ctx).Data(g.Map{ + dao.SysMenu.Columns().DeletedBy: uint(loginUserId), + dao.SysMenu.Columns().IsDeleted: 1, + }).Where(dao.SysMenu.Columns().Id, menuId).Update() + //删除菜单信息 + _, err = dao.SysMenu.Ctx(ctx).Where(dao.SysMenu.Columns().Id, menuId).Delete() + return +} + +// 查询关联数据是否存在 +func checkMenuJoin(ctx context.Context, menuId int64) string { + num := 0 + //查询是否有子节点 + num, _ = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().ParentId: menuId, + dao.SysMenu.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return "请先删除子节点!" + } + //查询关联Api + num, _ = dao.SysMenuApi.Ctx(ctx).Where(g.Map{ + dao.SysMenuApi.Columns().MenuId: menuId, + dao.SysMenuApi.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return "存在菜单API关联!" + } + //查询关联列表 + num, _ = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().MenuId: menuId, + dao.SysMenuButton.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return "存在菜单列表关联!" + } + //查询关联按钮 + num, _ = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().MenuId: menuId, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return "存在菜单按钮关联!" + } + return "" +} + +// GetData 执行获取数据操作 +func (s *sSysMenu) GetData(ctx context.Context, title string, status int) (data []*model.SysMenuOut, err error) { + m := dao.SysMenu.Ctx(ctx) + //模糊查询菜单标题名称 + if title != "" { + m = m.WhereLike(dao.SysMenu.Columns().Title, "%"+title+"%") + } + if status != -1 { + m = m.Where(dao.SysMenu.Columns().Status, status) + } + err = m.Where(dao.SysMenu.Columns().IsDeleted, 0). + OrderDesc(dao.SysMenu.Columns().Weigh). + Scan(&data) + if err != nil { + return + } + return +} + +// 检查指定ID的数据是否存在 +func checkMenuId(ctx context.Context, MenuId int64, menu *entity.SysMenu) *entity.SysMenu { + _ = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().Id: MenuId, + dao.SysMenu.Columns().IsDeleted: 0, + }).Scan(&menu) + return menu +} + +// GetInfoByMenuIds 根据菜单ID数组获取菜单信息 +func (s *sSysMenu) GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenu, err error) { + err = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().IsDeleted: 0, + dao.SysMenu.Columns().Status: 1, + }).WhereIn(dao.SysMenu.Columns().Id, menuIds).OrderDesc(dao.SysMenu.Columns().Weigh).Scan(&data) + return +} + +func (s *sSysMenu) GetInfoById(ctx context.Context, id int) (data *entity.SysMenu, err error) { + err = dao.SysMenu.Ctx(ctx).Where(g.Map{ + dao.SysMenu.Columns().IsDeleted: 0, + dao.SysMenu.Columns().Id: id, + }).Scan(&data) + return +} diff --git a/internal/logic/system/sys_menu_api.go b/internal/logic/system/sys_menu_api.go new file mode 100644 index 0000000..97e15f5 --- /dev/null +++ b/internal/logic/system/sys_menu_api.go @@ -0,0 +1,45 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysMenuApi struct { +} + +func sysMenuApiNew() *sSysMenuApi { + return &sSysMenuApi{} +} + +func init() { + service.RegisterSysMenuApi(sysMenuApiNew()) +} + +//GetInfoByIds 根据IDS数组获取菜单信息 +func (s *sSysMenuApi) GetInfoByIds(ctx context.Context, ids []int) (data []*entity.SysMenuApi, err error) { + err = dao.SysMenuApi.Ctx(ctx).Where(g.Map{ + dao.SysMenuApi.Columns().IsDeleted: 0, + }).WhereIn(dao.SysMenuApi.Columns().Id, ids).Scan(&data) + return +} + +//GetInfoByMenuIds 根据菜单ID数组获取菜单信息 +func (s *sSysMenuApi) GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuApi, err error) { + err = dao.SysMenuApi.Ctx(ctx).Where(g.Map{ + dao.SysMenuApi.Columns().IsDeleted: 0, + }).WhereIn(dao.SysMenuApi.Columns().MenuId, menuIds).Scan(&data) + return +} + +//GetInfoByApiId 根据接口ID数组获取菜单信息 +func (s *sSysMenuApi) GetInfoByApiId(ctx context.Context, apiId int) (data []*entity.SysMenuApi, err error) { + err = dao.SysMenuApi.Ctx(ctx).Where(g.Map{ + dao.SysMenuApi.Columns().IsDeleted: 0, + dao.SysMenuApi.Columns().ApiId: apiId, + }).Scan(&data) + return +} diff --git a/internal/logic/system/sys_menu_button.go b/internal/logic/system/sys_menu_button.go new file mode 100644 index 0000000..06a8825 --- /dev/null +++ b/internal/logic/system/sys_menu_button.go @@ -0,0 +1,228 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysMenuButton struct { +} + +func sysMenuButtonNew() *sSysMenuButton { + return &sSysMenuButton{} +} + +func init() { + service.RegisterSysMenuButton(sysMenuButtonNew()) +} + +// GetList 获取全部菜单按钮数据 +func (s *sSysMenuButton) GetList(ctx context.Context, status int, name string, menuId int) (data []model.UserMenuButtonRes, err error) { + var menuButton []model.UserMenuButtonRes + menuButton, err = s.GetData(ctx, status, name, menuId, menuButton) + return menuButton, err +} + +// GetData 执行获取数据操作 +func (s *sSysMenuButton) GetData(ctx context.Context, status int, name string, menuId int, menuButton []model.UserMenuButtonRes) (data []model.UserMenuButtonRes, err error) { + m := dao.SysMenuButton.Ctx(ctx) + + if status != -1 { + m = m.Where(dao.SysMenuButton.Columns().Status, status) + } + //模糊查询菜单按钮名称 + if name != "" { + m = m.WhereLike(dao.SysMenuButton.Columns().Name, "%"+name+"%") + } + err = m.Where(g.Map{ + dao.SysMenuButton.Columns().IsDeleted: 0, + dao.SysMenuButton.Columns().MenuId: menuId, + }).Scan(&menuButton) + return menuButton, err +} + +// Add 添加菜单按钮 +func (s *sSysMenuButton) Add(ctx context.Context, input *model.AddMenuButtonInput) (err error) { + var menuButton *entity.SysMenuButton + //根据名称查看角色是否存在 + menuButton = checkMenuButtonName(ctx, input.MenuId, input.Name, menuButton) + if menuButton != nil { + return gerror.New("菜单按钮已存在,无法添加") + } + menuButton = checkMenuButtonType(ctx, input.MenuId, input.Types, menuButton) + if menuButton != nil { + return gerror.New("菜单按钮类型已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + menuButton = new(entity.SysMenuButton) + if err := gconv.Scan(input, &menuButton); err != nil { + return err + } + menuButton.IsDeleted = 0 + menuButton.CreatedBy = uint(loginUserId) + _, err = dao.SysMenuButton.Ctx(ctx).Data(menuButton).Insert() + if err != nil { + return err + } + return +} + +// Detail 菜单按钮详情 +func (s *sSysMenuButton) Detail(ctx context.Context, Id int64) (entity *entity.SysMenuButton, err error) { + _ = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().Id: Id, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// Edit 修改菜单按钮 +func (s *sSysMenuButton) Edit(ctx context.Context, input *model.EditMenuButtonInput) (err error) { + var menuButton, menuButton2 *entity.SysMenuButton + //根据ID查看菜单按钮是否存在 + menuButton = checkMenuButtonId(ctx, input.Id, menuButton) + if menuButton == nil { + return gerror.New("菜单按钮不存在") + } + menuButton2 = checkMenuButtonName(ctx, input.MenuId, input.Name, menuButton) + if menuButton2 != nil && int(menuButton2.Id) != input.Id { + return gerror.New("菜单按钮已存在,无法添加") + } + menuButton2 = checkMenuButtonType(ctx, input.MenuId, input.Types, menuButton) + if menuButton2 != nil && int(menuButton2.Id) != input.Id { + return gerror.New("菜单按钮类型已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &menuButton); err != nil { + return err + } + menuButton.UpdatedBy = int(uint(loginUserId)) + _, err = dao.SysMenuButton.Ctx(ctx).Data(menuButton). + Where(dao.SysMenuButton.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + return +} + +// Del 根据ID删除菜单按钮信息 +func (s *sSysMenuButton) Del(ctx context.Context, Id int64) (err error) { + var menuButton *entity.SysMenuButton + _ = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().Id: Id, + }).Scan(&menuButton) + if menuButton == nil { + return gerror.New("ID错误") + } + //查询是否存在下级 + num, err := dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().ParentId: Id, + dao.SysMenuButton.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //更新菜单按钮信息 + _, err = dao.SysMenuButton.Ctx(ctx). + Data(g.Map{ + dao.SysMenuButton.Columns().DeletedBy: uint(loginUserId), + dao.SysMenuButton.Columns().IsDeleted: 1, + }).Where(dao.SysMenuButton.Columns().Id, Id). + Update() + //删除菜单按钮信息 + _, err = dao.SysMenuButton.Ctx(ctx).Where(dao.SysMenuButton.Columns().Id, Id). + Delete() + return +} + +// GetInfoByButtonIds 根据按钮ID数组获取菜单按钮信息 +func (s *sSysMenuButton) GetInfoByButtonIds(ctx context.Context, ids []int) (data []*entity.SysMenuButton, err error) { + err = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().IsDeleted: 0, + dao.SysMenuButton.Columns().Status: 1, + }).WhereIn(dao.SysMenuButton.Columns().Id, ids).Scan(&data) + return +} + +// GetInfoByMenuIds 根据菜单ID数组获取菜单按钮信息 +func (s *sSysMenuButton) GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuButton, err error) { + err = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().IsDeleted: 0, + dao.SysMenuButton.Columns().Status: 1, + }).WhereIn(dao.SysMenuButton.Columns().MenuId, menuIds).Scan(&data) + return +} + +// EditStatus 修改状态 +func (s *sSysMenuButton) EditStatus(ctx context.Context, id int, menuId int, status int) (err error) { + var menuButton *entity.SysMenuButton + _ = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().Id: id, + }).Scan(&menuButton) + if menuButton == nil { + return gerror.New("ID错误") + } + if menuButton.MenuId != menuId { + return gerror.New("按钮不属于当前菜单,无法修改") + } + if menuButton != nil && menuButton.IsDeleted == 1 { + return gerror.New("按钮已删除,无法修改") + } + if menuButton != nil && menuButton.Status == status { + return gerror.New("按钮已禁用或启用,无须重复修改") + } + loginUserId := service.Context().GetUserId(ctx) + menuButton.Status = status + menuButton.UpdatedBy = loginUserId + + _, err = dao.SysMenuButton.Ctx(ctx).Data(menuButton).Where(g.Map{ + dao.SysMenuButton.Columns().Id: id, + }).Update() + return +} + +// 检查指定ID的数据是否存在 +func checkMenuButtonId(ctx context.Context, Id int, menuButton *entity.SysMenuButton) *entity.SysMenuButton { + _ = dao.SysMenuButton.Ctx(ctx).Where(g.Map{ + dao.SysMenuButton.Columns().Id: Id, + dao.SysMenuButton.Columns().IsDeleted: 0, + }).Scan(&menuButton) + return menuButton +} + +// 检查相同菜单按钮名称的数据是否存在 +func checkMenuButtonName(ctx context.Context, menuId int, name string, menuButton *entity.SysMenuButton) *entity.SysMenuButton { + m := dao.SysMenuButton.Ctx(ctx) + _ = m.Where(g.Map{ + dao.SysMenuButton.Columns().Name: name, + dao.SysMenuButton.Columns().MenuId: menuId, + dao.SysMenuButton.Columns().IsDeleted: 0, + }).Scan(&menuButton) + return menuButton +} + +// 检查相同菜单按钮类型的数据是否存在 +func checkMenuButtonType(ctx context.Context, menuId int, types string, menuButton *entity.SysMenuButton) *entity.SysMenuButton { + m := dao.SysMenuButton.Ctx(ctx) + _ = m.Where(g.Map{ + dao.SysMenuButton.Columns().Types: types, + dao.SysMenuButton.Columns().MenuId: menuId, + dao.SysMenuButton.Columns().IsDeleted: 0, + }).Scan(&menuButton) + return menuButton +} diff --git a/internal/logic/system/sys_menu_column.go b/internal/logic/system/sys_menu_column.go new file mode 100644 index 0000000..976995d --- /dev/null +++ b/internal/logic/system/sys_menu_column.go @@ -0,0 +1,236 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysMenuColumn struct { +} + +func sysMenuColumnNew() *sSysMenuColumn { + return &sSysMenuColumn{} +} + +func init() { + service.RegisterSysMenuColumn(sysMenuColumnNew()) +} + +// GetList 获取全部菜单列表数据 +func (s *sSysMenuColumn) GetList(ctx context.Context, input *model.MenuColumnDoInput) (data []model.UserMenuColumnRes, err error) { + var menuColumn []model.UserMenuColumnRes + menuColumn, err = s.GetData(ctx, input, menuColumn) + return menuColumn, err +} + +// GetData 执行获取数据操作 +func (s *sSysMenuColumn) GetData(ctx context.Context, input *model.MenuColumnDoInput, menuColumn []model.UserMenuColumnRes) (data []model.UserMenuColumnRes, err error) { + m := dao.SysMenuColumn.Ctx(ctx) + //模糊查询菜单列表名称 + if input.Name != "" { + m = m.WhereLike(dao.SysMenuColumn.Columns().Name, "%"+input.Name+"%") + } + //查询菜单列表菜单ID关联数据 + if input.MenuId != "" { + m = m.Where(dao.SysMenuColumn.Columns().MenuId, input.MenuId) + } + //查询菜单列表上级 + if input.ParentId != "" { + m = m.Where(dao.SysMenuColumn.Columns().ParentId, input.ParentId) + } + //模糊查询菜单列表状态 + if input.Status != -1 { + m = m.Where(dao.SysMenuColumn.Columns().Status, input.Status) + } + err = m.Where(g.Map{ + dao.SysMenuColumn.Columns().MenuId: input.MenuId, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }). + Scan(&menuColumn) + return menuColumn, err +} + +// Add 添加菜单列表 +func (s *sSysMenuColumn) Add(ctx context.Context, input *model.AddMenuColumnInput) (err error) { + var menuColumn *entity.SysMenuColumn + //根据名称查看是否存在 + menuColumn = checkMenuColumnName(ctx, input.MenuId, input.Name, menuColumn) + if menuColumn != nil { + return gerror.New("菜单列表已存在,无法添加") + } + + menuColumn = checkMenuColumnCode(ctx, input.MenuId, input.Code, menuColumn) + if menuColumn != nil { + return gerror.New("菜单列表CODE已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + menuColumn = new(entity.SysMenuColumn) + if err := gconv.Scan(input, &menuColumn); err != nil { + return err + } + menuColumn.IsDeleted = 0 + menuColumn.CreatedBy = uint(loginUserId) + _, err = dao.SysMenuColumn.Ctx(ctx).Data(menuColumn).Insert() + if err != nil { + return err + } + return +} + +// Detail 菜单列表详情 +func (s *sSysMenuColumn) Detail(ctx context.Context, Id int64) (entity *entity.SysMenuColumn, err error) { + _ = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().Id: Id, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// Edit 修改菜单列表 +func (s *sSysMenuColumn) Edit(ctx context.Context, input *model.EditMenuColumnInput) (err error) { + var menuColumn, menuColumn2 *entity.SysMenuColumn + //根据ID查看菜单列表是否存在 + menuColumn = checkMenuColumnId(ctx, input.Id, menuColumn) + if menuColumn == nil { + return gerror.New("菜单列表不存在") + } + //根据名称查看是否存在 + menuColumn2 = checkMenuColumnName(ctx, input.MenuId, input.Name, menuColumn) + if menuColumn2 != nil && int(menuColumn2.Id) != input.Id { + return gerror.New("菜单列表已存在,无法添加") + } + + menuColumn2 = checkMenuColumnCode(ctx, input.MenuId, input.Code, menuColumn) + if menuColumn2 != nil && int(menuColumn2.Id) != input.Id { + return gerror.New("菜单列表CODE已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &menuColumn); err != nil { + return err + } + menuColumn.UpdatedBy = int(uint(loginUserId)) + _, err = dao.SysMenuColumn.Ctx(ctx).Data(menuColumn). + Where(dao.SysMenuColumn.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + return +} + +// Del 根据ID删除菜单列表信息 +func (s *sSysMenuColumn) Del(ctx context.Context, Id int64) (err error) { + var menuColumn *entity.SysMenuColumn + _ = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().Id: Id, + }).Scan(&menuColumn) + if menuColumn == nil { + return gerror.New("ID错误") + } + //查询是否存在下级 + num, err := dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().ParentId: Id, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //更新菜单列表信息 + _, err = dao.SysMenuColumn.Ctx(ctx). + Data(g.Map{ + dao.SysMenuColumn.Columns().DeletedBy: uint(loginUserId), + dao.SysMenuColumn.Columns().IsDeleted: 1, + }).Where(dao.SysMenuColumn.Columns().Id, Id). + Update() + //删除菜单列表信息 + _, err = dao.SysMenuColumn.Ctx(ctx).Where(dao.SysMenuColumn.Columns().Id, Id).Delete() + return +} + +// EditStatus 修改状态 +func (s *sSysMenuColumn) EditStatus(ctx context.Context, id int, menuId int, status int) (err error) { + var menuColum *entity.SysMenuColumn + _ = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().Id: id, + }).Scan(&menuColum) + if menuColum == nil { + return gerror.New("ID错误") + } + if menuColum.MenuId != menuId { + return gerror.New("列表字段不属于当前菜单,无法修改") + } + if menuColum != nil && menuColum.IsDeleted == 1 { + return gerror.New("列表字段已删除,无法修改") + } + if menuColum != nil && menuColum.Status == status { + return gerror.New("列表已禁用或启用,无须重复修改") + } + loginUserId := service.Context().GetUserId(ctx) + menuColum.Status = status + menuColum.UpdatedBy = loginUserId + + _, err = dao.SysMenuColumn.Ctx(ctx).Data(menuColum).Where(g.Map{ + dao.SysMenuColumn.Columns().Id: id, + }).Update() + return +} + +// 检查指定ID的数据是否存在 +func checkMenuColumnId(ctx context.Context, Id int, menuColumn *entity.SysMenuColumn) *entity.SysMenuColumn { + _ = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().Id: Id, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).Scan(&menuColumn) + return menuColumn +} + +// 检查相同菜单按钮名称的数据是否存在 +func checkMenuColumnName(ctx context.Context, menu int, name string, menuColumn *entity.SysMenuColumn) *entity.SysMenuColumn { + m := dao.SysMenuColumn.Ctx(ctx) + _ = m.Where(g.Map{ + dao.SysMenuColumn.Columns().Name: name, + dao.SysMenuColumn.Columns().MenuId: menu, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).Scan(&menuColumn) + return menuColumn +} + +func checkMenuColumnCode(ctx context.Context, menu int, code string, menuColumn *entity.SysMenuColumn) *entity.SysMenuColumn { + m := dao.SysMenuColumn.Ctx(ctx) + _ = m.Where(g.Map{ + dao.SysMenuColumn.Columns().Code: code, + dao.SysMenuColumn.Columns().MenuId: menu, + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).Scan(&menuColumn) + return menuColumn +} + +// GetInfoByColumnIds 根据列表ID数组获取菜单信息 +func (s *sSysMenuColumn) GetInfoByColumnIds(ctx context.Context, ids []int) (data []*entity.SysMenuColumn, err error) { + err = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).WhereIn(dao.SysMenuColumn.Columns().Id, ids).Scan(&data) + return +} + +// GetInfoByMenuIds 根据菜单ID数组获取菜单信息 +func (s *sSysMenuColumn) GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuColumn, err error) { + err = dao.SysMenuColumn.Ctx(ctx).Where(g.Map{ + dao.SysMenuColumn.Columns().IsDeleted: 0, + }).WhereIn(dao.SysMenuColumn.Columns().MenuId, menuIds).Scan(&data) + return +} diff --git a/internal/logic/system/sys_notifications.go b/internal/logic/system/sys_notifications.go new file mode 100644 index 0000000..77d6040 --- /dev/null +++ b/internal/logic/system/sys_notifications.go @@ -0,0 +1,66 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysNotifications struct{} + +func sSysNotificationsNew() *sSysNotifications { + return &sSysNotifications{} +} +func init() { + service.RegisterSysNotifications(sSysNotificationsNew()) +} + +// 获取列表数据 +func (s *sSysNotifications) GetSysNotificationsList(ctx context.Context, input *model.GetNotificationsListInput) (total, page int, list []*model.NotificationsOut, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysNotifications.Ctx(ctx) + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = input.PageNum + if input.PageSize == 0 { + input.PageSize = consts.PageSize + } + err = m.Page(page, input.PageSize).Order("created_at desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// 获取指定ID数据 +func (s *sSysNotifications) GetSysNotificationsById(ctx context.Context, id int) (out *model.NotificationsRes, err error) { + err = dao.SysNotifications.Ctx(ctx).Where("id", id).Scan(&out) + return +} + +// 添加数据 +func (s *sSysNotifications) AddSysNotifications(ctx context.Context, in model.NotificationsAddInput) (err error) { + _, err = dao.SysNotifications.Ctx(ctx).Insert(in) + return +} + +// 修改数据 +func (s *sSysNotifications) EditSysNotifications(ctx context.Context, in model.NotificationsEditInput) (err error) { + _, err = dao.SysNotifications.Ctx(ctx).FieldsEx(dao.SysNotifications.Columns().Id).Where(dao.SysNotifications.Columns().Id, in.Id).Update(in) + return +} + +// 删除数据 +func (s *sSysNotifications) DeleteSysNotifications(ctx context.Context, in *system.DeleteNotificationsReq) (err error) { + _, err = dao.SysNotifications.Ctx(ctx).Delete(dao.SysNotifications.Columns().Id+" in (?)", in.Ids) + return +} diff --git a/internal/logic/system/sys_oper_log.go b/internal/logic/system/sys_oper_log.go new file mode 100644 index 0000000..66ba95b --- /dev/null +++ b/internal/logic/system/sys_oper_log.go @@ -0,0 +1,230 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/grpool" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "net/url" + "strings" +) + +type sSysOperLog struct { +} + +func SysOperLog() *sSysOperLog { + return &sSysOperLog{} +} + +func init() { + service.RegisterSysOperLog(SysOperLog()) +} + +// GetList 获取操作日志数据列表 +func (s *sSysOperLog) GetList(ctx context.Context, input *model.SysOperLogDoInput) (total int, out []*model.SysOperLogOut, err error) { + m := dao.SysOperLog.Ctx(ctx) + if input.Title != "" { + m = m.WhereLike(dao.SysOperLog.Columns().Title, "%"+input.Title+"%") + } + if input.BusinessType != "" { + m = m.WhereLike(dao.SysOperLog.Columns().BusinessType, "%"+input.BusinessType+"%") + } + if input.Method != "" { + m = m.WhereLike(dao.SysOperLog.Columns().Method, "%"+input.Method+"%") + } + if input.RequestMethod != "" { + m = m.WhereLike(dao.SysOperLog.Columns().RequestMethod, "%"+input.RequestMethod+"%") + } + if input.OperatorType != "" { + m = m.WhereLike(dao.SysOperLog.Columns().OperatorType, "%"+input.OperatorType+"%") + } + if input.OperName != "" { + m = m.WhereLike(dao.SysOperLog.Columns().OperName, "%"+input.OperName+"%") + } + if input.DeptName != "" { + m = m.WhereLike(dao.SysOperLog.Columns().DeptName, "%"+input.DeptName+"%") + } + if input.OperUrl != "" { + m = m.WhereLike(dao.SysOperLog.Columns().OperUrl, "%"+input.OperUrl+"%") + } + if input.OperIp != "" { + m = m.WhereLike(dao.SysOperLog.Columns().OperIp, "%"+input.OperIp+"%") + } + if input.OperLocation != "" { + m = m.WhereLike(dao.SysOperLog.Columns().OperLocation, "%"+input.OperLocation+"%") + } + if input.Status != -1 { + m = m.Where(dao.SysOperLog.Columns().Status, input.Status) + } + //获取总数 + total, err = m.Count() + if err != nil { + err = gerror.New("获取操作日志列表数据失败") + return + } + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.DefaultPageSize + } + //获取操作日志列表信息 + err = m.Page(input.PageNum, input.PageSize).OrderDesc(dao.SysOperLog.Columns().OperId).Scan(&out) + if err != nil { + err = gerror.New("获取操作日志列表失败") + return + } + return +} + +func (s *sSysOperLog) Invoke(ctx context.Context, userId int, url *url.URL, param g.Map, method string, clientIp string, res map[string]interface{}, err error) { + pool := grpool.New(100) + if err := pool.Add(ctx, func(ctx context.Context) { + //写入操作数据 + err = s.Add(ctx, userId, url, param, method, clientIp, res, err) + }, + ); err != nil { + g.Log().Error(ctx, err.Error()) + } +} + +// Add 添加操作日志 +func (s *sSysOperLog) Add(ctx context.Context, userId int, url *url.URL, param g.Map, method string, clientIp string, res map[string]interface{}, erro error) (err error) { + var operLogInfo = new(entity.SysOperLog) + //根据用户ID查询用户信息 + var userInfo *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: userId, + dao.SysUser.Columns().IsDeleted: 0, + dao.SysUser.Columns().Status: 1, + }).Scan(&userInfo) + if userInfo != nil { + //操作人员 + operLogInfo.OperName = userInfo.UserName + //获取用户部门信息 + var deptInfo *entity.SysDept + err = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().DeptId: userInfo.DeptId, + dao.SysDept.Columns().IsDeleted: 0, + dao.SysDept.Columns().Status: 1, + }).Scan(&deptInfo) + if deptInfo != nil { + //部门名称 + operLogInfo.DeptName = deptInfo.DeptName + } + } + //请求地址 + operLogInfo.Method = url.Path + //根据请求地址获取请求信息 + apiInfo, _ := service.SysApi().GetInfoByAddress(ctx, url.Path) + if apiInfo != nil { + operLogInfo.Title = apiInfo.Name + } + //请求方法 + operLogInfo.RequestMethod = method + //操作类型 + operLogInfo.OperatorType = 1 + //业务类型 + if strings.EqualFold(method, "POST") { + operLogInfo.BusinessType = 1 + } else if strings.EqualFold(method, "PUT") { + operLogInfo.BusinessType = 2 + } else if strings.EqualFold(method, "DELETE") { + operLogInfo.BusinessType = 3 + } else { + operLogInfo.BusinessType = 0 + } + //请求地址 + rawQuery := url.RawQuery + if rawQuery != "" { + rawQuery = "?" + rawQuery + } + operLogInfo.OperUrl = url.Path + rawQuery + //客户端IP + operLogInfo.OperIp = clientIp + //操作地址 + operLogInfo.OperLocation = utils.GetCityByIp(operLogInfo.OperIp) + //获取当前时间 + time, err := gtime.StrToTimeFormat(gtime.Datetime(), "2006-01-02 15:04:05") + if err != nil { + return + } + //请求时间 + operLogInfo.OperTime = time + //参数 + if param != nil { + b, _ := gjson.Encode(param) + if len(b) > 0 { + operLogInfo.OperParam = string(b) + } + } + var code gcode.Code = gcode.CodeOK + if erro != nil { + code = gerror.Code(erro) + if code == gcode.CodeNil { + code = gcode.CodeInternalError + } + } + //返回参数 + if code.Code() != 0 { + operLogInfo.Status = 0 + errMsg := erro.Error() + var ( + errorMsgMap = map[string]interface{}{ + "code": code.Code(), + "message": errMsg, + } + ) + errorMsg, _ := gjson.Encode(errorMsgMap) + operLogInfo.ErrorMsg = string(errorMsg) + } else { + operLogInfo.Status = 1 + b, _ := gjson.Encode(res) + if len(b) > 0 { + operLogInfo.JsonResult = string(b) + } + } + _, err = dao.SysOperLog.Ctx(ctx).Data(operLogInfo).Insert() + return +} + +// Detail 操作日志详情 +func (s *sSysOperLog) Detail(ctx context.Context, operId int) (entity *entity.SysOperLog, err error) { + _ = dao.SysOperLog.Ctx(ctx).Where(g.Map{ + dao.SysOperLog.Columns().OperId: operId, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("日志ID错误") + } + return +} + +// Del 根据ID删除操作日志 +func (s *sSysOperLog) Del(ctx context.Context, operIds []int) (err error) { + for _, operId := range operIds { + var sysOperLog *entity.BaseDbLink + _ = dao.SysOperLog.Ctx(ctx).Where(g.Map{ + dao.SysOperLog.Columns().OperId: operId, + }).Scan(&sysOperLog) + if sysOperLog == nil { + return gerror.New("ID错误") + } + } + //删除操作日志 + _, err = dao.SysOperLog.Ctx(ctx).WhereIn(dao.SysOperLog.Columns().OperId, operIds).Delete() + return +} + +func (s *sSysOperLog) ClearOperationLogByDays(ctx context.Context, days int) (err error) { + _, err = dao.SysOperLog.Ctx(ctx).Delete("to_days(now())-to_days(`oper_time`) > ?", days+1) + return +} diff --git a/internal/logic/system/sys_organization.go b/internal/logic/system/sys_organization.go new file mode 100644 index 0000000..e43cdba --- /dev/null +++ b/internal/logic/system/sys_organization.go @@ -0,0 +1,301 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + "strings" + "time" +) + +type sSysOrganization struct { +} + +func SysOrganizationNew() *sSysOrganization { + return &sSysOrganization{} +} + +func init() { + service.RegisterSysOrganization(SysOrganizationNew()) +} + +// GetList 获取组织数据 +func (s *sSysOrganization) GetTree(ctx context.Context, name string, status int) (data []*model.OrganizationOut, err error) { + orgainzationInfo, err := s.GetData(ctx, name, status) + var parentNodeOut []*model.OrganizationOut + if orgainzationInfo != nil { + //获取所有的根节点 + for _, v := range orgainzationInfo { + var parentNode *model.OrganizationOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeOut = append(parentNodeOut, parentNode) + } + } + } + data = OrganizationTree(parentNodeOut, orgainzationInfo) + return +} + +// OrganizationTree 生成树结构 +func OrganizationTree(parentNodeOut []*model.OrganizationOut, data []*model.OrganizationOut) (dataTree []*model.OrganizationOut) { + //循环所有一级菜单 + for k, v := range parentNodeOut { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.OrganizationOut + if j.ParentId == v.Id { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeOut[k].Children = append(parentNodeOut[k].Children, node) + } + } + OrganizationTree(v.Children, data) + } + return parentNodeOut +} + +// GetData 执行获取数据操作 +func (s *sSysOrganization) GetData(ctx context.Context, name string, status int) (data []*model.OrganizationOut, err error) { + m := dao.SysOrganization.Ctx(ctx) + if status != -1 { + m = m.Where(dao.SysOrganization.Columns().Status, status) + } + //模糊查询组织名称 + if name != "" { + m = m.WhereLike(dao.SysOrganization.Columns().Name, "%"+name+"%") + } + err = m.Where(dao.SysOrganization.Columns().IsDeleted, 0). + OrderDesc(dao.SysOrganization.Columns().OrderNum). + Scan(&data) + if err != nil { + return + } + return +} + +// Add 添加 +func (s *sSysOrganization) Add(ctx context.Context, input *model.AddOrganizationInput) (err error) { + //根据名称查看组织是否存在 + organization := checkOrganizationName(ctx, input.Name, 0) + if organization != nil { + return gerror.New("组织已存在,无法添加") + } + organization = new(entity.SysOrganization) + organization.Number = "org_" + strconv.FormatInt(time.Now().Unix(), 10) + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + organization = new(entity.SysOrganization) + if err := gconv.Scan(input, &organization); err != nil { + return err + } + organization.IsDeleted = 0 + organization.CreatedBy = uint(loginUserId) + //开启事务管理 + err = dao.SysOrganization.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + lastId, err1 := dao.SysOrganization.Ctx(ctx).Data(organization).InsertAndGetId() + if err1 != nil { + return err1 + } + err = setOrganizationAncestors(ctx, input.ParentId, lastId) + if err != nil { + return err + } + return err + }) + return +} + +// Edit 修改组织 +func (s *sSysOrganization) Edit(ctx context.Context, input *model.EditOrganizationInput) (err error) { + var organization1, organization2 *entity.SysOrganization + //根据ID查看组织是否存在 + organization1 = checkOrganizationId(ctx, input.Id, organization1) + organization := organization1.ParentId + organizationAnces := organization1.Ancestors + if organization1 == nil { + return gerror.New("组织不存在") + } + organization2 = checkOrganizationName(ctx, input.Name, input.Id) + if organization2 != nil { + return gerror.New("相同组织已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &organization1); err != nil { + return err + } + organization1.UpdatedBy = loginUserId + //开启事务管理 + err = dao.SysOrganization.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + _, err = dao.SysOrganization.Ctx(ctx).Data(organization1). + Where(dao.SysOrganization.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("修改失败") + } + //修改祖籍字段 + if organization != input.ParentId { + err := setAncestors(ctx, input.ParentId, input.Id) + if err != nil { + return gerror.New("祖籍修改失败") + } + lId := strconv.FormatInt(input.Id, 10) + value, _ := dao.SysOrganization.Ctx(ctx). + Fields(dao.SysOrganization.Columns().Ancestors). + WhereLike(dao.SysOrganization.Columns().Ancestors, "%"+lId+"%").Array() + if input.ParentId == -1 { + for _, v := range value { + newAncestors := strings.Replace(v.String(), organizationAnces, lId, -1) + //修改相关祖籍字段 + _, err := dao.SysOrganization.Ctx(ctx). + Data(dao.SysOrganization.Columns().Ancestors, newAncestors). + Where(dao.SysOrganization.Columns().Ancestors, v.String()).Update() + if err != nil { + return gerror.New("关联祖籍修改失败") + } + } + } else { + //查询现有的进行拼接 + ancestors, _ := dao.SysOrganization.Ctx(ctx). + Fields(dao.SysOrganization.Columns().Ancestors). + Where(dao.SysOrganization.Columns().Id, input.Id).Value() + for _, v := range value { + newAncestors := strings.Replace(ancestors.String(), lId, "", -1) + newAncestor := newAncestors + v.String() + //修改相关祖籍字段 + _, err := dao.SysOrganization.Ctx(ctx). + Data(dao.SysOrganization.Columns().Ancestors, newAncestor). + Where(dao.SysOrganization.Columns().Ancestors, v.String()). + WhereNot(dao.SysOrganization.Columns().Id, input.Id). + Update() + if err != nil { + return gerror.New("关联祖籍修改失败") + } + } + } + } + return nil + }) + return +} + +// Detail 组织详情 +func (s *sSysOrganization) Detail(ctx context.Context, id int64) (entity *entity.SysOrganization, err error) { + _ = dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().Id: id, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// Del 根据ID删除组织信息 +func (s *sSysOrganization) Del(ctx context.Context, id int64) (err error) { + var organization *entity.SysOrganization + _ = dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().Id: id, + }).Scan(&organization) + if organization == nil { + return gerror.New("ID错误") + } + //查询是否有子节点 + num, err := dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().ParentId: id, + dao.SysOrganization.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //更新组织信息 + _, err = dao.SysOrganization.Ctx(ctx). + Data(g.Map{ + dao.SysOrganization.Columns().DeletedBy: uint(loginUserId), + dao.SysOrganization.Columns().IsDeleted: 1, + }). + Where(dao.SysOrganization.Columns().Id, id). + Update() + //删除组织信息 + _, err = dao.SysOrganization.Ctx(ctx).Where(dao.SysOrganization.Columns().Id, id).Delete() + return +} + +// GetAll 获取全部组织数据 +func (s *sSysOrganization) GetAll(ctx context.Context) (data []*entity.SysOrganization, err error) { + err = dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().Status: 1, + dao.SysOrganization.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +// 修改祖籍字段 +func setOrganizationAncestors(ctx context.Context, ParentId int64, lastId int64) (err error) { + lId := strconv.FormatInt(lastId, 10) + if ParentId == -1 { //根级别,修改祖籍为自己 + _, err := dao.SysOrganization.Ctx(ctx). + Data(dao.SysOrganization.Columns().Ancestors, lId). + Where(dao.SysOrganization.Columns().Id, lastId). + Update() + if err != nil { + return gerror.New("祖籍修改失败") + } + } else { + var oldorganization *entity.SysOrganization + _ = dao.SysOrganization.Ctx(ctx). + Where(dao.SysOrganization.Columns().Id, ParentId). + Scan(&oldorganization) + _, err := dao.SysOrganization.Ctx(ctx). + Data(dao.SysOrganization.Columns().Ancestors, oldorganization.Ancestors+","+lId). + Where(dao.SysOrganization.Columns().Id, lastId). + Update() + if err != nil { + return gerror.New("祖籍修改失败") + } + } + return +} + +// Count 获取组织数量 +func (s *sSysOrganization) Count(ctx context.Context) (count int, err error) { + count, _ = dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().IsDeleted: 0, + }).Count() + return +} + +// 检查相同组织名称的数据是否存在 +func checkOrganizationName(ctx context.Context, name string, tag int64) (organization *entity.SysOrganization) { + m := dao.SysOrganization.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysOrganization.Columns().Id, tag) + } + _ = m.Where(g.Map{ + dao.SysOrganization.Columns().Name: name, + dao.SysOrganization.Columns().IsDeleted: 0, + }).Scan(&organization) + return organization +} + +// 检查指定ID的数据是否存在 +func checkOrganizationId(ctx context.Context, id int64, organization *entity.SysOrganization) *entity.SysOrganization { + _ = dao.SysOrganization.Ctx(ctx).Where(g.Map{ + dao.SysOrganization.Columns().Id: id, + dao.SysOrganization.Columns().IsDeleted: 0, + }).Scan(&organization) + return organization +} diff --git a/internal/logic/system/sys_plugins.go b/internal/logic/system/sys_plugins.go new file mode 100644 index 0000000..2c77fc7 --- /dev/null +++ b/internal/logic/system/sys_plugins.go @@ -0,0 +1,99 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysPlugins struct{} + +func sysPluginsNew() *sSysPlugins { + return &sSysPlugins{} +} +func init() { + service.RegisterSysPlugins(sysPluginsNew()) +} + +// GetSysPluginsList 获取列表数据 +func (s *sSysPlugins) GetSysPluginsList(ctx context.Context, in *model.GetSysPluginsListInput) (total, page int, list []*model.SysPluginsOutput, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysPlugins.Ctx(ctx) + + if in.KeyWord != "" { + m = m.WhereLike(dao.SysPlugins.Columns().Name, "%"+in.KeyWord+"%") + m = m.WhereLike(dao.SysPlugins.Columns().Title, "%"+in.KeyWord+"%") + m = m.WhereLike(dao.SysPlugins.Columns().Intro, "%"+in.KeyWord+"%") + } + + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = in.PageNum + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(page, in.PageSize).Order("start_time desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +// GetSysPluginsById 获取指定ID数据 +func (s *sSysPlugins) GetSysPluginsById(ctx context.Context, id int) (out *model.SysPluginsOutput, err error) { + err = dao.SysPlugins.Ctx(ctx).Where(dao.SysPlugins.Columns().Id, id).Scan(&out) + return +} + +// AddSysPlugins 添加数据 +func (s *sSysPlugins) AddSysPlugins(ctx context.Context, in model.SysPluginsAddInput) (err error) { + _, err = dao.SysPlugins.Ctx(ctx).Insert(in) + return +} + +// EditSysPlugins 修改数据 +func (s *sSysPlugins) EditSysPlugins(ctx context.Context, in model.SysPluginsEditInput) (err error) { + _, err = dao.SysPlugins.Ctx(ctx).FieldsEx(dao.SysPlugins.Columns().Id).Where(dao.SysPlugins.Columns().Id, in.Id).Update(in) + return +} + +// DeleteSysPlugins 删除数据 +func (s *sSysPlugins) DeleteSysPlugins(ctx context.Context, Ids []int) (err error) { + _, err = dao.SysPlugins.Ctx(ctx).Delete(dao.SysPlugins.Columns().Id+" in (?)", Ids) + return +} + +//SaveSysPlugins 存入插件数据,跟据插件类型与名称,数据中只保存一份 +func (s *sSysPlugins) SaveSysPlugins(ctx context.Context, in model.SysPluginsAddInput) (err error) { + var req = g.Map{ + dao.SysPlugins.Columns().Types: in.Types, + dao.SysPlugins.Columns().Name: in.Name, + } + res, err := dao.SysPlugins.Ctx(ctx).Where(req).One() + if res != nil { + _, err = dao.SysPlugins.Ctx(ctx).Data(in).Where(req).Update() + + } else { + _, err = dao.SysPlugins.Ctx(ctx).Insert(in) + } + return +} + +func (s *sSysPlugins) EditStatus(ctx context.Context, id int, status int) (err error) { + //todo 进行插件的启停 + switch status { + case 0: + + case 1: + } + _, err = dao.SysPlugins.Ctx(ctx).Data("status", status).Where(dao.SysPlugins.Columns().Id, id).Update() + return +} diff --git a/internal/logic/system/sys_plugins_config.go b/internal/logic/system/sys_plugins_config.go new file mode 100644 index 0000000..9f421f6 --- /dev/null +++ b/internal/logic/system/sys_plugins_config.go @@ -0,0 +1,131 @@ +package system + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/encoding/gyaml" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSystemPluginsConfig struct{} + +func sSystemPluginsConfigNew() *sSystemPluginsConfig { + return &sSystemPluginsConfig{} +} +func init() { + service.RegisterSystemPluginsConfig(sSystemPluginsConfigNew()) +} + +//GetPluginsConfigList 获取列表数据 +func (s *sSystemPluginsConfig) GetPluginsConfigList(ctx context.Context, in *model.GetPluginsConfigListInput) (total, page int, list []*model.PluginsConfigOutput, err error) { + err = g.Try(ctx, func(ctx context.Context) { + m := dao.SysPluginsConfig.Ctx(ctx) + total, err = m.Count() + if err != nil { + err = gerror.New("获取总行数失败") + return + } + page = in.PageNum + if in.PageSize == 0 { + in.PageSize = consts.PageSize + } + err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list) + if err != nil { + err = gerror.New("获取数据失败") + } + }) + return +} + +//GetPluginsConfigById 获取指定ID数据 +func (s *sSystemPluginsConfig) GetPluginsConfigById(ctx context.Context, id int) (out *model.PluginsConfigOutput, err error) { + err = dao.SysPluginsConfig.Ctx(ctx).Where(dao.SysPluginsConfig.Columns().Id, id).Scan(&out) + return +} + +//GetPluginsConfigByName 获取指定ID数据 +func (s *sSystemPluginsConfig) GetPluginsConfigByName(ctx context.Context, types, name string) (out *model.PluginsConfigOutput, err error) { + var reqData = g.Map{ + dao.SysPluginsConfig.Columns().Type: types, + dao.SysPluginsConfig.Columns().Name: name, + } + err = dao.SysPluginsConfig.Ctx(ctx).Where(reqData).Scan(&out) + return +} + +//AddPluginsConfig 添加数据 +func (s *sSystemPluginsConfig) AddPluginsConfig(ctx context.Context, in model.PluginsConfigAddInput) (err error) { + _, err = dao.SysPluginsConfig.Ctx(ctx).Insert(in) + return +} + +//EditPluginsConfig 修改数据 +func (s *sSystemPluginsConfig) EditPluginsConfig(ctx context.Context, in model.PluginsConfigEditInput) (err error) { + _, err = dao.SysPluginsConfig.Ctx(ctx).FieldsEx(dao.SysPluginsConfig.Columns().Id).Where(dao.SysPluginsConfig.Columns().Id, in.Id).Update(in) + return +} + +//SavePluginsConfig 更新数据,有数据就修改,没有数据就添加 +func (s *sSystemPluginsConfig) SavePluginsConfig(ctx context.Context, in model.PluginsConfigAddInput) (err error) { + var reqData = g.Map{ + dao.SysPluginsConfig.Columns().Id: in.Type, + dao.SysPluginsConfig.Columns().Id: in.Name, + } + _, err = dao.SysPluginsConfig.Ctx(ctx).Where(reqData).Save(in) + if err != nil { + return + } + err = s.updateCache(ctx, in.Type, in.Name, in.Value) + + return +} + +//DeletePluginsConfig 删除数据 +func (s *sSystemPluginsConfig) DeletePluginsConfig(ctx context.Context, Ids []int) (err error) { + _, err = dao.SysPluginsConfig.Ctx(ctx).Delete(dao.SysPluginsConfig.Columns().Id+" in (?)", Ids) + return +} + +//UpdateAllPluginsConfigCache 将插件数据更新到缓存 +func (s *sSystemPluginsConfig) UpdateAllPluginsConfigCache() (err error) { + + var dataList []*model.PluginsConfigOutput + err = dao.SysPluginsConfig.Ctx(context.TODO()).Scan(&dataList) + if err != nil { + return + } + + var ( + ctx = gctx.New() + ) + for _, datum := range dataList { + err = s.updateCache(ctx, datum.Type, datum.Name, datum.Value) + } + return +} + +func (s *sSystemPluginsConfig) updateCache(ctx context.Context, pluginsType, name, value string) (err error) { + + //缓存的key的规则是:"plugins+插件类型+插件名称 + key := "plugins" + pluginsType + name + _, err = g.Redis().Do(ctx, "SET", key, value) + + return +} + +//GetPluginsConfigData 获取列表数据 +func (s *sSystemPluginsConfig) GetPluginsConfigData(pluginType, pluginName string) (res map[interface{}]interface{}, err error) { + key := "plugins" + pluginType + pluginName + fmt.Println(key) + pcgData, err := g.Redis().Do(context.TODO(), "GET", key) + + err = gyaml.DecodeTo([]byte(pcgData.String()), &res) + + return +} diff --git a/internal/logic/system/sys_post.go b/internal/logic/system/sys_post.go new file mode 100644 index 0000000..f43c2bd --- /dev/null +++ b/internal/logic/system/sys_post.go @@ -0,0 +1,226 @@ +package system + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" + "time" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" +) + +type sSysPost struct { +} + +func sysPostNew() *sSysPost { + return &sSysPost{} +} + +func init() { + service.RegisterSysPost(sysPostNew()) +} + +// GetTree 获取全部岗位数据 +func (s *sSysPost) GetTree(ctx context.Context, postName string, postCode string, status int) (data []*model.PostOut, err error) { + postInfo, err := s.GetData(ctx, postName, postCode, status) + if postInfo != nil { + var parentNodeOut []*model.PostOut + if postInfo != nil { + //获取所有的根节点 + for _, v := range postInfo { + var parentNode *model.PostOut + if v.ParentId == -1 { + if err = gconv.Scan(v, &parentNode); err != nil { + return + } + parentNodeOut = append(parentNodeOut, parentNode) + } + } + } + data = postTree(parentNodeOut, postInfo) + if len(data) == 0 { + if err = gconv.Scan(postInfo, &data); err != nil { + return + } + if err != nil { + return + } + } + } + return +} + +// Trees Tree 生成树结构 +func postTree(parentNodeOut []*model.PostOut, data []*model.PostOut) (dataTree []*model.PostOut) { + //循环所有一级菜单 + for k, v := range parentNodeOut { + //查询所有该菜单下的所有子菜单 + for _, j := range data { + var node *model.PostOut + if j.ParentId == v.PostId { + if err := gconv.Scan(j, &node); err != nil { + return + } + parentNodeOut[k].Children = append(parentNodeOut[k].Children, node) + } + } + postTree(v.Children, data) + } + return parentNodeOut +} + +// Add 添加岗位 +func (s *sSysPost) Add(ctx context.Context, input *model.AddPostInput) (err error) { + var post *entity.SysPost + //根据名称查看角色是否存在 + post = checkPostName(ctx, input.PostName, post, 0) + if post != nil { + return gerror.New("岗位已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + post = new(entity.SysPost) + if err := gconv.Scan(input, &post); err != nil { + return err + } + post.PostCode = "G" + time.Now().Format("20060102150405") + post.IsDeleted = 0 + post.CreatedBy = uint(loginUserId) + _, err = dao.SysPost.Ctx(ctx).Data(post).Insert() + if err != nil { + return err + } + return +} + +// Edit 修改岗位 +func (s *sSysPost) Edit(ctx context.Context, input *model.EditPostInput) (err error) { + var post, post2 *entity.SysPost + //根据ID查看岗位是否存在 + post = checkPostId(ctx, input.PostId, post) + if post == nil { + return gerror.New("岗位不存在") + } + post2 = checkPostName(ctx, input.PostName, post2, input.PostId) + if post2 != nil { + return gerror.New("相同岗位已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + if err := gconv.Scan(input, &post); err != nil { + return err + } + post.UpdatedBy = uint(loginUserId) + //开启事务管理 + _, err = dao.SysPost.Ctx(ctx).Data(post). + Where(dao.SysPost.Columns().PostId, input.PostId).Update() + if err != nil { + return gerror.New("修改失败") + } + return +} + +// Detail 岗位详情 +func (s *sSysPost) Detail(ctx context.Context, postId int64) (entity *entity.SysPost, err error) { + _ = dao.SysPost.Ctx(ctx).Where(g.Map{ + dao.SysPost.Columns().PostId: postId, + }).Scan(&entity) + if entity == nil { + return nil, gerror.New("ID错误") + } + return +} + +// GetData 执行获取数据操作 +func (s *sSysPost) GetData(ctx context.Context, postName string, postCode string, status int) (data []*model.PostOut, err error) { + m := dao.SysPost.Ctx(ctx) + + //模糊查询岗位名称 + if postName != "" { + m = m.WhereLike(dao.SysPost.Columns().PostName, "%"+postName+"%") + } + if postCode != "" { + m = m.WhereLike(dao.SysPost.Columns().PostCode, "%"+postCode+"%") + } + if status != -1 { + m = m.Where(dao.SysPost.Columns().Status, status) + } + err = m.Where(dao.SysPost.Columns().IsDeleted, 0). + OrderDesc(dao.SysPost.Columns().PostSort). + Scan(&data) + if err != nil { + return + } + return +} + +// 检查相同岗位名称的数据是否存在 +func checkPostName(ctx context.Context, postName string, post *entity.SysPost, tag int64) *entity.SysPost { + m := dao.SysPost.Ctx(ctx) + if tag > 0 { + m = m.WhereNot(dao.SysPost.Columns().PostId, tag) + } + _ = m.Where(g.Map{ + dao.SysPost.Columns().PostName: postName, + dao.SysPost.Columns().IsDeleted: 0, + }).Scan(&post) + return post +} + +// Del 根据ID删除岗位信息 +func (s *sSysPost) Del(ctx context.Context, postId int64) (err error) { + var post *entity.SysPost + _ = dao.SysPost.Ctx(ctx).Where(g.Map{ + dao.SysPost.Columns().PostId: postId, + }).Scan(&post) + if post == nil { + return gerror.New("ID错误") + } + //查询是否有子节点 + num, err := dao.SysPost.Ctx(ctx).Where(g.Map{ + dao.SysPost.Columns().ParentId: postId, + dao.SysPost.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //更新岗位信息 + _, err = dao.SysPost.Ctx(ctx). + Data(g.Map{ + dao.SysPost.Columns().DeletedBy: uint(loginUserId), + dao.SysPost.Columns().IsDeleted: 1, + }).Where(dao.SysPost.Columns().PostId, postId). + Update() + //删除岗位信息 + _, err = dao.SysPost.Ctx(ctx).Where(dao.SysPost.Columns().PostId, postId). + Delete() + return +} + +// 检查指定ID的数据是否存在 +func checkPostId(ctx context.Context, PostId int64, post *entity.SysPost) *entity.SysPost { + _ = dao.SysPost.Ctx(ctx).Where(g.Map{ + dao.SysPost.Columns().PostId: PostId, + dao.SysPost.Columns().IsDeleted: 0, + }).Scan(&post) + return post +} + +// GetUsedPost 获取正常状态的岗位 +func (s *sSysPost) GetUsedPost(ctx context.Context) (list []*model.DetailPostRes, err error) { + err = g.Try(ctx, func(ctx context.Context) { + err = dao.SysPost.Ctx(ctx).Where(dao.SysPost.Columns().Status, 1). + Order(dao.SysPost.Columns().PostSort + " ASC, " + dao.SysPost.Columns().PostId + " ASC ").Scan(&list) + liberr.ErrIsNil(ctx, err, "获取岗位数据失败") + }) + return +} diff --git a/internal/logic/system/sys_role.go b/internal/logic/system/sys_role.go new file mode 100644 index 0000000..1c689dc --- /dev/null +++ b/internal/logic/system/sys_role.go @@ -0,0 +1,326 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" + "strings" +) + +type sSysRole struct { +} + +func init() { + service.RegisterSysRole(sysRoleNew()) +} + +func sysRoleNew() *sSysRole { + return &sSysRole{} +} + +// GetAll 获取所有的角色 +func (s *sSysRole) GetAll(ctx context.Context) (entity []*entity.SysRole, err error) { + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Status: 1, + dao.SysRole.Columns().IsDeleted: 0, + }).OrderAsc(dao.SysRole.Columns().ListOrder).Scan(&entity) + return +} + +func (s *sSysRole) GetTree(ctx context.Context, name string, status int) (out []*model.RoleTreeOut, err error) { + var e []*entity.SysRole + m := dao.SysRole.Ctx(ctx) + if name != "" { + m = m.WhereLike(dao.SysRole.Columns().Name, "%"+name+"%") + } + if status != -1 { + m = m.Where(dao.SysRole.Columns().Status, status) + } + m = m.Where(dao.SysRole.Columns().IsDeleted, 0) + + err = m.OrderAsc(dao.SysRole.Columns().ListOrder).Scan(&e) + + if len(e) > 0 { + out, err = GetRoleTree(e) + if err != nil { + return + } + } + return +} + +// Add 添加 +func (s *sSysRole) Add(ctx context.Context, input *model.AddRoleInput) (err error) { + var role *entity.SysRole + //根据名称查看角色是否存在 + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Name: input.Name, + dao.SysRole.Columns().IsDeleted: 0, + }).Scan(&role) + if role != nil { + return gerror.New("角色已存在,无法添加") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + role = new(entity.SysRole) + role.Name = input.Name + role.DataScope = 1 + role.ParentId = input.ParentId + role.ListOrder = input.ListOrder + role.Remark = input.Remark + role.Status = input.Status + role.IsDeleted = 0 + role.CreateBy = uint(loginUserId) + _, err = dao.SysRole.Ctx(ctx).Data(role).Insert() + if err != nil { + return err + } + return +} + +// Edit 编辑 +func (s *sSysRole) Edit(ctx context.Context, input *model.EditRoleInput) (err error) { + var role *entity.SysRole + //根据ID查询角色是否存在 + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Id: input.Id, + dao.SysRole.Columns().IsDeleted: 0, + }).Scan(&role) + if role == nil { + return gerror.New("ID错误,无法修改") + } + //查看角色名称是否存在 + var roleByName *entity.SysRole + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Name: input.Name, + dao.SysRole.Columns().IsDeleted: 0, + }).Scan(&roleByName) + if roleByName != nil && roleByName.Id != input.Id { + return gerror.New("角色已存在,无法修改") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + role.Name = input.Name + role.ParentId = input.ParentId + role.ListOrder = input.ListOrder + role.Remark = input.Remark + role.Status = input.Status + role.UpdateBy = uint(loginUserId) + _, err = dao.SysRole.Ctx(ctx).Data(role).Where(dao.SysRole.Columns().Id, input.Id).Update() + if err != nil { + return err + } + return +} + +// GetInfoById 根据ID获取角色信息 +func (s *sSysRole) GetInfoById(ctx context.Context, id uint) (entity *entity.SysRole, err error) { + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Id: id, + }).Scan(&entity) + return +} + +// DelInfoById 根据ID删除角色信息 +func (s *sSysRole) DelInfoById(ctx context.Context, id uint) (err error) { + var roleData *entity.SysRole + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Id: id, + }).Scan(&roleData) + if roleData == nil { + return gerror.New("ID错误") + } + //查询是否有子节点 + num, err := dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().ParentId: id, + dao.SysRole.Columns().IsDeleted: 0, + }).Count() + if err != nil { + return err + } + if num > 0 { + return gerror.New("请先删除子节点!") + } + loginUserId := service.Context().GetUserId(ctx) + //开启十五 + err = dao.SysRole.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + _, err = dao.SysRole.Ctx(ctx).Data(g.Map{ + dao.SysRole.Columns().DeletedBy: uint(loginUserId), + dao.SysRole.Columns().IsDeleted: 1, + }).Where(dao.SysRole.Columns().Id, id).Update() + //删除角色信息 + _, err = dao.SysRole.Ctx(ctx).Where(dao.SysRole.Columns().Id, id).Delete() + if err != nil { + return gerror.New("删除角色失败") + } + //删除与角色相绑定的用户关系 + _, err = dao.SysUserRole.Ctx(ctx).Where(dao.SysUserRole.Columns().RoleId, id).Delete() + if err != nil { + return gerror.New("解除与用户绑定关系失败") + } + //删除与角色相绑定的部门关系 + _, err = dao.SysRoleDept.Ctx(ctx).Where(dao.SysRoleDept.Columns().RoleId, id).Delete() + if err != nil { + return gerror.New("解除与部门绑定关系失败") + } + //删除角色已授权的菜单,按钮,列表 + _, err = dao.SysAuthorize.Ctx(ctx).Data(g.Map{ + dao.SysAuthorize.Columns().IsDeleted: 1, + dao.SysAuthorize.Columns().DeletedBy: loginUserId, + }).Where(dao.SysAuthorize.Columns().RoleId, id).Update() + _, err = dao.SysAuthorize.Ctx(ctx).Where(dao.SysAuthorize.Columns().RoleId, id).Delete() + return + }) + + return +} + +// GetRoleList 获取角色列表 +func (s *sSysRole) GetRoleList(ctx context.Context) (list []*model.RoleInfoRes, err error) { + cache := common.Cache() + //从缓存获取 + iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysRole, s.getRoleListFromDb, 0, consts.CacheSysAuthTag) + if iList != nil { + err = gconv.Struct(iList, &list) + } + return +} + +// 从数据库获取所有角色 +func (s *sSysRole) getRoleListFromDb(ctx context.Context) (value interface{}, err error) { + err = g.Try(ctx, func(ctx2 context.Context) { + var v []*entity.SysRole + //从数据库获取 + err = dao.SysRole.Ctx(ctx). + Order(dao.SysRole.Columns().ListOrder + " asc," + dao.SysRole.Columns().Id + " asc"). + Scan(&v) + liberr.ErrIsNil(ctx, err, "获取角色数据失败") + value = v + }) + return +} + +// GetInfoByIds 根据ID数组获取角色信息 +func (s *sSysRole) GetInfoByIds(ctx context.Context, id []int) (entity []*entity.SysRole, err error) { + err = dao.SysRole.Ctx(ctx).WhereIn(dao.SysRole.Columns().Id, id).Where(g.Map{ + dao.SysRole.Columns().Status: 1, + dao.SysRole.Columns().IsDeleted: 0, + }).Scan(&entity) + return +} + +// DataScope 角色数据授权 +func (s *sSysRole) DataScope(ctx context.Context, id int, dataScope uint, deptIds []int64) (err error) { + //判断数据范围是否为自定义数据返回 + if dataScope == 2 { + if deptIds == nil { + return gerror.New("请选择部门信息") + } + } + //查询角色ID是否存在 + var role *entity.SysRole + err = dao.SysRole.Ctx(ctx).Where(dao.SysRole.Columns().Id, id).Scan(&role) + if role == nil { + return gerror.New("角色不存在,无法授权") + } + if role != nil && role.Status == 0 { + return gerror.New("角色已禁用,无法授权") + } + //获取登录用户ID + loginUserId := service.Context().GetUserId(ctx) + + //开启事务 + err = g.Try(ctx, func(ctx context.Context) { + //修改角色数据范围 + role.DataScope = dataScope + role.UpdateBy = uint(loginUserId) + _, editErr := dao.SysRole.Ctx(ctx).Data(role).Where(dao.SysRole.Columns().Id, id).Update() + if editErr != nil { + err = gerror.New("修改角色信息失败") + return + } + //判断数据范围是否为自定义数据范围 + if dataScope == 2 { + //自定义数据返回 + //根据部门ID数据获取部门信息 + var deptInfo []*entity.SysDept + err = dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().IsDeleted: 0, + dao.SysDept.Columns().Status: 1, + }).WhereIn(dao.SysDept.Columns().DeptId, deptIds).Scan(&deptInfo) + if deptInfo == nil { + err = gerror.New("部门ID错误") + } + //删除原有绑定关系 + _, delErr := dao.SysRoleDept.Ctx(ctx).Where(dao.SysRoleDept.Columns().RoleId, id).Delete() + if delErr != nil { + err = gerror.New("解决绑定关系失败") + return + } + //封装角色与部门绑定管理 + var roleDepts []*entity.SysRoleDept + for _, dept := range deptInfo { + var roleDept = new(entity.SysRoleDept) + roleDept.RoleId = int64(id) + roleDept.DeptId = dept.DeptId + roleDepts = append(roleDepts, roleDept) + } + //添加绑定关系 + _, addErr := dao.SysRoleDept.Ctx(ctx).Data(roleDepts).Insert() + if addErr != nil { + err = gerror.New("绑定关系失败") + return + } + } + return + }) + return +} + +func (s *sSysRole) GetAuthorizeById(ctx context.Context, id int) (menuIds []string, menuButtonIds []string, menuColumnIds []string, menuApiIds []string, err error) { + var e *entity.SysRole + err = dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Id: id, + }).Scan(&e) + if err != nil { + return + } + if e == nil { + err = gerror.New("ID错误") + return + } + if e.IsDeleted == 1 { + err = gerror.New("角色已删除,无法查询") + return + } + if e.Status == 0 { + err = gerror.New("角色已禁用,无法查询") + return + } + //根据角色ID获取权限信息 + authorizeInfo, err := service.SysAuthorize().GetInfoByRoleId(ctx, id) + if err != nil { + return + } + for _, authorize := range authorizeInfo { + if strings.EqualFold(authorize.ItemsType, consts.Menu) { + menuIds = append(menuIds, gconv.String(authorize.ItemsId)+"_"+gconv.String(authorize.IsCheckAll)) + } else if strings.EqualFold(authorize.ItemsType, consts.Button) { + menuButtonIds = append(menuButtonIds, gconv.String(authorize.ItemsId)+"_"+gconv.String(authorize.IsCheckAll)) + } else if strings.EqualFold(authorize.ItemsType, consts.Column) { + menuColumnIds = append(menuColumnIds, gconv.String(authorize.ItemsId)+"_"+gconv.String(authorize.IsCheckAll)) + } else if strings.EqualFold(authorize.ItemsType, consts.Api) { + menuApiIds = append(menuApiIds, gconv.String(authorize.ItemsId)+"_"+gconv.String(authorize.IsCheckAll)) + } + } + return +} diff --git a/internal/logic/system/sys_role_dept.go b/internal/logic/system/sys_role_dept.go new file mode 100644 index 0000000..7f0a546 --- /dev/null +++ b/internal/logic/system/sys_role_dept.go @@ -0,0 +1,41 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysRoleDept struct { +} + +func init() { + service.RegisterSysRoleDept(sysRoleDeptNew()) +} + +func sysRoleDeptNew() *sSysRoleDept { + return &sSysRoleDept{} +} + +//GetInfoByRoleId 根据角色ID获取信息 +func (s *sSysRoleDept) GetInfoByRoleId(ctx context.Context, roleId int) (data []*entity.SysRoleDept, err error) { + var roleDepts []*entity.SysRoleDept + err = dao.SysRoleDept.Ctx(ctx).Where(dao.SysRoleDept.Columns().RoleId, roleId).Scan(&roleDepts) + if roleDepts != nil { + for _, roleDept := range roleDepts { + //判断角色是否为已启动并未删除状态 + num, _ := dao.SysDept.Ctx(ctx).Where(g.Map{ + dao.SysDept.Columns().DeptId: roleDept.DeptId, + dao.SysDept.Columns().Status: 1, + dao.SysDept.Columns().IsDeleted: 0, + }).Count() + + if num > 0 { + data = append(data, roleDept) + } + } + } + return +} diff --git a/internal/logic/system/sys_token.go b/internal/logic/system/sys_token.go new file mode 100644 index 0000000..1dc5898 --- /dev/null +++ b/internal/logic/system/sys_token.go @@ -0,0 +1,73 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gctx" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/tiger1103/gfast-token/gftoken" + "sync" +) + +type sSysToken struct { +} + +func init() { + service.RegisterSysToken(sysTokenNew()) +} + +func sysTokenNew() *sSysToken { + return &sSysToken{} +} + +type gft struct { + options *model.TokenOptions + lock *sync.Mutex +} + +var gftService = &gft{ + options: nil, + lock: &sync.Mutex{}, +} + +func (m *sSysToken) GenerateToken(ctx context.Context, key string, data interface{}) (keys string, err error) { + keys, err = GfToken().GenerateToken(ctx, key, data) + return keys, err +} + +func (m *sSysToken) ParseToken(r *ghttp.Request) (*gftoken.CustomClaims, error) { + return GfToken().ParseToken(r) +} + +func GfToken() *gftoken.GfToken { + ctx := gctx.New() + err := g.Cfg().MustGet(ctx, "gfToken").Struct(&gftService.options) + if err != nil { + panic(err.Error()) + } + prefix := g.Cfg().MustGet(ctx, "system.cache.prefix").String() + m := g.Cfg().MustGet(ctx, "system.cache.model").String() + return GfTokenOption(gftService.options, prefix, m) +} + +func GfTokenOption(options *model.TokenOptions, prefix string, model string) *gftoken.GfToken { + var fun gftoken.OptionFunc + if model == consts.CacheModelRedis { + fun = gftoken.WithGRedis() + } else { + fun = gftoken.WithGCache() + } + + gfToken := gftoken.NewGfToken( + gftoken.WithCacheKey(prefix), + gftoken.WithTimeout(options.Timeout), + gftoken.WithMaxRefresh(options.MaxRefresh), + gftoken.WithMultiLogin(options.MultiLogin), + gftoken.WithExcludePaths(options.ExcludePaths), + fun, + ) + return gfToken +} diff --git a/internal/logic/system/sys_user.go b/internal/logic/system/sys_user.go new file mode 100644 index 0000000..0abfa4b --- /dev/null +++ b/internal/logic/system/sys_user.go @@ -0,0 +1,725 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcache" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/grand" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/liberr" + "github.com/sagoo-cloud/sagooiot/utility/utils" + "strings" + "time" +) + +type sSysUser struct { +} + +func init() { + service.RegisterSysUser(sysUserNew()) +} + +func sysUserNew() *sSysUser { + return &sSysUser{} +} + +// GetUserByUsername 通过用户名获取用户信息 +func (s *sSysUser) GetUserByUsername(ctx context.Context, userName string) (data *entity.SysUser, err error) { + var user *entity.SysUser + err = dao.SysUser.Ctx(ctx).Fields(user).Where(dao.SysUser.Columns().UserName, userName).Scan(&user) + if user == nil { + return nil, gerror.New("账号不存在,请重新输入!") + } + if user.IsDeleted == 1 { + return nil, gerror.New("该账号已删除") + } + if user.Status == 0 { + return nil, gerror.New("该账号已禁用") + } + if user.Status == 2 { + return nil, gerror.New("该账号未验证") + } + return user, nil +} + +// GetAdminUserByUsernamePassword 根据用户名和密码获取用户信息 +func (s *sSysUser) GetAdminUserByUsernamePassword(ctx context.Context, userName string, password string) (user *entity.SysUser, err error) { + //判断账号是否存在 + user, err = s.GetUserByUsername(ctx, userName) + if err != nil { + return nil, err + } + //验证密码是否正确 + if utils.EncryptPassword(password, user.UserSalt) != user.UserPassword { + err = gerror.New("密码错误") + return + } + return user, nil +} + +// UpdateLoginInfo 更新用户登录信息 +func (s *sSysUser) UpdateLoginInfo(ctx context.Context, id uint64, ip string) (err error) { + err = g.Try(ctx, func(ctx context.Context) { + _, err = dao.SysUser.Ctx(ctx).WherePri(id).Update(g.Map{ + dao.SysUser.Columns().LastLoginIp: ip, + dao.SysUser.Columns().LastLoginTime: gtime.Now(), + }) + liberr.ErrIsNil(ctx, err, "更新用户登录信息失败") + }) + return +} + +// UserList 用户列表 +func (s *sSysUser) UserList(ctx context.Context, input *model.UserListDoInput) (total int, out []*model.UserListOut, err error) { + m := dao.SysUser.Ctx(ctx) + if input.KeyWords != "" { + keyWords := "%" + input.KeyWords + "%" + m = m.Where("user_name like ? or user_nickname like ?", keyWords, keyWords) + } + if input.DeptId != 0 { + //m = m.Where(dao.SysUser.Columns().DeptId, req.DeptId) + deptIds, _ := s.getSearchDeptIds(ctx, gconv.Int64(input.DeptId)) + m = m.Where("dept_id in (?)", deptIds) + } + if input.UserName != "" { + m = m.Where(dao.SysUser.Columns().UserName, input.UserName) + } + if input.Status != -1 { + m = m.Where(dao.SysUser.Columns().Status, input.Status) + } + if input.Mobile != "" { + m = m.WhereLike(dao.SysUser.Columns().Mobile, "%"+input.Mobile+"%") + } + if len(input.DateRange) > 0 { + m = m.Where("created_at >=? AND created_at ", input.DateRange[0], gtime.NewFromStrFormat(input.DateRange[1], "Y-m-d").AddDate(0, 0, 1)) + } + m = m.Where(dao.SysUser.Columns().IsDeleted, 0) + //获取总数 + total, err = m.Count() + if err != nil { + err = gerror.New("获取数据失败") + return + } + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.DefaultPageSize + } + //获取用户信息 + err = m.Page(input.PageNum, input.PageSize).OrderDesc(dao.SysUser.Columns().CreatedAt).Scan(&out) + if err != nil { + err = gerror.New("获取用户列表失败") + } + + deptIds := g.Slice{} + for _, v := range out { + deptIds = append(deptIds, v.DeptId) + } + deptData, _ := GetDeptNameDict(ctx, deptIds) + for _, v := range out { + err = gconv.Scan(deptData[v.DeptId], &v.Dept) + v.RolesNames = getUserRoleName(ctx, gconv.Int(v.Id)) + } + return +} + +func getUserRoleName(ctx context.Context, userId int) (rolesNames string) { + + rolesData, _ := gcache.Get(ctx, "RoleListAtName"+gconv.String(userId)) + if rolesData != nil { + rolesNames = rolesData.String() + return + } + + var roleIds []int + //查询用户角色 + userRoleInfo, _ := service.SysUserRole().GetInfoByUserId(ctx, userId) + if userRoleInfo != nil { + for _, userRole := range userRoleInfo { + roleIds = append(roleIds, userRole.RoleId) + } + } + if roleIds != nil { + //获取所有的角色信息 + roleInfo, _ := service.SysRole().GetInfoByIds(ctx, roleIds) + var roleNames []string + if roleInfo != nil { + for _, role := range roleInfo { + roleNames = append(roleNames, role.Name) + } + rolesNames = strings.Join(roleNames, ",") + + //放入缓存 + effectiveTime := time.Minute * 5 + _, _ = gcache.SetIfNotExist(ctx, "RoleListAtName"+gconv.String(userId), rolesNames, effectiveTime) + + return + + } + } + + return "" +} + +// Add 添加 +func (s *sSysUser) Add(ctx context.Context, input *model.AddUserInput) (err error) { + //判断账户是否存在 + num, _ := dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().UserName: input.UserName, + dao.SysUser.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return gerror.New("账户已存在") + } + num, _ = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Mobile: input.Mobile, + dao.SysUser.Columns().IsDeleted: 0, + }).Count() + if num > 0 { + return gerror.New("手机号已存在") + } + //开启事务管理 + err = dao.SysUser.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + //添加用户 + var sysUser *entity.SysUser + if err = gconv.Scan(input, &sysUser); err != nil { + return err + } + //创建用户密码 + sysUser.UserSalt = grand.S(10) + sysUser.UserPassword = utils.EncryptPassword(input.UserPassword, sysUser.UserSalt) + //初始化为未删除 + sysUser.IsDeleted = 0 + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + sysUser.CreateBy = uint(loginUserId) + //添加用户信息 + lastInsertId, err := dao.SysUser.Ctx(ctx).Data(sysUser).InsertAndGetId() + if err != nil { + return gerror.New("添加用户失败") + } + err = BindUserAndPost(ctx, int(lastInsertId), input.PostIds) + + return err + }) + return +} + +func (s *sSysUser) Edit(ctx context.Context, input *model.EditUserInput) (err error) { + //根据ID获取用户信息 + var sysUser *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, input.Id).Scan(&sysUser) + if sysUser == nil { + return gerror.New("Id错误") + } + if sysUser.IsDeleted == 1 { + return gerror.New("该用户已删除") + } + + //判断账户是否存在 + var sysUserByUserName *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().UserName: input.UserName, + dao.SysUser.Columns().IsDeleted: 0, + }).Scan(&sysUserByUserName) + if sysUserByUserName != nil && sysUserByUserName.Id != input.Id { + return gerror.New("账户已存在") + } + //判断手机号是否存在 + var sysUserByMobile *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Mobile: input.Mobile, + dao.SysUser.Columns().IsDeleted: 0, + }).Scan(&sysUserByMobile) + if sysUserByMobile != nil && sysUserByMobile.Id != input.Id { + return gerror.New("手机号已存在") + } + //开启事务管理 + err = dao.SysUser.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) (err error) { + //编辑用户 + sysUser.UserNickname = input.UserNickname + sysUser.DeptId = input.DeptId + sysUser.Mobile = input.Mobile + sysUser.Status = input.Status + sysUser.Address = input.Address + sysUser.Avatar = input.Avatar + sysUser.Birthday = input.Birthday + sysUser.Describe = input.Describe + sysUser.UserTypes = input.UserTypes + sysUser.UserEmail = input.UserEmail + sysUser.Sex = input.Sex + sysUser.IsAdmin = input.IsAdmin + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + sysUser.UpdateBy = uint(loginUserId) + //编辑用户信息 + _, err = dao.SysUser.Ctx(ctx).Data(sysUser).Where(dao.SysUser.Columns().Id, input.Id).Update() + if err != nil { + return gerror.New("编辑用户失败") + } + //删除原有用户与岗位绑定管理 + _, err = dao.SysUserPost.Ctx(ctx).Where(dao.SysUserPost.Columns().UserId, input.Id).Delete() + if err != nil { + return gerror.New("删除用户与岗位绑定关系失败") + } + + err = BindUserAndPost(ctx, int(input.Id), input.PostIds) + + //删除原有用户与角色绑定管理 + _, err = dao.SysUserRole.Ctx(ctx).Where(dao.SysUserRole.Columns().UserId, input.Id).Delete() + if err != nil { + return gerror.New("删除用户与角色绑定关系失败") + } + + err = BindUserAndRole(ctx, int(input.Id), input.RoleIds) + return err + }) + return +} + +// BindUserAndPost 添加用户与岗位绑定关系 +func BindUserAndPost(ctx context.Context, userId int, postIds []int) (err error) { + if len(postIds) > 0 { + var sysUserPosts []*entity.SysUserPost + //查询用户与岗位是否存在 + for _, postId := range postIds { + var sysUserPost *entity.SysUserPost + err = dao.SysUserPost.Ctx(ctx).Where(g.Map{ + dao.SysUserPost.Columns().UserId: userId, + dao.SysUserPost.Columns().PostId: postId, + }).Scan(&sysUserPost) + + if sysUserPost == nil { + //添加用户与岗位绑定管理 + sysUserPost = new(entity.SysUserPost) + sysUserPost.UserId = userId + sysUserPost.PostId = postId + sysUserPosts = append(sysUserPosts, sysUserPost) + } + } + _, err = dao.SysUserPost.Ctx(ctx).Data(sysUserPosts).Insert() + if err != nil { + return gerror.New("绑定岗位失败") + } + } + return +} + +// BindUserAndRole 添加用户与角色绑定关系 +func BindUserAndRole(ctx context.Context, userId int, roleIds []int) (err error) { + if len(roleIds) > 0 { + var sysUserRoles []*entity.SysUserRole + //查询用户与角色是否存在 + for _, roleId := range roleIds { + var sysUserRole *entity.SysUserRole + err = dao.SysUserRole.Ctx(ctx).Where(g.Map{ + dao.SysUserRole.Columns().UserId: userId, + dao.SysUserRole.Columns().RoleId: roleId, + }).Scan(&sysUserRole) + + if sysUserRole == nil { + //添加用户与角色绑定管理 + sysUserRole = new(entity.SysUserRole) + sysUserRole.UserId = userId + sysUserRole.RoleId = roleId + sysUserRoles = append(sysUserRoles, sysUserRole) + } + } + _, err = dao.SysUserRole.Ctx(ctx).Data(sysUserRoles).Insert() + if err != nil { + return gerror.New("绑定角色失败") + } + } + return +} + +// GetUserById 根据ID获取用户信息 +func (s *sSysUser) GetUserById(ctx context.Context, id uint) (out *model.UserInfoOut, err error) { + var e *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + dao.SysUser.Columns().IsDeleted: 0, + }).Scan(&e) + if err != nil { + return + } + if e != nil { + if err = gconv.Scan(e, &out); err != nil { + return + } + + //获取用户角色ID + userRoleInfo, userRoleErr := service.SysUserRole().GetInfoByUserId(ctx, int(e.Id)) + if userRoleErr != nil { + return nil, userRoleErr + } + if userRoleInfo != nil { + var roleIds []int + for _, userRole := range userRoleInfo { + roleIds = append(roleIds, userRole.RoleId) + } + out.RoleIds = roleIds + } + //获取用户岗位ID + userPostInfo, userPostErr := service.SysUserPost().GetInfoByUserId(ctx, int(e.Id)) + if userPostErr != nil { + return nil, userPostErr + } + if userPostInfo != nil { + var postIds []int + for _, userPost := range userPostInfo { + postIds = append(postIds, userPost.PostId) + } + out.PostIds = postIds + } + } + + return +} + +// DelInfoById 根据ID删除信息 +func (s *sSysUser) DelInfoById(ctx context.Context, id uint) (err error) { + var sysUser *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Scan(&sysUser) + if sysUser == nil { + err = gerror.New("ID错误") + return + } + if sysUser.IsDeleted == 1 { + return gerror.New("用户已删除,无须重复删除") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + _, err = dao.SysUser.Ctx(ctx).Data(g.Map{ + dao.SysUser.Columns().IsDeleted: 1, + dao.SysUser.Columns().DeletedBy: loginUserId, + }).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Update() + //删除用户 + _, err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Delete() + if err != nil { + return gerror.New("删除用户失败") + } + return +} + +// ResetPassword 重置密码 +func (s *sSysUser) ResetPassword(ctx context.Context, id uint, userPassword string) (err error) { + var sysUser *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Scan(&sysUser) + if sysUser == nil { + err = gerror.New("ID错误") + return + } + if sysUser.Status == 0 { + return gerror.New("用户已禁用,无法重置密码") + } + if sysUser.IsDeleted == 1 { + return gerror.New("用户已删除,无法重置密码") + } + + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + //判断当前登录用户是否为超级管理员角色 + var isSuperAdmin = false + var sysUserRoles []*entity.SysUserRole + err = dao.SysUserRole.Ctx(ctx).Where(dao.SysUserRole.Columns().UserId, loginUserId).Scan(&sysUserRoles) + for _, sysUserRole := range sysUserRoles { + if sysUserRole.RoleId == 1 { + isSuperAdmin = true + break + } + } + if !isSuperAdmin { + return gerror.New("无重置密码权限") + } + + sysUser.UserSalt = grand.S(10) + sysUser.UserPassword = utils.EncryptPassword(userPassword, sysUser.UserSalt) + sysUser.UpdateBy = uint(loginUserId) + _, err = dao.SysUser.Ctx(ctx).Data(sysUser).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Update() + if err != nil { + return gerror.New("重置密码失败") + } + return +} + +// EditUserStatus 修改用户状态 +func (s *sSysUser) EditUserStatus(ctx context.Context, id uint, status uint) (err error) { + var sysUser *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Scan(&sysUser) + if sysUser == nil { + err = gerror.New("ID错误") + return + } + if sysUser.Status == status { + return gerror.New("无须重复修改状态") + } + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + sysUser.Status = status + sysUser.UpdateBy = uint(loginUserId) + _, err = dao.SysUser.Ctx(ctx).Data(sysUser).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Update() + if err != nil { + return gerror.New("修改状态失败") + } + return +} + +// 获取搜索的部门ID数组 +func (s *sSysUser) getSearchDeptIds(ctx context.Context, deptId int64) (deptIds []int64, err error) { + err = g.Try(ctx, func(ctx context.Context) { + deptAll, e := sysDeptNew().GetFromCache(ctx) + liberr.ErrIsNil(ctx, e) + deptWithChildren := sysDeptNew().FindSonByParentId(deptAll, gconv.Int64(deptId)) + deptIds = make([]int64, len(deptWithChildren)) + for k, v := range deptWithChildren { + deptIds[k] = v.DeptId + } + deptIds = append(deptIds, deptId) + }) + return +} + +func GetDeptNameDict(ctx context.Context, ids g.Slice) (dict map[int64]model.DetailDeptRes, err error) { + var depts []model.DetailDeptRes + dict = make(map[int64]model.DetailDeptRes) + err = dao.SysDept.Ctx(ctx).Where(dao.SysDept.Columns().DeptId, ids).Scan(&depts) + for _, d := range depts { + dict[d.DeptId] = d + } + return +} + +// GetUserByIds 根据ID数据获取用户信息 +func (s *sSysUser) GetUserByIds(ctx context.Context, id []int) (data []*entity.SysUser, err error) { + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().IsDeleted: 0, + }).WhereIn(dao.SysUser.Columns().Id, id).Scan(&data) + return +} + +// GetAll 获取所有用户信息 +func (s *sSysUser) GetAll(ctx context.Context) (data []*entity.SysUser, err error) { + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().IsDeleted: 0, + }).Scan(&data) + return +} + +func (s *sSysUser) CurrentUser(ctx context.Context) (userInfoOut *model.UserInfoOut, menuTreeOut []*model.UserMenuTreeOut, err error) { + //获取当前登录用户信息 + loginUserId := service.Context().GetUserId(ctx) + if loginUserId == 0 { + err = gerror.New("无登录用户信息,请先登录!") + return + } + //获取当前登录用户信息 + userInfo, err := service.SysUser().GetUserById(ctx, uint(loginUserId)) + if err = gconv.Scan(userInfo, &userInfoOut); err != nil { + return + } + + //根据当前登录用户ID查询用户角色信息 + userRoleInfo, err := service.SysUserRole().GetInfoByUserId(ctx, loginUserId) + if userRoleInfo == nil { + err = gerror.New("用户无权限,禁止访问") + return + } + var isSuperAdmin = false + var roleIds []int + //获取角色ID + for _, role := range userRoleInfo { + if role.RoleId == 1 { + isSuperAdmin = true + } + roleIds = append(roleIds, role.RoleId) + } + if isSuperAdmin { + //获取所有的菜单 + //根据菜单ID数组获取菜单列表信息 + userMenuTreeRes, menuTreeError := GetMenuInfo(ctx, nil) + if menuTreeError != nil { + err = menuTreeError + return + } + var menuIds []int + //获取菜单绑定的按钮信息 + for _, userMenu := range userMenuTreeRes { + menuIds = append(menuIds, int(userMenu.Id)) + } + //获取所有的按钮 + userMenuTreeRes, userItemsTypeTreeErr := GetUserItemsTypeTreeOut(ctx, menuIds, consts.Button, userMenuTreeRes) + if userItemsTypeTreeErr != nil { + err = userItemsTypeTreeErr + return + } + //获取所有的列表 + userMenuTreeRes, userItemsTypeTreeErr = GetUserItemsTypeTreeOut(ctx, menuIds, consts.Column, userMenuTreeRes) + if userItemsTypeTreeErr != nil { + err = userItemsTypeTreeErr + return + } + //获取所有的接口 + userMenuTreeRes, userItemsTypeTreeErr = GetUserItemsTypeTreeOut(ctx, menuIds, consts.Api, userMenuTreeRes) + if userItemsTypeTreeErr != nil { + err = userItemsTypeTreeErr + return + } + + //对菜单进行树状重组 + menuTreeOut = GetUserMenuTree(userMenuTreeRes) + return + } else { + //根据角色ID获取菜单配置 + authorizeInfo, authorizeErr := service.SysAuthorize().GetInfoByRoleIds(ctx, roleIds) + if authorizeErr != nil { + return + } + if authorizeInfo == nil { + authorizeErr = gerror.New("无权限配置,请联系管理员") + return + } + //菜单Ids + var menuIds []int + //按钮Ids + var menuButtonIds []int + //列表Ids + var menuColumnIds []int + //API Ids + var menuApiIds []int + for _, authorize := range authorizeInfo { + if strings.EqualFold(authorize.ItemsType, consts.Menu) { + menuIds = append(menuIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Button) { + menuButtonIds = append(menuButtonIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Column) { + menuColumnIds = append(menuColumnIds, authorize.ItemsId) + } else if strings.EqualFold(authorize.ItemsType, consts.Api) { + menuApiIds = append(menuApiIds, authorize.ItemsId) + } + } + //根据菜单ID数组获取菜单列表信息 + menuInfo, menuErr := service.SysMenu().GetInfoByMenuIds(ctx, menuIds) + if menuErr != nil { + return + } + if menuInfo == nil { + err = gerror.New("未配置菜单, 请联系系统管理员") + return + } + //根据按钮ID数组获取按钮信息 + menuButtonInfo, menuButtonErr := service.SysMenuButton().GetInfoByButtonIds(ctx, menuButtonIds) + if menuButtonErr != nil { + return + } + //根据列表字段ID数据获取字段信息 + menuColumnInfo, menuColumnErr := service.SysMenuColumn().GetInfoByColumnIds(ctx, menuColumnIds) + if menuColumnErr != nil { + return + } + //根据菜单接口ID数组获取接口信息 + menuApiInfo, menuApiErr := service.SysMenuApi().GetInfoByIds(ctx, menuApiIds) + if menuApiErr != nil { + return + } + /*if menuApiInfo == nil { + err = gerror.New("未配置相关接口访问权限, 请联系系统管理员") + return + }*/ + if err != nil { + return + } + + var userMenuTreeOut []*model.UserMenuTreeOut + + for _, menu := range menuInfo { + var userMenuTree *model.UserMenuTreeOut + if err = gconv.Scan(menu, &userMenuTree); err != nil { + return + } + + //获取菜单按钮权限 + if menuButtonInfo != nil { + menuButtonTreeData, _ := GetUserMenuButton(int(menu.Id), menuButtonInfo) + userMenuTree.Button = append(userMenuTree.Button, menuButtonTreeData...) + } + + //获取列表权限 + if menuColumnInfo != nil { + menuColumnTreeData, _ := GetUserMenuColumn(int(menu.Id), menuColumnInfo) + userMenuTree.Column = append(userMenuTree.Column, menuColumnTreeData...) + } + + //获取接口权限 + if menuApiIds != nil { + //获取相关接口ID + var apiIds []int + for _, menuApi := range menuApiInfo { + if menuApi.MenuId == int(menu.Id) { + apiIds = append(apiIds, menuApi.ApiId) + } + } + //获取相关接口信息 + apiInfo, _ := service.SysApi().GetInfoByIds(ctx, apiIds) + if apiInfo != nil { + var apiInfoOut []*model.UserApiOut + if err = gconv.Scan(apiInfo, &apiInfoOut); err != nil { + return + } + userMenuTree.Api = append(userMenuTree.Api, apiInfoOut...) + } + } + userMenuTreeOut = append(userMenuTreeOut, userMenuTree) + } + + //对菜单进行树状重组 + menuTreeOut = GetUserMenuTree(userMenuTreeOut) + return + } +} + +// EditUserAvatar 修改用户头像 +func (s *sSysUser) EditUserAvatar(ctx context.Context, id uint, avatar string) (err error) { + var sysUser *entity.SysUser + err = dao.SysUser.Ctx(ctx).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Scan(&sysUser) + if sysUser == nil { + err = gerror.New("ID错误") + return + } + sysUser.Avatar = avatar + //获取当前登录用户ID + loginUserId := service.Context().GetUserId(ctx) + sysUser.UpdateBy = uint(loginUserId) + _, err = dao.SysUser.Ctx(ctx).Data(sysUser).Where(g.Map{ + dao.SysUser.Columns().Id: id, + }).Update() + if err != nil { + return gerror.New("修改头像失败") + } + return +} diff --git a/internal/logic/system/sys_user_online.go b/internal/logic/system/sys_user_online.go new file mode 100644 index 0000000..37156f1 --- /dev/null +++ b/internal/logic/system/sys_user_online.go @@ -0,0 +1,110 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/grpool" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/logic/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysUserOnline struct { +} + +func init() { + service.RegisterSysUserOnline(sysUserOnlineNew()) +} + +func sysUserOnlineNew() *sSysUserOnline { + return &sSysUserOnline{} +} + +func (s *sSysUserOnline) Invoke(ctx context.Context, data *entity.SysUserOnline) { + pool := grpool.New(100) + if err := pool.Add(ctx, func(ctx context.Context) { + //写入用户在线 + s.Add(ctx, data) + }, + ); err != nil { + g.Log().Debug(ctx, err.Error()) + } +} + +// Add 记录用户在线 +func (s *sSysUserOnline) Add(ctx context.Context, data *entity.SysUserOnline) { + _, err := dao.SysUserOnline.Ctx(ctx).Data(data).Save() + if err != nil { + g.Log().Error(ctx, err) + } +} + +// DelByToken 根据token删除信息 +func (s *sSysUserOnline) DelByToken(ctx context.Context, token string) (err error) { + _, err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Token, token).Delete() + if err != nil { + return gerror.New("退出失败") + } + return +} + +// GetInfoByToken 根据token获取 +func (s *sSysUserOnline) GetInfoByToken(ctx context.Context, token string) (data *entity.SysUserOnline, err error) { + err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Token, token).Scan(&data) + return +} + +// DelByIds 根据IDS删除信息 +func (s *sSysUserOnline) DelByIds(ctx context.Context, ids []uint) (err error) { + _, err = dao.SysUserOnline.Ctx(ctx).WhereIn(dao.SysUserOnline.Columns().Id, ids).Delete() + if err != nil { + return gerror.New("删除失败") + } + return +} + +func (s *sSysUserOnline) GetAll(ctx context.Context) (data []*entity.SysUserOnline, err error) { + err = dao.SysUserOnline.Ctx(ctx).Scan(&data) + return +} + +// UserOnlineList 在线用户列表 +func (s *sSysUserOnline) UserOnlineList(ctx context.Context, input *model.UserOnlineDoListInput) (total int, out []*model.UserOnlineListOut, err error) { + m := dao.SysUserOnline.Ctx(ctx) + //获取总数 + total, err = m.Count() + if err != nil { + err = gerror.New("获取数据失败") + return + } + if input.PageNum == 0 { + input.PageNum = 1 + } + if input.PageSize == 0 { + input.PageSize = consts.DefaultPageSize + } + //获取在线用户信息 + err = m.Page(input.PageNum, input.PageSize).OrderDesc(dao.SysUser.Columns().CreatedAt).Scan(&out) + if err != nil { + err = gerror.New("获取在线用户列表失败") + return + } + return +} + +func (s *sSysUserOnline) UserOnlineStrongBack(ctx context.Context, id int) (err error) { + var userOnline *entity.SysUserOnline + err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Id, id).Scan(&userOnline) + if userOnline == nil { + return gerror.New("ID错误") + } + //删除缓存信息 + common.Cache().Remove(ctx, userOnline.Key) + //删除在线用户 + _, err = dao.SysUserOnline.Ctx(ctx).Where(dao.SysUserOnline.Columns().Id, id).Delete() + return +} diff --git a/internal/logic/system/sys_user_post.go b/internal/logic/system/sys_user_post.go new file mode 100644 index 0000000..6b48b4d --- /dev/null +++ b/internal/logic/system/sys_user_post.go @@ -0,0 +1,41 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysUserPost struct { +} + +func init() { + service.RegisterSysUserPost(sysUserPostNew()) +} + +func sysUserPostNew() *sSysUserPost { + return &sSysUserPost{} +} + +//GetInfoByUserId 根据用户ID获取信息 +func (s *sSysUserPost) GetInfoByUserId(ctx context.Context, userId int) (data []*entity.SysUserPost, err error) { + var userPost []*entity.SysUserPost + err = dao.SysUserPost.Ctx(ctx).Where(dao.SysUserPost.Columns().UserId, userId).Scan(&userPost) + if userPost != nil { + for _, post := range userPost { + //判断岗位是否为已启动并未删除状态 + num, _ := dao.SysPost.Ctx(ctx).Where(g.Map{ + dao.SysPost.Columns().PostId: post.PostId, + dao.SysPost.Columns().Status: 1, + dao.SysPost.Columns().IsDeleted: 0, + }).Count() + + if num > 0 { + data = append(data, post) + } + } + } + return +} diff --git a/internal/logic/system/sys_user_role.go b/internal/logic/system/sys_user_role.go new file mode 100644 index 0000000..43349a0 --- /dev/null +++ b/internal/logic/system/sys_user_role.go @@ -0,0 +1,41 @@ +package system + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/dao" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "github.com/sagoo-cloud/sagooiot/internal/service" +) + +type sSysUserRole struct { +} + +func init() { + service.RegisterSysUserRole(sysUserRoleNew()) +} + +func sysUserRoleNew() *sSysUserRole { + return &sSysUserRole{} +} + +//GetInfoByUserId 根据用户ID获取信息 +func (s *sSysUserRole) GetInfoByUserId(ctx context.Context, userId int) (data []*entity.SysUserRole, err error) { + var userRole []*entity.SysUserRole + err = dao.SysUserRole.Ctx(ctx).Where(dao.SysUserRole.Columns().UserId, userId).Scan(&userRole) + if userRole != nil { + for _, role := range userRole { + //判断角色是否为已启动并未删除状态 + num, _ := dao.SysRole.Ctx(ctx).Where(g.Map{ + dao.SysRole.Columns().Id: role.RoleId, + dao.SysRole.Columns().Status: 1, + dao.SysRole.Columns().IsDeleted: 0, + }).Count() + + if num > 0 { + data = append(data, role) + } + } + } + return +} diff --git a/internal/logic/tdengine/td_engine.go b/internal/logic/tdengine/td_engine.go new file mode 100644 index 0000000..4945ace --- /dev/null +++ b/internal/logic/tdengine/td_engine.go @@ -0,0 +1,292 @@ +package tdengine + +import ( + "context" + "database/sql" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "time" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + _ "github.com/taosdata/driver-go/v3/taosRestful" + //_ "github.com/taosdata/driver-go/v3/taosSql" //原生驱动 +) + +type sTdEngine struct { +} + +func tdEngineNew() *sTdEngine { + return &sTdEngine{} +} + +func init() { + service.RegisterTdEngine(tdEngineNew()) + + name, _ := g.Cfg().Get(context.TODO(), "tdengine.dbName") + if name.String() != "" { + dbName = name.String() + } +} + +// 数据库名 +var dbName = "sagoo_iot" + +// GetConn 获取链接 +func (s *sTdEngine) GetConn(ctx context.Context, dbName string) (db *sql.DB, err error) { + driver, err := g.Cfg().Get(ctx, "tdengine.type") + if err != nil { + err = gerror.New("请检查TDengine配置") + return + } + dsn, err := g.Cfg().Get(ctx, "tdengine.dsn") + if err != nil { + err = gerror.New("请检查TDengine配置") + return + } + + link := dsn.String() + if dbName != "" { + link += dbName + } + + taos, err := sql.Open(driver.String(), link) + if err != nil { + g.Log().Error(ctx, err) + err = gerror.New("TDengine连接失败") + return + } + return taos, nil +} + +// GetTdEngineAllDb 获取所有数据库 +func (s *sTdEngine) GetTdEngineAllDb(ctx context.Context) (data []string, err error) { + taos, err := s.GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + + defer taos.Close() + + rows, err := taos.Query("show databases;") + if err != nil { + err = gerror.New(err.Error()) + return + } + defer rows.Close() + + for rows.Next() { + var name string + + err = rows.Scan(&name) + data = append(data, name) + } + return +} + +// GetListTableByDatabases 获取指定数据库下所有的表列表 +func (s *sTdEngine) GetListTableByDatabases(ctx context.Context, dbName string) (data []*model.TDEngineTablesList, err error) { + taos, err := s.GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + + defer taos.Close() + + rows, err := taos.Query("SELECT table_name AS tableName, db_name AS dbName, create_time AS createTime, stable_name AS stableName FROM information_schema.ins_tables WHERE db_name = '" + dbName + "'") + if err != nil { + err = gerror.New(err.Error()) + return + } + defer rows.Close() + + for rows.Next() { + var tableName, db, stableName string + var createTime *gtime.Time + err = rows.Scan(&tableName, &db, &createTime, &stableName) + if err != nil { + err = gerror.New("获取失败") + return + } + var tDEngineTablesList = new(model.TDEngineTablesList) + tDEngineTablesList.TableName = tableName + tDEngineTablesList.DbName = db + tDEngineTablesList.StableName = stableName + tDEngineTablesList.CreateTime = createTime + data = append(data, tDEngineTablesList) + } + return +} + +// GetTdEngineTableInfoByTable 获取指定数据表结构信息 +func (s *sTdEngine) GetTdEngineTableInfoByTable(ctx context.Context, dbName string, tableName string) (data []*model.TDEngineTableInfo, err error) { + taos, err := s.GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + + defer taos.Close() + + rows, err := taos.Query("DESCRIBE " + dbName + "." + tableName + ";") + if err != nil { + err = gerror.New(err.Error()) + return + } + defer rows.Close() + + for rows.Next() { + var tDEngineTableInfo = new(model.TDEngineTableInfo) + err = rows.Scan(&tDEngineTableInfo.Field, &tDEngineTableInfo.Type, &tDEngineTableInfo.Length, &tDEngineTableInfo.Note) + if err != nil { + err = gerror.New("获取失败") + return + } + data = append(data, tDEngineTableInfo) + } + return +} + +// GetTdEngineTableDataByTable 获取指定数据表数据信息 +func (s *sTdEngine) GetTdEngineTableDataByTable(ctx context.Context, dbName string, tableName string) (data *model.TableDataInfo, err error) { + data = new(model.TableDataInfo) + taos, err := s.GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + + defer taos.Close() + + rows, err := taos.Query("SELECT * FROM " + tableName) + if err != nil { + err = gerror.New(err.Error()) + return + } + defer rows.Close() + + //获取查询结果字段 + columns, _ := rows.Columns() + //字段数组 + var filed []string + //封装scanArg + scanArgs := make([]any, len(columns)) + for i := range columns { + filed = append(filed, columns[i]) + scanArgs[i] = &columns[i] + } + data.Filed = append(data.Filed, filed...) + for rows.Next() { + err = rows.Scan(scanArgs...) + if err != nil { + err = gerror.New("获取失败") + return + } + //封装返回结果 + var resultMap = make(map[string]interface{}) + for i := range columns { + resultMap[filed[i]] = columns[i] + } + data.Info = append(data.Info, resultMap) + } + + return +} + +// 超级表查询,单条数据 +func (s *sTdEngine) GetOne(ctx context.Context, sql string, args ...any) (rs gdb.Record, err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + rows, err := taos.Query(sql, args...) + if err != nil { + g.Log().Error(ctx, err, sql, args) + return nil, err + } + defer rows.Close() + + columns, _ := rows.Columns() + values := make([]any, len(columns)) + rs = make(gdb.Record, len(columns)) + for i := range values { + values[i] = new(any) + } + + for rows.Next() { + err = rows.Scan(values...) + if err != nil { + return nil, err + } + + for i, c := range columns { + rs[c] = s.Time(gvar.New(values[i])) + } + + rows.Close() + } + + return +} + +// 超级表查询,多条数据 +func (s *sTdEngine) GetAll(ctx context.Context, sql string, args ...any) (rs gdb.Result, err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + rows, err := taos.Query(sql, args...) + if err != nil { + g.Log().Error(ctx, err, sql) + return nil, err + } + defer rows.Close() + + columns, _ := rows.Columns() + + for rows.Next() { + values := make([]any, len(columns)) + for i := range values { + values[i] = new(any) + } + + err = rows.Scan(values...) + if err != nil { + return nil, err + } + + m := make(gdb.Record, len(columns)) + for i, c := range columns { + m[c] = s.Time(gvar.New(values[i])) + } + rs = append(rs, m) + } + + return +} + +// REST连接时区处理 +func (s *sTdEngine) Time(v *g.Var) (rs *g.Var) { + driver, _ := g.Cfg().Get(context.TODO(), "tdengine.type") + + if driver.String() == "taosRestful" { + if t, err := time.Parse("2006-01-02 15:04:05 +0000 UTC", v.String()); err == nil { + rs = gvar.New(t.Local().Format("2006-01-02 15:04:05")) + return + } + } + + rs = v + return +} diff --git a/internal/logic/tdengine/td_log_table.go b/internal/logic/tdengine/td_log_table.go new file mode 100644 index 0000000..5b35471 --- /dev/null +++ b/internal/logic/tdengine/td_log_table.go @@ -0,0 +1,108 @@ +package tdengine + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "time" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// 设备日志 TDengine 表结构维护 +type sTdLogTable struct{} + +func init() { + service.RegisterTdLogTable(tdLogTableNew()) +} + +func tdLogTableNew() *sTdLogTable { + return &sTdLogTable{} +} + +// 添加超级表 +func (s *sTdLogTable) CreateStable(ctx context.Context) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + var name string + err = taos.QueryRow("SELECT stable_name FROM information_schema.ins_stables WHERE stable_name = 'device_log' LIMIT 1").Scan(&name) + if name != "" { + return + } + + sql := "CREATE STABLE device_log (ts TIMESTAMP, type VARCHAR(20), content VARCHAR(1000)) TAGS (device VARCHAR(255))" + _, err = taos.Exec(sql) + + return +} + +// 写入数据 +func (s *sTdLogTable) Insert(ctx context.Context, log *model.TdLogAddInput) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := "INSERT INTO ? USING device_log TAGS ('?') VALUES ('?', '?', '?')" + _, err = taos.Exec(sql, "log_"+log.Device, log.Device, log.Ts.String(), log.Type, log.Content) + + return +} + +// 清理过期数据 +func (s *sTdLogTable) Clear(ctx context.Context) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + ts := gtime.Now().Add(-7 * 24 * time.Hour).Format("Y-m-d") + + sql := "DELETE FROM device_log WHERE ts < '" + ts + "'" + _, err = taos.Exec(sql) + + return +} + +// 超级表查询,多条数据 +func (s *sTdLogTable) GetAll(ctx context.Context, sql string, args ...any) (list []model.TdLog, err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + rows, err := taos.Query(sql, args...) + if err != nil { + g.Log().Error(ctx, err, sql, args) + return nil, err + } + defer rows.Close() + + for rows.Next() { + var log model.TdLog + + err = rows.Scan(&log.Ts, &log.Type, &log.Content, &log.Device) + if err != nil { + return nil, err + } + log.Ts = service.TdEngine().Time(gvar.New(log.Ts.Format("Y-m-d H:i:s O T"))).GTime() + + list = append(list, log) + } + + return +} diff --git a/internal/logic/tdengine/td_log_table_test.go b/internal/logic/tdengine/td_log_table_test.go new file mode 100644 index 0000000..8535912 --- /dev/null +++ b/internal/logic/tdengine/td_log_table_test.go @@ -0,0 +1,32 @@ +package tdengine + +import ( + "context" + _ "github.com/sagoo-cloud/sagooiot/internal/logic/product" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + "github.com/gogf/gf/v2/os/gtime" +) + +func TestInsertLog(t *testing.T) { + logData := &model.TdLogAddInput{ + Ts: gtime.Now(), + Device: "k213213", + Type: "属性上报", + Content: `{"device_id":"k213213","return_time":"2022-11-10 10:49:33","property_99":2,"property_98":2,"property_97":3,"property_96":4,"property_95":2}`, + } + err := service.TdLogTable().Insert(context.TODO(), logData) + if err != nil { + t.Fatal(err) + } +} + +func TestClear(t *testing.T) { + err := service.TdLogTable().Clear(context.TODO()) + if err != nil { + t.Fatal(err) + } +} diff --git a/internal/logic/tdengine/tsl_table.go b/internal/logic/tdengine/tsl_table.go new file mode 100644 index 0000000..2c98c6e --- /dev/null +++ b/internal/logic/tdengine/tsl_table.go @@ -0,0 +1,298 @@ +package tdengine + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "strconv" + "strings" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gtime" +) + +// 物模型 TDengine 表结构维护 +type sTSLTable struct { +} + +func init() { + service.RegisterTSLTable(tslTableNew()) +} + +func tslTableNew() *sTSLTable { + return &sTSLTable{} +} + +// 数据入库 +func (s *sTSLTable) Insert(ctx context.Context, deviceKey string, data map[string]any) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + if len(data) == 0 { + return + } + + ts := gtime.Now().Format("Y-m-d H:i:s") + + var ( + field = []string{"ts"} + value = []string{"'" + ts + "'"} + ) + for k, v := range data { + field = append(field, k) + value = append(value, "'"+gvar.New(v).String()+"'") + } + + sql := "INSERT INTO ? (?) VALUES (?)" + _, err = taos.Exec(sql, deviceKey, strings.Join(field, ","), strings.Join(value, ",")) + if err != nil { + return + } + + return +} + +// 添加超级表 +func (s *sTSLTable) CreateStable(ctx context.Context, tsl *model.TSL) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + // 属性字段 + columns := []string{"ts TIMESTAMP"} + for _, v := range tsl.Properties { + maxLength := 0 + if v.ValueType.TSLParamBase.MaxLength != nil { + maxLength = *v.ValueType.TSLParamBase.MaxLength + } + columns = append(columns, s.column(v.ValueType.Type, v.Key, v.Name, maxLength)) + } + + // 标签字段 + tags := make([]string, len(tsl.Tags)+1) + tags[0] = "device VARCHAR(255) COMMENT '设备标识'" + for i, v := range tsl.Tags { + maxLength := 0 + if v.ValueType.TSLParamBase.MaxLength != nil { + maxLength = *v.ValueType.TSLParamBase.MaxLength + } + tags[i+1] = s.column(v.ValueType.Type, v.Key, v.Name, maxLength) + } + + tConent := "" + if len(tags) > 0 { + tConent = fmt.Sprintf("TAGS (%s)", strings.Join(tags, ",")) + } + sql := fmt.Sprintf("CREATE STABLE %s.%s (%s) %s", dbName, tsl.Key, strings.Join(columns, ","), tConent) + + _, err = taos.Exec(sql) + + return +} + +// 添加子表 +func (s *sTSLTable) CreateTable(ctx context.Context, stable, table string) (err error) { + taos, err := service.TdEngine().GetConn(ctx, dbName) + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("CREATE TABLE %s USING %s (device) TAGS ('%s')", table, stable, table) + println(sql) + + _, err = taos.Exec(sql) + + return +} + +func (s *sTSLTable) column(dataType, key, name string, maxLength int) string { + column := "" + comment := "" + if name != "" { + comment = "COMMENT '" + name + "'" + } + tdType := "" + switch dataType { + case "int": + tdType = "INT" + case "long": + tdType = "BIGINT" + case "float": + tdType = "FLOAT" + case "double": + tdType = "DOUBLE" + case "string": + if maxLength == 0 { + maxLength = 255 + } + tdType = "NCHAR(" + strconv.Itoa(maxLength) + ")" + case "boolean": + tdType = "BOOL" + case "date": + tdType = "TIMESTAMP" + default: + if maxLength == 0 { + maxLength = 255 + } + tdType = "NCHAR(" + strconv.Itoa(maxLength) + ")" + } + column = fmt.Sprintf("%s %s %s", key, tdType, comment) + return column +} + +// 删除超级表 +func (s *sTSLTable) DropStable(ctx context.Context, table string) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("DROP STABLE IF EXISTS %s.%s", dbName, table) + _, err = taos.Exec(sql) + + return +} + +// 删除子表 +func (s *sTSLTable) DropTable(ctx context.Context, table string) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("DROP TABLE IF EXISTS %s.%s", dbName, table) + _, err = taos.Exec(sql) + + return +} + +// 创建数据库 +func (s *sTSLTable) CreateDatabase(ctx context.Context) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + var name string + taos.QueryRow("SELECT name FROM information_schema.ins_databases WHERE name = '?' LIMIT 1", dbName).Scan(&name) + if name != "" { + return + } + + _, err = taos.Exec("CREATE DATABASE IF NOT EXISTS " + dbName) + + return +} + +// AddDatabaseField 添加数据库字段 +func (s *sTSLTable) AddDatabaseField(ctx context.Context, tableName, fieldName string, dataType string, len int) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s ADD COLUMN %s", dbName, tableName, s.column(dataType, fieldName, "", len)) + _, err = taos.Exec(sql) + + return +} + +// DelDatabaseField 删除数据库字段 +func (s *sTSLTable) DelDatabaseField(ctx context.Context, tableName, fieldName string) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s DROP COLUMN %s", dbName, tableName, fieldName) + _, err = taos.Exec(sql) + + return +} + +// ModifyDatabaseField 修改数据库指定字段长度 +func (s *sTSLTable) ModifyDatabaseField(ctx context.Context, tableName, fieldName string, dataType string, len int) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s MODIFY COLUMN %s", dbName, tableName, s.column(dataType, fieldName, "", len)) + _, err = taos.Exec(sql) + if err != nil { + err = gerror.New("设置字段长度失败,长度只能增大不能缩小") + return + } + return +} + +// AddTag 添加标签 +func (s *sTSLTable) AddTag(ctx context.Context, tableName, tagName string, dataType string, len int) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s ADD TAG %s", dbName, tableName, s.column(dataType, tagName, "", len)) + _, err = taos.Exec(sql) + + return +} + +// DelTag 删除标签 +func (s *sTSLTable) DelTag(ctx context.Context, tableName, tagName string) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s DROP TAG %s", dbName, tableName, tagName) + _, err = taos.Exec(sql) + + return +} + +// ModifyTag 修改标签 +func (s *sTSLTable) ModifyTag(ctx context.Context, tableName, tagName string, dataType string, len int) (err error) { + taos, err := service.TdEngine().GetConn(ctx, "") + if err != nil { + err = gerror.New("获取链接失败") + return + } + defer taos.Close() + + sql := fmt.Sprintf("ALTER STABLE %s.%s MODIFY TAG %s", dbName, tableName, s.column(dataType, tagName, "", len)) + _, err = taos.Exec(sql) + if err != nil { + err = gerror.New("设置标签长度失败,长度只能增大不能缩小") + return + } + return +} diff --git a/internal/logic/tdengine/tsl_table_test.go b/internal/logic/tdengine/tsl_table_test.go new file mode 100644 index 0000000..bf95125 --- /dev/null +++ b/internal/logic/tdengine/tsl_table_test.go @@ -0,0 +1,71 @@ +package tdengine + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "testing" + + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + "github.com/gogf/gf/v2/os/gtime" +) + +func TestInsertTSL(t *testing.T) { + deviceKey := "k213213" + data := map[string]any{ + "ts": gtime.Now(), + "property_99": 2, + "property_98": 2, + "property_97": 2, + "property_96": 2, + "property_95": 2, + } + err := service.TSLTable().Insert(context.TODO(), deviceKey, data) + if err != nil { + t.Fatal(err) + } +} + +func TestCreateStable(t *testing.T) { + metadata := `{"key":"product_cc","name":"产品_1","properties":[{"key":"property_1","name":"属性_1","accessMode":1,"valueType":{"type":"string","maxLength":0},"desc":"描述edit"}],"functions":[{"key":"function_3","name":"功能_3","inputs":[{"key":"input_1","name":"参数_1","valueType":{"type":"string","maxLength":22},"desc":"参数描述"}],"output":{"type":"string","maxLength":22},"desc":"描述编辑"}],"events":[{"key":"function_1","name":"事件_1","level":0,"valueType":{"type":"string","maxLength":22},"desc":"描述"}],"tags":[]}` + + var tsl *model.TSL + err := json.Unmarshal([]byte(metadata), &tsl) + if err != nil { + t.Fatal(err) + } + + err = service.TSLTable().CreateStable(context.TODO(), tsl) + if err != nil { + t.Fatal(err) + } +} + +func TestDropStable(t *testing.T) { + err := service.TSLTable().DropStable(context.TODO(), "product_cc") + if err != nil { + t.Fatal(err) + } +} + +func TestAddDatabaseField(t *testing.T) { + err := service.TSLTable().AddDatabaseField(context.TODO(), "product_cc", "test_add", "int", 0) + if err != nil { + t.Fatal(err) + } +} + +func TestAddTag(t *testing.T) { + err := service.TSLTable().AddTag(context.TODO(), "product_cc", "test_tag_add", "string", 10) + if err != nil { + t.Fatal(err) + } +} + +func TestDelTag(t *testing.T) { + err := service.TSLTable().DelTag(context.TODO(), "product_cc", "test_tag_add") + if err != nil { + t.Fatal(err) + } +} diff --git a/internal/model/alarm_level.go b/internal/model/alarm_level.go new file mode 100644 index 0000000..88c6d89 --- /dev/null +++ b/internal/model/alarm_level.go @@ -0,0 +1,24 @@ +package model + +import "github.com/sagoo-cloud/sagooiot/internal/model/entity" + +const ( + AlarmLevel_1 uint = iota + 1 // 告警级别:超紧急 + AlarmLevel_2 // 告警级别:紧急 + AlarmLevel_3 // 告警级别:严重 + AlarmLevel_4 // 告警级别:一般 + AlarmLevel_5 // 告警级别:提醒 +) + +type AlarmLevelOutput struct { + *entity.AlarmLevel +} + +type AlarmLevelListOutput struct { + List []*entity.AlarmLevel `json:"list"` +} + +type AlarmLevelEditInput struct { + Level uint `json:"level" dc:"告警级别" v:"required|in:1,2,3,4,5#告警级别不能为空|告警级别不正确"` + Name string `json:"name" dc:"告警名称" v:"required#请输入告警名称"` +} diff --git a/internal/model/alarm_log.go b/internal/model/alarm_log.go new file mode 100644 index 0000000..34b4623 --- /dev/null +++ b/internal/model/alarm_log.go @@ -0,0 +1,55 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" +) + +const ( + AlarmLogStatusUnhandle int = iota // 告警日志状态:未处理 + AlarmLogStatusHandle // 告警日志状态:已处理 + AlarmLogStatusIgnore // 告警日志状态:忽略 +) + +// 告警日志 +type AlarmLogOutput struct { + *entity.AlarmLog + + AlarmLevel *AlarmLevel `json:"alarmLevel" orm:"with:level"` + Product *DevProductWithName `json:"product" orm:"with:key=product_key"` + Device *DevDevice `json:"devcie" orm:"with:key=device_key"` +} + +// 告警日志写入 +type AlarmLogAddInput struct { + Type uint `json:"type" d:"1" dc:"告警类型:1=规则告警,2=设备自主告警"` + RuleId uint64 `json:"ruleId" dc:"规则id,type=2时为0"` + RuleName string `json:"ruleName" dc:"规则名称"` + Level uint `json:"level" dc:"告警级别"` + Data string `json:"data" dc:"触发告警的数据"` + ProductKey string `json:"productKey" dc:"产品标识"` + DeviceKey string `json:"deviceKey" dc:"设备标识"` +} + +// 告警处理 +type AlarmLogHandleInput struct { + Id uint64 `json:"id" dc:"告警日志ID" v:"required#告警日志ID不能为空"` + Status int `json:"status" d:"1" dc:"处理状态" v:"required|in:1,2#请选择处理状态|未知的处理状态,请正确选择"` + Content string `json:"content" dc:"处理意见"` +} + +// 日志级别统计 +type AlarmLogLevelTotal struct { + Level uint `json:"level" dc:"告警级别"` + Name string `json:"name" dc:"告警名称"` + Num int `json:"num" dc:"该级别日志数量"` + Ratio float64 `json:"ratio" dc:"该级别日志数量占比(百分比)"` +} + +// 日志列表 +type AlarmLogListInput struct { + PaginationInput +} +type AlarmLogListOutput struct { + List []AlarmLogOutput `json:"list" dc:"告警日志"` + PaginationOutput +} diff --git a/internal/model/alarm_rule.go b/internal/model/alarm_rule.go new file mode 100644 index 0000000..e9fa783 --- /dev/null +++ b/internal/model/alarm_rule.go @@ -0,0 +1,110 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" +) + +const ( + AlarmTriggerTypeOnline = iota + 1 // 触发类型:设备上线 + AlarmTriggerTypeOffline // 触发类型:设备离线 + AlarmTriggerTypeProperty // 触发类型:属性上报 +) + +var AlarmTriggerType = map[int]string{ + AlarmTriggerTypeOnline: "设备上线", + AlarmTriggerTypeOffline: "设备离线", + AlarmTriggerTypeProperty: "属性上报", +} + +const ( + OperatorEq = "eq" // 操作符:等于 + OperatorNe = "ne" // 操作符:不等于 + OperatorGt = "gt" // 操作符:大于 + OperatorGte = "gte" // 操作符:大于等于 + OperatorLt = "lt" // 操作符:小于 + OperatorLte = "lte" // 操作符:小于等于 + OperatorBet = "bet" // 操作符:在...之间 + OperatorNbet = "nbet" // 操作符:不在...之间 +) + +const ( + AlarmRuleStatusOff int = iota // 告警规则状态:未启用 + AlarmRuleStatusOn // 告警规则状态:已启用 +) + +type AlarmFilters struct { + Key string `json:"key" dc:"条件key"` + Operator string `json:"operator" dc:"操作符:eq,ne,gt,lt,gte,lte,bet,nbet"` + Value []string `json:"value" dc:"条件值"` + AndOr int `json:"andOr" dc:"多个条件参数的关系:0=无,1=并且,2=或"` +} +type AlarmCondition struct { + Filters []AlarmFilters `json:"filters" dc:"条件参数"` + AndOr int `json:"andOr" dc:"多个条件组的关系:0=无,1=并且,2=或"` +} +type AlarmTriggerCondition struct { + TriggerCondition []AlarmCondition `json:"triggerCondition" dc:"触发条件" v:"required#请添加触发条件"` +} + +type AlarmAction struct { + SendGateway string `json:"sendGateway" dc:"通知发送通道:sms、work_weixin、dingding"` + NoticeConfig string `json:"noticeConfig" dc:"通知配置"` + NoticeTemplate string `json:"noticeTemplate" dc:"通知模板"` + Addressee []string `json:"addressee" dc:"收信人"` +} +type AlarmPerformAction struct { + Action []AlarmAction `json:"action" dc:"执行动作" v:"required#请添加执行动作"` +} + +type AlarmRuleAddInput struct { + Name string `json:"name" dc:"告警规则名称" v:"required#请输入告警规则名称"` + Level uint `json:"level" dc:"告警级别" v:"required#请选择告警级别"` + ProductKey string `json:"productKey" dc:"产品标识" v:"required#请选择产品"` + DeviceKey string `json:"deviceKey" dc:"设备标识"` + TriggerType int `json:"triggerType" dc:"触发类型:1=上线,2=离线,3=属性上报" v:"required#请选择触发类型"` + AlarmTriggerCondition + AlarmPerformAction +} + +type AlarmRuleEditInput struct { + Id uint64 `json:"id" dc:"告警规则ID" v:"required#告警规则ID不能为空"` + AlarmRuleAddInput +} + +type AlarmRuleOutput struct { + *entity.AlarmRule + + TriggerTypeName string `json:"triggerTypeName" dc:"触发类型"` + + Condition AlarmTriggerCondition `json:"condition" dc:"触发条件"` + + PerformAction AlarmPerformAction `json:"performAction" dc:"执行动作"` + + AlarmLevel AlarmLevel `json:"alarmLevel" orm:"with:level" dc:"告警级别"` +} +type AlarmLevel struct { + *entity.AlarmLevel +} + +type OperatorOutput struct { + Title string `json:"title" dc:"操作符名称"` + Type string `json:"type" dc:"操作符值"` +} + +type TriggerTypeOutput struct { + Title string `json:"title" dc:"触发类型"` + Type int `json:"type" dc:"类型值"` +} + +type TriggerParamOutput struct { + Title string `json:"title" dc:"条件参数"` + ParamKey string `json:"paramKey" dc:"参数key"` +} + +type AlarmRuleListInput struct { + PaginationInput +} +type AlarmRuleListOutput struct { + List []AlarmRuleOutput `json:"list" dc:"告警规则列表"` + PaginationOutput +} diff --git a/internal/model/base_db_link.go b/internal/model/base_db_link.go new file mode 100644 index 0000000..d874d30 --- /dev/null +++ b/internal/model/base_db_link.go @@ -0,0 +1,82 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type BaseDbLinkDoInput struct { + Name string `p:"name" description:"数据源名称"` + Types string `p:"types" description:"驱动类型 mysql或oracle"` + Host string `p:"host" description:"主机地址"` + Port string `p:"port" description:"端口"` + UserName string `p:"user_name" description:"用户名称"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用"` + *PaginationInput +} + +type BaseDbLinkOut struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle"` + Host string `json:"host" description:"主机地址"` + Port int `json:"port" description:"端口号"` + UserName string `json:"userName" description:"用户名称"` + Password string `json:"password" description:"密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} + +// BaseDbLinkRes 数据源列表返回字段 +type BaseDbLinkRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle"` + Host string `json:"host" description:"主机地址"` + Port int `json:"port" description:"端口号"` + UserName string `json:"userName" description:"用户名称"` + Password string `json:"password" description:"密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} + +type DetailBaseDbLinkRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle"` + Host string `json:"host" description:"主机地址"` + Port int `json:"port" description:"端口号"` + UserName string `json:"userName" description:"用户名称"` + Password string `json:"password" description:"密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} + +type AddBaseDbLinkInput struct { + Name string `json:"name" description:"名称" v:"required#请输入数据源名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle" v:"required#请输入数据源驱动类型"` + Host string `json:"host" description:"主机地址" v:"required#请输入数据源主机地址"` + Port int `json:"port" description:"端口号" v:"required#请输入数据源端口号"` + UserName string `json:"userName" description:"用户名称" v:"required#请输入数据源用户名称"` + Password string `json:"password" description:"密码" v:"required#请输入数据源密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} + +type EditBaseDbLinkInput struct { + Id int `json:"id" description:"" v:"required#请输入数据源ID"` + Name string `json:"name" description:"名称" v:"required#请输入数据源名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle" v:"required#请输入数据源驱动类型"` + Host string `json:"host" description:"主机地址" v:"required#请输入数据源主机地址"` + Port int `json:"port" description:"端口号" v:"required#请输入数据源端口号"` + UserName string `json:"userName" description:"用户名称" v:"required#请输入数据源用户名称"` + Password string `json:"password" description:"密码" v:"required#请输入数据源密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} diff --git a/internal/model/base_model.go b/internal/model/base_model.go new file mode 100644 index 0000000..be2a4bc --- /dev/null +++ b/internal/model/base_model.go @@ -0,0 +1,14 @@ +package model + +type PaginationInput struct { + KeyWord string `json:"keyWord" dc:"搜索关键字"` //搜索关键字 + DateRange []string `p:"dateRange"` //日期范围 + OrderBy string //排序方式 + PageNum int `json:"pageNum" in:"query" d:"1" v:"min:0#分页号码错误" dc:"分页号码,默认1"` + PageSize int `json:"PageSize" in:"query" d:"10" v:"max:50#分页数量最大50条" dc:"分页数量,最大50"` +} + +type PaginationOutput struct { + CurrentPage int `json:"currentPage" dc:"当前页"` + Total int `dc:"总数"` +} diff --git a/internal/model/city_data.go b/internal/model/city_data.go new file mode 100644 index 0000000..d24aa6d --- /dev/null +++ b/internal/model/city_data.go @@ -0,0 +1,53 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type CityTreeRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + ParentId int `json:"parentId" description:"父ID"` + Sort int `json:"sort" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` + Children []*CityTreeRes `json:"children" description:"子集"` +} + +type AddCityReq struct { + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + ParentId int `json:"parentId" description:"父ID"` + Sort int `json:"sort" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` +} + +type EditCityReq struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + ParentId int `json:"parentId" description:"父ID"` + Sort int `json:"sort" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` +} + +type CityRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + ParentId int `json:"parentId" description:"父ID"` + Sort int `json:"sort" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/config_data.go b/internal/model/config_data.go new file mode 100644 index 0000000..be2bf9d --- /dev/null +++ b/internal/model/config_data.go @@ -0,0 +1,53 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type ConfigDoInput struct { + ConfigName string `p:"configName"` //参数名称 + ConfigKey string `p:"configKey"` //参数键名 + ConfigType string `p:"configType"` //状态 + *PaginationInput +} + +type SysConfigRes struct { + ConfigId uint `json:"configId" description:"参数主键"` + ConfigName string `json:"configName" description:"参数名称"` + ConfigKey string `json:"configKey" description:"参数键名"` + ConfigValue string `json:"configValue" description:"参数键值"` + ConfigType int `json:"configType" description:"系统内置(Y是 N否)"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` +} + +type SysConfigOut struct { + ConfigId uint `json:"configId" description:"参数主键"` + ConfigName string `json:"configName" description:"参数名称"` + ConfigKey string `json:"configKey" description:"参数键名"` + ConfigValue string `json:"configValue" description:"参数键值"` + ConfigType int `json:"configType" description:"系统内置(Y是 N否)"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` +} + +type AddConfigInput struct { + ConfigName string `p:"configName"` + ConfigKey string `p:"configKey"` + ConfigValue string `p:"configValue"` + ConfigType int `p:"configType"` + Remark string `p:"remark"` +} + +type EditConfigInput struct { + ConfigId int `p:"configId"` + ConfigName string `p:"configName"` + ConfigKey string `p:"configKey"` + ConfigValue string `p:"configValue"` + ConfigType int `p:"configType"` + Remark string `p:"remark"` +} diff --git a/internal/model/context.go b/internal/model/context.go new file mode 100644 index 0000000..f06433d --- /dev/null +++ b/internal/model/context.go @@ -0,0 +1,23 @@ +package model + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" +) + +// Context 请求上下文结构 +type Context struct { + Session *ghttp.Session // 当前Session管理对象 + User *ContextUser // 上下文用户信息 + Data g.Map // 自定KV变量,业务模块根据需要设置,不固定 +} + +// ContextUser 请求上下文中的用户信息 +type ContextUser struct { + Id int // 用户ID + Passport string // 用户账号 + Nickname string // 用户名称 + Avatar string // 用户 + IsAdmin bool // 是否是管理员 + DeptId int // 部门ID +} diff --git a/internal/model/data_node.go b/internal/model/data_node.go new file mode 100644 index 0000000..131832f --- /dev/null +++ b/internal/model/data_node.go @@ -0,0 +1,29 @@ +package model + +import "github.com/sagoo-cloud/sagooiot/internal/model/entity" + +// 添加节点 +type DataNodeAddInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Key string `json:"key" dc:"数据节点标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入数据节点标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"数据节点名称" v:"required#请输入数据节点名称"` + DataType string `json:"dataType" dc:"数据类型" v:"required#请选择数据类型"` + Value string `json:"value" dc:"取值项" v:"required#请输入取值项"` + IsPk int `json:"isPk" dc:"是否主键"` + + Rule []DataSourceRule `json:"rule" dc:"规则配置"` +} + +// 编辑节点 +type DataNodeEditInput struct { + NodeId uint64 `json:"nodeId" dc:"数据节点ID" v:"required#数据节点ID不能为空"` + Name string `json:"name" dc:"数据节点名称" v:"required#请输入数据节点名称"` + Value string `json:"value" dc:"取值项" v:"required#请输入取值项"` +} + +// 数据节点 +type DataNodeOutput struct { + *entity.DataNode + + NodeRule []*DataSourceRule `json:"nodeRule" dc:"数据节点规则配置"` +} diff --git a/internal/model/data_source.go b/internal/model/data_source.go new file mode 100644 index 0000000..70bf701 --- /dev/null +++ b/internal/model/data_source.go @@ -0,0 +1,188 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" +) + +const ( + DataSourceFromApi = iota + 1 // api数据源 + DataSourceFromDb // 数据库数据源 + DataSourceFromFile // 文件数据源 + DataSourceFromDevice // 设备数据源 +) + +const ( + DataSourceStatusOff int = iota // 数据源未发布 + DataSourceStatusOn // 数据源已发布 +) + +const ( + DataSourceDbQueryType = "tableName" // 数据库源获取数据方式:表 + DataSourceDbQueryTypeSql = "sql" // 数据库源获取数据方式:sql +) + +// 规则配置 +type DataSourceRule struct { + Expression string `json:"expression" dc:"正则表达式"` + Replace string `json:"replace" dc:"替换内容"` +} + +// 数据源 +type DataSource struct { + Key string `json:"key" dc:"数据源标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入数据源标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"数据源名称" v:"required#请输入数据源名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + From int `json:"from" dc:"数据来源:1=api导入,2=数据库,3=文件,4=设备" v:"required|in:1,2,3,4#请选择数据来源|未知数据来源,请正确选择"` + + Rule []DataSourceRule `json:"rule" dc:"规则配置"` +} + +// api 数据源配置 +type DataSourceConfigApi struct { + Method string `json:"method" dc:"请求方法(get、post、put)"` + Url string `json:"url" dc:"请求地址" v:"url"` + RequestParams [][]DataSourceApiRequestParam `json:"requestParams" dc:"请求参数"` + + // 数据更新间隔,cron 格式 + CronExpression string `json:"cronExpression" dc:"任务执行表达式" v:"required#任务表达式不能为空"` +} + +// api 请求参数 +type DataSourceApiRequestParam struct { + Type string `json:"type" dc:"参数类型(header、body、param)" v:"required|in:header,body,param#请选择参数类型|未知参数类型,请正确选择"` + Key string `json:"key" dc:"参数标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入参数标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"参数标题" v:"required#请输入参数标题"` + Value string `json:"value" dc:"参数值" v:"required#请输入参数值"` +} + +// 搜索数据源 +type DataSourceSearchInput struct { + Key string `json:"key" dc:"数据源标识"` + Name string `json:"name" dc:"数据源名称"` + From int `json:"from" dc:"数据来源" d:"1"` + PaginationInput +} +type DataSourceSearchOutput struct { + List []entity.DataSource `json:"list" dc:"数据源列表"` + PaginationOutput +} + +// 添加 api 数据源 +type DataSourceApiAddInput struct { + DataSource + + Config DataSourceConfigApi `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 编辑 api 数据源 +type DataSourceApiEditInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Name string `json:"name" dc:"数据源名称" v:"required#请输入数据源名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Key string `json:"key" dc:"数据源标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + + Rule []DataSourceRule `json:"rule" dc:"规则配置"` + + Config DataSourceConfigApi `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 数据源详情 +type DataSourceOutput struct { + *entity.DataSource + + SourceRule []*DataSourceRule `json:"sourceRule" dc:"数据源规则配置"` + + ApiConfig *DataSourceConfigApi `json:"apiConfig,omitempty" dc:"api配置"` + DeviceConfig *DataSourceConfigDevice `json:"deviceConfig,omitempty" dc:"设备配置"` + DbConfig *DataSourceConfigDb `json:"dbConfig,omitempty" dc:"数据库配置"` +} + +// 设备 数据源配置 +type DataSourceConfigDevice struct { + ProductKey string `json:"productKey" dc:"产品标识"` + DeviceKey string `json:"deviceKey" dc:"设备标识"` +} + +// 添加 设备 数据源 +type DataSourceDeviceAddInput struct { + DataSource + + Config DataSourceConfigDevice `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 编辑 设备 数据源 +type DataSourceDeviceEditInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Name string `json:"name" dc:"数据源名称" v:"required#请输入数据源名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Key string `json:"key" dc:"数据源标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + + Rule []DataSourceRule `json:"rule" dc:"规则配置"` + + Config DataSourceConfigDevice `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 数据库 数据源配置 +type DataSourceConfigDb struct { + Type string `json:"type" dc:"数据库类型(mysql/mssql)" v:"required#请配置数据库类型"` + Host string `json:"host" dc:"主机" v:"required#请配置主机地址"` + Port int `json:"port" dc:"端口" v:"required#请配置端口号"` + User string `json:"user" dc:"用户名" v:"required#请配置用户名"` + Passwd string `json:"passwd" dc:"密码" v:"required#请配置密码"` + DbName string `json:"dbName" dc:"数据库名称" v:"required#请配置数据库名称"` + + QueryType string `json:"queryType" dc:"数据获取方式" v:"required|in:tableName,sql#请选择数据获取方式|请正确选择数据获取方式"` + TableName string `json:"tableName" dc:"表名称" v:"required#请配置表名称或sql语句"` + + Pk string `json:"pk" dc:"主键字段"` + Num int `json:"num" dc:"每次获取数量" d:"100"` + + PkMax uint64 `json:"pkmax" dc:"主键最大值"` + + // 数据更新间隔,cron 格式 + CronExpression string `json:"cronExpression" dc:"任务执行表达式" v:"required#任务表达式不能为空"` +} + +// 添加 数据库 数据源 +type DataSourceDbAddInput struct { + DataSource + + Config DataSourceConfigDb `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 编辑 数据库 数据源 +type DataSourceDbEditInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Name string `json:"name" dc:"数据源名称" v:"required#请输入数据源名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Key string `json:"key" dc:"数据源标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + + Rule []DataSourceRule `json:"rule" dc:"规则配置"` + + Config DataSourceConfigDb `json:"config" dc:"数据源配置" v:"required#请配置数据源"` +} + +// 数据源获取数据的内网方法列表,供大屏使用 +type AllSourceOut struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID"` + Name string `json:"name" dc:"数据源名称"` + Path string `json:"path" dc:"接口地址"` +} + +type SourceDataAllInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Param map[string]interface{} `json:"param" dc:"搜索哪些字段的数据"` +} +type SourceDataAllOutput struct { + List string `json:"data" dc:"源数据记录"` +} + +type DataSourceDataInput struct { + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required#数据源ID不能为空"` + Param map[string]interface{} `json:"param" dc:"搜索哪些字段的数据"` + PaginationInput +} +type DataSourceDataOutput struct { + List string `json:"data" dc:"源数据记录"` + PaginationOutput +} diff --git a/internal/model/data_template.go b/internal/model/data_template.go new file mode 100644 index 0000000..c569f26 --- /dev/null +++ b/internal/model/data_template.go @@ -0,0 +1,106 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/frame/g" +) + +const ( + DataTemplateStatusOff int = iota // 数据模型未发布 + DataTemplateStatusOn // 数据模型已发布 +) + +type DataTemplate struct { + *entity.DataTemplate + + // 绑定的业务 + DataTemplateBusi []DataTemplateBusi `json:"dataTemplateBusi" orm:"with:data_template_id=id" dc:"绑定的业务单元"` + BusiTypes []int `json:"busiTypes" dc:"业务单元"` +} + +// 绑定业务模型 +type DataTemplateBusi struct { + DataTemplateId uint64 `json:"dataTemplateId" dc:"数据模型ID"` + BusiTypes int `json:"busiTypes" dc:"业务单元"` +} + +// 搜索数据模型 +type DataTemplateSearchInput struct { + Key string `json:"key" dc:"数据模型标识"` + Name string `json:"name" dc:"数据模型名称"` + PaginationInput +} +type DataTemplateSearchOutput struct { + List []DataTemplate `json:"list" dc:"数据模型列表"` + PaginationOutput +} + +// 添加数据模型 +type DataTemplateAddInput struct { + Key string `json:"key" dc:"数据模型标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入数据模型标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"数据模型名称" v:"required#请输入数据模型名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + + // 数据更新间隔,cron 格式 + CronExpression string `json:"cronExpression" dc:"任务执行表达式" v:"required#任务表达式不能为空"` +} + +// 编辑数据模型 +type DataTemplateEditInput struct { + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + Name string `json:"name" dc:"数据模型名称" v:"required#请输入数据模型名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Key string `json:"key" dc:"数据模型标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + + // 数据更新间隔,cron 格式 + CronExpression string `json:"cronExpression" dc:"任务执行表达式" v:"required#任务表达式不能为空"` + + // 绑定业务 + BusiTypes []int `json:"busiTypes" dc:"业务单元"` +} + +// 数据模型 +type DataTemplateOutput struct { + *entity.DataTemplate +} + +// 数据模型获取数据的内网方法列表,供大屏使用 +type AllTemplateOut struct { + Id uint64 `json:"id" dc:"数据模型ID"` + Name string `json:"name" dc:"数据模型名称"` + Path string `json:"path" dc:"接口地址"` +} + +type TemplateDataAllInput struct { + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + Param map[string]interface{} `json:"param" dc:"搜索哪些字段的数据"` +} +type TemplateDataAllOutput struct { + List g.List `json:"data" dc:"模型数据记录"` +} + +type TemplateDataLastInput struct { + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + Param map[string]interface{} `json:"param" dc:"搜索哪些字段的数据"` +} +type TemplateDataLastOutput struct { + Data g.Map `json:"data" dc:"模型数据记录"` +} + +// 数据模型设置主源、关联字段 +type TemplateDataRelationInput struct { + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + MainSourceId uint64 `json:"mainSourceId" dc:"主数据源" v:"required#主数据源ID不能为空"` + SourceNodeKey string `json:"sourceNodeKey" dc:"关联节点" v:"required#关联节点标识不能为空"` +} + +type DataTemplateDataInput struct { + Id uint64 `json:"id" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + Param map[string]interface{} `json:"param" dc:"搜索哪些字段的数据"` + PaginationInput +} +type DataTemplateDataOutput struct { + List string `json:"data" dc:"模型数据记录"` + PaginationOutput +} diff --git a/internal/model/data_template_busi.go b/internal/model/data_template_busi.go new file mode 100644 index 0000000..0dd8c8b --- /dev/null +++ b/internal/model/data_template_busi.go @@ -0,0 +1,7 @@ +package model + +// 绑定业务模型 +type DataTemplateBusiAddInput struct { + DataTemplateId uint64 `json:"dataTemplateId" dc:"数据模型ID"` + BusiTypes []int `json:"busiTypes" dc:"业务单元"` +} diff --git a/internal/model/data_template_node.go b/internal/model/data_template_node.go new file mode 100644 index 0000000..68e29e5 --- /dev/null +++ b/internal/model/data_template_node.go @@ -0,0 +1,63 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/util/gmeta" +) + +// 添加节点 +type DataTemplateNodeAddInput struct { + Tid uint64 `json:"tid" dc:"数据模型ID" v:"required#数据模型ID不能为空"` + From int `json:"from" dc:"字段生成方式:1=自动生成,2=数据源" v:"required|in:1,2#请选择字段生成方式|未知方式,请正确选择"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required-if:from,2#数据源ID不能为空"` + NodeId uint64 `json:"nodeId" dc:"数据节点ID" v:"required-if:from,2#数据节点ID不能为空"` + Key string `json:"key" dc:"模型节点标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入模型节点标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"模型节点名称" v:"required#请输入模型节点名称"` + DataType string `json:"dataType" dc:"数据类型" v:"required#请选择数据类型"` + Default string `json:"default" dc:"默认值"` + Method string `json:"method" dc:"数值类型,取值方式:max、min、avg"` + IsPk int `json:"isPk" dc:"是否主键"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + + IsSorting int `json:"isSorting" dc:"是否参与排序:0=否,1=是" v:"required|in:0,1#请选择是否参与排序|请正确选择"` + IsDesc int `json:"isDesc" dc:"排序方式:1=倒序,2=正序" v:"required-if:isSorting,1#请选择排序方式"` +} + +// 编辑节点 +type DataTemplateNodeEditInput struct { + Id uint64 `json:"id" dc:"模型节点ID" v:"required#模型节点ID不能为空"` + From int `json:"from" dc:"字段生成方式:1=自动生成,2=数据源" v:"required|in:1,2#请选择字段生成方式|未知方式,请正确选择"` + SourceId uint64 `json:"sourceId" dc:"数据源ID" v:"required-if:from,2#数据源ID不能为空"` + NodeId uint64 `json:"nodeId" dc:"数据节点ID" v:"required-if:from,2#数据节点ID不能为空"` + Name string `json:"name" dc:"模型节点名称" v:"required#请输入模型节点名称"` + Default string `json:"default" dc:"默认值"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + + IsSorting int `json:"isSorting" dc:"是否参与排序:0=否,1=是" v:"required|in:0,1#请选择是否参与排序|请正确选择"` + IsDesc int `json:"isDesc" dc:"排序方式:1=倒序,2=正序" v:"required-if:isSorting,1#请选择排序方式"` +} + +// 数据模型节点 +type DataTemplateNodeOutput struct { + *entity.DataTemplateNode + IsSorting int `json:"isSorting" dc:"是否参与排序:0=否,1=是"` + IsDesc int `json:"isDesc" dc:"排序方式:1=倒序,2=正序"` + + Source *WithSource `json:"source" orm:"with:source_id, where:source_id>0" dc:"数据源"` + Node *WithNode `json:"node" orm:"with:node_id, where:node_id>0" dc:"数据源节点"` +} + +type WithSource struct { + gmeta.Meta `orm:"table:data_source"` + SourceId uint64 `json:"sourceId" dc:"数据源ID"` + Key string `json:"key" dc:"数据源标识"` + Name string `json:"name" dc:"数据源名称"` + From int `json:"from" dc:"数据来源:1=api导入,2=数据库,3=文件,4=设备"` +} +type WithNode struct { + gmeta.Meta `orm:"table:data_node"` + NodeId uint64 `json:"nodeId" dc:"数据节点ID"` + Key string `json:"key" dc:"数据节点标识"` + Name string `json:"name" dc:"数据节点名称"` +} diff --git a/internal/model/dev_device.go b/internal/model/dev_device.go new file mode 100644 index 0000000..5d32236 --- /dev/null +++ b/internal/model/dev_device.go @@ -0,0 +1,138 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gmeta" +) + +const ( + DeviceStatusNoEnable int = iota // 设备未启用 + DeviceStatusOff // 设备离线 + DeviceStatusOn // 设备在线 +) + +type DeviceInput struct { + Key string `json:"key" dc:"设备标识" v:"regex:^[A-Za-z_]+[\\w]*$#请输入设备标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"设备名称"` + ProductId uint `json:"productId" dc:"所属产品"` + TunnelId int `json:"tunnelId" description:"tunnelId"` + Status string `p:"status"` //设备状态 +} + +type DevDevice struct { + Id uint `json:"id" dc:"设备ID"` + Name string `json:"name" dc:"设备名称"` + Key string `json:"key" dc:"设备标识"` +} +type DevProductWithName struct { + gmeta.Meta `orm:"table:dev_product"` + Id uint `json:"id" dc:"产品ID"` + Name string `json:"name" dc:"产品名称"` + Key string `json:"key" dc:"产品标识"` +} +type DevProduct struct { + Id uint `json:"id" dc:"产品ID"` + Name string `json:"name" dc:"产品名称"` + Key string `json:"key" dc:"产品标识"` + Metadata string `json:"metadata" dc:"物模型"` +} +type DevDeviceTag struct { + Id uint `json:"id" dc:"标签ID"` + Key string `json:"key" dc:"标签标识"` + Name string `json:"name" dc:"标签名称"` + Value string `json:"value" dc:"标签值"` +} + +type DeviceOutput struct { + *entity.DevDevice + ProductName string `json:"productName" dc:"产品名称"` + TSL *TSL `json:"tsl" dc:"物模型"` + + Product *DevProduct `json:"product" orm:"with:id=product_id" dc:"产品信息"` + Tags []*DevDeviceTag `json:"tags" orm:"with:device_id=id" dc:"设备标签"` +} + +type AddDeviceInput struct { + Key string `json:"key" dc:"设备标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入设备标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"设备名称" v:"required#请输入设备名称"` + ProductId uint `json:"productId" dc:"所属产品" v:"required#请选择所属产品"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Certificate string `json:"certificate" dc:"设备证书"` + SecureKey string `json:"secureKey" dc:"设备密钥"` + Version string `json:"version" dc:"固件版本号"` +} + +type EditDeviceInput struct { + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` + Name string `json:"name" dc:"设备名称" v:"required#请输入设备名称"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Certificate string `json:"certificate" dc:"设备证书"` + SecureKey string `json:"secureKey" dc:"设备密钥"` + Version string `json:"version" dc:"固件版本号"` +} + +type ListDeviceInput struct { + ProductId uint `json:"productId" dc:"产品ID"` +} + +type ListDeviceForPageInput struct { + *DeviceInput + PaginationInput +} +type ListDeviceForPageOutput struct { + Device []*DeviceOutput `json:"device" dc:"设备列表"` + PaginationOutput +} + +// 设备运行状态 +type DeviceRunStatusOutput struct { + Status int `json:"status" dc:"状态:0=未启用,1=离线,2=在线"` + LastOnlineTime *gtime.Time `json:"lastOnlineTime" dc:"最后上线时间"` + Properties []DevicePropertiy `json:"properties" dc:"属性列表"` +} + +type DevicePropertiy struct { + Key string `json:"key" dc:"属性标识"` + Name string `json:"name" dc:"属性名称"` + Type string `json:"type" dc:"属性值类型"` + Unit string `json:"unit" dc:"属性值单位"` + Value *gvar.Var `json:"value" dc:"属性值"` + List []*gvar.Var `json:"list" dc:"当天属性值列表"` +} + +type DevicePropertiyOut struct { + Ts *gtime.Time `json:"ts" dc:"时间"` + Value *gvar.Var `json:"value" dc:"属性值"` +} + +type DeviceGetPropertyInput struct { + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` + PropertyKey string `json:"propertyKey" dc:"属性标识" v:"required#属性标识不能为空"` +} + +type DeviceGetPropertyListInput struct { + Id uint `json:"id" dc:"设备ID" v:"required#设备ID不能为空"` + PropertyKey string `json:"propertyKey" dc:"属性标识" v:"required#属性标识不能为空"` + PaginationInput +} +type DeviceGetPropertyListOutput struct { + List []*DevicePropertiyOut + PaginationOutput +} + +type DeviceTotalOutput struct { + DeviceTotal int `json:"deviceTotal" dc:"设备总量"` + DeviceOffline int `json:"deviceOffline" dc:"离线设备数量"` + + ProductTotal int `json:"productTotal" dc:"产品总量"` + ProductAdded int `json:"productAdded" dc:"今日产品增量"` + + MsgTotal int `json:"msgTotal" dc:"设备消息总量"` + MsgAdded int `json:"msgAdded" dc:"今日设备消息增量"` + + AlarmTotal int `json:"alarmTotal" dc:"设备报警总量"` + AlarmAdded int `json:"alarmAdded" dc:"今日设备报警增量"` +} diff --git a/internal/model/dev_device_log.go b/internal/model/dev_device_log.go new file mode 100644 index 0000000..9e0e4b9 --- /dev/null +++ b/internal/model/dev_device_log.go @@ -0,0 +1,11 @@ +package model + +type DeviceLogSearchInput struct { + DeviceKey string `json:"deviceKey" dc:"设备标识" v:"required#设备标识不能为空"` + Types []string `json:"types" dc:"日志类型"` + PaginationInput +} +type DeviceLogSearchOutput struct { + List []TdLog `json:"list" dc:"日志类型列表"` + PaginationOutput +} diff --git a/internal/model/dev_device_tag.go b/internal/model/dev_device_tag.go new file mode 100644 index 0000000..1121b89 --- /dev/null +++ b/internal/model/dev_device_tag.go @@ -0,0 +1,15 @@ +package model + +type AddTagDeviceInput struct { + DeviceId uint `json:"deviceId" dc:"设备ID" v:"required#设备ID不能为空"` + DeviceKey string `json:"deviceKey" dc:"设备标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入设备标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Key string `json:"key" dc:"标签标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入标签标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"标签名称" v:"required#请输入标签名称"` + Value string `json:"value" dc:"标签值" v:"required#请输入标签值"` +} + +type EditTagDeviceInput struct { + Id uint `json:"id" dc:"标签ID" v:"required#标签ID不能为空"` + Name string `json:"name" dc:"标签名称" v:"required#请输入标签名称"` + Value string `json:"value" dc:"标签值" v:"required#请输入标签值"` +} diff --git a/internal/model/dev_product.go b/internal/model/dev_product.go new file mode 100644 index 0000000..8dca835 --- /dev/null +++ b/internal/model/dev_product.go @@ -0,0 +1,76 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" +) + +const ( + ProductStatusOff int = iota // 产品未发布 + ProductStatusOn // 产品已发布 +) + +type ListForPageInput struct { + ProductInput + PaginationInput +} +type ListForPageOutput struct { + Product []*ProductOutput `json:"product" dc:"产品列表"` + PaginationOutput +} + +type ProductInput struct { + Name string `json:"name" dc:"产品名称" ` + CategoryId uint `json:"categoryId" dc:"所属品类"` + MessageProtocols []string `json:"messageProtocol" dc:"消息协议"` + DeviceTypes []string `json:"deviceType" dc:"设备类型:网关、设备"` + Status string `p:"status"` //产品状态 +} + +type ProductOutput struct { + *entity.DevProduct + DeviceTotal int `json:"deviceTotal" dc:"设备数量"` + CategoryName string `json:"categoryName" dc:"分类名称"` + + Category *DevProductCategory `json:"category" orm:"with:id=category_id" dc:"分类信息"` +} + +type DevProductCategory struct { + Id uint `json:"id" dc:"分类ID"` + Name string `json:"name" dc:"分类名称"` +} +type SysDept struct { + DeptId uint `json:"deptId" dc:"部门ID"` + DeptName string `json:"deptName" dc:"部门名称"` +} + +type DetailProductOutput struct { + *entity.DevProduct + DeviceTotal int `json:"deviceTotal" dc:"设备数量"` + CategoryName string `json:"categoryName" dc:"分类名称"` + + Category *DevProductCategory `json:"category" orm:"with:id=category_id" dc:"部门信息"` + + TSL *TSL `json:"tsl" dc:"物模型"` +} + +type AddProductInput struct { + Key string `json:"key" dc:"产品标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入产品标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"产品名称" v:"required#请输入产品名称"` + CategoryId uint `json:"categoryId" dc:"所属品类" v:"required#请选择所属品类"` + MessageProtocol string `json:"messageProtocol" dc:"消息协议" v:"required#请选择消息协议"` + TransportProtocol string `json:"transportProtocol" dc:"传输协议: MQTT,COAP,UDP" v:"required#请选择传输协议"` + DeviceType string `json:"deviceType" dc:"设备类型:网关、设备" v:"required#请选择设备类型"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Icon string `json:"icon" dc:"图片地址"` +} + +type EditProductInput struct { + Id uint `json:"id" dc:"产品ID" v:"required#产品ID不能为空"` + Name string `json:"name" dc:"产品名称" v:"required#请输入产品名称"` + CategoryId uint `json:"categoryId" dc:"所属品类" v:"required#请选择所属品类"` + MessageProtocol string `json:"messageProtocol" dc:"消息协议" v:"required#请选择消息协议"` + TransportProtocol string `json:"transportProtocol" dc:"传输协议: MQTT,COAP,UDP" v:"required#请选择传输协议"` + DeviceType string `json:"deviceType" dc:"设备类型:网关、设备" v:"required#请选择设备类型"` + Desc string `json:"desc" dc:"描述" v:"max-length:200#描述长度不能超过200个字符"` + Icon *string `json:"icon" dc:"图片地址"` +} diff --git a/internal/model/dev_product_category.go b/internal/model/dev_product_category.go new file mode 100644 index 0000000..4a9d6b0 --- /dev/null +++ b/internal/model/dev_product_category.go @@ -0,0 +1,26 @@ +package model + +import "github.com/sagoo-cloud/sagooiot/internal/model/entity" + +type ProductCategoryTreeOutput struct { + *entity.DevProductCategory + Children []*ProductCategoryTreeOutput `json:"children" description:"子分类"` +} + +type ProductCategoryOutput struct { + *entity.DevProductCategory +} + +type AddProductCategoryInput struct { + ParentId uint `json:"parentId" description:"父级分类ID"` + Key string `json:"key" description:"分类标识" v:"required#请输入标识"` + Name string `json:"name" description:"分类名称" v:"required#请输入名称"` + Desc string `json:"desc" description:"描述" v:"max-length:200#描述长度不能超过200个字符"` +} + +type EditProductCategoryInput struct { + Id uint `json:"id" description:"分类ID" v:"required#分类ID不能为空"` + Key string `json:"key" description:"分类标识" v:"required#请输入标识"` + Name string `json:"name" description:"分类名称" v:"required#请输入名称"` + Desc string `json:"desc" description:"描述" v:"max-length:200#描述长度不能超过200个字符"` +} diff --git a/internal/model/dev_protocol.go b/internal/model/dev_protocol.go new file mode 100644 index 0000000..548edd8 --- /dev/null +++ b/internal/model/dev_protocol.go @@ -0,0 +1,13 @@ +package model + +// 消息协议 +type MessageProtocolRes struct { + Key string `json:"key" dc:"协议标识"` + Name string `json:"name" dc:"协议名称"` +} + +// 传输协议 +type TrunsportProtocolRes struct { + Key string `json:"key" dc:"协议标识"` + Name string `json:"name" dc:"协议名称"` +} diff --git a/internal/model/dev_tsl.go b/internal/model/dev_tsl.go new file mode 100644 index 0000000..41b2856 --- /dev/null +++ b/internal/model/dev_tsl.go @@ -0,0 +1,114 @@ +package model + +const ( + TSLAccessModeDefault int = iota // 访问类型:读写 + TSLAccessModeReadOnly // 访问类型:只读 +) + +const ( + TSLEventLevelDefault int = iota // 事件级别:普通 + TSLEventLevelWarn // 事件级别:警告 + TSLEventLevelUrgen // 事件级别:紧急 +) + +// 基础类型参数 +type TSLParamBase struct { + Max *int `json:"max,omitempty" dc:"最大,数字类型:int、long、float、double"` // 最大,数字类型:int、long、float、double + Min *int `json:"min,omitempty" dc:"最小,数字类型:int、long、float、double"` // 最小,数字类型:int、long、float、double + Decimals *int `json:"decimals,omitempty" dc:"小数位数,数字类型:float、double"` // 小数位数,数字类型:float、double + Unit *string `json:"unit,omitempty" dc:"单位,数字类型:int、long、float、double"` // 单位,数字类型:int、long、float、double + + TrueText *string `json:"trueText,omitempty" dc:"为true时的文本,默认为'是',布尔类型:bool"` // 为true时的文本,默认为`是`,布尔类型:bool + FalseText *string `json:"falseText,omitempty" dc:"为false时的文本,默认为'否',布尔类型:bool"` // 为false时的文本,默认为`否`,布尔类型:bool + TrueValue *bool `json:"trueValue,omitempty" dc:"为true时的值,默认为'true',布尔类型:bool"` // 为true时的值,默认为`true`,布尔类型:bool + FalseValue *bool `json:"falseValue,omitempty" dc:"为false时的值,默认为'false',布尔类型:bool"` // 为false时的值,默认为`false`,布尔类型:bool + + MaxLength *int `json:"maxLength,omitempty" dc:"最大长度,字符类型:string"` // 最大长度,字符类型:string +} + +// 扩展类型参数 +type TSLParamExtension struct { + // Format *string `json:"format,omitempty" dc:"时间类型:date,如:yyyy-MM-dd"` // 时间类型:date,如:yyyy-MM-dd + Elements []TSLEnumType `json:"elements,omitempty" dc:"枚举类型:enum"` // 枚举类型:enum + ElementType *TSLArrayType `json:"elementType,omitempty" dc:"数组类型:array"` // 数组类型:array + Properties []TSLObjectType `json:"properties,omitempty" dc:"对象类型:object"` // 对象类型:object +} + +// 扩展类型参数:枚举型 +type TSLEnumType struct { + Value string `json:"value" dc:"枚举值"` // 枚举值 + Text string `json:"text" dc:"枚举文本"` // 枚举文本 +} + +// 扩展类型参数:数组型 +type TSLArrayType struct { + TSLValueType +} + +// 扩展类型参数:对象型 +type TSLObjectType struct { + Key string `json:"key" dc:"参数标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"参数名称"` // 参数名称 + ValueType TSLValueType `json:"valueType" dc:"参数值"` // 参数值 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 类型参数 +type TSLParam struct { + TSLParamBase + TSLParamExtension +} + +// 属性 +type TSLProperty struct { + Key string `json:"key" dc:"属性标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入属性标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"属性名称" v:"required#请输入属性名称"` // 属性名称 + AccessMode int `json:"accessMode" dc:"属性访问类型:0=读写,1=只读" v:"required#请选择是否只读"` // 属性访问类型 + ValueType TSLValueType `json:"valueType" dc:"属性值"` // 属性值 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 功能 +type TSLFunction struct { + Key string `json:"key" dc:"功能标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入功能标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"功能名称" v:"required#请输入功能名称"` // 功能名称 + Inputs []TSLFunctionInput `json:"inputs" dc:"输入参数"` // 输入参数 + Output TSLValueType `json:"output" dc:"输出参数"` // 输出参数 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 功能:输入参数 +type TSLFunctionInput struct { + Key string `json:"key" dc:"参数标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"参数名称"` // 输入参数名称 + ValueType TSLValueType `json:"valueType" dc:"参数值"` // 参数值 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 事件 +type TSLEvent struct { + Key string `json:"key" dc:"事件标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入事件标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"事件名称" v:"required#请输入事件名称"` // 事件名称 + Level int `json:"level" dc:"事件级别:0=普通,1=警告,2=紧急" v:"required#请选择事件级别"` // 事件级别 + ValueType TSLValueType `json:"valueType" dc:"事件值"` // 事件值 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 标签 +type TSLTag struct { + Key string `json:"key" dc:"标签标识" v:"required|regex:^[A-Za-z_]+[\\w]*$#请输入标签标识|标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"标签名称" v:"required#请输入标签名称"` // 标签名称 + AccessMode int `json:"accessMode" dc:"标签访问类型:0=读写,1=只读" v:"required#请选择是否只读"` // 标签访问类型 + ValueType TSLValueType `json:"valueType" dc:"标签值"` // 标签值 + Desc string `json:"desc" dc:"描述"` // 描述 +} + +// 物模型 +type TSL struct { + Key string `json:"key" dc:"产品标识" v:"regex:^[A-Za-z_]+[\\w]*$#标识由字母、数字和下划线组成,且不能以数字开头"` + Name string `json:"name" dc:"产品名称"` // 产品名称 + Properties []TSLProperty `json:"properties" dc:"属性"` // 属性 + Functions []TSLFunction `json:"functions" dc:"功能"` // 功能 + Events []TSLEvent `json:"events" dc:"事件"` // 事件 + Tags []TSLTag `json:"tags" dc:"标签"` // 标签 +} diff --git a/internal/model/dev_tsl_data_type.go b/internal/model/dev_tsl_data_type.go new file mode 100644 index 0000000..6d0092c --- /dev/null +++ b/internal/model/dev_tsl_data_type.go @@ -0,0 +1,242 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/consts" + "strconv" + "time" +) + +// 数据类型列表 + +type DataTypeOutput struct { + BaseType []DataTypeValueBase `json:"baseType" dc:"基础类型"` + ExtensionType []DataTypeValueExtension `json:"extensionType" dc:"扩展类型"` +} + +type DataTypeValueBase struct { + Title string `json:"title" dc:"类型名称"` + Type string `json:"type" dc:"数据类型"` + TSLParamBase +} + +type DataTypeValueExtension struct { + Title string `json:"title" dc:"类型名称"` + Type string `json:"type" dc:"数据类型"` + TSLParamExtension +} + +// 参数值(类型、类型参数) +type TSLValueType struct { + Type string `json:"type" dc:"数据类型" v:"required#请选择数据类型"` // 类型 + TSLParam // 参数 +} + +func (t TSLValueType) ConvertValue(v interface{}) interface{} { + var transfer Transfer + switch t.Type { + case consts.TypeInt: + transfer = TInt(t.TSLParam) + case consts.TypeLong: + transfer = TLong(t.TSLParam) + case consts.TypeFloat: + transfer = TFloat(t.TSLParam) + case consts.TypeDouble: + transfer = TDouble(t.TSLParam) + case consts.TypeText: + transfer = TText(t.TSLParam) + case consts.TypeBool: + transfer = TBoolean(t.TSLParam) + case consts.TypeDate: + transfer = TDate(t.TSLParam) + case consts.TypeEnum: + transfer = TEnum(t.TSLParam) + case consts.TypeArray: + transfer = TArray(t.TSLParam) + case consts.TypeObject: + transfer = TObject(t.TSLParam) + default: + return nil + } + return transfer.Convert(v) +} + +type Transfer interface { + Convert(interface{}) interface{} +} + +type TInt TSLParam + +func (tInt TInt) Convert(v interface{}) interface{} { + number, ok := v.(int) + if !ok { + return 0 + } + if tInt.TSLParamBase.Min != nil && *tInt.TSLParamBase.Min > number { + return *tInt.TSLParamBase.Min + } + if tInt.TSLParamBase.Max != nil && *tInt.TSLParamBase.Max > number { + return *tInt.TSLParamBase.Max + } + return number +} + +type TLong TSLParam + +func (tLong TLong) Convert(v interface{}) interface{} { + number, ok := v.(int64) + if !ok { + return 0 + } + if tLong.TSLParamBase.Min != nil && int64(*tLong.TSLParamBase.Min) > number { + return *tLong.TSLParamBase.Min + } + if tLong.TSLParamBase.Max != nil && int64(*tLong.TSLParamBase.Max) > number { + return *tLong.TSLParamBase.Max + } + return number +} + +type TFloat TSLParam + +func (tFloat TFloat) Convert(v interface{}) interface{} { + number, ok := v.(float64) + if !ok { + return 0 + } + if tFloat.TSLParamBase.Min != nil && float32(*tFloat.TSLParamBase.Min) > float32(number) { + number = float64(*tFloat.TSLParamBase.Min) + } + if tFloat.TSLParamBase.Max != nil && float32(*tFloat.TSLParamBase.Max) > float32(number) { + number = float64(*tFloat.TSLParamBase.Max) + } + defaultDecimal := 2 + if tFloat.TSLParamBase.Decimals != nil { + defaultDecimal = *tFloat.TSLParamBase.Decimals + } + number32, _ := strconv.ParseFloat(strconv.FormatFloat(number, 'f', defaultDecimal, 64), 32) + return float32(number32) +} + +type TDouble TSLParam + +func (tDouble TDouble) Convert(v interface{}) interface{} { + number, ok := v.(float64) + if !ok { + return 0 + } + if tDouble.TSLParamBase.Min != nil && float64(*tDouble.TSLParamBase.Min) > number { + number = float64(*tDouble.TSLParamBase.Min) + } + if tDouble.TSLParamBase.Max != nil && float64(*tDouble.TSLParamBase.Max) > number { + number = float64(*tDouble.TSLParamBase.Max) + } + defaultDecimal := 2 + if tDouble.TSLParamBase.Decimals != nil { + defaultDecimal = *tDouble.TSLParamBase.Decimals + } + number64, _ := strconv.ParseFloat(strconv.FormatFloat(number, 'f', defaultDecimal, 64), 32) + return number64 +} + +type TText TSLParam + +func (tText TText) Convert(v interface{}) interface{} { + text, ok := v.(string) + if !ok { + return "" + } + if tText.MaxLength != nil && *tText.MaxLength > 0 && len(text) > *tText.MaxLength { + return text[:*tText.MaxLength-1] + } else { + return text + } +} + +type TBoolean TSLParam + +func (tBoolean TBoolean) Convert(v interface{}) interface{} { + b, ok := v.(bool) + if !ok { + return "" + } + //TODO 这里是返回文字还是类型,暂定是返回映射文字 + if !b && tBoolean.FalseText != nil { + return *tBoolean.FalseText + } else if b && tBoolean.TrueText != nil { + return *tBoolean.TrueText + } + return "" +} + +type TDate TSLParam + +const layout = "2006-01-02 15:04:05" + +func (TDate TDate) Convert(v interface{}) interface{} { + str, ok := v.(string) + if !ok { + return time.Time{} + } + t, err := time.Parse(layout, str) + if err != nil { + return time.Time{} + } else { + return t + } +} + +type TEnum TSLParam + +func (tEnum TEnum) Convert(v interface{}) interface{} { + tE, ok := v.(string) + if !ok { + return "" + } + if tEnum.TSLParamExtension.Elements == nil { + return "" + } + for _, node := range tEnum.TSLParamExtension.Elements { + if node.Text == tE { + return node.Value + } + } + return "" +} + +type TArray TSLParam + +func (tArray TArray) Convert(v interface{}) interface{} { + tA, ok := v.([]interface{}) + if !ok { + return nil + } + if tArray.TSLParamExtension.ElementType == nil { + return nil + } else { + result := make([]interface{}, 0) + for _, node := range tA { + result = append(result, (*tArray.TSLParamExtension.ElementType).ConvertValue(node)) + } + return result + } +} + +type TObject TSLParam + +func (tObject TObject) Convert(v interface{}) interface{} { + m, ok := v.(map[string]interface{}) + if !ok { + return nil + } + result := make(map[string]interface{}) + if tObject.TSLParamExtension.Properties != nil { + for k, value := range m { + for _, t := range tObject.TSLParamExtension.Properties { + if t.Name == k { + result[t.Name] = t.ValueType.ConvertValue(value) + } + } + } + } + return result +} diff --git a/internal/model/dev_tsl_event.go b/internal/model/dev_tsl_event.go new file mode 100644 index 0000000..07568d0 --- /dev/null +++ b/internal/model/dev_tsl_event.go @@ -0,0 +1,22 @@ +package model + +// 事件:添加、编辑 +type TSLEventInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + TSLEvent +} + +// 事件:删除 +type DelTSLEventInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + Key string `json:"key" dc:"事件标识" v:"required#事件标识不能为空"` +} + +type ListTSLEventInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + PaginationInput +} +type ListTSLEventOutput struct { + Data []TSLEvent + PaginationOutput +} diff --git a/internal/model/dev_tsl_function.go b/internal/model/dev_tsl_function.go new file mode 100644 index 0000000..8ae1e7b --- /dev/null +++ b/internal/model/dev_tsl_function.go @@ -0,0 +1,22 @@ +package model + +// 功能:添加、编辑 +type TSLFunctionAddInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + TSLFunction +} + +// 功能:删除 +type DelTSLFunctionInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + Key string `json:"key" dc:"功能标识" v:"required#功能标识不能为空"` +} + +type ListTSLFunctionInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + PaginationInput +} +type ListTSLFunctionOutput struct { + Data []TSLFunction + PaginationOutput +} diff --git a/internal/model/dev_tsl_property.go b/internal/model/dev_tsl_property.go new file mode 100644 index 0000000..2f6b254 --- /dev/null +++ b/internal/model/dev_tsl_property.go @@ -0,0 +1,24 @@ +package model + +// 添加、编辑属性 +type TSLPropertyInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + TSLProperty +} + +// 删除属性 +type DelTSLPropertyInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + Key string `json:"key" dc:"属性标识" v:"required#属性标识不能为空"` +} + +type ListTSLPropertyInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + Name string `json:"name" dc:"属性名称"` + DateType string `json:"dateType" dc:"数据类型"` + PaginationInput +} +type ListTSLPropertyOutput struct { + Data []TSLProperty + PaginationOutput +} diff --git a/internal/model/dev_tsl_tag.go b/internal/model/dev_tsl_tag.go new file mode 100644 index 0000000..03ecf33 --- /dev/null +++ b/internal/model/dev_tsl_tag.go @@ -0,0 +1,22 @@ +package model + +// 添加、编辑标签 +type TSLTagInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + TSLTag +} + +// 删除标签 +type DelTSLTagInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + Key string `json:"key" dc:"标签标识" v:"required#标签标识不能为空"` +} + +type ListTSLTagInput struct { + ProductId uint `json:"productId" dc:"产品ID" v:"required#产品ID不能为空"` + PaginationInput +} +type ListTSLTagOutput struct { + Data []TSLTag + PaginationOutput +} diff --git a/internal/model/do/alarm_level.go b/internal/model/do/alarm_level.go new file mode 100644 index 0000000..395f05a --- /dev/null +++ b/internal/model/do/alarm_level.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// AlarmLevel is the golang structure of table alarm_level for DAO operations like Where/Data. +type AlarmLevel struct { + g.Meta `orm:"table:alarm_level, do:true"` + Level interface{} // 告警级别 + Name interface{} // 名称 +} diff --git a/internal/model/do/alarm_log.go b/internal/model/do/alarm_log.go new file mode 100644 index 0000000..16bf389 --- /dev/null +++ b/internal/model/do/alarm_log.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AlarmLog is the golang structure of table alarm_log for DAO operations like Where/Data. +type AlarmLog struct { + g.Meta `orm:"table:alarm_log, do:true"` + Id interface{} // + Type interface{} // 告警类型:1=规则告警,2=设备自主告警 + RuleId interface{} // 规则id + RuleName interface{} // 规则名称 + Level interface{} // 告警级别 + Data interface{} // 触发告警的数据 + ProductKey interface{} // 产品标识 + DeviceKey interface{} // 设备标识 + Status interface{} // 告警状态:0=未处理,1=已处理 + CreatedAt *gtime.Time // 告警时间 + UpdateBy interface{} // 告警处理人员 + UpdatedAt *gtime.Time // 处理时间 + Content interface{} // 处理意见 +} diff --git a/internal/model/do/alarm_rule.go b/internal/model/do/alarm_rule.go new file mode 100644 index 0000000..a6843ac --- /dev/null +++ b/internal/model/do/alarm_rule.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// AlarmRule is the golang structure of table alarm_rule for DAO operations like Where/Data. +type AlarmRule struct { + g.Meta `orm:"table:alarm_rule, do:true"` + Id interface{} // + Name interface{} // 告警规则名称 + Level interface{} // 告警级别,默认:4(一般) + ProductKey interface{} // 产品标识 + DeviceKey interface{} // 设备标识 + TriggerType interface{} // 触发类型:1=上线,2=离线,3=属性上报 + TriggerCondition interface{} // 触发条件 + Action interface{} // 执行动作 + Status interface{} // 状态:0=未启用,1=已启用 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/base_db_link.go b/internal/model/do/base_db_link.go new file mode 100644 index 0000000..f1f9929 --- /dev/null +++ b/internal/model/do/base_db_link.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// BaseDbLink is the golang structure of table base_db_link for DAO operations like Where/Data. +type BaseDbLink struct { + g.Meta `orm:"table:base_db_link, do:true"` + Id interface{} // + Name interface{} // 名称 + Types interface{} // 驱动类型 mysql或oracle + Host interface{} // 主机地址 + Port interface{} // 端口号 + UserName interface{} // 用户名称 + Password interface{} // 密码 + Description interface{} // 描述 + Status interface{} // 状态 0 停用 1启用 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 更新时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/city_data.go b/internal/model/do/city_data.go new file mode 100644 index 0000000..d858ae6 --- /dev/null +++ b/internal/model/do/city_data.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// CityData is the golang structure of table city_data for DAO operations like Where/Data. +type CityData struct { + g.Meta `orm:"table:city_data, do:true"` + Id interface{} // + Name interface{} // 名字 + Code interface{} // 编码 + ParentId interface{} // 父ID + Sort interface{} // 排序 + Status interface{} // 状态;0:禁用;1:正常 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建日期 + UpdatedBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改日期 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/data_node.go b/internal/model/do/data_node.go new file mode 100644 index 0000000..efb30eb --- /dev/null +++ b/internal/model/do/data_node.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DataNode is the golang structure of table data_node for DAO operations like Where/Data. +type DataNode struct { + g.Meta `orm:"table:data_node, do:true"` + NodeId interface{} // + SourceId interface{} // 数据源ID + Name interface{} // 数据节点名称 + Key interface{} // 数据节点标识 + DataType interface{} // 数据类型 + Value interface{} // 取值项 + IsPk interface{} // 是否主键:0=否,1=是 + Rule interface{} // 规则配置json + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/data_source.go b/internal/model/do/data_source.go new file mode 100644 index 0000000..fb0c3ad --- /dev/null +++ b/internal/model/do/data_source.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DataSource is the golang structure of table data_source for DAO operations like Where/Data. +type DataSource struct { + g.Meta `orm:"table:data_source, do:true"` + SourceId interface{} // + Name interface{} // 数据源名称 + Key interface{} // 数据源标识 + Desc interface{} // 描述 + From interface{} // 数据来源:1=api导入,2=数据库,3=文件,4=设备 + Config interface{} // 数据源配置json:api配置、数据库配置、文件配置 + Rule interface{} // 规则配置json + LockKey interface{} // 锁定key标识:0=未锁定,1=锁定,不允许修改 + Status interface{} // 状态:0=未发布,1=已发布 + DataTable interface{} // 数据表名称 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/data_template.go b/internal/model/do/data_template.go new file mode 100644 index 0000000..0a12669 --- /dev/null +++ b/internal/model/do/data_template.go @@ -0,0 +1,33 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplate is the golang structure of table data_template for DAO operations like Where/Data. +type DataTemplate struct { + g.Meta `orm:"table:data_template, do:true"` + Id interface{} // ID + Name interface{} // 名称 + Key interface{} // 标识 + Desc interface{} // 描述 + Status interface{} // 状态:0=未发布,1=已发布 + CronExpression interface{} // cron执行表达式 + SortNodeKey interface{} // 排序节点标识 + SortDesc interface{} // 排序方式:1=倒序,2=正序 + DataTable interface{} // 数据表名称 + LockKey interface{} // 锁定key标识:0=未锁定,1=锁定,不允许修改 + MainSourceId interface{} // 主数据源 + SourceNodeKey interface{} // 数据源关联节点 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/data_template_busi.go b/internal/model/do/data_template_busi.go new file mode 100644 index 0000000..61541a5 --- /dev/null +++ b/internal/model/do/data_template_busi.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplateBusi is the golang structure of table data_template_busi for DAO operations like Where/Data. +type DataTemplateBusi struct { + g.Meta `orm:"table:data_template_busi, do:true"` + Id interface{} // + DataTemplateId interface{} // 数据建模ID + BusiTypes interface{} // 业务单元 + IsDeleted interface{} // 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/data_template_node.go b/internal/model/do/data_template_node.go new file mode 100644 index 0000000..027b5a8 --- /dev/null +++ b/internal/model/do/data_template_node.go @@ -0,0 +1,33 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplateNode is the golang structure of table data_template_node for DAO operations like Where/Data. +type DataTemplateNode struct { + g.Meta `orm:"table:data_template_node, do:true"` + Id interface{} // ID + Tid interface{} // 模型ID + From interface{} // 字段生成方式:1=自动生成,2=数据源 + SourceId interface{} // 数据源ID + NodeId interface{} // 数据源ID + Name interface{} // 节点名称 + Key interface{} // 节点标识 + DataType interface{} // 数据类型 + Default interface{} // 默认值 + Method interface{} // 数值类型,取值方式 + IsPk interface{} // 是否主键:0=否,1=是 + Desc interface{} // 描述 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/dev_device.go b/internal/model/do/dev_device.go new file mode 100644 index 0000000..4cd4c26 --- /dev/null +++ b/internal/model/do/dev_device.go @@ -0,0 +1,34 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DevDevice is the golang structure of table dev_device for DAO operations like Where/Data. +type DevDevice struct { + g.Meta `orm:"table:dev_device, do:true"` + Id interface{} // + Key interface{} // 设备标识 + Name interface{} // 设备名称 + ProductId interface{} // 所属产品 + Desc interface{} // 描述 + MetadataTable interface{} // 是否生成物模型子表:0=否,1=是 + Status interface{} // 状态:0=未启用,1=离线,2=在线 + RegistryTime *gtime.Time // 激活时间 + LastOnlineTime *gtime.Time // 最后上线时间 + Certificate interface{} // 设备证书 + SecureKey interface{} // 设备密钥 + Version interface{} // 固件版本号 + TunnelId interface{} // tunnelId + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/dev_device_tag.go b/internal/model/do/dev_device_tag.go new file mode 100644 index 0000000..26f7a63 --- /dev/null +++ b/internal/model/do/dev_device_tag.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DevDeviceTag is the golang structure of table dev_device_tag for DAO operations like Where/Data. +type DevDeviceTag struct { + g.Meta `orm:"table:dev_device_tag, do:true"` + Id interface{} // + DeviceId interface{} // 设备ID + DeviceKey interface{} // 设备标识 + Key interface{} // 标签标识 + Name interface{} // 标签名称 + Value interface{} // 标签值 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/dev_product.go b/internal/model/do/dev_product.go new file mode 100644 index 0000000..9c86712 --- /dev/null +++ b/internal/model/do/dev_product.go @@ -0,0 +1,35 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DevProduct is the golang structure of table dev_product for DAO operations like Where/Data. +type DevProduct struct { + g.Meta `orm:"table:dev_product, do:true"` + Id interface{} // + Key interface{} // 产品标识 + Name interface{} // 产品名称 + CategoryId interface{} // 所属品类 + MessageProtocol interface{} // 消息协议 + TransportProtocol interface{} // 传输协议: MQTT,COAP,UDP + ProtocolId interface{} // 协议id + DeviceType interface{} // 设备类型: 网关,设备 + Desc interface{} // 描述 + Icon interface{} // 图片地址 + Metadata interface{} // 物模型 + MetadataTable interface{} // 是否生成物模型表:0=否,1=是 + Policy interface{} // 采集策略 + Status interface{} // 发布状态:0=未发布,1=已发布 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/dev_product_category.go b/internal/model/do/dev_product_category.go new file mode 100644 index 0000000..86035fe --- /dev/null +++ b/internal/model/do/dev_product_category.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// DevProductCategory is the golang structure of table dev_product_category for DAO operations like Where/Data. +type DevProductCategory struct { + g.Meta `orm:"table:dev_product_category, do:true"` + Id interface{} // + ParentId interface{} // 父ID + Key interface{} // 分类标识 + Name interface{} // 分类名称 + Desc interface{} // 描述 + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + DeletedBy interface{} // 删除者 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/network_server.go b/internal/model/do/network_server.go new file mode 100644 index 0000000..f0c9100 --- /dev/null +++ b/internal/model/do/network_server.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NetworkServer is the golang structure of table network_server for DAO operations like Where/Data. +type NetworkServer struct { + g.Meta `orm:"table:network_server, do:true"` + Id interface{} // + Name interface{} // + Types interface{} // tcp/udp + Addr interface{} // + Register interface{} // 注册包 + Heartbeat interface{} // 心跳包 + Protocol interface{} // 协议 + Devices interface{} // 默认设备 + Status interface{} // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // + CreateBy interface{} // + Remark interface{} // 备注 +} diff --git a/internal/model/do/network_tunnel.go b/internal/model/do/network_tunnel.go new file mode 100644 index 0000000..23ec00a --- /dev/null +++ b/internal/model/do/network_tunnel.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NetworkTunnel is the golang structure of table network_tunnel for DAO operations like Where/Data. +type NetworkTunnel struct { + g.Meta `orm:"table:network_tunnel, do:true"` + Id interface{} // + ServerId interface{} // 服务ID + Name interface{} // + Types interface{} // + Addr interface{} // + Remote interface{} // + Retry interface{} // 断线重连 + Heartbeat interface{} // 心跳包 + Serial interface{} // 串口参数 + Protoccol interface{} // 适配协议 + DeviceKey interface{} // 设备标识 + Status interface{} // + Last *gtime.Time // + CreatedAt *gtime.Time // + UpdatedAt *gtime.Time // + Remark interface{} // 备注 +} diff --git a/internal/model/do/notice_config.go b/internal/model/do/notice_config.go new file mode 100644 index 0000000..0d51324 --- /dev/null +++ b/internal/model/do/notice_config.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeConfig is the golang structure of table notice_config for DAO operations like Where/Data. +type NoticeConfig struct { + g.Meta `orm:"table:notice_config, do:true"` + Id interface{} // + Title interface{} // + SendGateway interface{} // + Types interface{} // + CreatedAt *gtime.Time // +} diff --git a/internal/model/do/notice_info.go b/internal/model/do/notice_info.go new file mode 100644 index 0000000..01676e7 --- /dev/null +++ b/internal/model/do/notice_info.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeInfo is the golang structure of table notice_info for DAO operations like Where/Data. +type NoticeInfo struct { + g.Meta `orm:"table:notice_info, do:true"` + Id interface{} // + ConfigId interface{} // + ComeFrom interface{} // + Method interface{} // + MsgTitle interface{} // + MsgBody interface{} // + MsgUrl interface{} // + UserIds interface{} // + OrgIds interface{} // + Totag interface{} // + Status interface{} // + MethodCron interface{} // + MethodNum interface{} // + CreatedAt *gtime.Time // +} diff --git a/internal/model/do/notice_log.go b/internal/model/do/notice_log.go new file mode 100644 index 0000000..8a80432 --- /dev/null +++ b/internal/model/do/notice_log.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeLog is the golang structure of table notice_log for DAO operations like Where/Data. +type NoticeLog struct { + g.Meta `orm:"table:notice_log, do:true"` + Id interface{} // + SendGateway interface{} // 通知渠道 + TemplateId interface{} // 通知模板ID + Addressee interface{} // 收信人列表 + Title interface{} // 通知标题 + Content interface{} // 通知内容 + Status interface{} // 发送状态:0=失败,1=成功 + FailMsg interface{} // 失败信息 + SendTime *gtime.Time // 发送时间 +} diff --git a/internal/model/do/notice_template.go b/internal/model/do/notice_template.go new file mode 100644 index 0000000..57787d1 --- /dev/null +++ b/internal/model/do/notice_template.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeTemplate is the golang structure of table notice_template for DAO operations like Where/Data. +type NoticeTemplate struct { + g.Meta `orm:"table:notice_template, do:true"` + Id interface{} // + ConfigId interface{} // + SendGateway interface{} // + Code interface{} // + Title interface{} // + Content interface{} // + CreatedAt *gtime.Time // +} diff --git a/internal/model/do/sys_api.go b/internal/model/do/sys_api.go new file mode 100644 index 0000000..b700752 --- /dev/null +++ b/internal/model/do/sys_api.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysApi is the golang structure of table sys_api for DAO operations like Where/Data. +type SysApi struct { + g.Meta `orm:"table:sys_api, do:true"` + Id interface{} // + ParentId interface{} // + Name interface{} // 名称 + Types interface{} // 1 分类 2接口 + Method interface{} // 请求方式(数据字典维护) + Address interface{} // 接口地址 + Remark interface{} // 备注 + Status interface{} // 状态 0 停用 1启用 + Sort interface{} // 排序 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_authorize.go b/internal/model/do/sys_authorize.go new file mode 100644 index 0000000..6cd05aa --- /dev/null +++ b/internal/model/do/sys_authorize.go @@ -0,0 +1,25 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysAuthorize is the golang structure of table sys_authorize for DAO operations like Where/Data. +type SysAuthorize struct { + g.Meta `orm:"table:sys_authorize, do:true"` + Id interface{} // + RoleId interface{} // 角色ID + ItemsType interface{} // 项目类型 menu菜单 button按钮 column列表字段 api接口 + ItemsId interface{} // 项目ID + IsCheckAll interface{} // 是否全选 1是 0否 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_config.go b/internal/model/do/sys_config.go new file mode 100644 index 0000000..8c4a61b --- /dev/null +++ b/internal/model/do/sys_config.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysConfig is the golang structure of table sys_config for DAO operations like Where/Data. +type SysConfig struct { + g.Meta `orm:"table:sys_config, do:true"` + ConfigId interface{} // 参数主键 + ConfigName interface{} // 参数名称 + ConfigKey interface{} // 参数键名 + ConfigValue interface{} // 参数键值 + ConfigType interface{} // 系统内置(1是 2否) + Remark interface{} // 备注 + Status interface{} // 状态 0 停用 1启用 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建时间 + UpdateBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_dept.go b/internal/model/do/sys_dept.go new file mode 100644 index 0000000..82d53b0 --- /dev/null +++ b/internal/model/do/sys_dept.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDept is the golang structure of table sys_dept for DAO operations like Where/Data. +type SysDept struct { + g.Meta `orm:"table:sys_dept, do:true"` + DeptId interface{} // 部门id + OrganizationId interface{} // 组织ID + ParentId interface{} // 父部门id + Ancestors interface{} // 祖级列表 + DeptName interface{} // 部门名称 + OrderNum interface{} // 显示顺序 + Leader interface{} // 负责人 + Phone interface{} // 联系电话 + Email interface{} // 邮箱 + Status interface{} // 部门状态(0停用 1正常) + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedAt *gtime.Time // 创建时间 + CreatedBy interface{} // 创建人 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_dict_data.go b/internal/model/do/sys_dict_data.go new file mode 100644 index 0000000..8089d84 --- /dev/null +++ b/internal/model/do/sys_dict_data.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictData is the golang structure of table sys_dict_data for DAO operations like Where/Data. +type SysDictData struct { + g.Meta `orm:"table:sys_dict_data, do:true"` + DictCode interface{} // 字典编码 + DictSort interface{} // 字典排序 + DictLabel interface{} // 字典标签 + DictValue interface{} // 字典键值 + DictType interface{} // 字典类型 + CssClass interface{} // 样式属性(其他样式扩展) + ListClass interface{} // 表格回显样式 + IsDefault interface{} // 是否默认(1是 0否) + Remark interface{} // 备注 + Status interface{} // 状态(0正常 1停用) + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建时间 + UpdateBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_dict_type.go b/internal/model/do/sys_dict_type.go new file mode 100644 index 0000000..ed6d4b9 --- /dev/null +++ b/internal/model/do/sys_dict_type.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictType is the golang structure of table sys_dict_type for DAO operations like Where/Data. +type SysDictType struct { + g.Meta `orm:"table:sys_dict_type, do:true"` + DictId interface{} // 字典主键 + ParentId interface{} // 父主键ID + DictName interface{} // 字典名称 + DictType interface{} // 字典类型 + ModuleClassify interface{} // 模块分类 + Remark interface{} // 备注 + Status interface{} // 状态(0正常 1停用) + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建日期 + UpdateBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改日期 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_job.go b/internal/model/do/sys_job.go new file mode 100644 index 0000000..d0c229b --- /dev/null +++ b/internal/model/do/sys_job.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysJob is the golang structure of table sys_job for DAO operations like Where/Data. +type SysJob struct { + g.Meta `orm:"table:sys_job, do:true"` + JobId interface{} // 任务ID + JobName interface{} // 任务名称 + JobParams interface{} // 参数 + JobGroup interface{} // 任务组名 + InvokeTarget interface{} // 调用目标字符串 + CronExpression interface{} // cron执行表达式 + MisfirePolicy interface{} // 计划执行策略(1多次执行 2执行一次) + Concurrent interface{} // 是否并发执行(0允许 1禁止) + Status interface{} // 状态(0正常 1暂停) + CreateBy interface{} // 创建者 + UpdateBy interface{} // 更新者 + Remark interface{} // 备注信息 + CreatedAt *gtime.Time // 创建时间 + UpdatedAt *gtime.Time // 更新时间 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_login_log.go b/internal/model/do/sys_login_log.go new file mode 100644 index 0000000..8fd6538 --- /dev/null +++ b/internal/model/do/sys_login_log.go @@ -0,0 +1,25 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysLoginLog is the golang structure of table sys_login_log for DAO operations like Where/Data. +type SysLoginLog struct { + g.Meta `orm:"table:sys_login_log, do:true"` + InfoId interface{} // 访问ID + LoginName interface{} // 登录账号 + Ipaddr interface{} // 登录IP地址 + LoginLocation interface{} // 登录地点 + Browser interface{} // 浏览器类型 + Os interface{} // 操作系统 + Status interface{} // 登录状态(0成功 1失败) + Msg interface{} // 提示消息 + LoginTime *gtime.Time // 登录时间 + Module interface{} // 登录模块 +} diff --git a/internal/model/do/sys_menu.go b/internal/model/do/sys_menu.go new file mode 100644 index 0000000..9166259 --- /dev/null +++ b/internal/model/do/sys_menu.go @@ -0,0 +1,43 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenu is the golang structure of table sys_menu for DAO operations like Where/Data. +type SysMenu struct { + g.Meta `orm:"table:sys_menu, do:true"` + Id interface{} // + ParentId interface{} // 父ID + Name interface{} // 规则名称 + Title interface{} // 规则名称 + Icon interface{} // 图标 + Condition interface{} // 条件 + Remark interface{} // 备注 + MenuType interface{} // 类型 0目录 1菜单 2按钮 + Weigh interface{} // 权重 + IsHide interface{} // 显示状态 + Path interface{} // 路由地址 + Component interface{} // 组件路径 + IsLink interface{} // 是否外链 1是 0否 + ModuleType interface{} // 所属模块 system 运维 company企业 + ModelId interface{} // 模型ID + IsIframe interface{} // 是否内嵌iframe + IsCached interface{} // 是否缓存 + Redirect interface{} // 路由重定向地址 + IsAffix interface{} // 是否固定 + LinkUrl interface{} // 链接地址 + Status interface{} // 状态 0 停用 1启用 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 更新时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_menu_api.go b/internal/model/do/sys_menu_api.go new file mode 100644 index 0000000..8f4ed33 --- /dev/null +++ b/internal/model/do/sys_menu_api.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuApi is the golang structure of table sys_menu_api for DAO operations like Where/Data. +type SysMenuApi struct { + g.Meta `orm:"table:sys_menu_api, do:true"` + Id interface{} // id + MenuId interface{} // 菜单ID + ApiId interface{} // apiId + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_menu_button.go b/internal/model/do/sys_menu_button.go new file mode 100644 index 0000000..9ebeeff --- /dev/null +++ b/internal/model/do/sys_menu_button.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuButton is the golang structure of table sys_menu_button for DAO operations like Where/Data. +type SysMenuButton struct { + g.Meta `orm:"table:sys_menu_button, do:true"` + Id interface{} // + ParentId interface{} // 父ID + MenuId interface{} // 菜单ID + Name interface{} // 名称 + Types interface{} // 类型 自定义 add添加 edit编辑 del 删除 + Description interface{} // 描述 + Status interface{} // 状态 0 停用 1启用 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 更新时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_menu_column.go b/internal/model/do/sys_menu_column.go new file mode 100644 index 0000000..7852da9 --- /dev/null +++ b/internal/model/do/sys_menu_column.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuColumn is the golang structure of table sys_menu_column for DAO operations like Where/Data. +type SysMenuColumn struct { + g.Meta `orm:"table:sys_menu_column, do:true"` + Id interface{} // + ParentId interface{} // 父ID + MenuId interface{} // 菜单ID + Name interface{} // 名称 + Code interface{} // 代表字段 + Description interface{} // 描述 + Status interface{} // 状态 0 停用 1启用 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 更新时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_notifications.go b/internal/model/do/sys_notifications.go new file mode 100644 index 0000000..2f92622 --- /dev/null +++ b/internal/model/do/sys_notifications.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysNotifications is the golang structure of table sys_notifications for DAO operations like Where/Data. +type SysNotifications struct { + g.Meta `orm:"table:sys_notifications, do:true"` + Id interface{} // + Title interface{} // 标题 + Doc interface{} // 描述 + Source interface{} // 消息来源 + Types interface{} // 类型 + CreatedAt *gtime.Time // 发送时间 + Status interface{} // 0,未读,1,已读 +} diff --git a/internal/model/do/sys_oper_log.go b/internal/model/do/sys_oper_log.go new file mode 100644 index 0000000..d8180e6 --- /dev/null +++ b/internal/model/do/sys_oper_log.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysOperLog is the golang structure of table sys_oper_log for DAO operations like Where/Data. +type SysOperLog struct { + g.Meta `orm:"table:sys_oper_log, do:true"` + OperId interface{} // 日志主键 + Title interface{} // 模块标题 + BusinessType interface{} // 业务类型(0其它 1新增 2修改 3删除) + Method interface{} // 方法名称 + RequestMethod interface{} // 请求方式 + OperatorType interface{} // 操作类别(0其它 1后台用户 2手机端用户) + OperName interface{} // 操作人员 + DeptName interface{} // 部门名称 + OperUrl interface{} // 请求URL + OperIp interface{} // 主机地址 + OperLocation interface{} // 操作地点 + OperParam interface{} // 请求参数 + JsonResult interface{} // 返回参数 + Status interface{} // 操作状态(0正常 1异常) + ErrorMsg interface{} // 错误消息 + OperTime *gtime.Time // 操作时间 +} diff --git a/internal/model/do/sys_organization.go b/internal/model/do/sys_organization.go new file mode 100644 index 0000000..1e34785 --- /dev/null +++ b/internal/model/do/sys_organization.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysOrganization is the golang structure of table sys_organization for DAO operations like Where/Data. +type SysOrganization struct { + g.Meta `orm:"table:sys_organization, do:true"` + Id interface{} // 组织ID + ParentId interface{} // 父组织id + Ancestors interface{} // 祖级列表 + Name interface{} // 组织名称 + Number interface{} // 组织编号 + OrderNum interface{} // 显示顺序 + Leader interface{} // 负责人 + Phone interface{} // 联系电话 + Email interface{} // 邮箱 + Status interface{} // 组织状态(0停用 1正常) + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedAt *gtime.Time // 创建时间 + CreatedBy interface{} // 创建人 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_plugins.go b/internal/model/do/sys_plugins.go new file mode 100644 index 0000000..0bcbd00 --- /dev/null +++ b/internal/model/do/sys_plugins.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysPlugins is the golang structure of table sys_plugins for DAO operations like Where/Data. +type SysPlugins struct { + g.Meta `orm:"table:sys_plugins, do:true"` + Id interface{} // ID + Name interface{} // 名称 + Title interface{} // 标题 + Intro interface{} // 介绍 + Version interface{} // 版本 + Status interface{} // 状态 + Types interface{} // 插件类型 + Author interface{} // + StartTime *gtime.Time // +} diff --git a/internal/model/do/sys_plugins_config.go b/internal/model/do/sys_plugins_config.go new file mode 100644 index 0000000..755e63e --- /dev/null +++ b/internal/model/do/sys_plugins_config.go @@ -0,0 +1,19 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SysPluginsConfig is the golang structure of table sys_plugins_config for DAO operations like Where/Data. +type SysPluginsConfig struct { + g.Meta `orm:"table:sys_plugins_config, do:true"` + Id interface{} // + Type interface{} // 插件类型 + Name interface{} // 插件名称 + Value interface{} // 配置内容 + Doc interface{} // 配置说明 +} diff --git a/internal/model/do/sys_post.go b/internal/model/do/sys_post.go new file mode 100644 index 0000000..126ddde --- /dev/null +++ b/internal/model/do/sys_post.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysPost is the golang structure of table sys_post for DAO operations like Where/Data. +type SysPost struct { + g.Meta `orm:"table:sys_post, do:true"` + PostId interface{} // 岗位ID + ParentId interface{} // 父ID + PostCode interface{} // 岗位编码 + PostName interface{} // 岗位名称 + PostSort interface{} // 显示顺序 + Status interface{} // 状态(0正常 1停用) + Remark interface{} // 备注 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreatedBy interface{} // 创建人 + CreatedAt *gtime.Time // 创建时间 + UpdatedBy interface{} // 修改人 + UpdatedAt *gtime.Time // 修改时间 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_role.go b/internal/model/do/sys_role.go new file mode 100644 index 0000000..98581e7 --- /dev/null +++ b/internal/model/do/sys_role.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysRole is the golang structure of table sys_role for DAO operations like Where/Data. +type SysRole struct { + g.Meta `orm:"table:sys_role, do:true"` + Id interface{} // + ParentId interface{} // 父ID + ListOrder interface{} // 排序 + Name interface{} // 角色名称 + DataScope interface{} // 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + Remark interface{} // 备注 + Status interface{} // 状态;0:禁用;1:正常 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建日期 + UpdateBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改日期 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_role_dept.go b/internal/model/do/sys_role_dept.go new file mode 100644 index 0000000..df1a1ad --- /dev/null +++ b/internal/model/do/sys_role_dept.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SysRoleDept is the golang structure of table sys_role_dept for DAO operations like Where/Data. +type SysRoleDept struct { + g.Meta `orm:"table:sys_role_dept, do:true"` + RoleId interface{} // 角色ID + DeptId interface{} // 部门ID +} diff --git a/internal/model/do/sys_user.go b/internal/model/do/sys_user.go new file mode 100644 index 0000000..835e444 --- /dev/null +++ b/internal/model/do/sys_user.go @@ -0,0 +1,41 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysUser is the golang structure of table sys_user for DAO operations like Where/Data. +type SysUser struct { + g.Meta `orm:"table:sys_user, do:true"` + Id interface{} // + UserName interface{} // 用户名 + UserTypes interface{} // 系统 system 企业 company + Mobile interface{} // 中国手机不带国家代码,国际手机号格式为:国家代码-手机号 + UserNickname interface{} // 用户昵称 + Birthday interface{} // 生日 + UserPassword interface{} // 登录密码;cmf_password加密 + UserSalt interface{} // 加密盐 + UserEmail interface{} // 用户登录邮箱 + Sex interface{} // 性别;0:保密,1:男,2:女 + Avatar interface{} // 用户头像 + DeptId interface{} // 部门id + Remark interface{} // 备注 + IsAdmin interface{} // 是否后台管理员 1 是 0 否 + Address interface{} // 联系地址 + Describe interface{} // 描述信息 + LastLoginIp interface{} // 最后登录ip + LastLoginTime *gtime.Time // 最后登录时间 + Status interface{} // 用户状态;0:禁用,1:正常,2:未验证 + IsDeleted interface{} // 是否删除 0未删除 1已删除 + CreateBy interface{} // 创建者 + CreatedAt *gtime.Time // 创建日期 + UpdateBy interface{} // 更新者 + UpdatedAt *gtime.Time // 修改日期 + DeletedBy interface{} // 删除人 + DeletedAt *gtime.Time // 删除时间 +} diff --git a/internal/model/do/sys_user_online.go b/internal/model/do/sys_user_online.go new file mode 100644 index 0000000..5e10120 --- /dev/null +++ b/internal/model/do/sys_user_online.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// SysUserOnline is the golang structure of table sys_user_online for DAO operations like Where/Data. +type SysUserOnline struct { + g.Meta `orm:"table:sys_user_online, do:true"` + Id interface{} // + Uuid interface{} // 用户标识 + Key interface{} // + Token interface{} // 用户token + CreatedAt *gtime.Time // 登录时间 + UserName interface{} // 用户名 + Ip interface{} // 登录ip + Explorer interface{} // 浏览器 + Os interface{} // 操作系统 +} diff --git a/internal/model/do/sys_user_post.go b/internal/model/do/sys_user_post.go new file mode 100644 index 0000000..a06c02d --- /dev/null +++ b/internal/model/do/sys_user_post.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserPost is the golang structure of table sys_user_post for DAO operations like Where/Data. +type SysUserPost struct { + g.Meta `orm:"table:sys_user_post, do:true"` + UserId interface{} // 用户ID + PostId interface{} // 岗位ID +} diff --git a/internal/model/do/sys_user_role.go b/internal/model/do/sys_user_role.go new file mode 100644 index 0000000..de3ce76 --- /dev/null +++ b/internal/model/do/sys_user_role.go @@ -0,0 +1,16 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +// SysUserRole is the golang structure of table sys_user_role for DAO operations like Where/Data. +type SysUserRole struct { + g.Meta `orm:"table:sys_user_role, do:true"` + UserId interface{} // + RoleId interface{} // +} diff --git a/internal/model/entity/alarm_level.go b/internal/model/entity/alarm_level.go new file mode 100644 index 0000000..0ecdadb --- /dev/null +++ b/internal/model/entity/alarm_level.go @@ -0,0 +1,11 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +// AlarmLevel is the golang structure for table alarm_level. +type AlarmLevel struct { + Level uint `json:"level" description:"告警级别"` + Name string `json:"name" description:"名称"` +} diff --git a/internal/model/entity/alarm_log.go b/internal/model/entity/alarm_log.go new file mode 100644 index 0000000..985ffbc --- /dev/null +++ b/internal/model/entity/alarm_log.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// AlarmLog is the golang structure for table alarm_log. +type AlarmLog struct { + Id int64 `json:"id" description:""` + Type uint `json:"type" description:"告警类型:1=规则告警,2=设备自主告警"` + RuleId uint64 `json:"ruleId" description:"规则id"` + RuleName string `json:"ruleName" description:"规则名称"` + Level uint `json:"level" description:"告警级别"` + Data string `json:"data" description:"触发告警的数据"` + ProductKey string `json:"productKey" description:"产品标识"` + DeviceKey string `json:"deviceKey" description:"设备标识"` + Status int `json:"status" description:"告警状态:0=未处理,1=已处理"` + CreatedAt *gtime.Time `json:"createdAt" description:"告警时间"` + UpdateBy uint `json:"updateBy" description:"告警处理人员"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"处理时间"` + Content string `json:"content" description:"处理意见"` +} diff --git a/internal/model/entity/alarm_rule.go b/internal/model/entity/alarm_rule.go new file mode 100644 index 0000000..24bcb52 --- /dev/null +++ b/internal/model/entity/alarm_rule.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// AlarmRule is the golang structure for table alarm_rule. +type AlarmRule struct { + Id uint64 `json:"id" description:""` + Name string `json:"name" description:"告警规则名称"` + Level uint `json:"level" description:"告警级别,默认:4(一般)"` + ProductKey string `json:"productKey" description:"产品标识"` + DeviceKey string `json:"deviceKey" description:"设备标识"` + TriggerType int `json:"triggerType" description:"触发类型:1=上线,2=离线,3=属性上报"` + TriggerCondition string `json:"triggerCondition" description:"触发条件"` + Action string `json:"action" description:"执行动作"` + Status int `json:"status" description:"状态:0=未启用,1=已启用"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/base_db_link.go b/internal/model/entity/base_db_link.go new file mode 100644 index 0000000..986be49 --- /dev/null +++ b/internal/model/entity/base_db_link.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// BaseDbLink is the golang structure for table base_db_link. +type BaseDbLink struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"驱动类型 mysql或oracle"` + Host string `json:"host" description:"主机地址"` + Port int `json:"port" description:"端口号"` + UserName string `json:"userName" description:"用户名称"` + Password string `json:"password" description:"密码"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/city_data.go b/internal/model/entity/city_data.go new file mode 100644 index 0000000..2e4e014 --- /dev/null +++ b/internal/model/entity/city_data.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// CityData is the golang structure for table city_data. +type CityData struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + ParentId int `json:"parentId" description:"父ID"` + Sort int `json:"sort" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdatedBy uint `json:"updatedBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/data_node.go b/internal/model/entity/data_node.go new file mode 100644 index 0000000..f18f5ad --- /dev/null +++ b/internal/model/entity/data_node.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DataNode is the golang structure for table data_node. +type DataNode struct { + NodeId uint64 `json:"nodeId" description:""` + SourceId uint64 `json:"sourceId" description:"数据源ID"` + Name string `json:"name" description:"数据节点名称"` + Key string `json:"key" description:"数据节点标识"` + DataType string `json:"dataType" description:"数据类型"` + Value string `json:"value" description:"取值项"` + IsPk int `json:"isPk" description:"是否主键:0=否,1=是"` + Rule string `json:"rule" description:"规则配置json"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/data_source.go b/internal/model/entity/data_source.go new file mode 100644 index 0000000..1fb193a --- /dev/null +++ b/internal/model/entity/data_source.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DataSource is the golang structure for table data_source. +type DataSource struct { + SourceId uint64 `json:"sourceId" description:""` + Name string `json:"name" description:"数据源名称"` + Key string `json:"key" description:"数据源标识"` + Desc string `json:"desc" description:"描述"` + From int `json:"from" description:"数据来源:1=api导入,2=数据库,3=文件,4=设备"` + Config string `json:"config" description:"数据源配置json:api配置、数据库配置、文件配置"` + Rule string `json:"rule" description:"规则配置json"` + LockKey int `json:"lockKey" description:"锁定key标识:0=未锁定,1=锁定,不允许修改"` + Status int `json:"status" description:"状态:0=未发布,1=已发布"` + DataTable string `json:"dataTable" description:"数据表名称"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/data_template.go b/internal/model/entity/data_template.go new file mode 100644 index 0000000..3151baf --- /dev/null +++ b/internal/model/entity/data_template.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplate is the golang structure for table data_template. +type DataTemplate struct { + Id uint64 `json:"id" description:"ID"` + Name string `json:"name" description:"名称"` + Key string `json:"key" description:"标识"` + Desc string `json:"desc" description:"描述"` + Status int `json:"status" description:"状态:0=未发布,1=已发布"` + CronExpression string `json:"cronExpression" description:"cron执行表达式"` + SortNodeKey string `json:"sortNodeKey" description:"排序节点标识"` + SortDesc int `json:"sortDesc" description:"排序方式:1=倒序,2=正序"` + DataTable string `json:"dataTable" description:"数据表名称"` + LockKey int `json:"lockKey" description:"锁定key标识:0=未锁定,1=锁定,不允许修改"` + MainSourceId uint64 `json:"mainSourceId" description:"主数据源"` + SourceNodeKey string `json:"sourceNodeKey" description:"数据源关联节点"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/data_template_busi.go b/internal/model/entity/data_template_busi.go new file mode 100644 index 0000000..4324114 --- /dev/null +++ b/internal/model/entity/data_template_busi.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplateBusi is the golang structure for table data_template_busi. +type DataTemplateBusi struct { + Id int `json:"id" description:""` + DataTemplateId int `json:"dataTemplateId" description:"数据建模ID"` + BusiTypes int `json:"busiTypes" description:"业务单元"` + IsDeleted int `json:"isDeleted" description:"0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/data_template_node.go b/internal/model/entity/data_template_node.go new file mode 100644 index 0000000..c2a70e3 --- /dev/null +++ b/internal/model/entity/data_template_node.go @@ -0,0 +1,31 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DataTemplateNode is the golang structure for table data_template_node. +type DataTemplateNode struct { + Id uint64 `json:"id" description:"ID"` + Tid uint64 `json:"tid" description:"模型ID"` + From int `json:"from" description:"字段生成方式:1=自动生成,2=数据源"` + SourceId uint64 `json:"sourceId" description:"数据源ID"` + NodeId uint64 `json:"nodeId" description:"数据源ID"` + Name string `json:"name" description:"节点名称"` + Key string `json:"key" description:"节点标识"` + DataType string `json:"dataType" description:"数据类型"` + Default string `json:"default" description:"默认值"` + Method string `json:"method" description:"数值类型,取值方式"` + IsPk int `json:"isPk" description:"是否主键:0=否,1=是"` + Desc string `json:"desc" description:"描述"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/dev_device.go b/internal/model/entity/dev_device.go new file mode 100644 index 0000000..3f655b6 --- /dev/null +++ b/internal/model/entity/dev_device.go @@ -0,0 +1,32 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DevDevice is the golang structure for table dev_device. +type DevDevice struct { + Id uint `json:"id" description:""` + Key string `json:"key" description:"设备标识"` + Name string `json:"name" description:"设备名称"` + ProductId uint `json:"productId" description:"所属产品"` + Desc string `json:"desc" description:"描述"` + MetadataTable int `json:"metadataTable" description:"是否生成物模型子表:0=否,1=是"` + Status int `json:"status" description:"状态:0=未启用,1=离线,2=在线"` + RegistryTime *gtime.Time `json:"registryTime" description:"激活时间"` + LastOnlineTime *gtime.Time `json:"lastOnlineTime" description:"最后上线时间"` + Certificate string `json:"certificate" description:"设备证书"` + SecureKey string `json:"secureKey" description:"设备密钥"` + Version string `json:"version" description:"固件版本号"` + TunnelId int `json:"tunnelId" description:"tunnelId"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/dev_device_tag.go b/internal/model/entity/dev_device_tag.go new file mode 100644 index 0000000..0cb8427 --- /dev/null +++ b/internal/model/entity/dev_device_tag.go @@ -0,0 +1,25 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DevDeviceTag is the golang structure for table dev_device_tag. +type DevDeviceTag struct { + Id uint `json:"id" description:""` + DeviceId uint `json:"deviceId" description:"设备ID"` + DeviceKey string `json:"deviceKey" description:"设备标识"` + Key string `json:"key" description:"标签标识"` + Name string `json:"name" description:"标签名称"` + Value string `json:"value" description:"标签值"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/dev_product.go b/internal/model/entity/dev_product.go new file mode 100644 index 0000000..b7d6b22 --- /dev/null +++ b/internal/model/entity/dev_product.go @@ -0,0 +1,33 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DevProduct is the golang structure for table dev_product. +type DevProduct struct { + Id uint `json:"id" description:""` + Key string `json:"key" description:"产品标识"` + Name string `json:"name" description:"产品名称"` + CategoryId uint `json:"categoryId" description:"所属品类"` + MessageProtocol string `json:"messageProtocol" description:"消息协议"` + TransportProtocol string `json:"transportProtocol" description:"传输协议: MQTT,COAP,UDP"` + ProtocolId uint `json:"protocolId" description:"协议id"` + DeviceType string `json:"deviceType" description:"设备类型: 网关,设备"` + Desc string `json:"desc" description:"描述"` + Icon string `json:"icon" description:"图片地址"` + Metadata string `json:"metadata" description:"物模型"` + MetadataTable int `json:"metadataTable" description:"是否生成物模型表:0=否,1=是"` + Policy string `json:"policy" description:"采集策略"` + Status int `json:"status" description:"发布状态:0=未发布,1=已发布"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/dev_product_category.go b/internal/model/entity/dev_product_category.go new file mode 100644 index 0000000..54313fb --- /dev/null +++ b/internal/model/entity/dev_product_category.go @@ -0,0 +1,24 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// DevProductCategory is the golang structure for table dev_product_category. +type DevProductCategory struct { + Id uint `json:"id" description:""` + ParentId uint `json:"parentId" description:"父ID"` + Key string `json:"key" description:"分类标识"` + Name string `json:"name" description:"分类名称"` + Desc string `json:"desc" description:"描述"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + DeletedBy uint `json:"deletedBy" description:"删除者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/gen_table.go b/internal/model/entity/gen_table.go new file mode 100644 index 0000000..6d4ae05 --- /dev/null +++ b/internal/model/entity/gen_table.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// GenTable is the golang structure for table gen_table. +type GenTable struct { + Id int64 `json:"id" description:"编号"` + TableName string `json:"tableName" description:"表名称"` + TableComment string `json:"tableComment" description:"表描述"` + ClassName string `json:"className" description:"实体类名称"` + TplCategory string `json:"tplCategory" description:"使用的模板(crud单表操作 tree树表操作)"` + PackageName string `json:"packageName" description:"生成包路径"` + ModuleName string `json:"moduleName" description:"生成模块名"` + BusinessName string `json:"businessName" description:"生成业务名"` + FunctionName string `json:"functionName" description:"生成功能名"` + FunctionAuthor string `json:"functionAuthor" description:"生成功能作者"` + Options string `json:"options" description:"其它生成选项"` + Remark string `json:"remark" description:"备注"` + CreatedBy int `json:"createdBy" description:"创建人"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` +} diff --git a/internal/model/entity/gen_table_column.go b/internal/model/entity/gen_table_column.go new file mode 100644 index 0000000..435371d --- /dev/null +++ b/internal/model/entity/gen_table_column.go @@ -0,0 +1,41 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// GenTableColumn is the golang structure for table gen_table_column. +type GenTableColumn struct { + Id int64 `json:"id" description:"编号"` + TableId int64 `json:"tableId" description:"归属表编号"` + ColumnName string `json:"columnName" description:"列名称"` + ColumnComment string `json:"columnComment" description:"列描述"` + ColumnType string `json:"columnType" description:"列类型"` + GoType string `json:"goType" description:"Go类型"` + GoField string `json:"goField" description:"Go字段名"` + HtmlField string `json:"htmlField" description:"html字段名"` + IsPk string `json:"isPk" description:"是否主键(1是)"` + IsIncrement string `json:"isIncrement" description:"是否自增(1是)"` + IsRequired string `json:"isRequired" description:"是否必填(1是)"` + IsInsert string `json:"isInsert" description:"是否为插入字段(1是)"` + IsEdit string `json:"isEdit" description:"是否编辑字段(1是)"` + IsList string `json:"isList" description:"是否列表字段(1是)"` + IsQuery string `json:"isQuery" description:"是否查询字段(1是)"` + QueryType string `json:"queryType" description:"查询方式(等于、不等于、大于、小于、范围)"` + HtmlType string `json:"htmlType" description:"显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)"` + DictType string `json:"dictType" description:"字典类型"` + Sort int `json:"sort" description:"排序"` + LinkTableName string `json:"linkTableName" description:"关联表名"` + LinkTableClass string `json:"linkTableClass" description:"关联表类名"` + LinkTablePackage string `json:"linkTablePackage" description:"关联表包名"` + LinkLabelId string `json:"linkLabelId" description:"关联表键名"` + LinkLabelName string `json:"linkLabelName" description:"关联表字段值"` + CreateBy int `json:"createBy" description:"创建者"` + UpdateBy int `json:"updateBy" description:"更新者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` +} diff --git a/internal/model/entity/network_server.go b/internal/model/entity/network_server.go new file mode 100644 index 0000000..d77434a --- /dev/null +++ b/internal/model/entity/network_server.go @@ -0,0 +1,26 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NetworkServer is the golang structure for table network_server. +type NetworkServer struct { + Id int `json:"id" description:""` + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Status int `json:"status" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + CreateBy int `json:"createBy" description:""` + Remark string `json:"remark" description:"备注"` +} diff --git a/internal/model/entity/network_tunnel.go b/internal/model/entity/network_tunnel.go new file mode 100644 index 0000000..e76f96a --- /dev/null +++ b/internal/model/entity/network_tunnel.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NetworkTunnel is the golang structure for table network_tunnel. +type NetworkTunnel struct { + Id int `json:"id" description:""` + ServerId int `json:"serverId" description:"服务ID"` + Name string `json:"name" description:""` + Types string `json:"types" description:""` + Addr string `json:"addr" description:""` + Remote string `json:"remote" description:""` + Retry string `json:"retry" description:"断线重连"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Serial string `json:"serial" description:"串口参数"` + Protoccol string `json:"protoccol" description:"适配协议"` + DeviceKey string `json:"deviceKey" description:"设备标识"` + Status int `json:"status" description:""` + Last *gtime.Time `json:"last" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + Remark string `json:"remark" description:"备注"` +} diff --git a/internal/model/entity/notice_config.go b/internal/model/entity/notice_config.go new file mode 100644 index 0000000..b04644b --- /dev/null +++ b/internal/model/entity/notice_config.go @@ -0,0 +1,18 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeConfig is the golang structure for table notice_config. +type NoticeConfig struct { + Id string `json:"id" description:""` + Title string `json:"title" description:""` + SendGateway string `json:"sendGateway" description:""` + Types int `json:"types" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` +} diff --git a/internal/model/entity/notice_info.go b/internal/model/entity/notice_info.go new file mode 100644 index 0000000..41931e2 --- /dev/null +++ b/internal/model/entity/notice_info.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeInfo is the golang structure for table notice_info. +type NoticeInfo struct { + Id int64 `json:"id" description:""` + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + MsgTitle string `json:"msgTitle" description:""` + MsgBody string `json:"msgBody" description:""` + MsgUrl string `json:"msgUrl" description:""` + UserIds string `json:"userIds" description:""` + OrgIds string `json:"orgIds" description:""` + Totag string `json:"totag" description:""` + Status int `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + MethodNum int `json:"methodNum" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` +} diff --git a/internal/model/entity/notice_log.go b/internal/model/entity/notice_log.go new file mode 100644 index 0000000..64003f2 --- /dev/null +++ b/internal/model/entity/notice_log.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeLog is the golang structure for table notice_log. +type NoticeLog struct { + Id uint64 `json:"id" description:""` + SendGateway string `json:"sendGateway" description:"通知渠道"` + TemplateId string `json:"templateId" description:"通知模板ID"` + Addressee string `json:"addressee" description:"收信人列表"` + Title string `json:"title" description:"通知标题"` + Content string `json:"content" description:"通知内容"` + Status int `json:"status" description:"发送状态:0=失败,1=成功"` + FailMsg string `json:"failMsg" description:"失败信息"` + SendTime *gtime.Time `json:"sendTime" description:"发送时间"` +} diff --git a/internal/model/entity/notice_template.go b/internal/model/entity/notice_template.go new file mode 100644 index 0000000..9be2050 --- /dev/null +++ b/internal/model/entity/notice_template.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// NoticeTemplate is the golang structure for table notice_template. +type NoticeTemplate struct { + Id string `json:"id" description:""` + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` +} diff --git a/internal/model/entity/sys_api.go b/internal/model/entity/sys_api.go new file mode 100644 index 0000000..1ddb638 --- /dev/null +++ b/internal/model/entity/sys_api.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysApi is the golang structure for table sys_api. +type SysApi struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy uint `json:"updatedBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_authorize.go b/internal/model/entity/sys_authorize.go new file mode 100644 index 0000000..a876e14 --- /dev/null +++ b/internal/model/entity/sys_authorize.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysAuthorize is the golang structure for table sys_authorize. +type SysAuthorize struct { + Id int `json:"id" description:""` + RoleId int `json:"roleId" description:"角色ID"` + ItemsType string `json:"itemsType" description:"项目类型 menu菜单 button按钮 column列表字段 api接口"` + ItemsId int `json:"itemsId" description:"项目ID"` + IsCheckAll int `json:"isCheckAll" description:"是否全选 1是 0否"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_config.go b/internal/model/entity/sys_config.go new file mode 100644 index 0000000..7016b70 --- /dev/null +++ b/internal/model/entity/sys_config.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysConfig is the golang structure for table sys_config. +type SysConfig struct { + ConfigId uint `json:"configId" description:"参数主键"` + ConfigName string `json:"configName" description:"参数名称"` + ConfigKey string `json:"configKey" description:"参数键名"` + ConfigValue string `json:"configValue" description:"参数键值"` + ConfigType int `json:"configType" description:"系统内置(1是 2否)"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_dept.go b/internal/model/entity/sys_dept.go new file mode 100644 index 0000000..595ae33 --- /dev/null +++ b/internal/model/entity/sys_dept.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDept is the golang structure for table sys_dept. +type SysDept struct { + DeptId int64 `json:"deptId" description:"部门id"` + OrganizationId int `json:"organizationId" description:"组织ID"` + ParentId int64 `json:"parentId" description:"父部门id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + DeptName string `json:"deptName" description:"部门名称"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + CreatedBy uint `json:"createdBy" description:"创建人"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_dict_data.go b/internal/model/entity/sys_dict_data.go new file mode 100644 index 0000000..fea82b5 --- /dev/null +++ b/internal/model/entity/sys_dict_data.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictData is the golang structure for table sys_dict_data. +type SysDictData struct { + DictCode int64 `json:"dictCode" description:"字典编码"` + DictSort int `json:"dictSort" description:"字典排序"` + DictLabel string `json:"dictLabel" description:"字典标签"` + DictValue string `json:"dictValue" description:"字典键值"` + DictType string `json:"dictType" description:"字典类型"` + CssClass string `json:"cssClass" description:"样式属性(其他样式扩展)"` + ListClass string `json:"listClass" description:"表格回显样式"` + IsDefault int `json:"isDefault" description:"是否默认(1是 0否)"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态(1正常 0停用)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_dict_type.go b/internal/model/entity/sys_dict_type.go new file mode 100644 index 0000000..c0d91e1 --- /dev/null +++ b/internal/model/entity/sys_dict_type.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysDictType is the golang structure for table sys_dict_type. +type SysDictType struct { + DictId uint64 `json:"dictId" description:"字典主键"` + ParentId int `json:"parentId" description:"父主键ID"` + DictName string `json:"dictName" description:"字典名称"` + DictType string `json:"dictType" description:"字典类型"` + ModuleClassify string `json:"moduleClassify" description:"模块分类"` + Remark string `json:"remark" description:"备注"` + Status uint `json:"status" description:"状态(1正常 0停用)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_job.go b/internal/model/entity/sys_job.go new file mode 100644 index 0000000..6065a5d --- /dev/null +++ b/internal/model/entity/sys_job.go @@ -0,0 +1,28 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysJob is the golang structure for table sys_job. +type SysJob struct { + JobId int64 `json:"jobId" description:"任务ID"` + JobName string `json:"jobName" description:"任务名称"` + JobParams string `json:"jobParams" description:"参数"` + JobGroup string `json:"jobGroup" description:"任务组名"` + InvokeTarget string `json:"invokeTarget" description:"调用目标字符串"` + CronExpression string `json:"cronExpression" description:"cron执行表达式"` + MisfirePolicy int `json:"misfirePolicy" description:"计划执行策略(1多次执行 2执行一次)"` + Concurrent int `json:"concurrent" description:"是否并发执行(0允许 1禁止)"` + Status int `json:"status" description:"状态(0正常 1暂停)"` + CreateBy uint64 `json:"createBy" description:"创建者"` + UpdateBy uint64 `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注信息"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_login_log.go b/internal/model/entity/sys_login_log.go new file mode 100644 index 0000000..3a7b961 --- /dev/null +++ b/internal/model/entity/sys_login_log.go @@ -0,0 +1,23 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysLoginLog is the golang structure for table sys_login_log. +type SysLoginLog struct { + InfoId int64 `json:"infoId" description:"访问ID"` + LoginName string `json:"loginName" description:"登录账号"` + Ipaddr string `json:"ipaddr" description:"登录IP地址"` + LoginLocation string `json:"loginLocation" description:"登录地点"` + Browser string `json:"browser" description:"浏览器类型"` + Os string `json:"os" description:"操作系统"` + Status int `json:"status" description:"登录状态(0成功 1失败)"` + Msg string `json:"msg" description:"提示消息"` + LoginTime *gtime.Time `json:"loginTime" description:"登录时间"` + Module string `json:"module" description:"登录模块"` +} diff --git a/internal/model/entity/sys_menu.go b/internal/model/entity/sys_menu.go new file mode 100644 index 0000000..fe5e769 --- /dev/null +++ b/internal/model/entity/sys_menu.go @@ -0,0 +1,41 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenu is the golang structure for table sys_menu. +type SysMenu struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType uint `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide uint `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink uint `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId uint `json:"modelId" description:"模型ID"` + IsIframe uint `json:"isIframe" description:"是否内嵌iframe"` + IsCached uint `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix uint `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_menu_api.go b/internal/model/entity/sys_menu_api.go new file mode 100644 index 0000000..65f9d57 --- /dev/null +++ b/internal/model/entity/sys_menu_api.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuApi is the golang structure for table sys_menu_api. +type SysMenuApi struct { + Id uint `json:"id" description:"id"` + MenuId int `json:"menuId" description:"菜单ID"` + ApiId int `json:"apiId" description:"apiId"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_menu_button.go b/internal/model/entity/sys_menu_button.go new file mode 100644 index 0000000..8d22b37 --- /dev/null +++ b/internal/model/entity/sys_menu_button.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuButton is the golang structure for table sys_menu_button. +type SysMenuButton struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_menu_column.go b/internal/model/entity/sys_menu_column.go new file mode 100644 index 0000000..ccba0f1 --- /dev/null +++ b/internal/model/entity/sys_menu_column.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysMenuColumn is the golang structure for table sys_menu_column. +type SysMenuColumn struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Code string `json:"code" description:"代表字段"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_notifications.go b/internal/model/entity/sys_notifications.go new file mode 100644 index 0000000..2f395e7 --- /dev/null +++ b/internal/model/entity/sys_notifications.go @@ -0,0 +1,20 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysNotifications is the golang structure for table sys_notifications. +type SysNotifications struct { + Id int `json:"id" description:""` + Title string `json:"title" description:"标题"` + Doc string `json:"doc" description:"描述"` + Source string `json:"source" description:"消息来源"` + Types string `json:"types" description:"类型"` + CreatedAt *gtime.Time `json:"createdAt" description:"发送时间"` + Status int `json:"status" description:"0,未读,1,已读"` +} diff --git a/internal/model/entity/sys_oper_log.go b/internal/model/entity/sys_oper_log.go new file mode 100644 index 0000000..c68385d --- /dev/null +++ b/internal/model/entity/sys_oper_log.go @@ -0,0 +1,29 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysOperLog is the golang structure for table sys_oper_log. +type SysOperLog struct { + OperId uint64 `json:"operId" description:"日志主键"` + Title string `json:"title" description:"模块标题"` + BusinessType int `json:"businessType" description:"业务类型(0其它 1新增 2修改 3删除)"` + Method string `json:"method" description:"方法名称"` + RequestMethod string `json:"requestMethod" description:"请求方式"` + OperatorType int `json:"operatorType" description:"操作类别(0其它 1后台用户 2手机端用户)"` + OperName string `json:"operName" description:"操作人员"` + DeptName string `json:"deptName" description:"部门名称"` + OperUrl string `json:"operUrl" description:"请求URL"` + OperIp string `json:"operIp" description:"主机地址"` + OperLocation string `json:"operLocation" description:"操作地点"` + OperParam string `json:"operParam" description:"请求参数"` + JsonResult string `json:"jsonResult" description:"返回参数"` + Status int `json:"status" description:"操作状态(0正常 1异常)"` + ErrorMsg string `json:"errorMsg" description:"错误消息"` + OperTime *gtime.Time `json:"operTime" description:"操作时间"` +} diff --git a/internal/model/entity/sys_organization.go b/internal/model/entity/sys_organization.go new file mode 100644 index 0000000..9d6c491 --- /dev/null +++ b/internal/model/entity/sys_organization.go @@ -0,0 +1,30 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysOrganization is the golang structure for table sys_organization. +type SysOrganization struct { + Id int64 `json:"id" description:"组织ID"` + ParentId int64 `json:"parentId" description:"父组织id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + Name string `json:"name" description:"组织名称"` + Number string `json:"number" description:"组织编号"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"组织状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + CreatedBy uint `json:"createdBy" description:"创建人"` + UpdatedBy int `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_plugins.go b/internal/model/entity/sys_plugins.go new file mode 100644 index 0000000..82e904d --- /dev/null +++ b/internal/model/entity/sys_plugins.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysPlugins is the golang structure for table sys_plugins. +type SysPlugins struct { + Id int `json:"id" description:"ID"` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Intro string `json:"intro" description:"介绍"` + Version string `json:"version" description:"版本"` + Status int `json:"status" description:"状态"` + Types string `json:"types" description:"插件类型"` + Author string `json:"author" description:""` + StartTime *gtime.Time `json:"startTime" description:""` +} diff --git a/internal/model/entity/sys_plugins_config.go b/internal/model/entity/sys_plugins_config.go new file mode 100644 index 0000000..3dd0a66 --- /dev/null +++ b/internal/model/entity/sys_plugins_config.go @@ -0,0 +1,14 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +// SysPluginsConfig is the golang structure for table sys_plugins_config. +type SysPluginsConfig struct { + Id int `json:"id" description:""` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` +} diff --git a/internal/model/entity/sys_post.go b/internal/model/entity/sys_post.go new file mode 100644 index 0000000..bef0920 --- /dev/null +++ b/internal/model/entity/sys_post.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysPost is the golang structure for table sys_post. +type SysPost struct { + PostId int64 `json:"postId" description:"岗位ID"` + ParentId int64 `json:"parentId" description:"父ID"` + PostCode string `json:"postCode" description:"岗位编码"` + PostName string `json:"postName" description:"岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + Remark string `json:"remark" description:"备注"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedBy uint `json:"updatedBy" description:"修改人"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_role.go b/internal/model/entity/sys_role.go new file mode 100644 index 0000000..c0a7382 --- /dev/null +++ b/internal/model/entity/sys_role.go @@ -0,0 +1,27 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysRole is the golang structure for table sys_role. +type SysRole struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + ListOrder uint `json:"listOrder" description:"排序"` + Name string `json:"name" description:"角色名称"` + DataScope uint `json:"dataScope" description:"数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)"` + Remark string `json:"remark" description:"备注"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_role_dept.go b/internal/model/entity/sys_role_dept.go new file mode 100644 index 0000000..c795ca0 --- /dev/null +++ b/internal/model/entity/sys_role_dept.go @@ -0,0 +1,11 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +// SysRoleDept is the golang structure for table sys_role_dept. +type SysRoleDept struct { + RoleId int64 `json:"roleId" description:"角色ID"` + DeptId int64 `json:"deptId" description:"部门ID"` +} diff --git a/internal/model/entity/sys_user.go b/internal/model/entity/sys_user.go new file mode 100644 index 0000000..ce3c249 --- /dev/null +++ b/internal/model/entity/sys_user.go @@ -0,0 +1,39 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysUser is the golang structure for table sys_user. +type SysUser struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserPassword string `json:"userPassword" description:"登录密码;cmf_password加密"` + UserSalt string `json:"userSalt" description:"加密盐"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + DeletedBy int `json:"deletedBy" description:"删除人"` + DeletedAt *gtime.Time `json:"deletedAt" description:"删除时间"` +} diff --git a/internal/model/entity/sys_user_online.go b/internal/model/entity/sys_user_online.go new file mode 100644 index 0000000..f04d6c8 --- /dev/null +++ b/internal/model/entity/sys_user_online.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +// SysUserOnline is the golang structure for table sys_user_online. +type SysUserOnline struct { + Id uint `json:"id" description:""` + Uuid string `json:"uuid" description:"用户标识"` + Key string `json:"key" description:""` + Token string `json:"token" description:"用户token"` + CreatedAt *gtime.Time `json:"createdAt" description:"登录时间"` + UserName string `json:"userName" description:"用户名"` + Ip string `json:"ip" description:"登录ip"` + Explorer string `json:"explorer" description:"浏览器"` + Os string `json:"os" description:"操作系统"` +} diff --git a/internal/model/entity/sys_user_post.go b/internal/model/entity/sys_user_post.go new file mode 100644 index 0000000..d0bdf47 --- /dev/null +++ b/internal/model/entity/sys_user_post.go @@ -0,0 +1,11 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +// SysUserPost is the golang structure for table sys_user_post. +type SysUserPost struct { + UserId int `json:"userId" description:"用户ID"` + PostId int `json:"postId" description:"岗位ID"` +} diff --git a/internal/model/entity/sys_user_role.go b/internal/model/entity/sys_user_role.go new file mode 100644 index 0000000..4e99f93 --- /dev/null +++ b/internal/model/entity/sys_user_role.go @@ -0,0 +1,11 @@ +// ================================================================================= +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +// SysUserRole is the golang structure for table sys_user_role. +type SysUserRole struct { + UserId int `json:"userId" description:""` + RoleId int `json:"roleId" description:""` +} diff --git a/internal/model/env_weather.go b/internal/model/env_weather.go new file mode 100644 index 0000000..4f252cd --- /dev/null +++ b/internal/model/env_weather.go @@ -0,0 +1,39 @@ +package model + +type CityWeatherListOut struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + Windpower string `json:"windpower" description:"风力级别"` + Sunrise string `json:"sunrise" description:"日出"` + Sunset string `json:"sunset" description:"日落"` + SunshineDuration int `json:"sunshineDuration" description:"日照时长"` + Temperature int `json:"Temperature" description:"气温"` + Weather string `json:"weather" description:"天气现象"` + Winddirection string `json:"winddirection" description:"风向描述"` + Reporttime string `json:"reporttime" description:"发布时间"` +} + +type CityWeatherListRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:"名字"` + Code string `json:"code" description:"编码"` + Windpower string `json:"windpower" description:"风力级别"` + Sunrise string `json:"sunrise" description:"日出"` + Sunset string `json:"sunset" description:"日落"` + SunshineDuration int `json:"sunshineDuration" description:"日照时长"` + Temperature int `json:"Temperature" description:"气温"` + Weather string `json:"weather" description:"天气现象"` + Winddirection string `json:"winddirection" description:"风向描述"` + Reporttime string `json:"reporttime" description:"发布时间"` +} + +type CityWeatherEchartRes struct { + Value string `json:"value" description:"值"` + Time string `json:"time" description:"时间"` +} + +type CityWeatherEchartOut struct { + Value string `json:"value" description:"值"` + Time string `json:"time" description:"时间"` +} diff --git a/internal/model/network_server.go b/internal/model/network_server.go new file mode 100644 index 0000000..c512c27 --- /dev/null +++ b/internal/model/network_server.go @@ -0,0 +1,57 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type NetworkServerOut struct { + Id int `json:"id" description:""` + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp/mqtt"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Status int `json:"status" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + CreateBy int `json:"createBy" description:""` + Remark string `json:"remark" description:"备注"` +} + +type NetworkServerRes struct { + Id int `json:"id" description:""` + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp/mqtt"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Status int `json:"status" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + CreateBy int `json:"createBy" description:""` + Remark string `json:"remark" description:"备注"` +} +type NetworkServerAddInput struct { + Name string `json:"name" description:""` + Types string `json:"types" description:"tcp/udp"` + Addr string `json:"addr" description:""` + Register string `json:"register" description:"注册包"` + Heartbeat string `json:"heartbeat" description:"心跳包"` + Protocol string `json:"protocol" description:"协议"` + Devices string `json:"devices" description:"默认设备"` + Status int `json:"status" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + CreateBy int `json:"createBy" description:""` + Remark string `json:"remark" description:"备注"` +} +type NetworkServerEditInput struct { + Id int `json:"id" description:"ID"` + NetworkServerAddInput +} + +type GetNetworkServerListInput struct { + PaginationInput +} diff --git a/internal/model/network_tunnel.go b/internal/model/network_tunnel.go new file mode 100644 index 0000000..fd64920 --- /dev/null +++ b/internal/model/network_tunnel.go @@ -0,0 +1,65 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type GetNetworkTunnelListInput struct { + ServiceId int `json:"serviceId" dc:"服务ID"` + DeviceKey string `json:"deviceKey" dc:"设备标识"` + *PaginationInput +} +type NetworkTunnelOut struct { + Id int `json:"id" description:"ID"` + ServerId int `json:"serverId" description:"服务ID"` + Name string `json:"name" description:""` + Types string `json:"types" description:""` + Addr string `json:"addr" description:""` + Remote string `json:"remote" description:""` + Retry string `json:"retry" description:""` + Heartbeat string `json:"heartbeat" description:""` + Serial string `json:"serial" description:""` + Protoccol string `json:"protoccol" description:""` + DeviceKey string `json:"deviceKey" description:"设备标识"` + Status int `json:"status" description:""` + Last *gtime.Time `json:"last" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + Remark string `json:"remark" description:"备注"` +} + +type NetworkTunnelRes struct { + Id int `json:"id" description:"ID"` + ServerId int `json:"serverId" description:"服务ID"` + Name string `json:"name" description:""` + Types string `json:"types" description:""` + Addr string `json:"addr" description:""` + Remote string `json:"remote" description:""` + Retry string `json:"retry" description:""` + Heartbeat string `json:"heartbeat" description:""` + Serial string `json:"serial" description:""` + Protoccol string `json:"protoccol" description:""` + DeviceKey string `json:"deviceKey" description:"设备标识"` + Status int `json:"status" description:""` + Last *gtime.Time `json:"last" description:""` + CreatedAt *gtime.Time `json:"createdAt" description:""` + UpdatedAt *gtime.Time `json:"updatedAt" description:""` + Remark string `json:"remark" description:"备注"` +} +type NetworkTunnelAddInput struct { + ServerId int `json:"serverId" description:"服务ID"` + Name string `json:"name" description:""` + Types string `json:"types" description:""` + Addr string `json:"addr" description:""` + Remote string `json:"remote" description:""` + Retry string `json:"retry" description:""` + Heartbeat string `json:"heartbeat" description:""` + Serial string `json:"serial" description:""` + Protoccol string `json:"protoccol" description:""` + Status int `json:"status" description:""` + Remark string `json:"remark" description:"备注"` +} +type NetworkTunnelEditInput struct { + Id int `json:"id" description:"ID"` + NetworkTunnelAddInput +} diff --git a/internal/model/notice_config.go b/internal/model/notice_config.go new file mode 100644 index 0000000..c3b3b6c --- /dev/null +++ b/internal/model/notice_config.go @@ -0,0 +1,28 @@ +package model + +type GetNoticeConfigListInput struct { + SendGateway string `json:"sendGateway" description:"sendGateway"` + Types string `json:"types" description:"types"` + PaginationInput +} +type NoticeConfigListOutput struct { + Data []NoticeConfigOutput + PaginationOutput +} +type NoticeConfigOutput struct { + Id string `json:"id" description:""` + Title string `json:"title" description:""` + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type NoticeConfigAddInput struct { + Id string `json:"id" description:"ID"` + Title string `json:"title" description:""` + SendGateway string `json:"sendGateway" description:""` + Types string `json:"types" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type NoticeConfigEditInput struct { + NoticeConfigAddInput +} diff --git a/internal/model/notice_info.go b/internal/model/notice_info.go new file mode 100644 index 0000000..95ed0f2 --- /dev/null +++ b/internal/model/notice_info.go @@ -0,0 +1,48 @@ +package model + +type GetNoticeInfoListInput struct { + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + Status int `json:"status" description:""` + PaginationInput +} +type NoticeInfoListOutput struct { + Data []NoticeInfoOutput + PaginationOutput +} +type NoticeInfoOutput struct { + Status string `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + Id string `json:"id" description:""` + Totag string `json:"totag" description:""` + Method string `json:"method" description:""` + MsgBody string `json:"msgBody" description:""` + MsgUrl string `json:"msgUrl" description:""` + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + UserIds string `json:"userIds" description:""` + MethodNum string `json:"methodNum" description:""` + CreatedAt string `json:"createdAt" description:""` + MsgTitle string `json:"msgTitle" description:""` + OrgIds string `json:"orgIds" description:""` +} +type NoticeInfoAddInput struct { + Totag string `json:"totag" description:""` + Status string `json:"status" description:""` + MethodCron string `json:"methodCron" description:""` + ConfigId string `json:"configId" description:""` + ComeFrom string `json:"comeFrom" description:""` + Method string `json:"method" description:""` + MsgBody string `json:"msgBody" description:""` + MsgUrl string `json:"msgUrl" description:""` + UserIds string `json:"userIds" description:""` + MsgTitle string `json:"msgTitle" description:""` + OrgIds string `json:"orgIds" description:""` + MethodNum string `json:"methodNum" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type NoticeInfoEditInput struct { + Id int `json:"id" description:"ID"` + NoticeInfoAddInput +} diff --git a/internal/model/notice_log.go b/internal/model/notice_log.go new file mode 100644 index 0000000..c77d9cd --- /dev/null +++ b/internal/model/notice_log.go @@ -0,0 +1,31 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/model/entity" +) + +type NoticeLogAddInput struct { + TemplateId string `json:"templateId" dc:"通知模板ID"` + SendGateway string `json:"sendGateway" dc:"通知发送通道:sms、work_weixin、dingding"` + Addressee string `json:"addressee" dc:"收信人"` + Title string `json:"title" dc:"通知标题"` + Content string `json:"content" dc:"通知内容"` + Status int `json:"status" dc:"发送状态:0=失败,1=成功"` + FailMsg string `json:"failMsg" dc:"失败信息"` + SendTime string `json:"sendTime" dc:"发送时间"` +} + +type NoticeLogSearchInput struct { + Status int `json:"status" dc:"发送状态:0=失败,1=成功"` + PaginationInput +} +type NoticeLogSearchOutput struct { + List []NoticeLogList `json:"list" dc:"通知日志列表"` + PaginationOutput +} + +type NoticeLogList struct { + entity.NoticeLog + + Gateway string `json:"gateway" dc:"发送通道"` +} diff --git a/internal/model/notice_template.go b/internal/model/notice_template.go new file mode 100644 index 0000000..31a8945 --- /dev/null +++ b/internal/model/notice_template.go @@ -0,0 +1,33 @@ +package model + +type GetNoticeTemplateListInput struct { + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + PaginationInput +} +type NoticeTemplateListOutput struct { + Data []NoticeTemplateOutput + PaginationOutput +} +type NoticeTemplateOutput struct { + Id string `json:"id" description:""` + ConfigId string `json:"configId" description:""` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` +} +type NoticeTemplateAddInput struct { + Id string `json:"id" description:"ID"` + SendGateway string `json:"sendGateway" description:""` + Code string `json:"code" description:""` + Title string `json:"title" description:""` + Content string `json:"content" description:""` + CreatedAt string `json:"createdAt" description:""` + ConfigId string `json:"configId" description:""` +} +type NoticeTemplateEditInput struct { + NoticeTemplateAddInput +} diff --git a/internal/model/session.go b/internal/model/session.go new file mode 100644 index 0000000..143580b --- /dev/null +++ b/internal/model/session.go @@ -0,0 +1,7 @@ +package model + +// SessionNotice 存放在Session中的提示信息,往往使用后则删除 +type SessionNotice struct { + Type string // 消息类型 + Content string // 消息内容 +} diff --git a/internal/model/statistics_data_overview.go b/internal/model/statistics_data_overview.go new file mode 100644 index 0000000..2338f52 --- /dev/null +++ b/internal/model/statistics_data_overview.go @@ -0,0 +1,23 @@ +package model + +type BrokenLineChildRes struct { + AccessDay string `json:"accessDay" description:"日期"` + Values float64 `json:"values" description:"数值"` +} + +type TemperingRatioRes struct { + TemperatureRange string `json:"temperatureRange" description:"温度区间"` + Num string `json:"num" description:"区间数据量"` + Rate string `json:"rate" description:"占比率"` +} + +// 物联概览统计数据 +type ThingOverviewOutput struct { + Overview DeviceTotalOutput `json:"overview" dc:"物联概览统计数据"` + Device ThingDevice `json:"device" dc:"设备月度统计"` + AlarmLevel []AlarmLogLevelTotal `json:"alarmLevel" dc:"告警日志级别统计"` +} +type ThingDevice struct { + MsgTotal map[int]int `json:"msgTotal" dc:"设备消息量月度统计"` + AlarmTotal map[int]int `json:"alarmTotal" dc:"设备告警量月度统计"` +} diff --git a/internal/model/sys_api.go b/internal/model/sys_api.go new file mode 100644 index 0000000..25ab9fe --- /dev/null +++ b/internal/model/sys_api.go @@ -0,0 +1,144 @@ +package model + +type SysApiTreeRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + Children []*SysApiTreeRes `json:"children" description:"子集"` +} + +type SysApiTreeOut struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + Children []*SysApiTreeOut `json:"children" description:"子集"` +} + +type SysApiAllRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` +} + +type SysApiRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + MenuIds []int `json:"menuIds" description:"菜单Id数组" v:"required#菜单ID不能为空"` +} + +type SysApiOut struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` + MenuIds []int `json:"menuIds" description:"菜单Id数组" v:"required#菜单ID不能为空"` +} + +type AuthorizeQueryApiRes struct { + Id int `json:"id" description:"此ID为菜单与API的关联ID"` + ApiId int `json:"apiId" description:"接口ID"` + ParentId int `json:"parentId" description:""` + Title string `json:"title" description:"标题"` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` +} + +type AuthorizeQueryApiOut struct { + Id int `json:"id" description:"此ID为菜单与API的关联ID"` + ApiId int `json:"apiId" description:"接口ID"` + ParentId int `json:"parentId" description:""` + Title string `json:"title" description:"标题"` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` +} + +type UserApiRes struct { + Id int `json:"id" description:""` + MenuApiId int `json:"menuApiId" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` +} + +type UserApiOut struct { + Id int `json:"id" description:""` + MenuApiId int `json:"menuApiId" description:""` + ParentId int `json:"parentId" description:""` + Name string `json:"name" description:"名称"` + Types int `json:"types" description:"1 分类 2接口"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address" description:"接口地址"` + Remark string `json:"remark" description:"备注"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Sort int `json:"sort" description:"排序"` +} + +type AddApiInput struct { + ParentId int `json:"parentId"` + Name string `json:"name"` + Types int `json:"types"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address"` + Remark string `json:"remark"` + Status int `json:"status"` + Sort int `json:"sort"` + MenuIds []int `json:"menuIds"` +} + +type EditApiInput struct { + Id int `json:"id"` + ParentId int `json:"parentId"` + Name string `json:"name"` + Types int `json:"types"` + Method string `json:"method" description:"请求方式(数据字典维护)"` + Address string `json:"address"` + Remark string `json:"remark"` + Status int `json:"status"` + Sort int `json:"sort"` + MenuIds []int `json:"menuIds"` +} diff --git a/internal/model/sys_dept.go b/internal/model/sys_dept.go new file mode 100644 index 0000000..91c4a96 --- /dev/null +++ b/internal/model/sys_dept.go @@ -0,0 +1,73 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type DeptRes struct { + DeptId int64 `json:"deptId" description:"部门id"` + OrganizationId int `json:"organizationId" description:"组织ID"` + ParentId int64 `json:"parentId" description:"父部门id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + DeptName string `json:"deptName" description:"部门名称"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*DeptRes `json:"children" description:"子集"` +} + +type DeptOut struct { + DeptId int64 `json:"deptId" description:"部门id"` + OrganizationId int `json:"organizationId" description:"组织ID"` + ParentId int64 `json:"parentId" description:"父部门id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + DeptName string `json:"deptName" description:"部门名称"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*DeptOut `json:"children" description:"子集"` +} + +type AddDeptInput struct { + ParentId int64 `json:"parentId"` + OrganizationId int `json:"organizationId"` + DeptName string `json:"deptName"` + OrderNum int `json:"orderNum"` + Status uint `json:"status"` + Leader string `json:"leader"` + Phone string `json:"phone"` + Email string `json:"email"` +} + +type EditDeptInput struct { + DeptId int64 `json:"deptId"` + ParentId int64 `json:"parentId"` + OrganizationId int `json:"organizationId"` + DeptName string `json:"deptName"` + OrderNum int `json:"orderNum"` + Status uint `json:"status"` + Leader string `json:"leader"` + Phone string `json:"phone"` + Email string `json:"email"` +} + +type DetailDeptRes struct { + DeptId int64 `json:"deptId" description:"部门id"` + ParentId int64 `json:"parentId" description:"父部门id"` + OrganizationId int `json:"organizationId" description:"组织ID"` + Ancestors string `json:"ancestors" description:"祖级列表"` + DeptName string `json:"deptName" description:"部门名称"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} diff --git a/internal/model/sys_dict_data.go b/internal/model/sys_dict_data.go new file mode 100644 index 0000000..eb65f3c --- /dev/null +++ b/internal/model/sys_dict_data.go @@ -0,0 +1,112 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type GetDictInput struct { + Authorization string `p:"Authorization" in:"header" dc:"Bearer {{token}}"` + DictType string `p:"dictType" v:"required#字典类型不能为空"` + DefaultValue string `p:"defaultValue"` +} + +type GetDictOut struct { + Data *DictTypeOut `json:"info"` + Values []*DictDataOut `json:"values"` +} + +type GetDictRes struct { + Data *DictTypeRes `json:"info"` + Values []*DictDataRes `json:"values"` +} + +type DictTypeOut struct { + DictName string `json:"name"` + Remark string `json:"remark"` +} + +type DictTypeRes struct { + DictName string `json:"name"` + Remark string `json:"remark"` +} + +type DictDataOut struct { + DictValue string `json:"key"` + DictLabel string `json:"value"` + IsDefault int `json:"isDefault"` + Remark string `json:"remark"` +} + +// DictDataRes 字典数据 +type DictDataRes struct { + DictValue string `json:"key"` + DictLabel string `json:"value"` + IsDefault int `json:"isDefault"` + Remark string `json:"remark"` +} + +type SysDictSearchInput struct { + DictType string `p:"dictType"` //字典类型 + DictLabel string `p:"dictLabel"` //字典标签 + Status string `p:"status"` //状态 + PaginationInput +} + +type SysDictDataOut struct { + DictCode int64 `json:"dictCode" description:"字典编码"` + DictSort int `json:"dictSort" description:"字典排序"` + DictLabel string `json:"dictLabel" description:"字典标签"` + DictValue string `json:"dictValue" description:"字典键值"` + DictType string `json:"dictType" description:"字典类型"` + CssClass string `json:"cssClass" description:"样式属性(其他样式扩展)"` + ListClass string `json:"listClass" description:"表格回显样式"` + IsDefault int `json:"isDefault" description:"是否默认(1是 0否)"` + Status int `json:"status" description:"状态(0正常 1停用)"` + CreateBy uint64 `json:"createBy" description:"创建者"` + UpdateBy uint64 `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` +} + +type SysDictDataRes struct { + DictCode int64 `json:"dictCode" description:"字典编码"` + DictSort int `json:"dictSort" description:"字典排序"` + DictLabel string `json:"dictLabel" description:"字典标签"` + DictValue string `json:"dictValue" description:"字典键值"` + DictType string `json:"dictType" description:"字典类型"` + CssClass string `json:"cssClass" description:"样式属性(其他样式扩展)"` + ListClass string `json:"listClass" description:"表格回显样式"` + IsDefault int `json:"isDefault" description:"是否默认(1是 0否)"` + Status int `json:"status" description:"状态(0正常 1停用)"` + CreateBy uint64 `json:"createBy" description:"创建者"` + UpdateBy uint64 `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` +} + +type AddDictDataInput struct { + DictLabel string `p:"dictLabel"` + DictValue string `p:"dictValue"` + DictType string `p:"dictType"` + DictSort int `p:"dictSort"` + CssClass string `p:"cssClass"` + ListClass string `p:"listClass"` + IsDefault int `p:"isDefault"` + Status int `p:"status"` + Remark string `p:"remark"` +} + +type EditDictDataInput struct { + DictCode int `p:"dictCode"` + DictLabel string `p:"dictLabel"` + DictValue string `p:"dictValue"` + DictType string `p:"dictType"` + DictSort int `p:"dictSort"` + CssClass string `p:"cssClass"` + ListClass string `p:"listClass"` + IsDefault int `p:"isDefault"` + Status int `p:"status"` + Remark string `p:"remark"` +} diff --git a/internal/model/sys_dict_type.go b/internal/model/sys_dict_type.go new file mode 100644 index 0000000..dff263a --- /dev/null +++ b/internal/model/sys_dict_type.go @@ -0,0 +1,66 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type DictTypeDoInput struct { + DictName string `p:"dictName"` //字典名称 + DictType string `p:"dictType"` //字典类型 + Status string `p:"status"` //字典状态 + *PaginationInput +} +type SysDictTypeInfoOut struct { + DictId uint64 `orm:"dict_id,primary" json:"dictId"` // 字典主键 + DictName string `orm:"dict_name" json:"dictName"` // 字典名称 + DictType string `orm:"dict_type,unique" json:"dictType"` // 字典类型 + Status uint `orm:"status" json:"status"` // 状态(0正常 1停用) + Remark string `orm:"remark" json:"remark"` // 备注 + CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建日期 +} + +type AddDictTypeInput struct { + DictName string `p:"dictName"` + DictType string `p:"dictType"` + Status uint `p:"status"` + Remark string `p:"remark"` +} + +type EditDictTypeInput struct { + DictId int `p:"dictId"` + DictName string `p:"dictName"` + DictType string `p:"dictType"` + Status uint `p:"status"` + Remark string `p:"remark"` +} + +type SysDictTypeInfoRes struct { + DictId uint64 `orm:"dict_id,primary" json:"dictId"` // 字典主键 + DictName string `orm:"dict_name" json:"dictName"` // 字典名称 + DictType string `orm:"dict_type,unique" json:"dictType"` // 字典类型 + Status uint `orm:"status" json:"status"` // 状态(0正常 1停用) + Remark string `orm:"remark" json:"remark"` // 备注 + CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建日期 +} + +type SysDictTypeOut struct { + DictId uint64 `json:"dictId" description:"字典主键"` + DictName string `json:"dictName" description:"字典名称"` + DictType string `json:"dictType" description:"字典类型"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` +} + +type SysDictTypeRes struct { + DictId uint64 `json:"dictId" description:"字典主键"` + DictName string `json:"dictName" description:"字典名称"` + DictType string `json:"dictType" description:"字典类型"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + CreateBy uint `json:"createBy" description:"创建者"` + UpdateBy uint `json:"updateBy" description:"更新者"` + Remark string `json:"remark" description:"备注"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` +} diff --git a/internal/model/sys_job.go b/internal/model/sys_job.go new file mode 100644 index 0000000..5c96296 --- /dev/null +++ b/internal/model/sys_job.go @@ -0,0 +1,78 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type GetJobListInput struct { + JobName string `json:"jobName" description:"任务名称"` + JobGroup string `json:"jobGroup" description:"任务组名"` + Status string `json:"status" description:"状态(0正常 1暂停)"` + *PaginationInput +} + +type SysJobRes struct { + JobId int64 `orm:"job_id,primary" json:"jobId"` // 任务ID + JobName string `orm:"job_name,primary" json:"jobName"` // 任务名称 + JobParams string `orm:"job_params" json:"jobParams"` // 参数 + JobGroup string `orm:"job_group,primary" json:"jobGroup"` // 任务组名 + InvokeTarget string `orm:"invoke_target" json:"invokeTarget"` // 调用目标字符串 + CronExpression string `orm:"cron_expression" json:"cronExpression"` // cron执行表达式 + MisfirePolicy int `orm:"misfire_policy" json:"misfirePolicy"` // 计划执行策略(1多次执行 2执行一次) + Concurrent int `orm:"concurrent" json:"concurrent"` // 是否并发执行(0允许 1禁止) + Status int `orm:"status" json:"status"` // 状态(0正常 1暂停) + CreateBy uint64 `orm:"create_by" json:"createBy"` // 创建者 + UpdateBy uint64 `orm:"update_by" json:"updateBy"` // 更新者 + Remark string `orm:"remark" json:"remark"` // 备注信息 + CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 + UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 + DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间 +} + +type SysJobOut struct { + JobId int64 `orm:"job_id,primary" json:"jobId"` // 任务ID + JobName string `orm:"job_name,primary" json:"jobName"` // 任务名称 + JobParams string `orm:"job_params" json:"jobParams"` // 参数 + JobGroup string `orm:"job_group,primary" json:"jobGroup"` // 任务组名 + InvokeTarget string `orm:"invoke_target" json:"invokeTarget"` // 调用目标字符串 + CronExpression string `orm:"cron_expression" json:"cronExpression"` // cron执行表达式 + MisfirePolicy int `orm:"misfire_policy" json:"misfirePolicy"` // 计划执行策略(1多次执行 2执行一次) + Concurrent int `orm:"concurrent" json:"concurrent"` // 是否并发执行(0允许 1禁止) + Status int `orm:"status" json:"status"` // 状态(0正常 1暂停) + CreateBy uint64 `orm:"create_by" json:"createBy"` // 创建者 + UpdateBy uint64 `orm:"update_by" json:"updateBy"` // 更新者 + Remark string `orm:"remark" json:"remark"` // 备注信息 + CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间 + UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间 + DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间 +} + +// SysJobAddInput 添加JOB +type SysJobAddInput struct { + JobName string `json:"jobName" description:"任务名称"` + JobParams string `json:"jobParams" description:"任务参数"` + JobGroup string `json:"jobGroup" description:"分组"` + InvokeTarget string `json:"invokeTarget" description:"执行方法"` + CronExpression string `json:"cronExpression" description:"任务执行表达式" ` + MisfirePolicy int `json:"misfirePolicy"` + Concurrent int `json:"concurrent" ` + Status int `json:"status" description:"状态" ` + Remark string `json:"remark" ` + CreateBy uint64 +} + +// SysJobEditInput 修改JOB +type SysJobEditInput struct { + JobId int64 `json:"job_id" v:"min:1#任务id不能为空"` + JobName string `json:"jobName" description:"任务名称" ` + JobParams string `json:"jobParams" description:"任务参数"` + JobGroup string `json:"jobGroup" description:"分组"` + InvokeTarget string `json:"invokeTarget" description:"执行方法" ` + CronExpression string `json:"cronExpression" description:"任务执行表达式" ` + MisfirePolicy int `json:"misfirePolicy"` + Concurrent int `json:"concurrent" ` + Status int `json:"status" description:"状态"` + Remark string `json:"remark" ` + CreateBy uint64 + UpdateBy uint64 +} diff --git a/internal/model/sys_login_log.go b/internal/model/sys_login_log.go new file mode 100644 index 0000000..15b592b --- /dev/null +++ b/internal/model/sys_login_log.go @@ -0,0 +1,43 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type LoginLogParams struct { + Status int + Username string + Ip string + UserAgent string + Msg string + Module string +} + +type SysLoginLogInput struct { + LoginName string `json:"loginName" description:"登录账号"` + Ipaddr string `json:"ipaddr" description:"登录IP地址"` + LoginLocation string `json:"loginLocation" description:"登录地点"` + Browser string `json:"browser" description:"浏览器类型"` + Os string `json:"os" description:"操作系统"` + Status int `json:"status" description:"登录状态(0成功 1失败)"` + Msg string `json:"msg" description:"提示消息"` + LoginTime *gtime.Time `json:"loginTime" description:"登录时间"` + Module string `json:"module" description:"登录模块"` + PaginationInput +} + +type SysLoginLogListOut struct { + Data []*SysLoginLogOut + PaginationOutput +} + +type SysLoginLogOut struct { + InfoId int64 `json:"infoId" description:"访问ID"` + LoginName string `json:"loginName" description:"登录账号"` + Ipaddr string `json:"ipaddr" description:"登录IP地址"` + LoginLocation string `json:"loginLocation" description:"登录地点"` + Browser string `json:"browser" description:"浏览器类型"` + Os string `json:"os" description:"操作系统"` + Status int `json:"status" description:"登录状态(0成功 1失败)"` + Msg string `json:"msg" description:"提示消息"` + LoginTime *gtime.Time `json:"loginTime" description:"登录时间"` + Module string `json:"module" description:"登录模块"` +} diff --git a/internal/model/sys_menu.go b/internal/model/sys_menu.go new file mode 100644 index 0000000..f175a2f --- /dev/null +++ b/internal/model/sys_menu.go @@ -0,0 +1,283 @@ +package model + +import "github.com/gogf/gf/v2/frame/g" + +// SysMenuRes 菜单列表返回字段 +type SysMenuRes struct { + Id int64 `json:"id" description:""` + ParentId int64 `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType int64 `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide int64 `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink int64 `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId int64 `json:"modelId" description:"模型ID"` + IsIframe int64 `json:"isIframe" description:"是否内嵌iframe"` + IsCached int64 `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix int64 `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []*SysMenuRes `json:"children" description:"子集"` +} + +type SysMenuOut struct { + Id int64 `json:"id" description:""` + ParentId int64 `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType int64 `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide int64 `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink int64 `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId int64 `json:"modelId" description:"模型ID"` + IsIframe int64 `json:"isIframe" description:"是否内嵌iframe"` + IsCached int64 `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix int64 `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []*SysMenuOut `json:"children" description:"子集"` +} + +// SysMenuTreeRes 菜单树形结构 +type SysMenuTreeRes struct { + *SysMenuRes + Children []*SysMenuTreeRes `json:"children"` +} + +type DetailMenuRes struct { + Id int64 `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType int64 `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide int64 `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink int64 `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId int64 `json:"modelId" description:"模型ID"` + IsIframe int64 `json:"isIframe" description:"是否内嵌iframe"` + IsCached int64 `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix int64 `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} + +type AddMenuInput struct { + MenuType uint `p:"menuType"` + ParentId int `p:"parentId"` + Name string `p:"name"` + Title string `p:"title"` + Icon string `p:"icon"` + Weigh int `p:"weigh"` + Condition string `p:"condition"` + Remark string `p:"remark"` + IsHide uint `p:"isHide"` + Path string `p:"path"` + Component string `p:"component"` + IsLink uint `p:"isLink"` + IsIframe uint `p:"isIframe"` + IsCached uint `p:"isKeepAlive"` + IsAffix uint `p:"isAffix"` + LinkUrl string `p:"linkUrl"` + Status int `p:"status"` + ModuleType string `p:"moduleType"` +} + +type EditMenuInput struct { + Id int64 `json:"id"` + MenuType uint `p:"menuType"` + ParentId int `p:"parentId"` + Name string `p:"name"` + Title string `p:"title"` + Icon string `p:"icon"` + Weigh int `p:"weigh"` + Condition string `p:"condition"` + Remark string `p:"remark"` + IsHide uint `p:"isHide"` + Path string `p:"path"` + Component string `p:"component"` + IsLink uint `p:"isLink"` + IsIframe uint `p:"isIframe"` + IsCached uint `p:"isKeepAlive"` + IsAffix uint `p:"isAffix"` + LinkUrl string `p:"linkUrl"` + Status int `p:"status"` + ModuleType string `p:"moduleType"` +} + +type UserMenu struct { + Id uint `json:"id" description:""` + Pid uint `json:"pid" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Component string `json:"component" description:"组件路径"` + Path string `json:"path" description:"路由地址"` + *MenuMeta `json:"meta"` +} + +type UserMenus struct { + *UserMenu `json:""` + Children []*UserMenus `json:"children" description:"子集"` +} + +type MenuMeta struct { + Icon string `json:"icon" description:"图标"` + Title string `json:"title" description:"规则名称"` + IsLink string `json:"isLink" description:"是否外链 1是 0否"` + IsHide bool `json:"isHide" description:"显示状态"` + IsAffix bool `json:"isAffix" description:"是否固定"` + IsIframe bool `json:"isIframe" description:"是否内嵌iframe"` +} + +type AuthorizeQueryTreeRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType uint `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide uint `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink uint `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId uint `json:"modelId" description:"模型ID"` + IsIframe uint `json:"isIframe" description:"是否内嵌iframe"` + IsCached uint `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix uint `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []g.Map `json:"children" description:"子集 菜单,按钮,列表,接口API"` +} + +type AuthorizeQueryTreeOut struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"菜单名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType uint `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide uint `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink uint `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId uint `json:"modelId" description:"模型ID"` + IsIframe uint `json:"isIframe" description:"是否内嵌iframe"` + IsCached uint `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix uint `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []g.Map `json:"children" description:"子集 菜单,按钮,列表,接口API"` +} + +type UserMenuTreeRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType uint `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide uint `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink uint `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId uint `json:"modelId" description:"模型ID"` + IsIframe uint `json:"isIframe" description:"是否内嵌iframe"` + IsCached uint `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix uint `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Button []*UserMenuButtonRes `json:"button" description:"按钮集合"` + Column []*UserMenuColumnRes `json:"column" description:"列表集合"` + Api []*UserApiRes `json:"api" description:"接口API集合"` + Children []*UserMenuTreeRes `json:"children" description:"子集"` +} + +type UserMenuTreeOut struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType uint `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide uint `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink uint `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId uint `json:"modelId" description:"模型ID"` + IsIframe uint `json:"isIframe" description:"是否内嵌iframe"` + IsCached uint `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix uint `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Button []*UserMenuButtonOut `json:"button" description:"按钮集合"` + Column []*UserMenuColumnOut `json:"column" description:"列表集合"` + Api []*UserApiOut `json:"api" description:"接口API集合"` + Children []*UserMenuTreeOut `json:"children" description:"子集"` +} + +type MenuJoinRes struct { + Id int64 `json:"id" description:""` + ParentId int64 `json:"parentId" description:"父ID"` + Name string `json:"name" description:"规则名称"` + Title string `json:"title" description:"规则名称"` + Icon string `json:"icon" description:"图标"` + Condition string `json:"condition" description:"条件"` + Remark string `json:"remark" description:"备注"` + MenuType int64 `json:"menuType" description:"类型 0目录 1菜单 2按钮"` + Weigh int `json:"weigh" description:"权重"` + IsHide int64 `json:"isHide" description:"显示状态"` + Path string `json:"path" description:"路由地址"` + Component string `json:"component" description:"组件路径"` + IsLink int64 `json:"isLink" description:"是否外链 1是 0否"` + ModuleType string `json:"moduleType" description:"所属模块 system 运维 company企业"` + ModelId int64 `json:"modelId" description:"模型ID"` + IsIframe int64 `json:"isIframe" description:"是否内嵌iframe"` + IsCached int64 `json:"isCached" description:"是否缓存"` + Redirect string `json:"redirect" description:"路由重定向地址"` + IsAffix int64 `json:"isAffix" description:"是否固定"` + LinkUrl string `json:"linkUrl" description:"链接地址"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Button []*UserMenuButtonRes `json:"button" description:"按钮集合"` + Column []*UserMenuColumnRes `json:"column" description:"列表集合"` + Api []*SysMenuApiRes `json:"api" description:"接口API集合"` +} diff --git a/internal/model/sys_menu_api.go b/internal/model/sys_menu_api.go new file mode 100644 index 0000000..daa6c08 --- /dev/null +++ b/internal/model/sys_menu_api.go @@ -0,0 +1,17 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type SysMenuApiRes struct { + Id int `json:"id" description:"id"` + MenuId int `json:"menuId" description:"菜单ID"` + ApiId int `json:"apiId" description:"apiId"` +} + +type AddMenuApiReq struct { + MenuId int `json:"menuId" description:"菜单ID"` + ApiId int `json:"apiId" description:"apiId"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} diff --git a/internal/model/sys_menu_button.go b/internal/model/sys_menu_button.go new file mode 100644 index 0000000..0a5a593 --- /dev/null +++ b/internal/model/sys_menu_button.go @@ -0,0 +1,58 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type UserMenuButtonRes struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []*UserMenuButtonRes `json:"children" description:"子集"` +} + +type UserMenuButtonOut struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + Children []*UserMenuButtonOut `json:"children" description:"子集"` +} + +type AddMenuButtonInput struct { + ParentId int `json:"parentId"` + MenuId int `json:"menuId"` + Name string `json:"name"` + Types string `json:"types"` + Description string `json:"description"` + Status int `json:"status"` +} + +type DetailMenuButtonRes struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Types string `json:"types" description:"类型 自定义 add添加 edit编辑 del 删除"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} + +type EditMenuButtonInput struct { + Id int `json:"id"` + ParentId int `json:"parentId"` + MenuId int `json:"menuId"` + Name string `json:"name"` + Types string `json:"types"` + Description string `json:"description"` + Status int `json:"status"` +} diff --git a/internal/model/sys_menu_column.go b/internal/model/sys_menu_column.go new file mode 100644 index 0000000..af90c9c --- /dev/null +++ b/internal/model/sys_menu_column.go @@ -0,0 +1,70 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type MenuColumnDoInput struct { + MenuId string `json:"menuId"` + ParentId string `json:"parentId"` + Status int `json:"status"` + Name string `json:"name"` +} + +type UserMenuColumnRes struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*UserMenuColumnRes `json:"children" description:"子集"` +} + +type UserMenuColumnOut struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*UserMenuColumnOut `json:"children" description:"子集"` +} + +type AddMenuColumnInput struct { + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} + +type DetailMenuColumnRes struct { + Id int `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` + CreatedBy uint `json:"createdBy" description:"创建人"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} + +type EditMenuColumnInput struct { + Id int `json:"id" description:"" ` + ParentId int `json:"parentId" description:"父ID" ` + MenuId int `json:"menuId" description:"菜单ID"` + Name string `json:"name" description:"名称"` + Code string `json:"code" description:"代表列表"` + Description string `json:"description" description:"描述"` + Status int `json:"status" description:"状态 0 停用 1启用"` +} diff --git a/internal/model/sys_notifications.go b/internal/model/sys_notifications.go new file mode 100644 index 0000000..8886271 --- /dev/null +++ b/internal/model/sys_notifications.go @@ -0,0 +1,26 @@ +package model + +type GetNotificationsListInput struct { + *PaginationInput +} + +type NotificationsRes struct { + Id int `json:"id" description:"ID"` +} + +type NotificationsOut struct { + Id int `json:"id" description:"ID"` +} + +type NotificationsAddInput struct { + Title string `json:"title" description:"标题"` + Doc string `json:"doc" description:"描述"` + Source string `json:"source" description:"消息来源"` + Types string `json:"types" description:"类型"` + CreatedAt string `json:"createdAt" description:"发送时间"` + Status string `json:"status" description:"0,未读,1,已读"` +} +type NotificationsEditInput struct { + Id int `json:"id" description:"ID"` + NotificationsAddInput +} diff --git a/internal/model/sys_oper_log.go b/internal/model/sys_oper_log.go new file mode 100644 index 0000000..4ded5e0 --- /dev/null +++ b/internal/model/sys_oper_log.go @@ -0,0 +1,58 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type SysOperLogDoInput struct { + Title string `p:"title" description:"模块标题"` + BusinessType string `p:"business_type" description:"业务类型(0其它 1新增 2修改 3删除)"` + Method string `p:"method" description:"方法名称"` + RequestMethod string `p:"request_method" description:"请求方式"` + OperatorType string `p:"operator_type" description:"操作类别(0其它 1后台用户 2手机端用户)"` + OperName string `p:"oper_name" description:"操作人员"` + DeptName string `p:"dept_name" description:"部门名称"` + OperUrl string `p:"oper_url" description:"请求URL"` + OperIp string `p:"oper_ip" description:"主机地址"` + OperLocation string `p:"oper_location" description:"操作地点"` + Status int `p:"status" description:"状态:-1为全部,0为正常,1为停用"` + *PaginationInput +} + +type SysOperLogOut struct { + OperId uint64 `json:"operId" description:"日志主键"` + Title string `json:"title" description:"模块标题"` + BusinessType int `json:"businessType" description:"业务类型(0其它 1新增 2修改 3删除)"` + Method string `json:"method" description:"方法名称"` + RequestMethod string `json:"requestMethod" description:"请求方式"` + OperatorType int `json:"operatorType" description:"操作类别(0其它 1后台用户 2手机端用户)"` + OperName string `json:"operName" description:"操作人员"` + DeptName string `json:"deptName" description:"部门名称"` + OperUrl string `json:"operUrl" description:"请求URL"` + OperIp string `json:"operIp" description:"主机地址"` + OperLocation string `json:"operLocation" description:"操作地点"` + OperParam string `json:"operParam" description:"请求参数"` + JsonResult string `json:"jsonResult" description:"返回参数"` + Status int `json:"status" description:"操作状态(0正常 1异常)"` + ErrorMsg string `json:"errorMsg" description:"错误消息"` + OperTime *gtime.Time `json:"operTime" description:"操作时间"` +} + +type SysOperLogRes struct { + OperId uint64 `json:"operId" description:"日志主键"` + Title string `json:"title" description:"模块标题"` + BusinessType int `json:"businessType" description:"业务类型(0其它 1新增 2修改 3删除)"` + Method string `json:"method" description:"方法名称"` + RequestMethod string `json:"requestMethod" description:"请求方式"` + OperatorType int `json:"operatorType" description:"操作类别(0其它 1后台用户 2手机端用户)"` + OperName string `json:"operName" description:"操作人员"` + DeptName string `json:"deptName" description:"部门名称"` + OperUrl string `json:"operUrl" description:"请求URL"` + OperIp string `json:"operIp" description:"主机地址"` + OperLocation string `json:"operLocation" description:"操作地点"` + OperParam string `json:"operParam" description:"请求参数"` + JsonResult string `json:"jsonResult" description:"返回参数"` + Status int `json:"status" description:"操作状态(0正常 1异常)"` + ErrorMsg string `json:"errorMsg" description:"错误消息"` + OperTime *gtime.Time `json:"operTime" description:"操作时间"` +} diff --git a/internal/model/sys_orgainzation.go b/internal/model/sys_orgainzation.go new file mode 100644 index 0000000..6ea27b9 --- /dev/null +++ b/internal/model/sys_orgainzation.go @@ -0,0 +1,72 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type OrganizationRes struct { + Id int64 `json:"id" description:"组织id"` + ParentId int64 `json:"parentId" description:"父组织id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + Name string `json:"name" description:"组织名称"` + Number string `json:"number" description:"组织编号"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*OrganizationRes `json:"children" description:"子集"` +} + +type OrganizationOut struct { + Id int64 `json:"id" description:"组织id"` + ParentId int64 `json:"parentId" description:"父组织id"` + Ancestors string `json:"ancestors" description:"祖级列表"` + Name string `json:"name" description:"组织名称"` + Number string `json:"number" description:"组织编号"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*OrganizationOut `json:"children" description:"子集"` +} + +type AddOrganizationInput struct { + ParentId int64 `json:"parentId" description:"父组织id"` + Name string `json:"name" description:"组织名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` +} + +type EditOrganizationInput struct { + Id int64 `json:"id" description:"组织id"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + Name string `json:"name" description:"组织名称"` + OrderNum int `json:"orderNum" description:"排序"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` +} + +type DetailOrganizationRes struct { + Id int64 `json:"id" description:"组织id"` + ParentId int64 `json:"parentId" description:"父部门id"` + OrganizationId int `json:"organizationId" description:"组织ID"` + Ancestors string `json:"ancestors" description:"祖级列表"` + Name string `json:"name" description:"组织名称"` + Number string `json:"number" description:"组织编号"` + OrderNum int `json:"orderNum" description:"显示顺序"` + Leader string `json:"leader" description:"负责人"` + Phone string `json:"phone" description:"联系电话"` + Email string `json:"email" description:"邮箱"` + Status uint `json:"status" description:"部门状态(0停用 1正常)"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} diff --git a/internal/model/sys_plugins.go b/internal/model/sys_plugins.go new file mode 100644 index 0000000..4a12165 --- /dev/null +++ b/internal/model/sys_plugins.go @@ -0,0 +1,31 @@ +package model + +type GetSysPluginsListInput struct { + PaginationInput +} + +type SysPluginsOutput struct { + Intro string `json:"intro" description:"介绍"` + Status int `json:"status" description:"状态"` + Types string `json:"types" description:"插件类型"` + StartTime string `json:"startTime" description:""` + Id int `json:"id" description:"ID"` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Version string `json:"version" description:"版本"` + Author string `json:"author" description:""` +} +type SysPluginsAddInput struct { + Version string `json:"version" description:"版本"` + Author string `json:"author" description:""` + Status int `json:"status" description:"状态"` + Types string `json:"types" description:"插件类型"` + StartTime string `json:"startTime" description:""` + Name string `json:"name" description:"名称"` + Title string `json:"title" description:"标题"` + Intro string `json:"intro" description:"介绍"` +} +type SysPluginsEditInput struct { + Id int `json:"id" description:"ID"` + SysPluginsAddInput +} diff --git a/internal/model/sys_post.go b/internal/model/sys_post.go new file mode 100644 index 0000000..adc66df --- /dev/null +++ b/internal/model/sys_post.go @@ -0,0 +1,58 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type PostRes struct { + PostId int64 `json:"postId" description:"岗位ID"` + ParentId int64 `json:"parentId" description:"父ID"` + PostCode string `json:"postCode" description:"岗位编码"` + PostName string `json:"postName" description:"岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + Remark string `json:"remark" description:"备注"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*PostRes `json:"children" description:"子集"` +} + +type PostOut struct { + PostId int64 `json:"postId" description:"岗位ID"` + ParentId int64 `json:"parentId" description:"父ID"` + PostCode string `json:"postCode" description:"岗位编码"` + PostName string `json:"postName" description:"岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + Remark string `json:"remark" description:"备注"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` + Children []*PostOut `json:"children" description:"子集"` +} + +type AddPostInput struct { + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + PostName string `json:"postName" description:"岗位名称" v:"required#请输入岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} + +type EditPostInput struct { + PostId int64 `json:"postId" description:"岗位ID" v:"required#岗位ID不能为空"` + ParentId int64 `json:"parentId" description:"父ID" v:"required#请输入选择上级"` + PostName string `json:"postName" description:"岗位名称" v:"required#请输入岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)" v:"required#请选择状态"` + Remark string `json:"remark" description:"备注"` +} + +type DetailPostRes struct { + PostId int64 `json:"postId" description:"岗位ID"` + ParentId int64 `json:"parentId" description:"父ID"` + PostCode string `json:"postCode" description:"岗位编码"` + PostName string `json:"postName" description:"岗位名称"` + PostSort int `json:"postSort" description:"显示顺序"` + Status uint `json:"status" description:"状态(0正常 1停用)"` + Remark string `json:"remark" description:"备注"` + IsDeleted int `json:"isDeleted" description:"是否删除 0未删除 1已删除"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` +} diff --git a/internal/model/sys_role.go b/internal/model/sys_role.go new file mode 100644 index 0000000..e3ead9f --- /dev/null +++ b/internal/model/sys_role.go @@ -0,0 +1,65 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type RoleTreeRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + ListOrder uint `json:"listOrder" description:"排序"` + Name string `json:"name" description:"角色名称"` + DataScope uint `json:"dataScope" description:"数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)"` + Remark string `json:"remark" description:"备注"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + Children []*RoleTreeRes `json:"children" description:"子集"` +} + +type RoleTreeOut struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + ListOrder uint `json:"listOrder" description:"排序"` + Name string `json:"name" description:"角色名称"` + DataScope uint `json:"dataScope" description:"数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)"` + Remark string `json:"remark" description:"备注"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + Children []*RoleTreeOut `json:"children" description:"子集"` +} + +type AddRoleInput struct { + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"角色名称"` + ListOrder uint `json:"listOrder" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + Remark string `json:"remark" description:"备注"` +} + +type EditRoleInput struct { + Id uint `json:"id" description:"ID"` + ParentId int `json:"parentId" description:"父ID"` + Name string `json:"name" description:"角色名称"` + ListOrder uint `json:"listOrder" description:"排序"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + Remark string `json:"remark" description:"备注"` +} + +type RoleInfoRes struct { + Id uint `json:"id" description:""` + ParentId int `json:"parentId" description:"父ID"` + ListOrder uint `json:"listOrder" description:"排序"` + Name string `json:"name" description:"角色名称"` + DataScope uint `json:"dataScope" description:"数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)"` + DeptIds []int64 `json:"deptIds" description:"数据范围为自定义数据权限时返回部门ID数组"` + Remark string `json:"remark" description:"备注"` + Status uint `json:"status" description:"状态;0:禁用;1:正常"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` +} diff --git a/internal/model/sys_token.go b/internal/model/sys_token.go new file mode 100644 index 0000000..e5d4037 --- /dev/null +++ b/internal/model/sys_token.go @@ -0,0 +1,29 @@ +/* +* @desc:token options + */ + +package model + +import ( + "github.com/gogf/gf/v2/frame/g" +) + +type TokenOptions struct { + // server name + ServerName string `json:"serverName"` + // 缓存key (每创建一个实例CacheKey必须不相同) + Prefix string `json:"prefix"` + // 超时时间 默认10天(秒) + Timeout int64 `json:"timeout"` + // 缓存刷新时间 默认5天(秒) + // 处理携带token的请求时当前时间大于超时时间并小于缓存刷新时间时token将自动刷新即重置token存活时间 + // MaxRefresh值为0时,token将不会自动刷新 + MaxRefresh int64 `json:"maxRefresh"` + // 是否允许多点登录 + MultiLogin bool `json:"multiLogin"` + // Token加密key 32位 + EncryptKey []byte `json:"encryptKey"` + // 拦截排除地址 + ExcludePaths g.SliceStr `json:"excludePaths"` + CacheModel string `json:"cacheModel"` +} diff --git a/internal/model/sys_user.go b/internal/model/sys_user.go new file mode 100644 index 0000000..5a4327c --- /dev/null +++ b/internal/model/sys_user.go @@ -0,0 +1,194 @@ +package model + +import ( + "github.com/gogf/gf/v2/os/gtime" +) + +type UserListDoInput struct { + KeyWords string `json:"keyWords" description:"关键词(可根据账号或者用户昵称查询)"` + DeptId int `json:"deptId" description:"部门ID"` + UserName string `json:"userName" description:"用户名"` + Mobile string `json:"mobile" description:"手机号"` + Status int `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + *PaginationInput +} + +// LoginUserRes 登录返回 +type LoginUserRes struct { + UserNickname string `orm:"user_nickname" json:"userNickname"` // 用户昵称 + Avatar string `orm:"avatar" json:"avatar"` //头像 +} + +type LoginUserOut struct { + UserNickname string `orm:"user_nickname" json:"userNickname"` // 用户昵称 + Avatar string `orm:"avatar" json:"avatar"` //头像 +} + +type UserListOut struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId int64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + Dept *DetailDeptRes `json:"dept" description:"部门信息"` + RolesNames string `json:"rolesNames" description:"角色信息"` +} + +type UserListRes struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId int64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + Dept *DetailDeptRes `json:"dept" description:"部门信息"` + RolesNames string `json:"rolesNames" description:"角色信息"` +} + +type UserRes struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId int64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + Dept *DetailDeptRes `json:"dept" description:"部门信息"` + RolesNames string `json:"rolesNames" description:"角色信息"` +} + +type AddUserInput struct { + UserName string `json:"userName" description:"用户名" v:"required#用户名不能为空"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号" v:"required#手机号不能为空"` + UserNickname string `json:"userNickname" description:"用户昵称" v:"required#用户昵称不能为空"` + Birthday int `json:"birthday" description:"生日"` + UserPassword string `json:"userPassword" description:"登录密码;cmf_password加密"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id" v:"required#部门不能为空"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} + +type EditUserInput struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名" v:"required#用户名不能为空"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号" v:"required#手机号不能为空"` + UserNickname string `json:"userNickname" description:"用户昵称" v:"required#用户昵称不能为空"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id" v:"required#部门不能为空"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} + +type UserInfoRes struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} +type UserInfoOut struct { + Id uint64 `json:"id" description:""` + UserName string `json:"userName" description:"用户名"` + UserTypes string `json:"userTypes" description:"系统 system 企业 company"` + Mobile string `json:"mobile" description:"中国手机不带国家代码,国际手机号格式为:国家代码-手机号"` + UserNickname string `json:"userNickname" description:"用户昵称"` + Birthday int `json:"birthday" description:"生日"` + UserEmail string `json:"userEmail" description:"用户登录邮箱"` + Sex int `json:"sex" description:"性别;0:保密,1:男,2:女"` + Avatar string `json:"avatar" description:"用户头像"` + DeptId uint64 `json:"deptId" description:"部门id"` + Remark string `json:"remark" description:"备注"` + IsAdmin int `json:"isAdmin" description:"是否后台管理员 1 是 0 否"` + Address string `json:"address" description:"联系地址"` + Describe string `json:"describe" description:"描述信息"` + LastLoginIp string `json:"lastLoginIp" description:"最后登录ip"` + LastLoginTime *gtime.Time `json:"lastLoginTime" description:"最后登录时间"` + Status uint `json:"status" description:"用户状态;0:禁用,1:正常,2:未验证"` + CreateBy uint `json:"createBy" description:"创建者"` + CreatedAt *gtime.Time `json:"createdAt" description:"创建日期"` + UpdateBy uint `json:"updateBy" description:"更新者"` + UpdatedAt *gtime.Time `json:"updatedAt" description:"修改日期"` + RoleIds []int `json:"roleIds" description:"角色ID数组" v:"required#角色不能为空"` + PostIds []int `json:"postIds" description:"岗位ID数组" v:"required#岗位不能为空"` +} diff --git a/internal/model/sys_user_online.go b/internal/model/sys_user_online.go new file mode 100644 index 0000000..a2f3a41 --- /dev/null +++ b/internal/model/sys_user_online.go @@ -0,0 +1,30 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type UserOnlineDoListInput struct { + *PaginationInput +} +type UserOnlineListRes struct { + Id uint `json:"id" description:""` + Uuid string `json:"uuid" description:"用户标识"` + Key string `json:"key" description:""` + Token string `json:"token" description:"用户token"` + CreatedAt *gtime.Time `json:"createdAt" description:"登录时间"` + UserName string `json:"userName" description:"用户名"` + Ip string `json:"ip" description:"登录ip"` + Explorer string `json:"explorer" description:"浏览器"` + Os string `json:"os" description:"操作系统"` +} + +type UserOnlineListOut struct { + Id uint `json:"id" description:""` + Uuid string `json:"uuid" description:"用户标识"` + Key string `json:"key" description:""` + Token string `json:"token" description:"用户token"` + CreatedAt *gtime.Time `json:"createdAt" description:"登录时间"` + UserName string `json:"userName" description:"用户名"` + Ip string `json:"ip" description:"登录ip"` + Explorer string `json:"explorer" description:"浏览器"` + Os string `json:"os" description:"操作系统"` +} diff --git a/internal/model/system_plugins_config.go b/internal/model/system_plugins_config.go new file mode 100644 index 0000000..5431c2d --- /dev/null +++ b/internal/model/system_plugins_config.go @@ -0,0 +1,32 @@ +package model + +type GetPluginsConfigListInput struct { + Id int `json:"id" description:"ID"` + PaginationInput +} +type PluginsConfigListOutput struct { + Data []PluginsConfigOutput + PaginationOutput +} +type PluginsConfigOutput struct { + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` + Id string `json:"id" description:""` + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` +} +type PluginsConfigAddInput struct { + Type string `json:"type" description:"插件类型"` + Name string `json:"name" description:"插件名称"` + Value string `json:"value" description:"配置内容"` + Doc string `json:"doc" description:"配置说明"` +} +type PluginsConfigEditInput struct { + Id int `json:"id" description:"ID"` + PluginsConfigAddInput +} + +type PluginsConfigData struct { + Msg string + Data interface{} +} diff --git a/internal/model/td_engine.go b/internal/model/td_engine.go new file mode 100644 index 0000000..36184cd --- /dev/null +++ b/internal/model/td_engine.go @@ -0,0 +1,22 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +type TDEngineTablesList struct { + TableName string `json:"tableName" description:"表名"` + DbName string `json:"dbName" description:"数据库名"` + StableName string `json:"stableName" description:"超级表名"` + CreateTime *gtime.Time `json:"createTime" description:"创建时间"` +} + +type TDEngineTableInfo struct { + Field string `json:"field" description:"字段名"` + Type string `json:"type" description:"类型"` + Length int `json:"length" description:"长度"` + Note string `json:"note" description:"note"` +} + +type TableDataInfo struct { + Filed []string `json:"filed" description:"字段"` + Info []map[string]interface{} `json:"info" description:"数据"` +} diff --git a/internal/model/td_log_table.go b/internal/model/td_log_table.go new file mode 100644 index 0000000..a03f2aa --- /dev/null +++ b/internal/model/td_log_table.go @@ -0,0 +1,19 @@ +package model + +import "github.com/gogf/gf/v2/os/gtime" + +// 设备日志 TDengine +type TdLog struct { + Ts *gtime.Time `json:"ts" dc:"时间"` + Device string `json:"device" dc:"设备标识"` + Type string `json:"type" dc:"日志类型"` + Content string `json:"content" dc:"日志内容"` +} + +// 日志写入 +type TdLogAddInput struct { + Ts *gtime.Time `json:"ts" dc:"时间"` + Device string `json:"device" dc:"设备标识"` + Type string `json:"type" dc:"日志类型"` + Content string `json:"content" dc:"日志内容"` +} diff --git a/internal/mqtt/mqtt.go b/internal/mqtt/mqtt.go new file mode 100644 index 0000000..11cc360 --- /dev/null +++ b/internal/mqtt/mqtt.go @@ -0,0 +1,37 @@ +package mqtt + +import ( + "context" + MQTT "github.com/eclipse/paho.mqtt.golang" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/sagoo-cloud/sagooiot/network/pkg/mqttclient" +) + +var systemMqttClient *mqttclient.MqttWrapperClient + +func InitSystemMqtt() error { + var ctx = gctx.New() + var err error + systemMqttClient, err = mqttclient.InitMqtt(&mqttclient.MqttConf{ + Addr: g.Cfg().MustGet(ctx, "mqtt.addr").String(), + ClientId: g.Cfg().MustGet(ctx, "mqtt.clientId").String(), + UserName: g.Cfg().MustGet(ctx, "mqtt.auth.userName").String(), + Password: g.Cfg().MustGet(ctx, "mqtt.auth.userPassWorld").String(), + }) + return err +} + +func Close() { + systemMqttClient.Close() +} + +func Publish(topic string, payload []byte) error { + return systemMqttClient.Publish(topic, payload) +} + +func Subscribe(ctx context.Context, topic string, f func(context.Context, MQTT.Client, MQTT.Message)) error { + return systemMqttClient.Subscribe(ctx, topic, func(client MQTT.Client, message MQTT.Message) { + f(ctx, client, message) + }) +} diff --git a/internal/packed/packed.go b/internal/packed/packed.go new file mode 100644 index 0000000..e20ab1e --- /dev/null +++ b/internal/packed/packed.go @@ -0,0 +1 @@ +package packed diff --git a/internal/service/alarm.go b/internal/service/alarm.go new file mode 100644 index 0000000..d874b6e --- /dev/null +++ b/internal/service/alarm.go @@ -0,0 +1,80 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ( + IAlarmLog interface { + Detail(ctx context.Context, id uint64) (out *model.AlarmLogOutput, err error) + Add(ctx context.Context, in *model.AlarmLogAddInput) (id uint64, err error) + List(ctx context.Context, in *model.AlarmLogListInput) (out *model.AlarmLogListOutput, err error) + Handle(ctx context.Context, in *model.AlarmLogHandleInput) (err error) + TotalForLevel(ctx context.Context) (total []model.AlarmLogLevelTotal, err error) + ClearLogByDays(ctx context.Context, days int) (err error) + } + IAlarmRule interface { + List(ctx context.Context, in *model.AlarmRuleListInput) (out *model.AlarmRuleListOutput, err error) + Cache(ctx context.Context) (rs map[string][]model.AlarmRuleOutput, err error) + Detail(ctx context.Context, id uint64) (out *model.AlarmRuleOutput, err error) + Add(ctx context.Context, in *model.AlarmRuleAddInput) (err error) + Edit(ctx context.Context, in *model.AlarmRuleEditInput) (err error) + Deploy(ctx context.Context, id uint64) (err error) + Undeploy(ctx context.Context, id uint64) (err error) + Del(ctx context.Context, id uint64) (err error) + Operator(ctx context.Context) (out []model.OperatorOutput, err error) + TriggerType(ctx context.Context, productKey string) (out []model.TriggerTypeOutput, err error) + TriggerParam(ctx context.Context, productKey string) (out []model.TriggerParamOutput, err error) + Check(ctx context.Context, productKey string, deviceKey string, data map[string]any) (err error) + } + IAlarmLevel interface { + Detail(ctx context.Context, level uint) (out model.AlarmLevelOutput, err error) + All(ctx context.Context) (out *model.AlarmLevelListOutput, err error) + Edit(ctx context.Context, in []*model.AlarmLevelEditInput) (err error) + } +) + +var ( + localAlarmLevel IAlarmLevel + localAlarmLog IAlarmLog + localAlarmRule IAlarmRule +) + +func AlarmLevel() IAlarmLevel { + if localAlarmLevel == nil { + panic("implement not found for interface IAlarmLevel, forgot register?") + } + return localAlarmLevel +} + +func RegisterAlarmLevel(i IAlarmLevel) { + localAlarmLevel = i +} + +func AlarmLog() IAlarmLog { + if localAlarmLog == nil { + panic("implement not found for interface IAlarmLog, forgot register?") + } + return localAlarmLog +} + +func RegisterAlarmLog(i IAlarmLog) { + localAlarmLog = i +} + +func AlarmRule() IAlarmRule { + if localAlarmRule == nil { + panic("implement not found for interface IAlarmRule, forgot register?") + } + return localAlarmRule +} + +func RegisterAlarmRule(i IAlarmRule) { + localAlarmRule = i +} diff --git a/internal/service/common.go b/internal/service/common.go new file mode 100644 index 0000000..933bc2f --- /dev/null +++ b/internal/service/common.go @@ -0,0 +1,142 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/common" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/gogf/gf/v2/net/ghttp" +) + +type ( + IBaseDbLink interface { + GetList(ctx context.Context, input *model.BaseDbLinkDoInput) (total int, out []*model.BaseDbLinkOut, err error) + Add(ctx context.Context, input *model.AddBaseDbLinkInput) (err error) + Detail(ctx context.Context, baseDbLinkId int) (entity *entity.BaseDbLink, err error) + Edit(ctx context.Context, input *model.EditBaseDbLinkInput) (err error) + Del(ctx context.Context, BaseDbLinkId int) (err error) + } + ICityData interface { + GetList(ctx context.Context, status int, name string, code string) (data []*entity.CityData, err error) + Add(ctx context.Context, city *entity.CityData) (err error) + Edit(ctx context.Context, city *entity.CityData) (err error) + GetInfoById(ctx context.Context, id int) (cityInfo *entity.CityData, err error) + DelById(ctx context.Context, id int) (err error) + GetAll(ctx context.Context) (data []*entity.CityData, err error) + } + IConfigData interface { + List(ctx context.Context, input *model.ConfigDoInput) (total int, out []*model.SysConfigOut, err error) + Add(ctx context.Context, input *model.AddConfigInput, userId int) (err error) + CheckConfigKeyUnique(ctx context.Context, configKey string, configId ...int) (err error) + Get(ctx context.Context, id int) (out *model.SysConfigOut, err error) + Edit(ctx context.Context, input *model.EditConfigInput, userId int) (err error) + Delete(ctx context.Context, ids []int) (err error) + GetConfigByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) + GetByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) + } + IDictData interface { + GetDictWithDataByType(ctx context.Context, input *model.GetDictInput) (dict *model.GetDictOut, err error) + List(ctx context.Context, input *model.SysDictSearchInput) (total int, out []*model.SysDictDataOut, err error) + Add(ctx context.Context, input *model.AddDictDataInput, userId int) (err error) + Get(ctx context.Context, dictCode uint) (out *model.SysDictDataOut, err error) + Edit(ctx context.Context, input *model.EditDictDataInput, userId int) (err error) + Delete(ctx context.Context, ids []int) (err error) + } + IDictType interface { + List(ctx context.Context, input *model.DictTypeDoInput) (total int, out []*model.SysDictTypeInfoOut, err error) + Add(ctx context.Context, input *model.AddDictTypeInput, userId int) (err error) + Edit(ctx context.Context, input *model.EditDictTypeInput, userId int) (err error) + Get(ctx context.Context, req *common.DictTypeGetReq) (dictType *model.SysDictTypeOut, err error) + ExistsDictType(ctx context.Context, dictType string, dictId ...int) (err error) + Delete(ctx context.Context, dictIds []int) (err error) + } + IUpload interface { + UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result common.UploadMultipleRes, err error) + UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result common.UploadResponse, err error) + UploadTencent(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) + UploadLocal(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) + CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) + CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) + } +) + +var ( + localUpload IUpload + localBaseDbLink IBaseDbLink + localCityData ICityData + localConfigData IConfigData + localDictData IDictData + localDictType IDictType +) + +func BaseDbLink() IBaseDbLink { + if localBaseDbLink == nil { + panic("implement not found for interface IBaseDbLink, forgot register?") + } + return localBaseDbLink +} + +func RegisterBaseDbLink(i IBaseDbLink) { + localBaseDbLink = i +} + +func CityData() ICityData { + if localCityData == nil { + panic("implement not found for interface ICityData, forgot register?") + } + return localCityData +} + +func RegisterCityData(i ICityData) { + localCityData = i +} + +func ConfigData() IConfigData { + if localConfigData == nil { + panic("implement not found for interface IConfigData, forgot register?") + } + return localConfigData +} + +func RegisterConfigData(i IConfigData) { + localConfigData = i +} + +func DictData() IDictData { + if localDictData == nil { + panic("implement not found for interface IDictData, forgot register?") + } + return localDictData +} + +func RegisterDictData(i IDictData) { + localDictData = i +} + +func DictType() IDictType { + if localDictType == nil { + panic("implement not found for interface IDictType, forgot register?") + } + return localDictType +} + +func RegisterDictType(i IDictType) { + localDictType = i +} + +func Upload() IUpload { + if localUpload == nil { + panic("implement not found for interface IUpload, forgot register?") + } + return localUpload +} + +func RegisterUpload(i IUpload) { + localUpload = i +} diff --git a/internal/service/context.go b/internal/service/context.go new file mode 100644 index 0000000..d369bc1 --- /dev/null +++ b/internal/service/context.go @@ -0,0 +1,34 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/net/ghttp" +) + +type IContext interface { + Init(r *ghttp.Request, customCtx *model.Context) + Get(ctx context.Context) *model.Context + SetUser(ctx context.Context, ctxUser *model.ContextUser) + GetLoginUser(ctx context.Context) *model.ContextUser + GetUserId(ctx context.Context) int + GetUserDeptId(ctx context.Context) int +} + +var localContext IContext + +func Context() IContext { + if localContext == nil { + panic("implement not found for interface IContext, forgot register?") + } + return localContext +} + +func RegisterContext(i IContext) { + localContext = i +} diff --git a/internal/service/datahub.go b/internal/service/datahub.go new file mode 100644 index 0000000..72346cb --- /dev/null +++ b/internal/service/datahub.go @@ -0,0 +1,178 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + + "github.com/go-gota/gota/dataframe" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +type ( + IDataTemplateNode interface { + Add(ctx context.Context, in *model.DataTemplateNodeAddInput) (err error) + Edit(ctx context.Context, in *model.DataTemplateNodeEditInput) (err error) + Del(ctx context.Context, id uint64) (err error) + List(ctx context.Context, tid uint64) (list []*model.DataTemplateNodeOutput, err error) + } + IDataTemplateRecord interface { + UpdateData(ctx context.Context, tid uint64) error + } + IDataNode interface { + Add(ctx context.Context, in *model.DataNodeAddInput) (err error) + Edit(ctx context.Context, in *model.DataNodeEditInput) (err error) + Del(ctx context.Context, nodeId uint64) (err error) + List(ctx context.Context, sourceId uint64) (list []*model.DataNodeOutput, err error) + Detail(ctx context.Context, nodeId uint64) (out *model.DataNodeOutput, err error) + } + IDataSource interface { + Add(ctx context.Context, in *model.DataSourceApiAddInput) (sourceId uint64, err error) + Edit(ctx context.Context, in *model.DataSourceApiEditInput) (err error) + Del(ctx context.Context, ids []uint64) (err error) + Search(ctx context.Context, in *model.DataSourceSearchInput) (out *model.DataSourceSearchOutput, err error) + List(ctx context.Context) (list []*entity.DataSource, err error) + Detail(ctx context.Context, sourceId uint64) (out *model.DataSourceOutput, err error) + Deploy(ctx context.Context, sourceId uint64) (err error) + Undeploy(ctx context.Context, sourceId uint64) (err error) + UpdateData(ctx context.Context, sourceId uint64) (err error) + GetData(ctx context.Context, in *model.DataSourceDataInput) (out *model.DataSourceDataOutput, err error) + GetAllData(ctx context.Context, in *model.SourceDataAllInput) (out *model.SourceDataAllOutput, err error) + AllSource(ctx context.Context) (out []*model.AllSourceOut, err error) + CopeSource(ctx context.Context, sourceId uint64) (err error) + UpdateInterval(ctx context.Context, sourceId uint64, cronExpression string) (err error) + GetApiData(ctx context.Context, sourceId uint64) (apiData []string, err error) + AddDb(ctx context.Context, in *model.DataSourceDbAddInput) (sourceId uint64, err error) + EditDb(ctx context.Context, in *model.DataSourceDbEditInput) (err error) + GetDbFields(ctx context.Context, sourceId uint64) (g.MapStrAny, error) + GetDbData(ctx context.Context, sourceId uint64) (string, error) + AddDevice(ctx context.Context, in *model.DataSourceDeviceAddInput) (sourceId uint64, err error) + EditDevice(ctx context.Context, in *model.DataSourceDeviceEditInput) (err error) + GetDeviceData(ctx context.Context, sourceId uint64) (string, error) + } + IDataSourceRecord interface { + GetForTpl(ctx context.Context, sourceId uint64, tid uint64) (rs gdb.Result, err error) + } + IDataTemplate interface { + Add(ctx context.Context, in *model.DataTemplateAddInput) (id uint64, err error) + Edit(ctx context.Context, in *model.DataTemplateEditInput) (err error) + Del(ctx context.Context, ids []uint64) (err error) + Search(ctx context.Context, in *model.DataTemplateSearchInput) (out *model.DataTemplateSearchOutput, err error) + List(ctx context.Context) (list []*entity.DataTemplate, err error) + Detail(ctx context.Context, id uint64) (out *model.DataTemplateOutput, err error) + Deploy(ctx context.Context, id uint64) (err error) + Undeploy(ctx context.Context, id uint64) (err error) + GetData(ctx context.Context, in *model.DataTemplateDataInput) (out *model.DataTemplateDataOutput, err error) + GetAllData(ctx context.Context, in *model.TemplateDataAllInput) (out *model.TemplateDataAllOutput, err error) + GetDataBySql(ctx context.Context, sql string) (df dataframe.DataFrame, err error) + GetDataByTableName(ctx context.Context, tableName string) (df dataframe.DataFrame, err error) + GetLastData(ctx context.Context, in *model.TemplateDataLastInput) (out *model.TemplateDataLastOutput, err error) + UpdateData(ctx context.Context, id uint64) error + GetInfoByIds(ctx context.Context, ids []uint64) (data []*entity.DataTemplate, err error) + AllTemplate(ctx context.Context) (out []*model.AllTemplateOut, err error) + UpdateInterval(ctx context.Context, id uint64, cronExpression string) (err error) + CopeTemplate(ctx context.Context, id uint64) (err error) + CheckRelation(ctx context.Context, id uint64) (yes bool, err error) + SetRelation(ctx context.Context, in *model.TemplateDataRelationInput) (err error) + SourceList(ctx context.Context, id uint64) (list []*model.DataSourceOutput, err error) + } + IDataTemplateBusi interface { + Add(ctx context.Context, in *model.DataTemplateBusiAddInput) (err error) + GetInfos(ctx context.Context, busiTypes int) (data *entity.DataTemplateBusi, err error) + GetInfo(ctx context.Context, busiTypes int) (data *entity.DataTemplateBusi, err error) + GetTable(ctx context.Context, busiTypes int) (table string, err error) + } +) + +var ( + localDataNode IDataNode + localDataSource IDataSource + localDataSourceRecord IDataSourceRecord + localDataTemplate IDataTemplate + localDataTemplateBusi IDataTemplateBusi + localDataTemplateNode IDataTemplateNode + localDataTemplateRecord IDataTemplateRecord +) + +func DataTemplateBusi() IDataTemplateBusi { + if localDataTemplateBusi == nil { + panic("implement not found for interface IDataTemplateBusi, forgot register?") + } + return localDataTemplateBusi +} + +func RegisterDataTemplateBusi(i IDataTemplateBusi) { + localDataTemplateBusi = i +} + +func DataTemplateNode() IDataTemplateNode { + if localDataTemplateNode == nil { + panic("implement not found for interface IDataTemplateNode, forgot register?") + } + return localDataTemplateNode +} + +func RegisterDataTemplateNode(i IDataTemplateNode) { + localDataTemplateNode = i +} + +func DataTemplateRecord() IDataTemplateRecord { + if localDataTemplateRecord == nil { + panic("implement not found for interface IDataTemplateRecord, forgot register?") + } + return localDataTemplateRecord +} + +func RegisterDataTemplateRecord(i IDataTemplateRecord) { + localDataTemplateRecord = i +} + +func DataNode() IDataNode { + if localDataNode == nil { + panic("implement not found for interface IDataNode, forgot register?") + } + return localDataNode +} + +func RegisterDataNode(i IDataNode) { + localDataNode = i +} + +func DataSource() IDataSource { + if localDataSource == nil { + panic("implement not found for interface IDataSource, forgot register?") + } + return localDataSource +} + +func RegisterDataSource(i IDataSource) { + localDataSource = i +} + +func DataSourceRecord() IDataSourceRecord { + if localDataSourceRecord == nil { + panic("implement not found for interface IDataSourceRecord, forgot register?") + } + return localDataSourceRecord +} + +func RegisterDataSourceRecord(i IDataSourceRecord) { + localDataSourceRecord = i +} + +func DataTemplate() IDataTemplate { + if localDataTemplate == nil { + panic("implement not found for interface IDataTemplate, forgot register?") + } + return localDataTemplate +} + +func RegisterDataTemplate(i IDataTemplate) { + localDataTemplate = i +} diff --git a/internal/service/envirotronics.go b/internal/service/envirotronics.go new file mode 100644 index 0000000..bc61253 --- /dev/null +++ b/internal/service/envirotronics.go @@ -0,0 +1,35 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ( + IEnvWeather interface { + CityWeatherList(ctx context.Context) (cityWeatherListOut []*model.CityWeatherListOut, err error) + GetCityWeatherById(ctx context.Context, id int) (cityWeatherListOut *model.CityWeatherListOut, err error) + GetCityTemperatureById(ctx context.Context, id int, types int) (cityWeatherEchartOut []*model.CityWeatherEchartOut, avgCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastAvgCityWeatherEchartOut []*model.CityWeatherEchartOut, err error) + GetCityWindpowerById(ctx context.Context, id int, types int) (cityWeatherEchartOut []*model.CityWeatherEchartOut, avgCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastCityWeatherEchartOut []*model.CityWeatherEchartOut, foreCastAvgCityWeatherEchartOut []*model.CityWeatherEchartOut, err error) + } +) + +var ( + localEnvWeather IEnvWeather +) + +func EnvWeather() IEnvWeather { + if localEnvWeather == nil { + panic("implement not found for interface IEnvWeather, forgot register?") + } + return localEnvWeather +} + +func RegisterEnvWeather(i IEnvWeather) { + localEnvWeather = i +} diff --git a/internal/service/middleware.go b/internal/service/middleware.go new file mode 100644 index 0000000..6e82492 --- /dev/null +++ b/internal/service/middleware.go @@ -0,0 +1,30 @@ +// ========================================================================== +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package service + +import ( + "github.com/gogf/gf/v2/net/ghttp" +) + +type IMiddleware interface { + ResponseHandler(r *ghttp.Request) + Ctx(r *ghttp.Request) + Auth(r *ghttp.Request) + MiddlewareCORS(r *ghttp.Request) + OperationLog(r *ghttp.Request) +} + +var localMiddleware IMiddleware + +func Middleware() IMiddleware { + if localMiddleware == nil { + panic("implement not found for interface IMiddleware, forgot register?") + } + return localMiddleware +} + +func RegisterMiddleware(i IMiddleware) { + localMiddleware = i +} diff --git a/internal/service/network.go b/internal/service/network.go new file mode 100644 index 0000000..4e4384d --- /dev/null +++ b/internal/service/network.go @@ -0,0 +1,59 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ( + INetworkServer interface { + GetServerList(ctx context.Context, in *model.GetNetworkServerListInput) (total int, out []*model.NetworkServerOut, err error) + GetServerRunList(ctx context.Context) (list []*model.NetworkServerRes, err error) + GetServerById(ctx context.Context, id int) (out *model.NetworkServerOut, err error) + AddServer(ctx context.Context, in model.NetworkServerAddInput) (err error) + EditServer(ctx context.Context, in model.NetworkServerEditInput) (err error) + DeleteServer(ctx context.Context, ids []int) (err error) + SetServerStatus(ctx context.Context, id, status int) (err error) + } + INetworkTunnel interface { + GetTunnelList(ctx context.Context, in *model.GetNetworkTunnelListInput) (total int, out []*model.NetworkTunnelOut, err error) + GetTunnelRunList(ctx context.Context) (out []*model.NetworkTunnelOut, err error) + GetTunnelById(ctx context.Context, id int) (out *model.NetworkTunnelOut, err error) + AddTunnel(ctx context.Context, in model.NetworkTunnelAddInput) (id int, err error) + EditTunnel(ctx context.Context, in model.NetworkTunnelEditInput) (err error) + DeleteTunnel(ctx context.Context, ids []int) (err error) + SetTunnelStatus(ctx context.Context, id, status int) (err error) + } +) + +var ( + localNetworkServer INetworkServer + localNetworkTunnel INetworkTunnel +) + +func NetworkServer() INetworkServer { + if localNetworkServer == nil { + panic("implement not found for interface INetworkServer, forgot register?") + } + return localNetworkServer +} + +func RegisterNetworkServer(i INetworkServer) { + localNetworkServer = i +} + +func NetworkTunnel() INetworkTunnel { + if localNetworkTunnel == nil { + panic("implement not found for interface INetworkTunnel, forgot register?") + } + return localNetworkTunnel +} + +func RegisterNetworkTunnel(i INetworkTunnel) { + localNetworkTunnel = i +} diff --git a/internal/service/notice.go b/internal/service/notice.go new file mode 100644 index 0000000..be75d32 --- /dev/null +++ b/internal/service/notice.go @@ -0,0 +1,94 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ( + INoticeLog interface { + Add(ctx context.Context, in *model.NoticeLogAddInput) (err error) + Del(ctx context.Context, ids []uint64) (err error) + Search(ctx context.Context, in *model.NoticeLogSearchInput) (out *model.NoticeLogSearchOutput, err error) + ClearLogByDays(ctx context.Context, days int) (err error) + } + INoticeTemplate interface { + GetNoticeTemplateList(ctx context.Context, in *model.GetNoticeTemplateListInput) (total, page int, list []*model.NoticeTemplateOutput, err error) + GetNoticeTemplateById(ctx context.Context, id string) (out *model.NoticeTemplateOutput, err error) + GetNoticeTemplateByConfigId(ctx context.Context, configId string) (out *model.NoticeTemplateOutput, err error) + AddNoticeTemplate(ctx context.Context, in model.NoticeTemplateAddInput) (err error) + EditNoticeTemplate(ctx context.Context, in model.NoticeTemplateEditInput) (err error) + SaveNoticeTemplate(ctx context.Context, in model.NoticeTemplateAddInput) (err error) + DeleteNoticeTemplate(ctx context.Context, Ids []string) (err error) + } + INoticeConfig interface { + GetNoticeConfigList(ctx context.Context, in *model.GetNoticeConfigListInput) (total, page int, list []*model.NoticeConfigOutput, err error) + GetNoticeConfigById(ctx context.Context, id int) (out *model.NoticeConfigOutput, err error) + AddNoticeConfig(ctx context.Context, in model.NoticeConfigAddInput) (err error) + EditNoticeConfig(ctx context.Context, in model.NoticeConfigEditInput) (err error) + DeleteNoticeConfig(ctx context.Context, Ids []string) (err error) + } + INoticeInfo interface { + GetNoticeInfoList(ctx context.Context, in *model.GetNoticeInfoListInput) (total, page int, list []*model.NoticeInfoOutput, err error) + GetNoticeInfoById(ctx context.Context, id int) (out *model.NoticeInfoOutput, err error) + AddNoticeInfo(ctx context.Context, in model.NoticeInfoAddInput) (err error) + EditNoticeInfo(ctx context.Context, in model.NoticeInfoEditInput) (err error) + DeleteNoticeInfo(ctx context.Context, Ids []int) (err error) + } +) + +var ( + localNoticeConfig INoticeConfig + localNoticeInfo INoticeInfo + localNoticeLog INoticeLog + localNoticeTemplate INoticeTemplate +) + +func NoticeTemplate() INoticeTemplate { + if localNoticeTemplate == nil { + panic("implement not found for interface INoticeTemplate, forgot register?") + } + return localNoticeTemplate +} + +func RegisterNoticeTemplate(i INoticeTemplate) { + localNoticeTemplate = i +} + +func NoticeConfig() INoticeConfig { + if localNoticeConfig == nil { + panic("implement not found for interface INoticeConfig, forgot register?") + } + return localNoticeConfig +} + +func RegisterNoticeConfig(i INoticeConfig) { + localNoticeConfig = i +} + +func NoticeInfo() INoticeInfo { + if localNoticeInfo == nil { + panic("implement not found for interface INoticeInfo, forgot register?") + } + return localNoticeInfo +} + +func RegisterNoticeInfo(i INoticeInfo) { + localNoticeInfo = i +} + +func NoticeLog() INoticeLog { + if localNoticeLog == nil { + panic("implement not found for interface INoticeLog, forgot register?") + } + return localNoticeLog +} + +func RegisterNoticeLog(i INoticeLog) { + localNoticeLog = i +} diff --git a/internal/service/product.go b/internal/service/product.go new file mode 100644 index 0000000..f189ba2 --- /dev/null +++ b/internal/service/product.go @@ -0,0 +1,215 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/model" +) + +type ( + IDevTSLEvent interface { + ListEvent(ctx context.Context, in *model.ListTSLEventInput) (out *model.ListTSLEventOutput, err error) + AddEvent(ctx context.Context, in *model.TSLEventInput) (err error) + EditEvent(ctx context.Context, in *model.TSLEventInput) (err error) + DelEvent(ctx context.Context, in *model.DelTSLEventInput) (err error) + } + IDevTSLTag interface { + ListTag(ctx context.Context, in *model.ListTSLTagInput) (out *model.ListTSLTagOutput, err error) + AddTag(ctx context.Context, in *model.TSLTagInput) (err error) + EditTag(ctx context.Context, in *model.TSLTagInput) (err error) + DelTag(ctx context.Context, in *model.DelTSLTagInput) (err error) + } + IDevCategory interface { + Detail(ctx context.Context, id uint) (out *model.ProductCategoryOutput, err error) + GetNameByIds(ctx context.Context, categoryIds []uint) (names map[uint]string, err error) + ListForPage(ctx context.Context, page, limit int, name string) (out []*model.ProductCategoryTreeOutput, total int, err error) + List(ctx context.Context, name string) (out []*model.ProductCategoryTreeOutput, err error) + Add(ctx context.Context, in *model.AddProductCategoryInput) (err error) + Edit(ctx context.Context, in *model.EditProductCategoryInput) (err error) + Del(ctx context.Context, id uint) (err error) + } + IDevDeviceLog interface { + LogType(ctx context.Context) (list []string) + Search(ctx context.Context, in *model.DeviceLogSearchInput) (out *model.DeviceLogSearchOutput, err error) + } + IDevDeviceTag interface { + Add(ctx context.Context, in *model.AddTagDeviceInput) (err error) + Edit(ctx context.Context, in *model.EditTagDeviceInput) (err error) + Del(ctx context.Context, id uint) (err error) + } + IDevProduct interface { + Get(ctx context.Context, key string) (out *model.DetailProductOutput, err error) + Detail(ctx context.Context, id uint) (out *model.DetailProductOutput, err error) + GetNameByIds(ctx context.Context, productIds []uint) (names map[uint]string, err error) + ListForPage(ctx context.Context, in *model.ListForPageInput) (out *model.ListForPageOutput, err error) + List(ctx context.Context) (list []*model.ProductOutput, err error) + Add(ctx context.Context, in *model.AddProductInput) (err error) + Edit(ctx context.Context, in *model.EditProductInput) (err error) + Del(ctx context.Context, ids []uint) (err error) + Deploy(ctx context.Context, id uint) (err error) + Undeploy(ctx context.Context, id uint) (err error) + } + IDevTSLDataType interface { + DataTypeValueList(ctx context.Context) (out *model.DataTypeOutput, err error) + } + IDevDevice interface { + Get(ctx context.Context, key string) (out *model.DeviceOutput, err error) + Detail(ctx context.Context, id uint) (out *model.DeviceOutput, err error) + ListForPage(ctx context.Context, in *model.ListDeviceForPageInput) (out *model.ListDeviceForPageOutput, err error) + List(ctx context.Context, in *model.ListDeviceInput) (list []*model.DeviceOutput, err error) + Add(ctx context.Context, in *model.AddDeviceInput) (deviceId uint, err error) + Edit(ctx context.Context, in *model.EditDeviceInput) (err error) + Del(ctx context.Context, ids []uint) (err error) + Deploy(ctx context.Context, id uint) (err error) + Undeploy(ctx context.Context, id uint) (err error) + Online(ctx context.Context, key string) (err error) + Offline(ctx context.Context, key string) (err error) + TotalByProductId(ctx context.Context, productIds []uint) (totals map[uint]int, err error) + Total(ctx context.Context) (data model.DeviceTotalOutput, err error) + TotalForMonths(ctx context.Context) (data map[int]int, err error) + AlarmTotalForMonths(ctx context.Context) (data map[int]int, err error) + RunStatus(ctx context.Context, id uint) (out *model.DeviceRunStatusOutput, err error) + GetProperty(ctx context.Context, in *model.DeviceGetPropertyInput) (out *model.DevicePropertiy, err error) + GetPropertyList(ctx context.Context, in *model.DeviceGetPropertyListInput) (out *model.DeviceGetPropertyListOutput, err error) + } + IDevTSLFunction interface { + ListFunction(ctx context.Context, in *model.ListTSLFunctionInput) (out *model.ListTSLFunctionOutput, err error) + AddFunction(ctx context.Context, in *model.TSLFunctionAddInput) (err error) + EditFunction(ctx context.Context, in *model.TSLFunctionAddInput) (err error) + DelFunction(ctx context.Context, in *model.DelTSLFunctionInput) (err error) + } + IDevTSLProperty interface { + ListProperty(ctx context.Context, in *model.ListTSLPropertyInput) (out *model.ListTSLPropertyOutput, err error) + AllProperty(ctx context.Context, key string) (list []model.TSLProperty, err error) + AddProperty(ctx context.Context, in *model.TSLPropertyInput) (err error) + EditProperty(ctx context.Context, in *model.TSLPropertyInput) (err error) + DelProperty(ctx context.Context, in *model.DelTSLPropertyInput) (err error) + } +) + +var ( + localDevCategory IDevCategory + localDevDeviceLog IDevDeviceLog + localDevDeviceTag IDevDeviceTag + localDevProduct IDevProduct + localDevTSLDataType IDevTSLDataType + localDevTSLEvent IDevTSLEvent + localDevTSLTag IDevTSLTag + localDevDevice IDevDevice + localDevTSLFunction IDevTSLFunction + localDevTSLProperty IDevTSLProperty +) + +func DevTSLProperty() IDevTSLProperty { + if localDevTSLProperty == nil { + panic("implement not found for interface IDevTSLProperty, forgot register?") + } + return localDevTSLProperty +} + +func RegisterDevTSLProperty(i IDevTSLProperty) { + localDevTSLProperty = i +} + +func DevDevice() IDevDevice { + if localDevDevice == nil { + panic("implement not found for interface IDevDevice, forgot register?") + } + return localDevDevice +} + +func RegisterDevDevice(i IDevDevice) { + localDevDevice = i +} + +func DevTSLFunction() IDevTSLFunction { + if localDevTSLFunction == nil { + panic("implement not found for interface IDevTSLFunction, forgot register?") + } + return localDevTSLFunction +} + +func RegisterDevTSLFunction(i IDevTSLFunction) { + localDevTSLFunction = i +} + +func DevDeviceTag() IDevDeviceTag { + if localDevDeviceTag == nil { + panic("implement not found for interface IDevDeviceTag, forgot register?") + } + return localDevDeviceTag +} + +func RegisterDevDeviceTag(i IDevDeviceTag) { + localDevDeviceTag = i +} + +func DevProduct() IDevProduct { + if localDevProduct == nil { + panic("implement not found for interface IDevProduct, forgot register?") + } + return localDevProduct +} + +func RegisterDevProduct(i IDevProduct) { + localDevProduct = i +} + +func DevTSLDataType() IDevTSLDataType { + if localDevTSLDataType == nil { + panic("implement not found for interface IDevTSLDataType, forgot register?") + } + return localDevTSLDataType +} + +func RegisterDevTSLDataType(i IDevTSLDataType) { + localDevTSLDataType = i +} + +func DevTSLEvent() IDevTSLEvent { + if localDevTSLEvent == nil { + panic("implement not found for interface IDevTSLEvent, forgot register?") + } + return localDevTSLEvent +} + +func RegisterDevTSLEvent(i IDevTSLEvent) { + localDevTSLEvent = i +} + +func DevTSLTag() IDevTSLTag { + if localDevTSLTag == nil { + panic("implement not found for interface IDevTSLTag, forgot register?") + } + return localDevTSLTag +} + +func RegisterDevTSLTag(i IDevTSLTag) { + localDevTSLTag = i +} + +func DevCategory() IDevCategory { + if localDevCategory == nil { + panic("implement not found for interface IDevCategory, forgot register?") + } + return localDevCategory +} + +func RegisterDevCategory(i IDevCategory) { + localDevCategory = i +} + +func DevDeviceLog() IDevDeviceLog { + if localDevDeviceLog == nil { + panic("implement not found for interface IDevDeviceLog, forgot register?") + } + return localDevDeviceLog +} + +func RegisterDevDeviceLog(i IDevDeviceLog) { + localDevDeviceLog = i +} diff --git a/internal/service/system.go b/internal/service/system.go new file mode 100644 index 0000000..62bd81a --- /dev/null +++ b/internal/service/system.go @@ -0,0 +1,518 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/api/v1/system" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/model/entity" + "net/url" + + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/tiger1103/gfast-token/gftoken" +) + +type ( + ISysJob interface { + JobList(ctx context.Context, input *model.GetJobListInput) (total int, out []*model.SysJobOut, err error) + GetJobs(ctx context.Context) (jobs []*model.SysJobOut, err error) + AddJob(ctx context.Context, input *model.SysJobAddInput) (err error) + GetJobInfoById(ctx context.Context, id int) (job *model.SysJobOut, err error) + EditJob(ctx context.Context, input *model.SysJobEditInput) error + JobStart(ctx context.Context, job *model.SysJobOut) error + JobStartMult(ctx context.Context, jobs []*model.SysJobOut) error + JobStop(ctx context.Context, job *model.SysJobOut) error + JobRun(ctx context.Context, job *model.SysJobOut) error + DeleteJobByIds(ctx context.Context, ids []int) (err error) + WithValue(ctx context.Context, value string) context.Context + Value(ctx context.Context) uint64 + } + ISysMenu interface { + GetAll(ctx context.Context) (data []*entity.SysMenu, err error) + GetTree(ctx context.Context, title string, status int) (data []*model.SysMenuOut, err error) + Add(ctx context.Context, input *model.AddMenuInput) (err error) + Detail(ctx context.Context, menuId int64) (entity *entity.SysMenu, err error) + Edit(ctx context.Context, input *model.EditMenuInput) (err error) + Del(ctx context.Context, menuId int64) (err error) + GetData(ctx context.Context, title string, status int) (data []*model.SysMenuOut, err error) + GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenu, err error) + GetInfoById(ctx context.Context, id int) (data *entity.SysMenu, err error) + } + ISysOperLog interface { + GetList(ctx context.Context, input *model.SysOperLogDoInput) (total int, out []*model.SysOperLogOut, err error) + Invoke(ctx context.Context, userId int, url *url.URL, param g.Map, method string, clientIp string, res map[string]interface{}, err error) + Add(ctx context.Context, userId int, url *url.URL, param g.Map, method string, clientIp string, res map[string]interface{}, erro error) (err error) + Detail(ctx context.Context, operId int) (entity *entity.SysOperLog, err error) + Del(ctx context.Context, operIds []int) (err error) + ClearOperationLogByDays(ctx context.Context, days int) (err error) + } + ISysOrganization interface { + GetTree(ctx context.Context, name string, status int) (data []*model.OrganizationOut, err error) + GetData(ctx context.Context, name string, status int) (data []*model.OrganizationOut, err error) + Add(ctx context.Context, input *model.AddOrganizationInput) (err error) + Edit(ctx context.Context, input *model.EditOrganizationInput) (err error) + Detail(ctx context.Context, id int64) (entity *entity.SysOrganization, err error) + Del(ctx context.Context, id int64) (err error) + GetAll(ctx context.Context) (data []*entity.SysOrganization, err error) + Count(ctx context.Context) (count int, err error) + } + ISystemPluginsConfig interface { + GetPluginsConfigList(ctx context.Context, in *model.GetPluginsConfigListInput) (total, page int, list []*model.PluginsConfigOutput, err error) + GetPluginsConfigById(ctx context.Context, id int) (out *model.PluginsConfigOutput, err error) + GetPluginsConfigByName(ctx context.Context, types, name string) (out *model.PluginsConfigOutput, err error) + AddPluginsConfig(ctx context.Context, in model.PluginsConfigAddInput) (err error) + EditPluginsConfig(ctx context.Context, in model.PluginsConfigEditInput) (err error) + SavePluginsConfig(ctx context.Context, in model.PluginsConfigAddInput) (err error) + DeletePluginsConfig(ctx context.Context, Ids []int) (err error) + UpdateAllPluginsConfigCache() (err error) + GetPluginsConfigData(pluginType, pluginName string) (res map[interface{}]interface{}, err error) + } + ISysUser interface { + GetUserByUsername(ctx context.Context, userName string) (data *entity.SysUser, err error) + GetAdminUserByUsernamePassword(ctx context.Context, userName string, password string) (user *entity.SysUser, err error) + UpdateLoginInfo(ctx context.Context, id uint64, ip string) (err error) + UserList(ctx context.Context, input *model.UserListDoInput) (total int, out []*model.UserListOut, err error) + Add(ctx context.Context, input *model.AddUserInput) (err error) + Edit(ctx context.Context, input *model.EditUserInput) (err error) + GetUserById(ctx context.Context, id uint) (out *model.UserInfoOut, err error) + DelInfoById(ctx context.Context, id uint) (err error) + ResetPassword(ctx context.Context, id uint, userPassword string) (err error) + EditUserStatus(ctx context.Context, id uint, status uint) (err error) + GetUserByIds(ctx context.Context, id []int) (data []*entity.SysUser, err error) + GetAll(ctx context.Context) (data []*entity.SysUser, err error) + CurrentUser(ctx context.Context) (userInfoOut *model.UserInfoOut, menuTreeOut []*model.UserMenuTreeOut, err error) + EditUserAvatar(ctx context.Context, id uint, avatar string) (err error) + } + ILogin interface { + Login(ctx context.Context, verifyKey string, captcha string, userName string, password string) (loginUserOut *model.LoginUserOut, token string, err error) + LoginOut(ctx context.Context) (err error) + } + ISysMenuButton interface { + GetList(ctx context.Context, status int, name string, menuId int) (data []model.UserMenuButtonRes, err error) + GetData(ctx context.Context, status int, name string, menuId int, menuButton []model.UserMenuButtonRes) (data []model.UserMenuButtonRes, err error) + Add(ctx context.Context, input *model.AddMenuButtonInput) (err error) + Detail(ctx context.Context, Id int64) (entity *entity.SysMenuButton, err error) + Edit(ctx context.Context, input *model.EditMenuButtonInput) (err error) + Del(ctx context.Context, Id int64) (err error) + GetInfoByButtonIds(ctx context.Context, ids []int) (data []*entity.SysMenuButton, err error) + GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuButton, err error) + EditStatus(ctx context.Context, id int, menuId int, status int) (err error) + } + ISysPlugins interface { + GetSysPluginsList(ctx context.Context, in *model.GetSysPluginsListInput) (total, page int, list []*model.SysPluginsOutput, err error) + GetSysPluginsById(ctx context.Context, id int) (out *model.SysPluginsOutput, err error) + AddSysPlugins(ctx context.Context, in model.SysPluginsAddInput) (err error) + EditSysPlugins(ctx context.Context, in model.SysPluginsEditInput) (err error) + DeleteSysPlugins(ctx context.Context, Ids []int) (err error) + SaveSysPlugins(ctx context.Context, in model.SysPluginsAddInput) (err error) + EditStatus(ctx context.Context, id int, status int) (err error) + } + ISysRole interface { + GetAll(ctx context.Context) (entity []*entity.SysRole, err error) + GetTree(ctx context.Context, name string, status int) (out []*model.RoleTreeOut, err error) + Add(ctx context.Context, input *model.AddRoleInput) (err error) + Edit(ctx context.Context, input *model.EditRoleInput) (err error) + GetInfoById(ctx context.Context, id uint) (entity *entity.SysRole, err error) + DelInfoById(ctx context.Context, id uint) (err error) + GetRoleList(ctx context.Context) (list []*model.RoleInfoRes, err error) + GetInfoByIds(ctx context.Context, id []int) (entity []*entity.SysRole, err error) + DataScope(ctx context.Context, id int, dataScope uint, deptIds []int64) (err error) + GetAuthorizeById(ctx context.Context, id int) (menuIds []string, menuButtonIds []string, menuColumnIds []string, menuApiIds []string, err error) + } + ISysUserOnline interface { + Invoke(ctx context.Context, data *entity.SysUserOnline) + Add(ctx context.Context, data *entity.SysUserOnline) + DelByToken(ctx context.Context, token string) (err error) + GetInfoByToken(ctx context.Context, token string) (data *entity.SysUserOnline, err error) + DelByIds(ctx context.Context, ids []uint) (err error) + GetAll(ctx context.Context) (data []*entity.SysUserOnline, err error) + UserOnlineList(ctx context.Context, input *model.UserOnlineDoListInput) (total int, out []*model.UserOnlineListOut, err error) + UserOnlineStrongBack(ctx context.Context, id int) (err error) + } + ISysApi interface { + GetInfoByIds(ctx context.Context, ids []int) (data []*entity.SysApi, err error) + GetApiByMenuId(ctx context.Context, apiId int) (data []*entity.SysApi, err error) + GetInfoById(ctx context.Context, id int) (entity *entity.SysApi, err error) + GetApiAll(ctx context.Context) (data []*entity.SysApi, err error) + GetApiTree(ctx context.Context, name string, address string, status int, types int) (out []*model.SysApiTreeOut, err error) + Add(ctx context.Context, input *model.AddApiInput) (err error) + Detail(ctx context.Context, id int) (out *model.SysApiOut, err error) + Edit(ctx context.Context, input *model.EditApiInput) (err error) + Del(ctx context.Context, Id int) (err error) + EditStatus(ctx context.Context, id int, status int) (err error) + GetInfoByAddress(ctx context.Context, address string) (entity *entity.SysApi, err error) + } + ISysLoginLog interface { + Invoke(ctx context.Context, data *model.LoginLogParams) + Add(ctx context.Context, params *model.LoginLogParams) + GetList(ctx context.Context, req *model.SysLoginLogInput) (total, page int, list []*model.SysLoginLogOut, err error) + Detail(ctx context.Context, infoId int) (entity *entity.SysLoginLog, err error) + Del(ctx context.Context, infoIds []int) (err error) + } + ISysMenuApi interface { + GetInfoByIds(ctx context.Context, ids []int) (data []*entity.SysMenuApi, err error) + GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuApi, err error) + GetInfoByApiId(ctx context.Context, apiId int) (data []*entity.SysMenuApi, err error) + } + ISysMenuColumn interface { + GetList(ctx context.Context, input *model.MenuColumnDoInput) (data []model.UserMenuColumnRes, err error) + GetData(ctx context.Context, input *model.MenuColumnDoInput, menuColumn []model.UserMenuColumnRes) (data []model.UserMenuColumnRes, err error) + Add(ctx context.Context, input *model.AddMenuColumnInput) (err error) + Detail(ctx context.Context, Id int64) (entity *entity.SysMenuColumn, err error) + Edit(ctx context.Context, input *model.EditMenuColumnInput) (err error) + Del(ctx context.Context, Id int64) (err error) + EditStatus(ctx context.Context, id int, menuId int, status int) (err error) + GetInfoByColumnIds(ctx context.Context, ids []int) (data []*entity.SysMenuColumn, err error) + GetInfoByMenuIds(ctx context.Context, menuIds []int) (data []*entity.SysMenuColumn, err error) + } + ISysNotifications interface { + GetSysNotificationsList(ctx context.Context, input *model.GetNotificationsListInput) (total, page int, list []*model.NotificationsOut, err error) + GetSysNotificationsById(ctx context.Context, id int) (out *model.NotificationsRes, err error) + AddSysNotifications(ctx context.Context, in model.NotificationsAddInput) (err error) + EditSysNotifications(ctx context.Context, in model.NotificationsEditInput) (err error) + DeleteSysNotifications(ctx context.Context, in *system.DeleteNotificationsReq) (err error) + } + ISysToken interface { + GenerateToken(ctx context.Context, key string, data interface{}) (keys string, err error) + ParseToken(r *ghttp.Request) (*gftoken.CustomClaims, error) + } + ISysUserRole interface { + GetInfoByUserId(ctx context.Context, userId int) (data []*entity.SysUserRole, err error) + } + ISysAuthorize interface { + AuthorizeQuery(ctx context.Context, itemsType string, menuIds []int) (out []*model.AuthorizeQueryTreeOut, err error) + GetInfoByRoleId(ctx context.Context, roleId int) (data []*entity.SysAuthorize, err error) + GetInfoByRoleIds(ctx context.Context, roleIds []int) (data []*entity.SysAuthorize, err error) + GetInfoByRoleIdsAndItemsType(ctx context.Context, roleIds []int, itemsType string) (data []*entity.SysAuthorize, err error) + DelByRoleId(ctx context.Context, roleId int) (err error) + Add(ctx context.Context, authorize []*entity.SysAuthorize) (err error) + AddAuthorize(ctx context.Context, roleId int, menuIds []string, buttonIds []string, columnIds []string, apiIds []string) (err error) + IsAllowAuthorize(ctx context.Context, roleId int) (isAllow bool, err error) + } + ISysDept interface { + GetTree(ctx context.Context, deptName string, status int) (out []*model.DeptOut, err error) + GetData(ctx context.Context, deptName string, status int) (data []*model.DeptOut, err error) + Add(ctx context.Context, input *model.AddDeptInput) (err error) + Edit(ctx context.Context, input *model.EditDeptInput) (err error) + Detail(ctx context.Context, deptId int64) (entity *entity.SysDept, err error) + Del(ctx context.Context, deptId int64) (err error) + GetAll(ctx context.Context) (data []*entity.SysDept, err error) + GetFromCache(ctx context.Context) (list []*entity.SysDept, err error) + FindSonByParentId(deptList []*entity.SysDept, deptId int64) []*entity.SysDept + } + ISysPost interface { + GetTree(ctx context.Context, postName string, postCode string, status int) (data []*model.PostOut, err error) + Add(ctx context.Context, input *model.AddPostInput) (err error) + Edit(ctx context.Context, input *model.EditPostInput) (err error) + Detail(ctx context.Context, postId int64) (entity *entity.SysPost, err error) + GetData(ctx context.Context, postName string, postCode string, status int) (data []*model.PostOut, err error) + Del(ctx context.Context, postId int64) (err error) + GetUsedPost(ctx context.Context) (list []*model.DetailPostRes, err error) + } + ISysRoleDept interface { + GetInfoByRoleId(ctx context.Context, roleId int) (data []*entity.SysRoleDept, err error) + } + ISysUserPost interface { + GetInfoByUserId(ctx context.Context, userId int) (data []*entity.SysUserPost, err error) + } + ICaptcha interface { + GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string, err error) + VerifyString(id, answer string) bool + } +) + +var ( + localSysMenuButton ISysMenuButton + localSysPlugins ISysPlugins + localSysRole ISysRole + localSysUserOnline ISysUserOnline + localSysApi ISysApi + localSysLoginLog ISysLoginLog + localSysMenuApi ISysMenuApi + localSysMenuColumn ISysMenuColumn + localSysNotifications ISysNotifications + localSysToken ISysToken + localSysUserRole ISysUserRole + localSysAuthorize ISysAuthorize + localSysDept ISysDept + localSysPost ISysPost + localSysRoleDept ISysRoleDept + localSysUserPost ISysUserPost + localCaptcha ICaptcha + localSysJob ISysJob + localSysMenu ISysMenu + localSysOperLog ISysOperLog + localSysOrganization ISysOrganization + localSystemPluginsConfig ISystemPluginsConfig + localSysUser ISysUser + localLogin ILogin +) + +func SysOperLog() ISysOperLog { + if localSysOperLog == nil { + panic("implement not found for interface ISysOperLog, forgot register?") + } + return localSysOperLog +} + +func RegisterSysOperLog(i ISysOperLog) { + localSysOperLog = i +} + +func SysOrganization() ISysOrganization { + if localSysOrganization == nil { + panic("implement not found for interface ISysOrganization, forgot register?") + } + return localSysOrganization +} + +func RegisterSysOrganization(i ISysOrganization) { + localSysOrganization = i +} + +func SystemPluginsConfig() ISystemPluginsConfig { + if localSystemPluginsConfig == nil { + panic("implement not found for interface ISystemPluginsConfig, forgot register?") + } + return localSystemPluginsConfig +} + +func RegisterSystemPluginsConfig(i ISystemPluginsConfig) { + localSystemPluginsConfig = i +} + +func SysUser() ISysUser { + if localSysUser == nil { + panic("implement not found for interface ISysUser, forgot register?") + } + return localSysUser +} + +func RegisterSysUser(i ISysUser) { + localSysUser = i +} + +func Login() ILogin { + if localLogin == nil { + panic("implement not found for interface ILogin, forgot register?") + } + return localLogin +} + +func RegisterLogin(i ILogin) { + localLogin = i +} + +func SysJob() ISysJob { + if localSysJob == nil { + panic("implement not found for interface ISysJob, forgot register?") + } + return localSysJob +} + +func RegisterSysJob(i ISysJob) { + localSysJob = i +} + +func SysMenu() ISysMenu { + if localSysMenu == nil { + panic("implement not found for interface ISysMenu, forgot register?") + } + return localSysMenu +} + +func RegisterSysMenu(i ISysMenu) { + localSysMenu = i +} + +func SysRole() ISysRole { + if localSysRole == nil { + panic("implement not found for interface ISysRole, forgot register?") + } + return localSysRole +} + +func RegisterSysRole(i ISysRole) { + localSysRole = i +} + +func SysUserOnline() ISysUserOnline { + if localSysUserOnline == nil { + panic("implement not found for interface ISysUserOnline, forgot register?") + } + return localSysUserOnline +} + +func RegisterSysUserOnline(i ISysUserOnline) { + localSysUserOnline = i +} + +func SysApi() ISysApi { + if localSysApi == nil { + panic("implement not found for interface ISysApi, forgot register?") + } + return localSysApi +} + +func RegisterSysApi(i ISysApi) { + localSysApi = i +} + +func SysMenuButton() ISysMenuButton { + if localSysMenuButton == nil { + panic("implement not found for interface ISysMenuButton, forgot register?") + } + return localSysMenuButton +} + +func RegisterSysMenuButton(i ISysMenuButton) { + localSysMenuButton = i +} + +func SysPlugins() ISysPlugins { + if localSysPlugins == nil { + panic("implement not found for interface ISysPlugins, forgot register?") + } + return localSysPlugins +} + +func RegisterSysPlugins(i ISysPlugins) { + localSysPlugins = i +} + +func SysMenuColumn() ISysMenuColumn { + if localSysMenuColumn == nil { + panic("implement not found for interface ISysMenuColumn, forgot register?") + } + return localSysMenuColumn +} + +func RegisterSysMenuColumn(i ISysMenuColumn) { + localSysMenuColumn = i +} + +func SysNotifications() ISysNotifications { + if localSysNotifications == nil { + panic("implement not found for interface ISysNotifications, forgot register?") + } + return localSysNotifications +} + +func RegisterSysNotifications(i ISysNotifications) { + localSysNotifications = i +} + +func SysToken() ISysToken { + if localSysToken == nil { + panic("implement not found for interface ISysToken, forgot register?") + } + return localSysToken +} + +func RegisterSysToken(i ISysToken) { + localSysToken = i +} + +func SysUserRole() ISysUserRole { + if localSysUserRole == nil { + panic("implement not found for interface ISysUserRole, forgot register?") + } + return localSysUserRole +} + +func RegisterSysUserRole(i ISysUserRole) { + localSysUserRole = i +} + +func SysAuthorize() ISysAuthorize { + if localSysAuthorize == nil { + panic("implement not found for interface ISysAuthorize, forgot register?") + } + return localSysAuthorize +} + +func RegisterSysAuthorize(i ISysAuthorize) { + localSysAuthorize = i +} + +func SysLoginLog() ISysLoginLog { + if localSysLoginLog == nil { + panic("implement not found for interface ISysLoginLog, forgot register?") + } + return localSysLoginLog +} + +func RegisterSysLoginLog(i ISysLoginLog) { + localSysLoginLog = i +} + +func SysMenuApi() ISysMenuApi { + if localSysMenuApi == nil { + panic("implement not found for interface ISysMenuApi, forgot register?") + } + return localSysMenuApi +} + +func RegisterSysMenuApi(i ISysMenuApi) { + localSysMenuApi = i +} + +func SysRoleDept() ISysRoleDept { + if localSysRoleDept == nil { + panic("implement not found for interface ISysRoleDept, forgot register?") + } + return localSysRoleDept +} + +func RegisterSysRoleDept(i ISysRoleDept) { + localSysRoleDept = i +} + +func SysUserPost() ISysUserPost { + if localSysUserPost == nil { + panic("implement not found for interface ISysUserPost, forgot register?") + } + return localSysUserPost +} + +func RegisterSysUserPost(i ISysUserPost) { + localSysUserPost = i +} + +func Captcha() ICaptcha { + if localCaptcha == nil { + panic("implement not found for interface ICaptcha, forgot register?") + } + return localCaptcha +} + +func RegisterCaptcha(i ICaptcha) { + localCaptcha = i +} + +func SysDept() ISysDept { + if localSysDept == nil { + panic("implement not found for interface ISysDept, forgot register?") + } + return localSysDept +} + +func RegisterSysDept(i ISysDept) { + localSysDept = i +} + +func SysPost() ISysPost { + if localSysPost == nil { + panic("implement not found for interface ISysPost, forgot register?") + } + return localSysPost +} + +func RegisterSysPost(i ISysPost) { + localSysPost = i +} diff --git a/internal/service/tdengine.go b/internal/service/tdengine.go new file mode 100644 index 0000000..c3754b7 --- /dev/null +++ b/internal/service/tdengine.go @@ -0,0 +1,87 @@ +// ================================================================================ +// Code generated by GoFrame CLI tool. DO NOT EDIT. +// You can delete these comments if you wish manually maintain this interface file. +// ================================================================================ + +package service + +import ( + "context" + "database/sql" + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +type ( + ITdEngine interface { + GetConn(ctx context.Context, dbName string) (db *sql.DB, err error) + GetTdEngineAllDb(ctx context.Context) (data []string, err error) + GetListTableByDatabases(ctx context.Context, dbName string) (data []*model.TDEngineTablesList, err error) + GetTdEngineTableInfoByTable(ctx context.Context, dbName string, tableName string) (data []*model.TDEngineTableInfo, err error) + GetTdEngineTableDataByTable(ctx context.Context, dbName string, tableName string) (data *model.TableDataInfo, err error) + GetOne(ctx context.Context, sql string, args ...any) (rs gdb.Record, err error) + GetAll(ctx context.Context, sql string, args ...any) (rs gdb.Result, err error) + Time(v *g.Var) (rs *g.Var) + } + ITdLogTable interface { + CreateStable(ctx context.Context) (err error) + Insert(ctx context.Context, log *model.TdLogAddInput) (err error) + Clear(ctx context.Context) (err error) + GetAll(ctx context.Context, sql string, args ...any) (list []model.TdLog, err error) + } + ITSLTable interface { + Insert(ctx context.Context, deviceKey string, data map[string]any) (err error) + CreateStable(ctx context.Context, tsl *model.TSL) (err error) + CreateTable(ctx context.Context, stable, table string) (err error) + DropStable(ctx context.Context, table string) (err error) + DropTable(ctx context.Context, table string) (err error) + CreateDatabase(ctx context.Context) (err error) + AddDatabaseField(ctx context.Context, tableName, fieldName string, dataType string, len int) (err error) + DelDatabaseField(ctx context.Context, tableName, fieldName string) (err error) + ModifyDatabaseField(ctx context.Context, tableName, fieldName string, dataType string, len int) (err error) + AddTag(ctx context.Context, tableName, tagName string, dataType string, len int) (err error) + DelTag(ctx context.Context, tableName, tagName string) (err error) + ModifyTag(ctx context.Context, tableName, tagName string, dataType string, len int) (err error) + } +) + +var ( + localTdLogTable ITdLogTable + localTSLTable ITSLTable + localTdEngine ITdEngine +) + +func TdEngine() ITdEngine { + if localTdEngine == nil { + panic("implement not found for interface ITdEngine, forgot register?") + } + return localTdEngine +} + +func RegisterTdEngine(i ITdEngine) { + localTdEngine = i +} + +func TdLogTable() ITdLogTable { + if localTdLogTable == nil { + panic("implement not found for interface ITdLogTable, forgot register?") + } + return localTdLogTable +} + +func RegisterTdLogTable(i ITdLogTable) { + localTdLogTable = i +} + +func TSLTable() ITSLTable { + if localTSLTable == nil { + panic("implement not found for interface ITSLTable, forgot register?") + } + return localTSLTable +} + +func RegisterTSLTable(i ITSLTable) { + localTSLTable = i +} diff --git a/internal/task/HTTP_Client.go b/internal/task/HTTP_Client.go new file mode 100644 index 0000000..01b56bf --- /dev/null +++ b/internal/task/HTTP_Client.go @@ -0,0 +1,26 @@ +package task + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" +) + +// GetAccessURL 执行访问URL +func GetAccessURL(ctx context.Context) { + + //获取参数 + t := jobTask.TimeTaskList.GetByName("getAccessURL") + if t == nil { + return + } + glog.Infof(ctx, "执行任务:访问URL", gconv.Int(t.Param[0])) + + res, err := g.Client().Get(ctx, gconv.String(t.Param[0])) + if err != nil { + glog.Error(ctx, err) + } + defer res.Close() +} diff --git a/internal/task/bind_function.go b/internal/task/bind_function.go new file mode 100644 index 0000000..b065c44 --- /dev/null +++ b/internal/task/bind_function.go @@ -0,0 +1,98 @@ +/* +* @desc:定时任务配置 +* @company:Sagoo Co.,Ltd +* @Author: microrain +* @Date: 2021/7/16 15:45 + */ + +package task + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" + "strings" + + "github.com/gogf/gf/v2/frame/g" +) + +func init() { + + ctx := context.TODO() + + sysConfigInfo, err := service.ConfigData().GetConfigByKey(ctx, consts.IsAutoRunJob) + if err != nil { + return + } + if sysConfigInfo != nil { + if strings.EqualFold(sysConfigInfo.ConfigValue, "1") { + task1 := &jobTask.TimeTask{ + FuncName: "test1", + Run: Test1, + } + task2 := &jobTask.TimeTask{ + FuncName: "test2", + Run: Test2, + } + clearOperationLogByDaysTask := &jobTask.TimeTask{ + FuncName: "clearOperationLogByDays", + Run: ClearOperationLogByDays, + } + + clearNoticeLogByDaysTask := &jobTask.TimeTask{ + FuncName: "clearNoticeLogByDays", + Run: ClearNoticeLogByDays, + } + + clearAlarmLogByDaysTask := &jobTask.TimeTask{ + FuncName: "clearAlarmLogByDays", + Run: ClearAlarmLogByDays, + } + + getAccessURLTask := &jobTask.TimeTask{ + FuncName: "getAccessURL", + Run: GetAccessURL, + } + + dataSourceTask := &jobTask.TimeTask{ + FuncName: "dataSource", + Run: DataSource, + } + + dataTemplateTask := &jobTask.TimeTask{ + FuncName: "dataTemplate", + Run: DataTemplate, + } + + deviceLogClearTask := &jobTask.TimeTask{ + FuncName: "deviceLogClear", + Run: DeviceLogClear, + } + + jobTask.TimeTaskList.AddTask(task1).AddTask(task2). + AddTask(clearOperationLogByDaysTask). + AddTask(clearNoticeLogByDaysTask). + AddTask(clearAlarmLogByDaysTask). + AddTask(getAccessURLTask). + AddTask(dataSourceTask). + AddTask(dataTemplateTask). + AddTask(deviceLogClearTask) + + //自动执行已开启的任务 + var jobs []*model.SysJobOut + jobs, err = service.SysJob().GetJobs(ctx) + if err != nil { + g.Log().Error(ctx, err) + } + + //批量启动任务 + err = service.SysJob().JobStartMult(ctx, jobs) + if err != nil { + g.Log().Error(ctx, err.Error()) + } + } + } + +} diff --git a/internal/task/cleardata.go b/internal/task/cleardata.go new file mode 100644 index 0000000..01355ab --- /dev/null +++ b/internal/task/cleardata.go @@ -0,0 +1,51 @@ +package task + +import ( + "context" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" +) + +// ClearOperationLogByDays 清理超过指定天数的操作日志 +func ClearOperationLogByDays(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("clearOperationLogByDays") + if t == nil { + return + } + glog.Infof(ctx, "执行任务:清理超过%d天的操作日志", gconv.Int(t.Param[0])) + err := service.SysOperLog().ClearOperationLogByDays(ctx, gconv.Int(t.Param[0])) + if err != nil { + glog.Error(ctx, err) + } +} + +// ClearNoticeLogByDays 清理超过指定天数的通知服务日志 +func ClearNoticeLogByDays(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("clearNoticeLogByDays") + if t == nil { + return + } + glog.Infof(ctx, "执行任务:清理超过%d天的通知服务发送日志", gconv.Int(t.Param[0])) + err := service.NoticeLog().ClearLogByDays(ctx, gconv.Int(t.Param[0])) + if err != nil { + glog.Error(ctx, err) + } +} + +// ClearAlarmLogByDays 清理超过指定天数的告警日志 +func ClearAlarmLogByDays(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("clearAlarmLogByDays") + if t == nil { + return + } + glog.Infof(ctx, "执行任务:清理超过%d天的告警日志", gconv.Int(t.Param[0])) + err := service.AlarmLog().ClearLogByDays(ctx, gconv.Int(t.Param[0])) + if err != nil { + glog.Error(ctx, err) + } +} diff --git a/internal/task/data_source.go b/internal/task/data_source.go new file mode 100644 index 0000000..b0730f9 --- /dev/null +++ b/internal/task/data_source.go @@ -0,0 +1,25 @@ +package task + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" + + "github.com/gogf/gf/v2/frame/g" +) + +// 数据源获取数据 +func DataSource(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("dataSource") + if t == nil { + return + } + + id := service.SysJob().Value(ctx) + + err := service.DataSource().UpdateData(ctx, id) + if err != nil { + g.Log().Error(ctx, err) + } +} diff --git a/internal/task/data_template.go b/internal/task/data_template.go new file mode 100644 index 0000000..89d7ecb --- /dev/null +++ b/internal/task/data_template.go @@ -0,0 +1,25 @@ +package task + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" + + "github.com/gogf/gf/v2/frame/g" +) + +// 数据模型聚合数据 +func DataTemplate(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("dataTemplate") + if t == nil { + return + } + + id := service.SysJob().Value(ctx) + + err := service.DataTemplate().UpdateData(ctx, id) + if err != nil { + g.Log().Error(ctx, err) + } +} diff --git a/internal/task/demo.go b/internal/task/demo.go new file mode 100644 index 0000000..ba39343 --- /dev/null +++ b/internal/task/demo.go @@ -0,0 +1,33 @@ +/* +* @desc:测试定时任务 +* @company:Sagoo Co.,Ltd +* @Author: microrain +* @Date: 2021/7/16 15:52 + */ + +package task + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" +) + +func Test1(ctx context.Context) { + g.Log().Debug(ctx, "无参测试", gtime.Datetime()) +} + +func Test2(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("test2") + if t == nil { + return + } + for _, v := range t.Param { + g.Log().Debugf(ctx, "参数:%s; ", v, gtime.Datetime()) + + } + fmt.Println() +} diff --git a/internal/task/deviceLog_clear.go b/internal/task/deviceLog_clear.go new file mode 100644 index 0000000..df8317c --- /dev/null +++ b/internal/task/deviceLog_clear.go @@ -0,0 +1,22 @@ +package task + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/utility/jobTask" + + "github.com/gogf/gf/v2/frame/g" +) + +// 设备日志清理 +func DeviceLogClear(ctx context.Context) { + //获取参数 + t := jobTask.TimeTaskList.GetByName("deviceLogClear") + if t == nil { + return + } + + if err := service.TdLogTable().Clear(ctx); err != nil { + g.Log().Error(ctx, err) + } +} diff --git a/internal/webscoket/call.go b/internal/webscoket/call.go new file mode 100644 index 0000000..efe2e2d --- /dev/null +++ b/internal/webscoket/call.go @@ -0,0 +1,88 @@ +package webscoket + +import ( + "errors" + "fmt" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/text/gstr" + "github.com/sagoo-cloud/sagooiot/internal/webscoket/common" + "github.com/sagoo-cloud/sagooiot/internal/webscoket/sys" +) + +var ( + ctx = gctx.New() +) + +var logic = map[string]map[string]func(ctx *common.WorkContext) (g.Map, error){ + "sys": { + "ping": sys.Ping, + "go": sys.Go, + "sync": sys.Sync, + "point": sys.Point, + }, +} + +func Call(unique interface{}, data *gjson.Json) g.Map { + cmd := data.Get("cmd", "").String() + context := &common.WorkContext{ + Data: common.Medium{ + Cmd: cmd, + Unique: unique, + Original: data, + }, + } + var callBack g.Map + if gstr.Contains(cmd, ".") { + command := gstr.Explode(".", cmd) + back := g.Map{} + for _, cmd := range command[1:] { + call, err := callFunc(command[0], cmd, context) + if err != nil { + g.Log().Debug(ctx, command[0]+"."+cmd+" error:"+err.Error()) + back[command[0]+"."+cmd] = g.Map{ + "error": err.Error(), + } + } else { + back[command[0]+"."+cmd] = call + } + } + callBack = back + } else { + callBack = callAllFunc(cmd, context) + } + return callBack +} + +func callFunc(alias, method string, context *common.WorkContext) (data g.Map, err error) { + defer func() { + if e := recover(); e != nil { + err = errors.New(fmt.Sprintf(`%v`, e)) + runRecover(err) + } + return + }() + data, err = logic[alias][method](context) + return +} + +func callAllFunc(alias string, context *common.WorkContext) g.Map { + back := g.Map{} + for method := range logic[alias] { + call, err := callFunc(alias, method, context) + if err != nil { + g.Log().Debug(ctx, alias+"."+method+" error:"+err.Error()) + back[alias+"."+method] = g.Map{ + "error": err.Error(), + } + } else { + back[alias+"."+method] = call + } + } + return back +} + +func runRecover(err error) { + g.Log().Cat("logic").Error(ctx, err) +} diff --git a/internal/webscoket/common/webScoket.go b/internal/webscoket/common/webScoket.go new file mode 100644 index 0000000..b01602e --- /dev/null +++ b/internal/webscoket/common/webScoket.go @@ -0,0 +1,15 @@ +package common + +import ( + "github.com/gogf/gf/v2/encoding/gjson" +) + +// 公共struct +type WorkContext struct { + Data Medium +} +type Medium struct { + Cmd string + Unique interface{} + Original *gjson.Json +} diff --git a/internal/webscoket/model/websocket.go b/internal/webscoket/model/websocket.go new file mode 100644 index 0000000..1c19d1b --- /dev/null +++ b/internal/webscoket/model/websocket.go @@ -0,0 +1,7 @@ +package model + +type DataMsg struct { + Type string `json:"type" v:"required"` + Data interface{} `json:"data" v:"required"` + From string `json:"name" v:""` +} diff --git a/internal/webscoket/privater/handler.go b/internal/webscoket/privater/handler.go new file mode 100644 index 0000000..92c5161 --- /dev/null +++ b/internal/webscoket/privater/handler.go @@ -0,0 +1,136 @@ +package privater + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gmlock" + "github.com/gogf/gf/v2/os/grpool" + "github.com/gogf/gf/v2/os/gtimer" + "github.com/gorilla/websocket" + "github.com/sagoo-cloud/sagooiot/internal/webscoket" + "time" +) + +type Connection struct { + Socket *ghttp.WebSocket + closed bool + Unique string + writeCh chan []byte + Ctx context.Context + CtxClose func() + Heartbeat *gtimer.Entry +} + +var ( + WebsocketManager *gmap.Map + workPool *grpool.Pool + ctx = gctx.New() +) + +func init() { + //连接合集-线程安全 + WebsocketManager = gmap.New(true) + workPool = grpool.New(100) +} + +// 关闭连接 +func (c *Connection) Close() { + if gmlock.TryLock(c.Unique) { + if false == c.closed { + _ = c.Socket.Close() + c.closed = true + //必须优先关闭读写协程 + c.CtxClose() + close(c.writeCh) + c.Heartbeat.Close() + WebsocketManager.Remove(c.Unique) + g.Log().Debug(ctx, "remove:"+c.Unique) + } + gmlock.Unlock(c.Unique) + } +} + +// 连接读-同步响应 +func (c *Connection) read() { + for { + select { + case <-c.Ctx.Done(): + goto ERR + default: + if c.closed { + goto ERR + } + _, msg, err := c.Socket.ReadMessage() + if err != nil { + goto ERR + } + data := gjson.New(msg) + if data.IsNil() { + goto ERR + } + cmd := data.Get("cmd", "").String() + if len(cmd) == 0 { + goto ERR + } + //client有消息上来重置心跳 + c.Heartbeat.Reset() + err = workPool.AddWithRecover(ctx, func(ctx context.Context) { + callBack := webscoket.Call(c.Unique, data) + if len(callBack) > 0 { + c.WriteMsg(c.Pack(callBack)) + } + }, runRecover) + if err != nil { + goto ERR + } + } + } +ERR: + g.Log().Debug(ctx, c.Unique+":ReadSync quit") + c.Close() + return +} + +func (c *Connection) write() { + for { + select { + case <-c.Ctx.Done(): + goto ERR + case msg := <-c.writeCh: + err := c.Socket.WriteMessage(websocket.TextMessage, msg) + if err != nil { + goto ERR + } + } + } +ERR: + c.Close() + g.Log().Debug(ctx, c.Unique+":Write quit") + return +} +func (c *Connection) Pack(data g.Map) []byte { + data["pack_timestamp"] = time.Now().Unix() + encode, err := gjson.Encode(data) + if err != nil { + fmt.Println(err) + return []byte("server error") + } + return encode +} +func (c *Connection) WriteMsg(msg []byte) { + //未关闭连接则发送消息,已关闭连接则后台服务关闭此连接 + if !c.closed { + c.writeCh <- msg + } else { + c.Close() + } +} + +func runRecover(ctx context.Context, err error) { + g.Log().Cat("websocket").Error(ctx, err) +} diff --git a/internal/webscoket/sys/sys.go b/internal/webscoket/sys/sys.go new file mode 100644 index 0000000..d548e16 --- /dev/null +++ b/internal/webscoket/sys/sys.go @@ -0,0 +1,29 @@ +package sys + +import ( + "errors" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/webscoket/common" +) + +func Ping(ctx *common.WorkContext) (g.Map, error) { + return g.Map{ + "ping": "pong", + }, nil +} + +func Go(ctx *common.WorkContext) (g.Map, error) { + return g.Map{ + "go": "run", + }, nil +} + +func Sync(ctx *common.WorkContext) (g.Map, error) { + return nil, errors.New("sync error") +} + +func Point(ctx *common.WorkContext) (g.Map, error) { + panic("point panic") + //return nil, errors.New("point error") + +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..553b4fc --- /dev/null +++ b/main.go @@ -0,0 +1,25 @@ +package main + +import ( + _ "github.com/gogf/gf/contrib/drivers/mysql/v2" + "github.com/sagoo-cloud/sagooiot/utility/version" + + _ "github.com/sagoo-cloud/sagooiot/internal/packed" + + _ "github.com/sagoo-cloud/sagooiot/internal/logic" + _ "github.com/sagoo-cloud/sagooiot/internal/task" + + "github.com/gogf/gf/v2/os/gctx" + "github.com/sagoo-cloud/sagooiot/internal/cmd" +) + +var ( + BuildVersion = "0.0" + BuildTime = "" + CommitID = "" +) + +func main() { + version.ShowLogo(BuildVersion, BuildTime, CommitID) + cmd.Main.Run(gctx.New()) +} diff --git a/manifest/config/config.example.yaml b/manifest/config/config.example.yaml new file mode 100644 index 0000000..af3497d --- /dev/null +++ b/manifest/config/config.example.yaml @@ -0,0 +1,102 @@ +# 配置文件的键名命名方式统一使用小驼峰。 + +# HTTP Server. +server: + address: ":8199" + serverRoot: "resource/public" + dumpRouterMap: false + routeOverWrite: true + openapiPath: "/api.json" + swaggerPath: "/swagger" + NameToUriType: 3 + maxHeaderBytes: "20KB" + clientMaxBodySize: "50MB" + # Logging配置 + logPath: "resource/log/server" # 日志文件存储目录路径,建议使用绝对路径。默认为空,表示关闭 + logStdout: true # 日志是否输出到终端。默认为true + errorStack: true # 当Server捕获到异常时是否记录堆栈信息到日志中。默认为true + errorLogEnabled: true # 是否记录异常日志信息到日志中。默认为true + errorLogPattern: "error-{Ymd}.log" # 异常错误日志文件格式。默认为"error-{Ymd}.log" + accessLogEnabled: true # 是否记录访问日志。默认为false + accessLogPattern: "access-{Ymd}.log" # 访问日志文件格式。默认为"access-{Ymd}.log" + +# 数据库连接配置 +database: + logger: + path: "logs/sql" + level: "all" + stdout: true + ctxKeys: [ "RequestId" ] + + default: + link: "mysql:zhgy_sagoo_cn:aasdasdaHDc6i@tcp(101.200.200.249:3306)/zhgy_sagoo_cn?loc=Local&parseTime=true" + debug: false #开启调试模式 + charset: "utf8mb4" #数据库编码(如: utf8/gbk/gb2312),一般设置为utf8 + dryRun: false #ORM空跑(只读不写) + maxIdle: 10 #连接池最大闲置的连接数 + maxOpen: 10 #连接池最大打开的连接数 + maxLifetime: 30 #(单位秒)连接对象可重复使用的时间长度 + +# dataCenter: +# link: "mysql:zhgy_sagoo_cn:aRwerwqrewrc6i@tcp(101.200.200.249:3306)/zhgy_sagoo_cn" +# debug: true +# charset: "utf8mb4" #数据库编码 +# dryRun: false #ORM空跑(只读不写) +# maxIdle: 10 #连接池最大闲置的连接数 +# maxOpen: 10 #连接池最大打开的连接数 +# maxLifetime: 30 #(单位秒)连接对象可重复使用的时间长度 + +# TDengine配置 +tdengine: + type: "taosRestful" #http连接方式,端口是6041 + dsn: "zhgy_iot:sdfsdfsdf@http(101.200.200.249:6041)/" + dbName: "sagoo_iot" + +# 采用原生的时候,需要将sagoo-admin/internal/logic/tdengine下的td_engine.go文件里import中的原生驱动打开 +# type: "taosSql" #原生连接方式,端口是6030 +# dsn: "zhgy_iot:fsfadfas@tcp(101.200.200.249:6030)/" + +# 文件上传设置 +upload: + path: "upload" + +logger: + path: "resource/log/run" + file: "{Y-m-d}.log" + level: "all" + stdout: true + ctxKeys: [ "RequestId" ] + +#GFToken +gfToken: + timeOut: 10800 #token超时时间(秒) + maxRefresh: 5400 #token自动刷新时间(秒) + multiLogin: true #是否允许一个账号多人同时登录 + encryptKey: "49c54195e750b09e74a8429b17896321" #加密key (32位) + excludePaths: #排除不做登录验证的路由地址 + - "/api/v1/login" + +# Redis 配置示例 +redis: + # 单实例配置 + default: + address: r-2zesfsdfsdfdasda.redis.rds.aliyuncs.com:6379 + db: 1 + pass: FDassfsdfsdut + idleTimeout: 600 + maxActive: 100 + +# 这个mqtt客户端主要是服务端内部处理消息使用的通道 +mqtt: + addr: 101.200.200.249:1883 + # 最好带上服务名称,变成唯一id + clientId: example1233 + auth: + userName: fadaad + userPassWorld: 123456 + +system: + pluginsPath: "./plugins/built" + cache: + prefix: "SagooZhgy_" #缓存前缀 + model: "redis" #存储引擎 (memory使用内存|redis使用redis) \ No newline at end of file diff --git a/network/codebin/bytes.go b/network/codebin/bytes.go new file mode 100644 index 0000000..69f74fb --- /dev/null +++ b/network/codebin/bytes.go @@ -0,0 +1,300 @@ +package codebin + +import "math" + +//ParseUint64 解析 +func ParseUint64(b []byte) uint64 { + return (uint64(b[0]) << 56) | + (uint64(b[1]) << 48) | + (uint64(b[2]) << 40) | + (uint64(b[3]) << 32) | + (uint64(b[4]) << 24) | + (uint64(b[5]) << 16) | + (uint64(b[6]) << 8) | + uint64(b[7]) +} + +//ParseUint64LittleEndian 解析 +func ParseUint64LittleEndian(b []byte) uint64 { + return (uint64(b[7]) << 56) | + (uint64(b[6]) << 48) | + (uint64(b[5]) << 40) | + (uint64(b[4]) << 32) | + (uint64(b[3]) << 24) | + (uint64(b[2]) << 16) | + (uint64(b[1]) << 8) | + uint64(b[0]) +} + +//ParseUint32 解析 +func ParseUint32(buf []byte) uint32 { + return uint32(buf[0])<<24 + + uint32(buf[1])<<16 + + uint32(buf[2])<<8 + + uint32(buf[3]) +} + +//ParseUint32LittleEndian 解析 +func ParseUint32LittleEndian(buf []byte) uint32 { + return uint32(buf[3])<<24 + + uint32(buf[2])<<16 + + uint32(buf[1])<<8 + + uint32(buf[0]) +} + +//ParseUint16 解析 +func ParseUint16(buf []byte) uint16 { + return uint16(buf[0])<<8 + uint16(buf[1]) +} + +//ParseUint16LittleEndian 解析 +func ParseUint16LittleEndian(buf []byte) uint16 { + return uint16(buf[1])<<8 + uint16(buf[0]) +} + +//ParseFloat32 解析 +func ParseFloat32(buf []byte) float32 { + val := ParseUint32(buf) + return math.Float32frombits(val) +} + +//ParseFloat32LittleEndian 解析 +func ParseFloat32LittleEndian(buf []byte) float32 { + val := ParseUint32LittleEndian(buf) + return math.Float32frombits(val) +} + +//ParseFloat64 解析 +func ParseFloat64(buf []byte) float64 { + val := ParseUint64(buf) + return math.Float64frombits(val) +} + +//ParseFloat64LittleEndian 解析 +func ParseFloat64LittleEndian(buf []byte) float64 { + val := ParseUint64LittleEndian(buf) + return math.Float64frombits(val) +} + +//Uint32ToBytes 编码 +func Uint32ToBytes(value uint32) []byte { + buf := make([]byte, 4) + buf[0] = byte(value >> 24) + buf[1] = byte(value >> 16) + buf[2] = byte(value >> 8) + buf[3] = byte(value) + return buf +} + +//Uint32ToBytesLittleEndian 编码 +func Uint32ToBytesLittleEndian(value uint32) []byte { + buf := make([]byte, 4) + buf[3] = byte(value >> 24) + buf[2] = byte(value >> 16) + buf[1] = byte(value >> 8) + buf[0] = byte(value) + return buf +} + +//Uint16ToBytes 编码 +func Uint16ToBytes(value uint16) []byte { + buf := make([]byte, 2) + buf[0] = byte(value >> 8) + buf[1] = byte(value) + return buf +} + +//Uint16ToBytesLittleEndian 编码 +func Uint16ToBytesLittleEndian(value uint16) []byte { + buf := make([]byte, 2) + buf[1] = byte(value >> 8) + buf[0] = byte(value) + return buf +} + +//WriteUint64 编码 +func WriteUint64(buf []byte, value uint64) { + buf[0] = byte(value >> 56) + buf[1] = byte(value >> 48) + buf[2] = byte(value >> 40) + buf[3] = byte(value >> 32) + buf[4] = byte(value >> 24) + buf[5] = byte(value >> 16) + buf[6] = byte(value >> 8) + buf[7] = byte(value) +} + +//WriteUint64LittleEndian 编码 +func WriteUint64LittleEndian(buf []byte, value uint64) { + buf[7] = byte(value >> 56) + buf[6] = byte(value >> 48) + buf[5] = byte(value >> 40) + buf[4] = byte(value >> 32) + buf[3] = byte(value >> 24) + buf[2] = byte(value >> 16) + buf[1] = byte(value >> 8) + buf[0] = byte(value) +} + +//WriteUint32 编码 +func WriteUint32(buf []byte, value uint32) { + buf[0] = byte(value >> 24) + buf[1] = byte(value >> 16) + buf[2] = byte(value >> 8) + buf[3] = byte(value) +} + +//WriteUint32LittleEndian 编码 +func WriteUint32LittleEndian(buf []byte, value uint32) { + buf[3] = byte(value >> 24) + buf[2] = byte(value >> 16) + buf[1] = byte(value >> 8) + buf[0] = byte(value) +} + +//WriteUint24 编码 +func WriteUint24(buf []byte, value uint32) { + buf[0] = byte(value >> 16) + buf[1] = byte(value >> 8) + buf[2] = byte(value) +} + +//WriteUint24LittleEndian 编码 +func WriteUint24LittleEndian(buf []byte, value uint32) { + buf[2] = byte(value >> 16) + buf[1] = byte(value >> 8) + buf[0] = byte(value) +} + +//WriteUint16 编码 +func WriteUint16(buf []byte, value uint16) { + buf[0] = byte(value >> 8) + buf[1] = byte(value) +} + +//WriteUint16LittleEndian 编码 +func WriteUint16LittleEndian(buf []byte, value uint16) { + buf[1] = byte(value >> 8) + buf[0] = byte(value) +} + +//WriteFloat32 编码 +func WriteFloat32(buf []byte, value float32) { + val := math.Float32bits(value) + WriteUint32(buf, val) +} + +//WriteFloat32LittleEndian 编码 +func WriteFloat32LittleEndian(buf []byte, value float32) { + val := math.Float32bits(value) + WriteUint32LittleEndian(buf, val) +} + +//WriteFloat64 编码 +func WriteFloat64(buf []byte, value float64) { + val := math.Float64bits(value) + WriteUint64(buf, val) +} + +//WriteFloat64LittleEndian 编码 +func WriteFloat64LittleEndian(buf []byte, value float64) { + val := math.Float64bits(value) + WriteUint64LittleEndian(buf, val) +} + +//BoolToAscii 编码 +func BoolToAscii(buf []byte) []byte { + length := len(buf) + ret := make([]byte, length) + for i := 0; i < length; i++ { + if buf[i] == 0 { + ret[i] = '0' + } else { + ret[i] = '1' + } + } + return ret +} + +//AsciiToBool 编码 +func AsciiToBool(buf []byte) []byte { + length := len(buf) + ret := make([]byte, length) + for i := 0; i < length; i++ { + if buf[i] == '0' { + ret[i] = 0 + } else { + ret[i] = 1 + } + } + return ret +} + +//Dup 复制 +func Dup(buf []byte) []byte { + b := make([]byte, len(buf)) + copy(b, buf) + return b +} + +//BoolToByte 编码 +func BoolToByte(buf []bool) []byte { + r := make([]byte, len(buf)) + for i, v := range buf { + if v { + r[i] = 1 + } + } + return r +} + +//ByteToBool 编码 +func ByteToBool(buf []byte) []bool { + r := make([]bool, len(buf)) + for i, v := range buf { + if v > 0 { + r[i] = true + } + } + return r +} + +//ShrinkBool 压缩布尔类型 +func ShrinkBool(buf []byte) []byte { + length := len(buf) + //length = length % 8 == 0 ? length / 8 : length / 8 + 1; + ln := length >> 3 // length/8 + if length&0x07 > 0 { // length%8 + ln++ + } + + b := make([]byte, ln) + + for i := 0; i < length; i++ { + if buf[i] > 0 { + //b[i/8] += 1 << (i % 8) + b[i>>3] += 1 << (i & 0x07) + } + } + + return b +} + +//ExpandBool 展开布尔类型 +func ExpandBool(buf []byte, count int) []byte { + length := len(buf) + ln := length << 3 // length * 8 + if count > ln { + count = ln + } + b := make([]byte, count) + + for i := 0; i < length; i++ { + //b[i] = buf[i/8] & (1 << (i % 8)) + if buf[i>>3]&(1<<(i&0x07)) > 0 { + b[i] = 1 + } + } + + return b +} diff --git a/network/codebin/check.go b/network/codebin/check.go new file mode 100644 index 0000000..038d7e6 --- /dev/null +++ b/network/codebin/check.go @@ -0,0 +1,21 @@ +package codebin + +//Sum 和 +func Sum(buf []byte) byte { + var sum byte = 0 + l := len(buf) + for i := 0; i < l; i++ { + sum += buf[i] + } + return sum +} + +//Xor 异或 +func Xor(buf []byte) byte { + var xor = buf[0] + l := len(buf) + for i := 1; i < l; i++ { + xor ^= buf[i] + } + return xor +} diff --git a/network/codebin/hex.go b/network/codebin/hex.go new file mode 100644 index 0000000..d0e8b2b --- /dev/null +++ b/network/codebin/hex.go @@ -0,0 +1,55 @@ +package codebin + +import "encoding/hex" + +var hexNumbers = []byte("0123456789ABCDEF") + +//ByteToHex 编码 +func ByteToHex(value byte) []byte { + buf := make([]byte, 2) + buf[0] = hexNumbers[value>>4] + buf[1] = hexNumbers[value&0x0F] + return buf +} + +//WriteByteHex 编码 +func WriteByteHex(buf []byte, value uint8) { + buf[0] = hexNumbers[value>>4] + buf[1] = hexNumbers[value&0x0F] +} + +//WriteUint8Hex 编码 +func WriteUint8Hex(buf []byte, value uint8) { + buf[0] = hexNumbers[value>>4] + buf[1] = hexNumbers[value&0x0F] +} + +//WriteUint16Hex 编码 +func WriteUint16Hex(buf []byte, value uint16) { + h, l := value>>8, value&0xF + buf[0] = hexNumbers[h>>4] + buf[1] = hexNumbers[h&0x0F] + buf[3] = hexNumbers[l>>4] + buf[4] = hexNumbers[l&0x0F] + +} + +//ToHex 编码 +func ToHex(values []byte) []byte { + length := len(values) + buf := make([]byte, length<<1) //length * 2 + for i := 0; i < length; i++ { + value := values[i] + j := i << 1 //i * 2 + buf[j] = hexNumbers[value>>4] + buf[j+1] = hexNumbers[value&0x0F] + } + return buf +} + +//FromHex 解码 +func FromHex(values []byte) []byte { + buf := make([]byte, len(values)>>1) //length / 2 + _, _ = hex.Decode(buf, values) + return buf +} diff --git a/network/core/common.go b/network/core/common.go new file mode 100644 index 0000000..9b00b66 --- /dev/null +++ b/network/core/common.go @@ -0,0 +1,17 @@ +package core + +import ( + "context" + "encoding/json" + "github.com/gogf/gf/v2/frame/g" +) + +func StrToPointInterfaceWithError(str string, a interface{}) error { + return json.Unmarshal([]byte(str), a) +} + +func StrToPointInterfaceWithoutError(ctx context.Context, str string, a interface{}) { + if err := json.Unmarshal([]byte(str), a); err != nil { + g.Log().Debugf(ctx, "StrToPointInterfaceWithoutError %s", err.Error()) + } +} diff --git a/network/core/connect.go b/network/core/connect.go new file mode 100644 index 0000000..9a8bc95 --- /dev/null +++ b/network/core/connect.go @@ -0,0 +1 @@ +package core diff --git a/network/core/device-manager.go b/network/core/device-manager.go new file mode 100644 index 0000000..af1c0f5 --- /dev/null +++ b/network/core/device-manager.go @@ -0,0 +1,72 @@ +package core + +import ( + "context" + logicModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "sync" + + "github.com/gogf/gf/v2/frame/g" +) + +var allDevices sync.Map + +func GetDevice(id uint64) *Device { + d, ok := allDevices.Load(id) + if ok { + return d.(*Device) + } + return nil +} + +func RemoveDevice(id uint64) error { + d, ok := allDevices.LoadAndDelete(id) + if ok { + dev := d.(*Device) + return dev.Stop() + } + return nil //error +} + +func LoadDevices(ctx context.Context) error { + listDevice, err := service.DevDevice().List(ctx, &logicModel.ListDeviceInput{}) + if err != nil { + return err + } + if len(listDevice) == 0 { + return nil + } + devices := make([]*model.Device, len(listDevice)) + for index, node := range listDevice { + d := MapperDevice(*node) + devices[index] = &d + } + for index := range devices { + if devices[index].Disabled { + continue + } + dev, err := NewDevice(ctx, devices[index]) + if err != nil { + g.Log().Error(ctx, err) + return nil + } + allDevices.Store(devices[index].Id, dev) + } + return nil +} + +func LoadDevice(ctx context.Context, id uint) (*Device, error) { + deviceInfo, err := service.DevDevice().Detail(ctx, id) + if err != nil { + return nil, err + } + mDeviceInfo := MapperDevice(*deviceInfo) + dev, err := NewDevice(ctx, &mDeviceInfo) + if err != nil { + return dev, err + } + allDevices.Store(id, dev) + err = dev.Start(ctx) + return dev, nil +} diff --git a/network/core/device.go b/network/core/device.go new file mode 100644 index 0000000..b48ca3b --- /dev/null +++ b/network/core/device.go @@ -0,0 +1,117 @@ +package core + +import ( + "context" + "errors" + "github.com/sagoo-cloud/sagooiot/network/events" + "github.com/sagoo-cloud/sagooiot/network/model" +) + +// Device 设备 +type Device struct { + model.Device + events.EventEmitter + + product *model.Product + + Context map[string]interface{} + + pollers []*Poller + + //命令索引 + commandIndex map[string]*model.Command + + running bool + tunnel *Tunnel +} + +func NewDevice(ctx context.Context, m *model.Device) (*Device, error) { + dev := &Device{ + Device: *m, + Context: make(map[string]interface{}), + commandIndex: make(map[string]*model.Command, 0), + pollers: make([]*Poller, 0), + } + + //加载产品 + var err error + dev.product, err = LoadProduct(ctx, dev.ProductId) + if err != nil { + return nil, err + } + + //索引命令 + for _, cmd := range dev.product.Commands { + dev.commandIndex[cmd.Name] = cmd + } + + //初始化 + for _, v := range dev.product.Pollers { + dev.pollers = append(dev.pollers, &Poller{Poller: *v, Device: dev}) + } + + return dev, nil +} + +func (dev *Device) BindTunnel(tunnel *Tunnel) error { + if tunnel == nil { + return errors.New("通道未加载") + } + dev.tunnel = tunnel + return nil +} + +func (dev *Device) onData(data map[string]interface{}) { + + //向上广播 + dev.Emit("data", data) +} + +func (dev *Device) Start(ctx context.Context) error { + tunnel := GetTunnel(int(dev.TunnelId)) + if tunnel == nil { + return errors.New("找不到链接") + } + err := dev.BindTunnel(tunnel) + if err != nil { + return err + } + for _, poller := range dev.pollers { + err := poller.Start(ctx) + if err != nil { + return err + } + } + + dev.running = true + + return nil +} + +func (dev *Device) Stop() error { + dev.running = false + + for _, poller := range dev.pollers { + poller.Stop() + } + return nil +} + +func (dev *Device) Running() bool { + return dev.running +} + +func (dev *Device) read(size int) error { + //todo 等待实现 + return nil +} + +func (dev *Device) Refresh(ctx context.Context) error { + if !dev.running { + return errors.New("设备未运行") + } + for _, poller := range dev.pollers { + poller.Execute(ctx) + } + return nil +} diff --git a/network/core/mapper.go b/network/core/mapper.go new file mode 100644 index 0000000..062d8d9 --- /dev/null +++ b/network/core/mapper.go @@ -0,0 +1,90 @@ +package core + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + logicModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/network/model" + "strconv" +) + +// todo 需要处理下心跳和注册包,需要考虑到客户端可能不支持心跳或者注册包 +func MapperServer(ctx context.Context, res logicModel.NetworkServerOut) model.Server { + s := model.Server{ + Id: res.Id, + Name: res.Name, + Type: res.Types, + Addr: res.Addr, + Register: model.RegisterPacket{}, + Heartbeat: model.HeartBeatPacket{}, + Protocol: model.Protocol{}, + //TODO 这里暂时不写device,需要等待后续的device插入数据,考虑是不是启动的时候带入 + //Devices: res.Devices, + Disabled: true, + Created: res.CreatedAt.Time, + } + //TODO 等待model和前端修改补充下mqtt的options,主要是额外的一些配置 + if res.Status == consts.ServerStatusOnline { + s.Disabled = false + } + StrToPointInterfaceWithoutError(ctx, res.Register, &s.Register) + StrToPointInterfaceWithoutError(ctx, res.Heartbeat, &s.Heartbeat) + StrToPointInterfaceWithoutError(ctx, res.Protocol, &s.Protocol) + return s +} + +func MapperDevice(res logicModel.DeviceOutput) model.Device { + return model.Device{ + Id: uint64(res.Id), + TunnelId: uint64(res.TunnelId), + ProductId: strconv.Itoa(int(res.ProductId)), + Name: res.Name, + //todo 这里的station等待后面处理 + Station: res.Status, + Disabled: false, + Created: res.CreatedAt.Time, + } +} + +func mapperProduct(res logicModel.DetailProductOutput) model.Product { + return model.Product{ + Id: strconv.Itoa(int(res.Id)), + Name: res.Name, + Manufacturer: res.CategoryName, + //Version: res., + Protocol: model.Protocol{ + Name: res.MessageProtocol, + //TODO 消息的一些其他的配置 + Options: nil, + }, + Tags: nil, + Pollers: nil, + Commands: nil, + Created: res.CreatedAt.Time, + } +} + +func mapperTunnel(ctx context.Context, res logicModel.NetworkTunnelOut) model.Tunnel { + t := model.Tunnel{ + Id: uint64(res.Id), + ServerId: res.ServerId, + Name: res.Name, + //SN: res.SN, + Type: res.Types, + Addr: res.Addr, + Remote: res.Remote, + Retry: model.Retry{}, + Heartbeat: model.HeartBeatPacket{}, + Serial: model.SerialOptions{}, + Protocol: model.Protocol{}, + Disabled: res.Status == 0, + Last: res.Last.Time, + Created: res.CreatedAt.Time, + } + + StrToPointInterfaceWithoutError(ctx, res.Retry, &t.Retry) + StrToPointInterfaceWithoutError(ctx, res.Heartbeat, &t.Heartbeat) + StrToPointInterfaceWithoutError(ctx, res.Serial, &t.Serial) + StrToPointInterfaceWithoutError(ctx, res.Protoccol, &t.Protocol) + return t +} diff --git a/network/core/mqtt-databus.go b/network/core/mqtt-databus.go new file mode 100644 index 0000000..4c365e6 --- /dev/null +++ b/network/core/mqtt-databus.go @@ -0,0 +1,70 @@ +package core + +import ( + "context" + "encoding/json" + MQTT "github.com/eclipse/paho.mqtt.golang" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + networkModel "github.com/sagoo-cloud/sagooiot/network/model" + "strings" +) + +func onlineHandler(ctx context.Context, client MQTT.Client, message MQTT.Message) { + msg := networkModel.DeviceOnlineMessage{} + if err := json.Unmarshal(message.Payload(), &msg); err != nil { + g.Log().Errorf(ctx, "onlineHandler error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } + if err := service.TdLogTable().Insert(ctx, &model.TdLogAddInput{ + Ts: gtime.Now(), + Device: msg.DeviceKey, + Type: consts.GetTopicType(consts.DataBusOnline), + Content: string(message.Payload()), + }); err != nil { + g.Log().Errorf(ctx, "insert deviceLog failed, err: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } + if err := service.DevDevice().Online(ctx, msg.DeviceKey); err != nil { + g.Log().Errorf(ctx, "onlineHandler set device online error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } +} + +func offlineHandler(ctx context.Context, client MQTT.Client, message MQTT.Message) { + msg := networkModel.DeviceOfflineMessage{} + if err := json.Unmarshal(message.Payload(), &msg); err != nil { + g.Log().Errorf(ctx, "offlineHandler error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } + if err := service.TdLogTable().Insert(ctx, &model.TdLogAddInput{ + Ts: gtime.Now(), + Device: msg.DeviceKey, + Type: consts.GetTopicType(consts.DataBusOffline), + Content: string(message.Payload()), + }); err != nil { + g.Log().Errorf(ctx, "insert deviceLog failed, err: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } + if err := service.DevDevice().Offline(ctx, msg.DeviceKey); err != nil { + g.Log().Errorf(ctx, "onlineHandler set device online error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + } +} + +func reportPropertiesHandler(ctx context.Context, client MQTT.Client, message MQTT.Message) { + var reportMessage networkModel.ReportPropertyMessage + if err := json.Unmarshal(message.Payload(), &reportMessage); err != nil { + g.Log().Errorf(ctx, "unmarshal error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + return + } + if insertErr := service.TSLTable().Insert(ctx, reportMessage.DeviceKey, reportMessage.Properties); insertErr != nil { + g.Log().Errorf(ctx, "insert error: %w, topic:%s, message:%s, message ignored", insertErr, message.Topic(), string(message.Payload())) + return + } + topicNodes := strings.Split(message.Topic(), "/") + if len(topicNodes) < 3 { + return + } + if alarmCheckErr := service.AlarmRule().Check(ctx, topicNodes[2], reportMessage.DeviceKey, reportMessage.Properties); alarmCheckErr != nil { + g.Log().Errorf(ctx, "alarm check error: %w, topic:%s, message:%s, message ignored", alarmCheckErr, message.Topic(), string(message.Payload())) + return + } +} diff --git a/network/core/mqtt-device-property-report.go b/network/core/mqtt-device-property-report.go new file mode 100644 index 0000000..2c2a0dd --- /dev/null +++ b/network/core/mqtt-device-property-report.go @@ -0,0 +1,58 @@ +package core + +import ( + "encoding/json" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + networkModel "github.com/sagoo-cloud/sagooiot/network/model" + "time" +) + +type MessagePropertyReporter struct { + r messageRouter +} + +func (m MessagePropertyReporter) DeviceDataHandle() { + if err := service.TdLogTable().Insert(m.r.ctx, &model.TdLogAddInput{ + Ts: gtime.Now(), + Device: m.r.deviceDetail.Key, + Type: consts.GetTopicType(consts.DataBusPropertyReport), + Content: string(m.r.msg), + }); err != nil { + g.Log().Errorf(m.r.ctx, "insert deviceLog failed, err: %w, message:%s, message ignored", err, string(m.r.msg)) + } + + if m.r.data == nil || len(m.r.data) == 0 { + g.Log().Printf(m.r.ctx, "report data is empty, message:%s, message ignored\n", string(m.r.msg)) + return + } + + var reportFormatData = make(map[string]interface{}) + for k, v := range m.r.data { + for _, property := range m.r.deviceDetail.TSL.Properties { + if property.Key == k { + reportFormatData[k] = property.ValueType.ConvertValue(v) + break + } + } + } + nowTime := time.Now().Unix() + reportMessage := networkModel.ReportPropertyMessage{ + Common: networkModel.Common{ + DeviceKey: m.r.deviceDetail.Key, + MessageId: fmt.Sprintf("%s-%s-%d", m.r.deviceDetail.Product.Key, m.r.deviceDetail.Key, nowTime), + Timestamp: nowTime, + }, + Properties: reportFormatData, + } + reportFormatDataByte, _ := json.Marshal(reportMessage) + if propertyReportErr := mqtt.Publish(consts.GetDataBusWrapperTopic(m.r.deviceDetail.Product.Key, m.r.deviceDetail.Key, consts.DataBusPropertyReport), reportFormatDataByte); propertyReportErr != nil { + g.Log().Errorf(m.r.ctx, "publish data error: %w,message:%s, message ignored", propertyReportErr, string(m.r.msg)) + return + } +} diff --git a/network/core/mqtt-device-router.go b/network/core/mqtt-device-router.go new file mode 100644 index 0000000..2c63b8f --- /dev/null +++ b/network/core/mqtt-device-router.go @@ -0,0 +1,34 @@ +package core + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/model" + + "github.com/gogf/gf/v2/frame/g" +) + +type messageRouterHandler interface { + DeviceDataHandle() +} + +type messageRouter struct { + ctx context.Context + msg []byte + data map[string]interface{} + msgType string + deviceDetail *model.DeviceOutput +} + +func (m messageRouter) router() { + var h messageRouterHandler + switch m.msgType { + case consts.PropertyReport: + h = MessagePropertyReporter{m} + } + if h == nil { + g.Log().Errorf(m.ctx, "message type:%s not supported, message:%s, message ignored", m.msgType, string(m.msg)) + return + } + h.DeviceDataHandle() +} diff --git a/network/core/mqtt-device.go b/network/core/mqtt-device.go new file mode 100644 index 0000000..0c5526d --- /dev/null +++ b/network/core/mqtt-device.go @@ -0,0 +1,91 @@ +package core + +import ( + "context" + "encoding/json" + "fmt" + MQTT "github.com/eclipse/paho.mqtt.golang" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/extend" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + networkModel "github.com/sagoo-cloud/sagooiot/network/model" + "strings" + "time" +) + +var subMap = map[consts.Topic]func(context.Context, MQTT.Client, MQTT.Message){ + //device 处理的topic + consts.TopicDeviceData: deviceDataHandler, + + //dataBus 处理的topic + consts.CommonDataBusPrefix + consts.DataBusOnline: onlineHandler, + consts.CommonDataBusPrefix + consts.DataBusOffline: offlineHandler, + consts.CommonDataBusPrefix + consts.DataBusPropertyReport: reportPropertiesHandler, +} + +func StartSubscriber(ctx context.Context) error { + for topic, f := range subMap { + if err := mqtt.Subscribe(ctx, string(topic), f); err != nil { + return err + } + } + return nil +} + +func deviceDataHandler(ctx context.Context, client MQTT.Client, message MQTT.Message) { + topicInfo := strings.Split(message.Topic(), "/") + if len(topicInfo) != 3 { + g.Log().Error(ctx, fmt.Sprintf("topic:%s is illegal, message(%s) ignored", message.Topic(), string(message.Payload()))) + return + } + productKey, deviceKey := topicInfo[1], topicInfo[2] + productDetail, productDetailErr := service.DevProduct().Get(ctx, productKey) + if productDetailErr != nil || productDetail == nil { + g.Log().Errorf(ctx, "find product info error: %w, topic:%s, message:%s, message ignored", productDetailErr, message.Topic(), string(message.Payload())) + return + } + deviceDetail, err := service.DevDevice().Get(ctx, deviceKey) + if err != nil { + return + } + if deviceDetail == nil { + g.Log().Errorf(ctx, "fail to find device, topic:%s, message:%s, message ignored", message.Topic(), string(message.Payload())) + return + } + if deviceDetail != nil && deviceDetail.Status != consts.DeviceStatueOnline { + onlineMessage, _ := json.Marshal(networkModel.DeviceOnlineMessage{ + DeviceKey: deviceKey, + Timestamp: time.Now().Unix(), + }) + if propertyReportErr := mqtt.Publish(consts.GetDataBusWrapperTopic(productKey, deviceKey, consts.DataBusOnline), onlineMessage); propertyReportErr != nil { + g.Log().Errorf(ctx, "publish formate data error: %w, topic:%s, message:%s, message ignored", propertyReportErr, message.Topic(), string(message.Payload())) + return + } + } + messageProtocol := productDetail.MessageProtocol + res := string(message.Payload()) + if messageProtocol != "" { + if extend.GetProtocolPlugin() == nil { + return + } + res, err = extend.GetProtocolPlugin().GetProtocolUnpackData(messageProtocol, message.Payload()) + if err != nil { + g.Log().Errorf(ctx, "get plugin error: %w, topic:%s, message:%s, message ignored", err, message.Topic(), string(message.Payload())) + return + } + } + var reportData networkModel.DefaultMessageType + if reportDataErr := json.Unmarshal([]byte(res), &reportData); reportDataErr != nil { + g.Log().Errorf(ctx, "parse data error: %w, topic:%s, message:%s, message ignored", reportDataErr, message.Topic(), string(message.Payload())) + return + } + messageRouter{ + ctx: ctx, + data: reportData.Data, + msgType: reportData.DataType, + deviceDetail: deviceDetail, + msg: message.Payload(), + }.router() +} diff --git a/network/core/point.go b/network/core/point.go new file mode 100644 index 0000000..85c8e6c --- /dev/null +++ b/network/core/point.go @@ -0,0 +1,9 @@ +package core + +import ( + "github.com/sagoo-cloud/sagooiot/network/model" +) + +type Point struct { + model.Point +} diff --git a/network/core/poller.go b/network/core/poller.go new file mode 100644 index 0000000..b5e8e26 --- /dev/null +++ b/network/core/poller.go @@ -0,0 +1,55 @@ +package core + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/network/model" + "github.com/sagoo-cloud/sagooiot/network/pkg/cron" +) + +// Poller 采集器 +type Poller struct { + model.Poller + Device *Device + + reading bool + job *cron.Job +} + +// Start 启动 +func (p *Poller) Start(ctx context.Context) (err error) { + if p.job != nil { + p.job.Cancel() + //return errors.New("已经启动") + } + p.job, err = cron.Interval(p.Interval, func() { + p.Execute(ctx) + }) + return +} + +// Execute 执行 +func (p *Poller) Execute(ctx context.Context) { + if p.reading { + return + } + go p.read(ctx) +} + +func (p *Poller) read(ctx context.Context) { + p.reading = true + err := p.Device.read(p.Length) + p.reading = false + + if err != nil { + //log error + g.Log().Error(ctx, err) + } +} + +// Stop 结束 +func (p *Poller) Stop() { + if p.job != nil { + p.job.Cancel() + } +} diff --git a/network/core/product-manager.go b/network/core/product-manager.go new file mode 100644 index 0000000..5afa548 --- /dev/null +++ b/network/core/product-manager.go @@ -0,0 +1,34 @@ +package core + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "strconv" + "sync" +) + +var products sync.Map + +func LoadProduct(ctx context.Context, id string) (*model.Product, error) { + v, ok := products.Load(id) + if ok { + return v.(*model.Product), nil + } + + //加载产品 + var product model.Product + productId, err := strconv.Atoi(id) + if err != nil { + return nil, err + } + productDetail, err := service.DevProduct().Detail(ctx, uint(productId)) + if err != nil { + return nil, err + } + product = mapperProduct(*productDetail) + + products.Store(id, &product) + + return &product, nil +} diff --git a/network/core/server-common.go b/network/core/server-common.go new file mode 100644 index 0000000..bd3957f --- /dev/null +++ b/network/core/server-common.go @@ -0,0 +1,46 @@ +package core + +import ( + "context" + "encoding/json" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "time" + + "github.com/gogf/gf/v2/frame/g" +) + +func ServerOpenAction(serverId int) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionOpen, serverId), nil) +} + +func ServerCloseAction(serverId int) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionClose, serverId), nil) +} + +func ServerTunnelAction(ctx context.Context, serverId int, deviceKey string) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionTunnel, serverId), nil) + deviceDetail, _ := service.DevDevice().Get(ctx, deviceKey) + if deviceDetail == nil { + g.Log().Errorf(ctx, "deviceKey:%s not found,ignore", deviceKey) + return + } + _, err := LoadDevice(ctx, deviceDetail.Id) + if err != nil { + g.Log().Error(ctx, err) + } + if deviceDetail != nil && deviceDetail.Status != consts.DeviceStatueOnline { + onlineMessage, _ := json.Marshal(model.DeviceOnlineMessage{ + DeviceKey: deviceKey, + Timestamp: time.Now().Unix(), + }) + if dataBusOnlineErr := mqtt.Publish(consts.GetDataBusWrapperTopic(deviceDetail.Product.Key, deviceKey, consts.DataBusOnline), onlineMessage); dataBusOnlineErr != nil { + g.Log().Errorf(ctx, "publish data error: %w, topic:%s, message:%s, message ignored", dataBusOnlineErr, + consts.GetDataBusWrapperTopic(deviceDetail.Product.Key, deviceKey, consts.DataBusOnline), + string(onlineMessage)) + return + } + } +} diff --git a/network/core/server-manager.go b/network/core/server-manager.go new file mode 100644 index 0000000..c2a564f --- /dev/null +++ b/network/core/server-manager.go @@ -0,0 +1,103 @@ +package core + +import ( + "context" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + interModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "sync" +) + +var allServers sync.Map + +func startServer(ctx context.Context, server *model.Server) error { + svr, err := NewServer(server) + if err != nil { + return err + } + allServers.Store(server.Id, &Server{ + Server: *server, + Instance: svr, + }) + err = svr.Open(ctx) + if err != nil { + return err + } + + return nil +} + +// LoadServers 启动时候加载服务 +func LoadServers(ctx context.Context) error { + // 这里限制10000,后面需要注意这里的参数显示 + total, networkServerListRes, networkServerListResErr := service.NetworkServer().GetServerList(ctx, &interModel.GetNetworkServerListInput{ + PaginationInput: interModel.PaginationInput{ + PageNum: 1, + PageSize: consts.ServerListLimit, + }, + }) + if networkServerListResErr != nil { + return networkServerListResErr + } + if total >= consts.ServerListLimit { + return fmt.Errorf("server限制数量为%d实际已有%d超出限制,请联系管理员处理", consts.ServerListLimit, total) + } + var allServerModels = make([]model.Server, len(networkServerListRes)) + for index, node := range networkServerListRes { + allServerModels[index] = MapperServer(ctx, *node) + } + + for index := range allServerModels { + go func(server model.Server) error { + if server.Disabled { + return nil + } + go func() { + err := startServer(ctx, &server) + if err != nil { + g.Log().Errorf(ctx, "服务启动失败!服务名称:%s,无法启动。错误信息:%s", server.Name, server.Addr, err) + } + }() + return nil + }(allServerModels[index]) + } + return nil +} + +// LoadServer 启动时候加载服务 +func LoadServer(ctx context.Context, id int) error { + networkServerRes, networkServerResErr := service.NetworkServer().GetServerById(ctx, id) + if networkServerResErr != nil { + return networkServerResErr + } + server := MapperServer(ctx, *networkServerRes) + if server.Disabled { + return nil + } + err := startServer(ctx, &server) + if err != nil { + return err + } + return nil +} + +// GetServer 获取通道 +func GetServer(id int) *Server { + d, ok := allServers.Load(id) + if ok { + return d.(*Server) + } + return nil +} + +func RemoveServer(id int) error { + d, ok := allServers.LoadAndDelete(id) + if ok { + tnl := d.(*Server) + return tnl.Instance.Close() + } + return nil //error +} diff --git a/network/core/server-tcp-tunnel.go b/network/core/server-tcp-tunnel.go new file mode 100644 index 0000000..6892acb --- /dev/null +++ b/network/core/server-tcp-tunnel.go @@ -0,0 +1,58 @@ +package core + +import ( + "context" + "errors" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "net" +) + +// ServerTcpTunnel 网络连接 +type ServerTcpTunnel struct { + serverId int + deviceKey string + tunnelBase +} + +func newServerTcpTunnel(serverId, tunnelId int, deviceKey string, conn net.Conn) *ServerTcpTunnel { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOnline, tunnelId), nil) + return &ServerTcpTunnel{serverId: serverId, deviceKey: deviceKey, tunnelBase: tunnelBase{ + tunnelId: tunnelId, + link: conn, + }} +} + +func (l *ServerTcpTunnel) Open(ctx context.Context) error { + return errors.New("ServerTcpTunnel cannot open") +} + +func (l *ServerTcpTunnel) receive(ctx context.Context) { + l.running = true + l.online = true + TunnelOnlineAction(ctx, l.tunnelId, l.deviceKey) + + buf := make([]byte, 1024) + for { + n, err := l.link.Read(buf) + if err != nil { + l.onClose() + break + } + if n == 0 { + continue + } + if l.pipe != nil { + _, err = l.pipe.Write(buf[:n]) + if err != nil { + l.pipe = nil + } else { + continue + } + } + go l.tunnelBase.ReadData(ctx, l.deviceKey, buf[:n]) + } + l.running = false + l.online = false + TunnelOfflineAction(ctx, l.serverId, l.tunnelId) +} diff --git a/network/core/server-tcp.go b/network/core/server-tcp.go new file mode 100644 index 0000000..1689c67 --- /dev/null +++ b/network/core/server-tcp.go @@ -0,0 +1,149 @@ +package core + +import ( + "context" + "encoding/json" + "errors" + "github.com/sagoo-cloud/sagooiot/internal/consts" + interlModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/core/tunnelinstance" + "github.com/sagoo-cloud/sagooiot/network/model" + "net" +) + +type ServerTCP struct { + server *model.Server + + children map[int]*ServerTcpTunnel + + listener *net.TCPListener + + running bool +} + +func newServerTCP(server *model.Server) *ServerTCP { + svr := &ServerTCP{ + server: server, + children: make(map[int]*ServerTcpTunnel), + } + return svr +} + +func (server *ServerTCP) Open(ctx context.Context) error { + if server.running { + return errors.New("server is opened") + } + ServerOpenAction(server.server.Id) + + addr, err := net.ResolveTCPAddr("tcp", resolvePort(server.server.Addr)) + if err != nil { + return err + } + server.listener, err = net.ListenTCP("tcp", addr) + if err != nil { + return err + } + + server.running = true + go func() { + for { + c, err := server.listener.AcceptTCP() + if err != nil { + //todo print err + break + } + + buf := make([]byte, 128) + n := 0 + n, err = c.Read(buf) + if err != nil { + _ = c.Close() + continue + } + data := buf[:n] + deviceKey, checkIsOk := server.server.Register.Check(data) + if !checkIsOk { + _ = c.Close() + continue + } + _, tunnelList, err := service.NetworkTunnel().GetTunnelList(ctx, &interlModel.GetNetworkTunnelListInput{ + ServiceId: server.server.Id, + DeviceKey: deviceKey, + }) + if err != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(err.Error())) + continue + } + tunnelId := 0 + if len(tunnelList) == 0 { + heartbeatData, _ := json.Marshal(server.server.Heartbeat) + var addTunnelError error + if tunnelId, addTunnelError = service.NetworkTunnel().AddTunnel(ctx, interlModel.NetworkTunnelAddInput{ + ServerId: server.server.Id, + Name: deviceKey, + Types: "server-tcp", + Addr: c.LocalAddr().String(), + Remote: c.RemoteAddr().String(), + Heartbeat: string(heartbeatData), + Protoccol: "", + Status: 0, + Remark: "", + }); addTunnelError != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(addTunnelError.Error())) + continue + } + } else { + tunnelId = tunnelList[0].Id + if editTunnelError := service.NetworkTunnel().EditTunnel(ctx, interlModel.NetworkTunnelEditInput{ + Id: tunnelList[0].Id, + NetworkTunnelAddInput: interlModel.NetworkTunnelAddInput{ + ServerId: tunnelList[0].ServerId, + Name: tunnelList[0].Name, + Types: tunnelList[0].Types, + Addr: c.LocalAddr().String(), + Remote: c.RemoteAddr().String(), + Retry: tunnelList[0].Retry, + Heartbeat: tunnelList[0].Heartbeat, + Serial: tunnelList[0].Serial, + Protoccol: tunnelList[0].Protoccol, + Status: tunnelList[0].Status, + Remark: tunnelList[0].Remark, + }, + }); editTunnelError != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(editTunnelError.Error())) + continue + } + } + tnl := newServerTcpTunnel(server.server.Id, tunnelId, deviceKey, c) + go tnl.receive(ctx) + server.children[tunnelId] = tnl + ServerTunnelAction(ctx, server.server.Id, deviceKey) + } + server.running = false + }() + return nil +} + +func (server *ServerTCP) Close() (err error) { + ServerCloseAction(server.server.Id) + if server.children != nil { + for _, l := range server.children { + _ = l.Close() + } + } + return server.listener.Close() +} + +func (server *ServerTCP) GetTunnel(id int) tunnelinstance.TunnelInstance { + return server.children[id] +} + +func (server *ServerTCP) RemoveTunnel(id int) { + delete(server.children, id) +} + +func (server *ServerTCP) Running() bool { + return server.running +} diff --git a/network/core/server-udp-tunnel.go b/network/core/server-udp-tunnel.go new file mode 100644 index 0000000..84926a2 --- /dev/null +++ b/network/core/server-udp-tunnel.go @@ -0,0 +1,116 @@ +package core + +import ( + "context" + "errors" + "io" + "net" + "time" +) + +// ServerUdpTunnel UDP链接 +type ServerUdpTunnel struct { + tunnelBase + deviceKey string + conn *net.UDPConn + addr *net.UDPAddr +} + +func newServerUdpTunnel(deviceKey string, tunnelId int, conn *net.UDPConn, addr *net.UDPAddr) *ServerUdpTunnel { + return &ServerUdpTunnel{ + tunnelBase: tunnelBase{ + tunnelId: tunnelId, + link: conn, + }, + deviceKey: deviceKey, + conn: conn, + addr: addr, + } +} + +func (l *ServerUdpTunnel) Open(ctx context.Context) error { + return errors.New("ServerUdpTunnel cannot open") +} + +func (l *ServerUdpTunnel) Close() error { + return errors.New("ServerUdpTunnel cannot close") +} + +// Write 写 +func (l *ServerUdpTunnel) Write(data []byte) error { + if !l.running { + return errors.New("tunnel closed") + } + if l.pipe != nil { + return nil //透传模式下,直接抛弃 + } + _, err := l.conn.WriteToUDP(data, l.addr) + return err +} + +func (l *ServerUdpTunnel) Ask(cmd []byte, timeout time.Duration) ([]byte, error) { + if !l.running { + return nil, errors.New("tunnel closed") + } + //堵塞 + l.lock.Lock() + defer l.lock.Unlock() //自动解锁 + + err := l.Write(cmd) + if err != nil { + return nil, err + } + return l.wait(timeout) +} + +func (l *ServerUdpTunnel) Pipe(pipe io.ReadWriteCloser) { + //关闭之前的透传 + if l.pipe != nil { + _ = l.pipe.Close() + } + l.pipe = pipe + + //传入空,则关闭 + if l.pipe == nil { + return + } + + go func() { + buf := make([]byte, 1024) + for { + n, err := pipe.Read(buf) + if err != nil { + //if err == io.EOF { + // continue + //} + //pipe关闭,则不再透传 + break + } + //将收到的数据转发出去 + //n, err = l.link.Write(buf[:n]) + _, err = l.conn.WriteToUDP(buf[:n], l.addr) + if err != nil { + //发送失败,说明连接失效 + _ = pipe.Close() + break + } + } + l.pipe = nil + }() +} + +func (l *ServerUdpTunnel) onData(ctx context.Context, data []byte) { + l.running = true + l.online = true + + //透传 + if l.pipe != nil { + _, err := l.pipe.Write(data) + if err == nil { + return + } + l.pipe = nil + } + + go l.tunnelBase.ReadData(ctx, l.deviceKey, data) +} diff --git a/network/core/server-udp.go b/network/core/server-udp.go new file mode 100644 index 0000000..9fbea5f --- /dev/null +++ b/network/core/server-udp.go @@ -0,0 +1,163 @@ +package core + +import ( + "context" + "encoding/json" + "errors" + "github.com/sagoo-cloud/sagooiot/internal/consts" + interlModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/core/tunnelinstance" + "github.com/sagoo-cloud/sagooiot/network/model" + "net" +) + +// ServerUDP UDP服务器 +type ServerUDP struct { + server *model.Server + + children map[int]*ServerUdpTunnel + tunnels map[string]*ServerUdpTunnel + + listener *net.UDPConn + running bool +} + +func newServerUDP(server *model.Server) *ServerUDP { + svr := &ServerUDP{ + server: server, + children: make(map[int]*ServerUdpTunnel), + tunnels: make(map[string]*ServerUdpTunnel), + } + return svr +} + +// Open 打开 +func (server *ServerUDP) Open(ctx context.Context) error { + if server.running { + return errors.New("server is opened") + } + ServerOpenAction(server.server.Id) + + addr, err := net.ResolveUDPAddr("udp", resolvePort(server.server.Addr)) + if err != nil { + return err + } + c, err := net.ListenUDP("udp", addr) + if err != nil { + //TODO 需要正确处理接收错误 + return err + } + server.listener = c //共用连接 + + server.running = true + go func() { + for { + buf := make([]byte, 1024) + n, addr, err := c.ReadFromUDP(buf) + if err != nil { + _ = c.Close() + //continue + break + } + data := buf[:n] + + //如果已经保存了链接 TODO 要有超时处理 + tnl, ok := server.tunnels[addr.String()] + if ok { + tnl.onData(ctx, data) + continue + } + + deviceKey, checkIsOk := server.server.Register.Check(data) + if !checkIsOk { + _ = c.Close() + continue + } + tunnelId := 0 + _, tunnelList, err := service.NetworkTunnel().GetTunnelList(ctx, &interlModel.GetNetworkTunnelListInput{ + ServiceId: server.server.Id, + DeviceKey: deviceKey, + }) + if err != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(err.Error())) + continue + } + if len(tunnelList) == 0 { + heartbeatData, _ := json.Marshal(server.server.Heartbeat) + var addTunnelError error + if tunnelId, addTunnelError = service.NetworkTunnel().AddTunnel(ctx, interlModel.NetworkTunnelAddInput{ + ServerId: server.server.Id, + Name: deviceKey, + Types: "server-udp", + Addr: c.LocalAddr().String(), + Remote: c.RemoteAddr().String(), + Heartbeat: string(heartbeatData), + Protoccol: "", + Status: 0, + Remark: "", + }); addTunnelError != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(addTunnelError.Error())) + continue + } + } else { + tunnelId = tunnelList[0].Id + if editTunnelError := service.NetworkTunnel().EditTunnel(ctx, interlModel.NetworkTunnelEditInput{ + Id: tunnelList[0].Id, + NetworkTunnelAddInput: interlModel.NetworkTunnelAddInput{ + ServerId: tunnelList[0].ServerId, + Name: tunnelList[0].Name, + Types: tunnelList[0].Types, + Addr: c.LocalAddr().String(), + Remote: c.RemoteAddr().String(), + Retry: tunnelList[0].Retry, + Heartbeat: tunnelList[0].Heartbeat, + Serial: tunnelList[0].Serial, + Protoccol: tunnelList[0].Protoccol, + Status: tunnelList[0].Status, + Remark: tunnelList[0].Remark, + }, + }); editTunnelError != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionError, server.server.Id), []byte(editTunnelError.Error())) + continue + } + } + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOnline, server.server.Id), nil) + + tnl = newServerUdpTunnel(deviceKey, tunnelId, c, addr) + server.children[tunnelId] = tnl + ServerTunnelAction(ctx, server.server.Id, deviceKey) + TunnelOnlineAction(ctx, tunnelId, deviceKey) + } + + server.running = false + }() + + return nil +} + +// Close 关闭 +func (server *ServerUDP) Close() (err error) { + ServerCloseAction(server.server.Id) + //close tunnels + if server.children != nil { + for _, l := range server.children { + _ = l.Close() + } + } + return server.listener.Close() +} + +// GetTunnel 获取链接 +func (server *ServerUDP) GetTunnel(id int) tunnelinstance.TunnelInstance { + return server.children[id] +} + +func (server *ServerUDP) RemoveTunnel(id int) { + delete(server.children, id) +} + +func (server *ServerUDP) Running() bool { + return server.running +} diff --git a/network/core/server.go b/network/core/server.go new file mode 100644 index 0000000..2b5104a --- /dev/null +++ b/network/core/server.go @@ -0,0 +1,35 @@ +package core + +import ( + "context" + "fmt" + "github.com/sagoo-cloud/sagooiot/network/core/tunnelinstance" + "github.com/sagoo-cloud/sagooiot/network/model" +) + +// Server 通道 +type ServerInstance interface { + Open(ctx context.Context) error + Close() error + GetTunnel(id int) tunnelinstance.TunnelInstance + RemoveTunnel(id int) + Running() bool +} + +// NewServer 创建通道 +func NewServer(server *model.Server) (ServerInstance, error) { + var svr ServerInstance + var err error + switch server.Type { + case "tcp": + svr = newServerTCP(server) + break + case "udp": + svr = newServerUDP(server) + break + default: + return nil, fmt.Errorf("Unsupport type %s ", server.Type) + } + + return svr, err +} diff --git a/network/core/tunnel-base.go b/network/core/tunnel-base.go new file mode 100644 index 0000000..5e0d8c2 --- /dev/null +++ b/network/core/tunnel-base.go @@ -0,0 +1,167 @@ +package core + +import ( + "context" + "encoding/json" + "errors" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/extend" + "github.com/sagoo-cloud/sagooiot/internal/service" + networkModel "github.com/sagoo-cloud/sagooiot/network/model" + "io" + "sync" + "time" +) + +type tunnelBase struct { + tunnelId int + + lock sync.Mutex + + link io.ReadWriteCloser + + running bool + online bool + first bool + + retry int + retryTimer *time.Timer + + pipe io.ReadWriteCloser + data chan []byte +} + +func (l *tunnelBase) Running() bool { + return l.running +} + +func (l *tunnelBase) Online() bool { + return l.online +} + +// Close 关闭 +func (l *tunnelBase) Close() error { + if l.retryTimer != nil { + l.retryTimer.Stop() + } + if !l.running { + return errors.New("tunnel closed") + } + TunnelCloseAction(l.tunnelId) + l.onClose() + return l.link.Close() +} + +func (l *tunnelBase) onClose() { + l.running = false + if l.pipe != nil { + _ = l.pipe.Close() + } + TunnelCloseAction(l.tunnelId) +} + +// Write 写 +func (l *tunnelBase) Write(data []byte) error { + if !l.running { + return errors.New("tunnel closed") + } + if l.pipe != nil { + return nil //透传模式下,直接抛弃 + } + _, err := l.link.Write(data) + return err +} + +func (l *tunnelBase) wait(duration time.Duration) ([]byte, error) { + select { + case <-time.After(duration): + return nil, errors.New("超时") + case buf := <-l.data: + return buf, nil + } +} + +func (l *tunnelBase) ReadData(ctx context.Context, deviceKey string, data []byte) { + res := string(data) + deviceDetail, err := service.DevDevice().Get(ctx, deviceKey) + if err != nil { + g.Log().Errorf(ctx, "get deviceInfo error: %w, deviceKey:%s, message ignored", err, deviceDetail.Key) + return + } + productDetail, productDetailErr := service.DevProduct().Get(ctx, deviceDetail.Product.Key) + if productDetailErr != nil || productDetail == nil { + g.Log().Errorf(ctx, "find product info error: %w, productKey:%s, message ignored", productDetailErr, deviceDetail.Product.Key) + return + } + if productDetail.MessageProtocol != "" { + if extend.GetProtocolPlugin() == nil { + return + } + res, err = extend.GetProtocolPlugin().GetProtocolUnpackData(productDetail.MessageProtocol, data) + if err != nil { + g.Log().Errorf(ctx, "get plugin error: %w, message:%s, message ignored", err, res) + return + } + } + var reportData networkModel.DefaultMessageType + if reportDataErr := json.Unmarshal([]byte(res), &reportData); reportDataErr != nil { + g.Log().Errorf(ctx, "parse data error: %w, topic:%s, message:%s, message ignored", reportDataErr, res) + return + } + messageRouter{ + ctx: ctx, + data: reportData.Data, + msgType: reportData.DataType, + deviceDetail: deviceDetail, + }.router() + +} + +func (l *tunnelBase) Ask(cmd []byte, timeout time.Duration) ([]byte, error) { + if !l.running { + return nil, errors.New("tunnel closed") + } + + //堵塞 + l.lock.Lock() + defer l.lock.Unlock() //自动解锁 + + _, err := l.link.Write(cmd) + if err != nil { + return nil, err + } + return l.wait(timeout) +} + +func (l *tunnelBase) Pipe(pipe io.ReadWriteCloser) { + //关闭之前的透传 + if l.pipe != nil { + _ = l.pipe.Close() + } + + l.pipe = pipe + //传入空,则关闭 + if pipe == nil { + return + } + + buf := make([]byte, 1024) + for { + n, err := pipe.Read(buf) + if err != nil { + //if err == io.EOF { + // continue + //} + //pipe关闭,则不再透传 + break + } + //将收到的数据转发出去 + n, err = l.link.Write(buf[:n]) + if err != nil { + //发送失败,说明连接失效 + _ = pipe.Close() + break + } + } + l.pipe = nil +} diff --git a/network/core/tunnel-client.go b/network/core/tunnel-client.go new file mode 100644 index 0000000..0f8db76 --- /dev/null +++ b/network/core/tunnel-client.go @@ -0,0 +1,135 @@ +package core + +import ( + "context" + "errors" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + interlModel "github.com/sagoo-cloud/sagooiot/internal/model" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "net" + "time" +) + +// TunnelClient 网络链接 +type TunnelClient struct { + tunnelBase + tunnelInfo *model.Tunnel + net string +} + +func newTunnelClient(tunnel *model.Tunnel, net string) *TunnelClient { + return &TunnelClient{ + tunnelBase: tunnelBase{tunnelId: int(tunnel.Id)}, + tunnelInfo: tunnel, + net: net, + } +} + +// Open 打开 +func (client *TunnelClient) Open(ctx context.Context) error { + if client.running { + return errors.New("client is opened") + } + TunnelOpenAction(client.tunnelId) + + //发起连接 + conn, err := net.Dial(client.net, client.tunnelInfo.Addr) + if err != nil { + client.Retry(ctx) + return err + } + client.retry = 0 + client.link = conn + + //开始接收数据 + go client.receive(ctx) + if editTunnelError := service.NetworkTunnel().EditTunnel(ctx, interlModel.NetworkTunnelEditInput{ + Id: int(client.tunnelInfo.Id), + NetworkTunnelAddInput: interlModel.NetworkTunnelAddInput{ + ServerId: client.tunnelInfo.ServerId, + Name: client.tunnelInfo.Name, + Addr: conn.LocalAddr().String(), + Remote: conn.RemoteAddr().String(), + }, + }); editTunnelError != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionError, int(client.tunnelInfo.Id)), []byte(editTunnelError.Error())) + return editTunnelError + } + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOnline, int(client.tunnelInfo.Id)), nil) + return nil +} + +func (client *TunnelClient) Retry(ctx context.Context) { + //重连 + retry := &client.tunnelInfo.Retry + if retry.Enable && (retry.Maximum == 0 || client.retry < retry.Maximum) { + client.retry++ + client.retryTimer = time.AfterFunc(time.Second*time.Duration(retry.Timeout), func() { + client.retryTimer = nil + err := client.Open(ctx) + if err != nil { + g.Log().Error(ctx, err) + } + }) + } +} + +func (client *TunnelClient) receive(ctx context.Context) { + client.running = true + client.online = true + + tunnelInfo, tunnelInfoErr := service.NetworkTunnel().GetTunnelById(ctx, int(client.tunnelInfo.Id)) + if tunnelInfoErr != nil { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionError, int(client.tunnelInfo.Id)), []byte(tunnelInfoErr.Error())) + } else { + TunnelOnlineAction(ctx, int(client.tunnelInfo.Id), tunnelInfo.DeviceKey) + buf := make([]byte, 1024) + for { + n, err := client.link.Read(buf) + if err != nil { + client.onClose() + break + } + if n == 0 { + continue + } + + data := buf[:n] + //过滤心跳包 + if client.tunnelInfo.Heartbeat.Enable && client.tunnelInfo.Heartbeat.Check(data) { + continue + } + + //透传转发 + if client.pipe != nil { + _, err = client.pipe.Write(data) + if err != nil { + client.pipe = nil + } else { + continue + } + } + go client.tunnelBase.ReadData(ctx, tunnelInfo.DeviceKey, data) + } + } + client.running = false + client.online = false + TunnelOfflineAction(ctx, 0, client.tunnelId) + client.Retry(ctx) +} + +// Close 关闭 +func (client *TunnelClient) Close() error { + client.running = false + TunnelCloseAction(client.tunnelId) + + if client.link != nil { + link := client.link + client.link = nil + return link.Close() + } + return errors.New("tunnel is closed") +} diff --git a/network/core/tunnel-common.go b/network/core/tunnel-common.go new file mode 100644 index 0000000..9b27de8 --- /dev/null +++ b/network/core/tunnel-common.go @@ -0,0 +1,89 @@ +package core + +import ( + "context" + "encoding/json" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/model" + "time" +) + +func TunnelOpenAction(tunnelId int) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOpen, tunnelId), nil) +} + +func TunnelCloseAction(tunnelId int) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionClose, tunnelId), nil) +} + +func TunnelOnlineAction(ctx context.Context, tunnelId int, deviceKey string) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOnline, tunnelId), nil) + deviceRes, err := service.DevDevice().Get(ctx, deviceKey) + if err != nil { + g.Log().Error(ctx, err) + return + } + deviceDetail := GetDevice(uint64(deviceRes.Id)) + if deviceDetail != nil { + err = deviceDetail.Start(ctx) + if err != nil { + g.Log().Error(ctx, err) + return + } else { + if deviceRes != nil && deviceRes.Status != consts.DeviceStatueOnline { + onlineMessage, _ := json.Marshal(model.DeviceOnlineMessage{ + DeviceKey: deviceRes.DevDevice.Key, + Timestamp: time.Now().Unix(), + }) + if dataBusOfflineErr := mqtt.Publish(consts.GetDataBusWrapperTopic(deviceRes.Product.Key, deviceRes.DevDevice.Key, consts.DataBusOffline), onlineMessage); dataBusOfflineErr != nil { + g.Log().Errorf(ctx, "publish data error: %w, topic:%s, message:%s, message ignored", dataBusOfflineErr, + consts.GetDataBusWrapperTopic(deviceRes.Product.Key, deviceRes.DevDevice.Key, consts.DataBusOffline), + string(onlineMessage)) + return + } + } + } + } +} + +func TunnelOfflineAction(ctx context.Context, serverId, tunnelId int) { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusTunnel, consts.ActionOffline, tunnelId), nil) + tunnelInfo, err := service.NetworkTunnel().GetTunnelById(ctx, tunnelId) + + //TODO log error + if err == nil && tunnelInfo != nil { + deviceDetail, _ := service.DevDevice().Get(ctx, tunnelInfo.DeviceKey) + if deviceDetail == nil { + g.Log().Errorf(ctx, "deviceKey:%s not found,ignore", tunnelInfo.DeviceKey) + return + } + if deviceStopError := GetDevice(uint64(deviceDetail.Id)).Stop(); deviceStopError != nil { + g.Log().Errorf(ctx, "Stop device error:%w ,ignore", deviceStopError) + } + if deviceDetail != nil && deviceDetail.Status == consts.DeviceStatueOnline { + onlineMessage, _ := json.Marshal(model.DeviceOnlineMessage{ + DeviceKey: tunnelInfo.DeviceKey, + Timestamp: time.Now().Unix(), + }) + if dataBusOfflineErr := mqtt.Publish(consts.GetDataBusWrapperTopic(deviceDetail.Product.Key, tunnelInfo.DeviceKey, consts.DataBusOffline), onlineMessage); dataBusOfflineErr != nil { + g.Log().Errorf(ctx, "publish data error: %w, topic:%s, message:%s, message ignored", dataBusOfflineErr, + consts.GetDataBusWrapperTopic(deviceDetail.Product.Key, tunnelInfo.DeviceKey, consts.DataBusOffline), + string(onlineMessage)) + return + } + } + + } else if err != nil { + g.Log().Errorf(ctx, "getTunnel ifno error:%w ,ignore", err) + } + + if serverId != 0 { + server := GetServer(serverId) + if server != nil { + server.Instance.RemoveTunnel(tunnelId) + } + } +} diff --git a/network/core/tunnel-manager.go b/network/core/tunnel-manager.go new file mode 100644 index 0000000..dfeb3dd --- /dev/null +++ b/network/core/tunnel-manager.go @@ -0,0 +1,87 @@ +package core + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/internal/service" + "github.com/sagoo-cloud/sagooiot/network/core/tunnelinstance" + "github.com/sagoo-cloud/sagooiot/network/model" + "sync" +) + +var allTunnels sync.Map + +type Server struct { + model.Server + Instance ServerInstance +} + +type Tunnel struct { + Instance tunnelinstance.TunnelInstance +} + +func startTunnel(ctx context.Context, tunnel *model.Tunnel) error { + tnl, err := NewTunnel(tunnel) + if err != nil { + // log.Error(err) + return err + } + return tnl.Open(ctx) +} + +func LoadTunnels(ctx context.Context) error { + allTunnelModels := make([]*model.Tunnel, 0) + + tunnelRunList, err := service.NetworkTunnel().GetTunnelRunList(ctx) + if err != nil { + return err + } + for _, node := range tunnelRunList { + t := mapperTunnel(ctx, *node) + allTunnelModels = append(allTunnelModels, &t) + } + + for index := range allTunnelModels { + go func(tunnel *model.Tunnel) { + err = startTunnel(ctx, tunnel) + if err != nil { + g.Log().Error(ctx, err) + } + }(allTunnelModels[index]) + } + return nil +} + +func LoadTunnel(ctx context.Context, id int) error { + + tunnelInfo, err := service.NetworkTunnel().GetTunnelById(ctx, id) + if err != nil { + return err + } + tunnel := mapperTunnel(ctx, *tunnelInfo) + if tunnel.Disabled { + return nil // TODO error ?? + } + err = startTunnel(ctx, &tunnel) + if err != nil { + return err + } + return nil +} + +func GetTunnel(id int) *Tunnel { + d, ok := allTunnels.Load(id) + if ok { + return d.(*Tunnel) + } + return nil +} + +func RemoveTunnel(id int) error { + d, ok := allTunnels.LoadAndDelete(id) + if ok { + lnk := d.(*Tunnel) + return lnk.Instance.Close() + } + return nil // error +} diff --git a/network/core/tunnel.go b/network/core/tunnel.go new file mode 100644 index 0000000..0d2c454 --- /dev/null +++ b/network/core/tunnel.go @@ -0,0 +1,35 @@ +package core + +import ( + "fmt" + "github.com/sagoo-cloud/sagooiot/network/core/tunnelinstance" + "github.com/sagoo-cloud/sagooiot/network/model" + "strings" +) + +// NewTunnel 创建通道 +func NewTunnel(tunnel *model.Tunnel) (tunnelinstance.TunnelInstance, error) { + var tnl tunnelinstance.TunnelInstance + switch tunnel.Type { + case "serial": + //TODO 等待补全 + //tnl = newTunnelSerial(tunnel) + break + case "tcp-client": + tnl = newTunnelClient(tunnel, "tcp") + break + case "udp-client": + tnl = newTunnelClient(tunnel, "udp") + break + default: + return nil, fmt.Errorf("Unsupport type %s ", tunnel.Type) + } + return tnl, nil +} + +func resolvePort(addr string) string { + if strings.IndexByte(addr, ':') == -1 { + return ":" + addr + } + return addr +} diff --git a/network/core/tunnelinstance/tunnel-instance.go b/network/core/tunnelinstance/tunnel-instance.go new file mode 100644 index 0000000..f3db43b --- /dev/null +++ b/network/core/tunnelinstance/tunnel-instance.go @@ -0,0 +1,26 @@ +package tunnelinstance + +import ( + "context" + "io" + "time" +) + +// Tunnel 通道 +type TunnelInstance interface { + Write(data []byte) error + + Open(context.Context) error + + Close() error + + Running() bool + + Online() bool + + //Pipe 透传 + Pipe(pipe io.ReadWriteCloser) + + //Ask 发送指令,接收数据 + Ask(cmd []byte, timeout time.Duration) ([]byte, error) +} diff --git a/network/events/events.go b/network/events/events.go new file mode 100644 index 0000000..39fff15 --- /dev/null +++ b/network/events/events.go @@ -0,0 +1,111 @@ +package events + +import ( + "reflect" + "sync" +) + +type Handler func(args ...interface{}) + +//EventInterface Events接口 +type EventInterface interface { + Emit(event string, data ...interface{}) + On(event string, fn interface{}) + Once(event string, fn interface{}) + Off(event string, fn interface{}) +} + +type EventEmitter struct { + events sync.Map +} + +type subscriber struct { + callback reflect.Value + once bool +} + +//Emit 发送消息 +func (e *EventEmitter) Emit(event string, data ...interface{}) { + sub, ok1 := e.events.Load(event) + subAll, ok2 := e.events.Load("*") + + if !ok1 && !ok2 { + return + } + + //整理参数 + args := make([]reflect.Value, 0) + args = append(args, reflect.ValueOf(event)) + for _, v := range data { + args = append(args, reflect.ValueOf(v)) + } + + if ok1 { + subscribers := sub.(*sync.Map) + //args := make([]reflect.Value, 1+len(data)) + subscribers.Range(func(key, value interface{}) bool { + handler := value.(*subscriber) + handler.callback.Call(args[1:]) + //处理仅订阅一次 + if handler.once { + subscribers.Delete(key) + } + return true + }) + } + + //处理全局订阅* + if ok2 { + subscribers := subAll.(*sync.Map) + subscribers.Range(func(key, value interface{}) bool { + handler := value.(*subscriber) + handler.callback.Call(args) + //处理仅订阅一次 + if handler.once { + subscribers.Delete(key) + } + return true + }) + } +} + +//On 监听 +func (e *EventEmitter) On(event string, fn interface{}) { + callback := reflect.ValueOf(fn) + val, ok := e.events.Load(event) + if !ok { + val = new(sync.Map) + e.events.Store(event, val) + } + subscribers := val.(*sync.Map) + subscribers.Store(callback.Pointer(), &subscriber{ + callback: callback, + once: false, + }) +} + +//Once 监听一次 +func (e *EventEmitter) Once(event string, fn interface{}) { + callback := reflect.ValueOf(fn) + val, ok := e.events.Load(event) + if !ok { + val = new(sync.Map) + e.events.Store(event, val) + } + subscribers := val.(*sync.Map) + subscribers.Store(callback.Pointer(), &subscriber{ + callback: callback, + once: true, + }) +} + +//Off 取消监听 +func (e *EventEmitter) Off(event string, fn interface{}) { + callback := reflect.ValueOf(fn) + val, ok := e.events.Load(event) + if !ok { + return + } + subscribers := val.(*sync.Map) + subscribers.Delete(callback.Pointer()) +} diff --git a/network/model/command.go b/network/model/command.go new file mode 100644 index 0000000..6f32b15 --- /dev/null +++ b/network/model/command.go @@ -0,0 +1,18 @@ +package model + +// Command 命令 +type Command struct { + Name string `json:"name"` + Argument bool `json:"argument"` + Directives []Directive `json:"directives"` +} + +// Directive 指令 +type Directive struct { + Point string `json:"point"` + Value float64 `json:"value"` + Delay int64 `json:"delay"` + + //使用表达式 + Expression string `json:"expression,omitempty"` +} diff --git a/network/model/default.go b/network/model/default.go new file mode 100644 index 0000000..c15b94a --- /dev/null +++ b/network/model/default.go @@ -0,0 +1,7 @@ +package model + +type DefaultReportFormate struct { + Attr map[string]interface{} `json:"attr"` + DeviceId string `json:"device_id"` + ReturnTime string `json:"return_time"` +} diff --git a/network/model/device.go b/network/model/device.go new file mode 100644 index 0000000..1b28353 --- /dev/null +++ b/network/model/device.go @@ -0,0 +1,34 @@ +package model + +import ( + "time" +) + +// Product 产品 +type Product struct { + Id string `json:"id" xorm:"pk"` + Name string `json:"name"` + Manufacturer string `json:"manufacturer"` //厂家 + Version string `json:"version"` //SEMVER + Protocol Protocol `json:"protocol"` + //Tunnel string `json:"tunnel"` // serial tcp udp ??? + + Tags []string `json:"tags,omitempty"` + Pollers []*Poller `json:"pollers"` + Commands []*Command `json:"commands"` + + Created time.Time `json:"created" xorm:"created"` +} + +// Device 设备 +type Device struct { + Id uint64 `json:"id"` + TunnelId uint64 `json:"tunnel_id" boltholdIndex:"TunnelId"` + ProductId string `json:"product_id"` + + Name string `json:"name"` + Station int `json:"station"` + + Disabled bool `json:"disabled"` + Created time.Time `json:"created" xorm:"created"` +} diff --git a/network/model/message.go b/network/model/message.go new file mode 100644 index 0000000..e677d00 --- /dev/null +++ b/network/model/message.go @@ -0,0 +1,177 @@ +package model + +// 设备上报的报文解析为平台统一的消息,消息体结构如下 +type DefaultMessageType struct { + ReturnTime string `json:"return_time"` + DataType string `json:"data_type"` + DeviceKey string `json:"device_key"` + Data map[string]any `json:"data"` +} + +// 通用的结构体 +type ( + Header struct { + Async bool `json:"async" desc:"是否异步"` + Timeout int `json:"timeout" desc:"超时时间,单位为毫秒"` + FragMsgId int `json:"fragMsgId" desc:"分片主消息ID,为平台下发消息时的消息ID(messageId"` + FragNum int `json:"fragNum" desc:"分片总数"` + FragPart int `json:"fragPart" desc:"当前分片索引"` + FragLast int `json:"fragLast" desc:"是否为最后一个分片。当无法确定分片数量的时候,可以将分片设置到足够大,最后一个分片设置frag_last=true来完成返回。"` + KeepOnline int `json:"keepOnline" desc:"与DeviceOnlineMessage配合使用,在TCP短链接,保持设备一直在线状态,连接断开不会设置设备离线."` + KeepOnlineTimeoutSeconds int `json:"keepOnlineTimeoutSeconds" desc:"指定在线超时时间。在短链接时,如果超过此间隔没有收到消息则认为设备离线。"` + IgnoreStorage int `json:"ignoreStorage" desc:"不存储此消息数据。如:读写属性回复默认也会记录到属性时序数据库中,设置为true后,将不记录。"` + IgnoreLog bool `json:"ignoreLog" desc:"不记录此消息的日志。如:设置为true,将不记录此消息的日志。"` + MergeLatest bool `json:"mergeLatest" desc:"是否合并最新属性数据。设置此消息头后,将会把最新的消息合并到消息体里(需要开启最新数据存储。"` + } + Common struct { + H Header + DeviceKey string + MessageId string + Timestamp int64 + } +) + +// 读取属性的消息结构体 +type ( + ReadPropertyMessage struct { + Common + Properties []string + } + ReadPropertyMessageReply struct { + Common + Success bool + Properties map[string]any + } +) + +// 写属性消息结构体 +type ( + WritePropertyMessage struct { + Common + Properties map[string]any + } + + WritePropertyMessageReply struct { + Common + Success bool + Properties map[string]any + } + + ReportPropertyMessage struct { + Common + Properties map[string]any + } +) + +// 功能消息结构体 +type ( + FunctionParameter struct { + Name string + Value any + } + FunctionInvokeMessage struct { + Common + FunctionId string + Inputs []FunctionParameter + } + FunctionInvokeMessageReply struct { + Common + Success bool + Output any + } +) + +//设备上报消息结构体 + +type ( + EventMessage struct { + H Header + Event string + Data any + Timestamp int64 + } +) + +// 设备上线下线结构体 +type ( + Message any + DeviceOnlineMessage struct { + DeviceKey string + Timestamp int64 + } + + DeviceOfflineMessage struct { + DeviceKey string + Timestamp int64 + } +) + +// 子设备消息结构体 +type ( + ChildDeviceMessage struct { + DeviceKey string + Timestamp int64 + ChildDeviceKey string + ChildDeviceMessage Message + } + + ChildDeviceMessageReply struct { + DeviceKey string + MessageId string + ChildDeviceKey string + ChildDeviceMessage Message + } +) + +// 设备元信息相关结构体 +type ( + UpdateTagMessage struct { + DeviceKey string + Timestamp int64 + tags map[string]any + } + + DerivedMetadataMessage struct { + DeviceKey string + Timestamp int64 + Metadata string + All bool + } +) + +type ( + DeviceRegisterMessage struct { + DeviceKey string + Timestamp int64 + } +) + +// 更新相关消息结构体 +type ( + UpgradeFirmwareMessage struct { + DeviceKey string + Timestamp int64 + Url string + Version string + Parameters map[string]any + Sign string + SignMethod string + FirmwareId string + Size float64 + } + UpgradeFirmwareMessageReply struct { + DeviceKey string + Timestamp int64 + Success bool + } + + UpgradeFirmwareProgressMessage struct { + DeviceKey string + Progress int + Complete bool + Version string + Success bool + ErrorReason string + FirmwareId string + } +) diff --git a/network/model/point.go b/network/model/point.go new file mode 100644 index 0000000..aa56031 --- /dev/null +++ b/network/model/point.go @@ -0,0 +1,24 @@ +package model + +import ( + "time" +) + +// Point 数据点 +type Point struct { + Name string `json:"name"` + Label string `json:"label"` + Unit string `json:"unit"` + Type DataType `json:"type"` + LittleEndian bool `json:"le"` + Precision int `json:"precision"` + Code string `json:"code"` + Address string `json:"address"` + Store bool `json:"store"` + //Default float64 `json:"default"` +} + +type DataPoint struct { + Value interface{} `json:"value"` + Time time.Time `json:"time"` +} diff --git a/network/model/poller.go b/network/model/poller.go new file mode 100644 index 0000000..ee135f0 --- /dev/null +++ b/network/model/poller.go @@ -0,0 +1,10 @@ +package model + +// Poller 采集器 +type Poller struct { + Disabled bool `json:"disabled,omitempty"` + Interval int `json:"interval"` + Code string `json:"code"` + Address string `json:"address"` + Length int `json:"length"` +} diff --git a/network/model/server.go b/network/model/server.go new file mode 100644 index 0000000..76ad0fa --- /dev/null +++ b/network/model/server.go @@ -0,0 +1,34 @@ +package model + +import ( + "github.com/sagoo-cloud/sagooiot/internal/consts" + "github.com/sagoo-cloud/sagooiot/internal/mqtt" + "regexp" + "time" +) + +type Server struct { + Id int `json:"id"` + Name string `json:"name"` + Type string `json:"type"` //tcp udp + Addr string `json:"addr"` + Register RegisterPacket `json:"register"` + Heartbeat HeartBeatPacket `json:"heartbeat"` + Options map[string]string `json:"options"` + Protocol Protocol `json:"protocol"` + Devices []DefaultDevice `json:"devices"` //默认设备 + Disabled bool `json:"disabled"` + Created time.Time `json:"created" xorm:"created"` +} + +func (s *Server) Open() { + _ = mqtt.Publish(consts.GetWrapperTopic(consts.DataBusServer, consts.ActionOpen, s.Id), nil) +} + +// RegisterPacket 注册包 +type RegisterPacket struct { + Regex string `json:"regex,omitempty"` + Length int `json:"length,omitempty"` + + regex *regexp.Regexp +} diff --git a/network/model/tunnel.go b/network/model/tunnel.go new file mode 100644 index 0000000..8786d63 --- /dev/null +++ b/network/model/tunnel.go @@ -0,0 +1,137 @@ +package model + +import ( + "bytes" + "encoding/hex" + "regexp" + "time" +) + +type Protocol struct { + Name string `json:"name"` + Options map[string]interface{} `json:"options"` +} + +/* +boltholdIndex 标签是嵌入式数据库 BoltDB 上面的query layer需要的一个特殊标记 +*/ +//Tunnel 通道模型 +type Tunnel struct { + Id uint64 `json:"id"` + ServerId int `json:"server_id" boltholdIndex:"ServerId"` + Name string `json:"name"` + SN string `json:"sn" boltholdIndex:"Addr"` + Type string `json:"type"` //serial tcp-client tcp-server udp-client udp-server server-tcp server-udp + Addr string `json:"addr"` + Remote string `json:"remote"` + Retry Retry `json:"retry"` //重试 + Heartbeat HeartBeatPacket `json:"heartbeat"` // 主要是检查设备的心跳,过滤掉心跳数据 + Serial SerialOptions `json:"serial"` // 串口通信配置参数 + Protocol Protocol `json:"protocol"` //协议配置,包含协议名称和配置 + //Devices []DefaultDevice `json:"devices"` //默认设备 + Disabled bool `json:"disabled"` + Last time.Time `json:"last"` + Created time.Time `json:"created" xorm:"created"` +} + +type DefaultDevice struct { + Station int `json:"station"` + ProductId string `json:"product_id"` +} + +type TunnelEx struct { + Tunnel `xorm:"extends"` + Running bool `json:"running"` + Online bool `json:"online"` + Server string `json:"server"` +} + +func (tunnel *TunnelEx) TableName() string { + return "tunnel" +} + +type Retry struct { + Enable bool `json:"enable"` + Timeout int `json:"timeout"` + Maximum int `json:"maximum"` +} + +// SerialOptions 串口参数 +type SerialOptions struct { + Port string `json:"port"` // /dev/tty.usb.. COM1 + BaudRate uint `json:"baud_rate"` //9600 ... 115200 ... + DataBits uint `json:"data_bits"` //5 6 7 8 + StopBits uint `json:"stop_bits"` //1 2 + Parity uint `json:"parity"` // 0:NONE 1:ODD 2:EVEN + //RS485 bool `json:"rs485"` +} + +func (p *RegisterPacket) Check(buf []byte) (deviceKey string, checkOk bool) { + if p.Regex != "" { + if p.regex == nil { + p.regex = regexp.MustCompile(p.Regex) + } + return string(buf), p.regex.MatchString(string(buf)) + } + if p.Length > 0 { + if len(buf) != p.Length { + return "", false + } + } + return string(buf), true +} + +// HeartBeatPacket 心跳包 +type HeartBeatPacket struct { + Enable bool `json:"enable"` + Timeout int64 `json:"timeout"` + Regex string `json:"regex,omitempty"` + Hex string `json:"hex,omitempty"` + Text string `json:"text,omitempty"` + Length int `json:"length,omitempty"` + + hex []byte + regex *regexp.Regexp + last int64 +} + +// Check 检查 +func (p *HeartBeatPacket) Check(buf []byte) bool { + + now := time.Now().Unix() + if p.last == 0 { + p.last = now + } + if p.last+p.Timeout > now { + p.last = now + return false + } + p.last = now + + if p.Regex != "" { + if p.regex == nil { + p.regex = regexp.MustCompile(p.Regex) + } + return p.regex.Match(buf) + } + + if p.Length > 0 { + if len(buf) != p.Length { + return false + } + } + + if p.Hex != "" { + if p.hex == nil { + //var err error + p.hex, _ = hex.DecodeString(p.Hex) + } + return bytes.Equal(p.hex, buf) + } + + if p.Text != "" { + return p.Text == string(buf) + } + + return true +} diff --git a/network/model/type.go b/network/model/type.go new file mode 100644 index 0000000..9d9c7c7 --- /dev/null +++ b/network/model/type.go @@ -0,0 +1,412 @@ +package model + +import ( + "errors" + "fmt" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/network/codebin" + "math" + "strings" +) + +//DataType 数据类型 +type DataType int + +const ( + //TypeNONE 空类型 + TypeNONE DataType = iota + TypeBIT + TypeBYTE + TypeWORD + TypeDWORD + TypeQWORD + TypeSHORT + TypeINTEGER + TypeLONG + TypeFLOAT + TypeDOUBLE +) + +//Parse 解析类型 +func (dt *DataType) Parse(tp string) error { + //var *dt DataType + tp = tp[1 : len(tp)-1] + //strings.ToLower(tp) + switch strings.ToLower(tp) { + case "none": + *dt = TypeNONE + case "bit": + *dt = TypeBIT + case "byte": + *dt = TypeBYTE + case "word": + fallthrough + case "uint16": + *dt = TypeWORD + case "dword": + fallthrough + case "uint32": + *dt = TypeDWORD + case "qword": + fallthrough + case "uint64": + *dt = TypeQWORD + case "short": + fallthrough + case "int16": + *dt = TypeSHORT + case "integer": + fallthrough + case "int32": + fallthrough + case "int": + *dt = TypeINTEGER + case "long": + fallthrough + case "int64": + *dt = TypeLONG + case "float": + *dt = TypeFLOAT + case "double": + fallthrough + case "float64": + *dt = TypeDOUBLE + default: + return fmt.Errorf("Unknown data type: %s ", tp) + } + return nil +} + +//String 转化成字符串 +func (dt *DataType) String() string { + var str string + switch *dt { + case TypeBIT: + str = "bit" + case TypeBYTE: + str = "byte" + case TypeWORD: + str = "word" + case TypeDWORD: + str = "dword" + case TypeQWORD: + str = "qword" + case TypeSHORT: + str = "short" + case TypeINTEGER: + str = "integer" + case TypeLONG: + str = "long" + case TypeFLOAT: + str = "float" + case TypeDOUBLE: + str = "double" + default: + str = "none" + } + return str +} + +func (dt *DataType) Default() interface{} { + switch *dt { + case TypeBIT: + return false + case TypeBYTE: + return byte(0) + case TypeWORD: + return uint16(0) + case TypeDWORD: + return uint32(0) + case TypeQWORD: + return uint64(0) + case TypeSHORT: + return int16(0) + case TypeINTEGER: + return int32(0) + case TypeLONG: + return int64(0) + case TypeFLOAT: + return float32(0) + case TypeDOUBLE: + return float64(0) + default: + return 0 + } +} + +func (dt *DataType) Normalize(val interface{}) interface{} { + switch *dt { + case TypeBIT: + return gconv.Bool(val) + case TypeBYTE: + return gconv.Uint8(val) + case TypeWORD: + return gconv.Uint16(val) + case TypeDWORD: + return gconv.Uint32(val) + case TypeQWORD: + return gconv.Uint64(val) + case TypeSHORT: + return gconv.Int16(val) + case TypeINTEGER: + return gconv.Int32(val) + case TypeLONG: + return gconv.Int64(val) + case TypeFLOAT: + return gconv.Float32(val) + case TypeDOUBLE: + return gconv.Float64(val) + default: + return 0 + } +} + +//Size 宽度 +func (dt *DataType) Size() int { + var s int + switch *dt { + case TypeBIT: + s = 1 + case TypeBYTE: + s = 1 + case TypeWORD: + s = 2 + case TypeDWORD: + s = 4 + case TypeQWORD: + s = 8 + case TypeSHORT: + s = 2 + case TypeINTEGER: + s = 4 + case TypeLONG: + s = 8 + case TypeFLOAT: + s = 4 + case TypeDOUBLE: + s = 8 + default: + s = 1 + } + return s +} + +//Encode 编码 +func (dt *DataType) Encode(value interface{}, le bool, precision int) []byte { + buf := make([]byte, 8) + switch *dt { + case TypeBIT: + if gconv.Bool(value) { + buf[0] = 1 //????? + } else { + buf[0] = 0 + } + case TypeBYTE: + buf[0] = gconv.Uint8(value) + case TypeWORD: + var val uint16 + if precision > 0 { + val = uint16(gconv.Float64(value) * math.Pow10(precision)) + } else { + val = gconv.Uint16(value) + } + if le { + codebin.WriteUint16LittleEndian(buf, val) + } else { + codebin.WriteUint16(buf, val) + } + case TypeDWORD: + var val uint32 + if precision > 0 { + val = uint32(gconv.Float64(value) * math.Pow10(precision)) + } else { + val = gconv.Uint32(value) + } + if le { + codebin.WriteUint32LittleEndian(buf, val) + } else { + codebin.WriteUint32(buf, val) + } + case TypeQWORD: + var val uint64 + if precision > 0 { + val = uint64(value.(float64) * math.Pow10(precision)) + } else { + val = gconv.Uint64(value) + } + if le { + codebin.WriteUint64LittleEndian(buf, val) + } else { + codebin.WriteUint64(buf, val) + } + case TypeSHORT: + var val int16 + if precision > 0 { + val = int16(gconv.Float64(value) * math.Pow10(precision)) + } else { + val = gconv.Int16(value) + } + if le { + codebin.WriteUint16LittleEndian(buf, uint16(val)) + } else { + codebin.WriteUint16(buf, uint16(val)) + } + case TypeINTEGER: + var val int32 + if precision > 0 { + val = int32(gconv.Float64(value) * math.Pow10(precision)) + } else { + val = gconv.Int32(value) + } + if le { + codebin.WriteUint32LittleEndian(buf, uint32(val)) + } else { + codebin.WriteUint32(buf, uint32(val)) + } + case TypeLONG: + var val int64 + if precision > 0 { + val = int64(gconv.Float64(value) * math.Pow10(precision)) + } else { + val = gconv.Int64(value) + } + if le { + codebin.WriteUint64LittleEndian(buf, uint64(val)) + } else { + codebin.WriteUint64(buf, uint64(val)) + } + case TypeFLOAT: + val := gconv.Float32(value) + if le { + codebin.WriteFloat32LittleEndian(buf, val) + } else { + codebin.WriteFloat32(buf, val) + } + case TypeDOUBLE: + val := gconv.Float64(value) + if le { + codebin.WriteFloat64LittleEndian(buf, val) + } else { + codebin.WriteFloat64(buf, val) + } + default: + //TODO error + } + return buf[:dt.Size()] +} + +//Decode 解码 +func (dt *DataType) Decode(buf []byte, le bool, precision int) (val interface{}, err error) { + //避免越界访问 + if len(buf) < dt.Size() { + return nil, fmt.Errorf("长度不够") + } + + switch *dt { + case TypeBIT: + if buf[0] > 0 { + val = true + } else { + val = false + } + case TypeBYTE: + val = buf[0] + case TypeWORD: + var value uint16 + if le { + value = codebin.ParseUint16LittleEndian(buf) + } else { + value = codebin.ParseUint16(buf) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeDWORD: + var value uint32 + if le { + value = codebin.ParseUint32LittleEndian(buf) + } else { + value = codebin.ParseUint32(buf) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeQWORD: + var value uint64 + if le { + value = codebin.ParseUint64LittleEndian(buf) + } else { + value = codebin.ParseUint64(buf) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeSHORT: + var value int16 + if le { + value = int16(codebin.ParseUint16LittleEndian(buf)) + } else { + value = int16(codebin.ParseUint16(buf)) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeINTEGER: + var value int32 + if le { + value = int32(codebin.ParseUint32LittleEndian(buf)) + } else { + value = int32(codebin.ParseUint32(buf)) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeLONG: + var value int64 + if le { + value = int64(codebin.ParseUint64LittleEndian(buf)) + } else { + value = int64(codebin.ParseUint64(buf)) + } + if precision > 0 { + val = float64(value) / math.Pow10(precision) + } else { + val = value + } + case TypeFLOAT: + if le { + val = codebin.ParseFloat32LittleEndian(buf) + } else { + val = codebin.ParseFloat32(buf) + } + case TypeDOUBLE: + if le { + val = codebin.ParseFloat64LittleEndian(buf) + } else { + val = codebin.ParseFloat64(buf) + } + default: + err = errors.New("未知的数据类型") + } + return +} + +//MarshalJSON 序列化 +func (dt *DataType) MarshalJSON() ([]byte, error) { + return []byte(`"` + dt.String() + `"`), nil +} + +//UnmarshalJSON 解析 +func (dt *DataType) UnmarshalJSON(buf []byte) error { + return dt.Parse(string(buf)) +} diff --git a/network/network.go b/network/network.go new file mode 100644 index 0000000..fa288dd --- /dev/null +++ b/network/network.go @@ -0,0 +1,15 @@ +package network + +import ( + "context" + "github.com/sagoo-cloud/sagooiot/network/core" +) + +func ReloadNetwork(c context.Context) (err error) { + for _, f := range []func(ctx context.Context) error{core.StartSubscriber, core.LoadDevices, core.LoadTunnels, core.LoadServers} { + if err = f(c); err != nil { + return err + } + } + return +} diff --git a/network/pkg/cron/cron.go b/network/pkg/cron/cron.go new file mode 100644 index 0000000..8806d25 --- /dev/null +++ b/network/pkg/cron/cron.go @@ -0,0 +1,70 @@ +package cron + +import ( + "github.com/go-co-op/gocron" + "time" +) + +// Scheduler 调度器 +var Scheduler *gocron.Scheduler + +func init() { + Scheduler = gocron.NewScheduler(time.Local) // time.UTC + Scheduler.StartAsync() +} + +//是否是使用单一协程??? 是则要改成协程池??? + +// Schedule 创建任务 +func Schedule(crontab string, fn func()) (*Job, error) { + job, err := Scheduler.Cron(crontab).Do(fn) + if err != nil { + return nil, err + } + return &Job{job: job}, nil +} + +// Interval 创建周期任务 +func Interval(interval int, fn func()) (*Job, error) { + job, err := Scheduler.Every(interval).Milliseconds().Do(fn) + if err != nil { + return nil, err + } + return &Job{job: job}, nil +} + +// Clock 创建每日任务 +func Clock(hours int, minutes int, fn func()) (*Job, error) { + job, err := Scheduler.Every(1).Day().At(hours).Hours().At(minutes).Minutes().Do(fn) + if err != nil { + return nil, err + } + return &Job{job: job}, nil +} + +// ClockWithWeekdays 创建每日任务 +func ClockWithWeekdays(hours int, minutes int, weekdays []time.Weekday, fn func()) (*Job, error) { + s := Scheduler.Every(1).Day().At(hours).Hours().At(minutes).Minutes() + if len(weekdays) > 0 { + s.Weeks() + for _, w := range weekdays { + s.Weekday(w) + } + } + + job, err := s.Do(fn) + if err != nil { + return nil, err + } + return &Job{job: job}, nil +} + +// Job 任务 +type Job struct { + job *gocron.Job +} + +// Cancel 取消任务 +func (j *Job) Cancel() { + Scheduler.Remove(j.job) +} diff --git a/network/pkg/mqttclient/mqtt.go b/network/pkg/mqttclient/mqtt.go new file mode 100644 index 0000000..d40bcbe --- /dev/null +++ b/network/pkg/mqttclient/mqtt.go @@ -0,0 +1,51 @@ +package mqttclient + +import ( + "context" + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/gogf/gf/v2/frame/g" +) + +type MqttConf struct { + Addr string + ClientId string + UserName string + Password string +} + +type MqttWrapperClient struct { + c mqtt.Client +} + +func InitMqtt(c *MqttConf) (*MqttWrapperClient, error) { + opts := mqtt.NewClientOptions() + opts.AddBroker(c.Addr) + opts.SetClientID(c.ClientId) + opts.SetUsername(c.UserName) + opts.SetPassword(c.Password) + mqttClient := mqtt.NewClient(opts) + if token := mqttClient.Connect(); token.Wait() && token.Error() != nil { + return nil, token.Error() + } else { + return &MqttWrapperClient{mqttClient}, nil + } +} + +func (m *MqttWrapperClient) Close() { + m.c.Disconnect(uint(250)) +} + +func (m *MqttWrapperClient) Publish(topic string, payload []byte) error { + pubToken := m.c.Publish(topic, 2, false, payload) + return pubToken.Error() +} + +func (m *MqttWrapperClient) Subscribe(ctx context.Context, topic string, h mqtt.MessageHandler) (err error) { + if subErr := m.c.Subscribe(topic, 2, h); subErr.Error() != nil { + g.Log().Errorf(ctx, "subscribe error: %s", subErr.Error()) + return subErr.Error() + } else { + return nil + } + +} diff --git a/plugin_test.go b/plugin_test.go new file mode 100644 index 0000000..35a4cfc --- /dev/null +++ b/plugin_test.go @@ -0,0 +1,124 @@ +package main + +import ( + "fmt" + "github.com/gogf/gf/v2/util/gconv" + "github.com/sagoo-cloud/sagooiot/extend" + "github.com/sagoo-cloud/sagooiot/extend/model" + "github.com/sagoo-cloud/sagooiot/extend/module" + "net" + "testing" +) + +func TestManagerInit(t *testing.T) { + manager := extend.NewManager("protocol", "protocol-*", "../plugins/built", &module.ProtocolPlugin{}) + defer manager.Dispose() + err := manager.Init() + if err != nil { + t.Fatal(err.Error()) + } + err = manager.Launch() + for id, info := range manager.Plugins { + t.Log(id) + t.Log(info.Path) + t.Log(info.Client) + } + + modbus, err := manager.GetInterface("modbus") + if err != nil { + t.Fatal(err.Error()) + } + + data := gconv.Bytes("aadsfsfsfdfsfsdfsfs") + res := modbus.(module.Protocol).Read(data) + t.Log(res) + +} + +//测试插件服务使用,需要先将要测试的插件进行编译 +func TestProtocolPluginServer(t *testing.T) { + NetData() +} + +func NetData() { + fmt.Println("Starting the server ...") + // 创建 listener + listener, err := net.Listen("tcp", "localhost:5000") + if err != nil { + fmt.Println("Error listening", err.Error()) + return //终止程序 + } + // 监听并接受来自客户端的连接 + for { + conn, err := listener.Accept() + if err != nil { + fmt.Println("Error accepting", err.Error()) + return // 终止程序 + } + go doServerStuff(conn) + } +} + +func doServerStuff(conn net.Conn) { + //获取插件 + //pm := GetPlugin(ProtocolPluginName) + + for { + buf := make([]byte, 512) + l, err := conn.Read(buf) + if err != nil { + fmt.Println("Error reading", err.Error()) + return //终止程序 + } + fmt.Printf("Received data: %v\n", string(buf[:l])) + + //获取协议插件解析后的数据 传入插件ID,及需要解析的数据 + data, err := extend.GetProtocolPlugin().GetProtocolUnpackData("modbus", buf[:l]) + fmt.Println("============通过插件获取数据:", data) + } +} + +func TestNotice(t *testing.T) { + + // 准备通知数据 + var msg = model.NoticeInfoData{} + msg.Totag = "[{\"name\":\"mail\",\"value\":\"940290@qq.com\"},{\"name\":\"webhook\",\"value\":\"cccc\"}],{\"name\":\"sms\",\"value\":\"13700005102\"}]" + msg.MsgBody = "new111111" + msg.MsgTitle = "title111112222" + + //通过邮件发送通知 + res, err := extend.GetNoticePlugin().NoticeSend("mail", msg) + if err != nil { + t.Log("Error: ", err.Error()) + } + t.Log(res) + + //通过短信发送通知 + res, err = extend.GetNoticePlugin().NoticeSend("sms", msg) + if err != nil { + t.Log("Error: ", err.Error()) + } + t.Log(res) + + //通过webhook发送通知 + res, err = extend.GetNoticePlugin().NoticeSend("webhook", msg) + if err != nil { + t.Log("Error: ", err.Error()) + } + t.Log(res) + + //通过企业微信发送通知 + res, err = extend.GetNoticePlugin().NoticeSend("wework", msg) + if err != nil { + t.Log("Error: ", err.Error()) + } + t.Log(res) + + //通过钉钉发送通知 + res, err = extend.GetNoticePlugin().NoticeSend("dingding", msg) + if err != nil { + t.Log("Error: ", err.Error()) + } + t.Log(res) + +} diff --git a/plugins/Makefile b/plugins/Makefile new file mode 100644 index 0000000..7f4a378 --- /dev/null +++ b/plugins/Makefile @@ -0,0 +1,23 @@ +PROTOCOL_PLUGIN_DIRS=$(wildcard ./protocol/*) #网络协议解析插件目录 +NOTICE_PLUGIN_DIRS=$(wildcard ./notice/*) #通知服务插件目录 + +BUILD_SYS=local #编译方式: local,本地环境编译;linux,linux交叉编译 + +all: build-plugins + +clean: clean-plugins + +build-plugins: $(PROTOCOL_PLUGIN_DIRS) $(NOTICE_PLUGIN_DIRS) + +clean-plugins: + rm -f ./built/* + +$(PROTOCOL_PLUGIN_DIRS): + $(info Clubber plugins at: $(PROTOCOL_PLUGIN_DIRS)) + $(MAKE) $(BUILD_SYS) -C $@ + +$(NOTICE_PLUGIN_DIRS): + $(info Clubber plugins at: $(NOTICE_PLUGIN_DIRS)) + $(MAKE) $(BUILD_SYS) -C $@ + +.PHONY: all $(PROTOCOL_PLUGIN_DIRS) $(NOTICE_PLUGIN_DIRS) \ No newline at end of file diff --git a/plugins/built/.gitignore b/plugins/built/.gitignore new file mode 100644 index 0000000..4ba2bdd --- /dev/null +++ b/plugins/built/.gitignore @@ -0,0 +1,2 @@ +greeter* +clubber* diff --git a/plugins/notice/dingding/Makefile b/plugins/notice/dingding/Makefile new file mode 100644 index 0000000..06580d1 --- /dev/null +++ b/plugins/notice/dingding/Makefile @@ -0,0 +1,11 @@ +BINARY_NAME=notice-dingding + +local: + echo "========local============" + go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built + +linux: + echo "========linux============" + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built \ No newline at end of file diff --git a/plugins/notice/dingding/dingding.go b/plugins/notice/dingding/dingding.go new file mode 100644 index 0000000..6bbeedc --- /dev/null +++ b/plugins/notice/dingding/dingding.go @@ -0,0 +1,86 @@ +package main + +import ( + "fmt" + "github.com/gogf/gf/v2/util/gconv" + gplugin "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" + extend "github.com/sagoo-cloud/sagooiot/extend/module" + "github.com/sagoo-cloud/sagooiot/extend/sdk" + "github.com/sagoo-cloud/sagooiot/plugins/notice/dingding/internal" + "net/rpc" +) + +type Options struct { + PayloadURL string + Secret string + Subject string + Body string +} + +//NoticeDingding 实现 +type NoticeDingding struct{} + +func (NoticeDingding) Info() model.ModuleInfo { + var res = model.ModuleInfo{} + res.Name = "dingding" + res.Title = "Ding Ding" + res.Author = "Microrain" + res.Intro = "通过钉钉方式发送通知" + res.Version = "0.01" + return res +} + +func (NoticeDingding) Send(data []byte) (res model.JsonRes) { + //解析通知数据 + nd, err := sdk.DecodeNoticeData(data) + if err != nil { + res.Code = 2 + res.Message = "插件数据解析失败" + res.Data = err.Error() + return res + } + + // 设定相关参数 + opts := []internal.Option{ + internal.AppKey(gconv.String(nd.Config["AppKey"])), + internal.AppSecret(gconv.String(nd.Config["AppSecret"])), + internal.AgentID(gconv.String(nd.Config["AgentID"])), + } + ding := internal.GetDingdingChannel(opts...) + accessToken, err := ding.GetAccessToken() + if err != nil { + fmt.Println(err) + return + } + err = ding.SendTextMessage(accessToken, "", "", "", "Hello, world!", "") + if err != nil { + fmt.Println(err) + return + } + return +} + +//DingdingPlugin 插件接口实现 +type DingdingPlugin struct{} + +//Server 此方法由插件进程延迟调 +func (DingdingPlugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &extend.NoticeRPCServer{Impl: new(NoticeDingding)}, nil +} + +// Client 此方法由宿主进程调用 +func (DingdingPlugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &extend.NoticeRPC{Client: c}, nil +} + +func main() { + gplugin.Serve(&gplugin.ServeConfig{ + HandshakeConfig: extend.HandshakeConfig, + Plugins: pluginMap, + }) +} + +var pluginMap = map[string]gplugin.Plugin{ + "dingding": new(DingdingPlugin), +} diff --git a/plugins/notice/dingding/internal/options.go b/plugins/notice/dingding/internal/options.go new file mode 100644 index 0000000..9d3c9d9 --- /dev/null +++ b/plugins/notice/dingding/internal/options.go @@ -0,0 +1,26 @@ +package internal + +type options struct { + appKey string + appSecret string + agentID string +} + +type Option func(c *options) + +func AppKey(d string) Option { + return func(opts *options) { + opts.appKey = d + } +} + +func AppSecret(d string) Option { + return func(opts *options) { + opts.appSecret = d + } +} +func AgentID(d string) Option { + return func(opts *options) { + opts.agentID = d + } +} diff --git a/plugins/notice/dingding/internal/send.go b/plugins/notice/dingding/internal/send.go new file mode 100644 index 0000000..fe328bc --- /dev/null +++ b/plugins/notice/dingding/internal/send.go @@ -0,0 +1,127 @@ +package internal + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gcache" + "github.com/sagoo-cloud/sagooiot/extend/model" + "io/ioutil" + "net/http" + "sync" + "time" +) + +type dingdingChannel struct { + opts *options +} + +var ins *dingdingChannel + +var once sync.Once + +//GetDingdingChannel 构造方法 +func GetDingdingChannel(opts ...Option) *dingdingChannel { + clusterOpts := options{} + for _, opt := range opts { + // 函数指针的赋值调用 + opt(&clusterOpts) + } + once.Do(func() { + ins = &dingdingChannel{} + }) + ins.opts = &clusterOpts + + return ins +} + +// GetAccessToken 获取 access_token +func (d *dingdingChannel) GetAccessToken() (accessToken string, err error) { + + cacheKey := "Dingding" + d.opts.agentID + //存缓存里获取accessToken + accessTokenData, _ := gcache.Get(context.TODO(), cacheKey) + if accessTokenData != nil { + accessToken = accessTokenData.String() + return + } + + url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", d.opts.appKey, d.opts.appSecret) + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var data struct { + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` + Token string `json:"access_token"` + } + if err := json.Unmarshal(body, &data); err != nil { + return "", err + } + if data.Errcode != 0 { + return "", fmt.Errorf("%d: %s", data.Errcode, data.Errmsg) + } + + // 钉钉的AccessToken的有效期是2小时,这里设置为缓存1小时 + _, err = gcache.SetIfNotExist(context.TODO(), cacheKey, data.Token, time.Hour) + + return +} + +//Send 发送 +func (d *dingdingChannel) Send(accessToken string, msg model.NoticeInfoData) (err error) { + var sendObjectList []model.NoticeSendObject + err = gjson.DecodeTo(msg.Totag, &sendObjectList) + if err != nil { + g.Log().Error(context.TODO(), err) + return + } + + var touser string + for _, object := range sendObjectList { + if object.Name == "dingding" { + touser = object.Value + "," + } + } + err = d.SendTextMessage(accessToken, touser, "", "", msg.MsgBody, "") + + return +} + +// SendTextMessage 发送文本消息 +func (d *dingdingChannel) SendTextMessage(accessToken, touser, totag, toparty, message, atMobiles string) error { + url := fmt.Sprintf("https://oapi.dingtalk.com/message/send?access_token=%s", accessToken) + + data := map[string]interface{}{ + "touser": touser, + "toparty": toparty, + "totag": totag, + "msgtype": "text", + "agentid": d.opts.agentID, + "text": map[string]string{ + "content": message, + }, + "at": map[string]interface{}{ + "atMobiles": []string{atMobiles}, + "isAtAll": false, + }, + } + payload, err := json.Marshal(data) + if err != nil { + return err + } + + _, err = http.Post(url, "application/json", bytes.NewReader(payload)) + return err +} diff --git a/plugins/notice/dingding/readme.MD b/plugins/notice/dingding/readme.MD new file mode 100644 index 0000000..bc3eb33 --- /dev/null +++ b/plugins/notice/dingding/readme.MD @@ -0,0 +1,27 @@ +首先,你需要在钉钉开发平台中创建一个应用并获取到对应的 AppKey 和 AppSecret。然后,你可以使用以下步骤来发送通知: + +使用 AppKey 和 AppSecret 获取到 access_token。你可以使用以下 API 获取 access_token: +``` +https://oapi.dingtalk.com/gettoken?appkey=APPKEY&appsecret=APPSECRET + +``` +使用 access_token 和其他所需的参数调用钉钉的发送消息 API 发送通知。你可以使用以下 API 发送通知: + +``` +https://oapi.dingtalk.com/message/send?access_token=ACCESS_TOKEN +``` +具体的,你需要构造一个 JSON 对象作为请求体,包含以下字段: + +touser: 接收通知的用户的 userid,多个用户用逗号分隔。 + +toparty: 接收通知的部门的 ID,多个部门用逗号分隔。 + +totag: 接收通知的标签的 ID,多个标签用逗号分隔。 + +msgtype: 消息类型,此处应为 "text"。 + +agentid: 发送通知的应用的 ID。 + +text: 消息内容,类型为文本时,此字段包含文本消息的内容。 + +at: 被 @ 的用户的 userid 列表,多个用户用逗号分隔。 \ No newline at end of file diff --git a/plugins/notice/mail/Makefile b/plugins/notice/mail/Makefile new file mode 100644 index 0000000..3dcbece --- /dev/null +++ b/plugins/notice/mail/Makefile @@ -0,0 +1,11 @@ +BINARY_NAME=notice-mail + +local: + echo "========local============" + go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built + +linux: + echo "========linux============" + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built \ No newline at end of file diff --git a/plugins/notice/mail/internal/options.go b/plugins/notice/mail/internal/options.go new file mode 100644 index 0000000..ebf8616 --- /dev/null +++ b/plugins/notice/mail/internal/options.go @@ -0,0 +1,33 @@ +package internal + +type options struct { + mailHost string + mailPort int + mailUser string // 发件人 + mailPass string // 发件人密码 +} + +type Option func(c *options) + +func MailHost(d string) Option { + return func(opts *options) { + opts.mailHost = d + } +} + +func MailPort(d int) Option { + return func(opts *options) { + opts.mailPort = d + } +} +func MailUser(d string) Option { + return func(opts *options) { + opts.mailUser = d + } +} + +func MailPass(d string) Option { + return func(opts *options) { + opts.mailPass = d + } +} diff --git a/plugins/notice/mail/internal/send.go b/plugins/notice/mail/internal/send.go new file mode 100644 index 0000000..bd1dee2 --- /dev/null +++ b/plugins/notice/mail/internal/send.go @@ -0,0 +1,75 @@ +package internal + +import ( + "context" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/extend/model" + "gopkg.in/gomail.v2" + "strings" + "sync" +) + +type mailChannel struct { + opts *options +} + +var ins *mailChannel + +var once sync.Once + +//GetMailChannel 构造方法 +func GetMailChannel(opts ...Option) *mailChannel { + clusterOpts := options{} + for _, opt := range opts { + // 函数指针的赋值调用 + opt(&clusterOpts) + } + once.Do(func() { + ins = &mailChannel{} + }) + ins.opts = &clusterOpts + + return ins +} + +//Send 发送 +func (m *mailChannel) Send(msg model.NoticeInfoData) (err error) { + + var sendObjectList []model.NoticeSendObject + err = gjson.DecodeTo(msg.Totag, &sendObjectList) + if err != nil { + g.Log().Error(context.TODO(), err) + return + } + + for _, object := range sendObjectList { + if object.Name == "mail" { + var data = make(map[string]string) + data["mailTo"] = object.Value + data["subject"] = msg.MsgTitle + data["body"] = msg.MsgBody + err = m.sendMail(data) + } + } + return err +} + +func (m *mailChannel) sendMail(data map[string]string) (err error) { + + mail := gomail.NewMessage() + //设置发件人 + mail.SetHeader("From", m.opts.mailUser) + //设置发送给多个用户 + mailArrTo := strings.Split(data["mailTo"], ",") + mail.SetHeader("To", mailArrTo...) + //设置邮件主题 + mail.SetHeader("Subject", data["subject"]) + + //设置邮件正文 + mail.SetBody("text/html", data["body"]) + d := gomail.NewDialer(m.opts.mailHost, m.opts.mailPort, m.opts.mailUser, m.opts.mailPass) + + err = d.DialAndSend(mail) + return err +} diff --git a/plugins/notice/mail/internal/send_test.go b/plugins/notice/mail/internal/send_test.go new file mode 100644 index 0000000..f8d7cd4 --- /dev/null +++ b/plugins/notice/mail/internal/send_test.go @@ -0,0 +1,27 @@ +package internal + +import ( + "fmt" + "github.com/sagoo-cloud/sagooiot/extend/model" + "testing" +) + +func TestSend(t *testing.T) { + var msg = model.NoticeInfoData{} + // 设定相关参数 + opts := []Option{ + MailHost("smtp.qq.com"), + MailPort(465), + MailUser("xinjy@qq.com"), + MailPass("zdqkqrdzplnabiig"), + } + m := GetMailChannel(opts...) + + msg.Totag = "[{\"name\":\"mail\",\"value\":\"940290@qq.com\"},{\"name\":\"webhook\",\"value\":\"cccc\"}]" + msg.MsgTitle = "test sagoo iot msg" + msg.MsgBody = "this is doc" + if err := m.Send(msg); err != nil { + fmt.Println(err) + } + +} diff --git a/plugins/notice/mail/mail.go b/plugins/notice/mail/mail.go new file mode 100644 index 0000000..9b9ac08 --- /dev/null +++ b/plugins/notice/mail/mail.go @@ -0,0 +1,85 @@ +package main + +import ( + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/gconv" + gplugin "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" + extend "github.com/sagoo-cloud/sagooiot/extend/module" + "github.com/sagoo-cloud/sagooiot/extend/sdk" + "github.com/sagoo-cloud/sagooiot/plugins/notice/mail/internal" + "net/rpc" +) + +var logger *glog.Logger + +//NoticeMail 实现 +type NoticeMail struct{} + +func (NoticeMail) Info() model.ModuleInfo { + var res = model.ModuleInfo{} + res.Name = "mail" + res.Title = "电子邮件通知" + res.Author = "Microrain" + res.Intro = "通过电子邮件发送通知" + res.Version = "0.01" + return res +} + +func (NoticeMail) Send(data []byte) (res model.JsonRes) { + + //解析通知数据 + nd, err := sdk.DecodeNoticeData(data) + if err != nil { + res.Code = 2 + res.Message = "邮件插件数据解析失败" + res.Data = err.Error() + return res + } + + // 设定相关参数 + opts := []internal.Option{ + internal.MailHost(gconv.String(nd.Config["MailHost"])), + internal.MailPort(gconv.Int(nd.Config["MailPort"])), + internal.MailUser(gconv.String(nd.Config["MailUser"])), + internal.MailPass(gconv.String(nd.Config["MailPass"])), + } + m := internal.GetMailChannel(opts...) + if err := m.Send(nd.Msg); err != nil { + res.Code = 2 + res.Message = "邮件发送失败" + res.Data = err.Error() + return res + } + + tmpData := gjson.New(nd) + res.Code = 0 + res.Message = "邮件发送成功" + res.Data = tmpData.MustToJsonString() + return res +} + +//MailPlugin 插件接口实现 +type MailPlugin struct{} + +//Server 此方法由插件进程延迟调 +func (MailPlugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &extend.NoticeRPCServer{Impl: new(NoticeMail)}, nil +} + +// Client 此方法由宿主进程调用 +func (MailPlugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &extend.NoticeRPC{Client: c}, nil +} + +func main() { + gplugin.Serve(&gplugin.ServeConfig{ + HandshakeConfig: extend.HandshakeConfig, + Plugins: pluginMap, + }) +} + +var pluginMap = map[string]gplugin.Plugin{ + "mail": new(MailPlugin), +} diff --git a/plugins/notice/wework/Makefile b/plugins/notice/wework/Makefile new file mode 100644 index 0000000..933fd15 --- /dev/null +++ b/plugins/notice/wework/Makefile @@ -0,0 +1,11 @@ +BINARY_NAME=notice-wework + +local: + echo "========local============" + go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built + +linux: + echo "========linux============" + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built \ No newline at end of file diff --git a/plugins/notice/wework/internal/internal.go b/plugins/notice/wework/internal/internal.go new file mode 100644 index 0000000..6268414 --- /dev/null +++ b/plugins/notice/wework/internal/internal.go @@ -0,0 +1,73 @@ +package internal + +import ( + "context" + "encoding/json" + "github.com/fastwego/wxwork/corporation" + "github.com/fastwego/wxwork/corporation/apis/message" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/sagoo-cloud/sagooiot/plugins/notice/wework/model" +) + +type Alarm struct { + Corp *corporation.Corporation + CorpApp *corporation.App + AppConfig corporation.AppConfig +} + +/** + * 建立私有变量 + */ +var instance *Alarm + +func GetInstance(corpid, agentID, secret, token, encodingAESKey string) *Alarm { + instance = new(Alarm) + // 加载应用的配置 + appConfigInfo, _ := g.Cfg().Get(context.TODO(), "wework.alarm", corporation.AppConfig{}) + p := gjson.New(appConfigInfo) + + if err := p.Scan(&instance.AppConfig); err != nil { + g.Log().Error(context.TODO(), err) + } + + instance.AppConfig.Token = token + instance.AppConfig.AgentId = agentID + instance.AppConfig.Secret = secret + instance.AppConfig.EncodingAESKey = encodingAESKey + + instance.Corp = corporation.New(corporation.Config{Corpid: corpid}) + instance.CorpApp = instance.Corp.NewApp(instance.AppConfig) + + return instance +} + +func (e *Alarm) SendMessage(toUser, content string) (interface{}, error) { + if content == "" { + return nil, gerror.New("发送的内容为空值") + } + + sendMsg := new(model.Text) + sendMsg.Agentid = e.AppConfig.AgentId + sendMsg.Touser = toUser //"@all" + sendMsg.Msgtype = "text" + sendMsg.Text.Content = content + sendMsg.DuplicateCheckInterval = 1800 + + jsonByte := ToJson(sendMsg) + + resp, err := message.Send(e.CorpApp, jsonByte) + if err != nil { + return nil, err + } + return resp, nil +} + +func ToJson(data interface{}) []byte { + jsonByte, err := json.Marshal(data) + if err != nil { + g.Log().Error(context.TODO(), err) + } + return jsonByte +} diff --git a/plugins/notice/wework/model/sendmessage.go b/plugins/notice/wework/model/sendmessage.go new file mode 100644 index 0000000..bf16d7b --- /dev/null +++ b/plugins/notice/wework/model/sendmessage.go @@ -0,0 +1,32 @@ +package model + +type Base struct { + Touser string `json:"touser"` + Toparty string `json:"toparty"` + Totag string `json:"totag"` + Msgtype string `json:"msgtype"` + Agentid string `json:"agentid"` + Safe int `json:"safe"` + EnableIDTrans int `json:"enable_id_trans"` + EnableDuplicateCheck int `json:"enable_duplicate_check"` + DuplicateCheckInterval int `json:"duplicate_check_interval"` +} + +//文本消息结构体 +type Text struct { + Base + Text struct { + Content string `json:"content"` + } `json:"text"` +} + +//文本卡片消息结构 +type Textcard struct { + Base + Textcard struct { + Title string `json:"title"` + Description string `json:"description"` + URL string `json:"url"` + Btntxt string `json:"btntxt"` + } `json:"textcard"` +} diff --git a/plugins/notice/wework/wework.go b/plugins/notice/wework/wework.go new file mode 100644 index 0000000..5ec103d --- /dev/null +++ b/plugins/notice/wework/wework.go @@ -0,0 +1,97 @@ +package main + +import ( + "context" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + gplugin "github.com/hashicorp/go-plugin" + "github.com/sagoo-cloud/sagooiot/extend/model" + extend "github.com/sagoo-cloud/sagooiot/extend/module" + "github.com/sagoo-cloud/sagooiot/extend/sdk" + "github.com/sagoo-cloud/sagooiot/plugins/notice/wework/internal" + "net/rpc" +) + +type Options struct { + PayloadURL string + Secret string + Subject string + Body string +} + +//NoticeWework 实现 +type NoticeWework struct{} + +func (NoticeWework) Info() model.ModuleInfo { + var res = model.ModuleInfo{} + res.Name = "wework" + res.Title = "企业微信通知" + res.Author = "Microrain" + res.Intro = "通过企业微信方式发送通知" + res.Version = "0.01" + return res +} + +func (NoticeWework) Send(data []byte) (res model.JsonRes) { + //解析通知数据 + nd, err := sdk.DecodeNoticeData(data) + if err != nil { + res.Code = 2 + res.Message = "插件数据解析失败" + res.Data = err.Error() + return res + } + + var sendObjectList []model.NoticeSendObject + err = gjson.DecodeTo(nd.Msg.Totag, &sendObjectList) + if err != nil { + g.Log().Error(context.TODO(), err) + return + } + corpid := gconv.String(nd.Config["Corpid"]) + agentID := gconv.String(nd.Config["AgentID"]) + secret := gconv.String(nd.Config["Secret"]) + token := gconv.String(nd.Config["Token"]) + encodingAESKey := gconv.String(nd.Config["EncodingAESKey"]) + + alarmService := internal.GetInstance(corpid, agentID, secret, token, encodingAESKey) + for _, object := range sendObjectList { + if object.Name == "wework" { + toUser := object.Value + content := nd.Msg.MsgBody + g.Log().Debug(context.TODO(), toUser, content) + data, err := alarmService.SendMessage(toUser, content) + if err != nil { + g.Log().Error(context.TODO(), err) + } + g.Log().Debug(context.TODO(), data) + } + } + + return +} + +//WeworkPlugin 插件接口实现 +type WeworkPlugin struct{} + +//Server 此方法由插件进程延迟调 +func (WeworkPlugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &extend.NoticeRPCServer{Impl: new(NoticeWework)}, nil +} + +// Client 此方法由宿主进程调用 +func (WeworkPlugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &extend.NoticeRPC{Client: c}, nil +} + +func main() { + gplugin.Serve(&gplugin.ServeConfig{ + HandshakeConfig: extend.HandshakeConfig, + Plugins: pluginMap, + }) +} + +var pluginMap = map[string]gplugin.Plugin{ + "wework": new(WeworkPlugin), +} diff --git a/plugins/protocol/tgn52/Makefile b/plugins/protocol/tgn52/Makefile new file mode 100644 index 0000000..1b71b79 --- /dev/null +++ b/plugins/protocol/tgn52/Makefile @@ -0,0 +1,11 @@ +BINARY_NAME=protocol-tgn52 + +local: + echo "========local============" + go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built + +linux: + echo "========linux============" + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY_NAME} + mv ${BINARY_NAME} ../../built \ No newline at end of file diff --git a/plugins/protocol/tgn52/model.go b/plugins/protocol/tgn52/model.go new file mode 100644 index 0000000..4b620cd --- /dev/null +++ b/plugins/protocol/tgn52/model.go @@ -0,0 +1,18 @@ +package main + +import "reflect" + +type DeviceData struct { + HeadStr string //字头 + DeviceID string //设备ID + Signal string //信号质量 + Battery string //电池电量 + Temperature string //温度 + Humidity string //湿度 + Cycle string //周期 + Update []string //待上传 +} + +func (d DeviceData) IsEmpty() bool { + return reflect.DeepEqual(d, DeviceData{}) +} diff --git a/plugins/protocol/tgn52/readme.md b/plugins/protocol/tgn52/readme.md new file mode 100644 index 0000000..d2a2994 --- /dev/null +++ b/plugins/protocol/tgn52/readme.md @@ -0,0 +1,11 @@ +# TG-N5 设备说明 + + +```go +NB1;1234567;1;2;+25.5;00;030;+21;+22 +``` + + +电量和信号都是123, 分别代表低中高 + +断点续传功能,说明之前有因如信号不稳定等因素,造成上传不成功的数据。缓存起来,有上传条件时,一起上传。先进先出原则:即先发送的温度数据为先存储的不成功数据,距离目前时间点较远。每个数据时间间隔为上传周期。上面例子中的就是30分钟 \ No newline at end of file diff --git a/plugins/protocol/tgn52/tgn52.go b/plugins/protocol/tgn52/tgn52.go new file mode 100644 index 0000000..1bebde7 --- /dev/null +++ b/plugins/protocol/tgn52/tgn52.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "github.com/sagoo-cloud/sagooiot/extend/model" + "net/rpc" + "strings" + + gplugin "github.com/hashicorp/go-plugin" + plugin "github.com/sagoo-cloud/sagooiot/extend/module" +) + +//ProtocolTgn52 实现 +type ProtocolTgn52 struct{} + +func (ProtocolTgn52) Info() model.ModuleInfo { + var res = model.ModuleInfo{} + res.Name = "tgn52" + res.Title = "TG-N5 v2设备协议" + res.Author = "Microrain" + res.Intro = "对TG-N5插座设备进行数据采集v2" + res.Version = "0.01" + return res +} + +func (ProtocolTgn52) Write(args interface{}) (err error) { + fmt.Println("接收到参数:", args) + return +} + +func (ProtocolTgn52) Read(data []byte) string { + tmpData := strings.Split(string(data), ";") + var rd = DeviceData{} + l := len(tmpData) + if l > 7 { + rd.HeadStr = tmpData[0] + rd.DeviceID = tmpData[1] + rd.Signal = tmpData[2] + rd.Battery = tmpData[3] + rd.Temperature = tmpData[4] + rd.Humidity = tmpData[5] + rd.Cycle = tmpData[6] + //处理续传数据 + for i := 7; i < l; i++ { + rd.Update = append(rd.Update, tmpData[i]) + } + } + res := plugin.OutJsonRes(0, "", rd) + if rd.IsEmpty() { + res = plugin.OutJsonRes(1, "数据为空,或数据结构不对", nil) + } + return res +} + +//Tgn52Plugin 插件接口实现 +//这有两种方法:服务器必须为此插件返回RPC服务器类型。我们为此构建了一个RPCServer。 +//客户端必须返回我们的接口的实现通过RPC客户端。我们为此返回RPC。 +type Tgn52Plugin struct{} + +//Server 此方法由插件进程延迟调 +func (Tgn52Plugin) Server(*gplugin.MuxBroker) (interface{}, error) { + return &plugin.ProtocolRPCServer{Impl: new(ProtocolTgn52)}, nil +} + +// Client 此方法由宿主进程调用 +func (Tgn52Plugin) Client(b *gplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &plugin.ProtocolRPC{Client: c}, nil +} + +func main() { + //调用plugin.Serve()启动侦听,并提供服务 + //ServeConfig 握手配置,插件进程和宿主机进程,都需要保持一致 + gplugin.Serve(&gplugin.ServeConfig{ + HandshakeConfig: plugin.HandshakeConfig, + Plugins: pluginMap, + }) +} + +// 插件进程必须指定Impl,此处赋值为greeter对象 +var pluginMap = map[string]gplugin.Plugin{ + "tgn52": new(Tgn52Plugin), +} diff --git a/resource/public/.gitignore b/resource/public/.gitignore new file mode 100644 index 0000000..4ba2bdd --- /dev/null +++ b/resource/public/.gitignore @@ -0,0 +1,2 @@ +greeter* +clubber* diff --git a/tools/migration/internal/td_conn.go b/tools/migration/internal/td_conn.go new file mode 100644 index 0000000..ead1e26 --- /dev/null +++ b/tools/migration/internal/td_conn.go @@ -0,0 +1,21 @@ +package internal + +import ( + "context" + "database/sql" + + "github.com/gogf/gf/v2/frame/g" + _ "github.com/taosdata/driver-go/v3/taosRestful" +) + +func GetConn(ctx context.Context, tdname string) *sql.DB { + driver := g.Cfg("tdengine").MustGet(ctx, tdname+".type") + dsn := g.Cfg("tdengine").MustGet(ctx, tdname+".dsn") + dbName := g.Cfg("tdengine").MustGet(ctx, tdname+".dbName") + + taos, err := sql.Open(driver.String(), dsn.String()+dbName.String()) + if err != nil { + panic(tdname + "连接失败" + err.Error()) + } + return taos +} diff --git a/tools/migration/internal/td_destination.go b/tools/migration/internal/td_destination.go new file mode 100644 index 0000000..5fbde69 --- /dev/null +++ b/tools/migration/internal/td_destination.go @@ -0,0 +1,100 @@ +package internal + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/gogf/gf/v2/container/gvar" +) + +type TdDestination struct { + db *sql.DB +} + +func NewTdDestination() *TdDestination { + db := GetConn(context.Background(), "tdengineDest") + return &TdDestination{db: db} +} + +func (s *TdDestination) CreateStables() (err error) { + tdSrc := NewTdSource() + stables, createSql, err := tdSrc.ShowCreateStable() + if err != nil || len(stables) == 0 || len(createSql) == 0 { + return + } + + for i, v := range stables { + if err = s.DropStable(v); err == nil { + _, err = s.db.Exec(createSql[i]) + } + } + return +} + +func (s *TdDestination) CreateTables() (err error) { + tdSrc := NewTdSource() + tables, createSql, err := tdSrc.ShowCreateTable() + if err != nil { + return + } + if err != nil || len(tables) == 0 || len(createSql) == 0 { + return + } + + for i, v := range tables { + if err = s.DropTable(v); err == nil { + _, err = s.db.Exec(createSql[i]) + } + } + return +} + +func (s *TdDestination) InsertData() (err error) { + tdSrc := NewTdSource() + tables, err := tdSrc.Tables() + if err != nil || tables.Len() == 0 { + return + } + + for _, rs := range tables { + tb := rs["table_name"].String() + count, _ := tdSrc.Count(tb) + if count > 0 { + data, err := tdSrc.Data(tb, 1, 1000) + if err != nil || data.Len() == 0 { + continue + } + + for _, row := range data { + var ( + field []string + value []string + ) + for k, v := range row { + field = append(field, k) + value = append(value, "'"+gvar.New(v).String()+"'") + } + sqlStr := fmt.Sprintf("insert into %s (%s) values (%s)", tb, strings.Join(field, ","), strings.Join(value, ",")) + if _, err = s.db.Exec(sqlStr); err != nil { + return err + } + } + } + } + + return +} + +func (s *TdDestination) DropStable(stable string) (err error) { + sqlStr := "drop stable if exists " + stable + _, err = s.db.Exec(sqlStr) + return +} + +func (s *TdDestination) DropTable(table string) (err error) { + sqlStr := "drop table if exists " + table + _, err = s.db.Exec(sqlStr) + return +} diff --git a/tools/migration/internal/td_source.go b/tools/migration/internal/td_source.go new file mode 100644 index 0000000..75c4e51 --- /dev/null +++ b/tools/migration/internal/td_source.go @@ -0,0 +1,135 @@ +package internal + +import ( + "context" + "database/sql" + "fmt" + "github.com/gogf/gf/v2/errors/gerror" + "time" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +type TdSource struct { + db *sql.DB +} + +func NewTdSource() *TdSource { + db := GetConn(context.Background(), "tdengineSrc") + return &TdSource{db: db} +} + +func (s *TdSource) ShowCreateStable() (stables, createSql []string, err error) { + list, err := s.Stables() + if err != nil || list.Len() == 0 { + return + } + if list == nil { + gerror.New("数据为空") + return + } + + for _, v := range list { + stable := v["stable_name"].String() + sqlStr := "show create stable " + stable + rs, err := s.GetAll(sqlStr) + if err != nil || rs.Len() == 0 { + continue + } + stables = append(stables, stable) + createSql = append(createSql, rs[0]["Create Table"].String()) + } + return +} + +func (s *TdSource) ShowCreateTable() (tables, createSql []string, err error) { + list, err := s.Tables() + if err != nil || list.Len() == 0 { + return + } + if list == nil { + return + } + + for _, v := range list { + table := v["table_name"].String() + sqlStr := "show create table " + table + rs, err := s.GetAll(sqlStr) + if err != nil || rs.Len() == 0 { + continue + } + tables = append(tables, table) + createSql = append(createSql, rs[0]["Create Table"].String()) + } + return +} + +func (s *TdSource) Stables() (rs gdb.Result, err error) { + sqlStr := "show stables" + rs, err = s.GetAll(sqlStr) + return +} + +func (s *TdSource) Tables() (rs gdb.Result, err error) { + sqlStr := "show tables" + rs, err = s.GetAll(sqlStr) + return +} + +func (s *TdSource) Count(table string) (total int, err error) { + sqlStr := "select count(*) as num from " + table + rs, err := s.GetAll(sqlStr) + if err != nil || rs.Len() == 0 { + return + } + total = rs[0]["num"].Int() + return +} + +func (s *TdSource) Data(table string, pageNum, pageSize int) (rs gdb.Result, err error) { + sqlStr := fmt.Sprintf("select * from %s limit %d, %d", table, (pageNum-1)*pageSize, pageSize) + rs, err = s.GetAll(sqlStr) + return +} + +// 超级表查询,多条数据 +func (s *TdSource) GetAll(sql string, args ...any) (rs gdb.Result, err error) { + rows, err := s.db.Query(sql, args...) + if err != nil { + return + } + defer rows.Close() + + columns, _ := rows.Columns() + + for rows.Next() { + values := make([]any, len(columns)) + for i := range values { + values[i] = new(any) + } + + err = rows.Scan(values...) + if err != nil { + return nil, err + } + + m := make(gdb.Record, len(columns)) + for i, c := range columns { + m[c] = s.Time(gvar.New(values[i])) + } + rs = append(rs, m) + } + return +} + +// REST连接时区处理 +func (s *TdSource) Time(v *g.Var) (rs *g.Var) { + if t, err := time.Parse("2006-01-02 15:04:05 +0000 UTC", v.String()); err == nil { + rs = gvar.New(t.Local().Format("2006-01-02 15:04:05")) + } else { + rs = v + } + return +} diff --git a/tools/migration/main.go b/tools/migration/main.go new file mode 100644 index 0000000..873c976 --- /dev/null +++ b/tools/migration/main.go @@ -0,0 +1,21 @@ +package main + +import ( + itl "github.com/sagoo-cloud/sagooiot/tools/migration/internal" +) + +func main() { + td := itl.NewTdDestination() + + if err := td.CreateStables(); err != nil { + panic(err) + } + + if err := td.CreateTables(); err != nil { + panic(err) + } + + if err := td.InsertData(); err != nil { + panic(err) + } +} diff --git a/tools/migration/tdengine.yaml b/tools/migration/tdengine.yaml new file mode 100644 index 0000000..e625b21 --- /dev/null +++ b/tools/migration/tdengine.yaml @@ -0,0 +1,15 @@ +# TDengine配置 +tdengineSrc: + type: "taosRestful" #http连接方式,端口是6041 + dsn: "zhgy_iot:adsafdsfa@http(101.200.200.249:6041)/" + dbName: "sagoo_iot" + +# tdengineSrc: +# type: "taosRestful" #http连接方式,端口是6041 +# dsn: "root:taosdata@http(127.0.0.1:6041)/" +# dbName: "sagoo_iot" + +tdengineDest: + type: "taosRestful" #http连接方式,端口是6041 + dsn: "root:taosdata@http(127.0.0.1:6041)/" + dbName: "sagoo_iot" \ No newline at end of file diff --git a/utility/cron/cron.go b/utility/cron/cron.go new file mode 100644 index 0000000..dc4c150 --- /dev/null +++ b/utility/cron/cron.go @@ -0,0 +1,39 @@ +package cron + +import ( + "errors" + "github.com/robfig/cron/v3" +) + +var secondParser = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.DowOptional | cron.Descriptor) + +// ParseSpec 尝试转换定时任务表达式 +func ParseSpec(spec string) (err error) { + defer func() { + if r := recover(); r != nil { + switch x := r.(type) { + case string: + err = errors.New(x) + case error: + err = x + default: + err = errors.New("发生未知panic") + } + } + }() + _, err = secondParser.Parse(spec) + return +} + +// IsValidSpec 校验spec表达式是否合法 +func IsValidSpec(spec string) (valid bool, err error) { + err = ParseSpec(spec) + if err == nil { + //log.Infof("定时任务表达式(%+v)合法", spec) + valid = true + } else { + //log.Errorf("定时任务表达式(%+v)非法", spec) + valid = false + } + return +} diff --git a/utility/cron/cron_test.go b/utility/cron/cron_test.go new file mode 100644 index 0000000..608613a --- /dev/null +++ b/utility/cron/cron_test.go @@ -0,0 +1,27 @@ +package cron + +import ( + "fmt" + "strings" + "testing" +) + +func TestIsValidSpec(t *testing.T) { + var tests = []struct{ expr, err string }{ + {"* 5 j * * *", "failed to parse int from"}, + {"@every Xm", "failed to parse duration"}, + {"@unrecognized", "unrecognized descriptor"}, + {"* * * *", "expected 5 to 6 fields"}, + {"", "empty spec string"}, + } + for _, c := range tests { + actual, err := IsValidSpec(c.expr) + if err == nil || !strings.Contains(err.Error(), c.err) { + t.Errorf("%s => expected %v, got %v", c.expr, c.err, err) + } + fmt.Println(actual) + if !actual { + fmt.Println(err.Error()) + } + } +} diff --git a/utility/excel.go b/utility/excel.go new file mode 100644 index 0000000..9778fe4 --- /dev/null +++ b/utility/excel.go @@ -0,0 +1,115 @@ +package utility + +import ( + "bytes" + "context" + "github.com/gogf/gf/v2/frame/g" + "github.com/tealeg/xlsx" + "io" + "log" + "os" + "path/filepath" + "reflect" + "strconv" + "time" +) + +//ToExcel 生成io.ReadSeeker 参数 titleList 为Excel表头,dataList 为数据 +func ToExcel(dataList []interface{}) (content io.ReadSeeker) { + // 生成一个新的文件 + file := xlsx.NewFile() + // 添加sheet页 + sheet, _ := file.AddSheet("Sheet1") + // 插入表头 + titleRow := sheet.AddRow() + + //获取表头 + objType := reflect.TypeOf(dataList[0]) + elem := objType.Elem() + var titleList []string + if elem.Kind() == reflect.Struct { + for i := 1; i <= elem.NumField(); i++ { + field := elem.Field(i - 1) + if field.Name != "PageReq" { + titleList = append(titleList, g.I18n().T(context.TODO(), field.Name)) + } + } + } + + for _, v := range titleList { + cell := titleRow.AddCell() + cell.Value = v + //表头字体颜色 + cell.GetStyle().Font.Color = "000000" + cell.GetStyle().Fill.BgColor = "cfe2f3" + //居中显示 + cell.GetStyle().Alignment.Horizontal = "center" + cell.GetStyle().Alignment.Vertical = "center" + } + // 插入内容 + for _, v := range dataList { + row := sheet.AddRow() + row.WriteStruct(v, -1) + } + + var buffer bytes.Buffer + _ = file.Write(&buffer) + content = bytes.NewReader(buffer.Bytes()) + return +} + +func DownloadExcel(titleList []string, dataList []interface{}, filename ...string) (string, error) { + curDir, err := os.Getwd() + + if err != nil { + return "", err + } + var fileName string + if len(filename) > 0 && filename[0] != "" { + fileName = filename[0] + } else { + curdate := time.Now().UnixNano() + fileName = strconv.FormatInt(curdate, 10) + ".xls" + } + filePath := curDir + "/public/upload/" + fileName + + err = CreateFilePath(filePath) + if err != nil { + log.Printf("%s", err.Error()) + return "", err + } + + // 生成一个新的文件 + file := xlsx.NewFile() + // 添加sheet页 + sheet, _ := file.AddSheet("Sheet1") + // 插入表头 + titleRow := sheet.AddRow() + for _, v := range titleList { + cell := titleRow.AddCell() + cell.Value = v + } + // 插入内容 + for _, v := range dataList { + row := sheet.AddRow() + row.WriteStruct(v, -1) + } + + // 在提供的路径中将文件保存到xlsx文件 + err = file.Save(filePath) + if err != nil { + return "", err + } + return fileName, nil +} + +//CreateFilePath 创建路径 +func CreateFilePath(filePath string) error { + // 路径不存在创建路径 + path, _ := filepath.Split(filePath) // 获取路径 + _, err := os.Stat(path) // 检查路径状态,不存在创建 + if err != nil || os.IsExist(err) { + err = os.MkdirAll(path, os.ModePerm) + } + return err +} diff --git a/utility/jobTask/job_task.go b/utility/jobTask/job_task.go new file mode 100644 index 0000000..d3c6942 --- /dev/null +++ b/utility/jobTask/job_task.go @@ -0,0 +1,54 @@ +package jobTask + +import ( + "context" + "github.com/gogf/gf/v2/os/gmutex" +) + +var TimeTaskList = &taskList{ + mu: gmutex.New(), +} + +type TimeTask struct { + FuncName string + Param []string + Run func(ctx context.Context) +} + +type taskList struct { + taskList []*TimeTask + mu *gmutex.Mutex +} + +// AddTask 添加任务 +func (s *taskList) AddTask(task *TimeTask) *taskList { + if task.FuncName == "" || task.Run == nil { + return s + } + s.taskList = append(s.taskList, task) + return s +} + +// GetByName 通过方法名获取对应task信息 +func (s *taskList) GetByName(funcName string) *TimeTask { + var result *TimeTask + for _, item := range s.taskList { + if item.FuncName == funcName { + result = item + break + } + } + return result +} + +// EditParams 修改参数 +func (s *taskList) EditParams(funcName string, params []string) { + s.mu.Lock() + defer s.mu.Unlock() + for _, item := range s.taskList { + if item.FuncName == funcName { + item.Param = params + break + } + } +} diff --git a/utility/liberr/err.go b/utility/liberr/err.go new file mode 100644 index 0000000..55dff56 --- /dev/null +++ b/utility/liberr/err.go @@ -0,0 +1,27 @@ +/* +* @desc:错误处理 + */ + +package liberr + +import ( + "context" + "github.com/gogf/gf/v2/frame/g" +) + +func ErrIsNil(ctx context.Context, err error, msg ...string) { + if !g.IsNil(err) { + if len(msg) > 0 { + g.Log().Error(ctx, err.Error()) + panic(msg[0]) + } else { + panic(err.Error()) + } + } +} + +func ValueIsNil(value interface{}, msg string) { + if g.IsNil(value) { + panic(msg) + } +} diff --git a/utility/notifier/notifier.go b/utility/notifier/notifier.go new file mode 100644 index 0000000..251ea3c --- /dev/null +++ b/utility/notifier/notifier.go @@ -0,0 +1,127 @@ +package notifier + +import ( + "time" +) + +type State struct { + sentAt *time.Time + lastRemindedAt *time.Time +} + +// LastRemindedAt 获取上一次提醒的时间 +func (p *State) LastRemindedAt() time.Time { + return *p.lastRemindedAt +} + +// SentAt 获取首次触发的时间 +func (p *State) SentAt() time.Time { + return *p.sentAt +} + +// FromSentAt 获取首次触发到现在的时间间隔 +func (p *State) FromSentAt() time.Duration { + if p.sentAt == nil { + return 0 + } + return time.Since(*p.sentAt) +} + +// FromLastRemindedAt 获取上次提醒到现在的时间间隔 +func (p *State) FromLastRemindedAt() time.Duration { + if p.lastRemindedAt == nil { + return 0 + } + return time.Since(*p.lastRemindedAt) +} + +type Callback func(state State) + +func NewNotifier(remindDuration time.Duration) *Notifier { + return &Notifier{ + RemindDuration: remindDuration, + } +} + +// Notifier 监控通知器 +type Notifier struct { + RemindDuration time.Duration // 提醒周期,在此时间段内,将不会触发提醒 + state *State + alertCallback Callback + remindCallback Callback + repairCallback Callback + initialed bool +} + +// SetCallbacks 设置通知器的触发回调函数,在里面实现告警、提醒、修复的消息触发 +func (p *Notifier) SetCallbacks(alert, remind, repair Callback) { + p.alertCallback = alert + p.remindCallback = remind + p.repairCallback = repair +} + +// Trigger 是否触发报警,内部重置状态 +func (p *Notifier) Trigger(trigger bool) { + if trigger { + if p.empty() { + if p.alertCallback != nil { + p.alertCallback(*p.getState()) + } + p.sent() + } else if p.remind() { + if p.remindCallback != nil { + p.remindCallback(*p.getState()) + } + } + } else if !p.empty() { + if p.repairCallback != nil { + p.repairCallback(*p.getState()) + } + p.clear() + } +} + +func (p *Notifier) getState() *State { + if p.state == nil { + p.state = &State{} + } + return p.state +} + +// 标记通知已发送状态 +func (p *Notifier) sent() { + now := time.Now() + p.getState().sentAt = &now +} + +// 判断通知器是否为空状态(未触发过的状态) +func (p *Notifier) empty() bool { + return p.getState().sentAt == nil +} + +// 重置通知器状态 +func (p *Notifier) clear() { + p.getState().sentAt = nil + p.getState().lastRemindedAt = nil +} + +// 获取是否到达发送提醒的时间点 +// 获取再次触发后,静默周期将从头计算。 +// 后续的触发动作有必要保证触发成功,否则将在下个周期获得重新触发的机会 +func (p *Notifier) remind() bool { + if p.getState().sentAt == nil { + return false + } + if p.getState().lastRemindedAt == nil { + p.getState().lastRemindedAt = p.getState().sentAt + } + if p.RemindDuration == 0 || p.getState().lastRemindedAt == nil { + return false + } + if uint64(time.Since(*p.getState().lastRemindedAt)) > uint64(p.RemindDuration) { + now := time.Now() + p.getState().lastRemindedAt = &now + return true + } + return false +} diff --git a/utility/notifier/notifier_test.go b/utility/notifier/notifier_test.go new file mode 100644 index 0000000..2d52fa1 --- /dev/null +++ b/utility/notifier/notifier_test.go @@ -0,0 +1,36 @@ +package notifier + +import ( + "testing" + "time" +) + +func TestNewTimer(t *testing.T) { + notifier := NewNotifier(3 * time.Second) + notifier.SetCallbacks( + func(state State) { + t.Log("告警了") + }, + func(state State) { + t.Log("提醒了") + }, + func(state State) { + t.Log("修复了") + }) + i := 0 + for { + i++ + t.Logf("第 %d 秒", i) + if i == 6 || i == 12 { + notifier.Trigger(true) + } + if i == 9 || i == 15 { + notifier.Trigger(false) + } + + time.Sleep(1 * time.Second) + if i > 20 { + break + } + } +} diff --git a/utility/notifier/sysenv/sysenv.go b/utility/notifier/sysenv/sysenv.go new file mode 100644 index 0000000..3521f63 --- /dev/null +++ b/utility/notifier/sysenv/sysenv.go @@ -0,0 +1,110 @@ +package sysenv + +import ( + "encoding/json" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/host" + "github.com/shirou/gopsutil/v3/load" + "github.com/shirou/gopsutil/v3/mem" + "github.com/shirou/gopsutil/v3/net" + "runtime" + "time" +) + +//GetHostInfo 获取主机信息 +func GetHostInfo() (data []byte) { + hostInfo, _ := host.Info() + timestamp, _ := host.BootTime() + t := time.Unix(int64(timestamp), 0) + tmpData := gconv.Map(hostInfo) + tmpData["bootTime"] = t + data = gconv.Bytes(tmpData) + return +} + +//GetSysLoad 获取系统负载信息 +func GetSysLoad() (data []byte) { + loadInfo, _ := load.Avg() + data = gconv.Bytes(g.Map{ + "load1": loadInfo.Load1, + "load5": loadInfo.Load5, + "load15": loadInfo.Load15, + }) + return +} + +type CpuInfo struct { + Number int //cup个数 + Cores int32 //核数 + UsedPercent []float64 //cpu使用率 +} + +//GetCpuInfo 获取CPU信息 +func GetCpuInfo() (data []byte) { + var CpuInfoData CpuInfo + cpus, _ := cpu.Info() + for _, c := range cpus { + CpuInfoData.Cores = CpuInfoData.Cores + c.Cores + } + CpuInfoData.Number = len(cpus) + percent, _ := cpu.Percent(time.Second, false) //获取CPU使用率 + CpuInfoData.UsedPercent = percent + data, _ = json.Marshal(CpuInfoData) + return +} + +//GetMemInfo 获取内存信息 +func GetMemInfo() (data []byte) { + hostInfo, _ := mem.VirtualMemory() + tmpData := gconv.Map(hostInfo) + var gomem runtime.MemStats + runtime.ReadMemStats(&gomem) + tmpData["goUsed"] = gomem.Sys + + data, _ = json.Marshal(tmpData) + return +} + +//GetDiskInfo 获取磁盘信息 +func GetDiskInfo() (data []byte) { + //diskPart, _ := disk.Partitions(false) + //for _, dp := range diskPart { + // fmt.Println(dp) + // diskUsed, _ := disk.Usage(dp.Mountpoint) + // fmt.Printf("分区总大小: %d MB \n", diskUsed.Total/1024/1024) + // fmt.Printf("分区使用率: %.3f %% \n", diskUsed.UsedPercent) + // fmt.Printf("分区inode使用率: %.3f %% \n", diskUsed.InodesUsedPercent) + //} + diskUsed, _ := disk.Usage("/") + data = gconv.Bytes(diskUsed) + return +} + +// NetWorkInfo 网速信息 +type NetWorkInfo struct { + Name string + Receive uint64 + Sent uint64 + ReceiveSpeed uint64 + SentSpeed uint64 +} + +//GetNetStatusInfo 获取网络信息 +func GetNetStatusInfo() (data []byte) { + IOCountersStat, _ := net.IOCounters(true) + netWorkInfo := make([]NetWorkInfo, len(IOCountersStat)) + for i, n := range IOCountersStat { + netWorkInfo[i].Name = n.Name + netWorkInfo[i].Receive = n.BytesRecv + netWorkInfo[i].Sent = n.BytesSent + if netWorkInfo != nil && len(netWorkInfo) > i { + netWorkInfo[i].ReceiveSpeed = n.BytesRecv - netWorkInfo[i].Receive + netWorkInfo[i].SentSpeed = n.BytesSent - netWorkInfo[i].Sent + } + } + data, _ = json.Marshal(netWorkInfo) + return +} diff --git a/utility/notifier/sysenv_enevt.go b/utility/notifier/sysenv_enevt.go new file mode 100644 index 0000000..5e7b0d1 --- /dev/null +++ b/utility/notifier/sysenv_enevt.go @@ -0,0 +1,56 @@ +package notifier + +import ( + "github.com/gogf/gf/v2/net/ghttp" + "github.com/sagoo-cloud/sagooiot/utility/notifier/sysenv" + "github.com/xinjiayu/sse" + "time" +) + +func SysenvMessageEvent(r *ghttp.Request) { + + sseServer := sseserver.NewServer() + go func() { + for { + hostMsg := sseserver.SSEMessage{} + hostMsg.Event = "host" + hostMsg.Data = sysenv.GetHostInfo() + hostMsg.Namespace = "/sysenv/host" + sseServer.Broadcast <- hostMsg + + sysLoadMsg := sseserver.SSEMessage{} + sysLoadMsg.Event = "sysLoad" + sysLoadMsg.Data = sysenv.GetSysLoad() + sysLoadMsg.Namespace = "/sysenv/sysLoad" + sseServer.Broadcast <- sysLoadMsg + + cpuMsg := sseserver.SSEMessage{} + cpuMsg.Event = "cpu" + cpuMsg.Data = sysenv.GetCpuInfo() + cpuMsg.Namespace = "/sysenv/cpu" + sseServer.Broadcast <- cpuMsg + + memMsg := sseserver.SSEMessage{} + memMsg.Event = "mem" + memMsg.Data = sysenv.GetMemInfo() + memMsg.Namespace = "/sysenv/mem" + sseServer.Broadcast <- memMsg + + diskMsg := sseserver.SSEMessage{} + diskMsg.Event = "disk" + diskMsg.Data = sysenv.GetDiskInfo() + diskMsg.Namespace = "/sysenv/disk" + sseServer.Broadcast <- diskMsg + + netMsg := sseserver.SSEMessage{} + netMsg.Event = "net" + netMsg.Data = sysenv.GetNetStatusInfo() + netMsg.Namespace = "/sysenv/net" + sseServer.Broadcast <- netMsg + + time.Sleep(time.Duration(2) * time.Second) + } + }() + sseServer.ServeHTTP(r.Response.RawWriter(), r.Request) + +} diff --git a/utility/notifier/sysenv_html_test.html b/utility/notifier/sysenv_html_test.html new file mode 100644 index 0000000..f9e577a --- /dev/null +++ b/utility/notifier/sysenv_html_test.html @@ -0,0 +1,54 @@ + +
+ + +