sys_export_template.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. package system
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "mime/multipart"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/flipped-aurora/gin-vue-admin/server/global"
  12. "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
  13. "github.com/flipped-aurora/gin-vue-admin/server/model/system"
  14. systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
  15. "github.com/flipped-aurora/gin-vue-admin/server/utils"
  16. "github.com/xuri/excelize/v2"
  17. "gorm.io/gorm"
  18. )
  19. type SysExportTemplateService struct {
  20. }
  21. var SysExportTemplateServiceApp = new(SysExportTemplateService)
  22. // CreateSysExportTemplate 创建导出模板记录
  23. // Author [piexlmax](https://github.com/piexlmax)
  24. func (sysExportTemplateService *SysExportTemplateService) CreateSysExportTemplate(sysExportTemplate *system.SysExportTemplate) (err error) {
  25. err = global.GVA_DB.Create(sysExportTemplate).Error
  26. return err
  27. }
  28. // DeleteSysExportTemplate 删除导出模板记录
  29. // Author [piexlmax](https://github.com/piexlmax)
  30. func (sysExportTemplateService *SysExportTemplateService) DeleteSysExportTemplate(sysExportTemplate system.SysExportTemplate) (err error) {
  31. err = global.GVA_DB.Delete(&sysExportTemplate).Error
  32. return err
  33. }
  34. // DeleteSysExportTemplateByIds 批量删除导出模板记录
  35. // Author [piexlmax](https://github.com/piexlmax)
  36. func (sysExportTemplateService *SysExportTemplateService) DeleteSysExportTemplateByIds(ids request.IdsReq) (err error) {
  37. err = global.GVA_DB.Delete(&[]system.SysExportTemplate{}, "id in ?", ids.Ids).Error
  38. return err
  39. }
  40. // UpdateSysExportTemplate 更新导出模板记录
  41. // Author [piexlmax](https://github.com/piexlmax)
  42. func (sysExportTemplateService *SysExportTemplateService) UpdateSysExportTemplate(sysExportTemplate system.SysExportTemplate) (err error) {
  43. return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
  44. conditions := sysExportTemplate.Conditions
  45. e := tx.Delete(&[]system.Condition{}, "template_id = ?", sysExportTemplate.TemplateID).Error
  46. if e != nil {
  47. return e
  48. }
  49. sysExportTemplate.Conditions = nil
  50. joins := sysExportTemplate.JoinTemplate
  51. e = tx.Delete(&[]system.JoinTemplate{}, "template_id = ?", sysExportTemplate.TemplateID).Error
  52. if e != nil {
  53. return e
  54. }
  55. sysExportTemplate.JoinTemplate = nil
  56. e = tx.Updates(&sysExportTemplate).Error
  57. if e != nil {
  58. return e
  59. }
  60. if len(conditions) > 0 {
  61. for i := range conditions {
  62. conditions[i].ID = 0
  63. }
  64. e = tx.Create(&conditions).Error
  65. }
  66. if len(joins) > 0 {
  67. for i := range joins {
  68. joins[i].ID = 0
  69. }
  70. e = tx.Create(&joins).Error
  71. }
  72. return e
  73. })
  74. }
  75. // GetSysExportTemplate 根据id获取导出模板记录
  76. // Author [piexlmax](https://github.com/piexlmax)
  77. func (sysExportTemplateService *SysExportTemplateService) GetSysExportTemplate(id uint) (sysExportTemplate system.SysExportTemplate, err error) {
  78. err = global.GVA_DB.Where("id = ?", id).Preload("JoinTemplate").Preload("Conditions").First(&sysExportTemplate).Error
  79. return
  80. }
  81. // GetSysExportTemplateInfoList 分页获取导出模板记录
  82. // Author [piexlmax](https://github.com/piexlmax)
  83. func (sysExportTemplateService *SysExportTemplateService) GetSysExportTemplateInfoList(info systemReq.SysExportTemplateSearch) (list []system.SysExportTemplate, total int64, err error) {
  84. limit := info.PageSize
  85. offset := info.PageSize * (info.Page - 1)
  86. // 创建db
  87. db := global.GVA_DB.Model(&system.SysExportTemplate{})
  88. var sysExportTemplates []system.SysExportTemplate
  89. // 如果有条件搜索 下方会自动创建搜索语句
  90. if info.StartCreatedAt != nil && info.EndCreatedAt != nil {
  91. db = db.Where("created_at BETWEEN ? AND ?", info.StartCreatedAt, info.EndCreatedAt)
  92. }
  93. if info.Name != "" {
  94. db = db.Where("name LIKE ?", "%"+info.Name+"%")
  95. }
  96. if info.TableName != "" {
  97. db = db.Where("table_name = ?", info.TableName)
  98. }
  99. if info.TemplateID != "" {
  100. db = db.Where("template_id = ?", info.TemplateID)
  101. }
  102. err = db.Count(&total).Error
  103. if err != nil {
  104. return
  105. }
  106. if limit != 0 {
  107. db = db.Limit(limit).Offset(offset)
  108. }
  109. err = db.Find(&sysExportTemplates).Error
  110. return sysExportTemplates, total, err
  111. }
  112. // ExportExcel 导出Excel
  113. // Author [piexlmax](https://github.com/piexlmax)
  114. func (sysExportTemplateService *SysExportTemplateService) ExportExcel(templateID string, values url.Values) (file *bytes.Buffer, name string, err error) {
  115. var template system.SysExportTemplate
  116. err = global.GVA_DB.Preload("Conditions").Preload("JoinTemplate").First(&template, "template_id = ?", templateID).Error
  117. if err != nil {
  118. return nil, "", err
  119. }
  120. f := excelize.NewFile()
  121. defer func() {
  122. if err := f.Close(); err != nil {
  123. fmt.Println(err)
  124. }
  125. }()
  126. // Create a new sheet.
  127. index, err := f.NewSheet("Sheet1")
  128. if err != nil {
  129. fmt.Println(err)
  130. return
  131. }
  132. var templateInfoMap = make(map[string]string)
  133. columns, err := utils.GetJSONKeys(template.TemplateInfo)
  134. if err != nil {
  135. return nil, "", err
  136. }
  137. err = json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap)
  138. if err != nil {
  139. return nil, "", err
  140. }
  141. var tableTitle []string
  142. var selectKeyFmt []string
  143. for _, key := range columns {
  144. selectKeyFmt = append(selectKeyFmt, key)
  145. tableTitle = append(tableTitle, templateInfoMap[key])
  146. }
  147. selects := strings.Join(selectKeyFmt, ", ")
  148. var tableMap []map[string]interface{}
  149. db := global.GVA_DB
  150. if template.DBName != "" {
  151. db = global.MustGetGlobalDBByDBName(template.DBName)
  152. }
  153. if len(template.JoinTemplate) > 0 {
  154. for _, join := range template.JoinTemplate {
  155. db = db.Joins(join.JOINS + " " + join.Table + " ON " + join.ON)
  156. }
  157. }
  158. db = db.Select(selects).Table(template.TableName)
  159. if len(template.Conditions) > 0 {
  160. for _, condition := range template.Conditions {
  161. sql := fmt.Sprintf("%s %s ?", condition.Column, condition.Operator)
  162. value := values.Get(condition.From)
  163. if value != "" {
  164. if condition.Operator == "LIKE" {
  165. value = "%" + value + "%"
  166. }
  167. db = db.Where(sql, value)
  168. }
  169. }
  170. }
  171. // 通过参数传入limit
  172. limit := values.Get("limit")
  173. if limit != "" {
  174. l, e := strconv.Atoi(limit)
  175. if e == nil {
  176. db = db.Limit(l)
  177. }
  178. }
  179. // 模板的默认limit
  180. if limit == "" && template.Limit != nil && *template.Limit != 0 {
  181. db = db.Limit(*template.Limit)
  182. }
  183. // 通过参数传入offset
  184. offset := values.Get("offset")
  185. if offset != "" {
  186. o, e := strconv.Atoi(offset)
  187. if e == nil {
  188. db = db.Offset(o)
  189. }
  190. }
  191. // 获取当前表的所有字段
  192. table := template.TableName
  193. orderColumns, err := db.Migrator().ColumnTypes(table)
  194. if err != nil {
  195. return nil, "", err
  196. }
  197. // 创建一个 map 来存储字段名
  198. fields := make(map[string]bool)
  199. for _, column := range orderColumns {
  200. fields[column.Name()] = true
  201. }
  202. // 通过参数传入order
  203. order := values.Get("order")
  204. if order == "" && template.Order != "" {
  205. // 如果没有order入参,这里会使用模板的默认排序
  206. order = template.Order
  207. }
  208. if order != "" {
  209. checkOrderArr := strings.Split(order, " ")
  210. orderStr := ""
  211. // 检查请求的排序字段是否在字段列表中
  212. if _, ok := fields[checkOrderArr[0]]; !ok {
  213. return nil, "", fmt.Errorf("order by %s is not in the fields", order)
  214. }
  215. orderStr = checkOrderArr[0]
  216. if len(checkOrderArr) > 1 {
  217. if checkOrderArr[1] != "asc" && checkOrderArr[1] != "desc" {
  218. return nil, "", fmt.Errorf("order by %s is not secure", order)
  219. }
  220. orderStr = orderStr + " " + checkOrderArr[1]
  221. }
  222. db = db.Order(orderStr)
  223. }
  224. err = db.Debug().Find(&tableMap).Error
  225. if err != nil {
  226. return nil, "", err
  227. }
  228. var rows [][]string
  229. rows = append(rows, tableTitle)
  230. for _, exTable := range tableMap {
  231. var row []string
  232. for _, column := range columns {
  233. column = strings.ReplaceAll(column, "\"", "")
  234. column = strings.ReplaceAll(column, "`", "")
  235. if len(template.JoinTemplate) > 0 {
  236. columnAs := strings.Split(column, " as ")
  237. if len(columnAs) > 1 {
  238. column = strings.TrimSpace(strings.Split(column, " as ")[1])
  239. } else {
  240. columnArr := strings.Split(column, ".")
  241. if len(columnArr) > 1 {
  242. column = strings.Split(column, ".")[1]
  243. }
  244. }
  245. }
  246. // 需要对时间类型特殊处理
  247. if t, ok := exTable[column].(time.Time); ok {
  248. row = append(row, t.Format("2006-01-02 15:04:05"))
  249. } else {
  250. row = append(row, fmt.Sprintf("%v", exTable[column]))
  251. }
  252. }
  253. rows = append(rows, row)
  254. }
  255. for i, row := range rows {
  256. for j, colCell := range row {
  257. sErr := f.SetCellValue("Sheet1", fmt.Sprintf("%s%d", getColumnName(j+1), i+1), colCell)
  258. if sErr != nil {
  259. return nil, "", sErr
  260. }
  261. }
  262. }
  263. f.SetActiveSheet(index)
  264. file, err = f.WriteToBuffer()
  265. if err != nil {
  266. return nil, "", err
  267. }
  268. return file, template.Name, nil
  269. }
  270. // ExportTemplate 导出Excel模板
  271. // Author [piexlmax](https://github.com/piexlmax)
  272. func (sysExportTemplateService *SysExportTemplateService) ExportTemplate(templateID string) (file *bytes.Buffer, name string, err error) {
  273. var template system.SysExportTemplate
  274. err = global.GVA_DB.First(&template, "template_id = ?", templateID).Error
  275. if err != nil {
  276. return nil, "", err
  277. }
  278. f := excelize.NewFile()
  279. defer func() {
  280. if err := f.Close(); err != nil {
  281. fmt.Println(err)
  282. }
  283. }()
  284. // Create a new sheet.
  285. index, err := f.NewSheet("Sheet1")
  286. if err != nil {
  287. fmt.Println(err)
  288. return
  289. }
  290. var templateInfoMap = make(map[string]string)
  291. columns, err := utils.GetJSONKeys(template.TemplateInfo)
  292. err = json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap)
  293. if err != nil {
  294. return nil, "", err
  295. }
  296. var tableTitle []string
  297. for _, key := range columns {
  298. tableTitle = append(tableTitle, templateInfoMap[key])
  299. }
  300. for i := range tableTitle {
  301. fErr := f.SetCellValue("Sheet1", fmt.Sprintf("%s%d", getColumnName(i+1), 1), tableTitle[i])
  302. if fErr != nil {
  303. return nil, "", fErr
  304. }
  305. }
  306. f.SetActiveSheet(index)
  307. file, err = f.WriteToBuffer()
  308. if err != nil {
  309. return nil, "", err
  310. }
  311. return file, template.Name, nil
  312. }
  313. // ImportExcel 导入Excel
  314. // Author [piexlmax](https://github.com/piexlmax)
  315. func (sysExportTemplateService *SysExportTemplateService) ImportExcel(templateID string, file *multipart.FileHeader) (err error) {
  316. var template system.SysExportTemplate
  317. err = global.GVA_DB.First(&template, "template_id = ?", templateID).Error
  318. if err != nil {
  319. return err
  320. }
  321. src, err := file.Open()
  322. if err != nil {
  323. return err
  324. }
  325. defer src.Close()
  326. f, err := excelize.OpenReader(src)
  327. if err != nil {
  328. return err
  329. }
  330. rows, err := f.GetRows("Sheet1")
  331. if err != nil {
  332. return err
  333. }
  334. var templateInfoMap = make(map[string]string)
  335. err = json.Unmarshal([]byte(template.TemplateInfo), &templateInfoMap)
  336. if err != nil {
  337. return err
  338. }
  339. var titleKeyMap = make(map[string]string)
  340. for key, title := range templateInfoMap {
  341. titleKeyMap[title] = key
  342. }
  343. db := global.GVA_DB
  344. if template.DBName != "" {
  345. db = global.MustGetGlobalDBByDBName(template.DBName)
  346. }
  347. return db.Transaction(func(tx *gorm.DB) error {
  348. excelTitle := rows[0]
  349. values := rows[1:]
  350. items := make([]map[string]interface{}, 0, len(values))
  351. for _, row := range values {
  352. var item = make(map[string]interface{})
  353. for ii, value := range row {
  354. key := titleKeyMap[excelTitle[ii]]
  355. item[key] = value
  356. }
  357. needCreated := tx.Migrator().HasColumn(template.TableName, "created_at")
  358. needUpdated := tx.Migrator().HasColumn(template.TableName, "updated_at")
  359. if item["created_at"] == nil && needCreated {
  360. item["created_at"] = time.Now()
  361. }
  362. if item["updated_at"] == nil && needUpdated {
  363. item["updated_at"] = time.Now()
  364. }
  365. items = append(items, item)
  366. }
  367. cErr := tx.Table(template.TableName).CreateInBatches(&items, 1000).Error
  368. return cErr
  369. })
  370. }
  371. func getColumnName(n int) string {
  372. columnName := ""
  373. for n > 0 {
  374. n--
  375. columnName = string(rune('A'+n%26)) + columnName
  376. n /= 26
  377. }
  378. return columnName
  379. }