mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: 增加应用参数修改功能
This commit is contained in:
parent
b54cbe1d11
commit
1e9833d7b7
@ -283,3 +283,25 @@ func (b *BaseApi) GetParams(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, content)
|
helper.SuccessWithData(c, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags App
|
||||||
|
// @Summary Change app params
|
||||||
|
// @Description 修改应用参数
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.AppInstalledUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /apps/installed/params/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["installId"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用参数修改 [installId]","formatEN":"Application param update [installId]"}
|
||||||
|
func (b *BaseApi) UpdateInstalled(c *gin.Context) {
|
||||||
|
var req request.AppInstalledUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := appInstallService.Update(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
@ -76,6 +76,8 @@ type AppFormFields struct {
|
|||||||
Default interface{} `json:"default"`
|
Default interface{} `json:"default"`
|
||||||
EnvKey string `json:"envKey"`
|
EnvKey string `json:"envKey"`
|
||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
|
Edit bool `json:"edit"`
|
||||||
|
Rule string `json:"rule"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppResource struct {
|
type AppResource struct {
|
||||||
|
@ -48,6 +48,11 @@ type AppInstalledOperate struct {
|
|||||||
DeleteDB bool `json:"deleteDB"`
|
DeleteDB bool `json:"deleteDB"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AppInstalledUpdate struct {
|
||||||
|
InstallId uint `json:"installId" validate:"required"`
|
||||||
|
Params map[string]interface{} `json:"params" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type PortUpdate struct {
|
type PortUpdate struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -61,6 +61,11 @@ type AppService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AppParam struct {
|
type AppParam struct {
|
||||||
Label string `json:"label"`
|
Value interface{} `json:"value"`
|
||||||
Value interface{} `json:"value"`
|
Edit bool `json:"edit"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Rule string `json:"rule"`
|
||||||
|
LabelZh string `json:"labelZh"`
|
||||||
|
LabelEn string `json:"labelEn"`
|
||||||
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package service
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -156,15 +158,7 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||||||
dockerComposePath := install.GetComposePath()
|
dockerComposePath := install.GetComposePath()
|
||||||
switch req.Operate {
|
switch req.Operate {
|
||||||
case constant.Rebuild:
|
case constant.Rebuild:
|
||||||
out, err := compose.Down(dockerComposePath)
|
return rebuildApp(install)
|
||||||
if err != nil {
|
|
||||||
return handleErr(install, err, out)
|
|
||||||
}
|
|
||||||
out, err = compose.Up(dockerComposePath)
|
|
||||||
if err != nil {
|
|
||||||
return handleErr(install, err, out)
|
|
||||||
}
|
|
||||||
return syncById(install.ID)
|
|
||||||
case constant.Start:
|
case constant.Start:
|
||||||
out, err := compose.Start(dockerComposePath)
|
out, err := compose.Start(dockerComposePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -193,13 +187,59 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||||||
return nil
|
return nil
|
||||||
case constant.Sync:
|
case constant.Sync:
|
||||||
return syncById(install.ID)
|
return syncById(install.ID)
|
||||||
case constant.Update:
|
case constant.Upgrade:
|
||||||
return updateInstall(install.ID, req.DetailId)
|
return updateInstall(install.ID, req.DetailId)
|
||||||
default:
|
default:
|
||||||
return errors.New("operate not support")
|
return errors.New("operate not support")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
|
||||||
|
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
|
||||||
|
if ok {
|
||||||
|
portN := int(math.Ceil(port.(float64)))
|
||||||
|
if portN != installed.HttpPort {
|
||||||
|
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
installed.HttpPort = httpPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
|
||||||
|
if ok {
|
||||||
|
portN := int(math.Ceil(ports.(float64)))
|
||||||
|
if portN != installed.HttpsPort {
|
||||||
|
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
installed.HttpsPort = httpsPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
envPath := path.Join(installed.GetPath(), ".env")
|
||||||
|
oldEnvMaps, err := godotenv.Read(envPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
handleMap(req.Params, oldEnvMaps)
|
||||||
|
paramByte, err := json.Marshal(oldEnvMaps)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
installed.Env = string(paramByte)
|
||||||
|
if err := godotenv.Write(oldEnvMaps, envPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = appInstallRepo.Save(&installed)
|
||||||
|
return rebuildApp(installed)
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppInstallService) SyncAll() error {
|
func (a AppInstallService) SyncAll() error {
|
||||||
allList, err := appInstallRepo.ListBy()
|
allList, err := appInstallRepo.ListBy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -391,17 +431,24 @@ func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
|
|||||||
}
|
}
|
||||||
for _, form := range appForm.FormFields {
|
for _, form := range appForm.FormFields {
|
||||||
if v, ok := envs[form.EnvKey]; ok {
|
if v, ok := envs[form.EnvKey]; ok {
|
||||||
|
appParam := response.AppParam{
|
||||||
|
Edit: false,
|
||||||
|
Key: form.EnvKey,
|
||||||
|
Rule: form.Rule,
|
||||||
|
Type: form.Type,
|
||||||
|
}
|
||||||
|
if form.Edit {
|
||||||
|
appParam.Edit = true
|
||||||
|
}
|
||||||
|
appParam.LabelZh = form.LabelZh
|
||||||
|
appParam.LabelEn = form.LabelEn
|
||||||
if form.Type == "service" {
|
if form.Type == "service" {
|
||||||
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
|
||||||
res = append(res, response.AppParam{
|
appParam.Value = appInstall.Name
|
||||||
Label: form.LabelZh,
|
res = append(res, appParam)
|
||||||
Value: appInstall.Name,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
res = append(res, response.AppParam{
|
appParam.Value = v
|
||||||
Label: form.LabelZh,
|
res = append(res, appParam)
|
||||||
Value: v,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,6 +345,19 @@ func upApp(composeFilePath string, appInstall model.AppInstall) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func rebuildApp(appInstall model.AppInstall) error {
|
||||||
|
dockerComposePath := appInstall.GetComposePath()
|
||||||
|
out, err := compose.Down(dockerComposePath)
|
||||||
|
if err != nil {
|
||||||
|
return handleErr(appInstall, err, out)
|
||||||
|
}
|
||||||
|
out, err = compose.Up(dockerComposePath)
|
||||||
|
if err != nil {
|
||||||
|
return handleErr(appInstall, err, out)
|
||||||
|
}
|
||||||
|
return syncById(appInstall.ID)
|
||||||
|
}
|
||||||
|
|
||||||
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
|
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
|
||||||
appDetails := make(map[string]model.AppDetail, len(details))
|
appDetails := make(map[string]model.AppDetail, len(details))
|
||||||
for _, old := range details {
|
for _, old := range details {
|
||||||
|
@ -32,4 +32,5 @@ var (
|
|||||||
Restore AppOperate = "restore"
|
Restore AppOperate = "restore"
|
||||||
Update AppOperate = "update"
|
Update AppOperate = "update"
|
||||||
Rebuild AppOperate = "rebuild"
|
Rebuild AppOperate = "rebuild"
|
||||||
|
Upgrade AppOperate = "upgrade"
|
||||||
)
|
)
|
||||||
|
@ -33,5 +33,6 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
|
|||||||
appRouter.GET("/services/:key", baseApi.GetServices)
|
appRouter.GET("/services/:key", baseApi.GetServices)
|
||||||
appRouter.GET("/installed/conf/:key", baseApi.GetDefaultConfig)
|
appRouter.GET("/installed/conf/:key", baseApi.GetDefaultConfig)
|
||||||
appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams)
|
appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams)
|
||||||
|
appRouter.POST("/installed/params/update", baseApi.UpdateInstalled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
frontend/auto-imports.d.ts
vendored
2
frontend/auto-imports.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
// Generated by 'unplugin-auto-import'
|
// Generated by 'unplugin-auto-import'
|
||||||
// We suggest you to commit this file into source control
|
// We suggest you to commit this file into source control
|
||||||
declare global {
|
declare global {
|
||||||
|
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||||
}
|
}
|
||||||
export {}
|
export {}
|
||||||
|
@ -151,7 +151,12 @@ export namespace App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface InstallParams {
|
export interface InstallParams {
|
||||||
label: string;
|
labelZh: string;
|
||||||
value: string;
|
labelEn: string;
|
||||||
|
value: any;
|
||||||
|
edit: boolean;
|
||||||
|
key: string;
|
||||||
|
rule: string;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,3 +77,7 @@ export const GetAppDefaultConfig = (key: string) => {
|
|||||||
export const GetAppInstallParams = (id: number) => {
|
export const GetAppInstallParams = (id: number) => {
|
||||||
return http.get<App.InstallParams[]>(`apps/installed/params/${id}`);
|
return http.get<App.InstallParams[]>(`apps/installed/params/${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const UpdateAppInstallParams = (req: any) => {
|
||||||
|
return http.post<any>(`apps/installed/params/update`, req);
|
||||||
|
};
|
||||||
|
@ -150,7 +150,7 @@ const checkParamCommon = (rule: any, value: any, callback: any) => {
|
|||||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||||
callback(new Error(i18n.global.t('commons.rule.paramName')));
|
callback(new Error(i18n.global.t('commons.rule.paramName')));
|
||||||
} else {
|
} else {
|
||||||
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9._-]{2,30}$/;
|
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9._-]{1,29}$/;
|
||||||
if (!reg.test(value) && value !== '') {
|
if (!reg.test(value) && value !== '') {
|
||||||
callback(new Error(i18n.global.t('commons.rule.paramName')));
|
callback(new Error(i18n.global.t('commons.rule.paramName')));
|
||||||
} else {
|
} else {
|
||||||
@ -163,7 +163,7 @@ const checkParamComplexity = (rule: any, value: any, callback: any) => {
|
|||||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||||
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@$!&~_'])));
|
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@$!&~_'])));
|
||||||
} else {
|
} else {
|
||||||
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9.%@$!&~_]{6,30}$/;
|
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9.%@$!&~_]{5,29}$/;
|
||||||
if (!reg.test(value) && value !== '') {
|
if (!reg.test(value) && value !== '') {
|
||||||
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@$!&~_'])));
|
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@$!&~_'])));
|
||||||
} else {
|
} else {
|
||||||
|
@ -881,7 +881,7 @@ export default {
|
|||||||
deleteWarn:
|
deleteWarn:
|
||||||
'The delete operation will delete all data and backups together. This operation cannot be rolled back. Do you want to continue? ',
|
'The delete operation will delete all data and backups together. This operation cannot be rolled back. Do you want to continue? ',
|
||||||
syncSuccess: 'Sync successfully',
|
syncSuccess: 'Sync successfully',
|
||||||
canUpdate: 'Upgrade',
|
canUpgrade: 'Upgrade',
|
||||||
backup: 'Backup',
|
backup: 'Backup',
|
||||||
backupName: 'File Name',
|
backupName: 'File Name',
|
||||||
backupPath: 'File Path',
|
backupPath: 'File Path',
|
||||||
@ -889,7 +889,8 @@ export default {
|
|||||||
restore: 'Restore',
|
restore: 'Restore',
|
||||||
restoreWarn:
|
restoreWarn:
|
||||||
'The restore operation will restart the application and replace the data. This operation cannot be rolled back. Do you want to continue?',
|
'The restore operation will restart the application and replace the data. This operation cannot be rolled back. Do you want to continue?',
|
||||||
update: 'upgrade',
|
update: 'update',
|
||||||
|
upgrade: 'upgrade',
|
||||||
versioneSelect: 'Please select a version',
|
versioneSelect: 'Please select a version',
|
||||||
operatorHelper: 'Operation {0} will be performed on the selected application, continue? ',
|
operatorHelper: 'Operation {0} will be performed on the selected application, continue? ',
|
||||||
checkInstalledWarn: '{0} is not detected, please enter the app store and click to install!',
|
checkInstalledWarn: '{0} is not detected, please enter the app store and click to install!',
|
||||||
@ -919,6 +920,7 @@ export default {
|
|||||||
syncAppList: 'Sync',
|
syncAppList: 'Sync',
|
||||||
updatePrompt: 'The current application is the latest version',
|
updatePrompt: 'The current application is the latest version',
|
||||||
installPrompt: 'No apps installed yet',
|
installPrompt: 'No apps installed yet',
|
||||||
|
updateHelper: 'Updating parameters may cause the application to fail to start, please operate with caution',
|
||||||
},
|
},
|
||||||
website: {
|
website: {
|
||||||
website: 'Website',
|
website: 'Website',
|
||||||
|
@ -885,14 +885,15 @@ export default {
|
|||||||
delete: '删除',
|
delete: '删除',
|
||||||
deleteWarn: '删除操作会把所有数据和备份一并删除,此操作不可回滚,是否继续?',
|
deleteWarn: '删除操作会把所有数据和备份一并删除,此操作不可回滚,是否继续?',
|
||||||
syncSuccess: '同步成功',
|
syncSuccess: '同步成功',
|
||||||
canUpdate: '可升级',
|
canUpgrade: '可升级',
|
||||||
backup: '备份',
|
backup: '备份',
|
||||||
backupName: '文件名称',
|
backupName: '文件名称',
|
||||||
backupPath: '文件路径',
|
backupPath: '文件路径',
|
||||||
backupdate: '备份时间',
|
backupdate: '备份时间',
|
||||||
restore: '恢复',
|
restore: '恢复',
|
||||||
restoreWarn: '恢复操作会重启应用,并替换数据,此操作不可回滚,是否继续?',
|
restoreWarn: '恢复操作会重启应用,并替换数据,此操作不可回滚,是否继续?',
|
||||||
update: '升级',
|
update: '更新',
|
||||||
|
upgrade: '升级',
|
||||||
versioneSelect: '请选择版本',
|
versioneSelect: '请选择版本',
|
||||||
operatorHelper: '将对选中应用进行 {0} 操作,是否继续?',
|
operatorHelper: '将对选中应用进行 {0} 操作,是否继续?',
|
||||||
checkInstalledWarn: '未检测到 {0} ,请进入应用商店点击安装!',
|
checkInstalledWarn: '未检测到 {0} ,请进入应用商店点击安装!',
|
||||||
@ -929,6 +930,8 @@ export default {
|
|||||||
document: '文档说明',
|
document: '文档说明',
|
||||||
updatePrompt: '当前应用均为最新版本',
|
updatePrompt: '当前应用均为最新版本',
|
||||||
installPrompt: '尚未安装任何应用',
|
installPrompt: '尚未安装任何应用',
|
||||||
|
updateHelper: '更新参数可能导致应用无法启动,请提前备份并谨慎操作',
|
||||||
|
updateWarn: '更新参数需要重建应用,是否继续?',
|
||||||
},
|
},
|
||||||
website: {
|
website: {
|
||||||
website: '网站',
|
website: '网站',
|
||||||
|
@ -51,8 +51,8 @@ const appStoreRouter = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'update',
|
path: 'upgrade',
|
||||||
name: 'AppUpdate',
|
name: 'AppUpgrade',
|
||||||
component: () => import('@/views/app-store/installed/index.vue'),
|
component: () => import('@/views/app-store/installed/index.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
hidden: true,
|
hidden: true,
|
||||||
|
@ -27,8 +27,8 @@ const buttons = [
|
|||||||
path: '/apps/installed',
|
path: '/apps/installed',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('app.canUpdate'),
|
label: i18n.global.t('app.canUpgrade'),
|
||||||
path: '/apps/update',
|
path: '/apps/upgrade',
|
||||||
count: 0,
|
count: 0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -49,7 +49,7 @@ const search = () => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
search();
|
search();
|
||||||
bus.on('update', () => {
|
bus.on('upgrade', () => {
|
||||||
showButton.value = false;
|
showButton.value = false;
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
@ -1,20 +1,57 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-drawer :close-on-click-modal="false" v-model="open" size="40%">
|
<el-drawer :close-on-click-modal="false" v-model="open" size="40%">
|
||||||
<template #header>
|
<template #header>
|
||||||
<Header :header="$t('app.param')" :back="handleClose"></Header>
|
<Header :header="$t('app.param')" :back="handleClose">
|
||||||
|
<template #buttons v-if="canEdit">
|
||||||
|
<el-button type="primary" plain @click="editParam" :disabled="loading">
|
||||||
|
{{ edit ? $t('app.detail') : $t('commons.button.edit') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</Header>
|
||||||
</template>
|
</template>
|
||||||
<el-descriptions border :column="1">
|
<el-descriptions border :column="1" v-if="!edit">
|
||||||
<el-descriptions-item v-for="(param, key) in params" :label="param.label" :key="key">
|
<el-descriptions-item v-for="(param, key) in params" :label="getLabel(param)" :key="key">
|
||||||
{{ param.value }}
|
{{ param.value }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
<el-row v-else v-loading="loading">
|
||||||
|
<el-col :span="22" :offset="1">
|
||||||
|
<el-alert :title="$t('app.updateHelper')" type="warning" :closable="false" />
|
||||||
|
<el-form ref="paramForm" :model="paramModel" label-position="top" :rules="rules">
|
||||||
|
<div v-for="(p, index) in params" :key="index">
|
||||||
|
<el-form-item :prop="p.key" :label="getLabel(p)">
|
||||||
|
<el-input
|
||||||
|
v-if="p.type == 'number'"
|
||||||
|
type="number"
|
||||||
|
v-model.number="paramModel[p.key]"
|
||||||
|
:disabled="!p.edit"
|
||||||
|
></el-input>
|
||||||
|
<el-input v-else v-model.trim="paramModel[p.key]" :disabled="!p.edit"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<template #footer v-if="edit">
|
||||||
|
<span>
|
||||||
|
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" :disabled="loading" @click="submit(paramForm)">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import { GetAppInstallParams } from '@/api/modules/app';
|
import { GetAppInstallParams, UpdateAppInstallParams } from '@/api/modules/app';
|
||||||
import { ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import Header from '@/components/drawer-header/index.vue';
|
import Header from '@/components/drawer-header/index.vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { FormInstance } from 'element-plus';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
|
||||||
interface ParamProps {
|
interface ParamProps {
|
||||||
id: Number;
|
id: Number;
|
||||||
@ -23,31 +60,114 @@ const paramData = ref<ParamProps>({
|
|||||||
id: 0,
|
id: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface EditForm extends App.InstallParams {
|
||||||
|
default: any;
|
||||||
|
}
|
||||||
|
|
||||||
let open = ref(false);
|
let open = ref(false);
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
const params = ref<App.InstallParams[]>();
|
const params = ref<EditForm[]>();
|
||||||
|
let edit = ref(false);
|
||||||
|
const paramForm = ref<FormInstance>();
|
||||||
|
let paramModel = ref<any>({});
|
||||||
|
let rules = reactive({});
|
||||||
|
let submitModel = ref<any>({});
|
||||||
|
let canEdit = ref(false);
|
||||||
|
|
||||||
const acceptParams = (props: ParamProps) => {
|
const acceptParams = async (props: ParamProps) => {
|
||||||
|
submitModel.value.installId = props.id;
|
||||||
params.value = [];
|
params.value = [];
|
||||||
paramData.value.id = props.id;
|
paramData.value.id = props.id;
|
||||||
get();
|
edit.value = false;
|
||||||
|
await get();
|
||||||
open.value = true;
|
open.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
};
|
};
|
||||||
|
const editParam = () => {
|
||||||
|
params.value.forEach((param: EditForm) => {
|
||||||
|
paramModel.value[param.key] = param.value;
|
||||||
|
});
|
||||||
|
edit.value = !edit.value;
|
||||||
|
};
|
||||||
|
|
||||||
const get = async () => {
|
const get = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await GetAppInstallParams(Number(paramData.value.id));
|
const res = await GetAppInstallParams(Number(paramData.value.id));
|
||||||
params.value = res.data;
|
if (res.data && res.data.length > 0) {
|
||||||
|
res.data.forEach((d) => {
|
||||||
|
if (d.edit) {
|
||||||
|
console.log(d.edit);
|
||||||
|
canEdit.value = true;
|
||||||
|
}
|
||||||
|
let value = d.value;
|
||||||
|
if (d.type === 'number') {
|
||||||
|
value = Number(value);
|
||||||
|
}
|
||||||
|
params.value.push({
|
||||||
|
default: value,
|
||||||
|
labelEn: d.labelEn,
|
||||||
|
labelZh: d.labelZh,
|
||||||
|
rule: d.rule,
|
||||||
|
value: value,
|
||||||
|
edit: d.edit,
|
||||||
|
key: d.key,
|
||||||
|
type: d.type,
|
||||||
|
});
|
||||||
|
rules[d.key] = [Rules.requiredInput];
|
||||||
|
if (d.rule) {
|
||||||
|
rules[d.key].push(Rules[d.rule]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getLabel = (row: EditForm): string => {
|
||||||
|
const language = useI18n().locale.value;
|
||||||
|
if (language == 'zh') {
|
||||||
|
return row.labelZh;
|
||||||
|
} else {
|
||||||
|
return row.labelEn;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async (formEl: FormInstance) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessageBox.confirm(i18n.global.t('app.updateWarn'), i18n.global.t('app.update'), {
|
||||||
|
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||||
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
|
type: 'info',
|
||||||
|
}).then(async () => {
|
||||||
|
submitModel.value.params = paramModel.value;
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
await UpdateAppInstallParams(submitModel.value);
|
||||||
|
loading.value = false;
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||||
|
handleClose();
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
defineExpose({ acceptParams });
|
defineExpose({ acceptParams });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.change-button {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
<template #main>
|
<template #main>
|
||||||
<div class="update-prompt" v-if="data == null">
|
<div class="update-prompt" v-if="data == null">
|
||||||
<span>{{ mode === 'update' ? $t('app.updatePrompt') : $t('app.installPrompt') }}</span>
|
<span>{{ mode === 'upgrade' ? $t('app.updatePrompt') : $t('app.installPrompt') }}</span>
|
||||||
<div>
|
<div>
|
||||||
<img src="@/assets/images/no_update_app.svg" />
|
<img src="@/assets/images/no_update_app.svg" />
|
||||||
</div>
|
</div>
|
||||||
@ -129,7 +129,7 @@
|
|||||||
round
|
round
|
||||||
size="small"
|
size="small"
|
||||||
@click="openOperate(installed, 'update')"
|
@click="openOperate(installed, 'update')"
|
||||||
v-if="mode === 'update'"
|
v-if="mode === 'upgrade'"
|
||||||
>
|
>
|
||||||
{{ $t('app.update') }}
|
{{ $t('app.update') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -171,7 +171,7 @@
|
|||||||
<AppResources ref="checkRef" />
|
<AppResources ref="checkRef" />
|
||||||
<AppDelete ref="deleteRef" @close="search" />
|
<AppDelete ref="deleteRef" @close="search" />
|
||||||
<AppParams ref="appParamRef" />
|
<AppParams ref="appParamRef" />
|
||||||
<AppUpdate ref="updateRef" @close="search" />
|
<AppUpgrade ref="upgradeRef" @close="search" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -191,7 +191,7 @@ import Uploads from '@/components/upload/index.vue';
|
|||||||
import AppResources from './check/index.vue';
|
import AppResources from './check/index.vue';
|
||||||
import AppDelete from './delete/index.vue';
|
import AppDelete from './delete/index.vue';
|
||||||
import AppParams from './detail/index.vue';
|
import AppParams from './detail/index.vue';
|
||||||
import AppUpdate from './update/index.vue';
|
import AppUpgrade from './upgrade/index.vue';
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import Status from '@/components/status/index.vue';
|
import Status from '@/components/status/index.vue';
|
||||||
import { getAge } from '@/utils/util';
|
import { getAge } from '@/utils/util';
|
||||||
@ -217,7 +217,7 @@ const uploadRef = ref();
|
|||||||
const checkRef = ref();
|
const checkRef = ref();
|
||||||
const deleteRef = ref();
|
const deleteRef = ref();
|
||||||
const appParamRef = ref();
|
const appParamRef = ref();
|
||||||
const updateRef = ref();
|
const upgradeRef = ref();
|
||||||
let tags = ref<App.Tag[]>([]);
|
let tags = ref<App.Tag[]>([]);
|
||||||
let activeTag = ref('all');
|
let activeTag = ref('all');
|
||||||
let searchReq = reactive({
|
let searchReq = reactive({
|
||||||
@ -273,7 +273,7 @@ const openOperate = (row: any, op: string) => {
|
|||||||
operateReq.installId = row.id;
|
operateReq.installId = row.id;
|
||||||
operateReq.operate = op;
|
operateReq.operate = op;
|
||||||
if (op == 'update') {
|
if (op == 'update') {
|
||||||
updateRef.value.acceptParams(row.id, row.name);
|
upgradeRef.value.acceptParams(row.id, row.name);
|
||||||
} else if (op == 'delete') {
|
} else if (op == 'delete') {
|
||||||
AppInstalledDeleteCheck(row.id).then(async (res) => {
|
AppInstalledDeleteCheck(row.id).then(async (res) => {
|
||||||
const items = res.data;
|
const items = res.data;
|
||||||
@ -393,9 +393,9 @@ const openParam = (installId: number) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const path = router.currentRoute.value.path;
|
const path = router.currentRoute.value.path;
|
||||||
if (path == '/apps/update') {
|
if (path == '/apps/upgrade') {
|
||||||
activeName.value = i18n.global.t('app.canUpdate');
|
activeName.value = i18n.global.t('app.canUpgrade');
|
||||||
mode.value = 'update';
|
mode.value = 'upgrade';
|
||||||
searchReq.update = true;
|
searchReq.update = true;
|
||||||
}
|
}
|
||||||
search();
|
search();
|
||||||
|
@ -46,7 +46,7 @@ let loading = ref(false);
|
|||||||
let versions = ref<App.VersionDetail[]>();
|
let versions = ref<App.VersionDetail[]>();
|
||||||
let operateReq = reactive({
|
let operateReq = reactive({
|
||||||
detailId: 0,
|
detailId: 0,
|
||||||
operate: 'update',
|
operate: 'upgrade',
|
||||||
installId: 0,
|
installId: 0,
|
||||||
});
|
});
|
||||||
const resourceName = ref('');
|
const resourceName = ref('');
|
||||||
@ -77,7 +77,7 @@ const operate = async () => {
|
|||||||
await InstalledOp(operateReq)
|
await InstalledOp(operateReq)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
bus.emit('update', true);
|
bus.emit('upgrade', true);
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@ -100,7 +100,7 @@ const onOperate = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
bus.off('update');
|
bus.off('upgrade');
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
Loading…
x
Reference in New Issue
Block a user