mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-09 08:00:27 +00:00
Compare commits
19
Commits
v2.0.11
...
v1.10.11-lts
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
174d60e3d6 | ||
|
|
88f19b792c | ||
|
|
790e9252e7 | ||
|
|
3d8d18db4d | ||
|
|
297e630753 | ||
|
|
7583196c80 | ||
|
|
a06e4060a2 | ||
|
|
60d484bce4 | ||
|
|
ebc6a1bd6d | ||
|
|
9bcfce14cb | ||
|
|
dfd84d414e | ||
|
|
1b07314c23 | ||
|
|
f7e2f2dbb8 | ||
|
|
1a617e71bd | ||
|
|
794ebfab2b | ||
|
|
d33b836d3e | ||
|
|
408997e725 | ||
|
|
3ca3949b1e | ||
|
|
2e05af650a |
@@ -593,6 +593,10 @@ func (b *BaseApi) Size(c *gin.Context) {
|
||||
}
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int, overwrite bool) error {
|
||||
defer func() {
|
||||
_ = os.RemoveAll(fileDir)
|
||||
}()
|
||||
|
||||
op := files.NewFileOp()
|
||||
dstDir = strings.TrimSpace(dstDir)
|
||||
mode, _ := files.GetParentMode(dstDir)
|
||||
@@ -629,9 +633,10 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(chunkPath)
|
||||
}
|
||||
|
||||
return files.NewFileOp().DeleteDir(fileDir)
|
||||
return nil
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
|
||||
@@ -88,6 +88,12 @@ type AppInstalledDTO struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type AppDetail struct {
|
||||
Website string `json:"website"`
|
||||
Document string `json:"document"`
|
||||
Github string `json:"github"`
|
||||
}
|
||||
|
||||
type AppInstallDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -109,6 +115,7 @@ type AppInstallDTO struct {
|
||||
AppStatus string `json:"appStatus"`
|
||||
DockerCompose string `json:"dockerCompose"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
App AppDetail `json:"app"`
|
||||
}
|
||||
|
||||
type DatabaseConn struct {
|
||||
|
||||
@@ -367,7 +367,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
||||
}
|
||||
|
||||
value, ok := composeMap["services"]
|
||||
if !ok {
|
||||
if !ok || value == nil {
|
||||
err = buserr.New(constant.ErrFileParse)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
||||
@@ -449,7 +450,7 @@ func getUpgradeCompose(install model.AppInstall, detail model.AppDetail) (string
|
||||
return "", err
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok {
|
||||
if !ok || value == nil {
|
||||
return "", buserr.New(constant.ErrFileParse)
|
||||
}
|
||||
servicesMap := value.(map[string]interface{})
|
||||
@@ -511,6 +512,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
var (
|
||||
upErr error
|
||||
backupFile string
|
||||
preErr error
|
||||
)
|
||||
global.LOG.Infof(i18n.GetMsgWithName("UpgradeAppStart", install.Name, nil))
|
||||
if req.Backup {
|
||||
@@ -543,18 +545,27 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
_ = 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()
|
||||
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
|
||||
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
|
||||
}
|
||||
if detail.DockerCompose == "" {
|
||||
composeDetail, err := fileOp.GetContent(path.Join(detailDir, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
upErr = err
|
||||
preErr = err
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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()))
|
||||
stdout, _ := command.CombinedOutput()
|
||||
if stdout != nil {
|
||||
@@ -597,36 +634,6 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
install.Version = detail.Version
|
||||
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 != "" {
|
||||
upErr = errors.New(out)
|
||||
@@ -1255,6 +1262,11 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
||||
AppType: installed.App.Type,
|
||||
Path: installed.GetPath(),
|
||||
CreatedAt: installed.CreatedAt,
|
||||
App: response.AppDetail{
|
||||
Github: installed.App.Github,
|
||||
Website: installed.App.Website,
|
||||
Document: installed.App.Document,
|
||||
},
|
||||
}
|
||||
if updated {
|
||||
installDTO.DockerCompose = installed.DockerCompose
|
||||
|
||||
@@ -29,7 +29,7 @@ type ICronjobService interface {
|
||||
UpdateStatus(id uint, status string) error
|
||||
Delete(req dto.CronjobBatchDelete) 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
|
||||
|
||||
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)
|
||||
spec := cronjob.Spec
|
||||
entryIDs, err := u.StartJob(&cronjob)
|
||||
entryIDs, err := u.StartJob(&cronjob, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -193,8 +193,8 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (string, error) {
|
||||
if len(cronjob.EntryIDs) != 0 {
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error) {
|
||||
if len(cronjob.EntryIDs) != 0 && isUpdate {
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
@@ -251,7 +251,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
cronjob.Type = cronModel.Type
|
||||
spec := cronjob.Spec
|
||||
if cronModel.Status == constant.StatusEnable {
|
||||
newEntryIDs, err := u.StartJob(&cronjob)
|
||||
newEntryIDs, err := u.StartJob(&cronjob, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -294,7 +294,7 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
entryIDs, err = u.StartJob(&cronjob)
|
||||
entryIDs, err = u.StartJob(&cronjob, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+12
-11
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
"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)
|
||||
var decodeName string
|
||||
if len(content) > 1024 {
|
||||
_, decodeName, _ = charset.DetermineEncoding(content[:1024], "")
|
||||
} else {
|
||||
_, decodeName, _ = charset.DetermineEncoding(content, "")
|
||||
content = content[:1024]
|
||||
}
|
||||
if decodeName == "windows-1252" {
|
||||
reader := strings.NewReader(info.Content)
|
||||
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
|
||||
contents, err := io.ReadAll(item)
|
||||
if err != nil {
|
||||
return response.FileInfo{}, err
|
||||
if !utf8.Valid(content) {
|
||||
_, decodeName, _ := charset.DetermineEncoding(content, "")
|
||||
if decodeName == "windows-1252" {
|
||||
reader := strings.NewReader(info.Content)
|
||||
item := transform.NewReader(reader, simplifiedchinese.GBK.NewDecoder())
|
||||
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
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
|
||||
for _, domain := range domainModels {
|
||||
wafSite.Domains = append(wafSite.Domains, domain.Domain)
|
||||
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 {
|
||||
@@ -619,7 +619,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
|
||||
oldHostArray := wafSite.Host
|
||||
var newHostArray []string
|
||||
for _, host := range oldHostArray {
|
||||
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) {
|
||||
if host == webSiteDomain.Domain+":"+strconv.Itoa(webSiteDomain.Port) {
|
||||
continue
|
||||
}
|
||||
newHostArray = append(newHostArray, host)
|
||||
|
||||
@@ -316,9 +316,7 @@ func createWafConfig(website *model.Website, domains []model.WebsiteDomain) erro
|
||||
|
||||
for _, domain := range domains {
|
||||
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
|
||||
if domain.Port != 80 && domain.Port != 443 {
|
||||
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
|
||||
}
|
||||
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
|
||||
}
|
||||
websitesArray = append(websitesArray, wafWebsite)
|
||||
websitesContent, err := json.Marshal(websitesArray)
|
||||
@@ -563,6 +561,16 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
if err != 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
|
||||
server := config.FindServers()[0]
|
||||
|
||||
@@ -582,13 +590,17 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
||||
server.RemoveListenByBind(httpPortIPV6)
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
case constant.HTTPToHTTPS:
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
}
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
}
|
||||
server.AddHTTP2HTTPS()
|
||||
case constant.HTTPAlso:
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
if !noDefaultPort {
|
||||
server.UpdateListen(httpPort, website.DefaultServer)
|
||||
}
|
||||
server.RemoveDirective("if", []string{"($scheme"})
|
||||
if website.IPV6 {
|
||||
server.UpdateListen(httpPortIPV6, website.DefaultServer)
|
||||
@@ -849,7 +861,7 @@ func changeServiceName(newComposeContent, newServiceName string) (composeByte []
|
||||
return
|
||||
}
|
||||
value, ok := composeMap["services"]
|
||||
if !ok {
|
||||
if !ok || value == nil {
|
||||
err = buserr.New(constant.ErrFileParse)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func Run() {
|
||||
global.LOG.Errorf("start my cronjob failed, err: %v", err)
|
||||
}
|
||||
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 {
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ var whiteUrlList = map[string]struct{}{
|
||||
|
||||
"/api/v1/waf/attack/stat": {},
|
||||
"/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 {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -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;
|
||||
}
|
||||
:deep(.default-theme h2) {
|
||||
color: var(--dark-gold-base-color);
|
||||
margin: 13px, 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
|
||||
@@ -8,12 +8,14 @@ export const useTheme = () => {
|
||||
body.setAttribute('class', 'dark-gold');
|
||||
return;
|
||||
}
|
||||
|
||||
let itemTheme = globalStore.themeConfig.theme;
|
||||
if (globalStore.themeConfig.theme === 'auto') {
|
||||
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;
|
||||
if (globalStore.themeConfig.theme === 'dark') body.setAttribute('class', 'dark');
|
||||
if (itemTheme === 'dark') body.setAttribute('class', 'dark');
|
||||
else body.setAttribute('class', '');
|
||||
};
|
||||
|
||||
|
||||
@@ -1729,7 +1729,8 @@ const message = {
|
||||
takeDown: 'TakeDown',
|
||||
allReadyInstalled: 'Installed',
|
||||
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:
|
||||
'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',
|
||||
@@ -1737,7 +1738,8 @@ const message = {
|
||||
ignoreList: 'ignore list',
|
||||
appHelper: 'Please view the installation instructions of some applications on the application details page',
|
||||
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',
|
||||
openrestyDeleteHelper:
|
||||
'Forcibly deleting OpenResty will delete all websites, please confirm the risk before operation',
|
||||
|
||||
@@ -827,12 +827,12 @@ const message = {
|
||||
perMonth: '每月',
|
||||
perWeek: '每周',
|
||||
perHour: '每小時',
|
||||
perNDay: '每隔 N 日',
|
||||
perNDay: '每 N 日',
|
||||
perDay: '每天',
|
||||
perNHour: '每隔 N 時',
|
||||
perNMinute: '每隔 N 分鐘',
|
||||
perNSecond: '每隔 N 秒',
|
||||
per: '每隔',
|
||||
perNHour: '每 N 時',
|
||||
perNMinute: '每 N 分鐘',
|
||||
perNSecond: '每 N 秒',
|
||||
per: '每',
|
||||
handle: '執行',
|
||||
day: '日',
|
||||
monday: '周一',
|
||||
@@ -1610,14 +1610,14 @@ const message = {
|
||||
takeDown: '已廢棄',
|
||||
allReadyInstalled: '已安裝',
|
||||
installHelper: '配置鏡像加速可以解決鏡像拉取失敗的問題',
|
||||
upgradeHelper: '異常應用需要先同步到正常狀態',
|
||||
upgradeHelper: '異常應用程式需要先同步到正常狀態,升級失敗請在日誌審計-系統日誌中查看失敗原因',
|
||||
installWarn: '當前未勾選端口外部訪問,將無法通過外網IP:端口訪問,是否繼續? ',
|
||||
showIgnore: '查看忽略應用',
|
||||
cancelIgnore: '取消忽略',
|
||||
ignoreList: '忽略列表',
|
||||
appHelper: '部分應用的安裝使用說明請在應用詳情頁查看',
|
||||
backupApp: '升級前備份應用',
|
||||
backupAppHelper: '升級失敗可以使用應用備份回滾',
|
||||
backupAppHelper: '升級失敗會使用備份自動回滾,請在日誌審計-系統日誌中查看失敗原因',
|
||||
delete: '刪除',
|
||||
openrestyDeleteHelper: '強制刪除 OpenResty 會刪除所有的網站,請確認風險後操作',
|
||||
downloadLogHelper1: '即將下載 {0} 套用所有日誌,是否繼續? ',
|
||||
|
||||
@@ -828,12 +828,12 @@ const message = {
|
||||
perMonth: '每月',
|
||||
perWeek: '每周',
|
||||
perHour: '每小时',
|
||||
perNDay: '每隔 N 日',
|
||||
perNDay: '每 N 日',
|
||||
perDay: '每天',
|
||||
perNHour: '每隔 N 时',
|
||||
perNMinute: '每隔 N 分钟',
|
||||
perNSecond: '每隔 N 秒',
|
||||
per: '每隔',
|
||||
perNHour: '每 N 时',
|
||||
perNMinute: '每 N 分钟',
|
||||
perNSecond: '每 N 秒',
|
||||
per: '每',
|
||||
handle: '执行',
|
||||
day: '日',
|
||||
monday: '周一',
|
||||
@@ -1610,14 +1610,14 @@ const message = {
|
||||
takeDown: '已废弃',
|
||||
allReadyInstalled: '已安装',
|
||||
installHelper: '配置镜像加速可以解决镜像拉取失败的问题',
|
||||
upgradeHelper: '异常应用需要先同步到正常状态',
|
||||
upgradeHelper: '异常应用需要先同步到正常状态,升级失败请在日志审计-系统日志中查看失败原因',
|
||||
installWarn: '当前未勾选端口外部访问,将无法通过外网IP:端口访问,是否继续?',
|
||||
showIgnore: '查看忽略应用',
|
||||
cancelIgnore: '取消忽略',
|
||||
ignoreList: '忽略列表',
|
||||
appHelper: '部分应用的安装使用说明请在应用详情页查看',
|
||||
backupApp: '升级前备份应用',
|
||||
backupAppHelper: '升级失败可以使用应用备份回滚',
|
||||
backupAppHelper: '升级失败会使用备份自动回滚,请在日志审计-系统日志中查看失败原因',
|
||||
delete: '删除',
|
||||
openrestyDeleteHelper: '强制删除 OpenResty 会删除所有的网站,请确认风险之后操作',
|
||||
downloadLogHelper1: '即将下载 {0} 应用所有日志,是否继续?',
|
||||
|
||||
@@ -23,6 +23,8 @@ import { DeviceType } from '@/enums/app';
|
||||
import { getSystemAvailable } from '@/api/modules/setting';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { loadProductProFromDB } from '@/utils/xpack';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
const { switchTheme } = useTheme();
|
||||
useResize();
|
||||
|
||||
const router = useRouter();
|
||||
@@ -98,6 +100,17 @@ onMounted(() => {
|
||||
|
||||
loadStatus();
|
||||
loadProductProFromDB();
|
||||
|
||||
const mqList = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
if (mqList.addEventListener) {
|
||||
mqList.addEventListener('change', () => {
|
||||
switchTheme();
|
||||
});
|
||||
} else if (mqList.addListener) {
|
||||
mqList.addListener(() => {
|
||||
switchTheme();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ const GlobalStore = defineStore({
|
||||
errStatus: '',
|
||||
}),
|
||||
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,
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
html.dark {
|
||||
--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-fill-color-blank: #111417;
|
||||
--el-bg-color: rgba(0, 11, 21, 1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getLicenseStatus } from '@/api/modules/setting';
|
||||
import { getLicenseStatus, getSettingInfo } from '@/api/modules/setting';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
@@ -18,7 +18,12 @@ export function initFavicon() {
|
||||
const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement;
|
||||
link.type = 'image/x-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);
|
||||
}
|
||||
|
||||
@@ -27,12 +32,22 @@ export async function getXpackSetting() {
|
||||
const module = await searchXSettingGlob?.['../xpack/api/modules/setting.ts']?.();
|
||||
const res = await module?.searchXSetting();
|
||||
if (!res) {
|
||||
initFavicon();
|
||||
resetXSetting();
|
||||
return;
|
||||
}
|
||||
initFavicon();
|
||||
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() {
|
||||
const res = await getLicenseStatus();
|
||||
if (!res.data) {
|
||||
@@ -48,6 +63,7 @@ export async function loadProductProFromDB() {
|
||||
}
|
||||
switchTheme();
|
||||
initFavicon();
|
||||
loadDataFromDB();
|
||||
}
|
||||
|
||||
export async function getXpackSettingForTheme() {
|
||||
|
||||
@@ -53,7 +53,9 @@
|
||||
</el-form-item>
|
||||
<el-form-item prop="backup" v-if="operateReq.operate === 'upgrade'">
|
||||
<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 pro="pullImage" v-if="operateReq.operate === 'upgrade'">
|
||||
<el-checkbox v-model="operateReq.pullImage" :label="$t('container.forcePull')" size="large" />
|
||||
|
||||
@@ -92,12 +92,10 @@ export function transObjToSpec(specType: string, week, day, hour, minute, second
|
||||
case 'perWeek':
|
||||
return `${minute} ${hour} * * ${week}`;
|
||||
case 'perNDay':
|
||||
day = Number(day) + 1 + '';
|
||||
return `${minute} ${hour} */${day} * *`;
|
||||
case 'perDay':
|
||||
return `${minute} ${hour} * * *`;
|
||||
case 'perNHour':
|
||||
hour = Number(hour) + 1 + '';
|
||||
return `${minute} */${hour} * * *`;
|
||||
case 'perHour':
|
||||
return `${minute} * * * *`;
|
||||
@@ -141,13 +139,13 @@ export function transSpecToObj(spec: string) {
|
||||
}
|
||||
if (specs[1].indexOf('*/') !== -1) {
|
||||
specItem.specType = 'perNHour';
|
||||
specItem.hour = Number(specs[1].replaceAll('*/', '')) - 1;
|
||||
specItem.hour = Number(specs[1].replaceAll('*/', ''));
|
||||
return specItem;
|
||||
}
|
||||
specItem.hour = Number(specs[1]);
|
||||
if (specs[2].indexOf('*/') !== -1) {
|
||||
specItem.specType = 'perNDay';
|
||||
specItem.day = Number(specs[2].replaceAll('*/', '')) - 1;
|
||||
specItem.day = Number(specs[2].replaceAll('*/', ''));
|
||||
return specItem;
|
||||
}
|
||||
if (specs[2] !== '*') {
|
||||
|
||||
@@ -448,7 +448,7 @@ onMounted(() => {
|
||||
font-weight: 600;
|
||||
}
|
||||
.fullScreen {
|
||||
background-color: #efefef;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
position: absolute;
|
||||
right: 50px;
|
||||
|
||||
@@ -361,6 +361,7 @@ const loadDataFromDB = async () => {
|
||||
i18n.locale.value = res.data.language;
|
||||
i18n.warnHtmlMessage = false;
|
||||
globalStore.entrance = res.data.securityEntrance;
|
||||
globalStore.setDefaultNetwork(res.data.defaultNetwork);
|
||||
globalStore.setOpenMenuTabs(res.data.menuTabs === 'enable');
|
||||
globalStore.updateLanguage(res.data.language);
|
||||
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme, panelName: res.data.panelName });
|
||||
|
||||
@@ -224,6 +224,7 @@ const form = reactive({
|
||||
allowIPs: '',
|
||||
bindDomain: '',
|
||||
noAuthSetting: '200 - ' + i18n.global.t('setting.help200'),
|
||||
noAuthSettingValue: '200',
|
||||
});
|
||||
|
||||
const unset = ref(i18n.global.t('setting.unSetting'));
|
||||
@@ -246,6 +247,7 @@ const search = async () => {
|
||||
form.mfaInterval = Number(res.data.mfaInterval);
|
||||
form.allowIPs = res.data.allowIPs.replaceAll(',', '\n');
|
||||
form.bindDomain = res.data.bindDomain;
|
||||
form.noAuthSettingValue = res.data.noAuthSetting;
|
||||
if (res.data.noAuthSetting !== '200') {
|
||||
form.noAuthSetting = res.data.noAuthSetting + ' - ' + i18n.global.t('setting.error' + res.data.noAuthSetting);
|
||||
} else {
|
||||
@@ -297,7 +299,7 @@ const onChangeBind = () => {
|
||||
bindRef.value.acceptParams({ ipv6: form.ipv6, bindAddress: form.bindAddress });
|
||||
};
|
||||
const onChangeResponse = () => {
|
||||
responseRef.value.acceptParams({ noAuthSetting: form.noAuthSetting });
|
||||
responseRef.value.acceptParams({ noAuthSetting: form.noAuthSettingValue });
|
||||
};
|
||||
const onChangeBindDomain = () => {
|
||||
domainRef.value.acceptParams({ bindDomain: form.bindDomain });
|
||||
|
||||
Reference in New Issue
Block a user