Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8c3365384 | ||
|
|
2e284b5af9 | ||
|
|
89ddd4e6a3 | ||
|
|
36524ea481 | ||
|
|
35cf693610 | ||
|
|
42148a66bd | ||
|
|
96878715bf | ||
|
|
1a5f3342e7 | ||
|
|
3613d13a2b | ||
|
|
7786140d85 | ||
|
|
3a23b57f1b | ||
|
|
5a6e6fba69 | ||
|
|
910b3a6162 | ||
|
|
0dc19bed45 | ||
|
|
a7bdb64301 | ||
|
|
4739072a85 | ||
|
|
07bdae2488 | ||
|
|
b84035d821 | ||
|
|
dc0a7b9dae | ||
|
|
2937bd8de0 | ||
|
|
37315ef4d9 | ||
|
|
1986fece07 | ||
|
|
16b1657f35 | ||
|
|
c115c62cd9 | ||
|
|
d2df7f8d5b | ||
|
|
6cb79864e6 | ||
|
|
982d28c7b4 | ||
|
|
0f57516fdc | ||
|
|
75a89defcb | ||
|
|
22a6c52060 | ||
|
|
37607e4a41 | ||
|
|
5936155998 | ||
|
|
8d76de935f | ||
|
|
9baa530064 | ||
|
|
103414b338 | ||
|
|
72fe68ebfe | ||
|
|
cfed31958b | ||
|
|
3d5fca2d36 | ||
|
|
a5710286ec | ||
|
|
d0ce0c6c58 | ||
|
|
779e2cf0f2 | ||
|
|
2108474777 | ||
|
|
e25e0f1747 | ||
|
|
e8e74b639c | ||
|
|
a14fcd1e50 | ||
|
|
485c0e0891 | ||
|
|
00a19e9d43 | ||
|
|
67d0dc0783 | ||
|
|
3718c35842 |
1
docker/.gitignore
vendored
Normal file
1
docker/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.zip
|
||||||
36
docker/Dockerfile
Normal file
36
docker/Dockerfile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
FROM alpine:latest
|
||||||
|
LABEL maintainer="iwind.liu@gmail.com"
|
||||||
|
ENV TZ "Asia/Shanghai"
|
||||||
|
ENV VERSION 0.5.8
|
||||||
|
ENV ROOT_DIR /usr/local/goedge
|
||||||
|
ENV TAR_FILE edge-admin-linux-amd64-plus-v${VERSION}.zip
|
||||||
|
ENV TAR_URL "https://dl.goedge.cn/edge/v${VERSION}/edge-admin-linux-amd64-plus-v${VERSION}.zip"
|
||||||
|
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
|
||||||
|
RUN apk add wget
|
||||||
|
RUN mkdir ${ROOT_DIR}; \
|
||||||
|
cd ${ROOT_DIR}; \
|
||||||
|
wget ${TAR_URL} -O ${TAR_FILE}; \
|
||||||
|
apk add unzip; \
|
||||||
|
unzip ${TAR_FILE}; \
|
||||||
|
rm -f ${TAR_FILE}
|
||||||
|
|
||||||
|
RUN apk add mysql mysql-client; \
|
||||||
|
sed -e "s/\[mysqld\]/\[mysqld\]\n\ndatadir=\/var\/lib\/mysql\nport=3306\ninnodb_flush_log_at_trx_commit=2\nmax_connections=256\nmax_prepared_stmt_count=65535\nbinlog_cache_size=1M\nbinlog_stmt_cache_size=1M\nthread_cache_size=32\nbinlog_expire_logs_seconds=1209600\n\n/" /etc/my.cnf > /tmp/my.cnf; \
|
||||||
|
cp /tmp/my.cnf /etc/my.cnf; \
|
||||||
|
sed -e "s/skip-networking/#skip-networking/" /etc/my.cnf.d/mariadb-server.cnf > /tmp/mariadb-server.cnf; \
|
||||||
|
cp /tmp/mariadb-server.cnf /etc/my.cnf.d/mariadb-server.cnf; \
|
||||||
|
mysql_install_db --user=mysql
|
||||||
|
RUN mysqld_safe --user=mysql & \
|
||||||
|
sleep 5; \
|
||||||
|
mysql -uroot -hlocalhost --execute="ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';"
|
||||||
|
|
||||||
|
RUN echo -e "#!/usr/bin/env sh\n\nmysqld_safe --user=mysql &\n/usr/local/goedge/edge-admin/bin/edge-admin\n" > ${ROOT_DIR}/run.sh; \
|
||||||
|
chmod u+x ${ROOT_DIR}/run.sh
|
||||||
|
|
||||||
|
EXPOSE 7788
|
||||||
|
EXPOSE 8001
|
||||||
|
EXPOSE 3306
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/usr/local/goedge/run.sh" ]
|
||||||
5
docker/build.sh
Executable file
5
docker/build.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
VERSION=latest
|
||||||
|
|
||||||
|
docker build --no-cache -t goedge/edge-admin:${VERSION} .
|
||||||
5
docker/run.sh
Executable file
5
docker/run.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
VERSION=latest
|
||||||
|
|
||||||
|
docker run -d -p 7788:7788 -p 8001:8001 -p 3306:3306 --name edge-admin goedge/edge-admin:${VERSION}
|
||||||
8
go.mod
8
go.mod
@@ -15,9 +15,9 @@ require (
|
|||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
github.com/tealeg/xlsx/v3 v3.2.3
|
github.com/tealeg/xlsx/v3 v3.2.3
|
||||||
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
golang.org/x/sys v0.2.0
|
||||||
google.golang.org/grpc v1.45.0
|
google.golang.org/grpc v1.45.0
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -36,8 +36,8 @@ require (
|
|||||||
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
||||||
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
|
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
golang.org/x/net v0.2.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
|
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
|
|||||||
20
go.sum
20
go.sum
@@ -74,6 +74,7 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
|||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
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-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
|
||||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
|
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
|
||||||
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
|
||||||
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
|
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
|
||||||
@@ -170,8 +171,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -198,20 +199,16 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -266,7 +263,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
package configloaders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
|
||||||
"github.com/iwind/TeaGo/logs"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sharedUserUIConfig *systemconfigs.UserUIConfig = nil
|
|
||||||
|
|
||||||
const (
|
|
||||||
UserUISettingName = "userUIConfig"
|
|
||||||
)
|
|
||||||
|
|
||||||
func LoadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
|
|
||||||
config, err := loadUserUIConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
v := reflect.Indirect(reflect.ValueOf(config)).Interface().(systemconfigs.UserUIConfig)
|
|
||||||
return &v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateUserUIConfig(uiConfig *systemconfigs.UserUIConfig) error {
|
|
||||||
locker.Lock()
|
|
||||||
defer locker.Unlock()
|
|
||||||
|
|
||||||
var rpcClient, err = rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
valueJSON, err := json.Marshal(uiConfig)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
|
|
||||||
Code: UserUISettingName,
|
|
||||||
ValueJSON: valueJSON,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sharedUserUIConfig = uiConfig
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
|
|
||||||
if sharedUserUIConfig != nil {
|
|
||||||
return sharedUserUIConfig, nil
|
|
||||||
}
|
|
||||||
var rpcClient, err = rpc.SharedRPC()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
|
|
||||||
Code: UserUISettingName,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(resp.ValueJSON) == 0 {
|
|
||||||
sharedUserUIConfig = defaultUserUIConfig()
|
|
||||||
return sharedUserUIConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &systemconfigs.UserUIConfig{}
|
|
||||||
err = json.Unmarshal(resp.ValueJSON, config)
|
|
||||||
if err != nil {
|
|
||||||
logs.Println("[UI_MANAGER]" + err.Error())
|
|
||||||
sharedUserUIConfig = defaultUserUIConfig()
|
|
||||||
return sharedUserUIConfig, nil
|
|
||||||
}
|
|
||||||
sharedUserUIConfig = config
|
|
||||||
return sharedUserUIConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultUserUIConfig() *systemconfigs.UserUIConfig {
|
|
||||||
return &systemconfigs.UserUIConfig{
|
|
||||||
ProductName: "GoEdge",
|
|
||||||
UserSystemName: "GoEdge用户系统",
|
|
||||||
ShowOpenSourceInfo: true,
|
|
||||||
ShowVersion: true,
|
|
||||||
ShowFinance: true,
|
|
||||||
BandwidthUnit: systemconfigs.BandwidthUnitBit,
|
|
||||||
ShowBandwidthCharts: true,
|
|
||||||
ShowTrafficCharts: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.5.7"
|
Version = "0.5.9"
|
||||||
|
|
||||||
APINodeVersion = "0.5.7"
|
APINodeVersion = "0.5.9"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -571,41 +571,30 @@ func (this *RPCClient) pickConn() *grpc.ClientConn {
|
|||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
// 检查连接状态
|
// 检查连接状态
|
||||||
if len(this.conns) > 0 {
|
var countConns = len(this.conns)
|
||||||
var availableConns = []*grpc.ClientConn{}
|
if countConns > 0 {
|
||||||
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
if countConns == 1 {
|
||||||
|
return this.conns[0]
|
||||||
|
}
|
||||||
|
for _, state := range []connectivity.State{
|
||||||
|
connectivity.Ready,
|
||||||
|
connectivity.Idle,
|
||||||
|
connectivity.Connecting,
|
||||||
|
connectivity.TransientFailure,
|
||||||
|
} {
|
||||||
|
var availableConns = []*grpc.ClientConn{}
|
||||||
for _, conn := range this.conns {
|
for _, conn := range this.conns {
|
||||||
if conn.GetState() == state {
|
if conn.GetState() == state {
|
||||||
availableConns = append(availableConns, conn)
|
availableConns = append(availableConns, conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(availableConns) > 0 {
|
if len(availableConns) > 0 {
|
||||||
break
|
return this.randConn(availableConns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(availableConns) > 0 {
|
|
||||||
return availableConns[rands.Int(0, len(availableConns)-1)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭
|
|
||||||
for _, conn := range this.conns {
|
|
||||||
_ = conn.Close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新初始化
|
return this.randConn(this.conns)
|
||||||
err := this.init()
|
|
||||||
if err != nil {
|
|
||||||
// 错误提示已经在构造对象时打印过,所以这里不再重复打印
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(this.conns) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.conns[rands.Int(0, len(this.conns)-1)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close 关闭
|
// Close 关闭
|
||||||
@@ -639,3 +628,14 @@ func (this *RPCClient) localIPAddrs() []string {
|
|||||||
}
|
}
|
||||||
return localIPAddrs
|
return localIPAddrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) randConn(conns []*grpc.ClientConn) *grpc.ClientConn {
|
||||||
|
var l = len(conns)
|
||||||
|
if l == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if l == 1 {
|
||||||
|
return conns[0]
|
||||||
|
}
|
||||||
|
return conns[rands.Int(0, l-1)]
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/iwind/TeaGo/assert"
|
"github.com/iwind/TeaGo/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|||||||
55
internal/utils/time.go
Normal file
55
internal/utils/time.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RangeTimes 计算时间点
|
||||||
|
func RangeTimes(timeFrom string, timeTo string, everyMinutes int32) (result []string, err error) {
|
||||||
|
if everyMinutes <= 0 {
|
||||||
|
return nil, errors.New("invalid 'everyMinutes'")
|
||||||
|
}
|
||||||
|
|
||||||
|
var reg = regexp.MustCompile(`^\d{4}$`)
|
||||||
|
if !reg.MatchString(timeFrom) {
|
||||||
|
return nil, errors.New("invalid timeFrom '" + timeFrom + "'")
|
||||||
|
}
|
||||||
|
if !reg.MatchString(timeTo) {
|
||||||
|
return nil, errors.New("invalid timeTo '" + timeTo + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeFrom > timeTo {
|
||||||
|
// swap
|
||||||
|
timeFrom, timeTo = timeTo, timeFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
var everyMinutesInt = int(everyMinutes)
|
||||||
|
|
||||||
|
var fromHour = types.Int(timeFrom[:2])
|
||||||
|
var fromMinute = types.Int(timeFrom[2:])
|
||||||
|
var toHour = types.Int(timeTo[:2])
|
||||||
|
var toMinute = types.Int(timeTo[2:])
|
||||||
|
|
||||||
|
if fromMinute%everyMinutesInt == 0 {
|
||||||
|
result = append(result, timeFrom)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
fromMinute += everyMinutesInt
|
||||||
|
if fromMinute > 59 {
|
||||||
|
fromHour += fromMinute / 60
|
||||||
|
fromMinute = fromMinute % 60
|
||||||
|
}
|
||||||
|
if fromHour > toHour || (fromHour == toHour && fromMinute > toMinute) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = append(result, fmt.Sprintf("%02d%02d", fromHour, fromMinute))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -49,7 +49,11 @@ func (this *ParentAction) ErrorText(err string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ParentAction) NotFound(name string, itemId int64) {
|
func (this *ParentAction) NotFound(name string, itemId int64) {
|
||||||
this.ErrorPage(errors.New(name + " id: '" + strconv.FormatInt(itemId, 10) + "' is not found"))
|
if itemId > 0 {
|
||||||
|
this.ErrorPage(errors.New(name + " id: '" + strconv.FormatInt(itemId, 10) + "' is not found"))
|
||||||
|
} else {
|
||||||
|
this.ErrorPage(errors.New(name + " is not found"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
|
func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
|
||||||
@@ -126,11 +130,8 @@ func (this *ParentAction) RPC() *rpc.RPCClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AdminContext 获取Context
|
// AdminContext 获取Context
|
||||||
|
// 每个请求的context都必须是一个新的实例
|
||||||
func (this *ParentAction) AdminContext() context.Context {
|
func (this *ParentAction) AdminContext() context.Context {
|
||||||
if this.ctx != nil {
|
|
||||||
return this.ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
if this.rpcClient == nil {
|
if this.rpcClient == nil {
|
||||||
rpcClient, err := rpc.SharedRPC()
|
rpcClient, err := rpc.SharedRPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func init() {
|
|||||||
Post("/options", new(OptionsAction)).
|
Post("/options", new(OptionsAction)).
|
||||||
|
|
||||||
// AccessKeys
|
// AccessKeys
|
||||||
Prefix("/admins/accessKeys").
|
Prefix("/admins/accesskeys").
|
||||||
Get("", new(accesskeys.IndexAction)).
|
Get("", new(accesskeys.IndexAction)).
|
||||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||||
Post("/delete", new(accesskeys.DeleteAction)).
|
Post("/delete", new(accesskeys.DeleteAction)).
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreatePopupAction struct {
|
type CreatePopupAction struct {
|
||||||
@@ -40,11 +42,11 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Field("name", params.Name).
|
Field("name", params.Name).
|
||||||
Require("请输入API节点名称")
|
Require("请输入API节点名称")
|
||||||
|
|
||||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||||
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||||
|
|
||||||
// 监听地址
|
// 监听地址
|
||||||
listens := []*serverconfigs.NetworkAddressConfig{}
|
var listens = []*serverconfigs.NetworkAddressConfig{}
|
||||||
err := json.Unmarshal(params.ListensJSON, &listens)
|
err := json.Unmarshal(params.ListensJSON, &listens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
@@ -64,15 +66,19 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rest监听地址
|
// Rest监听地址
|
||||||
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{}
|
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||||
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{}
|
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||||
if params.RestIsOn {
|
if params.RestIsOn {
|
||||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
var restListens = []*serverconfigs.NetworkAddressConfig{}
|
||||||
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(restListens) == 0 {
|
||||||
|
this.Fail("请至少添加一个HTTP API监听端口")
|
||||||
|
return
|
||||||
|
}
|
||||||
for _, addr := range restListens {
|
for _, addr := range restListens {
|
||||||
if addr.Protocol.IsHTTPFamily() {
|
if addr.Protocol.IsHTTPFamily() {
|
||||||
restHTTPConfig.IsOn = true
|
restHTTPConfig.IsOn = true
|
||||||
@@ -82,10 +88,35 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否有端口冲突
|
||||||
|
var rpcAddresses = []string{}
|
||||||
|
for _, listen := range listens {
|
||||||
|
err := listen.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listen := range restListens {
|
||||||
|
err := listen.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, address := range listen.Addresses() {
|
||||||
|
if lists.ContainsString(rpcAddresses, address) {
|
||||||
|
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突,请修改后提交")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 证书
|
// 证书
|
||||||
certIds := []int64{}
|
var certIds = []int64{}
|
||||||
if len(params.CertIdsJSON) > 0 {
|
if len(params.CertIdsJSON) > 0 {
|
||||||
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,7 +128,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
this.Fail("请添加至少一个证书")
|
this.Fail("请添加至少一个证书")
|
||||||
}
|
}
|
||||||
|
|
||||||
certRefs := []*sslconfigs.SSLCertRef{}
|
var certRefs = []*sslconfigs.SSLCertRef{}
|
||||||
for _, certId := range certIds {
|
for _, certId := range certIds {
|
||||||
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||||
IsOn: true,
|
IsOn: true,
|
||||||
@@ -131,7 +162,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 访问地址
|
// 访问地址
|
||||||
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||||
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/lists"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -175,12 +177,16 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||||
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||||
if params.RestIsOn {
|
if params.RestIsOn {
|
||||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
var restListens = []*serverconfigs.NetworkAddressConfig{}
|
||||||
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(restListens) == 0 {
|
||||||
|
this.Fail("请至少添加一个HTTP API监听端口")
|
||||||
|
return
|
||||||
|
}
|
||||||
for _, addr := range restListens {
|
for _, addr := range restListens {
|
||||||
if addr.Protocol.IsHTTPFamily() {
|
if addr.Protocol.IsHTTPFamily() {
|
||||||
restHTTPConfig.IsOn = true
|
restHTTPConfig.IsOn = true
|
||||||
@@ -190,6 +196,31 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否有端口冲突
|
||||||
|
var rpcAddresses = []string{}
|
||||||
|
for _, listen := range listens {
|
||||||
|
err := listen.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listen := range restListens {
|
||||||
|
err := listen.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, address := range listen.Addresses() {
|
||||||
|
if lists.ContainsString(rpcAddresses, address) {
|
||||||
|
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突,请修改后提交")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 证书
|
// 证书
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"time"
|
"time"
|
||||||
@@ -300,6 +301,22 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
lnAddrs = []string{}
|
lnAddrs = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API节点地址
|
||||||
|
var apiNodeAddrStrings = []string{}
|
||||||
|
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
if len(node.ApiNodeAddrsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, addr := range apiNodeAddrs {
|
||||||
|
if addr.Init() == nil {
|
||||||
|
apiNodeAddrStrings = append(apiNodeAddrStrings, addr.FullAddresses()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.Data["node"] = maps.Map{
|
this.Data["node"] = maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -319,6 +336,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||||
"lnAddrs": lnAddrs,
|
"lnAddrs": lnAddrs,
|
||||||
"enableIPLists": node.EnableIPLists,
|
"enableIPLists": node.EnableIPLists,
|
||||||
|
"apiNodeAddrs": apiNodeAddrStrings,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": status.IsActive,
|
||||||
@@ -338,6 +356,8 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||||
"exePath": status.ExePath,
|
"exePath": status.ExePath,
|
||||||
|
"apiSuccessPercent": status.APISuccessPercent,
|
||||||
|
"apiAvgCostSeconds": status.APIAvgCostSeconds,
|
||||||
},
|
},
|
||||||
|
|
||||||
"group": groupMap,
|
"group": groupMap,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -57,9 +58,19 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diskSubDirs = []*serverconfigs.CacheDir{}
|
||||||
|
if len(node.CacheDiskSubDirsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(node.CacheDiskSubDirsJSON, &diskSubDirs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var nodeMap = this.Data["node"].(maps.Map)
|
var nodeMap = this.Data["node"].(maps.Map)
|
||||||
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
|
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
|
||||||
nodeMap["cacheDiskDir"] = node.CacheDiskDir
|
nodeMap["cacheDiskDir"] = node.CacheDiskDir
|
||||||
|
nodeMap["cacheDiskSubDirs"] = diskSubDirs
|
||||||
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
|
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
@@ -69,6 +80,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
NodeId int64
|
NodeId int64
|
||||||
MaxCacheDiskCapacityJSON []byte
|
MaxCacheDiskCapacityJSON []byte
|
||||||
CacheDiskDir string
|
CacheDiskDir string
|
||||||
|
CacheDiskSubDirsJSON []byte
|
||||||
MaxCacheMemoryCapacityJSON []byte
|
MaxCacheMemoryCapacityJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
@@ -105,10 +117,20 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(params.CacheDiskSubDirsJSON) > 0 {
|
||||||
|
var cacheSubDirs = []*serverconfigs.CacheDir{}
|
||||||
|
err := json.Unmarshal(params.CacheDiskSubDirsJSON, &cacheSubDirs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
|
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||||
CacheDiskDir: params.CacheDiskDir,
|
CacheDiskDir: params.CacheDiskDir,
|
||||||
|
CacheDiskSubDirsJSON: params.CacheDiskSubDirsJSON,
|
||||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
@@ -50,6 +51,22 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
this.Data["dnsResolverConfig"] = dnsResolverConfig
|
this.Data["dnsResolverConfig"] = dnsResolverConfig
|
||||||
|
|
||||||
|
// API相关
|
||||||
|
apiConfigResp, err := this.RPC().NodeRPC().FindNodeAPIConfig(this.AdminContext(), &pb.FindNodeAPIConfigRequest{NodeId: params.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
if len(apiConfigResp.ApiNodeAddrsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(apiConfigResp.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Data["apiNodeAddrs"] = apiNodeAddrs
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +76,8 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
|
|
||||||
DnsResolverJSON []byte
|
DnsResolverJSON []byte
|
||||||
|
|
||||||
|
ApiNodeAddrsJSON []byte
|
||||||
|
|
||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
CSRF *actionutils.CSRF
|
CSRF *actionutils.CSRF
|
||||||
}) {
|
}) {
|
||||||
@@ -68,6 +87,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
this.Fail("CPU线程数不能小于0")
|
this.Fail("CPU线程数不能小于0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 系统设置
|
||||||
_, err := this.RPC().NodeRPC().UpdateNodeSystem(this.AdminContext(), &pb.UpdateNodeSystemRequest{
|
_, err := this.RPC().NodeRPC().UpdateNodeSystem(this.AdminContext(), &pb.UpdateNodeSystemRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
MaxCPU: params.MaxCPU,
|
MaxCPU: params.MaxCPU,
|
||||||
@@ -77,6 +97,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DNS解析设置
|
||||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||||
err = json.Unmarshal(params.DnsResolverJSON, dnsResolverConfig)
|
err = json.Unmarshal(params.DnsResolverJSON, dnsResolverConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -98,5 +119,28 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API节点设置
|
||||||
|
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||||
|
if len(params.ApiNodeAddrsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(params.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("API节点地址校验错误:" + err.Error())
|
||||||
|
}
|
||||||
|
for _, addr := range apiNodeAddrs {
|
||||||
|
err = addr.Init()
|
||||||
|
if err != nil {
|
||||||
|
this.Fail("API节点地址校验错误:" + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = this.RPC().NodeRPC().UpdateNodeAPIConfig(this.AdminContext(), &pb.UpdateNodeAPIConfigRequest{
|
||||||
|
NodeId: params.NodeId,
|
||||||
|
ApiNodeAddrsJSON: params.ApiNodeAddrsJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
AutoOpenPorts bool
|
AutoOpenPorts bool
|
||||||
ClockAutoSync bool
|
ClockAutoSync bool
|
||||||
ClockServer string
|
ClockServer string
|
||||||
|
ClockCheckChrony bool
|
||||||
AutoRemoteStart bool
|
AutoRemoteStart bool
|
||||||
AutoInstallNftables bool
|
AutoInstallNftables bool
|
||||||
|
|
||||||
@@ -154,6 +155,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
var clockConfig = nodeconfigs.DefaultClockConfig()
|
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||||
clockConfig.AutoSync = params.ClockAutoSync
|
clockConfig.AutoSync = params.ClockAutoSync
|
||||||
clockConfig.Server = params.ClockServer
|
clockConfig.Server = params.ClockServer
|
||||||
|
clockConfig.CheckChrony = params.ClockCheckChrony
|
||||||
clockConfigJSON, err := json.Marshal(clockConfig)
|
clockConfigJSON, err := json.Marshal(clockConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
|||||||
var tabbar = actionutils.NewTabbar()
|
var tabbar = actionutils.NewTabbar()
|
||||||
tabbar.Add("集群列表", "", "/clusters", "", false)
|
tabbar.Add("集群列表", "", "/clusters", "", false)
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
tabbar.Add("集群看板", "", "/clusters/cluster/boards?clusterId="+clusterIdString, "board", selectedTabbar == "board")
|
tabbar.Add("集群看板", "", "/clusters/cluster/boards?clusterId="+clusterIdString, "chart line area", selectedTabbar == "board")
|
||||||
}
|
}
|
||||||
tabbar.Add("集群节点", "", "/clusters/cluster/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
tabbar.Add("集群节点", "", "/clusters/cluster/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||||
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
||||||
|
|||||||
@@ -71,7 +71,10 @@ func ValidateRecordName(name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pieces := strings.Split(name, ".")
|
pieces := strings.Split(name, ".")
|
||||||
for _, piece := range pieces {
|
for index, piece := range pieces {
|
||||||
|
if index == 0 && piece == "*" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if piece == "-" ||
|
if piece == "-" ||
|
||||||
strings.HasPrefix(piece, "-") ||
|
strings.HasPrefix(piece, "-") ||
|
||||||
strings.HasSuffix(piece, "-") ||
|
strings.HasSuffix(piece, "-") ||
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func (this *CreateRulePopupAction) RunGet(params struct {
|
|||||||
"params": checkpoint.Params,
|
"params": checkpoint.Params,
|
||||||
"options": checkpoint.Options,
|
"options": checkpoint.Options,
|
||||||
"isComposed": checkpoint.IsComposed,
|
"isComposed": checkpoint.IsComposed,
|
||||||
|
"dataType": checkpoint.DataType,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,11 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
KeepArgs bool
|
KeepArgs bool
|
||||||
|
|
||||||
// 域名
|
// 域名
|
||||||
DomainsAll bool
|
DomainsAll bool
|
||||||
DomainsBeforeJSON []byte
|
DomainsBeforeJSON []byte
|
||||||
DomainAfter string
|
DomainBeforeIgnorePorts bool
|
||||||
DomainAfterScheme string
|
DomainAfter string
|
||||||
|
DomainAfterScheme string
|
||||||
|
|
||||||
// 端口
|
// 端口
|
||||||
PortsAll bool
|
PortsAll bool
|
||||||
@@ -128,6 +129,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
config.DomainBeforeIgnorePorts = params.DomainBeforeIgnorePorts
|
||||||
if len(params.DomainAfter) == 0 {
|
if len(params.DomainAfter) == 0 {
|
||||||
this.FailField("domainAfter", "请输入跳转后域名")
|
this.FailField("domainAfter", "请输入跳转后域名")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
package userui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IndexAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
|
||||||
config, err := configloaders.LoadUserUIConfig()
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.Data["config"] = config
|
|
||||||
|
|
||||||
// 时区
|
|
||||||
this.Data["timeZoneGroups"] = nodeconfigs.FindAllTimeZoneGroups()
|
|
||||||
this.Data["timeZoneLocations"] = nodeconfigs.FindAllTimeZoneLocations()
|
|
||||||
|
|
||||||
if len(config.TimeZone) == 0 {
|
|
||||||
config.TimeZone = nodeconfigs.DefaultTimeZoneLocation
|
|
||||||
}
|
|
||||||
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(config.TimeZone)
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) RunPost(params struct {
|
|
||||||
ProductName string
|
|
||||||
UserSystemName string
|
|
||||||
ShowOpenSourceInfo bool
|
|
||||||
ShowVersion bool
|
|
||||||
Version string
|
|
||||||
ShowFinance bool
|
|
||||||
FaviconFile *actions.File
|
|
||||||
LogoFile *actions.File
|
|
||||||
TimeZone string
|
|
||||||
|
|
||||||
ShowTrafficCharts bool
|
|
||||||
ShowBandwidthCharts bool
|
|
||||||
BandwidthUnit string
|
|
||||||
|
|
||||||
Must *actions.Must
|
|
||||||
CSRF *actionutils.CSRF
|
|
||||||
}) {
|
|
||||||
params.Must.
|
|
||||||
Field("productName", params.ProductName).
|
|
||||||
Require("请输入产品名称").
|
|
||||||
Field("userSystemName", params.UserSystemName).
|
|
||||||
Require("请输入管理员系统名称")
|
|
||||||
|
|
||||||
config, err := configloaders.LoadUserUIConfig()
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
config.ProductName = params.ProductName
|
|
||||||
config.UserSystemName = params.UserSystemName
|
|
||||||
config.ShowOpenSourceInfo = params.ShowOpenSourceInfo
|
|
||||||
config.ShowVersion = params.ShowVersion
|
|
||||||
config.Version = params.Version
|
|
||||||
config.ShowFinance = params.ShowFinance
|
|
||||||
config.ShowTrafficCharts = params.ShowTrafficCharts
|
|
||||||
config.ShowBandwidthCharts = params.ShowBandwidthCharts
|
|
||||||
config.BandwidthUnit = params.BandwidthUnit
|
|
||||||
config.TimeZone = params.TimeZone
|
|
||||||
|
|
||||||
// 上传Favicon文件
|
|
||||||
if params.FaviconFile != nil {
|
|
||||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
|
||||||
Filename: params.FaviconFile.Filename,
|
|
||||||
Size: params.FaviconFile.Size,
|
|
||||||
IsPublic: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileId := createResp.FileId
|
|
||||||
|
|
||||||
// 上传内容
|
|
||||||
buf := make([]byte, 512*1024)
|
|
||||||
reader, err := params.FaviconFile.OriginFile.Open()
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
n, err := reader.Read(buf)
|
|
||||||
if n > 0 {
|
|
||||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
|
||||||
FileId: fileId,
|
|
||||||
Data: buf[:n],
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 置为已完成
|
|
||||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
}
|
|
||||||
config.FaviconFileId = fileId
|
|
||||||
}
|
|
||||||
|
|
||||||
// 上传Logo文件
|
|
||||||
if params.LogoFile != nil {
|
|
||||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
|
||||||
Filename: params.LogoFile.Filename,
|
|
||||||
Size: params.LogoFile.Size,
|
|
||||||
IsPublic: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileId := createResp.FileId
|
|
||||||
|
|
||||||
// 上传内容
|
|
||||||
buf := make([]byte, 512*1024)
|
|
||||||
reader, err := params.LogoFile.OriginFile.Open()
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
n, err := reader.Read(buf)
|
|
||||||
if n > 0 {
|
|
||||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
|
||||||
FileId: fileId,
|
|
||||||
Data: buf[:n],
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 置为已完成
|
|
||||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
}
|
|
||||||
config.LogoFileId = fileId
|
|
||||||
}
|
|
||||||
|
|
||||||
err = configloaders.UpdateUserUIConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package userui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
|
||||||
"github.com/iwind/TeaGo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
|
||||||
server.
|
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
|
||||||
Helper(settingutils.NewHelper("userUI")).
|
|
||||||
Prefix("/settings/user-ui").
|
|
||||||
GetPost("", new(IndexAction)).
|
|
||||||
EndAll()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -31,10 +32,21 @@ func (this *DetectDBAction) RunPost(params struct{}) {
|
|||||||
localPort = "3306"
|
localPort = "3306"
|
||||||
|
|
||||||
var username = "root"
|
var username = "root"
|
||||||
for _, pass := range []string{"", "123456", "654321", "Aa_123456"} {
|
var passwords = []string{"", "123456", "654321", "Aa_123456", "111111"}
|
||||||
|
|
||||||
|
// 使用 foolish-mysql 安装的MySQL
|
||||||
|
localGeneratedPasswordData, err := os.ReadFile("/usr/local/mysql/generated-password.txt")
|
||||||
|
if err == nil {
|
||||||
|
var localGeneratedPassword = strings.TrimSpace(string(localGeneratedPasswordData))
|
||||||
|
if len(localGeneratedPassword) > 0 {
|
||||||
|
passwords = append(passwords, localGeneratedPassword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pass := range passwords {
|
||||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||||
Driver: "mysql",
|
Driver: "mysql",
|
||||||
Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges11111",
|
Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges",
|
||||||
Prefix: "",
|
Prefix: "",
|
||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
currentHost = host
|
currentHost = host
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if net.ParseIP(currentHost) != nil {
|
if net.ParseIP(currentHost) != nil && currentHost != "localhost" && currentHost != "127.0.0.1" {
|
||||||
this.Data["currentHost"] = currentHost
|
this.Data["currentHost"] = currentHost
|
||||||
} else {
|
} else {
|
||||||
this.Data["currentHost"] = ""
|
this.Data["currentHost"] = ""
|
||||||
|
|||||||
@@ -17,13 +17,17 @@ import (
|
|||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InstallAction struct {
|
type InstallAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
|
|
||||||
|
apiSetupFinished bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *InstallAction) RunPost(params struct {
|
func (this *InstallAction) RunPost(params struct {
|
||||||
@@ -40,7 +44,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
|
|
||||||
// API节点配置
|
// API节点配置
|
||||||
currentStatusText = "正在检查API节点配置"
|
currentStatusText = "正在检查API节点配置"
|
||||||
apiNodeMap := maps.Map{}
|
var apiNodeMap = maps.Map{}
|
||||||
err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
|
err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("API节点配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
this.Fail("API节点配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||||
@@ -48,7 +52,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
|
|
||||||
// 数据库
|
// 数据库
|
||||||
currentStatusText = "正在检查数据库配置"
|
currentStatusText = "正在检查数据库配置"
|
||||||
dbMap := maps.Map{}
|
var dbMap = maps.Map{}
|
||||||
err = json.Unmarshal(params.DbJSON, &dbMap)
|
err = json.Unmarshal(params.DbJSON, &dbMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||||
@@ -56,14 +60,14 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
|
|
||||||
// 管理员
|
// 管理员
|
||||||
currentStatusText = "正在检查管理员配置"
|
currentStatusText = "正在检查管理员配置"
|
||||||
adminMap := maps.Map{}
|
var adminMap = maps.Map{}
|
||||||
err = json.Unmarshal(params.AdminJSON, &adminMap)
|
err = json.Unmarshal(params.AdminJSON, &adminMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 安装API节点
|
// 安装API节点
|
||||||
mode := apiNodeMap.GetString("mode")
|
var mode = apiNodeMap.GetString("mode")
|
||||||
if mode == "new" {
|
if mode == "new" {
|
||||||
currentStatusText = "准备启动新API节点"
|
currentStatusText = "准备启动新API节点"
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
// ...
|
// ...
|
||||||
|
|
||||||
// 检查环境
|
// 检查环境
|
||||||
apiNodeDir := Tea.Root + "/edge-api"
|
var apiNodeDir = Tea.Root + "/edge-api"
|
||||||
for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} {
|
for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} {
|
||||||
apiNodeDir := Tea.Root + "/" + dir
|
apiNodeDir := Tea.Root + "/" + dir
|
||||||
_, err = os.Stat(apiNodeDir)
|
_, err = os.Stat(apiNodeDir)
|
||||||
@@ -87,7 +91,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存数据库配置
|
// 保存数据库配置
|
||||||
dsn := dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
|
var dsn = dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
|
||||||
dbConfig := &dbs.Config{
|
dbConfig := &dbs.Config{
|
||||||
DBs: map[string]*dbs.DBConfig{
|
DBs: map[string]*dbs.DBConfig{
|
||||||
"prod": {
|
"prod": {
|
||||||
@@ -108,7 +112,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
|
|
||||||
// 生成备份文件
|
// 生成备份文件
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
backupDirs := []string{"/etc/edge-api"}
|
var backupDirs = []string{"/etc/edge-api"}
|
||||||
if len(homeDir) > 0 {
|
if len(homeDir) > 0 {
|
||||||
backupDirs = append(backupDirs, homeDir+"/.edge-api")
|
backupDirs = append(backupDirs, homeDir+"/.edge-api")
|
||||||
}
|
}
|
||||||
@@ -151,15 +155,21 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
var resultMap = maps.Map{}
|
var resultMap = maps.Map{}
|
||||||
logs.Println("[INSTALL]setup edge-api")
|
logs.Println("[INSTALL]setup edge-api")
|
||||||
{
|
{
|
||||||
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
|
this.apiSetupFinished = false
|
||||||
output := bytes.NewBuffer([]byte{})
|
var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
|
||||||
|
var output = bytes.NewBuffer([]byte{})
|
||||||
cmd.Stdout = output
|
cmd.Stdout = output
|
||||||
|
|
||||||
|
// 试图读取执行日志
|
||||||
|
go this.startReadingAPIInstallLog()
|
||||||
|
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
|
this.apiSetupFinished = true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("安装失败:" + err.Error())
|
this.Fail("安装失败:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
resultData := output.Bytes()
|
var resultData = output.Bytes()
|
||||||
err = json.Unmarshal(resultData, &resultMap)
|
err = json.Unmarshal(resultData, &resultMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
|
this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
|
||||||
@@ -175,7 +185,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
// 关闭正在运行的API节点,防止冲突
|
// 关闭正在运行的API节点,防止冲突
|
||||||
logs.Println("[INSTALL]stop edge-api")
|
logs.Println("[INSTALL]stop edge-api")
|
||||||
{
|
{
|
||||||
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "stop")
|
var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "stop")
|
||||||
_ = cmd.Run()
|
_ = cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +193,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
currentStatusText = "正在启动API节点"
|
currentStatusText = "正在启动API节点"
|
||||||
logs.Println("[INSTALL]start edge-api")
|
logs.Println("[INSTALL]start edge-api")
|
||||||
{
|
{
|
||||||
cmd := exec.Command(apiNodeDir + "/bin/edge-api")
|
var cmd = exec.Command(apiNodeDir + "/bin/edge-api")
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("API节点启动失败:" + err.Error())
|
this.Fail("API节点启动失败:" + err.Error())
|
||||||
@@ -220,7 +230,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 写入API节点配置,完成安装
|
// 写入API节点配置,完成安装
|
||||||
apiConfig := &configs.APIConfig{
|
var apiConfig = &configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
DisableUpdate bool `yaml:"disableUpdate"`
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
@@ -283,7 +293,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
this.Success()
|
this.Success()
|
||||||
} else if mode == "old" {
|
} else if mode == "old" {
|
||||||
// 构造RPC
|
// 构造RPC
|
||||||
apiConfig := &configs.APIConfig{
|
var apiConfig = &configs.APIConfig{
|
||||||
RPC: struct {
|
RPC: struct {
|
||||||
Endpoints []string `yaml:"endpoints"`
|
Endpoints []string `yaml:"endpoints"`
|
||||||
DisableUpdate bool `yaml:"disableUpdate"`
|
DisableUpdate bool `yaml:"disableUpdate"`
|
||||||
@@ -303,7 +313,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// 设置管理员
|
// 设置管理员
|
||||||
ctx := client.APIContext(0)
|
var ctx = client.APIContext(0)
|
||||||
_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
|
_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
|
||||||
Username: adminMap.GetString("username"),
|
Username: adminMap.GetString("username"),
|
||||||
Password: adminMap.GetString("password"),
|
Password: adminMap.GetString("password"),
|
||||||
@@ -344,3 +354,73 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
this.Fail("错误的API节点模式:'" + mode + "'")
|
this.Fail("错误的API节点模式:'" + mode + "'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 读取API安装时的日志,以便于显示当前正在执行的任务
|
||||||
|
func (this *InstallAction) startReadingAPIInstallLog() {
|
||||||
|
var tmpDir = os.TempDir()
|
||||||
|
if len(tmpDir) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var logFile = tmpDir + "/edge-install.log"
|
||||||
|
|
||||||
|
var logFp *os.File
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// 尝试5秒钟
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
logFp, err = os.Open(logFile)
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.apiSetupFinished {
|
||||||
|
_ = logFp.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
_ = logFp.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
var ticker = time.NewTicker(1 * time.Second)
|
||||||
|
var logBuf = make([]byte, 256)
|
||||||
|
for range ticker.C {
|
||||||
|
if this.apiSetupFinished {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = logFp.Seek(-256, io.SeekEnd)
|
||||||
|
if err != nil {
|
||||||
|
currentStatusText = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := logFp.Read(logBuf)
|
||||||
|
if err != nil {
|
||||||
|
currentStatusText = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
var logData = string(logBuf[:n])
|
||||||
|
var lines = strings.Split(logData, "\n")
|
||||||
|
if len(lines) >= 3 {
|
||||||
|
var line = strings.TrimSpace(lines[len(lines)-2])
|
||||||
|
if len(line) > 0 {
|
||||||
|
if !this.apiSetupFinished {
|
||||||
|
currentStatusText = "正在执行 " + line + " ..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func init() {
|
|||||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||||
|
|
||||||
// AccessKeys
|
// AccessKeys
|
||||||
Prefix("/users/accessKeys").
|
Prefix("/users/accesskeys").
|
||||||
Get("", new(accesskeys.IndexAction)).
|
Get("", new(accesskeys.IndexAction)).
|
||||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||||
Post("/delete", new(accesskeys.DeleteAction)).
|
Post("/delete", new(accesskeys.DeleteAction)).
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/updates"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/updates"
|
||||||
_ "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/settings/user-ui"
|
|
||||||
|
|
||||||
// 恢复
|
// 恢复
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/recover"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/recover"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2392,9 +2392,9 @@ Vue.component("ns-access-log-box", {
|
|||||||
if (accessLog.recordValue == null || accessLog.recordValue.length == 0) {
|
if (accessLog.recordValue == null || accessLog.recordValue.length == 0) {
|
||||||
isFailure = true
|
isFailure = true
|
||||||
}
|
}
|
||||||
} else if (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) {
|
|
||||||
isFailure = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 没有找到记录的不需要高亮显示,防止管理员看到红色就心理恐慌
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -3435,7 +3435,7 @@ Vue.component("http-stat-config-box", {
|
|||||||
<prior-checkbox :v-config="stat" v-if="vIsLocation || vIsGroup" ></prior-checkbox>
|
<prior-checkbox :v-config="stat" v-if="vIsLocation || vIsGroup" ></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || stat.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || stat.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否开启统计</td>
|
<td class="title">启用统计</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="stat.isOn"/>
|
<input type="checkbox" v-model="stat.isOn"/>
|
||||||
@@ -4511,6 +4511,7 @@ Vue.component("http-host-redirect-box", {
|
|||||||
<div style="margin-top: 0.4em">
|
<div style="margin-top: 0.4em">
|
||||||
<grey-label><strong>域名跳转</strong></grey-label>
|
<grey-label><strong>域名跳转</strong></grey-label>
|
||||||
<grey-label v-if="redirect.domainAfterScheme != null && redirect.domainAfterScheme.length > 0">{{redirect.domainAfterScheme}}</grey-label>
|
<grey-label v-if="redirect.domainAfterScheme != null && redirect.domainAfterScheme.length > 0">{{redirect.domainAfterScheme}}</grey-label>
|
||||||
|
<grey-label v-if="redirect.domainBeforeIgnorePorts">忽略端口</grey-label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="redirect.type == 'port'">
|
<div v-if="redirect.type == 'port'">
|
||||||
@@ -6679,7 +6680,7 @@ Vue.component("http-websocket-box", {
|
|||||||
<prior-checkbox :v-config="websocketRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="websocketRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="((!vIsLocation && !vIsGroup) || websocketRef.isPrior)">
|
<tbody v-show="((!vIsLocation && !vIsGroup) || websocketRef.isPrior)">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用配置</td>
|
<td class="title">启用Websocket</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="websocketRef.isOn"/>
|
<input type="checkbox" v-model="websocketRef.isOn"/>
|
||||||
@@ -7275,7 +7276,7 @@ Vue.component("domains-box", {
|
|||||||
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)。</p>
|
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)<span v-if="vSupportWildcard == undefined">、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)</span>;如果域名后有端口,请加上端口号。</p>
|
||||||
<p class="comment" v-if="!supportWildcard">只支持普通域名(<code-label>example.com</code-label>、<code-label>www.example.com</code-label>)。</p>
|
<p class="comment" v-if="!supportWildcard">只支持普通域名(<code-label>example.com</code-label>、<code-label>www.example.com</code-label>)。</p>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -7352,14 +7353,14 @@ Vue.component("http-referers-config-box", {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>允许的来源域名</td>
|
<td>允许的来源域名</td>
|
||||||
<td>
|
<td>
|
||||||
<values-box :values="config.allowDomains" @change="changeAllowDomains"></values-box>
|
<domains-box :v-domains="config.allowDomains" @change="changeAllowDomains">></domains-box>
|
||||||
<p class="comment">允许的其他来源域名列表,比如<code-label>example.com</code-label>、<code-label>*.example.com</code-label>。单个星号<code-label>*</code-label>表示允许所有域名。</p>
|
<p class="comment">允许的其他来源域名列表,比如<code-label>example.com</code-label>、<code-label>*.example.com</code-label>。单个星号<code-label>*</code-label>表示允许所有域名。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>禁止的来源域名</td>
|
<td>禁止的来源域名</td>
|
||||||
<td>
|
<td>
|
||||||
<values-box :values="config.denyDomains" @change="changeDenyDomains"></values-box>
|
<domains-box :v-domains="config.denyDomains" @change="changeDenyDomains"></domains-box>
|
||||||
<p class="comment">禁止的来源域名列表,比如<code-label>example.org</code-label>、<code-label>*.example.org</code-label>;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。</p>
|
<p class="comment">禁止的来源域名列表,比如<code-label>example.org</code-label>、<code-label>*.example.org</code-label>;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -9106,7 +9107,7 @@ Vue.component("http-compression-config-box", {
|
|||||||
brotliRef: null,
|
brotliRef: null,
|
||||||
minLength: {count: 0, "unit": "kb"},
|
minLength: {count: 0, "unit": "kb"},
|
||||||
maxLength: {count: 0, "unit": "kb"},
|
maxLength: {count: 0, "unit": "kb"},
|
||||||
mimeTypes: ["text/*", "application/*", "font/*"],
|
mimeTypes: ["text/*", "application/javascript", "application/json", "application/atom+xml", "application/rss+xml", "application/xhtml+xml", "font/*", "image/svg+xml"],
|
||||||
extensions: [".js", ".json", ".html", ".htm", ".xml", ".css", ".woff2", ".txt"],
|
extensions: [".js", ".json", ".html", ".htm", ".xml", ".css", ".woff2", ".txt"],
|
||||||
conds: null
|
conds: null
|
||||||
}
|
}
|
||||||
@@ -9237,7 +9238,7 @@ Vue.component("http-compression-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用内容压缩</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||||
@@ -9432,7 +9433,7 @@ Vue.component("http-charsets-box", {
|
|||||||
<prior-checkbox :v-config="charsetConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="charsetConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || charsetConfig.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || charsetConfig.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用字符编码</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="charsetConfig.isOn"/>
|
<input type="checkbox" v-model="charsetConfig.isOn"/>
|
||||||
@@ -10063,7 +10064,7 @@ Vue.component("http-access-log-config-box", {
|
|||||||
<prior-checkbox :v-config="accessLog" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="accessLog" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || accessLog.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || accessLog.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">开启访问日志</td>
|
<td class="title">启用访问日志</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="accessLog.isOn"/>
|
<input type="checkbox" v-model="accessLog.isOn"/>
|
||||||
@@ -11180,7 +11181,7 @@ Vue.component("http-access-log-search-box", {
|
|||||||
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http"></tip-icon></div>
|
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST"></tip-icon></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui fields inline" style="margin-top: 0.5em">
|
<div class="ui fields inline" style="margin-top: 0.5em">
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
@@ -11446,7 +11447,7 @@ Vue.component("http-web-root-box", {
|
|||||||
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || rootConfig.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || rootConfig.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否开启静态资源分发</td>
|
<td class="title">启用静态资源分发</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="rootConfig.isOn"/>
|
<input type="checkbox" v-model="rootConfig.isOn"/>
|
||||||
@@ -11585,7 +11586,7 @@ Vue.component("http-webp-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用WebP压缩</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||||
@@ -11848,6 +11849,7 @@ Vue.component("http-firewall-rules-box", {
|
|||||||
window.UPDATING_RULE = null
|
window.UPDATING_RULE = null
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
||||||
|
height: "30em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
that.rules.push(resp.data.rule)
|
that.rules.push(resp.data.rule)
|
||||||
}
|
}
|
||||||
@@ -11857,6 +11859,7 @@ Vue.component("http-firewall-rules-box", {
|
|||||||
window.UPDATING_RULE = rule
|
window.UPDATING_RULE = rule
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
||||||
|
height: "30em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
Vue.set(that.rules, index, resp.data.rule)
|
Vue.set(that.rules, index, resp.data.rule)
|
||||||
}
|
}
|
||||||
@@ -13537,7 +13540,7 @@ Vue.component("firewall-syn-flood-config-box", {
|
|||||||
<td class="title">启用</td>
|
<td class="title">启用</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="config.isOn"></checkbox>
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
<p class="comment">启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用Firewalld。</p>
|
<p class="comment">启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -15696,7 +15699,7 @@ Vue.component("checkbox", {
|
|||||||
this.newValue = ""
|
this.newValue = ""
|
||||||
},
|
},
|
||||||
isChecked: function () {
|
isChecked: function () {
|
||||||
return this.newValue == this.elementValue
|
return (typeof (this.newValue) == "boolean" && this.newValue) || this.newValue == this.elementValue
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -16333,6 +16336,13 @@ Vue.component("datepicker", {
|
|||||||
watch: {
|
watch: {
|
||||||
value: function (v) {
|
value: function (v) {
|
||||||
this.day = v
|
this.day = v
|
||||||
|
|
||||||
|
let picker = this.$refs.dayInput.picker
|
||||||
|
if (picker != null) {
|
||||||
|
if (v != null && /^\d+-\d+-\d+$/.test(v)) {
|
||||||
|
picker.setDate(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -16525,6 +16535,86 @@ Vue.component("finance-user-selector", {
|
|||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Vue.component("node-cache-disk-dirs-box", {
|
||||||
|
props: ["value", "name"],
|
||||||
|
data: function () {
|
||||||
|
let dirs = this.value
|
||||||
|
if (dirs == null) {
|
||||||
|
dirs = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
dirs: dirs,
|
||||||
|
|
||||||
|
isEditing: false,
|
||||||
|
isAdding: false,
|
||||||
|
|
||||||
|
addingPath: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.isAdding = true
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.$refs.addingPath.focus()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
confirm: function () {
|
||||||
|
let addingPath = this.addingPath.trim()
|
||||||
|
if (addingPath.length == 0) {
|
||||||
|
let that = this
|
||||||
|
teaweb.warn("请输入要添加的缓存目录", function () {
|
||||||
|
that.$refs.addingPath.focus()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (addingPath[0] != "/") {
|
||||||
|
addingPath = "/" + addingPath
|
||||||
|
}
|
||||||
|
this.dirs.push({
|
||||||
|
path: addingPath
|
||||||
|
})
|
||||||
|
this.cancel()
|
||||||
|
},
|
||||||
|
cancel: function () {
|
||||||
|
this.addingPath = ""
|
||||||
|
this.isAdding = false
|
||||||
|
this.isEditing = false
|
||||||
|
},
|
||||||
|
remove: function (index) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除此目录吗?", function () {
|
||||||
|
that.dirs.$remove(index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" :name="name" :value="JSON.stringify(dirs)"/>
|
||||||
|
<div style="margin-bottom: 0.3em">
|
||||||
|
<span class="ui label small basic" v-for="(dir, index) in dirs">
|
||||||
|
<i class="icon folder"></i>{{dir.path}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加 -->
|
||||||
|
<div v-if="isAdding">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" style="width: 30em" v-model="addingPath" @keyup.enter="confirm()" @keypress.enter.prevent="1" @keydown.esc="cancel()" ref="addingPath" placeholder="新的缓存目录,比如 /mnt/cache"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button small" type="button" @click.prevent="confirm">确定</button>
|
||||||
|
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!isAdding">
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
|
|
||||||
// 节点登录推荐端口
|
// 节点登录推荐端口
|
||||||
Vue.component("node-login-suggest-ports", {
|
Vue.component("node-login-suggest-ports", {
|
||||||
data: function () {
|
data: function () {
|
||||||
@@ -17812,7 +17902,7 @@ window.REQUEST_COND_COMPONENTS = [{"type":"url-extension","name":"URL扩展名",
|
|||||||
|
|
||||||
window.REQUEST_COND_OPERATORS = [{"description":"判断是否正则表达式匹配","name":"正则表达式匹配","op":"regexp"},{"description":"判断是否正则表达式不匹配","name":"正则表达式不匹配","op":"not regexp"},{"description":"使用字符串对比参数值是否相等于某个值","name":"字符串等于","op":"eq"},{"description":"参数值包含某个前缀","name":"字符串前缀","op":"prefix"},{"description":"参数值包含某个后缀","name":"字符串后缀","op":"suffix"},{"description":"参数值包含另外一个字符串","name":"字符串包含","op":"contains"},{"description":"参数值不包含另外一个字符串","name":"字符串不包含","op":"not contains"},{"description":"使用字符串对比参数值是否不相等于某个值","name":"字符串不等于","op":"not"},{"description":"判断参数值在某个列表中","name":"在列表中","op":"in"},{"description":"判断参数值不在某个列表中","name":"不在列表中","op":"not in"},{"description":"判断小写的扩展名(不带点)在某个列表中","name":"扩展名","op":"file ext"},{"description":"判断MimeType在某个列表中,支持类似于image/*的语法","name":"MimeType","op":"mime type"},{"description":"判断版本号在某个范围内,格式为version1,version2","name":"版本号范围","op":"version range"},{"description":"将参数转换为整数数字后进行对比","name":"整数等于","op":"eq int"},{"description":"将参数转换为可以有小数的浮点数字进行对比","name":"浮点数等于","op":"eq float"},{"description":"将参数转换为数字进行对比","name":"数字大于","op":"gt"},{"description":"将参数转换为数字进行对比","name":"数字大于等于","op":"gte"},{"description":"将参数转换为数字进行对比","name":"数字小于","op":"lt"},{"description":"将参数转换为数字进行对比","name":"数字小于等于","op":"lte"},{"description":"对整数参数值取模,除数为10,对比值为余数","name":"整数取模10","op":"mod 10"},{"description":"对整数参数值取模,除数为100,对比值为余数","name":"整数取模100","op":"mod 100"},{"description":"对整数参数值取模,对比值格式为:除数,余数,比如10,1","name":"整数取模","op":"mod"},{"description":"将参数转换为IP进行对比","name":"IP等于","op":"eq ip"},{"description":"将参数转换为IP进行对比","name":"IP大于","op":"gt ip"},{"description":"将参数转换为IP进行对比","name":"IP大于等于","op":"gte ip"},{"description":"将参数转换为IP进行对比","name":"IP小于","op":"lt ip"},{"description":"将参数转换为IP进行对比","name":"IP小于等于","op":"lte ip"},{"description":"IP在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits","name":"IP范围","op":"ip range"},{"description":"对IP参数值取模,除数为10,对比值为余数","name":"IP取模10","op":"ip mod 10"},{"description":"对IP参数值取模,除数为100,对比值为余数","name":"IP取模100","op":"ip mod 100"},{"description":"对IP参数值取模,对比值格式为:除数,余数,比如10,1","name":"IP取模","op":"ip mod"},{"description":"判断参数值解析后的文件是否存在","name":"文件存在","op":"file exist"},{"description":"判断参数值解析后的文件是否不存在","name":"文件不存在","op":"file not exist"}]
|
window.REQUEST_COND_OPERATORS = [{"description":"判断是否正则表达式匹配","name":"正则表达式匹配","op":"regexp"},{"description":"判断是否正则表达式不匹配","name":"正则表达式不匹配","op":"not regexp"},{"description":"使用字符串对比参数值是否相等于某个值","name":"字符串等于","op":"eq"},{"description":"参数值包含某个前缀","name":"字符串前缀","op":"prefix"},{"description":"参数值包含某个后缀","name":"字符串后缀","op":"suffix"},{"description":"参数值包含另外一个字符串","name":"字符串包含","op":"contains"},{"description":"参数值不包含另外一个字符串","name":"字符串不包含","op":"not contains"},{"description":"使用字符串对比参数值是否不相等于某个值","name":"字符串不等于","op":"not"},{"description":"判断参数值在某个列表中","name":"在列表中","op":"in"},{"description":"判断参数值不在某个列表中","name":"不在列表中","op":"not in"},{"description":"判断小写的扩展名(不带点)在某个列表中","name":"扩展名","op":"file ext"},{"description":"判断MimeType在某个列表中,支持类似于image/*的语法","name":"MimeType","op":"mime type"},{"description":"判断版本号在某个范围内,格式为version1,version2","name":"版本号范围","op":"version range"},{"description":"将参数转换为整数数字后进行对比","name":"整数等于","op":"eq int"},{"description":"将参数转换为可以有小数的浮点数字进行对比","name":"浮点数等于","op":"eq float"},{"description":"将参数转换为数字进行对比","name":"数字大于","op":"gt"},{"description":"将参数转换为数字进行对比","name":"数字大于等于","op":"gte"},{"description":"将参数转换为数字进行对比","name":"数字小于","op":"lt"},{"description":"将参数转换为数字进行对比","name":"数字小于等于","op":"lte"},{"description":"对整数参数值取模,除数为10,对比值为余数","name":"整数取模10","op":"mod 10"},{"description":"对整数参数值取模,除数为100,对比值为余数","name":"整数取模100","op":"mod 100"},{"description":"对整数参数值取模,对比值格式为:除数,余数,比如10,1","name":"整数取模","op":"mod"},{"description":"将参数转换为IP进行对比","name":"IP等于","op":"eq ip"},{"description":"将参数转换为IP进行对比","name":"IP大于","op":"gt ip"},{"description":"将参数转换为IP进行对比","name":"IP大于等于","op":"gte ip"},{"description":"将参数转换为IP进行对比","name":"IP小于","op":"lt ip"},{"description":"将参数转换为IP进行对比","name":"IP小于等于","op":"lte ip"},{"description":"IP在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits","name":"IP范围","op":"ip range"},{"description":"对IP参数值取模,除数为10,对比值为余数","name":"IP取模10","op":"ip mod 10"},{"description":"对IP参数值取模,除数为100,对比值为余数","name":"IP取模100","op":"ip mod 100"},{"description":"对IP参数值取模,对比值格式为:除数,余数,比如10,1","name":"IP取模","op":"ip mod"},{"description":"判断参数值解析后的文件是否存在","name":"文件存在","op":"file exist"},{"description":"判断参数值解析后的文件是否不存在","name":"文件不存在","op":"file not exist"}]
|
||||||
|
|
||||||
window.REQUEST_VARIABLES = [{"code":"${edgeVersion}","description":"","name":"边缘节点版本"},{"code":"${remoteAddr}","description":"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适合前端有别的反向代理服务时使用,存在伪造的风险","name":"客户端地址(IP)"},{"code":"${rawRemoteAddr}","description":"返回直接连接服务的客户端原始IP地址","name":"客户端地址(IP)"},{"code":"${remotePort}","description":"","name":"客户端端口"},{"code":"${remoteUser}","description":"","name":"客户端用户名"},{"code":"${requestURI}","description":"比如/hello?name=lily","name":"请求URI"},{"code":"${requestPath}","description":"比如/hello","name":"请求路径(不包括参数)"},{"code":"${requestURL}","description":"比如https://example.com/hello?name=lily","name":"完整的请求URL"},{"code":"${requestLength}","description":"","name":"请求内容长度"},{"code":"${requestMethod}","description":"比如GET、POST","name":"请求方法"},{"code":"${requestFilename}","description":"","name":"请求文件路径"},{"code":"${scheme}","description":"","name":"请求协议,http或https"},{"code":"${proto}","description:":"类似于HTTP/1.0","name":"包含版本的HTTP请求协议"},{"code":"${timeISO8601}","description":"比如2018-07-16T23:52:24.839+08:00","name":"ISO 8601格式的时间"},{"code":"${timeLocal}","description":"比如17/Jul/2018:09:52:24 +0800","name":"本地时间"},{"code":"${msec}","description":"比如1531756823.054","name":"带有毫秒的时间"},{"code":"${timestamp}","description":"","name":"unix时间戳,单位为秒"},{"code":"${host}","description":"","name":"主机名"},{"code":"${serverName}","description":"","name":"接收请求的服务器名"},{"code":"${serverPort}","description":"","name":"接收请求的服务器端口"},{"code":"${referer}","description":"","name":"请求来源URL"},{"code":"${referer.host}","description":"","name":"请求来源URL域名"},{"code":"${userAgent}","description":"","name":"客户端信息"},{"code":"${contentType}","description":"","name":"请求头部的Content-Type"},{"code":"${cookies}","description":"","name":"所有cookie组合字符串"},{"code":"${cookie.NAME}","description":"","name":"单个cookie值"},{"code":"${isArgs}","description":"如果URL有参数,则值为`?`;否则,则值为空","name":"问号(?)标记"},{"code":"${args}","description":"","name":"所有参数组合字符串"},{"code":"${arg.NAME}","description":"","name":"单个参数值"},{"code":"${headers}","description":"","name":"所有Header信息组合字符串"},{"code":"${header.NAME}","description":"","name":"单个Header值"},{"code":"${geo.country.name}","description":"","name":"国家/地区名称"},{"code":"${geo.country.id}","description":"","name":"国家/地区ID"},{"code":"${geo.province.name}","description":"目前只包含中国省份","name":"省份名称"},{"code":"${geo.province.id}","description":"目前只包含中国省份","name":"省份ID"},{"code":"${geo.city.name}","description":"目前只包含中国城市","name":"城市名称"},{"code":"${geo.city.id}","description":"目前只包含中国城市","name":"城市名称"},{"code":"${isp.name}","description":"","name":"ISP服务商名称"},{"code":"${isp.id}","description":"","name":"ISP服务商ID"},{"code":"${browser.os.name}","description":"客户端所在操作系统名称","name":"操作系统名称"},{"code":"${browser.os.version}","description":"客户端所在操作系统版本","name":"操作系统版本"},{"code":"${browser.name}","description":"客户端浏览器名称","name":"浏览器名称"},{"code":"${browser.version}","description":"客户端浏览器版本","name":"浏览器版本"},{"code":"${browser.isMobile}","description":"如果客户端是手机,则值为1,否则为0","name":"手机标识"}]
|
window.REQUEST_VARIABLES = [{"code":"${edgeVersion}","description":"","name":"边缘节点版本"},{"code":"${remoteAddr}","description":"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适合前端有别的反向代理服务时使用,存在伪造的风险","name":"客户端地址(IP)"},{"code":"${rawRemoteAddr}","description":"返回直接连接服务的客户端原始IP地址","name":"客户端地址(IP)"},{"code":"${remotePort}","description":"","name":"客户端端口"},{"code":"${remoteUser}","description":"","name":"客户端用户名"},{"code":"${requestURI}","description":"比如/hello?name=lily","name":"请求URI"},{"code":"${requestPath}","description":"比如/hello","name":"请求路径(不包括参数)"},{"code":"${requestURL}","description":"比如https://example.com/hello?name=lily","name":"完整的请求URL"},{"code":"${requestLength}","description":"","name":"请求内容长度"},{"code":"${requestMethod}","description":"比如GET、POST","name":"请求方法"},{"code":"${requestFilename}","description":"","name":"请求文件路径"},{"code":"${scheme}","description":"","name":"请求协议,http或https"},{"code":"${proto}","description:":"类似于HTTP/1.0","name":"包含版本的HTTP请求协议"},{"code":"${timeISO8601}","description":"比如2018-07-16T23:52:24.839+08:00","name":"ISO 8601格式的时间"},{"code":"${timeLocal}","description":"比如17/Jul/2018:09:52:24 +0800","name":"本地时间"},{"code":"${msec}","description":"比如1531756823.054","name":"带有毫秒的时间"},{"code":"${timestamp}","description":"","name":"unix时间戳,单位为秒"},{"code":"${host}","description":"","name":"主机名"},{"code":"${cname}","description":"比如38b48e4f.goedge.cn","name":"当前网站的CNAME"},{"code":"${serverName}","description":"","name":"接收请求的服务器名"},{"code":"${serverPort}","description":"","name":"接收请求的服务器端口"},{"code":"${referer}","description":"","name":"请求来源URL"},{"code":"${referer.host}","description":"","name":"请求来源URL域名"},{"code":"${userAgent}","description":"","name":"客户端信息"},{"code":"${contentType}","description":"","name":"请求头部的Content-Type"},{"code":"${cookies}","description":"","name":"所有cookie组合字符串"},{"code":"${cookie.NAME}","description":"","name":"单个cookie值"},{"code":"${isArgs}","description":"如果URL有参数,则值为`?`;否则,则值为空","name":"问号(?)标记"},{"code":"${args}","description":"","name":"所有参数组合字符串"},{"code":"${arg.NAME}","description":"","name":"单个参数值"},{"code":"${headers}","description":"","name":"所有Header信息组合字符串"},{"code":"${header.NAME}","description":"","name":"单个Header值"},{"code":"${geo.country.name}","description":"","name":"国家/地区名称"},{"code":"${geo.country.id}","description":"","name":"国家/地区ID"},{"code":"${geo.province.name}","description":"目前只包含中国省份","name":"省份名称"},{"code":"${geo.province.id}","description":"目前只包含中国省份","name":"省份ID"},{"code":"${geo.city.name}","description":"目前只包含中国城市","name":"城市名称"},{"code":"${geo.city.id}","description":"目前只包含中国城市","name":"城市名称"},{"code":"${isp.name}","description":"","name":"ISP服务商名称"},{"code":"${isp.id}","description":"","name":"ISP服务商ID"},{"code":"${browser.os.name}","description":"客户端所在操作系统名称","name":"操作系统名称"},{"code":"${browser.os.version}","description":"客户端所在操作系统版本","name":"操作系统版本"},{"code":"${browser.name}","description":"客户端浏览器名称","name":"浏览器名称"},{"code":"${browser.version}","description":"客户端浏览器版本","name":"浏览器版本"},{"code":"${browser.isMobile}","description":"如果客户端是手机,则值为1,否则为0","name":"手机标识"}]
|
||||||
|
|
||||||
window.METRIC_HTTP_KEYS = [{"name":"客户端地址(IP)","code":"${remoteAddr}","description":"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适用于前端可能有别的反向代理的情形,存在被伪造的可能","icon":""},{"name":"直接客户端地址(IP)","code":"${rawRemoteAddr}","description":"返回直接连接服务的客户端原始IP地址","icon":""},{"name":"客户端用户名","code":"${remoteUser}","description":"通过基本认证填入的用户名","icon":""},{"name":"请求URI","code":"${requestURI}","description":"包含参数,比如/hello?name=lily","icon":""},{"name":"请求路径","code":"${requestPath}","description":"不包含参数,比如/hello","icon":""},{"name":"完整URL","code":"${requestURL}","description":"比如https://example.com/hello?name=lily","icon":""},{"name":"请求方法","code":"${requestMethod}","description":"比如GET、POST等","icon":""},{"name":"请求协议Scheme","code":"${scheme}","description":"http或https","icon":""},{"name":"文件扩展名","code":"${requestPathExtension}","description":"请求路径中的文件扩展名,包括点符号,比如.html、.png","icon":""},{"name":"主机名","code":"${host}","description":"通常是请求的域名","icon":""},{"name":"请求协议Proto","code":"${proto}","description":"包含版本的HTTP请求协议,类似于HTTP/1.0","icon":""},{"name":"HTTP协议","code":"${proto}","description":"包含版本的HTTP请求协议,类似于HTTP/1.0","icon":""},{"name":"URL参数值","code":"${arg.NAME}","description":"单个URL参数值","icon":""},{"name":"请求来源URL","code":"${referer}","description":"请求来源Referer URL","icon":""},{"name":"请求来源URL域名","code":"${referer.host}","description":"请求来源Referer URL域名","icon":""},{"name":"Header值","code":"${header.NAME}","description":"单个Header值,比如${header.User-Agent}","icon":""},{"name":"Cookie值","code":"${cookie.NAME}","description":"单个cookie值,比如${cookie.sid}","icon":""},{"name":"状态码","code":"${status}","description":"","icon":""},{"name":"响应的Content-Type值","code":"${response.contentType}","description":"","icon":""}]
|
window.METRIC_HTTP_KEYS = [{"name":"客户端地址(IP)","code":"${remoteAddr}","description":"会依次根据X-Forwarded-For、X-Real-IP、RemoteAddr获取,适用于前端可能有别的反向代理的情形,存在被伪造的可能","icon":""},{"name":"直接客户端地址(IP)","code":"${rawRemoteAddr}","description":"返回直接连接服务的客户端原始IP地址","icon":""},{"name":"客户端用户名","code":"${remoteUser}","description":"通过基本认证填入的用户名","icon":""},{"name":"请求URI","code":"${requestURI}","description":"包含参数,比如/hello?name=lily","icon":""},{"name":"请求路径","code":"${requestPath}","description":"不包含参数,比如/hello","icon":""},{"name":"完整URL","code":"${requestURL}","description":"比如https://example.com/hello?name=lily","icon":""},{"name":"请求方法","code":"${requestMethod}","description":"比如GET、POST等","icon":""},{"name":"请求协议Scheme","code":"${scheme}","description":"http或https","icon":""},{"name":"文件扩展名","code":"${requestPathExtension}","description":"请求路径中的文件扩展名,包括点符号,比如.html、.png","icon":""},{"name":"主机名","code":"${host}","description":"通常是请求的域名","icon":""},{"name":"请求协议Proto","code":"${proto}","description":"包含版本的HTTP请求协议,类似于HTTP/1.0","icon":""},{"name":"HTTP协议","code":"${proto}","description":"包含版本的HTTP请求协议,类似于HTTP/1.0","icon":""},{"name":"URL参数值","code":"${arg.NAME}","description":"单个URL参数值","icon":""},{"name":"请求来源URL","code":"${referer}","description":"请求来源Referer URL","icon":""},{"name":"请求来源URL域名","code":"${referer.host}","description":"请求来源Referer URL域名","icon":""},{"name":"Header值","code":"${header.NAME}","description":"单个Header值,比如${header.User-Agent}","icon":""},{"name":"Cookie值","code":"${cookie.NAME}","description":"单个cookie值,比如${cookie.sid}","icon":""},{"name":"状态码","code":"${status}","description":"","icon":""},{"name":"响应的Content-Type值","code":"${response.contentType}","description":"","icon":""}]
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Vue.component("checkbox", {
|
|||||||
this.newValue = ""
|
this.newValue = ""
|
||||||
},
|
},
|
||||||
isChecked: function () {
|
isChecked: function () {
|
||||||
return this.newValue == this.elementValue
|
return (typeof (this.newValue) == "boolean" && this.newValue) || this.newValue == this.elementValue
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ Vue.component("datepicker", {
|
|||||||
watch: {
|
watch: {
|
||||||
value: function (v) {
|
value: function (v) {
|
||||||
this.day = v
|
this.day = v
|
||||||
|
|
||||||
|
let picker = this.$refs.dayInput.picker
|
||||||
|
if (picker != null) {
|
||||||
|
if (v != null && /^\d+-\d+-\d+$/.test(v)) {
|
||||||
|
picker.setDate(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
79
web/public/js/components/node/node-cache-disk-dirs-box.js
Normal file
79
web/public/js/components/node/node-cache-disk-dirs-box.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
Vue.component("node-cache-disk-dirs-box", {
|
||||||
|
props: ["value", "name"],
|
||||||
|
data: function () {
|
||||||
|
let dirs = this.value
|
||||||
|
if (dirs == null) {
|
||||||
|
dirs = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
dirs: dirs,
|
||||||
|
|
||||||
|
isEditing: false,
|
||||||
|
isAdding: false,
|
||||||
|
|
||||||
|
addingPath: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.isAdding = true
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.$refs.addingPath.focus()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
confirm: function () {
|
||||||
|
let addingPath = this.addingPath.trim()
|
||||||
|
if (addingPath.length == 0) {
|
||||||
|
let that = this
|
||||||
|
teaweb.warn("请输入要添加的缓存目录", function () {
|
||||||
|
that.$refs.addingPath.focus()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (addingPath[0] != "/") {
|
||||||
|
addingPath = "/" + addingPath
|
||||||
|
}
|
||||||
|
this.dirs.push({
|
||||||
|
path: addingPath
|
||||||
|
})
|
||||||
|
this.cancel()
|
||||||
|
},
|
||||||
|
cancel: function () {
|
||||||
|
this.addingPath = ""
|
||||||
|
this.isAdding = false
|
||||||
|
this.isEditing = false
|
||||||
|
},
|
||||||
|
remove: function (index) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除此目录吗?", function () {
|
||||||
|
that.dirs.$remove(index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" :name="name" :value="JSON.stringify(dirs)"/>
|
||||||
|
<div style="margin-bottom: 0.3em">
|
||||||
|
<span class="ui label small basic" v-for="(dir, index) in dirs">
|
||||||
|
<i class="icon folder"></i>{{dir.path}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加 -->
|
||||||
|
<div v-if="isAdding">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" style="width: 30em" v-model="addingPath" @keyup.enter="confirm()" @keypress.enter.prevent="1" @keydown.esc="cancel()" ref="addingPath" placeholder="新的缓存目录,比如 /mnt/cache"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button class="ui button small" type="button" @click.prevent="confirm">确定</button>
|
||||||
|
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!isAdding">
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -13,9 +13,9 @@ Vue.component("ns-access-log-box", {
|
|||||||
if (accessLog.recordValue == null || accessLog.recordValue.length == 0) {
|
if (accessLog.recordValue == null || accessLog.recordValue.length == 0) {
|
||||||
isFailure = true
|
isFailure = true
|
||||||
}
|
}
|
||||||
} else if (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) {
|
|
||||||
isFailure = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 没有找到记录的不需要高亮显示,防止管理员看到红色就心理恐慌
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ Vue.component("domains-box", {
|
|||||||
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)<span v-if="vSupportWildcard == undefined">、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)</span>。</p>
|
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)<span v-if="vSupportWildcard == undefined">、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)</span>;如果域名后有端口,请加上端口号。</p>
|
||||||
<p class="comment" v-if="!supportWildcard">只支持普通域名(<code-label>example.com</code-label>、<code-label>www.example.com</code-label>)。</p>
|
<p class="comment" v-if="!supportWildcard">只支持普通域名(<code-label>example.com</code-label>、<code-label>www.example.com</code-label>)。</p>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Vue.component("http-access-log-config-box", {
|
|||||||
<prior-checkbox :v-config="accessLog" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="accessLog" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || accessLog.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || accessLog.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">开启访问日志</td>
|
<td class="title">启用访问日志</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="accessLog.isOn"/>
|
<input type="checkbox" v-model="accessLog.isOn"/>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ Vue.component("http-access-log-search-box", {
|
|||||||
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http"></tip-icon></div>
|
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST"></tip-icon></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui fields inline" style="margin-top: 0.5em">
|
<div class="ui fields inline" style="margin-top: 0.5em">
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Vue.component("http-charsets-box", {
|
|||||||
<prior-checkbox :v-config="charsetConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="charsetConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || charsetConfig.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || charsetConfig.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用字符编码</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="charsetConfig.isOn"/>
|
<input type="checkbox" v-model="charsetConfig.isOn"/>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Vue.component("http-compression-config-box", {
|
|||||||
brotliRef: null,
|
brotliRef: null,
|
||||||
minLength: {count: 0, "unit": "kb"},
|
minLength: {count: 0, "unit": "kb"},
|
||||||
maxLength: {count: 0, "unit": "kb"},
|
maxLength: {count: 0, "unit": "kb"},
|
||||||
mimeTypes: ["text/*", "application/*", "font/*"],
|
mimeTypes: ["text/*", "application/javascript", "application/json", "application/atom+xml", "application/rss+xml", "application/xhtml+xml", "font/*", "image/svg+xml"],
|
||||||
extensions: [".js", ".json", ".html", ".htm", ".xml", ".css", ".woff2", ".txt"],
|
extensions: [".js", ".json", ".html", ".htm", ".xml", ".css", ".woff2", ".txt"],
|
||||||
conds: null
|
conds: null
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ Vue.component("http-compression-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用内容压缩</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Vue.component("http-firewall-rules-box", {
|
|||||||
window.UPDATING_RULE = null
|
window.UPDATING_RULE = null
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
||||||
|
height: "30em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
that.rules.push(resp.data.rule)
|
that.rules.push(resp.data.rule)
|
||||||
}
|
}
|
||||||
@@ -23,6 +24,7 @@ Vue.component("http-firewall-rules-box", {
|
|||||||
window.UPDATING_RULE = rule
|
window.UPDATING_RULE = rule
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
||||||
|
height: "30em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
Vue.set(that.rules, index, resp.data.rule)
|
Vue.set(that.rules, index, resp.data.rule)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ Vue.component("http-host-redirect-box", {
|
|||||||
<div style="margin-top: 0.4em">
|
<div style="margin-top: 0.4em">
|
||||||
<grey-label><strong>域名跳转</strong></grey-label>
|
<grey-label><strong>域名跳转</strong></grey-label>
|
||||||
<grey-label v-if="redirect.domainAfterScheme != null && redirect.domainAfterScheme.length > 0">{{redirect.domainAfterScheme}}</grey-label>
|
<grey-label v-if="redirect.domainAfterScheme != null && redirect.domainAfterScheme.length > 0">{{redirect.domainAfterScheme}}</grey-label>
|
||||||
|
<grey-label v-if="redirect.domainBeforeIgnorePorts">忽略端口</grey-label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="redirect.type == 'port'">
|
<div v-if="redirect.type == 'port'">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Vue.component("http-stat-config-box", {
|
|||||||
<prior-checkbox :v-config="stat" v-if="vIsLocation || vIsGroup" ></prior-checkbox>
|
<prior-checkbox :v-config="stat" v-if="vIsLocation || vIsGroup" ></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || stat.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || stat.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否开启统计</td>
|
<td class="title">启用统计</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="stat.isOn"/>
|
<input type="checkbox" v-model="stat.isOn"/>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Vue.component("http-web-root-box", {
|
|||||||
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || rootConfig.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || rootConfig.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否开启静态资源分发</td>
|
<td class="title">启用静态资源分发</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="rootConfig.isOn"/>
|
<input type="checkbox" v-model="rootConfig.isOn"/>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ Vue.component("http-webp-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用</td>
|
<td class="title">启用WebP压缩</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Vue.component("http-websocket-box", {
|
|||||||
<prior-checkbox :v-config="websocketRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="websocketRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="((!vIsLocation && !vIsGroup) || websocketRef.isPrior)">
|
<tbody v-show="((!vIsLocation && !vIsGroup) || websocketRef.isPrior)">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">启用配置</td>
|
<td class="title">启用Websocket</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" v-model="websocketRef.isOn"/>
|
<input type="checkbox" v-model="websocketRef.isOn"/>
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ window.teaweb = {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typeof (element) == "string") {
|
if (typeof (element) == "string") {
|
||||||
element = document.getElementById(element);
|
element = document.getElementById(element);
|
||||||
}
|
}
|
||||||
@@ -112,6 +111,8 @@ window.teaweb = {
|
|||||||
},
|
},
|
||||||
reposition: !bottomLeft
|
reposition: !bottomLeft
|
||||||
})
|
})
|
||||||
|
|
||||||
|
element.picker = picker
|
||||||
},
|
},
|
||||||
formatBytes: function (bytes) {
|
formatBytes: function (bytes) {
|
||||||
bytes = Math.ceil(bytes);
|
bytes = Math.ceil(bytes);
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
<span class="item">|</span>
|
<span class="item">|</span>
|
||||||
<menu-item :href="'/admins/admin?adminId=' + admin.id" code="index">"{{admin.fullname}}" 详情</menu-item>
|
<menu-item :href="'/admins/admin?adminId=' + admin.id" code="index">"{{admin.fullname}}" 详情</menu-item>
|
||||||
<menu-item :href="'/admins/update?adminId=' + admin.id" code="update">修改</menu-item>
|
<menu-item :href="'/admins/update?adminId=' + admin.id" code="update">修改</menu-item>
|
||||||
<menu-item :href="'/admins/accessKeys?adminId=' + admin.id" code="accessKey">API AccessKey({{admin.countAccessKeys}})</menu-item>
|
<menu-item :href="'/admins/accesskeys?adminId=' + admin.id" code="accessKey">API AccessKey({{admin.countAccessKeys}})</menu-item>
|
||||||
</first-menu>
|
</first-menu>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.createAccessKey = function () {
|
this.createAccessKey = function () {
|
||||||
teaweb.popup("/admins/accessKeys/createPopup?adminId=" + this.admin.id, {
|
teaweb.popup("/admins/accesskeys/createPopup?adminId=" + this.admin.id, {
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="restIsOn">
|
<tr v-if="restIsOn">
|
||||||
<td class="color-border">HTTP API监听端口</td>
|
<td class="color-border">HTTP API监听端口 *</td>
|
||||||
<td>
|
<td>
|
||||||
<network-addresses-box :v-name="'restListensJSON'" :v-server-type="'httpWeb'" @change="changeRestListens"></network-addresses-box>
|
<network-addresses-box :v-name="'restListensJSON'" :v-server-type="'httpWeb'" @change="changeRestListens"></network-addresses-box>
|
||||||
<p class="comment">HTTP API节点进程监听的网络端口。</p>
|
<p class="comment">HTTP API节点进程监听的网络端口,需要和当前节点的GRPC端口不同。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>是否启用</td>
|
<td>启用当前节点</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Tea.context(function () {
|
|||||||
|
|
||||||
this.hasHTTPS = this.grpcAddrs.$any(function (k, v) {
|
this.hasHTTPS = this.grpcAddrs.$any(function (k, v) {
|
||||||
return v.protocol == "https"
|
return v.protocol == "https"
|
||||||
}) || (this.node.restIsOn && this.restAddrs.$any(function (k, v) {
|
}) || (this.restIsOn && this.restAddrs.$any(function (k, v) {
|
||||||
return v.protocol == "https"
|
return v.protocol == "https"
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="node.restIsOn">
|
<tr v-if="node.restIsOn">
|
||||||
<td class="color-border">HTTP API监听端口</td>
|
<td class="color-border">HTTP API监听端口 *</td>
|
||||||
<td>
|
<td>
|
||||||
<network-addresses-box :v-name="'restListensJSON'" :v-server-type="'httpWeb'" @change="changeRestListens" :v-addresses="node.restListens"></network-addresses-box>
|
<network-addresses-box :v-name="'restListensJSON'" :v-server-type="'httpWeb'" @change="changeRestListens" :v-addresses="node.restListens"></network-addresses-box>
|
||||||
<p class="comment">HTTP API节点进程监听的网络端口。</p>
|
<p class="comment">HTTP API节点进程监听的网络端口,需要和当前节点的GRPC端口不同。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>启用</td>
|
<td>启用当前节点</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input type="checkbox" name="isOn" value="1" v-model="node.isOn"/>
|
<input type="checkbox" name="isOn" value="1" v-model="node.isOn"/>
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
<menu-item :href="'/clusters/cluster?clusterId=' + clusterId">{{currentClusterName}}</menu-item>
|
<menu-item :href="'/clusters/cluster?clusterId=' + clusterId">{{currentClusterName}}</menu-item>
|
||||||
<span class="disabled item" style="padding: 0">»</span>
|
<span class="disabled item" style="padding: 0">»</span>
|
||||||
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId" code="index">节点列表</menu-item>
|
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId" code="index">节点列表</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/createNode?clusterId=' + clusterId" code="create">创建节点</menu-item>
|
<span class="disabled item">|</span>
|
||||||
|
<menu-item :href="'/clusters/cluster/createNode?clusterId=' + clusterId" code="create">[创建节点]</menu-item>
|
||||||
|
<span class="disabled item">|</span>
|
||||||
<menu-item :href="'/clusters/cluster/installManual?clusterId=' + clusterId" code="install">安装升级</menu-item>
|
<menu-item :href="'/clusters/cluster/installManual?clusterId=' + clusterId" code="install">安装升级</menu-item>
|
||||||
<menu-item :href="'/clusters/cluster/groups?clusterId=' + clusterId" code="group">节点分组</menu-item>
|
<menu-item :href="'/clusters/cluster/groups?clusterId=' + clusterId" code="group">节点分组</menu-item>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="title">节点名称 *</td>
|
<td class="title">节点名称 *</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="name" maxlength="50" ref="focus"/>
|
<input type="text" name="name" maxlength="50" ref="focus" v-model="name" @input="changeName"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IP地址 *</td>
|
<td>IP地址 *</td>
|
||||||
<td>
|
<td>
|
||||||
<node-ip-addresses-box></node-ip-addresses-box>
|
<node-ip-addresses-box></node-ip-addresses-box>
|
||||||
<p class="comment">用于访问节点和域名解析等。</p>
|
<p class="comment">用于访问节点和域名解析等<span v-if="defaultIP.length > 0"><strong>,如果没有填写默认为{{defaultIP}}</strong></span>。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="dnsRoutes.length > 0">
|
<tr v-if="dnsRoutes.length > 0">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Tea.context(function () {
|
|||||||
this.sshPort = ""
|
this.sshPort = ""
|
||||||
this.grantId = 0
|
this.grantId = 0
|
||||||
this.step = "info"
|
this.step = "info"
|
||||||
|
this.name = ""
|
||||||
|
|
||||||
this.success = function (resp) {
|
this.success = function (resp) {
|
||||||
this.node = resp.data.node
|
this.node = resp.data.node
|
||||||
@@ -170,4 +171,32 @@ Tea.context(function () {
|
|||||||
this.createNext = function () {
|
this.createNext = function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.defaultIP = ""
|
||||||
|
this.changeName = function () {
|
||||||
|
if (this.validateIP(this.name)) {
|
||||||
|
this.defaultIP = this.name
|
||||||
|
} else {
|
||||||
|
this.defaultIP = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.validateIP = function (v) {
|
||||||
|
// 目前只支持ipv4
|
||||||
|
let pieces = v.split(".")
|
||||||
|
if (pieces.length != 4) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (let i = 0; i < pieces.length; i++) {
|
||||||
|
if (!/^\d{1,3}$/.test(pieces[i])) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let p = parseInt(pieces[i], 10)
|
||||||
|
if (p > 255) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
{$template "/code_editor"}
|
{$template "/code_editor"}
|
||||||
|
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<p>在官网下载节点安装包,然后通过修改节点安装包中的<code-label>configs/cluster.yaml</code-label>,启动后会自动注册节点。</p>
|
<p>在官网下载节点安装包,然后通过修改节点安装包中的<code-label>configs/cluster.yaml</code-label>(如果此配置文件尚未创建,你需要先创建)为以下内容,启动后会自动注册节点。</p>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">cluster.yaml<br/>
|
<td class="title">cluster.yaml<br/>
|
||||||
|
|||||||
@@ -143,13 +143,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>CPU线程数</td>
|
|
||||||
<td>
|
|
||||||
<span v-if="node.maxCPU > 0">{{node.maxCPU}}线程</span>
|
|
||||||
<span v-else class="disabled">没有限制。</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>缓存磁盘容量</td>
|
<td>缓存磁盘容量</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -167,6 +160,22 @@
|
|||||||
<size-capacity-view :v-value="node.maxCacheMemoryCapacity"></size-capacity-view>
|
<size-capacity-view :v-value="node.maxCacheMemoryCapacity"></size-capacity-view>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CPU线程数</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="node.maxCPU > 0">{{node.maxCPU}}线程</span>
|
||||||
|
<span v-else class="disabled">没有限制。</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>API节点地址</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="node.apiNodeAddrs != null && node.apiNodeAddrs.length > 0">
|
||||||
|
<span v-for="addr in node.apiNodeAddrs" class="ui label basic small">{{addr}}</span>
|
||||||
|
</div>
|
||||||
|
<span v-else class="disabled">使用全局设置</span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -226,11 +235,28 @@
|
|||||||
<td>主程序位置</td>
|
<td>主程序位置</td>
|
||||||
<td>{{node.status.exePath}}</td>
|
<td>{{node.status.exePath}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>最近API连接状况</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="node.status.apiSuccessPercent > 0 && node.status.apiAvgCostSeconds > 0">
|
||||||
|
<span v-if="node.status.apiSuccessPercent <= 50" class="red">连接错误异常严重({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||||
|
<span v-else-if="node.status.apiSuccessPercent <= 80" class="red">连接错误较多({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||||
|
<span v-else-if="node.status.apiSuccessPercent < 100" class="orange">有连接错误发生({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||||
|
<span v-else>
|
||||||
|
<span v-if="node.status.apiAvgCostSeconds <= 1" class="green">连接良好</span>
|
||||||
|
<span v-else-if="node.status.apiAvgCostSeconds <= 5" class="orange">连接基本稳定(平均{{round(node.status.apiAvgCostSeconds)}}秒)</span>
|
||||||
|
<span v-else-if="node.status.apiAvgCostSeconds <= 10" class="orange">连接速度较慢(平均{{round(node.status.apiAvgCostSeconds)}}秒)</span>
|
||||||
|
<span v-else class="red">连接非常慢(平均{{round(node.status.apiAvgCostSeconds)}}秒),请改善当前节点和API节点之间通讯</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span v-else class="disabled">尚未上报数据</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr v-if="nodeDatetime.length > 0">
|
<tr v-if="nodeDatetime.length > 0">
|
||||||
<td>上次更新时间</td>
|
<td>上次更新时间</td>
|
||||||
<td>
|
<td>
|
||||||
{{nodeDatetime}}
|
{{nodeDatetime}}
|
||||||
<p class="comment" v-if="nodeTimeDiff > 3"><span class="red">当前节点时间与API节点时间相差 {{nodeTimeDiff}} 秒,请同步节点时间。</span></p>
|
<p class="comment" v-if="nodeTimeDiff > 30"><span class="red">当前节点时间与API节点时间相差 {{nodeTimeDiff}} 秒,请同步节点时间。</span></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -32,4 +32,8 @@ Tea.context(function () {
|
|||||||
this.isStopping = false
|
this.isStopping = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.round = function (f) {
|
||||||
|
return Math.round(f * 100) / 100
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -15,10 +15,17 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>磁盘缓存目录</td>
|
<td>磁盘缓存主目录</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="cacheDiskDir" maxlength="500" value="" v-model="node.cacheDiskDir"/>
|
<input type="text" name="cacheDiskDir" maxlength="500" value="" v-model="node.cacheDiskDir"/>
|
||||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。不填则表示使用集群缓存策略中定义的目录。</p>
|
<p class="comment">存放文件缓存的主目录,通常填写绝对路径。不填则表示使用集群缓存策略中定义的目录。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>其他磁盘缓存目录</td>
|
||||||
|
<td>
|
||||||
|
<node-cache-disk-dirs-box name="cacheDiskSubDirsJSON" v-model="node.cacheDiskSubDirs"></node-cache-disk-dirs-box>
|
||||||
|
<p class="comment">除了主目录外,可以在这里添加别的可用于缓存的目录;缓存目录有变更时(添加、删除或修改)需要手动将这些缓存目录清空。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<td class="title">SSH主机地址</td>
|
<td class="title">SSH主机地址</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="sshHost" maxlength="64" v-model="sshHost"/>
|
<input type="text" name="sshHost" maxlength="64" v-model="sshHost"/>
|
||||||
<p class="comment"><span v-if="hostIsAutoFilled"><strong>已自动填充,需要保存</strong>。</span>比如192.168.1.100。</p>
|
<p class="comment"><span v-if="hostIsAutoFilled" class="red"><strong>已自动填充</strong>,需要点击"保存"按钮后生效。</span>比如192.168.1.100。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="ui message" v-if="isTesting">正在测试是否连接 ...</div>
|
<div class="ui message" v-if="isTesting">正在测试连接 ...</div>
|
||||||
<div class="ui message green" v-if="resp != null && resp.isOk">连接成功!</div>
|
<div class="ui message green" v-if="resp != null && resp.isOk">连接成功!</div>
|
||||||
<div class="ui message red" v-if="resp != null && !resp.isOk">连接失败:{{resp.error}}</div>
|
<div class="ui message red" v-if="resp != null && !resp.isOk">连接失败:{{resp.error}}</div>
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,19 @@
|
|||||||
<h4>DNS解析</h4>
|
<h4>DNS解析</h4>
|
||||||
<dns-resolver-config-box :v-dns-resolver-config="dnsResolverConfig"></dns-resolver-config-box>
|
<dns-resolver-config-box :v-dns-resolver-config="dnsResolverConfig"></dns-resolver-config-box>
|
||||||
|
|
||||||
|
<h4>API相关</h4>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">API节点地址</td>
|
||||||
|
<td>
|
||||||
|
<div style="margin-bottom: 0.5em">
|
||||||
|
<api-node-addresses-box :v-name="'apiNodeAddrsJSON'" :v-addrs="apiNodeAddrs"></api-node-addresses-box>
|
||||||
|
</div>
|
||||||
|
<p class="comment">当前节点单独使用的API节点设置。<pro-warning-label></pro-warning-label></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<submit-btn></submit-btn>
|
<submit-btn></submit-btn>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -19,4 +19,17 @@ a.small {
|
|||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.node-name-td {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.node-name-td .icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -1em;
|
||||||
|
}
|
||||||
|
.node-name-td:hover .icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=nodes.css.map */
|
/*# sourceMappingURL=nodes.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["nodes.less"],"names":[],"mappings":"AAAA,MAAO;EACN,oBAAA;;AAGD,CACC;EACC,iCAAA;;AAIF,WACC;EACC,kBAAA;EACA,aAAA;;AAIF,WAAW,UACV;EACC,eAAA;EACA,cAAA;;AAIF,WAAW,MACV;EACC,eAAA;;AAIF,CAAC;EACA,gBAAA;EACA,kBAAA","file":"nodes.css"}
|
{"version":3,"sources":["nodes.less"],"names":[],"mappings":"AAAA,MAAO;EACN,oBAAA;;AAGD,CACC;EACC,iCAAA;;AAIF,WACC;EACC,kBAAA;EACA,aAAA;;AAIF,WAAW,UACV;EACC,eAAA;EACA,cAAA;;AAIF,WAAW,MACV;EACC,eAAA;;AAIF,CAAC;EACA,gBAAA;EACA,kBAAA;;AAGD;EACC,kBAAA;;AADD,aAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,gBAAA;;AAIF,aAAa,MACZ,MAAK;EACJ,eAAA","file":"nodes.css"}
|
||||||
@@ -73,7 +73,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td><a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">{{node.name}}<sup v-if="node.level > 1"><span class="blue"> L{{node.level}}</span></sup></a>
|
<td class="node-name-td"><a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">{{node.name}}<sup v-if="node.level > 1"><span class="blue"> L{{node.level}}</span></sup></a>
|
||||||
|
|
||||||
|
<a :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" title="设置"><i class="icon setting grey"></i></a>
|
||||||
|
|
||||||
<div v-if="node.region != null">
|
<div v-if="node.region != null">
|
||||||
<grey-label>区域:{{node.region.name}}</grey-label>
|
<grey-label>区域:{{node.region.name}}</grey-label>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +121,7 @@
|
|||||||
<span v-else class="disabled">-</span>
|
<span v-else class="disabled">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBytes(node.status.trafficOutBytes/60)}}/s</span>
|
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBits(node.status.trafficOutBytes * 8/60)}}</span>
|
||||||
<span v-else class="disabled">-</span>
|
<span v-else class="disabled">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
|
|||||||
@@ -31,4 +31,22 @@ a {
|
|||||||
a.small {
|
a.small {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-name-td {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-name-td:hover {
|
||||||
|
.icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +85,13 @@
|
|||||||
<p class="comment">可选项。默认使用<code-label>pool.ntp.org</code-label>。</p>
|
<p class="comment">可选项。默认使用<code-label>pool.ntp.org</code-label>。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="cluster.clock.autoSync">
|
||||||
|
<td class="color-border">检查Chrony</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="clockCheckChrony" v-model="cluster.clock.checkChrony"></checkbox>
|
||||||
|
<p class="comment">选中后,表示如果chrony(另一款时间同步软件)正在运行,则不重复执行时间同步。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>自动远程启动</td>
|
<td>自动远程启动</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -15,7 +15,17 @@
|
|||||||
.cluster-name-td .icon.opacity {
|
.cluster-name-td .icon.opacity {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
.cluster-name-td .icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 3em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -0.7em;
|
||||||
|
}
|
||||||
.cluster-name-td:hover .icon.pin {
|
.cluster-name-td:hover .icon.pin {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
.cluster-name-td:hover .icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
/*# sourceMappingURL=index.css.map */
|
/*# sourceMappingURL=index.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AADD,gBAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;EACA,YAAA;;AATF,gBAYC,MAAK;EACJ,eAAA;;AAbF,gBAgBC,MAAK;EACJ,YAAA;;AAIF,gBAAgB,MACf,MAAK;EACJ,eAAA","file":"index.css"}
|
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AADD,gBAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;EACA,YAAA;;AATF,gBAYC,MAAK;EACJ,eAAA;;AAbF,gBAgBC,MAAK;EACJ,YAAA;;AAjBF,gBAoBC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;;AAIF,gBAAgB,MACf,MAAK;EACJ,eAAA;;AAFF,gBAAgB,MAIf,MAAK;EACJ,eAAA","file":"index.css"}
|
||||||
@@ -43,6 +43,9 @@
|
|||||||
<tr v-for="cluster in clusters">
|
<tr v-for="cluster in clusters">
|
||||||
<td class="cluster-name-td">
|
<td class="cluster-name-td">
|
||||||
<a :href="'/clusters/cluster?clusterId=' + cluster.id"><keyword :v-word="keyword">{{cluster.name}}</keyword></a>
|
<a :href="'/clusters/cluster?clusterId=' + cluster.id"><keyword :v-word="keyword">{{cluster.name}}</keyword></a>
|
||||||
|
|
||||||
|
<a :href="'/clusters/cluster/settings?clusterId=' + cluster.id" title="设置"><i class="icon setting grey"></i></a>
|
||||||
|
|
||||||
<div v-if="cluster.timeZone != null && cluster.timeZone.length > 0">
|
<div v-if="cluster.timeZone != null && cluster.timeZone.length > 0">
|
||||||
<grey-label>时区:{{cluster.timeZone}}</grey-label>
|
<grey-label>时区:{{cluster.timeZone}}</grey-label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,10 +17,21 @@
|
|||||||
.icon.opacity {
|
.icon.opacity {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 3em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -0.7em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cluster-name-td:hover {
|
.cluster-name-td:hover {
|
||||||
.icon.pin {
|
.icon.pin {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
}
|
.icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
14
web/views/@default/clusters/nodes.css
Normal file
14
web/views/@default/clusters/nodes.css
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.node-name-td {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.node-name-td .icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -1em;
|
||||||
|
}
|
||||||
|
.node-name-td:hover .icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=nodes.css.map */
|
||||||
1
web/views/@default/clusters/nodes.css.map
Normal file
1
web/views/@default/clusters/nodes.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["nodes.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AADD,aAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,gBAAA;;AAIF,aAAa,MACZ,MAAK;EACJ,eAAA","file":"nodes.css"}
|
||||||
@@ -67,7 +67,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td><a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">{{node.name}}<sup v-if="node.level > 1"><span class="blue"> L{{node.level}}</span></sup></a>
|
<td class="node-name-td"><a :href="'/clusters/cluster/node?clusterId=' + node.cluster.id + '&nodeId=' + node.id">{{node.name}}<sup v-if="node.level > 1"><span class="blue"> L{{node.level}}</span></sup></a>
|
||||||
|
|
||||||
|
<a :href="'/clusters/cluster/node/update?clusterId=' + node.cluster.id + '&nodeId=' + node.id" title="设置"><i class="icon setting grey"></i></a>
|
||||||
|
|
||||||
<div v-if="node.region != null">
|
<div v-if="node.region != null">
|
||||||
<grey-label>区域:{{node.region.name}}</grey-label>
|
<grey-label>区域:{{node.region.name}}</grey-label>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,7 +115,7 @@
|
|||||||
<span v-else class="disabled">-</span>
|
<span v-else class="disabled">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBytes(node.status.trafficOutBytes/60)}}/s</span>
|
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBits(node.status.trafficOutBytes * 8/60)}}</span>
|
||||||
<span v-else class="disabled">-</span>
|
<span v-else class="disabled">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
|
|||||||
17
web/views/@default/clusters/nodes.less
Normal file
17
web/views/@default/clusters/nodes.less
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.node-name-td {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.icon.setting {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 1em;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-name-td:hover {
|
||||||
|
.icon.setting {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
|
|
||||||
<div class="ui tabular menu tiny">
|
<div class="ui tabular menu tiny">
|
||||||
<a href="" class="item" :class="{active: tab == 'domainMatch'}" @click.prevent="selectTab('domainMatch')">域名匹配配置</a>
|
|
||||||
<a href="" class="item" :class="{active: tab == 'domainAuditing'}" @click.prevent="selectTab('domainAuditing')">域名审核配置</a>
|
<a href="" class="item" :class="{active: tab == 'domainAuditing'}" @click.prevent="selectTab('domainAuditing')">域名审核配置</a>
|
||||||
<a href="" class="item" :class="{active: tab == 'tcpPorts'}" @click.prevent="selectTab('tcpPorts')">TCP/TLS端口</a>
|
<a href="" class="item" :class="{active: tab == 'tcpPorts'}" @click.prevent="selectTab('tcpPorts')">TCP/TLS端口</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -9,11 +8,6 @@
|
|||||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
<input type="hidden" name="globalConfigJSON" :value="JSON.stringify(globalConfig)"/>
|
<input type="hidden" name="globalConfigJSON" :value="JSON.stringify(globalConfig)"/>
|
||||||
|
|
||||||
<!-- 域名相关配置 -->
|
|
||||||
<div v-show="tab == 'domainMatch'">
|
|
||||||
<p class="comment">域名匹配相关配置已经转移到集群设置中,请到对应的集群设置中修改。</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 域名审核相关配置 -->
|
<!-- 域名审核相关配置 -->
|
||||||
<div v-show="tab == 'domainAuditing'">
|
<div v-show="tab == 'domainAuditing'">
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.tab = "domainMatch"
|
this.tab = "domainAuditing"
|
||||||
|
|
||||||
this.$delay(function () {
|
this.$delay(function () {
|
||||||
if (window.location.hash != null && window.location.hash.length > 1) {
|
if (window.location.hash != null && window.location.hash.length > 1) {
|
||||||
this.selectTab(window.location.hash.substr(1))
|
this.selectTab(window.location.hash.substring(1))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="rule.operator == 'match' || rule.operator == 'not match'">正则表达式</span>
|
<span v-if="(checkpoint == null || checkpoint.dataType != 'bool') && (rule.operator == 'match' || rule.operator == 'not match')">正则表达式</span>
|
||||||
<span v-else>对比值</span>
|
<span v-else>对比值</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -105,6 +105,15 @@
|
|||||||
<p class="comment">将二进制进行Base64Encode后放在这里,比如<code-label>Hello</code-label>对应<code-label>SGVsbG8=</code-label>。</p>
|
<p class="comment">将二进制进行Base64Encode后放在这里,比如<code-label>Hello</code-label>对应<code-label>SGVsbG8=</code-label>。</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- bool数据 -->
|
||||||
|
<div v-else-if="checkpoint != null && checkpoint.dataType == 'bool'">
|
||||||
|
<select name="value" class="ui selectable auto-width" v-model="rule.value" @change="changeRuleValue">
|
||||||
|
<option value="">[请选择]</option>
|
||||||
|
<option value="1">是(1)</option>
|
||||||
|
<option value="0">否(0)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 其余数据 -->
|
<!-- 其余数据 -->
|
||||||
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value" @input="changeRuleValue" v-else></textarea>
|
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value" @input="changeRuleValue" v-else></textarea>
|
||||||
|
|
||||||
@@ -132,7 +141,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="rule.operator == 'match' || rule.operator == 'not match'">
|
<tr v-if="(checkpoint == null || checkpoint.dataType != 'bool') && (rule.operator == 'match' || rule.operator == 'not match')">
|
||||||
<td>正则表达式测试</td>
|
<td>正则表达式测试</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="" v-if="!regexpTestIsOn" @click.prevent="changeRegexpTestIsOn">[输入测试字符串]</a>
|
<a href="" v-if="!regexpTestIsOn" @click.prevent="changeRegexpTestIsOn">[输入测试字符串]</a>
|
||||||
@@ -147,7 +156,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="operator.case != 'none'">
|
<tr v-if="(checkpoint == null || checkpoint.dataType != 'bool') && operator != null && operator.case != 'none'">
|
||||||
<td>不区分大小写</td>
|
<td>不区分大小写</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
|
|||||||
@@ -52,6 +52,19 @@ Tea.context(function () {
|
|||||||
this.checkpoint = this.checkpoints.$find(function (k, v) {
|
this.checkpoint = this.checkpoints.$find(function (k, v) {
|
||||||
return v.prefix == that.rule.checkpointPrefix
|
return v.prefix == that.rule.checkpointPrefix
|
||||||
})
|
})
|
||||||
|
if (this.checkpoint == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (this.checkpoint.dataType) {
|
||||||
|
case "bool":
|
||||||
|
this.rule.operator = "eq"
|
||||||
|
break
|
||||||
|
case "number":
|
||||||
|
this.rule.operator = "eq"
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
this.rule.operator = "match"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +76,9 @@ Tea.context(function () {
|
|||||||
this.operator = this.operators.$find(function (k, v) {
|
this.operator = this.operators.$find(function (k, v) {
|
||||||
return v.code == that.rule.operator
|
return v.code == that.rule.operator
|
||||||
})
|
})
|
||||||
|
if (this.operator == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!this.isUpdating) {
|
if (!this.isUpdating) {
|
||||||
this.rule.isCaseInsensitive = (this.operator.case == "yes")
|
this.rule.isCaseInsensitive = (this.operator.case == "yes")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Tea.context(function () {
|
|||||||
this.createSet = function (groupId) {
|
this.createSet = function (groupId) {
|
||||||
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
@@ -47,7 +47,7 @@ Tea.context(function () {
|
|||||||
this.updateSet = function (setId) {
|
this.updateSet = function (setId) {
|
||||||
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Tea.context(function () {
|
|||||||
this.createSet = function (groupId) {
|
this.createSet = function (groupId) {
|
||||||
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
@@ -48,7 +48,7 @@ Tea.context(function () {
|
|||||||
this.updateSet = function (setId) {
|
this.updateSet = function (setId) {
|
||||||
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<th>部署集群</th>
|
<th>部署集群</th>
|
||||||
<th>域名</th>
|
<th>域名</th>
|
||||||
<th>端口</th>
|
<th>端口</th>
|
||||||
<th class="center" style="width: 8em">下行带宽<tip-icon content="最近5分钟峰值带宽,每5分钟更新一次,单位:比特"></tip-icon><sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
<th class="center" style="width: 8em">下行带宽<tip-icon content="最近5分钟峰值带宽,每5分钟更新一次"></tip-icon><sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||||
<th class="two wide center">状态</th>
|
<th class="two wide center">状态</th>
|
||||||
<th class="two op">操作</th>
|
<th class="two op">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="title">当前服务CNAME</td>
|
<td class="title">当前服务CNAME</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="cname-text">{{dnsName}}.<span v-if="dnsDomain.length > 0">{{dnsDomain}}.</span><span v-else>根域名</span></span> <copy-to-clipboard :v-target="'cname-text'"></copy-to-clipboard> <a href="" @click.prevent="regenerateCNAME()" style="font-size: 0.8em">[重新生成]</a> <a href="" @click.prevent="updateCNAME()" style="font-size: 0.8em">[手动修改]</a>
|
<span id="cname-text">{{dnsName}}.<span v-if="dnsDomain.length > 0">{{dnsDomain}}</span><span v-else>根域名</span></span> <copy-to-clipboard :v-target="'cname-text'"></copy-to-clipboard> <a href="" @click.prevent="regenerateCNAME()" style="font-size: 0.8em">[重新生成]</a> <a href="" @click.prevent="updateCNAME()" style="font-size: 0.8em">[手动修改]</a>
|
||||||
<p class="comment">你需要为你的每个<a :href="'/servers/server/settings/serverNames?serverId=' + serverId">网站域名</a>设置一个CNAME解析,值为上面内容。</p>
|
<p class="comment">你需要为你的每个<a :href="'/servers/server/settings/serverNames?serverId=' + serverId">网站域名</a>设置一个CNAME解析,值为上面内容。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="title">证书包含的域名 *</td>
|
<td class="title">证书包含的域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="serverNames.length == 0" class="disabled">还没有设置域名,暂时不能申请。</span>
|
<span v-if="serverNames.length == 0" class="disabled">还没有需要申请证书的域名,暂时不能申请。</span>
|
||||||
<div v-if="serverNames.length > 0">
|
<div v-if="serverNames.length > 0">
|
||||||
<div v-for="(serverName, index) in serverNames" class="ui tiny basic label">
|
<div v-for="(serverName, index) in serverNames" class="ui tiny basic label">
|
||||||
<input type="hidden" name="serverNames" :value="serverName"/>
|
<input type="hidden" name="serverNames" :value="serverName"/>
|
||||||
|
|||||||
@@ -80,6 +80,13 @@
|
|||||||
<domains-box name="domainsBeforeJSON" :v-domains="redirect.domainsBefore"></domains-box>
|
<domains-box name="domainsBeforeJSON" :v-domains="redirect.domainsBefore"></domains-box>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="color-border">忽略跳转前端口</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="domainBeforeIgnorePorts" v-model="redirect.domainBeforeIgnorePorts"></checkbox>
|
||||||
|
<p class="comment">选中后,表示忽略跳转前域名端口,只要域名匹配时就跳转;如不选中,则表示只有域名和端口同时匹配时才会跳转。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="color-border">跳转后域名 *</td>
|
<td class="color-border">跳转后域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ Tea.context(function () {
|
|||||||
|
|
||||||
domainsAll: false,
|
domainsAll: false,
|
||||||
domainBefore: [],
|
domainBefore: [],
|
||||||
|
domainBeforeIgnorePorts: true,
|
||||||
domainAfter: "",
|
domainAfter: "",
|
||||||
domainAfterScheme: "",
|
domainAfterScheme: "",
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ Tea.context(function () {
|
|||||||
this.createSet = function (groupId) {
|
this.createSet = function (groupId) {
|
||||||
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
@@ -48,7 +48,7 @@ Tea.context(function () {
|
|||||||
this.updateSet = function (setId) {
|
this.updateSet = function (setId) {
|
||||||
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
||||||
width: "50em",
|
width: "50em",
|
||||||
height: "30em",
|
height: "40em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
.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 .button.disabled {
|
||||||
|
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 .button-group button {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.install-box .button-group .status-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 3em;
|
||||||
|
left: 5em;
|
||||||
|
right: 5em;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
.install-box::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=@install.css.map */
|
||||||
@@ -1 +1 @@
|
|||||||
undefined
|
{"version":3,"sources":["@install.less"],"names":[],"mappings":"AAAA;EAIC,WAAA;EACA,eAAA;EACA,SAAA;EACA,kBAAA;EACA,QAAA;EACA,WAAA;EACA,gBAAA;;AAVD,YAYC,QAAO;EACN,eAAA;;AAbF,YAgBC,QAAO;EACN,YAAA;;AAjBF,YAoBC,QAAO;EACN,YAAA;;AArBF,YAwBC,MACC,GAAE;EACD,WAAA;;AA1BH,YA8BC;EACC,iBAAA;;AA/BF,YA8BC,OAGC;EACC,0BAAA;EACA,gBAAA;;AAnCH,YAuCC;EACC,mBAAA;;AAxCF,YA2CC;EACC,gBAAA;EACA,eAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,UAAA;;AApDF,YAuDC,aAAY;EACX,UAAA;;AAxDF,YA2DC;EACC,eAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,WAAA;;AAjEF,YA2DC,cAQC;EACC,WAAA;;AApEH,YA2DC,cAYC;EACC,kBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;;AAKH,YAAY;EACX,UAAA","file":"@install.css"}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
.install-box {
|
.install-box {
|
||||||
@width: 50em;
|
@width: 50em;
|
||||||
|
@half-width: 25em;
|
||||||
|
|
||||||
width: @width;
|
width: @width;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -@width/2;
|
margin-left: -@half-width;
|
||||||
top: 1em;
|
top: 1em;
|
||||||
bottom: 1em;
|
bottom: 1em;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
width: @width;
|
width: @width;
|
||||||
padding-right: 1em;
|
padding-right: 1em;
|
||||||
margin-left: -@width/2;
|
margin-left: -@half-width;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
.button-group {
|
.button-group {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -@width/2;
|
margin-left: -@half-width;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
width: @width;
|
width: @width;
|
||||||
bottom: 1em;
|
bottom: 1em;
|
||||||
@@ -71,8 +72,8 @@
|
|||||||
.status-box {
|
.status-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3em;
|
top: 3em;
|
||||||
left: 15em;
|
left: 5em;
|
||||||
right: 15em;
|
right: 5em;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
|||||||
@@ -57,8 +57,8 @@
|
|||||||
.install-box .button-group .status-box {
|
.install-box .button-group .status-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3em;
|
top: 3em;
|
||||||
left: 15em;
|
left: 5em;
|
||||||
right: 15em;
|
right: 5em;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
|||||||
@@ -1 +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,QAAO;EACN,YAAA;;AApBF,YAuBC,MACC,GAAE;EACD,WAAA;;AAzBH,YA6BC;EACC,iBAAA;;AA9BF,YA6BC,OAGC;EACC,0BAAA;EACA,2BAAA;;AAlCH,YAsCC;EACC,mBAAA;;AAvCF,YA0CC;EACC,gBAAA;EACA,eAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,UAAA;;AAnDF,YAsDC,aAAY;EACX,UAAA;;AAvDF,YA0DC;EACC,eAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,WAAA;;AAhEF,YA0DC,cAQC;EACC,WAAA;;AAnEH,YA0DC,cAYC;EACC,kBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;;AAKH,YAAY;EACX,UAAA","file":"index.css"}
|
{"version":3,"sources":["@install.less"],"names":[],"mappings":"AAAA;EAIC,WAAA;EACA,eAAA;EACA,SAAA;EACA,kBAAA;EACA,QAAA;EACA,WAAA;EACA,gBAAA;;AAVD,YAYC,QAAO;EACN,eAAA;;AAbF,YAgBC,QAAO;EACN,YAAA;;AAjBF,YAoBC,QAAO;EACN,YAAA;;AArBF,YAwBC,MACC,GAAE;EACD,WAAA;;AA1BH,YA8BC;EACC,iBAAA;;AA/BF,YA8BC,OAGC;EACC,0BAAA;EACA,gBAAA;;AAnCH,YAuCC;EACC,mBAAA;;AAxCF,YA2CC;EACC,gBAAA;EACA,eAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,kBAAA;EACA,UAAA;;AApDF,YAuDC,aAAY;EACX,UAAA;;AAxDF,YA2DC;EACC,eAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,WAAA;;AAjEF,YA2DC,cAQC;EACC,WAAA;;AApEH,YA2DC,cAYC;EACC,kBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,SAAA;EACA,kBAAA;EACA,UAAA;;AAKH,YAAY;EACX,UAAA","file":"index.css"}
|
||||||
@@ -47,10 +47,10 @@
|
|||||||
|
|
||||||
<!-- 介绍 -->
|
<!-- 介绍 -->
|
||||||
<div v-show="step == STEP_INTRO">
|
<div v-show="step == STEP_INTRO">
|
||||||
<div>感谢你选择使用<strong>GoEdge</strong>集群服务系统,下面让我们一起开始配置系统。</div>
|
<div>感谢你选择使用<strong>GoEdge</strong>CDN系统,下面让我们一起开始配置系统。</div>
|
||||||
<div class="margin">在这之前如果你还没有可用的MySQL数据库,请先安装数据库再进行。</div>
|
<div class="margin">在这之前如果你还没有可用的MySQL数据库,请先安装MySQL数据库再进行。</div>
|
||||||
<div class="margin" style="color: grey">免责声明:GoEdge软件开发者并不对您的软件使用方法、服务对象、服务内容负道德或法律上的约束责任,在使用本软件时产生的一切法律风险自负。</div>
|
<div class="margin" style="color: grey">免责声明:GoEdge软件开发者并不对您的软件使用方法、服务对象、服务内容负道德或法律上的约束责任,在使用本软件时产生的一切法律风险自负。</div>
|
||||||
<div class="margin" style="color: grey">用户协议:请在遵守中华人民共和国政策、法律、法规的前提下使用本软件;自愿承担因不当使用本软件产生的一切法律后果;承认GoEdge开发者拥有本软件的著作权;点击"开始"安装表示你同意此用户协议。</div>
|
<div class="margin" style="color: grey">用户协议:请在遵守中华人民共和国政策、法律、法规的前提下使用本软件;自愿承担因不当使用本软件产生的一切法律后果;承认GoEdge开发者拥有本软件的所有著作权;点击"开始"安装表示你同意此用户协议。</div>
|
||||||
<button class="ui button primary" style="margin-top: 10em" type="button" @click.prevent="goIntroNext()">开始<i class="icon long arrow right"></i></button>
|
<button class="ui button primary" style="margin-top: 10em" type="button" @click.prevent="goIntroNext()">开始<i class="icon long arrow right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
@import "@install";
|
@import "@install";
|
||||||
|
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
<menu-item :href="'/users/update?userId=' + user.id" code="update">修改</menu-item>
|
<menu-item :href="'/users/update?userId=' + user.id" code="update">修改</menu-item>
|
||||||
<menu-item :href="'/users/features?userId=' + user.id" code="feature" v-if="teaIsPlus">功能</menu-item>
|
<menu-item :href="'/users/features?userId=' + user.id" code="feature" v-if="teaIsPlus">功能</menu-item>
|
||||||
<menu-item :href="'/users/identity?userId=' + user.id" code="identity" v-if="teaIsPlus">实名认证<span v-if="user.hasNewIndividualIdentity || user.hasNewEnterpriseIdentity" class="red small">(待审核)</span><span v-if="user.identityTag != null && user.identityTag.length > 0" class="green">({{user.identityTag}})</span></menu-item>
|
<menu-item :href="'/users/identity?userId=' + user.id" code="identity" v-if="teaIsPlus">实名认证<span v-if="user.hasNewIndividualIdentity || user.hasNewEnterpriseIdentity" class="red small">(待审核)</span><span v-if="user.identityTag != null && user.identityTag.length > 0" class="green">({{user.identityTag}})</span></menu-item>
|
||||||
<menu-item :href="'/users/accessKeys?userId=' + user.id" code="accessKey">API AccessKey({{user.countAccessKeys}})</menu-item>
|
<menu-item :href="'/users/accesskeys?userId=' + user.id" code="accessKey">API AccessKey({{user.countAccessKeys}})</menu-item>
|
||||||
</first-menu>
|
</first-menu>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.createAccessKey = function () {
|
this.createAccessKey = function () {
|
||||||
teaweb.popup("/users/accessKeys/createPopup?userId=" + this.user.id, {
|
teaweb.popup("/users/accesskeys/createPopup?userId=" + this.user.id, {
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
teaweb.reload()
|
teaweb.reload()
|
||||||
|
|||||||
Reference in New Issue
Block a user