update front ui
This commit is contained in:
parent
75ca055772
commit
dfbe88cb5a
9
Makefile
9
Makefile
|
@ -3,7 +3,14 @@ DATETIME:=$(shell date "+%Y-%m-%d %H:%M:%S")
|
||||||
PKGNAME:="git.nobla.cn/golang/moto"
|
PKGNAME:="git.nobla.cn/golang/moto"
|
||||||
GIT_VERSION=$(shell git rev-parse --short HEAD)
|
GIT_VERSION=$(shell git rev-parse --short HEAD)
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build font-build dev-serve
|
||||||
|
|
||||||
|
|
||||||
|
dev-serve:
|
||||||
|
cd web && npm run dev
|
||||||
|
|
||||||
|
font-build:
|
||||||
|
cd web && npm run build
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
12
api.go
12
api.go
|
@ -2,6 +2,9 @@ package moto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
httpkg "net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"git.nobla.cn/golang/kos"
|
"git.nobla.cn/golang/kos"
|
||||||
"git.nobla.cn/golang/kos/entry/http"
|
"git.nobla.cn/golang/kos/entry/http"
|
||||||
"git.nobla.cn/golang/kos/util/arrays"
|
"git.nobla.cn/golang/kos/util/arrays"
|
||||||
|
@ -13,8 +16,6 @@ import (
|
||||||
"git.nobla.cn/golang/rest"
|
"git.nobla.cn/golang/rest"
|
||||||
restTypes "git.nobla.cn/golang/rest/types"
|
restTypes "git.nobla.cn/golang/rest/types"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
httpkg "net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed web/release
|
//go:embed web/release
|
||||||
|
@ -151,8 +152,11 @@ func (svr *Server) handleSaveSchema(ctx *http.Context) (err error) {
|
||||||
schemas[i].Domain = domainName
|
schemas[i].Domain = domainName
|
||||||
}
|
}
|
||||||
if err = db.WithContext(ctx.Request().Context()).Transaction(func(tx *gorm.DB) (errTx error) {
|
if err = db.WithContext(ctx.Request().Context()).Transaction(func(tx *gorm.DB) (errTx error) {
|
||||||
for _, scm := range schemas {
|
for _, row := range schemas {
|
||||||
if errTx = tx.Save(scm).Error; errTx != nil {
|
if row.Domain == "" {
|
||||||
|
row.Domain = "localhost"
|
||||||
|
}
|
||||||
|
if errTx = tx.Save(row).Error; errTx != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
database:
|
database:
|
||||||
address: "192.168.9.199:3306"
|
address: "192.168.1.200:3306"
|
||||||
username: "root"
|
username: "root"
|
||||||
password: "root"
|
password: "smile1210"
|
||||||
database: "test2"
|
database: "test"
|
||||||
|
|
||||||
adminUsers:
|
adminUsers:
|
||||||
- "1000"
|
- "1000"
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -3,8 +3,8 @@ module git.nobla.cn/golang/moto
|
||||||
go 1.22.9
|
go 1.22.9
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.nobla.cn/golang/kos v0.1.32
|
git.nobla.cn/golang/kos v0.1.34
|
||||||
git.nobla.cn/golang/rest v0.0.4
|
git.nobla.cn/golang/rest v0.0.5
|
||||||
github.com/disintegration/letteravatar v0.0.0-20160912210445-1a457b860450
|
github.com/disintegration/letteravatar v0.0.0-20160912210445-1a457b860450
|
||||||
github.com/go-sql-driver/mysql v1.8.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -1,9 +1,9 @@
|
||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
git.nobla.cn/golang/kos v0.1.32 h1:sFVCA7vKc8dPUd0cxzwExOSPX2mmMh2IuwL6cYS1pBc=
|
git.nobla.cn/golang/kos v0.1.34 h1:GkyU9ya9tAMaq2SMbfV+yd8AAWLCWvyJUiYNVhP5IR4=
|
||||||
git.nobla.cn/golang/kos v0.1.32/go.mod h1:35Z070+5oB39WcVrh5DDlnVeftL/Ccmscw2MZFe9fUg=
|
git.nobla.cn/golang/kos v0.1.34/go.mod h1:35Z070+5oB39WcVrh5DDlnVeftL/Ccmscw2MZFe9fUg=
|
||||||
git.nobla.cn/golang/rest v0.0.4 h1:i8hD/z5UAgoKjRA0ED83yK0q0IuYJ+xiiUZ1nGdn8PY=
|
git.nobla.cn/golang/rest v0.0.5 h1:dgEuGLt2xYdyNxXKdQ5/k27O2zJFbrMBX7s4PRlyduk=
|
||||||
git.nobla.cn/golang/rest v0.0.4/go.mod h1:tGDOul2GGJtxk6fAeu+YLpMt/Up/TsBonTkygymN/wE=
|
git.nobla.cn/golang/rest v0.0.5/go.mod h1:4viDk7VujDokpUeHQGbnSp2bkkVZEoIkWQIs/l/TTPQ=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|
|
@ -12,20 +12,21 @@
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"element-plus": "^2.9.0",
|
"element-plus": "^2.9.6",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pinia": "^2.2.6",
|
"pinia": "^2.2.6",
|
||||||
"pinia-plugin-persistedstate": "^4.1.3",
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"query-string": "^9.1.1",
|
"query-string": "^9.1.1",
|
||||||
"sass": "^1.82.0",
|
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.4.5",
|
"vue-router": "^4.4.5",
|
||||||
"vue3-puzzle-vcode": "^1.1.7"
|
"vue3-puzzle-vcode": "^1.1.7",
|
||||||
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"sass": "^1.82.0",
|
||||||
"vite": "^6.0.1",
|
"vite": "^6.0.1",
|
||||||
"vite-plugin-vue-devtools": "^7.6.5"
|
"vite-plugin-vue-devtools": "^7.6.5"
|
||||||
}
|
}
|
||||||
|
@ -1101,6 +1102,7 @@
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz",
|
||||||
"integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==",
|
"integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==",
|
||||||
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
@ -1140,6 +1142,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1160,6 +1163,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1180,6 +1184,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1200,6 +1205,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1220,6 +1226,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1240,6 +1247,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1260,6 +1268,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1280,6 +1289,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1300,6 +1310,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1320,6 +1331,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1340,6 +1352,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1360,6 +1373,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -1380,6 +1394,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
@ -2424,6 +2439,7 @@
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -2452,9 +2468,9 @@
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/element-plus": {
|
"node_modules/element-plus": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.7",
|
||||||
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.0.tgz",
|
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.7.tgz",
|
||||||
"integrity": "sha512-ccOFXKsauo2dtokAr4OX7gZsb7TuAoVxA2zGRZo5o2yyDDBLBaZxOoFQPoxITSLcHbBfQuNDGK5Iag5hnyKkZA==",
|
"integrity": "sha512-6vjZh5SXBncLhUwJGTVKS5oDljfgGMh6J4zVTeAZK3YdMUN76FgpvHkwwFXocpJpMbii6rDYU3sgie64FyPerQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ctrl/tinycolor": "^3.4.1",
|
"@ctrl/tinycolor": "^3.4.1",
|
||||||
|
@ -2932,6 +2948,7 @@
|
||||||
"version": "5.0.3",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz",
|
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz",
|
||||||
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
|
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
|
@ -3407,6 +3424,7 @@
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
@ -3955,6 +3973,7 @@
|
||||||
"version": "1.82.0",
|
"version": "1.82.0",
|
||||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.82.0.tgz",
|
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.82.0.tgz",
|
||||||
"integrity": "sha512-j4GMCTa8elGyN9A7x7bEglx0VgSpNUG4W4wNedQ33wSMdnkqQCT8HTwOaVSV4e6yQovcu/3Oc4coJP/l0xhL2Q==",
|
"integrity": "sha512-j4GMCTa8elGyN9A7x7bEglx0VgSpNUG4W4wNedQ33wSMdnkqQCT8HTwOaVSV4e6yQovcu/3Oc4coJP/l0xhL2Q==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.0",
|
"chokidar": "^4.0.0",
|
||||||
|
@ -4067,6 +4086,12 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
@ -4587,6 +4612,18 @@
|
||||||
"resolved": "https://registry.npmmirror.com/vue3-puzzle-vcode/-/vue3-puzzle-vcode-1.1.7.tgz",
|
"resolved": "https://registry.npmmirror.com/vue3-puzzle-vcode/-/vue3-puzzle-vcode-1.1.7.tgz",
|
||||||
"integrity": "sha512-mW780dz7HKjrElnE60CeYSeHGidKBKHoMjTDYfqF21330rTkFOsfDK1FQKZ22MktgMtTEoS/imfpEDlM1cxY/g=="
|
"integrity": "sha512-mW780dz7HKjrElnE60CeYSeHGidKBKHoMjTDYfqF21330rTkFOsfDK1FQKZ22MktgMtTEoS/imfpEDlM1cxY/g=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vuedraggable": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sortablejs": "1.14.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/webpack-virtual-modules": {
|
"node_modules/webpack-virtual-modules": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||||
|
|
|
@ -13,20 +13,21 @@
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"element-plus": "^2.9.0",
|
"element-plus": "^2.9.6",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pinia": "^2.2.6",
|
"pinia": "^2.2.6",
|
||||||
"pinia-plugin-persistedstate": "^4.1.3",
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"query-string": "^9.1.1",
|
"query-string": "^9.1.1",
|
||||||
"sass": "^1.82.0",
|
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.4.5",
|
"vue-router": "^4.4.5",
|
||||||
"vue3-puzzle-vcode": "^1.1.7"
|
"vue3-puzzle-vcode": "^1.1.7",
|
||||||
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"sass": "^1.82.0",
|
||||||
"vite": "^6.0.1",
|
"vite": "^6.0.1",
|
||||||
"vite-plugin-vue-devtools": "^7.6.5"
|
"vite-plugin-vue-devtools": "^7.6.5"
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
|
@ -7,8 +7,8 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>MOTO</title>
|
<title>MOTO</title>
|
||||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3832926_ya7vh14nje.css">
|
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3832926_ya7vh14nje.css">
|
||||||
<script type="module" crossorigin src="/static/index-4E04Ax0l.js"></script>
|
<script type="module" crossorigin src="/static/index-CttRSJAf.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/static/index-BhBbL-Pz.css">
|
<link rel="stylesheet" crossorigin href="/static/index-DXC70i67.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ export function getBaseHost() {
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
return location.host;
|
return location.host;
|
||||||
} else {
|
} else {
|
||||||
return 'api-dev.echo.me'
|
return '//devapi-local.tryfly.eu.org'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ export function getBaseUrl() {
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
return location.protocol + '//' + host;
|
return location.protocol + '//' + host;
|
||||||
} else {
|
} else {
|
||||||
return location.protocol + '//' + host
|
return location.protocol + '//' + host;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import request from './request'
|
||||||
|
|
||||||
|
export function getModules() {
|
||||||
|
return request.get('/rest/schemas')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSchemas(tableName) {
|
||||||
|
return request.get(`/rest/schema/${tableName}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveSchemas(tableName, schemas) {
|
||||||
|
return request.put(`/rest/schema/${tableName}`, schemas)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteSchema(id) {
|
||||||
|
return request.delete(`/rest/schema/${id}`)
|
||||||
|
}
|
|
@ -149,6 +149,12 @@ body,
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile-container {
|
||||||
|
.el-tabs__header {
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { encode, decode } from './libs/codec'
|
||||||
import FormItem from './parts/FormItem.vue';
|
import FormItem from './parts/FormItem.vue';
|
||||||
import Action from './parts/Action.vue';
|
import Action from './parts/Action.vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { generateSchemaRule, checkSchemaVisible } from './libs/form'
|
import { generateSchemaRule, checkSchemaVisible } from './libs/form';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
size: {
|
size: {
|
||||||
|
|
|
@ -246,6 +246,10 @@ const formTitle = computed(() => {
|
||||||
return actionText + (title || '')
|
return actionText + (title || '')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否有权限
|
||||||
|
* @param s 权限标识符
|
||||||
|
*/
|
||||||
const hasPermission = (s) => {
|
const hasPermission = (s) => {
|
||||||
if (props.disablePermission) {
|
if (props.disablePermission) {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -82,13 +82,24 @@ export function encode(raw, schemas, scenario) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (['multiSelect'].indexOf(schema.format) > -1) {
|
} else if (['multiSelect'].indexOf(schema.format) > -1 || (scenario === "search" && schema.attribute.multiple_for_search)) {
|
||||||
try {
|
try {
|
||||||
if (typeof raw[schema.column] === 'object') {
|
if (Array.isArray(raw[schema.column]) && raw[schema.column].length > 0) {
|
||||||
data[schema.column] = mustMarshal(
|
if (scenario === "search") {
|
||||||
JSON.stringify(raw[schema.column]),
|
let vs = [];
|
||||||
schema.type
|
for (let i in raw[schema.column]) {
|
||||||
)
|
vs.push(mustMarshal(
|
||||||
|
raw[schema.column][i],
|
||||||
|
schema.type
|
||||||
|
))
|
||||||
|
}
|
||||||
|
data[schema.column] = vs
|
||||||
|
} else {
|
||||||
|
data[schema.column] = mustMarshal(
|
||||||
|
JSON.stringify(raw[schema.column]),
|
||||||
|
schema.type
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
} else if (['date', 'datetime', 'timestamp'].indexOf(schema.format) > -1) {
|
} else if (['date', 'datetime', 'timestamp'].indexOf(schema.format) > -1) {
|
||||||
|
|
|
@ -17,7 +17,9 @@ export function clearSearchModel(model, schemas) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps[schema.column] = model[schema.column]
|
if (model[schema.column]) {
|
||||||
|
ps[schema.column] = model[schema.column]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="isVisible('dropdown', schema)">
|
<template v-else-if="isVisible('dropdown', schema)">
|
||||||
<el-select clearable v-if="!isDropdownMulitLevel(schema)" v-model="model[schema.column]"
|
<el-select clearable v-if="!isDropdownMulitLevel(schema)" v-model="model[schema.column]"
|
||||||
:multiple="schema.format === 'multiSelect'" :disabled="isDisabled(schema)"
|
:multiple="isMulutSelete(schema)" :disabled="isDisabled(schema)" :placeholder="getPlaceholder(schema)"
|
||||||
:placeholder="getPlaceholder(schema)" :allow-create="isDropdownCreated(schema)"
|
:allow-create="isDropdownCreated(schema)" :filterable="isDropdownFilterable(schema)"
|
||||||
:filterable="isDropdownFilterable(schema)" :default-first-option="isDropdownDefaultFirst(schema)">
|
:default-first-option="isDropdownDefaultFirst(schema)">
|
||||||
<template v-for="(v, k) in schema.attribute.values" :key="k">
|
<template v-for="(v, k) in schema.attribute.values" :key="k">
|
||||||
<el-option v-if="typeof v === 'object'" :label="v.label" :value="v.value"></el-option>
|
<el-option v-if="typeof v === 'object'" :label="v.label" :value="v.value"></el-option>
|
||||||
<el-option v-else :label="v" :value="k"></el-option>
|
<el-option v-else :label="v" :value="k"></el-option>
|
||||||
|
@ -101,6 +101,16 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isMulutSelete = (schema) => {
|
||||||
|
if (schema.format == "multiSelect") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (schema.attribute.multiple_for_search && props.scenario == 'search') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const isDropdownCreated = (schema) => {
|
const isDropdownCreated = (schema) => {
|
||||||
if (props.scenario === 'search') {
|
if (props.scenario === 'search') {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,6 +19,7 @@ const menu = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
label: "组织架构",
|
label: "组织架构",
|
||||||
icon: "org",
|
icon: "org",
|
||||||
|
@ -87,6 +88,20 @@ const menu = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "系统设置",
|
||||||
|
icon: "connect",
|
||||||
|
hidden: false,
|
||||||
|
route: '/setting',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "表单设置",
|
||||||
|
hidden: false,
|
||||||
|
access: 'allow',
|
||||||
|
route: "/setting/schemas"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default menu;
|
export default menu;
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="flex-shrink">
|
<div class="flex-shrink">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-fill">
|
<div class="flex-fill">
|
||||||
<div class="text-right text-muted">{{ copyright }}</div>
|
<div class="text-right text-muted" style="font-size: .8rem;">{{ copyright }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import LayoutView from '@/layouts/default/Layout.vue'
|
import LayoutView from '@/layouts/default/Layout.vue'
|
||||||
import { getMenus, buildRoutes } from '@/assets/js/menu'
|
import { getMenus, buildRoutes } from '@/assets/js/menu'
|
||||||
|
|
||||||
const components = import.meta.glob("../views/**/**.vue")
|
const components = import.meta.glob("../views/**/**.vue");
|
||||||
|
|
||||||
const childRoutes = buildRoutes(getMenus(), components);
|
const childRoutes = buildRoutes(getMenus(), components);
|
||||||
|
|
||||||
|
@ -32,5 +32,4 @@ const router = createRouter({
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="个人简介" prop="confirmPassword">
|
<el-form-item label="个人简介" prop="confirmPassword">
|
||||||
<el-input v-model="basicModel.description" type="textarea" autocomplete="off"
|
<el-input v-model="basicModel.description" type="textarea" autocomplete="off"
|
||||||
rows="10" placeholder="请介绍下自己" />
|
:rows="10" placeholder="请介绍下自己" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleUpdateProfile">修改</el-button>
|
<el-button type="primary" @click="handleUpdateProfile">修改</el-button>
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
<template>
|
||||||
|
<div class="card box">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-fill">
|
||||||
|
<h3>字段配置</h3>
|
||||||
|
</div>
|
||||||
|
<div class="flex-shrink">
|
||||||
|
<el-button type="primary" @click="handleSubmit" round>保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body d-flex flex-horizontal" v-loading="loading">
|
||||||
|
<div class="flex-shrink auto-scroll" style="width:280px" v-if="enableAddSchema">
|
||||||
|
<div class="schema-form-elements">
|
||||||
|
<draggable v-model="formElements" :group="elementGroup" itemKey="name" :clone="handleCloneSchema">
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<div class="form-element">
|
||||||
|
<div class="form-element-inner">
|
||||||
|
<icon :name="element.icon"></icon>
|
||||||
|
<span>{{ element.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-shrink px-1 border-right border-left schemas-build-form auto-scroll"
|
||||||
|
:style="{ width: enableAddSchema ? '600px' : '60%' }">
|
||||||
|
<el-form label-width="120px">
|
||||||
|
<el-empty v-if="schemas.length <= 0"></el-empty>
|
||||||
|
<draggable v-else v-model="schemas" handle=".drag-move" :group="fieldGroup" itemKey="column"
|
||||||
|
@add="handleAddSchema">
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<column :schema="element" @click="handleSelected" @delete="handleDeleteSchema"
|
||||||
|
:class="schema && schema.column == element.column ? 'active' : ''">
|
||||||
|
</column>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill px-1 auto-scroll">
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane label="基础配置" name="attr">
|
||||||
|
<attribute v-if="schema.column" :schema="schema" :schemas="schemas"></attribute>
|
||||||
|
<el-empty v-else></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="校验规则" name="rule">
|
||||||
|
<rule v-if="schema.column" :schema="schema"></rule>
|
||||||
|
<el-empty v-else></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="显示条件" name="visible">
|
||||||
|
<visible v-if="schema.column" :schema="schema" :schemas="schemas"></visible>
|
||||||
|
<el-empty v-else></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getSchemas, saveSchemas } from '@/apis/schema'
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { onMounted, computed, ref } from 'vue';
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
import Column from './parts/Column.vue'
|
||||||
|
import Attribute from './parts/Attribute.vue'
|
||||||
|
import Visible from './parts/Visible.vue';
|
||||||
|
import Rule from './parts/Rule.vue'
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import Icon from '@/components/widgets/Icon.vue';
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
import { getSupportedElements, grantElementSchema } from './schema'
|
||||||
|
|
||||||
|
const schemas = ref([]);
|
||||||
|
|
||||||
|
const schema = ref({});
|
||||||
|
|
||||||
|
const activeTab = ref('attr')
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const tableName = route.query['table'] || '';
|
||||||
|
|
||||||
|
const enableAddSchema = ref(false)
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
let cloneID = '';
|
||||||
|
|
||||||
|
const formElements = computed(() => {
|
||||||
|
return getSupportedElements()
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (route.query['enable_schema_add'] == "true") {
|
||||||
|
enableAddSchema.value = true
|
||||||
|
}
|
||||||
|
getSchemas(tableName).then(res => {
|
||||||
|
schemas.value = [];
|
||||||
|
for (let v of res) {
|
||||||
|
schemas.value.push(v)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error(e.message)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleSelected = (e) => {
|
||||||
|
schema.value = e
|
||||||
|
activeTab.value = 'attr'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteSchema = (e) => {
|
||||||
|
for (let i in schemas.value) {
|
||||||
|
if (schemas.value[i].column == e.column) {
|
||||||
|
schemas.value.splice(i, 1)
|
||||||
|
if (e.column === schema.value.column) {
|
||||||
|
if (i > 0) {
|
||||||
|
schema.value = schema.value[i - 1]
|
||||||
|
} else {
|
||||||
|
schema.value = schemas.value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloneSchema = (e) => {
|
||||||
|
cloneID = nanoid(12).toString()
|
||||||
|
let schema = Object.assign(grantElementSchema(e), {
|
||||||
|
namespace: "default",
|
||||||
|
table_name: tableName,
|
||||||
|
column: cloneID,
|
||||||
|
shadow: cloneID,
|
||||||
|
label: e.label,
|
||||||
|
})
|
||||||
|
return schema
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddSchema = (e) => {
|
||||||
|
for (let i in schemas.value) {
|
||||||
|
if (schemas.value[i].column === cloneID) {
|
||||||
|
schema.value = schemas.value[i]
|
||||||
|
activeTab.value = 'attr'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementGroup = computed(() => {
|
||||||
|
return {
|
||||||
|
name: 'schema',
|
||||||
|
pull: 'clone',
|
||||||
|
put: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const fieldGroup = computed(() => {
|
||||||
|
return {
|
||||||
|
name: 'schema',
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
const columnOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
animation: 200,
|
||||||
|
disabled: false,
|
||||||
|
ghostClass: "ghost"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
let data = [];
|
||||||
|
let index = 0;
|
||||||
|
for (let i in schemas.value) {
|
||||||
|
let row = Object.assign({}, schemas.value[i])
|
||||||
|
row.position = ++index;
|
||||||
|
if (row.attribute.live.enable) {
|
||||||
|
row.attribute.values = [];
|
||||||
|
}
|
||||||
|
//影子ID,用于新添加的字段允许设置列的名字
|
||||||
|
if (row.shadow) {
|
||||||
|
row.column = row.shadow
|
||||||
|
}
|
||||||
|
data.push(row)
|
||||||
|
}
|
||||||
|
saveSchemas(tableName, data).then(res => {
|
||||||
|
ElMessage.success("保存成功")
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error(`保存失败: ${e.message}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.schemas-build-form {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-form-elements {
|
||||||
|
list-style: none;
|
||||||
|
padding: .38rem;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.form-element {
|
||||||
|
width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
.form-element-inner {
|
||||||
|
cursor: move;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px dotted transparent;
|
||||||
|
padding: .5rem 0 .5rem .5rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
margin-right: .38rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: .8rem;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
transition: all .5s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--text-color-second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,303 @@
|
||||||
|
<template>
|
||||||
|
<el-form label-position="top" label-width="100px" :model="schema">
|
||||||
|
<el-form-item label="字段标识">
|
||||||
|
<template v-if="schema.native == 0 && !schema.id">
|
||||||
|
<el-input v-model="schema.shadow" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-input v-model="schema.column" readonly />
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段名称">
|
||||||
|
<el-input v-model="schema.label" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="启用状态">
|
||||||
|
<el-switch v-model="schema.enable" :active-value="1" :inactive-value="0"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="启用排序">
|
||||||
|
<el-switch v-model="schema.attribute.sort"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="匹配模式">
|
||||||
|
<el-select v-model="schema.attribute.match">
|
||||||
|
<el-option v-for="(v, k) in mtchOptioons" :key="k" :label="v" :value="k"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段类型">
|
||||||
|
<template v-if="isNormalFormat(schema.format)">
|
||||||
|
<el-select v-model="schema.format">
|
||||||
|
<el-option v-for="(v, k) in allowFormats" :key="k" :label="v" :value="k"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span>自定义类型</span>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="搜索多选" v-if="schema.format == 'dropdown'">
|
||||||
|
<el-switch v-model="schema.attribute.multiple_for_search"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="只读场景">
|
||||||
|
<el-checkbox-group v-model="schema.attribute.readonly">
|
||||||
|
<el-checkbox-button :label="k" v-for="(v, k) in formScenarios" :value="k">{{ v }}</el-checkbox-button>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="禁用场景">
|
||||||
|
<el-checkbox-group v-model="schema.attribute.disable">
|
||||||
|
<el-checkbox-button :label="k" v-for="(v, k) in formScenarios" :value="k">{{ v }}</el-checkbox-button>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="显示场景">
|
||||||
|
<el-checkbox-group v-model="schema.scenarios">
|
||||||
|
<el-checkbox-button :label="k" v-for="(v, k) in allowScenarios" :value="k">{{ v }}</el-checkbox-button>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<template v-if="isDatasourceFile(schema.format)">
|
||||||
|
<el-tabs v-model="datasourceTabValue" @tab-change="hangleDatasourceTabChange">
|
||||||
|
<el-tab-pane label="自定义" name="inner">
|
||||||
|
<el-form-item>
|
||||||
|
<draggable class="d-flex flex-vertical" v-model="schema.attribute.values"
|
||||||
|
handle=".schema-datasource-handle" itemKey="id">
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<div class="d-flex w-100 schema-datasource-row">
|
||||||
|
<el-col :span="9" style="padding-right:5px">
|
||||||
|
<el-input placeholder="请输入字段名称" v-model="element.value"></el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="9" style="padding-right:5px">
|
||||||
|
<el-input placeholder="请输入显示名称" v-model="element.label"></el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="3">
|
||||||
|
<el-color-picker v-model="element.color" show-alpha />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="3" class="text-right">
|
||||||
|
<el-tooltip content="移动">
|
||||||
|
<icon class="schema-datasource-handle" name="icon-move1"></icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除">
|
||||||
|
<icon @click="handleDelDatasourceItem(index)" name="ashbin"></icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-col>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
<div class="w-100 py-1 ">
|
||||||
|
<small @click="handleAddDatasourceItem">
|
||||||
|
<span class="text-color-primary cursor-pointer">添加</span>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="接口数据" name="live">
|
||||||
|
<div class="inline-form-item">
|
||||||
|
<label class="el-form-item__label">数据类型</label>
|
||||||
|
<el-select v-model="schema.attribute.live.type">
|
||||||
|
<el-option label="下拉" value="dropdown"></el-option>
|
||||||
|
<el-option label="级联" value="cascader"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="inline-form-item">
|
||||||
|
<label class="el-form-item__label">接口类型</label>
|
||||||
|
<el-select v-model="schema.attribute.live.method">
|
||||||
|
<el-option v-for="row in requestMethod" :label="row.label" :value="row.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="inline-form-item">
|
||||||
|
<label class="el-form-item__label">接口地址</label>
|
||||||
|
<el-input v-model="schema.attribute.live.url"></el-input>
|
||||||
|
</div>
|
||||||
|
<div class="inline-form-item" v-if="schema.attribute.live.method != 'get'">
|
||||||
|
<label class="el-form-item__label">数据类型</label>
|
||||||
|
<el-select v-model="schema.attribute.live.content_type">
|
||||||
|
<el-option v-for="row in requestContentType" :label="row.label"
|
||||||
|
:value="row.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="inline-form-item" v-if="schema.attribute.live.method != 'get'">
|
||||||
|
<label class="el-form-item__label">请求数据</label>
|
||||||
|
<el-input v-model="schema.attribute.live.body"></el-input>
|
||||||
|
</div>
|
||||||
|
<div class="inline-form-item" v-if="schema.attribute.live.type == 'cascader'">
|
||||||
|
<label class="el-form-item__label">数据列</label>
|
||||||
|
<el-select v-model="schema.attribute.live.columns" :multiple="true">
|
||||||
|
<el-option v-for="row in schemas" :label="row.label" :value="row.column"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<el-divider>
|
||||||
|
</el-divider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form-item label="默认值">
|
||||||
|
<el-input v-model="schema.attribute.default_value" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="占位文本">
|
||||||
|
<el-input v-model="schema.attribute.tooltip" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段解释">
|
||||||
|
<el-input type="textarea" v-model="schema.attribute.description" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.schema-datasource-row {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
margin-right: .5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-move1 {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-form-item {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
max-width: 280px;
|
||||||
|
--el-select-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
max-width: 280px;
|
||||||
|
--el-input-height: 29px;
|
||||||
|
--el-input-width: 80%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Icon from '@/components/widgets/Icon.vue'
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
import { ref, computed, onMounted, watch } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
schemas: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mtchOptioons = {
|
||||||
|
'exactly': '精确匹配',
|
||||||
|
'fuzzy': '模糊匹配'
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowFormats = {
|
||||||
|
'integer': '整数',
|
||||||
|
'decimal': '小数',
|
||||||
|
'string': '文本',
|
||||||
|
'boolean': '是否',
|
||||||
|
'textarea': '多行文本',
|
||||||
|
'date': '日期',
|
||||||
|
'time': '时间',
|
||||||
|
'datetime': '日期时间',
|
||||||
|
'dropdown': '单项选择',
|
||||||
|
'multiSelect': '多项选择'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const allowScenarios = {
|
||||||
|
create: '创建',
|
||||||
|
update: '更新',
|
||||||
|
search: '查询',
|
||||||
|
export: '导出',
|
||||||
|
list: '列表',
|
||||||
|
view: '详情',
|
||||||
|
};
|
||||||
|
|
||||||
|
const formScenarios = {
|
||||||
|
create: '创建',
|
||||||
|
update: '更新',
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestMethod = computed(() => {
|
||||||
|
return [
|
||||||
|
{ label: 'GET', value: 'get' },
|
||||||
|
{ label: 'POST', value: 'post' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const requestContentType = computed(() => {
|
||||||
|
return [
|
||||||
|
{ label: 'JSON', value: 'application/json' },
|
||||||
|
{ label: 'XML', value: 'application/xml' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const datasourceTabValue = ref('inner')
|
||||||
|
|
||||||
|
const isDatasourceFile = (v) => {
|
||||||
|
return ['dropdown', 'multiSelect'].indexOf(v) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNormalFormat = (v) => {
|
||||||
|
for (let k in allowFormats) {
|
||||||
|
if (k.toUpperCase() === v.toUpperCase()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hangleDatasourceTabChange = (v) => {
|
||||||
|
if (v === 'live') {
|
||||||
|
props.schema.attribute.live.enable = true;
|
||||||
|
if (!props.schema.attribute.live.type) {
|
||||||
|
props.schema.attribute.live.type = 'dropdown'
|
||||||
|
}
|
||||||
|
if (!props.schema.attribute.live.method) {
|
||||||
|
props.schema.attribute.live.method = 'get'
|
||||||
|
}
|
||||||
|
if (!props.schema.attribute.live.content_type) {
|
||||||
|
props.schema.attribute.live.content_type = 'application/json'
|
||||||
|
}
|
||||||
|
if (!props.schema.attribute.live.body) {
|
||||||
|
props.schema.attribute.live.body = ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.schema.attribute.live.enable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelDatasourceItem = (index) => {
|
||||||
|
props.schema.attribute.values.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddDatasourceItem = () => {
|
||||||
|
if (!Array.isArray(props.schema.attribute.values)) {
|
||||||
|
props.schema.attribute.values = [];
|
||||||
|
}
|
||||||
|
let hasEmpty = false;
|
||||||
|
for (let v of props.schema.attribute.values) {
|
||||||
|
if (v.label === '' && v.value === '' && v.color === '') {
|
||||||
|
hasEmpty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasEmpty) {
|
||||||
|
props.schema.attribute.values.push({ label: '', value: '', color: '', id: props.schema.attribute.values.length + 1 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
watch(() => props.schema, (v) => {
|
||||||
|
if (v.attribute.live.enable) {
|
||||||
|
datasourceTabValue.value = 'live'
|
||||||
|
} else {
|
||||||
|
datasourceTabValue.value = 'inner'
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,204 @@
|
||||||
|
<template>
|
||||||
|
<div class="schema-build-item"
|
||||||
|
:class="schema.enable === 1 ? `schema-column-${schema.column}` : `schema-column-${schema.column} disabled`"
|
||||||
|
@click="handleClick">
|
||||||
|
<div class="drag-move">
|
||||||
|
<icon name="icon-move"></icon>
|
||||||
|
</div>
|
||||||
|
<div class="schema-build-item-mask">
|
||||||
|
<div class="schema-build-toolbar" v-if="schema.native === 0">
|
||||||
|
<el-tooltip content="删除字段">
|
||||||
|
<icon name="ashbin" @click="handleDeleteSchema"></icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-form-item :label="schema.label">
|
||||||
|
<el-time-picker v-if="isVisible('time', schema)" :placeholder="getPlaceholder(schema)"></el-time-picker>
|
||||||
|
<el-date-picker v-else-if="isVisible('date', schema)"
|
||||||
|
:placeholder="getPlaceholder(schema)"></el-date-picker>
|
||||||
|
<el-date-picker v-else-if="isVisible('datetime', schema)" :placeholder="getPlaceholder(schema)">
|
||||||
|
</el-date-picker>
|
||||||
|
<el-select v-else-if="isVisible('dropdown', schema)" clearable :placeholder="getPlaceholder(schema)">
|
||||||
|
<template v-for="(v, k) in schema.attribute.values" :key="k">
|
||||||
|
<el-option v-if="typeof v === 'object'" :label="v.label" :value="v.value"></el-option>
|
||||||
|
<el-option v-else :label="v" :value="k"></el-option>
|
||||||
|
</template>
|
||||||
|
</el-select>
|
||||||
|
<el-cascader v-else-if="isVisible('cascader', schema)" :options="schema.attribute.values" filterable
|
||||||
|
clearable :placeholder="getPlaceholder(schema)"></el-cascader>
|
||||||
|
<el-switch v-else-if="isVisible('boolean', schema)" :inactive-value="0" :active-value="1"></el-switch>
|
||||||
|
<el-input v-else-if="isVisible('password', schema)" show-password :readonly="true"
|
||||||
|
:placeholder="getPlaceholder(schema)"></el-input>
|
||||||
|
<el-input v-else-if="isVisible('multistr', schema)" type="textarea" :readonly="true"
|
||||||
|
:placeholder="getPlaceholder(schema)"></el-input>
|
||||||
|
<el-input v-else-if="isVisible('number', schema)" :placeholder="getPlaceholder(schema)" :readonly="true">
|
||||||
|
<template v-if="schema.attribute.suffix" #append>
|
||||||
|
{{ schema.attribute.suffix }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-input v-else :placeholder="getPlaceholder(schema)" :readonly="true">
|
||||||
|
<template v-if="schema.attribute.suffix" #append>
|
||||||
|
{{ schema.attribute.suffix }}
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.schema-build-item {
|
||||||
|
display: block;
|
||||||
|
padding: .8rem 1rem;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
max-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
|
||||||
|
.drag-move {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-build-toolbar {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ghost {
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.schema-build-item-mask {
|
||||||
|
background-color: var(--el-mask-color-extra-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-build-item-mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 8;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-build-toolbar {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
color: white;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: .5rem .8rem;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-move {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
display: none;
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size: 1.38rem;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
background-color: var(--el-color-primary-light-8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import Icon from '@/components/widgets/Icon.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
scenario: {
|
||||||
|
type: String,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(["click", "delete"])
|
||||||
|
|
||||||
|
onMounted(() => { })
|
||||||
|
|
||||||
|
const handleClick = (e) => {
|
||||||
|
emit('click', props.schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isVisible = (type, schema) => {
|
||||||
|
let visible = false
|
||||||
|
switch (type) {
|
||||||
|
case 'number':
|
||||||
|
visible = ['integer', 'decimal'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'password':
|
||||||
|
visible = ['password', 'pass'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'time':
|
||||||
|
visible = ['time'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'date':
|
||||||
|
visible = ['date'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'datetime':
|
||||||
|
visible = ['datetime', 'timestamp'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'dropdown':
|
||||||
|
visible = ['dropdown', 'multiSelect'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'cascader':
|
||||||
|
visible = ['cascader'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
case 'multistr':
|
||||||
|
if (props.scenario !== 'search') {
|
||||||
|
visible = ['textarea'].indexOf(schema.format) > -1
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'boolean':
|
||||||
|
if (
|
||||||
|
props.scenario !== 'search' &&
|
||||||
|
['bool', 'boolean'].indexOf(schema.format) > -1
|
||||||
|
) {
|
||||||
|
visible = true
|
||||||
|
} else {
|
||||||
|
visible = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'string':
|
||||||
|
visible = ['string', 'text'].indexOf(schema.format) > -1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return visible
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPlaceholder = (schema) => {
|
||||||
|
if (schema.attribute.tooltip) {
|
||||||
|
return schema.attribute.tooltip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteSchema = (e) => {
|
||||||
|
emit('delete', props.schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<el-form label-position="top" label-width="100px" :model="schema">
|
||||||
|
<el-form-item :label="maxLabel(schema.type)">
|
||||||
|
<el-input type="number" v-model.number="schema.rule.max" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="minLabel(schema.type)">
|
||||||
|
<el-input type="number" v-model.number="schema.rule.min" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="是否唯一">
|
||||||
|
<el-switch v-model="schema.rule.unique"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="必填场景">
|
||||||
|
<el-checkbox-group v-model="schema.rule.required">
|
||||||
|
<el-checkbox-button :label="k" v-for="(v, k) in formScenarios" :value="k">{{ v }}</el-checkbox-button>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="schema.type === 'string'" label="校验规则">
|
||||||
|
<el-input v-model="schema.rule.regular" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const formScenarios = {
|
||||||
|
create: '创建',
|
||||||
|
update: '更新',
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLabel = (v) => {
|
||||||
|
if (['string'].indexOf(v) > -1) {
|
||||||
|
return '最大长度'
|
||||||
|
} else if (['integer', 'double'].indexOf(v) > -1) {
|
||||||
|
return '最大值'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const minLabel = (v) => {
|
||||||
|
if (['string'].indexOf(v) > -1) {
|
||||||
|
return '最小长度'
|
||||||
|
} else if (['integer', 'double'].indexOf(v) > -1) {
|
||||||
|
return '最小值'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,135 @@
|
||||||
|
<template>
|
||||||
|
<el-alert title="温馨提示" type="info" effect="dark">
|
||||||
|
显示条件可以配置字段的显示条件
|
||||||
|
<ul>
|
||||||
|
<li>只有当表单的值全部满足用户配置的条件时候,字段才会显示出来</li>
|
||||||
|
</ul>
|
||||||
|
</el-alert>
|
||||||
|
<template v-if="schema.attribute.visible.length > 0">
|
||||||
|
<el-table :data="schema.attribute.visible">
|
||||||
|
<el-table-column prop="column" label="字段名称">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ formatSchemaLabel(scope.row.column) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="column" label="匹配值">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-for="tag in scope.row.values" class="mr-1">
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="column">
|
||||||
|
<template #default="scope">
|
||||||
|
<icon name="ashbin" class="text-color-danger cursor-pointer"
|
||||||
|
@click="handleDeleteCondition(scope.index)"></icon>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-empty></el-empty>
|
||||||
|
</template>
|
||||||
|
<el-divider>添加选项</el-divider>
|
||||||
|
<el-form :model="model">
|
||||||
|
<el-form-item>
|
||||||
|
<el-select v-model="model.column" class="mr-1">
|
||||||
|
<template v-for="(v, k) in allowFields" :key="k">
|
||||||
|
<el-option :label="v.label" :value="v.value"></el-option>
|
||||||
|
</template>
|
||||||
|
</el-select>
|
||||||
|
<div class="d-flex" v-if="model.column">
|
||||||
|
<div class="flex-shrink">
|
||||||
|
<el-tag v-for="tag in model.values" closable class="mr-1" :disable-transitions="false"
|
||||||
|
@close="handleRemoveTag(tag)">
|
||||||
|
{{ tag }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill">
|
||||||
|
<el-input v-model="inputValue" round placeholder="请输入值,按回车键确定" @keyup.enter="handleInputConfirm"
|
||||||
|
@blur="handleInputConfirm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" round @click="handleCreateCondition">添加</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import Icon from '@/components/widgets/Icon.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
schema: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
schemas: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const model = ref({
|
||||||
|
column: '',
|
||||||
|
values: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const inputVisible = ref(false);
|
||||||
|
|
||||||
|
const inputValue = ref('');
|
||||||
|
|
||||||
|
const allowFields = computed(() => {
|
||||||
|
let vs = [];
|
||||||
|
for (let schema of props.schemas) {
|
||||||
|
if (schema.column === props.schema.column) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vs.push({
|
||||||
|
label: schema.label,
|
||||||
|
value: schema.column
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
})
|
||||||
|
|
||||||
|
const formatSchemaLabel = (v) => {
|
||||||
|
for (let schema of props.schemas) {
|
||||||
|
if (schema.column === v) {
|
||||||
|
return schema.label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemoveTag = (tag) => {
|
||||||
|
let index = model.value.values.indexOf(tag);
|
||||||
|
if (index > -1) {
|
||||||
|
model.value.values.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInputConfirm = (e) => {
|
||||||
|
if (inputValue.value !== '') {
|
||||||
|
model.value.values.push(inputValue.value)
|
||||||
|
inputValue.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteCondition = (e) => {
|
||||||
|
props.schema.attribute.visible.splice(e, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreateCondition = (e) => {
|
||||||
|
props.schema.attribute.visible.push({
|
||||||
|
column: model.value.column,
|
||||||
|
values: model.value.values
|
||||||
|
})
|
||||||
|
model.value.column = '';
|
||||||
|
model.value.values = [];
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,118 @@
|
||||||
|
export function getDefaultSchema() {
|
||||||
|
return {
|
||||||
|
namespace: "default",
|
||||||
|
module_name: '',
|
||||||
|
table_name: '',
|
||||||
|
enable: 1,
|
||||||
|
column: '',
|
||||||
|
label: '',
|
||||||
|
type: "string",
|
||||||
|
format: 'string',
|
||||||
|
native: 0,
|
||||||
|
is_primary_key: 0,
|
||||||
|
expression: "",
|
||||||
|
scenarios: ["create", "update", "view"],
|
||||||
|
rule: {
|
||||||
|
min: 0,
|
||||||
|
max: 0,
|
||||||
|
type: "",
|
||||||
|
unique: true,
|
||||||
|
required: [],
|
||||||
|
regular: ""
|
||||||
|
},
|
||||||
|
attribute: {
|
||||||
|
match: "fuzzy",
|
||||||
|
primary_key: true,
|
||||||
|
default_value: "",
|
||||||
|
readonly: [],
|
||||||
|
disable: [],
|
||||||
|
visible: [],
|
||||||
|
values: [],
|
||||||
|
live: {
|
||||||
|
enable: false,
|
||||||
|
type: "",
|
||||||
|
url: "",
|
||||||
|
method: "",
|
||||||
|
body: "",
|
||||||
|
content_type: "",
|
||||||
|
columns: []
|
||||||
|
},
|
||||||
|
icon: "",
|
||||||
|
sort: false,
|
||||||
|
suffix: "",
|
||||||
|
tooltip: "",
|
||||||
|
description: ""
|
||||||
|
},
|
||||||
|
position: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSupportedElements() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'string',
|
||||||
|
icon: 'input',
|
||||||
|
label: '文本'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'integer',
|
||||||
|
icon: 'number-input',
|
||||||
|
label: '数字'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'password',
|
||||||
|
icon: 'miyue',
|
||||||
|
label: '密码'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'textarea',
|
||||||
|
icon: 'textarea',
|
||||||
|
label: '多行文本'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'boolean',
|
||||||
|
icon: 'boolean',
|
||||||
|
label: '是否'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
icon: 'timer',
|
||||||
|
label: '时间'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'date',
|
||||||
|
icon: 'date',
|
||||||
|
label: '日期'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'datetime',
|
||||||
|
icon: 'datetime',
|
||||||
|
label: '时间日期'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'dropdown',
|
||||||
|
icon: 'dropdown',
|
||||||
|
label: '单项选择'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'multiSelect',
|
||||||
|
icon: 'select',
|
||||||
|
label: '多项选择'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTypeFromFormat(format) {
|
||||||
|
if (['boolean', 'number'].indexOf(format) > -1) {
|
||||||
|
return 'integer'
|
||||||
|
} else {
|
||||||
|
return 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function grantElementSchema(e) {
|
||||||
|
let schema = getDefaultSchema();
|
||||||
|
schema.format = e.name
|
||||||
|
schema.type = getTypeFromFormat(e.name)
|
||||||
|
return schema
|
||||||
|
}
|
|
@ -15,13 +15,18 @@ export default defineConfig({
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
port: 18081,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
allowedHosts: ['dev-local.tryfly.eu.org'],
|
||||||
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'release',
|
outDir: 'release',
|
||||||
assetsDir: 'static',
|
assetsDir: 'static',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks(id) {
|
manualChunks(id) {
|
||||||
return 'notebook'
|
return 'moto'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue