import { Prop, Vue, Watch } from 'vue-property-decorator'; import { CreateElement, VNode, VNodeData } from 'vue'; import sortable from 'sortablejs'; import { clone, mergeDeepRight } from 'ramda'; import { IDesignDefaultContext } from '../../interface'; import { GlobalService, IParams, IEntityLocalDataService } from '@ibizstudio/api'; import { generateOrderValue } from 'qx-util'; import { Modal } from 'ant-design-vue'; import { Util } from '@ibizstudio-ex/runtime'; import './design-item-base.less'; /** * 中部设计区项基类 * * @export * @class DesignItemBase * @extends {Vue} */ export class DesignItemBase extends Vue { /** * 设计上下文 * * @type {IDesignContext} * @memberof DesignItemBase */ @Prop() ctx!: IDesignDefaultContext; ctrl!: IDesignDefaultContext['ctrl']; globalService!: GlobalService; /** * 当前容器dom实例 * * @type {HTMLDivElement} * @memberof DesignItemBase */ el!: HTMLDivElement; /** * 数据 * * @type {any[]} * @memberof DesignItemBase */ list: any[] = []; ctrlCtrl: any; context: any; /** * 当前是否为激活状态 * * @memberof DesignItemBase */ get active() { return this.data?.srfkey === this.ctrl?.select.data?.srfkey; } /** * 拖拽参数 * * @type {sortable.Options} * @memberof DesignMaterialPanelBase */ options: sortable.Options = {}; /** * 项数据 * * @type {any} * @memberof DesignItemBase */ @Prop() data!: any; @Watch('data', { deep: true, immediate: true }) dataWatch(newVal: any, oldVal: any): void { this.dataChange(newVal, oldVal); } /** * 父数据 * * @type {any} * @memberof DesignItemBase */ @Prop() parentData!: any; @Watch('parentData', { deep: true, immediate: true }) parentDataChange(newVal: any, old: any) { this.$forceUpdate(); } /** * 当前设计对象数据服务 * * @type {IEntityLocalDataService} * @memberof DesignItemBase */ service!: IEntityLocalDataService; /** * 当前预览设计对象数据服务 * * @type {IEntityLocalDataService} * @memberof DesignItemBase */ previewService!: IEntityLocalDataService; /** * 是否禁用消息中心通知 * * @memberof DesignItemBase */ isAcc = true; /** * 启用应用消息订阅 * * @memberof DesignItemBase */ enableAcc(): void { this.isAcc = true; } /** * 禁用应用消息订阅 * * @memberof DesignItemBase */ disableAcc(): void { this.isAcc = false; } initOption(): void { this.options = { handle: '.drag-handle', group: { name: this.ctx.tag, }, animation: 150, }; } /** * 数据变更 * * @param {any} _newVal * @param {any} _oldData * @memberof DesignItemBase */ dataChange(_newVal: any, _oldData: any): void {} /** * 组件创建完毕 * * @memberof DesignItemBase */ componentCreated(): void {} private created(): void { if (!this.ctx) { console.error('未设置上下文「ctx」,初始化异常!', this); return; } this.ctrl = this.ctx.ctrl; this.globalService = this.ctx.gs; this.initOption(); this.selectChange = this.selectChange.bind(this); this.ctrl.select.evt.on('change', this.selectChange); this.componentCreated(); } /** * 组件加载完毕 * * @memberof DesignItemBase */ componentMounted(): void {} private mounted(): void { this.el = this.$refs.designItem as any; this.options = mergeDeepRight(this.options, this.generateOption()) as any; this.ctrlCtrl = (this.ctrl.ctx.ctrl as any).ctrlCtrl; this.context = Util.deepCopy((this.ctrl.ctx as any).context); this.componentMounted(); } /** * 组件销毁 * * @memberof DesignItemBase */ componentDestroyed(): void {} private destroyed(): void { this.ctrl.select.evt.off('change', this.selectChange); this.componentDestroyed(); } /** * 查询数据 * * @param {IParams} [params] * @return {*} {Promise} * @memberof DesignItemBase */ async loadChild(params?: IParams): Promise { if (this.previewService) { const arr = await this.previewService.selectLocal(this.ctx.context, params!); if (arr) { this.list.splice(0, this.list.length); this.list.push(...arr); } return arr; } console.warn('未设置当前设计对象所属服务', this); return []; } /** * 生成拖拽参数 * * @return {*} {sortable.Options} * @memberof DesignItemBase */ generateOption(): sortable.Options { return {}; } /** * 绘制内容 * * @param {CreateElement} _h * @return {*} {VNode[]} * @memberof DesignItemBase */ renderContentList(_h: CreateElement): VNode[] { throw new Error('「renderContentList」此方法必须重写实现!'); } /** * 设置选中数据 * * @param {*} data * @memberof DesignItemBase */ setSelect(data: any): void { if (this.ctrl) { this.ctrl.select.set(data); } } /** * 选中数据变更 * * @param {any} data * @memberof DesignItemBase */ selectChange(data: any): void { this.activeChange(data as any); } /** * 激活数据变更 * * @param {any} data * @memberof DesignItemBase */ activeChange(data: any): void {} /** * 用户操作提示 * * @param {any} data * @memberof DesignItemBase */ userOperationTips(event: any) { if (event?.added) { const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl; if (panelCtrl.evt) { panelCtrl.evt.emit('resetLayout'); } } let select: string = ''; const modal: any = Modal.confirm({ class: 'operation-tips', width: 720, centered: true, maskClosable: false, content: () => { return (
新建布局 onCancel()}/>
当前为默认布局无法编辑,是否进行自定义布局
selectNewMode('cloneDefaultLayoutNew')}>
克隆默认布局新建
以当前视图默认布局为蓝本,建立用户自定义布局面板
selectNewMode('useExistingLayout')}>
选用已有布局
选择已经建立的自定义布局面板数据
onCancel()}>取消 nextStep()} disabled={!select}>下一步
) }, onOk: () => { const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl; if (panelCtrl.evt) { if (Object.is(select, 'cloneDefaultLayoutNew')) { panelCtrl.evt.emit('cloneDefaultLayout'); } else { panelCtrl.evt.emit('itemClick', { tag: 'switchpanel' }); } } }, onCancel: () => { } }); const selectNewMode = (model: string) => { select = model; modal?.update(); } const onCancel = () => { modal?.destroy(); } const nextStep = () => { modal?.destroy(); const panelCtrl: any = (this.ctrl.ctx as any)?.panelCtrl || this.ctrl; if (panelCtrl.evt) { if (Object.is(select, 'cloneDefaultLayoutNew')) { panelCtrl.evt.emit('cloneDefaultLayout'); } else if (Object.is(select, 'useExistingLayout')) { panelCtrl.evt.emit('itemClick', { tag: 'switchpanel' }); } } } } /** * 拖拽数据变更 * * @param {*} evt * @memberof DesignItemBase */ change(evt: any, list: any[] = []): void { if ((evt?.added || evt?.moved) && (this.ctrl as any)?.isDefaultLayout) { this.userOperationTips(evt); } else if (evt?.added) { if ((this.ctrl as any)?.isDefaultLayout) { this.userOperationTips(evt); } else { const data = { ...evt.added, element: clone(Object.assign(evt.added.element) || {}), }; if (data.element.isCtrls) { this.addCtrlItem(data, list); } else { this.add(data); } } } else if (evt?.moved) { this.move(evt.moved); } } /** * 新增项 * * @param {{ element: any; newIndex: number }} _opt * @return {*} {Promise} * @memberof DesignItemBase */ async add(_opt: { element: any; newIndex: number }): Promise {} /** * @description 新增拖拽部件 * @param {*} arg * @memberof DesignItemBase */ addCtrlItem(data: any, list: any[]) { const param = { psctrltypeid: data?.element?.predefinedtype, }; if ((this.ctrl as any).evt) { (this.ctrl as any).evt.emit('itemClick', { tag: 'viewctrlcreate', param: param, callback: (_data: any) => { if (_data.codename) { Object.assign(data.element, { pssysviewpanelitemname: _data.codename, isCtrls: false }); this.add(data); } }, }); } } /** * 子项移动 * * @param {{ data: any; newIndex: number; oldIndex: number }} opt * @return {*} {Promise} * @memberof DesignItemBase */ async move(opt: { data: any; newIndex: number; oldIndex: number }): Promise { const { newIndex, oldIndex } = opt; // 根据变更位置更新排序值 if (newIndex > oldIndex) { await this.updateOrderValue(oldIndex); } else { await this.updateOrderValue(newIndex); } } /** * 根据当前列表,更新排序值 * * @param {number} [num=0] 更新起始下标,默认从0开始 * @return {*} {Promise} * @memberof DesignItemBase */ async updateOrderValue(num: number = 0): Promise { this.disableAcc(); for (let i = num; i < this.list.length; i++) { const item = this.list[i]; item.ordervalue = generateOrderValue(i); item.srfordervalue = item.ordervalue; await this.service.UpdateTemp(this.ctx.context, item); } this.enableAcc(); } /** * 获取拖拽容器样式 * * @return {*} {*} * @memberof DesignItemBase */ getDraggableClass(): any { return { 'transition-group': true, 'draggable-warp': true, 'ant-row': true, }; } /** * 拖拽容器render额外参数 * * @return {*} {VNodeData} * @memberof DesignItemBase */ getDraggableOtherParams(): VNodeData { return {}; } /** * 绘制拖拽区 * * @param {any[]} list * @param {*} content * @returns {*} * @memberof DragDesignBase */ renderDraggable(list: any[], content?: any): any { const h = this.$createElement; return h( 'draggable', { attrs: { handle: this.options.handle, group: this.options.group, animation: this.options.animation, list: list, disabled: (this.ctx.ctrl as any)?.isViewDesign }, class: 'draggable-container', on: { change: (e: any) => this.change(e), }, }, [ h( 'transition-group', { attrs: { type: 'transition', name: 'flip-list', }, class: this.getDraggableClass(), ...this.getDraggableOtherParams(), }, content, ), ], ); } }