From b811ad8bf57dda67e77a3c7213450d80b21b6e9d Mon Sep 17 00:00:00 2001
From: microrain
Date: Sun, 1 Jan 2023 17:10:14 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitattributes | 1 +
.gitignore | 25 +
Makefile | 67 ++
README.MD | 193 +++++
README.md | 2 -
api/v1/alarm/alarm_level.go | 20 +
api/v1/alarm/alarm_log.go | 29 +
api/v1/alarm/alarm_rule.go | 76 ++
api/v1/common/api.go | 14 +
api/v1/common/base_db_link.go | 66 ++
api/v1/common/city_data.go | 45 ++
api/v1/common/config_data.go | 63 ++
api/v1/common/dict_data.go | 88 +++
api/v1/common/dict_type.go | 61 ++
api/v1/common/notice.go | 23 +
api/v1/common/sysinfo.go | 17 +
api/v1/common/upload.go | 34 +
api/v1/envirotronics/env_weather.go | 46 ++
api/v1/network/server.go | 74 ++
api/v1/network/tunnel.go | 77 ++
api/v1/notice/config.go | 59 ++
api/v1/notice/info.go | 88 +++
api/v1/notice/log.go | 21 +
api/v1/notice/template.go | 95 +++
api/v1/product/category.go | 44 ++
api/v1/product/device.go | 120 +++
api/v1/product/device_log.go | 22 +
api/v1/product/device_tag.go | 25 +
api/v1/product/product.go | 77 ++
api/v1/product/protocol.go | 23 +
api/v1/product/tsl.go | 136 ++++
api/v1/source/node.go | 33 +
api/v1/source/source.go | 83 ++
api/v1/source/source_db.go | 35 +
api/v1/source/source_device.go | 27 +
api/v1/source/template.go | 97 +++
api/v1/source/template_node.go | 33 +
api/v1/system/captcha.go | 14 +
api/v1/system/login.go | 24 +
api/v1/system/sys_api.go | 79 ++
api/v1/system/sys_authorize.go | 34 +
api/v1/system/sys_dept.go | 60 ++
api/v1/system/sys_job.go | 89 +++
api/v1/system/sys_login_log.go | 53 ++
api/v1/system/sys_menu.go | 210 +++++
api/v1/system/sys_monitor.go | 9 +
api/v1/system/sys_notifications.go | 58 ++
api/v1/system/sys_oper_log.go | 53 ++
api/v1/system/sys_organization.go | 65 ++
api/v1/system/sys_plugins.go | 40 +
api/v1/system/sys_plugins_config.go | 81 ++
api/v1/system/sys_post.go | 55 ++
api/v1/system/sys_role.go | 74 ++
api/v1/system/sys_user.go | 133 ++++
api/v1/system/sys_user_online.go | 23 +
api/v1/tdengine/td_engine.go | 43 ++
api/v1/websocket/websocket.go | 19 +
build.sh | 91 +++
curl.sh | 103 +++
extend/extend.go | 133 ++++
extend/manager.go | 159 ++++
extend/model/base.go | 14 +
extend/model/info.go | 9 +
extend/model/notice.go | 26 +
extend/module/module.go | 24 +
extend/module/notice.go | 63 ++
extend/module/protocol.go | 87 +++
extend/sdk/sdk.go | 29 +
go.mod | 90 +++
go.sum | 397 ++++++++++
internal/cmd/cmd.go | 116 +++
internal/cmd/router/business.go | 20 +
internal/cmd/router/system.go | 138 ++++
internal/consts/cache.go | 27 +
internal/consts/config.go | 5 +
internal/consts/consts.go | 76 ++
internal/consts/content.go | 13 +
internal/consts/device.go | 7 +
internal/consts/energy.go | 7 +
internal/consts/interact.go | 8 +
internal/consts/openapi.go | 13 +
internal/consts/session.go | 8 +
internal/consts/topic.go | 123 +++
internal/consts/tsl_type.go | 14 +
internal/consts/upload.go | 18 +
internal/consts/user.go | 10 +
internal/controller/alarm/alarm_level.go | 26 +
internal/controller/alarm/alarm_log.go | 34 +
internal/controller/alarm/alarm_rule.go | 84 ++
internal/controller/common/base_db_link.go | 80 ++
internal/controller/common/city_data.go | 127 +++
internal/controller/common/config_data.go | 78 ++
internal/controller/common/dict_data.go | 97 +++
internal/controller/common/dict_type.go | 78 ++
internal/controller/common/sysinfo.go | 60 ++
internal/controller/common/upload.go | 87 +++
.../controller/envirotronics/env_weather.go | 128 ++++
internal/controller/network/server.go | 81 ++
internal/controller/network/tunnel.go | 86 +++
internal/controller/notice/Log.go | 26 +
internal/controller/notice/config.go | 64 ++
internal/controller/notice/info.go | 67 ++
internal/controller/notice/template.go | 92 +++
internal/controller/product/category.go | 44 ++
internal/controller/product/device.go | 119 +++
internal/controller/product/device_log.go | 27 +
internal/controller/product/device_tag.go | 26 +
internal/controller/product/product.go | 92 +++
internal/controller/product/protocol.go | 35 +
internal/controller/product/tsl_data_type.go | 17 +
internal/controller/product/tsl_event.go | 34 +
internal/controller/product/tsl_function.go | 34 +
internal/controller/product/tsl_property.go | 42 +
internal/controller/product/tsl_tag.go | 34 +
internal/controller/source/node.go | 38 +
internal/controller/source/source.go | 94 +++
internal/controller/source/source_db.go | 33 +
internal/controller/source/source_device.go | 26 +
internal/controller/source/template.go | 99 +++
internal/controller/source/template_node.go | 38 +
internal/controller/system/captcha.go | 26 +
internal/controller/system/login.go | 39 +
internal/controller/system/sys_api.go | 99 +++
internal/controller/system/sys_authorize.go | 49 ++
internal/controller/system/sys_dept.go | 75 ++
internal/controller/system/sys_job.go | 126 +++
internal/controller/system/sys_login_log.go | 88 +++
internal/controller/system/sys_menu.go | 271 +++++++
internal/controller/system/sys_monitor.go | 150 ++++
.../controller/system/sys_notifications.go | 68 ++
internal/controller/system/sys_oper_log.go | 69 ++
.../controller/system/sys_organization.go | 87 +++
internal/controller/system/sys_plugins.go | 41 +
.../controller/system/sys_plugins_config.go | 83 ++
internal/controller/system/sys_post.go | 75 ++
internal/controller/system/sys_role.go | 111 +++
internal/controller/system/sys_user.go | 150 ++++
internal/controller/system/sys_user_online.go | 44 ++
internal/controller/tdengine/td_engine.go | 55 ++
internal/dao/alarm_level.go | 27 +
internal/dao/alarm_log.go | 27 +
internal/dao/alarm_rule.go | 27 +
internal/dao/base_db_link.go | 27 +
internal/dao/city_data.go | 27 +
internal/dao/data_node.go | 27 +
internal/dao/data_source.go | 27 +
internal/dao/data_template.go | 27 +
internal/dao/data_template_busi.go | 27 +
internal/dao/data_template_node.go | 27 +
internal/dao/dev_device.go | 27 +
internal/dao/dev_device_tag.go | 27 +
internal/dao/dev_product.go | 27 +
internal/dao/dev_product_category.go | 27 +
internal/dao/internal/alarm_level.go | 75 ++
internal/dao/internal/alarm_log.go | 97 +++
internal/dao/internal/alarm_rule.go | 101 +++
internal/dao/internal/base_db_link.go | 103 +++
internal/dao/internal/city_data.go | 97 +++
internal/dao/internal/data_node.go | 99 +++
internal/dao/internal/data_source.go | 103 +++
internal/dao/internal/data_template.go | 107 +++
internal/dao/internal/data_template_busi.go | 87 +++
internal/dao/internal/data_template_node.go | 107 +++
internal/dao/internal/dev_device.go | 109 +++
internal/dao/internal/dev_device_tag.go | 95 +++
internal/dao/internal/dev_product.go | 111 +++
internal/dao/internal/dev_product_category.go | 93 +++
internal/dao/internal/network_server.go | 97 +++
internal/dao/internal/network_tunnel.go | 103 +++
internal/dao/internal/notice_config.go | 81 ++
internal/dao/internal/notice_info.go | 99 +++
internal/dao/internal/notice_log.go | 89 +++
internal/dao/internal/notice_template.go | 85 ++
internal/dao/internal/sys_api.go | 103 +++
internal/dao/internal/sys_authorize.go | 91 +++
internal/dao/internal/sys_config.go | 99 +++
internal/dao/internal/sys_dept.go | 105 +++
internal/dao/internal/sys_dict_data.go | 105 +++
internal/dao/internal/sys_dict_type.go | 99 +++
internal/dao/internal/sys_job.go | 101 +++
internal/dao/internal/sys_login_log.go | 91 +++
internal/dao/internal/sys_menu.go | 127 +++
internal/dao/internal/sys_menu_api.go | 87 +++
internal/dao/internal/sys_menu_button.go | 99 +++
internal/dao/internal/sys_menu_column.go | 99 +++
internal/dao/internal/sys_notifications.go | 85 ++
internal/dao/internal/sys_oper_log.go | 103 +++
internal/dao/internal/sys_organization.go | 105 +++
internal/dao/internal/sys_plugins.go | 89 +++
internal/dao/internal/sys_plugins_config.go | 81 ++
internal/dao/internal/sys_post.go | 99 +++
internal/dao/internal/sys_role.go | 99 +++
internal/dao/internal/sys_role_dept.go | 75 ++
internal/dao/internal/sys_user.go | 123 +++
internal/dao/internal/sys_user_online.go | 89 +++
internal/dao/internal/sys_user_post.go | 75 ++
internal/dao/internal/sys_user_role.go | 75 ++
internal/dao/network_server.go | 27 +
internal/dao/network_tunnel.go | 27 +
internal/dao/notice_config.go | 27 +
internal/dao/notice_info.go | 27 +
internal/dao/notice_log.go | 27 +
internal/dao/notice_template.go | 27 +
internal/dao/sys_api.go | 27 +
internal/dao/sys_authorize.go | 27 +
internal/dao/sys_config.go | 27 +
internal/dao/sys_dept.go | 27 +
internal/dao/sys_dict_data.go | 27 +
internal/dao/sys_dict_type.go | 27 +
internal/dao/sys_job.go | 27 +
internal/dao/sys_login_log.go | 27 +
internal/dao/sys_menu.go | 27 +
internal/dao/sys_menu_api.go | 27 +
internal/dao/sys_menu_button.go | 27 +
internal/dao/sys_menu_column.go | 27 +
internal/dao/sys_notifications.go | 27 +
internal/dao/sys_oper_log.go | 27 +
internal/dao/sys_organization.go | 27 +
internal/dao/sys_plugins.go | 27 +
internal/dao/sys_plugins_config.go | 27 +
internal/dao/sys_post.go | 27 +
internal/dao/sys_role.go | 27 +
internal/dao/sys_role_dept.go | 27 +
internal/dao/sys_user.go | 27 +
internal/dao/sys_user_online.go | 27 +
internal/dao/sys_user_post.go | 27 +
internal/dao/sys_user_role.go | 27 +
internal/logic/alarm/alarm_level.go | 55 ++
internal/logic/alarm/alarm_log.go | 106 +++
internal/logic/alarm/alarm_log_test.go | 26 +
internal/logic/alarm/alarm_rule.go | 303 ++++++++
internal/logic/alarm/alarm_rule_check.go | 298 +++++++
internal/logic/alarm/alarm_rule_check_test.go | 35 +
internal/logic/common/base_db_link.go | 170 ++++
internal/logic/common/cache.go | 53 ++
internal/logic/common/city_data.go | 178 +++++
internal/logic/common/config_data.go | 165 ++++
internal/logic/common/dict_data.go | 160 ++++
internal/logic/common/dict_type.go | 158 ++++
internal/logic/common/upload.go | 307 ++++++++
internal/logic/context/context.go | 69 ++
internal/logic/datahub/data_node.go | 196 +++++
internal/logic/datahub/data_source.go | 624 +++++++++++++++
internal/logic/datahub/data_source_api.go | 262 +++++++
internal/logic/datahub/data_source_db.go | 495 ++++++++++++
internal/logic/datahub/data_source_device.go | 300 ++++++++
internal/logic/datahub/data_source_record.go | 115 +++
.../logic/datahub/data_source_record_test.go | 19 +
internal/logic/datahub/data_source_test.go | 49 ++
internal/logic/datahub/data_table.go | 180 +++++
internal/logic/datahub/data_table_test.go | 16 +
internal/logic/datahub/data_template.go | 720 +++++++++++++++++
internal/logic/datahub/data_template_busi.go | 81 ++
internal/logic/datahub/data_template_node.go | 209 +++++
.../logic/datahub/data_template_record.go | 230 ++++++
.../datahub/data_template_record_test.go | 16 +
internal/logic/datahub/data_template_table.go | 181 +++++
internal/logic/datahub/data_template_test.go | 76 ++
internal/logic/envirotronics/env_weather.go | 477 ++++++++++++
internal/logic/logic.go | 19 +
internal/logic/middleware/middleware.go | 227 ++++++
internal/logic/network/network_server.go | 140 ++++
internal/logic/network/network_tunnel.go | 170 ++++
internal/logic/notice/notice_config.go | 80 ++
internal/logic/notice/notice_info.go | 89 +++
internal/logic/notice/notice_log.go | 72 ++
internal/logic/notice/notice_template.go | 97 +++
internal/logic/product/dev_category.go | 209 +++++
internal/logic/product/dev_device.go | 654 ++++++++++++++++
internal/logic/product/dev_device_log.go | 57 ++
internal/logic/product/dev_device_tag.go | 79 ++
internal/logic/product/dev_device_test.go | 34 +
internal/logic/product/dev_product.go | 367 +++++++++
internal/logic/product/dev_tsl_data_type.go | 62 ++
internal/logic/product/dev_tsl_event.go | 195 +++++
internal/logic/product/dev_tsl_function.go | 195 +++++
internal/logic/product/dev_tsl_property.go | 301 ++++++++
internal/logic/product/dev_tsl_tag.go | 237 ++++++
internal/logic/system/captcha.go | 50 ++
internal/logic/system/login.go | 137 ++++
internal/logic/system/sys_api.go | 419 ++++++++++
internal/logic/system/sys_authorize.go | 456 +++++++++++
internal/logic/system/sys_authorize_utils.go | 651 ++++++++++++++++
internal/logic/system/sys_dept.go | 323 ++++++++
internal/logic/system/sys_job.go | 284 +++++++
internal/logic/system/sys_login_log.go | 140 ++++
internal/logic/system/sys_menu.go | 252 ++++++
internal/logic/system/sys_menu_api.go | 45 ++
internal/logic/system/sys_menu_button.go | 228 ++++++
internal/logic/system/sys_menu_column.go | 236 ++++++
internal/logic/system/sys_notifications.go | 66 ++
internal/logic/system/sys_oper_log.go | 230 ++++++
internal/logic/system/sys_organization.go | 301 ++++++++
internal/logic/system/sys_plugins.go | 99 +++
internal/logic/system/sys_plugins_config.go | 131 ++++
internal/logic/system/sys_post.go | 226 ++++++
internal/logic/system/sys_role.go | 326 ++++++++
internal/logic/system/sys_role_dept.go | 41 +
internal/logic/system/sys_token.go | 73 ++
internal/logic/system/sys_user.go | 725 ++++++++++++++++++
internal/logic/system/sys_user_online.go | 110 +++
internal/logic/system/sys_user_post.go | 41 +
internal/logic/system/sys_user_role.go | 41 +
internal/logic/tdengine/td_engine.go | 292 +++++++
internal/logic/tdengine/td_log_table.go | 108 +++
internal/logic/tdengine/td_log_table_test.go | 32 +
internal/logic/tdengine/tsl_table.go | 298 +++++++
internal/logic/tdengine/tsl_table_test.go | 71 ++
internal/model/alarm_level.go | 24 +
internal/model/alarm_log.go | 55 ++
internal/model/alarm_rule.go | 110 +++
internal/model/base_db_link.go | 82 ++
internal/model/base_model.go | 14 +
internal/model/city_data.go | 53 ++
internal/model/config_data.go | 53 ++
internal/model/context.go | 23 +
internal/model/data_node.go | 29 +
internal/model/data_source.go | 188 +++++
internal/model/data_template.go | 106 +++
internal/model/data_template_busi.go | 7 +
internal/model/data_template_node.go | 63 ++
internal/model/dev_device.go | 138 ++++
internal/model/dev_device_log.go | 11 +
internal/model/dev_device_tag.go | 15 +
internal/model/dev_product.go | 76 ++
internal/model/dev_product_category.go | 26 +
internal/model/dev_protocol.go | 13 +
internal/model/dev_tsl.go | 114 +++
internal/model/dev_tsl_data_type.go | 242 ++++++
internal/model/dev_tsl_event.go | 22 +
internal/model/dev_tsl_function.go | 22 +
internal/model/dev_tsl_property.go | 24 +
internal/model/dev_tsl_tag.go | 22 +
internal/model/do/alarm_level.go | 16 +
internal/model/do/alarm_log.go | 28 +
internal/model/do/alarm_rule.go | 30 +
internal/model/do/base_db_link.go | 31 +
internal/model/do/city_data.go | 28 +
internal/model/do/data_node.go | 29 +
internal/model/do/data_source.go | 31 +
internal/model/do/data_template.go | 33 +
internal/model/do/data_template_busi.go | 23 +
internal/model/do/data_template_node.go | 33 +
internal/model/do/dev_device.go | 34 +
internal/model/do/dev_device_tag.go | 27 +
internal/model/do/dev_product.go | 35 +
internal/model/do/dev_product_category.go | 26 +
internal/model/do/network_server.go | 28 +
internal/model/do/network_tunnel.go | 31 +
internal/model/do/notice_config.go | 20 +
internal/model/do/notice_info.go | 29 +
internal/model/do/notice_log.go | 24 +
internal/model/do/notice_template.go | 22 +
internal/model/do/sys_api.go | 31 +
internal/model/do/sys_authorize.go | 25 +
internal/model/do/sys_config.go | 29 +
internal/model/do/sys_dept.go | 32 +
internal/model/do/sys_dict_data.go | 32 +
internal/model/do/sys_dict_type.go | 29 +
internal/model/do/sys_job.go | 30 +
internal/model/do/sys_login_log.go | 25 +
internal/model/do/sys_menu.go | 43 ++
internal/model/do/sys_menu_api.go | 23 +
internal/model/do/sys_menu_button.go | 29 +
internal/model/do/sys_menu_column.go | 29 +
internal/model/do/sys_notifications.go | 22 +
internal/model/do/sys_oper_log.go | 31 +
internal/model/do/sys_organization.go | 32 +
internal/model/do/sys_plugins.go | 24 +
internal/model/do/sys_plugins_config.go | 19 +
internal/model/do/sys_post.go | 29 +
internal/model/do/sys_role.go | 29 +
internal/model/do/sys_role_dept.go | 16 +
internal/model/do/sys_user.go | 41 +
internal/model/do/sys_user_online.go | 24 +
internal/model/do/sys_user_post.go | 16 +
internal/model/do/sys_user_role.go | 16 +
internal/model/entity/alarm_level.go | 11 +
internal/model/entity/alarm_log.go | 26 +
internal/model/entity/alarm_rule.go | 28 +
internal/model/entity/base_db_link.go | 29 +
internal/model/entity/city_data.go | 26 +
internal/model/entity/data_node.go | 27 +
internal/model/entity/data_source.go | 29 +
internal/model/entity/data_template.go | 31 +
internal/model/entity/data_template_busi.go | 21 +
internal/model/entity/data_template_node.go | 31 +
internal/model/entity/dev_device.go | 32 +
internal/model/entity/dev_device_tag.go | 25 +
internal/model/entity/dev_product.go | 33 +
internal/model/entity/dev_product_category.go | 24 +
internal/model/entity/gen_table.go | 29 +
internal/model/entity/gen_table_column.go | 41 +
internal/model/entity/network_server.go | 26 +
internal/model/entity/network_tunnel.go | 29 +
internal/model/entity/notice_config.go | 18 +
internal/model/entity/notice_info.go | 27 +
internal/model/entity/notice_log.go | 22 +
internal/model/entity/notice_template.go | 20 +
internal/model/entity/sys_api.go | 29 +
internal/model/entity/sys_authorize.go | 23 +
internal/model/entity/sys_config.go | 27 +
internal/model/entity/sys_dept.go | 30 +
internal/model/entity/sys_dict_data.go | 30 +
internal/model/entity/sys_dict_type.go | 27 +
internal/model/entity/sys_job.go | 28 +
internal/model/entity/sys_login_log.go | 23 +
internal/model/entity/sys_menu.go | 41 +
internal/model/entity/sys_menu_api.go | 21 +
internal/model/entity/sys_menu_button.go | 27 +
internal/model/entity/sys_menu_column.go | 27 +
internal/model/entity/sys_notifications.go | 20 +
internal/model/entity/sys_oper_log.go | 29 +
internal/model/entity/sys_organization.go | 30 +
internal/model/entity/sys_plugins.go | 22 +
internal/model/entity/sys_plugins_config.go | 14 +
internal/model/entity/sys_post.go | 27 +
internal/model/entity/sys_role.go | 27 +
internal/model/entity/sys_role_dept.go | 11 +
internal/model/entity/sys_user.go | 39 +
internal/model/entity/sys_user_online.go | 22 +
internal/model/entity/sys_user_post.go | 11 +
internal/model/entity/sys_user_role.go | 11 +
internal/model/env_weather.go | 39 +
internal/model/network_server.go | 57 ++
internal/model/network_tunnel.go | 65 ++
internal/model/notice_config.go | 28 +
internal/model/notice_info.go | 48 ++
internal/model/notice_log.go | 31 +
internal/model/notice_template.go | 33 +
internal/model/session.go | 7 +
internal/model/statistics_data_overview.go | 23 +
internal/model/sys_api.go | 144 ++++
internal/model/sys_dept.go | 73 ++
internal/model/sys_dict_data.go | 112 +++
internal/model/sys_dict_type.go | 66 ++
internal/model/sys_job.go | 78 ++
internal/model/sys_login_log.go | 43 ++
internal/model/sys_menu.go | 283 +++++++
internal/model/sys_menu_api.go | 17 +
internal/model/sys_menu_button.go | 58 ++
internal/model/sys_menu_column.go | 70 ++
internal/model/sys_notifications.go | 26 +
internal/model/sys_oper_log.go | 58 ++
internal/model/sys_orgainzation.go | 72 ++
internal/model/sys_plugins.go | 31 +
internal/model/sys_post.go | 58 ++
internal/model/sys_role.go | 65 ++
internal/model/sys_token.go | 29 +
internal/model/sys_user.go | 194 +++++
internal/model/sys_user_online.go | 30 +
internal/model/system_plugins_config.go | 32 +
internal/model/td_engine.go | 22 +
internal/model/td_log_table.go | 19 +
internal/mqtt/mqtt.go | 37 +
internal/packed/packed.go | 1 +
internal/service/alarm.go | 80 ++
internal/service/common.go | 142 ++++
internal/service/context.go | 34 +
internal/service/datahub.go | 178 +++++
internal/service/envirotronics.go | 35 +
internal/service/middleware.go | 30 +
internal/service/network.go | 59 ++
internal/service/notice.go | 94 +++
internal/service/product.go | 215 ++++++
internal/service/system.go | 518 +++++++++++++
internal/service/tdengine.go | 87 +++
internal/task/HTTP_Client.go | 26 +
internal/task/bind_function.go | 98 +++
internal/task/cleardata.go | 51 ++
internal/task/data_source.go | 25 +
internal/task/data_template.go | 25 +
internal/task/demo.go | 33 +
internal/task/deviceLog_clear.go | 22 +
internal/webscoket/call.go | 88 +++
internal/webscoket/common/webScoket.go | 15 +
internal/webscoket/model/websocket.go | 7 +
internal/webscoket/privater/handler.go | 136 ++++
internal/webscoket/sys/sys.go | 29 +
main.go | 25 +
manifest/config/config.example.yaml | 102 +++
network/codebin/bytes.go | 300 ++++++++
network/codebin/check.go | 21 +
network/codebin/hex.go | 55 ++
network/core/common.go | 17 +
network/core/connect.go | 1 +
network/core/device-manager.go | 72 ++
network/core/device.go | 117 +++
network/core/mapper.go | 90 +++
network/core/mqtt-databus.go | 70 ++
network/core/mqtt-device-property-report.go | 58 ++
network/core/mqtt-device-router.go | 34 +
network/core/mqtt-device.go | 91 +++
network/core/point.go | 9 +
network/core/poller.go | 55 ++
network/core/product-manager.go | 34 +
network/core/server-common.go | 46 ++
network/core/server-manager.go | 103 +++
network/core/server-tcp-tunnel.go | 58 ++
network/core/server-tcp.go | 149 ++++
network/core/server-udp-tunnel.go | 116 +++
network/core/server-udp.go | 163 ++++
network/core/server.go | 35 +
network/core/tunnel-base.go | 167 ++++
network/core/tunnel-client.go | 135 ++++
network/core/tunnel-common.go | 89 +++
network/core/tunnel-manager.go | 87 +++
network/core/tunnel.go | 35 +
.../core/tunnelinstance/tunnel-instance.go | 26 +
network/events/events.go | 111 +++
network/model/command.go | 18 +
network/model/default.go | 7 +
network/model/device.go | 34 +
network/model/message.go | 177 +++++
network/model/point.go | 24 +
network/model/poller.go | 10 +
network/model/server.go | 34 +
network/model/tunnel.go | 137 ++++
network/model/type.go | 412 ++++++++++
network/network.go | 15 +
network/pkg/cron/cron.go | 70 ++
network/pkg/mqttclient/mqtt.go | 51 ++
plugin_test.go | 124 +++
plugins/Makefile | 23 +
plugins/built/.gitignore | 2 +
plugins/notice/dingding/Makefile | 11 +
plugins/notice/dingding/dingding.go | 86 +++
plugins/notice/dingding/internal/options.go | 26 +
plugins/notice/dingding/internal/send.go | 127 +++
plugins/notice/dingding/readme.MD | 27 +
plugins/notice/mail/Makefile | 11 +
plugins/notice/mail/internal/options.go | 33 +
plugins/notice/mail/internal/send.go | 75 ++
plugins/notice/mail/internal/send_test.go | 27 +
plugins/notice/mail/mail.go | 85 ++
plugins/notice/wework/Makefile | 11 +
plugins/notice/wework/internal/internal.go | 73 ++
plugins/notice/wework/model/sendmessage.go | 32 +
plugins/notice/wework/wework.go | 97 +++
plugins/protocol/tgn52/Makefile | 11 +
plugins/protocol/tgn52/model.go | 18 +
plugins/protocol/tgn52/readme.md | 11 +
plugins/protocol/tgn52/tgn52.go | 82 ++
resource/public/.gitignore | 2 +
tools/migration/internal/td_conn.go | 21 +
tools/migration/internal/td_destination.go | 100 +++
tools/migration/internal/td_source.go | 135 ++++
tools/migration/main.go | 21 +
tools/migration/tdengine.yaml | 15 +
utility/cron/cron.go | 39 +
utility/cron/cron_test.go | 27 +
utility/excel.go | 115 +++
utility/jobTask/job_task.go | 54 ++
utility/liberr/err.go | 27 +
utility/notifier/notifier.go | 127 +++
utility/notifier/notifier_test.go | 36 +
utility/notifier/sysenv/sysenv.go | 110 +++
utility/notifier/sysenv_enevt.go | 56 ++
utility/notifier/sysenv_html_test.html | 54 ++
utility/response/response.go | 71 ++
utility/utils/date_utils.go | 157 ++++
utility/utils/template.go | 23 +
utility/utils/template_test.go | 23 +
utility/utils/utils.go | 180 +++++
utility/utils/utils_test.go | 21 +
utility/version/version.go | 22 +
566 files changed, 44180 insertions(+), 2 deletions(-)
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100644 Makefile
create mode 100644 README.MD
delete mode 100644 README.md
create mode 100644 api/v1/alarm/alarm_level.go
create mode 100644 api/v1/alarm/alarm_log.go
create mode 100644 api/v1/alarm/alarm_rule.go
create mode 100644 api/v1/common/api.go
create mode 100644 api/v1/common/base_db_link.go
create mode 100644 api/v1/common/city_data.go
create mode 100644 api/v1/common/config_data.go
create mode 100644 api/v1/common/dict_data.go
create mode 100644 api/v1/common/dict_type.go
create mode 100644 api/v1/common/notice.go
create mode 100644 api/v1/common/sysinfo.go
create mode 100644 api/v1/common/upload.go
create mode 100644 api/v1/envirotronics/env_weather.go
create mode 100644 api/v1/network/server.go
create mode 100644 api/v1/network/tunnel.go
create mode 100644 api/v1/notice/config.go
create mode 100644 api/v1/notice/info.go
create mode 100644 api/v1/notice/log.go
create mode 100644 api/v1/notice/template.go
create mode 100644 api/v1/product/category.go
create mode 100644 api/v1/product/device.go
create mode 100644 api/v1/product/device_log.go
create mode 100644 api/v1/product/device_tag.go
create mode 100644 api/v1/product/product.go
create mode 100644 api/v1/product/protocol.go
create mode 100644 api/v1/product/tsl.go
create mode 100644 api/v1/source/node.go
create mode 100644 api/v1/source/source.go
create mode 100644 api/v1/source/source_db.go
create mode 100644 api/v1/source/source_device.go
create mode 100644 api/v1/source/template.go
create mode 100644 api/v1/source/template_node.go
create mode 100644 api/v1/system/captcha.go
create mode 100644 api/v1/system/login.go
create mode 100644 api/v1/system/sys_api.go
create mode 100644 api/v1/system/sys_authorize.go
create mode 100644 api/v1/system/sys_dept.go
create mode 100644 api/v1/system/sys_job.go
create mode 100644 api/v1/system/sys_login_log.go
create mode 100644 api/v1/system/sys_menu.go
create mode 100644 api/v1/system/sys_monitor.go
create mode 100644 api/v1/system/sys_notifications.go
create mode 100644 api/v1/system/sys_oper_log.go
create mode 100644 api/v1/system/sys_organization.go
create mode 100644 api/v1/system/sys_plugins.go
create mode 100644 api/v1/system/sys_plugins_config.go
create mode 100644 api/v1/system/sys_post.go
create mode 100644 api/v1/system/sys_role.go
create mode 100644 api/v1/system/sys_user.go
create mode 100644 api/v1/system/sys_user_online.go
create mode 100644 api/v1/tdengine/td_engine.go
create mode 100644 api/v1/websocket/websocket.go
create mode 100755 build.sh
create mode 100755 curl.sh
create mode 100644 extend/extend.go
create mode 100644 extend/manager.go
create mode 100644 extend/model/base.go
create mode 100644 extend/model/info.go
create mode 100644 extend/model/notice.go
create mode 100644 extend/module/module.go
create mode 100644 extend/module/notice.go
create mode 100644 extend/module/protocol.go
create mode 100644 extend/sdk/sdk.go
create mode 100644 go.mod
create mode 100644 go.sum
create mode 100644 internal/cmd/cmd.go
create mode 100644 internal/cmd/router/business.go
create mode 100644 internal/cmd/router/system.go
create mode 100644 internal/consts/cache.go
create mode 100644 internal/consts/config.go
create mode 100644 internal/consts/consts.go
create mode 100644 internal/consts/content.go
create mode 100644 internal/consts/device.go
create mode 100644 internal/consts/energy.go
create mode 100644 internal/consts/interact.go
create mode 100644 internal/consts/openapi.go
create mode 100644 internal/consts/session.go
create mode 100644 internal/consts/topic.go
create mode 100644 internal/consts/tsl_type.go
create mode 100644 internal/consts/upload.go
create mode 100644 internal/consts/user.go
create mode 100644 internal/controller/alarm/alarm_level.go
create mode 100644 internal/controller/alarm/alarm_log.go
create mode 100644 internal/controller/alarm/alarm_rule.go
create mode 100644 internal/controller/common/base_db_link.go
create mode 100644 internal/controller/common/city_data.go
create mode 100644 internal/controller/common/config_data.go
create mode 100644 internal/controller/common/dict_data.go
create mode 100644 internal/controller/common/dict_type.go
create mode 100644 internal/controller/common/sysinfo.go
create mode 100644 internal/controller/common/upload.go
create mode 100644 internal/controller/envirotronics/env_weather.go
create mode 100644 internal/controller/network/server.go
create mode 100644 internal/controller/network/tunnel.go
create mode 100644 internal/controller/notice/Log.go
create mode 100644 internal/controller/notice/config.go
create mode 100644 internal/controller/notice/info.go
create mode 100644 internal/controller/notice/template.go
create mode 100644 internal/controller/product/category.go
create mode 100644 internal/controller/product/device.go
create mode 100644 internal/controller/product/device_log.go
create mode 100644 internal/controller/product/device_tag.go
create mode 100644 internal/controller/product/product.go
create mode 100644 internal/controller/product/protocol.go
create mode 100644 internal/controller/product/tsl_data_type.go
create mode 100644 internal/controller/product/tsl_event.go
create mode 100644 internal/controller/product/tsl_function.go
create mode 100644 internal/controller/product/tsl_property.go
create mode 100644 internal/controller/product/tsl_tag.go
create mode 100644 internal/controller/source/node.go
create mode 100644 internal/controller/source/source.go
create mode 100644 internal/controller/source/source_db.go
create mode 100644 internal/controller/source/source_device.go
create mode 100644 internal/controller/source/template.go
create mode 100644 internal/controller/source/template_node.go
create mode 100644 internal/controller/system/captcha.go
create mode 100644 internal/controller/system/login.go
create mode 100644 internal/controller/system/sys_api.go
create mode 100644 internal/controller/system/sys_authorize.go
create mode 100644 internal/controller/system/sys_dept.go
create mode 100644 internal/controller/system/sys_job.go
create mode 100644 internal/controller/system/sys_login_log.go
create mode 100644 internal/controller/system/sys_menu.go
create mode 100644 internal/controller/system/sys_monitor.go
create mode 100644 internal/controller/system/sys_notifications.go
create mode 100644 internal/controller/system/sys_oper_log.go
create mode 100644 internal/controller/system/sys_organization.go
create mode 100644 internal/controller/system/sys_plugins.go
create mode 100644 internal/controller/system/sys_plugins_config.go
create mode 100644 internal/controller/system/sys_post.go
create mode 100644 internal/controller/system/sys_role.go
create mode 100644 internal/controller/system/sys_user.go
create mode 100644 internal/controller/system/sys_user_online.go
create mode 100644 internal/controller/tdengine/td_engine.go
create mode 100644 internal/dao/alarm_level.go
create mode 100644 internal/dao/alarm_log.go
create mode 100644 internal/dao/alarm_rule.go
create mode 100644 internal/dao/base_db_link.go
create mode 100644 internal/dao/city_data.go
create mode 100644 internal/dao/data_node.go
create mode 100644 internal/dao/data_source.go
create mode 100644 internal/dao/data_template.go
create mode 100644 internal/dao/data_template_busi.go
create mode 100644 internal/dao/data_template_node.go
create mode 100644 internal/dao/dev_device.go
create mode 100644 internal/dao/dev_device_tag.go
create mode 100644 internal/dao/dev_product.go
create mode 100644 internal/dao/dev_product_category.go
create mode 100644 internal/dao/internal/alarm_level.go
create mode 100644 internal/dao/internal/alarm_log.go
create mode 100644 internal/dao/internal/alarm_rule.go
create mode 100644 internal/dao/internal/base_db_link.go
create mode 100644 internal/dao/internal/city_data.go
create mode 100644 internal/dao/internal/data_node.go
create mode 100644 internal/dao/internal/data_source.go
create mode 100644 internal/dao/internal/data_template.go
create mode 100644 internal/dao/internal/data_template_busi.go
create mode 100644 internal/dao/internal/data_template_node.go
create mode 100644 internal/dao/internal/dev_device.go
create mode 100644 internal/dao/internal/dev_device_tag.go
create mode 100644 internal/dao/internal/dev_product.go
create mode 100644 internal/dao/internal/dev_product_category.go
create mode 100644 internal/dao/internal/network_server.go
create mode 100644 internal/dao/internal/network_tunnel.go
create mode 100644 internal/dao/internal/notice_config.go
create mode 100644 internal/dao/internal/notice_info.go
create mode 100644 internal/dao/internal/notice_log.go
create mode 100644 internal/dao/internal/notice_template.go
create mode 100644 internal/dao/internal/sys_api.go
create mode 100644 internal/dao/internal/sys_authorize.go
create mode 100644 internal/dao/internal/sys_config.go
create mode 100644 internal/dao/internal/sys_dept.go
create mode 100644 internal/dao/internal/sys_dict_data.go
create mode 100644 internal/dao/internal/sys_dict_type.go
create mode 100644 internal/dao/internal/sys_job.go
create mode 100644 internal/dao/internal/sys_login_log.go
create mode 100644 internal/dao/internal/sys_menu.go
create mode 100644 internal/dao/internal/sys_menu_api.go
create mode 100644 internal/dao/internal/sys_menu_button.go
create mode 100644 internal/dao/internal/sys_menu_column.go
create mode 100644 internal/dao/internal/sys_notifications.go
create mode 100644 internal/dao/internal/sys_oper_log.go
create mode 100644 internal/dao/internal/sys_organization.go
create mode 100644 internal/dao/internal/sys_plugins.go
create mode 100644 internal/dao/internal/sys_plugins_config.go
create mode 100644 internal/dao/internal/sys_post.go
create mode 100644 internal/dao/internal/sys_role.go
create mode 100644 internal/dao/internal/sys_role_dept.go
create mode 100644 internal/dao/internal/sys_user.go
create mode 100644 internal/dao/internal/sys_user_online.go
create mode 100644 internal/dao/internal/sys_user_post.go
create mode 100644 internal/dao/internal/sys_user_role.go
create mode 100644 internal/dao/network_server.go
create mode 100644 internal/dao/network_tunnel.go
create mode 100644 internal/dao/notice_config.go
create mode 100644 internal/dao/notice_info.go
create mode 100644 internal/dao/notice_log.go
create mode 100644 internal/dao/notice_template.go
create mode 100644 internal/dao/sys_api.go
create mode 100644 internal/dao/sys_authorize.go
create mode 100644 internal/dao/sys_config.go
create mode 100644 internal/dao/sys_dept.go
create mode 100644 internal/dao/sys_dict_data.go
create mode 100644 internal/dao/sys_dict_type.go
create mode 100644 internal/dao/sys_job.go
create mode 100644 internal/dao/sys_login_log.go
create mode 100644 internal/dao/sys_menu.go
create mode 100644 internal/dao/sys_menu_api.go
create mode 100644 internal/dao/sys_menu_button.go
create mode 100644 internal/dao/sys_menu_column.go
create mode 100644 internal/dao/sys_notifications.go
create mode 100644 internal/dao/sys_oper_log.go
create mode 100644 internal/dao/sys_organization.go
create mode 100644 internal/dao/sys_plugins.go
create mode 100644 internal/dao/sys_plugins_config.go
create mode 100644 internal/dao/sys_post.go
create mode 100644 internal/dao/sys_role.go
create mode 100644 internal/dao/sys_role_dept.go
create mode 100644 internal/dao/sys_user.go
create mode 100644 internal/dao/sys_user_online.go
create mode 100644 internal/dao/sys_user_post.go
create mode 100644 internal/dao/sys_user_role.go
create mode 100644 internal/logic/alarm/alarm_level.go
create mode 100644 internal/logic/alarm/alarm_log.go
create mode 100644 internal/logic/alarm/alarm_log_test.go
create mode 100644 internal/logic/alarm/alarm_rule.go
create mode 100644 internal/logic/alarm/alarm_rule_check.go
create mode 100644 internal/logic/alarm/alarm_rule_check_test.go
create mode 100644 internal/logic/common/base_db_link.go
create mode 100644 internal/logic/common/cache.go
create mode 100644 internal/logic/common/city_data.go
create mode 100644 internal/logic/common/config_data.go
create mode 100644 internal/logic/common/dict_data.go
create mode 100644 internal/logic/common/dict_type.go
create mode 100644 internal/logic/common/upload.go
create mode 100644 internal/logic/context/context.go
create mode 100644 internal/logic/datahub/data_node.go
create mode 100644 internal/logic/datahub/data_source.go
create mode 100644 internal/logic/datahub/data_source_api.go
create mode 100644 internal/logic/datahub/data_source_db.go
create mode 100644 internal/logic/datahub/data_source_device.go
create mode 100644 internal/logic/datahub/data_source_record.go
create mode 100644 internal/logic/datahub/data_source_record_test.go
create mode 100644 internal/logic/datahub/data_source_test.go
create mode 100644 internal/logic/datahub/data_table.go
create mode 100644 internal/logic/datahub/data_table_test.go
create mode 100644 internal/logic/datahub/data_template.go
create mode 100644 internal/logic/datahub/data_template_busi.go
create mode 100644 internal/logic/datahub/data_template_node.go
create mode 100644 internal/logic/datahub/data_template_record.go
create mode 100644 internal/logic/datahub/data_template_record_test.go
create mode 100644 internal/logic/datahub/data_template_table.go
create mode 100644 internal/logic/datahub/data_template_test.go
create mode 100644 internal/logic/envirotronics/env_weather.go
create mode 100644 internal/logic/logic.go
create mode 100644 internal/logic/middleware/middleware.go
create mode 100644 internal/logic/network/network_server.go
create mode 100644 internal/logic/network/network_tunnel.go
create mode 100644 internal/logic/notice/notice_config.go
create mode 100644 internal/logic/notice/notice_info.go
create mode 100644 internal/logic/notice/notice_log.go
create mode 100644 internal/logic/notice/notice_template.go
create mode 100644 internal/logic/product/dev_category.go
create mode 100644 internal/logic/product/dev_device.go
create mode 100644 internal/logic/product/dev_device_log.go
create mode 100644 internal/logic/product/dev_device_tag.go
create mode 100644 internal/logic/product/dev_device_test.go
create mode 100644 internal/logic/product/dev_product.go
create mode 100644 internal/logic/product/dev_tsl_data_type.go
create mode 100644 internal/logic/product/dev_tsl_event.go
create mode 100644 internal/logic/product/dev_tsl_function.go
create mode 100644 internal/logic/product/dev_tsl_property.go
create mode 100644 internal/logic/product/dev_tsl_tag.go
create mode 100644 internal/logic/system/captcha.go
create mode 100644 internal/logic/system/login.go
create mode 100644 internal/logic/system/sys_api.go
create mode 100644 internal/logic/system/sys_authorize.go
create mode 100644 internal/logic/system/sys_authorize_utils.go
create mode 100644 internal/logic/system/sys_dept.go
create mode 100644 internal/logic/system/sys_job.go
create mode 100644 internal/logic/system/sys_login_log.go
create mode 100644 internal/logic/system/sys_menu.go
create mode 100644 internal/logic/system/sys_menu_api.go
create mode 100644 internal/logic/system/sys_menu_button.go
create mode 100644 internal/logic/system/sys_menu_column.go
create mode 100644 internal/logic/system/sys_notifications.go
create mode 100644 internal/logic/system/sys_oper_log.go
create mode 100644 internal/logic/system/sys_organization.go
create mode 100644 internal/logic/system/sys_plugins.go
create mode 100644 internal/logic/system/sys_plugins_config.go
create mode 100644 internal/logic/system/sys_post.go
create mode 100644 internal/logic/system/sys_role.go
create mode 100644 internal/logic/system/sys_role_dept.go
create mode 100644 internal/logic/system/sys_token.go
create mode 100644 internal/logic/system/sys_user.go
create mode 100644 internal/logic/system/sys_user_online.go
create mode 100644 internal/logic/system/sys_user_post.go
create mode 100644 internal/logic/system/sys_user_role.go
create mode 100644 internal/logic/tdengine/td_engine.go
create mode 100644 internal/logic/tdengine/td_log_table.go
create mode 100644 internal/logic/tdengine/td_log_table_test.go
create mode 100644 internal/logic/tdengine/tsl_table.go
create mode 100644 internal/logic/tdengine/tsl_table_test.go
create mode 100644 internal/model/alarm_level.go
create mode 100644 internal/model/alarm_log.go
create mode 100644 internal/model/alarm_rule.go
create mode 100644 internal/model/base_db_link.go
create mode 100644 internal/model/base_model.go
create mode 100644 internal/model/city_data.go
create mode 100644 internal/model/config_data.go
create mode 100644 internal/model/context.go
create mode 100644 internal/model/data_node.go
create mode 100644 internal/model/data_source.go
create mode 100644 internal/model/data_template.go
create mode 100644 internal/model/data_template_busi.go
create mode 100644 internal/model/data_template_node.go
create mode 100644 internal/model/dev_device.go
create mode 100644 internal/model/dev_device_log.go
create mode 100644 internal/model/dev_device_tag.go
create mode 100644 internal/model/dev_product.go
create mode 100644 internal/model/dev_product_category.go
create mode 100644 internal/model/dev_protocol.go
create mode 100644 internal/model/dev_tsl.go
create mode 100644 internal/model/dev_tsl_data_type.go
create mode 100644 internal/model/dev_tsl_event.go
create mode 100644 internal/model/dev_tsl_function.go
create mode 100644 internal/model/dev_tsl_property.go
create mode 100644 internal/model/dev_tsl_tag.go
create mode 100644 internal/model/do/alarm_level.go
create mode 100644 internal/model/do/alarm_log.go
create mode 100644 internal/model/do/alarm_rule.go
create mode 100644 internal/model/do/base_db_link.go
create mode 100644 internal/model/do/city_data.go
create mode 100644 internal/model/do/data_node.go
create mode 100644 internal/model/do/data_source.go
create mode 100644 internal/model/do/data_template.go
create mode 100644 internal/model/do/data_template_busi.go
create mode 100644 internal/model/do/data_template_node.go
create mode 100644 internal/model/do/dev_device.go
create mode 100644 internal/model/do/dev_device_tag.go
create mode 100644 internal/model/do/dev_product.go
create mode 100644 internal/model/do/dev_product_category.go
create mode 100644 internal/model/do/network_server.go
create mode 100644 internal/model/do/network_tunnel.go
create mode 100644 internal/model/do/notice_config.go
create mode 100644 internal/model/do/notice_info.go
create mode 100644 internal/model/do/notice_log.go
create mode 100644 internal/model/do/notice_template.go
create mode 100644 internal/model/do/sys_api.go
create mode 100644 internal/model/do/sys_authorize.go
create mode 100644 internal/model/do/sys_config.go
create mode 100644 internal/model/do/sys_dept.go
create mode 100644 internal/model/do/sys_dict_data.go
create mode 100644 internal/model/do/sys_dict_type.go
create mode 100644 internal/model/do/sys_job.go
create mode 100644 internal/model/do/sys_login_log.go
create mode 100644 internal/model/do/sys_menu.go
create mode 100644 internal/model/do/sys_menu_api.go
create mode 100644 internal/model/do/sys_menu_button.go
create mode 100644 internal/model/do/sys_menu_column.go
create mode 100644 internal/model/do/sys_notifications.go
create mode 100644 internal/model/do/sys_oper_log.go
create mode 100644 internal/model/do/sys_organization.go
create mode 100644 internal/model/do/sys_plugins.go
create mode 100644 internal/model/do/sys_plugins_config.go
create mode 100644 internal/model/do/sys_post.go
create mode 100644 internal/model/do/sys_role.go
create mode 100644 internal/model/do/sys_role_dept.go
create mode 100644 internal/model/do/sys_user.go
create mode 100644 internal/model/do/sys_user_online.go
create mode 100644 internal/model/do/sys_user_post.go
create mode 100644 internal/model/do/sys_user_role.go
create mode 100644 internal/model/entity/alarm_level.go
create mode 100644 internal/model/entity/alarm_log.go
create mode 100644 internal/model/entity/alarm_rule.go
create mode 100644 internal/model/entity/base_db_link.go
create mode 100644 internal/model/entity/city_data.go
create mode 100644 internal/model/entity/data_node.go
create mode 100644 internal/model/entity/data_source.go
create mode 100644 internal/model/entity/data_template.go
create mode 100644 internal/model/entity/data_template_busi.go
create mode 100644 internal/model/entity/data_template_node.go
create mode 100644 internal/model/entity/dev_device.go
create mode 100644 internal/model/entity/dev_device_tag.go
create mode 100644 internal/model/entity/dev_product.go
create mode 100644 internal/model/entity/dev_product_category.go
create mode 100644 internal/model/entity/gen_table.go
create mode 100644 internal/model/entity/gen_table_column.go
create mode 100644 internal/model/entity/network_server.go
create mode 100644 internal/model/entity/network_tunnel.go
create mode 100644 internal/model/entity/notice_config.go
create mode 100644 internal/model/entity/notice_info.go
create mode 100644 internal/model/entity/notice_log.go
create mode 100644 internal/model/entity/notice_template.go
create mode 100644 internal/model/entity/sys_api.go
create mode 100644 internal/model/entity/sys_authorize.go
create mode 100644 internal/model/entity/sys_config.go
create mode 100644 internal/model/entity/sys_dept.go
create mode 100644 internal/model/entity/sys_dict_data.go
create mode 100644 internal/model/entity/sys_dict_type.go
create mode 100644 internal/model/entity/sys_job.go
create mode 100644 internal/model/entity/sys_login_log.go
create mode 100644 internal/model/entity/sys_menu.go
create mode 100644 internal/model/entity/sys_menu_api.go
create mode 100644 internal/model/entity/sys_menu_button.go
create mode 100644 internal/model/entity/sys_menu_column.go
create mode 100644 internal/model/entity/sys_notifications.go
create mode 100644 internal/model/entity/sys_oper_log.go
create mode 100644 internal/model/entity/sys_organization.go
create mode 100644 internal/model/entity/sys_plugins.go
create mode 100644 internal/model/entity/sys_plugins_config.go
create mode 100644 internal/model/entity/sys_post.go
create mode 100644 internal/model/entity/sys_role.go
create mode 100644 internal/model/entity/sys_role_dept.go
create mode 100644 internal/model/entity/sys_user.go
create mode 100644 internal/model/entity/sys_user_online.go
create mode 100644 internal/model/entity/sys_user_post.go
create mode 100644 internal/model/entity/sys_user_role.go
create mode 100644 internal/model/env_weather.go
create mode 100644 internal/model/network_server.go
create mode 100644 internal/model/network_tunnel.go
create mode 100644 internal/model/notice_config.go
create mode 100644 internal/model/notice_info.go
create mode 100644 internal/model/notice_log.go
create mode 100644 internal/model/notice_template.go
create mode 100644 internal/model/session.go
create mode 100644 internal/model/statistics_data_overview.go
create mode 100644 internal/model/sys_api.go
create mode 100644 internal/model/sys_dept.go
create mode 100644 internal/model/sys_dict_data.go
create mode 100644 internal/model/sys_dict_type.go
create mode 100644 internal/model/sys_job.go
create mode 100644 internal/model/sys_login_log.go
create mode 100644 internal/model/sys_menu.go
create mode 100644 internal/model/sys_menu_api.go
create mode 100644 internal/model/sys_menu_button.go
create mode 100644 internal/model/sys_menu_column.go
create mode 100644 internal/model/sys_notifications.go
create mode 100644 internal/model/sys_oper_log.go
create mode 100644 internal/model/sys_orgainzation.go
create mode 100644 internal/model/sys_plugins.go
create mode 100644 internal/model/sys_post.go
create mode 100644 internal/model/sys_role.go
create mode 100644 internal/model/sys_token.go
create mode 100644 internal/model/sys_user.go
create mode 100644 internal/model/sys_user_online.go
create mode 100644 internal/model/system_plugins_config.go
create mode 100644 internal/model/td_engine.go
create mode 100644 internal/model/td_log_table.go
create mode 100644 internal/mqtt/mqtt.go
create mode 100644 internal/packed/packed.go
create mode 100644 internal/service/alarm.go
create mode 100644 internal/service/common.go
create mode 100644 internal/service/context.go
create mode 100644 internal/service/datahub.go
create mode 100644 internal/service/envirotronics.go
create mode 100644 internal/service/middleware.go
create mode 100644 internal/service/network.go
create mode 100644 internal/service/notice.go
create mode 100644 internal/service/product.go
create mode 100644 internal/service/system.go
create mode 100644 internal/service/tdengine.go
create mode 100644 internal/task/HTTP_Client.go
create mode 100644 internal/task/bind_function.go
create mode 100644 internal/task/cleardata.go
create mode 100644 internal/task/data_source.go
create mode 100644 internal/task/data_template.go
create mode 100644 internal/task/demo.go
create mode 100644 internal/task/deviceLog_clear.go
create mode 100644 internal/webscoket/call.go
create mode 100644 internal/webscoket/common/webScoket.go
create mode 100644 internal/webscoket/model/websocket.go
create mode 100644 internal/webscoket/privater/handler.go
create mode 100644 internal/webscoket/sys/sys.go
create mode 100644 main.go
create mode 100644 manifest/config/config.example.yaml
create mode 100644 network/codebin/bytes.go
create mode 100644 network/codebin/check.go
create mode 100644 network/codebin/hex.go
create mode 100644 network/core/common.go
create mode 100644 network/core/connect.go
create mode 100644 network/core/device-manager.go
create mode 100644 network/core/device.go
create mode 100644 network/core/mapper.go
create mode 100644 network/core/mqtt-databus.go
create mode 100644 network/core/mqtt-device-property-report.go
create mode 100644 network/core/mqtt-device-router.go
create mode 100644 network/core/mqtt-device.go
create mode 100644 network/core/point.go
create mode 100644 network/core/poller.go
create mode 100644 network/core/product-manager.go
create mode 100644 network/core/server-common.go
create mode 100644 network/core/server-manager.go
create mode 100644 network/core/server-tcp-tunnel.go
create mode 100644 network/core/server-tcp.go
create mode 100644 network/core/server-udp-tunnel.go
create mode 100644 network/core/server-udp.go
create mode 100644 network/core/server.go
create mode 100644 network/core/tunnel-base.go
create mode 100644 network/core/tunnel-client.go
create mode 100644 network/core/tunnel-common.go
create mode 100644 network/core/tunnel-manager.go
create mode 100644 network/core/tunnel.go
create mode 100644 network/core/tunnelinstance/tunnel-instance.go
create mode 100644 network/events/events.go
create mode 100644 network/model/command.go
create mode 100644 network/model/default.go
create mode 100644 network/model/device.go
create mode 100644 network/model/message.go
create mode 100644 network/model/point.go
create mode 100644 network/model/poller.go
create mode 100644 network/model/server.go
create mode 100644 network/model/tunnel.go
create mode 100644 network/model/type.go
create mode 100644 network/network.go
create mode 100644 network/pkg/cron/cron.go
create mode 100644 network/pkg/mqttclient/mqtt.go
create mode 100644 plugin_test.go
create mode 100644 plugins/Makefile
create mode 100644 plugins/built/.gitignore
create mode 100644 plugins/notice/dingding/Makefile
create mode 100644 plugins/notice/dingding/dingding.go
create mode 100644 plugins/notice/dingding/internal/options.go
create mode 100644 plugins/notice/dingding/internal/send.go
create mode 100644 plugins/notice/dingding/readme.MD
create mode 100644 plugins/notice/mail/Makefile
create mode 100644 plugins/notice/mail/internal/options.go
create mode 100644 plugins/notice/mail/internal/send.go
create mode 100644 plugins/notice/mail/internal/send_test.go
create mode 100644 plugins/notice/mail/mail.go
create mode 100644 plugins/notice/wework/Makefile
create mode 100644 plugins/notice/wework/internal/internal.go
create mode 100644 plugins/notice/wework/model/sendmessage.go
create mode 100644 plugins/notice/wework/wework.go
create mode 100644 plugins/protocol/tgn52/Makefile
create mode 100644 plugins/protocol/tgn52/model.go
create mode 100644 plugins/protocol/tgn52/readme.md
create mode 100644 plugins/protocol/tgn52/tgn52.go
create mode 100644 resource/public/.gitignore
create mode 100644 tools/migration/internal/td_conn.go
create mode 100644 tools/migration/internal/td_destination.go
create mode 100644 tools/migration/internal/td_source.go
create mode 100644 tools/migration/main.go
create mode 100644 tools/migration/tdengine.yaml
create mode 100644 utility/cron/cron.go
create mode 100644 utility/cron/cron_test.go
create mode 100644 utility/excel.go
create mode 100644 utility/jobTask/job_task.go
create mode 100644 utility/liberr/err.go
create mode 100644 utility/notifier/notifier.go
create mode 100644 utility/notifier/notifier_test.go
create mode 100644 utility/notifier/sysenv/sysenv.go
create mode 100644 utility/notifier/sysenv_enevt.go
create mode 100644 utility/notifier/sysenv_html_test.html
create mode 100644 utility/response/response.go
create mode 100644 utility/utils/date_utils.go
create mode 100644 utility/utils/template.go
create mode 100644 utility/utils/template_test.go
create mode 100644 utility/utils/utils.go
create mode 100644 utility/utils/utils_test.go
create mode 100644 utility/version/version.go
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 @@
+
+
+
+
+
+System Info:
+
+
+
+
+
diff --git a/utility/response/response.go b/utility/response/response.go
new file mode 100644
index 0000000..2698592
--- /dev/null
+++ b/utility/response/response.go
@@ -0,0 +1,71 @@
+package response
+
+import (
+ "fmt"
+ "github.com/gogf/gf/v2/frame/g"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/os/gtime"
+ "io"
+ "net/http"
+ "time"
+)
+
+// JsonRes 数据返回通用JSON数据结构
+type JsonRes struct {
+ Code int `json:"code"` // 错误码((0:成功, 1:失败, >1:错误码))
+ Message string `json:"message"` // 提示信息
+ Data interface{} `json:"data"` // 返回数据(业务接口定义具体数据结构)
+ //Redirect string `json:"redirect"` // 引导客户端跳转到指定路由
+}
+
+// Json 返回标准JSON数据。
+func Json(r *ghttp.Request, code int, message string, data ...interface{}) {
+ var responseData interface{}
+ if len(data) > 0 {
+ responseData = data[0]
+ } else {
+ responseData = g.Map{}
+ }
+ r.Response.WriteJson(JsonRes{
+ Code: code,
+ Message: message,
+ Data: responseData,
+ })
+}
+
+// JsonExit 返回标准JSON数据并退出当前HTTP执行函数。
+func JsonExit(r *ghttp.Request, code int, message string, data ...interface{}) {
+ Json(r, code, message, data...)
+ r.Exit()
+}
+
+// JsonRedirect 返回标准JSON数据引导客户端跳转。
+func JsonRedirect(r *ghttp.Request, code int, message, redirect string, data ...interface{}) {
+ responseData := interface{}(nil)
+ if len(data) > 0 {
+ responseData = data[0]
+ }
+ r.Response.WriteJson(JsonRes{
+ Code: code,
+ Message: message,
+ Data: responseData,
+ //Redirect: redirect,
+ })
+}
+
+// JsonRedirectExit 返回标准JSON数据引导客户端跳转,并退出当前HTTP执行函数。
+func JsonRedirectExit(r *ghttp.Request, code int, message, redirect string, data ...interface{}) {
+ JsonRedirect(r, code, message, redirect, data...)
+ r.Exit()
+}
+
+//ToXls 向前端返回Excel文件 参数 content 为上面生成的io.ReadSeeker, fileTag 为返回前端的文件名
+func ToXls(r *ghttp.Request, content io.ReadSeeker, fileTag string) {
+ fileName := fmt.Sprintf("%s%s%s.xlsx", gtime.Now().String(), `-`, fileTag)
+ r.Response.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
+ r.Response.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
+ r.Response.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+ http.ServeContent(r.Response.Writer, r.Request, fileName, time.Now(), content)
+ r.Exit()
+ return
+}
diff --git a/utility/utils/date_utils.go b/utility/utils/date_utils.go
new file mode 100644
index 0000000..2f8f86a
--- /dev/null
+++ b/utility/utils/date_utils.go
@@ -0,0 +1,157 @@
+package utils
+
+import (
+ "github.com/gogf/gf/v2/os/gtime"
+ "strconv"
+ "time"
+)
+
+// GetWeekDay 获取本周的开始时间和结束时间
+func GetWeekDay() (string, string) {
+ now := time.Now()
+ offset := int(time.Monday - now.Weekday())
+ //周日做特殊判断 因为time.Monday = 0
+ if offset > 0 {
+ offset = -6
+ }
+
+ lastoffset := int(time.Saturday - now.Weekday())
+ //周日做特殊判断 因为time.Monday = 0
+ if lastoffset == 6 {
+ lastoffset = -1
+ }
+
+ firstOfWeek := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
+ lastOfWeeK := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, lastoffset+1)
+ f := firstOfWeek.Unix()
+ l := lastOfWeeK.Unix()
+ return time.Unix(f, 0).Format("2006-01-02") + " 00:00:00", time.Unix(l, 0).Format("2006-01-02") + " 23:59:59"
+}
+
+// GetBetweenDates 根据开始日期和结束日期计算出时间段内所有日期
+// 参数为日期格式,如:2020-01-01
+func GetBetweenDates(sdate, edate string) []string {
+ var d []string
+ timeFormatTpl := "2006-01-02 15:04:05"
+ if len(timeFormatTpl) != len(sdate) {
+ timeFormatTpl = timeFormatTpl[0:len(sdate)]
+ }
+ date, err := time.Parse(timeFormatTpl, sdate)
+ if err != nil {
+ // 时间解析,异常
+ return d
+ }
+ date2, err := time.Parse(timeFormatTpl, edate)
+ if err != nil {
+ // 时间解析,异常
+ return d
+ }
+ if date2.Before(date) {
+ // 如果结束时间小于开始时间,异常
+ return d
+ }
+ // 输出日期格式固定
+ timeFormatTpl = "2006-01-02"
+ date2Str := date2.Format(timeFormatTpl)
+ d = append(d, date.Format(timeFormatTpl))
+ for {
+ date = date.AddDate(0, 0, 1)
+ dateStr := date.Format(timeFormatTpl)
+ d = append(d, dateStr)
+ if dateStr == date2Str {
+ break
+ }
+ }
+ return d
+}
+
+// GetQuarterDay 获得当前季度的初始和结束日期
+func GetQuarterDay() (string, string) {
+ year := time.Now().Format("2006")
+ month := int(time.Now().Month())
+ var firstOfQuarter string
+ var lastOfQuarter string
+ if month >= 1 && month <= 3 {
+ //1月1号
+ firstOfQuarter = year + "-01-01 00:00:00"
+ lastOfQuarter = year + "-03-31 23:59:59"
+ } else if month >= 4 && month <= 6 {
+ firstOfQuarter = year + "-04-01 00:00:00"
+ lastOfQuarter = year + "-06-30 23:59:59"
+ } else if month >= 7 && month <= 9 {
+ firstOfQuarter = year + "-07-01 00:00:00"
+ lastOfQuarter = year + "-09-30 23:59:59"
+ } else {
+ firstOfQuarter = year + "-10-01 00:00:00"
+ lastOfQuarter = year + "-12-31 23:59:59"
+ }
+ return firstOfQuarter, lastOfQuarter
+}
+
+// GetTimeByType 根据类型获取开始时间、结束时间及差值 1 天 2 周 3 月 4 年
+func GetTimeByType(types int) (index int, begin string, end string) {
+ switch types {
+ case 1:
+ begin = gtime.Now().Format("Y-m-d 00:00:00")
+ end = gtime.Now().Format("Y-m-d H:i:s")
+ index = gtime.Now().Hour() + 1
+ break
+ case 2:
+ //begin, _ = GetWeekDay()
+ begin = gtime.Now().AddDate(0, 0, -6).Format("Y-m-d 00:00:00")
+
+ end = gtime.Now().Format("Y-m-d H:i:s")
+ index = int(gtime.New(end).Sub(gtime.New(begin)).Hours()/24) + 1
+ break
+ case 3:
+ //begin = gtime.Now().Format("Y-m-01 00:00:00")
+ begin = gtime.Now().AddDate(0, 0, -23).Format("Y-m-d 00:00:00")
+ //end = gtime.Now().AddDate(0, 1, 0).Format("Y-m-01 00:00:00")
+ end = gtime.Now().Format("Y-m-d H:i:s")
+ //index = gtime.Now().Day()
+ index = int(gtime.New(end).Sub(gtime.New(begin)).Hours()/24) + 1
+ break
+ case 4:
+ begin = gtime.Now().Format("Y-01-01 00:00:00")
+ end = gtime.Now().AddDate(1, 0, 0).Format("Y-01-01 00:00:00")
+ index = gtime.Now().Month()
+ break
+ default:
+ begin = gtime.Now().Format("Y-m-d 00:00:00")
+ end = gtime.Now().Format("Y-m-d H:i:s")
+ index = gtime.Now().Hour() + 1
+ break
+ }
+ return
+}
+
+// GetTime 根据类型和开始时间获取时间段及长度
+func GetTime(i int, types int, begin string) (startTime string, endTime string, duration int, unit string) {
+ switch types {
+ case 1:
+ h, _ := time.ParseDuration(strconv.Itoa(i) + "h")
+ startTime = gtime.New(begin).Add(h).Format("Y-m-d H:i:s")
+ endTime = gtime.New(startTime).Add(time.Hour).Format("Y-m-d H:i:s")
+ duration = gtime.New(startTime).Hour()
+ unit = "时"
+ break
+ case 2, 3:
+ startTime = gtime.New(begin).AddDate(0, 0, i).Format("Y-m-d H:i:s")
+ endTime = gtime.New(startTime).AddDate(0, 0, 1).Format("Y-m-d H:i:s")
+ duration = gtime.New(startTime).Day()
+ unit = "日"
+ case 4:
+ startTime = gtime.New(begin).AddDate(0, i, 0).Format("Y-m-d H:i:s")
+ endTime = gtime.New(startTime).AddDate(0, 1, 0).Format("Y-m-d H:i:s")
+ duration = gtime.New(startTime).Month()
+ unit = "月"
+ break
+ default:
+ startTime = gtime.New(begin).Add(time.Duration(i)).Format("Y-m-d H:i:s")
+ endTime = gtime.New(startTime).Add(time.Hour).Format("Y-m-d H:i:s")
+ duration = gtime.New(startTime).Hour()
+ unit = "时"
+ break
+ }
+ return
+}
diff --git a/utility/utils/template.go b/utility/utils/template.go
new file mode 100644
index 0000000..d503678
--- /dev/null
+++ b/utility/utils/template.go
@@ -0,0 +1,23 @@
+package utils
+
+import (
+ "bytes"
+ "text/template"
+)
+
+func ReplaceTemplate(content string, variable map[string]interface{}) (result string, err error) {
+ // 创建模版对象
+ tmpl, err := template.New("text").Parse(content)
+ if err != nil {
+ return
+ }
+ // 创建缓冲区
+ var buf bytes.Buffer
+ // 执行模版替换
+ if err = tmpl.Execute(&buf, variable); err != nil {
+ return
+ }
+ // 输出结果
+ result = buf.String()
+ return
+}
diff --git a/utility/utils/template_test.go b/utility/utils/template_test.go
new file mode 100644
index 0000000..3fbc7d1
--- /dev/null
+++ b/utility/utils/template_test.go
@@ -0,0 +1,23 @@
+package utils
+
+import (
+ "testing"
+)
+
+func TestReplaceTemplate(t *testing.T) {
+ // 定义文本模版
+ textTmpl := `Hello, {{.Name}}! You are {{.Age}} years old`
+ // 定义数据
+ data := map[string]interface{}{
+ "Name": "John Doe",
+ "Age": 30,
+ }
+
+ res, err := ReplaceTemplate(textTmpl, data)
+ if err != nil {
+ t.Error(res)
+
+ }
+ t.Log(res)
+
+}
diff --git a/utility/utils/utils.go b/utility/utils/utils.go
new file mode 100644
index 0000000..4bf4cc5
--- /dev/null
+++ b/utility/utils/utils.go
@@ -0,0 +1,180 @@
+package utils
+
+import (
+ "context"
+ "fmt"
+ "github.com/gogf/gf/v2/crypto/gmd5"
+ "github.com/gogf/gf/v2/encoding/gcharset"
+ "github.com/gogf/gf/v2/encoding/gjson"
+ "github.com/gogf/gf/v2/encoding/gurl"
+ "github.com/gogf/gf/v2/frame/g"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/russross/blackfriday/v2"
+ "io"
+ "net"
+ "os"
+ "path"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// MarkdownToHtml 解析markdown为html
+func MarkdownToHtml(mdContent string) string {
+ return string(blackfriday.Run([]byte(mdContent)))
+}
+
+// EncryptPassword 密码加密
+func EncryptPassword(password, salt string) string {
+ return gmd5.MustEncryptString(gmd5.MustEncryptString(password) + gmd5.MustEncryptString(salt))
+}
+
+// GetDomain 获取当前请求接口域名
+func GetDomain(ctx context.Context) string {
+ r := g.RequestFromCtx(ctx)
+ pathInfo, err := gurl.ParseURL(r.GetUrl(), -1)
+ if err != nil {
+ g.Log().Error(ctx, err)
+ return ""
+ }
+ return fmt.Sprintf("%s://%s:%s/", pathInfo["scheme"], pathInfo["host"], pathInfo["port"])
+}
+
+// GetClientIp 获取客户端IP
+func GetClientIp(ctx context.Context) string {
+ return g.RequestFromCtx(ctx).GetClientIp()
+}
+
+// GetUserAgent 获取user-agent
+func GetUserAgent(ctx context.Context) string {
+ return ghttp.RequestFromCtx(ctx).Header.Get("User-Agent")
+}
+
+// GetLocalIP 服务端ip
+func GetLocalIP() (ip string, err error) {
+ var addrs []net.Addr
+ addrs, err = net.InterfaceAddrs()
+ if err != nil {
+ return
+ }
+ for _, addr := range addrs {
+ ipAddr, ok := addr.(*net.IPNet)
+ if !ok {
+ continue
+ }
+ if ipAddr.IP.IsLoopback() {
+ continue
+ }
+ if !ipAddr.IP.IsGlobalUnicast() {
+ continue
+ }
+ return ipAddr.IP.String(), nil
+ }
+ return
+}
+
+// GetCityByIp 获取ip所属城市
+func GetCityByIp(ip string) string {
+ if ip == "" {
+ return ""
+ }
+ if ip == "[::1]" || ip == "127.0.0.1" {
+ return "内网IP"
+ }
+ url := "http://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" + ip
+ bytes := g.Client().GetBytes(context.TODO(), url)
+ src := string(bytes)
+ srcCharset := "GBK"
+ tmp, _ := gcharset.ToUTF8(srcCharset, src)
+ json, err := gjson.DecodeToJson(tmp)
+ if err != nil {
+ return ""
+ }
+ if json.Get("code").Int() == 0 {
+ city := fmt.Sprintf("%s %s", json.Get("pro").String(), json.Get("city").String())
+ return city
+ } else {
+ return ""
+ }
+}
+
+// 写入文件
+func WriteToFile(fileName string, content string) error {
+ f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
+ if err != nil {
+ return err
+ }
+ n, _ := f.Seek(0, io.SeekEnd)
+ _, err = f.WriteAt([]byte(content), n)
+ defer f.Close()
+ return err
+}
+
+// 文件或文件夹是否存在
+func FileIsExisted(filename string) bool {
+ existed := true
+ if _, err := os.Stat(filename); os.IsNotExist(err) {
+ existed = false
+ }
+ return existed
+}
+
+// 解析路径获取文件名称及后缀
+func ParseFilePath(pathStr string) (fileName string, fileType string) {
+ fileNameWithSuffix := path.Base(pathStr)
+ fileType = path.Ext(fileNameWithSuffix)
+ fileName = strings.TrimSuffix(fileNameWithSuffix, fileType)
+ return
+}
+
+func RemoveRepeatedElementAndEmpty(arr []int) []int {
+ newArr := make([]int, 0)
+ for _, item := range arr {
+ repeat := false
+ if len(newArr) > 0 {
+ for _, v := range newArr {
+ if v == item {
+ repeat = true
+ break
+ }
+ }
+ }
+ if repeat {
+ continue
+ }
+ newArr = append(newArr, item)
+ }
+ return newArr
+}
+
+// RemoveDuplicationMap 数组去重
+func RemoveDuplicationMap(arr []string) []string {
+ set := make(map[string]struct{}, len(arr))
+ j := 0
+ for _, v := range arr {
+ _, ok := set[v]
+ if ok {
+ continue
+ }
+ set[v] = struct{}{}
+ arr[j] = v
+ j++
+ }
+ return arr[:j]
+}
+
+// Decimal 保留两位小数
+func Decimal(value float64) float64 {
+ value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
+ return value
+}
+
+// InArray 判断字符串是否存在数组中
+func InArray(target string, strArray []string) bool {
+ sort.Strings(strArray)
+ index := sort.SearchStrings(strArray, target)
+ if index < len(strArray) && strArray[index] == target {
+ return true
+ }
+ return false
+}
diff --git a/utility/utils/utils_test.go b/utility/utils/utils_test.go
new file mode 100644
index 0000000..7740477
--- /dev/null
+++ b/utility/utils/utils_test.go
@@ -0,0 +1,21 @@
+package utils
+
+import (
+ "testing"
+
+ "github.com/gogf/gf/v2/frame/g"
+ "github.com/gogf/gf/v2/test/gtest"
+)
+
+func TestMarkdownToHtml(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ content := `
+## 参与贡献
+
+1. 框架代码:参与框架功能开发、单元测试、ISSUE提交、反馈建议等等,https://github.com/gogf/gf
+2. 开发文档:参与开发文档的撰写,便于更多的人了解、热爱并加入团队,https://github.com/gogf/gf-doc
+
+`
+ g.Dump(MarkdownToHtml(content))
+ })
+}
diff --git a/utility/version/version.go b/utility/version/version.go
new file mode 100644
index 0000000..d075d4d
--- /dev/null
+++ b/utility/version/version.go
@@ -0,0 +1,22 @@
+package version
+
+import "fmt"
+
+var (
+ BuildTime string
+ BuildVersion string
+ CommitID string
+)
+
+func ShowLogo(buildVersion, buildTime, commitID string) {
+ BuildVersion = buildVersion
+ BuildTime = buildTime
+ CommitID = commitID
+ //版本号
+ fmt.Println(" _____ \n / ____| \n | (___ __ _ __ _ ___ ___ \n \\___ \\ / _` |/ _` |/ _ \\ / _ \\ \n ____) | (_| | (_| | (_) | (_) |\n |_____/ \\__,_|\\__, |\\___/ \\___/ \n __/ | \n |___/ ")
+ fmt.Println("Version :", buildVersion)
+ fmt.Println("BuildTime :", buildTime)
+ fmt.Println("CommitID :", commitID)
+ fmt.Println("")
+
+}