package api import ( "box-cost/db/model" "box-cost/db/repo" "box-cost/log" "bytes" "errors" "fmt" "math" "math/rand" "net/http" "os" "sync" "time" "unsafe" "github.com/gin-gonic/gin" "github.com/thecodingmachine/gotenberg-go-client/v7" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) var SignatureDir string = "https://www.3dqueen.cloud/box/v1/boxcost/public/" func isCompareStatus(apictx *ApiSession, collection string, id primitive.ObjectID, sv string) (bool, error) { ok, ret := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: collection, Query: repo.Map{"_id": id}, Project: []string{"status"}, }) if !ok { return false, errors.New("未找到该单据") } if _, ok := ret["status"]; !ok { return false, errors.New("状态为空") } // 更新状态和完成状态相同 if ret["status"].(string) == sv { return true, nil } return false, nil } func makeBillQuery(query map[string]interface{}) map[string]interface{} { if query["packId"] != nil { query["packId"], _ = primitive.ObjectIDFromHex(query["packId"].(string)) } if query["planId"] != nil { query["planId"], _ = primitive.ObjectIDFromHex(query["planId"].(string)) } // 时间范围查询 // createTime 选中的当天时间 st, ok1 := query["startTime"] delete(query, "startTime") et, ok2 := query["endTime"] delete(query, "endTime") if ok1 && ok2 { startTime := st.(string) endTime := et.(string) start, end := getTimeRange(startTime, endTime) query["createTime"] = bson.M{"$gte": start, "$lte": end} } if productName, ok := query["productName"]; ok { delete(query, "productName") query["productName"] = bson.M{"$regex": productName.(string)} } return query } // func getRowHeight(content string, width float64,lineHeight float64) float64 { // 第一个参数为 行宽 第二个参数为 行高 func getRowHeight(content string, params ...float64) float64 { var perHeight float64 = 16 if len(params) == 2 { perHeight = params[1] } num := float64(len([]rune(content))) // 一行能容纳多少字 rowNum := params[0] / 1.5 // 向上取整获取行数 * 每行高度 rowHeight := math.Ceil(num/rowNum) * perHeight return rowHeight } // 保存文件为pdf func savePdfToTmp(saveTmpDir, fileName string, data []byte) error { err := os.MkdirAll(saveTmpDir, os.ModePerm) if err != nil { log.Error(err) return err } fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName) if err := os.WriteFile(fullFileName, data, 0666); err != nil { log.Error(err) return err } return nil } // 保存文件 func saveExcelToTmp(saveTmpDir, fileName string, data []byte, toExcelResult chan<- int, wg *sync.WaitGroup) { err := os.MkdirAll(saveTmpDir, os.ModePerm) if err != nil { log.Error(err) fmt.Println(err) toExcelResult <- -1 wg.Done() return } fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName) if err := os.WriteFile(fullFileName, data, 0666); err != nil { log.Error(err) fmt.Println(err) toExcelResult <- -1 wg.Done() return } toExcelResult <- 1 wg.Done() } func saveExcelToTmp1(saveTmpDir, fileName string, data []byte) error { err := os.MkdirAll(saveTmpDir, os.ModePerm) if err != nil { log.Error(err) fmt.Println(err) return err } fullFileName := fmt.Sprintf("%s/%s", saveTmpDir, fileName) if err := os.WriteFile(fullFileName, data, 0666); err != nil { log.Error(err) fmt.Println(err) return err } return nil } func isExistDir(dir string) bool { _, err := os.Stat(dir) if err != nil { return os.IsExist(err) } return true } // 去重相邻元素 func removeDuplicationSort(arr []string) []string { length := len(arr) if length == 0 { return arr } j := 0 for i := 1; i < length; i++ { if arr[i] != arr[j] { j++ if j < i { swap(arr, i, j) } } } return arr[:j+1] } func swap(arr []string, a, b int) { arr[a], arr[b] = arr[b], arr[a] } func generateSerial(c *gin.Context, ctx *ApiSession, typeName string) (serial string, err error) { // 获取类型 cate := &model.Category{} found, err := repo.RepoSeachDoc(ctx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: "cates", Project: []string{"letterName"}, Query: repo.Map{"name": typeName}, Sort: bson.M{"_id": -1}, }, cate) if !found || err != nil { return "", fmt.Errorf("未找到该类型") } // 自增器 increment index加1 increment := &model.Increment{} found, _ = repo.RepoSeachDoc(ctx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionIncrement, Query: repo.Map{"type": cate.LetterName}, Project: []string{"index"}, Sort: bson.M{"_id": -1}, }, increment) if !found { repo.RepoAddDoc(ctx.CreateRepoCtx(), repo.CollectionIncrement, &model.Increment{ Type: cate.LetterName, Index: 1, }) return fmt.Sprintf("%s-%06d", cate.LetterName, 1), nil } index := increment.Index + 1 // repo.RepoUpdateSetDoc(ctx.CreateRepoCtx(), repo.CollectionIncrement, increment.Id.Hex(), &model.Increment{Index: index}) repo.RepoUpdateSetDoc1(ctx.CreateRepoCtx(), repo.CollectionIncrement, increment.Id.Hex(), &model.Increment{Index: index}, &repo.RecordLogReq{ Path: c.Request.URL.Path, TargetId: increment.Id.Hex(), }) // 拼接为序号 return fmt.Sprintf("%s-%06d", cate.LetterName, index), nil } func searchBillTypeById(ctx *ApiSession, collectName string, id primitive.ObjectID) (string, error) { fmt.Println(id.Hex()) found, curbill := repo.RepoSeachDocMap(ctx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: collectName, Project: []string{"type"}, Query: repo.Map{"_id": id}, Sort: bson.M{"_id": -1}, }) if !found { return "", fmt.Errorf("未找到该类型") } return curbill["type"].(string), nil } func excelToPdf(formBody *bytes.Buffer, pdfHost string) (*http.Response, error) { httpClient := &http.Client{ Timeout: time.Duration(15) * time.Second, } client := &gotenberg.Client{Hostname: pdfHost, HTTPClient: httpClient} // 'merge="true"' \ // --form 'pdfFormat="PDF/A-1a"' \ // formData := url.Values{ // "merge": {"true"}, // "pdfFormat": {"PDF/A-1a"}, // } // 构建请求体 // reqData := bytes.NewBufferString(formData.Encode()) // reqData.WriteTo(formBody) doc, err := gotenberg.NewDocumentFromBytes("foo.xlsx", formBody.Bytes()) if err != nil { fmt.Println(" to pdf read data err:", err) return nil, err } req := gotenberg.NewOfficeRequest(doc) req.Landscape(true) return client.Post(req) } func isManager(roles []string) bool { if len(roles) > 0 { for _, role := range roles { if role == "manager" { return true } } } return false } func isSender(roles []string) bool { if len(roles) > 0 { for _, role := range roles { if role == "sender" { return true } } } return false } func getUserById(apictx *ApiSession, id primitive.ObjectID) (*model.UserSmaple, error) { user := &model.UserSmaple{} _, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ Db: "box-user", CollectName: repo.CollectionUsers, Query: repo.Map{"_id": id}, Project: []string{"name", "avatar", "city", "loginName", "roles", "phone"}, }, user) return user, err } // 获取一天的起始终止时间 // func getDayRange(t time.Time) (start, end time.Time) { // loc, _ := time.LoadLocation("Local") // date := t.Format("2006-01-02") // startDate := date + " 00:00:00" // startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", startDate, loc) // endDate := date + " 23:59:59" // endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endDate, loc) // return startTime, endTime // } // 获取时间跨度的起始终止时间 // startDate/endDate 2023-01-31 func getTimeRange(startDate, endDate string) (start, end time.Time) { loc, _ := time.LoadLocation("Local") startDateTime := startDate + " 00:00:00" endDateTime := endDate + " 23:59:59" start, _ = time.ParseInLocation("2006-01-02 15:04:05", startDateTime, loc) end, _ = time.ParseInLocation("2006-01-02 15:04:05", endDateTime, loc) return } // 处理报表query条件 func handleReportQuery(query map[string]interface{}) map[string]interface{} { // 条件处理 query["status"] = "complete" if _supplierId, ok := query["supplierId"]; ok { delete(query, "supplierId") supplierId, _ := primitive.ObjectIDFromHex(_supplierId.(string)) if !supplierId.IsZero() { query["supplierId"] = supplierId } } if _timeRange, ok := query["timeRange"]; ok { timeRange, _ := _timeRange.([]interface{}) if len(timeRange) == 2 { start, end := getTimeRange(timeRange[0].(string), timeRange[1].(string)) query["completeTime"] = bson.M{"$gte": start, "$lte": end} } delete(query, "timeRange") } if _planIds, ok := query["planIds"]; ok { if len(_planIds.([]interface{})) > 0 { planQuery := bson.A{} for _, _planId := range _planIds.([]interface{}) { planId, _ := primitive.ObjectIDFromHex(_planId.(string)) planQuery = append(planQuery, bson.M{"planId": planId}) } query["$or"] = planQuery } delete(query, "planIds") } return query } // 获取公司名字 func getCompanyName(apictx *ApiSession) string { companyName := "中鱼互动" info := model.Setting{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: "infos", }, &info) if found { if info.CompanyName != "" { companyName = info.CompanyName } } return companyName } const ( letterIdBits = 6 letterIdMask = 1<= 0; { if remain == 0 { cache, remain = src.Int63(), letterIdMax } if idx := int(cache & letterIdMask); idx < len(letters) { b[i] = letters[idx] i-- } cache >>= letterIdBits remain-- } return *(*string)(unsafe.Pointer(&b)) }