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

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>
<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);
// null500ms
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>

View File

@ -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
}