/* * @description: 常用函数 * @Author: CP * @Date: 2020-08-21 11:12:56 * @FilePath: \construction_management\comm\functions.go */ package comm import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "errors" "math" "math/rand" "time" "unicode" "crypto/md5" "encoding/binary" "fmt" "strconv" "strings" "go.mod/conf" "go.mod/models" "go.mod/web/viewmodels" ) // 账号-构造视图层models func MakeProjectAccountVM(modelsAccount *models.CmProjectAccount) viewmodels.ProjectAccount { viewAccountData := viewmodels.ProjectAccount{} aesId, _ := AesEncrypt(strconv.Itoa(modelsAccount.Id), conf.SignSecret) aesProjectId, _ := AesEncrypt(strconv.Itoa(modelsAccount.ProjectId), conf.SignSecret) viewAccountData.Id = aesId viewAccountData.ProjectId = aesProjectId viewAccountData.Account = modelsAccount.Account viewAccountData.Name = modelsAccount.Name viewAccountData.Company = modelsAccount.Company viewAccountData.Role = modelsAccount.Role viewAccountData.Mobile = modelsAccount.Mobile viewAccountData.Telephone = modelsAccount.Telephone viewAccountData.JlAuth = modelsAccount.JlAuth viewAccountData.BoolAdmin = false if modelsAccount.IsAdmin == 1 { viewAccountData.BoolAdmin = true } viewAccountData.IsAdmin = modelsAccount.IsAdmin viewAccountData.AccountGroup = modelsAccount.AccountGroup viewAccountData.Enable = modelsAccount.Enable viewAccountData.Position = modelsAccount.Position // viewAccountData.ContractPermission = modelsAccount.ContractPermission // viewAccountData.QualityPermission = modelsAccount.QualityPermission // viewAccountData.SafePermission = modelsAccount.SafePermission return viewAccountData } // 创建合同目录树 func MakeFolderContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) { //参数为父节点,添加父节点的子节点指针切片 childs, _ := HaveChildContract(Data, node) //判断节点是否有子节点并返回 if childs != nil { // 子节点总数 Total := len(childs) node.ChildsTotal = Total // 标记最后一个元素 end := Total - 1 childs[end].IsEnd = true // 往父节点添加子节点 node.Children = append(node.Children, childs[0:]...) //添加子节点 // 1.标段汇总 // 1-1.合同相关汇总-收入金额 totalIncome := 0.00 // 1-2.合同总数 totalContractNumber := 0 // 1-3.汇款进度 totalReturn := 0.00 // 1-4支出金额 totalPay := 0.00 totalPaid := 0.00 // 1-5 安全巡检 safeTotal := 0 safeTotalRectification := 0 safeTotalRectificationIn := 0 safeTotalRectificationFinish := 0 safeTotalApproval := 0 safeTotalClose := 0 // 1-6 质量巡检 qualityTotal := 0 qualityTotalRectification := 0 qualityTotalRectificationIn := 0 qualityTotalRectificationFinish := 0 qualityTotalApproval := 0 qualityTotalClose := 0 // 总扣款金额 contractDeductionPriceTotal := 0.00 for _, v := range childs { //查询子节点的子节点,并添加到子节点 _, has := HaveChildContract(Data, v) if has { // 递归添加节点 MakeFolderContract(Data, v) } // 目录下是否包含标段 if v.Isfolder == 0 { node.IsBid = true } else { node.HasFolder = true } // 2.标段汇总 // 2-1收入金额 合计 // returnDate[item.Time.Format(conf.SysTimeformMonth)], _ = decimal.NewFromFloat(returnDate[item.Time.Format(conf.SysTimeformMonth)]).Add(decimal.NewFromFloat(typePrice)).Float64() price, _ := strconv.ParseFloat(v.ContractsIncome, 64) // totalIncome, _ = decimal.NewFromFloat(totalIncome).Add(decimal.NewFromFloat(price)).Float64() totalIncome = totalIncome + price // 2-2合同总数 合计 totalContractNumber = totalContractNumber + v.Contracts // 2-3 汇款进度 price, _ = strconv.ParseFloat(v.ContractsReturned, 64) // totalReturn, _ = decimal.NewFromFloat(totalReturn).Add(decimal.NewFromFloat(price)).Float64() totalReturn = totalReturn + price // price, _ = strconv.ParseFloat(v.ContractsPay, 64) // totalPay, _ = decimal.NewFromFloat(totalPay).Add(decimal.NewFromFloat(price)).Float64() totalPay = totalPay + price price, _ = strconv.ParseFloat(v.ContractsPaid, 64) // totalPaid, _ = decimal.NewFromFloat(totalPaid).Add(decimal.NewFromFloat(price)).Float64() totalPaid = totalPaid + price // 安全巡检 safeTotal = safeTotal + v.SafeTotal safeTotalRectification = safeTotalRectification + v.SafeRectification safeTotalRectificationIn = safeTotalRectificationIn + v.SafeRectificationIn safeTotalRectificationFinish = safeTotalRectificationFinish + v.SafeRectificationFinish safeTotalApproval = safeTotalApproval + v.SafeApproval safeTotalClose = safeTotalClose + v.SafeClose // 1-6 质量巡检 qualityTotal = safeTotal + v.QualityTotal qualityTotalRectification = safeTotalRectification + v.QualityRectification qualityTotalRectificationIn = safeTotalRectificationIn + v.QualityRectificationIn qualityTotalRectificationFinish = qualityTotalRectificationFinish + v.QualityRectificationFinish qualityTotalApproval = qualityTotalApproval + v.QualityApproval qualityTotalClose = qualityTotalClose + v.QualityClose // 1-7 总扣款金额 contractDeductionTotal, _ := strconv.ParseFloat(v.ContractDeductionTotal, 64) contractDeductionPriceTotal = contractDeductionPriceTotal + contractDeductionTotal } // 汇款进度 // fmt.Println("============================") // fmt.Println("totalIncome", totalIncome) // fmt.Println("totalReturn", totalReturn) // fmt.Println("name", node.Name) node.ContractsIncome = fmt.Sprintf("%.2f", totalIncome) node.Contracts = totalContractNumber node.ContractsReturned = fmt.Sprintf("%.2f", totalReturn) quotient := totalReturn / totalIncome if math.IsNaN(quotient) { quotient = 0 } node.ContractsIncomeProgress = fmt.Sprintf("%.2f", (quotient)*100) // 支出相关 // node.ContractsPay = fmt.Sprintf("%.2f", totalPay) node.ContractsPay = fmt.Sprintf("%.2f", totalPay) node.ContractsPaid = fmt.Sprintf("%.2f", totalPaid) quotient = totalPaid / totalPay if math.IsNaN(quotient) { quotient = 0 } node.ContractsPayProgress = fmt.Sprintf("%.2f", (quotient)*100) // 安全巡检 node.SafeTotal = safeTotal node.SafeRectification = safeTotalRectification node.SafeRectificationIn = safeTotalRectificationIn node.SafeRectificationFinish = safeTotalRectificationFinish node.SafeApproval = safeTotalApproval node.SafeClose = safeTotalClose // 质量巡检 node.QualityTotal = qualityTotal node.QualityRectification = qualityTotalRectification node.QualityRectificationIn = qualityTotalRectificationIn node.QualityRectificationFinish = qualityTotalRectificationFinish node.QualityApproval = qualityTotalApproval node.QualityClose = qualityTotalClose // 总扣款金额 node.ContractDeductionTotal = fmt.Sprintf("%.2f", contractDeductionPriceTotal) } } // 是否有子树 func HaveChildContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) (child []*viewmodels.FolderContract, yes bool) { for _, v := range Data { if v.ParentId == node.Id { child = append(child, v) } } if child != nil { yes = true } return } // 创建合同项目节树 func MakeSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) { //参数为父节点,添加父节点的子节点指针切片 childs, _ := haveChildSectionContract(Data, node) //判断节点是否有子节点并返回 if childs != nil { // 往父节点添加子节点 // 孩子们从小到大排序 if len(childs) != 0 { sectionSelectionSort(childs) childs[0].ElderBrother = false childs[len(childs)-1].IsEnd = true } // 项目节父项使用 // 1.合同总金额 回款总金额 已支付总金额 contractPriceTotal := 0.00 returnPriceTotal := 0.00 paidPriceTotal := 0.00 contractDeductionPriceTotal := 0.00 node.Children = append(node.Children, childs[0:]...) //添加子节点 for _, v := range childs { //查询子节点的子节点,并添加到子节点 _, has := haveChildSectionContract(Data, v) if has { // 递归添加节点 MakeSectionContract(Data, v) } // 2.计算父项中金额 contractPrice, _ := strconv.ParseFloat(v.ContractPrice, 64) contractPriceTotal += contractPrice returnPrice, _ := strconv.ParseFloat(v.ContractReturned, 64) returnPriceTotal += returnPrice paidPrice, _ := strconv.ParseFloat(v.ContractsPaid, 64) paidPriceTotal += paidPrice ContractDeductionTotal, _ := strconv.ParseFloat(v.ContractDeductionTotal, 64) contractDeductionPriceTotal += ContractDeductionTotal } // 3.赋值到父项中 node.ContractPrice = fmt.Sprintf("%.2f", contractPriceTotal) node.ContractReturned = fmt.Sprintf("%.2f", returnPriceTotal) node.ContractsPaid = fmt.Sprintf("%.2f", paidPriceTotal) node.ContractDeductionTotal = fmt.Sprintf("%.2f", contractDeductionPriceTotal) } } // 合同项目节孩子排序 func sectionSelectionSort(child []*viewmodels.TreeSectionContract) { for i := 0; i < len(child); i++ { minIndex := i // 查找最小值 for j := i; j < len(child); j++ { if child[j].Serial < child[minIndex].Serial { minIndex = j } } swapContract(child, i, minIndex) } } func swapContract(child []*viewmodels.TreeSectionContract, i int, minIndex int) { t := child[i] child[i] = child[minIndex] child[minIndex] = t } // 是否有子树 func haveChildSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) (child []*viewmodels.TreeSectionContract, yes bool) { for _, v := range Data { if v.ParentId == node.Id { child = append(child, v) } } if child != nil { yes = true } return } // 当前时间的时间戳 func NowUnix() int { return int(time.Now().In(conf.SysTimeLocation).Unix()) } // 将unix时间戳格式化为yyyymmdd H:i:s格式字符串 func FormatFromUnixTime(t int64) string { if t > 0 { return time.Unix(t, 0).Format(conf.SysTimeform) } else { return time.Now().Format(conf.SysTimeform) } } // 将unix时间戳格式化为yyyymmdd格式字符串 func FormatFromUnixTimeShort(t int64) string { if t > 0 { return time.Unix(t, 0).Format(conf.SysTimeformShort) } else { return time.Now().Format(conf.SysTimeformShort) } } // 将字符串转成时间 func ParseTime(str string) (time.Time, error) { return time.ParseInLocation(conf.SysTimeform, str, conf.SysTimeLocation) } // 得到一个随机数 func Random(max int) int { r := rand.New(rand.NewSource(time.Now().UnixNano())) if max < 1 { return r.Int() } else { return r.Intn(max) } } // 加密密码 func CreatePasswordSign(password string, account string) string { str := string(conf.SignSecret) + password + account str1 := fmt.Sprintf("%x", md5.Sum([]byte(str))) sign := fmt.Sprintf("%x", md5.Sum([]byte(str1))) return sign } // 对字符串进行签名 func CreateSign(str string) string { str = string(conf.SignSecret) + str str1 := fmt.Sprintf("%x", md5.Sum([]byte(str))) sign := fmt.Sprintf("%x", md5.Sum([]byte(str1))) return sign } // 对一个字符串进行加密 func Encrypt(key, text []byte) (string, error) { block, err := aes.NewCipher(key) if err != nil { return "", err } b := base64.StdEncoding.EncodeToString(text) ciphertext := make([]byte, aes.BlockSize+len(b)) iv := ciphertext[:aes.BlockSize] //if _, err := io.ReadFull(rand.Reader, iv); err != nil { // return nil, err //} cfb := cipher.NewCFBEncrypter(block, iv) cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) return base64.RawURLEncoding.EncodeToString(ciphertext), nil } // 对一个字符串进行解密 func Decrypt(key, text []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(text) < aes.BlockSize { return nil, errors.New("ciphertext too short") } iv := text[:aes.BlockSize] text = text[aes.BlockSize:] cfb := cipher.NewCFBDecrypter(block, iv) cfb.XORKeyStream(text, text) data, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { return nil, err } return data, nil } // 加密 func AesEncrypt(orig string, key string) (string, error) { // 转成字节数组 origData := []byte(orig) k := []byte(key) // 分组秘钥 block, err := aes.NewCipher(k) if err != nil { return "", err } // 获取秘钥块的长度 blockSize := block.BlockSize() // 补全码 origData = PKCS7Padding(origData, blockSize) // 加密模式 blockMode := cipher.NewCBCEncrypter(block, k[:blockSize]) // 创建数组 cryted := make([]byte, len(origData)) // 加密 blockMode.CryptBlocks(cryted, origData) //使用RawURLEncoding 不要使用StdEncoding //不要使用StdEncoding 放在url参数中回导致错误 return base64.RawURLEncoding.EncodeToString(cryted), nil } // 解密 func AesDecrypt(cryted string, key string) (string, error) { //使用RawURLEncoding 不要使用StdEncoding //不要使用StdEncoding 放在url参数中回导致错误 crytedByte, err := base64.RawURLEncoding.DecodeString(cryted) if err != nil { return "", err } k := []byte(key) // 分组秘钥 block, err := aes.NewCipher(k) if err != nil { return "", err } // 获取秘钥块的长度 blockSize := block.BlockSize() // 加密模式 blockMode := cipher.NewCBCDecrypter(block, k[:blockSize]) // 创建数组 orig := make([]byte, len(crytedByte)) // 解密--传入不正确的字符时会报错-TODO 需捕获 blockMode.CryptBlocks(orig, crytedByte) // 去补全码 orig = PKCS7UnPadding(orig) return string(orig), nil } // 补码 func PKCS7Padding(ciphertext []byte, blocksize int) []byte { padding := blocksize - len(ciphertext)%blocksize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } // 去码 func PKCS7UnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] } // addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。 // 预定义字符是: // 单引号(') // 双引号(") // 反斜杠(\) func Addslashes(str string) string { tmpRune := []rune{} strRune := []rune(str) for _, ch := range strRune { switch ch { case []rune{'\\'}[0], []rune{'"'}[0], []rune{'\''}[0]: tmpRune = append(tmpRune, []rune{'\\'}[0]) tmpRune = append(tmpRune, ch) default: tmpRune = append(tmpRune, ch) } } return string(tmpRune) } // stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。 func Stripslashes(str string) string { dstRune := []rune{} strRune := []rune(str) strLenth := len(strRune) for i := 0; i < strLenth; i++ { if strRune[i] == []rune{'\\'}[0] { i++ } dstRune = append(dstRune, strRune[i]) } return string(dstRune) } // 将字符串的IP转化为数字 func Ip4toInt(ip string) int64 { bits := strings.Split(ip, ".") if len(bits) == 4 { b0, _ := strconv.Atoi(bits[0]) b1, _ := strconv.Atoi(bits[1]) b2, _ := strconv.Atoi(bits[2]) b3, _ := strconv.Atoi(bits[3]) var sum int64 sum += int64(b0) << 24 sum += int64(b1) << 16 sum += int64(b2) << 8 sum += int64(b3) return sum } else { return 0 } } // 得到当前时间到下一天零点的延时 func NextDayDuration() time.Duration { year, month, day := time.Now().Add(time.Hour * 24).Date() next := time.Date(year, month, day, 0, 0, 0, 0, conf.SysTimeLocation) return next.Sub(time.Now()) } // 从接口类型安全获取到int64 func GetInt64(i interface{}, d int64) int64 { if i == nil { return d } switch i.(type) { case string: num, err := strconv.Atoi(i.(string)) if err != nil { return d } else { return int64(num) } case []byte: bits := i.([]byte) if len(bits) == 8 { return int64(binary.LittleEndian.Uint64(bits)) } else if len(bits) <= 4 { num, err := strconv.Atoi(string(bits)) if err != nil { return d } else { return int64(num) } } case uint: return int64(i.(uint)) case uint8: return int64(i.(uint8)) case uint16: return int64(i.(uint16)) case uint32: return int64(i.(uint32)) case uint64: return int64(i.(uint64)) case int: return int64(i.(int)) case int8: return int64(i.(int8)) case int16: return int64(i.(int16)) case int32: return int64(i.(int32)) case int64: return i.(int64) case float32: return int64(i.(float32)) case float64: return int64(i.(float64)) } return d } // 从接口类型安全获取到字符串类型 func GetString(str interface{}, d string) string { if str == nil { return d } switch str.(type) { case string: return str.(string) case []byte: return string(str.([]byte)) } return fmt.Sprintf("%s", str) } // 从map中得到指定的key func GetInt64FromMap(dm map[string]interface{}, key string, dft int64) int64 { data, ok := dm[key] if !ok { return dft } return GetInt64(data, dft) } // 从map中得到指定的key func GetInt64FromStringMap(dm map[string]string, key string, dft int64) int64 { data, ok := dm[key] if !ok { return dft } return GetInt64(data, dft) } // 从map中得到指定的key func GetStringFromMap(dm map[string]interface{}, key string, dft string) string { data, ok := dm[key] if !ok { return dft } return GetString(data, dft) } // 从map中得到指定的key func GetStringFromStringMap(dm map[string]string, key string, dft string) string { data, ok := dm[key] if !ok { return dft } return data } // 首字母大写 func Ucfirst(str string) string { for i, v := range str { return string(unicode.ToUpper(v)) + str[i+1:] } return "" }