已安装app后增加卸载按钮

This commit is contained in:
jingrow 2025-06-30 12:45:25 +08:00
parent 07133169da
commit d14334fe03
6 changed files with 2997 additions and 2947 deletions

View File

@ -109,7 +109,65 @@ function getAppsTabColumns(forSite: boolean) {
}
];
if (forSite) return appTabColumns;
// 为站点应用添加操作列,包含卸载按钮
if (forSite) {
appTabColumns.push({
label: '操作',
width: 0.75,
align: 'right',
type: 'Button',
Button: ({ row, listResource, documentResource }) => {
// 如果是 jingrow 应用,不显示卸载按钮
if (row.app === 'jingrow') {
return null;
}
return {
label: '卸载',
variant: 'ghost',
class: 'text-red-600 hover:text-red-700 hover:bg-red-50',
slots: {
prefix: icon('trash-2')
},
onClick: () => {
const appName = row.title || row.app_title;
const dialogConfig: DialogConfig = {
title: `卸载应用`,
message: `您确定要从站点 <b>${documentResource.pg?.name}</b> 卸载应用 <b>${appName}</b> 吗?<br>
`,
onSuccess({ hide }) {
// 立即从列表中移除该应用(乐观更新)
const currentData = listResource.data || [];
const updatedData = currentData.filter(item => item.name !== row.name);
listResource.data = updatedData;
const promise = documentResource.uninstallApp.submit({
app: row.app
});
toast.promise(promise, {
loading: '正在安排应用卸载...',
success: (jobId: string) => {
hide();
return '应用卸载已安排';
},
error: (e: Error) => {
// 如果失败,重新加载列表恢复状态
listResource.reload();
return getToastErrorMessage(e);
}
});
}
};
confirmDialog(dialogConfig);
}
};
}
});
return appTabColumns;
}
return appTabColumns.filter(c => c.label !== '计划');
}
@ -175,12 +233,12 @@ const siteAppListOptions: Partial<TabList> = {
label: '卸载',
condition: () => row.app !== 'jingrow',
onClick() {
const appName = row.title || row.app_title;
const dialogConfig: DialogConfig = {
title: `卸载应用`,
message: `您确定要从站点 <b>${site.pg?.name}</b> 卸载应用 <b>${row.title}</b> 吗?<br>
message: `您确定要从站点 <b>${site.pg?.name}</b> 卸载应用 <b>${appName}</b> 吗?<br>
`,
onSuccess({ hide }) {
if (site.uninstallApp.loading) return;
toast.promise(
site.uninstallApp.submit({
app: row.app
@ -189,16 +247,12 @@ const siteAppListOptions: Partial<TabList> = {
loading: '正在安排应用卸载...',
success: (jobId: string) => {
hide();
router.push({
name: 'Site Job',
params: {
name: site.name,
id: jobId
}
});
apps.reload();
return '应用卸载已安排';
},
error: (e: Error) => getToastErrorMessage(e)
error: (e: Error) => {
return getToastErrorMessage(e);
}
}
);
}

View File

@ -113,6 +113,19 @@ export interface ColumnField {
suffix?: (row: Row) => Component | undefined;
theme?: (value: unknown) => string;
align?: 'left' | 'right';
Button?: (r: {
row: Row;
listResource: ListResource;
documentResource: DocumentResource;
}) => {
label: string;
variant?: string;
class?: string;
slots?: {
prefix?: Icon;
};
onClick?: () => void;
} | null;
}
export type Row = Record<string, any>;
@ -186,8 +199,7 @@ interface Option {
export interface BannerConfig {
title: string;
}
dismissable: boolean;
dismissable: boolean;
id: string;
type?: string;
button?: {

View File

@ -22,6 +22,7 @@ import { trialDays } from '../utils/site';
import { clusterOptions, getUpsellBanner } from './common';
import { getAppsTab } from './common/apps';
import { isMobile } from '../utils/device';
import { getJobsTab } from './common/jobs';
export default {
pagetype: 'Site',
@ -881,6 +882,7 @@ export default {
},
},
},
getJobsTab('Site'),
{
label: '操作',
icon: icon('sliders'),
@ -1340,5 +1342,10 @@ export default {
path: 'updates/:id',
component: () => import('../pages/SiteUpdate.vue'),
},
{
name: 'Site Job',
path: 'jobs/:id',
component: () => import('../pages/JobPage.vue')
}
],
};

File diff suppressed because it is too large Load Diff

View File

@ -299,7 +299,7 @@ class Site(Document, TagHelpers):
status = jingrow.get_value(inst.pagetype, inst.name, "status", for_update=True)
if status not in allowed_status:
jingrow.throw(
f"Site action not allowed for site with status: {jingrow.bold(status)}.\nAllowed status are: {jingrow.bold(comma_and(allowed_status))}."
f"不允许对状态为 {jingrow.bold(status)} 的站点执行此操作。\n允许的状态为:{jingrow.bold(comma_and(allowed_status))}"
)
return func(inst, *args, **kwargs)

1094
yarn.lock

File diff suppressed because it is too large Load Diff