Files
pj_admin_cloud/src/views/flow/form/index.vue
T

272 lines
6.9 KiB
Vue

<template>
<el-container>
<el-aside width="400px">
<div effect="dark">
<h4 style="text-align: center">{{ $t('flow.componentLibrary') }}</h4>
<div v-for="item in oriFormList" :key="item.id">
<h5 style="padding-left: 60px">{{ $i18n.locale === 'en' ? item.type : item.name }}</h5>
<draggable
v-model="item.formList"
ghost-class="ghost"
:force-fallback="true"
item-key="index"
:sort="false"
@end="dragEnd"
@start="drag = true"
class="leftItem"
:animation="300"
:group="{ name: 'dragFormList', pull: 'clone', put: false }"
:clone="cloneFunc"
>
<template #item="{ element }">
<div class="zj">
<el-button size="large" style="width: 100%" :icon="element.icon">{{ $i18n.locale === 'en' ? element.type : element.name }}</el-button>
</div>
</template>
</draggable>
</div>
</div>
</el-aside>
<el-main>
<div style="display: flex; flex-direction: row">
<div class="f11">
<el-form label-position="top">
<draggable
v-model="targetList"
class="drag-content"
item-key="index"
:sort="true"
effect="dark"
:group="{ name: 'dragFormList', pull: true, put: true }"
@change="dragChanged"
>
<template #item="{ element, index }">
<div class="border okcomponent line" effect="dark" @click.stop="showCurrentPageConfigPanel(element.id)">
<el-icon v-if="element.type != 'Empty'" class="deleteIcon" @click.stop="deleteForm(element.id)">
<Delete />
</el-icon>
<el-form-item :label="step2Object[element.id]?.name" :required="step2Object[element.id]?.required">
<component
style="width: 100%"
@showPanel="showPanel"
:index="index"
:is="getFormWidget(element.type)"
:id="element.id"
v-model:form="step2Object[element.id]"
></component>
</el-form-item>
</div>
</template>
</draggable>
</el-form>
</div>
<el-drawer v-model="drawer">
<template #header>
<div class="card-header">
{{ currentForm?.typeName }}
</div>
</template>
<el-form label-width="120px" label-position="top">
<el-form-item required label="字段ID">
<el-input v-model="currentForm.id" maxlength="50" />
</el-form-item>
<el-form-item required :label="$t('flow.title')">
<el-input v-model="currentForm.name" maxlength="10" />
</el-form-item>
<el-form-item :label="$t('flow.tips')" :required="currentForm?.type === 'Description'">
<el-input v-model="currentForm.placeholder" maxlength="50" />
</el-form-item>
<component :is="getFormConfigWidget(currentForm?.type)" :id="currentForm?.id" ref="currentFormConfigRef"></component>
<el-form-item :label="$t('flow.other')">
<el-checkbox v-model="currentForm.required" :label="$t('flow.required')" />
</el-form-item>
</el-form>
</el-drawer>
</div>
</el-main>
</el-container>
</template>
<script lang="ts" setup name="flow-form-designer">
import getFormName from '/@/views/flow/form/tools/utils/getFormWidget';
import getFormConfigName from '/@/views/flow/form/tools/utils/getFormConfigWidget';
import { formValidateDict } from '/@/views/flow/form/tools/utils/formValidate';
import { Delete } from '@element-plus/icons-vue';
import { useFlowStore } from '../workflow/stores/flow';
import draggable from 'vuedraggable';
import { FormGroupVO } from '/@/views/flow/form/const/types';
import { formGroupConfig } from '/@/views/flow/form/const/data';
import { computed } from 'vue';
import other from '/@/utils/other';
const drag = ref(false);
const currentForm = ref();
const drawer = ref(false);
let oriFormList = ref<FormGroupVO[]>(formGroupConfig);
const flowStore = useFlowStore();
const currentFormConfigRef = ref();
const step2List = computed(() => flowStore.step2);
const step2Object = computed(() => {
const obj = {};
step2List.value.forEach((res) => (obj[res.id] = res));
return obj;
});
const cloneFunc = (el) => {
el.id = other.getNonDuplicateID();
return el;
};
const deleteForm = (id) => {
const existForm = flowStore.step2.find((res) => res.id === id);
if (existForm?.type === 'Layout' && currentForm.value) {
//明细
const value = existForm.props.value;
const filter = value.filter((res) => res.id === currentForm.value.id);
if (filter.length > 0) {
currentForm.value = undefined;
}
}
flowStore.setStep2(flowStore.step2.filter((res) => res.id !== id));
if (currentForm.value && currentForm.value?.id === id) {
currentForm.value = undefined;
}
};
const showCurrentPageConfigPanel = (id) => {
currentForm.value = flowStore.step2.find((res) => res.id === id);
drawer.value = true;
};
const showPanel = (form) => {
currentForm.value = form;
};
const getFormWidget = (name) => {
//写的时候,组件的起名一定要与dragList中的element名字一模一样,不然会映射不上
return getFormName[name];
};
const getFormConfigWidget = (name) => {
//写的时候,组件的起名一定要与dragList中的element名字一模一样,不然会映射不上
return getFormConfigName[name];
};
const { proxy } = getCurrentInstance();
const dragEnd = (a) => {
drag.value = false;
oriFormList.value = other.deepClone(oriFormList.value);
};
const dragChanged = (a) => {};
const targetList = computed({
get: () => {
const value = flowStore.step2;
if (value?.length == 0) {
return [
{
type: 'Empty',
name: '',
},
];
}
return value;
},
set: (v) => {
const value = v.filter((res) => res.type != 'Empty');
flowStore.setStep2(value);
},
});
const validate = (f) => {
const err = [];
const formList = step2List.value;
if (formList.length == 0) {
err.push('表单不能为空');
}
console.log(formList);
for (let form of formList) {
const count = formList.filter((item) => item.id === form.id).length;
if (count > 1) {
err.push(`发现字段ID重复: ${form.id}`);
}
const formValidateDictElement = formValidateDict[form.type];
if (formValidateDictElement) {
const result = formValidateDictElement(form, proxy);
if (!result.valid) {
err.push(result.msg);
}
}
}
const newList = Array.from(new Set(formList.map((res) => res.name)));
if (newList.length < formList.length) {
err.push('表单名称不能重复');
}
f(err.length == 0, err);
};
defineExpose({ validate });
</script>
<style scoped lang="scss">
$width: 140px;
$f22_width: 400px;
$center_width: 360px;
.leftItem {
padding-left: 50px;
}
.zj {
display: inline-block;
width: $width;
margin: 5px;
}
.drag-content {
border: 1px solid;
width: $center_width;
border-radius: 10px;
padding: 10px 10px;
}
.f11 {
width: calc(100% - #{$f22_width});
}
.f22 {
width: $f22_width;
}
.okcomponent {
padding: 5px;
border-radius: 5px;
margin-bottom: 10px;
}
.deleteIcon {
margin-left: calc(#{$center_width} - 50px);
z-index: 20;
}
.deleteIcon:hover {
cursor: pointer;
color: palevioletred;
}
</style>