增加安装app时条件判断,符合条件才能安装
This commit is contained in:
parent
da162f3cb2
commit
70e2158dd6
@ -13,7 +13,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCachedDocumentResource } from 'jingrow-ui';
|
||||
import { getCachedDocumentResource, createResource } from 'jingrow-ui';
|
||||
import { defineAsyncComponent, h } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { renderDialog } from '../../utils/components';
|
||||
@ -34,47 +34,114 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: true
|
||||
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 = row => {
|
||||
const handleInstall = async row => {
|
||||
if (this.$site.installApp.loading) return;
|
||||
|
||||
if (row.plans) {
|
||||
this.show = false;
|
||||
|
||||
import('./SiteAppPlanSelectDialog.vue').then(module => {
|
||||
const SiteAppPlanSelectDialog = module.default;
|
||||
// 设置当前应用以便资源可以使用
|
||||
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;
|
||||
|
||||
const component = h(SiteAppPlanSelectDialog, {
|
||||
app: row,
|
||||
currentPlan: null,
|
||||
onPlanSelected: plan => {
|
||||
handleAppInstall(row, plan);
|
||||
},
|
||||
"onPlan-selected": plan => {
|
||||
handleAppInstall(row, plan);
|
||||
},
|
||||
await this.$resources.checkAppInstallable.submit();
|
||||
|
||||
console.log('API调用完成,状态:', {
|
||||
loading: this.$resources.checkAppInstallable.loading,
|
||||
error: this.$resources.checkAppInstallable.error
|
||||
});
|
||||
|
||||
renderDialog(component);
|
||||
}).catch(err => {
|
||||
toast.error('加载组件失败');
|
||||
this.show = true;
|
||||
});
|
||||
} else {
|
||||
toast.promise(
|
||||
this.$site.installApp.submit({
|
||||
app: row.app
|
||||
// 获取检查结果
|
||||
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;
|
||||
|
||||
@ -87,58 +154,28 @@ export default {
|
||||
id: String(jobId)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('导航到作业页面失败:', err);
|
||||
});
|
||||
} else {
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('处理作业ID时出错:', err);
|
||||
}
|
||||
|
||||
return '应用安装任务已创建';
|
||||
},
|
||||
error: e => {
|
||||
console.error('安装过程中出错:', e);
|
||||
return getToastErrorMessage(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error('检查应用安装权限失败:', error);
|
||||
toast.error('无法验证安装权限,安装已取消');
|
||||
}
|
||||
};
|
||||
|
||||
const handleAppInstall = (app, plan) => {
|
||||
toast.promise(
|
||||
this.$site.installApp.submit({
|
||||
app: app.app,
|
||||
plan: plan.name
|
||||
}),
|
||||
{
|
||||
loading: '正在创建安装任务...',
|
||||
success: jobId => {
|
||||
this.$emit('installed');
|
||||
this.show = false;
|
||||
|
||||
try {
|
||||
if (jobId) {
|
||||
router.push({
|
||||
name: 'Site Job',
|
||||
params: {
|
||||
name: this.site,
|
||||
id: String(jobId)
|
||||
}
|
||||
}).catch(err => {
|
||||
});
|
||||
} else {
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
return '应用安装任务已创建';
|
||||
},
|
||||
error: e => {
|
||||
return getToastErrorMessage(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
label: '应用',
|
||||
fieldname: 'app',
|
||||
|
||||
@ -2410,3 +2410,80 @@ def get_site_config_standard_keys():
|
||||
["name", "key", "title", "description", "type"],
|
||||
order_by="title asc",
|
||||
)
|
||||
|
||||
|
||||
@jingrow.whitelist()
|
||||
def check_app_installable(name, app):
|
||||
"""检查站点是否有权限安装指定的应用
|
||||
|
||||
Args:
|
||||
name: 站点名称
|
||||
app: 应用名称
|
||||
|
||||
Returns:
|
||||
dict: 包含是否可安装的信息
|
||||
{
|
||||
"installable": True/False,
|
||||
"required_plan_level": 1-5, # 如果不可安装
|
||||
"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)
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
"allow_guest_to_view": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2022-02-04 19:53:27.058972",
|
||||
"pagetype": "PageType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
@ -16,6 +15,7 @@
|
||||
"section_break_7",
|
||||
"jingrow_approved",
|
||||
"subscription_type",
|
||||
"subscription_level",
|
||||
"column_break_10",
|
||||
"categories",
|
||||
"published",
|
||||
@ -388,6 +388,15 @@
|
||||
"fieldtype": "Table",
|
||||
"label": "Localisation Apps",
|
||||
"options": "Marketplace Localisation App"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "subscription_level",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Subscription Level",
|
||||
"options": "1\n2\n3\n4\n5"
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
@ -397,25 +406,26 @@
|
||||
"links": [
|
||||
{
|
||||
"group": "General",
|
||||
"link_pagetype": "App Release Approval Request",
|
||||
"link_fieldname": "marketplace_app"
|
||||
"link_fieldname": "marketplace_app",
|
||||
"link_pagetype": "App Release Approval Request"
|
||||
},
|
||||
{
|
||||
"group": "App Subscription",
|
||||
"link_pagetype": "Marketplace App Plan",
|
||||
"link_fieldname": "app"
|
||||
"link_fieldname": "app",
|
||||
"link_pagetype": "Marketplace App Plan"
|
||||
},
|
||||
{
|
||||
"group": "App Subscription",
|
||||
"link_pagetype": "Marketplace App Subscription",
|
||||
"link_fieldname": "app"
|
||||
"link_fieldname": "app",
|
||||
"link_pagetype": "Marketplace App Subscription"
|
||||
}
|
||||
],
|
||||
"modified": "2025-02-13 17:16:24.333531",
|
||||
"modified": "2025-04-22 19:06:40.765966",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Jcloud",
|
||||
"name": "Marketplace App",
|
||||
"owner": "Administrator",
|
||||
"pagetype": "PageType",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
@ -430,6 +440,7 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [
|
||||
|
||||
@ -37,18 +37,11 @@ class MarketplaceApp(WebsiteGenerator):
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from jingrow.types import DF
|
||||
|
||||
from jcloud.jcloud.pagetype.marketplace_app_categories.marketplace_app_categories import (
|
||||
MarketplaceAppCategories,
|
||||
)
|
||||
from jcloud.jcloud.pagetype.marketplace_app_screenshot.marketplace_app_screenshot import (
|
||||
MarketplaceAppScreenshot,
|
||||
)
|
||||
from jcloud.jcloud.pagetype.marketplace_app_categories.marketplace_app_categories import MarketplaceAppCategories
|
||||
from jcloud.jcloud.pagetype.marketplace_app_screenshot.marketplace_app_screenshot import MarketplaceAppScreenshot
|
||||
from jcloud.jcloud.pagetype.marketplace_app_version.marketplace_app_version import MarketplaceAppVersion
|
||||
from jcloud.jcloud.pagetype.marketplace_localisation_app.marketplace_localisation_app import (
|
||||
MarketplaceLocalisationApp,
|
||||
)
|
||||
from jcloud.jcloud.pagetype.marketplace_localisation_app.marketplace_localisation_app import MarketplaceLocalisationApp
|
||||
from jingrow.types import DF
|
||||
|
||||
after_install_script: DF.Code | None
|
||||
after_uninstall_script: DF.Code | None
|
||||
@ -58,8 +51,8 @@ class MarketplaceApp(WebsiteGenerator):
|
||||
custom_verify_template: DF.Check
|
||||
description: DF.SmallText
|
||||
documentation: DF.Data | None
|
||||
jingrow_approved: DF.Check
|
||||
image: DF.AttachImage | None
|
||||
jingrow_approved: DF.Check
|
||||
localisation_apps: DF.Table[MarketplaceLocalisationApp]
|
||||
long_description: DF.TextEditor | None
|
||||
message: DF.TextEditor | None
|
||||
@ -68,15 +61,7 @@ class MarketplaceApp(WebsiteGenerator):
|
||||
poll_method: DF.Data | None
|
||||
privacy_policy: DF.Data | None
|
||||
published: DF.Check
|
||||
review_stage: DF.Literal[
|
||||
"Not Started",
|
||||
"Description Missing",
|
||||
"Logo Missing",
|
||||
"App Release Not Reviewed",
|
||||
"Ready for Review",
|
||||
"Ready to Publish",
|
||||
"Rejected",
|
||||
]
|
||||
review_stage: DF.Literal["Not Started", "Description Missing", "Logo Missing", "App Release Not Reviewed", "Ready for Review", "Ready to Publish", "Rejected"]
|
||||
route: DF.Data | None
|
||||
run_after_install_script: DF.Check
|
||||
run_after_uninstall_script: DF.Check
|
||||
@ -88,6 +73,7 @@ class MarketplaceApp(WebsiteGenerator):
|
||||
status: DF.Literal["Draft", "Published", "In Review", "Attention Required", "Rejected", "Disabled"]
|
||||
stop_auto_review: DF.Check
|
||||
subject: DF.Data | None
|
||||
subscription_level: DF.Literal["1", "2", "3", "4", "5"]
|
||||
subscription_type: DF.Literal["Free", "Paid", "Freemium"]
|
||||
subscription_update_hook: DF.Data | None
|
||||
support: DF.Data | None
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
"column_break_5",
|
||||
"price_cny",
|
||||
"price_usd",
|
||||
"plan_level",
|
||||
"allow_downgrading_from_other_plan",
|
||||
"features_section",
|
||||
"cpu_time_per_day",
|
||||
@ -235,11 +236,18 @@
|
||||
"fieldname": "allow_downgrading_from_other_plan",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow Downgrading From Other Plan"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "plan_level",
|
||||
"fieldtype": "Select",
|
||||
"label": "Plan Level",
|
||||
"options": "1\n2\n3\n4\n5"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-04-20 20:46:00.570720",
|
||||
"modified": "2025-04-22 18:40:33.565094",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Jcloud",
|
||||
"name": "Site Plan",
|
||||
|
||||
@ -39,6 +39,7 @@ class SitePlan(Plan):
|
||||
memory: DF.Int
|
||||
monitor_access: DF.Check
|
||||
offsite_backups: DF.Check
|
||||
plan_level: DF.Literal["1", "2", "3", "4", "5"]
|
||||
plan_title: DF.Data | None
|
||||
price_cny: DF.Currency
|
||||
price_usd: DF.Currency
|
||||
@ -52,6 +53,7 @@ class SitePlan(Plan):
|
||||
dashboard_fields = (
|
||||
"name",
|
||||
"plan_title",
|
||||
"plan_level",
|
||||
"interval",
|
||||
"document_type",
|
||||
"document_name",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user