mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-11 16:06:02 +08:00
513 lines
18 KiB
Vue
513 lines
18 KiB
Vue
<template>
|
|
<DrawerPro
|
|
v-model="open"
|
|
:header="$t('runtime.' + mode)"
|
|
size="large"
|
|
:resource="mode === 'edit' ? runtime.name : ''"
|
|
@close="handleClose"
|
|
>
|
|
<el-form
|
|
ref="runtimeForm"
|
|
label-position="top"
|
|
:model="runtime"
|
|
label-width="125px"
|
|
:rules="rules"
|
|
:validate-on-rule-change="false"
|
|
v-loading="loading"
|
|
>
|
|
<el-form-item :label="$t('commons.table.name')" prop="name">
|
|
<el-input :disabled="mode === 'edit'" v-model="runtime.name"></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="$t('app.source')" prop="resource">
|
|
<el-radio-group
|
|
:disabled="mode === 'edit'"
|
|
v-model="runtime.resource"
|
|
@change="changeResource(runtime.resource)"
|
|
>
|
|
<el-radio :value="'appstore'">
|
|
{{ $t('menu.apps') }}
|
|
</el-radio>
|
|
<el-radio :value="'local'">
|
|
{{ $t('commons.table.local') }}
|
|
</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<div v-if="runtime.resource === 'appstore'">
|
|
<el-form-item :label="$t('app.app')" prop="appID">
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-select
|
|
v-model="runtime.appID"
|
|
:disabled="mode === 'edit'"
|
|
@change="changeApp(runtime.appID)"
|
|
class="p-w-200"
|
|
>
|
|
<el-option
|
|
v-for="(app, index) in apps"
|
|
:key="index"
|
|
:label="app.name"
|
|
:value="app.id"
|
|
></el-option>
|
|
</el-select>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-select
|
|
v-model="runtime.version"
|
|
:disabled="mode === 'edit'"
|
|
@change="changeVersion()"
|
|
class="p-w-200"
|
|
>
|
|
<el-option
|
|
v-for="(version, index) in appVersions"
|
|
:key="index"
|
|
:label="version"
|
|
:value="version"
|
|
></el-option>
|
|
</el-select>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form-item>
|
|
<div v-if="initParam">
|
|
<el-form-item
|
|
:label="getLabel(formFields['PHP_VERSION'])"
|
|
:rules="rules.params.PHP_VERSION"
|
|
v-if="formFields['PHP_VERSION']"
|
|
>
|
|
<el-select
|
|
v-model="runtime.params['PHP_VERSION']"
|
|
filterable
|
|
default-first-option
|
|
@change="changePHPVersion(runtime.params['PHP_VERSION'])"
|
|
>
|
|
<el-option
|
|
v-for="service in formFields['PHP_VERSION'].values"
|
|
:key="service.label"
|
|
:value="service.value"
|
|
:label="service.label"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="$t('container.image')" prop="image">
|
|
<el-input v-model="runtime.image"></el-input>
|
|
</el-form-item>
|
|
<el-form-item
|
|
:label="getLabel(formFields['CONTAINER_PACKAGE_URL'])"
|
|
:rules="rules.params.CONTAINER_PACKAGE_URL"
|
|
v-if="runtime.params['PHP_VERSION'] != '5.6.40' && formFields['CONTAINER_PACKAGE_URL']"
|
|
>
|
|
<el-select v-model="runtime.source" filterable default-first-option>
|
|
<el-option
|
|
v-for="source in phpSources"
|
|
:key="source.label"
|
|
:value="source.value"
|
|
:label="source.label + ' [' + source.value + ']'"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item
|
|
:label="getLabel(formFields['PANEL_APP_PORT_HTTP'])"
|
|
prop="params.PANEL_APP_PORT_HTTP"
|
|
v-if="formFields['PANEL_APP_PORT_HTTP']"
|
|
>
|
|
<el-input
|
|
v-model.number="runtime.params['PANEL_APP_PORT_HTTP']"
|
|
maxlength="15"
|
|
:disabled="mode == 'edit'"
|
|
></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="$t('app.containerName')" prop="params.CONTAINER_NAME">
|
|
<el-input v-model.trim="runtime.params['CONTAINER_NAME']"></el-input>
|
|
</el-form-item>
|
|
<el-text>{{ $t('container.env') }}</el-text>
|
|
<br />
|
|
<Environment :environments="runtime.environments" />
|
|
<br />
|
|
<el-form-item>
|
|
<el-alert type="warning" :closable="false">
|
|
<template #default>
|
|
<div>
|
|
<div>{{ $t('runtime.buildHelper') }}</div>
|
|
<span>
|
|
{{ $t('runtime.extendHelper') }}
|
|
</span>
|
|
<span
|
|
class="custom-link"
|
|
@click="openLink(globalStore.docsUrl + '/user_manual/websites/php/#php_1')"
|
|
>
|
|
{{ $t('php.toExtensionsList') }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
</el-alert>
|
|
</el-form-item>
|
|
<el-form-item :label="$t('php.extensions')">
|
|
<el-select v-model="extensions" @change="changePHPExtension()" clearable>
|
|
<el-option
|
|
v-for="(extension, index) in phpExtensions"
|
|
:key="index"
|
|
:label="extension.name"
|
|
:value="extension.extensions"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="getLabel(formFields['PHP_EXTENSIONS'])" v-if="formFields['PHP_EXTENSIONS']">
|
|
<el-select v-model="runtime.params['PHP_EXTENSIONS']" multiple allowCreate filterable>
|
|
<el-option
|
|
v-for="service in formFields['PHP_EXTENSIONS'].values"
|
|
:key="service.label"
|
|
:value="service.value"
|
|
:label="service.label"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<el-form-item>
|
|
<el-alert :title="$t('runtime.localHelper')" type="info" :closable="false" />
|
|
</el-form-item>
|
|
<el-form-item :label="$t('app.version')" prop="version">
|
|
<el-input v-model="runtime.version" :placeholder="$t('runtime.versionHelper')"></el-input>
|
|
</el-form-item>
|
|
</div>
|
|
</el-form>
|
|
<template #footer>
|
|
<span>
|
|
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
|
<el-button type="primary" @click="submit(runtimeForm)" :disabled="loading">
|
|
{{ $t('commons.button.confirm') }}
|
|
</el-button>
|
|
</span>
|
|
</template>
|
|
</DrawerPro>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { App } from '@/api/interface/app';
|
|
import { Runtime } from '@/api/interface/runtime';
|
|
import Environment from '@/views/website/runtime/environment/index.vue';
|
|
import { getAppByKey, getAppDetail, searchApp } from '@/api/modules/app';
|
|
import { CreateRuntime, GetRuntime, ListPHPExtensions, UpdateRuntime } from '@/api/modules/runtime';
|
|
import { Rules } from '@/global/form-rules';
|
|
import i18n from '@/lang';
|
|
import { MsgSuccess } from '@/utils/message';
|
|
import { FormInstance } from 'element-plus';
|
|
import { reactive, ref } from 'vue';
|
|
import { GlobalStore } from '@/store';
|
|
import { getLabel } from '@/utils/util';
|
|
const globalStore = GlobalStore();
|
|
|
|
interface OperateRrops {
|
|
id?: number;
|
|
mode: string;
|
|
type: string;
|
|
appID?: number;
|
|
}
|
|
|
|
const open = ref(false);
|
|
const apps = ref<App.App[]>([]);
|
|
const runtimeForm = ref<FormInstance>();
|
|
const loading = ref(false);
|
|
const initParam = ref(false);
|
|
const mode = ref('create');
|
|
const appParams = ref<App.AppParams>();
|
|
const appVersions = ref<string[]>([]);
|
|
const phpExtensions = ref([]);
|
|
const appReq = reactive({
|
|
type: 'php',
|
|
page: 1,
|
|
pageSize: 20,
|
|
});
|
|
const phpSources = globalStore.isIntl
|
|
? [
|
|
{
|
|
label: i18n.global.t('runtime.default'),
|
|
value: 'https://deb.debian.org',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.xtom'),
|
|
value: 'https://mirrors.xtom.com',
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
label: i18n.global.t('runtime.ustc'),
|
|
value: 'https://mirrors.ustc.edu.cn',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.netease'),
|
|
value: 'https://mirrors.163.com',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.aliyun'),
|
|
value: 'https://mirrors.aliyun.com',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.tsinghua'),
|
|
value: 'https://mirrors.tuna.tsinghua.edu.cn',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.xtomhk'),
|
|
value: 'https://mirrors.xtom.com.hk',
|
|
},
|
|
{
|
|
label: i18n.global.t('runtime.xtom'),
|
|
value: 'https://mirrors.xtom.com',
|
|
},
|
|
{
|
|
label: i18n.global.t('commons.table.default'),
|
|
value: 'https://deb.debian.org',
|
|
},
|
|
];
|
|
|
|
const initData = (type: string) => ({
|
|
name: '',
|
|
appDetailID: undefined,
|
|
image: '',
|
|
params: {},
|
|
type: type,
|
|
resource: 'appstore',
|
|
rebuild: false,
|
|
source: phpSources[0].value,
|
|
environments: [],
|
|
});
|
|
const extensions = ref();
|
|
const formFields = ref();
|
|
|
|
let runtime = reactive<Runtime.RuntimeCreate>(initData('php'));
|
|
|
|
const rules = ref<any>({
|
|
name: [Rules.appName],
|
|
resource: [Rules.requiredInput],
|
|
appID: [Rules.requiredSelect],
|
|
version: [Rules.requiredInput, Rules.paramCommon],
|
|
image: [Rules.requiredInput, Rules.imageName],
|
|
source: [Rules.requiredSelect],
|
|
params: {
|
|
PANEL_APP_PORT_HTTP: [Rules.requiredInput, Rules.port],
|
|
PHP_VERSION: [Rules.requiredSelect],
|
|
CONTAINER_PACKAGE_URL: [Rules.requiredSelect],
|
|
CONTAINER_NAME: [Rules.containerName, Rules.requiredInput],
|
|
},
|
|
});
|
|
|
|
const em = defineEmits(['close', 'submit']);
|
|
|
|
const openLink = (url: string) => {
|
|
window.open(url, '_blank');
|
|
};
|
|
|
|
const handleClose = () => {
|
|
open.value = false;
|
|
em('close', false);
|
|
};
|
|
|
|
const changeResource = (resource: string) => {
|
|
if (resource === 'local') {
|
|
runtime.appDetailID = undefined;
|
|
runtime.version = '';
|
|
runtime.params = {};
|
|
runtime.image = '';
|
|
} else {
|
|
runtime.version = '';
|
|
searchAppList(null);
|
|
}
|
|
};
|
|
|
|
const searchAppList = (appId: number) => {
|
|
searchApp(appReq).then((res) => {
|
|
apps.value = res.data.items || [];
|
|
if (res.data && res.data.items && res.data.items.length > 0) {
|
|
if (appId == null) {
|
|
runtime.appID = res.data.items[0].id;
|
|
getApp(res.data.items[0].key, mode.value);
|
|
} else {
|
|
res.data.items.forEach((item) => {
|
|
if (item.id === appId) {
|
|
getApp(item.key, mode.value);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
const changeApp = (appId: number) => {
|
|
extensions.value = undefined;
|
|
for (const app of apps.value) {
|
|
if (app.id === appId) {
|
|
initParam.value = false;
|
|
getApp(app.key, mode.value);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
const changePHPVersion = (version: string) => {
|
|
runtime.image = 'php:' + version;
|
|
};
|
|
|
|
const changeVersion = () => {
|
|
loading.value = true;
|
|
initParam.value = false;
|
|
extensions.value = undefined;
|
|
getAppDetail(runtime.appID, runtime.version, 'runtime')
|
|
.then((res) => {
|
|
runtime.appDetailID = res.data.id;
|
|
runtime.image = res.data.image + ':' + runtime.version;
|
|
appParams.value = res.data.params;
|
|
const fileds = res.data.params.formFields;
|
|
formFields.value = {};
|
|
for (const index in fileds) {
|
|
formFields.value[fileds[index]['envKey']] = fileds[index];
|
|
runtime.params[fileds[index]['envKey']] = fileds[index]['default'];
|
|
if (fileds[index]['envKey'] == 'PHP_VERSION') {
|
|
runtime.image = 'php:' + fileds[index]['default'];
|
|
}
|
|
}
|
|
initParam.value = true;
|
|
})
|
|
.finally(() => {
|
|
loading.value = false;
|
|
});
|
|
};
|
|
|
|
const getApp = (appkey: string, mode: string) => {
|
|
getAppByKey(appkey).then((res) => {
|
|
appVersions.value = res.data.versions || [];
|
|
if (res.data.versions.length > 0) {
|
|
runtime.version = res.data.versions[0];
|
|
if (mode === 'create') {
|
|
changeVersion();
|
|
} else {
|
|
initParam.value = true;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
const submit = async (formEl: FormInstance | undefined) => {
|
|
if (!formEl) return;
|
|
await formEl.validate((valid) => {
|
|
if (!valid) {
|
|
return;
|
|
}
|
|
if (mode.value == 'create') {
|
|
loading.value = true;
|
|
CreateRuntime(runtime)
|
|
.then((res) => {
|
|
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
|
handleClose();
|
|
em('submit', res.data.id);
|
|
})
|
|
.finally(() => {
|
|
loading.value = false;
|
|
});
|
|
} else {
|
|
loading.value = true;
|
|
UpdateRuntime(runtime)
|
|
.then(() => {
|
|
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
|
handleClose();
|
|
em('submit', runtime.id);
|
|
})
|
|
.finally(() => {
|
|
loading.value = false;
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
const getRuntime = async (id: number) => {
|
|
try {
|
|
const res = await GetRuntime(id);
|
|
const data = res.data;
|
|
Object.assign(runtime, {
|
|
id: data.id,
|
|
name: data.name,
|
|
appDetailID: data.appDetailID,
|
|
image: data.image,
|
|
params: data.params,
|
|
type: data.type,
|
|
resource: data.resource,
|
|
appID: data.appID,
|
|
version: data.version,
|
|
rebuild: true,
|
|
source: data.source,
|
|
});
|
|
|
|
const fileds = data.appParams;
|
|
const forms = {};
|
|
for (const index in fileds) {
|
|
forms[fileds[index].key] = fileds[index];
|
|
}
|
|
formFields.value = forms;
|
|
if (data.params['PHP_EXTENSIONS'] != '') {
|
|
runtime.params['PHP_EXTENSIONS'] = runtime.params['PHP_EXTENSIONS'].split(',');
|
|
}
|
|
initParam.value = true;
|
|
} catch (error) {}
|
|
};
|
|
|
|
const listPHPExtensions = async () => {
|
|
try {
|
|
const res = await ListPHPExtensions({
|
|
all: true,
|
|
page: 1,
|
|
pageSize: 100,
|
|
});
|
|
phpExtensions.value = res.data.items;
|
|
} catch (error) {}
|
|
};
|
|
|
|
const changePHPExtension = () => {
|
|
if (extensions.value == '') {
|
|
return;
|
|
}
|
|
runtime.params['PHP_EXTENSIONS'] = extensions.value.split(',');
|
|
};
|
|
|
|
const acceptParams = async (props: OperateRrops) => {
|
|
mode.value = props.mode;
|
|
initParam.value = false;
|
|
if (props.mode === 'create') {
|
|
Object.assign(runtime, initData(props.type));
|
|
searchAppList(null);
|
|
} else {
|
|
searchAppList(props.appID);
|
|
getRuntime(props.id);
|
|
}
|
|
extensions.value = '';
|
|
open.value = true;
|
|
listPHPExtensions();
|
|
};
|
|
|
|
watch(
|
|
() => runtime.name,
|
|
(newVal) => {
|
|
if (newVal && mode.value == 'create') {
|
|
runtime.params['CONTAINER_NAME'] = newVal;
|
|
}
|
|
},
|
|
{ deep: true },
|
|
);
|
|
|
|
defineExpose({
|
|
acceptParams,
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.custom-link {
|
|
color: var(--el-color-primary);
|
|
cursor: pointer;
|
|
text-decoration: underline;
|
|
font-size: inherit;
|
|
line-height: inherit;
|
|
}
|
|
|
|
.custom-link:hover {
|
|
color: var(--el-color-primary-light-3);
|
|
}
|
|
</style>
|