Browse Source

初始配置,定一些项目规则

庄逸洲 4 years ago
parent
commit
001db7a0bd

+ 4 - 4
conf/app.conf View File

@@ -47,13 +47,13 @@ readmysqlhost = shengws1.mysql.rds.aliyuncs.com
47 47
 readmysqlport = 3306
48 48
 readmysqluser = syh
49 49
 readmysqlpass = xhPECP2nFObR8aUK
50
-readmysqlname = sgj_xt
50
+readmysqlname = sgj_patient
51 51
 
52 52
 writemysqlhost = shengws1.mysql.rds.aliyuncs.com
53 53
 writemysqlport = 3306
54 54
 writemysqluser = syh
55 55
 writemysqlpass = xhPECP2nFObR8aUK
56
-writemysqlname = sgj_xt
56
+writemysqlname = sgj_patient
57 57
 
58 58
 readuserhost = shengws1.mysql.rds.aliyuncs.com
59 59
 readuserport = 3306
@@ -81,13 +81,13 @@ readmysqlhost = rm-wz9rg531npf61q03tro.mysql.rds.aliyuncs.com
81 81
 readmysqlport = 3306
82 82
 readmysqluser = root
83 83
 readmysqlpass = 1Q2W3e4r!@#$
84
-readmysqlname = sgj_xt
84
+readmysqlname = sgj_patient
85 85
 
86 86
 writemysqlhost = rm-wz9rg531npf61q03tro.mysql.rds.aliyuncs.com
87 87
 writemysqlport = 3306
88 88
 writemysqluser = root
89 89
 writemysqlpass = 1Q2W3e4r!@#$
90
-writemysqlname = sgj_xt
90
+writemysqlname = sgj_patient
91 91
 
92 92
 readuserhost = rm-wz9rg531npf61q03tro.mysql.rds.aliyuncs.com
93 93
 readuserport = 3306

+ 3 - 0
controllers/Readme.md View File

@@ -0,0 +1,3 @@
1
+按业务分模块(包);  
2
+对于业务比较复杂的模块,再细分业务,拆分为多个控制器;
3
+每个控制器文件提供注册 router 的方法,每个模块建立一个 router_collector.go 文件,定义一个 RegisterRouters 方法,用以收集模块中控制器提供的注册 router 的方法,并在 router.go 中最终调用;

+ 107 - 0
controllers/admin/admin_controller.go View File

@@ -0,0 +1,107 @@
1
+package admin
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	base_service "SCRM/service"
7
+	"SCRM/service/admin_service"
8
+	"SCRM/service/role_service"
9
+
10
+	"github.com/astaxie/beego"
11
+)
12
+
13
+func AdminCtlRegistRouters() {
14
+	beego.Router("/api/password/code", &AdminController{}, "post:CodeOfModifyPwd")
15
+	beego.Router("/api/password/modify", &AdminController{}, "post:ModifyPwd")
16
+	beego.Router("/api/admin/edit_info", &AdminController{}, "post:EditAdminUserInfo")
17
+}
18
+
19
+type AdminController struct {
20
+	base_ctl.BaseAuthAPIController
21
+}
22
+
23
+// /api/admin/edit_info [post]
24
+// @param avatar:string
25
+// @param name:string
26
+// @param opwd?:string 没有原始密码的时候,认为不修改密码
27
+// @param npwd?:string
28
+func (this *AdminController) EditAdminUserInfo() {
29
+	adminUserInfo := this.GetAdminUserInfo()
30
+
31
+	avatar := this.GetString("avatar")
32
+	name := this.GetString("name")
33
+	if len(name) == 0 {
34
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeMissingUserName)
35
+		return
36
+	}
37
+	modifyErr := role_service.ModifyAdminUserInfo(adminUserInfo.AdminUser.Id, adminUserInfo.CurrentOrgId, adminUserInfo.CurrentAppId, name, avatar, "")
38
+	if modifyErr != nil {
39
+		this.ErrorLog("修改个人信息失败:%v", modifyErr)
40
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDBUpdate)
41
+
42
+	} else {
43
+		appRole := adminUserInfo.AppRoles[adminUserInfo.CurrentAppId]
44
+		appRole.UserName = name
45
+		appRole.Avatar = avatar
46
+		this.ServeSuccessJSON(nil)
47
+	}
48
+}
49
+
50
+// /api/password/code [post]
51
+func (this *AdminController) CodeOfModifyPwd() {
52
+	//////////////////////////////
53
+	// 待把 SMS 的 service 添加完再重新放开
54
+	//////////////////////////////
55
+	this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
56
+	return
57
+	// adminUserInfo := this.GetAdminUserInfo()
58
+	// mobile := adminUserInfo.AdminUser.Mobile
59
+	// if err := service.SMSSendVerificationCode(mobile); err != nil {
60
+	// 	utils.ErrorLog("修改密码发送验证码失败:%v", err)
61
+	// 	this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
62
+	// 	return
63
+	// } else {
64
+	// 	this.ServeSuccessJSON(map[string]interface{}{
65
+	// 		"msg": "短信发送成功,有效期为10分钟",
66
+	// 	})
67
+	// }
68
+}
69
+
70
+// /api/password/modify [post]
71
+// @param password:string
72
+// @param code:string
73
+func (this *AdminController) ModifyPwd() {
74
+	new_pwd := this.GetString("password")
75
+	code := this.GetString("code")
76
+	if len(new_pwd) == 0 || len(code) == 0 {
77
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
78
+		return
79
+	}
80
+
81
+	adminUserInfo := this.GetAdminUserInfo()
82
+	mobile := adminUserInfo.AdminUser.Mobile
83
+
84
+	redisClient := base_service.RedisClient()
85
+	defer redisClient.Close()
86
+	cachedCode, err := redisClient.Get("xt_modify_pwd_" + mobile).Result()
87
+	if err != nil {
88
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeAccountOrVerCodeWrong)
89
+		return
90
+	}
91
+	if code != cachedCode {
92
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeAccountOrVerCodeWrong)
93
+		return
94
+	}
95
+
96
+	if modifyErr := admin_service.ModifyPassword(adminUserInfo.AdminUser.Id, new_pwd); modifyErr != nil {
97
+		this.ErrorLog("修改密码失败:%v", modifyErr)
98
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
99
+		return
100
+	}
101
+
102
+	// 清除验证码
103
+	redisClient.Del("xt_modify_pwd_" + mobile)
104
+	this.ServeSuccessJSON(map[string]interface{}{
105
+		"msg": "密码已修改",
106
+	})
107
+}

+ 5 - 0
controllers/admin/router_collector.go View File

@@ -0,0 +1,5 @@
1
+package admin
2
+
3
+func RegisterRouters() {
4
+	AdminCtlRegistRouters()
5
+}

+ 69 - 0
controllers/base_api_controller.go View File

@@ -0,0 +1,69 @@
1
+package controllers
2
+
3
+import (
4
+	"SCRM/enums"
5
+)
6
+
7
+type BaseAPIController struct {
8
+	BaseController
9
+}
10
+
11
+// 输出数据格式化
12
+/*
13
+	success json:
14
+	{
15
+		"state": 1,
16
+		"code": 0,
17
+		"data": json,
18
+	}
19
+
20
+	fail json:
21
+	{
22
+		"state": 0,
23
+		"code": int,
24
+		"msg": string,
25
+	}
26
+*/
27
+func (this *BaseAPIController) ServeSuccessJSON(data map[string]interface{}) {
28
+	this.Data["json"] = enums.MakeSuccessResponseJSON(data)
29
+	this.ServeJSON()
30
+}
31
+
32
+func (this *BaseAPIController) ServeFailJSONWithSGJErrorCode(code int) {
33
+	this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(code)
34
+	this.ServeJSON()
35
+}
36
+
37
+func (this *BaseAPIController) ServeFailJSONWithSGJError(err *enums.SGJError) {
38
+	this.Data["json"] = enums.MakeFailResponseJSONWithSGJError(err)
39
+	this.ServeJSON()
40
+}
41
+
42
+func (this *BaseAPIController) ServeFailJsonSend(code int, msg string) {
43
+	this.Data["json"] = enums.MakeFailResponseJSON(msg, code)
44
+	this.ServeJSON()
45
+}
46
+
47
+type BaseAuthAPIController struct {
48
+	BaseAPIController
49
+}
50
+
51
+func (this *BaseAuthAPIController) Prepare() {
52
+	this.BaseAPIController.Prepare()
53
+	if this.GetAdminUserInfo() == nil {
54
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeNotLogin)
55
+		this.StopRun()
56
+	}
57
+}
58
+
59
+type BaseServeAPIController struct {
60
+	BaseAPIController
61
+}
62
+
63
+func (this *BaseServeAPIController) Prepare() {
64
+	this.BaseAPIController.Prepare()
65
+	if this.GetAdminUserInfo() == nil {
66
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeNotLogin)
67
+		this.StopRun()
68
+	}
69
+}

+ 40 - 0
controllers/base_controller.go View File

@@ -0,0 +1,40 @@
1
+package controllers
2
+
3
+import (
4
+	service "SCRM/service/admin_service"
5
+
6
+	"github.com/astaxie/beego"
7
+)
8
+
9
+type BaseController struct {
10
+	beego.Controller
11
+}
12
+
13
+func (this *BaseController) GetAdminUserInfo() *service.AdminUserInfo {
14
+	userInfo := this.GetSession("admin_user_info")
15
+	if userInfo == nil {
16
+		return nil
17
+	} else {
18
+		return userInfo.(*service.AdminUserInfo)
19
+	}
20
+}
21
+
22
+func (this *BaseController) ErrorLog(format string, a ...interface{}) {
23
+	//beego.Error(fmt.Sprintf(format, a...))
24
+}
25
+
26
+func (this *BaseController) WarnLog(format string, a ...interface{}) {
27
+	//beego.Warn(fmt.Sprintf(format, a...))
28
+}
29
+
30
+func (this *BaseController) InfoLog(format string, a ...interface{}) {
31
+	//beego.Info(fmt.Sprintf(format, a...))
32
+}
33
+
34
+func (this *BaseController) DebugLog(format string, a ...interface{}) {
35
+	//beego.Debug(fmt.Sprintf(format, a...))
36
+}
37
+
38
+func (this *BaseController) TraceLog(format string, a ...interface{}) {
39
+	//beego.Trace(fmt.Sprintf(format, a...))
40
+}

+ 34 - 0
controllers/base_view_controller.go View File

@@ -0,0 +1,34 @@
1
+package controllers
2
+
3
+type BaseViewController struct {
4
+	BaseController
5
+}
6
+
7
+// 设置模板
8
+// 第一个参数模板,第二个参数为layout
9
+func (this *BaseViewController) SetTpl(template ...string) {
10
+	var tplName string
11
+	layout := ""
12
+	switch {
13
+	case len(template) == 1:
14
+		tplName = template[0]
15
+	case len(template) == 2:
16
+		tplName = template[0]
17
+		layout = template[1]
18
+	default:
19
+		tplName = "index.tpl"
20
+	}
21
+	this.Layout = layout
22
+	this.TplName = tplName
23
+}
24
+
25
+// 重定向
26
+func (this *BaseViewController) Redirect302(url string) {
27
+	this.Redirect(url, 302)
28
+	this.StopRun()
29
+}
30
+
31
+// 错误页面
32
+func (this *BaseViewController) Abort404() {
33
+	this.Abort("404")
34
+}

+ 0 - 15
controllers/default.go View File

@@ -1,15 +0,0 @@
1
-package controllers
2
-
3
-import (
4
-	"github.com/astaxie/beego"
5
-)
6
-
7
-type MainController struct {
8
-	beego.Controller
9
-}
10
-
11
-func (c *MainController) Get() {
12
-	c.Data["Website"] = "beego.me"
13
-	c.Data["Email"] = "astaxie@gmail.com"
14
-	c.TplName = "index.tpl"
15
-}

+ 36 - 0
controllers/global/error_controller.go View File

@@ -0,0 +1,36 @@
1
+package global
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"fmt"
7
+
8
+	"github.com/astaxie/beego"
9
+)
10
+
11
+func ErrorCtlRegistRouters() {
12
+	beego.Router("/error", &ErrorViewController{}, "get:HandleError")
13
+}
14
+
15
+type ErrorViewController struct {
16
+	base_ctl.BaseViewController
17
+}
18
+
19
+// /handle_error [get]
20
+// @param code:int
21
+func (this *ErrorViewController) HandleError() {
22
+	code, _ := this.GetInt("code")
23
+	if code == enums.ErrorCodeNeverCreateTypeApp {
24
+		ssoDomain := beego.AppConfig.String("sso_domain")
25
+		createAppURL := fmt.Sprintf("%v/org/app/create", ssoDomain)
26
+		this.Redirect302(createAppURL)
27
+
28
+	} else if code == enums.ErrorCodeContactSuperAdminCreateTypeApp {
29
+		ssoDomain := beego.AppConfig.String("sso_domain")
30
+		hitURL := fmt.Sprintf("%v/create_app_hint", ssoDomain)
31
+		this.Redirect302(hitURL)
32
+
33
+	} else {
34
+		this.Abort404()
35
+	}
36
+}

+ 5 - 0
controllers/global/router_collector.go View File

@@ -0,0 +1,5 @@
1
+package global
2
+
3
+func RegisterRouters() {
4
+	ErrorCtlRegistRouters()
5
+}

+ 154 - 0
controllers/login/login_controller.go View File

@@ -0,0 +1,154 @@
1
+package login
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"SCRM/service/admin_service"
7
+	"SCRM/service/org_service"
8
+	"SCRM/utils"
9
+	"fmt"
10
+	"net/url"
11
+
12
+	"github.com/astaxie/beego"
13
+)
14
+
15
+func LoginCtlRegistRouters() {
16
+	beego.Router("/login", &LoginViewController{}, "get:Login")
17
+	beego.Router("/logout", &LoginViewController{}, "get,post:Logout")
18
+	beego.Router("/api/token/verify", &VerifyUserLoginAPIController{}, "post:VerifyToken")
19
+}
20
+
21
+type LoginViewController struct {
22
+	base_ctl.BaseViewController
23
+}
24
+
25
+// /login [get]
26
+// @param token?:string
27
+// @param relogin?:bool
28
+func (this *LoginViewController) Login() {
29
+	token := this.Ctx.Input.Query("token")
30
+	if len(token) > 0 { // 带 token 参数的一般是从 SSO 回调回来的
31
+		utils.TraceLog("SSO Login 回调: token=%v", token)
32
+		xtFrontEndDomain := beego.AppConfig.String("front_end_domain") + "?lt=" + token
33
+		this.Redirect302(xtFrontEndDomain)
34
+
35
+	} else {
36
+		relogin, _ := this.GetBool("relogin", false)
37
+		returnURL := url.QueryEscape(fmt.Sprintf("%v%v", beego.AppConfig.String("httpdomain"), this.Ctx.Request.RequestURI))
38
+		ssoDomain := beego.AppConfig.String("sso_domain")
39
+		ssoLoginURL := fmt.Sprintf("%v/login?returnurl=%v&app_type=3&relogin=%v", ssoDomain, returnURL, relogin)
40
+		this.Redirect302(ssoLoginURL)
41
+	}
42
+}
43
+
44
+// /logout [get/post]
45
+func (this *LoginViewController) Logout() {
46
+	if this.Ctx.Request.Method == "GET" {
47
+		this.DelSession("admin_user_info")
48
+		this.Redirect302(fmt.Sprintf("%v/logout", beego.AppConfig.String("sso_domain")))
49
+	} else if this.Ctx.Request.Method == "POST" {
50
+		this.DelSession("admin_user_info")
51
+	}
52
+}
53
+
54
+type VerifyUserLoginAPIController struct {
55
+	base_ctl.BaseAPIController
56
+}
57
+
58
+// /api/token/verify [post]
59
+// @param token:string
60
+func (this *VerifyUserLoginAPIController) VerifyToken() {
61
+	if this.Ctx.Request.Method == "OPTIONS" {
62
+		this.Abort("200")
63
+
64
+	} else {
65
+		token := this.GetString("token")
66
+		utils.TraceLog("token: %v", token)
67
+		if len(token) == 0 {
68
+			this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
69
+			return
70
+		}
71
+
72
+		ip := utils.GetIP(this.Ctx.Request)
73
+		sessionID := this.Ctx.GetCookie("s")
74
+		this.TraceLog("cookie session id: %v", sessionID)
75
+		adminUserInfo, err, errCode := admin_service.VerifyToken(token, ip, sessionID)
76
+		if err != nil {
77
+			if errCode == 903 { // 未创建应用
78
+				this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeNeverCreateTypeApp)
79
+
80
+			} else if errCode == 904 { // 联系超管来开通
81
+				this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeContactSuperAdminCreateTypeApp)
82
+
83
+			} else {
84
+				utils.ErrorLog("令牌验证失败:%v", err)
85
+				this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeInvalidToken)
86
+			}
87
+			return
88
+
89
+		} else {
90
+			this.SetSession("admin_user_info", adminUserInfo)
91
+
92
+			adminUser := adminUserInfo.AdminUser
93
+			appRole := adminUserInfo.AppRoles[adminUserInfo.CurrentAppId]
94
+			userInfo := map[string]interface{}{
95
+				"id":         adminUser.Id,
96
+				"mobile":     adminUser.Mobile,
97
+				"user_name":  appRole.UserName,
98
+				"avatar":     appRole.Avatar,
99
+				"intro":      appRole.Intro,
100
+				"user_type":  appRole.UserType,
101
+				"user_title": appRole.UserTitle,
102
+			}
103
+			curOrg := adminUserInfo.Orgs[adminUserInfo.CurrentOrgId]
104
+			org := map[string]interface{}{
105
+				"id":             curOrg.Id,
106
+				"org_name":       curOrg.OrgName,
107
+				"org_short_name": curOrg.OrgShortName,
108
+				"org_intro":      curOrg.OrgIntroduction,
109
+				"org_logo":       curOrg.OrgLogo,
110
+				"province":       curOrg.Province,
111
+				"city":           curOrg.City,
112
+				"district":       curOrg.District,
113
+				"address":        curOrg.Address,
114
+			}
115
+			curAppUrlfors := adminUserInfo.AppUrlfors[adminUserInfo.CurrentAppId]
116
+
117
+			subscibe := adminUserInfo.Subscibes[adminUserInfo.CurrentOrgId]
118
+			if err := org_service.GetOrgSubscibeState(subscibe); err != nil {
119
+				this.ErrorLog("没有机构订阅信息,数据有误")
120
+				this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
121
+				return
122
+			}
123
+
124
+			orgApps := adminUserInfo.OrgApps[curOrg.Id]
125
+			didRegistedForSCRM := false
126
+			didRegistedForMall := false
127
+			didRegistedForCDM := false
128
+			for _, app := range orgApps {
129
+				if app.AppType == 1 {
130
+					didRegistedForSCRM = true
131
+				}
132
+				if app.AppType == 4 {
133
+					didRegistedForCDM = true
134
+				}
135
+				if app.AppType == 5 {
136
+					didRegistedForMall = true
137
+				}
138
+			}
139
+
140
+			this.ServeSuccessJSON(map[string]interface{}{
141
+				"user":            userInfo,
142
+				"org":             org,
143
+				"urlfors":         curAppUrlfors,
144
+				"current_org_id":  adminUserInfo.CurrentOrgId,
145
+				"current_app_id":  adminUserInfo.CurrentAppId,
146
+				"subscibe":        subscibe,
147
+				"scrm_role_exist": didRegistedForSCRM,
148
+				"cdm_role_exist":  didRegistedForCDM,
149
+				"mall_role_exist": didRegistedForMall,
150
+			})
151
+			return
152
+		}
153
+	}
154
+}

