|
@@ -0,0 +1,455 @@
|
|
|
+<template>
|
|
|
+ <el-col class="cus-form-column" :class="{
|
|
|
+ span1: filterSpan == 1,
|
|
|
+ span2: filterSpan == 2,
|
|
|
+ span3: filterSpan == 3,
|
|
|
+ span4: filterSpan == 4,
|
|
|
+ span5: filterSpan == 5,
|
|
|
+ }" :span="span" :offset="offset" ref="ref_cusFormColumn">
|
|
|
+ <el-form-item :label="label" :label-width="labelWidth" :class="{ required: required !== false }"
|
|
|
+ :error="errorMessage" :required="required">
|
|
|
+ <slot name="cus" :handleValidate="handleValidate">
|
|
|
+ <template v-if="link === 'input'">
|
|
|
+ <InputCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ @emitEnter="handleEnter"
|
|
|
+ >
|
|
|
+ <template v-if="$slots.prefix" #prefix>
|
|
|
+ <slot name="prefix"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.suffix" #suffix>
|
|
|
+ <slot name="suffix"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.prepend" #prepend>
|
|
|
+ <slot name="prepend"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.append" #append>
|
|
|
+ <slot name="append"/>
|
|
|
+ </template>
|
|
|
+ </InputCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'select'">
|
|
|
+ <SelectCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <slot/>
|
|
|
+ </SelectCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'date'">
|
|
|
+ <DateCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template #default="{cell}">
|
|
|
+ <slot v-bind="cell"/>
|
|
|
+ </template>
|
|
|
+ </DateCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'datetime'">
|
|
|
+ <DateTimeCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template #default="{cell}">
|
|
|
+ <slot v-bind="cell"/>
|
|
|
+ </template>
|
|
|
+ </DateTimeCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'time'">
|
|
|
+ <TimeCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ </TimeCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'cascader'">
|
|
|
+ <CascaderCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template v-if="$slots.default" #default="{node, data}">
|
|
|
+ <slot v-bind="{node, data}"/>
|
|
|
+ </template>
|
|
|
+ </CascaderCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'switch'">
|
|
|
+ <SwitchCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ </SwitchCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'radio'">
|
|
|
+ <RadioCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ </RadioCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'checkbox'">
|
|
|
+ <CheckboxCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ </CheckboxCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'portOfRegistry'">
|
|
|
+ <PortOfRegistryCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :paramOne="paramOne"
|
|
|
+ :paramTwo="paramTwo"
|
|
|
+ @emitParam="(pOne, pTwo) => {
|
|
|
+ $emit('update:paramOne', pOne), $emit('update:paramTwo', pTwo), handleValidate(pOne, pTwo)
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'residentMooringPoint'">
|
|
|
+ <ResidentMooringPointCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :paramOne="paramOne"
|
|
|
+ :paramTwo="paramTwo"
|
|
|
+ @emitParam="(pOne, pTwo) => {
|
|
|
+ $emit('update:paramOne', pOne), $emit('update:paramTwo', pTwo), handleValidate(pOne, pTwo)
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'dept'">
|
|
|
+ <DeptCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ @emitDefault="val => $emit('getDefault', val)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'upload'">
|
|
|
+ <UploadCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'number'">
|
|
|
+ <NumberCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ @emitEnter="handleEnter"
|
|
|
+ >
|
|
|
+ <template v-if="$slots.prefix" #prefix>
|
|
|
+ <slot name="prefix"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.suffix" #suffix>
|
|
|
+ <slot name="suffix"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.prepend" #prepend>
|
|
|
+ <slot name="prepend"/>
|
|
|
+ </template>
|
|
|
+ <template v-if="$slots.append" #append>
|
|
|
+ <slot name="append"/>
|
|
|
+ </template>
|
|
|
+ </NumberCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'input-number'">
|
|
|
+ <InputNumberCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ @emitEnter="handleEnter"
|
|
|
+ >
|
|
|
+ </InputNumberCom>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="link === 'tree-select'">
|
|
|
+ <TreeSelectCom
|
|
|
+ v-bind="$attrs"
|
|
|
+ :label="labelCpt"
|
|
|
+ :param="param"
|
|
|
+ @emitParam="val => {
|
|
|
+ $emit('update:param', val), handleValidate(val)
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ </TreeSelectCom>
|
|
|
+ </template>
|
|
|
+ </slot>
|
|
|
+ <div v-if="unit" class="unit">{{unit}}</div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ computed,
|
|
|
+ onMounted,
|
|
|
+ ref,
|
|
|
+ reactive,
|
|
|
+ watch,
|
|
|
+ getCurrentInstance,
|
|
|
+ ComponentInternalInstance,
|
|
|
+ toRefs,
|
|
|
+ nextTick
|
|
|
+} from 'vue'
|
|
|
+import {useStore} from 'vuex'
|
|
|
+import {useRouter, useRoute} from 'vue-router'
|
|
|
+import InputCom from './cus-form-link/input.vue'
|
|
|
+import InputNumberCom from './cus-form-link/input-number.vue'
|
|
|
+import SelectCom from './cus-form-link/select.vue'
|
|
|
+import DateCom from './cus-form-link/date.vue'
|
|
|
+import DateTimeCom from './cus-form-link/datetime.vue'
|
|
|
+import TimeCom from './cus-form-link/time.vue'
|
|
|
+import CascaderCom from './cus-form-link/cascader.vue'
|
|
|
+import SwitchCom from './cus-form-link/switch.vue'
|
|
|
+import RadioCom from './cus-form-link/radio.vue'
|
|
|
+import CheckboxCom from './cus-form-link/checkbox.vue'
|
|
|
+import PortOfRegistryCom from './cus-form-link/portOfRegistry.vue'
|
|
|
+import ResidentMooringPointCom from './cus-form-link/residentMooringPoint.vue'
|
|
|
+import DeptCom from './cus-form-link/dept.vue'
|
|
|
+import UploadCom from './cus-form-link/upload.vue'
|
|
|
+import NumberCom from './cus-form-link/number.vue'
|
|
|
+import TreeSelectCom from './cus-form-link/tree-select.vue'
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'CusFormColumn',
|
|
|
+ components: {
|
|
|
+ InputCom,
|
|
|
+ InputNumberCom,
|
|
|
+ SelectCom,
|
|
|
+ DateCom,
|
|
|
+ DateTimeCom,
|
|
|
+ TimeCom,
|
|
|
+ CascaderCom,
|
|
|
+ SwitchCom,
|
|
|
+ RadioCom,
|
|
|
+ CheckboxCom,
|
|
|
+ PortOfRegistryCom,
|
|
|
+ ResidentMooringPointCom,
|
|
|
+ DeptCom,
|
|
|
+ UploadCom,
|
|
|
+ NumberCom,
|
|
|
+ TreeSelectCom
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ span: {type: Number, default: 6},
|
|
|
+ filterSpan: { default: null },
|
|
|
+ offset: {type: Number, default: 0},
|
|
|
+ param: {},
|
|
|
+ paramOne: {},
|
|
|
+ paramTwo: {},
|
|
|
+ label: {type: String, default: ''},
|
|
|
+ required: {default: false},
|
|
|
+ labelWidth: {type: String, default: ''},
|
|
|
+ link: {type: String, default: 'input', validator(val: string) {
|
|
|
+ return ['cascader', 'checkbox', 'date', 'datetime', 'input', 'radio', 'select', 'switch', 'portOfRegistry', 'residentMooringPoint', 'dept', 'time', 'upload', 'number', 'input-number', 'tree-select'].includes(val)
|
|
|
+ }},
|
|
|
+ rules: {type: Array, default: () => []},
|
|
|
+ maxLength: {type: Number, default: null},
|
|
|
+ minLength: {type: Number, default: null},
|
|
|
+ defaultErrorMsg: {default: null},
|
|
|
+ unit: {default: '', type: String}
|
|
|
+ },
|
|
|
+ setup(props) {
|
|
|
+ const store = useStore();
|
|
|
+ const router = useRouter();
|
|
|
+ const route = useRoute();
|
|
|
+ const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
|
|
|
+ const state = reactive({
|
|
|
+ errorMessage: null
|
|
|
+ })
|
|
|
+ const ref_cusFormColumn: any = ref(null)
|
|
|
+ const isValue = (val: any) => {
|
|
|
+ if (val === null || val === undefined || (typeof val === 'string' && val.trim() === '') || (typeof val === 'object' && val?.length === 0)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ const labelCpt = computed(() => {
|
|
|
+ return props.label.replace(/[::]([^::]*)$/, "")
|
|
|
+ })
|
|
|
+ const rulesCpt = computed(() => {
|
|
|
+ const r = [...props.rules]
|
|
|
+ if (isValue(props.minLength)) {
|
|
|
+ r.unshift({
|
|
|
+ handle: (val: any) => !isValue(val) || (isValue(val) && String(val).length >= props.minLength),
|
|
|
+ message: `内容过短,字数需大于等于${props.minLength}`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (isValue(props.maxLength)) {
|
|
|
+ r.unshift({
|
|
|
+ handle: (val: any) => !isValue(val) || (isValue(val) && String(val).length <= props.maxLength),
|
|
|
+ message: `内容过长,字数需小于等于${props.maxLength}`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ const doStr = ['input', 'number', 'input-number'].includes(props.link) ? '输入' : '选择'
|
|
|
+ if (props.required !== false && !props.rules.some((v: any) => v.type === 'default')) {
|
|
|
+ if (['portOfRegistry', 'residentMooringPoint'].includes(props.link)) {
|
|
|
+ r.unshift({
|
|
|
+ handle: (pOne: any, pTwo: any) => isValue(pOne) && isValue(pTwo),
|
|
|
+ message: props.defaultErrorMsg ?? `请${doStr}${labelCpt.value}`
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ r.unshift({
|
|
|
+ handle: (val: any) => isValue(val),
|
|
|
+ message: props.defaultErrorMsg ?? `请${doStr}${labelCpt.value}`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return r
|
|
|
+ })
|
|
|
+ const handleValidate = (val: any = undefined, val2: any = undefined) => {
|
|
|
+ state.errorMessage = null
|
|
|
+ for (let i = 0; i < rulesCpt.value.length; i++) {
|
|
|
+ const item: any = rulesCpt.value[i]
|
|
|
+ if (['portOfRegistry', 'residentMooringPoint'].includes(props.link)) {
|
|
|
+ if (!item.handle(val === undefined ? props.paramOne : val, val2 === undefined ? props.paramTwo : val2)) {
|
|
|
+ state.errorMessage = item.message
|
|
|
+ break
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!item.handle(val === undefined ? props.param : val)) {
|
|
|
+ state.errorMessage = item.message
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return state.errorMessage
|
|
|
+ }
|
|
|
+ const handleEnter = () => {
|
|
|
+ const find = (itemVue: any) => {
|
|
|
+ if (itemVue?.type.name === "CusForm") {
|
|
|
+ itemVue.setupState.handleEnter()
|
|
|
+ } else {
|
|
|
+ find(itemVue.parent)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ find(ref_cusFormColumn?.value?.$el?.__vueParentComponent)
|
|
|
+ }
|
|
|
+ const reset = () => {
|
|
|
+ state.errorMessage = null
|
|
|
+ }
|
|
|
+ watch(() => state.errorMessage, (n) => {
|
|
|
+ const p = ref_cusFormColumn.value?.$el?.getElementsByClassName('el-form-item')?.[0]
|
|
|
+ if (n) {
|
|
|
+ setTimeout(() => {
|
|
|
+ const e = p?.getElementsByClassName('el-form-item__content')?.[0]?.getElementsByClassName('el-form-item__error')?.[0]
|
|
|
+ if (e?.clientHeight) {
|
|
|
+ p.style.marginBottom = `${e.clientHeight + 4}px`
|
|
|
+ }
|
|
|
+ }, 200)
|
|
|
+ } else {
|
|
|
+ p.style.marginBottom = '18px'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return {
|
|
|
+ ...toRefs(state),
|
|
|
+ handleValidate,
|
|
|
+ handleEnter,
|
|
|
+ ref_cusFormColumn,
|
|
|
+ reset,
|
|
|
+ labelCpt
|
|
|
+ }
|
|
|
+ },
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.cus-form-column {
|
|
|
+ &.span1 {
|
|
|
+ width: 20%;
|
|
|
+ max-width: 20%;
|
|
|
+ flex: unset;
|
|
|
+ }
|
|
|
+ &.span2 {
|
|
|
+ width: 40%;
|
|
|
+ max-width: 40%;
|
|
|
+ flex: unset;
|
|
|
+ }
|
|
|
+ &.span3 {
|
|
|
+ width: 60%;
|
|
|
+ max-width: 60%;
|
|
|
+ flex: unset;
|
|
|
+ }
|
|
|
+ &.span4 {
|
|
|
+ width: 80%;
|
|
|
+ max-width: 80%;
|
|
|
+ flex: unset;
|
|
|
+ }
|
|
|
+ &.span5 {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 100%;
|
|
|
+ flex: unset;
|
|
|
+ }
|
|
|
+ :deep(.el-form-item) {
|
|
|
+ .el-form-item__label {
|
|
|
+ line-height: 1;
|
|
|
+ text-align: right;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding-left: 10px;
|
|
|
+ }
|
|
|
+ .el-form-item__content {
|
|
|
+ flex-wrap: unset;
|
|
|
+ >div:first-child {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ .unit {
|
|
|
+ margin-left: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-family: PingFang SC-Regular, PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|