functions.go 17 KB

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