jcloud/dashboard/src2/components/site/InstallAppDialog.vue

196 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<Dialog
v-model="show"
:options="{
title: '在您的站点上安装应用',
size: '4xl'
}"
>
<template #body-content>
<ObjectList :options="listOptions" />
</template>
</Dialog>
</template>
<script>
import { getCachedDocumentResource, createResource } from 'jingrow-ui';
import { defineAsyncComponent, h } from 'vue';
import { toast } from 'vue-sonner';
import { renderDialog } from '../../utils/components';
import router from '../../router';
import ObjectList from '../ObjectList.vue';
import { getToastErrorMessage } from '../../utils/toast';
export default {
props: {
site: {
type: String,
required: true
}
},
emits: ['installed'],
components: {
ObjectList
},
data() {
return {
show: true,
installPending: false
};
},
computed: {
$site() {
return getCachedDocumentResource('Site', this.site);
},
listOptions() {
const handleInstall = async row => {
// 防止重复点击或正在处理中
if (this.$site.installApp.loading || this.installPending) return;
// 确保有有效的app
if (!row || !row.app) {
toast.error('无效的应用信息');
return;
}
// 标记为处理中,防止重复点击
this.installPending = true;
try {
// 直接创建一个资源进行应用安装权限检查
const checkResource = createResource({
url: 'jcloud.api.site.check_app_installable',
params: {
name: this.site,
app: row.app
},
auto: true
});
// 等待资源加载完成
await new Promise(resolve => {
const unwatch = this.$watch(
() => !checkResource.loading,
isNotLoading => {
if (isNotLoading) {
unwatch();
resolve();
}
},
{ immediate: true }
);
});
// 获取检查结果
const checkResult = checkResource.data;
// 如果API返回错误或结果无效取消安装
if (!checkResult) {
toast.error('应用安装权限验证失败,安装已取消');
this.installPending = false;
return;
}
// 如果应用不可安装,显示对应提示
if (!checkResult.installable) {
const subscriptionTypeMap = {
2: '299元/月',
3: '399元/月',
4: '499元/月',
5: '599元/月'
};
const requiredPlan = subscriptionTypeMap[checkResult.required_plan_level] ||
`Level ${checkResult.required_plan_level}`;
toast.error(`无法安装此应用,需要${requiredPlan}或更高级别的站点计划。请先升级您的站点计划。`);
this.installPending = false;
return;
}
// 应用可安装,执行安装流程
await toast.promise(
this.$site.installApp.submit({ app: row.app })
.then(jobId => {
this.$emit('installed');
this.show = false;
return jobId;
}),
{
loading: '正在创建安装任务...',
success: () => '应用安装任务已创建',
error: e => {
// 尝试从错误对象中提取消息
const errorMessage = e?.message || e?.messages?.[0] || e?.exc_info?.exception || '安装任务创建失败';
// 返回用户友好的错误消息
return typeof errorMessage === 'string' ? errorMessage : '安装任务创建失败,请稍后重试';
}
}
);
} catch (error) {
toast.error('无法验证安装权限,安装已取消');
} finally {
// 无论成功失败,都清除处理标记
this.installPending = false;
}
};
return {
label: '应用',
fieldname: 'app',
fieldtype: 'ListSelection',
emptyStateMessage:
'未找到应用' +
(!this.$site.pg?.group_public
? '。请从您的工作台添加它们。'
: ''),
columns: [
{
label: '标题',
fieldname: 'title',
class: 'font-medium',
width: 2,
format: (value, row) => value || row.app_title
},
{
label: '仓库',
fieldname: 'repository_owner',
class: 'text-gray-600',
width: '10rem'
},
{
label: '版本',
fieldname: 'branch',
class: 'text-gray-600',
width: '20rem'
},
{
label: '',
fieldname: '',
align: 'right',
type: 'Button',
width: '5rem',
Button: function({ row }) {
return {
label: '安装',
onClick: () => handleInstall(row)
};
}
}
],
resource: () => {
return {
url: 'jcloud.api.site.available_apps',
params: {
name: this.site
},
auto: true
};
}
};
}
}
};
</script>