@@ -213,6 +213,16 @@ func (sysExportTemplateService *SysExportTemplateService) ExportExcel(templateID
213213 sql = fmt .Sprintf ("%s %s (?)" , condition .Column , condition .Operator )
214214 }
215215
216+ if condition .Operator == "BETWEEN" {
217+ sql = fmt .Sprintf ("%s BETWEEN ? AND ?" , condition .Column )
218+ startValue := paramsValues .Get ("start" + condition .From )
219+ endValue := paramsValues .Get ("end" + condition .From )
220+ if startValue != "" && endValue != "" {
221+ db = db .Where (sql , startValue , endValue )
222+ }
223+ continue
224+ }
225+
216226 if value != "" {
217227 if condition .Operator == "LIKE" {
218228 value = "%" + value + "%"
@@ -317,14 +327,14 @@ func (sysExportTemplateService *SysExportTemplateService) ExportExcel(templateID
317327 for j , colCell := range row {
318328 cell := fmt .Sprintf ("%s%d" , getColumnName (j + 1 ), i + 1 )
319329
320- var sErr error
321- if v , err := strconv .ParseFloat (colCell , 64 ); err == nil {
322- sErr = f .SetCellValue ("Sheet1" , cell , v )
323- } else if v , err := strconv .ParseInt (colCell , 10 , 64 ); err == nil {
324- sErr = f .SetCellValue ("Sheet1" , cell , v )
325- } else {
326- sErr = f .SetCellValue ("Sheet1" , cell , colCell )
327- }
330+ var sErr error
331+ if v , err := strconv .ParseFloat (colCell , 64 ); err == nil {
332+ sErr = f .SetCellValue ("Sheet1" , cell , v )
333+ } else if v , err := strconv .ParseInt (colCell , 10 , 64 ); err == nil {
334+ sErr = f .SetCellValue ("Sheet1" , cell , v )
335+ } else {
336+ sErr = f .SetCellValue ("Sheet1" , cell , colCell )
337+ }
328338
329339 if sErr != nil {
330340 return nil , "" , sErr
@@ -340,6 +350,185 @@ func (sysExportTemplateService *SysExportTemplateService) ExportExcel(templateID
340350 return file , template .Name , nil
341351}
342352
353+ // PreviewSQL 预览最终生成的 SQL(不执行查询,仅返回 SQL 字符串)
354+ // Author [piexlmax](https://github.com/piexlmax) & [trae-ai]
355+ func (sysExportTemplateService * SysExportTemplateService ) PreviewSQL (templateID string , values url.Values ) (sqlPreview string , err error ) {
356+ // 解析 params(与导出逻辑保持一致)
357+ var params = values .Get ("params" )
358+ paramsValues , _ := url .ParseQuery (params )
359+
360+ // 加载模板
361+ var template system.SysExportTemplate
362+ err = global .GVA_DB .Preload ("Conditions" ).Preload ("JoinTemplate" ).First (& template , "template_id = ?" , templateID ).Error
363+ if err != nil {
364+ return "" , err
365+ }
366+
367+ // 解析模板列
368+ var templateInfoMap = make (map [string ]string )
369+ columns , err := utils .GetJSONKeys (template .TemplateInfo )
370+ if err != nil {
371+ return "" , err
372+ }
373+ err = json .Unmarshal ([]byte (template .TemplateInfo ), & templateInfoMap )
374+ if err != nil {
375+ return "" , err
376+ }
377+ var selectKeyFmt []string
378+ for _ , key := range columns {
379+ selectKeyFmt = append (selectKeyFmt , key )
380+ }
381+ selects := strings .Join (selectKeyFmt , ", " )
382+
383+ // 生成 FROM 与 JOIN 片段
384+ var sb strings.Builder
385+ sb .WriteString ("SELECT " )
386+ sb .WriteString (selects )
387+ sb .WriteString (" FROM " )
388+ sb .WriteString (template .TableName )
389+
390+ if len (template .JoinTemplate ) > 0 {
391+ for _ , join := range template .JoinTemplate {
392+ sb .WriteString (" " )
393+ sb .WriteString (join .JOINS )
394+ sb .WriteString (" " )
395+ sb .WriteString (join .Table )
396+ sb .WriteString (" ON " )
397+ sb .WriteString (join .ON )
398+ }
399+ }
400+
401+ // WHERE 条件
402+ var wheres []string
403+
404+ // 软删除过滤
405+ filterDeleted := false
406+ if paramsValues != nil {
407+ filterParam := paramsValues .Get ("filterDeleted" )
408+ if filterParam == "true" {
409+ filterDeleted = true
410+ }
411+ }
412+ if filterDeleted {
413+ wheres = append (wheres , fmt .Sprintf ("%s.deleted_at IS NULL" , template .TableName ))
414+ if len (template .JoinTemplate ) > 0 {
415+ for _ , join := range template .JoinTemplate {
416+ if sysExportTemplateService .hasDeletedAtColumn (join .Table ) {
417+ wheres = append (wheres , fmt .Sprintf ("%s.deleted_at IS NULL" , join .Table ))
418+ }
419+ }
420+ }
421+ }
422+
423+ // 模板条件(保留与 ExportExcel 同步的解析规则)
424+ if len (template .Conditions ) > 0 {
425+ for _ , condition := range template .Conditions {
426+ op := strings .ToUpper (strings .TrimSpace (condition .Operator ))
427+ col := strings .TrimSpace (condition .Column )
428+
429+ // 预览优先展示传入值,没有则展示占位符
430+ val := ""
431+ if paramsValues != nil {
432+ val = paramsValues .Get (condition .From )
433+ }
434+
435+ switch op {
436+ case "BETWEEN" :
437+ startValue := ""
438+ endValue := ""
439+ if paramsValues != nil {
440+ startValue = paramsValues .Get ("start" + condition .From )
441+ endValue = paramsValues .Get ("end" + condition .From )
442+ }
443+ if startValue != "" && endValue != "" {
444+ wheres = append (wheres , fmt .Sprintf ("%s BETWEEN '%s' AND '%s'" , col , startValue , endValue ))
445+ } else {
446+ wheres = append (wheres , fmt .Sprintf ("%s BETWEEN {start%s} AND {end%s}" , col , condition .From , condition .From ))
447+ }
448+ case "IN" , "NOT IN" :
449+ if val != "" {
450+ // 逗号分隔值做简单展示
451+ parts := strings .Split (val , "," )
452+ for i := range parts { parts [i ] = strings .TrimSpace (parts [i ]) }
453+ wheres = append (wheres , fmt .Sprintf ("%s %s ('%s')" , col , op , strings .Join (parts , "','" )))
454+ } else {
455+ wheres = append (wheres , fmt .Sprintf ("%s %s ({%s})" , col , op , condition .From ))
456+ }
457+ case "LIKE" :
458+ if val != "" {
459+ wheres = append (wheres , fmt .Sprintf ("%s LIKE '%%%s%%'" , col , val ))
460+ } else {
461+ wheres = append (wheres , fmt .Sprintf ("%s LIKE {%%%s%%}" , col , condition .From ))
462+ }
463+ default :
464+ if val != "" {
465+ wheres = append (wheres , fmt .Sprintf ("%s %s '%s'" , col , op , val ))
466+ } else {
467+ wheres = append (wheres , fmt .Sprintf ("%s %s {%s}" , col , op , condition .From ))
468+ }
469+ }
470+ }
471+ }
472+
473+ if len (wheres ) > 0 {
474+ sb .WriteString (" WHERE " )
475+ sb .WriteString (strings .Join (wheres , " AND " ))
476+ }
477+
478+ // 排序
479+ order := ""
480+ if paramsValues != nil {
481+ order = paramsValues .Get ("order" )
482+ }
483+ if order == "" && template .Order != "" {
484+ order = template .Order
485+ }
486+ if order != "" {
487+ sb .WriteString (" ORDER BY " )
488+ sb .WriteString (order )
489+ }
490+
491+ // limit/offset(如果传入或默认值为0,则不生成)
492+ limitStr := ""
493+ offsetStr := ""
494+ if paramsValues != nil {
495+ limitStr = paramsValues .Get ("limit" )
496+ offsetStr = paramsValues .Get ("offset" )
497+ }
498+
499+ // 处理模板默认limit(仅当非0时)
500+ if limitStr == "" && template .Limit != nil && * template .Limit != 0 {
501+ limitStr = strconv .Itoa (* template .Limit )
502+ }
503+
504+ // 解析为数值,用于判断是否生成
505+ limitInt := 0
506+ offsetInt := 0
507+ if limitStr != "" {
508+ if v , e := strconv .Atoi (limitStr ); e == nil { limitInt = v }
509+ }
510+ if offsetStr != "" {
511+ if v , e := strconv .Atoi (offsetStr ); e == nil { offsetInt = v }
512+ }
513+
514+ if limitInt > 0 {
515+ sb .WriteString (" LIMIT " )
516+ sb .WriteString (strconv .Itoa (limitInt ))
517+ if offsetInt > 0 {
518+ sb .WriteString (" OFFSET " )
519+ sb .WriteString (strconv .Itoa (offsetInt ))
520+ }
521+ } else {
522+ // 当limit未设置或为0时,仅当offset>0才生成OFFSET
523+ if offsetInt > 0 {
524+ sb .WriteString (" OFFSET " )
525+ sb .WriteString (strconv .Itoa (offsetInt ))
526+ }
527+ }
528+
529+ return sb .String (), nil
530+ }
531+
343532// ExportTemplate 导出Excel模板
344533// Author [piexlmax](https://github.com/piexlmax)
345534func (sysExportTemplateService * SysExportTemplateService ) ExportTemplate (templateID string ) (file * bytes.Buffer , name string , err error ) {
0 commit comments