fix: 升级抽屉样式调整,安装包时间错误问题解决

pull/119/head
ssongliu 2023-02-07 15:33:47 +08:00 committed by ssongliu
parent 46be5b7537
commit 1bdc531c7d
21 changed files with 418 additions and 356 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ build
/pkg/ /pkg/
backend/__debug_bin backend/__debug_bin
cmd/server/__debug_bin cmd/server/__debug_bin
cmd/server/web

View File

@ -75,12 +75,10 @@ type SnapshotInfo struct {
} }
type UpgradeInfo struct { type UpgradeInfo struct {
ID int64 `json:"id"`
NewVersion string `json:"newVersion"` NewVersion string `json:"newVersion"`
ReleaseNote string `json:"releaseNote"` ReleaseNote string `json:"releaseNote"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
} }
type Upgrade struct { type Upgrade struct {
Source string `json:"source" validate:"required,oneof=github gitee"`
Version string `json:"version"` Version string `json:"version"`
} }

View File

@ -2,7 +2,10 @@ package service
import ( import (
"context" "context"
"crypto/tls"
"errors"
"fmt" "fmt"
"net/http"
"os" "os"
"runtime" "runtime"
"strconv" "strconv"
@ -34,27 +37,34 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
infoFromGithub, err := u.loadLatestFromGithub()
if err != nil { var releaseInfo dto.UpgradeInfo
global.LOG.Error(err) isGiteeOK := checkValid("https://gitee.com/wanghe-fit2cloud/1Panel")
} else { if isGiteeOK {
isNew, err := compareVersion(currentVerion.Value, infoFromGithub.NewVersion) releaseInfo, err = u.loadLatestFromGitee()
if !isNew || err != nil { if err != nil {
global.LOG.Error(err)
}
}
if len(releaseInfo.NewVersion) == 0 {
isGithubOK := checkValid("https://gitee.com/1Panel-dev/1Panel")
if isGithubOK {
releaseInfo, err = u.loadLatestFromGithub()
if err != nil {
global.LOG.Error(err)
return nil, err
}
}
}
if len(releaseInfo.NewVersion) != 0 {
isNew, err := compareVersion(currentVerion.Value, releaseInfo.NewVersion)
if !isNew && err != nil {
return nil, err return nil, err
} }
return infoFromGithub, nil return &releaseInfo, nil
} }
infoFromGitee, err := u.loadLatestFromGitee() return nil, errors.New("both gitee and github were unavailable")
if err != nil {
global.LOG.Error(err)
return nil, err
}
isNew, err := compareVersion(currentVerion.Value, infoFromGitee.NewVersion)
if !isNew && err != nil {
return nil, err
}
return infoFromGitee, nil
} }
func (u *UpgradeService) Upgrade(req dto.Upgrade) error { func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
@ -71,9 +81,15 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
} }
downloadPath := fmt.Sprintf("https://gitee.com/%s/%s/releases/download/%s/", "wanghe-fit2cloud", "1Panel", req.Version) downloadPath := fmt.Sprintf("https://gitee.com/%s/%s/releases/download/%s/", "wanghe-fit2cloud", "1Panel", req.Version)
if req.Source == "github" { isGiteeOK := checkValid(downloadPath)
if !isGiteeOK {
downloadPath = fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/", "wanghe-fit2cloud", "1Panel", req.Version) downloadPath = fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/", "wanghe-fit2cloud", "1Panel", req.Version)
isGithubOK := checkValid(downloadPath)
if !isGithubOK {
return errors.New("both gitee and github were unavailabl")
}
} }
panelName := fmt.Sprintf("1panel-%s-%s", "linux", runtime.GOARCH) panelName := fmt.Sprintf("1panel-%s-%s", "linux", runtime.GOARCH)
fileName := fmt.Sprintf("1panel-online-installer-%s.tar.gz", req.Version) fileName := fmt.Sprintf("1panel-online-installer-%s.tar.gz", req.Version)
_ = settingRepo.Update("SystemStatus", "Upgrading") _ = settingRepo.Update("SystemStatus", "Upgrading")
@ -174,36 +190,34 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
} }
} }
func (u *UpgradeService) loadLatestFromGithub() (*dto.UpgradeInfo, error) { func (u *UpgradeService) loadLatestFromGithub() (dto.UpgradeInfo, error) {
var info dto.UpgradeInfo
client := github.NewClient(nil) client := github.NewClient(nil)
ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second)
defer cancle() defer cancle()
stats, res, err := client.Repositories.GetLatestRelease(ctx, "wanghe-fit2cloud", "1Panel") stats, res, err := client.Repositories.GetLatestRelease(ctx, "wanghe-fit2cloud", "1Panel")
if res.StatusCode != 200 || err != nil { if res.StatusCode != 200 || err != nil {
return nil, fmt.Errorf("load upgrade info from github failed, err: %v", err) return info, fmt.Errorf("load upgrade info from github failed, err: %v", err)
} }
info := dto.UpgradeInfo{ info.NewVersion = string(*stats.Name)
NewVersion: string(*stats.Name), info.ReleaseNote = string(*stats.Body)
ReleaseNote: string(*stats.Body), info.CreatedAt = stats.PublishedAt.Add(8 * time.Hour).Format("2006-01-02 15:04:05")
CreatedAt: github.Timestamp(*stats.CreatedAt).Format("2006-01-02 15:04:05"), return info, nil
}
return &info, nil
} }
func (u *UpgradeService) loadLatestFromGitee() (*dto.UpgradeInfo, error) { func (u *UpgradeService) loadLatestFromGitee() (dto.UpgradeInfo, error) {
var info dto.UpgradeInfo
client := gitee.NewAPIClient(gitee.NewConfiguration()) client := gitee.NewAPIClient(gitee.NewConfiguration())
ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second)
defer cancle() defer cancle()
stats, res, err := client.RepositoriesApi.GetV5ReposOwnerRepoReleasesLatest(ctx, "wanghe-fit2cloud", "1Panel", &gitee.GetV5ReposOwnerRepoReleasesLatestOpts{}) stats, res, err := client.RepositoriesApi.GetV5ReposOwnerRepoReleasesLatest(ctx, "wanghe-fit2cloud", "1Panel", &gitee.GetV5ReposOwnerRepoReleasesLatestOpts{})
if res.StatusCode != 200 || err != nil { if res.StatusCode != 200 || err != nil {
return nil, fmt.Errorf("load upgrade info from gitee failed, err: %v", err) return info, fmt.Errorf("load upgrade info from gitee failed, err: %v", err)
} }
info := dto.UpgradeInfo{ info.NewVersion = string(stats.Name)
NewVersion: string(stats.Name), info.ReleaseNote = string(stats.Body)
ReleaseNote: string(stats.Body), info.CreatedAt = stats.CreatedAt.Format("2006-01-02 15:04:05")
CreatedAt: stats.CreatedAt.Format("2006-01-02 15:04:05"), return info, nil
}
return &info, nil
} }
func compareVersion(version, newVersion string) (bool, error) { func compareVersion(version, newVersion string) (bool, error) {
@ -245,3 +259,18 @@ func compareVersion(version, newVersion string) (bool, error) {
return false, nil return false, nil
} }
} }
func checkValid(addr string) bool {
timeout := time.Duration(2 * time.Second)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := http.Client{
Transport: tr,
Timeout: timeout,
}
if _, err := client.Get(addr); err != nil {
return false
}
return true
}

View File

@ -4,9 +4,7 @@
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
403: typeof import('./src/components/error-message/403.vue')['default']
404: typeof import('./src/components/error-message/404.vue')['default'] 404: typeof import('./src/components/error-message/404.vue')['default']
500: typeof import('./src/components/error-message/500.vue')['default']
AppLayout: typeof import('./src/components/app-layout/index.vue')['default'] AppLayout: typeof import('./src/components/app-layout/index.vue')['default']
AppStatus: typeof import('./src/components/app-status/index.vue')['default'] AppStatus: typeof import('./src/components/app-status/index.vue')['default']
BackButton: typeof import('./src/components/back-button/index.vue')['default'] BackButton: typeof import('./src/components/back-button/index.vue')['default']

View File

@ -80,8 +80,4 @@ export namespace Setting {
releaseNote: string; releaseNote: string;
createdAt: string; createdAt: string;
} }
export interface Upgrade {
source: string;
version: string;
}
} }

View File

@ -70,6 +70,6 @@ export const searchSnapshotPage = (param: ReqPage) => {
export const loadUpgradeInfo = () => { export const loadUpgradeInfo = () => {
return http.get<Setting.UpgradeInfo>(`/settings/upgrade`); return http.get<Setting.UpgradeInfo>(`/settings/upgrade`);
}; };
export const upgrade = (param: Setting.Upgrade) => { export const upgrade = (version: string) => {
return http.post(`/settings/upgrade`, param); return http.post(`/settings/upgrade`, { version: version });
}; };

View File

@ -535,7 +535,7 @@ export default {
missBackupAccount: '', missBackupAccount: '',
syncDate: ' ', syncDate: ' ',
releaseMemory: '', releaseMemory: '',
curl: '访', curl: '访 URL',
taskName: '', taskName: '',
cronSpec: '', cronSpec: '',
directory: '', directory: '',

View File

@ -1,21 +1,9 @@
import { Layout } from '@/routers/constant'; import { Layout } from '@/routers/constant';
// 错误页面模块
const errorRouter = { const errorRouter = {
path: '/error', path: '/error',
component: Layout, component: Layout,
children: [ children: [
{
path: '403',
name: '403',
hidden: true,
component: () => import('@/components/error-message/403.vue'),
meta: {
requiresAuth: true,
title: '403',
key: '403',
},
},
{ {
path: '404', path: '404',
name: '404', name: '404',
@ -27,17 +15,6 @@ const errorRouter = {
key: '404', key: '404',
}, },
}, },
{
path: '500',
name: '500',
hidden: true,
component: () => import('@/components/error-message/500.vue'),
meta: {
requiresAuth: false,
title: '500',
key: '500',
},
},
], ],
}; };
export default errorRouter; export default errorRouter;

View File

@ -1,17 +1,9 @@
<template> <template>
<el-dialog <el-drawer v-model="newNameVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
@close="onClose()"
v-model="newNameVisiable"
:destroy-on-close="true"
:close-on-click-modal="false"
width="30%"
>
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('container.rename')" :back="handleClose" />
<span>{{ $t('container.rename') }}</span>
</div>
</template> </template>
<el-form ref="newNameRef" v-loading="loading" :model="renameForm"> <el-form ref="newNameRef" v-loading="loading" :model="renameForm" label-position="top">
<el-form-item :label="$t('container.newName')" :rules="Rules.requiredInput" prop="newName"> <el-form-item :label="$t('container.newName')" :rules="Rules.requiredInput" prop="newName">
<el-input v-model="renameForm.newName"></el-input> <el-input v-model="renameForm.newName"></el-input>
</el-form-item> </el-form-item>
@ -26,7 +18,7 @@
</el-button> </el-button>
</span> </span>
</template> </template>
</el-dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -80,7 +72,8 @@ const acceptParams = (props: DialogProps): void => {
newNameVisiable.value = true; newNameVisiable.value = true;
}; };
const onClose = async () => { const handleClose = async () => {
newNameVisiable.value = false;
emit('search'); emit('search');
}; };

View File

@ -1,11 +1,9 @@
<template> <template>
<el-dialog v-model="loadVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%"> <el-drawer v-model="loadVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('container.importImage')" :back="handleClose" />
<span>{{ $t('container.importImage') }}</span>
</div>
</template> </template>
<el-form v-loading="loading" ref="formRef" :model="form" label-width="80px"> <el-form v-loading="loading" ref="formRef" :model="form" label-position="top">
<el-form-item :label="$t('container.path')" :rules="Rules.requiredSelect" prop="path"> <el-form-item :label="$t('container.path')" :rules="Rules.requiredSelect" prop="path">
<el-input disabled v-model="form.path"> <el-input disabled v-model="form.path">
<template #append> <template #append>
@ -24,7 +22,7 @@
</el-button> </el-button>
</span> </span>
</template> </template>
</el-dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -46,6 +44,9 @@ const acceptParams = () => {
loadVisiable.value = true; loadVisiable.value = true;
form.path = ''; form.path = '';
}; };
const handleClose = () => {
loadVisiable.value = false;
};
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();

View File

@ -10,7 +10,7 @@
<el-tag round class="status-content" v-if="form.status === 'Stopped'" type="info"> <el-tag round class="status-content" v-if="form.status === 'Stopped'" type="info">
{{ $t('commons.status.stopped') }} {{ $t('commons.status.stopped') }}
</el-tag> </el-tag>
<el-tag class="status-content" type="info">{{ $t('app.version') }}: {{ form.version }}</el-tag> <el-tag class="status-content">{{ $t('app.version') }}: {{ form.version }}</el-tag>
<span v-if="form.status === 'Running'" class="buttons"> <span v-if="form.status === 'Running'" class="buttons">
<el-button type="primary" @click="onOperator('stop')" link> <el-button type="primary" @click="onOperator('stop')" link>

View File

@ -25,7 +25,11 @@
:data="data" :data="data"
> >
<el-table-column type="selection" fix /> <el-table-column type="selection" fix />
<el-table-column :label="$t('cronjob.taskName')" prop="name" /> <el-table-column :label="$t('cronjob.taskName')" prop="name">
<template #default="{ row }">
<el-link @click="loadDetail(row)" type="primary">{{ row.name }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
@ -227,6 +231,14 @@ const loadCopies = (item) => {
} }
}; };
const loadDetail = (row: any) => {
isRecordShow.value = true;
let params = {
rowData: { ...row },
};
dialogRecordRef.value!.acceptParams(params);
};
const buttons = [ const buttons = [
{ {
label: i18n.global.t('commons.button.handle'), label: i18n.global.t('commons.button.handle'),
@ -253,11 +265,7 @@ const buttons = [
label: i18n.global.t('cronjob.record'), label: i18n.global.t('cronjob.record'),
icon: 'Clock', icon: 'Clock',
click: (row: Cronjob.CronjobInfo) => { click: (row: Cronjob.CronjobInfo) => {
isRecordShow.value = true; loadDetail(row);
let params = {
rowData: { ...row },
};
dialogRecordRef.value!.acceptParams(params);
}, },
}, },
]; ];

View File

@ -12,7 +12,7 @@
<el-option value="website" :label="$t('cronjob.website')" /> <el-option value="website" :label="$t('cronjob.website')" />
<el-option value="database" :label="$t('cronjob.database')" /> <el-option value="database" :label="$t('cronjob.database')" />
<el-option value="directory" :label="$t('cronjob.directory')" /> <el-option value="directory" :label="$t('cronjob.directory')" />
<el-option value="curl" :label="$t('cronjob.curl') + ' URL'" /> <el-option value="curl" :label="$t('cronjob.curl')" />
</el-select> </el-select>
</el-form-item> </el-form-item>

View File

@ -7,7 +7,7 @@
<el-tag round class="status-content" type="success"> <el-tag round class="status-content" type="success">
{{ $t('cronjob.' + dialogData.rowData.type) }} {{ $t('cronjob.' + dialogData.rowData.type) }}
</el-tag> </el-tag>
<el-tag class="status-content" type="info"> <el-tag class="status-content">
<span <span
v-if=" v-if="
dialogData.rowData?.specType.indexOf('N') === -1 || dialogData.rowData?.specType.indexOf('N') === -1 ||
@ -53,7 +53,7 @@
</div> </div>
<LayoutContent :title="$t('cronjob.record')" :reload="true"> <LayoutContent :title="$t('cronjob.record')" :reload="true">
<template #main> <template #search>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="6"> <el-col :span="6">
<el-date-picker <el-date-picker
@ -66,7 +66,20 @@
:end-placeholder="$t('commons.search.timeEnd')" :end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts" :shortcuts="shortcuts"
></el-date-picker> ></el-date-picker>
<el-card style="margin-top: 20px"> </el-col>
<el-col :span="18">
<el-select @change="search()" v-model="searchInfo.status">
<el-option :label="$t('cronjob.all')" value="" />
<el-option :label="$t('cronjob.failedRecord')" value="Failed" />
<el-option :label="$t('cronjob.successRecord')" value="Success" />
</el-select>
</el-col>
</el-row>
</template>
<template #main>
<el-row :gutter="20">
<el-col :span="6">
<el-card>
<ul v-infinite-scroll="nextPage" class="infinite-list" style="overflow: auto"> <ul v-infinite-scroll="nextPage" class="infinite-list" style="overflow: auto">
<li <li
v-for="(item, index) in records" v-for="(item, index) in records"
@ -88,12 +101,7 @@
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="18">
<el-select @change="search()" v-model="searchInfo.status"> <el-card style="height: 362px">
<el-option :label="$t('cronjob.all')" value="" />
<el-option :label="$t('cronjob.failedRecord')" value="Failed" />
<el-option :label="$t('cronjob.successRecord')" value="Success" />
</el-select>
<el-card style="height: 382px; margin-top: 20px">
<el-form> <el-form>
<el-row v-if="hasScript()"> <el-row v-if="hasScript()">
<span>{{ $t('cronjob.shellContent') }}</span> <span>{{ $t('cronjob.shellContent') }}</span>
@ -103,7 +111,7 @@
placeholder="None data" placeholder="None data"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="height: 120px; width: 100%; margin-top: 5px" style="height: 100px; width: 100%; margin-top: 5px"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"
@ -442,7 +450,7 @@ defineExpose({
<style lang="scss" scoped> <style lang="scss" scoped>
.infinite-list { .infinite-list {
height: 330px; height: 310px;
padding: 0; padding: 0;
margin: 0; margin: 0;
list-style: none; list-style: none;

View File

@ -3,7 +3,7 @@
<template #header> <template #header>
<DrawerHeader :header="$t('database.create')" :back="handleClose" /> <DrawerHeader :header="$t('database.create')" :back="handleClose" />
</template> </template>
<el-form ref="formRef" label-position="top" :model="form" :rules="rules" label-width="80px"> <el-form ref="formRef" label-position="top" :model="form" :rules="rules">
<el-row type="flex" justify="center"> <el-row type="flex" justify="center">
<el-col :span="22"> <el-col :span="22">
<el-form-item :label="$t('commons.table.name')" prop="name"> <el-form-item :label="$t('commons.table.name')" prop="name">

View File

@ -101,56 +101,6 @@
</el-card> </el-card>
<Setting ref="settingRef" style="margin-top: 20px" /> <Setting ref="settingRef" style="margin-top: 20px" />
<el-dialog v-model="changeVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
<template #header>
<div class="card-header">
<span>{{ $t('database.changePassword') }}</span>
</div>
</template>
<el-form>
<el-form v-loading="loading" ref="changeFormRef" :model="changeForm" label-width="80px">
<div v-if="changeForm.operation === 'password'">
<el-form-item :label="$t('commons.login.username')" prop="userName">
<el-input disabled v-model="changeForm.userName"></el-input>
</el-form-item>
<el-form-item
:label="$t('commons.login.password')"
prop="password"
:rules="Rules.requiredInput"
>
<el-input type="password" clearable show-password v-model="changeForm.password"></el-input>
</el-form-item>
</div>
<div v-if="changeForm.operation === 'privilege'">
<el-form-item :label="$t('database.permission')" prop="privilege">
<el-select style="width: 100%" v-model="changeForm.privilege">
<el-option value="localhost" :label="$t('database.permissionLocal')" />
<el-option value="%" :label="$t('database.permissionAll')" />
<el-option value="ip" :label="$t('database.permissionForIP')" />
</el-select>
</el-form-item>
<el-form-item
v-if="changeForm.privilege === 'ip'"
prop="privilegeIPs"
:rules="Rules.requiredInput"
>
<el-input clearable v-model="changeForm.privilegeIPs" />
</el-form-item>
</div>
</el-form>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="changeVisiable = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" @click="submitChangeInfo(changeFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
<el-dialog <el-dialog
v-model="phpVisiable" v-model="phpVisiable"
:title="$t('app.checkTitle')" :title="$t('app.checkTitle')"
@ -170,6 +120,7 @@
</template> </template>
</el-dialog> </el-dialog>
<PasswordDialog ref="passwordRef" />
<RootPasswordDialog ref="rootPasswordRef" /> <RootPasswordDialog ref="rootPasswordRef" />
<RemoteAccessDialog ref="remoteAccessRef" /> <RemoteAccessDialog ref="remoteAccessRef" />
<UploadDialog ref="uploadRef" /> <UploadDialog ref="uploadRef" />
@ -178,8 +129,6 @@
<AppResources ref="checkRef"></AppResources> <AppResources ref="checkRef"></AppResources>
<DeleteDialog ref="deleteRef" @search="search" /> <DeleteDialog ref="deleteRef" @search="search" />
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
</div> </div>
</template> </template>
@ -188,28 +137,20 @@ import LayoutContent from '@/layout/layout-content.vue';
import ComplexTable from '@/components/complex-table/index.vue'; import ComplexTable from '@/components/complex-table/index.vue';
import OperateDialog from '@/views/database/mysql/create/index.vue'; import OperateDialog from '@/views/database/mysql/create/index.vue';
import DeleteDialog from '@/views/database/mysql/delete/index.vue'; import DeleteDialog from '@/views/database/mysql/delete/index.vue';
import RootPasswordDialog from '@/views/database/mysql/password/index.vue'; import PasswordDialog from '@/views/database/mysql/password/index.vue';
import RootPasswordDialog from '@/views/database/mysql/root-password/index.vue';
import RemoteAccessDialog from '@/views/database/mysql/remote/index.vue'; import RemoteAccessDialog from '@/views/database/mysql/remote/index.vue';
import BackupRecords from '@/views/database/mysql/backup/index.vue'; import BackupRecords from '@/views/database/mysql/backup/index.vue';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import UploadDialog from '@/views/database/mysql/upload/index.vue'; import UploadDialog from '@/views/database/mysql/upload/index.vue';
import AppResources from '@/views/database/mysql/check/index.vue'; import AppResources from '@/views/database/mysql/check/index.vue';
import Setting from '@/views/database/mysql/setting/index.vue'; import Setting from '@/views/database/mysql/setting/index.vue';
import AppStatus from '@/components/app-status/index.vue'; import AppStatus from '@/components/app-status/index.vue';
import { dateFormat } from '@/utils/util'; import { dateFormat } from '@/utils/util';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { import { deleteCheckMysqlDB, loadRemoteAccess, searchMysqlDBs, updateMysqlDescription } from '@/api/modules/database';
deleteCheckMysqlDB,
loadRemoteAccess,
searchMysqlDBs,
updateMysqlAccess,
updateMysqlDescription,
updateMysqlPassword,
} from '@/api/modules/database';
import i18n from '@/lang'; import i18n from '@/lang';
import { ElForm, ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { Database } from '@/api/interface/database'; import { Database } from '@/api/interface/database';
import { Rules } from '@/global/form-rules';
import { App } from '@/api/interface/app'; import { App } from '@/api/interface/app';
import { GetAppPort } from '@/api/modules/app'; import { GetAppPort } from '@/api/modules/app';
import router from '@/routers'; import router from '@/routers';
@ -270,6 +211,8 @@ const onChangeAccess = async () => {
remoteAccessRef.value!.acceptParams(param); remoteAccessRef.value!.acceptParams(param);
}; };
const passwordRef = ref();
const settingRef = ref(); const settingRef = ref();
const onSetting = async () => { const onSetting = async () => {
isOnSetting.value = true; isOnSetting.value = true;
@ -281,68 +224,6 @@ const onSetting = async () => {
settingRef.value!.acceptParams(params); settingRef.value!.acceptParams(params);
}; };
const changeVisiable = ref(false);
type FormInstance = InstanceType<typeof ElForm>;
const changeFormRef = ref<FormInstance>();
const changeForm = reactive({
id: 0,
mysqlName: '',
userName: '',
password: '',
operation: '',
privilege: '',
privilegeIPs: '',
value: '',
});
const submitChangeInfo = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let param = {
id: changeForm.id,
value: '',
};
if (changeForm.operation === 'password') {
const res = await deleteCheckMysqlDB(changeForm.id);
if (res.data && res.data.length > 0) {
let params = {
header: i18n.global.t('database.changePassword'),
operationInfo: i18n.global.t('database.changePasswordHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(params);
} else {
param.value = changeForm.password;
loading.value = true;
await updateMysqlPassword(param)
.then(() => {
loading.value = false;
search();
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
}
return;
}
param.value = changeForm.privilege;
changeForm.mysqlName = mysqlName.value;
loading.value = true;
await updateMysqlAccess(param)
.then(() => {
loading.value = false;
search();
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
});
};
const search = async () => { const search = async () => {
let params = { let params = {
page: paginationConfig.currentPage, page: paginationConfig.currentPage,
@ -382,7 +263,7 @@ const loadDashboardPort = async () => {
const checkExist = (data: App.CheckInstalled) => { const checkExist = (data: App.CheckInstalled) => {
mysqlIsExist.value = data.isExist; mysqlIsExist.value = data.isExist;
mysqlName.value = data.name; mysqlName.value = data.name;
mysqlStatus.value = 'Failed'; mysqlStatus.value = data.status;
mysqlVersion.value = data.version; mysqlVersion.value = data.version;
mysqlContainer.value = data.containerName; mysqlContainer.value = data.containerName;
if (mysqlIsExist.value) { if (mysqlIsExist.value) {
@ -410,48 +291,36 @@ const onDelete = async (row: Database.MysqlDBInfo) => {
} }
}; };
const confirmDialogRef = ref();
const onSubmit = async () => {
let param = {
id: changeForm.id,
value: changeForm.password,
};
loading.value = true;
await updateMysqlPassword(param)
.then(() => {
loading.value = false;
search();
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
};
const buttons = [ const buttons = [
{ {
label: i18n.global.t('database.changePassword'), label: i18n.global.t('database.changePassword'),
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
changeForm.id = row.id; let param = {
changeForm.operation = 'password'; id: row.id,
changeForm.userName = row.username; operation: 'password',
changeForm.password = row.password; username: row.username,
changeVisiable.value = true; password: row.password,
};
passwordRef.value.acceptParams(param);
}, },
}, },
{ {
label: i18n.global.t('database.permission'), label: i18n.global.t('database.permission'),
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
changeForm.id = row.id; let param = {
changeForm.operation = 'privilege'; id: row.id,
operation: 'privilege',
privilege: '',
privilegeIPs: '',
password: '',
};
if (row.permission === '%' || row.permission === 'localhost') { if (row.permission === '%' || row.permission === 'localhost') {
changeForm.privilege = row.permission; param.privilege = row.permission;
} else { } else {
changeForm.privilegeIPs = row.permission; param.privilegeIPs = row.permission;
changeForm.privilege = 'ip'; param.privilege = 'ip';
} }
changeVisiable.value = true; passwordRef.value.acceptParams(param);
}, },
}, },
{ {

View File

@ -1,93 +1,174 @@
<template> <template>
<el-dialog v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%"> <div>
<template #header> <el-drawer v-model="changeVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
<div class="card-header"> <template #header>
<span>{{ $t('database.rootPassword') }}</span> <DrawerHeader :header="$t('database.changePassword')" :back="handleClose" />
</div> </template>
</template> <el-form>
<el-form v-loading="loading" ref="formRef" :model="form" label-width="80px"> <el-form v-loading="loading" ref="changeFormRef" :model="changeForm" label-width="80px">
<el-form-item :label="$t('database.rootPassword')" :rules="Rules.requiredInput" prop="password"> <div v-if="changeForm.operation === 'password'">
<el-input type="password" show-password clearable v-model="form.password" /> <el-form-item :label="$t('commons.login.username')" prop="userName">
</el-form-item> <el-input disabled v-model="changeForm.userName"></el-input>
</el-form> </el-form-item>
<el-form-item
:label="$t('commons.login.password')"
prop="password"
:rules="Rules.requiredInput"
>
<el-input type="password" clearable show-password v-model="changeForm.password"></el-input>
</el-form-item>
</div>
<div v-if="changeForm.operation === 'privilege'">
<el-form-item :label="$t('database.permission')" prop="privilege">
<el-select style="width: 100%" v-model="changeForm.privilege">
<el-option value="localhost" :label="$t('database.permissionLocal')" />
<el-option value="%" :label="$t('database.permissionAll')" />
<el-option value="ip" :label="$t('database.permissionForIP')" />
</el-select>
</el-form-item>
<el-form-item
v-if="changeForm.privilege === 'ip'"
prop="privilegeIPs"
:rules="Rules.requiredInput"
>
<el-input clearable v-model="changeForm.privilegeIPs" />
</el-form-item>
</div>
</el-form>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="changeVisiable = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="submitChangeInfo(changeFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog> <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
</div>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="dialogVisiable = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="onSave(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang'; import i18n from '@/lang';
import { ElForm, ElMessage } from 'element-plus'; import { ElForm, ElMessage } from 'element-plus';
import { updateMysqlPassword } from '@/api/modules/database'; import { deleteCheckMysqlDB, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import DrawerHeader from '@/components/drawer-header/index.vue';
import { GetAppPassword } from '@/api/modules/app'; import { Rules } from '@/global/form-rules';
const loading = ref(false); const loading = ref();
const changeVisiable = ref(false);
const dialogVisiable = ref(false); type FormInstance = InstanceType<typeof ElForm>;
const form = reactive({ const changeFormRef = ref<FormInstance>();
const changeForm = reactive({
id: 0,
mysqlName: '',
userName: '',
password: '', password: '',
operation: '',
privilege: '',
privilegeIPs: '',
value: '',
}); });
const confirmDialogRef = ref(); const confirmDialogRef = ref();
type FormInstance = InstanceType<typeof ElForm>; interface DialogProps {
const formRef = ref<FormInstance>(); id: number;
mysqlName: string;
username: string;
password: string;
operation: string;
privilege: string;
privilegeIPs: string;
value: string;
}
const acceptParams = (params: DialogProps): void => {
changeForm.id = params.id;
changeForm.mysqlName = params.mysqlName;
changeForm.userName = params.username;
changeForm.password = params.password;
changeForm.operation = params.operation;
changeForm.privilege = params.privilege;
changeForm.privilegeIPs = params.privilegeIPs;
changeForm.value = params.value;
console.log(changeForm.password);
changeVisiable.value = true;
};
const emit = defineEmits<{ (e: 'search'): void }>();
const acceptParams = (): void => { const handleClose = () => {
form.password = ''; changeVisiable.value = false;
loadPassword();
dialogVisiable.value = true;
}; };
const loadPassword = async () => { const submitChangeInfo = async (formEl: FormInstance | undefined) => {
const res = await GetAppPassword('mysql'); if (!formEl) return;
form.password = res.data; formEl.validate(async (valid) => {
if (!valid) return;
let param = {
id: changeForm.id,
value: '',
};
if (changeForm.operation === 'password') {
const res = await deleteCheckMysqlDB(changeForm.id);
if (res.data && res.data.length > 0) {
let params = {
header: i18n.global.t('database.changePassword'),
operationInfo: i18n.global.t('database.changePasswordHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(params);
} else {
param.value = changeForm.password;
loading.value = true;
await updateMysqlPassword(param)
.then(() => {
loading.value = false;
emit('search');
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
}
return;
}
param.value = changeForm.privilege;
loading.value = true;
await updateMysqlAccess(param)
.then(() => {
loading.value = false;
emit('search');
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
});
}; };
const onSubmit = async () => { const onSubmit = async () => {
let param = { let param = {
id: 0, id: changeForm.id,
value: form.password, value: changeForm.password,
}; };
loading.value = true; loading.value = true;
await updateMysqlPassword(param) await updateMysqlPassword(param)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
emit('search');
changeVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
dialogVisiable.value = false;
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;
}); });
}; };
const onSave = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let params = {
header: i18n.global.t('database.confChange'),
operationInfo: i18n.global.t('database.restartNowHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(params);
});
};
defineExpose({ defineExpose({
acceptParams, acceptParams,
}); });

View File

@ -1,15 +1,17 @@
<template> <template>
<el-dialog v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%"> <el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('database.remoteAccess')" :back="handleClose" />
<span>{{ $t('database.remoteAccess') }}</span>
</div>
</template> </template>
<el-form v-loading="loading" ref="formRef" :model="form" label-width="80px"> <el-form v-loading="loading" ref="formRef" :model="form" label-position="top">
<el-form-item :label="$t('database.remoteAccess')" :rules="Rules.requiredInput" prop="privilege"> <el-row type="flex" justify="center">
<el-switch v-model="form.privilege" /> <el-col :span="22">
<span class="input-help">{{ $t('database.remoteConnHelper') }}</span> <el-form-item :label="$t('database.remoteAccess')" :rules="Rules.requiredInput" prop="privilege">
</el-form-item> <el-switch v-model="form.privilege" />
<span class="input-help">{{ $t('database.remoteConnHelper') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog> <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
@ -22,7 +24,7 @@
</el-button> </el-button>
</span> </span>
</template> </template>
</el-dialog> </el-drawer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -32,6 +34,7 @@ import i18n from '@/lang';
import { ElForm, ElMessage } from 'element-plus'; import { ElForm, ElMessage } from 'element-plus';
import { updateMysqlAccess } from '@/api/modules/database'; import { updateMysqlAccess } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import DrawerHeader from '@/components/drawer-header/index.vue';
const loading = ref(false); const loading = ref(false);
@ -54,6 +57,10 @@ const acceptParams = (prop: DialogProps): void => {
dialogVisiable.value = true; dialogVisiable.value = true;
}; };
const handleClose = () => {
dialogVisiable.value = false;
};
const onSubmit = async () => { const onSubmit = async () => {
let param = { let param = {
id: 0, id: 0,

View File

@ -0,0 +1,97 @@
<template>
<el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('database.rootPassword')" :back="handleClose" />
</template>
<el-form v-loading="loading" ref="formRef" :model="form" label-position="top">
<el-form-item :label="$t('database.rootPassword')" :rules="Rules.requiredInput" prop="password">
<el-input type="password" show-password clearable v-model="form.password" />
</el-form-item>
</el-form>
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="dialogVisiable = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="onSave(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm, ElMessage } from 'element-plus';
import { updateMysqlPassword } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { GetAppPassword } from '@/api/modules/app';
import DrawerHeader from '@/components/drawer-header/index.vue';
const loading = ref(false);
const dialogVisiable = ref(false);
const form = reactive({
password: '',
});
const confirmDialogRef = ref();
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const acceptParams = (): void => {
form.password = '';
loadPassword();
dialogVisiable.value = true;
};
const handleClose = () => {
dialogVisiable.value = false;
};
const loadPassword = async () => {
const res = await GetAppPassword('mysql');
form.password = res.data;
};
const onSubmit = async () => {
let param = {
id: 0,
value: form.password,
};
loading.value = true;
await updateMysqlPassword(param)
.then(() => {
loading.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
dialogVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
};
const onSave = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let params = {
header: i18n.global.t('database.confChange'),
operationInfo: i18n.global.t('database.restartNowHelper'),
submitInputInfo: i18n.global.t('database.restartNow'),
};
confirmDialogRef.value!.acceptParams(params);
});
};
defineExpose({
acceptParams,
});
</script>

View File

@ -35,7 +35,7 @@
</div> </div>
</template> </template>
</LayoutContent> </LayoutContent>
<el-drawer :key="refresh" v-model="drawerVisiable" size="50%"> <el-drawer :close-on-click-modal="false" :key="refresh" v-model="drawerVisiable" size="50%">
<template #header> <template #header>
<DrawerHeader :header="$t('setting.upgrade')" :back="handleClose" /> <DrawerHeader :header="$t('setting.upgrade')" :back="handleClose" />
</template> </template>
@ -49,16 +49,13 @@
<el-form-item :label="$t('setting.upgradeNotes')"> <el-form-item :label="$t('setting.upgradeNotes')">
<MdEditor style="height: calc(100vh - 330px)" v-model="upgradeInfo.releaseNote" previewOnly /> <MdEditor style="height: calc(100vh - 330px)" v-model="upgradeInfo.releaseNote" previewOnly />
</el-form-item> </el-form-item>
<el-form-item :label="$t('setting.source')">
<el-radio-group v-model="Source">
<el-radio label="gitee">Gitee</el-radio>
<el-radio label="github">GitHub</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onUpgrade">{{ $t('setting.upgradeNow') }}</el-button>
</el-form-item>
</el-form> </el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="onUpgrade">{{ $t('setting.upgradeNow') }}</el-button>
</span>
</template>
</el-drawer> </el-drawer>
</div> </div>
</template> </template>
@ -75,7 +72,6 @@ import DrawerHeader from '@/components/drawer-header/index.vue';
const version = ref(); const version = ref();
const upgradeInfo = ref(); const upgradeInfo = ref();
const Source = ref('gitee');
const drawerVisiable = ref(); const drawerVisiable = ref();
const refresh = ref(); const refresh = ref();
@ -103,13 +99,20 @@ const handleClose = () => {
}; };
const onLoadUpgradeInfo = async () => { const onLoadUpgradeInfo = async () => {
const res = await loadUpgradeInfo(); loading.value = true;
if (!res.data) { await loadUpgradeInfo()
ElMessage.info(i18n.global.t('setting.noUpgrade')); .then((res) => {
return; loading.value = false;
} if (!res.data) {
upgradeInfo.value = res.data; ElMessage.info(i18n.global.t('setting.noUpgrade'));
drawerVisiable.value = true; return;
}
upgradeInfo.value = res.data;
drawerVisiable.value = true;
})
.catch(() => {
loading.value = false;
});
}; };
const onUpgrade = async () => { const onUpgrade = async () => {
ElMessageBox.confirm(i18n.global.t('setting.upgradeHelper', i18n.global.t('setting.upgrade')), { ElMessageBox.confirm(i18n.global.t('setting.upgradeHelper', i18n.global.t('setting.upgrade')), {
@ -118,11 +121,7 @@ const onUpgrade = async () => {
type: 'info', type: 'info',
}).then(() => { }).then(() => {
loading.value = true; loading.value = true;
let param = { upgrade(upgradeInfo.value.newVersion)
version: upgradeInfo.value.newVersion,
source: Source.value,
};
upgrade(param)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
drawerVisiable.value = false; drawerVisiable.value = false;

View File

@ -13,7 +13,7 @@
</el-col> </el-col>
<el-col :lg="4" :xl="4"> <el-col :lg="4" :xl="4">
<div class="span-font"> <div class="span-font">
<el-tag type="info"> <el-tag>
{{ $t('website.expireDate') }}: {{ $t('website.expireDate') }}:
<span v-if="isEver(props.expireDate)"> <span v-if="isEver(props.expireDate)">
{{ $t('website.neverExpire') }} {{ $t('website.neverExpire') }}