<script lang="tsx">
|
import { defineComponent } from 'vue';
|
|
import { BasicHelp } from '@jnpf/ui';
|
|
import { CopyOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
import draggable from 'vuedraggable';
|
|
import { $t } from '#/locales';
|
|
import { vModelIgnoreList } from './helper/config';
|
import render from './helper/render';
|
|
interface AttrsType {
|
onActiveItem: (element) => void;
|
onCopyItem: (element, parent) => void;
|
onDeleteItem: (index, parent) => void;
|
put: (...args: unknown[]) => void;
|
end: (...args: unknown[]) => void;
|
onAddRow: (element) => void;
|
onAddCol: (element) => void;
|
}
|
|
export default defineComponent({
|
components: {
|
CopyOutlined,
|
DeleteOutlined,
|
Draggable: draggable,
|
Render: render,
|
},
|
inheritAttrs: false,
|
props: ['element', 'index', 'drawingList', 'activeId', 'formConf', 'showType'],
|
|
setup(props, { attrs }) {
|
let activeData = {};
|
const useCompList = new Set(['alert', 'barcode', 'button', 'groupTitle', 'link', 'qrcode', 'text']);
|
|
const components = {
|
itemBtns(element, index, parent, isTableGrid = false) {
|
const gutter = element.__config__?.layout === 'colFormItem' && props.formConf?.gutter ? props.formConf.gutter : 0;
|
const rightDistance = gutter;
|
const { onCopyItem, onDeleteItem } = attrs as unknown as AttrsType;
|
const tableSetting = (element, isTableGrid) => {
|
const { onAddRow, onAddCol } = attrs as unknown as AttrsType;
|
if (!isTableGrid) return null;
|
return [
|
<span
|
class="drawing-item-action-item drawing-item-add-row"
|
onClick={(event) => {
|
onAddRow(element);
|
event.stopPropagation();
|
}}
|
title="插入行">
|
<i class="icon-ym icon-ym-generator-insertRow" />
|
</span>,
|
<span
|
class="drawing-item-action-item drawing-item-add-col"
|
onClick={(event) => {
|
onAddCol(element);
|
event.stopPropagation();
|
}}
|
title="插入列">
|
<i class="icon-ym icon-ym-generator-insertCol" />
|
</span>,
|
];
|
};
|
return (
|
<div class="drawing-item-action" style={{ '--rightDistance': `${rightDistance + 10}px` }}>
|
{tableSetting(element, isTableGrid)}
|
<span
|
class="drawing-item-action-item drawing-item-copy"
|
onClick={(event) => {
|
onCopyItem(element, parent);
|
event.stopPropagation();
|
}}
|
title={$t('common.copyText')}>
|
<copy-outlined />
|
</span>
|
<a-popconfirm
|
class="drawing-item-action-item drawing-item-delete"
|
onConfirm={(_) => {
|
onDeleteItem(index, parent);
|
}}
|
title={$t('formGenerator.delComponentTip')}>
|
<span title={$t('common.delText')}>
|
<delete-outlined />
|
</span>
|
</a-popconfirm>
|
</div>
|
);
|
},
|
cellSetting(element, rowIndex, colIndex) {
|
const {
|
onHandleTableSetting,
|
onHandleShowMenu,
|
mergeLeftColDisabled,
|
mergeRightColDisabled,
|
mergeWholeRowDisabled,
|
mergeAboveRowDisabled,
|
mergeBelowRowDisabled,
|
mergeWholeColDisabled,
|
undoMergeRowDisabled,
|
undoMergeColDisabled,
|
deleteWholeColDisabled,
|
deleteWholeRowDisabled,
|
} = attrs as unknown as any;
|
|
const slots = {
|
overlay: () => {
|
return (
|
<a-menu
|
onClick={({ key }) => {
|
onHandleTableSetting(key, element);
|
}}>
|
<a-menu-item key="1">插入左侧列</a-menu-item>
|
<a-menu-item key="2">插入右侧列</a-menu-item>
|
<a-menu-item key="3">插入上方行</a-menu-item>
|
<a-menu-item key="4">插入下方行</a-menu-item>
|
<a-menu-divider />
|
<a-menu-item disabled={mergeLeftColDisabled} key="5">
|
向左合并
|
</a-menu-item>
|
<a-menu-item disabled={mergeRightColDisabled} key="6">
|
向右合并
|
</a-menu-item>
|
<a-menu-item disabled={mergeWholeRowDisabled} key="7">
|
合并整行
|
</a-menu-item>
|
<a-menu-divider />
|
<a-menu-item disabled={mergeAboveRowDisabled} key="8">
|
向上合并
|
</a-menu-item>
|
<a-menu-item disabled={mergeBelowRowDisabled} key="9">
|
向下合并
|
</a-menu-item>
|
<a-menu-item disabled={mergeWholeColDisabled} key="10">
|
合并整列
|
</a-menu-item>
|
<a-menu-divider />
|
<a-menu-item disabled={undoMergeRowDisabled} key="11">
|
撤销行合并
|
</a-menu-item>
|
<a-menu-item disabled={undoMergeColDisabled} key="12">
|
撤销列合并
|
</a-menu-item>
|
<a-menu-divider />
|
<a-menu-item disabled={deleteWholeColDisabled} key="13">
|
删除整列
|
</a-menu-item>
|
<a-menu-item disabled={deleteWholeRowDisabled} key="14">
|
删除整行
|
</a-menu-item>
|
</a-menu>
|
);
|
},
|
};
|
return [
|
<span class="drawing-item-cell">
|
<a-dropdown
|
onOpenChange={(visible) => {
|
if (visible) onHandleShowMenu(element, rowIndex, colIndex);
|
}}
|
trigger="click"
|
v-slots={slots}>
|
<i class="icon-ym icon-ym-generator-TableSettings" />
|
</a-dropdown>
|
</span>,
|
];
|
},
|
};
|
const layouts = {
|
colFormItem(element, index, parent) {
|
const { onActiveItem } = attrs as unknown as AttrsType;
|
const config = element.__config__;
|
const className = props.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item';
|
const globalLabelWidth = props.formConf.labelWidth;
|
let labelCol = {};
|
if ((props.formConf.labelPosition !== 'top' && config.showLabel) || vModelIgnoreList.includes(config.jnpfKey)) {
|
let labelWidth = `${config.labelWidth || globalLabelWidth}px`;
|
if (!config.showLabel) labelWidth = '0px';
|
labelCol = { style: { width: labelWidth } };
|
}
|
if (config.jnpfKey == 'location') element.useAutoLocation = false;
|
const Item =
|
props.showType === 'app' && !useCompList.has(config.jnpfKey) ? (
|
<span>{element.__vModel__}</span>
|
) : (
|
<render
|
conf={element}
|
key={config.renderKey}
|
onUpdate:value={(event) => {
|
config.defaultValue = event;
|
}}
|
size={element.size ? element.size : props.formConf.size}
|
/>
|
);
|
let basicHelp: any = null;
|
if (config.label && config.tipLabel) basicHelp = <BasicHelp text={config.tipLabel} />;
|
const labelSuffix = !config.isSubTable && props.formConf.labelSuffix ? props.formConf.labelSuffix : '';
|
const slots = {
|
label: () => {
|
if (!config.showLabel) return null;
|
return (
|
<span>
|
{config.label ? config.label + labelSuffix : ''}
|
{basicHelp}
|
</span>
|
);
|
},
|
};
|
return (
|
<a-col
|
class={className}
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-form-item labelCol={labelCol} required={config.required} v-slots={slots}>
|
{Item}
|
</a-form-item>
|
{components.itemBtns(element, index, parent)}
|
</a-col>
|
);
|
},
|
rowFormItem(element, index, parent) {
|
const { onActiveItem, put, end } = attrs as unknown as AttrsType;
|
const config = element.__config__;
|
const className = props.activeId === config.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item';
|
|
if (config.jnpfKey === 'tab') {
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={className}>
|
<a-tabs
|
size={props.formConf.size}
|
tabPosition={props.showType === 'app' ? 'top' : element.tabPosition}
|
type={element.type}
|
v-model:activeKey={config.active}>
|
{config.children.map((item) => {
|
const group = { name: 'componentsGroup', put: (...arg) => put(...arg, item) };
|
const onEnd = (...arg) => end(...arg, activeData, item);
|
const slots = {
|
item: ({ element: childElement, index }) => {
|
return renderChildren(childElement, index, item.__config__.children);
|
},
|
};
|
let tip: Element | JSX.Element | null = null;
|
if (!item.__config__.children.length) {
|
tip = <div class="row-tip">请将组件拖到此区域(可拖多个组件)</div>;
|
}
|
return (
|
<a-tab-pane key={item.name} tab={item.title}>
|
<a-col>
|
{tip}
|
<a-row gutter={props.formConf.gutter || 15}>
|
<draggable
|
animation={300}
|
class="drag-wrapper"
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
style="padding-top:12px"
|
v-model={item.__config__.children}
|
v-slots={slots}></draggable>
|
</a-row>
|
</a-col>
|
</a-tab-pane>
|
);
|
})}
|
</a-tabs>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'collapse') {
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={className}>
|
<a-collapse accordion={element.accordion} expandIconPosition="end" ghost={true} v-model:activeKey={config.active}>
|
{config.children.map((item) => {
|
const group = { name: 'componentsGroup', put: (...arg) => put(...arg, item) };
|
const onEnd = (...arg) => end(...arg, activeData, item);
|
const slots = {
|
item: ({ element: childElement, index }) => {
|
return renderChildren(childElement, index, item.__config__.children);
|
},
|
};
|
let tip: Element | JSX.Element | null = null;
|
if (!item.__config__.children.length) {
|
tip = <div class="row-tip">请将组件拖到此区域(可拖多个组件)</div>;
|
}
|
return (
|
<a-collapse-panel header={item.title} key={item.name}>
|
<a-col>
|
{tip}
|
<a-row gutter={props.formConf.gutter || 15}>
|
<draggable
|
animation={300}
|
class="drag-wrapper"
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
v-model={item.__config__.children}
|
v-slots={slots}></draggable>
|
</a-row>
|
</a-col>
|
</a-collapse-panel>
|
);
|
})}
|
</a-collapse>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'steps') {
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={className}>
|
<div class="w-full p-[10px]">
|
<a-steps
|
size={props.formConf.size}
|
status={element.processStatus}
|
type={element.simple ? 'navigation' : 'default'}
|
v-model:current={config.active}>
|
{config.children.map((item) => {
|
const slots: any = {};
|
if (item.icon) slots.icon = () => <span class={`${item.icon} custom-icon`}></span>;
|
return <a-step title={item.title} v-slots={slots} />;
|
})}
|
</a-steps>
|
{config.children.map((item, childIndex) => {
|
const group = { name: 'componentsGroup', put: (...arg) => put(...arg, item) };
|
const onEnd = (...arg) => end(...arg, activeData, item);
|
const slots = {
|
item: ({ element: childElement, index }) => {
|
return renderChildren(childElement, index, item.__config__.children);
|
},
|
};
|
let tip: Element | JSX.Element | null = null;
|
if (!item.__config__.children.length) {
|
tip = <div class="row-tip">请将组件拖到此区域(可拖多个组件)</div>;
|
}
|
if (config.active != childIndex) return null;
|
return (
|
<a-col>
|
{tip}
|
<a-row gutter={props.formConf.gutter || 15}>
|
<draggable
|
animation={300}
|
class="drag-wrapper"
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
style="padding-top:12px"
|
v-model={item.__config__.children}
|
v-slots={slots}
|
/>
|
</a-row>
|
</a-col>
|
);
|
})}
|
</div>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (element.__config__.jnpfKey === 'tableGrid') {
|
if (props.showType === 'app') {
|
return (
|
<a-col data-draggable={true} draggable={false} span={24}>
|
<a-row
|
class={`${className} pt-[30px]`}
|
gutter={element.__config__.gutter}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}>
|
<span class="component-name">{config.label}</span>
|
<div class="drag-wrapper tableGrid-app-wrapper">
|
<div class="row-tip">请在桌面端设计表格(移动端不支持)</div>
|
</div>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
return (
|
<a-col data-draggable={true} draggable={false} span={config.span}>
|
<a-row
|
class={`${className} drawing-row-item-row drawing-row-item-table-grid`}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}>
|
<table class="table-grid">
|
<tbody>
|
{element.__config__.children.map((item, rowIndex) => {
|
return (
|
<tr>
|
{item.__config__.children.map((it, colIndex) => {
|
const slots = {
|
item: ({ element: childElement, index }) => {
|
return renderChildren(childElement, index, it.__config__.children);
|
},
|
};
|
const childGroup = { name: 'componentsGroup', put: (...arg) => put(...arg, it) };
|
const onChildEnd = (...arg) => end(...arg, activeData, it);
|
const childClassName = props.activeId === it.__config__.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item';
|
if (it.__config__.merged) return '';
|
return (
|
<td
|
class={childClassName}
|
colspan={it.__config__.colspan || 1}
|
onClick={(event) => {
|
onActiveItem(it);
|
event.stopPropagation();
|
}}
|
rowspan={it.__config__.rowspan || 1}>
|
<a-col>
|
<a-row>
|
<draggable
|
animation={300}
|
class="drag-wrapper table-cell"
|
group={childGroup}
|
item-key="renderKey"
|
onEnd={onChildEnd}
|
v-model={it.__config__.children}
|
v-slots={slots}></draggable>
|
</a-row>
|
</a-col>
|
{components.cellSetting(element, rowIndex, colIndex)}
|
</td>
|
);
|
})}
|
</tr>
|
);
|
})}
|
</tbody>
|
</table>
|
{components.itemBtns(element, index, parent, true)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
const group = { name: 'componentsGroup', put: (...arg) => put(...arg, element) };
|
const onEnd = (...arg) => end(...arg, activeData, element);
|
const slots = {
|
item: ({ element: childElement, index }) => {
|
return renderChildren(childElement, index, config.children);
|
},
|
};
|
let tip: Element | JSX.Element | null = null;
|
if (!config.children.length) {
|
tip = <div class="row-tip">请将组件拖到此区域(可拖多个组件)</div>;
|
}
|
|
if (config.jnpfKey === 'row' || (props.showType === 'app' && config.jnpfKey === 'card')) {
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={`${className} drawing-row-item-row`}>
|
<span class="component-name">{config.jnpfKey === 'card' ? config.label : config.componentName}</span>
|
<a-col>
|
<a-row class="child-drawing-row" gutter={props.formConf.gutter || 15}>
|
{tip}
|
<draggable
|
animation={300}
|
class="drag-wrapper"
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
style="padding-top:30px"
|
v-model={config.children}
|
v-slots={slots}></draggable>
|
</a-row>
|
</a-col>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'table') {
|
let basicHelp: any = null;
|
if (config.label && config.tipLabel) basicHelp = <BasicHelp text={config.tipLabel} />;
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={`${className} drawing-row-item-table`}>
|
<span class="component-name">
|
{config.label}
|
{basicHelp}
|
</span>
|
{tip}
|
<a-form
|
colon={false}
|
labelAlign={props.formConf.labelPosition === 'right' ? 'right' : 'left'}
|
layout={props.showType === 'app' ? (props.formConf.labelPosition === 'top' ? 'vertical' : 'horizontal') : 'vertical'}>
|
<draggable
|
animation={300}
|
class={`drag-wrapper table-wrapper ${props.showType === 'app' ? '' : 'table-wrapper-web'}`}
|
clone={cloneComponent}
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
v-model={config.children}
|
v-slots={slots}></draggable>
|
</a-form>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'card') {
|
let basicHelp: any = null;
|
if (config.tipLabel) basicHelp = <BasicHelp text={config.tipLabel} />;
|
const cardSlots = {
|
title: () => {
|
if (!element.header) return null;
|
return (
|
<span>
|
{element.header}
|
{basicHelp}
|
</span>
|
);
|
},
|
};
|
return (
|
<a-col
|
data-draggable={true}
|
draggable={false}
|
onClick={(event) => {
|
onActiveItem(element);
|
event.stopPropagation();
|
}}
|
span={props.showType === 'app' ? 24 : config.span}>
|
<a-row class={className}>
|
<a-card hoverable={element.shadow === 'hover'} size={props.formConf.size} v-slots={cardSlots}>
|
<a-col>
|
<a-row class="child-drawing-row" gutter={props.formConf.gutter || 15}>
|
{tip}
|
<draggable
|
animation={300}
|
class="drag-wrapper"
|
group={group}
|
item-key="renderKey"
|
onEnd={onEnd}
|
v-model={config.children}
|
v-slots={slots}></draggable>
|
</a-row>
|
</a-col>
|
</a-card>
|
{components.itemBtns(element, index, parent)}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
return null;
|
},
|
};
|
|
function cloneComponent(origin) {
|
activeData = origin;
|
return origin;
|
}
|
|
function renderChildren(element, index, parent) {
|
const layout = layouts[element.__config__.layout];
|
if (layout) {
|
return layout(element, index, parent);
|
}
|
return null;
|
}
|
|
return () => {
|
const layout = layouts[props.element.__config__.layout];
|
if (layout) {
|
return layout(props.element, props.index, props.drawingList);
|
}
|
return null;
|
};
|
},
|
});
|
</script>
|