Compare commits

...
Author SHA1 Message Date
zhengkunwang223 174d60e3d6 fix: 解决网站配置文件生成错误问题 2024-06-26 15:52:00 +08:00
ssongliu 88f19b792c fix: 解决依赖升级导致的引用问题 2024-06-25 15:45:43 +08:00
ssongliu 790e9252e7 fix: 增加系统主题变化监听事件 (#5555) 2024-06-25 14:43:42 +08:00
zhengkunwang223 3d8d18db4d feat: 优化应用升级逻辑,拉取镜像失败无需回滚 2024-06-25 14:13:08 +08:00
zhengkunwang223 297e630753 feat: 优化 WAF 配置文件生成 2024-06-24 14:54:17 +08:00
ssongliu 7583196c80 fix: 解决面板主题跟随系统失效的问题 (#5547)
Refs #5527
2024-06-24 14:44:50 +08:00
zhengkunwang a06e4060a2 feat: 优化文件上传逻辑,减少临时空间占用 (#5508)
Refs https://github.com/1Panel-dev/1Panel/issues/5184
2024-06-24 14:44:40 +08:00
ssongliu 60d484bce4 fix: 解决升级导致的计划任务未执行问题 (#5483)
Refs #5414
2024-06-24 14:42:25 +08:00
ssongliu ebc6a1bd6d fix: 解决界面设置主题色不统一的问题 (#5449) 2024-06-24 14:40:42 +08:00
zhengkunwang 9bcfce14cb feat: demo 环境适配网站监控 (#5446) 2024-06-24 14:39:20 +08:00
zhengkunwang dfd84d414e fix: 解决应用安装 services 为空报系统错误的问题 (#5445) 2024-06-24 14:39:16 +08:00
zhengkunwang 1b07314c23 feat: 优化非80端口网站开启 https 端口配置 (#5443)
Refs https://github.com/1Panel-dev/1Panel/issues/5364
2024-06-24 14:39:13 +08:00
ssongliu f7e2f2dbb8 fix: 修改终端全屏按钮样式 (#5442)
Refs #5435
2024-06-24 14:38:41 +08:00
ssongliu 1a617e71bd fix: 解决浏览器切换时部分设置未同步的问题 (#5436)
Refs #5422
2024-06-24 14:38:38 +08:00
zhengkunwang 794ebfab2b fix: 解决部分情况下打开文件中文乱码的问题 (#5425)
Refs https://github.com/1Panel-dev/1Panel/issues/5374
2024-06-24 14:37:43 +08:00
zhengkunwang d33b836d3e fix: 解决升级页面 链接点击不跳转的问题 (#5413)
Refs https://github.com/1Panel-dev/1Panel/issues/5371
2024-06-24 14:37:40 +08:00
ssongliu 408997e725 fix: 解决计划任务执行周期错误的问题 (#5412)
Refs #5404
2024-06-24 14:37:13 +08:00
Frost-ZX 3ca3949b1e fix: 修正未认证设置表单初始值 (#5383) 2024-06-24 14:37:01 +08:00
ssongliu 2e05af650a fix: 解决深色模式下版本显示问题 (#5402)
Refs #5370
2024-06-24 14:36:56 +08:00
26 changed files with 181 additions and 89 deletions
+6 -1
View File
@@ -593,6 +593,10 @@ func (b *BaseApi) Size(c *gin.Context) {
} }
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int, overwrite bool) error { func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int, overwrite bool) error {
defer func() {
_ = os.RemoveAll(fileDir)
}()
op := files.NewFileOp() op := files.NewFileOp()
dstDir = strings.TrimSpace(dstDir) dstDir = strings.TrimSpace(dstDir)
mode, _ := files.GetParentMode(dstDir) mode, _ := files.GetParentMode(dstDir)
@@ -629,9 +633,10 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
if err != nil { if err != nil {
return err return err
} }
_ = os.Remove(chunkPath)
} }
return files.NewFileOp().DeleteDir(fileDir) return nil
} }
// @Tags File // @Tags File
+7
View File
@@ -88,6 +88,12 @@ type AppInstalledDTO struct {
Path string `json:"path"` Path string `json:"path"`
} }
type AppDetail struct {
Website string `json:"website"`
Document string `json:"document"`
Github string `json:"github"`
}
type AppInstallDTO struct { type AppInstallDTO struct {
ID uint `json:"id"` ID uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -109,6 +115,7 @@ type AppInstallDTO struct {
AppStatus string `json:"appStatus"` AppStatus string `json:"appStatus"`
DockerCompose string `json:"dockerCompose"` DockerCompose string `json:"dockerCompose"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
App AppDetail `json:"app"`
} }
type DatabaseConn struct { type DatabaseConn struct {
+1 -1
View File
@@ -367,7 +367,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
} }
value, ok := composeMap["services"] value, ok := composeMap["services"]
if !ok { if !ok || value == nil {
err = buserr.New(constant.ErrFileParse) err = buserr.New(constant.ErrFileParse)
return return
} }
+45 -33
View File
@@ -14,6 +14,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@@ -449,7 +450,7 @@ func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string
return "", err return "", err
} }
value, ok := composeMap["services"] value, ok := composeMap["services"]
if !ok { if !ok || value == nil {
return "", buserr.New(constant.ErrFileParse) return "", buserr.New(constant.ErrFileParse)
} }
servicesMap := value.(map[string]interface{}) servicesMap := value.(map[string]interface{})
@@ -511,6 +512,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
var ( var (
upErr error upErr error
backupFile string backupFile string
preErr error
) )
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil)) global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil))
if req.Backup { if req.Backup {
@@ -543,18 +545,27 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
_ = appInstallRepo.Save(context.Background(), &existInstall) _ = appInstallRepo.Save(context.Background(), &existInstall)
} }
} }
if preErr != nil {
global.LOG.Infof(i18n.GetMsgWithName("ErrAppUpgrade", install.Name, preErr))
existInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallID))
if existInstall.ID > 0 {
existInstall.Status = constant.UpgradeErr
existInstall.Message = preErr.Error()
_ = appInstallRepo.Save(context.Background(), &existInstall)
}
}
}() }()
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version) detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
if install.App.Resource == constant.AppResourceRemote { if install.App.Resource == constant.AppResourceRemote {
if upErr = downloadApp(install.App, detail, &install); upErr != nil { if preErr = downloadApp(install.App, detail, &install); preErr != nil {
return return
} }
if detail.DockerCompose == "" { if detail.DockerCompose == "" {
composeDetail, err := fileOp.GetContent(path.Join(detailDir, "docker-compose.yml")) composeDetail, err := fileOp.GetContent(path.Join(detailDir, "docker-compose.yml"))
if err != nil { if err != nil {
upErr = err preErr = err
return return
} }
detail.DockerCompose = string(composeDetail) detail.DockerCompose = string(composeDetail)
@@ -569,6 +580,32 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version) detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
} }
content, err := fileOp.GetContent(install.GetEnvPath())
if err != nil {
preErr = err
return
}
if req.PullImage {
projectName := strings.ToLower(install.Name)
images, err := composeV2.GetDockerComposeImages(projectName, content, []byte(detail.DockerCompose))
if err != nil {
preErr = err
return
}
for _, image := range images {
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
if out, err := cmd.ExecWithTimeOut("docker pull "+image, 20*time.Minute); err != nil {
if out != "" {
err = errors.New(out)
}
preErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
return
} else {
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
}
}
}
command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath())) command := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rn %s/* %s || true", detailDir, install.GetPath()))
stdout, _ := command.CombinedOutput() stdout, _ := command.CombinedOutput()
if stdout != nil { if stdout != nil {
@@ -597,36 +634,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
install.Version = detail.Version install.Version = detail.Version
install.AppDetailId = req.DetailID install.AppDetailId = req.DetailID
content, err := fileOp.GetContent(install.GetEnvPath())
if err != nil {
upErr = err
return
}
if req.PullImage {
projectName := strings.ToLower(install.Name)
images, err := composeV2.GetDockerComposeImages(projectName, content, []byte(detail.DockerCompose))
if err != nil {
upErr = err
return
}
dockerCli, err := composeV2.NewClient()
if err != nil {
upErr = err
return
}
defer dockerCli.Close()
for _, image := range images {
global.LOG.Infof(i18n.GetMsgWithName("PullImageStart", image, nil))
if err = dockerCli.PullImage(image, true); err != nil {
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
return
} else {
global.LOG.Infof(i18n.GetMsgByKey("PullImageSuccess"))
}
}
}
if out, err := compose.Down(install.GetComposePath()); err != nil { if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" { if out != "" {
upErr = errors.New(out) upErr = errors.New(out)
@@ -1255,6 +1262,11 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
AppType: installed.App.Type, AppType: installed.App.Type,
Path: installed.GetPath(), Path: installed.GetPath(),
CreatedAt: installed.CreatedAt, CreatedAt: installed.CreatedAt,
App: response.AppDetail{
Github: installed.App.Github,
Website: installed.App.Website,
Document: installed.App.Document,
},
} }
if updated { if updated {
installDTO.DockerCompose = installed.DockerCompose installDTO.DockerCompose = installed.DockerCompose
+6 -6
View File
@@ -29,7 +29,7 @@ type ICronjobService interface {
UpdateStatus(id uint, status string) error UpdateStatus(id uint, status string) error
Delete(req dto.CronjobBatchDelete) error Delete(req dto.CronjobBatchDelete) error
Download(down dto.CronjobDownload) (string, error) Download(down dto.CronjobDownload) (string, error)
StartJob(cronjob *model.Cronjob) (string, error) StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
CleanRecord(req dto.CronjobClean) error CleanRecord(req dto.CronjobClean) error
LoadRecordLog(req dto.OperateByID) string LoadRecordLog(req dto.OperateByID) string
@@ -181,7 +181,7 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec) global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec)
spec := cronjob.Spec spec := cronjob.Spec
entryIDs, err := u.StartJob(&cronjob) entryIDs, err := u.StartJob(&cronjob, false)
if err != nil { if err != nil {
return err return err
} }
@@ -193,8 +193,8 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
return nil return nil
} }
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (string, error) { func (u *CronjobService) StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error) {
if len(cronjob.EntryIDs) != 0 { if len(cronjob.EntryIDs) != 0 && isUpdate {
ids := strings.Split(cronjob.EntryIDs, ",") ids := strings.Split(cronjob.EntryIDs, ",")
for _, id := range ids { for _, id := range ids {
idItem, _ := strconv.Atoi(id) idItem, _ := strconv.Atoi(id)
@@ -251,7 +251,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
cronjob.Type = cronModel.Type cronjob.Type = cronModel.Type
spec := cronjob.Spec spec := cronjob.Spec
if cronModel.Status == constant.StatusEnable { if cronModel.Status == constant.StatusEnable {
newEntryIDs, err := u.StartJob(&cronjob) newEntryIDs, err := u.StartJob(&cronjob, true)
if err != nil { if err != nil {
return err return err
} }
@@ -294,7 +294,7 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
err error err error
) )
if status == constant.StatusEnable { if status == constant.StatusEnable {
entryIDs, err = u.StartJob(&cronjob) entryIDs, err = u.StartJob(&cronjob, false)
if err != nil { if err != nil {
return err return err
} }
+12 -11
View File
@@ -10,6 +10,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"unicode/utf8"
"github.com/1Panel-dev/1Panel/backend/app/dto/request" "github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response" "github.com/1Panel-dev/1Panel/backend/app/dto/response"
@@ -236,20 +237,20 @@ func (f *FileService) GetContent(op request.FileContentReq) (response.FileInfo,
} }
content := []byte(info.Content) content := []byte(info.Content)
var decodeName string
if len(content) > 1024 { if len(content) > 1024 {
_, decodeName, _ = charset.DetermineEncoding(content[:1024], "") content = content[:1024]
} else {
_, decodeName, _ = charset.DetermineEncoding(content, "")
} }
if decodeName == "windows-1252" { if !utf8.Valid(content) {
reader := strings.NewReader(info.Content) _, decodeName, _ := charset.DetermineEncoding(content, "")
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder()) if decodeName == "windows-1252" {
contents, err := io.ReadAll(item) reader := strings.NewReader(info.Content)
if err != nil { item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
return response.FileInfo{}, err contents, err := io.ReadAll(item)
if err != nil {
return response.FileInfo{}, err
}
info.Content = string(contents)
} }
info.Content = string(contents)
} }
return response.FileInfo{FileInfo: *info}, nil return response.FileInfo{FileInfo: *info}, nil
} }
+2 -2
View File
@@ -526,7 +526,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
for _, domain := range domainModels { for _, domain := range domainModels {
wafSite.Domains = append(wafSite.Domains, domain.Domain) wafSite.Domains = append(wafSite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 { if domain.Port != 80 && domain.Port != 443 {
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port))) wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
} }
} }
if len(wafSite.Host) == 0 { if len(wafSite.Host) == 0 {
@@ -619,7 +619,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
oldHostArray := wafSite.Host oldHostArray := wafSite.Host
var newHostArray []string var newHostArray []string
for _, host := range oldHostArray { for _, host := range oldHostArray {
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) { if host == webSiteDomain.Domain+":"+strconv.Itoa(webSiteDomain.Port) {
continue continue
} }
newHostArray = append(newHostArray, host) newHostArray = append(newHostArray, host)
+18 -6
View File
@@ -316,9 +316,7 @@ func createWafConfig(website *model.Website, domains []model.WebsiteDomain) erro
for _, domain := range domains { for _, domain := range domains {
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain) wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 { wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
} }
websitesArray = append(websitesArray, wafWebsite) websitesArray = append(websitesArray, wafWebsite)
websitesContent, err := json.Marshal(websitesArray) websitesContent, err := json.Marshal(websitesArray)
@@ -563,6 +561,16 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
if err != nil { if err != nil {
return nil return nil
} }
domains, err := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
if err != nil {
return nil
}
noDefaultPort := true
for _, domain := range domains {
if domain.Port == 80 {
noDefaultPort = false
}
}
config := nginxFull.SiteConfig.Config config := nginxFull.SiteConfig.Config
server := config.FindServers()[0] server := config.FindServers()[0]
@@ -582,13 +590,17 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
server.RemoveListenByBind(httpPortIPV6) server.RemoveListenByBind(httpPortIPV6)
server.RemoveDirective("if", []string{"($scheme"}) server.RemoveDirective("if", []string{"($scheme"})
case constant.HTTPToHTTPS: case constant.HTTPToHTTPS:
server.UpdateListen(httpPort, website.DefaultServer) if !noDefaultPort {
server.UpdateListen(httpPort, website.DefaultServer)
}
if website.IPV6 { if website.IPV6 {
server.UpdateListen(httpPortIPV6, website.DefaultServer) server.UpdateListen(httpPortIPV6, website.DefaultServer)
} }
server.AddHTTP2HTTPS() server.AddHTTP2HTTPS()
case constant.HTTPAlso: case constant.HTTPAlso:
server.UpdateListen(httpPort, website.DefaultServer) if !noDefaultPort {
server.UpdateListen(httpPort, website.DefaultServer)
}
server.RemoveDirective("if", []string{"($scheme"}) server.RemoveDirective("if", []string{"($scheme"})
if website.IPV6 { if website.IPV6 {
server.UpdateListen(httpPortIPV6, website.DefaultServer) server.UpdateListen(httpPortIPV6, website.DefaultServer)
@@ -849,7 +861,7 @@ func changeServiceName(newComposeContent, newServiceName string) (composeByte []
return return
} }
value, ok := composeMap["services"] value, ok := composeMap["services"]
if !ok { if !ok || value == nil {
err = buserr.New(constant.ErrFileParse) err = buserr.New(constant.ErrFileParse)
return return
} }
+1 -1
View File
@@ -71,7 +71,7 @@ func Run() {
global.LOG.Errorf("start my cronjob failed, err: %v", err) global.LOG.Errorf("start my cronjob failed, err: %v", err)
} }
for i := 0; i < len(cronJobs); i++ { for i := 0; i < len(cronJobs); i++ {
entryIDs, err := service.NewICronjobService().StartJob(&cronJobs[i]) entryIDs, err := service.NewICronjobService().StartJob(&cronJobs[i], false)
if err != nil { if err != nil {
global.LOG.Errorf("start %s job %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err) global.LOG.Errorf("start %s job %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
} }
+5
View File
@@ -30,6 +30,11 @@ var whiteUrlList = map[string]struct{}{
"/api/v1/waf/attack/stat": {}, "/api/v1/waf/attack/stat": {},
"/api/v1/waf/config/website": {}, "/api/v1/waf/config/website": {},
"/api/v1/monitor/stat": {},
"/api/v1/monitor/visitors": {},
"/api/v1/monitor/visitors/loc": {},
"/api/v1/monitor/qps": {},
} }
func DemoHandle() gin.HandlerFunc { func DemoHandle() gin.HandlerFunc {
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M11.1451 18.8875L5.66228 15.7224V8.40336L3.5376 7.1759V16.9488L9.02038 20.114L11.1451 18.8875Z" />
<path d="M18.3397 15.7224L12.0005 19.3819L9.87683 20.6083L12.0005 21.8348L20.4644 16.9488L18.3397 15.7224Z" />
<path d="M12.0015 4.74388L14.1252 3.5174L12.0005 2.28995L3.5376 7.17591L5.66228 8.40337L12.0005 4.74388H12.0015Z" />
<path d="M14.9816 4.01077L12.8569 5.23723L18.3397 8.40336V15.7224L20.4634 16.9488V7.1759L14.9816 4.01077Z" />
<path d="M11.9995 1.02569L21.5576 6.54428V17.5795L11.9995 23.0971L2.44343 17.5795V6.54428L11.9995 1.02569ZM11.9995 0.72728L2.18182 6.39707V17.7366L11.9995 23.4064L21.8182 17.7366V6.39707L11.9995 0.72728Z" />
<path d="M12.3079 6.78001L12.9564 7.16695V17.105L12.3079 17.48V6.78001Z" />
<path d="M12.3078 6.78001L9.10889 8.6222V9.86954H10.2359V16.2854L12.3059 17.481L12.3078 6.78001Z" />
</svg>

After

Width:  |  Height:  |  Size: 942 B

@@ -205,6 +205,7 @@ onMounted(() => {
font-size: 14px; font-size: 14px;
} }
:deep(.default-theme h2) { :deep(.default-theme h2) {
color: var(--dark-gold-base-color);
margin: 13px, 0; margin: 13px, 0;
padding: 0; padding: 0;
font-size: 16px; font-size: 16px;
+4 -2
View File
@@ -8,12 +8,14 @@ export const useTheme = () => {
body.setAttribute('class', 'dark-gold'); body.setAttribute('class', 'dark-gold');
return; return;
} }
let itemTheme = globalStore.themeConfig.theme;
if (globalStore.themeConfig.theme === 'auto') { if (globalStore.themeConfig.theme === 'auto') {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
globalStore.themeConfig.theme = prefersDark.matches ? 'dark' : 'light'; itemTheme = prefersDark.matches ? 'dark' : 'light';
} }
const body = document.documentElement as HTMLElement; const body = document.documentElement as HTMLElement;
if (globalStore.themeConfig.theme === 'dark') body.setAttribute('class', 'dark'); if (itemTheme === 'dark') body.setAttribute('class', 'dark');
else body.setAttribute('class', ''); else body.setAttribute('class', '');
}; };
+4 -2
View File
@@ -1729,7 +1729,8 @@ const message = {
takeDown: 'TakeDown', takeDown: 'TakeDown',
allReadyInstalled: 'Installed', allReadyInstalled: 'Installed',
installHelper: 'Configuring image acceleration can solve the problem of image pull failure', installHelper: 'Configuring image acceleration can solve the problem of image pull failure',
upgradeHelper: 'The abnormal application needs to be synchronized to the normal state first', upgradeHelper:
'Abnormal applications need to be synchronized to normal status first. If the upgrade fails, please check the failure reason in the log audit-system log',
installWarn: installWarn:
'Currently, if the port external access is not checked, it will not be able to access through the external network IP: port. Do you want to continue?', 'Currently, if the port external access is not checked, it will not be able to access through the external network IP: port. Do you want to continue?',
showIgnore: 'View ignore application', showIgnore: 'View ignore application',
@@ -1737,7 +1738,8 @@ const message = {
ignoreList: 'ignore list', ignoreList: 'ignore list',
appHelper: 'Please view the installation instructions of some applications on the application details page', appHelper: 'Please view the installation instructions of some applications on the application details page',
backupApp: 'Backup application before upgrade', backupApp: 'Backup application before upgrade',
backupAppHelper: 'If the upgrade fails, you can use the application backup to roll back', backupAppHelper:
'If the upgrade fails, the backup will be automatically rolled back. Please check the failure reason in the log audit-system log',
delete: 'Delete', delete: 'Delete',
openrestyDeleteHelper: openrestyDeleteHelper:
'Forcibly deleting OpenResty will delete all websites, please confirm the risk before operation', 'Forcibly deleting OpenResty will delete all websites, please confirm the risk before operation',
+7 -7
View File
@@ -827,12 +827,12 @@ const message = {
perMonth: '每月', perMonth: '每月',
perWeek: '每周', perWeek: '每周',
perHour: '每小時', perHour: '每小時',
perNDay: '每隔 N 日', perNDay: '每 N 日',
perDay: '每天', perDay: '每天',
perNHour: '每隔 N 時', perNHour: '每 N 時',
perNMinute: '每隔 N 分鐘', perNMinute: '每 N 分鐘',
perNSecond: '每隔 N 秒', perNSecond: '每 N 秒',
per: '每隔', per: '每',
handle: '執行', handle: '執行',
day: '日', day: '日',
monday: '周一', monday: '周一',
@@ -1610,14 +1610,14 @@ const message = {
takeDown: '已廢棄', takeDown: '已廢棄',
allReadyInstalled: '已安裝', allReadyInstalled: '已安裝',
installHelper: '配置鏡像加速可以解決鏡像拉取失敗的問題', installHelper: '配置鏡像加速可以解決鏡像拉取失敗的問題',
upgradeHelper: '異常應用需要先同步到正常狀態', upgradeHelper: '異常應用程式需要先同步到正常狀態,升級失敗請在日誌審計-系統日誌中查看失敗原因',
installWarn: '當前未勾選端口外部訪問,將無法通過外網IP:端口訪問,是否繼續? ', installWarn: '當前未勾選端口外部訪問,將無法通過外網IP:端口訪問,是否繼續? ',
showIgnore: '查看忽略應用', showIgnore: '查看忽略應用',
cancelIgnore: '取消忽略', cancelIgnore: '取消忽略',
ignoreList: '忽略列表', ignoreList: '忽略列表',
appHelper: '部分應用的安裝使用說明請在應用詳情頁查看', appHelper: '部分應用的安裝使用說明請在應用詳情頁查看',
backupApp: '升級前備份應用', backupApp: '升級前備份應用',
backupAppHelper: '升級失敗可以使用應用備份回滾', backupAppHelper: '升級失敗會使用備份自動回滾,請在日誌審計-系統日誌中查看失敗原因',
delete: '刪除', delete: '刪除',
openrestyDeleteHelper: '強制刪除 OpenResty 會刪除所有的網站,請確認風險後操作', openrestyDeleteHelper: '強制刪除 OpenResty 會刪除所有的網站,請確認風險後操作',
downloadLogHelper1: '即將下載 {0} 套用所有日誌,是否繼續? ', downloadLogHelper1: '即將下載 {0} 套用所有日誌,是否繼續? ',
+7 -7
View File
@@ -828,12 +828,12 @@ const message = {
perMonth: '每月', perMonth: '每月',
perWeek: '每周', perWeek: '每周',
perHour: '每小时', perHour: '每小时',
perNDay: '每隔 N 日', perNDay: '每 N 日',
perDay: '每天', perDay: '每天',
perNHour: '每隔 N 时', perNHour: '每 N 时',
perNMinute: '每隔 N 分钟', perNMinute: '每 N 分钟',
perNSecond: '每隔 N 秒', perNSecond: '每 N 秒',
per: '每隔', per: '每',
handle: '执行', handle: '执行',
day: '日', day: '日',
monday: '周一', monday: '周一',
@@ -1610,14 +1610,14 @@ const message = {
takeDown: '已废弃', takeDown: '已废弃',
allReadyInstalled: '已安装', allReadyInstalled: '已安装',
installHelper: '配置镜像加速可以解决镜像拉取失败的问题', installHelper: '配置镜像加速可以解决镜像拉取失败的问题',
upgradeHelper: '异常应用需要先同步到正常状态', upgradeHelper: '异常应用需要先同步到正常状态,升级失败请在日志审计-系统日志中查看失败原因',
installWarn: '当前未勾选端口外部访问,将无法通过外网IP:端口访问,是否继续?', installWarn: '当前未勾选端口外部访问,将无法通过外网IP:端口访问,是否继续?',
showIgnore: '查看忽略应用', showIgnore: '查看忽略应用',
cancelIgnore: '取消忽略', cancelIgnore: '取消忽略',
ignoreList: '忽略列表', ignoreList: '忽略列表',
appHelper: '部分应用的安装使用说明请在应用详情页查看', appHelper: '部分应用的安装使用说明请在应用详情页查看',
backupApp: '升级前备份应用', backupApp: '升级前备份应用',
backupAppHelper: '升级失败可以使用应用备份回滚', backupAppHelper: '升级失败会使用备份自动回滚,请在日志审计-系统日志中查看失败原因',
delete: '删除', delete: '删除',
openrestyDeleteHelper: '强制删除 OpenResty 会删除所有的网站,请确认风险之后操作', openrestyDeleteHelper: '强制删除 OpenResty 会删除所有的网站,请确认风险之后操作',
downloadLogHelper1: '即将下载 {0} 应用所有日志,是否继续?', downloadLogHelper1: '即将下载 {0} 应用所有日志,是否继续?',
+13
View File
@@ -23,6 +23,8 @@ import { DeviceType } from '@/enums/app';
import { getSystemAvailable } from '@/api/modules/setting'; import { getSystemAvailable } from '@/api/modules/setting';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { loadProductProFromDB } from '@/utils/xpack'; import { loadProductProFromDB } from '@/utils/xpack';
import { useTheme } from '@/hooks/use-theme';
const { switchTheme } = useTheme();
useResize(); useResize();
const router = useRouter(); const router = useRouter();
@@ -98,6 +100,17 @@ onMounted(() => {
loadStatus(); loadStatus();
loadProductProFromDB(); loadProductProFromDB();
const mqList = window.matchMedia('(prefers-color-scheme: dark)');
if (mqList.addEventListener) {
mqList.addEventListener('change', () => {
switchTheme();
});
} else if (mqList.addListener) {
mqList.addListener(() => {
switchTheme();
});
}
}); });
</script> </script>
+4 -1
View File
@@ -43,7 +43,10 @@ const GlobalStore = defineStore({
errStatus: '', errStatus: '',
}), }),
getters: { getters: {
isDarkTheme: (state) => state.themeConfig.theme === 'dark' || state.themeConfig.isGold, isDarkTheme: (state) =>
state.themeConfig.theme === 'dark' ||
state.themeConfig.isGold ||
(state.themeConfig.theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches),
isDarkGoldTheme: (state) => state.themeConfig.isGold && state.isProductPro, isDarkGoldTheme: (state) => state.themeConfig.isGold && state.isProductPro,
}, },
actions: { actions: {
+1
View File
@@ -1,5 +1,6 @@
html.dark { html.dark {
--el-box-shadow-light: 0px 0px 4px rgba(0, 0, 0, 0.1) !important; --el-box-shadow-light: 0px 0px 4px rgba(0, 0, 0, 0.1) !important;
--dark-gold-base-color: #5a5a5a;
--el-border-color-lighter: #1d2023; --el-border-color-lighter: #1d2023;
--el-fill-color-blank: #111417; --el-fill-color-blank: #111417;
--el-bg-color: rgba(0, 11, 21, 1); --el-bg-color: rgba(0, 11, 21, 1);
+18 -2
View File
@@ -1,4 +1,4 @@
import { getLicenseStatus } from '@/api/modules/setting'; import { getLicenseStatus, getSettingInfo } from '@/api/modules/setting';
import { useTheme } from '@/hooks/use-theme'; import { useTheme } from '@/hooks/use-theme';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
@@ -18,7 +18,12 @@ export function initFavicon() {
const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement; const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement;
link.type = 'image/x-icon'; link.type = 'image/x-icon';
link.rel = 'shortcut icon'; link.rel = 'shortcut icon';
link.href = favicon ? '/api/v1/images/favicon' : '/public/favicon.png'; if (globalStore.isDarkGoldTheme) {
let goldLink = new URL(`../assets/images/favicon-gold.png`, import.meta.url).href;
link.href = favicon ? '/api/v1/images/favicon' : goldLink;
} else {
link.href = favicon ? '/api/v1/images/favicon' : '/public/favicon.png';
}
document.getElementsByTagName('head')[0].appendChild(link); document.getElementsByTagName('head')[0].appendChild(link);
} }
@@ -27,12 +32,22 @@ export async function getXpackSetting() {
const module = await searchXSettingGlob?.['../xpack/api/modules/setting.ts']?.(); const module = await searchXSettingGlob?.['../xpack/api/modules/setting.ts']?.();
const res = await module?.searchXSetting(); const res = await module?.searchXSetting();
if (!res) { if (!res) {
initFavicon();
resetXSetting(); resetXSetting();
return; return;
} }
initFavicon();
return res; return res;
} }
const loadDataFromDB = async () => {
const res = await getSettingInfo();
document.title = res.data.panelName;
globalStore.entrance = res.data.securityEntrance;
globalStore.setDefaultNetwork(res.data.defaultNetwork);
globalStore.setOpenMenuTabs(res.data.menuTabs === 'enable');
};
export async function loadProductProFromDB() { export async function loadProductProFromDB() {
const res = await getLicenseStatus(); const res = await getLicenseStatus();
if (!res.data) { if (!res.data) {
@@ -48,6 +63,7 @@ export async function loadProductProFromDB() {
} }
switchTheme(); switchTheme();
initFavicon(); initFavicon();
loadDataFromDB();
} }
export async function getXpackSettingForTheme() { export async function getXpackSettingForTheme() {
@@ -53,7 +53,9 @@
</el-form-item> </el-form-item>
<el-form-item prop="backup" v-if="operateReq.operate === 'upgrade'"> <el-form-item prop="backup" v-if="operateReq.operate === 'upgrade'">
<el-checkbox v-model="operateReq.backup" :label="$t('app.backupApp')" /> <el-checkbox v-model="operateReq.backup" :label="$t('app.backupApp')" />
<span class="input-help">{{ $t('app.backupAppHelper') }}</span> <span class="input-help">
<el-text type="warning">{{ $t('app.backupAppHelper') }}</el-text>
</span>
</el-form-item> </el-form-item>
<el-form-item pro="pullImage" v-if="operateReq.operate === 'upgrade'"> <el-form-item pro="pullImage" v-if="operateReq.operate === 'upgrade'">
<el-checkbox v-model="operateReq.pullImage" :label="$t('container.forcePull')" size="large" /> <el-checkbox v-model="operateReq.pullImage" :label="$t('container.forcePull')" size="large" />
+2 -4
View File
@@ -92,12 +92,10 @@ export function transObjToSpec(specType: string, week, day, hour, minute, second
case 'perWeek': case 'perWeek':
return `${minute} ${hour} * * ${week}`; return `${minute} ${hour} * * ${week}`;
case 'perNDay': case 'perNDay':
day = Number(day) + 1 + '';
return `${minute} ${hour} */${day} * *`; return `${minute} ${hour} */${day} * *`;
case 'perDay': case 'perDay':
return `${minute} ${hour} * * *`; return `${minute} ${hour} * * *`;
case 'perNHour': case 'perNHour':
hour = Number(hour) + 1 + '';
return `${minute} */${hour} * * *`; return `${minute} */${hour} * * *`;
case 'perHour': case 'perHour':
return `${minute} * * * *`; return `${minute} * * * *`;
@@ -141,13 +139,13 @@ export function transSpecToObj(spec: string) {
} }
if (specs[1].indexOf('*/') !== -1) { if (specs[1].indexOf('*/') !== -1) {
specItem.specType = 'perNHour'; specItem.specType = 'perNHour';
specItem.hour = Number(specs[1].replaceAll('*/', '')) - 1; specItem.hour = Number(specs[1].replaceAll('*/', ''));
return specItem; return specItem;
} }
specItem.hour = Number(specs[1]); specItem.hour = Number(specs[1]);
if (specs[2].indexOf('*/') !== -1) { if (specs[2].indexOf('*/') !== -1) {
specItem.specType = 'perNDay'; specItem.specType = 'perNDay';
specItem.day = Number(specs[2].replaceAll('*/', '')) - 1; specItem.day = Number(specs[2].replaceAll('*/', ''));
return specItem; return specItem;
} }
if (specs[2] !== '*') { if (specs[2] !== '*') {
@@ -448,7 +448,7 @@ onMounted(() => {
font-weight: 600; font-weight: 600;
} }
.fullScreen { .fullScreen {
background-color: #efefef; background-color: transparent;
border: none; border: none;
position: absolute; position: absolute;
right: 50px; right: 50px;
@@ -361,6 +361,7 @@ const loadDataFromDB = async () => {
i18n.locale.value = res.data.language; i18n.locale.value = res.data.language;
i18n.warnHtmlMessage = false; i18n.warnHtmlMessage = false;
globalStore.entrance = res.data.securityEntrance; globalStore.entrance = res.data.securityEntrance;
globalStore.setDefaultNetwork(res.data.defaultNetwork);
globalStore.setOpenMenuTabs(res.data.menuTabs === 'enable'); globalStore.setOpenMenuTabs(res.data.menuTabs === 'enable');
globalStore.updateLanguage(res.data.language); globalStore.updateLanguage(res.data.language);
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme, panelName: res.data.panelName }); globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme, panelName: res.data.panelName });
+3 -1
View File
@@ -224,6 +224,7 @@ const form = reactive({
allowIPs: '', allowIPs: '',
bindDomain: '', bindDomain: '',
noAuthSetting: '200 - ' + i18n.global.t('setting.help200'), noAuthSetting: '200 - ' + i18n.global.t('setting.help200'),
noAuthSettingValue: '200',
}); });
const unset = ref(i18n.global.t('setting.unSetting')); const unset = ref(i18n.global.t('setting.unSetting'));
@@ -246,6 +247,7 @@ const search = async () => {
form.mfaInterval = Number(res.data.mfaInterval); form.mfaInterval = Number(res.data.mfaInterval);
form.allowIPs = res.data.allowIPs.replaceAll(',', '\n'); form.allowIPs = res.data.allowIPs.replaceAll(',', '\n');
form.bindDomain = res.data.bindDomain; form.bindDomain = res.data.bindDomain;
form.noAuthSettingValue = res.data.noAuthSetting;
if (res.data.noAuthSetting !== '200') { if (res.data.noAuthSetting !== '200') {
form.noAuthSetting = res.data.noAuthSetting + ' - ' + i18n.global.t('setting.error' + res.data.noAuthSetting); form.noAuthSetting = res.data.noAuthSetting + ' - ' + i18n.global.t('setting.error' + res.data.noAuthSetting);
} else { } else {
@@ -297,7 +299,7 @@ const onChangeBind = () => {
bindRef.value.acceptParams({ ipv6: form.ipv6, bindAddress: form.bindAddress }); bindRef.value.acceptParams({ ipv6: form.ipv6, bindAddress: form.bindAddress });
}; };
const onChangeResponse = () => { const onChangeResponse = () => {
responseRef.value.acceptParams({ noAuthSetting: form.noAuthSetting }); responseRef.value.acceptParams({ noAuthSetting: form.noAuthSettingValue });
}; };
const onChangeBindDomain = () => { const onChangeBindDomain = () => {
domainRef.value.acceptParams({ bindDomain: form.bindDomain }); domainRef.value.acceptParams({ bindDomain: form.bindDomain });