This commit is contained in:
Max 2022-01-18 10:00:38 +08:00
parent 5da0b00b72
commit 633fe903fe
5 changed files with 104 additions and 19 deletions

View file

@ -11,6 +11,7 @@ import (
"github.com/yaoapp/xiang/chart" "github.com/yaoapp/xiang/chart"
"github.com/yaoapp/xiang/config" "github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/flow" "github.com/yaoapp/xiang/flow"
"github.com/yaoapp/xiang/importer"
"github.com/yaoapp/xiang/model" "github.com/yaoapp/xiang/model"
"github.com/yaoapp/xiang/page" "github.com/yaoapp/xiang/page"
"github.com/yaoapp/xiang/plugin" "github.com/yaoapp/xiang/plugin"
@ -30,13 +31,15 @@ func Load(cfg config.Config) {
LoadEngine(cfg.Path) LoadEngine(cfg.Path)
query.Load(cfg) // 加载数据分析引擎 query.Load(cfg) // 加载数据分析引擎
share.Load(cfg) // 加载共享库 lib share.Load(cfg) // 加载共享库 lib
model.Load(cfg) // 加载数据模型 model model.Load(cfg) // 加载数据模型 model
flow.Load(cfg) // 加载业务逻辑 Flow flow.Load(cfg) // 加载业务逻辑 Flow
plugin.Load(cfg) // 加载业务插件 plugin plugin.Load(cfg) // 加载业务插件 plugin
table.Load(cfg) // 加载数据表格 table table.Load(cfg) // 加载数据表格 table
chart.Load(cfg) // 加载分析图表 chart chart.Load(cfg) // 加载分析图表 chart
page.Load(cfg) // 加载页面 page page.Load(cfg) // 加载页面 page
importer.Load(cfg) // 加载数据导入 imports
workflow.Load(cfg) // 加载工作流 workflow workflow.Load(cfg) // 加载工作流 workflow
api.Load(cfg) // 加载业务接口 API api.Load(cfg) // 加载业务接口 API

View file

@ -13,7 +13,9 @@ import (
"github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/exception"
"github.com/yaoapp/xiang/config" "github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/importer/from" "github.com/yaoapp/xiang/importer/from"
"github.com/yaoapp/xiang/importer/xlsx"
"github.com/yaoapp/xiang/share" "github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xfs"
"github.com/yaoapp/xiang/xlog" "github.com/yaoapp/xiang/xlog"
) )
@ -51,6 +53,21 @@ func Select(name string) *Importer {
return im return im
} }
// Open 打开导入内容源
func Open(name string) from.Source {
ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(name), "."))
switch ext {
case "xlsx":
fullpath := name
if !strings.HasPrefix(fullpath, "/") {
fullpath = filepath.Join(xfs.Stor.Root, name)
}
return xlsx.Open(fullpath)
}
exception.New("暂不支持: %s 文件导入", 400, ext).Throw()
return nil
}
// AutoMapping 根据文件信息获取字段映射表 // AutoMapping 根据文件信息获取字段映射表
func (imp *Importer) AutoMapping(src from.Source) *Mapping { func (imp *Importer) AutoMapping(src from.Source) *Mapping {
sourceColumns := getSourceColumns(src) sourceColumns := getSourceColumns(src)

View file

@ -1,6 +1,10 @@
package importer package importer
import "github.com/yaoapp/gou" import (
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
)
func init() { func init() {
// 注册处理器 // 注册处理器
@ -15,13 +19,30 @@ func init() {
// ProcessRun xiang.import.Run // ProcessRun xiang.import.Run
// 导入数据 // 导入数据
func ProcessRun(process *gou.Process) interface{} { func ProcessRun(process *gou.Process) interface{} {
return nil process.ValidateArgNums(3)
name := process.ArgsString(0)
imp := Select(name)
filename := process.ArgsString(1)
src := Open(filename)
mapping := anyToMapping(process.Args[2])
return imp.Run(src, mapping)
} }
// ProcessData xiang.import.Data // ProcessData xiang.import.Data
// 数据预览 // 数据预览
func ProcessData(process *gou.Process) interface{} { func ProcessData(process *gou.Process) interface{} {
return nil process.ValidateArgNums(5)
name := process.ArgsString(0)
imp := Select(name)
filename := process.ArgsString(1)
src := Open(filename)
page := process.ArgsInt(2)
size := process.ArgsInt(3)
mapping := anyToMapping(process.Args[4])
return imp.DataPreview(src, page, size, mapping)
} }
// ProcessDataSetting xiang.import.DataSetting // ProcessDataSetting xiang.import.DataSetting
@ -33,7 +54,13 @@ func ProcessDataSetting(process *gou.Process) interface{} {
// ProcessMapping xiang.import.Mapping // ProcessMapping xiang.import.Mapping
// 字段映射预览 // 字段映射预览
func ProcessMapping(process *gou.Process) interface{} { func ProcessMapping(process *gou.Process) interface{} {
return nil process.ValidateArgNums(2)
name := process.ArgsString(0)
imp := Select(name)
filename := process.ArgsString(1)
src := Open(filename)
return imp.MappingPreview(src)
} }
// ProcessMappingSetting xiang.import.MappingSetting // ProcessMappingSetting xiang.import.MappingSetting
@ -47,3 +74,19 @@ func ProcessMappingSetting(process *gou.Process) interface{} {
func ProcessRules(process *gou.Process) interface{} { func ProcessRules(process *gou.Process) interface{} {
return nil return nil
} }
// 转换为映射表
func anyToMapping(v interface{}) *Mapping {
var mapping Mapping
bytes, err := jsoniter.Marshal(v)
if err != nil {
exception.New("字段映射表数据格式不正确", 400).Throw()
}
err = jsoniter.Unmarshal(bytes, &mapping)
if err != nil {
exception.New("字段映射表数据格式不正确", 400).Throw()
}
return &mapping
}

View file

@ -1,16 +1,20 @@
package importer package importer
import ( import (
"path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/yaoapp/gou" "github.com/yaoapp/gou"
"github.com/yaoapp/xiang/config"
) )
func TestProcessMapping(t *testing.T) { func TestProcessMapping(t *testing.T) {
args := []interface{}{"order"} simple := filepath.Join(config.Conf.Root, "imports", "assets", "simple.xlsx")
args := []interface{}{"order", simple}
response := gou.NewProcess("xiang.import.Mapping", args...).Run() response := gou.NewProcess("xiang.import.Mapping", args...).Run()
assert.Nil(t, response) _, ok := response.(*Mapping)
assert.True(t, ok)
} }
func TestProcessMappingSetting(t *testing.T) { func TestProcessMappingSetting(t *testing.T) {
@ -20,9 +24,12 @@ func TestProcessMappingSetting(t *testing.T) {
} }
func TestProcessData(t *testing.T) { func TestProcessData(t *testing.T) {
args := []interface{}{"order"} simple := filepath.Join(config.Conf.Root, "imports", "assets", "simple.xlsx")
mapping := gou.NewProcess("xiang.import.Mapping", "order", simple).Run()
args := []interface{}{"order", simple, 1, 2, mapping}
response := gou.NewProcess("xiang.import.Data", args...).Run() response := gou.NewProcess("xiang.import.Data", args...).Run()
assert.Nil(t, response) _, ok := response.(map[string]interface{})
assert.True(t, ok)
} }
func TestProcessDataSetting(t *testing.T) { func TestProcessDataSetting(t *testing.T) {
@ -31,6 +38,15 @@ func TestProcessDataSetting(t *testing.T) {
assert.Nil(t, response) assert.Nil(t, response)
} }
func TestProcessRun(t *testing.T) {
simple := filepath.Join(config.Conf.Root, "imports", "assets", "simple.xlsx")
mapping := gou.NewProcess("xiang.import.Mapping", "order", simple).Run()
args := []interface{}{"order", simple, mapping}
response := gou.NewProcess("xiang.import.Run", args...).Run()
_, ok := response.(map[string]int)
assert.True(t, ok)
}
func TestProcessRules(t *testing.T) { func TestProcessRules(t *testing.T) {
args := []interface{}{"order"} args := []interface{}{"order"}
response := gou.NewProcess("xiang.import.Rules", args...).Run() response := gou.NewProcess("xiang.import.Rules", args...).Run()

View file

@ -3,13 +3,13 @@
"version": "1.0.0", "version": "1.0.0",
"description": "数据分析接口API", "description": "数据分析接口API",
"group": "xiang/import", "group": "xiang/import",
"guard": "bearer-jwt", "guard": "-",
"paths": [ "paths": [
{ {
"path": "/:name", "path": "/:name",
"method": "POST", "method": "POST",
"process": "xiang.import.Run", "process": "xiang.import.Run",
"in": ["$param.name", ":payload"], "in": ["$param.name", "$payload.file", "$payload.mapping"],
"out": { "out": {
"status": 200, "status": 200,
"type": "application/json" "type": "application/json"
@ -19,7 +19,13 @@
"path": "/:name/data", "path": "/:name/data",
"method": "POST", "method": "POST",
"process": "xiang.import.Data", "process": "xiang.import.Data",
"in": ["$param.name", ":payload"], "in": [
"$param.name",
"$payload.file",
"$payload.page",
"$payload.size",
"$payload.mapping"
],
"out": { "out": {
"status": 200, "status": 200,
"type": "application/json" "type": "application/json"
@ -39,7 +45,7 @@
"path": "/:name/mapping", "path": "/:name/mapping",
"method": "GET", "method": "GET",
"process": "xiang.import.Mapping", "process": "xiang.import.Mapping",
"in": ["$param.name", ":query"], "in": ["$param.name", "$query.file"],
"out": { "out": {
"status": 200, "status": 200,
"type": "application/json" "type": "application/json"