修复安装市场应用时各种错误
This commit is contained in:
parent
70e2158dd6
commit
776679c000
@ -1,237 +1,196 @@
|
||||
<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,
|
||||
currentApp: null,
|
||||
retryCount: 0
|
||||
};
|
||||
},
|
||||
resources: {
|
||||
// 添加API资源定义:检查应用是否可安装
|
||||
checkAppInstallable() {
|
||||
return {
|
||||
url: 'jcloud.api.site.check_app_installable',
|
||||
params: {
|
||||
name: this.site,
|
||||
app: this.currentApp
|
||||
},
|
||||
auto: false
|
||||
};
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
$site() {
|
||||
return getCachedDocumentResource('Site', this.site);
|
||||
},
|
||||
listOptions() {
|
||||
const handleInstall = async row => {
|
||||
if (this.$site.installApp.loading) return;
|
||||
|
||||
// 设置当前应用以便资源可以使用
|
||||
this.currentApp = row.app;
|
||||
this.retryCount = 0
|
||||
|
||||
// 打印关键变量进行调试
|
||||
console.log('=== 安装应用调试信息 ===');
|
||||
console.log('站点名称:', this.site);
|
||||
console.log('应用ID:', this.currentApp);
|
||||
console.log('站点对象:', this.$site);
|
||||
console.log('站点plan:', this.$site.pg?.plan);
|
||||
console.log('=== 调试信息结束 ===');
|
||||
|
||||
try {
|
||||
// 尝试获取应用安装权限信息,最多重试2次
|
||||
let checkResult = null;
|
||||
let apiCalled = false;
|
||||
|
||||
while (!checkResult && this.retryCount < 3) {
|
||||
console.log(`正在调用check_app_installable API... (尝试 ${this.retryCount + 1}/3)`);
|
||||
apiCalled = true;
|
||||
|
||||
await this.$resources.checkAppInstallable.submit();
|
||||
|
||||
console.log('API调用完成,状态:', {
|
||||
loading: this.$resources.checkAppInstallable.loading,
|
||||
error: this.$resources.checkAppInstallable.error
|
||||
});
|
||||
|
||||
// 获取检查结果
|
||||
checkResult = this.$resources.checkAppInstallable.data;
|
||||
console.log('API返回结果:', checkResult);
|
||||
|
||||
// 如果返回结果为null且未达到最大重试次数,等待500ms后重试
|
||||
if (!checkResult && this.retryCount < 2) {
|
||||
this.retryCount++;
|
||||
console.log(`API返回null,将在500ms后重试(${this.retryCount}/2)...`);
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查返回结果是否有效
|
||||
if (!checkResult) {
|
||||
console.error('API返回结果无效,已达到最大重试次数');
|
||||
toast.error('应用安装权限验证失败,安装已取消');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查应用是否可安装
|
||||
console.log('应用可安装?', checkResult.installable);
|
||||
console.log('required_plan_level:', checkResult.required_plan_level);
|
||||
console.log('current_plan_level:', checkResult.current_plan_level);
|
||||
|
||||
// 如果结果显示不可安装,显示错误信息并退出
|
||||
if (checkResult.installable !== true) {
|
||||
console.log('应用不可安装,显示错误信息');
|
||||
|
||||
const subscriptionTypeMap = {
|
||||
2: 'Pro',
|
||||
3: 'Business',
|
||||
4: 'Enterprise',
|
||||
5: 'Ultimate'
|
||||
};
|
||||
|
||||
const requiredPlan = subscriptionTypeMap[checkResult.required_plan_level] ||
|
||||
`Level ${checkResult.required_plan_level}`;
|
||||
|
||||
toast.error(`无法安装此应用,需要${requiredPlan}或更高级别的站点计划。请先升级您的站点计划。`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果可安装,执行安装
|
||||
console.log('应用可安装,开始安装流程');
|
||||
await toast.promise(
|
||||
this.$site.installApp.submit({
|
||||
app: row.app
|
||||
}),
|
||||
{
|
||||
loading: '正在创建安装任务...',
|
||||
success: jobId => {
|
||||
console.log('安装任务创建成功,jobId:', jobId);
|
||||
this.$emit('installed');
|
||||
this.show = false;
|
||||
|
||||
try {
|
||||
if (jobId) {
|
||||
router.push({
|
||||
name: 'Site Job',
|
||||
params: {
|
||||
name: this.site,
|
||||
id: String(jobId)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('导航到作业页面失败:', err);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('处理作业ID时出错:', err);
|
||||
}
|
||||
|
||||
return '应用安装任务已创建';
|
||||
},
|
||||
error: e => {
|
||||
console.error('安装过程中出错:', e);
|
||||
return getToastErrorMessage(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error('检查应用安装权限失败:', error);
|
||||
toast.error('无法验证安装权限,安装已取消');
|
||||
}
|
||||
};
|
||||
|
||||
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({ row }) {
|
||||
return {
|
||||
label: '安装',
|
||||
onClick: () => {
|
||||
handleInstall(row);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
],
|
||||
resource: () => {
|
||||
return {
|
||||
url: 'jcloud.api.site.available_apps',
|
||||
params: {
|
||||
name: this.site
|
||||
},
|
||||
auto: true
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
<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: 'Pro',
|
||||
3: 'Business',
|
||||
4: 'Enterprise',
|
||||
5: 'Ultimate'
|
||||
};
|
||||
|
||||
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>
|
||||
@ -2428,62 +2428,24 @@ def check_app_installable(name, app):
|
||||
"current_plan_level": 1-5, # 当前站点计划等级
|
||||
}
|
||||
"""
|
||||
try:
|
||||
print(f"check_app_installable被调用: name={name}, app={app}")
|
||||
|
||||
site = jingrow.get_pg("Site", name)
|
||||
print(f"获取到站点: {site.name}, plan={site.plan}")
|
||||
|
||||
# 获取应用的subscription_level
|
||||
app_subscription_level = jingrow.db.get_value(
|
||||
"Marketplace App", app, "subscription_level")
|
||||
print(f"应用{app}的subscription_level={app_subscription_level}")
|
||||
|
||||
# 确保subscription_level是有效值
|
||||
if app_subscription_level is None or app_subscription_level == "":
|
||||
app_subscription_level = 1
|
||||
print(f"应用{app}的subscription_level为空,使用默认值1")
|
||||
else:
|
||||
try:
|
||||
app_subscription_level = int(app_subscription_level)
|
||||
print(f"应用{app}的subscription_level转换为整数: {app_subscription_level}")
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"转换subscription_level出错: {e}, 使用默认值1")
|
||||
app_subscription_level = 1
|
||||
|
||||
# 获取站点的plan_level
|
||||
site_plan_level = 1
|
||||
if site.plan:
|
||||
plan_level = jingrow.db.get_value(
|
||||
"Site Plan", site.plan, "plan_level")
|
||||
print(f"站点plan={site.plan}, plan_level={plan_level}")
|
||||
|
||||
if plan_level is not None and plan_level != "":
|
||||
try:
|
||||
site_plan_level = int(plan_level)
|
||||
print(f"站点plan_level转换为整数: {site_plan_level}")
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"转换plan_level出错: {e}, 使用默认值1")
|
||||
else:
|
||||
print(f"站点没有plan信息,使用默认plan_level=1")
|
||||
|
||||
installable = site_plan_level >= app_subscription_level
|
||||
print(f"安装条件判断: {site_plan_level} >= {app_subscription_level} = {installable}")
|
||||
|
||||
result = {
|
||||
"installable": installable,
|
||||
"required_plan_level": app_subscription_level,
|
||||
"current_plan_level": site_plan_level
|
||||
}
|
||||
print(f"返回结果: {result}")
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"check_app_installable出现异常: {e}")
|
||||
# 发生异常时返回默认值,确保前端收到有效响应
|
||||
return {
|
||||
"installable": False,
|
||||
"required_plan_level": 1,
|
||||
"current_plan_level": 1,
|
||||
"error": str(e)
|
||||
}
|
||||
site = jingrow.get_pg("Site", name)
|
||||
|
||||
# 获取应用的subscription_level
|
||||
app_subscription_level = jingrow.db.get_value(
|
||||
"Marketplace App", app, "subscription_level") or "1"
|
||||
app_subscription_level = int(app_subscription_level)
|
||||
|
||||
# 获取站点的plan_level
|
||||
site_plan_level = 1
|
||||
if site.plan:
|
||||
site_plan_level = jingrow.db.get_value(
|
||||
"Site Plan", site.plan, "plan_level") or "1"
|
||||
site_plan_level = int(site_plan_level)
|
||||
|
||||
installable = site_plan_level >= app_subscription_level
|
||||
|
||||
return {
|
||||
"installable": installable,
|
||||
"required_plan_level": app_subscription_level,
|
||||
"current_plan_level": site_plan_level
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user