+ 5 - 0
controllers/login/router_collector.go View File

@@ -0,0 +1,5 @@
1
+package login
2
+
3
+func RegisterRouters() {
4
+	LoginCtlRegistRouters()
5
+}

+ 357 - 0
enums/error_code.go View File

@@ -0,0 +1,357 @@
1
+package enums
2
+
3
+import "SCRM/utils"
4
+
5
+const ( // ErrorCode
6
+	// 登录注册错误 6000+
7
+	ErrorCodeLoginTimeout                   = 6001
8
+	ErrorCodeNotLogin                       = 6002
9
+	ErrorCodePermissionDenied               = 6003
10
+	ErrorCodeMobileRegistered               = 6004
11
+	ErrorCodePasswordEmpty                  = 6005
12
+	ErrorCodeVerificationCodeWrong          = 6006
13
+	ErrorCodeRegisterFail                   = 6007
14
+	ErrorCodeInvalidToken                   = 6008
15
+	ErrorCodeAccountOrPasswordWrong         = 6009
16
+	ErrorCodeMissingOrg                     = 6010
17
+	ErrorCodeMissingOrgApp                  = 6011
18
+	ErrorCodeAccountOrVerCodeWrong          = 6012
19
+	ErrorCodeMobileNotExit                  = 6013
20
+	ErrorCodeUserNotExist                   = 6014
21
+	ErrorCodeUserWasForbidden               = 6015
22
+	ErrorCodeNeverCreateTypeApp             = 6016
23
+	ErrorCodeContactSuperAdminCreateTypeApp = 6017
24
+
25
+	// 数据验证错误 7000+
26
+	ErrorCodeMobileFormat     = 7001
27
+	ErrorCodeTelphoneFormat   = 7002
28
+	ErrorCodeParamWrong       = 7003
29
+	ErrorCodeParamFormatWrong = 7004
30
+
31
+	// 数据库操作错误 8000+
32
+	ErrorCodeDBCreate         = 8001
33
+	ErrorCodeDBUpdate         = 8002
34
+	ErrorCodeDBDelete         = 8003
35
+	ErrorCodeDBSelectNoResult = 8004
36
+	ErrorCodeDataException    = 8005
37
+
38
+	// 业务逻辑操作错误 9000+
39
+	ErrorCodeRoleNotExist           = 9001
40
+	ErrorCodeAdminUserNotExist      = 9002
41
+	ErrorCodeMobileDidUsedInApp     = 9003
42
+	ErrorCodeMissingUserName        = 9004
43
+	ErrorCodeOldPasswordWrong       = 9005
44
+	ErrorCodeCannotRemoveRole       = 9006
45
+	ErrorCodeRoleMobileIsSuperAdmin = 9007
46
+
47
+	ErrorCodeGetQiniuUpToken                = 1001
48
+	ErrorCodeCreatePatient                  = 1002
49
+	ErrorCodeDialysisNoExist                = 1003
50
+	ErrorCodeIdCardNoExist                  = 1004
51
+	ErrorCodePatientNoExist                 = 1005
52
+	ErrorCodeUpdatePatient                  = 1006
53
+	ErrorCodeDialysisSolutionExist          = 1007
54
+	ErrorCodeDialysisSolutionCreate         = 1008
55
+	ErrorCodeDialysisSolutionUpdate         = 1009
56
+	ErrorCodeDialysisSolutionNotExist       = 1010
57
+	ErrorCodeParentDialysisSolutionNotExist = 1011
58
+	ErrorCodeAlReadyHadChildSolution        = 1012
59
+	ErrorCodeCanntCreateChildChildSolution  = 1013
60
+	ErrorCodeDialysisSolutionUsed           = 1014
61
+	ErrorCodeCreateDryWeightFail            = 1015
62
+	ErrorCodeCreateDoctorAdviceFail         = 1016
63
+	ErrorCodeDoctorAdviceNotExist           = 1017
64
+	ErrorCodeUpdateDoctorAdviceFail         = 1018
65
+	ErrorCodeLongTimeAdviceNotCanntEdit     = 1019
66
+	ErrorCodeAdviceStoped                   = 1020
67
+	ErrorCodeParentAdviceNotExist           = 1021
68
+	ErrorCodeStopAdviceFail                 = 1022
69
+	ErrorCodeDeleteAdviceFail               = 1023
70
+	ErrorCodeDialysisSolutionDelete         = 1024
71
+	ErrorCodeDeviceNumberNotTheZone         = 1025
72
+	ErrorCodeCreateScheduleFail             = 1026
73
+	ErrorCodeCantSetScheduleAgainOneDay     = 1027
74
+	ErrorCodeCantSetScheduleBeforeNow       = 1028
75
+	ErrorCodeScheduleNotExist               = 1029
76
+	ErrorCodeDeleteScheduleFail             = 1030
77
+	ErrorCodeChangeScheduleFail             = 1031
78
+	ErrorCodePatientPhoneUsed               = 1032
79
+	ErrorCodeAdviceExced                    = 1033
80
+	ErrorCodeAdviceChecked                  = 1034
81
+	ErrorCodePointScheduleExist             = 1035
82
+	ErrorCodeExceAndCheckNotOneUser         = 1036
83
+	ErrorCodeCanotEditOtherAdvice           = 1037
84
+	ErrorCodeEditLapsetoFail                = 1038
85
+	ErrorCodeAdviceCheckBeforeExce          = 1039
86
+	ErrorCodeAdviceExceBeforeStart          = 1040
87
+	ErrorCodeDelScheduleFailByDialysis      = 1041
88
+	ErrorCodeNotSelectLapsetoType           = 1042
89
+	ErrorCodeNotSelectLapsetoTime           = 1043
90
+
91
+	ErrorCodeInspectionDateExit    = 1201
92
+	ErrorCodeInspectionAddFail     = 1202
93
+	ErrorCodeInspectionEditFail    = 1204
94
+	ErrorCodeInspectionDateNotExit = 1203
95
+	ErrorCodeInspectionDeleteFail  = 1205
96
+
97
+	ErrorCodeMonitorCreate                  = 1128
98
+	ErrorCodeMonitorNotExist                = 1129
99
+	ErrorCodeMonitorUpdate                  = 1130
100
+	ErrorDialysisOrderNoStart               = 1132
101
+	ErrorDialysisOrderNoEND                 = 1133
102
+	ErrorDialysisOrderRepeatStart           = 1134
103
+	ErrorCodeDialysisPermissionDeniedModify = 1135
104
+
105
+	ErrorCodeNotSubscibe       = 4003
106
+	ErrorCodeServeNotExist     = 4004
107
+	ErrorCodeInvoiceExist      = 4005
108
+	ErrorCodeApplyInvoiceFail  = 4006
109
+	ErrorCodeHetongHad         = 4007
110
+	ErrorCodeCreateHetongFail  = 4008
111
+	ErrorCodePatientReachLimit = 4009
112
+
113
+	ErrorCodeDeviceZoneNotExist                      = 9021
114
+	ErrorCodeDeviceZoneNameRepeat                    = 9022
115
+	ErrorCodeDeviceGroupNotExist                     = 9023
116
+	ErrorCodeDeviceGroupNameRepeat                   = 9024
117
+	ErrorCodeDeviceNumberNotExist                    = 9025
118
+	ErrorCodeDeviceNumberRepeat                      = 9026
119
+	ErrorCodeDeviceNotExist                          = 9027
120
+	ErrorCodeDeviceZoneCannotDisable                 = 9028
121
+	ErrorCodeDeviceNumberCannotDisableCuzDevice      = 9029
122
+	ErrorCodeDeviceNumberCannotDisableCuzSchedule    = 9030
123
+	ErrorCodeDeviceNumberCannotDisableCuzSchTemplate = 9031
124
+
125
+	ErrorCommitFail = 90000
126
+
127
+	ErrorCodeCreateStockInFail = 20001
128
+
129
+	ErrorCodeScheduleTemplateNotExist = 10001
130
+
131
+	ErrorCodeSystemError  = 6666
132
+	ErrorCodeProductError = 6667
133
+	ErrorCodeFieldExist   = 100001
134
+	ErrorCodeCreateConfig = 100002
135
+	ErrorCodeUpdateConfig = 100003
136
+
137
+	ErrorCodeDoubleCheckWrong     = 200003
138
+	ErrorCodeDoubleCheckUserWrong = 200004
139
+	ErrorCodeGoodNoStockInError   = 200005
140
+	ErrorCodeCancelStockFail      = 200006
141
+	ErrorCodeDeleteGoodTypeFail   = 200007
142
+	ErrorCodeDeleteGoodInfoFail   = 200008
143
+	ErrorCodeDeleteFail           = 200009
144
+
145
+	ErrorCodeKeyFail                 = 200010
146
+	ErrorCodeDeleteStockInRecordFail = 200011
147
+	ErrorCodeNameWrong               = 200012
148
+
149
+	ErrorCodeParamEmptyWrong       = 200013
150
+	ErrorCodeParamAdviceEmptyWrong = 200014
151
+
152
+	ErrorCodeParamTemplateNOEXISTWrong = 200015
153
+
154
+	ErrorCodeDeleteDealerWrong       = 200016
155
+	ErrorCodeDeleteManufacturerWrong = 200017
156
+)
157
+
158
+var ErrCodeMsgs = map[int]string{
159
+	// 登录注册错误
160
+	ErrorCodeLoginTimeout:                   "登录超时",
161
+	ErrorCodeNotLogin:                       "未登录",
162
+	ErrorCodePermissionDenied:               "权限不足",
163
+	ErrorCodeMobileRegistered:               "手机号已被注册",
164
+	ErrorCodePasswordEmpty:                  "密码为空",
165
+	ErrorCodeVerificationCodeWrong:          "验证码错误",
166
+	ErrorCodeRegisterFail:                   "注册失败",
167
+	ErrorCodeInvalidToken:                   "令牌无效",
168
+	ErrorCodeAccountOrPasswordWrong:         "账号或密码错误",
169
+	ErrorCodeMissingOrg:                     "未创建机构",
170
+	ErrorCodeMissingOrgApp:                  "未创建任何应用",
171
+	ErrorCodeAccountOrVerCodeWrong:          "账号或验证码错误",
172
+	ErrorCodeMobileNotExit:                  "手机号不存在",
173
+	ErrorCodeUserNotExist:                   "用户不存在",
174
+	ErrorCodeUserWasForbidden:               "该用户被禁用",
175
+	ErrorCodeNeverCreateTypeApp:             "未创建此种应用",
176
+	ErrorCodeContactSuperAdminCreateTypeApp: "请联系超级管理员开通此种应用",
177
+
178
+	// 数据验证错误
179
+	ErrorCodeMobileFormat:     "手机号格式错误",
180
+	ErrorCodeTelphoneFormat:   "电话格式错误",
181
+	ErrorCodeParamWrong:       "参数错误",
182
+	ErrorCodeParamFormatWrong: "参数格式错误",
183
+
184
+	// 数据库操作错误
185
+	ErrorCodeDBCreate:         "数据库创建出错",
186
+	ErrorCodeDBUpdate:         "数据库更新出错",
187
+	ErrorCodeDBDelete:         "数据库删除出错",
188
+	ErrorCodeDBSelectNoResult: "查询无结果",
189
+	ErrorCodeDataException:    "数据异常",
190
+
191
+	// 业务逻辑操作错误
192
+	ErrorCodeRoleNotExist:           "角色不存在",
193
+	ErrorCodeAdminUserNotExist:      "管理员不存在",
194
+	ErrorCodeMobileDidUsedInApp:     "该手机号已在该应用中被注册为管理员",
195
+	ErrorCodeMissingUserName:        "缺少用户名",
196
+	ErrorCodeOldPasswordWrong:       "原密码不正确",
197
+	ErrorCodeCannotRemoveRole:       "存在该角色的管理员,不能删除该角色",
198
+	ErrorCodeRoleMobileIsSuperAdmin: "该手机号已注册为超级管理员",
199
+
200
+	ErrorCodeGetQiniuUpToken: "获取七牛uptoken失败",
201
+	ErrorCodeCreatePatient:   "创建患者失败",
202
+	ErrorCodeDialysisNoExist: "患者透析号重复!",
203
+	ErrorCodeIdCardNoExist:   "身份证号重复!",
204
+	ErrorCodePatientNoExist:  "患者信息不存在!",
205
+	ErrorCodeUpdatePatient:   "修改患者信息失败",
206
+
207
+	ErrorCodeDialysisSolutionExist:          "该处方已经存在",
208
+	ErrorCodeDialysisSolutionCreate:         "创建处方失败",
209
+	ErrorCodeDialysisSolutionUpdate:         "修改处方失败",
210
+	ErrorCodeDialysisSolutionNotExist:       "该处方不存在",
211
+	ErrorCodeParentDialysisSolutionNotExist: "上级处方不存在",
212
+	ErrorCodeAlReadyHadChildSolution:        "所选处方已经存在子方案",
213
+	ErrorCodeCanntCreateChildChildSolution:  "子方案不能添加子方案",
214
+	ErrorCodeDialysisSolutionUsed:           "处方已被使用,不能删除",
215
+	ErrorCodeCreateDryWeightFail:            "添加干体重失败",
216
+	ErrorCodeCreateDoctorAdviceFail:         "添加医嘱失败",
217
+	ErrorCodeUpdateDoctorAdviceFail:         "修改医嘱信息失败",
218
+	ErrorCodeDoctorAdviceNotExist:           "医嘱不存在",
219
+	ErrorCodeLongTimeAdviceNotCanntEdit:     "长期医嘱不能修改!",
220
+	ErrorCodeAdviceStoped:                   "所选医嘱已停止",
221
+	ErrorCodeParentAdviceNotExist:           "上级医嘱不存在",
222
+	ErrorCodeDeleteAdviceFail:               "删除医嘱失败",
223
+	ErrorCodeStopAdviceFail:                 "停止医嘱失败",
224
+	ErrorCodeDialysisSolutionDelete:         "删除方案失败",
225
+	ErrorCodeDeviceNumberNotTheZone:         "所选机号不在选择分区中",
226
+	ErrorCodeCreateScheduleFail:             "添加排班失败",
227
+	ErrorCodeCantSetScheduleAgainOneDay:     "同一天不可有两次排班",
228
+	ErrorCodeCantSetScheduleBeforeNow:       "不能给今天之前的日期排班",
229
+	ErrorCodeScheduleNotExist:               "排班不存在",
230
+	ErrorCodePointScheduleExist:             "所先位置排班已经存在",
231
+	ErrorCodeDeleteScheduleFail:             "取消排班失败",
232
+	ErrorCodeChangeScheduleFail:             "修改排班失败",
233
+	ErrorCodePatientPhoneUsed:               "手机号已经存在",
234
+	ErrorCodeAdviceExced:                    "医嘱已经执行",
235
+	ErrorCodeAdviceCheckBeforeExce:          "核对医嘱不能在执行医嘱之前",
236
+	ErrorCodeAdviceExceBeforeStart:          "执行医嘱不能在开始之前",
237
+	ErrorCodeAdviceChecked:                  "医嘱已经核对",
238
+	ErrorCodeExceAndCheckNotOneUser:         "核对与执行不能是同一人",
239
+	ErrorCodeCanotEditOtherAdvice:           "不能修改非本人添加的医嘱",
240
+	ErrorCodeEditLapsetoFail:                "转归失败",
241
+	ErrorCodeDelScheduleFailByDialysis:      "已经上机透析,不能取消排班",
242
+	ErrorCodeNotSelectLapsetoType:           "请选择转归状态",
243
+	ErrorCodeNotSelectLapsetoTime:           "请选择转归时间",
244
+
245
+	ErrorCodeInspectionDateExit:    "当天已经存在检验检查记录",
246
+	ErrorCodeInspectionAddFail:     "添加记录失败",
247
+	ErrorCodeInspectionDateNotExit: "当天不存在检验检查记录",
248
+	ErrorCodeInspectionEditFail:    "修改记录失败",
249
+	ErrorCodeInspectionDeleteFail:  "删除记录失败",
250
+
251
+	ErrorCodeDeviceZoneNotExist:                      "设备分区不存在",
252
+	ErrorCodeDeviceZoneNameRepeat:                    "该分区名已存在",
253
+	ErrorCodeDeviceGroupNotExist:                     "设备分组不存在",
254
+	ErrorCodeDeviceGroupNameRepeat:                   "该分组名已存在",
255
+	ErrorCodeDeviceNumberNotExist:                    "机号不存在",
256
+	ErrorCodeDeviceNumberRepeat:                      "该机号已存在",
257
+	ErrorCodeDeviceNotExist:                          "该设备不存在",
258
+	ErrorCodeDeviceZoneCannotDisable:                 "该分区存在床位号,不能删除",
259
+	ErrorCodeDeviceNumberCannotDisableCuzDevice:      "该床位存在设备,不能删除",
260
+	ErrorCodeDeviceNumberCannotDisableCuzSchedule:    "该床位尚有排班安排,不能删除",
261
+	ErrorCodeDeviceNumberCannotDisableCuzSchTemplate: "排班模板在该床位尚有排班安排,不能删除",
262
+
263
+	ErrorCodeNotSubscibe:       "没有订阅服务或服务已过期,请先购买服务!",
264
+	ErrorCodeServeNotExist:     "服务订单不存在!",
265
+	ErrorCodeInvoiceExist:      "已经申请了发票!",
266
+	ErrorCodeApplyInvoiceFail:  "申请发票失败!",
267
+	ErrorCodeHetongHad:         "合同已经存在!",
268
+	ErrorCodeCreateHetongFail:  "合同创建失败",
269
+	ErrorCodePatientReachLimit: "患者数已达到当前服务版本病人数,需要升级到更高的版本",
270
+
271
+	ErrorCodeMonitorCreate:                  "创建监测失败",
272
+	ErrorCodeMonitorNotExist:                "监测记录不存在",
273
+	ErrorCodeMonitorUpdate:                  "修改监测失败",
274
+	ErrorCodeDialysisPermissionDeniedModify: "您没有权限修改其他医护的数据!",
275
+
276
+	ErrorDialysisOrderNoStart:     "尚未上机,无法执行下机操作",
277
+	ErrorDialysisOrderNoEND:       "已处于下机状态",
278
+	ErrorDialysisOrderRepeatStart: "已上机",
279
+	//ErrorCodeScheduleTemplateNotExist: "排班模板不存在",
280
+
281
+	ErrorCodeSystemError:              "系统异常",
282
+	ErrorCodeProductError:             "该服务商品已丢失",
283
+	ErrorCodeScheduleTemplateNotExist: "排班模板不存在",
284
+
285
+	ErrorCodeCreateStockInFail: "入库失败",
286
+	//ErrorCodeSystemError:  "系统异常",
287
+	//ErrorCodeProductError: "该服务商品已丢失",
288
+	ErrorCodeFieldExist:   "配置字段已存在",
289
+	ErrorCodeCreateConfig: "创建配置失败",
290
+	ErrorCodeUpdateConfig: "修改配置失败",
291
+
292
+	ErrorCommitFail:               "提交失败",
293
+	ErrorCodeDoubleCheckWrong:     "核对已完成, 无法再次提交",
294
+	ErrorCodeDoubleCheckUserWrong: "你已完成核对,不能重复核对",
295
+	ErrorCodeGoodNoStockInError:   "该商品尚未入库",
296
+
297
+	ErrorCodeCancelStockFail:    "出库退库失败",
298
+	ErrorCodeDeleteGoodTypeFail: "该类型存在商品信息,无法删除",
299
+	ErrorCodeDeleteGoodInfoFail: "该商品已经入库无法删除",
300
+
301
+	ErrorCodeDeleteFail: "删除失败",
302
+
303
+	ErrorCodeKeyFail:                 "关键字不能为空",
304
+	ErrorCodeDeleteStockInRecordFail: "该记录已经有出库或退货操作,无法删除",
305
+	ErrorCodeNameWrong:               "该模版名字已存在",
306
+	ErrorCodeParamEmptyWrong:         "模版名称不能为空",
307
+	ErrorCodeParamAdviceEmptyWrong:   "医嘱名称不能为空",
308
+
309
+	ErrorCodeDeleteDealerWrong:       "该经销商所属商品已入库无法删除",
310
+	ErrorCodeDeleteManufacturerWrong: "该厂商所属商品已入库无法删除",
311
+}
312
+
313
+type SGJError struct {
314
+	Code int
315
+}
316
+
317
+func (e *SGJError) Error() string {
318
+	value, ok := ErrCodeMsgs[e.Code]
319
+	if ok {
320
+		return value
321
+	} else {
322
+		return "未知错误"
323
+	}
324
+}
325
+
326
+func MakeSuccessResponseJSON(data map[string]interface{}) map[string]interface{} {
327
+	json := make(map[string]interface{})
328
+	if data != nil {
329
+		json["data"] = data
330
+	} else {
331
+		json["data"] = make(map[string]interface{})
332
+	}
333
+	json["state"] = 1
334
+	json["code"] = 0
335
+	return json
336
+}
337
+
338
+func MakeFailResponseJSON(errMsg string, errCode int) map[string]interface{} {
339
+	json := make(map[string]interface{})
340
+	json["msg"] = errMsg
341
+	json["code"] = errCode
342
+	json["state"] = 0
343
+	return json
344
+}
345
+
346
+func MakeFailResponseJSONWithSGJError(err *SGJError) map[string]interface{} {
347
+	if err == nil {
348
+		utils.WarningLog("MakeFailResponseJSONWithSGJError 参数err 不能为空")
349
+		return nil
350
+	}
351
+	return MakeFailResponseJSON(err.Error(), err.Code)
352
+}
353
+
354
+func MakeFailResponseJSONWithSGJErrorCode(code int) map[string]interface{} {
355
+	err := &SGJError{Code: code}
356
+	return MakeFailResponseJSON(err.Error(), err.Code)
357
+}

