mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-12-01 19:37:48 +08:00
feat: 完成面板设置、完成国际化
This commit is contained in:
parent
5342b758cb
commit
d28697b63a
BIN
backend/__debug_bin
Executable file
BIN
backend/__debug_bin
Executable file
Binary file not shown.
@ -5,6 +5,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/constant"
|
||||
"github.com/1Panel-dev/1Panel/global"
|
||||
"github.com/1Panel-dev/1Panel/utils/ntp"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -52,3 +53,20 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) SyncTime(c *gin.Context) {
|
||||
var timeLayoutStr = "2006-01-02 15:04:05"
|
||||
|
||||
ntime, err := ntp.Getremotetime()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
ts := ntime.Format(timeLayoutStr)
|
||||
if err := ntp.UpdateSystemDate(ts); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, ts)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
|
||||
if err := json.Unmarshal(arr, &info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info.LocalTime = time.Now().Format("2006.01.02 15:04:05")
|
||||
info.LocalTime = time.Now().Format("2006-01-02 15:04:05")
|
||||
return &info, err
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ require (
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.0.2
|
||||
github.com/go-playground/validator/v10 v10.11.0
|
||||
github.com/gogf/gf v1.16.9
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||
github.com/gorilla/csrf v1.7.1
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
@ -49,6 +50,7 @@ require (
|
||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
@ -77,6 +79,7 @@ require (
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
@ -97,6 +100,8 @@ require (
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel v1.0.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.0.0 // indirect
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
|
@ -59,6 +59,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@ -90,8 +92,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||
@ -141,6 +147,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
|
||||
github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||
@ -183,6 +191,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
|
||||
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
|
||||
@ -198,6 +208,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
@ -223,8 +234,11 @@ github.com/gorilla/csrf v1.7.1 h1:Ir3o2c1/Uzj6FBxMlAUB6SivgVMy1ONXwYgXn+/aHPE=
|
||||
github.com/gorilla/csrf v1.7.1/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/gwatts/gin-adapter v1.0.0 h1:TsmmhYTR79/RMTsfYJ2IQvI1F5KZ3ZFJxuQSYEOpyIA=
|
||||
github.com/gwatts/gin-adapter v1.0.0/go.mod h1:44AEV+938HsS0mjfXtBDCUZS9vONlF2gwvh8wu4sRYc=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@ -287,9 +301,15 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
@ -314,6 +334,8 @@ github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPm
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
|
||||
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
@ -424,6 +446,10 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
|
||||
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
|
||||
go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
|
||||
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -506,6 +532,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@ -543,6 +570,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -574,6 +602,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -64,7 +64,7 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.Setting{Key: "PanelName", Value: "1Panel"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "Language", Value: "ch"}).Error; err != nil {
|
||||
if err := tx.Create(&model.Setting{Key: "Language", Value: "zh"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "Theme", Value: "auto"}).Error; err != nil {
|
||||
|
@ -10,10 +10,12 @@ type SettingRouter struct{}
|
||||
|
||||
func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
||||
settingRouter := Router.Group("settings").Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||
withRecordRouter := Router.Group("settings").Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.OperationRecord())
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
settingRouter.POST("/search", baseApi.GetSettingInfo)
|
||||
settingRouter.PUT("", baseApi.UpdateSetting)
|
||||
withRecordRouter.PUT("", baseApi.UpdateSetting)
|
||||
settingRouter.PUT("/password", baseApi.UpdatePassword)
|
||||
settingRouter.POST("/time/sync", baseApi.SyncTime)
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func TestStringEncrypt(t *testing.T) {
|
||||
|
||||
func TestStringDecrypt(t *testing.T) {
|
||||
viper.Init()
|
||||
p, err := StringDecrypt("5WYEZ4XcitdomVvAyimt9WwJwBJJSbTTHncZoqyOraQ=")
|
||||
p, err := StringDecrypt("Jmg4EUACGznt3dEQTJ+0ZRxwLaVNsNg7R5RcZ0V7ElQ=")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
76
backend/utils/ntp/ntp.go
Normal file
76
backend/utils/ntp/ntp.go
Normal file
@ -0,0 +1,76 @@
|
||||
package ntp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
const ntpEpochOffset = 2208988800
|
||||
|
||||
type packet struct {
|
||||
Settings uint8
|
||||
Stratum uint8
|
||||
Poll int8
|
||||
Precision int8
|
||||
RootDelay uint32
|
||||
RootDispersion uint32
|
||||
ReferenceID uint32
|
||||
RefTimeSec uint32
|
||||
RefTimeFrac uint32
|
||||
OrigTimeSec uint32
|
||||
OrigTimeFrac uint32
|
||||
RxTimeSec uint32
|
||||
RxTimeFrac uint32
|
||||
TxTimeSec uint32
|
||||
TxTimeFrac uint32
|
||||
}
|
||||
|
||||
func Getremotetime() (*time.Time, error) {
|
||||
var host string
|
||||
flag.StringVar(&host, "e", "ntp1.aliyun.com:123", "NTP host")
|
||||
flag.Parse()
|
||||
|
||||
conn, err := net.Dial("udp", host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := conn.SetDeadline(time.Now().Add(15 * time.Second)); err != nil {
|
||||
return nil, fmt.Errorf("failed to set deadline: %v", err)
|
||||
}
|
||||
|
||||
req := &packet{Settings: 0x1B}
|
||||
|
||||
if err := binary.Write(conn, binary.BigEndian, req); err != nil {
|
||||
return nil, fmt.Errorf("failed to set request: %v", err)
|
||||
}
|
||||
|
||||
rsp := &packet{}
|
||||
if err := binary.Read(conn, binary.BigEndian, rsp); err != nil {
|
||||
return nil, fmt.Errorf("failed to read server response: %v", err)
|
||||
}
|
||||
|
||||
secs := float64(rsp.TxTimeSec) - ntpEpochOffset
|
||||
nanos := (int64(rsp.TxTimeFrac) * 1e9) >> 32
|
||||
|
||||
showtime := time.Unix(int64(secs), nanos)
|
||||
|
||||
return &showtime, nil
|
||||
}
|
||||
|
||||
func UpdateSystemDate(dateTime string) error {
|
||||
system := runtime.GOOS
|
||||
if system == "linux" {
|
||||
if _, err := gproc.ShellExec(`date -s "` + dateTime + `"`); err != nil {
|
||||
return fmt.Errorf("update system date failed, err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("The current system architecture does not support synchronization")
|
||||
}
|
@ -7,27 +7,22 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, computed } from 'vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
// 配置element中英文
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import en from 'element-plus/es/locale/lang/en';
|
||||
// 使用主题
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
useTheme();
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
// 配置element按钮文字中间是否有空格
|
||||
const config = reactive({
|
||||
autoInsertSpace: false,
|
||||
});
|
||||
|
||||
// element 语言配置
|
||||
const i18nLocale = computed((): any => {
|
||||
if (globalStore.language && globalStore.language == 'zh') return zhCn;
|
||||
if (globalStore.language == 'en') return en;
|
||||
return '';
|
||||
});
|
||||
|
||||
// 配置全局组件大小 (small/default(medium)/large)
|
||||
const assemblySize = computed((): string => globalStore.assemblySize);
|
||||
</script>
|
||||
|
||||
|
@ -12,3 +12,7 @@ export const updateSetting = (param: Setting.SettingUpdate) => {
|
||||
export const updatePassword = (param: Setting.PasswordUpdate) => {
|
||||
return http.put(`/settings/password`, param);
|
||||
};
|
||||
|
||||
export const syncTime = () => {
|
||||
return http.post(`/settings/time/sync`, {});
|
||||
};
|
||||
|
@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<el-breadcrumb :separator-icon="ArrowRight">
|
||||
<transition-group name="breadcrumb" mode="out-in">
|
||||
<el-breadcrumb-item :to="{ path: HOME_URL }" key="/home">{{ $t('menu.home') }}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item v-for="item in matched" :key="item.path" :to="{ path: item.path }">
|
||||
{{ $t(item.meta?.title as string) }}
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ArrowRight } from '@element-plus/icons-vue';
|
||||
import { HOME_URL } from '@/config/config';
|
||||
const route = useRoute();
|
||||
|
||||
const matched = computed(() =>
|
||||
route.matched.filter((item) => item.meta && item.meta.title && item.meta.title !== 'menu.home'),
|
||||
);
|
||||
</script>
|
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<el-icon :size="25" class="collapse-icon" @click="menuStore.setCollapse()">
|
||||
<component :is="isCollapse ? 'expand' : 'fold'"></component>
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { MenuStore } from '@/store/modules/menu';
|
||||
const menuStore = MenuStore();
|
||||
const isCollapse = computed((): boolean => menuStore.isCollapse);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// @import '../index.scss';
|
||||
|
||||
.collapse-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tooltip effect="dark" :content="$t('commons.header.theme')" placement="bottom">
|
||||
<i :class="'panel p-theme'" class="icon-style" @click="openDrawer"></i>
|
||||
</el-tooltip>
|
||||
<el-drawer v-model="drawerVisible" :title="$t('commons.header.theme')" size="300px">
|
||||
<el-divider class="divider" content-position="center">
|
||||
<el-icon><ColdDrink /></el-icon>
|
||||
{{ $t('commons.header.globalTheme') }}
|
||||
</el-divider>
|
||||
<div class="theme-item">
|
||||
<span>{{ $t('commons.header.themeColor') }}</span>
|
||||
<el-color-picker
|
||||
v-model="themeConfig.primary"
|
||||
:predefine="colorList"
|
||||
@change="changePrimary"
|
||||
></el-color-picker>
|
||||
</div>
|
||||
<div class="theme-item">
|
||||
<span>{{ $t('commons.header.darkTheme') }}</span>
|
||||
<SwitchDark></SwitchDark>
|
||||
</div>
|
||||
<br />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
import SwitchDark from '@/components/switch-dark/index.vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
|
||||
// 预定义主题颜色
|
||||
const colorList = [
|
||||
'#409EFF',
|
||||
'#DAA96E',
|
||||
'#0C819F',
|
||||
'#009688',
|
||||
'#27ae60',
|
||||
'#ff5c93',
|
||||
'#e74c3c',
|
||||
'#fd726d',
|
||||
'#f39c12',
|
||||
'#9b59b6',
|
||||
];
|
||||
|
||||
// 主题初始化
|
||||
const globalStore = GlobalStore();
|
||||
const themeConfig = computed(() => globalStore.themeConfig);
|
||||
|
||||
const { changePrimary } = useTheme();
|
||||
|
||||
// 打开主题设置
|
||||
const drawerVisible = ref(false);
|
||||
const openDrawer = () => {
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../index.scss';
|
||||
</style>
|
@ -1,101 +0,0 @@
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 55px;
|
||||
padding: 0 15px;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
.header-lf {
|
||||
.collapse-icon {
|
||||
margin-right: 20px;
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.header-ri {
|
||||
margin: 0 30px;
|
||||
.header-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 66px;
|
||||
margin-right: 22px;
|
||||
.icon-style {
|
||||
font-size: 20px;
|
||||
color: rgb(0 0 0 / 75%);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.username {
|
||||
margin: 0 20px 0 0;
|
||||
font-size: 15px;
|
||||
color: rgb(0 0 0 / 75%);
|
||||
}
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.theme-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 15px 0;
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.divider {
|
||||
margin-top: 20px;
|
||||
.el-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.theme-switch {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 菜单搜索样式 */
|
||||
.layout-search-dialog {
|
||||
:deep(.el-dialog) {
|
||||
background: rgb(0 0 0 / 50%);
|
||||
border-radius: 0 !important;
|
||||
box-shadow: unset !important;
|
||||
.el-dialog__header {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
}
|
||||
:deep(.el-autocomplete) {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 50%;
|
||||
width: 560px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
.el-autocomplete__popper {
|
||||
.el-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
font-size: 16px;
|
||||
}
|
||||
span {
|
||||
margin: 0 0 0 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="header-lf flx-center">
|
||||
<CollapseIcon id="collapseIcon"></CollapseIcon>
|
||||
<Breadcrumb id="breadcrumb" v-if="themeConfig.breadcrumb"></Breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import CollapseIcon from './components/collapseicon.vue';
|
||||
import Breadcrumb from './components/breadcrumb.vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const themeConfig = computed(() => globalStore.themeConfig);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import './index.scss';
|
||||
</style>
|
@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<Layout>
|
||||
<template #menu>
|
||||
<Menu></Menu>
|
||||
</template>
|
||||
<template #header>
|
||||
<Header></Header>
|
||||
<Menu :panelName="themeConfig.panelName"></Menu>
|
||||
</template>
|
||||
<template #footer>
|
||||
<Footer></Footer>
|
||||
@ -13,7 +10,28 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Layout from '@/layout/index.vue';
|
||||
import Header from './header/index.vue';
|
||||
import Footer from './footer/index.vue';
|
||||
import Menu from './menu/index.vue';
|
||||
import { onMounted, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
import { getSettingInfo } from '@/api/modules/setting';
|
||||
|
||||
const i18n = useI18n();
|
||||
const globalStore = GlobalStore();
|
||||
const themeConfig = computed(() => globalStore.themeConfig);
|
||||
const { switchDark } = useTheme();
|
||||
|
||||
const loadDataFromDB = async () => {
|
||||
const res = await getSettingInfo();
|
||||
i18n.locale.value = res.data.language;
|
||||
globalStore.updateLanguage(res.data.language);
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme });
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, panelName: res.data.panelName });
|
||||
switchDark();
|
||||
};
|
||||
onMounted(() => {
|
||||
loadDataFromDB();
|
||||
});
|
||||
</script>
|
||||
|
@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div class="logo flx-center">
|
||||
<img src="@/assets/images/logo.svg" alt="logo" />
|
||||
<span v-show="!isCollapse">1Panel</span>
|
||||
<span v-show="!isCollapse">{{ panelName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{ isCollapse: boolean }>();
|
||||
defineProps<{ isCollapse: boolean; panelName: string }>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -7,7 +7,7 @@
|
||||
element-loading-svg-view-box="-10, -10, 50, 50"
|
||||
element-loading-background="rgba(122, 122, 122, 0.01)"
|
||||
>
|
||||
<Logo :isCollapse="isCollapse"></Logo>
|
||||
<Logo :panelName="panelName" :isCollapse="isCollapse"></Logo>
|
||||
<el-scrollbar>
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
@ -48,11 +48,6 @@ import { GlobalStore } from '@/store';
|
||||
const route = useRoute();
|
||||
const menuStore = MenuStore();
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
onMounted(async () => {
|
||||
menuStore.setMenuList(menuList);
|
||||
});
|
||||
|
||||
// const activeMenu = computed((): string => route.path);
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
@ -62,6 +57,9 @@ const activeMenu = computed(() => {
|
||||
return path;
|
||||
});
|
||||
const isCollapse = computed((): boolean => menuStore.isCollapse);
|
||||
const panelName = computed(() => {
|
||||
return globalStore.themeConfig.panelName;
|
||||
});
|
||||
const routerMenus = computed((): RouteRecordRaw[] => menuStore.menuList);
|
||||
|
||||
const screenWidth = ref<number>(0);
|
||||
@ -95,6 +93,9 @@ const logout = () => {
|
||||
const systemLogOut = async () => {
|
||||
await logOutApi();
|
||||
};
|
||||
onMounted(async () => {
|
||||
menuStore.setMenuList(menuList);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -3,34 +3,27 @@ import { getLightColor, getDarkColor } from '@/utils/theme/tool';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
/**
|
||||
* @description 切换主题
|
||||
* */
|
||||
export const useTheme = () => {
|
||||
const globalStore = GlobalStore();
|
||||
const themeConfig = computed(() => globalStore.themeConfig);
|
||||
|
||||
// 切换暗黑模式
|
||||
const switchDark = () => {
|
||||
const body = document.documentElement as HTMLElement;
|
||||
if (themeConfig.value.isDark) body.setAttribute('class', 'dark');
|
||||
if (themeConfig.value.theme === 'dark') body.setAttribute('class', 'dark');
|
||||
else body.setAttribute('class', '');
|
||||
};
|
||||
|
||||
// 修改主题颜色
|
||||
const changePrimary = (val: string) => {
|
||||
if (!val) {
|
||||
val = '#409EFF';
|
||||
ElMessage({ type: 'success', message: '主题颜色已重置为 #409EFF' });
|
||||
}
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, primary: val });
|
||||
// 颜色加深
|
||||
document.documentElement.style.setProperty(
|
||||
'--el-color-primary-dark-2',
|
||||
`${getDarkColor(themeConfig.value.primary, 0.1)}`,
|
||||
);
|
||||
document.documentElement.style.setProperty('--el-color-primary', themeConfig.value.primary);
|
||||
// 颜色变浅
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
document.documentElement.style.setProperty(
|
||||
`--el-color-primary-light-${i}`,
|
||||
|
@ -3,6 +3,9 @@ export default {
|
||||
button: {
|
||||
create: 'Create',
|
||||
add: 'Add',
|
||||
save: 'Save',
|
||||
set: 'Reset',
|
||||
sync: 'Sync',
|
||||
delete: 'Delete',
|
||||
edit: 'Edit',
|
||||
confirm: 'Confirm',
|
||||
@ -74,13 +77,11 @@ export default {
|
||||
logout: 'Logout',
|
||||
},
|
||||
},
|
||||
business: {
|
||||
user: {
|
||||
auth: {
|
||||
username: 'Username',
|
||||
email: 'Email',
|
||||
password: 'Password',
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
home: 'Overview',
|
||||
demo: 'Example',
|
||||
@ -249,4 +250,23 @@ export default {
|
||||
downloadProcess: 'Download Process',
|
||||
downloading: 'Downloading...',
|
||||
},
|
||||
setting: {
|
||||
panel: 'Panel',
|
||||
emailHelper: 'For password retrieval',
|
||||
title: 'Panel alias',
|
||||
theme: 'Theme',
|
||||
dark: 'Dark',
|
||||
light: 'Light',
|
||||
language: 'Language',
|
||||
languageHelper:
|
||||
'By default, it follows the browser language. This parameter takes effect only on the current browser',
|
||||
sessionTimeout: 'Timeout',
|
||||
sessionTimeoutHelper:
|
||||
'If you do not operate the panel for more than {0} seconds, the panel automatically logs out',
|
||||
syncTime: 'Synchronization time',
|
||||
changePassword: 'Password change',
|
||||
oldPassword: 'Original password',
|
||||
newPassword: 'New password',
|
||||
retryPassword: 'Confirm password',
|
||||
},
|
||||
};
|
||||
|
@ -3,6 +3,9 @@ export default {
|
||||
button: {
|
||||
create: '新建',
|
||||
add: '添加',
|
||||
save: '保存',
|
||||
set: '设置',
|
||||
sync: '同步',
|
||||
delete: '删除',
|
||||
edit: '编辑',
|
||||
confirm: '确认',
|
||||
@ -85,13 +88,11 @@ export default {
|
||||
logout: '退出登录',
|
||||
},
|
||||
},
|
||||
business: {
|
||||
user: {
|
||||
auth: {
|
||||
username: '用户名',
|
||||
email: '邮箱',
|
||||
password: '密码',
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
home: '概览',
|
||||
demo: '样例',
|
||||
@ -259,4 +260,22 @@ export default {
|
||||
downloadProcess: '下载进度',
|
||||
downloading: '正在下载...',
|
||||
},
|
||||
setting: {
|
||||
panel: '面板',
|
||||
emailHelper: '用于密码找回',
|
||||
title: '面板别名',
|
||||
theme: '主题色',
|
||||
componentSize: '组件大小',
|
||||
dark: '黑金',
|
||||
light: '白金',
|
||||
language: '系统语言',
|
||||
languageHelper: '默认跟随浏览器语言,设置后只对当前浏览器生效,更换浏览器后需要重新设置',
|
||||
sessionTimeout: '超时时间',
|
||||
sessionTimeoutHelper: '如果用户超过 {0} 秒未操作面板,面板将自动退出登录',
|
||||
syncTime: '同步时间',
|
||||
changePassword: '密码修改',
|
||||
oldPassword: '原密码',
|
||||
newPassword: '新密码',
|
||||
retryPassword: '确认密码',
|
||||
},
|
||||
};
|
||||
|
@ -8,17 +8,13 @@ export const GlobalStore = defineStore({
|
||||
id: 'GlobalState',
|
||||
state: (): GlobalState => ({
|
||||
isLogin: false,
|
||||
userInfo: '',
|
||||
csrfToken: '',
|
||||
assemblySize: 'default',
|
||||
assemblySize: 'small',
|
||||
language: '',
|
||||
themeConfig: {
|
||||
panelName: '',
|
||||
primary: '#409EFF',
|
||||
isDark: false,
|
||||
isGrey: false,
|
||||
isWeak: false,
|
||||
breadcrumb: true,
|
||||
tabs: false,
|
||||
theme: 'bright',
|
||||
footer: true,
|
||||
},
|
||||
}),
|
||||
@ -27,13 +23,10 @@ export const GlobalStore = defineStore({
|
||||
setLogStatus(login: boolean) {
|
||||
this.isLogin = login;
|
||||
},
|
||||
setUserInfo(userInfo: any) {
|
||||
this.userInfo = userInfo;
|
||||
},
|
||||
setCsrfToken(token: string) {
|
||||
this.csrfToken = token;
|
||||
},
|
||||
setAssemblySizeSize(assemblySize: string) {
|
||||
setAssemblySize(assemblySize: string) {
|
||||
this.assemblySize = assemblySize;
|
||||
},
|
||||
updateLanguage(language: string) {
|
||||
@ -46,7 +39,6 @@ export const GlobalStore = defineStore({
|
||||
persist: piniaPersistConfig('GlobalState'),
|
||||
});
|
||||
|
||||
// piniaPersist(持久化)
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
|
@ -2,22 +2,18 @@ import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
/* themeConfigProp */
|
||||
export interface ThemeConfigProp {
|
||||
panelName: string;
|
||||
primary: string;
|
||||
isDark: boolean;
|
||||
isGrey: boolean;
|
||||
isWeak: boolean;
|
||||
breadcrumb: boolean;
|
||||
tabs: boolean;
|
||||
theme: string; // dark | bright | auto
|
||||
footer: boolean;
|
||||
}
|
||||
|
||||
/* GlobalState */
|
||||
export interface GlobalState {
|
||||
isLogin: boolean;
|
||||
userInfo: any;
|
||||
csrfToken: string;
|
||||
assemblySize: string;
|
||||
language: string;
|
||||
language: string; // zh | en
|
||||
assemblySize: string; // small | default | large
|
||||
themeConfig: ThemeConfigProp;
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,7 @@ const whiteList = ['/login', '/error'];
|
||||
export const MenuStore = defineStore({
|
||||
id: 'MenuState',
|
||||
state: (): MenuState => ({
|
||||
// menu collapse
|
||||
isCollapse: false,
|
||||
// menu List
|
||||
menuList: [],
|
||||
}),
|
||||
getters: {},
|
||||
|
@ -2,13 +2,13 @@
|
||||
<LayoutContent :header="$t('commons.button.' + op)" :back-name="'Table'">
|
||||
<template #form>
|
||||
<el-form ref="ruleFormRef" label-position="left" :model="demoForm" :rules="rules" label-width="140px">
|
||||
<el-form-item :label="$t('business.user.username')" prop="name">
|
||||
<el-form-item :label="$t('auth.username')" prop="name">
|
||||
<el-input v-model="demoForm.name" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('business.user.email')" prop="email">
|
||||
<el-form-item :label="$t('auth.email')" prop="email">
|
||||
<el-input v-model="demoForm.email" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('business.user.password')" prop="password">
|
||||
<el-form-item :label="$t('auth.password')" prop="password">
|
||||
<el-input type="password" v-model="demoForm.password" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@ -65,7 +65,7 @@ const loginRules = reactive({
|
||||
// 登录表单数据
|
||||
const loginForm = reactive<Login.ReqLoginForm>({
|
||||
name: 'admin',
|
||||
password: 'Songliu123++',
|
||||
password: 'Calong@2015',
|
||||
captcha: '',
|
||||
captchaID: '',
|
||||
authMethod: '',
|
||||
@ -93,8 +93,7 @@ const login = (formEl: FormInstance | undefined) => {
|
||||
captchaID: captcha.captchaID,
|
||||
authMethod: '',
|
||||
};
|
||||
const res = await loginApi(requestLoginForm);
|
||||
globalStore.setUserInfo(res.data.name);
|
||||
await loginApi(requestLoginForm);
|
||||
globalStore.setLogStatus(true);
|
||||
menuStore.setMenuList([]);
|
||||
ElMessage.success(i18n.global.t('commons.msg.loginSuccess'));
|
||||
|
@ -1,109 +1,111 @@
|
||||
<template>
|
||||
<el-form size="small" :model="form" label-position="left" label-width="120px">
|
||||
<el-form size="small" :model="form" label-position="left" label-width="160px">
|
||||
<el-card style="margin-top: 20px">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>面板</span>
|
||||
<span>{{ $t('setting.panel') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :span="1"><br /></el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="用户名">
|
||||
<el-col :span="10">
|
||||
<el-form-item :label="$t('auth.username')">
|
||||
<el-input clearable v-model="form.settingInfo.userName">
|
||||
<template #append>
|
||||
<el-button
|
||||
@click="SaveSetting('UserName', form.settingInfo.userName)"
|
||||
icon="Collection"
|
||||
>
|
||||
保存
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-form-item :label="$t('auth.password')">
|
||||
<el-input type="password" clearable disabled v-model="form.settingInfo.password">
|
||||
<template #append>
|
||||
<el-button icon="Setting" @click="passwordVisiable = true">设置</el-button>
|
||||
<el-button icon="Setting" @click="passwordVisiable = true">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-form-item :label="$t('auth.email')">
|
||||
<el-input clearable v-model="form.settingInfo.email">
|
||||
<template #append>
|
||||
<el-button @click="SaveSetting('Email', form.settingInfo.email)" icon="Collection">
|
||||
保存
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<div><span class="input-help">用于密码找回</span></div>
|
||||
<div>
|
||||
<span class="input-help">{{ $t('setting.emailHelper') }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="面板别名">
|
||||
<el-form-item :label="$t('setting.title')">
|
||||
<el-input clearable v-model="form.settingInfo.panelName">
|
||||
<template #append>
|
||||
<el-button
|
||||
@click="SaveSetting('PanelName', form.settingInfo.panelName)"
|
||||
icon="Collection"
|
||||
>
|
||||
保存
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="主题色">
|
||||
<el-form-item :label="$t('setting.theme')">
|
||||
<el-radio-group
|
||||
@change="SaveSetting('Theme', form.settingInfo.theme)"
|
||||
v-model="form.settingInfo.theme"
|
||||
>
|
||||
<el-radio-button label="black">
|
||||
<el-icon><Moon /></el-icon>黑金
|
||||
<el-radio-button label="dark">
|
||||
<el-icon><Moon /></el-icon>
|
||||
{{ $t('setting.dark') }}
|
||||
</el-radio-button>
|
||||
<el-radio-button label="auto" icon="Sunny">
|
||||
<el-icon><MagicStick /></el-icon>自动
|
||||
</el-radio-button>
|
||||
<el-radio-button label="write">
|
||||
<el-icon><Sunny /></el-icon>白金
|
||||
<el-radio-button label="light">
|
||||
<el-icon><Sunny /></el-icon>
|
||||
{{ $t('setting.light') }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
<div>
|
||||
<span class="input-help">
|
||||
选择自动设置,将会在晚 6 点到次日早 6 点间自动切换到黑金主题。
|
||||
</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统语言">
|
||||
<el-form-item :label="$t('setting.language')">
|
||||
<el-radio-group
|
||||
@change="SaveSetting('Language', form.settingInfo.language)"
|
||||
v-model="form.settingInfo.language"
|
||||
>
|
||||
<el-radio-button label="ch">中文 </el-radio-button>
|
||||
<el-radio-button label="zh">中文</el-radio-button>
|
||||
<el-radio-button label="en">English</el-radio-button>
|
||||
</el-radio-group>
|
||||
<div>
|
||||
<span class="input-help">
|
||||
默认跟随浏览器语言,设置后只对当前浏览器生效,更换浏览器后需要重新设置。
|
||||
{{ $t('setting.languageHelper') }}
|
||||
</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="超时时间">
|
||||
<el-form-item :label="$t('setting.sessionTimeout')">
|
||||
<el-input v-model="form.settingInfo.sessionTimeout">
|
||||
<template #append>
|
||||
<el-button
|
||||
@click="SaveSetting('SessionTimeout', form.settingInfo.sessionTimeout)"
|
||||
icon="Collection"
|
||||
>
|
||||
保存
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<div>
|
||||
<span class="input-help">如果用户超过 86400秒未操作面板,面板将自动退出登录 </span>
|
||||
<span class="input-help">
|
||||
{{ $t('setting.sessionTimeoutHelper', [form.settingInfo.sessionTimeout]) }}
|
||||
</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="同步时间">
|
||||
<el-input v-model="form.settingInfo.localTime">
|
||||
<el-form-item :label="$t('setting.syncTime')">
|
||||
<el-input disabled v-model="form.settingInfo.localTime">
|
||||
<template #append>
|
||||
<el-button icon="Refresh">同步</el-button>
|
||||
<el-button @click="onSyncTime" icon="Refresh">
|
||||
{{ $t('commons.button.sync') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
@ -111,7 +113,7 @@
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<el-dialog v-model="passwordVisiable" title="密码修改" width="30%">
|
||||
<el-dialog v-model="passwordVisiable" :title="$t('setting.changePassword')" width="30%">
|
||||
<el-form
|
||||
size="small"
|
||||
ref="passFormRef"
|
||||
@ -120,13 +122,13 @@
|
||||
:model="passForm"
|
||||
:rules="passRules"
|
||||
>
|
||||
<el-form-item label="原密码" prop="oldPassword">
|
||||
<el-form-item :label="$t('setting.oldPassword')" prop="oldPassword">
|
||||
<el-input type="password" show-password clearable v-model="passForm.oldPassword" />
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-form-item :label="$t('setting.newPassword')" prop="newPassword">
|
||||
<el-input type="password" show-password clearable v-model="passForm.newPassword" />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="retryPassword">
|
||||
<el-form-item :label="$t('setting.retryPassword')" prop="retryPassword">
|
||||
<el-input type="password" show-password clearable v-model="passForm.retryPassword" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -142,9 +144,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { ElMessage, ElForm } from 'element-plus';
|
||||
import { updateSetting, updatePassword } from '@/api/modules/setting';
|
||||
import { updateSetting, updatePassword, syncTime } from '@/api/modules/setting';
|
||||
import { Setting } from '@/api/interface/setting';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { GlobalStore } from '@/store';
|
||||
@ -154,6 +156,7 @@ import router from '@/routers/router';
|
||||
|
||||
const i18n = useI18n();
|
||||
const globalStore = GlobalStore();
|
||||
const themeConfig = computed(() => globalStore.themeConfig);
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const passFormRef = ref<FormInstance>();
|
||||
@ -193,9 +196,13 @@ const SaveSetting = async (key: string, val: string) => {
|
||||
i18n.locale.value = val;
|
||||
globalStore.updateLanguage(val);
|
||||
break;
|
||||
case 'theme':
|
||||
case 'Theme':
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, theme: val });
|
||||
switchDark();
|
||||
break;
|
||||
case 'PanelName':
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, panelName: val });
|
||||
break;
|
||||
}
|
||||
let param = {
|
||||
key: key,
|
||||
@ -218,4 +225,9 @@ const submitChangePassword = async () => {
|
||||
router.push({ name: 'login' });
|
||||
globalStore.setLogStatus(false);
|
||||
};
|
||||
const onSyncTime = async () => {
|
||||
const res = await syncTime();
|
||||
form.settingInfo.localTime = res.data;
|
||||
ElMessage.success(i18n.t('commons.msg.operationSuccess'));
|
||||
};
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user