| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 | /* * @description: 常用函数 * @Author: CP * @Date: 2020-08-21 11:12:56 * @FilePath: \construction_management\comm\functions.go */package commimport (	"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")// 账号-构造视图层modelsfunc 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.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		// 1-6 质量巡检		qualityTotal := 0		qualityTotalRectification := 0		qualityTotalRectificationIn := 0		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收入金额 合计			price, _ := strconv.ParseFloat(v.ContractsIncome, 64)			totalIncome = totalIncome + price			// 2-2合同总数 合计			totalContractNumber = totalContractNumber + v.Contracts			// 2-3 汇款进度			price, _ = strconv.ParseFloat(v.ContractsReturned, 64)			totalReturn = totalReturn + price			//			price, _ = strconv.ParseFloat(v.ContractsPay, 64)			totalPay = totalPay + price			price, _ = strconv.ParseFloat(v.ContractsPaid, 64)			totalPaid = totalPaid + price			// 安全巡检			safeTotal = safeTotal + v.SafeTotal			safeTotalRectification = safeTotalRectification + v.SafeRectification			safeTotalRectificationIn = safeTotalRectificationIn + v.SafeRectificationIn			// 1-6 质量巡检			qualityTotal = safeTotal + v.QualityTotal			qualityTotalRectification = safeTotalRectification + v.QualityRectification			qualityTotalRectificationIn = safeTotalRectificationIn + v.QualityRectificationIn		}		node.ContractsIncome = fmt.Sprintf("%.2f", totalIncome)		node.Contracts = totalContractNumber		// 汇款进度		quotient := totalReturn / totalIncome		if math.IsNaN(quotient) {			quotient = 0		}		node.ContractsIncomeProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"		// 支出相关		node.ContractsPay = fmt.Sprintf("%.2f", totalPay)		quotient = totalPaid / totalPay		if math.IsNaN(quotient) {			quotient = 0		}		node.ContractsPayProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"		// 安全巡检		node.SafeTotal = safeTotal		node.SafeRectification = safeTotalRectification		node.SafeRectificationIn = safeTotalRectificationIn		// 质量巡检		node.QualityTotal = qualityTotal		node.QualityRectification = qualityTotalRectification		node.QualityRectificationIn = qualityTotalRectificationIn	}}// 是否有子树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		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		}		// 3.赋值到父项中		// node.ContractPrice = fmt.Sprintf("%.2f", contractPriceTotal)		// node.ContractReturned = fmt.Sprintf("%.2f", returnPriceTotal)		// node.ContractsPaid = fmt.Sprintf("%.2f", paidPriceTotal)	}}// 合同项目节孩子排序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())}// 从接口类型安全获取到int64func 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中得到指定的keyfunc GetInt64FromMap(dm map[string]interface{}, key string, dft int64) int64 {	data, ok := dm[key]	if !ok {		return dft	}	return GetInt64(data, dft)}// 从map中得到指定的keyfunc GetInt64FromStringMap(dm map[string]string, key string, dft int64) int64 {	data, ok := dm[key]	if !ok {		return dft	}	return GetInt64(data, dft)}// 从map中得到指定的keyfunc GetStringFromMap(dm map[string]interface{}, key string, dft string) string {	data, ok := dm[key]	if !ok {		return dft	}	return GetString(data, dft)}// 从map中得到指定的keyfunc 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 ""}
 |