表单设计UI、表单发布-添加编号重复检验

zzq
滕嵩 2024-06-12 17:51:25 +08:00
parent 770bef07ce
commit f5a4eaa968
9 changed files with 323 additions and 65 deletions

View File

@ -25,6 +25,8 @@ enum Api {
Post_UpdateForm = '/api/FormModule/UpdateForm', Post_UpdateForm = '/api/FormModule/UpdateForm',
// 获取字典分类列表 // 获取字典分类列表
Get_SysDataItemLoad = '/api/SysDataItem/Load', Get_SysDataItemLoad = '/api/SysDataItem/Load',
// 判断数据表字段重复
Get_ExistFiled = '/api/FormModule/ExistFiled',
} }
// 获取分页列表 // 获取分页列表
@ -78,3 +80,11 @@ export function Get_SysDataItemLoad() {
url: Api.Get_SysDataItemLoad, url: Api.Get_SysDataItemLoad,
}); });
} }
// 判断数据表字段重复
export function Get_Get_ExistFiled(params) {
return defHttp.get<responsesmodel>({
url: Api.Get_ExistFiled,
params,
});
}

View File

@ -31,6 +31,10 @@
* Delayed loading time * Delayed loading time
*/ */
lazyTime: { type: Number, default: 0 }, lazyTime: { type: Number, default: 0 },
/**
* Title is Bold?
*/
isTitleBold: { type: Boolean, default: false },
}; };
export type CollapseContainerProps = ExtractPropTypes<typeof collapseContainerProps>; export type CollapseContainerProps = ExtractPropTypes<typeof collapseContainerProps>;
@ -65,6 +69,7 @@
v-slots={{ v-slots={{
title: slots.title, title: slots.title,
action: slots.action, action: slots.action,
isTitleBold: slots.isTitleBold,
}} }}
/> />

View File

@ -6,6 +6,7 @@
const collapseHeaderProps = { const collapseHeaderProps = {
prefixCls: String, prefixCls: String,
title: String, title: String,
isTitleBold: Boolean,
show: Boolean, show: Boolean,
canExpan: Boolean, canExpan: Boolean,
helpMessage: { helpMessage: {
@ -24,21 +25,40 @@
setup(props, { slots, attrs, emit }) { setup(props, { slots, attrs, emit }) {
const { prefixCls } = useDesign('collapse-container'); const { prefixCls } = useDesign('collapse-container');
const _prefixCls = computed(() => props.prefixCls || unref(prefixCls)); const _prefixCls = computed(() => props.prefixCls || unref(prefixCls));
return () => ( // v-if="props.isTitleBold"
<div class={[`${unref(_prefixCls)}__header px-2 py-5`, attrs.class]}> if (props.isTitleBold) {
<BasicTitle helpMessage={props.helpMessage} normal> return () => (
{slots.title?.() || props.title} <div class={[`${unref(_prefixCls)}__header px-2 py-5`, attrs.class]}>
</BasicTitle> <BasicTitle helpMessage={props.helpMessage} normal>
<strong>{slots.title?.() || props.title}</strong>
</BasicTitle>
<div class={`${unref(_prefixCls)}__action`}> <div class={`${unref(_prefixCls)}__action`}>
{slots.action {slots.action
? slots.action({ expand: props.show, onClick: () => emit('expand') }) ? slots.action({ expand: props.show, onClick: () => emit('expand') })
: props.canExpan && ( : props.canExpan && (
<BasicArrow up expand={props.show} onClick={() => emit('expand')} /> <BasicArrow up expand={props.show} onClick={() => emit('expand')} />
)} )}
</div>
</div> </div>
</div> );
); } else {
return () => (
<div class={[`${unref(_prefixCls)}__header px-2 py-5`, attrs.class]}>
<BasicTitle helpMessage={props.helpMessage} normal>
{slots.title?.() || props.title}
</BasicTitle>
<div class={`${unref(_prefixCls)}__action`}>
{slots.action
? slots.action({ expand: props.show, onClick: () => emit('expand') })
: props.canExpan && (
<BasicArrow up expand={props.show} onClick={() => emit('expand')} />
)}
</div>
</div>
);
}
}, },
}); });
</script> </script>

