package service import ( "context" "dashoo.cn/opms_libary/multipart" "encoding/base64" "fmt" "github.com/gogf/gf/encoding/gurl" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/guid" "github.com/xuri/excelize/v2" "io/ioutil" "log" "net/http" "os" "reflect" "dashoo.cn/opms_libary/myerrors" "dashoo.cn/opms_libary/request" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/util/gconv" "github.com/smallnest/rpcx/share" "dashoo.cn/common_definition/comm_def" "dashoo.cn/opms_libary/micro_srv" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/os/gtime" ) var ( // DingTalkSpaceId 钉钉 空间Id。 DingTalkSpaceId = "21077726250" // CommonUpdateFieldEx UpdateFieldEx 更新过滤字段 CommonUpdateFieldEx = []interface{}{"created_by", "created_name", "created_time"} UpdateFieldEx = []interface{}{"id", "created_by", "created_name", "created_time"} ) func Sequence(db gdb.DB, name string) (string, error) { v, err := db.GetValue("select `nextval`( ? );", name) if err != nil { return "", err } return v.String(), nil } func SequenceYearRest(db gdb.DB, name string) (int, error) { v, err := db.GetValue("select `next_year_reset_val`( ? );", name) if err != nil { return 0, err } return v.Int(), nil } // SetCreatedInfo 插入数据库时设置创建信息 func SetCreatedInfo(entry interface{}, id int, name string) { v := reflect.ValueOf(entry) t := reflect.TypeOf(entry) if t.Kind() == reflect.Map { data := entry.(map[string]interface{}) data["created_by"] = id data["created_name"] = name data["created_time"] = gtime.Now() return } if t.Kind() == reflect.Ptr { t = t.Elem() v = v.Elem() } if t.Kind() == reflect.Slice { } if t.Kind() != reflect.Struct { log.Println("Check type error not Struct") return } for i := 0; i < t.NumField(); i++ { fieldName := t.Field(i).Name if tag, ok := t.Field(i).Tag.Lookup("orm"); ok { switch tag { case "created_by": v.FieldByName(fieldName).Set(reflect.ValueOf(id)) case "created_name": v.FieldByName(fieldName).Set(reflect.ValueOf(name)) case "created_time": v.FieldByName(fieldName).Set(reflect.ValueOf(gtime.Now())) } } } } // SetUpdatedInfo 插入数据库时设置修改信息 func SetUpdatedInfo(entry interface{}, id int, name string) { v := reflect.ValueOf(entry) t := reflect.TypeOf(entry) if t.Kind() == reflect.Map { data := entry.(map[string]interface{}) data["updated_by"] = id data["updated_name"] = name data["updated_time"] = gtime.Now() return } if t.Kind() == reflect.Ptr { t = t.Elem() v = v.Elem() } if t.Kind() != reflect.Struct { log.Println("Check type error not Struct") return } for i := 0; i < t.NumField(); i++ { fieldName := t.Field(i).Name if tag, ok := t.Field(i).Tag.Lookup("orm"); ok { switch tag { case "updated_by": v.FieldByName(fieldName).Set(reflect.ValueOf(id)) case "updated_name": v.FieldByName(fieldName).Set(reflect.ValueOf(name)) case "updated_time": v.FieldByName(fieldName).Set(reflect.ValueOf(gtime.Now())) } } } } // Div 数字转字母 func Div(Num int) string { var ( Str string = "" k int temp []int //保存转化后每一位数据的值,然后通过索引的方式匹配A-Z ) //用来匹配的字符A-Z Slice := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"} if Num > 26 { //数据大于26需要进行拆分 for { k = Num % 26 //从个位开始拆分,如果求余为0,说明末尾为26,也就是Z,如果是转化为26进制数,则末尾是可以为0的,这里必须为A-Z中的一个 if k == 0 { temp = append(temp, 26) k = 26 } else { temp = append(temp, k) } Num = (Num - k) / 26 //减去Num最后一位数的值,因为已经记录在temp中 if Num <= 26 { //小于等于26直接进行匹配,不需要进行数据拆分 temp = append(temp, Num) break } } } else { return Slice[Num] } for _, value := range temp { Str = Slice[value] + Str //因为数据切分后存储顺序是反的,所以Str要放在后面 } return Str } type GetDictReq struct { DictType string `p:"dictType" v:"required#字典类型不能为空"` DefaultValue string `p:"defaultValue"` } type GetDictLabelByTypeAndValueReq struct { DictType string `p:"dictType"` //字典类型 DictValue string `p:"dictValue"` //字典标签 } func baseGetDictDataByType(ctx context.Context, typ string) ([]interface{}, error) { srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} err := srv.Call(ctx, "GetDictDataByType", GetDictReq{ DictType: typ, }, resp) if err != nil { return nil, fmt.Errorf("获取字典 %s %s", typ, err.Error()) } fmt.Println(resp.Data) data := resp.Data.(map[string]interface{})["Values"].([]interface{}) fmt.Println(data) return data, nil } func GetDictDataByType(ctx context.Context, typ string) (map[string]string, error) { data, err := baseGetDictDataByType(ctx, typ) if err != nil { return nil, err } res := map[string]string{} for _, i := range data { info := i.(map[string]interface{}) res[info["DictValue"].(string)] = info["DictLabel"].(string) } return res, nil } // Find获取一个切片并在其中查找元素。如果找到它,它将返回它的密钥,否则它将返回-1和一个错误的bool。 func FindItem(slice []string, val string) (int, bool) { for i, item := range slice { if item == val { return i, true } } return -1, false } // 有序 func GetDictDataTreeByType(ctx context.Context, typ string) (*gmap.ListMap, error) { data, err := baseGetDictDataByType(ctx, typ) if err != nil { return nil, err } res := gmap.NewListMap(true) for _, i := range data { info := i.(map[string]interface{}) res.Set(info["DictValue"], info["DictLabel"]) } return res, nil } // 根据字典类型和字典值获取字典明细名称 func GetDictLabelByTypeAndValue(ctx context.Context, dictType, value string) (string, error) { srv := micro_srv.InitMicroSrvClient("Dict", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} err := srv.Call(ctx, "GetDictLabelByTypeAndValue", GetDictLabelByTypeAndValueReq{ DictType: dictType, DictValue: value, }, resp) if err != nil { g.Log().Error(err) return value, nil } return gconv.String(resp.Data), nil } func StringSlicecontains(s []string, ele string) bool { for _, i := range s { if i == ele { return true } } return false } // CreateSystemMessage 创建系统消息 func CreateSystemMessage(msg g.MapStrStr) error { srv := micro_srv.InitMicroSrvClient("SystemMessage", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} tenant := g.Config().GetString("micro_srv.tenant") ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant}) err := srv.Call(ctx, "Create", msg, resp) if err != nil { g.Log().Error(err) return myerrors.MicroCallError("系统创建消息失败") } fmt.Println(resp.Data) return nil } type DeptIdReq struct { DeptId int `json:"dept_id,omitempty"` Include bool `json:"include,omitempty"` } // GetUsersByDept 根据部门获取用户 func GetUsersByDept(ctx context.Context, req *DeptIdReq) (map[string]int, error) { srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} err := srv.Call(ctx, "GetUserByDept", req, resp) if err != nil { return nil, myerrors.MicroCallError("获取部门下用户失败") } if resp.Data == nil { return nil, myerrors.TipsError("部门不存在") } fmt.Println(resp.Data) data := resp.Data.([]interface{}) fmt.Println(data) res := map[string]int{} for _, i := range data { info := i.(map[string]interface{}) res[info["NickName"].(string)] = gconv.Int(info["Id"]) } return res, nil } type SysUserSearchReq struct { KeyWords string `json:"keyWords"` DeptId int `json:"deptId"` //部门id DeptIds []int //所属部门id数据 Phone string `json:"phone"` Status string `json:"status"` Roles []string `json:"roles"` Posts []string `json:"posts"` Groups []string `json:"groups"` request.PageReq } // GetUsersByRoleCode 根据角色编码获取用户 func GetUsersByRoleCode(ctx context.Context, roleCode []string, pageSize ...int) (map[string]int, error) { srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} req := &SysUserSearchReq{Roles: roleCode, Status: "10"} if len(pageSize) > 0 { req.PageSize = pageSize[0] } err := srv.Call(ctx, "GetList", req, resp) if err != nil { return nil, myerrors.MicroCallError("根据角色编码获取用户失败") } if resp.Data == nil { return nil, myerrors.TipsError("用户不存在") } data := resp.Data.(map[string]interface{}) list := data["list"].([]interface{}) res := map[string]int{} for _, i := range list { info := i.(map[string]interface{}) res[info["NickName"].(string)] = gconv.Int(info["Id"]) } return res, nil } // GetUserListByRoleCode 根据角色编码获取用户列表 func GetUserListByRoleCode(ctx context.Context, roleCode []string, pageSize ...int) ([]map[string]interface{}, error) { srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} req := &SysUserSearchReq{Roles: roleCode, Status: "10"} if len(pageSize) > 0 { req.PageSize = pageSize[0] } err := srv.Call(ctx, "GetList", req, resp) if err != nil { return nil, myerrors.MicroCallError("根据角色编码获取用户失败") } if resp.Data == nil { return nil, myerrors.TipsError("用户不存在") } data := resp.Data.(map[string]interface{}) list := data["list"].([]interface{}) var res []map[string]interface{} for _, i := range list { info := i.(map[string]interface{}) data := map[string]interface{}{ "Id": gconv.Int(info["Id"]), "NickName": info["NickName"].(string), } res = append(res, data) } return res, nil } // 获取用户权限 func GetUserDataScope(userId int) (g.Map, error) { srv := micro_srv.InitMicroSrvClient("User", "micro_srv.auth") defer srv.Close() req := &comm_def.IdReq{Id: int64(userId)} resp := &comm_def.CommonMsg{} tenant := g.Config().GetString("micro_srv.tenant") ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant}) err := srv.Call(ctx, "GetDataScope", req, resp) if err != nil || resp.Data == nil { g.Log().Error(err) return nil, myerrors.MicroCallError("获取用户权限失败") } return resp.Data.(g.Map), nil } // 跟进发送邮件消息 func GSendMail(msg g.MapStrStr) error { srv := micro_srv.InitMicroSrvClient("Message", "micro_srv.auth") defer srv.Close() resp := &comm_def.CommonMsg{} tenant := g.Config().GetString("micro_srv.tenant") ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant}) err := srv.Call(ctx, "SendMail", msg, resp) if err != nil { g.Log().Error(err) return myerrors.MicroCallError("项目未跟进发送邮件提醒失败") } fmt.Println(resp.Data) return nil } func ColumnInt(m *gdb.Model, name string) ([]int, error) { v, err := m.Fields(name).Array() if err != nil { return nil, err } res := []int{} for _, i := range v { res = append(res, i.Int()) } return res, nil } func ColumnString(m *gdb.Model, name string) ([]string, error) { v, err := m.Fields(name).Array() if err != nil { return nil, err } res := []string{} for _, i := range v { res = append(res, i.String()) } return res, nil } func StringsContains(s []string, ele string) bool { for _, i := range s { if i == ele { return true } } return false } func UserIdByRoles(db gdb.DB, roles ...string) ([]int, error) { roleId, err := ColumnInt(db.Table("sys_role").Where("role_key in (?)", roles), "id") if err != nil { return nil, err } return ColumnInt(db.Table("sys_user_role").Where("role_id in (?)", roleId), "user_id") } func UserDingtalkUid(db gdb.DB, id int) (string, error) { v, err := db.Table("sys_user").Where("id = ?", id).Fields("dingtalk_uid").Value() if err != nil { return "", err } uid := v.String() if uid == "" { return "", fmt.Errorf("没有找到 %d 的钉钉用户id", id) } return uid, nil } func SliceIntDeduplication(elems []int) []int { emap := map[int]struct{}{} for _, i := range elems { emap[i] = struct{}{} } ret := []int{} for i := range emap { ret = append(ret, i) } return ret } // DownloadTempFile 下载临时文件 func DownloadTempFile(url string) (*multipart.FileHeader, error) { r, err := http.Get(url) if err != nil { g.Log().Error(err) return nil, err } if r.StatusCode != http.StatusOK { return nil, fmt.Errorf("DownloadFile from %s StatusCode %d", url, r.StatusCode) } defer r.Body.Close() bytes, err := ioutil.ReadAll(r.Body) if err != nil { g.Log().Error(err) return nil, err } names := gstr.Split(r.Header.Get("Content-Disposition"), "filename=") fileName := guid.S() if len(names) > 1 { fileName, _ = gurl.Decode(names[1]) fileName = gstr.TrimStr(fileName, `"`) } file, err := os.CreateTemp("", fileName) if err != nil { g.Log().Error(err) } file.Write(bytes) fmt.Println(file.Name()) fileData := new(multipart.FileHeader) fileData.FileName = fileName fileData.FileSize = gconv.Int64(r.Header.Get("Content-Length")) fileData.File = file return fileData, nil } // getExcelHeader 获取Excel表头 func getExcelHeader(exportStruct interface{}, tag string) ([]string, g.MapStrStr) { var headerList []string headerMap := g.MapStrStr{} reqType := reflect.TypeOf(exportStruct) if reqType.Kind() == reflect.Ptr { reqType = reqType.Elem() } for i := 0; i < reqType.NumField(); i++ { fieldName, ok := reqType.Field(i).Tag.Lookup("json") if !ok { fieldName = reqType.Field(i).Name } if tag, ok := reqType.Field(i).Tag.Lookup(tag); ok { headerList = append(headerList, tag) headerMap[tag] = fieldName } } return headerList, headerMap } // CommonExportExcel 公共单表导出excel func CommonExportExcel(ctx context.Context, fileName string, exportStruct interface{}, dataList []map[string]interface{}, handleFunc ...func(map[string]interface{}, string) interface{}) (path string, err error) { headerList, headerMap := getExcelHeader(exportStruct, "export") // 转换数据 xlsxFile := excelize.NewFile() defer xlsxFile.Close() // 插入表头 if fileName == "" { fileName = "Sheet1" } colStyle, err := xlsxFile.NewStyle(&excelize.Style{ Alignment: &excelize.Alignment{ Horizontal: "center", Vertical: "center", WrapText: true, }, Font: &excelize.Font{ Size: 11, Family: "宋体", }, }) headerStyle, err := xlsxFile.NewStyle(&excelize.Style{ Alignment: &excelize.Alignment{ Horizontal: "center", }, Fill: excelize.Fill{ Type: "pattern", Color: []string{"#a6a6a6"}, Pattern: 1, }, Border: []excelize.Border{ {Type: "left", Color: "#000000", Style: 1}, {Type: "top", Color: "#000000", Style: 1}, {Type: "bottom", Color: "#000000", Style: 1}, {Type: "right", Color: "#000000", Style: 1}, }, }) lastColName, err := excelize.ColumnNumberToName(len(headerList)) xlsxFile.SetColStyle("Sheet1", "A:"+lastColName, colStyle) xlsxFile.SetCellStyle("Sheet1", "A1", lastColName+"1", headerStyle) xlsxFile.SetColWidth("Sheet1", "A", lastColName, 20) xlsxFile.SetSheetName("Sheet1", fileName) xlsxFile.SetSheetRow(fileName, "A1", &headerList) if err != nil { return "", err } for k, item := range dataList { var row []interface{} for _, h := range headerList { val := item[headerMap[h]] if len(handleFunc) > 0 { val = handleFunc[0](item, headerMap[h]) } row = append(row, val) } xlsxFile.SetSheetRow(fileName, fmt.Sprintf("A%d", k+2), &row) } //dir := g.Config().GetString("setting.export-path") //gfile.Mkdir(dir) //path = dir + "/" + fileName + gtime.Now().Format("Y-m-d_H-i-s") + ".xlsx" //// 根据指定路径保存文件 //if err := xlsxFile.SaveAs(path); err != nil { // g.Log().Error(ctx, err) //} buf, err := xlsxFile.WriteToBuffer() if err != nil { return "", err } path = base64.StdEncoding.EncodeToString(buf.Bytes()) return path, err }