functions.go 14 KB

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