You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

438 lines
13 KiB

  1. package couponusers
  2. import (
  3. "CouponBackendGo/api/v1/couponusers"
  4. "CouponBackendGo/internal/dao"
  5. "CouponBackendGo/internal/service"
  6. "context"
  7. "database/sql"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "github.com/gogf/gf/v2/frame/g"
  12. "github.com/gogf/gf/v2/os/gtime"
  13. "github.com/xuri/excelize/v2"
  14. "mime/multipart"
  15. "strconv"
  16. "strings"
  17. )
  18. type sCouponUsers struct{}
  19. func init() {
  20. service.RegisterCouponUsers(&sCouponUsers{})
  21. }
  22. // 根据优惠券id查看拥有优惠券的用户
  23. func (s *sCouponUsers) GetCouponUsersByCondition(ctx context.Context, couponId, jwcode int, name string, pageNo, pageSize int) (users []couponusers.GetCouponUsersRes, err error) {
  24. //没有条件查询时,分页
  25. if jwcode == 0 && name == "" {
  26. //从redis中获取当前分页数据
  27. value, _ := g.Redis().Get(ctx, fmt.Sprintf("%d %d-%d CouponUsers", couponId, pageNo, pageSize))
  28. //redis中有数据
  29. if value.String() != "" {
  30. err = json.Unmarshal(value.Bytes(), &users)
  31. if err != nil {
  32. return nil, errors.New("redis中数据解析失败")
  33. }
  34. return users, err
  35. } else { //redis中没有数据
  36. //没有从redis中获取成功,从数据库中查询,并存储到redis中
  37. /*查询所有数据*/
  38. //在coupon_users中查询出对应的jwcode
  39. err = dao.CouponUsers.Ctx(ctx).Fields("jwcode").
  40. Where("coupon_id = ", couponId).Page(pageNo, pageSize).Scan(&users)
  41. if err != nil {
  42. return nil, errors.New("根据卡券id搜索jwcode失败")
  43. }
  44. //根据jwcode查询用户信息
  45. for i, userInfo := range users {
  46. err = dao.MemberInfo.Ctx(ctx).Fields("jwcode", "name", "deptName", "shopName").
  47. Where("jwcode = ?", userInfo.Jwcode).Scan(&users[i])
  48. if err != nil {
  49. return nil, errors.New("根据jwcode搜索用户信息失败")
  50. }
  51. }
  52. /*查询所有数据*/
  53. //将数据存入redis
  54. UsersMarshal, _ := json.Marshal(users)
  55. _, err = g.Redis().Set(ctx, fmt.Sprintf("%d %d-%d CouponUsers", couponId, pageNo, pageSize), UsersMarshal)
  56. if err != nil {
  57. return nil, errors.New("将数据存入redis失败")
  58. }
  59. }
  60. return users, err
  61. //有条件查询时,不在分页,全查后筛选
  62. } else {
  63. //从redis中获取所有数据但暂时不返回, 用于条件查询
  64. value, _ := g.Redis().Get(ctx, fmt.Sprintf("%d CouponUsers", couponId))
  65. //redis中有数据
  66. if value.String() != "" {
  67. err = json.Unmarshal(value.Bytes(), &users)
  68. if err != nil {
  69. return nil, errors.New("redis中数据解析失败")
  70. }
  71. } else { //redis中没有数据
  72. //没有从redis中获取成功,从数据库中查询,并存储到redis中
  73. /*查询所有数据*/
  74. //在coupon_users中查询出对应的jwcode
  75. err = dao.CouponUsers.Ctx(ctx).Fields("jwcode").
  76. Where("coupon_id = ", couponId).Scan(&users)
  77. if err != nil {
  78. return nil, errors.New("根据卡券id搜索jwcode失败")
  79. }
  80. //根据jwcode查询用户信息
  81. for i, userInfo := range users {
  82. err = dao.MemberInfo.Ctx(ctx).Fields("jwcode", "name", "deptName", "shopName").
  83. Where("jwcode = ?", userInfo.Jwcode).Scan(&users[i])
  84. if err != nil {
  85. return nil, errors.New("根据jwcode搜索用户信息失败")
  86. }
  87. }
  88. /*查询所有数据*/
  89. //将数据存入redis
  90. UsersMarshal, _ := json.Marshal(users)
  91. _, err = g.Redis().Set(ctx, fmt.Sprintf("%d CouponUsers", couponId), UsersMarshal)
  92. if err != nil {
  93. return nil, errors.New("将数据存入redis失败")
  94. }
  95. }
  96. //条件查询
  97. if jwcode != 0 && name == "" {
  98. var result []couponusers.GetCouponUsersRes
  99. for _, user := range users {
  100. if user.Jwcode == jwcode {
  101. result = append(result, user)
  102. }
  103. }
  104. return result, err
  105. } else if jwcode == 0 && name != "" {
  106. var result []couponusers.GetCouponUsersRes
  107. for _, user := range users {
  108. if strings.Contains(user.Name, name) {
  109. result = append(result, user)
  110. }
  111. }
  112. return result, err
  113. } else if jwcode != 0 && name != "" {
  114. var result []couponusers.GetCouponUsersRes
  115. for _, user := range users {
  116. if user.Jwcode == jwcode && strings.Contains(user.Name, name) {
  117. result = append(result, user)
  118. }
  119. }
  120. return result, err
  121. }
  122. return users, err
  123. }
  124. }
  125. // 根据jwcode,优惠券id删除用户
  126. func (s *sCouponUsers) DeleteCouponUserByJwcode(ctx context.Context, couponId, jwcode int) (result sql.Result, err error) {
  127. if jwcode == 0 {
  128. return nil, errors.New("jwcode不能为空")
  129. }
  130. if couponId == 0 {
  131. return nil, errors.New("couponId不能为空")
  132. }
  133. result, err = dao.CouponUsers.Ctx(ctx).Where("coupon_id = ?", couponId).Where("jwcode = ?", jwcode).Delete()
  134. if err != nil {
  135. return nil, errors.New("删除用户失败")
  136. }
  137. //删除redis中的数据
  138. _, err = g.Redis().Del(ctx, fmt.Sprintf("%d CouponUsers", couponId))
  139. if err != nil {
  140. return nil, errors.New("删除redis中的数据失败")
  141. }
  142. keys, err := g.Redis().Keys(ctx, fmt.Sprintf("%d *-* CouponUsers", couponId))
  143. if len(keys) > 0 {
  144. _, err = g.Redis().Del(ctx, keys...)
  145. }
  146. return result, err
  147. }
  148. // 通过excel导入精网号
  149. func (s *sCouponUsers) InsertJwcodeByExcel(file multipart.File) (jwcodes []int, err error) {
  150. //打开文件并返回一个excelize.File对象,用于读取和操作Excel文件的内容
  151. f, err := excelize.OpenReader(file)
  152. if err != nil {
  153. return nil, errors.New("打开文件失败")
  154. }
  155. // 延时关闭文件
  156. defer func(f *excelize.File) {
  157. err := f.Close()
  158. if err != nil {
  159. return // 返回错误
  160. }
  161. }(f)
  162. //读取所有工作表名称
  163. GetSheetMap := f.GetSheetMap()
  164. if len(GetSheetMap) == 0 {
  165. return nil, errors.New("没有工作表")
  166. }
  167. // 读取第一个工作表
  168. //sheetName := GetSheetMap[1]
  169. //rows, err := f.GetRows(f.GetSheetName(1))
  170. rows, err := f.GetRows("Sheet1")
  171. if err != nil {
  172. return nil, err
  173. }
  174. // 将每行的第一列转换为int,并添加到切片中
  175. for i, row := range rows {
  176. //跳过第一行
  177. if i == 0 {
  178. continue
  179. }
  180. // 假设jwcode在每行的第一列
  181. /*参数校验*/
  182. //参数校验,检查每行是否有足够数据
  183. if len(row) == 0 {
  184. continue // 跳过空行
  185. }
  186. //参数校验,检查jwcode是否为非空字符串
  187. jwcodeStr := row[0]
  188. if jwcodeStr == "" {
  189. continue // 跳过空行
  190. }
  191. //将字符串转换为整数
  192. jwcode, err := strconv.Atoi(jwcodeStr)
  193. if err != nil {
  194. return nil, errors.New("参数转换失败")
  195. }
  196. jwcodes = append(jwcodes, jwcode)
  197. /*参数校验*/
  198. }
  199. return //返回jwcodes切片
  200. }
  201. // 根据精网号发放用户优惠券
  202. func (s *sCouponUsers) InsertCouponUsersByJwcodes(ctx context.Context, jwcodes []int, couponId int) (num int, err error) {
  203. //去重
  204. m := make(map[int]bool)
  205. var uniqueJwcodes []int //存放去重后的精网号
  206. for _, jwcode := range jwcodes {
  207. if _, exist := m[jwcode]; !exist {
  208. m[jwcode] = true
  209. uniqueJwcodes = append(uniqueJwcodes, jwcode)
  210. }
  211. }
  212. //插入数据
  213. for _, jwcode := range uniqueJwcodes {
  214. //检查数据库中是否存在
  215. count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count()
  216. if err != nil {
  217. return num, errors.New("检索数据库中是否已存在数据失败")
  218. }
  219. //不存在,可以插入
  220. if count == 0 {
  221. result, err := dao.CouponUsers.Ctx(ctx).Insert(g.Map{
  222. "jwcode": jwcode,
  223. "coupon_id": couponId,
  224. "time": gtime.Now().Unix(),
  225. })
  226. if err != nil {
  227. return num, errors.New("插入数据库失败")
  228. }
  229. //获取受影响的行数
  230. affected, err := result.RowsAffected()
  231. num += int(affected)
  232. }
  233. }
  234. //删除redis中的数据
  235. _, err = g.Redis().Del(ctx, fmt.Sprintf("%d CouponUsers", couponId))
  236. if err != nil {
  237. return 0, errors.New("删除redis中的数据失败")
  238. }
  239. keys, err := g.Redis().Keys(ctx, fmt.Sprintf("%d *-* CouponUsers", couponId))
  240. if len(keys) > 0 {
  241. _, err = g.Redis().Del(ctx, keys...)
  242. }
  243. return num, err //返回受影响的行数,即新增的条数
  244. }
  245. // 导入满足条件的用户jwcode到redis
  246. func (s *sCouponUsers) InsertJwcodesToRedisByExcel(file multipart.File) (err error) {
  247. var ctx g.Ctx
  248. //打开文件并返回一个excelize.File对象,用于读取和操作Excel文件的内容
  249. f, err := excelize.OpenReader(file)
  250. if err != nil {
  251. return errors.New("打开文件失败")
  252. }
  253. // 延时关闭文件
  254. defer func(f *excelize.File) {
  255. err := f.Close()
  256. if err != nil {
  257. // 处理关闭文件时的错误
  258. return
  259. }
  260. }(f)
  261. //读取所有工作表名称
  262. GetSheetMap := f.GetSheetMap()
  263. if len(GetSheetMap) == 0 {
  264. return errors.New("没有工作表")
  265. }
  266. // 读取第一个工作表
  267. //sheetName := GetSheetMap[1]
  268. //rows, err := f.GetRows(f.GetSheetName(1))
  269. rows, err := f.GetRows("Sheet1")
  270. if err != nil {
  271. return err
  272. }
  273. // 将每行的第一列转换为int,并添加到切片中
  274. var jwcodes []int
  275. for i, row := range rows {
  276. //跳过第一行
  277. if i == 0 {
  278. continue
  279. }
  280. // 假设jwcode在每行的第一列
  281. /*参数校验*/
  282. //参数校验,检查每行是否有足够数据
  283. if len(row) == 0 {
  284. continue // 跳过空行
  285. }
  286. //参数校验,检查jwcode是否为非空字符串
  287. jwcodeStr := row[0]
  288. if jwcodeStr == "" {
  289. continue // 跳过空行
  290. }
  291. //将字符串转换为整数
  292. jwcode, err := strconv.Atoi(jwcodeStr)
  293. if err != nil {
  294. return errors.New("参数转换失败")
  295. }
  296. jwcodes = append(jwcodes, jwcode)
  297. /*参数校验*/
  298. }
  299. //将jwcodes存入redis
  300. MarshalJwcodes, _ := json.Marshal(jwcodes)
  301. _, err = g.Redis().Set(ctx, "EligibleJwcodes", MarshalJwcodes)
  302. if err != nil {
  303. return errors.New("存入redis失败")
  304. }
  305. return //返回nil表示成功
  306. }
  307. // 判断某用户能否抽到卡券
  308. func (s *sCouponUsers) IsEligibleUser(ctx context.Context, jwcode int, couponIds []int) (img string, err error) {
  309. /*从redis中获取符合条件的精网号EligibleJwcodes*/
  310. redisResult, err := g.Redis().Get(ctx, "EligibleJwcodes")
  311. if err != nil {
  312. return "", errors.New("从redis中获取数据失败")
  313. }
  314. var EligibleJwcodes []int
  315. err = json.Unmarshal(redisResult.Bytes(), &EligibleJwcodes)
  316. if err != nil {
  317. return "", errors.New("redis中数据解析失败")
  318. }
  319. if len(EligibleJwcodes) == 0 {
  320. return "", errors.New("redis中数据为空")
  321. }
  322. /*从redis中获取符合条件的精网号EligibleJwcodes*/
  323. //检查jwcode是否在EligibleJwcodes中
  324. for _, EligibleJwcode := range EligibleJwcodes {
  325. if EligibleJwcode == jwcode {
  326. //存在,有资格,判断是否抽取过
  327. for _, couponId := range couponIds {
  328. count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count()
  329. if err != nil {
  330. return "", errors.New("检索数据库中是否已存在数据失败")
  331. }
  332. //有记录,抽取过
  333. if count > 0 {
  334. err = dao.CouponUsers.Ctx(ctx).Fields("img_url").Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Scan(&img)
  335. return img, errors.New("该用户已领取过该卡券")
  336. }
  337. }
  338. //所有的都没有记录,没有抽取过
  339. return "", nil
  340. }
  341. }
  342. return "", errors.New("该用户不满足领取条件")
  343. }
  344. // 给单个用户发放卡券
  345. func (s *sCouponUsers) IssueCouponToUser(ctx context.Context, jwcode, couponId int) (err error) {
  346. //查看库中是否已经存在
  347. count, err := dao.CouponUsers.Ctx(ctx).Where("jwcode = ?", jwcode).Where("coupon_id = ?", couponId).Count()
  348. if err != nil {
  349. return errors.New("检索数据库中是否已存在数据失败")
  350. }
  351. //已存在 不添加,直接返回
  352. if count > 0 {
  353. return errors.New("该用户已领取该卡券")
  354. }
  355. //不存在 查看是否满足条件,满足就添加,不满足就返回
  356. /*从redis中获取符合条件的精网号EligibleJwcodes*/
  357. redisResult, err := g.Redis().Get(ctx, "EligibleJwcodes")
  358. if err != nil {
  359. return errors.New("从redis中获取数据失败")
  360. }
  361. var EligibleJwcodes []int
  362. err = json.Unmarshal(redisResult.Bytes(), &EligibleJwcodes)
  363. if err != nil {
  364. return errors.New("redis中数据解析失败")
  365. }
  366. if len(EligibleJwcodes) == 0 {
  367. return errors.New("redis中数据为空")
  368. }
  369. /*从redis中获取符合条件的精网号EligibleJwcodes*/
  370. //检查jwcode是否在EligibleJwcodes中
  371. for _, EligibleJwcode := range EligibleJwcodes {
  372. if EligibleJwcode == jwcode {
  373. //存在,可以插入
  374. _, err := dao.CouponUsers.Ctx(ctx).Insert(g.Map{
  375. "jwcode": jwcode,
  376. "coupon_id": couponId,
  377. "time": gtime.Now().Unix(),
  378. })
  379. if err != nil {
  380. return errors.New("插入数据库失败")
  381. }
  382. //删除redis中的数据
  383. _, err = g.Redis().Del(ctx, fmt.Sprintf("%d CouponUsers", couponId))
  384. if err != nil {
  385. return errors.New("删除redis中的数据失败")
  386. }
  387. keys, err := g.Redis().Keys(ctx, fmt.Sprintf("%d *-* CouponUsers", couponId))
  388. if len(keys) > 0 {
  389. _, err = g.Redis().Del(ctx, keys...)
  390. }
  391. return err
  392. }
  393. }
  394. return errors.New("该用户精网号不符合领取条件") //遍历完了所有满足条件的用户,发现不在其中,不符合条件
  395. }
  396. // 导出拥有卡券的用户列表
  397. func (s *sCouponUsers) ExportCouponUsers() {
  398. }