+ 3 - 0
models/Readme.md View File

@@ -0,0 +1,3 @@
1
+这个文件夹下只定义数据库相关的 model;  
2
+其他如 view model 则在具体的 controller 或 service 中定义;  
3
+避免因为 model 太多而导致混乱和难查;  

+ 69 - 0
models/admin_user_models.go View File

@@ -0,0 +1,69 @@
1
+package models
2
+
3
+type AdminUser struct {
4
+	Id           int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"` // 管理员用户 ID
5
+	Mobile       string `json:"mobile"`
6
+	Password     string `json:"password"`
7
+	IsSuperAdmin bool   `gorm:"column:is_super_admin" json:"is_super_admin"` // 是否为超级管理员
8
+	Status       int8   `json:"status"`                                      // 状态 0.无效 1.有效
9
+	CreateTime   int64  `gorm:"column:ctime" json:"ctime"`                   // 创建时间
10
+	ModifyTime   int64  `gorm:"column:mtime" json:"mtime"`                   // 修改时间
11
+}
12
+
13
+func (AdminUser) TableName() string {
14
+	return "sgj_user_admin"
15
+}
16
+
17
+type AdminUserLoginLog struct {
18
+	Id          int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT"` // 记录 ID
19
+	AdminUserId int64  `gorm:"column:admin_user_id"`
20
+	OrgId       int64  `gorm:"column:org_id"`
21
+	AppId       int64  `gorm:"column:app_id"`
22
+	IP          string `gorm:"column:ip"`
23
+	OperateType int8   `gorm:"column:operate_type"` // 操作类型(1.登录;2.退出;3.切换机构)
24
+	AppType     int8   `gorm:"column:app_type"`     // 应用类型,与 OrgApp.AppType 一致
25
+	CreateTime  int64  `gorm:"column:ctime"`        // 创建时间
26
+}
27
+
28
+func (AdminUserLoginLog) TableName() string {
29
+	return "sgj_user_admin_login_log"
30
+}
31
+
32
+type AdminUserElectronicSignature struct {
33
+	ID      int64  `gorm:"column:id" json:"id" form:"id"`
34
+	Creator int64  `gorm:"column:creator" json:"creator" form:"creator"`
35
+	OrgId   int64  `gorm:"column:org_id" json:"org_id" form:"org_id"`
36
+	AppId   int64  `gorm:"column:app_id" json:"app_id" form:"app_id"`
37
+	Url     string `gorm:"column:url" json:"url" form:"url"`
38
+	Hash    string `gorm:"column:hash" json:"hash" form:"hash"`
39
+	Status  int64  `gorm:"column:status" json:"status" form:"status"`
40
+	Ctime   int64  `gorm:"column:ctime" json:"ctime" form:"ctime"`
41
+	Mtime   int64  `gorm:"column:mtime" json:"mtime" form:"mtime"`
42
+}
43
+
44
+func (AdminUserElectronicSignature) TableName() string {
45
+	return "sgj_user_admin_electronic_signature"
46
+}
47
+
48
+// 管理员用户特殊权限,详见表注释
49
+type AdminUserSpecialPermission struct {
50
+	ID          int64 `gorm:"column:id" json:"id"`
51
+	OrgID       int64 `gorm:"column:org_id" json:"org_id"`
52
+	AppID       int64 `gorm:"column:app_id" json:"app_id"`
53
+	AdminUserID int64 `gorm:"column:admin_user_id" json:"admin_user_id"`
54
+	Permission  int64 `gorm:"column:permission" json:"permission"`
55
+	Status      int64 `gorm:"column:status" json:"-"`
56
+	CreateTime  int64 `gorm:"column:ctime" json:"-"`
57
+	ModifyTime  int64 `gorm:"column:mtime" json:"-"`
58
+}
59
+
60
+func (AdminUserSpecialPermission) TableName() string {
61
+	return "xt_admin_user_special_permission"
62
+}
63
+
64
+type SpecialPermissionType int64
65
+
66
+const (
67
+	_                              SpecialPermissionType = iota
68
+	SpecialPermissionTypeHeadNurse                       // 护士长
69
+)

+ 0 - 0
models/default.go View File


+ 50 - 0
models/org_models.go View File

@@ -0,0 +1,50 @@
1
+package models
2
+
3
+type Org struct {
4
+	Id              int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"` // 机构 ID
5
+	Creator         int64  `json:"creator"`                              // 创建者,即管理员用户的 id
6
+	OrgName         string `gorm:"column:org_name" json:"org_name"`
7
+	OrgShortName    string `gorm:"column:org_short_name" json:"org_short_name"` // 简称
8
+	OrgLogo         string `gorm:"column:org_logo" json:"org_logo"`
9
+	OrgIntroduction string `gorm:"column:org_introduction" json:"org_introduction"`
10
+	Province        int64  `json:"province"` // 省,代号,下面的市、区也一样
11
+	City            int64  `json:"city"`
12
+	District        int64  `json:"district"`
13
+	Address         string `json:"address"`                   // 详细地址
14
+	Illness         string `json:"illness"`                   // 服务病种 多个并用“,”隔开
15
+	Status          int8   `json:"status"`                    // 状态 0.无效 1.有效 2.禁用
16
+	CreateTime      int64  `gorm:"column:ctime" json:"ctime"` // 创建时间
17
+	ModifyTime      int64  `gorm:"column:mtime" json:"mtime"` // 修改时间
18
+}
19
+
20
+func (Org) TableName() string {
21
+	return "sgj_user_org"
22
+}
23
+
24
+type OrgApp struct {
25
+	Id         int64 `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"` // ID
26
+	AppType    int   `gorm:"column:app_type" json:"app_type"`      // 应用类型 1.病友经营;2.科普号;3.血透经营;4.慢病管理
27
+	Creator    int   `json:"creator"`                              // 创建者,即管理员用户的 id
28
+	OrgId      int   `gorm:"column:org_id" json:"org_id"`
29
+	Status     int8  `json:"status"`                    // 状态 0.无效 1.有效 2.禁用
30
+	CreateTime int64 `gorm:"column:ctime" json:"ctime"` // 创建时间
31
+	ModifyTime int64 `gorm:"column:mtime" json:"mtime"` // 修改时间
32
+}
33
+
34
+func (OrgApp) TableName() string {
35
+	return "sgj_user_org_app"
36
+}
37
+
38
+type OrgBan struct {
39
+	ID      int64  `gorm:"column:id" json:"id"`
40
+	OrgId   int64  `gorm:"column:org_id" json:"org_id"`
41
+	Reason  string `gorm:"column:reason" json:"reason"`
42
+	Ctime   int64  `gorm:"column:ctime" json:"ctime"`
43
+	BanTime int64  `gorm:"column:ban_time" json:"ban_time"`
44
+	Status  int64  `gorm:"column:status" json:"status"`
45
+	Mtime   int64  `gorm:"column:mtime" json:"mtime"`
46
+}
47
+
48
+func (OrgBan) TableName() string {
49
+	return "sgj_user_admin_org_ban"
50
+}

+ 37 - 0
models/purview_models.go View File

@@ -0,0 +1,37 @@
1
+package models
2
+
3
+type Purview struct {
4
+	Id                  int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"`
5
+	Parentid            int64  `json:"pid"`                                                // 父级ID
6
+	Module              int8   `json:"module"`                                             // 所属应用类型 1.病友经营;2.科普号;3.血透经营;4.慢病管理;
7
+	Name                string `json:"name"`                                               // 规则名称(也是菜单名)
8
+	Urlfor              string `json:"urlfor"`                                             // 规则唯一英文标识,(Controller.Method)
9
+	MenuIconClass       string `gorm:"menu_icon_class" json:"menu_icon_class"`             // 菜单图标的 css 样式
10
+	SuperAdminExclusive int8   `gorm:"super_admin_exclusive" json:"super_admin_exclusive"` // 是否为超级管理员专属 0否1是
11
+	Listorder           int    `json:"-"`                                                  // 排序ID
12
+	Status              int8   `json:"status"`                                             // 状态 0.无效 1.有效 2.禁用
13
+	CreateTime          int64  `gorm:"column:ctime" json:"-"`                              // 创建时间
14
+	ModifyTime          int64  `gorm:"column:mtime" json:"-"`                              // 修改时间
15
+
16
+	Link   string     `gorm:"-" json:"link"`   // urlfor 解析后的链接
17
+	Childs []*Purview `gorm:"-" json:"childs"` // 子节点
18
+}
19
+
20
+func (Purview) TableName() string {
21
+	return "sgj_user_purview"
22
+}
23
+
24
+type RolePurview struct {
25
+	Id         int64 `gorm:"PRIMARY_KEY;AUTO_INCREMENT"`
26
+	RoleId     int64
27
+	OrgId      int64
28
+	AppId      int64
29
+	PurviewIds string
30
+	Status     int8  // 状态 0.无效 1.有效 2.禁用
31
+	CreateTime int64 `gorm:"column:ctime"` // 创建时间
32
+	ModifyTime int64 `gorm:"column:mtime"` // 修改时间
33
+}
34
+
35
+func (RolePurview) TableName() string {
36
+	return "sgj_user_role_purview"
37
+}

