commonBIzService.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package base
  2. import (
  3. "fmt"
  4. "github.com/samber/lo"
  5. "go_server/base/config"
  6. "go_server/base/core"
  7. "go_server/global"
  8. "go_server/utils"
  9. "gorm.io/gorm"
  10. "reflect"
  11. "strings"
  12. "sync"
  13. "time"
  14. )
  15. // 业务库公共服务
  16. type BizCommonService struct {
  17. DbAlias string
  18. }
  19. var lock sync.RWMutex
  20. func (s *BizCommonService) mustAlias() string {
  21. lock.RLock()
  22. defer lock.RUnlock()
  23. if s.DbAlias == "" {
  24. return global.DefaultAlias()
  25. }
  26. return s.DbAlias
  27. }
  28. func (s *BizCommonService) SetDbAlias(alias string) {
  29. lock.RLock()
  30. defer lock.RUnlock()
  31. s.DbAlias = alias
  32. }
  33. func (s *BizCommonService) DB() *gorm.DB {
  34. db, _ := global.BizDBByAlias(s.mustAlias())
  35. return db
  36. }
  37. func (s *BizCommonService) GetColumnComment(dbAlias string, tableName string) (data []Column, err error) {
  38. var entities []Column
  39. sql := `
  40. SELECT
  41. c.COLUMN_NAME column_name,
  42. c.DATA_TYPE data_type,
  43. CASE c.DATA_TYPE
  44. WHEN 'longtext' THEN c.CHARACTER_MAXIMUM_LENGTH
  45. WHEN 'varchar' THEN c.CHARACTER_MAXIMUM_LENGTH
  46. WHEN 'double' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
  47. WHEN 'decimal' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE)
  48. WHEN 'int' THEN c.NUMERIC_PRECISION
  49. WHEN 'bigint' THEN c.NUMERIC_PRECISION
  50. ELSE ''
  51. END AS data_type_long,
  52. c.COLUMN_COMMENT column_comment,
  53. CASE WHEN kcu.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END AS primary_key,
  54. c.ORDINAL_POSITION
  55. FROM
  56. INFORMATION_SCHEMA.COLUMNS c
  57. LEFT JOIN
  58. INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
  59. ON
  60. c.TABLE_SCHEMA = kcu.TABLE_SCHEMA
  61. AND c.TABLE_NAME = kcu.TABLE_NAME
  62. AND c.COLUMN_NAME = kcu.COLUMN_NAME
  63. AND kcu.CONSTRAINT_NAME = 'PRIMARY'
  64. WHERE
  65. c.TABLE_NAME = ?
  66. AND c.TABLE_SCHEMA = ?
  67. ORDER BY
  68. c.ORDINAL_POSITION;`
  69. db, err := global.BizDBByAlias(s.mustAlias())
  70. if err != nil {
  71. return entities, err
  72. }
  73. core.Log.Infof("dbName:%s tableName:%s", db.Migrator().CurrentDatabase(), tableName)
  74. err = db.Raw(sql, tableName, db.Migrator().CurrentDatabase()).Scan(&entities).Error
  75. return entities, err
  76. }
  77. // 反射获得结构体字段与备注信息 获取json gorm.comment
  78. type ClmInfo struct {
  79. Field string `json:"field"`
  80. Json string `json:"json"`
  81. Comment string `json:"comment"`
  82. }
  83. func (s *BizCommonService) GetColumnCommentFromStruct(anyStruct any) []ClmInfo {
  84. t := reflect.TypeOf(anyStruct)
  85. var fieldInfoList []ClmInfo
  86. for i := 0; i < t.NumField(); i++ {
  87. field := t.Field(i)
  88. // 处理嵌套结构体
  89. //if field.Anonymous && field.Type.Kind() == reflect.Struct {
  90. // // 递归处理嵌套结构体的字段
  91. // nestedFields := s.GetColumnCommentFromStruct(reflect.New(field.Type).Elem().Interface())
  92. // fieldInfoList = append(fieldInfoList, nestedFields...)
  93. // continue
  94. //}
  95. // 处理嵌套结构体(包括指针类型)
  96. if field.Anonymous {
  97. fieldType := field.Type
  98. // 如果是指针类型,获取其指向的类型
  99. if fieldType.Kind() == reflect.Ptr {
  100. fieldType = fieldType.Elem()
  101. }
  102. // 如果是结构体类型,递归处理
  103. if fieldType.Kind() == reflect.Struct {
  104. // 创建该类型的零值实例进行递归
  105. nestedFields := s.GetColumnCommentFromStruct(reflect.New(fieldType).Elem().Interface())
  106. fieldInfoList = append(fieldInfoList, nestedFields...)
  107. continue
  108. }
  109. }
  110. // 获取json标签值
  111. jsonTag := field.Tag.Get("json")
  112. // 获取gorm标签中的comment值
  113. gormTag := field.Tag.Get("gorm")
  114. comment := s.extractCommentFromGormTag(gormTag)
  115. // 添加到结果列表
  116. fieldInfoList = append(fieldInfoList, ClmInfo{
  117. Field: field.Name,
  118. Json: jsonTag,
  119. Comment: comment,
  120. })
  121. }
  122. return fieldInfoList
  123. }
  124. func (s *BizCommonService) extractCommentFromGormTag(gormTag string) string {
  125. pairs := strings.Split(gormTag, ";")
  126. for _, pair := range pairs {
  127. if strings.HasPrefix(pair, "comment:") {
  128. return strings.TrimPrefix(pair, "comment:")
  129. }
  130. }
  131. return ""
  132. }
  133. // 通用CSV导出方法
  134. // 表名 传入需要导出字段名 表字段信息
  135. func ExportCsv[T any](db *gorm.DB, fields []string, colInfo []ClmInfo) (string, error) {
  136. core.Log.Infof("申请导出字段:%+v", fields)
  137. allRecords, err := GetMore[T](db)
  138. if err != nil {
  139. return "", err
  140. }
  141. core.Log.Infof("导出数据总量:%d", len(allRecords))
  142. if len(allRecords) == 0 {
  143. return "", nil
  144. }
  145. var csvHeard []string
  146. var csvCols []string
  147. for _, cls := range colInfo {
  148. if lo.Contains(fields, cls.Field) {
  149. csvHeard = append(csvHeard, cls.Comment)
  150. csvCols = append(csvCols, cls.Field)
  151. }
  152. }
  153. core.Log.Infof("导出表头:%+v", csvHeard)
  154. core.Log.Infof("可导出csvCols字段:%+v", csvCols)
  155. var csvData [][]string
  156. for _, item := range allRecords {
  157. var row []string
  158. val := reflect.ValueOf(item)
  159. if val.Kind() == reflect.Ptr {
  160. val = val.Elem()
  161. }
  162. for _, fieldName := range csvCols {
  163. fieldVal := val.FieldByName(fieldName)
  164. if !fieldVal.IsValid() {
  165. // 如果直接字段找不到,尝试从嵌套结构体查找
  166. for i := 0; i < val.NumField(); i++ {
  167. field := val.Type().Field(i)
  168. if field.Anonymous {
  169. nestedVal := val.Field(i)
  170. // 处理嵌套结构体指针
  171. if nestedVal.Kind() == reflect.Ptr {
  172. if nestedVal.IsNil() {
  173. continue
  174. }
  175. nestedVal = nestedVal.Elem()
  176. }
  177. if nestedVal.IsValid() {
  178. nestedField := nestedVal.FieldByName(fieldName)
  179. if nestedField.IsValid() {
  180. fieldVal = nestedField
  181. break
  182. }
  183. }
  184. }
  185. }
  186. }
  187. var strVal string
  188. if fieldVal.IsValid() {
  189. strVal = fmt.Sprintf("%v", fieldVal.Interface())
  190. }
  191. row = append(row, strVal)
  192. }
  193. csvData = append(csvData, row)
  194. }
  195. filename := fmt.Sprintf("export_%s.csv", time.Now().Format("0102150405"))
  196. viewPath := utils.ToPath(config.EnvConf().File.Path, config.EnvConf().File.ProxyPath, filename)
  197. storePath := utils.ToPath(config.EnvConf().File.StorePath, filename)
  198. _, err = config.ExportCsv(csvHeard, csvData, storePath)
  199. if err != nil {
  200. return "", err
  201. }
  202. return viewPath, nil
  203. }