import { type ActiveRecord, Dialog, executeViewAction, FunctionMetadata, ModelCache, ModuleCache, type Pagination, type QueryContext, type QueryVariables, RedirectTargetEnum, type RuntimeAction, type RuntimeModelField, type RuntimeViewAction, translateValueByKey, ViewCache } from '@oinone/kunlun-engine'; import { type IModelField, ViewType } from '@oinone/kunlun-meta'; import { Condition } from '@oinone/kunlun-request'; import { customQueryPage, DEFAULT_TRUE_CONDITION, EDirection, getModel, http, insertOne, IQueryPageResult, ISort, updateOne } from '@oinone/kunlun-service'; import { CastHelper } from '@oinone/kunlun-shared'; import { SPI } from '@oinone/kunlun-spi'; import { appFinderSymbol } from '@oinone/kunlun-vue-admin-layout'; import { OioNotification } from '@oinone/kunlun-vue-ui-antd'; import { Widget, type WidgetSubjection } from '@oinone/kunlun-vue-widget'; import { BaseElementListViewWidget, BaseElementWidget } from '../../../basic'; import { createRuntimeContextForWidget } from '../../../tags'; import { onJumpCodeFuse, onJumpModelDesigner, onJumpUiDesignerHomePage } from '../../../util'; import { FormWidget } from '../../form'; import GalleryVue from './Gallery.vue'; import { AppBindType, appQueryOne, BindAppHomepageForm, BindAppHomepageFormXml, bindHomePageByMenu, bindHomePageByURL, bindHomePageByView, CreateAppForm, CreateAppFormXml, EditAppModelModel, uninstallAppFun, UpdateAppForm, UpdateAppFormXml } from './service'; import { type ActionPermission, AppState, AppStateDisplayNameENum } from './type'; @SPI.ClassFactory(BaseElementWidget.Token({ widget: 'AppsGallery' })) export class AppsGalleryWidget extends BaseElementListViewWidget { public initialize(props) { super.initialize(props); this.setComponent(GalleryVue); return this; } private disableClick = ['logic_designer', 'model_designer', 'data_designer', 'ui_designer', 'workflow_designer']; private createAppDialogFormWidget!: FormWidget | undefined; private updateAppDialogFormWidget!: FormWidget | undefined; private bindAppHomepageDialogFormWidget!: FormWidget | undefined; @Widget.Reactive() private moduleCategory = []; @Widget.SubContext(appFinderSymbol) private reloadAppFinder$!: WidgetSubjection; @Widget.Reactive() protected get defaultPageSize(): number { return 30; } @Widget.Reactive() protected get modelActions() { const actions = this.metadataRuntimeContext.viewDsl?.widgets.find((w) => w.slot === 'actions'); if (!actions) { return []; } return actions.widgets as unknown as RuntimeAction[]; } @Widget.Reactive() protected get actionPermission(): ActionPermission { const CreateAppAction = this.modelActions.find((a) => a.name === 'create' && !!a.actionType); const UpdateAppAction = this.modelActions.find((a) => a.name === 'update' && !!a.actionType); const UninstallAction = this.modelActions.find((a) => a.name === 'uninstall' && !!a.actionType); const InstallAction = this.modelActions.find((a) => a.name === 'install' && !!a.actionType); const BindHomepageAction = this.modelActions.find((a) => a.name === 'bindHomePage' && !!a.actionType); const DetailAction = this.modelActions.find((a) => a.name === 'apps_business_screen_detail' && !!a.actionType); const LikeAction = this.modelActions.find((a) => a.name === 'like' && !!a.actionType); const UnLikeAction = this.modelActions.find((a) => a.name === 'unLike' && !!a.actionType); const ModelDesignerAction = this.modelActions.find( (a) => a.name === 'homepage' && a.model === 'designer.DesignerModelDefinition' && !!a.actionType ); const UiDesignerAction = this.modelActions.find( (a) => a.name === 'homepage' && a.model === 'ui.designer.UiDesignerView' && !!a.actionType ); const PaasAction = this.modelActions.find((a) => a.name === 'PaasMenus_Menu_LowCodeMenu' && !!a.actionType); return { hasCreateAppAction: !!CreateAppAction, hasUpdateAppAction: !!UpdateAppAction, hasUninstallAction: !!UninstallAction, hasInstallAction: !!InstallAction, hasBindHomepageAction: !!BindHomepageAction, hasDetailAction: !!DetailAction, hasLikeAction: !!LikeAction, hasUnLikeAction: !!UnLikeAction, hasModelDesignerAction: !!ModelDesignerAction, hasUiDesignerAction: !!UiDesignerAction, hasPaasAction: !!PaasAction }; } // #region 导出动作 @Widget.Reactive() protected get hasExportAction() { const actionNames = Object.keys(this.exportAction); return actionNames.some((name) => !!this.exportAction[name]); } @Widget.Reactive() protected get exportAction() { return { exportModelAction: this.modelActions.find( (a) => a.name === 'modelDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportUiAction: this.modelActions.find( (a) => a.name === 'uiDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportWorkFlowAction: this.modelActions.find( (a) => a.name === 'wfDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportEipAction: this.modelActions.find( (a) => a.name === 'eipDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportDataAction: this.modelActions.find( (a) => a.name === 'dataDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportMicroFlowAction: this.modelActions.find( (a) => a.name === 'mfDesignerDialog' && !!a.actionType ) as RuntimeViewAction, exportPrintAction: this.modelActions.find( (a) => a.name === 'printDesignerDialog' && !!a.actionType ) as RuntimeViewAction }; } // #endregion // #region 导入动作 @Widget.Reactive() protected get hasImportAction() { const actionNames = Object.keys(this.importAction); return actionNames.some((name) => !!this.importAction[name]); } @Widget.Reactive() protected get importAction() { return { importModelAction: this.modelActions.find( (a) => a.name === 'modelDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importUiAction: this.modelActions.find( (a) => a.name === 'uiDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importWorkFlowAction: this.modelActions.find( (a) => a.name === 'wfDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importEipAction: this.modelActions.find( (a) => a.name === 'eipDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importDataAction: this.modelActions.find( (a) => a.name === 'dataDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importMicroFlowAction: this.modelActions.find( (a) => a.name === 'mfDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction, importPrintAction: this.modelActions.find( (a) => a.name === 'printDesignerImportDialog' && !!a.actionType ) as RuntimeViewAction }; } // #endregion // #region 同步部署动作 @Widget.Reactive() protected get hasSyncAction() { const actionNames = Object.keys(this.syncAction); return actionNames.some((name) => !!this.syncAction[name]); } @Widget.Reactive() protected get syncAction() { return { syncModelAction: this.modelActions.find( (a) => a.name === 'modelDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncUiAction: this.modelActions.find( (a) => a.name === 'uiDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncWorkFlowAction: this.modelActions.find( (a) => a.name === 'wfDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncEipAction: this.modelActions.find( (a) => a.name === 'eipDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncDataAction: this.modelActions.find( (a) => a.name === 'dataDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncMicroFlowAction: this.modelActions.find( (a) => a.name === 'mfDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction, syncPrintAction: this.modelActions.find( (a) => a.name === 'printDesignerSyncDialog' && !!a.actionType ) as RuntimeViewAction }; } // #endregion @Widget.Reactive() protected get moreActions() { return [ { displayName: translateValueByKey('编辑'), icon: 'oinone-jiemiansheji1', hasBorderBottom: true, visible: (record) => record.systemSource === 'UI' && this.actionPermission.hasUpdateAppAction, exe: (record) => { this.clickUpdateViewAction(record); } }, { displayName: translateValueByKey('卸载'), icon: 'oinone-jiemiansheji1', hasBorderBottom: true, visible: (record) => record.state === AppState.INSTALLED && this.actionPermission.hasUninstallAction, exe: async (record) => { const result = await uninstallAppFun(record.id); if (result.state) { record.state = result.state; } } }, { displayName: translateValueByKey('设置首页'), icon: 'oinone-jiemiansheji1', visible: (record) => record.state === AppState.INSTALLED && record.application && this.actionPermission.hasBindHomepageAction, exe: (record) => { this.clickBindHomepageViewAction(record); } }, { displayName: translateValueByKey('设计页面'), icon: 'oinone-shejiyemian', visible: (record) => record.application && !this.disableClick.includes(record.module) && record.systemSource === 'UI' && this.actionPermission.hasUiDesignerAction, exe: (record) => { onJumpUiDesignerHomePage(record); } }, { displayName: translateValueByKey('设计模型'), icon: 'oinone-shejimoxing', visible: (record) => !this.disableClick.includes(record.module) && this.actionPermission.hasModelDesignerAction, exe: (record) => { onJumpModelDesigner(record, 'graph'); } }, { displayName: translateValueByKey('低无一体'), icon: 'oinone-diwuyiti', hasBorderBottom: true, visible: (record) => record.systemSource !== 'BASE' && this.actionPermission.hasPaasAction, exe: (record) => { onJumpCodeFuse(record.id); } }, { displayName: translateValueByKey('设计导入(迁移)'), icon: 'oinone-a-shejidaoru4x', visible: (record) => this.hasImportAction && record.state === AppState.INSTALLED, exe: () => {}, children: [ { displayName: translateValueByKey('模型导入'), icon: 'oinone-a-moxingdaoru3x', visible: (record) => !!this.importAction.importModelAction, exe: (record) => { executeViewAction(this.importAction.importModelAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('界面导入'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.importAction.importUiAction, exe: (record) => { executeViewAction(this.importAction.importUiAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('流程导入'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.importAction.importWorkFlowAction, exe: (record) => { executeViewAction(this.importAction.importWorkFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('微流导入'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.importAction.importMicroFlowAction, exe: (record) => { executeViewAction(this.importAction.importMicroFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('集成导入'), icon: 'oinone-a-jichengdaoru2x', visible: (record) => !!this.importAction.importEipAction, exe: (record) => { executeViewAction(this.importAction.importEipAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('数据可视化导入'), icon: 'oinone-a-shujukeshihuadaoru2x', visible: (record) => !!this.importAction.importDataAction, exe: (record) => { executeViewAction(this.importAction.importDataAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('打印导入'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.importAction.importPrintAction, exe: (record) => { executeViewAction(this.importAction.importPrintAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } } ] }, { displayName: translateValueByKey('设计导出'), icon: 'oinone-a-shejidaochu4x', visible: (record) => this.hasExportAction && record.state === AppState.INSTALLED, exe: () => {}, children: [ { displayName: translateValueByKey('模型导出'), icon: 'oinone-a-moxingdaoru3x', visible: (record) => !!this.exportAction.exportModelAction, exe: (record) => { executeViewAction(this.exportAction.exportModelAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('界面导出'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.exportAction.exportUiAction, exe: (record) => { executeViewAction(this.exportAction.exportUiAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('流程导出'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.exportAction.exportWorkFlowAction, exe: (record) => { executeViewAction(this.exportAction.exportWorkFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('微流导出'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.exportAction.exportMicroFlowAction, exe: (record) => { executeViewAction(this.exportAction.exportMicroFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('集成导出'), icon: 'oinone-a-jichengdaoru2x', visible: (record) => !!this.exportAction.exportEipAction, exe: (record) => { executeViewAction(this.exportAction.exportEipAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('数据可视化导出'), icon: 'oinone-a-shujukeshihuadaoru2x', visible: (record) => !!this.exportAction.exportDataAction, exe: (record) => { executeViewAction(this.exportAction.exportDataAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('打印导出'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.exportAction.exportPrintAction, exe: (record) => { executeViewAction(this.exportAction.exportPrintAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } } ] }, { displayName: translateValueByKey('同步部署'), icon: 'oinone-a-tongbubushu4x', visible: (record) => this.hasSyncAction && record.state === AppState.INSTALLED, exe: () => {}, children: [ { displayName: translateValueByKey('模型部署'), icon: 'oinone-a-moxingdaoru3x', visible: (record) => !!this.syncAction.syncModelAction, exe: (record) => { executeViewAction(this.syncAction.syncModelAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('界面部署'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.syncAction.syncUiAction, exe: (record) => { executeViewAction(this.syncAction.syncUiAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('流程部署'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.syncAction.syncWorkFlowAction, exe: (record) => { executeViewAction(this.syncAction.syncWorkFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('微流部署'), icon: 'oinone-a-liuchengdaoru2x', visible: (record) => !!this.syncAction.syncMicroFlowAction, exe: (record) => { executeViewAction(this.syncAction.syncMicroFlowAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('集成部署'), icon: 'oinone-a-jichengdaoru2x', visible: (record) => !!this.syncAction.syncEipAction, exe: (record) => { executeViewAction(this.syncAction.syncEipAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('数据可视化部署'), icon: 'oinone-a-shujukeshihuadaoru2x', visible: (record) => !!this.syncAction.syncDataAction, exe: (record) => { executeViewAction(this.syncAction.syncDataAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } }, { displayName: translateValueByKey('打印部署'), icon: 'oinone-a-jiemiandaoru2x', visible: (record) => !!this.syncAction.syncPrintAction, exe: (record) => { executeViewAction(this.syncAction.syncPrintAction!, undefined, undefined, { module: record.module, moduleName: record.displayName }); } } ] }, { displayName: translateValueByKey('了解更多'), icon: 'oinone-gengduo', visible: (record) => this.actionPermission.hasDetailAction, exe: async (record) => { const model = await getModel('apps.AppsManagementModule'); const action = model?.viewActionList?.filter((v) => v.name === 'apps_business_screen_detail')[0]; if (action) { executeViewAction( CastHelper.cast(action), undefined, undefined, { appsManagementModule: {}, id: record.id, state: record.state }, RedirectTargetEnum.BLANK ); } } } ]; } @Widget.Method() private async onLikeApp(module: string) { const body = `mutation { appSwitcherModuleProxyMutation { like(modules: [{ module: "${module}" }]) { id } } }`; await http.query('base', body); } @Widget.Method() private async onUnLikeApp(module: string) { const body = `mutation { appSwitcherModuleProxyMutation { unLike(modules: [{ module: "${module}" }]) { id } } }`; await http.query('base', body); } private async fetchTree({ displayName = '', like = 'ALL', status = 'ALL' }) { const body = `query { appsModuleCategoryProxyQuery { fetchCateTree(data: {displayName: "${displayName || ''}", like: ${like}, status: ${status} }) { id code name moduleNum sequence children { id name moduleNum code sequence } } } }`; const result = (await http.query('base', body)) as any; const arr = result.data.appsModuleCategoryProxyQuery.fetchCateTree || []; this.moduleCategory = arr .reduce((p, n) => { const children = n.children || []; return p.concat(...children); }, []) .sort((a, b) => a.sequence - b.sequence); } @Widget.Method() private async onChangeCategory(code?: string) { const pagination = this.generatorPagination(); pagination.current = 1; if (code) { this.refreshProcess(new Condition('category').equal(code)); } else { this.refreshProcess(); } } public async queryPage( condition: Condition, pagination: Pagination, sort: ISort[], variables: QueryVariables, context: QueryContext ): Promise> { const requestFields: IModelField[] = CastHelper.cast( ((await ModelCache.get(this.model.model))?.modelFields as RuntimeModelField[])?.filter((f) => [ 'id', 'displayName', 'name', 'module', 'latestVersion', 'application', 'platformVersion', 'logo', 'canUpgrade', 'state', 'status', 'like', 'homepageViewId', 'homepageViewSystemSource', 'homePageModel', 'moduleCategory', 'description', 'systemSource' ].includes(f.data) ) || [] ); const result = await customQueryPage( this.loadFunctionNamespace, this.loadFunctionFun || FunctionMetadata.QUERY_PAGE_NAME, { currentPage: pagination.current, pageSize: this.showPagination ? pagination.pageSize : -1, sort: { sortField: 'createDate', direction: EDirection.DESC }, condition: condition.toString() === DEFAULT_TRUE_CONDITION ? '' : condition }, requestFields, requestFields, variables, context ); this.fetchTree((this.searchBody || {}) as any); result.content?.forEach((a: any) => { a.stateDisplayName = translateValueByKey(AppStateDisplayNameENum[a.state] || ''); }); return result; } @Widget.Method() public async clickCreateViewAction() { this.initAppFormWidget( this.createAppDialogFormWidget, {}, CreateAppForm, CreateAppFormXml, translateValueByKey('创建'), async (data) => { await insertOne(EditAppModelModel, data, undefined); this.refreshCallChaining?.syncCall(); this.reloadAppFinder$.subject.next(true); OioNotification.success(translateValueByKey('成功'), translateValueByKey('创建成功')); } ); } @Widget.Method() public async clickUpdateViewAction(record) { let data = {} as Record; if (record.id) { data = await appQueryOne(record.id); } this.initAppFormWidget( this.updateAppDialogFormWidget, data, UpdateAppForm, UpdateAppFormXml, translateValueByKey('编辑'), async (e) => { await updateOne(EditAppModelModel, e, undefined); this.refreshCallChaining?.syncCall(); OioNotification.success(translateValueByKey('成功'), translateValueByKey('更新成功')); } ); } @Widget.Method() public async clickBindHomepageViewAction(record) { let data = {} as Record; if (record.id) { data = await appQueryOne(record.id); } const { name: moduleName, homePageModel, homePageName } = data; let bindType: AppBindType = AppBindType.MENU; if (homePageModel && homePageName) { const moduleDefinition = await ModuleCache.get(moduleName); const bindHomePageMenu = moduleDefinition?.allMenus?.find((v) => { const { viewAction } = v; if (!viewAction) { return false; } const { model, name } = viewAction; return homePageModel === model && homePageName === name; }); if (bindHomePageMenu) { data.bindHomePageMenu = bindHomePageMenu; data.bindHomePageModel = undefined; data.bindHomePageView = undefined; } } if (data.urlHomePage) { bindType = AppBindType.URL; data.bindHomePageModel = undefined; data.bindHomePageView = undefined; } else if (data.bindHomePageModel && data.bindHomePageView) { bindType = AppBindType.VIEW; } this.initAppFormWidget( this.bindAppHomepageDialogFormWidget, { ...data, bindType }, BindAppHomepageForm, BindAppHomepageFormXml, translateValueByKey('设置首页'), async (result) => { if (result.bindType === 'MENU') { await bindHomePageByMenu(result.id, result.bindHomePageMenu?.id); OioNotification.success(translateValueByKey('成功'), translateValueByKey('绑定菜单成功')); } else if (result.bindType === 'VIEW') { await bindHomePageByView(result.id, result.bindHomePageView?.id); OioNotification.success(translateValueByKey('成功'), translateValueByKey('绑定视图成功')); } else if (result.bindType === 'URL') { await bindHomePageByURL(result.id, result.urlHomePage.url, result.urlHomePage.target); OioNotification.success(translateValueByKey('成功'), translateValueByKey('绑定链接成功')); } } ); } @Widget.Method() public async bindAppHomepage() { return true; } public isPending = false; public async initAppFormWidget(widget, initData, viewName, xml, title, confirmFun) { if (this.isPending) { return; } try { this.isPending = true; if (widget) { widget.dispose(); } const resView = await ViewCache.compile(EditAppModelModel, viewName, xml); if (!resView) { return; } resView.type = ViewType.Form; const runtimeContext = createRuntimeContextForWidget(resView!); const runtimeContextHandle = runtimeContext.handle; const dialogWidget = Dialog.create(); dialogWidget.setWidth(600); dialogWidget.on('ok', async () => { const result = await widget?.validator(); if (result) { await confirmFun(widget?.getData()); dialogWidget.onVisibleChange(false); } }); dialogWidget.on('cancel', () => { dialogWidget.onVisibleChange(false); }); widget = dialogWidget.createWidget(FormWidget, undefined, { metadataHandle: runtimeContextHandle, rootHandle: runtimeContextHandle, template: runtimeContext.viewTemplate, dataSource: initData, activeRecords: initData, inline: true }); dialogWidget.setTitle(title); dialogWidget.onVisibleChange(true); } finally { this.isPending = false; } } protected async mounted() { getModel(EditAppModelModel); ViewCache.compile(EditAppModelModel, CreateAppForm, CreateAppFormXml); ViewCache.compile(EditAppModelModel, UpdateAppForm, UpdateAppFormXml); ViewCache.compile(EditAppModelModel, BindAppHomepageForm, BindAppHomepageFormXml); } } export default AppsGalleryWidget;