base.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. package service
  2. import (
  3. "context"
  4. "dashoo.cn/opms_libary/multipart"
  5. "encoding/base64"
  6. "fmt"
  7. "github.com/gogf/gf/encoding/gurl"
  8. "github.com/gogf/gf/text/gstr"
  9. "github.com/gogf/gf/util/guid"
  10. "github.com/xuri/excelize/v2"
  11. "io/ioutil"
  12. "log"
  13. "net/http"
  14. "os"
  15. "reflect"
  16. "dashoo.cn/opms_libary/myerrors"
  17. "dashoo.cn/opms_libary/request"
  18. "github.com/gogf/gf/container/gmap"
  19. "github.com/gogf/gf/frame/g"
  20. "github.com/gogf/gf/util/gconv"
  21. "github.com/smallnest/rpcx/share"
  22. "dashoo.cn/common_definition/comm_def"
  23. "dashoo.cn/opms_libary/micro_srv"
  24. "github.com/gogf/gf/database/gdb"
  25. "github.com/gogf/gf/os/gtime"
  26. )
  27. var (
  28. // DingTalkSpaceId 钉钉 空间Id。
  29. DingTalkSpaceId = "21077726250"
  30. // CommonUpdateFieldEx UpdateFieldEx 更新过滤字段
  31. CommonUpdateFieldEx = []interface{}{"created_by", "created_name", "created_time"}
  32. UpdateFieldEx = []interface{}{"id", "created_by", "created_name", "created_time"}
  33. )
  34. func Sequence(db gdb.DB, name string) (string, error) {
  35. v, err := db.GetValue("select `nextval`( ? );", name)
  36. if err != nil {
  37. return "", err
  38. }
  39. return v.String(), nil
  40. }
  41. func SequenceYearRest(db gdb.DB, name string) (int, error) {
  42. v, err := db.GetValue("select `next_year_reset_val`( ? );", name)
  43. if err != nil {
  44. return 0, err
  45. }
  46. return v.Int(), nil
  47. }
  48. // SetCreatedInfo 插入数据库时设置创建信息
  49. func SetCreatedInfo(entry interface{}, id int, name string) {
  50. v := reflect.ValueOf(entry)
  51. t := reflect.TypeOf(entry)
  52. if t.Kind() == reflect.Map {
  53. data := entry.(map[string]interface{})
  54. data["created_by"] = id
  55. data["created_name"] = name
  56. data["created_time"] = gtime.Now()
  57. return
  58. }
  59. if t.Kind() == reflect.Ptr {
  60. t = t.Elem()
  61. v = v.Elem()
  62. }
  63. if t.Kind() == reflect.Slice {
  64. }
  65. if t.Kind() != reflect.Struct {
  66. log.Println("Check type error not Struct")
  67. return
  68. }
  69. for i := 0; i < t.NumField(); i++ {
  70. fieldName := t.Field(i).Name
  71. if tag, ok := t.Field(i).Tag.Lookup("orm"); ok {
  72. switch tag {
  73. case "created_by":
  74. v.FieldByName(fieldName).Set(reflect.ValueOf(id))
  75. case "created_name":
  76. v.FieldByName(fieldName).Set(reflect.ValueOf(name))
  77. case "created_time":
  78. v.FieldByName(fieldName).Set(reflect.ValueOf(gtime.Now()))
  79. }
  80. }
  81. }
  82. }
  83. // SetUpdatedInfo 插入数据库时设置修改信息
  84. func SetUpdatedInfo(entry interface{}, id int, name string) {
  85. v := reflect.ValueOf(entry)
  86. t := reflect.TypeOf(entry)
  87. if t.Kind() == reflect.Map {
  88. data := entry.(map[string]interface{})
  89. data["updated_by"] = id
  90. data["updated_name"] = name
  91. data["updated_time"] = gtime.Now()
  92. return
  93. }
  94. if t.Kind() == reflect.Ptr {
  95. t = t.Elem()
  96. v = v.Elem()
  97. }
  98. if t.Kind() != reflect.Struct {
  99. log.Println("Check type error not Struct")
  100. return
  101. }
  102. for i := 0; i < t.NumField(); i++ {
  103. fieldName := t.Field(i).Name
  104. if tag, ok := t.Field(i).Tag.Lookup("orm"); ok {
  105. switch tag {
  106. case "updated_by":
  107. v.FieldByName(fieldName).Set(reflect.ValueOf(id))
  108. case "updated_name":
  109. v.FieldByName(fieldName).Set(reflect.ValueOf(name))
  110. case "updated_time":
  111. v.FieldByName(fieldName).Set(reflect.ValueOf(gtime.Now()))
  112. }
  113. }
  114. }
  115. }
  116. // Div 数字转字母
  117. func Div(Num int) string {
  118. var (
  119. Str string = ""
  120. k int
  121. temp []int //保存转化后每一位数据的值,然后通过索引的方式匹配A-Z
  122. )
  123. //用来匹配的字符A-Z
  124. Slice := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
  125. "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
  126. if Num > 26 { //数据大于26需要进行拆分
  127. for {
  128. k = Num % 26 //从个位开始拆分,如果求余为0,说明末尾为26,也就是Z,如果是转化为26进制数,则末尾是可以为0的,这里必须为A-Z中的一个
  129. if k == 0 {
  130. temp = append(temp, 26)
  131. k = 26
  132. } else {
  133. temp = append(temp, k)
  134. }
  135. Num = (Num - k) / 26 //减去Num最后一位数的值,因为已经记录在temp中
  136. if Num <= 26 { //小于等于26直接进行匹配,不需要进行数据拆分
  137. temp = append(temp, Num)
  138. break
  139. }
  140. }
  141. } else {
  142. return Slice[Num]
  143. }
  144. for _, value := range temp {
  145. Str = Slice[value] + Str //因为数据切分后存储顺序是反的,所以Str要放在后面
  146. }
  147. return Str
  148. }
  149. type GetDictReq struct {
  150. DictType string `p:"dictType" v:"required#字典类型不能为空"`
  151. DefaultValue string `p:"defaultValue"`
  152. }
  153. type GetDictLabelByTypeAndValueReq struct {
  154. DictType string `p:"dictType"` //字典类型
  155. DictValue string `p:"dictValue"` //字典标签
  156. }
  157. func baseGetDictDataByType(ctx context.Context, typ string) ([]interface{}, error) {
  158. srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth")
  159. defer srv.Close()
  160. resp := &comm_def.CommonMsg{}
  161. err := srv.Call(ctx, "GetDictDataByType", GetDictReq{
  162. DictType: typ,
  163. }, resp)
  164. if err != nil {
  165. return nil, fmt.Errorf("获取字典 %s %s", typ, err.Error())
  166. }
  167. fmt.Println(resp.Data)
  168. data := resp.Data.(map[string]interface{})["Values"].([]interface{})
  169. fmt.Println(data)
  170. return data, nil
  171. }
  172. func GetDictDataByType(ctx context.Context, typ string) (map[string]string, error) {
  173. data, err := baseGetDictDataByType(ctx, typ)
  174. if err != nil {
  175. return nil, err
  176. }
  177. res := map[string]string{}
  178. for _, i := range data {
  179. info := i.(map[string]interface{})
  180. res[info["DictValue"].(string)] = info["DictLabel"].(string)
  181. }
  182. return res, nil
  183. }
  184. // Find获取一个切片并在其中查找元素。如果找到它,它将返回它的密钥,否则它将返回-1和一个错误的bool。
  185. func FindItem(slice []string, val string) (int, bool) {
  186. for i, item := range slice {
  187. if item == val {
  188. return i, true
  189. }
  190. }
  191. return -1, false
  192. }
  193. // 有序
  194. func GetDictDataTreeByType(ctx context.Context, typ string) (*gmap.ListMap, error) {
  195. data, err := baseGetDictDataByType(ctx, typ)
  196. if err != nil {
  197. return nil, err
  198. }
  199. res := gmap.NewListMap(true)
  200. for _, i := range data {
  201. info := i.(map[string]interface{})
  202. res.Set(info["DictValue"], info["DictLabel"])
  203. }
  204. return res, nil
  205. }
  206. // 根据字典类型和字典值获取字典明细名称
  207. func GetDictLabelByTypeAndValue(ctx context.Context, dictType, value string) (string, error) {
  208. srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth")
  209. defer srv.Close()
  210. resp := &comm_def.CommonMsg{}
  211. err := srv.Call(ctx, "GetDictLabelByTypeAndValue", GetDictLabelByTypeAndValueReq{
  212. DictType: dictType,
  213. DictValue: value,
  214. }, resp)
  215. if err != nil {
  216. g.Log().Error(err)
  217. return value, nil
  218. }
  219. return gconv.String(resp.Data), nil
  220. }
  221. func StringSlicecontains(s []string, ele string) bool {
  222. for _, i := range s {
  223. if i == ele {
  224. return true
  225. }
  226. }
  227. return false
  228. }
  229. // CreateSystemMessage 创建系统消息
  230. func CreateSystemMessage(msg g.MapStrStr) error {
  231. srv := micro_srv.InitMicroSrvClient("SystemMessage", "micro_srv.auth")
  232. defer srv.Close()
  233. resp := &comm_def.CommonMsg{}
  234. tenant := g.Config().GetString("micro_srv.tenant")
  235. ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
  236. err := srv.Call(ctx, "Create", msg, resp)
  237. if err != nil {
  238. g.Log().Error(err)
  239. return myerrors.MicroCallError("系统创建消息失败")
  240. }
  241. fmt.Println(resp.Data)
  242. return nil
  243. }
  244. type DeptIdReq struct {
  245. DeptId int `json:"dept_id,omitempty"`
  246. Include bool `json:"include,omitempty"`
  247. }
  248. // GetUsersByDept 根据部门获取用户
  249. func GetUsersByDept(ctx context.Context, req *DeptIdReq) (map[string]int, error) {
  250. srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth")
  251. defer srv.Close()
  252. resp := &comm_def.CommonMsg{}
  253. err := srv.Call(ctx, "GetUserByDept", req, resp)
  254. if err != nil {
  255. return nil, myerrors.MicroCallError("获取部门下用户失败")
  256. }
  257. if resp.Data == nil {
  258. return nil, myerrors.TipsError("部门不存在")
  259. }
  260. fmt.Println(resp.Data)
  261. data := resp.Data.([]interface{})
  262. fmt.Println(data)
  263. res := map[string]int{}
  264. for _, i := range data {
  265. info := i.(map[string]interface{})
  266. res[info["NickName"].(string)] = gconv.Int(info["Id"])
  267. }
  268. return res, nil
  269. }
  270. type SysUserSearchReq struct {
  271. KeyWords string `json:"keyWords"`
  272. DeptId int `json:"deptId"` //部门id
  273. DeptIds []int //所属部门id数据
  274. Phone string `json:"phone"`
  275. Status string `json:"status"`
  276. Roles []string `json:"roles"`
  277. Posts []string `json:"posts"`
  278. Groups []string `json:"groups"`
  279. request.PageReq
  280. }
  281. // GetUsersByRoleCode 根据角色编码获取用户
  282. func GetUsersByRoleCode(ctx context.Context, roleCode []string, pageSize ...int) (map[string]int, error) {
  283. srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth")
  284. defer srv.Close()
  285. resp := &comm_def.CommonMsg{}
  286. req := &SysUserSearchReq{Roles: roleCode, Status: "10"}
  287. if len(pageSize) > 0 {
  288. req.PageSize = pageSize[0]
  289. }
  290. err := srv.Call(ctx, "GetList", req, resp)
  291. if err != nil {
  292. return nil, myerrors.MicroCallError("根据角色编码获取用户失败")
  293. }
  294. if resp.Data == nil {
  295. return nil, myerrors.TipsError("用户不存在")
  296. }
  297. data := resp.Data.(map[string]interface{})
  298. list := data["list"].([]interface{})
  299. res := map[string]int{}
  300. for _, i := range list {
  301. info := i.(map[string]interface{})
  302. res[info["NickName"].(string)] = gconv.Int(info["Id"])
  303. }
  304. return res, nil
  305. }
  306. // GetUserListByRoleCode 根据角色编码获取用户列表
  307. func GetUserListByRoleCode(ctx context.Context, roleCode []string, pageSize ...int) ([]map[string]interface{}, error) {
  308. srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth")
  309. defer srv.Close()
  310. resp := &comm_def.CommonMsg{}
  311. req := &SysUserSearchReq{Roles: roleCode, Status: "10"}
  312. if len(pageSize) > 0 {
  313. req.PageSize = pageSize[0]
  314. }
  315. err := srv.Call(ctx, "GetList", req, resp)
  316. if err != nil {
  317. return nil, myerrors.MicroCallError("根据角色编码获取用户失败")
  318. }
  319. if resp.Data == nil {
  320. return nil, myerrors.TipsError("用户不存在")
  321. }
  322. data := resp.Data.(map[string]interface{})
  323. list := data["list"].([]interface{})
  324. var res []map[string]interface{}
  325. for _, i := range list {
  326. info := i.(map[string]interface{})
  327. data := map[string]interface{}{
  328. "Id": gconv.Int(info["Id"]),
  329. "NickName": info["NickName"].(string),
  330. }
  331. res = append(res, data)
  332. }
  333. return res, nil
  334. }
  335. // 获取用户权限
  336. func GetUserDataScope(userId int) (g.Map, error) {
  337. srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth")
  338. defer srv.Close()
  339. req := &comm_def.IdReq{Id: int64(userId)}
  340. resp := &comm_def.CommonMsg{}
  341. tenant := g.Config().GetString("micro_srv.tenant")
  342. ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
  343. err := srv.Call(ctx, "GetDataScope", req, resp)
  344. if err != nil || resp.Data == nil {
  345. g.Log().Error(err)
  346. return nil, myerrors.MicroCallError("获取用户权限失败")
  347. }
  348. return resp.Data.(g.Map), nil
  349. }
  350. // 跟进发送邮件消息
  351. func GSendMail(msg g.MapStrStr) error {
  352. srv := micro_srv.InitMicroSrvClient("Message", "micro_srv.auth")
  353. defer srv.Close()
  354. resp := &comm_def.CommonMsg{}
  355. tenant := g.Config().GetString("micro_srv.tenant")
  356. ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
  357. err := srv.Call(ctx, "SendMail", msg, resp)
  358. if err != nil {
  359. g.Log().Error(err)
  360. return myerrors.MicroCallError("项目未跟进发送邮件提醒失败")
  361. }
  362. fmt.Println(resp.Data)
  363. return nil
  364. }
  365. func ColumnInt(m *gdb.Model, name string) ([]int, error) {
  366. v, err := m.Fields(name).Array()
  367. if err != nil {
  368. return nil, err
  369. }
  370. res := []int{}
  371. for _, i := range v {
  372. res = append(res, i.Int())
  373. }
  374. return res, nil
  375. }
  376. func ColumnString(m *gdb.Model, name string) ([]string, error) {
  377. v, err := m.Fields(name).Array()
  378. if err != nil {
  379. return nil, err
  380. }
  381. res := []string{}
  382. for _, i := range v {
  383. res = append(res, i.String())
  384. }
  385. return res, nil
  386. }
  387. func StringsContains(s []string, ele string) bool {
  388. for _, i := range s {
  389. if i == ele {
  390. return true
  391. }
  392. }
  393. return false
  394. }
  395. func UserIdByRoles(db gdb.DB, roles ...string) ([]int, error) {
  396. roleId, err := ColumnInt(db.Table("sys_role").Where("role_key in (?)", roles), "id")
  397. if err != nil {
  398. return nil, err
  399. }
  400. return ColumnInt(db.Table("sys_user_role").Where("role_id in (?)", roleId), "user_id")
  401. }
  402. func UserDingtalkUid(db gdb.DB, id int) (string, error) {
  403. v, err := db.Table("sys_user").Where("id = ?", id).Fields("dingtalk_uid").Value()
  404. if err != nil {
  405. return "", err
  406. }
  407. uid := v.String()
  408. if uid == "" {
  409. return "", fmt.Errorf("没有找到 %d 的钉钉用户id", id)
  410. }
  411. return uid, nil
  412. }
  413. func SliceIntDeduplication(elems []int) []int {
  414. emap := map[int]struct{}{}
  415. for _, i := range elems {
  416. emap[i] = struct{}{}
  417. }
  418. ret := []int{}
  419. for i := range emap {
  420. ret = append(ret, i)
  421. }
  422. return ret
  423. }
  424. // DownloadTempFile 下载临时文件
  425. func DownloadTempFile(url string) (*multipart.FileHeader, error) {
  426. r, err := http.Get(url)
  427. if err != nil {
  428. g.Log().Error(err)
  429. return nil, err
  430. }
  431. if r.StatusCode != http.StatusOK {
  432. return nil, fmt.Errorf("DownloadFile from %s StatusCode %d", url, r.StatusCode)
  433. }
  434. defer r.Body.Close()
  435. bytes, err := ioutil.ReadAll(r.Body)
  436. if err != nil {
  437. g.Log().Error(err)
  438. return nil, err
  439. }
  440. names := gstr.Split(r.Header.Get("Content-Disposition"), "filename=")
  441. fileName := guid.S()
  442. if len(names) > 1 {
  443. fileName, _ = gurl.Decode(names[1])
  444. fileName = gstr.TrimStr(fileName, `"`)
  445. }
  446. file, err := os.CreateTemp("", fileName)
  447. if err != nil {
  448. g.Log().Error(err)
  449. }
  450. file.Write(bytes)
  451. fmt.Println(file.Name())
  452. fileData := new(multipart.FileHeader)
  453. fileData.FileName = fileName
  454. fileData.FileSize = gconv.Int64(r.Header.Get("Content-Length"))
  455. fileData.File = file
  456. return fileData, nil
  457. }
  458. // getExcelHeader 获取Excel表头
  459. func getExcelHeader(exportStruct interface{}, tag string) ([]string, g.MapStrStr) {
  460. var headerList []string
  461. headerMap := g.MapStrStr{}
  462. reqType := reflect.TypeOf(exportStruct)
  463. if reqType.Kind() == reflect.Ptr {
  464. reqType = reqType.Elem()
  465. }
  466. for i := 0; i < reqType.NumField(); i++ {
  467. fieldName, ok := reqType.Field(i).Tag.Lookup("json")
  468. if !ok {
  469. fieldName = reqType.Field(i).Name
  470. }
  471. if tag, ok := reqType.Field(i).Tag.Lookup(tag); ok {
  472. headerList = append(headerList, tag)
  473. headerMap[tag] = fieldName
  474. }
  475. }
  476. return headerList, headerMap
  477. }
  478. // CommonExportExcel 公共单表导出excel
  479. func CommonExportExcel(ctx context.Context, fileName string, exportStruct interface{}, dataList []map[string]interface{}, handleFunc ...func(map[string]interface{}, string) interface{}) (path string, err error) {
  480. headerList, headerMap := getExcelHeader(exportStruct, "export")
  481. // 转换数据
  482. xlsxFile := excelize.NewFile()
  483. defer xlsxFile.Close()
  484. // 插入表头
  485. if fileName == "" {
  486. fileName = "Sheet1"
  487. }
  488. colStyle, err := xlsxFile.NewStyle(&excelize.Style{
  489. Alignment: &excelize.Alignment{
  490. Horizontal: "center",
  491. Vertical: "center",
  492. WrapText: true,
  493. },
  494. Font: &excelize.Font{
  495. Size: 11,
  496. Family: "宋体",
  497. },
  498. })
  499. headerStyle, err := xlsxFile.NewStyle(&excelize.Style{
  500. Alignment: &excelize.Alignment{
  501. Horizontal: "center",
  502. },
  503. Fill: excelize.Fill{
  504. Type: "pattern",
  505. Color: []string{"#a6a6a6"},
  506. Pattern: 1,
  507. },
  508. Border: []excelize.Border{
  509. {Type: "left", Color: "#000000", Style: 1},
  510. {Type: "top", Color: "#000000", Style: 1},
  511. {Type: "bottom", Color: "#000000", Style: 1},
  512. {Type: "right", Color: "#000000", Style: 1},
  513. },
  514. })
  515. lastColName, err := excelize.ColumnNumberToName(len(headerList))
  516. xlsxFile.SetColStyle("Sheet1", "A:"+lastColName, colStyle)
  517. xlsxFile.SetCellStyle("Sheet1", "A1", lastColName+"1", headerStyle)
  518. xlsxFile.SetColWidth("Sheet1", "A", lastColName, 20)
  519. xlsxFile.SetSheetName("Sheet1", fileName)
  520. xlsxFile.SetSheetRow(fileName, "A1", &headerList)
  521. if err != nil {
  522. return "", err
  523. }
  524. for k, item := range dataList {
  525. var row []interface{}
  526. for _, h := range headerList {
  527. val := item[headerMap[h]]
  528. if len(handleFunc) > 0 {
  529. val = handleFunc[0](item, headerMap[h])
  530. }
  531. row = append(row, val)
  532. }
  533. xlsxFile.SetSheetRow(fileName, fmt.Sprintf("A%d", k+2), &row)
  534. }
  535. //dir := g.Config().GetString("setting.export-path")
  536. //gfile.Mkdir(dir)
  537. //path = dir + "/" + fileName + gtime.Now().Format("Y-m-d_H-i-s") + ".xlsx"
  538. //// 根据指定路径保存文件
  539. //if err := xlsxFile.SaveAs(path); err != nil {
  540. // g.Log().Error(ctx, err)
  541. //}
  542. buf, err := xlsxFile.WriteToBuffer()
  543. if err != nil {
  544. return "", err
  545. }
  546. path = base64.StdEncoding.EncodeToString(buf.Bytes())
  547. return path, err
  548. }