functions.go 15 KB

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