import { AppModelService, GetModelService, Util } from '@ibizstudio-ex/runtime'; import { IPSDEFormDetailPreview, acc } from '@ibizstudio/api'; import { generateOrderValue } from 'qx-util'; import { LayoutUtil } from '../../utils'; import { DesignItemBase } from '../design-item/design-item-base'; import { message, Modal } from 'ant-design-vue'; import './drag-design-item-base.less'; import { IMaterialItem } from '../../interface'; /** * 表单设计项基类 * * @export * @class DragDesignItemBase * @extends {DesignItemBase} * @template T */ export class DragDesignItemBase extends DesignItemBase { /** * 布局工具 * * @memberof DragDesignItemBase */ layoutUtil = LayoutUtil.getInstance(); /** * 样式 * * @type {*} * @memberof DragDesignItemBase */ style: any; /** * 是否为flex布局 * * @memberof DragDesignItemBase */ isFlexStyle = false; /** * 应用消息订阅 * * @type {string[]} * @memberof DragDesignItemBase */ accSubs: string[] = []; /** * 视图部件服务 */ viewCtrlService: any = ''; /** * 视图部件数据 */ viewCtrlData: any = []; /** * 部件控件删除模式 */ ctrlPosDeleteMode: string = ''; /** * 模型服务 * * @author zhanghengfeng * @date 2023-03-14 19:03:29 * @type {AppModelService} */ modelService!: AppModelService; /** * 容器类型 * * @author zhanghengfeng * @date 2023-05-18 14:05:54 */ static containerType = ['FORMPAGE', 'TABPAGE', 'GROUPPANEL']; /** * 子项类型 * * @author zhanghengfeng * @date 2023-05-18 15:05:05 * @static */ static childType = ['FORMITEM', 'RAWITEM', 'BUTTON', 'IFRAME', 'FORMITEMEX', 'DRUIPART', 'MDCTRL']; /** * 监听素材项双击 * * @author zhanghengfeng * @date 2023-05-18 14:05:13 * @param {IMaterialItem} [item] */ onItemDblClick(item?: IMaterialItem): void { if (this.active && item && item.data && this.data && Array.isArray(this.list)) { const type = this.data.detailtype; if (type) { if (DragDesignItemBase.containerType.includes(type)) { this.list.push(item.data); this.add({ element: item.data, newIndex: this.list.length - 1, }); } else if (DragDesignItemBase.childType.includes(type)) { this.ctx.ctrl.itemEvt?.emit('child-item-dblclick', { item, child: this.data, }); } } } } /** * 监听子项触发的素材项双击 * * @author zhanghengfeng * @date 2023-05-18 14:05:36 * @param {{ item: IMaterialItem; child: IPSDEFormDetailPreview }} [args] */ onChildItemDblClick(args?: { item: IMaterialItem; child: IPSDEFormDetailPreview }): void { if (args) { const { item, child } = args; if (item && item.data && child && this.data && Array.isArray(this.list)) { const id = this.data.psdeformdetailid; const parentId = child.ppsdeformdetailid; const childId = child.psdeformdetailid; if (id && parentId && childId && id === parentId) { const index = this.list.findIndex(data => { const dataId = data.psdeformdetailid; return dataId && dataId === childId; }); if (index !== -1) { this.list.splice(index + 1, 0, item.data); this.add({ element: item.data, newIndex: index + 1, }); } } } } } async componentCreated() { if (this.data && this.data.itemtype && Object.is(this.data.itemtype, 'CTRLPOS')) { this.viewCtrlService = await ___ibz___.gs.getPSDEViewCtrlService(); this.loadViewCtrl(); } this.subAcc(); this.deletePanel = this.deletePanel.bind(this); const event: any = (this.ctrl as any).evt; if (event) { event.on('removePanel', this.deletePanel); } this.modelService = await GetModelService(this.ctx.context); if (this.ctx.ctrl.itemEvt) { this.onItemDblClick = this.onItemDblClick.bind(this); this.ctx.ctrl.itemEvt.on('item-dblclick', this.onItemDblClick); const type = this.data?.detailtype; if (type && DragDesignItemBase.containerType.includes(type)) { this.onChildItemDblClick = this.onChildItemDblClick.bind(this); this.ctx.ctrl.itemEvt.on('child-item-dblclick', this.onChildItemDblClick); } } } async componentMounted() { this.service = this.ctx.ctrl.itemService; if (this.ctx.ctrl.previewService) { this.previewService = this.ctx.ctrl.previewService; } else { this.previewService = this.ctx.ctrl.itemService; } this.load(); } componentDestroyed() { this.accSubs.forEach(str => acc.unsubscribeLocal(str)); const event: any = (this.ctrl as any).evt; if (event) { event.off('removePanel', this.deletePanel); } if (this.ctx.ctrl.itemEvt) { this.ctx.ctrl.itemEvt.off('item-dblclick', this.onItemDblClick); this.ctx.ctrl.itemEvt.off('child-item-dblclick', this.onChildItemDblClick); } } /** * 订阅应用中心消息 * * @memberof DragDesignItemBase */ subAcc(): void { const entityName = this.ctx.ctrl.itemEntity?.codeName?.toUpperCase(); this.accSubs.push( acc.commandLocal( (data: any) => { if (!this.isAcc) { return; } this.accCreated(data); }, 'create', entityName, ), ); this.accSubs.push( acc.commandLocal( (data: any) => { if (!this.isAcc) { return; } this.accRemove(data); }, 'remove', entityName, ), ); this.accSubs.push( acc.commandLocal( (data: any) => { if (!this.isAcc) { return; } this.accUpdate(data); }, 'update', entityName, ), ); if (this.viewCtrlService) { this.accSubs.push( ...acc.commandLocals( (data: any) => { if (Object.is(this.context.psdeviewbase, data.psdeviewbaseid)) { this.loadViewCtrl(); } }, ['create', 'remove'], this.viewCtrlService.APPDENAME.toUpperCase(), ), ); } } accCreated(data: any): void { if (this.data?.srfkey === data.srfpkey || !data.srfpkey) { this.load(); } } accRemove(data: any): void { if (this.data?.srfkey === data.srfpkey || !data.srfpkey) { this.load(); } } accUpdate(data: any): void { if (this.data?.srfkey === data.srfkey && this.data.srftempdate !== data.srftempdate) { this.reloadData(); } else if (this.data?.srfkey === data.srfpkey) { this.load(); } } /** * 加载数据 * * @author chitanda * @date 2021-04-15 10:04:34 * @return {*} {Promise} */ async load(): Promise {} /** * 加载视图部件数据 * * @memberof CollapseList */ async loadViewCtrl() { const res = await this.viewCtrlService.FetchDefault(this.ctx.context); if (res && res.data.length > 0) { this.viewCtrlData = res.data; } } /** * 删除项 * * @param {string} srfKey * @return {*} {Promise} * @memberof DragDesignItemBase */ async remove(srfKey: string): Promise { const tab = this.list.find((item: any) => { return item.srfkey === srfKey; }); const res = await this.service.RemoveTemp(this.ctx.context, tab); if (res.ok === false) { message.error(res.statusText || ''); return res; } return res; } /** * 新增表单项 * * @param {any} entity * @return {*} {(Promise)} * @memberof DragDesignItemBase */ async create(entity: any): Promise { const res: any = await this.service.CreateTemp(this.ctx.context, entity); if (res.ok) { this.setSelect(res.data); return res.data; } } /** * 更新表单项 * * @param {any} entity * @return {*} {(Promise)} * @memberof DragDesignItemBase */ update(entity: any): Promise { return this.service.UpdateTemp(this.ctx.context, entity); } /** * 获取表单项 * * @param {string} srfkey * @return {*} {(Promise)} * @memberof DragDesignItemBase */ get(srfkey: string): Promise { return this.previewService.getLocal(this.ctx.context, srfkey); } /** * @description 获取内容样式 * @param {*} data * @return {*} * @memberof DragDesignItemBase */ getContentStyle(data: any) { if (data && data.rawcssstyle) { const res = data.rawcssstyle.split('\n'); const target: string[] = []; for (let i = 0; i < res.length; i++) { target.push(...res[i].split(';').filter((value: string) => value)); } return target .filter((value: string) => { return value.split(':').length === 2; }) .join(';'); } } /** * 获取默认值 * * @param {any} data * @return {*} {(Promise)} * @memberof DragDesignItemBase */ async getDraft(data: any): Promise { const res = await this.service.GetDraftTemp({ ...this.ctx.context, [this.ctx.ctrl.itemEntity?.codeName?.toLowerCase()]: this.data?.srfkey }, data); if (res.ok && res.data) { return res.data; } return {}; } /** * 重新加载当前数据 * * @memberof DragDesignItemBase */ async reloadData() { const data = await this.get(this.data.srfkey); if (data) { this.data._reset(data); this.$forceUpdate(); } } /** * 新增子项 * * @param {{ element: any; newIndex: number }} opt * @memberof DragDesignItemBase */ async add(opt: { element: any; newIndex: number }) { const { element, newIndex } = opt; await this.updateOrderValue(newIndex + 1); this.list.splice(newIndex, 1); let data: any = await this.get(element.srfkey); if (data == null) { data = await this.getDraft(element); data.ordervalue = generateOrderValue(newIndex); data.srfordervalue = data.ordervalue; data.formtype = this.ctx.context.formtype; await this.create(data); } else { data.ordervalue = generateOrderValue(newIndex); data.srfordervalue = data.ordervalue; if (!this.data || this.data.itemtype == 'PSSysViewPanel') { data.srfpkey = null; data.srfpmajortext = null; } else { data.srfpkey = this.data.srfkey; data.srfpmajortext = this.data.srfmajortext; } await this.update(data); if (!this.data || this.data.itemtype == 'PSSysViewPanel') { const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl; if (panelCtrl.evt) { panelCtrl.evt.emit('refreshPanel'); } } } } /** * 激活数据点击 * * @param {MouseEvent} event * @param {any} data * @memberof DragDesignItemBase */ onActiveClick(event: MouseEvent, data: any): void { if (event) { event.stopPropagation(); } this.setSelect(data); } /** * 计算当前布局是否为Flex * * @param {*} node * @memberof DragDesignItemBase */ calcLayoutMode(): void { if (this.parentData && Object.is(this.parentData.layoutmode, 'FLEX')) { this.isFlexStyle = true; } else { this.isFlexStyle = false; } } /** * 计算当前项样式 * * @memberof DragDesignItemBase */ calcStyle() { this.calcLayoutMode(); this.style = this.layoutUtil.formatStyle(this.data, this.parentData, this.isFlexStyle); } /** * 计算栅格布局样式 * * @param {*} item * @returns {*} * @memberof DragDesignItemBase */ calcColClass(item: any): any { return this.layoutUtil.calcColClass(item, this.parentData, this.isFlexStyle); } /** * 绘制其他内容 * * @returns {*} * @memberof DragDesignItemBase */ renderOther(): any { return [this.renderHandle(), this.renderActions()]; } /** * 绘制拖拽节点 * * @returns {*} * @memberof DragDesignItemBase */ renderHandle(): any { // 视图设计中表单预览不允许移动编辑 if (!(this.ctx.ctrl as any).isViewDesign) { return (
); } } /** * 绘制行为 * * @returns {*} * @memberof DragDesignItemBase */ renderActions(): any { return (
    {this.renderActionItems()}
); } /** * 删除当前数据 * * @param {MouseEvent} e * @return {*} {Promise} * @memberof DragDesignItemBase */ async deleteHandle(e: MouseEvent): Promise { e.stopPropagation(); if (Object.is(this.data.itemtype, 'CTRLPOS')) { this.deletePromptMessage(e); return; } this.removeDesingItem(e); } /** * 删除占位控件 * @param {MouseEvent} e * */ async removeDesingItem(e: MouseEvent) { if ((this.ctrl as any)?.isDefaultLayout) { this.userOperationTips(e); } else { const res = await this.service.RemoveTemp(this.ctx.context, this.data); if (res.ok === false) { message.error(res.statusText || ''); return; } this.setSelect(this.parentData); } } /** * @description 删除当前面板 * @param {*} data * @memberof DragDesignItemBase */ async deletePanel(data: any) { if (this.data.srfpkey && Object.is(this.data.srfpkey, data.srfkey)) { const res = await this.service.RemoveTemp(this.ctx.context, this.data); if (res.ok === false) { message.error(res.statusText || ''); return; } } } /** * 拷贝当前表单项数据 * * @param {MouseEvent} e * @return {*} {Promise} * @memberof DragDesignItemBase */ async copyHandle(e: MouseEvent): Promise { e.stopPropagation(); const res = await (this.service as any).DeepCopy(this.ctx.context, this.data); if (res.ok) { console.log(res); } } /** * @description 保存为自定义部件 * @param {MouseEvent} e * @return {*} {Promise} * @memberof DragDesignItemBase */ async saveHandle(e: MouseEvent): Promise { e.stopPropagation(); //todo 待补充 } /** * @description 编辑部件 * @param {MouseEvent} e * @return {*} {Promise} * @memberof DragDesignItemBase */ async editorHandle(event: MouseEvent): Promise { event.stopPropagation(); if (!Object.is(this.data.itemtype, 'CTRLPOS')) { return; } const evt: any = (this.ctrl as any).evt; const curCtrl = this.getActiveCtrl(); if (curCtrl && evt) { Object.assign(curCtrl, { linktype: curCtrl.psdeviewctrltype }); evt.emit('itemClick', { tag: 'redirectctrldesign', param: curCtrl }); } else { const ctrlCtrl = (this.ctrl.ctx.ctrl as any)?.ctrlCtrl; if (ctrlCtrl && evt && ctrlCtrl.deUIActionItems.length > 0) { evt.emit('addCtrl', { event, item: ctrlCtrl.deUIActionItems[0], callback: (_data: any) => { if (_data.codename) { const result = { caption: _data.psctrlname, psdeviewctrltype: _data.psctrltypename, pssysviewpanelitemname: _data.codename, [`psde${_data.psctrltypename?.toLowerCase()}id`]: _data.psctrlid, srfkey: this.data.srfkey, }; const data = Object.assign(Util.deepCopy(this.data), result); this.update(data); } }, }); } } } /** * @description 获取激活部件 * @return {*} * @memberof DragDesignItemBase */ public getActiveCtrl() { const data: any = this.ctrl.ctx.ctrl.select.data; if (data) { return Object.is(data.psdeviewctrlname, this.data.pssysviewpanelitemname) ? data : null; } } /** * 绘制删除占位提示信息 * @param {MouseEvent} e */ deletePromptMessage(e: MouseEvent) { this.ctrlPosDeleteMode = ''; const modal: any = Modal.confirm({ class: 'delete-prompt-message-main', mask: true, centered: true, icon: 'info-circle', width: 400, cancelText: '取消', okText: '确定', title: '请确认是否删除控件占位元素', okButtonProps: { props: { disabled: !this.ctrlPosDeleteMode, }, }, content: () => { return (
deletePlaceholderPro('synchroDeleteViewCtrl')}> 是,同步删除已加入视图部件 deletePlaceholderPro('onlyDeletePlaceholder')}> 是,仅删除控件占位元素
); }, onOk: async () => { if (Object.is(this.ctrlPosDeleteMode, 'synchroDeleteViewCtrl')) { // 筛选删除部件数据 await this.viewCtrlData.find((item: any) => { return Object.is(item.psdeviewctrlname.toUpperCase(), this.data.pssysviewpanelitemname.toUpperCase()); }); const res = await this.viewCtrlService.RemoveTemp(this.ctx.context, this.data); if (res.ok === false) { message.error(res.statusText || ''); return; } } await this.removeDesingItem(e); }, onCancel: () => {}, }); const deletePlaceholderPro = (model: any) => { this.ctrlPosDeleteMode = model; modal.update({ okButtonProps: { props: { disabled: !this.ctrlPosDeleteMode, }, }, }); }; } /** * 打开动态逻辑设计界面 * * @author zhanghengfeng * @date 2023-03-14 18:03:19 */ async openFormItemLogicView() { const entity = this.ctx.ctrl.itemEntity; if (entity && this.data) { const codeName = entity.codeName?.toLowerCase(); const key = entity.getKeyPSAppDEField()?.codeName?.toLowerCase(); const majorKey = entity.getMajorPSAppDEField()?.codeName?.toLowerCase(); if (codeName && key && majorKey) { const tempContext = Util.deepCopy(this.ctx.context); tempContext.viewpath = 'PSSYSAPPS/FormDesign/PSAPPDEVIEWS/PSDEFormDetailFDLogicEditView.json'; tempContext.srfparentdemapname = entity.getPSDEName(); tempContext[codeName] = this.data[key]; const viewparams = { [key]: this.data[key], [majorKey]: this.data[majorKey], }; const parentObj = { srfparentdename: codeName, srfparentkey: tempContext[codeName], }; Object.assign(tempContext, parentObj); Object.assign(viewparams, parentObj); const type = this.data.detailtype; if (type === 'FORMITEM' || type === 'FORMITEMEX') { tempContext.viewpath = 'PSSYSAPPS/FormDesign/PSAPPDEVIEWS/PSDEFormDetailFDLogic2EditView.json'; } const appView = await this.modelService.getPSAppView(tempContext.viewpath); const view = { viewname: 'app-view-shell', height: appView.height, width: appView.width, title: this.$tl(appView.getCapPSLanguageRes()?.lanResTag, appView.caption), placement: appView.openMode, }; const container = this.$appdrawer.openDrawer(view, Util.getViewProps(tempContext, viewparams, [this.data])); container.subscribe((result: Record | null) => { if (!result || !Object.is(result.ret, 'OK')) { return; } }); } } } /** * 绘制行为项 * * @param {*} h * @returns {*} * @memberof DragDesignItemBase */ renderActionItems(): any { return [ Object.is(this.data.itemtype, 'CTRLPOS') ? (
  • this.editorHandle(e)} />
  • ) : null, //
  • // // this.saveHandle(e)} /> // //
  • , //
  • // // this.copyHandle(e)} /> // //
  • ,
  • this.openFormItemLogicView()}>
  • ,
  • this.deleteHandle(e)} />
  • , ]; } /** * 根据项类型绘制 * * @param {any} item * @return {*} * @memberof DragDesignItemBase */ renderChildItem(item: any) { return this.ctx.ctrl.renderChildItem(this.$createElement, this.ctx, item, this.data); } /** * 绘制子数据 * * @return {*} {any[]} * @memberof DragDesignItemBase */ renderChild(): any[] { return this.list.map(item => this.renderChildItem(item)); } /** * 绘制内容 * * @return {*} {*} * @memberof DragDesignItemBase */ renderContent(): any {} render() { const { srfkey } = this.data; this.calcStyle(); return (
    this.onActiveClick(e, this.data)} on-dblclick={(e: any) => this.editorHandle(e)} > {this.renderContent()} {this.renderOther()}
    ); } }