View File

@ -18,7 +18,7 @@
breakpoint="md" breakpoint="md"
> >
<div class="collapseItem-box"> <div class="collapseItem-box">
<CollapseContainer title="基础控件"> <CollapseContainer title="基础控件" isTitleBold="true">
<CollapseItem <CollapseItem
:list="baseComponents" :list="baseComponents"
:handleListPush="handleListPushDrag" :handleListPush="handleListPushDrag"
@ -26,7 +26,7 @@
@handle-list-push="handleListPush" @handle-list-push="handleListPush"
/> />
</CollapseContainer> </CollapseContainer>
<CollapseContainer title="自定义控件"> <CollapseContainer title="自定义控件" isTitleBold="true">
<CollapseItem <CollapseItem
:list="customComponents" :list="customComponents"
@add-attrs="handleAddAttrs" @add-attrs="handleAddAttrs"
@ -34,7 +34,7 @@
@handle-list-push="handleListPush" @handle-list-push="handleListPush"
/> />
</CollapseContainer> </CollapseContainer>
<CollapseContainer title="布局控件"> <CollapseContainer title="布局控件" isTitleBold="true">
<CollapseItem <CollapseItem
:list="layoutComponents" :list="layoutComponents"
:handleListPush="handleListPushDrag" :handleListPush="handleListPushDrag"
@ -451,4 +451,8 @@
height: calc(100vh - 55px); height: calc(100vh - 55px);
overflow: auto; overflow: auto;
} }
.vben-basic-title {
font-weight: bold;
}
</style> </style>

View File

