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.

453 lines
14 KiB

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