package logic import ( "VoteManage_Go/api/v1/vote" "VoteManage_Go/internal/dao" "VoteManage_Go/internal/model/dto" "VoteManage_Go/internal/service" "context" "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gtime" "github.com/xuri/excelize/v2" "net/url" "strconv" "time" ) type sVote struct{} func init() { service.RegisterVote(New()) } func New() *sVote { return &sVote{} } func (s *sVote) GetVoteByCondition(ctx context.Context, req *vote.GetVoteDetailListReq) (votes []*dto.VoteDto, total int, err error) { query := g.Model("vote_records v").LeftJoin("member_info m", "v.jwcode = m.jwcode"). Fields("v.id, m.nickname, v.jwcode, m.dept, v.options_title, v.time"). Where("v.activity_id = ?", req.ActivityId) // 条件1:jwcode输入(精确匹配) if req.Jwcode != "" { query = query.Where("v.jwcode = ?", req.Jwcode) } // 条件2:地区dept下拉框(精确匹配)dept是汉字 if req.Dept != "" { query = query.Where("m.dept = ?", req.Dept) } // 条件3:投票日期范围(时间戳转换) //if req.StartTime != nil && req.EndTime != nil { // // 将前端日期字符串转为Unix时间戳(示例:2025.04.01 00:00:00 → 时间戳) // query = query.Where("v.time BETWEEN ? AND ?", req.StartTime.Unix(), req.EndTime.Unix()) //} if req.StartDate != "" && req.EndDate != "" { start := gtime.New(req.StartDate + " 00:00:00").Unix() end := gtime.New(req.EndDate + " 23:59:59").Unix() query = query.Where("v.time BETWEEN ? AND ?", start, end) } // 条件4:分页 query.Page(req.PageNo, req.PageSize).ScanAndCount(&votes, &total, false) return } func (s *sVote) ExportVote(r *ghttp.Request, req *vote.GetVoteDetailListReq) { votes, _, err := s.GetVoteByCondition(r.Context(), req) if err != nil { r.Response.WriteJsonExit(dto.Error("查询失败:" + err.Error())) return } if len(votes) == 0 { r.Response.WriteJsonExit(dto.Error("查询结果为空")) return } // 内存中创建Excel文件(不落盘) excelFile := excelize.NewFile() sheetName := "投票记录" excelFile.SetSheetName("Sheet1", sheetName) // 设置表头样式 headers := []string{"序号", "姓名", "精网号", "地区", "投票明细", "投票时间"} for i, header := range headers { col := string('A' + i) excelFile.SetCellValue(sheetName, col+"1", header) excelFile.SetColWidth(sheetName, col, col, 18) // 列宽调整 } // 动态写入数据 for rowIdx, vote := range votes { row := strconv.Itoa(rowIdx + 2) excelFile.SetCellValue(sheetName, "A"+row, rowIdx+1) excelFile.SetCellValue(sheetName, "B"+row, vote.Nickname) excelFile.SetCellValue(sheetName, "C"+row, vote.Jwcode) excelFile.SetCellValue(sheetName, "D"+row, vote.Dept) excelFile.SetCellValue(sheetName, "E"+row, vote.OptionsTitle) excelFile.SetCellValue(sheetName, "F"+row, vote.Time) } // 生成唯一文件名并响应流 fileName := fmt.Sprintf("投票记录_%s.xlsx", time.Now().Format("20060102150405"), ) r.Response.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") r.Response.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.QueryEscape(fileName)) // 直接写入HTTP响应流 if buffer, err := excelFile.WriteToBuffer(); err == nil { r.Response.Write(buffer.Bytes()) } else { r.Response.WriteJsonExit(dto.Error("文件生成失败:" + err.Error())) } } func (s *sVote) GetActivityList(ctx context.Context, req *vote.GetActivityListReq) (activities []*dto.Activity, total int, err error) { err = g.DB("live").Model("float_window").Fields("id, title, start, end, created_at"). OrderDesc("id").Page(req.PageNo, req.PageSize).ScanAndCount(&activities, &total, false) for _, v := range activities { v.VoteCount, _ = dao.VoteRecords.Ctx(ctx).Where("activity_id", v.Id).Fields("DISTINCT jwcode").Count() //fmt.Printf(strconv.Itoa(v.VoteCount)) if gtime.Date() < v.Start { v.Status = 1 } else if gtime.Date() > v.End { v.Status = 3 } else { v.Status = 2 } } return }