+ 61 - 0
models/role_models.go View File

@@ -0,0 +1,61 @@
1
+package models
2
+
3
+type Role struct {
4
+	Id           int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"`
5
+	RoleName     string `gorm:"column:role_name" json:"name"`
6
+	RoleIntro    string `gorm:"column:role_introduction" json:"intro"`
7
+	Creator      int64  `json:"-"`
8
+	OrgId        int64  `gorm:"column:org_id" json:"-"`
9
+	AppId        int64  `gorm:"column:app_id" json:"-"`
10
+	IsSuperAdmin bool   `gorm:"column:is_super_admin" json:"-"`
11
+	Status       int8   `json:"status"`                // 状态 0.无效 1.有效 2.禁用
12
+	CreateTime   int64  `gorm:"column:ctime" json:"-"` // 创建时间
13
+	ModifyTime   int64  `gorm:"column:mtime" json:"-"` // 修改时间
14
+}
15
+
16
+func (Role) TableName() string {
17
+	return "sgj_user_role"
18
+}
19
+
20
+type App_Role struct {
21
+	Id          int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"`
22
+	AdminUserId int64  `gorm:"column:admin_user_id" json:"admin_user_id"`
23
+	OrgId       int64  `gorm:"column:org_id" json:"org_id"`
24
+	AppId       int64  `gorm:"column:app_id" json:"app_id"`
25
+	RoleId      int64  `gorm:"column:role_id" json:"role_id"`
26
+	Avatar      string `json:"avatar" json:"avatar"`
27
+	UserName    string `gorm:"column:user_name" json:"user_name"`   // 用户名称
28
+	Intro       string `json:"intro"`                               // 简介
29
+	UserType    int8   `gorm:"column:user_type" json:"user_type"`   // 用户类型(1.管理员;2.医生;3.护士;4.运营)
30
+	UserTitle   int8   `gorm:"column:user_title" json:"user_title"` // 用户职称(1.医士;2.医师;3.住院医师;4.主治医师;5.副主任医师;6.主任医师;7.护士;8.护师;9.主管护师;10.副主任护师;11.主任护师;12.运营专员;13.运营主管)
31
+	Status      int8   `json:"status"`                              // 状态 0.无效 1.有效
32
+	CreateTime  int64  `gorm:"column:ctime" json:"ctime"`           // 创建时间
33
+	ModifyTime  int64  `gorm:"column:mtime" json:"mtime"`           // 修改时间
34
+}
35
+
36
+func (App_Role) TableName() string {
37
+	return "sgj_user_admin_role"
38
+}
39
+
40
+var UserType = map[int]string{
41
+	1: "管理员",
42
+	2: "医生",
43
+	3: "护士",
44
+	4: "运营",
45
+}
46
+
47
+var UserTitle = map[int]string{
48
+	1:  "医士",
49
+	2:  "医师",
50
+	3:  "住院医师",
51
+	4:  "主治医师",
52
+	5:  "副主任医师",
53
+	6:  "主任医师",
54
+	7:  "护士",
55
+	8:  "护师",
56
+	9:  "主管护师",
57
+	10: "副主任护师",
58
+	11: "主任护师",
59
+	12: "运营专员",
60
+	13: "运营主管",
61
+}

+ 130 - 0
models/service_models.go View File

