import { IController, ICtrlAbility, IDECtrlAbility, IParam, IViewLogicInput, getRouteParams, srfFilePath2, IViewEvent, IViewAbility, IViewStore, IMDViewAbility, IMDViewStore, IPickupViewStore, IPickupViewAbility, IMPickupViewStore, IMPickupViewAbility, IOptViewStore, IOptViewAbility, IExpViewModel, computedNavData, IExpViewStore, IExpViewAbility, deepCopy, IEvent, IMPickupView2Model } from '@/core'; import { IExpViewController, IMDViewController, IMPickupViewController, IOptViewController, IPickupViewController, IViewController, } from '@/core/interface/view/controller'; import { IViewModel } from '@/core/interface/view/model/i-view-model'; import { useAppStoreWithOut, useViewActionStoreWithOut, useViewCtxStoreWithOut, } from '@/store'; import { formatRouteParams } from '@/utils'; import { createUUID, isNilOrEmpty, QXEvent } from 'qx-util'; import { useRoute } from 'vue-router'; /** * 计算导航参数 * * @param {IViewController} controller * @param {IParam} props */ function computeNavParams( controller: IViewController, props: IParam ) { const model = controller.getModel(); const { context, viewParams } = useViewParams(model, props); const viewCtx = useViewCtx(context, viewParams, model, props, controller); controller.setNavParams(context, viewParams, viewCtx); onActivated(() => { Object.assign(viewParams, { srfactivatedtime: Date.now() }) controller.setNavParams(context, viewParams, viewCtx); }) } /** * 计算视图参数 * * @export * @param {IParam} model * @param {IParam} props * @return {*} {{ context: IParam; viewParams: IParam }} */ export function useViewParams( model: IParam, props: IParam ): { context: IParam; viewParams: IParam } { const { getAppData: appData } = useAppStoreWithOut(); const { context: propContext, viewParams: propViewParams, openType } = props; // 应用上下文 const context: IParam = {}; // 视图参数 const viewParams: IParam = {}; // 非路由模式视图(包含模态,嵌入) if (openType !== 'ROUTE') { Object.assign(context, propContext); Object.assign(viewParams, propViewParams); if ( isNilOrEmpty(context.srfsessionid) && isNilOrEmpty(context.srfsessionkey) ) { context.srfsessionid = createUUID(); } if (context && context.srfparentdename) { Object.assign(viewParams, { srfparentdename: context.srfparentdename }); } if (context && context.srfparentkey) { Object.assign(viewParams, { srfparentkey: context.srfparentkey }); } } else { Object.assign(context, appData && appData.context ? appData.context : {}); const { fullPath, params, matched } = useRoute(); // 应用级参数 const appRouteParams = getRouteParams(window.location.href); Object.assign(context, appRouteParams); // 应用起始页合并自己一级路由的路由参数,其他视图正常合并 if (Object.is(model.viewType, 'APPINDEXVIEW') && model.defaultPage) { if (matched.length == 1) { formatRouteParams(params, fullPath, context, viewParams); } } else { formatRouteParams(params, fullPath, context, viewParams); } // 定义顶层视图srfsessionid context.srfsessionid = createUUID(); } // 计算自定义参数 const appViewConfig = App.getAppViewConfig(); const view = appViewConfig[model.codeName]; if ( view && view.navigateContext && Object.keys(view.navigateContext).length > 0 ) { const localContext = computedNavData( {}, context, viewParams, view.navigateContext ); Object.assign(context, localContext); } if ( view && view.navigateParams && Object.keys(view.navigateParams).length > 0 ) { const localViewParam = computedNavData( {}, context, viewParams, view.navigateParams ); Object.assign(viewParams, localViewParam); } return { context, viewParams }; } /** * 计算视图操作参数 * * @export * @param {IParam} context * @param {IParam} viewParam */ export function useViewCtx( context: IParam, viewParam: IParam, model: IParam, props: IParam, control: IViewController, ) { const viewCtx: IParam = {}; const { openType } = props; // 应用全局数据对象 const { getAppGlobal, getRouteViewGlobal, setRouteViewGlobal, setView, getView } = useViewCtxStoreWithOut(); viewCtx['appGlobal'] = getAppGlobal(); if (openType === 'ROUTE') { setRouteViewGlobal(context.srfsessionid, {}); setView(context.srfsessionid, control); } // 路由视图全局数据对象(嵌入视图可共享) viewCtx['routeViewGlobal'] = getRouteViewGlobal(); if(context && context.parentviewid){ viewCtx['parentView'] = getView(context.parentviewid); } // 顶级视图 viewCtx['rootView'] = getView(context.srfsessionid); // 父视图id const parentviewid = createUUID(); setView(parentviewid, control); // 当前上下文的父视图id context.parentviewid = parentviewid; return viewCtx; } /** * 导航参数绑定 * * @export * @param {IViewController} controller * @param {IParam} props */ export function useNavParamsBind( controller: IViewController, props: IParam ) { watch( () => props.context, () => { computeNavParams(controller, props); }, { immediate: true } ); watch( () => props.viewParams, () => { computeNavParams(controller, props); }, { immediate: true } ); } /** * 视图事件绑定 * * @export * @template T * @template A * @param {Function} emit * @return {*} {QXEvent>} */ export function useEventBind( emit: Function ): QXEvent> { const evt = new QXEvent>(); // 绑定事件回调 evt.on('viewAction', (controlName: string, action: T, data: any) => { emit('view-action', controlName, action, data); }); evt.on('viewInit', (controlName: string, data: A) => { emit('view-init', controlName, data); }); evt.on('viewMounted', (controlName: string, data: IParam) => { emit('view-mounted', controlName, data); }); evt.on('viewDestroy', (controlName: string, data: IParam) => { emit('view-destroy', controlName, data); }); return evt; } /** * 工具栏点击 * * @export * @param {IViewController} controller * @param {string} name * @param {MouseEvent} event * @param {IParam} [logic] * @return {*} */ export function handleToolbarItemClick( controller: IController, name: string, event: MouseEvent, logic?: IViewLogicInput ) { if (!logic) { console.warn('无事件逻辑'); return; } const model = controller.getModel(); if (!logic.xDataCtrlName) { console.warn('无数据目标部件'); } else { // 触发源为部件 if (model?.name?.toLowerCase() === logic.xDataCtrlName.toLowerCase()) { // TOTO } // 触发源为视图 else { // 获取参数 const { context, viewParams } = controller.getStore(); const tempContext = deepCopy(context); const tempViewParams = deepCopy(viewParams); // 获取能力 let ability: any = controller.getSubAbility( logic.xDataCtrlName.toLowerCase() ) as IDECtrlAbility; const ctrl = ability.controller; // 获取数据 const data: IParam[] = ability.getData(); // 特殊识别,导出时合并导出参数 if (logic.actionTag === 'ExportExcel') { Object.assign(tempViewParams, { srfactionparams: { type: (logic as IParam).type, startPage: (logic as IParam).startPage, endPage: (logic as IParam).endPage, }, }); } // 特殊识别,当行为标识为ToggleFilter时,使用视图能力 if (logic.actionTag === 'ToggleFilter') { ability = controller.getAbility(); } Object.assign(ability.viewCtx, { ctrl }); // 执行视图逻辑 App.getViewLogicHelper().executeViewLogic( tempContext, tempViewParams, data, event, ability, logic ); } } } /** * 处理部件初始化 * * @export * @template C * @param {C} controller 控制器 * @param {string} name 部件名称 * @param {ICtrlAbility} ability 部件能力 */ export function handleCtrlInit< C extends IViewController, A extends ICtrlAbility >(controller: C, name: string, ability: A) { controller.handleCtrlInit(name, ability); } /** * 处理部件行为 * * @export * @template C * @template A * @param {C} controller 控制器 * @param {string} name 部件名称 * @param {A} action 行为标识 * @param {IParam[]} data 数据 */ export function handleCtrlAction< C extends IViewController, A extends string >(controller: C, name: string, action: A, data: IParam[]) { controller.handleCtrlAction(name, action, data); } /** * 处理部件销毁 * * @export * @template C * @param {C} controller 控制器 * @param {string} name 部件名称 * @param {IParam} data 数据 */ export function handleCtrlDestroy< C extends IViewController >(controller: C, name: string, data: IParam) { controller.handleCtrlDestroy(name, data); } /** * 处理选项操作视图按钮行为 * * @export * @template C * @template A * @param {C} controller * @param {('confirm' | 'cancel')} type */ export function handleOptViewButtonAction< C extends IOptViewController, A extends string >(controller: C, type: 'confirm' | 'cancel') { if (type === 'cancel') { controller.cancel(); } if (type === 'confirm') { controller.confirm(); } } /** * 处理多项选择视图选择按钮行为 * * @export * @template C * @param {C} controller * @param {('toLeft' | 'toRight' | 'toAllLeft' | 'toAllRight')} type */ export function handleMPickupViewPickButtonAction< C extends IMPickupViewController >(controller: C, type: 'toLeft' | 'toRight' | 'toAllLeft' | 'toAllRight') { controller.handleMPickupViewPickButtonAction(type); } /** * 处理选择视图按钮行为 * * @export * @template C * @param {C} controller * @param {('confirm' | 'cancel')} type */ export function handlePickupViewButtonAction< C extends IPickupViewController >(controller: C, type: 'confirm' | 'cancel') { if (type === 'confirm') { controller.confirm(); } if (type === 'cancel') { controller.cancel(); } } /** * 处理多项选择视图行为 * * @export * @template C * @param {C} controller * @param {string} action * @param {IParam} data */ export function handleMPickupViewAction< C extends IMPickupViewController >(controller: C, action: string, data: IParam) { controller.handleMPickupViewAction(action, data); } /** * 处理多数据视图快速分组值变化 * * @export * @param {IMDViewController} controller * @param {IParam} item */ export function handleQuickGroupValueChange( controller: | IMDViewController | IExpViewController, item: IParam ) { controller.handleQuickGroupValueChange(item); } /** * 处理组件行为 * * @export * @param {IViewController} controller * @param {IEvent} actionParam * @param {number} [index] */ export function handleComponentAction( controller: IViewController, actionParam: IEvent, index?: number ) { controller.handleComponentAction(actionParam, index); } /** * 视图类名 * * @export * @param {*} [model={}] 视图模型 * @param {string} [customClassNames] 自定义样式名 * @return {*} {string} */ export function getViewClassNames( model: IParam = {}, props: IParam = {} ): IParam { const classNames: IParam = {}; if (model.viewStyle) { Object.assign(classNames, { [`view-style-${model.viewStyle.toLowerCase()}`]: true, }); } if (model.viewType) { Object.assign(classNames, { [model.viewType.toLowerCase()]: true }); } if (model.codeName) { Object.assign(classNames, { [srfFilePath2(model.codeName)]: true }); } if (model.cssName) { Object.assign(classNames, { [model.cssName]: true }); } if (!model.useDefaultLayout) { Object.assign(classNames, { 'view-layout': true, [`view-layout--${model.layoutMode.toLowerCase()}`]: true, }); } return classNames; } /** * 编辑视图类名 * * @export * @param {IParam} [model={}] 视图模型 * @param {IParam} [props={}] 视图输入参数 * @param {IParam} [customClassNames={}] 自定义类名 * @return {*} */ export function getEditViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 多表单编辑视图类名 * * @export * @param {IParam} [model={}] * @param {IParam} [props={}] * @param {IParam} [customClassNames] * @return {*} */ export function getMEditViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 首页视图类名 * * @export * @param {IParam} [model={}] 视图模型 * @param {IParam} [props={}] 视图输入参数 * @param {IParam} [customClassNames={}] 自定义类名 * @return {*} */ export function getIndexViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames: IParam = { 'app-container': true, }; if (model.viewStyle) { Object.assign(classNames, { [`app-style-${model.viewStyle.toLowerCase()}`]: true, }); } if (model.viewType) { Object.assign(classNames, { [model.viewType.toLowerCase()]: true }); } if (model.codeName) { Object.assign(classNames, { [srfFilePath2(model.codeName)]: true }); } if (model.cssName) { Object.assign(classNames, { [model.cssName]: true }); } if (customClassNames) { Object.assign(classNames, customClassNames); } Object.assign(classNames, { [`app-content--${model.viewStyle === 'DEFAULT' ? 'tab' : 'route'}`]: true, }); if (!model.useDefaultLayout) { Object.assign(classNames, { 'view-layout': true, [`view-layout--${model.layoutMode.toLowerCase()}`]: true, }); } if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 选项操作视图类名 * * @export * @param {IParam} [model={}] 视图模型 * @param {IParam} [props={}] 视图输入参数 * @param {IParam} [customClassNames={}] 自定义类名 * @return {*} */ export function getOptViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 门户视图类名 * * @export * @param {IParam} [model={}] 视图模型 * @param {IParam} [props={}] 视图输入参数 * @param {IParam} [customClassNames={}] 自定义类名 * @return {*} */ export function getPortalViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 树视图类名 * * @export * @param {IParam} [model={}] 视图模型 * @param {IParam} [props={}] 视图输入参数 * @param {IParam} [customClassNames={}] 自定义类名 * @return {*} */ export function getTreeViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 树导航视图类名 * * @export * @param {IParam} [model={}] * @param {IParam} [props={}] * @param {IParam} [customClassNames] * @return {*} */ export function getTreeExpBarViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * HTML视图类名 * * @export * @param {IParam} [model={}] * @param {IParam} [props={}] * @param {IParam} [customClassNames] * @return {*} */ export function getHtmlViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 自定义视图类名 * * @export * @param {IParam} [model={}] * @param {IParam} [props={}] * @param {IParam} [customClassNames] * @return {*} */ export function getCustomViewClassNames( model: IParam = {}, props: IParam = {}, customClassNames?: IParam ) { const classNames = getViewClassNames(model, props); if (customClassNames) { Object.assign(classNames, customClassNames); } return classNames; } /** * 获取导航视图类名 * * @export * @param {IExpViewModel} model * @param {IParam} [props={}] * @param {IParam} [customClassNames={}] * @return {*} */ export function getExpViewClassNames( model: IExpViewModel, props: IParam = {}, customClassNames: IParam = {} ) { const classNames = getViewClassNames(model, props); Object.assign(classNames, { deexpview: true }); Object.assign(classNames, customClassNames); return classNames; } /** * 初始化导航视图分隔值 * * @export * @param {HTMLElement} element * @param {IExpViewModel} model * @return {*} {(number | undefined)} */ export function initExpViewSplit( element: HTMLElement, model: IExpViewModel ): number | undefined { const { expBarWidth, expBarName, expBarHeight, sideBarLayout } = model; if (!element || !expBarName) { return undefined; } const tempSplit = getExpViewSplit(model); if (tempSplit) { return tempSplit; } if (sideBarLayout === 'LEFT' && expBarWidth && expBarWidth > 0) { const split = expBarWidth / element.offsetWidth; setExpViewSplit(model, split); return split; } if (sideBarLayout === 'TOP' && expBarHeight && expBarHeight > 0) { const split = expBarHeight / element.offsetHeight; setExpViewSplit(model, split); return split; } return undefined; } /** * 获取导航视图分隔值 * * @export * @param {IExpViewModel} model * @return {*} {(number | undefined)} */ export function getExpViewSplit(model: IExpViewModel): number | undefined { const { codeName, expBarName } = model; const { getViewSplit } = useViewActionStoreWithOut(); return getViewSplit(`${codeName}_${expBarName}`); } /** *设置导航视图分隔值 * * @export * @param {IExpViewModel} model * @param {number} split */ export function setExpViewSplit(model: IExpViewModel | IMPickupView2Model, split: number) { const { setViewSplit } = useViewActionStoreWithOut(); const { codeName, expBarName } = model; setViewSplit(`${codeName}_${expBarName}`, split); } /** * 处理快速搜索 * * @export * @param {IMDViewController} controller * @param {string} searchValue */ export function handleQuickSearch( controller: IMDViewController, searchValue: string ) { controller.search(searchValue); }