@ -7,20 +7,25 @@
<!-- 操作左侧区域 start --> <!-- 操作左侧区域 start -->
<div class="left-btn-box" style="text-indent: 20px"> <div class="left-btn-box" style="text-indent: 20px">
<Tooltip v-for="item in toolbarsConfigs" :title="item.title" :key="item.icon"> <Tooltip v-for="item in toolbarsConfigs" :title="item.title" :key="item.icon">
<a @click="$emit(item.event)" class="toolbar-text"> <a-button @click="$emit(item.event)" id="button">
<Icon :icon="item.icon" :style="{ fontSize: '21px' }" /> <template #icon>
</a> <Icon :icon="item.icon" :style="{ fontSize: '16px' }" />
</template>
</a-button>
</Tooltip> </Tooltip>
<Divider type="vertical" />
<Tooltip title="撤销"> <Tooltip title="撤销">
<a :class="{ disabled: !canUndo }" :disabled="!canUndo" @click="undo"> <a-button :class="{ disabled: !canUndo }" :disabled="!canUndo" @click="undo" id="button">
<Icon icon="ant-design:undo-outlined" :style="{ fontSize: '21px' }" /> <template #icon>
</a> <Icon icon="ant-design:undo-outlined" :style="{ fontSize: '16px' }" />
</template>
</a-button>
</Tooltip> </Tooltip>
<Tooltip title="重做"> <Tooltip title="重做">
<a :class="{ disabled: !canRedo }" :disabled="!canRedo" @click="redo"> <a-button :class="{ disabled: !canRedo }" @click="redo" id="button">
<Icon icon="ant-design:redo-outlined" :style="{ fontSize: '21px' }" /> <template #icon>
</a> <Icon icon="ant-design:redo-outlined" :style="{ fontSize: '16px' }" />
</template>
</a-button>
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
@ -30,7 +35,7 @@
import { defineComponent, inject, reactive, toRefs } from 'vue'; import { defineComponent, inject, reactive, toRefs } from 'vue';
import { UseRefHistoryReturn } from '@vueuse/core'; import { UseRefHistoryReturn } from '@vueuse/core';
import { IFormConfig } from '../../../typings/v-form-component'; import { IFormConfig } from '../../../typings/v-form-component';
import { Tooltip, Divider } from 'ant-design-vue'; import { Tooltip } from 'ant-design-vue';
import Icon from '@/components/Icon/Icon.vue'; import Icon from '@/components/Icon/Icon.vue';
interface IToolbarsConfig { interface IToolbarsConfig {
@ -45,7 +50,6 @@
components: { components: {
Tooltip, Tooltip,
Icon, Icon,
Divider,
}, },
setup() { setup() {
const state = reactive<{ const state = reactive<{
@ -56,7 +60,7 @@
title: '预览-支持布局', title: '预览-支持布局',
type: 'preview', type: 'preview',
event: 'handlePreview', event: 'handlePreview',
icon: 'ant-design:chrome-filled', icon: 'bi:life-preserver',
}, },
// { // {
// title: '-', // title: '-',
@ -113,9 +117,10 @@
line-height: @operating-area-height; line-height: @operating-area-height;
text-align: left; text-align: left;
a { #button {
margin: 0 5px; margin: 0 5px;
color: #666; width: 32px;
height: 32px;
&.disabled, &.disabled,
&.disabled:hover { &.disabled:hover {
@ -127,7 +132,6 @@
} }
> span { > span {
padding-left: 2px;
font-size: 14px; font-size: 14px;
} }
} }

View File

@ -1,11 +1,14 @@
.draggable-box { .draggable-box {
height: 100%; height: 100%;
overflow: auto; overflow: auto;
background-color: @background-color;
:deep(.list-main) { :deep(.list-main) {
position: relative; position: relative;
padding: 5px; padding: 5px;
overflow: hidden; overflow: hidden;
border-radius: 4px;
.moving { .moving {
position: relative; position: relative;
@ -21,7 +24,7 @@
top: 0; top: 0;
right: 0; right: 0;
width: 100%; width: 100%;
height: 5px; height: 3px;
background-color: @primary-color; background-color: @primary-color;
} }
} }
@ -33,6 +36,7 @@
padding: 8px; padding: 8px;
overflow: hidden; overflow: hidden;
transition: all 0.3s; transition: all 0.3s;
border-radius: 3px;
&:hover { &:hover {
background-color: @primary-hover-bg-color; background-color: @primary-hover-bg-color;
@ -44,14 +48,16 @@
position: absolute; position: absolute;
top: 0; top: 0;
right: -100%; right: -100%;
width: 100%; width: 0%;
height: 5px; height: 3px;
transition: all 0.3s; transition: all 0.3s;
outline: 3px solid @primary-color;
background-color: @primary-color; background-color: @primary-color;
} }
&.active { &.active {
outline-offset: 0; outline: 3px solid @primary-color;
// outline-offset: 0;
background-color: @primary-hover-bg-color; background-color: @primary-hover-bg-color;
&::before { &::before {
@ -84,7 +90,7 @@
.show-key-box { .show-key-box {
// 显示key // 显示key
position: absolute; position: absolute;
right: 5px; right: 3px;
bottom: 2px; bottom: 2px;
// z-index: 999; // z-index: 999;
color: @primary-color; color: @primary-color;
@ -133,6 +139,12 @@
overflow: hidden; overflow: hidden;
transition: all 0.3s; transition: all 0.3s;
background-color: @layout-background-color; background-color: @layout-background-color;
border-radius: 3px;
// 鼠标划过
&:hover {
background-color: @layout-hover-bg-color;
}
.form-item-box { .form-item-box {
position: relative; position: relative;
@ -170,14 +182,15 @@
position: absolute; position: absolute;
top: 0; top: 0;
right: -100%; right: -100%;
width: 100%; width: 0%;
height: 5px; height: 3px;
transition: all 0.3s; transition: all 0.3s;
background: transparent; background: transparent;
} }
&.active { &.active {
outline-offset: 0; outline: 3px solid @layout-color;
// outline-offset: 0;
background-color: @layout-hover-bg-color; background-color: @layout-hover-bg-color;
&::before { &::before {

View File

@ -1,11 +1,11 @@
// 表单设计器样式 // 表单设计器样式
@primary-color: #13c2c2; @background-color: #EBEDF1;
@layout-color: #9867f7; @primary-color: #1E5EFFFF;
@layout-color: #A91EFFFF;
@primary-background-color: fade(@primary-color, 6%); @primary-hover-bg-color: #DFEAFC;
@primary-hover-bg-color: fade(@primary-color, 20%); @layout-background-color: #E9E4F5;
@layout-background-color: fade(@layout-color, 12%); @layout-hover-bg-color: #d7d2ff;
@layout-hover-bg-color: fade(@layout-color, 24%);
@title-text-color: #fff; @title-text-color: #fff;
@border-color: #ccc; @border-color: #ccc;

View File

@ -453,7 +453,7 @@ export const baseComponents: IVFormComponent[] = [
{ {
component: 'Cascader', component: 'Cascader',
label: '级联选择', label: '级联选择',
icon: 'ant-design:check-outlined', icon: 'ant-design:block-outlined',
field: '', field: '',
colProps: { span: 24 }, colProps: { span: 24 },
componentProps: { componentProps: {

View File

@ -74,9 +74,10 @@
import { useMessage } from '@/hooks/web/useMessage'; import { useMessage } from '@/hooks/web/useMessage';
import { getMenuList } from '@/api/demo/system'; import { getMenuList } from '@/api/demo/system';
import { useI18n } from '@/hooks/web/useI18n'; import { useI18n } from '@/hooks/web/useI18n';
import { FormInstance } from 'ant-design-vue';
import ModuleModal from './modalForm-Modal.vue'; import ModuleModal from './modalForm-Modal.vue';
import { functionGetSchemePageList, functionGetForm } from '@/api/demo/formScheme'; import { functionGetSchemePageList, functionGetForm } from '@/api/demo/formScheme';
import { Get_Get_ExistFiled } from '@/api/demo/formModule';
// emit // emit
const emit = defineEmits(['change-form-verisons', 'set-steps-current']); const emit = defineEmits(['change-form-verisons', 'set-steps-current']);
@ -110,7 +111,7 @@
// //
const [registerModal, { openModal }] = useModal(); const [registerModal, { openModal }] = useModal();
// ref // ref
const formModuleRef = ref<any>(); let formModuleRef: FormInstance | null = null;
// options // options
const formVerisons = ref([]); const formVerisons = ref([]);
// options // options
@ -134,12 +135,147 @@
}); });
// //
let rules = { let rules = {
code: [{ required: true, message: '请输入' }], code: [
name: [{ required: true, message: '请输入' }], {
icon: [{ component: 'IconPicker', required: true, message: '请输入' }], required: true,
formCodeName: [{ required: true, message: '请输入' }], asyncValidator: async (rule, value, callback) => {
formVerison: [{ required: true, message: '请选择版本' }], //
pmoduleId: [{ required: true, message: '请输入' }], if (value) {
try {
let filedsJson = {
Code: formData.value.code,
};
if (props.isEdit) {
//
let query: any = {
keyValue: props.editData.record.id,
tableName: 'form_module',
keyName: 'Id',
filedsJson: JSON.stringify(filedsJson),
};
await Get_Get_ExistFiled(query).then((res) => {
if (res) {
callback();
} else {
callback(new Error('编号重复'));
}
});
} else {
//
let query: any = {
tableName: 'form_module',
keyName: 'Id',
filedsJson: JSON.stringify(filedsJson),
};
await Get_Get_ExistFiled(query).then((res) => {
if (res) {
callback();
} else {
callback(new Error('编号重复'));
}
});
}
} catch (error) {
('验证出错');
}
} else {
callback(new Error('请输入编号'));
}
},
trigger: ['blur'],
},
],
name: [
{
required: true,
validator: (rule, value, callback) => {
try {
//
if (value) {
callback();
} else {
callback(new Error('请输入名称'));
}
} catch (error) {
console.log(error);
}
},
trigger: ['blur'],
},
],
icon: [
{
component: 'IconPicker',
required: true,
validator: (rule, value, callback) => {
try {
//
if (value) {
callback();
} else {
callback(new Error('请选择图标'));
}
} catch (error) {
console.log(error);
}
},
trigger: ['blur'],
},
],
formCodeName: [
{
required: true,
validator: (rule, value, callback) => {
try {
//
if (value) {
callback();
} else {
callback(new Error('请选择表单'));
}
} catch (error) {
console.log(error);
}
},
trigger: ['blur'],
},
],
formVerison: [
{
required: true,
validator: (rule, value, callback) => {
try {
//
if (value) {
callback();
} else {
callback(new Error('请选择表单版本'));
}
} catch (error) {
console.log(error);
}
},
trigger: ['blur'],
},
],
pmoduleId: [
{
required: true,
validator: (rule, value, callback) => {
try {
//
if (value) {
callback();
} else {
callback(new Error('请选择上级'));
}
} catch (error) {
console.log(error);
}
},
trigger: ['blur'],
},
],
enabledMark: [{ required: true }], enabledMark: [{ required: true }],
}; };
@ -159,21 +295,34 @@
// props // props
watch( watch(
() => props.isNextSteps, () => props.isNextSteps,
() => { async () => {
//
if (props.isNextSteps) { if (props.isNextSteps) {
let checkdata = formData.value; // if (formModuleRef) {
// try {
// await formModuleRef.validate();
// } catch (error) {
// console.log(error);
// }
// }
if ( if (
checkdata.code === '' || formData.value.code === '' ||
checkdata.formCode === '' || formData.value.name === '' ||
checkdata.name === '' || formData.value.icon === '' ||
checkdata.formVerison === '' || formData.value.formCode === '' ||
checkdata.pmoduleId === '' formData.value.formVerison === '' ||
formData.value.pmoduleId === ''
) { ) {
createMessage.error(t('数据未填完整')); createMessage.error(t('数据未填完整'));
emit('set-steps-current', false); emit('set-steps-current', false);
} else { } else {
emit('set-steps-current', true); //
let res = await checkExistFiled();
if (res) {
emit('set-steps-current', true);
} else {
createMessage.error(t('表单的编号值重复'));
emit('set-steps-current', false);
}
} }
} }
}, },
@ -238,6 +387,59 @@
getSchemeRow(result.info); getSchemeRow(result.info);
} }
//
async function checkExistFiled() {
try {
let filedsJson = {
Code: formData.value.code,
};
let result = false;
if (props.isEdit) {
//
let query: any = {
keyValue: props.editData.record.id,
tableName: 'form_module',
keyName: 'Id',
filedsJson: JSON.stringify(filedsJson),
};
await Get_Get_ExistFiled(query)
.then((res) => {
if (res) {
result = true;
} else {
result = false;
}
})
.catch((error) => {
createMessage.error('验证出错' + error);
result = true;
});
} else {
//
let query: any = {
tableName: 'form_module',
keyName: 'Id',
filedsJson: JSON.stringify(filedsJson),
};
await Get_Get_ExistFiled(query)
.then((res) => {
if (res) {
result = true;
} else {
result = false;
}
})
.catch((error) => {
createMessage.error('验证出错' + error);
result = false;
});
}
return result;
} catch (error) {
('验证出错');
}
}
defineExpose({ defineExpose({
formData, formData,
}); });