@@ -0,0 +1,130 @@
1
+package models
2
+
3
+import "time"
4
+
5
+type ServeOrder struct {
6
+	ID                    int64     `gorm:"column:id" json:"id"`
7
+	OrgId                 int64     `gorm:"column:org_id" json:"org_id"`
8
+	Period                int64     `gorm:"column:period" json:"period"`
9
+	PeriodStart           int64     `gorm:"column:period_start" json:"period_start"`
10
+	PeriodEnd             int64     `gorm:"column:period_end" json:"period_end"`
11
+	PeriodStartTime       time.Time `gorm:"column:period_start_time" json:"period_start_time"`
12
+	PeriodEndTime         time.Time `gorm:"column:period_end_time" json:"period_end_time"`
13
+	Status                int64     `gorm:"column:status" json:"status"`
14
+	CreatedTime           int64     `gorm:"column:created_time" json:"created_time"`
15
+	UpdatedTime           int64     `gorm:"column:updated_time" json:"updated_time"`
16
+	OrderNumber           string    `gorm:"column:order_number" json:"order_number"`
17
+	OrderStatus           int64     `gorm:"column:order_status" json:"order_status"`
18
+	PayType               int64     `gorm:"column:pay_type" json:"pay_type"`
19
+	PayTime               int64     `gorm:"column:pay_time" json:"pay_time"`
20
+	PaymentAmount         float64   `gorm:"column:payment_amount" json:"payment_amount"`
21
+	PayableAmount         float64   `gorm:"column:payable_amount" json:"payable_amount"`
22
+	DiscountableAmount    float64   `gorm:"column:discountable_amount" json:"discountable_amount"`
23
+	PaymentTransactionId  string    `gorm:"column:payment_transaction_id" json:"payment_transaction_id"`
24
+	ServeName             string    `gorm:"column:serve_name" json:"serve_name"`
25
+	ServeDesc             string    `gorm:"column:serve_desc" json:"serve_desc"`
26
+	ServeDuration         string    `gorm:"column:serve_duration" json:"serve_duration"`
27
+	OrderExpireTime       int64     `gorm:"column:order_expire_time" json:"order_expire_time"`
28
+	Price                 float64   `gorm:"column:price" json:"price"`
29
+	Quantity              int64     `gorm:"column:quantity" json:"quantity"`
30
+	ServeId               int64     `gorm:"column:serve_id" json:"serve_id"`
31
+	OrderExpireTimeFormat string    `gorm:"-"`
32
+}
33
+
34
+func (ServeOrder) TableName() string {
35
+	return "sgj_serve_order"
36
+}
37
+
38
+type ServeOrderInfomation struct {
39
+	ID          int64   `gorm:"column:id" json:"id"`
40
+	OrgId       int64   `gorm:"column:org_id" json:"org_id"`
41
+	OrderNumber string  `gorm:"column:order_number" json:"order_number"`
42
+	ProductId   int64   `gorm:"column:product_id" json:"product_id"`
43
+	ProductName string  `gorm:"column:product_name" json:"product_name"`
44
+	ProductDesc string  `gorm:"column:product_desc" json:"product_desc"`
45
+	Price       float64 `gorm:"column:price" json:"price"`
46
+	Quantity    int64   `gorm:"column:quantity" json:"quantity"`
47
+	MarketPrice float64 `gorm:"column:market_price" json:"market_price"`
48
+	Status      int64   `gorm:"column:status" json:"status"`
49
+}
50
+
51
+func (ServeOrderInfomation) TableName() string {
52
+	return "sgj_serve_order_infomation"
53
+}
54
+
55
+type ServeProduct struct {
56
+	ID            int64   `gorm:"column:id" json:"id"`
57
+	ServeName     string  `gorm:"column:serve_name" json:"serve_name"`
58
+	ServeDesc     string  `gorm:"column:serve_desc" json:"serve_desc"`
59
+	OriginalPrice float64 `gorm:"column:original_price" json:"original_price"`
60
+	Price         float64 `gorm:"column:price" json:"price"`
61
+	Status        int64   `gorm:"column:status" json:"status"`
62
+	CreatedTime   int64   `gorm:"column:created_time" json:"created_time"`
63
+	UpdatedTime   int64   `gorm:"column:updated_time" json:"updated_time"`
64
+	ServeDuration int64   `gorm:"column:serve_duration" json:"serve_duration"`
65
+	Edition       int64   `gorm:"column:edition" json:"edition"`
66
+}
67
+
68
+func (ServeProduct) TableName() string {
69
+	return "sgj_serve_product"
70
+}
71
+
72
+type ServeSubscibe struct {
73
+	ID              int64     `gorm:"column:id" json:"id"`
74
+	OrgId           int64     `gorm:"column:org_id" json:"org_id"`
75
+	PeriodStart     int64     `gorm:"column:period_start" json:"period_start"`
76
+	PeriodEnd       int64     `gorm:"column:period_end" json:"period_end"`
77
+	PeriodStartTime time.Time `gorm:"column:period_start_time" json:"period_start_time"`
78
+	PeriodEndTime   time.Time `gorm:"column:period_end_time" json:"period_end_time"`
79
+	Status          int64     `gorm:"column:status" json:"status"`
80
+	CreatedTime     int64     `gorm:"column:created_time" json:"created_time"`
81
+	UpdatedTime     int64     `gorm:"column:updated_time" json:"updated_time"`
82
+	State           int64     `gorm:"column:state" json:"state" form:"statstateus"`
83
+	Org             Org       `gorm:"ForeignKey:OrgId"`
84
+
85
+	Patients int64 `gorm:"-" json:"patients"`
86
+}
87
+
88
+func (ServeSubscibe) TableName() string {
89
+	return "sgj_serve_subscibe"
90
+}
91
+
92
+type ServeInvoice struct {
93
+	ID                      int64   `gorm:"column:id" json:"id" form:"id"`
94
+	InvoiceType             int64   `gorm:"column:invoice_type" json:"invoice_type" form:"invoice_type"`
95
+	OrgId                   int64   `gorm:"column:org_id" json:"org_id" form:"org_id"`
96
+	InvoiceTitle            string  `gorm:"column:invoice_title" json:"invoice_title" form:"invoice_title"`
97
+	InvoiceAmountGross      float64 `gorm:"column:invoice_amount_gross" json:"invoice_amount_gross" form:"invoice_amount_gross"`
98
+	Recipient               string  `gorm:"column:recipient" json:"recipient" form:"recipient"`
99
+	ContactPhone            string  `gorm:"column:contact_phone" json:"contact_phone" form:"contact_phone"`
100
+	Address                 string  `gorm:"column:address" json:"address" form:"address"`
101
+	TaxIdentificationNumber string  `gorm:"column:tax_identification_number" json:"tax_identification_number" form:"tax_identification_number"`
102
+	Remark                  string  `gorm:"column:remark" json:"remark" form:"remark"`
103
+	Status                  int64   `gorm:"column:status" json:"status" form:"status"`
104
+	CreatedTime             int64   `gorm:"column:created_time" json:"created_time" form:"created_time"`
105
+	UpdatedTime             int64   `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
106
+	Orders                  string  `gorm:"column:orders" json:"orders" form:"orders"`
107
+	InvoiceStatus           int64   `gorm:"column:invoice_status" json:"invoice_status" form:"invoice_status"`
108
+}
109
+
110
+func (ServeInvoice) TableName() string {
111
+	return "sgj_serve_invoice"
112
+}
113
+
114
+type ServeOrderContract struct {
115
+	ID             int64  `gorm:"column:id" json:"id" form:"id"`
116
+	OrgId          int64  `gorm:"column:org_id" json:"org_id" form:"org_id"`
117
+	OrderId        int64  `gorm:"column:order_id" json:"order_id" form:"order_id"`
118
+	OrderNumber    string `gorm:"column:order_number" json:"order_number" form:"order_number"`
119
+	CompanyTitle   string `gorm:"column:company_title" json:"company_title" form:"company_title"`
120
+	CompanyAddress string `gorm:"column:company_address" json:"company_address" form:"company_address"`
121
+	ContactPhone   string `gorm:"column:contact_phone" json:"contact_phone" form:"contact_phone"`
122
+	Contact        string `gorm:"column:contact" json:"contact" form:"contact"`
123
+	Status         int64  `gorm:"column:status" json:"status" form:"status"`
124
+	CreatedTime    int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
125
+	UpdatedTime    int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
126
+}
127
+
128
+func (ServeOrderContract) TableName() string {
129
+	return "sgj_serve_order_contract"
130
+}

+ 11 - 0
models/subscibe_state_models.go View File

@@ -0,0 +1,11 @@
1
+package models
2
+
3
+type ServeSubscibeState struct {
4
+	ServeSubscibe
5
+
6
+	State int64 `gorm:"-" json:"state"`
7
+}
8
+
9
+func (ServeSubscibeState) TableName() string {
10
+	return "sgj_serve_subscibe"
11
+}

+ 15 - 2
routers/router.go View File

@@ -1,11 +1,24 @@
1 1
 package routers
2 2
 
3 3
 import (
4
-	"SCRM/controllers"
4
+	"SCRM/controllers/admin"
5
+	"SCRM/controllers/global"
6
+	"SCRM/controllers/login"
5 7
 
6 8
 	"github.com/astaxie/beego"
9
+	"github.com/astaxie/beego/plugins/cors"
7 10
 )
8 11
 
9 12
 func init() {
10
-	beego.Router("/", &controllers.MainController{})
13
+	beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
14
+		AllowOrigins:     []string{"http://jk.kuyicloud.com", "http://localhost:9533", "http://test1.sgjyun.com", "https://www.ucpaas.com"},
15
+		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
16
+		AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
17
+		ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
18
+		AllowCredentials: true,
19
+	}))
20
+
21
+	global.RegisterRouters()
22
+	admin.RegisterRouters()
23
+	login.RegisterRouters()
11 24
 }

+ 5 - 0
service/Readme.md View File

@@ -0,0 +1,5 @@
1
+将 service 模块化;  
2
+通用的 redis 和 db 配置处在最外层;  
3
+具体的业务 service 按业务分模块(包);  
4
+在具体的模块包里定义 service 方法和 view model;  
5
+如果某个模块比较复杂,service 代码很多,则再将其业务细分,拆分为多个文件;  

+ 382 - 0
service/admin_service/verify_login_token_service.go View File

@@ -0,0 +1,382 @@
1
+package admin_service
2
+
3
+import (
4
+	"encoding/json"
5
+	"io/ioutil"
6
+	"net/http"
7
+	"net/url"
8
+	"strconv"
9
+	"time"
10
+
11
+	"SCRM/models"
12
+	"SCRM/service"
13
+	"SCRM/utils"
14
+
15
+	"github.com/astaxie/beego"
16
+)
17
+
18
+type AdminUserInfo struct {
19
+	AdminUser    *models.AdminUser                    `json:"user"`
20
+	CurrentOrgId int64                                `json:"current_org_id"`
21
+	CurrentAppId int64                                `json:"current_app_id"`
22
+	OrgIds       []int64                              `json:"org_ids"`
23
+	Orgs         map[int64]*models.Org                `json:"orgs"`
24
+	OrgAppIds    map[int64][]int64                    `json:"org_app_ids"`
25
+	OrgApps      map[int64](map[int64]*models.OrgApp) `json:"org_apps"`
26
+	App2OrgIds   map[int64]int64                      `json:"app_to_org_ids"`
27
+	AppRoles     map[int64]*models.App_Role           `json:"app_roles"`
28
+	AppPurviews  map[int64][]*models.Purview          `json:"app_purviews"`
29
+	AppUrlfors   map[int64][]string                   `json:"app_urlfors"`
30
+	Subscibes    map[int64]*models.ServeSubscibe      `json:"org_subscibes"`
31
+}
32
+
33
+type verifyTokenError struct {
34
+	Msg string
35
+}
36
+
37
+func (e *verifyTokenError) Error() string {
38
+	return e.Msg
39
+}
40
+
41
+// 验证 token 成功后返回的管理员用户的所有信息,包括:基本用户信息,所属的所有机构,机构下的所有应用,应用的用户权限
42
+// map 的数据格式为
43
+/*
44
+"admin_user": { AdminUser's json },
45
+current_org_id: 1,
46
+current_app_id: 11,
47
+"org_ids": [1, 2, 3],
48
+"orgs": { (org_id: Org_Obj)
49
+	1: { Org's json },
50
+	2: { Org's json },
51
+},
52
+"org_app_ids": { (org_id: org_app_ids)
53
+	1: [11, 12, 13],
54
+	2: [21, 22, 23],
55
+},
56
+"org_apps": { (org_id: {app_id: OrgApp_Obj})
57
+	1: {
58
+		11: { OrgApp's json },
59
+		12: { OrgApp's json },
60
+	},
61
+	2: {
62
+		21: { OrgApp's json },
63
+		22: { OrgApp's json },
64
+	},
65
+},
66
+"app_to_org_ids": { (app_id: org_id)
67
+	11: 1,
68
+	12: 1,
69
+	21: 2,
70
+	22: 2,
71
+},
72
+"app_roles": { (app_id: App_Role Obj)
73
+	11: {App_Role's json},
74
+	12: {App_Role's json},
75
+	21: {App_Role's json},
76
+},
77
+"purviews": { (app_id: [processed Purviews' json])
78
+	11: [
79
+		{Purview's json .childs[
80
+			{Purview's json},
81
+			{Purview's json},
82
+		]},
83
+		{Purview's json},
84
+	],
85
+	12: [
86
+		{Purview's json},
87
+		{Purview's json},
88
+	],
89
+},
90
+"purview_urlfors": { (app_id: [url_for])
91
+	11: [
92
+		"Controller1.Action1",
93
+		"Controller1.Action2",
94
+		"Controller2.Action1",
95
+		"Controller2.Action2",
96
+	],
97
+}
98
+应当注意的是,屈服于 Golang 令人恶心的类型机制,这里将所有数值型的 key 或 value 全部转成了 string
99
+*/
100
+// 解析用户信息,并返回
101
+func VerifyToken(token string, ip string, sessionID string) (*AdminUserInfo, error, int) {
102
+	// if len(sessionID) == 0 {
103
+	// 	return nil, &verifyTokenError{"sessionID 为空"}
104
+	// }
105
+	ssoDomain := beego.AppConfig.String("sso_domain")
106
+	api := ssoDomain + "/verifytoken"
107
+	values := make(url.Values)
108
+	values.Set("token", token)
109
+	values.Set("app_type", "1")
110
+	values.Set("ip", ip)
111
+	values.Set("session_id", sessionID)
112
+	resp, requestErr := http.PostForm(api, values)
113
+
114
+	if requestErr != nil {
115
+		utils.ErrorLog("请求验证 sso token 接口失败: %v", requestErr)
116
+		return nil, requestErr, 0
117
+	}
118
+	defer resp.Body.Close()
119
+	body, ioErr := ioutil.ReadAll(resp.Body)
120
+	if ioErr != nil {
121
+		utils.ErrorLog("验证 sso token 接口返回数据读取失败: %v", ioErr)
122
+		return nil, ioErr, 0
123
+	}
124
+	var respJSON map[string]interface{}
125
+	utils.InfoLog(string(body))
126
+	if err := json.Unmarshal([]byte(string(body)), &respJSON); err != nil {
127
+		utils.ErrorLog("验证 sso token 接口返回数据解析JSON失败: %v", err)
128
+		return nil, err, 0
129
+	}
130
+
131
+	if respJSON["state"].(float64) != 1 {
132
+		msg := respJSON["msg"].(string)
133
+		utils.ErrorLog("验证 sso token 接口请求失败: %v", msg)
134
+		return nil, &verifyTokenError{"验证 sso token 接口请求失败"}, int(respJSON["code"].(float64))
135
+	} else {
136
+		utils.SuccessLog("验证 sso token 成功")
137
+		return processAdminUserInfo(respJSON["data"].(map[string]interface{})), nil, 0
138
+	}
139
+}
140
+
141
+func processAdminUserInfo(data map[string]interface{}) *AdminUserInfo {
142
+	adminUser := processAdminUser(data)
143
+	currentOrgId, currentAppId := processCurrentOrgIDAndAppID(data)
144
+	orgIds := processOrgIds(data)
145
+	orgs := processOrgs(data)
146
+	orgAppIds := processOrgAppIds(data)
147
+	orgApps := processOrgApps(data)
148
+	app2OrgIds := processApp2OrgIds(data)
149
+	appRoles := processAppRoles(data)
150
+	appPurviews := processPurviews(data)
151
+	appUrlfors := processPurviewUrlfors(data)
152
+	orgSubscibes := processOrgSubscibes(data)
153
+	sessionAdminUserInfo := &AdminUserInfo{
154
+		AdminUser:    adminUser,
155
+		CurrentOrgId: currentOrgId,
156
+		CurrentAppId: currentAppId,
157
+		OrgIds:       orgIds,
158
+		Orgs:         orgs,
159
+		OrgAppIds:    orgAppIds,
160
+		OrgApps:      orgApps,
161
+		App2OrgIds:   app2OrgIds,
162
+		AppRoles:     appRoles,
163
+		AppPurviews:  appPurviews,
164
+		AppUrlfors:   appUrlfors,
165
+		Subscibes:    orgSubscibes,
166
+	}
167
+	return sessionAdminUserInfo
168
+}
169
+
170
+// "admin_user": { AdminUser's json },
171
+func processAdminUser(data map[string]interface{}) *models.AdminUser {
172
+	userJSONStr := data["admin_user"].(string)
173
+	var adminUser models.AdminUser
174
+	if err := json.Unmarshal([]byte(userJSONStr), &adminUser); err != nil {
175
+		utils.ErrorLog("解析用户信息失败:%v", err)
176
+		return nil
177
+	} else {
178
+		return &adminUser
179
+	}
180
+}
181
+
182
+// current_org_id: 1,
183
+// current_app_id: 11,
184
+func processCurrentOrgIDAndAppID(data map[string]interface{}) (int64, int64) {
185
+	orgIDStr := data["current_org_id"].(string)
186
+	appIDStr := data["current_app_id"].(string)
187
+	orgID, _ := strconv.Atoi(orgIDStr)
188
+	appID, _ := strconv.Atoi(appIDStr)
189
+	return int64(orgID), int64(appID)
190
+}
191
+
192
+// "org_ids": [1, 2, 3],
193
+func processOrgIds(data map[string]interface{}) []int64 {
194
+	orgIdStrs := data["org_ids"].([]interface{})
195
+	orgIds := make([]int64, 0, len(orgIdStrs))
196
+	for _, idstr := range orgIdStrs {
197
+		id, _ := strconv.Atoi(idstr.(string))
198
+		orgIds = append(orgIds, int64(id))
199
+	}
200
+	return orgIds
201
+}
202
+
203
+// "orgs": { (org_id: Org_Obj)
204
+// 	1: { Org's json },
205
+// 	2: { Org's json },
206
+// },
207
+func processOrgs(data map[string]interface{}) map[int64]*models.Org {
208
+	orgJSONs := data["orgs"].(map[string]interface{})
209
+	orgs := make(map[int64]*models.Org)
210
+	for orgIdStr, orgJSON := range orgJSONs {
211
+		orgId, _ := strconv.Atoi(orgIdStr)
212
+		var org models.Org
213
+		json.Unmarshal([]byte(orgJSON.(string)), &org)
214
+		orgs[int64(orgId)] = &org
215
+	}
216
+	return orgs
217
+}
218
+
219
+// "org_app_ids": { (org_id: org_app_ids)
220
+// 	1: [11, 12, 13],
221
+// 	2: [21, 22, 23],
222
+// },
223
+func processOrgAppIds(data map[string]interface{}) map[int64][]int64 {
224
+	orgAppIdStrs := data["org_app_ids"].(map[string]interface{})
225
+	orgAppIds := make(map[int64][]int64)
226
+	for orgIdStr, appIdStrs := range orgAppIdStrs {
227
+		orgId, _ := strconv.Atoi(orgIdStr)
228
+		appIds := make([]int64, 0, len(appIdStrs.([]interface{})))
229
+		for _, appIdStr := range appIdStrs.([]interface{}) {
230
+			appId, _ := strconv.Atoi(appIdStr.(string))
231
+			appIds = append(appIds, int64(appId))
232
+		}
233
+		orgAppIds[int64(orgId)] = appIds
234
+	}
235
+	return orgAppIds
236
+}
237
+
238
+// "org_apps": { (org_id: {app_id: OrgApp_Obj})
239
+// 	1: {
240
+// 		11: { OrgApp's json },
241
+// 		12: { OrgApp's json },
242
+// 	},
243
+// 	2: {
244
+// 		21: { OrgApp's json },
245
+// 		22: { OrgApp's json },
246
+// 	},
247
+// },
248
+func processOrgApps(data map[string]interface{}) map[int64]map[int64]*models.OrgApp {
249
+	orgAppJSONs := data["org_apps"].(map[string]interface{})
250
+	orgApps := make(map[int64]map[int64]*models.OrgApp)
251
+	for orgIdStr, appJSONStrMap := range orgAppJSONs {
252
+		orgId, _ := strconv.Atoi(orgIdStr)
253
+
254
+		apps := make(map[int64]*models.OrgApp)
255
+		for appIdStr, appJSONStr := range appJSONStrMap.(map[string]interface{}) {
256
+			appId, _ := strconv.Atoi(appIdStr)
257
+
258
+			var app models.OrgApp
259
+			json.Unmarshal([]byte(appJSONStr.(string)), &app)
260
+			apps[int64(appId)] = &app
261
+		}
262
+
263
+		orgApps[int64(orgId)] = apps
264
+	}
265
+	return orgApps
266
+}
267
+
268
+// "app_to_org_ids": { (app_id: org_id)
269
+// 	11: 1,
270
+// 	12: 1,
271
+// 	21: 2,
272
+// 	22: 2,
273
+// },
274
+func processApp2OrgIds(data map[string]interface{}) map[int64]int64 {
275
+	app2OrgIdStrs := data["app_to_org_ids"].(map[string]interface{})
276
+	app2OrgIds := make(map[int64]int64)
277
+	for appIdStr, orgIdStr := range app2OrgIdStrs {
278
+		orgId, _ := strconv.Atoi(orgIdStr.(string))
279
+		appId, _ := strconv.Atoi(appIdStr)
280
+		app2OrgIds[int64(appId)] = int64(orgId)
281
+	}
282
+	return app2OrgIds
283
+}
284
+
285
+// "app_roles": { (app_id: App_Role Obj)
286
+// 	11: {App_Role's json},
287
+// 	12: {App_Role's json},
288
+// 	21: {App_Role's json},
289
+// },
290
+func processAppRoles(data map[string]interface{}) map[int64]*models.App_Role {
291
+	appRoleJSONs := data["app_roles"].(map[string]interface{})
292
+	appRoles := make(map[int64]*models.App_Role)
293
+	for appIDStr, appRoleJSON := range appRoleJSONs {
294
+		appID, _ := strconv.Atoi(appIDStr)
295
+		var appRole models.App_Role
296
+		json.Unmarshal([]byte(appRoleJSON.(string)), &appRole)
297
+		appRoles[int64(appID)] = &appRole
298
+	}
299
+	return appRoles
300
+}
301
+
302
+// "purviews": { (app_id: [processed Purviews' json])
303
+// 	11: [
304
+// 		{Purview's json .childs[
305
+// 			{Purview's json},
306
+// 			{Purview's json},
307
+// 		]},
308
+// 		{Purview's json},
309
+// 	],
310
+// 	12: [
311
+// 		{Purview's json},
312
+// 		{Purview's json},
313
+// 	],
314
+// },
315
+func processPurviews(data map[string]interface{}) map[int64][]*models.Purview {
316
+	appPurviewJSONsStrs := data["purviews"].(map[string]interface{})
317
+	appPurviews := make(map[int64][]*models.Purview)
318
+	for appIdStr, purviewJSONsStr := range appPurviewJSONsStrs {
319
+		appId, _ := strconv.Atoi(appIdStr)
320
+		var purviews []*models.Purview
321
+		json.Unmarshal([]byte(purviewJSONsStr.(string)), &purviews)
322
+		// setLinkForPurviews(purviews)
323
+		appPurviews[int64(appId)] = purviews
324
+	}
325
+	return appPurviews
326
+}
327
+
328
+// func setLinkForPurviews(purviews []*models.Purview) {
329
+// 	for _, purview := range purviews {
330
+// 		if len(purview.Urlfor) == 0 {
331
+// 			purview.Link = ""
332
+// 		} else {
333
+// 			purview.Link = beego.URLFor(purview.Urlfor)
334
+// 		}
335
+// 		if purview.Childs == nil {
336
+// 			purview.Childs = make([]*models.Purview, 0)
337
+// 		} else {
338
+// 			setLinkForPurviews(purview.Childs)
339
+// 		}
340
+// 		// utils.TraceLog("%+v", purview)
341
+// 	}
342
+// }
343
+
344
+// "purview_urlfors": { (app_id: [url_for])
345
+// 	11: [
346
+// 		"Controller1.Action1",
347
+// 		"Controller1.Action2",
348
+// 		"Controller2.Action1",
349
+// 		"Controller2.Action2",
350
+// 	],
351
+// }
352
+func processPurviewUrlfors(data map[string]interface{}) map[int64][]string {
353
+	appUrlforsStrs := data["purview_urlfors"].(map[string]interface{})
354
+	appUrlfors := make(map[int64][]string)
355
+	for appIdStr, urlforsStr := range appUrlforsStrs {
356
+		appId, _ := strconv.Atoi(appIdStr)
357
+		var urlfors []string
358
+		json.Unmarshal([]byte(urlforsStr.(string)), &urlfors)
359
+		appUrlfors[int64(appId)] = urlfors
360
+	}
361
+	return appUrlfors
362
+}
363
+
364
+// "org_subscibes": { (org_id: ServeSubscibe)
365
+//  11: {ServeSubscibe's json}
366
+// },
367
+func processOrgSubscibes(data map[string]interface{}) map[int64]*models.ServeSubscibe {
368
+	subscibeJSONs := data["org_subscibes"].(map[string]interface{})
369
+	subscibes := make(map[int64]*models.ServeSubscibe)
370
+	for orgIDStr, subscibeJSON := range subscibeJSONs {
371
+		orgID, _ := strconv.Atoi(orgIDStr)
372
+		var subscibe models.ServeSubscibe
373
+		json.Unmarshal([]byte(subscibeJSON.(string)), &subscibe)
374
+		subscibes[int64(orgID)] = &subscibe
375
+	}
376
+	return subscibes
377
+}
378
+
379
+func ModifyPassword(adminID int64, password string) error {
380
+	err := service.UserWriteDB().Model(&models.AdminUser{}).Where("id = ? AND status = 1", adminID).Updates(map[string]interface{}{"password": password, "mtime": time.Now().Unix()}).Error
381
+	return err
382
+}

+ 109 - 0
service/db.go View File

@@ -0,0 +1,109 @@
1
+// Pipe - A small and beautiful blogging platform written in golang.
2
+// Copyright (C) 2017-2018, b3log.org
3
+//
4
+// This program is free software: you can redistribute it and/or modify
5
+// it under the terms of the GNU General Public License as published by
6
+// the Free Software Foundation, either version 3 of the License, or
7
+// (at your option) any later version.
8
+//
9
+// This program is distributed in the hope that it will be useful,
10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+// GNU General Public License for more details.
13
+//
14
+// You should have received a copy of the GNU General Public License
15
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
+
17
+package service
18
+
19
+import (
20
+	"fmt"
21
+
22
+	"github.com/astaxie/beego"
23
+	"github.com/jinzhu/gorm"
24
+	_ "github.com/jinzhu/gorm/dialects/mysql" // mysql
25
+)
26
+
27
+var readDb *gorm.DB
28
+var writeDb *gorm.DB
29
+var readUserDb *gorm.DB
30
+var writeUserDb *gorm.DB
31
+
32
+var err error
33
+
34
+func ConnectDB() {
35
+	readHost := beego.AppConfig.String("readmysqlhost")
36
+	readPort := beego.AppConfig.String("readmysqlport")
37
+	readUser := beego.AppConfig.String("readmysqluser")
38
+	readPass := beego.AppConfig.String("readmysqlpass")
39
+	readName := beego.AppConfig.String("readmysqlname")
40
+
41
+	writeHost := beego.AppConfig.String("writemysqlhost")
42
+	writePort := beego.AppConfig.String("writemysqlport")
43
+	writeUser := beego.AppConfig.String("writemysqluser")
44
+	writePass := beego.AppConfig.String("writemysqlpass")
45
+	writeName := beego.AppConfig.String("writemysqlname")
46
+
47
+	readUserHost := beego.AppConfig.String("readuserhost")
48
+	readUserPort := beego.AppConfig.String("readuserport")
49
+	readUserUser := beego.AppConfig.String("readuseruser")
50
+	readUserPass := beego.AppConfig.String("readuserpass")
51
+	readUserName := beego.AppConfig.String("readusername")
52
+
53
+	writeUserHost := beego.AppConfig.String("writeuserhost")
54
+	writeUserPort := beego.AppConfig.String("writeuserport")
55
+	writeUserUser := beego.AppConfig.String("writeuseruser")
56
+	writeUserPass := beego.AppConfig.String("writeuserpass")
57
+	writeUserName := beego.AppConfig.String("writeusername")
58
+
59
+	rdsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true", readUser, readPass, readHost, readPort, readName)
60
+	wdsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true", writeUser, writePass, writeHost, writePort, writeName)
61
+
62
+	rudsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true", readUserUser, readUserPass, readUserHost, readUserPort, readUserName)
63
+	wudsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true", writeUserUser, writeUserPass, writeUserHost, writeUserPort, writeUserName)
64
+
65
+	readDb, err = gorm.Open("mysql", rdsn)
66
+	if err != nil {
67
+		//beego.Error(err)
68
+	}
69
+	readDb.DB().SetMaxIdleConns(10)
70
+	readDb.DB().SetMaxOpenConns(100)
71
+	readDb.LogMode(true)
72
+
73
+	writeDb, err = gorm.Open("mysql", wdsn)
74
+	if err != nil {
75
+		//beego.Error(err)
76
+	}
77
+	writeDb.DB().SetMaxIdleConns(10)
78
+	writeDb.DB().SetMaxOpenConns(100)
79
+	writeDb.LogMode(true)
80
+
81
+	readUserDb, err = gorm.Open("mysql", rudsn)
82
+	if err != nil {
83
+		//beego.Error(err)
84
+	}
85
+	readUserDb.DB().SetMaxIdleConns(10)
86
+	readUserDb.DB().SetMaxOpenConns(100)
87
+	readUserDb.LogMode(true)
88
+
89
+	writeUserDb, err = gorm.Open("mysql", wudsn)
90
+	if err != nil {
91
+		//beego.Error(err)
92
+	}
93
+	writeUserDb.DB().SetMaxIdleConns(10)
94
+	writeUserDb.DB().SetMaxOpenConns(100)
95
+	writeUserDb.LogMode(true)
96
+}
97
+
98
+func XTReadDB() *gorm.DB {
99
+	return readDb
100
+}
101
+func XTWriteDB() *gorm.DB {
102
+	return writeDb
103
+}
104
+func UserReadDB() *gorm.DB {
105
+	return readUserDb
106
+}
107
+func UserWriteDB() *gorm.DB {
108
+	return writeUserDb
109
+}

+ 29 - 0
service/org_service/subscibe_service.go View File

@@ -0,0 +1,29 @@
1
+package org_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"errors"
6
+	"time"
7
+)
8
+
9
+func GetOrgSubscibeState(subscibe *models.ServeSubscibe) (err error) {
10
+	if subscibe == nil {
11
+		err = errors.New("没有订阅信息")
12
+		return
13
+	}
14
+
15
+	//免费试用版2,永久免费版9 不过期
16
+	if subscibe.State == 9 || subscibe.State == 2 {
17
+		return
18
+	}
19
+
20
+	timeNow := time.Now().Unix()
21
+	if timeNow < subscibe.PeriodStart || timeNow > subscibe.PeriodEnd {
22
+		subscibe.State = 3
23
+	}
24
+	if subscibe.State != 1 && subscibe.State != 8 {
25
+		subscibe.State = 3
26
+	}
27
+	return
28
+
29
+}

+ 21 - 0
service/redis.go View File

@@ -0,0 +1,21 @@
1
+package service
2
+
3
+import (
4
+	"fmt"
5
+
6
+	"github.com/astaxie/beego"
7
+	"github.com/go-redis/redis"
8
+)
9
+
10
+func RedisClient() *redis.Client {
11
+	address := fmt.Sprintf("%s:%s", beego.AppConfig.String("redishost"), beego.AppConfig.String("redisport"))
12
+	client := redis.NewClient(&redis.Options{
13
+		Addr:     address,
14
+		Password: beego.AppConfig.String("redispasswrod"), // no password set
15
+		DB:       0,                                       // use default DB
16
+	})
17
+
18
+	// pong, err := client.Ping().Result()
19
+	// fmt.Println(pong, err)
20
+	return client
21
+}

+ 407 - 0
service/role_service/role_service.go View File

@@ -0,0 +1,407 @@
1
+package role_service
2
+
3
+import (
4
+	"time"
5
+
6
+	"SCRM/models"
7
+	"SCRM/service"
8
+	"SCRM/utils"
9
+
10
+	"github.com/jinzhu/gorm"
11
+)
12
+
13
+func GetRoles(orgID int64, appID int64, page int, count int) ([]*models.Role, int, error) {
14
+	var roles []*models.Role
15
+	var totalCount int
16
+	err := service.UserReadDB().Model(&models.Role{}).
17
+		Where("org_id = ? AND app_id = ?", orgID, appID).
18
+		Count(&totalCount).
19
+		Order("ctime asc").Limit(count).Offset((page - 1) * count).
20
+		Find(&roles).
21
+		Error
22
+	if err != nil {
23
+		if err == gorm.ErrRecordNotFound {
24
+			return make([]*models.Role, 0), 0, nil
25
+		} else {
26
+			return nil, 0, err
27
+		}
28
+	}
29
+	return roles, totalCount, nil
30
+}
31
+
32
+func GetAppRole(orgID int64, appID int64, adminUserID int64) (*models.App_Role, error) {
33
+	var appRole models.App_Role
34
+	err := service.UserReadDB().Model(models.App_Role{}).Where("org_id = ? and app_id = ? and admin_user_id = ?", orgID, appID, adminUserID).First(&appRole).Error
35
+	if err != nil {
36
+		if err == gorm.ErrRecordNotFound {
37
+			return nil, nil
38
+		} else {
39
+			return nil, err
40
+		}
41
+	}
42
+	return &appRole, nil
43
+}
44
+
45
+func CreateRole(adminUserID int64, orgID int64, appID int64, name string, intro string) (*models.Role, error) {
46
+	role := models.Role{
47
+		RoleName:     name,
48
+		RoleIntro:    intro,
49
+		Creator:      adminUserID,
50
+		OrgId:        orgID,
51
+		AppId:        appID,
52
+		IsSuperAdmin: false,
53
+		Status:       1,
54
+		CreateTime:   time.Now().Unix(),
55
+		ModifyTime:   time.Now().Unix(),
56
+	}
57
+	tx := service.UserWriteDB().Begin()
58
+	if err := tx.Create(&role).Error; err != nil {
59
+		tx.Rollback()
60
+		return nil, err
61
+	}
62
+	tx.Commit()
63
+	return &role, nil
64
+}
65
+
66
+func GetRoleByRoleID(roleID int64) (*models.Role, error) {
67
+	var role models.Role
68
+	err := service.UserReadDB().Model(&models.Role{}).Where("id = ?", roleID).First(&role).Error
69
+	if err != nil {
70
+		if err == gorm.ErrRecordNotFound {
71
+			return nil, nil
72
+		}
73
+		return nil, err
74
+	} else {
75
+		return &role, nil
76
+	}
77
+}
78
+
79
+func ModifyRole(role *models.Role) error {
80
+	tx := service.UserWriteDB().Begin()
81
+	if err := tx.Save(role).Error; err != nil {
82
+		tx.Rollback()
83
+		return err
84
+	}
85
+	return tx.Commit().Error
86
+}
87
+
88
+// 拥有xx角色的管理员的数量
89
+func RoleAdminUserCount(orgID int64, appID int64, roleID int64) (int, error) {
90
+	var count int
91
+	err := service.UserReadDB().Model(models.App_Role{}).
92
+		Where("org_id = ? AND app_id = ? AND role_id = ? AND status = 1", orgID, appID, roleID).
93
+		Count(&count).
94
+		Error
95
+	if err != nil {
96
+		return 0, err
97
+	} else {
98
+		return count, nil
99
+	}
100
+}
101
+
102
+type AdminUserManageViewModel struct {
103
+	AdminUserId int    `gorm:"admin_user_id" json:"user_id"`
104
+	UserName    string `gorm:"user_name" json:"user_name"`
105
+	RoleName    string `gorm:"role_name" json:"role_name"`
106
+	UserTitle   int    `gorm:"user_title" json:"user_title"`
107
+	Ip          string `gorm:"ip" json:"ip"`
108
+	Ctime       int64  `gorm:"ctime" json:"last_login_time"`
109
+	Status      int    `gorm:"status" json:"status"`
110
+
111
+	// LastLoginTimeStr string `gorm:"-" json:"last_login_time_formatted"`
112
+	TitleName string `gorm:"-" json:"title_name"`
113
+}
114
+
115
+func GetAdminUsersAndLoginInfo(orgID int64, appID int64, page int, count int) ([]*AdminUserManageViewModel, int, error) {
116
+	if count <= 0 {
117
+		return []*AdminUserManageViewModel{}, 0, nil
118
+	}
119
+	if page < 1 {
120
+		page = 1
121
+	}
122
+	var viewModels []*AdminUserManageViewModel = make([]*AdminUserManageViewModel, 0)
123
+	userReadDB := service.UserReadDB()
124
+	rows, err := userReadDB.Raw("SELECT u_a_r.admin_user_id, u_a_r.user_name, u_r.role_name, u_a_r.user_title, u_l.ip, u_l.ctime, u_a_r.status FROM sgj_user_admin_role AS u_a_r INNER JOIN sgj_user_role AS u_r ON u_a_r.org_id = u_r.org_id AND u_a_r.app_id = u_r.app_id AND u_r.id = u_a_r.role_id LEFT JOIN (SELECT * FROM (SELECT admin_user_id, org_id, app_id, ip, ctime FROM sgj_user_admin_login_log WHERE org_id = ? AND app_id = ? ORDER BY ctime DESC) AS t GROUP BY admin_user_id) AS u_l ON u_a_r.org_id = u_l.org_id AND u_a_r.app_id = u_l.app_id AND u_a_r.admin_user_id = u_l.admin_user_id WHERE u_a_r.org_id = ? AND u_a_r.app_id = ? GROUP BY u_a_r.admin_user_id LIMIT ? OFFSET ?;", orgID, appID, orgID, appID, count, (page-1)*count).Rows()
125
+	defer rows.Close()
126
+	if err != nil {
127
+		if err == gorm.ErrRecordNotFound {
128
+			return viewModels, 0, nil
129
+		} else {
130
+			return nil, 0, err
131
+		}
132
+	}
133
+	for rows.Next() {
134
+		var viewModel AdminUserManageViewModel
135
+		userReadDB.ScanRows(rows, &viewModel)
136
+		title, _ := models.UserTitle[viewModel.UserTitle]
137
+		viewModel.TitleName = title
138
+		// if viewModel.Ctime == 0 {
139
+		// 	viewModel.LastLoginTimeStr = ""
140
+		// } else {
141
+		// 	loginTime := time.Unix(viewModel.Ctime, 0)
142
+		// 	viewModel.LastLoginTimeStr = loginTime.Format("2006-01-02 15:04")
143
+		// }
144
+		viewModels = append(viewModels, &viewModel)
145
+	}
146
+	total := 0
147
+	userReadDB.Table("sgj_user_admin_role as u_a_r").Joins("join sgj_user_role as u_r on u_r.org_id = u_a_r.org_id AND u_r.app_id = u_a_r.app_id AND u_r.id = u_a_r.role_id").Where("u_a_r.org_id = ? AND u_a_r.app_id = ?", orgID, appID).Count(&total)
148
+	return viewModels, total, nil
149
+}
150
+
151
+func GetValidRoleCount(orgID int64, appID int64, superAdminUserID int64) (int, error) {
152
+	var count int
153
+	err := service.UserReadDB().Model(models.Role{}).
154
+		Where("org_id = ? AND app_id = ? AND creator = ? AND is_super_admin = 0 AND status = 1", orgID, appID, superAdminUserID).
155
+		Count(&count).
156
+		Error
157
+	if err != nil {
158
+		return 0, err
159
+	} else {
160
+		return count, nil
161
+	}
162
+}
163
+
164
+func GetAllValidRoles(orgID int64, appID int64) ([]*models.Role, error) {
165
+	var roles []*models.Role
166
+	err := service.UserReadDB().Model(models.Role{}).
167
+		Where("org_id = ? AND app_id = ? AND status = 1", orgID, appID).
168
+		Order("ctime asc").
169
+		Find(&roles).
170
+		Error
171
+	if err != nil {
172
+		if err == gorm.ErrRecordNotFound {
173
+			return make([]*models.Role, 0), nil
174
+		} else {
175
+			return nil, err
176
+		}
177
+	}
178
+	return roles, nil
179
+}
180
+
181
+func IsRoleExist(orgID int64, appID int64, roleID int64) (bool, error) {
182
+	var count int
183
+	err := service.UserReadDB().Model(models.Role{}).Where("org_id = ? AND app_id = ? AND id = ? AND status = 1", orgID, appID, roleID).Count(&count).Error
184
+	if err != nil {
185
+		return false, err
186
+	} else {
187
+		return count > 0, nil
188
+	}
189
+}
190
+
191
+type AdminUserEditViewModel struct {
192
+	AdminUserId int64  `gorm:"admin_user_id" json:"user_id"`
193
+	UserName    string `gorm:"user_name" json:"user_name"`
194
+	Mobile      string `gorm:"mobile" json:"mobile"`
195
+	UserType    int    `gorm:"user_type" json:"user_type"`
196
+	UserTitle   int    `gorm:"user_title" json:"user_title"`
197
+	Intro       string `gorm:"intro" json:"intro"`
198
+	RoleId      int64  `gorm:"role_id" json:"role_id"`
199
+}
200
+
201
+func GetGeneralAdminUser(orgID int64, appID int64, user_id int64) (*AdminUserEditViewModel, error) {
202
+	rows, err := service.UserReadDB().Raw("SELECT u_a.mobile, u_a_r.admin_user_id, u_a_r.user_name, u_a_r.user_type, u_a_r.user_title, u_a_r.intro, u_a_r.role_id FROM sgj_user_admin AS u_a, sgj_user_admin_role AS u_a_r WHERE u_a.id = u_a_r.admin_user_id AND u_a.id = ? AND u_a_r.status = 1 AND u_a_r.org_id = ? AND u_a_r.app_id = ?;", user_id, orgID, appID).Rows()
203
+	defer rows.Close()
204
+	if err != nil {
205
+		if err == gorm.ErrRecordNotFound {
206
+			return nil, nil
207
+		} else {
208
+			return nil, err
209
+		}
210
+	}
211
+	if rows.Next() {
212
+		var viewModel AdminUserEditViewModel
213
+		err := service.UserReadDB().ScanRows(rows, &viewModel)
214
+		if err != nil {
215
+			return nil, err
216
+		} else {
217
+			return &viewModel, nil
218
+		}
219
+	}
220
+	return nil, nil
221
+}
222
+
223
+func SaveAppRole(appRole *models.App_Role) error {
224
+	tx := service.UserWriteDB().Begin()
225
+	if err := tx.Model(&models.App_Role{}).Save(appRole).Error; err != nil {
226
+		tx.Rollback()
227
+		return err
228
+	}
229
+	return tx.Commit().Error
230
+}
231
+
232
+func IsMobileDidUsedAtApp(orgID int64, appID int64, mobile string) (bool, error) {
233
+	var count int
234
+	rows, err := service.UserReadDB().Raw("select count(u_a.id) as count from sgj_user_admin as u_a, sgj_user_admin_role as u_a_r where u_a_r.org_id = ? and u_a_r.app_id = ? and u_a.mobile = ? and u_a.id = u_a_r.admin_user_id;", orgID, appID, mobile).Rows()
235
+	defer rows.Close()
236
+	if err != nil {
237
+		if err == gorm.ErrRecordNotFound {
238
+			return false, nil
239
+		} else {
240
+			return true, err
241
+		}
242
+	}
243
+	if rows.Next() {
244
+		rows.Scan(&count)
245
+		return count > 0, nil
246
+	}
247
+	return true, nil
248
+}
249
+
250
+func IsUserSuperAdminWithMobile(mobile string) (bool, error) {
251
+	var user models.AdminUser
252
+	err := service.UserReadDB().Where("mobile = ?", mobile).First(&user).Error
253
+	if err != nil {
254
+		if err == gorm.ErrRecordNotFound {
255
+			return false, nil
256
+		} else {
257
+			return false, err
258
+		}
259
+	}
260
+	return user.IsSuperAdmin, nil
261
+}
262
+
263
+func CreateGeneralAdminUser(orgID int64, appID int64, mobile string, name string, userType int, userTitle int, intro string, roleID int64) (*models.AdminUser, string, error) {
264
+	now := time.Now().Unix()
265
+	tx := service.UserWriteDB().Begin()
266
+	var adminUser models.AdminUser
267
+	err := service.UserReadDB().Where("mobile = ? AND status = 1", mobile).First(&adminUser).Error
268
+	password := ""
269
+	if err != nil {
270
+		if err != gorm.ErrRecordNotFound {
271
+			return nil, "", err
272
+		} else {
273
+			password = utils.RandomNumberString(6)
274
+			adminUser.Mobile = mobile
275
+			adminUser.Password = utils.String2md5(password)
276
+			adminUser.IsSuperAdmin = false
277
+			adminUser.Status = 1
278
+			adminUser.CreateTime = now
279
+			adminUser.ModifyTime = now
280
+			if createErr := tx.Create(&adminUser).Error; createErr != nil {
281
+				tx.Rollback()
282
+				return nil, "", createErr
283
+			}
284
+		}
285
+	}
286
+	app_role := models.App_Role{
287
+		AdminUserId: adminUser.Id,
288
+		OrgId:       orgID,
289
+		AppId:       appID,
290
+		RoleId:      roleID,
291
+		Avatar:      "",
292
+		UserName:    name,
293
+		Intro:       intro,
294
+		UserType:    int8(userType),
295
+		UserTitle:   int8(userTitle),
296
+		Status:      1,
297
+		CreateTime:  now,
298
+		ModifyTime:  now,
299
+	}
300
+	if createApp_RoleErr := tx.Create(&app_role).Error; createApp_RoleErr != nil {
301
+		tx.Rollback()
302
+		return nil, "", createApp_RoleErr
303
+	}
304
+
305
+	tx.Commit()
306
+	return &adminUser, password, nil
307
+}
308
+
309
+type PurviewTreeViewModel struct {
310
+	ID     int64                   `json:"id"`
311
+	PID    int64                   `json:"pid"`
312
+	Name   string                  `json:"name"`
313
+	Childs []*PurviewTreeViewModel `json:"childs"`
314
+}
315
+
316
+func GetAllGeneralPurviewVMsProcessed() ([]*PurviewTreeViewModel, error) {
317
+	var originPurviews []*models.Purview
318
+	getPurviewErr := service.UserReadDB().Model(models.Purview{}).Where("module = 3 AND status = 1 AND super_admin_exclusive = 0").Order("listorder asc").Order("id asc").Find(&originPurviews).Error
319
+	if getPurviewErr != nil {
320
+		return nil, getPurviewErr
321
+	}
322
+	// 加工这些规则:树形化
323
+	purviewVMs := make([]*PurviewTreeViewModel, 0)
324
+	pid_childs := make(map[int64][]*PurviewTreeViewModel)
325
+	for _, purview := range originPurviews {
326
+		// warning:下面这个算法只适用最多两层树形结构的菜单,对于两层以上的会丢失掉第三层及其以下的节点
327
+		// 因为取出 originPurviews 的时候已经排过序了,所以顶级节点肯定最先处理,不需要担心子节点比父节点先处理
328
+		pvm := &PurviewTreeViewModel{
329
+			ID:   purview.Id,
330
+			PID:  purview.Parentid,
331
+			Name: purview.Name,
332
+		}
333
+		if purview.Parentid == 0 {
334
+			purviewVMs = append(purviewVMs, pvm)
335
+		} else {
336
+			childs := pid_childs[purview.Parentid]
337
+			if childs == nil {
338
+				childs = make([]*PurviewTreeViewModel, 0)
339
+			}
340
+			childs = append(childs, pvm)
341
+			pid_childs[purview.Parentid] = childs
342
+		}
343
+	}
344
+
345
+	for _, vm := range purviewVMs {
346
+		vm.Childs = pid_childs[vm.ID]
347
+	}
348
+
349
+	return purviewVMs, nil
350
+}
351
+
352
+func GetRolePurviewIds(roleID int64) (string, error) {
353
+	var rolePurview models.RolePurview
354
+	err := service.UserReadDB().Where("role_id = ?", roleID).First(&rolePurview).Error
355
+	if err != nil {
356
+		if err == gorm.ErrRecordNotFound {
357
+			return "", nil
358
+		} else {
359
+			return "", err
360
+		}
361
+	}
362
+	return rolePurview.PurviewIds, nil
363
+}
364
+
365
+func SaveRolePurviewIds(orgID int64, appID int64, roleID int64, purviewIds string) error {
366
+	var rolePurview models.RolePurview
367
+	getRPErr := service.UserReadDB().Where("org_id = ? AND app_id = ? AND role_id = ?", orgID, appID, roleID).First(&rolePurview).Error
368
+	if getRPErr != nil {
369
+		if getRPErr == gorm.ErrRecordNotFound {
370
+			rolePurview = models.RolePurview{
371
+				RoleId:     roleID,
372
+				OrgId:      orgID,
373
+				AppId:      appID,
374
+				Status:     1,
375
+				CreateTime: time.Now().Unix(),
376
+			}
377
+		} else {
378
+			return getRPErr
379
+		}
380
+	}
381
+	rolePurview.PurviewIds = purviewIds
382
+	rolePurview.ModifyTime = time.Now().Unix()
383
+	tx := service.UserWriteDB().Begin()
384
+	if err := tx.Save(&rolePurview).Error; err != nil {
385
+		tx.Rollback()
386
+		return err
387
+	}
388
+	return tx.Commit().Error
389
+}
390
+
391
+func ModifyAdminUserInfo(adminUserID int64, orgID int64, appID int64, name string, avatar string, newPassword string) error {
392
+	tx := service.UserWriteDB().Begin()
393
+	editInfoErr := tx.Exec("update sgj_user_admin_role set user_name = ?, avatar = ?, mtime = ? where admin_user_id = ? and org_id = ?", name, avatar, time.Now().Unix(), adminUserID, orgID).Error
394
+	if editInfoErr != nil {
395
+		tx.Rollback()
396
+		return editInfoErr
397
+	}
398
+	if len(newPassword) > 0 {
399
+		editPwdErr := tx.Exec("update sgj_user_admin set password = ?, mtime = ? where id = ?", newPassword, time.Now().Unix(), adminUserID).Error
400
+		if editPwdErr != nil {
401
+			tx.Rollback()
402
+			return editPwdErr
403
+		}
404
+	}
405
+	tx.Commit()
406
+	return nil
407
+}

+ 13 - 0
utils/ip_helper.go View File

@@ -0,0 +1,13 @@
1
+package utils
2
+
3
+import (
4
+	"net/http"
5
+)
6
+
7
+func GetIP(r *http.Request) string {
8
+	ip := r.Header.Get("X-Forwarded-For")
9
+	if ip == "" {
10
+		ip = r.RemoteAddr
11
+	}
12
+	return ip
13
+}

+ 66 - 0
utils/log.go View File

@@ -0,0 +1,66 @@
1
+package utils
2
+
3
+import (
4
+	"fmt"
5
+	"time"
6
+)
7
+
8
+const (
9
+	color_red = uint8(iota + 91)
10
+	color_green
11
+	color_yellow
12
+	color_blue
13
+	color_magenta //洋红
14
+
15
+	// info = "[INFO]"
16
+	// trac = "[TRAC]"
17
+	// erro = "[ERRO]"
18
+	// warn = "[WARN]"
19
+	// succ = "[SUCC]"
20
+)
21
+
22
+// 根据 https://github.com/liyu4/chill 修改的
23
+// see complete color rules in document in https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-ecma48-13
24
+func TraceLog(format string, a ...interface{}) {
25
+	fmt.Println(formatLog(yellow(fmt.Sprintf(format, a...))))
26
+}
27
+
28
+func InfoLog(format string, a ...interface{}) {
29
+	fmt.Println(formatLog(blue(fmt.Sprintf(format, a...))))
30
+}
31
+
32
+func SuccessLog(format string, a ...interface{}) {
33
+	fmt.Println(formatLog(green(fmt.Sprintf(format, a...))))
34
+}
35
+
36
+func WarningLog(format string, a ...interface{}) {
37
+	fmt.Println(formatLog(magenta(fmt.Sprintf(format, a...))))
38
+}
39
+
40
+func ErrorLog(format string, a ...interface{}) {
41
+	fmt.Println(formatLog(red(fmt.Sprintf(format, a...))))
42
+}
43
+
44
+func red(s string) string {
45
+	return fmt.Sprintf("\x1b[%dm%s\x1b[0m", color_red, s)
46
+}
47
+
48
+func green(s string) string {
49
+	return fmt.Sprintf("\x1b[%dm%s\x1b[0m", color_green, s)
50
+}
51
+
52
+func yellow(s string) string {
53
+	return fmt.Sprintf("\x1b[%dm%s\x1b[0m", color_yellow, s)
54
+}
55
+
56
+func blue(s string) string {
57
+	return fmt.Sprintf("\x1b[%dm%s\x1b[0m", color_blue, s)
58
+}
59
+
60
+func magenta(s string) string {
61
+	return fmt.Sprintf("\x1b[%dm%s\x1b[0m", color_magenta, s)
62
+}
63
+
64
+func formatLog(prefix string) string {
65
+	return time.Now().Format("[2006/01/02 15:04:05]") + " " + prefix + " "
66
+}

+ 191 - 0
utils/paginator.go View File

@@ -0,0 +1,191 @@
1
+// Copyright 2013 wetalk authors
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
4
+// not use this file except in compliance with the License. You may obtain
5
+// a copy of the License at
6
+//
7
+//     http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+// License for the specific language governing permissions and limitations
13
+// under the License.
14
+
15
+package utils
16
+
17
+import (
18
+	"math"
19
+	"net/http"
20
+	"net/url"
21
+	"strconv"
22
+)
23
+
24
+type Paginator struct {
25
+	Request     *http.Request
26
+	PerPageNums int
27
+	MaxPages    int
28
+
29
+	nums      int64
30
+	pageRange []int
31
+	pageNums  int
32
+	page      int
33
+}
34
+
35
+func (p *Paginator) PageNums() int {
36
+	if p.pageNums != 0 {
37
+		return p.pageNums
38
+	}
39
+	pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums))
40
+	if p.MaxPages > 0 {
41
+		pageNums = math.Min(pageNums, float64(p.MaxPages))
42
+	}
43
+	p.pageNums = int(pageNums)
44
+	return p.pageNums
45
+}
46
+
47
+func (p *Paginator) Nums() int64 {
48
+	return p.nums
49
+}
50
+
51
+func (p *Paginator) SetNums(nums int64) {
52
+	p.nums = nums
53
+}
54
+
55
+func (p *Paginator) Page() int {
56
+	if p.page != 0 {
57
+		return p.page
58
+	}
59
+	if p.Request.Form == nil {
60
+		p.Request.ParseForm()
61
+	}
62
+	p.page, _ = strconv.Atoi(p.Request.Form.Get("page"))
63
+	if p.page > p.PageNums() {
64
+		p.page = p.PageNums()
65
+	}
66
+	if p.page <= 0 {
67
+		p.page = 1
68
+	}
69
+	return p.page
70
+}
71
+
72
+func (p *Paginator) Pages() []int {
73
+	if p.pageRange == nil && p.nums > 0 {
74
+		var pages []int
75
+		pageNums := p.PageNums()
76
+		page := p.Page()
77
+		switch {
78
+		case page >= pageNums-4 && pageNums > 9:
79
+			start := pageNums - 9 + 1
80
+			pages = make([]int, 9)
81
+			for i, _ := range pages {
82
+				pages[i] = start + i
83
+			}
84
+		case page >= 5 && pageNums > 9:
85
+			start := page - 5 + 1
86
+			pages = make([]int, int(math.Min(9, float64(page+4+1))))
87
+			for i, _ := range pages {
88
+				pages[i] = start + i
89
+			}
90
+		default:
91
+			pages = make([]int, int(math.Min(9, float64(pageNums))))
92
+			for i, _ := range pages {
93
+				pages[i] = i + 1
94
+			}
95
+		}
96
+		p.pageRange = pages
97
+	}
98
+	return p.pageRange
99
+}
100
+
101
+func (p *Paginator) PageLink(page int) string {
102
+	link, _ := url.ParseRequestURI(p.Request.RequestURI)
103
+	values := link.Query()
104
+	if page == 1 {
105
+		values.Del("page")
106
+	} else {
107
+		values.Set("page", strconv.Itoa(page))
108
+	}
109
+	link.RawQuery = values.Encode()
110
+	return link.String()
111
+}
112
+
113
+func (p *Paginator) PageParams() url.Values {
114
+	link, _ := url.ParseRequestURI(p.Request.RequestURI)
115
+	values := link.Query()
116
+	values.Del("page")
117
+	return values
118
+}
119
+
120
+func (p *Paginator) BasePageLink() string {
121
+	link, _ := url.ParseRequestURI(p.Request.RequestURI)
122
+	values := link.Query()
123
+	values.Del("page")
124
+	link.RawQuery = values.Encode()
125
+	return link.String()
126
+}
127
+
128
+func (p *Paginator) PageLinkPrev() (link string) {
129
+	if p.HasPrev() {
130
+		link = p.PageLink(p.Page() - 1)
131
+	}
132
+	return
133
+}
134
+
135
+func (p *Paginator) PageLinkNext() (link string) {
136
+	if p.HasNext() {
137
+		link = p.PageLink(p.Page() + 1)
138
+	}
139
+	return
140
+}
141
+
142
+func (p *Paginator) PageLinkFirst() (link string) {
143
+	return p.PageLink(1)
144
+}
145
+
146
+func (p *Paginator) PageLinkLast() (link string) {
147
+	return p.PageLink(p.PageNums())
148
+}
149
+
150
+func (p *Paginator) HasPrev() bool {
151
+	return p.Page() > 1
152
+}
153
+
154
+func (p *Paginator) HasNext() bool {
155
+	return p.Page() < p.PageNums()
156
+}
157
+
158
+func (p *Paginator) IsActive(page int) bool {
159
+	return p.Page() == page
160
+}
161
+
162
+func (p *Paginator) Offset() int {
163
+	return (p.Page() - 1) * p.PerPageNums
164
+}
165
+
166
+func (p *Paginator) HasPages() bool {
167
+	return p.PageNums() > 1
168
+}
169
+
170
+func (p *Paginator) Total() int {
171
+	return p.PageNums()
172
+}
173
+func (p *Paginator) TotalSubOne() int {
174
+	return p.PageNums() - 1
175
+}
176
+
177
+func NewPaginator(req *http.Request, per int, nums int64) *Paginator {
178
+	p := Paginator{}
179
+	p.Request = req
180
+	if per <= 0 {
181
+		per = 10
182
+	}
183
+	p.PerPageNums = per
184
+	p.SetNums(nums)
185
+	return &p
186
+}
187
+
188
+func FakePaginator(currentPage int, per int, nums int64) *Paginator {
189
+	fakeReq, _ := http.NewRequest("GET", "/?page="+strconv.Itoa(currentPage), nil)
190
+	return NewPaginator(fakeReq, per, nums)
191
+}

+ 75 - 0
utils/regex_helper.go View File

@@ -0,0 +1,75 @@
1
+package utils
2
+
3
+import (
4
+	"fmt"
5
+	"regexp"
6
+)
7
+
8
+// 正整数正则
9
+func PositiveIntegerRegexp() *regexp.Regexp {
10
+	reg, _ := regexp.Compile("^[1-9][0-9]*$")
11
+	return reg
12
+}
13
+
14
+// 手机号正则 不那么严谨的
15
+func CellPhoneRegexp() *regexp.Regexp {
16
+	reg, _ := regexp.Compile("^1\\d{10}$")
17
+	return reg
18
+}
19
+
20
+// 固话正则
21
+func TelPhoneRegexp() *regexp.Regexp {
22
+	// reg, _ := regexp.Compile("^0\\d{2,3}-?\\d{7,8}$")
23
+	reg, _ := regexp.Compile("^0\\d{2,3}-?\\d{7,8}$")
24
+	return reg
25
+}
26
+
27
+// 手机号或固话正则
28
+func PhoneRegexp() *regexp.Regexp {
29
+	reg, _ := regexp.Compile("^(0\\d{2,3}-?\\d{7,8}$)|(1\\d{10}$)")
30
+	return reg
31
+}
32
+
33
+// tests
34
+func PositiveIntegerRegexpTest() {
35
+	reg := PositiveIntegerRegexp()
36
+	fmt.Println("12 是否匹配:", reg.MatchString("12"))
37
+	fmt.Println("1 是否匹配:", reg.MatchString("1"))
38
+	fmt.Println("980030 是否匹配:", reg.MatchString("980030"))
39
+	fmt.Println("01 是否匹配:", reg.MatchString("01"))
40
+	fmt.Println("asd1asd 是否匹配:", reg.MatchString("asd1asd"))
41
+	fmt.Println("a12 是否匹配:", reg.MatchString("a12"))
42
+	fmt.Println("12a 是否匹配:", reg.MatchString("12a"))
43
+	fmt.Println("-12 是否匹配:", reg.MatchString("-12"))
44
+	fmt.Println("12.1 是否匹配:", reg.MatchString("12.1"))
45
+	fmt.Println("14j2a 是否匹配:", reg.MatchString("14j2a"))
46
+}
47
+
48
+func CellPhoneRegexpTest() {
49
+	reg := CellPhoneRegexp()
50
+	fmt.Println("13632250447 是否匹配:", reg.MatchString("13632250447"))
51
+	fmt.Println("12000000000 是否匹配:", reg.MatchString("12000000000"))
52
+	fmt.Println("30001212325 是否匹配:", reg.MatchString("30001212325"))
53
+	fmt.Println("1233123 是否匹配:", reg.MatchString("1233123"))
54
+	fmt.Println("123312312344 是否匹配:", reg.MatchString("123312312344"))
55
+	fmt.Println("13345678a12 是否匹配:", reg.MatchString("13345678a12"))
56
+	fmt.Println("a13345678a1 是否匹配:", reg.MatchString("a13345678a1"))
57
+	fmt.Println("1334a678a12 是否匹配:", reg.MatchString("1334a678a12"))
58
+	fmt.Println("1345678a12a 是否匹配:", reg.MatchString("1345678a12a"))
59
+	fmt.Println("aqwertyuioo 是否匹配:", reg.MatchString("aqwertyuioo"))
60
+}
61
+
62
+func TelPhoneRegexpTest() {
63
+	reg := TelPhoneRegexp()
64
+	fmt.Println("020-39006917 是否匹配:", reg.MatchString("020-39006917"))
65
+	fmt.Println("02039006917 是否匹配:", reg.MatchString("02039006917"))
66
+	fmt.Println("0754-5916612 是否匹配:", reg.MatchString("0754-5916612"))
67
+	fmt.Println("07545916612 是否匹配:", reg.MatchString("07545916612"))
68
+	fmt.Println("123-39006917 是否匹配:", reg.MatchString("123-39006917"))
69
+	fmt.Println("1754-5916612 是否匹配:", reg.MatchString("1754-5916612"))
70
+	fmt.Println("0a0-39006917 是否匹配:", reg.MatchString("0a0-39006917"))
71
+	fmt.Println("0a039006917 是否匹配:", reg.MatchString("0a039006917"))
72
+	fmt.Println("010-39s06917 是否匹配:", reg.MatchString("010-39s06917"))
73
+	fmt.Println("020-390069171 是否匹配:", reg.MatchString("020-390069171"))
74
+	fmt.Println("020-3900691 是否匹配:", reg.MatchString("020-3900691"))
75
+}

+ 115 - 0
utils/stringtool.go View File

@@ -0,0 +1,115 @@
1
+package utils
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/aes"
6
+	"crypto/cipher"
7
+	"crypto/md5"
8
+	"encoding/base64"
9
+	"fmt"
10
+	"math/rand"
11
+	"strconv"
12
+	"strings"
13
+	"time"
14
+
15
+	"github.com/astaxie/beego"
16
+)
17
+
18
+// 将字符串加密成 md5
19
+func String2md5(str string) string {
20
+	data := []byte(str)
21
+	has := md5.Sum(data)
22
+	return fmt.Sprintf("%x", has) //将[]byte转成16进制
23
+}
24
+
25
+// RandomString 在数字、大写字母、小写字母范围内生成num位的随机字符串
26
+func RandomString(length int) string {
27
+	// 48 ~ 57 数字
28
+	// 65 ~ 90 A ~ Z
29
+	// 97 ~ 122 a ~ z
30
+	// 一共62个字符,在0~61进行随机,小于10时,在数字范围随机,
31
+	// 小于36在大写范围内随机,其他在小写范围随机
32
+	rand.Seed(time.Now().UnixNano())
33
+	result := make([]string, 0, length)
34
+	for i := 0; i < length; i++ {
35
+		t := rand.Intn(62)
36
+		if t < 10 {
37
+			result = append(result, strconv.Itoa(rand.Intn(10)))
38
+		} else if t < 36 {
39
+			result = append(result, string(rand.Intn(26)+65))
40
+		} else {
41
+			result = append(result, string(rand.Intn(26)+97))
42
+		}
43
+	}
44
+	return strings.Join(result, "")
45
+}
46
+
47
+func RandomNumberString(length int) string {
48
+	var str string
49
+	for i := 0; i < length; i++ {
50
+		rand.Seed(time.Now().UnixNano())
51
+		str += strconv.Itoa(rand.Intn(10))
52
+	}
53
+	return str
54
+}
55
+
56
+// AES加密
57
+func AESEncrypt(origin string) string {
58
+	aes_key := beego.AppConfig.String("aes_key")
59
+	fmt.Println(aes_key)
60
+	xpass, _ := _aesEncrypt([]byte(origin), []byte(aes_key))
61
+	fmt.Println(_aesEncrypt([]byte(origin), []byte(aes_key)))
62
+	fmt.Println(xpass)
63
+	pass64 := base64.StdEncoding.EncodeToString(xpass)
64
+	fmt.Println(pass64)
65
+	return pass64
66
+}
67
+
68
+func AESDecrypt(crypted []byte) string {
69
+	aes_key := beego.AppConfig.String("aes_key")
70
+	origData, err := _aesDecrypt(crypted, []byte(aes_key))
71
+	if err != nil {
72
+		return ""
73
+	}
74
+	return string(origData)
75
+}
76
+
77
+func _PKCS5Padding(ciphertext []byte, blockSize int) []byte {
78
+	padding := blockSize - len(ciphertext)%blockSize
79
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
80
+	return append(ciphertext, padtext...)
81
+}
82
+
83
+func _PKCS5UnPadding(origData []byte) []byte {
84
+	length := len(origData)
85
+	unpadding := int(origData[length-1])
86
+	return origData[:(length - unpadding)]
87
+}
88
+
89
+func _aesEncrypt(origData, key []byte) ([]byte, error) {
90
+	block, err := aes.NewCipher(key)
91
+	if err != nil {
92
+		return nil, err
93
+	}
94
+
95
+	blockSize := block.BlockSize()
96
+	origData = _PKCS5Padding(origData, blockSize)
97
+	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
98
+	crypted := make([]byte, len(origData))
99
+	blockMode.CryptBlocks(crypted, origData)
100
+	return crypted, nil
101
+}
102
+
103
+func _aesDecrypt(crypted, key []byte) ([]byte, error) {
104
+	block, err := aes.NewCipher(key)
105
+	if err != nil {
106
+		return nil, err
107
+	}
108
+
109
+	blockSize := block.BlockSize()
110
+	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
111
+	origData := make([]byte, len(crypted))
112
+	blockMode.CryptBlocks(origData, crypted)
113
+	origData = _PKCS5UnPadding(origData)
114
+	return origData, nil
115
+}

+ 27 - 0
utils/time_helper.go View File

@@ -0,0 +1,27 @@
1
+package utils
2
+
3
+import (
4
+	"time"
5
+)
6
+
7
+// day 当天凌晨0点
8
+func ZeroHourTimeOfDay(day time.Time) time.Time {
9
+	dayStr := day.Format("2006-01-02")
10
+	zeroHourTime, _ := ParseTimeStringToTime("2006-01-02", dayStr)
11
+	return *zeroHourTime
12
+}
13
+
14
+// day 当月一号凌晨0点
15
+func BeginningOfMonth(day time.Time) time.Time {
16
+	dayStr := day.Format("2006-01")
17
+	monthTime, _ := ParseTimeStringToTime("2006-01", dayStr)
18
+	return *monthTime
19
+}
20
+
21
+// 指定年月的月份的月初凌晨0点和月末23点59分59秒
22
+func MonthBeginningToEnd(year int, month int) (time.Time, time.Time) {
23
+	beginningOfMonth := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.Local)
24
+	beginningOfNextMonth := beginningOfMonth.AddDate(0, 1, 0)
25
+	endOfMonth := beginningOfNextMonth.Add(time.Duration(-1))
26
+	return beginningOfMonth, endOfMonth
27
+}

+ 230 - 0
utils/tools.go View File

@@ -0,0 +1,230 @@
1
+package utils
2
+
3
+import (
4
+	"crypto/sha1"
5
+	"encoding/base64"
6
+	"errors"
7
+	"fmt"
8
+	"io"
9
+	"math/rand"
10
+	"regexp"
11
+	"sort"
12
+	"strconv"
13
+	"strings"
14
+	"time"
15
+
16
+	"github.com/astaxie/beego"
17
+)
18
+
19
+func TimeSub(t1, t2 time.Time) int {
20
+	t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
21
+	t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)
22
+
23
+	return int(t1.Sub(t2).Hours() / 24)
24
+}
25
+
26
+func MarkBackUrl(backUrl, defaultUrl string) string {
27
+	if len(backUrl) == 0 {
28
+		backUrl = defaultUrl
29
+	} else {
30
+		backURLByte, err := base64.URLEncoding.DecodeString(backUrl)
31
+		if err != nil {
32
+			backUrl = backUrl
33
+		} else {
34
+			backUrl = string(backURLByte)
35
+		}
36
+	}
37
+	return backUrl
38
+}
39
+
40
+func CheckMobile(mobile string) (match bool) {
41
+	//过滤手机
42
+	match, _ = regexp.MatchString("^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$", mobile)
43
+	return
44
+}
45
+
46
+func RandCode(min, max int64) string {
47
+	if min >= max || min == 0 || max == 0 {
48
+		return strconv.FormatInt(max, 10)
49
+	}
50
+	rand.Seed(time.Now().UnixNano())
51
+	randNum := rand.Int63n(max-min) + min
52
+	return strconv.FormatInt(randNum, 10)
53
+}
54
+
55
+func TimeAgo(timeUnix int64) string {
56
+	timeUnixS := time.Unix(timeUnix, 0)
57
+	timeNow := time.Now()
58
+	timeSub := timeNow.Sub(timeUnixS)
59
+
60
+	if timeSub < time.Minute*1 {
61
+		return "刚刚"
62
+	} else if timeSub < time.Hour*1 {
63
+		return strconv.Itoa(int(timeSub.Minutes())) + "分钟前"
64
+	} else if timeSub < time.Hour*24 {
65
+		return strconv.Itoa(int(timeSub.Hours())) + "小时前"
66
+	} else if timeSub < time.Hour*24*7 {
67
+		return strconv.Itoa(int(timeSub.Hours()/24)) + "天前"
68
+	} else {
69
+		return timeUnixS.Format("2006-01-02 15:04")
70
+	}
71
+	return ""
72
+}
73
+
74
+//Signature sha1签名
75
+func Signature(params ...string) string {
76
+	sort.Strings(params)
77
+	h := sha1.New()
78
+	for _, s := range params {
79
+		io.WriteString(h, s)
80
+	}
81
+	return fmt.Sprintf("%x", h.Sum(nil))
82
+}
83
+
84
+//RandomStr 随机生成字符串
85
+func RandomStr(length int) string {
86
+	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
87
+	bytes := []byte(str)
88
+	result := []byte{}
89
+	r := rand.New(rand.NewSource(time.Now().UnixNano()))
90
+	for i := 0; i < length; i++ {
91
+		result = append(result, bytes[r.Intn(len(bytes))])
92
+	}
93
+	return string(result)
94
+}
95
+
96
+//GetCurrTs return current timestamps
97
+func GetCurrTs() int64 {
98
+	return time.Now().Unix()
99
+}
100
+
101
+func SetThisRequestURI(uri string) string {
102
+	return fmt.Sprintf("%v%v", beego.AppConfig.String("httpdomain"), uri)
103
+}
104
+
105
+func SetThisBasr64RequestURI(uri string) string {
106
+	backUrl := fmt.Sprintf("%v%v", beego.AppConfig.String("httpdomain"), uri)
107
+	backUrl = base64.URLEncoding.EncodeToString([]byte(backUrl))
108
+
109
+	return backUrl
110
+}
111
+
112
+func TransNum2Str(read int64) (transRead string) {
113
+	if read < 0 {
114
+		transRead = "0"
115
+	} else if read < 10000 {
116
+		transRead = fmt.Sprintf("%v", read)
117
+	} else {
118
+		var c float64 = 10000
119
+		var rc float64 = float64(read)
120
+		transRead = fmt.Sprintf("%.2f万", rc/c)
121
+	}
122
+
123
+	return
124
+}
125
+
126
+func GenMobileToken(mobile string) (token string) {
127
+	st := strings.Split(mobile, "")
128
+
129
+	s := fmt.Sprintf("%s%v%v%v%v%v%v", mobile, st[0], st[1], st[3], st[7], st[6], st[9])
130
+
131
+	h := sha1.New()
132
+	h.Write([]byte(s))
133
+	bs := h.Sum(nil)
134
+
135
+	token = fmt.Sprintf("%x", bs)
136
+
137
+	return
138
+}
139
+
140
+func CheckMobileToken(mobile, token string) bool {
141
+	o := GenMobileToken(mobile)
142
+	if token == o {
143
+		return true
144
+	}
145
+
146
+	return false
147
+}
148
+
149
+type jSapiConfig struct {
150
+	AppID     string `json:"app_id"`
151
+	Timestamp int64  `json:"timestamp"`
152
+	NonceStr  string `json:"nonce_str"`
153
+	Signature string `json:"signature"`
154
+}
155
+
156
+//GetAJTConfig jsapi_ticket config
157
+func GetAJTConfig(jsapiTicket, uri string) (jSapiConfig, error) {
158
+	var config jSapiConfig
159
+	nonceStr := RandomStr(16)
160
+	timestamp := GetCurrTs()
161
+	str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", jsapiTicket, nonceStr, timestamp, uri)
162
+	sigStr := Signature(str)
163
+
164
+	config.AppID = beego.AppConfig.String("wxappId")
165
+	config.NonceStr = nonceStr
166
+	config.Timestamp = timestamp
167
+	config.Signature = sigStr
168
+	return config, nil
169
+}
170
+
171
+func TrimHtml(src string) string {
172
+	//将HTML标签全转换成小写
173
+	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
174
+	src = re.ReplaceAllStringFunc(src, strings.ToLower)
175
+	//去除STYLE
176
+	re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
177
+	src = re.ReplaceAllString(src, "")
178
+	//去除SCRIPT
179
+	re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
180
+	src = re.ReplaceAllString(src, "")
181
+	//去除所有尖括号内的HTML代码,并换成换行符
182
+	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
183
+	src = re.ReplaceAllString(src, "\n")
184
+	//去除连续的换行符
185
+	re, _ = regexp.Compile("\\s{2,}")
186
+	src = re.ReplaceAllString(src, "\n")
187
+	return strings.TrimSpace(src)
188
+}
189
+
190
+func SubString(str string, begin, length int) string {
191
+	rs := []rune(str)
192
+	lth := len(rs)
193
+	if begin < 0 {
194
+		begin = 0
195
+	}
196
+	if begin >= lth {
197
+		begin = lth
198
+	}
199
+	end := begin + length
200
+
201
+	if end > lth {
202
+		end = lth
203
+	}
204
+	return string(rs[begin:end])
205
+}
206
+
207
+func ParseTimeStringToTime(layout string, timeStr string) (*time.Time, error) {
208
+	if len(layout) == 0 || len(timeStr) == 0 {
209
+		return nil, errors.New("layout 或 日期字符串 为空,无法解析")
210
+	}
211
+	loc, _ := time.LoadLocation("Local")
212
+	date, parseDateErr := time.ParseInLocation(layout, timeStr, loc)
213
+	return &date, parseDateErr
214
+}
215
+
216
+// 获取 date 所在周的周一和周日,以周一0点为一周的开始,周日24点为一周的结束
217
+func GetMondayAndSundayOfWeekDate(date *time.Time) (time.Time, time.Time) {
218
+	if date == nil {
219
+		now := time.Now()
220
+		date = &now
221
+	}
222
+	weekday := int(date.Weekday())
223
+	if weekday == 0 {
224
+		weekday = 7
225
+	}
226
+	loc, _ := time.LoadLocation("Local")
227
+	monday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 1-weekday).Format("2006-01-02")+" 00:00:00", loc)
228
+	sunday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 7-weekday).Format("2006-01-02")+" 23:59:59", loc)
229
+	return monday, sunday
230
+}