mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	初步实现安装界面
This commit is contained in:
		
							
								
								
									
										1
									
								
								build/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								build/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					edge-api/
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
rpc:
 | 
					rpc:
 | 
				
			||||||
  endpoints: [ "http://127.0.0.1:8003" ]
 | 
					  endpoints: [ "http://127.0.0.1:8003" ]
 | 
				
			||||||
  nodeId: ""
 | 
					nodeId: ""
 | 
				
			||||||
  secret: ""
 | 
					secret: ""
 | 
				
			||||||
@@ -7,8 +7,11 @@ import (
 | 
				
			|||||||
	"github.com/iwind/TeaGo"
 | 
						"github.com/iwind/TeaGo"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
						_ "github.com/iwind/TeaGo/bootstrap"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/logs"
 | 
				
			||||||
	"github.com/iwind/TeaGo/rands"
 | 
						"github.com/iwind/TeaGo/rands"
 | 
				
			||||||
	"github.com/iwind/TeaGo/sessions"
 | 
						"github.com/iwind/TeaGo/sessions"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
@@ -26,6 +29,16 @@ func main() {
 | 
				
			|||||||
			secret = "8f983f4d69b83aaa0d74b21a212f6967"
 | 
								secret = "8f983f4d69b83aaa0d74b21a212f6967"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 启动API节点
 | 
				
			||||||
 | 
							_, err := os.Stat(Tea.Root + "/edge-api/configs/api.yaml")
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								logs.Println("start edge-api")
 | 
				
			||||||
 | 
								err = exec.Command(Tea.Root + "/edge-api/bin/edge-api").Start()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									logs.Println("[ERROR]start edge-api failed: " + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		server := TeaGo.NewServer(false).
 | 
							server := TeaGo.NewServer(false).
 | 
				
			||||||
			AccessLog(false).
 | 
								AccessLog(false).
 | 
				
			||||||
			EndAll().
 | 
								EndAll().
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,15 +6,10 @@ replace github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
 | 
						github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
 | 
				
			||||||
	github.com/go-redis/redis v6.15.8+incompatible // indirect
 | 
						github.com/go-sql-driver/mysql v1.5.0
 | 
				
			||||||
	github.com/go-yaml/yaml v2.1.0+incompatible
 | 
						github.com/go-yaml/yaml v2.1.0+incompatible
 | 
				
			||||||
	github.com/golang/protobuf v1.4.2 // indirect
 | 
						github.com/iwind/TeaGo v0.0.0-20201010005321-430e836dee8a
 | 
				
			||||||
	github.com/iwind/TeaGo v0.0.0-20200924024009-d088df3778a6
 | 
						golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c // indirect
 | 
				
			||||||
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 | 
					 | 
				
			||||||
	github.com/modern-go/reflect2 v1.0.1 // indirect
 | 
					 | 
				
			||||||
	github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect
 | 
					 | 
				
			||||||
	golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa
 | 
					 | 
				
			||||||
	google.golang.org/grpc v1.32.0
 | 
						google.golang.org/grpc v1.32.0
 | 
				
			||||||
	google.golang.org/protobuf v1.25.0 // indirect
 | 
					 | 
				
			||||||
	gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
 | 
						gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								go.sum
									
									
									
									
									
								
							@@ -3,7 +3,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
 | 
				
			|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
					github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
				
			||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
					github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 | 
				
			||||||
github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 | 
					github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
 | 
				
			||||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 | 
					 | 
				
			||||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 | 
					github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 | 
				
			||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 | 
					github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 | 
				
			||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 | 
					github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 | 
				
			||||||
@@ -20,8 +19,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 | 
				
			|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
					github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 | 
					github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 | 
				
			||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
					github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
				
			||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
 | 
					 | 
				
			||||||
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 | 
					 | 
				
			||||||
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
 | 
					github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
 | 
				
			||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 | 
					github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 | 
				
			||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 | 
					github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 | 
				
			||||||
@@ -49,23 +46,12 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 | 
				
			|||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
					github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 | 
				
			||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
					github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
				
			||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
					github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200723131229-30dff10543ad h1:EVwLRNPYoCNCinN/J9FylGBpKdCilvzUFykKtQABfNA=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200723131229-30dff10543ad/go.mod h1:zjM7k+b+Jthhf0T0fKwuF0iy4TWb5SsU1gmKR2l+OmE=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200816132655-f784df8e9c42 h1:X58QYxjoTstHR4sQEwx4ChAFRYtlWAfqwimQ3d2osT0=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200816132655-f784df8e9c42/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200822074248-b1cf7248c98a h1:VaWcMNOzHHT1y8MeTA2fWhG6GEfAdy6CwF2tW+KiY5Y=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200822074248-b1cf7248c98a/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200909062051-96811444bb22 h1:bCv4Emo49CZyZFbnq9lWNr8nYM1yrfhjuaM7KJEc0jk=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200909062051-96811444bb22/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200910072805-729cffe36729 h1:/v0WhSFVeNay/dA5zU9iCBXlgVDfxnztuanlauXE0gM=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200910072805-729cffe36729/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200923021120-f5d76441fe9e h1:/xn7wUvlwaoA5IkdBUctv2OQbJSZ0/Dw8qRJmn55sJk=
 | 
					github.com/iwind/TeaGo v0.0.0-20200923021120-f5d76441fe9e h1:/xn7wUvlwaoA5IkdBUctv2OQbJSZ0/Dw8qRJmn55sJk=
 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200923021120-f5d76441fe9e/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					github.com/iwind/TeaGo v0.0.0-20200923021120-f5d76441fe9e/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200924024009-d088df3778a6 h1:7OZC/Qy7Z/hK9vG6YQOwHNOUPunSImYYJMiIfvuDQZ0=
 | 
					github.com/iwind/TeaGo v0.0.0-20201010005321-430e836dee8a h1:sO6uDbQOEe6/tIB3o31vn6eD/JmkKGErKgcOA/Cpb+Q=
 | 
				
			||||||
github.com/iwind/TeaGo v0.0.0-20200924024009-d088df3778a6/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
					github.com/iwind/TeaGo v0.0.0-20201010005321-430e836dee8a/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
 | 
				
			||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 | 
					github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 | 
				
			||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
					github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
				
			||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
					 | 
				
			||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
					github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 | 
				
			||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
					github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
				
			||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
					github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
				
			||||||
@@ -89,14 +75,9 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
 | 
				
			|||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 | 
					github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 | 
				
			||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 | 
					github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 | 
				
			||||||
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 | 
					github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 | 
				
			||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
					 | 
				
			||||||
github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
 | 
					 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
					github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
					github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
				
			||||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
 | 
					 | 
				
			||||||
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
 | 
					 | 
				
			||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 | 
					github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 | 
				
			||||||
github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 | 
					 | 
				
			||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
				
			||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
					github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
				
			||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 | 
					github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 | 
				
			||||||
@@ -104,7 +85,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 | 
				
			|||||||
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
 | 
					go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					 | 
				
			||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
					golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
					golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 | 
					golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
 | 
				
			||||||
@@ -145,6 +125,8 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
 | 
					golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
					golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
					golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// API配置
 | 
				
			||||||
type APIConfig struct {
 | 
					type APIConfig struct {
 | 
				
			||||||
	RPC struct {
 | 
						RPC struct {
 | 
				
			||||||
		Endpoints []string `yaml:"endpoints"`
 | 
							Endpoints []string `yaml:"endpoints"`
 | 
				
			||||||
@@ -14,6 +15,7 @@ type APIConfig struct {
 | 
				
			|||||||
	Secret string `yaml:"secret"`
 | 
						Secret string `yaml:"secret"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 加载API配置
 | 
				
			||||||
func LoadAPIConfig() (*APIConfig, error) {
 | 
					func LoadAPIConfig() (*APIConfig, error) {
 | 
				
			||||||
	data, err := ioutil.ReadFile(Tea.ConfigFile("api.yaml"))
 | 
						data, err := ioutil.ReadFile(Tea.ConfigFile("api.yaml"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -28,3 +30,12 @@ func LoadAPIConfig() (*APIConfig, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return config, nil
 | 
						return config, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 写入API配置
 | 
				
			||||||
 | 
					func (this *APIConfig) WriteFile(path string) error {
 | 
				
			||||||
 | 
						data, err := yaml.Marshal(this)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ioutil.WriteFile(path, data, 0666)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -175,7 +175,7 @@ func (this *RPCClient) SysSettingRPC() pb.SysSettingServiceClient {
 | 
				
			|||||||
	return pb.NewSysSettingServiceClient(this.pickConn())
 | 
						return pb.NewSysSettingServiceClient(this.pickConn())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 构造上下文
 | 
					// 构造Admin上下文
 | 
				
			||||||
func (this *RPCClient) Context(adminId int64) context.Context {
 | 
					func (this *RPCClient) Context(adminId int64) context.Context {
 | 
				
			||||||
	ctx := context.Background()
 | 
						ctx := context.Background()
 | 
				
			||||||
	m := maps.Map{
 | 
						m := maps.Map{
 | 
				
			||||||
@@ -198,6 +198,29 @@ func (this *RPCClient) Context(adminId int64) context.Context {
 | 
				
			|||||||
	return ctx
 | 
						return ctx
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 构造API上下文
 | 
				
			||||||
 | 
					func (this *RPCClient) APIContext(apiNodeId int64) context.Context {
 | 
				
			||||||
 | 
						ctx := context.Background()
 | 
				
			||||||
 | 
						m := maps.Map{
 | 
				
			||||||
 | 
							"timestamp": time.Now().Unix(),
 | 
				
			||||||
 | 
							"type":      "api",
 | 
				
			||||||
 | 
							"userId":    apiNodeId,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						method, err := encrypt.NewMethodInstance(teaconst.EncryptMethod, this.apiConfig.Secret, this.apiConfig.NodeId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							utils.PrintError(err)
 | 
				
			||||||
 | 
							return context.Background()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						data, err := method.Encrypt(m.AsJSON())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							utils.PrintError(err)
 | 
				
			||||||
 | 
							return context.Background()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						token := base64.StdEncoding.EncodeToString(data)
 | 
				
			||||||
 | 
						ctx = metadata.AppendToOutgoingContext(ctx, "nodeId", this.apiConfig.NodeId, "token", token)
 | 
				
			||||||
 | 
						return ctx
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 随机选择一个连接
 | 
					// 随机选择一个连接
 | 
				
			||||||
func (this *RPCClient) pickConn() *grpc.ClientConn {
 | 
					func (this *RPCClient) pickConn() *grpc.ClientConn {
 | 
				
			||||||
	if len(this.conns) == 0 {
 | 
						if len(this.conns) == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								internal/setup/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								internal/setup/utils.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var isConfigured bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 判断系统是否已经配置过
 | 
				
			||||||
 | 
					func IsConfigured() bool {
 | 
				
			||||||
 | 
						if isConfigured {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := configs.LoadAPIConfig()
 | 
				
			||||||
 | 
						isConfigured = err == nil
 | 
				
			||||||
 | 
						return isConfigured
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,10 +4,11 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/setup"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
	"github.com/iwind/TeaGo/actions"
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
	stringutil "github.com/iwind/TeaGo/utils/string"
 | 
						stringutil "github.com/iwind/TeaGo/utils/string"
 | 
				
			||||||
@@ -25,6 +26,12 @@ func (this *IndexAction) RunGet(params struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	Auth *helpers.UserShouldAuth
 | 
						Auth *helpers.UserShouldAuth
 | 
				
			||||||
}) {
 | 
					}) {
 | 
				
			||||||
 | 
						// 检查系统是否已经配置过
 | 
				
			||||||
 | 
						if !setup.IsConfigured() {
 | 
				
			||||||
 | 
							this.RedirectURL("/setup")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 已登录跳转到dashboard
 | 
						// 已登录跳转到dashboard
 | 
				
			||||||
	if params.Auth.IsUser() {
 | 
						if params.Auth.IsUser() {
 | 
				
			||||||
		this.RedirectURL("/dashboard")
 | 
							this.RedirectURL("/dashboard")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,16 +41,15 @@ func (this *IndexAction) RunGet(params struct{}) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if config.DBs == nil {
 | 
						if config.DBs == nil {
 | 
				
			||||||
		this.Data["error"] = "can not find valid database config: api_db.yaml"
 | 
							this.Data["error"] = "no database configured in config file: api_db.yaml"
 | 
				
			||||||
		this.Show()
 | 
							this.Show()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbConfig, ok := config.DBs[config.Default.DB]
 | 
						var dbConfig *dbs.DBConfig
 | 
				
			||||||
	if !ok {
 | 
						for _, db := range config.DBs {
 | 
				
			||||||
		this.Data["error"] = "can not find valid database config: api_db.yaml"
 | 
							dbConfig = db
 | 
				
			||||||
		this.Show()
 | 
							break
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	dsn := dbConfig.Dsn
 | 
						dsn := dbConfig.Dsn
 | 
				
			||||||
	dsn = regexp.MustCompile(`tcp\((.+)\)`).ReplaceAllString(dsn, "$1")
 | 
						dsn = regexp.MustCompile(`tcp\((.+)\)`).ReplaceAllString(dsn, "$1")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,11 +50,12 @@ func (this *UpdateAction) RunGet(params struct{}) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbConfig, ok := config.DBs[config.Default.DB]
 | 
						var dbConfig *dbs.DBConfig
 | 
				
			||||||
	if !ok {
 | 
						for _, db := range config.DBs {
 | 
				
			||||||
		this.Show()
 | 
							dbConfig = db
 | 
				
			||||||
		return
 | 
							break
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	dsn := dbConfig.Dsn
 | 
						dsn := dbConfig.Dsn
 | 
				
			||||||
	dsn = regexp.MustCompile(`tcp\((.+)\)`).ReplaceAllString(dsn, "$1")
 | 
						dsn = regexp.MustCompile(`tcp\((.+)\)`).ReplaceAllString(dsn, "$1")
 | 
				
			||||||
	dsnURL, err := url.Parse("mysql://" + dsn)
 | 
						dsnURL, err := url.Parse("mysql://" + dsn)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								internal/web/actions/default/setup/helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								internal/web/actions/default/setup/helper.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/setup"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Helper struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
 | 
				
			||||||
 | 
						if setup.IsConfigured() {
 | 
				
			||||||
 | 
							actionPtr.Object().RedirectURL("/")
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								internal/web/actions/default/setup/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								internal/web/actions/default/setup/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IndexAction struct {
 | 
				
			||||||
 | 
						actionutils.ParentAction
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IndexAction) Init() {
 | 
				
			||||||
 | 
						this.Nav("", "", "")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *IndexAction) RunGet(params struct{}) {
 | 
				
			||||||
 | 
						// 当前服务器的IP
 | 
				
			||||||
 | 
						serverIPs := []string{}
 | 
				
			||||||
 | 
						addrs, _ := net.InterfaceAddrs()
 | 
				
			||||||
 | 
						for _, addr := range addrs {
 | 
				
			||||||
 | 
							netAddr, ok := addr.(*net.IPNet)
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							serverIPs = append(serverIPs, netAddr.IP.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 对IP进行排序,我们希望IPv4排在前面,而且希望127.0.0.1排在IPv4里的最后
 | 
				
			||||||
 | 
						sort.Slice(serverIPs, func(i, j int) bool {
 | 
				
			||||||
 | 
							ip1 := serverIPs[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ip1 == "127.0.0.1" {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if regexp.MustCompile(`^\d+\.\d+\.\d+.\d+$`).MatchString(ip1) {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						this.Data["serverIPs"] = serverIPs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Show()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								internal/web/actions/default/setup/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								internal/web/actions/default/setup/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/iwind/TeaGo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
				
			||||||
 | 
							server.
 | 
				
			||||||
 | 
								Helper(new(Helper)).
 | 
				
			||||||
 | 
								Prefix("/setup").
 | 
				
			||||||
 | 
								Get("", new(IndexAction)).
 | 
				
			||||||
 | 
								Post("/validateApi", new(ValidateApiAction)).
 | 
				
			||||||
 | 
								Post("/validateDb", new(ValidateDbAction)).
 | 
				
			||||||
 | 
								Post("/validateAdmin", new(ValidateAdminAction)).
 | 
				
			||||||
 | 
								Post("/install", new(InstallAction)).
 | 
				
			||||||
 | 
								EndAll()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										203
									
								
								internal/web/actions/default/setup/install.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								internal/web/actions/default/setup/install.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
 | 
						"github.com/go-yaml/yaml"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type InstallAction struct {
 | 
				
			||||||
 | 
						actionutils.ParentAction
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *InstallAction) RunPost(params struct {
 | 
				
			||||||
 | 
						ApiNodeJSON []byte
 | 
				
			||||||
 | 
						DbJSON      []byte
 | 
				
			||||||
 | 
						AdminJSON   []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Must *actions.Must
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
						// API节点配置
 | 
				
			||||||
 | 
						apiNodeMap := maps.Map{}
 | 
				
			||||||
 | 
						err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.Fail("API节点配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 数据库
 | 
				
			||||||
 | 
						dbMap := maps.Map{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(params.DbJSON, &dbMap)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 管理员
 | 
				
			||||||
 | 
						adminMap := maps.Map{}
 | 
				
			||||||
 | 
						err = json.Unmarshal(params.AdminJSON, &adminMap)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 安装API节点
 | 
				
			||||||
 | 
						mode := apiNodeMap.GetString("mode")
 | 
				
			||||||
 | 
						if mode == "new" {
 | 
				
			||||||
 | 
							// 整个系统目录结构为:
 | 
				
			||||||
 | 
							//  edge-admin/
 | 
				
			||||||
 | 
							//    edge-api/
 | 
				
			||||||
 | 
							//    bin/
 | 
				
			||||||
 | 
							//    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 检查环境
 | 
				
			||||||
 | 
							apiNodeDir := Tea.Root + "/edge-api"
 | 
				
			||||||
 | 
							for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} {
 | 
				
			||||||
 | 
								apiNodeDir := Tea.Root + "/" + dir
 | 
				
			||||||
 | 
								_, err = os.Stat(apiNodeDir)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if os.IsNotExist(err) {
 | 
				
			||||||
 | 
										this.Fail("在当前目录下找不到" + dir + "目录,请将" + dir + "目录上传或者重新下载解压")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									this.Fail("无法检查" + dir + "目录,发生错误:" + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 保存数据库配置
 | 
				
			||||||
 | 
							dsn := dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + dbMap.GetString("host") + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
 | 
				
			||||||
 | 
							dbConfig := &dbs.Config{
 | 
				
			||||||
 | 
								DBs: map[string]*dbs.DBConfig{
 | 
				
			||||||
 | 
									"prod": {
 | 
				
			||||||
 | 
										Driver: "mysql",
 | 
				
			||||||
 | 
										Dsn:    dsn,
 | 
				
			||||||
 | 
										Prefix: "edge",
 | 
				
			||||||
 | 
									}},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dbConfigData, err := yaml.Marshal(dbConfig)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("生成数据库配置失败:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = ioutil.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("保存数据库配置失败:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = ioutil.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("保存数据库配置失败:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 开始安装
 | 
				
			||||||
 | 
							var resultMap = maps.Map{}
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								cmd := exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
 | 
				
			||||||
 | 
								output := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
								cmd.Stdout = output
 | 
				
			||||||
 | 
								err = cmd.Run()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									this.Fail("安装失败:" + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								resultData := output.Bytes()
 | 
				
			||||||
 | 
								err = json.Unmarshal(resultData, &resultMap)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !resultMap.GetBool("isOk") {
 | 
				
			||||||
 | 
									this.Fail("节点安装错误:" + resultMap.GetString("error"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 启动API节点
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								cmd := exec.Command(apiNodeDir + "/bin/edge-api")
 | 
				
			||||||
 | 
								err = cmd.Start()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									this.Fail("API节点启动失败:" + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 写入API节点配置,完成安装
 | 
				
			||||||
 | 
							apiConfig := &configs.APIConfig{
 | 
				
			||||||
 | 
								RPC: struct {
 | 
				
			||||||
 | 
									Endpoints []string `yaml:"endpoints"`
 | 
				
			||||||
 | 
								}{
 | 
				
			||||||
 | 
									Endpoints: []string{"http://" + apiNodeMap.GetString("newHost") + ":" + apiNodeMap.GetString("newPort")},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								NodeId: resultMap.GetString("adminNodeId"),
 | 
				
			||||||
 | 
								Secret: resultMap.GetString("adminNodeSecret"),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 设置管理员
 | 
				
			||||||
 | 
							client, err := rpc.NewRPCClient(apiConfig)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.FailField("oldHost", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctx := client.Context(0)
 | 
				
			||||||
 | 
							for i := 0; i < 3; i++ {
 | 
				
			||||||
 | 
								_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
 | 
				
			||||||
 | 
									Username: adminMap.GetString("username"),
 | 
				
			||||||
 | 
									Password: adminMap.GetString("password"),
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
								// 这里我们尝试多次是为了当代API节点启动完毕
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									time.Sleep(1 * time.Second)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("设置管理员账号出错:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("保存配置失败,原因:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.Success()
 | 
				
			||||||
 | 
						} else if mode == "old" {
 | 
				
			||||||
 | 
							// 构造RPC
 | 
				
			||||||
 | 
							apiConfig := &configs.APIConfig{
 | 
				
			||||||
 | 
								RPC: struct {
 | 
				
			||||||
 | 
									Endpoints []string `yaml:"endpoints"`
 | 
				
			||||||
 | 
								}{
 | 
				
			||||||
 | 
									Endpoints: []string{apiNodeMap.GetString("oldProtocol") + "://" + apiNodeMap.GetString("oldHost") + ":" + apiNodeMap.GetString("oldPort")},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								NodeId: apiNodeMap.GetString("oldNodeId"),
 | 
				
			||||||
 | 
								Secret: apiNodeMap.GetString("oldNodeSecret"),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							client, err := rpc.NewRPCClient(apiConfig)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.FailField("oldHost", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 设置管理员
 | 
				
			||||||
 | 
							ctx := client.APIContext(0)
 | 
				
			||||||
 | 
							_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
 | 
				
			||||||
 | 
								Username: adminMap.GetString("username"),
 | 
				
			||||||
 | 
								Password: adminMap.GetString("password"),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("设置管理员账号出错:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 写入API节点配置,完成安装
 | 
				
			||||||
 | 
							err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								this.Fail("保存配置失败,原因:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 成功
 | 
				
			||||||
 | 
							this.Success()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							this.Fail("错误的API节点模式:'" + mode + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								internal/web/actions/default/setup/validateAdmin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								internal/web/actions/default/setup/validateAdmin.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ValidateAdminAction struct {
 | 
				
			||||||
 | 
						actionutils.ParentAction
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ValidateAdminAction) RunPost(params struct {
 | 
				
			||||||
 | 
						AdminUsername  string
 | 
				
			||||||
 | 
						AdminPassword  string
 | 
				
			||||||
 | 
						AdminPassword2 string
 | 
				
			||||||
 | 
						Must           *actions.Must
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
						params.Must.
 | 
				
			||||||
 | 
							Field("adminUsername", params.AdminUsername).
 | 
				
			||||||
 | 
							Require("请输入登录用户名").
 | 
				
			||||||
 | 
							Match(`^[a-zA-Z0-9_]+$`, "用户名中只能包含英文、数字或下划线").
 | 
				
			||||||
 | 
							Field("adminPassword", params.AdminPassword).
 | 
				
			||||||
 | 
							Require("请输入登录密码").
 | 
				
			||||||
 | 
							Match(`^[a-zA-Z0-9_]+$`, "密码中只能包含英文、数字或下划线").
 | 
				
			||||||
 | 
							Field("adminPassword2", params.AdminPassword2).
 | 
				
			||||||
 | 
							Require("请输入确认密码").
 | 
				
			||||||
 | 
							Equal(params.AdminPassword, "两次输入的密码不一致")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Data["admin"] = maps.Map{
 | 
				
			||||||
 | 
							"username":     params.AdminUsername,
 | 
				
			||||||
 | 
							"password":     params.AdminPassword,
 | 
				
			||||||
 | 
							"passwordMask": strings.Repeat("*", len(params.AdminPassword)),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										105
									
								
								internal/web/actions/default/setup/validateApi.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								internal/web/actions/default/setup/validateApi.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/configs"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ValidateApiAction struct {
 | 
				
			||||||
 | 
						actionutils.ParentAction
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ValidateApiAction) RunPost(params struct {
 | 
				
			||||||
 | 
						Mode          string
 | 
				
			||||||
 | 
						NewPort       string
 | 
				
			||||||
 | 
						NewHost       string
 | 
				
			||||||
 | 
						OldProtocol   string
 | 
				
			||||||
 | 
						OldHost       string
 | 
				
			||||||
 | 
						OldPort       string
 | 
				
			||||||
 | 
						OldNodeId     string
 | 
				
			||||||
 | 
						OldNodeSecret string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Must *actions.Must
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
						params.OldNodeId = strings.Trim(params.OldNodeId, "\"' ")
 | 
				
			||||||
 | 
						params.OldNodeSecret = strings.Trim(params.OldNodeSecret, "\"' ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Data["apiNode"] = maps.Map{
 | 
				
			||||||
 | 
							"mode": params.Mode,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							"newPort": params.NewPort,
 | 
				
			||||||
 | 
							"newHost": params.NewHost,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							"oldProtocol":   params.OldProtocol,
 | 
				
			||||||
 | 
							"oldHost":       params.OldHost,
 | 
				
			||||||
 | 
							"oldPort":       params.OldPort,
 | 
				
			||||||
 | 
							"oldNodeId":     params.OldNodeId,
 | 
				
			||||||
 | 
							"oldNodeSecret": params.OldNodeSecret,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if params.Mode == "new" {
 | 
				
			||||||
 | 
							params.Must.
 | 
				
			||||||
 | 
								Field("newPort", params.NewPort).
 | 
				
			||||||
 | 
								Require("请输入节点端口").
 | 
				
			||||||
 | 
								Match(`^\d+$`, "节点端口只能是数字").
 | 
				
			||||||
 | 
								MinLength(4, "请输入4位以上的数字").
 | 
				
			||||||
 | 
								MaxLength(5, "请输入5位以下的数字")
 | 
				
			||||||
 | 
							newPort := types.Int(params.NewPort)
 | 
				
			||||||
 | 
							if newPort < 1024 {
 | 
				
			||||||
 | 
								this.FailField("newPort", "端口号不能小于1024")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if newPort > 65534 {
 | 
				
			||||||
 | 
								this.FailField("newPort", "端口号不能大于65534")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							conn, err := net.Dial("tcp", "127.0.0.1:"+params.NewPort)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								_ = conn.Close()
 | 
				
			||||||
 | 
								this.FailField("newPort", "此端口已经被别的服务占用,请换一个")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							params.Must.
 | 
				
			||||||
 | 
								Field("newHost", params.NewHost).
 | 
				
			||||||
 | 
								Require("请输入节点主机地址")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.Success()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 使用已有的API节点
 | 
				
			||||||
 | 
						params.Must.
 | 
				
			||||||
 | 
							Field("oldHost", params.OldHost).
 | 
				
			||||||
 | 
							Require("请输入主机地址").
 | 
				
			||||||
 | 
							Field("oldPort", params.OldPort).
 | 
				
			||||||
 | 
							Require("请输入服务端口").
 | 
				
			||||||
 | 
							Match(`^\d+$`, "服务端口只能是数字").
 | 
				
			||||||
 | 
							Field("oldNodeId", params.OldNodeId).
 | 
				
			||||||
 | 
							Require("请输入节点nodeId").
 | 
				
			||||||
 | 
							Field("oldNodeSecret", params.OldNodeSecret).
 | 
				
			||||||
 | 
							Require("请输入节点secret")
 | 
				
			||||||
 | 
						client, err := rpc.NewRPCClient(&configs.APIConfig{
 | 
				
			||||||
 | 
							RPC: struct {
 | 
				
			||||||
 | 
								Endpoints []string `yaml:"endpoints"`
 | 
				
			||||||
 | 
							}{
 | 
				
			||||||
 | 
								Endpoints: []string{params.OldProtocol + "://" + params.OldHost + ":" + params.OldPort},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							NodeId: params.OldNodeId,
 | 
				
			||||||
 | 
							Secret: params.OldNodeSecret,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.FailField("oldHost", "测试API节点时出错,请检查配置,错误信息:"+err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err = client.APINodeRPC().FindCurrentAPINodeVersion(client.APIContext(0), &pb.FindCurrentAPINodeVersionRequest{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.FailField("oldHost", "无法连接此API节点,错误信息:"+err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										78
									
								
								internal/web/actions/default/setup/validateDb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								internal/web/actions/default/setup/validateDb.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					package setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ValidateDbAction struct {
 | 
				
			||||||
 | 
						actionutils.ParentAction
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ValidateDbAction) RunPost(params struct {
 | 
				
			||||||
 | 
						Host     string
 | 
				
			||||||
 | 
						Port     string
 | 
				
			||||||
 | 
						Database string
 | 
				
			||||||
 | 
						Username string
 | 
				
			||||||
 | 
						Password string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Must *actions.Must
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
						params.Must.
 | 
				
			||||||
 | 
							Field("host", params.Host).
 | 
				
			||||||
 | 
							Require("请输入主机地址").
 | 
				
			||||||
 | 
							Match(`^[\w\.-]+$`, "主机地址中不能包含特殊字符").
 | 
				
			||||||
 | 
							Field("port", params.Port).
 | 
				
			||||||
 | 
							Require("请输入端口").
 | 
				
			||||||
 | 
							Match(`^\d+$`, "端口中只能包含数字").
 | 
				
			||||||
 | 
							Field("database", params.Database).
 | 
				
			||||||
 | 
							Require("请输入数据库名称").
 | 
				
			||||||
 | 
							Match(`^[\w\.-]+$`, "数据库名称中不能包含特殊字符").
 | 
				
			||||||
 | 
							Field("username", params.Username).
 | 
				
			||||||
 | 
							Require("请输入连接数据库的用户名").
 | 
				
			||||||
 | 
							Match(`^[\w\.-]+$`, "用户名中不能包含特殊字符")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 测试连接
 | 
				
			||||||
 | 
						db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
 | 
				
			||||||
 | 
							Driver: "mysql",
 | 
				
			||||||
 | 
							Dsn:    params.Username + ":" + params.Password + "@tcp(" + params.Host + ":" + params.Port + ")/" + params.Database,
 | 
				
			||||||
 | 
							Prefix: "",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							this.Fail("数据库信息错误:" + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = db.Raw().Ping()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// 是否是数据库不存在
 | 
				
			||||||
 | 
							if strings.Contains(err.Error(), "Error 1049") {
 | 
				
			||||||
 | 
								db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
 | 
				
			||||||
 | 
									Driver: "mysql",
 | 
				
			||||||
 | 
									Dsn:    params.Username + ":" + params.Password + "@tcp(" + params.Host + ":" + params.Port + ")/",
 | 
				
			||||||
 | 
									Prefix: "",
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_, err = db.Exec("CREATE DATABASE `" + params.Database + "`")
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									this.Fail("尝试创建数据库失败:" + err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								this.Fail("无法连接到数据库,请检查配置:" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Data["db"] = maps.Map{
 | 
				
			||||||
 | 
							"host":         params.Host,
 | 
				
			||||||
 | 
							"port":         params.Port,
 | 
				
			||||||
 | 
							"database":     params.Database,
 | 
				
			||||||
 | 
							"username":     params.Username,
 | 
				
			||||||
 | 
							"password":     params.Password,
 | 
				
			||||||
 | 
							"passwordMask": strings.Repeat("*", len(params.Password)),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.Success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package ui
 | 
					package ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"compress/gzip"
 | 
				
			||||||
	"github.com/iwind/TeaGo"
 | 
						"github.com/iwind/TeaGo"
 | 
				
			||||||
	"github.com/iwind/TeaGo/actions"
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -12,7 +13,7 @@ func init() {
 | 
				
			|||||||
			Get("/download", new(DownloadAction)).
 | 
								Get("/download", new(DownloadAction)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 以下的需要压缩
 | 
								// 以下的需要压缩
 | 
				
			||||||
			Helper(new(actions.Gzip)).
 | 
								Helper(&actions.Gzip{Level: gzip.BestCompression}).
 | 
				
			||||||
			Get("/components.js", new(ComponentsAction)).
 | 
								Get("/components.js", new(ComponentsAction)).
 | 
				
			||||||
			EndAll()
 | 
								EndAll()
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package helpers
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
						teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
				
			||||||
	nodes "github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
						nodes "github.com/TeaOSLab/EdgeAdmin/internal/rpc"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/setup"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
						"github.com/TeaOSLab/EdgeAdmin/internal/utils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
	"github.com/iwind/TeaGo/actions"
 | 
						"github.com/iwind/TeaGo/actions"
 | 
				
			||||||
@@ -23,6 +24,12 @@ func NewUserMustAuth() *UserMustAuth {
 | 
				
			|||||||
func (this *UserMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramName string) (goNext bool) {
 | 
					func (this *UserMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramName string) (goNext bool) {
 | 
				
			||||||
	var action = actionPtr.Object()
 | 
						var action = actionPtr.Object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 检查系统是否已经配置过
 | 
				
			||||||
 | 
						if !setup.IsConfigured() {
 | 
				
			||||||
 | 
							action.RedirectURL("/setup")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var session = action.Session()
 | 
						var session = action.Session()
 | 
				
			||||||
	var adminId = session.GetInt("adminId")
 | 
						var adminId = session.GetInt("adminId")
 | 
				
			||||||
	if adminId <= 0 {
 | 
						if adminId <= 0 {
 | 
				
			||||||
@@ -33,6 +40,7 @@ func (this *UserMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
 | 
				
			|||||||
	// 检查用户是否存在
 | 
						// 检查用户是否存在
 | 
				
			||||||
	rpc, err := nodes.SharedRPC()
 | 
						rpc, err := nodes.SharedRPC()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							action.WriteString("setup rpc error: " + err.Error())
 | 
				
			||||||
		utils.PrintError(err)
 | 
							utils.PrintError(err)
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -40,7 +48,7 @@ func (this *UserMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
 | 
				
			|||||||
	rpcResp, err := rpc.AdminRPC().CheckAdminExists(rpc.Context(0), &pb.CheckAdminExistsRequest{AdminId: int64(adminId)})
 | 
						rpcResp, err := rpc.AdminRPC().CheckAdminExists(rpc.Context(0), &pb.CheckAdminExistsRequest{AdminId: int64(adminId)})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		utils.PrintError(err)
 | 
							utils.PrintError(err)
 | 
				
			||||||
		actionPtr.Object().WriteString(teaconst.ErrServer)
 | 
							action.WriteString(teaconst.ErrServer)
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,5 +71,6 @@ import (
 | 
				
			|||||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/profile"
 | 
						_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/profile"
 | 
				
			||||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/security"
 | 
						_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/security"
 | 
				
			||||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
 | 
						_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
 | 
				
			||||||
 | 
						_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/setup"
 | 
				
			||||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ui"
 | 
						_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ui"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,8 +138,8 @@ window.teaweb = {
 | 
				
			|||||||
		if (message.length > 30) {
 | 
							if (message.length > 30) {
 | 
				
			||||||
			width = "30em";
 | 
								width = "30em";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		Swal.fire({
 | 
					
 | 
				
			||||||
			text: message,
 | 
							let config = {
 | 
				
			||||||
			confirmButtonText: "确定",
 | 
								confirmButtonText: "确定",
 | 
				
			||||||
			buttonsStyling: false,
 | 
								buttonsStyling: false,
 | 
				
			||||||
			icon: "success",
 | 
								icon: "success",
 | 
				
			||||||
@@ -154,9 +154,19 @@ window.teaweb = {
 | 
				
			|||||||
					setTimeout(function () {
 | 
										setTimeout(function () {
 | 
				
			||||||
						callback();
 | 
											callback();
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
									} else if (typeof (callback) == "string") {
 | 
				
			||||||
 | 
										window.location = callback
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (message.startsWith("html:")) {
 | 
				
			||||||
 | 
								config.html = message.substring(5)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								config.text = message
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Swal.fire(config);
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	successToast: function (message, timeout) {
 | 
						successToast: function (message, timeout) {
 | 
				
			||||||
		if (timeout == null) {
 | 
							if (timeout == null) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,7 +130,7 @@ p.comment,
 | 
				
			|||||||
div.comment {
 | 
					div.comment {
 | 
				
			||||||
  color: rgba(0, 0, 0, 0.3);
 | 
					  color: rgba(0, 0, 0, 0.3);
 | 
				
			||||||
  padding-top: 0.4em;
 | 
					  padding-top: 0.4em;
 | 
				
			||||||
  font-size: 0.9em;
 | 
					  font-size: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
p.comment em,
 | 
					p.comment em,
 | 
				
			||||||
div.comment em {
 | 
					div.comment em {
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -23,7 +23,7 @@
 | 
				
			|||||||
    <!-- 顶部导航 -->
 | 
					    <!-- 顶部导航 -->
 | 
				
			||||||
    <div class="ui menu top-nav blue inverted small borderless" v-cloak="">
 | 
					    <div class="ui menu top-nav blue inverted small borderless" v-cloak="">
 | 
				
			||||||
        <a href="/" class="item">
 | 
					        <a href="/" class="item">
 | 
				
			||||||
			<i class="ui icon leaf"></i>   {{teaName}}管理员系统  
 | 
								<i class="ui icon leaf"></i>   {{teaName}}管理员系统 <sup>v{{teaVersion}}</sup>  
 | 
				
			||||||
		</a>
 | 
							</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="right menu">
 | 
					        <div class="right menu">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,7 @@ tbody {
 | 
				
			|||||||
p.comment, div.comment {
 | 
					p.comment, div.comment {
 | 
				
			||||||
	color: rgba(0, 0, 0, 0.3);
 | 
						color: rgba(0, 0, 0, 0.3);
 | 
				
			||||||
	padding-top: 0.4em;
 | 
						padding-top: 0.4em;
 | 
				
			||||||
	font-size: 0.9em;
 | 
						font-size: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
p.comment em, div.comment em {
 | 
					p.comment em, div.comment em {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@
 | 
				
			|||||||
			<td>外部访问地址 *</td>
 | 
								<td>外部访问地址 *</td>
 | 
				
			||||||
			<td>
 | 
								<td>
 | 
				
			||||||
				<api-node-addresses-box :v-name="'accessAddrsJSON'"></api-node-addresses-box>
 | 
									<api-node-addresses-box :v-name="'accessAddrsJSON'"></api-node-addresses-box>
 | 
				
			||||||
				<p class="comment">外部访问API节点的网络地址。</p>
 | 
									<p class="comment">边缘节点和管理平台等外部节点访问API节点的网络地址。</p>
 | 
				
			||||||
			</td>
 | 
								</td>
 | 
				
			||||||
		</tr>
 | 
							</tr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@
 | 
				
			|||||||
			<td>外部访问地址 *</td>
 | 
								<td>外部访问地址 *</td>
 | 
				
			||||||
			<td>
 | 
								<td>
 | 
				
			||||||
				<api-node-addresses-box :v-name="'accessAddrsJSON'" :v-addrs="node.accessAddrs"></api-node-addresses-box>
 | 
									<api-node-addresses-box :v-name="'accessAddrsJSON'" :v-addrs="node.accessAddrs"></api-node-addresses-box>
 | 
				
			||||||
				<p class="comment">外部访问API节点的网络地址。</p>
 | 
									<p class="comment">边缘节点和管理平台等外部节点访问API节点的网络地址。</p>
 | 
				
			||||||
			</td>
 | 
								</td>
 | 
				
			||||||
		</tr>
 | 
							</tr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
{$template "menu"}
 | 
					{$template "menu"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<p class="ui message error" v-if="error.length > 0">{{error}}</p>
 | 
					<p class="ui message error" v-if="error.length > 0">{{error}}</p>
 | 
				
			||||||
<div v-show="error.length == 0 && dbConfig != null">
 | 
					<div v-if="error.length == 0 && dbConfig != null">
 | 
				
			||||||
	<table class="ui table selectable definition">
 | 
						<table class="ui table selectable definition">
 | 
				
			||||||
		<tr>
 | 
							<tr>
 | 
				
			||||||
			<td class="title">主机地址</td>
 | 
								<td class="title">主机地址</td>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										0
									
								
								web/views/@default/setup/@install.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								web/views/@default/setup/@install.css
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								web/views/@default/setup/@install.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/views/@default/setup/@install.css.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					undefined
 | 
				
			||||||
							
								
								
									
										67
									
								
								web/views/@default/setup/@install.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								web/views/@default/setup/@install.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					.install-box {
 | 
				
			||||||
 | 
						@width: 50em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						width: @width;
 | 
				
			||||||
 | 
						position: fixed;
 | 
				
			||||||
 | 
						left: 50%;
 | 
				
			||||||
 | 
						margin-left: -@width/2;
 | 
				
			||||||
 | 
						top: 1em;
 | 
				
			||||||
 | 
						bottom: 1em;
 | 
				
			||||||
 | 
						overflow-y: auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.button.margin {
 | 
				
			||||||
 | 
							margin-top: 1em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.button.primary {
 | 
				
			||||||
 | 
							float: right;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						table {
 | 
				
			||||||
 | 
							td.title {
 | 
				
			||||||
 | 
								width: 10em;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.radio {
 | 
				
			||||||
 | 
							margin-right: 1em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							label {
 | 
				
			||||||
 | 
								cursor: pointer !important;
 | 
				
			||||||
 | 
								font-size: 0.9em !important;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h3 {
 | 
				
			||||||
 | 
							font-weight: normal;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.content-box {
 | 
				
			||||||
 | 
							overflow-y: auto;
 | 
				
			||||||
 | 
							position: fixed;
 | 
				
			||||||
 | 
							top: 5em;
 | 
				
			||||||
 | 
							bottom: 5em;
 | 
				
			||||||
 | 
							left: 50%;
 | 
				
			||||||
 | 
							width: @width;
 | 
				
			||||||
 | 
							padding-right: 1em;
 | 
				
			||||||
 | 
							margin-left: -@width/2;
 | 
				
			||||||
 | 
							z-index: 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.content-box::-webkit-scrollbar {
 | 
				
			||||||
 | 
							width: 4px;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.button-group {
 | 
				
			||||||
 | 
							position: fixed;
 | 
				
			||||||
 | 
							left: 50%;
 | 
				
			||||||
 | 
							margin-left: -@width/2;
 | 
				
			||||||
 | 
							z-index: 1;
 | 
				
			||||||
 | 
							width: @width;
 | 
				
			||||||
 | 
							bottom: 1em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.install-box::-webkit-scrollbar {
 | 
				
			||||||
 | 
						width: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								web/views/@default/setup/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								web/views/@default/setup/index.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					.install-box {
 | 
				
			||||||
 | 
					  width: 50em;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  margin-left: -25em;
 | 
				
			||||||
 | 
					  top: 1em;
 | 
				
			||||||
 | 
					  bottom: 1em;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .button.margin {
 | 
				
			||||||
 | 
					  margin-top: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .button.primary {
 | 
				
			||||||
 | 
					  float: right;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box table td.title {
 | 
				
			||||||
 | 
					  width: 10em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .radio {
 | 
				
			||||||
 | 
					  margin-right: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .radio label {
 | 
				
			||||||
 | 
					  cursor: pointer !important;
 | 
				
			||||||
 | 
					  font-size: 0.9em !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box h3 {
 | 
				
			||||||
 | 
					  font-weight: normal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .content-box {
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  top: 5em;
 | 
				
			||||||
 | 
					  bottom: 5em;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  width: 50em;
 | 
				
			||||||
 | 
					  padding-right: 1em;
 | 
				
			||||||
 | 
					  margin-left: -25em;
 | 
				
			||||||
 | 
					  z-index: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .content-box::-webkit-scrollbar {
 | 
				
			||||||
 | 
					  width: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box .button-group {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  margin-left: -25em;
 | 
				
			||||||
 | 
					  z-index: 1;
 | 
				
			||||||
 | 
					  width: 50em;
 | 
				
			||||||
 | 
					  bottom: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.install-box::-webkit-scrollbar {
 | 
				
			||||||
 | 
					  width: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*# sourceMappingURL=index.css.map */
 | 
				
			||||||
							
								
								
									
										1
									
								
								web/views/@default/setup/index.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/views/@default/setup/index.css.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"version":3,"sources":["@install.less"],"names":[],"mappings":"AAAA;EAGC,WAAA;EACA,eAAA;EACA,SAAA;EACA,kBAAA;EACA,QAAA;EACA,WAAA;EACA,gBAAA;;AATD,YAWC,QAAO;EACN,eAAA;;AAZF,YAeC,QAAO;EACN,YAAA;;AAhBF,YAmBC,MACC,GAAE;EACD,WAAA;;AArBH,YAyBC;EACC,iBAAA;;AA1BF,YAyBC,OAGC;EACC,0BAAA;EACA,2BAAA;;AA9BH,YAkCC;EACC,mBAAA;;AAnCF,YAsCC;EACC,gBAAA;EACA,eAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,UAAA;;AA/CF,YAkDC,aAAY;EACX,UAAA;;AAnDF,YAsDC;EACC,eAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,WAAA;;AAIF,YAAY;EACX,UAAA","file":"index.css"}
 | 
				
			||||||
							
								
								
									
										346
									
								
								web/views/@default/setup/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								web/views/@default/setup/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,346 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html lang="zh">
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
						<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 | 
				
			||||||
 | 
						<link rel="shortcut icon" href="/images/favicon.png"/>
 | 
				
			||||||
 | 
						<title>安装Edge管理系统</title>
 | 
				
			||||||
 | 
						<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
 | 
				
			||||||
 | 
						{$TEA.VUE}
 | 
				
			||||||
 | 
						{$TEA.SEMANTIC}
 | 
				
			||||||
 | 
						<script type="text/javascript" src="/js/md5.min.js"></script>
 | 
				
			||||||
 | 
						<script type="text/javascript" src="/js/utils.js"></script>
 | 
				
			||||||
 | 
						<script type="text/javascript" src="/js/sweetalert2/dist/sweetalert2.all.min.js"></script>
 | 
				
			||||||
 | 
						<script type="text/javascript" src="/ui/components.js"></script>
 | 
				
			||||||
 | 
						<link rel="stylesheet" href="/_/@default/@layout.css"/>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="install-box">
 | 
				
			||||||
 | 
						<!-- 步骤列表 -->
 | 
				
			||||||
 | 
						<div class="ui steps fluid small">
 | 
				
			||||||
 | 
							<div class="ui step" :class="{active: step == STEP_INTRO}">
 | 
				
			||||||
 | 
								<div class="content">
 | 
				
			||||||
 | 
									<div :class="{title: step == STEP_INTRO}">1. 介绍</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="ui step" :class="{active: step == STEP_API}">
 | 
				
			||||||
 | 
								<div class="content">
 | 
				
			||||||
 | 
									<div :class="{title: step == STEP_API}">2. 设置API节点</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="ui step" :class="{active: step == STEP_DB}">
 | 
				
			||||||
 | 
								<div class="content">
 | 
				
			||||||
 | 
									<div :class="{title: step == STEP_DB}">3. 设置MySQL数据库</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="ui step" :class="{active: step == STEP_ADMIN}">
 | 
				
			||||||
 | 
								<div class="content">
 | 
				
			||||||
 | 
									<div :class="{title: step == STEP_ADMIN}">4. 设置管理员账号</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="ui step" :class="{active: step == STEP_FINISH}">
 | 
				
			||||||
 | 
								<div class="content">
 | 
				
			||||||
 | 
									<div :class="{title: step == STEP_FINISH}">5. 完成安装</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- 介绍 -->
 | 
				
			||||||
 | 
						<div v-show="step == STEP_INTRO">
 | 
				
			||||||
 | 
							<div>感谢你选择使用<strong>Edge</strong>集群服务系统,下面让我们一起开始配置系统。</div>
 | 
				
			||||||
 | 
							<div class="margin">在这之前如果你还没有可用的MySQL数据库,请先安装数据库再进行。</div>
 | 
				
			||||||
 | 
							<button class="ui button primary" style="margin-top: 10em" type="button" @click.prevent="goIntroNext()">开始<i class="icon long arrow right"></i></button>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- 设置API节点 -->
 | 
				
			||||||
 | 
						<div v-show="step == STEP_API">
 | 
				
			||||||
 | 
							<div class="ui message"><strong>API节点</strong>是管理系统和数据库之间通讯的桥梁,新安装时可以先使用自动启动的API节点,等系统变得庞大时再扩展新的API节点。</div>
 | 
				
			||||||
 | 
							<form class="ui form" data-tea-action=".validateApi" data-tea-success="apiSuccess" data-tea-before="apiSubmit" data-tea-done="apiDone">
 | 
				
			||||||
 | 
								<table class="ui table definition selectable">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">API节点类型</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<div class="ui radio checkbox">
 | 
				
			||||||
 | 
												<input type="radio" name="mode" value="new" id="auto-start-api-node" v-model="apiNodeMode"/>
 | 
				
			||||||
 | 
												<label for="auto-start-api-node">自动启动新API节点</label>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											<div class="ui radio checkbox">
 | 
				
			||||||
 | 
												<input type="radio" name="mode" value="old" id="use-old-api-node" v-model="apiNodeMode"/>
 | 
				
			||||||
 | 
												<label for="use-old-api-node">使用已安装节点</label>
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<tbody v-show="apiNodeMode == 'new'">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="newPort" style="width:6em" maxlength="5" v-model="newAPINodePort"/>
 | 
				
			||||||
 | 
												<p class="comment">选一个在1024-65535之间并且没有正在使用的端口作为要启动的节点端口。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点主机地址</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<div v-if="serverIPs.length > 0">
 | 
				
			||||||
 | 
													<select name="newHost" class="ui dropdown auto-width">
 | 
				
			||||||
 | 
														<option v-for="ip in serverIPs" :value="ip">{{ip}}</option>
 | 
				
			||||||
 | 
													</select>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
												<div v-else="">
 | 
				
			||||||
 | 
													<input type="text" name="newHost" value=""/>
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
												<p class="comment">其他节点访问此API节点的主机地址,可以是IP或者域名,第一次安装时通常是<strong>当前服务器</strong>的IP地址。后期可以修改这个地址。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
									</tbody>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<tbody v-show="apiNodeMode == 'old'">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点协议 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<select class="ui dropdown auto-width" name="oldProtocol">
 | 
				
			||||||
 | 
													<option value="http">HTTP</option>
 | 
				
			||||||
 | 
													<option value="https">HTTPS</option>
 | 
				
			||||||
 | 
												</select>
 | 
				
			||||||
 | 
												<p class="comment">API节点使用的协议。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>主机地址 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="oldHost" maxlength="100" style="width:20em"/>
 | 
				
			||||||
 | 
												<p class="comment">API节点所在主机地址。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>服务端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="oldPort" style="width:6em" maxlength="5"/>
 | 
				
			||||||
 | 
												<p class="comment">API节点启动的端口。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点nodeId *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="oldNodeId" maxlength="100"/>
 | 
				
			||||||
 | 
												<p class="comment">在节点的配置文件中<code-label>configs/api.yaml</code-label>中获取,不需要带双引号。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点secret *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="password" name="oldNodeSecret" maxlength="100"/>
 | 
				
			||||||
 | 
												<p class="comment">在节点的配置文件中<code-label>configs/api.yaml</code-label>中获取,不需要带双引号。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
									</tbody>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
								<button class="ui button" type="button" @click.prevent="goBackIntro"><i class="icon long arrow left"></i>上一步</button>  
 | 
				
			||||||
 | 
								<button class="ui button primary" type="submit" v-if="!apiRequesting">下一步<i class="icon long arrow right"></i></button>
 | 
				
			||||||
 | 
								<button class="ui button primary" type="button" v-if="apiRequesting">提交中</button>
 | 
				
			||||||
 | 
							</form>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- 设置数据库 -->
 | 
				
			||||||
 | 
						<div v-show="step == STEP_DB">
 | 
				
			||||||
 | 
							<div v-show="apiNodeMode == 'new'">
 | 
				
			||||||
 | 
								<form class="ui form" data-tea-action=".validateDb" data-tea-success="dbSuccess" data-tea-before="dbSubmit" data-tea-done="dbDone">
 | 
				
			||||||
 | 
									<table class="ui table definition selectable">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td class="title">MySQL主机地址 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="host" maxlength="100" placeholder="比如 192.168.1.100" style="width:16em" ref="dbHost"/>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>数据库连接端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="port" maxlength="5" placeholder="比如 3306" style="width:7em"/>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>数据库名称 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="database" value="edges" style="width:16em"/>
 | 
				
			||||||
 | 
												<p class="comment">请事先创建好此数据库,如果不存在,则会尝试自动创建。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>连接用户名 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="text" name="username" style="width:16em" maxlength="100"/>
 | 
				
			||||||
 | 
												<p class="comment">此用户需要可以在数据库中有操作数据和创建数据表的权限。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>连接密码</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<input type="password" name="password" style="width:16em" maxlength="100"/>
 | 
				
			||||||
 | 
												<p class="comment">连接数据库所需密码,没有密码的话就不需要填写。</p>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
									</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<button class="ui button" type="button" @click.prevent="goBackAPI"><i class="icon long arrow left"></i>上一步</button>  
 | 
				
			||||||
 | 
									<button class="ui button primary" v-if="!dbRequesting" type="submit">下一步<i class="icon long arrow right"></i></button>
 | 
				
			||||||
 | 
									<button class="ui button primary" v-if="dbRequesting" type="button">提交中...</button>
 | 
				
			||||||
 | 
								</form>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<div v-show="apiNodeMode == 'old'">
 | 
				
			||||||
 | 
								<div style="margin-bottom: 2em">你选择使用了已安装节点,无需重新配置数据库。</div>
 | 
				
			||||||
 | 
								<button class="ui button margin" type="button" @click.prevent="goBackAPI"><i class="icon long arrow left"></i>上一步</button>  
 | 
				
			||||||
 | 
								<button class="ui button primary margin" type="button" @click.prevent="goDBNext()">下一步<i class="icon long arrow right"></i></button>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- 设置管理员账号 -->
 | 
				
			||||||
 | 
						<div v-show="step == STEP_ADMIN">
 | 
				
			||||||
 | 
							<form class="ui form" data-tea-action=".validateAdmin" data-tea-success="adminSuccess">
 | 
				
			||||||
 | 
								<table class="ui table definition selectable">
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td class="title">登录用户名 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="text" name="adminUsername" style="width:16em" maxlength="100" value="admin"/>
 | 
				
			||||||
 | 
											<p class="comment">只能是英文、数字和下划线的组合。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>登录密码 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="password" name="adminPassword" maxlength="100" style="width:16em" v-model="adminPassword" v-show="!adminPasswordVisible"/>
 | 
				
			||||||
 | 
											<input type="text" value="" v-model="adminPassword" style="width:16em" v-show="adminPasswordVisible"/>
 | 
				
			||||||
 | 
											<p class="comment">只能是英文、数字和下划线的组合 <a href="" title="显示明文密码" @click.prevent="showAdminPassword"><i class="icon eye grey"></i></a>。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
									<tr>
 | 
				
			||||||
 | 
										<td>确认密码 *</td>
 | 
				
			||||||
 | 
										<td>
 | 
				
			||||||
 | 
											<input type="password" name="adminPassword2" maxlength="100" style="width:16em" v-model="adminPassword2" v-show="!adminPasswordVisible"/>
 | 
				
			||||||
 | 
											<input type="text" value="" v-model="adminPassword2" style="width:16em" v-show="adminPasswordVisible"/>
 | 
				
			||||||
 | 
											<p class="comment">再次输入密码以便于确认  <a href="" title="显示明文密码" @click.prevent="showAdminPassword"><i class="icon eye grey"></i></a>。</p>
 | 
				
			||||||
 | 
										</td>
 | 
				
			||||||
 | 
									</tr>
 | 
				
			||||||
 | 
								</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<button class="ui button margin" type="button" @click.prevent="goBackDB"><i class="icon long arrow left"></i>上一步</button>  
 | 
				
			||||||
 | 
								<button class="ui button primary margin" type="submit">下一步<i class="icon long arrow right"></i></button>
 | 
				
			||||||
 | 
							</form>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- 完成安装 -->
 | 
				
			||||||
 | 
						<div v-show="step == STEP_FINISH">
 | 
				
			||||||
 | 
							<form class="ui form" data-tea-action=".install" data-tea-success="finishSuccess" data-tea-before="finishSubmit" data-tea-done="finishDone">
 | 
				
			||||||
 | 
								<input type="hidden" name="apiNodeJSON" :value="JSON.stringify(apiNodeInfo)"/>
 | 
				
			||||||
 | 
								<input type="hidden" name="dbJSON" :value="JSON.stringify(dbInfo)"/>
 | 
				
			||||||
 | 
								<input type="hidden" name="adminJSON" :value="JSON.stringify(adminInfo)"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<div class="content-box">
 | 
				
			||||||
 | 
									<h3>API节点信息</h3>
 | 
				
			||||||
 | 
									<table class="ui table definition selectable">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td class="title">API节点类型</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<span v-if="apiNodeInfo.mode == 'new'">自动启动新API节点</span>
 | 
				
			||||||
 | 
												<span v-if="apiNodeInfo.mode == 'old'">使用已安装节点</span>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										<tbody v-show="apiNodeInfo.mode == 'new'">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{apiNodeInfo.newPort}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点主机地址</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{apiNodeInfo.newHost}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										</tbody>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										<tbody v-show="apiNodeInfo.mode == 'old'">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>节点协议 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{apiNodeInfo.oldProtocol}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>主机地址 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{apiNodeInfo.oldHost}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>服务端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{apiNodeInfo.oldPort}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										</tbody>
 | 
				
			||||||
 | 
									</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<h3 v-if="apiNodeMode == 'new'">数据库信息</h3>
 | 
				
			||||||
 | 
									<table class="ui table definition selectable" v-if="apiNodeMode == 'new'">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td class="title">MySQL主机地址 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{dbInfo.host}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>数据库连接端口 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{dbInfo.port}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>数据库名称 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{dbInfo.database}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>连接用户名 *</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												{{dbInfo.username}}
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>连接密码</td>
 | 
				
			||||||
 | 
											<td>
 | 
				
			||||||
 | 
												<span v-if="dbInfo.passwordMask != null && dbInfo.passwordMask.length > 0">{{dbInfo.passwordMask}}</span>
 | 
				
			||||||
 | 
												<span v-else class="disabled">未填入密码</span>
 | 
				
			||||||
 | 
											</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
									</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									<h3>管理员信息</h3>
 | 
				
			||||||
 | 
									<table class="ui table definition selectable">
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td class="title">登录用户名</td>
 | 
				
			||||||
 | 
											<td>{{adminInfo.username}}</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
										<tr>
 | 
				
			||||||
 | 
											<td>登录密码</td>
 | 
				
			||||||
 | 
											<td>{{adminInfo.passwordMask}}</td>
 | 
				
			||||||
 | 
										</tr>
 | 
				
			||||||
 | 
									</table>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<div class="button-group">
 | 
				
			||||||
 | 
									<div class="ui divider"></div>
 | 
				
			||||||
 | 
									<button class="ui button" type="button" @click.prevent="goBackAdmin"><i class="icon long arrow left"></i>上一步</button>
 | 
				
			||||||
 | 
									<button class="ui button primary" type="submit" v-if="!isInstalling">确认并开始安装</button>
 | 
				
			||||||
 | 
									<button class="ui button primary" type="button" v-if="isInstalling">安装中...</button>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</form>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										106
									
								
								web/views/@default/setup/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								web/views/@default/setup/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					Tea.context(function () {
 | 
				
			||||||
 | 
						this.STEP_INTRO = "intro"
 | 
				
			||||||
 | 
						this.STEP_API = "api"
 | 
				
			||||||
 | 
						this.STEP_DB = "db"
 | 
				
			||||||
 | 
						this.STEP_ADMIN = "admin"
 | 
				
			||||||
 | 
						this.STEP_FINISH = "finish"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.step = this.STEP_INTRO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 介绍
 | 
				
			||||||
 | 
						this.goIntroNext = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_API
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// API节点
 | 
				
			||||||
 | 
						this.apiNodeInfo = {}
 | 
				
			||||||
 | 
						this.apiNodeMode = "new"
 | 
				
			||||||
 | 
						this.newAPINodePort = "8001"
 | 
				
			||||||
 | 
						this.apiRequesting = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.apiSubmit = function () {
 | 
				
			||||||
 | 
							this.apiRequesting = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.apiDone = function () {
 | 
				
			||||||
 | 
							this.apiRequesting = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.apiSuccess = function (resp) {
 | 
				
			||||||
 | 
							this.step = this.STEP_DB
 | 
				
			||||||
 | 
							this.apiNodeInfo = resp.data.apiNode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this.apiNodeMode == "new") {
 | 
				
			||||||
 | 
								this.$delay(function () {
 | 
				
			||||||
 | 
									this.$refs.dbHost.focus()
 | 
				
			||||||
 | 
								}, 200)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.goBackIntro = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_INTRO
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 数据库
 | 
				
			||||||
 | 
						this.dbInfo = {}
 | 
				
			||||||
 | 
						this.dbRequesting = false
 | 
				
			||||||
 | 
						this.dbSubmit = function () {
 | 
				
			||||||
 | 
							this.dbRequesting = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.dbSuccess = function (resp) {
 | 
				
			||||||
 | 
							this.step = this.STEP_ADMIN
 | 
				
			||||||
 | 
							this.dbInfo = resp.data.db
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.dbDone = function () {
 | 
				
			||||||
 | 
							this.dbRequesting = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.goBackAPI = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_API
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.goDBNext = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_ADMIN
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 管理员
 | 
				
			||||||
 | 
						this.goBackDB = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_DB
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.adminInfo = {}
 | 
				
			||||||
 | 
						this.adminPassword = ""
 | 
				
			||||||
 | 
						this.adminPassword2 = ""
 | 
				
			||||||
 | 
						this.adminPasswordVisible = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.showAdminPassword = function () {
 | 
				
			||||||
 | 
							this.adminPasswordVisible = !this.adminPasswordVisible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// TODO 切换密码显示的时候应该focus输入框
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.adminSuccess = function (resp) {
 | 
				
			||||||
 | 
							this.step = this.STEP_FINISH
 | 
				
			||||||
 | 
							this.adminInfo = resp.data.admin
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 结束
 | 
				
			||||||
 | 
						this.goBackAdmin = function () {
 | 
				
			||||||
 | 
							this.step = this.STEP_ADMIN
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.isInstalling = false
 | 
				
			||||||
 | 
						this.finishSubmit = function () {
 | 
				
			||||||
 | 
							this.isInstalling = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.finishDone = function () {
 | 
				
			||||||
 | 
							this.isInstalling = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this.finishSuccess = function () {
 | 
				
			||||||
 | 
							teaweb.success("html:恭喜你!安装完成!<br/>请记住你创建的管理员账号,现在跳转到登录界面。", "/")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										2
									
								
								web/views/@default/setup/index.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								web/views/@default/setup/index.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					@import "@install";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user