修复安装市场应用时各种错误

This commit is contained in:
jingrow 2025-04-23 01:39:54 +08:00
parent 70e2158dd6
commit 776679c000
2 changed files with 216 additions and 295 deletions

View File

@ -1,237 +1,196 @@
<template> <template>
<Dialog <Dialog
v-model="show" v-model="show"
:options="{ :options="{
title: '在您的站点上安装应用', title: '在您的站点上安装应用',
size: '4xl' size: '4xl'
}" }"
> >
<template #body-content> <template #body-content>
<ObjectList :options="listOptions" /> <ObjectList :options="listOptions" />
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script> <script>
import { getCachedDocumentResource, createResource } from 'jingrow-ui'; import { getCachedDocumentResource, createResource } from 'jingrow-ui';
import { defineAsyncComponent, h } from 'vue'; import { defineAsyncComponent, h } from 'vue';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { renderDialog } from '../../utils/components'; import { renderDialog } from '../../utils/components';
import router from '../../router'; import router from '../../router';
import ObjectList from '../ObjectList.vue'; import ObjectList from '../ObjectList.vue';
import { getToastErrorMessage } from '../../utils/toast'; import { getToastErrorMessage } from '../../utils/toast';
export default { export default {
props: { props: {
site: { site: {
type: String, type: String,
required: true required: true
} }
}, },
emits: ['installed'], emits: ['installed'],
components: { components: {
ObjectList ObjectList
}, },
data() { data() {
return { return {
show: true, show: true,
currentApp: null, installPending: false
retryCount: 0 };
}; },
}, computed: {
resources: { $site() {
// API return getCachedDocumentResource('Site', this.site);
checkAppInstallable() { },
return { listOptions() {
url: 'jcloud.api.site.check_app_installable', const handleInstall = async row => {
params: { //
name: this.site, if (this.$site.installApp.loading || this.installPending) return;
app: this.currentApp
}, // app
auto: false if (!row || !row.app) {
}; toast.error('无效的应用信息');
} return;
}, }
computed: {
$site() { //
return getCachedDocumentResource('Site', this.site); this.installPending = true;
},
listOptions() { try {
const handleInstall = async row => { //
if (this.$site.installApp.loading) return; const checkResource = createResource({
url: 'jcloud.api.site.check_app_installable',
// 便使 params: {
this.currentApp = row.app; name: this.site,
this.retryCount = 0 app: row.app
},
// auto: true
console.log('=== 安装应用调试信息 ==='); });
console.log('站点名称:', this.site);
console.log('应用ID:', this.currentApp); //
console.log('站点对象:', this.$site); await new Promise(resolve => {
console.log('站点plan:', this.$site.pg?.plan); const unwatch = this.$watch(
console.log('=== 调试信息结束 ==='); () => !checkResource.loading,
isNotLoading => {
try { if (isNotLoading) {
// 2 unwatch();
let checkResult = null; resolve();
let apiCalled = false; }
},
while (!checkResult && this.retryCount < 3) { { immediate: true }
console.log(`正在调用check_app_installable API... (尝试 ${this.retryCount + 1}/3)`); );
apiCalled = true; });
await this.$resources.checkAppInstallable.submit(); //
const checkResult = checkResource.data;
console.log('API调用完成状态:', {
loading: this.$resources.checkAppInstallable.loading, // API
error: this.$resources.checkAppInstallable.error if (!checkResult) {
}); toast.error('应用安装权限验证失败,安装已取消');
this.installPending = false;
// return;
checkResult = this.$resources.checkAppInstallable.data; }
console.log('API返回结果:', checkResult);
//
// null500ms if (!checkResult.installable) {
if (!checkResult && this.retryCount < 2) { const subscriptionTypeMap = {
this.retryCount++; 2: 'Pro',
console.log(`API返回null将在500ms后重试(${this.retryCount}/2)...`); 3: 'Business',
await new Promise(resolve => setTimeout(resolve, 500)); 4: 'Enterprise',
} else { 5: 'Ultimate'
break; };
}
} const requiredPlan = subscriptionTypeMap[checkResult.required_plan_level] ||
`Level ${checkResult.required_plan_level}`;
//
if (!checkResult) { toast.error(`无法安装此应用,需要${requiredPlan}或更高级别的站点计划。请先升级您的站点计划。`);
console.error('API返回结果无效已达到最大重试次数'); this.installPending = false;
toast.error('应用安装权限验证失败,安装已取消'); return;
return; }
}
//
// await toast.promise(
console.log('应用可安装?', checkResult.installable); this.$site.installApp.submit({ app: row.app })
console.log('required_plan_level:', checkResult.required_plan_level); .then(jobId => {
console.log('current_plan_level:', checkResult.current_plan_level); this.$emit('installed');
this.show = false;
// 退 return jobId;
if (checkResult.installable !== true) { }),
console.log('应用不可安装,显示错误信息'); {
loading: '正在创建安装任务...',
const subscriptionTypeMap = { success: () => '应用安装任务已创建',
2: 'Pro', error: e => {
3: 'Business', //
4: 'Enterprise', const errorMessage = e?.message || e?.messages?.[0] || e?.exc_info?.exception || '安装任务创建失败';
5: 'Ultimate'
}; //
return typeof errorMessage === 'string' ? errorMessage : '安装任务创建失败,请稍后重试';
const requiredPlan = subscriptionTypeMap[checkResult.required_plan_level] || }
`Level ${checkResult.required_plan_level}`; }
);
toast.error(`无法安装此应用,需要${requiredPlan}或更高级别的站点计划。请先升级您的站点计划。`);
return; } catch (error) {
} toast.error('无法验证安装权限,安装已取消');
} finally {
// //
console.log('应用可安装,开始安装流程'); this.installPending = false;
await toast.promise( }
this.$site.installApp.submit({ };
app: row.app
}), return {
{ label: '应用',
loading: '正在创建安装任务...', fieldname: 'app',
success: jobId => { fieldtype: 'ListSelection',
console.log('安装任务创建成功jobId:', jobId); emptyStateMessage:
this.$emit('installed'); '未找到应用' +
this.show = false; (!this.$site.pg?.group_public
? '。请从您的工作台添加它们。'
try { : ''),
if (jobId) { columns: [
router.push({ {
name: 'Site Job', label: '标题',
params: { fieldname: 'title',
name: this.site, class: 'font-medium',
id: String(jobId) width: 2,
} format: (value, row) => value || row.app_title
}).catch(err => { },
console.error('导航到作业页面失败:', err); {
}); label: '仓库',
} fieldname: 'repository_owner',
} catch (err) { class: 'text-gray-600',
console.error('处理作业ID时出错:', err); width: '10rem'
} },
{
return '应用安装任务已创建'; label: '版本',
}, fieldname: 'branch',
error: e => { class: 'text-gray-600',
console.error('安装过程中出错:', e); width: '20rem'
return getToastErrorMessage(e); },
} {
} label: '',
); fieldname: '',
align: 'right',
} catch (error) { type: 'Button',
console.error('检查应用安装权限失败:', error); width: '5rem',
toast.error('无法验证安装权限,安装已取消'); Button: function({ row }) {
} return {
}; label: '安装',
onClick: () => handleInstall(row)
return { };
label: '应用', }
fieldname: 'app', }
fieldtype: 'ListSelection', ],
emptyStateMessage: resource: () => {
'未找到应用' + return {
(!this.$site.pg?.group_public url: 'jcloud.api.site.available_apps',
? '。请从您的工作台添加它们。' params: {
: ''), name: this.site
columns: [ },
{ auto: true
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
};
}
};
}
}
};
</script> </script>

View File

@ -2428,62 +2428,24 @@ def check_app_installable(name, app):
"current_plan_level": 1-5, # 当前站点计划等级 "current_plan_level": 1-5, # 当前站点计划等级
} }
""" """
try: site = jingrow.get_pg("Site", name)
print(f"check_app_installable被调用: name={name}, app={app}")
# 获取应用的subscription_level
site = jingrow.get_pg("Site", name) app_subscription_level = jingrow.db.get_value(
print(f"获取到站点: {site.name}, plan={site.plan}") "Marketplace App", app, "subscription_level") or "1"
app_subscription_level = int(app_subscription_level)
# 获取应用的subscription_level
app_subscription_level = jingrow.db.get_value( # 获取站点的plan_level
"Marketplace App", app, "subscription_level") site_plan_level = 1
print(f"应用{app}的subscription_level={app_subscription_level}") if site.plan:
site_plan_level = jingrow.db.get_value(
# 确保subscription_level是有效值 "Site Plan", site.plan, "plan_level") or "1"
if app_subscription_level is None or app_subscription_level == "": site_plan_level = int(site_plan_level)
app_subscription_level = 1
print(f"应用{app}的subscription_level为空使用默认值1") installable = site_plan_level >= app_subscription_level
else:
try: return {
app_subscription_level = int(app_subscription_level) "installable": installable,
print(f"应用{app}的subscription_level转换为整数: {app_subscription_level}") "required_plan_level": app_subscription_level,
except (ValueError, TypeError) as e: "current_plan_level": site_plan_level
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)
}