user.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. package services
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/silenceper/wechat/v2/miniprogram/auth"
  8. "hongze/hongze_yb/global"
  9. "hongze/hongze_yb/models/tables/session"
  10. "hongze/hongze_yb/models/tables/user_record"
  11. "hongze/hongze_yb/models/tables/wx_user"
  12. "hongze/hongze_yb/models/tables/wx_user_log"
  13. "hongze/hongze_yb/utils"
  14. "strconv"
  15. "time"
  16. )
  17. var ERR_NO_USER_RECORD = errors.New("用户关系没有入库")
  18. var ERR_USER_NOT_BIND = errors.New("用户没有绑定")
  19. type UserInfo struct {
  20. wx_user.WxUser
  21. RecordInfo *user_record.UserRecord
  22. }
  23. // GetWxUserItemByOpenId 通过openid获取用户信息
  24. func GetWxUserItemByOpenId(openid string) (userInfo UserInfo, err error) {
  25. //通过openid获取用户关联信息
  26. userRecord, userRecordErr := user_record.GetByOpenID(openid)
  27. if userRecordErr != nil {
  28. if userRecordErr == utils.ErrNoRow {
  29. err = ERR_NO_USER_RECORD
  30. return
  31. } else {
  32. err = userRecordErr
  33. return
  34. }
  35. }
  36. //该openid在系统中没有关联关系
  37. if userRecord == nil {
  38. err = ERR_NO_USER_RECORD
  39. return
  40. }
  41. //该openid没有绑定用户
  42. if userRecord.UserID <= 0 {
  43. err = ERR_USER_NOT_BIND
  44. item := new(wx_user.WxUser)
  45. //格式化返回用户数据
  46. userInfo = formatWxUserAndUserRecord(item, userRecord)
  47. return
  48. }
  49. //获取用户信息
  50. item, wxUserErr := wx_user.GetByUserId(userRecord.UserID)
  51. if wxUserErr != nil {
  52. err = wxUserErr
  53. //如果是找不到数据,那么可能是该用户被删除了,但是user_record没有删除对应的关系
  54. if wxUserErr == utils.ErrNoRow {
  55. //用户被删除了,但是user_record没有删除对应的关系,那么去解除绑定
  56. userUnbindErr := user_record.UnBindUserRecordByOpenid(openid)
  57. if userUnbindErr != nil {
  58. err = userUnbindErr
  59. return
  60. }
  61. //返回状态为 用户未绑定 逻辑代码
  62. err = ERR_USER_NOT_BIND
  63. item := new(wx_user.WxUser)
  64. //格式化返回用户数据
  65. userInfo = formatWxUserAndUserRecord(item, userRecord)
  66. return
  67. }
  68. return
  69. }
  70. //格式化返回用户数据
  71. userInfo = formatWxUserAndUserRecord(item, userRecord)
  72. return
  73. }
  74. // GetWxUserItemByUserId 根据用户id和平台id获取用户信息
  75. func GetWxUserItemByUserId(userId, platform int) (userInfo UserInfo, err error) {
  76. //获取用户信息
  77. wxUser, err := wx_user.GetByUserId(userId)
  78. if err != nil {
  79. return
  80. }
  81. //格式化返回用户数据
  82. userInfo = formatWxUser(wxUser, platform)
  83. return
  84. }
  85. // GetWxUserItemByEmail 根据用户邮箱和平台id获取用户信息
  86. func GetWxUserItemByEmail(email string, platform int) (userInfo UserInfo, err error) {
  87. //获取用户信息
  88. wxUser, err := wx_user.GetByEmail(email)
  89. if err != nil {
  90. return
  91. }
  92. //格式化返回用户数据
  93. userInfo = formatWxUser(wxUser, platform)
  94. return
  95. }
  96. // GetWxUserItemByMobile 根据用户手机号和平台id获取用户信息
  97. func GetWxUserItemByMobile(mobile string, platform int) (userInfo UserInfo, err error) {
  98. //获取用户信息
  99. wxUser, err := wx_user.GetByMobile(mobile)
  100. if err != nil {
  101. return
  102. }
  103. //格式化返回用户数据
  104. userInfo = formatWxUser(wxUser, platform)
  105. return
  106. }
  107. // GetWxUserItemByUnionId 根据用户unionid和平台id获取用户信息
  108. func GetWxUserItemByUnionId(unionId string, platform int) (userInfo UserInfo, err error) {
  109. //获取用户信息
  110. userRecord, err := user_record.GetByUnionID(unionId, platform)
  111. if err != nil {
  112. return
  113. }
  114. wxUser, err := wx_user.GetByUserId(userRecord.UserID)
  115. if err != nil {
  116. return
  117. }
  118. //格式化返回用户数据
  119. userInfo = formatWxUserAndUserRecord(wxUser, userRecord)
  120. return
  121. }
  122. //通过用户 关系表记录 和 用户记录 格式化返回 用户数据
  123. func formatWxUserAndUserRecord(wxUser *wx_user.WxUser, userRecord *user_record.UserRecord) (userInfo UserInfo) {
  124. wxUser.OpenID = userRecord.OpenID
  125. wxUser.UnionID = userRecord.UnionID
  126. wxUser.NickName = userRecord.NickName
  127. //wxUser.RealName = userRecord.RealName
  128. //wxUser.BindAccount = userRecord.BindAccount
  129. wxUser.Headimgurl = userRecord.Headimgurl
  130. wxUserJson, _ := json.Marshal(wxUser)
  131. _ = json.Unmarshal(wxUserJson, &userInfo)
  132. userInfo.RecordInfo = userRecord
  133. return
  134. }
  135. //通过用户 用户记录 和 来源平台 格式化返回 用户数据
  136. func formatWxUser(wxUser *wx_user.WxUser, platform int) (userInfo UserInfo) {
  137. //根据用户id和平台id获取用户关系
  138. userRecord, userRecordErr := user_record.GetByUserId(int(wxUser.UserID), platform)
  139. if userRecordErr != nil {
  140. if userRecordErr != utils.ErrNoRow {
  141. return
  142. }
  143. }
  144. //该openid在系统中没有关联关系
  145. if userRecord == nil {
  146. wxUserJson, _ := json.Marshal(wxUser)
  147. _ = json.Unmarshal(wxUserJson, &userInfo)
  148. return
  149. } else {
  150. userInfo = formatWxUserAndUserRecord(wxUser, userRecord)
  151. }
  152. return
  153. }
  154. //用户绑定
  155. func BindWxUser(openid, mobile, email string, areaNum, registerPlatform int) (wxUser *wx_user.WxUser, err error) {
  156. var source int8
  157. source = 6 //绑定来源,1:微信端,2:pc网页端,3:查研观向小程序,4:每日咨询
  158. if mobile == "" && email == "" {
  159. err = errors.New("手机号或邮箱必填一个")
  160. return
  161. }
  162. var bindAccount string
  163. //根据手机号获取用户信息
  164. if mobile != "" {
  165. tmpWxUser, wxUserErr := wx_user.GetByMobile(mobile)
  166. if wxUserErr != nil && wxUserErr != utils.ErrNoRow {
  167. err = wxUserErr
  168. return
  169. }
  170. wxUser = tmpWxUser
  171. bindAccount = mobile
  172. }
  173. //根据邮箱获取用户信息
  174. if wxUser == nil && email != "" {
  175. tmpWxUser, wxUserErr := wx_user.GetByEmail(email)
  176. if wxUserErr != nil && wxUserErr != utils.ErrNoRow {
  177. err = wxUserErr
  178. return
  179. }
  180. wxUser = tmpWxUser
  181. bindAccount = email
  182. }
  183. //查询openid的第三方(微信)信息
  184. userRecord, err := user_record.GetByOpenID(openid)
  185. if err != nil {
  186. return
  187. }
  188. var userId int
  189. //如果查询出来的用户是nil,那么需要新增用户
  190. if wxUser == nil {
  191. key := "bind_wx_user:mobile:" + mobile + ":email:" + email
  192. isHas, _ := global.Redis.Exists(context.TODO(), key).Result()
  193. if isHas > 0 {
  194. err = errors.New("多次提交,请关闭页面重新进入")
  195. return
  196. }
  197. global.Redis.SetNX(context.TODO(), key, "ok", time.Second*300)
  198. addwxUser := &wx_user.WxUser{
  199. CompanyID: 1,
  200. CreatedTime: time.Now(),
  201. FirstLogin: 1,
  202. Enabled: 1,
  203. RegisterPlatform: int8(registerPlatform), //账号注册来源,注册平台,1:微信端,2:PC网页端
  204. RegisterTime: time.Now(),
  205. Mobile: mobile,
  206. Email: email,
  207. IsRegister: 1,
  208. Source: source,
  209. CountryCode: strconv.Itoa(areaNum),
  210. OutboundMobile: mobile,
  211. OutboundCountryCode: strconv.Itoa(areaNum),
  212. }
  213. addUserErr := addwxUser.Create()
  214. //添加完成,清除缓存
  215. _ = global.Redis.Del(context.TODO(), key)
  216. if addUserErr != nil {
  217. err = addUserErr
  218. return
  219. }
  220. userId = int(addwxUser.UserID)
  221. tmpWxUser, _ := wx_user.GetByUserId(userId)
  222. wxUser = tmpWxUser
  223. } else {
  224. userId = int(wxUser.UserID)
  225. }
  226. //如果存在该手机号/邮箱,那么需要校验
  227. if userRecord.UserID > 0 && userRecord.UserID != userId {
  228. err = errors.New(fmt.Sprint("用户已绑定其他账户,已绑定的用户编号:", userRecord.UserID, ",不允许重复绑定"))
  229. return
  230. }
  231. if userRecord.UserID == 0 {
  232. userRecord.BindAccount = bindAccount
  233. userRecord.UserID = userId
  234. var updateCols = []string{"UserID", "BindAccount"}
  235. tmpErr := userRecord.Update(updateCols)
  236. if tmpErr != nil {
  237. err = tmpErr
  238. return
  239. }
  240. }
  241. //如果当前该第三方用户信息的昵称为空串的话,那么需要去查询该用户的第一个绑定信息的数据作为来源做数据修复
  242. if userRecord.NickName == "" {
  243. oldUserRecord, err := user_record.GetUserThirdRecordByUserId(userId)
  244. if err == nil && oldUserRecord != nil {
  245. //如果该用户绑定的第一条数据的头像信息不为空串,那么就去做新数据的修复
  246. if oldUserRecord.NickName != "" {
  247. _ = userRecord.ModifyUserRecordInfo(oldUserRecord.NickName, oldUserRecord.Headimgurl, oldUserRecord.City, oldUserRecord.Province, oldUserRecord.Country, oldUserRecord.Sex)
  248. }
  249. }
  250. }
  251. //如果该用户 绑定注册状态 字段处于 未注册 的情况下,那么去修改该数据
  252. if wxUser.IsRegister == 0 {
  253. err = wxUser.ModifyWxUserRegisterStatus(1, source, time.Now())
  254. if err != nil {
  255. return
  256. }
  257. }
  258. //格式化用户数据
  259. formatWxUserAndUserRecord(wxUser, userRecord)
  260. return
  261. }
  262. //微信登录
  263. func WxLogin(wxPlatform int, code string, wxSession auth.ResCode2Session, userInfo UserInfo) (token string, userId, firstLogin, permission int, err error) {
  264. openId := wxSession.OpenID
  265. unionId := wxSession.UnionID
  266. if unionId == "" {
  267. unionId = userInfo.UnionID
  268. }
  269. //firstLogin==1,强制绑定手机号或者邮箱
  270. firstLogin = 1
  271. QUERY_WX_USER:
  272. wxUser, wxUserErr := GetWxUserItemByOpenId(openId)
  273. if wxUserErr == ERR_NO_USER_RECORD { //没有用户openid记录
  274. _, recordErr := AddUserRecord(openId, unionId, "", "", "", "", "", "", "", wxPlatform, 0, 0)
  275. //如果插入失败,那么直接将错误信息返回
  276. if recordErr != nil {
  277. err = recordErr
  278. return
  279. }
  280. //插入成功后,需要重新查询该用户,并进入下面的逻辑
  281. goto QUERY_WX_USER
  282. } else if wxUserErr == ERR_USER_NOT_BIND {
  283. //没有用户信息
  284. //wxUser.FirstLogin = 1
  285. } else if wxUserErr != nil {
  286. err = wxUserErr
  287. return
  288. }
  289. //如果已经登录注册绑定的情况下
  290. if wxUserErr == nil {
  291. //获取用户权限
  292. firstLogin = int(wxUser.FirstLogin)
  293. userId = int(wxUser.UserID)
  294. //if wxUserInfo != nil {
  295. // go models.ModifyUserRecordInfo(openId, wxUserInfo.Nickname, wxUserInfo.Headimgurl, wxUserInfo.City, wxUserInfo.Province, wxUserInfo.Country, wxUserInfo.Sex, userId)
  296. //}
  297. if wxUser.Mobile == "" && wxUser.Email == "" {
  298. firstLogin = 1
  299. } else {
  300. firstLogin = 0
  301. }
  302. }
  303. //获取登录token
  304. tokenItem, tokenErr := session.GetTokenByOpenId(openId)
  305. if tokenErr != nil && tokenErr != utils.ErrNoRow {
  306. err = errors.New("登录失败,获取token失败:" + tokenErr.Error())
  307. return
  308. }
  309. if tokenItem == nil || (tokenErr != nil && tokenErr == utils.ErrNoRow) {
  310. timeUnix := time.Now().Unix()
  311. timeUnixStr := strconv.FormatInt(timeUnix, 10)
  312. token = utils.MD5(openId) + utils.MD5(timeUnixStr)
  313. //新增session
  314. {
  315. //session := new(session.Session)
  316. //session.OpenID = openId
  317. //session.UserID = int64(userId)
  318. //session.CreatedTime = time.Now()
  319. //session.LastUpdatedTime = time.Now()
  320. //session.ExpireTime = time.Now().AddDate(0, 3, 0)
  321. //session.AccessToken = token
  322. sessionItem := &session.Session{
  323. OpenID: openId,
  324. UserID: int64(userId),
  325. CreatedTime: time.Now(),
  326. LastUpdatedTime: time.Now(),
  327. ExpireTime: time.Now().AddDate(0, 3, 0),
  328. AccessToken: token,
  329. }
  330. sessionErr := sessionItem.Create()
  331. if err != nil {
  332. err = errors.New("登录失败,新增用户session信息失败:" + sessionErr.Error())
  333. return
  334. }
  335. }
  336. } else {
  337. token = tokenItem.AccessToken
  338. //如果联系人编号不为空,且联系人编号与session里面的联系人编号不一致的时候,需要做session变更
  339. if userId > 0 && tokenItem.UserID != int64(userId) {
  340. _ = tokenItem.UpdateSession(userId, time.Now().AddDate(0, 1, 0))
  341. }
  342. }
  343. //新增登录日志
  344. {
  345. loginLog := &wx_user_log.WxUserLog{
  346. UserID: userId,
  347. OpenID: openId,
  348. UnionID: unionId,
  349. CreateTime: time.Now(),
  350. Handle: "yb_login",
  351. Remark: token,
  352. }
  353. go loginLog.Create()
  354. }
  355. return
  356. }
  357. // AddUserRecord 添加第三方用户(微信)记录
  358. func AddUserRecord(openId, unionId, nickName, realName, province, city, country, headimgurl, sessionKey string, platform, sex, subscribe int) (userRecordInfo *user_record.UserRecord, err error) {
  359. find, err := user_record.GetByOpenID(openId)
  360. if err != nil && err != utils.ErrNoRow {
  361. return
  362. }
  363. if find != nil {
  364. userRecordInfo = find
  365. return
  366. }
  367. userRecordInfo = &user_record.UserRecord{
  368. OpenID: openId, //用户open_id
  369. UnionID: unionId, //用户union_id
  370. Subscribe: int8(subscribe),
  371. NickName: nickName, //用户昵称,最大长度:32
  372. RealName: realName, //用户实际名称,最大长度:32
  373. Sex: int64(sex), //普通用户性别,1为男性,2为女性
  374. Province: province, //普通用户个人资料填写的省份,最大长度:30
  375. City: city, //普通用户个人资料填写的城市,最大长度:30
  376. Country: country, //国家,如中国为CN,最大长度:30
  377. Headimgurl: headimgurl, //用户第三方(微信)头像,最大长度:512
  378. CreateTime: time.Now(), //创建时间,关系添加时间、用户授权时间
  379. CreatePlatform: int8(platform), //注册平台,1:日度点评公众号,2:管理后台,3:pc端网站,4:查研观向小程序;默认:1
  380. SessionKey: sessionKey, //微信小程序会话密钥,最大长度:255
  381. }
  382. err = userRecordInfo.Create()
  383. if err != nil {
  384. return
  385. }
  386. return
  387. }