functions.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * @description: 常用函数
  3. * @Author: CP
  4. * @Date: 2020-08-21 11:12:56
  5. * @FilePath: \construction_management\comm\functions.go
  6. */
  7. package comm
  8. import (
  9. "bytes"
  10. "crypto/aes"
  11. "crypto/cipher"
  12. "encoding/base64"
  13. "errors"
  14. "math"
  15. "math/rand"
  16. "time"
  17. "unicode"
  18. "crypto/md5"
  19. "encoding/binary"
  20. "fmt"
  21. "strconv"
  22. "strings"
  23. "github.com/shopspring/decimal"
  24. "go.mod/conf"
  25. "go.mod/models"
  26. "go.mod/web/viewmodels"
  27. )
  28. // 账号-构造视图层models
  29. func MakeProjectAccountVM(modelsAccount *models.CmProjectAccount) viewmodels.ProjectAccount {
  30. viewAccountData := viewmodels.ProjectAccount{}
  31. aesId, _ := AesEncrypt(strconv.Itoa(modelsAccount.Id), conf.SignSecret)
  32. aesProjectId, _ := AesEncrypt(strconv.Itoa(modelsAccount.ProjectId), conf.SignSecret)
  33. viewAccountData.Id = aesId
  34. viewAccountData.ProjectId = aesProjectId
  35. viewAccountData.Account = modelsAccount.Account
  36. viewAccountData.Name = modelsAccount.Name
  37. viewAccountData.Company = modelsAccount.Company
  38. viewAccountData.Role = modelsAccount.Role
  39. viewAccountData.Mobile = modelsAccount.Mobile
  40. viewAccountData.Telephone = modelsAccount.Telephone
  41. viewAccountData.IsAdmin = modelsAccount.IsAdmin
  42. viewAccountData.AccountGroup = modelsAccount.AccountGroup
  43. viewAccountData.Enable = modelsAccount.Enable
  44. viewAccountData.Position = modelsAccount.Position
  45. // viewAccountData.ContractPermission = modelsAccount.ContractPermission
  46. // viewAccountData.QualityPermission = modelsAccount.QualityPermission
  47. // viewAccountData.SafePermission = modelsAccount.SafePermission
  48. return viewAccountData
  49. }
  50. // 创建合同目录树
  51. func MakeFolderContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) { //参数为父节点,添加父节点的子节点指针切片
  52. childs, _ := HaveChildContract(Data, node) //判断节点是否有子节点并返回
  53. if childs != nil {
  54. // 子节点总数
  55. Total := len(childs)
  56. node.ChildsTotal = Total
  57. // 标记最后一个元素
  58. end := Total - 1
  59. childs[end].IsEnd = true
  60. // 往父节点添加子节点
  61. node.Children = append(node.Children, childs[0:]...) //添加子节点
  62. // 1.标段汇总
  63. // 1-1.合同相关汇总-收入金额
  64. totalIncome := 0.00
  65. // 1-2.合同总数
  66. totalContractNumber := 0
  67. // 1-3.汇款进度
  68. totalReturn := 0.00
  69. // 1-4支出金额
  70. totalPay := 0.00
  71. totalPaid := 0.00
  72. // 1-5 安全巡检
  73. safeTotal := 0
  74. safeTotalRectification := 0
  75. safeTotalRectificationIn := 0
  76. SafeTotalApproval := 0
  77. SafeTotalClose := 0
  78. // 1-6 质量巡检
  79. qualityTotal := 0
  80. qualityTotalRectification := 0
  81. qualityTotalRectificationIn := 0
  82. QualityTotalApproval := 0
  83. QualityTotalClose := 0
  84. for _, v := range childs { //查询子节点的子节点,并添加到子节点
  85. _, has := HaveChildContract(Data, v)
  86. if has {
  87. // 递归添加节点
  88. MakeFolderContract(Data, v)
  89. }
  90. // 目录下是否包含标段
  91. if v.Isfolder == 0 {
  92. node.IsBid = true
  93. } else {
  94. node.HasFolder = true
  95. }
  96. // 2.标段汇总
  97. // 2-1收入金额 合计
  98. // returnDate[item.Time.Format(conf.SysTimeformMonth)], _ = decimal.NewFromFloat(returnDate[item.Time.Format(conf.SysTimeformMonth)]).Add(decimal.NewFromFloat(typePrice)).Float64()
  99. price, _ := strconv.ParseFloat(v.ContractsIncome, 64)
  100. totalIncome, _ = decimal.NewFromFloat(totalIncome).Add(decimal.NewFromFloat(price)).Float64()
  101. // 2-2合同总数 合计
  102. totalContractNumber = totalContractNumber + v.Contracts
  103. // 2-3 汇款进度
  104. price, _ = strconv.ParseFloat(v.ContractsReturned, 64)
  105. totalReturn, _ = decimal.NewFromFloat(totalReturn).Add(decimal.NewFromFloat(price)).Float64()
  106. // totalReturn = totalReturn + price
  107. //
  108. price, _ = strconv.ParseFloat(v.ContractsPay, 64)
  109. totalPay, _ = decimal.NewFromFloat(totalPay).Add(decimal.NewFromFloat(price)).Float64()
  110. // totalPay = totalPay + price
  111. price, _ = strconv.ParseFloat(v.ContractsPaid, 64)
  112. totalPaid, _ = decimal.NewFromFloat(totalPaid).Add(decimal.NewFromFloat(price)).Float64()
  113. // totalPaid = totalPaid + price
  114. // 安全巡检
  115. safeTotal = safeTotal + v.SafeTotal
  116. safeTotalRectification = safeTotalRectification + v.SafeRectification
  117. safeTotalRectificationIn = safeTotalRectificationIn + v.SafeRectificationIn
  118. SafeTotalApproval = SafeTotalApproval + v.SafeApproval
  119. SafeTotalClose = SafeTotalClose + v.SafeClose
  120. // 1-6 质量巡检
  121. qualityTotal = safeTotal + v.QualityTotal
  122. qualityTotalRectification = safeTotalRectification + v.QualityRectification
  123. qualityTotalRectificationIn = safeTotalRectificationIn + v.QualityRectificationIn
  124. QualityTotalApproval = QualityTotalApproval + v.QualityApproval
  125. QualityTotalClose = QualityTotalClose + v.QualityClose
  126. }
  127. node.ContractsIncome = fmt.Sprintf("%G", totalIncome)
  128. node.Contracts = totalContractNumber
  129. // 汇款进度
  130. quotient := totalReturn / totalIncome
  131. if math.IsNaN(quotient) {
  132. quotient = 0
  133. }
  134. node.ContractsIncomeProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"
  135. // 支出相关
  136. // node.ContractsPay = fmt.Sprintf("%.2f", totalPay)
  137. node.ContractsPay = fmt.Sprintf("%G", totalPay)
  138. quotient = totalPaid / totalPay
  139. if math.IsNaN(quotient) {
  140. quotient = 0
  141. }
  142. node.ContractsPayProgress = fmt.Sprintf("%.0f", (quotient)*100) + "%"
  143. // 安全巡检
  144. node.SafeTotal = safeTotal
  145. node.SafeRectification = safeTotalRectification
  146. node.SafeRectificationIn = safeTotalRectificationIn
  147. node.SafeApproval = SafeTotalApproval
  148. node.SafeClose = SafeTotalClose
  149. // 质量巡检
  150. node.QualityTotal = qualityTotal
  151. node.QualityRectification = qualityTotalRectification
  152. node.QualityRectificationIn = qualityTotalRectificationIn
  153. node.QualityApproval = QualityTotalApproval
  154. node.QualityClose = QualityTotalClose
  155. }
  156. }
  157. // 是否有子树
  158. func HaveChildContract(Data []*viewmodels.FolderContract, node *viewmodels.FolderContract) (child []*viewmodels.FolderContract, yes bool) {
  159. for _, v := range Data {
  160. if v.ParentId == node.Id {
  161. child = append(child, v)
  162. }
  163. }
  164. if child != nil {
  165. yes = true
  166. }
  167. return
  168. }
  169. // 创建合同项目节树
  170. func MakeSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) { //参数为父节点,添加父节点的子节点指针切片
  171. childs, _ := haveChildSectionContract(Data, node) //判断节点是否有子节点并返回
  172. if childs != nil {
  173. // 往父节点添加子节点
  174. // 孩子们从小到大排序
  175. if len(childs) != 0 {
  176. sectionSelectionSort(childs)
  177. childs[0].ElderBrother = false
  178. childs[len(childs)-1].IsEnd = true
  179. }
  180. // 项目节父项使用
  181. // 1.合同总金额 回款总金额 已支付总金额
  182. contractPriceTotal := 0.00
  183. returnPriceTotal := 0.00
  184. paidPriceTotal := 0.00
  185. node.Children = append(node.Children, childs[0:]...) //添加子节点
  186. for _, v := range childs { //查询子节点的子节点,并添加到子节点
  187. _, has := haveChildSectionContract(Data, v)
  188. if has {
  189. // 递归添加节点
  190. MakeSectionContract(Data, v)
  191. }
  192. // 2.计算父项中金额
  193. contractPrice, _ := strconv.ParseFloat(v.ContractPrice, 64)
  194. contractPriceTotal += contractPrice
  195. returnPrice, _ := strconv.ParseFloat(v.ContractReturned, 64)
  196. returnPriceTotal += returnPrice
  197. paidPrice, _ := strconv.ParseFloat(v.ContractsPaid, 64)
  198. paidPriceTotal += paidPrice
  199. }
  200. // 3.赋值到父项中
  201. node.ContractPrice = fmt.Sprintf("%.2f", contractPriceTotal)
  202. node.ContractReturned = fmt.Sprintf("%.2f", returnPriceTotal)
  203. node.ContractsPaid = fmt.Sprintf("%.2f", paidPriceTotal)
  204. }
  205. }
  206. // 合同项目节孩子排序
  207. func sectionSelectionSort(child []*viewmodels.TreeSectionContract) {
  208. for i := 0; i < len(child); i++ {
  209. minIndex := i
  210. // 查找最小值
  211. for j := i; j < len(child); j++ {
  212. if child[j].Serial < child[minIndex].Serial {
  213. minIndex = j
  214. }
  215. }
  216. swapContract(child, i, minIndex)
  217. }
  218. }
  219. func swapContract(child []*viewmodels.TreeSectionContract, i int, minIndex int) {
  220. t := child[i]
  221. child[i] = child[minIndex]
  222. child[minIndex] = t
  223. }
  224. // 是否有子树
  225. func haveChildSectionContract(Data []*viewmodels.TreeSectionContract, node *viewmodels.TreeSectionContract) (child []*viewmodels.TreeSectionContract, yes bool) {
  226. for _, v := range Data {
  227. if v.ParentId == node.Id {
  228. child = append(child, v)
  229. }
  230. }
  231. if child != nil {
  232. yes = true
  233. }
  234. return
  235. }
  236. // 当前时间的时间戳
  237. func NowUnix() int {
  238. return int(time.Now().In(conf.SysTimeLocation).Unix())
  239. }
  240. // 将unix时间戳格式化为yyyymmdd H:i:s格式字符串
  241. func FormatFromUnixTime(t int64) string {
  242. if t > 0 {
  243. return time.Unix(t, 0).Format(conf.SysTimeform)
  244. } else {
  245. return time.Now().Format(conf.SysTimeform)
  246. }
  247. }
  248. // 将unix时间戳格式化为yyyymmdd格式字符串
  249. func FormatFromUnixTimeShort(t int64) string {
  250. if t > 0 {
  251. return time.Unix(t, 0).Format(conf.SysTimeformShort)
  252. } else {
  253. return time.Now().Format(conf.SysTimeformShort)
  254. }
  255. }
  256. // 将字符串转成时间
  257. func ParseTime(str string) (time.Time, error) {
  258. return time.ParseInLocation(conf.SysTimeform, str, conf.SysTimeLocation)
  259. }
  260. // 得到一个随机数
  261. func Random(max int) int {
  262. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  263. if max < 1 {
  264. return r.Int()
  265. } else {
  266. return r.Intn(max)
  267. }
  268. }
  269. // 加密密码
  270. func CreatePasswordSign(password string, account string) string {
  271. str := string(conf.SignSecret) + password + account
  272. str1 := fmt.Sprintf("%x", md5.Sum([]byte(str)))
  273. sign := fmt.Sprintf("%x", md5.Sum([]byte(str1)))
  274. return sign
  275. }
  276. // 对字符串进行签名
  277. func CreateSign(str string) string {
  278. str = string(conf.SignSecret) + str
  279. str1 := fmt.Sprintf("%x", md5.Sum([]byte(str)))
  280. sign := fmt.Sprintf("%x", md5.Sum([]byte(str1)))
  281. return sign
  282. }
  283. // 对一个字符串进行加密
  284. func Encrypt(key, text []byte) (string, error) {
  285. block, err := aes.NewCipher(key)
  286. if err != nil {
  287. return "", err
  288. }
  289. b := base64.StdEncoding.EncodeToString(text)
  290. ciphertext := make([]byte, aes.BlockSize+len(b))
  291. iv := ciphertext[:aes.BlockSize]
  292. //if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  293. // return nil, err
  294. //}
  295. cfb := cipher.NewCFBEncrypter(block, iv)
  296. cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
  297. return base64.RawURLEncoding.EncodeToString(ciphertext), nil
  298. }
  299. // 对一个字符串进行解密
  300. func Decrypt(key, text []byte) ([]byte, error) {
  301. block, err := aes.NewCipher(key)
  302. if err != nil {
  303. return nil, err
  304. }
  305. if len(text) < aes.BlockSize {
  306. return nil, errors.New("ciphertext too short")
  307. }
  308. iv := text[:aes.BlockSize]
  309. text = text[aes.BlockSize:]
  310. cfb := cipher.NewCFBDecrypter(block, iv)
  311. cfb.XORKeyStream(text, text)
  312. data, err := base64.StdEncoding.DecodeString(string(text))
  313. if err != nil {
  314. return nil, err
  315. }
  316. return data, nil
  317. }
  318. // 加密
  319. func AesEncrypt(orig string, key string) (string, error) {
  320. // 转成字节数组
  321. origData := []byte(orig)
  322. k := []byte(key)
  323. // 分组秘钥
  324. block, err := aes.NewCipher(k)
  325. if err != nil {
  326. return "", err
  327. }
  328. // 获取秘钥块的长度
  329. blockSize := block.BlockSize()
  330. // 补全码
  331. origData = PKCS7Padding(origData, blockSize)
  332. // 加密模式
  333. blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
  334. // 创建数组
  335. cryted := make([]byte, len(origData))
  336. // 加密
  337. blockMode.CryptBlocks(cryted, origData)
  338. //使用RawURLEncoding 不要使用StdEncoding
  339. //不要使用StdEncoding 放在url参数中回导致错误
  340. return base64.RawURLEncoding.EncodeToString(cryted), nil
  341. }
  342. // 解密
  343. func AesDecrypt(cryted string, key string) (string, error) {
  344. //使用RawURLEncoding 不要使用StdEncoding
  345. //不要使用StdEncoding 放在url参数中回导致错误
  346. crytedByte, err := base64.RawURLEncoding.DecodeString(cryted)
  347. if err != nil {
  348. return "", err
  349. }
  350. k := []byte(key)
  351. // 分组秘钥
  352. block, err := aes.NewCipher(k)
  353. if err != nil {
  354. return "", err
  355. }
  356. // 获取秘钥块的长度
  357. blockSize := block.BlockSize()
  358. // 加密模式
  359. blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
  360. // 创建数组
  361. orig := make([]byte, len(crytedByte))
  362. // 解密--传入不正确的字符时会报错-TODO 需捕获
  363. blockMode.CryptBlocks(orig, crytedByte)
  364. // 去补全码
  365. orig = PKCS7UnPadding(orig)
  366. return string(orig), nil
  367. }
  368. //补码
  369. func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
  370. padding := blocksize - len(ciphertext)%blocksize
  371. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  372. return append(ciphertext, padtext...)
  373. }
  374. //去码
  375. func PKCS7UnPadding(origData []byte) []byte {
  376. length := len(origData)
  377. unpadding := int(origData[length-1])
  378. return origData[:(length - unpadding)]
  379. }
  380. // addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
  381. // 预定义字符是:
  382. // 单引号(')
  383. // 双引号(")
  384. // 反斜杠(\)
  385. func Addslashes(str string) string {
  386. tmpRune := []rune{}
  387. strRune := []rune(str)
  388. for _, ch := range strRune {
  389. switch ch {
  390. case []rune{'\\'}[0], []rune{'"'}[0], []rune{'\''}[0]:
  391. tmpRune = append(tmpRune, []rune{'\\'}[0])
  392. tmpRune = append(tmpRune, ch)
  393. default:
  394. tmpRune = append(tmpRune, ch)
  395. }
  396. }
  397. return string(tmpRune)
  398. }
  399. // stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
  400. func Stripslashes(str string) string {
  401. dstRune := []rune{}
  402. strRune := []rune(str)
  403. strLenth := len(strRune)
  404. for i := 0; i < strLenth; i++ {
  405. if strRune[i] == []rune{'\\'}[0] {
  406. i++
  407. }
  408. dstRune = append(dstRune, strRune[i])
  409. }
  410. return string(dstRune)
  411. }
  412. // 将字符串的IP转化为数字
  413. func Ip4toInt(ip string) int64 {
  414. bits := strings.Split(ip, ".")
  415. if len(bits) == 4 {
  416. b0, _ := strconv.Atoi(bits[0])
  417. b1, _ := strconv.Atoi(bits[1])
  418. b2, _ := strconv.Atoi(bits[2])
  419. b3, _ := strconv.Atoi(bits[3])
  420. var sum int64
  421. sum += int64(b0) << 24
  422. sum += int64(b1) << 16
  423. sum += int64(b2) << 8
  424. sum += int64(b3)
  425. return sum
  426. } else {
  427. return 0
  428. }
  429. }
  430. // 得到当前时间到下一天零点的延时
  431. func NextDayDuration() time.Duration {
  432. year, month, day := time.Now().Add(time.Hour * 24).Date()
  433. next := time.Date(year, month, day, 0, 0, 0, 0, conf.SysTimeLocation)
  434. return next.Sub(time.Now())
  435. }
  436. // 从接口类型安全获取到int64
  437. func GetInt64(i interface{}, d int64) int64 {
  438. if i == nil {
  439. return d
  440. }
  441. switch i.(type) {
  442. case string:
  443. num, err := strconv.Atoi(i.(string))
  444. if err != nil {
  445. return d
  446. } else {
  447. return int64(num)
  448. }
  449. case []byte:
  450. bits := i.([]byte)
  451. if len(bits) == 8 {
  452. return int64(binary.LittleEndian.Uint64(bits))
  453. } else if len(bits) <= 4 {
  454. num, err := strconv.Atoi(string(bits))
  455. if err != nil {
  456. return d
  457. } else {
  458. return int64(num)
  459. }
  460. }
  461. case uint:
  462. return int64(i.(uint))
  463. case uint8:
  464. return int64(i.(uint8))
  465. case uint16:
  466. return int64(i.(uint16))
  467. case uint32:
  468. return int64(i.(uint32))
  469. case uint64:
  470. return int64(i.(uint64))
  471. case int:
  472. return int64(i.(int))
  473. case int8:
  474. return int64(i.(int8))
  475. case int16:
  476. return int64(i.(int16))
  477. case int32:
  478. return int64(i.(int32))
  479. case int64:
  480. return i.(int64)
  481. case float32:
  482. return int64(i.(float32))
  483. case float64:
  484. return int64(i.(float64))
  485. }
  486. return d
  487. }
  488. // 从接口类型安全获取到字符串类型
  489. func GetString(str interface{}, d string) string {
  490. if str == nil {
  491. return d
  492. }
  493. switch str.(type) {
  494. case string:
  495. return str.(string)
  496. case []byte:
  497. return string(str.([]byte))
  498. }
  499. return fmt.Sprintf("%s", str)
  500. }
  501. // 从map中得到指定的key
  502. func GetInt64FromMap(dm map[string]interface{}, key string, dft int64) int64 {
  503. data, ok := dm[key]
  504. if !ok {
  505. return dft
  506. }
  507. return GetInt64(data, dft)
  508. }
  509. // 从map中得到指定的key
  510. func GetInt64FromStringMap(dm map[string]string, key string, dft int64) int64 {
  511. data, ok := dm[key]
  512. if !ok {
  513. return dft
  514. }
  515. return GetInt64(data, dft)
  516. }
  517. // 从map中得到指定的key
  518. func GetStringFromMap(dm map[string]interface{}, key string, dft string) string {
  519. data, ok := dm[key]
  520. if !ok {
  521. return dft
  522. }
  523. return GetString(data, dft)
  524. }
  525. // 从map中得到指定的key
  526. func GetStringFromStringMap(dm map[string]string, key string, dft string) string {
  527. data, ok := dm[key]
  528. if !ok {
  529. return dft
  530. }
  531. return data
  532. }
  533. // 首字母大写
  534. func Ucfirst(str string) string {
  535. for i, v := range str {
  536. return string(unicode.ToUpper(v)) + str[i+1:]
  537. }
  538. return ""
  539. }