mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-14 01:34:47 +08:00
feat: 网站增加切换数据库功能 (#6592)
This commit is contained in:
parent
f8431c787f
commit
1e1fce4c77
@ -968,7 +968,6 @@ func (b *BaseApi) SetRealIPConfig(c *gin.Context) {
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// 写一个调用 GetRealIPConfig 的接口
|
||||
// @Tags Website
|
||||
// @Summary Get Real IP Config
|
||||
// @Description 获取真实 IP 配置
|
||||
@ -990,3 +989,61 @@ func (b *BaseApi) GetRealIPConfig(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get website resource
|
||||
// @Description 获取网站资源
|
||||
// @Accept json
|
||||
// @Param id path int true "id"
|
||||
// @Success 200 {object} response.WebsiteResource
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/resource/{id} [get]
|
||||
func (b *BaseApi) GetWebsiteResource(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
res, err := websiteService.GetWebsiteResource(id)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get databases
|
||||
// @Description 获取数据库列表
|
||||
// @Accept json
|
||||
// @Success 200 {object} response.WebsiteDatabase
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/databases [get]
|
||||
func (b *BaseApi) GetWebsiteDatabase(c *gin.Context) {
|
||||
res, err := websiteService.ListDatabases()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Change website database
|
||||
// @Description 切换网站数据库
|
||||
// @Accept json
|
||||
// @Param request body request.ChangeDatabase true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/databases [post]
|
||||
func (b *BaseApi) ChangeWebsiteDatabase(c *gin.Context) {
|
||||
var req request.ChangeDatabase
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteService.ChangeDatabase(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
@ -275,3 +275,9 @@ type WebsiteRealIP struct {
|
||||
IPHeader string `json:"ipHeader"`
|
||||
IPOther string `json:"ipOther"`
|
||||
}
|
||||
|
||||
type ChangeDatabase struct {
|
||||
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||
DatabaseID uint `json:"databaseID" validate:"required"`
|
||||
DatabaseType string `json:"databaseType" validate:"required"`
|
||||
}
|
||||
|
@ -102,3 +102,16 @@ type WebsiteRealIP struct {
|
||||
IPHeader string `json:"ipHeader"`
|
||||
IPOther string `json:"ipOther"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
ResourceID uint `json:"resourceID"`
|
||||
Detail interface{} `json:"detail"`
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
@ -113,6 +113,10 @@ type IWebsiteService interface {
|
||||
GetRealIPConfig(websiteID uint) (*response.WebsiteRealIP, error)
|
||||
|
||||
ChangeGroup(group, newGroup uint) error
|
||||
|
||||
GetWebsiteResource(websiteID uint) ([]response.Resource, error)
|
||||
ListDatabases() ([]response.Database, error)
|
||||
ChangeDatabase(req request.ChangeDatabase) error
|
||||
}
|
||||
|
||||
func NewIWebsiteService() IWebsiteService {
|
||||
@ -3052,3 +3056,116 @@ func (w WebsiteService) GetRealIPConfig(websiteID uint) (*response.WebsiteRealIP
|
||||
res.IPFrom = strings.Join(ips, "\n")
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetWebsiteResource(websiteID uint) ([]response.Resource, error) {
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
res []response.Resource
|
||||
databaseID uint
|
||||
databaseType string
|
||||
)
|
||||
if website.Type == constant.Runtime {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, response.Resource{
|
||||
Name: runtime.Name,
|
||||
Type: "runtime",
|
||||
ResourceID: runtime.ID,
|
||||
Detail: runtime,
|
||||
})
|
||||
}
|
||||
if website.Type == constant.Deployment {
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, response.Resource{
|
||||
Name: install.Name,
|
||||
Type: "app",
|
||||
ResourceID: install.ID,
|
||||
Detail: install,
|
||||
})
|
||||
installResources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
for _, resource := range installResources {
|
||||
if resource.Key == constant.AppMysql || resource.Key == constant.AppMariaDB || resource.Key == constant.AppPostgres || resource.Key == constant.AppPostgresql {
|
||||
databaseType = resource.Key
|
||||
databaseID = resource.ResourceId
|
||||
}
|
||||
}
|
||||
}
|
||||
if website.DbID > 0 {
|
||||
databaseType = website.DbType
|
||||
databaseID = website.DbID
|
||||
}
|
||||
if databaseID > 0 {
|
||||
switch databaseType {
|
||||
case constant.AppMysql, constant.AppMariaDB:
|
||||
db, _ := mysqlRepo.Get(commonRepo.WithByID(databaseID))
|
||||
if db.ID > 0 {
|
||||
res = append(res, response.Resource{
|
||||
Name: db.Name,
|
||||
Type: "database",
|
||||
ResourceID: db.ID,
|
||||
Detail: db,
|
||||
})
|
||||
}
|
||||
case constant.AppPostgresql, constant.AppPostgres:
|
||||
db, _ := postgresqlRepo.Get(commonRepo.WithByID(databaseID))
|
||||
if db.ID > 0 {
|
||||
res = append(res, response.Resource{
|
||||
Name: db.Name,
|
||||
Type: "database",
|
||||
ResourceID: db.ID,
|
||||
Detail: db,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) ListDatabases() ([]response.Database, error) {
|
||||
var res []response.Database
|
||||
mysqlDBs, _ := mysqlRepo.List()
|
||||
for _, db := range mysqlDBs {
|
||||
database, _ := databaseRepo.Get(commonRepo.WithByName(db.MysqlName))
|
||||
if database.ID > 0 {
|
||||
res = append(res, response.Database{
|
||||
ID: db.ID,
|
||||
Name: db.Name,
|
||||
Type: database.Type,
|
||||
})
|
||||
}
|
||||
}
|
||||
pgSqls, _ := postgresqlRepo.List()
|
||||
for _, db := range pgSqls {
|
||||
database, _ := databaseRepo.Get(commonRepo.WithByName(db.Name))
|
||||
if database.ID > 0 {
|
||||
res = append(res, response.Database{
|
||||
ID: db.ID,
|
||||
Name: db.Name,
|
||||
Type: database.Type,
|
||||
})
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) ChangeDatabase(req request.ChangeDatabase) error {
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if website.DbID == req.DatabaseID {
|
||||
return nil
|
||||
}
|
||||
website.DbID = req.DatabaseID
|
||||
website.DbType = req.DatabaseType
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
@ -77,5 +77,9 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
|
||||
websiteRouter.POST("/realip/config", baseApi.SetRealIPConfig)
|
||||
websiteRouter.GET("/realip/config/:id", baseApi.GetRealIPConfig)
|
||||
|
||||
websiteRouter.GET("/resource/:id", baseApi.GetWebsiteResource)
|
||||
websiteRouter.GET("/databases", baseApi.GetWebsiteDatabase)
|
||||
websiteRouter.POST("/databases", baseApi.ChangeWebsiteDatabase)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
|
||||
type ComposeService struct {
|
||||
api.Service
|
||||
project *types.Project
|
||||
}
|
||||
|
||||
func GetComposeProject(projectName, workDir string, yml []byte, env []byte, skipNormalization bool) (*types.Project, error) {
|
||||
|
@ -607,4 +607,23 @@ export namespace Website {
|
||||
ipHeader: string;
|
||||
ipOther: string;
|
||||
}
|
||||
|
||||
export interface WebsiteResource {
|
||||
name: string;
|
||||
type: string;
|
||||
resourceID: number;
|
||||
detail: any;
|
||||
}
|
||||
|
||||
export interface WebsiteDatabase {
|
||||
type: string;
|
||||
databaseID: number;
|
||||
websiteID: number;
|
||||
}
|
||||
|
||||
export interface ChangeDatabase {
|
||||
websiteID: number;
|
||||
databaseID: number;
|
||||
databaseType: string;
|
||||
}
|
||||
}
|
||||
|
@ -319,3 +319,15 @@ export const UpdateRealIPConfig = (req: Website.WebsiteRealIPConfig) => {
|
||||
export const GetRealIPConfig = (id: number) => {
|
||||
return http.get<Website.WebsiteRealIPConfig>(`/websites/realip/config/${id}`);
|
||||
};
|
||||
|
||||
export const GetWebsiteResource = (id: number) => {
|
||||
return http.get<Website.WebsiteResource[]>(`/websites/resource/${id}`);
|
||||
};
|
||||
|
||||
export const GetWebsiteDatabase = () => {
|
||||
return http.get<Website.WebsiteDatabase[]>(`/websites/databases`);
|
||||
};
|
||||
|
||||
export const ChangeDatabase = (req: Website.ChangeDatabase) => {
|
||||
return http.post(`/websites/databases`, req);
|
||||
};
|
||||
|
@ -2238,6 +2238,11 @@ const message = {
|
||||
'If unsure, you can enter 0.0.0.0/0 (ipv4) ::/0 (ipv6) [Note: Allowing any source IP is not secure]',
|
||||
http3Helper:
|
||||
'HTTP/3 is an upgrade to HTTP/2, offering faster connection speeds and better performance, but not all browsers support HTTP/3. Enabling it may cause some browsers to be unable to access the site.',
|
||||
|
||||
database: 'Database',
|
||||
changeDatabase: 'Change Database',
|
||||
changeDatabaseHelper1: 'Database association is used for backing up and restoring the website.',
|
||||
changeDatabaseHelper2: 'Switching to another database will cause previous backups to be unrecoverable.',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: 'Short tag support',
|
||||
|
@ -2085,6 +2085,11 @@ const message = {
|
||||
ipFromExample3: '如果不確定,可以填 0.0.0.0/0(ipv4) ::/0(ipv6) [注意:允許任意來源 IP 不安全]',
|
||||
http3Helper:
|
||||
'HTTP/3 是 HTTP/2 的升級版本,提供更快的連線速度和更好的性能,但並非所有瀏覽器都支援 HTTP/3,啟用後可能會導致部分瀏覽器無法訪問',
|
||||
|
||||
database: '資料庫',
|
||||
changeDatabase: '切換資料庫',
|
||||
changeDatabaseHelper1: '資料庫關聯用於備份恢復網站。',
|
||||
changeDatabaseHelper2: '切換其他資料庫會導致以前的備份無法恢復。',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短標簽支持',
|
||||
|
@ -2083,6 +2083,11 @@ const message = {
|
||||
ipFromExample3: '如果不确定,可以填 0.0.0.0/0(ipv4) ::/0(ipv6) [注意:允许任意来源 IP 不安全]',
|
||||
http3Helper:
|
||||
'HTTP/3 是 HTTP/2 的升级版本,提供更快的连接速度和更好的性能,但是不是所有浏览器都支持 HTTP/3,开启后可能会导致部分浏览器无法访问',
|
||||
|
||||
database: '数据库',
|
||||
changeDatabase: '切换数据库',
|
||||
changeDatabaseHelper1: '数据库关联用于备份恢复网站',
|
||||
changeDatabaseHelper2: '切换其他数据库会导致以前的备份无法恢复',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-row :gutter="20" v-loading="loading">
|
||||
<el-row v-loading="loading">
|
||||
<el-col :xs="24" :sm="18" :md="16" :lg="16" :xl="16">
|
||||
<el-form
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="leechRef"
|
||||
label-position="right"
|
||||
label-width="180px"
|
||||
label-width="120px"
|
||||
class="moblie-form"
|
||||
>
|
||||
<el-form-item :label="$t('website.enableOrNot')">
|
||||
@ -43,11 +43,18 @@
|
||||
<el-form-item :label="$t('website.leechReturn')" prop="return">
|
||||
<el-input v-model="form.return" type="text" :maxlength="35"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-button type="primary" @click="submit(leechRef, true)" :disabled="loading" v-if="form.enable">
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="submit(leechRef, true)"
|
||||
:disabled="loading"
|
||||
v-if="form.enable"
|
||||
>
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
@ -36,15 +36,20 @@
|
||||
<el-tab-pane :label="$t('website.redirect')">
|
||||
<Redirect :id="id" v-if="tabIndex == '11'"></Redirect>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.other')">
|
||||
<Other :id="id" v-if="tabIndex == '12'"></Other>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane
|
||||
:label="'PHP'"
|
||||
name="13"
|
||||
v-if="(website.type === 'runtime' && website.runtimeType === 'php') || website.type === 'static'"
|
||||
>
|
||||
<PHP :website="website" v-if="tabIndex == '13'"></PHP>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('logs.resource')" name="14">
|
||||
<Resource :id="id" :websiteType="website.type" v-if="tabIndex == '14'"></Resource>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.other')" name="12">
|
||||
<Other :id="id" v-if="tabIndex == '12'"></Other>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
@ -65,6 +70,7 @@ import Redirect from './redirect/index.vue';
|
||||
import LoadBalance from './load-balance/index.vue';
|
||||
import PHP from './php/index.vue';
|
||||
import RealIP from './real-ip/index.vue';
|
||||
import Resource from './resource/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
website: {
|
||||
|
@ -28,11 +28,13 @@
|
||||
<el-input v-model.number="form.rate" maxlength="15"></el-input>
|
||||
<span class="input-help">{{ $t('website.rateHelper') }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submit(limitForm)" :disabled="loading">
|
||||
<span v-if="enable">{{ $t('commons.button.save') }}</span>
|
||||
<span v-else>{{ $t('commons.button.saveAndEnable') }}</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-row :gutter="20" v-loading="loading">
|
||||
<el-col :xs="24" :sm="18" :md="8" :lg="8" :xl="8">
|
||||
<el-form ref="websiteForm" label-position="right" label-width="100px" :model="form" :rules="rules">
|
||||
<el-form ref="websiteForm" label-position="right" label-width="80px" :model="form" :rules="rules">
|
||||
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||
<el-input v-model="form.primaryDomain"></el-input>
|
||||
</el-form-item>
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-row>
|
||||
<el-col :xs="20" :sm="12" :md="10" :lg="10" :xl="8" :offset="1">
|
||||
<el-form>
|
||||
<el-col :xs="20" :sm="12" :md="10" :lg="10" :xl="8">
|
||||
<el-form label-position="right" label-width="80px">
|
||||
<div v-if="website.type === 'static'">
|
||||
<el-text type="info">{{ $t('website.staticChangePHPHelper') }}</el-text>
|
||||
</div>
|
||||
<el-form-item :label="$t('website.changeVersion')">
|
||||
<el-select v-model="versionReq.runtimeID" style="width: 100%">
|
||||
<el-select v-model="versionReq.runtimeID" class="w-full">
|
||||
<el-option :key="-1" :label="$t('website.static')" :value="0"></el-option>
|
||||
<el-option
|
||||
v-for="(item, index) in versions"
|
||||
|
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="p-w-400">
|
||||
<el-descriptions border :column="1">
|
||||
<div v-for="(resource, index) of data" :key="index">
|
||||
<el-descriptions-item :label="$t('website.' + resource.type)">{{ resource.name }}</el-descriptions-item>
|
||||
</div>
|
||||
</el-descriptions>
|
||||
<el-form
|
||||
ref="changeForm"
|
||||
:model="req"
|
||||
label-position="left"
|
||||
label-width="90px"
|
||||
class="mt-5"
|
||||
v-if="websiteType === 'static' || websiteType === 'runtime'"
|
||||
>
|
||||
<el-form-item :label="$t('website.changeDatabase')" prop="databaseID">
|
||||
<el-select v-model="req.databaseID" class="w-full" @change="changeDatabase">
|
||||
<el-option v-for="(item, index) in databases" :key="index" :label="item.name" :value="item.id">
|
||||
<div class="flex justify-between items-center">
|
||||
<span>{{ item.name }}</span>
|
||||
<el-tag>{{ item.type }}</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-text type="warning">{{ $t('website.changeDatabaseHelper1') }}</el-text>
|
||||
<el-text type="warning">{{ $t('website.changeDatabaseHelper2') }}</el-text>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submit()">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ChangeDatabase, GetWebsiteDatabase, GetWebsiteResource } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
websiteType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const data = ref([]);
|
||||
const req = reactive({
|
||||
websiteID: props.id,
|
||||
databaseID: 0,
|
||||
databaseType: '',
|
||||
});
|
||||
const databases = ref([]);
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
const res = await GetWebsiteResource(props.id);
|
||||
data.value = res.data;
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const listDatabases = async () => {
|
||||
try {
|
||||
const res = await GetWebsiteDatabase();
|
||||
databases.value = res.data;
|
||||
if (databases.value.length > 0) {
|
||||
req.databaseID = databases.value[0].id;
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const changeDatabase = () => {
|
||||
req.databaseType = databases.value.find((item) => item.id === req.databaseID)?.type;
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
try {
|
||||
await ChangeDatabase(req);
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('websiteType', props.websiteType);
|
||||
search();
|
||||
listDatabases();
|
||||
});
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user