校验表格中的多个表单

news2025/3/3 5:12:55

 要实现的效果是:  点击保存回校验当前页面的所有输入框

首先 分成两个上下两个子组件,

        上面的子组件是一个表单包括规则名称和区域

         下面的子组件是一个表格,表格可以是多行的,需要校验每一行的输入框

 

父组件调用两个子组件的校验方法, 第一个子组件可以直接校验,第二个子组件在分别调用下面的子组件

最外层-父组件

<template>
    <div>
            <!-- 基础信息 -->
            <baseForm
                ref="baseFormRef"
                :mode="mode"
                @cityUpdate="cityUpdate"
            />
            <h3>规则配置</h3>
            <ruleConfigurationTable
                ref="ruleConfigRef"
                v-model="detailsData.ruleConfigModels"
                :mode="mode"
                :details-data="detailsData"
            />
            <div>
                <el-button @click="saveRule" > 保存 </el-button>
            </div>
    </div>

</template>

<script>
import {
    defineComponent, reactive, toRefs, getCurrentInstance,
} from 'vue';
import baseForm from '../components/BaseForm';
import ruleConfigurationTable from '../components/RuleConfigurationTable';
import { ruleDefaultData } from '../constants';

export default defineComponent({
    name: 'PriceComparisonRulesManagement',
    components: {
        baseForm,
        ruleConfigurationTable,
    },
    setup() {
        const { proxy } = getCurrentInstance();
        const mode = proxy.$query.get('mode') || '';
        const id = +proxy.$query.get('id') || '';

        // 如果是创建,默认输入框都是空
        const detailsData = mode === 'create' ? ruleDefaultData : {};

        const initData = reactive({
            mode,
            detailsData,
        });

        // 详情接口
        const initialization = async () => {
            try {
                const ruleDetail = await proxy.$hPost('/detail', {id});

                // 基础信息,这里调用子组件的setFormData对每个输入框进行赋值
                const { ruleName, managementCityId } = ruleDetail;
                proxy.$refs.baseFormRef?.setFormData({ ruleName, managementCityId });
                // 规则配置,这里赋值给一个变量,然后传递给子组件
                initData.detailsData = ruleDetail;
            } catch (e) {
                console.log(e);
            }
        };
        initialization();

        // 返回
        const cancel = () => {//自定义返回地址};

        // 保存规则接口
        const saveCompetition = async () => {
            try {
                const params = {
                    ...initData.detailsData,
                };
                // 拿基础信息输入框的信息
                const { managementCityId, managementCityName, ruleName } = await proxy.$refs.baseFormRef?.getUpdatedFormData();
                Object.assign(params, { managementCityId, managementCityName, ruleName });
                
                await proxy.$hPost('/price/parity/rule/insertOrUpdate', params);
                
                cancel();
            } catch (e) {
                console.log(e);
            }
        };

        // 保存规则校验
        const saveRule = async () => {
            // 校验基础信息   
            const res1 = await proxy.$refs.baseFormRef?.validate().catch(() => false);    
            // 规则配置  
            const res2 = await proxy.$refs.ruleConfigRef?.validate().catch(() => false);
            if (!res1 || !res2) return false;
            // 如果这两个子组件通过校验的话, 那么就可以调保存接口了
            saveCompetition();
        }
        return {
            ...toRefs(initData),
            cancel,
            saveRule,
            cityUpdate,
        };
    },
});

</script>

constants.js

// 竞价规则初始化数据
export const ruleDefaultData = {
    id: '',
    ruleName: '', // 规则名称,比价区域城市名/ID
    managementCityId: '',
    managementCityName: '',
    ruleConfigModels: [
        {
            procurementOrgIds: [], // 第一列 组织
            strategyConfigByCategories: [ // 第二列 商品分层
                {
                    priceType: 2, // 对标价格类型
                    productType: [], // 第三列
                    cptType: [], // 竞对设置
                },
            ],
        },
    ],
};


// 规则配置表头
export function ruleConfigurationTableHeader() {
    return [
        {
            label: '商品所属组织',
            width: '20%',
        },
        {
            label: '商品分层',
            width: '20%',
        },
        {
            label: '对标价格类型',
            width: '20%',
        },
        {
            label: '竞对设置',
            width: '40%',
        },
    ];
}

baseForm - 子组件

<template>
    <el-form
        ref="baseFormRef"
        :model="formData"
        :rules="rules"
        label-width="100px"
    >
        <el-form-item
            label="规则名称"
            prop="ruleName"
        >
            <el-input
                v-model="formData.ruleName"
            />
        </el-form-item>
        <el-form-item
            label="比价区域"
            prop="managementCityId"
        >
            <!-- 这里其实就是el-selsct -->
            <manageCitySelect
                ref="manageCitySelectRef"
                v-model="formData.managementCityId"
            />
        </el-form-item>
    </el-form>
</template>
<script>

const getBaseFormRules = () => ({
    ruleName: [
        { required: true, message: '请输入规则名称', trigger: 'blur' },
    ],
    managementCityId: [
        { required: true, message: '请选择比价区域', trigger: 'blur' },
    ],
});

import manageCitySelect from 'components/ManageCitySelect';
import {
    defineComponent, computed, getCurrentInstance, reactive, toRefs,
} from 'vue';

// 获取初始化的数据
import {
    ruleDefaultData,
} from '../constants';

export default defineComponent({
    name: 'BaseForm',
    components: {
        manageCitySelect,
    },
    setup() {
        const { proxy } = getCurrentInstance();
        const initData = reactive({
            formData: ruleDefaultData,
        });

        // 自动校验
        const rules = computed(() => getBaseFormRules());

        // 手动校验, 父组件点击保存的时候调用validate方法
        const validate = () => proxy.$refs.baseFormRef?.validate();

        // 回显. 父组件调用setFormData把数据带过来
        const setFormData = (newFormData) => {
            Object.assign(initData.formData, newFormData);
        };

        // 父组件点击保存的时候调用getUpdatedFormData获取最新数据
        const getUpdatedFormData = async () => {
            const { formData } = initData;
            return { ...formData };
        };

        return {
            ...toRefs(initData),
            rules,
            validate,
            setFormData,
            getUpdatedFormData,
        };
    },
});
</script>

RuleConfigurationTable  子组件

<template>
    <div class="content">
        <dl class="multi-level-table">
            <dt>
                <div
                    v-for="(column, c1) in columns"
                    :key="c1"
                    class="th"
                    :style="`width: ${column.width}`"
                >
                    <span v-text="column.label"></span>
                </div>
            </dt>
            <dd
                v-for="(item, i) in detailsData.ruleConfigModels"
                :key="`${i}_1`"
            >
                <!-- 第一行的第一个表格---所属组织-->
                <div
                    class="td p10"
                    :style="`width: ${columns[0].width}`"
                >
                    <BelongOrganization
                        ref="purchasingOrganizationRef"
                        v-model="item.procurementOrgIds"
                        :index="i"
                        :details-data="detailsData"
                    />

                    <AddDelButtonGroup
                        :index-list="[i]"
                        :disabled="detailsData.ruleConfigModels.length === 1"
                        @operator="operatorRow"
                    />
                </div>
                <!-- 第一行的第二个表格  商品分层-->
                <div
                    v-for="(strategy, s) in item.strategyConfigByCategories"
                    :key="`${s}_2`"
                    class="td-line"
                >
                    <div
                        class="td p10"
                        :style="`width: ${columns[1].width}`"
                    >
                        <GoodsStratification
                            ref="commodityStratification"
                            v-model="strategy.productType"
                            :strategy-config-by-categories="item.strategyConfigByCategories"
                        />

                        <AddDelButtonGroup
                            :index-list="[i, s]"
                            :disabled="item.strategyConfigByCategories.length === 1"
                            @operator="operatorRow"
                        />
                    </div>
                    <!-- 第一行的第三个表格     对标价格类型 -->
                    <div
                        class="td p10"
                        :style="`width: ${columns[2].width};`"
                    >
                        <div
                            class="td p10"
                            :style="`width: ${columns[2].width};`"
                        >
                            <!-- 忽略 -->
                        </div>
                    </div>
                    <!-- 第一行的第四个表格 -->
                    <div
                        class="p10 td"
                        :style="`width: ${columns[3].width}`"
                    >
                        <!-- 忽略 -->
                    </div>
                </div>
            </dd>
        </dl>
    </div>
</template>

<script>
import {
    defineComponent, getCurrentInstance, reactive, toRefs,
} from 'vue';
import {
    ruleConfigurationTableHeader, ruleDefaultData,
} from '../constants';
import AddDelButtonGroup from './AddDelButtonGroup';
import GoodsStratification from './GoodsStratification';
import BelongOrganization from './BelongOrganization';

export default defineComponent({
    name: 'ConventionalPricingTableRef',
    components: {
        AddDelButtonGroup,
        GoodsStratification,
        BelongOrganization,
    },
    props: {
        detailsData: {
            type: Object,
            default: () => ({}),
        },
    },
    setup(props, { emit }) {
        const { proxy } = getCurrentInstance();
        // 从库里引入的深拷贝函数
        const { cloneDeep } = proxy.$tools;

        // 初始化
        const initData = reactive({
            // 表头
            columns: ruleConfigurationTableHeader(),
            // 添加的空数据列
            defaultDataSimulation: ruleDefaultData,

        });

        // 父组件调用校验
        const validate = () => {
            // 商品分层的校验
            const proArr1 = proxy.$refs.commodityStratification.map((item, index) => (
                proxy.$refs.commodityStratification[index].validate()
            ));
            // 所属组织的校验
            const proArr2 = proxy.$refs.purchasingOrganizationRef.map((item, index) => (
                proxy.$refs.purchasingOrganizationRef[index].validate()
            ));
            return Promise.all([...proArr1, ...proArr2]);
        };

        // 添加/复制/删除每行数据
        const operatorRow = (obj) => {
            const { isAdd, indexList } = obj || {};
            const indexLen = indexList.length;

            // 拷贝一下原数据(ruleConfigModels是规则配置的数据),等下操作这个数据的增删
            const sourceData = cloneDeep(props.detailsData.ruleConfigModels);
            switch (indexLen) {
                case 1: // 添加第一列
                    if (isAdd === 'copy') {
                        // 实现逻辑是如果复制的是组织,那么需要将组织项清空,如果不深拷贝的话,会影响原数据
                        const copyValue = sourceData[indexList[0]];
                        const deepCloneCopy = cloneDeep(copyValue);
                        deepCloneCopy.procurementOrgIds = [];
                        sourceData.splice(+indexList[0] + 1, 0, cloneDeep(deepCloneCopy));
                    } else if (isAdd === 'add') {
                        sourceData.splice(+indexList[0] + 1, 0, cloneDeep(initData.defaultDataSimulation.ruleConfigModels[0]));
                    } else {
                        sourceData.splice(+indexList[0], 1);
                    }
                    break;
                case 2:// 添加第二列
                    if (isAdd === 'copy') {
                        // 要复制的数据
                        const copyValue = sourceData[indexList[0]].strategyConfigByCategories[indexList[1]];
                        const deepCloneCopy = cloneDeep(copyValue);
                        deepCloneCopy.productType = [];
                        sourceData[+indexList[0]].strategyConfigByCategories.splice(+indexList[1] + 1, 0, cloneDeep(deepCloneCopy));
                    } else if (isAdd === 'add') {
                        sourceData[+indexList[0]].strategyConfigByCategories.splice(+indexList[1] + 1, 0, cloneDeep(initData.defaultDataSimulation.ruleConfigModels[0].strategyConfigByCategories[0]));
                    } else {
                        sourceData[+indexList[0]].strategyConfigByCategories.splice(+indexList[1], 1);
                    }
                    break;
                default:
                    break;
            }
            emit('input', sourceData);
        };

        return {
            ...toRefs(initData),
            operatorRow,
            validate,
        };
    },
});
</script>

<style scoped lang="scss">
$tBorderColor: #edf0f5;
.multi-table-wrapper {
    width: 100%;
    overflow-x: auto;
}
.multi-level-table {
    min-width: 100%;
    display: table;
    border: $tBorderColor 1px solid;
    border-bottom: none;
    dt,
    dd {
        width: 100%;
        margin: 0;
        padding: 0;
        border-bottom: $tBorderColor 1px solid;
        display: table;
        table-layout: fixed;
        line-height: 20px;
        .th,
        .td {
            display: table-cell;
            vertical-align: middle!important;
            font-size: 12px;
            border-right: $tBorderColor 1px solid;
            &:last-child {
                border-right: none;
            }
            line-height: 22px;
            box-sizing: border-box;
            &.p10 {
                padding: 0 10px;
            }
            &.inner {
                padding: 0 10px;
                height: 120px;
            }
            &.inner-mini {
                padding: 0 10px;
                height: 80px;
            }
        }
        .th {
            padding: 10px;
        }
        .td-line {
            width: 100%;
            display: table;
            table-layout: fixed;
            border-bottom: $tBorderColor 1px solid;
            &:last-child {
                border-bottom: none;
            }
        }
        .error-tips {
            margin: 0;
            padding: 5px 0;
            color: #ff0000;
        }
    }
    dt {
        background: #f5f6f7;
        font-weight: bold;
    }
    .border-box {
        box-sizing: border-box
    }
    .table {
        display: table;
    }
}
</style>

AddDelButtonGroup   孙组件

<template>
    <div class="btn-wrapper">
        <el-button
            type="text"
            @click="operatorRow('copy')"
        >
            复制
        </el-button>
        <el-button
            type="text"
            @click="operatorRow('add')"
        >
            添加
        </el-button>
        <el-button
            type="text"
            v-bind="$attrs"
            @click="operatorRow('delete')"
        >
            删除
        </el-button>
    </div>
</template>

<script>
export default {
    name: 'AddDelButtonGroup',
    props: {
        indexList: {
            type: Array,
            required: true,
        },
    },
    setup(props, { emit }) {
        // 复制/添加\删除行
        const operatorRow = (isAdd) => {
            emit('operator', { isAdd, indexList: props.indexList.map((index) => `${index}`) });
        };
        return {
            operatorRow,
        };
    },
};
</script>

<style lang="scss" scoped>
.btn-wrapper {
    margin-top: 10px;
}
.del-btn {
    color: #ff0000;
    &:disabled {
        color: #B0B3B8;
    }
}
</style>

BelongOrganization   组织组件(孙组件)

<template>
    <el-form
        ref="BelongOrganizationRef"
        :model="ruleForm"
        :rules="rules"
        style="padding-top: 10px;"
    >
        <el-form-item prop="procurementOrgIds">
            <!-- 这里其实是一个el-tree -->
            <PurchasingOrganizationDeletable
                ref="purchasingOrganizationRef"
                v-model="ruleForm.procurementOrgIds"
                :multiple="true"
                node-key="id"
                :tag-tender="true"
                :merge-value="true"
                :organization-data="organizationData"
                :clone-deep-organization-data="cloneDeepOrganizationData"
                :remote="false"
                :disabled-ids="getPurchasingOrgDisList(index)"
                @change="change"
            />
        </el-form-item>
    </el-form>
</template>

<script>
import PurchasingOrganizationDeletable from 'components/PurchasingOrganizationDeletable';

import {
    reactive, getCurrentInstance, toRefs, watch,
} from 'vue';

export default {
    name: 'BelongOrganization',
    components: {
        PurchasingOrganizationDeletable,
    },
    props: {
        value: {
            type: Array,
            default: () => ([]),
        },
        index: {
            type: Number,
            required: true,
        },
        detailsData: {
            type: Object,
            default: () => ({}),
        },
    },
    setup(props, { emit }) {
        const { proxy } = getCurrentInstance();
        const { cloneDeep } = proxy.$tools;

        const init = reactive({
            ruleForm: {
                procurementOrgIds: props.value,
            },
            // 所有的组织树
            organizationData: [],
            // 深拷贝的所有的组织树
            cloneDeepOrganizationData: [],
            rules: {
                procurementOrgIds: [
                    {
                        required: true, type: 'array', message: '请选择商品所属组织', trigger: 'change',
                    },
                ],
            },
        });

        watch(() => props.value, (v) => {
            init.ruleForm.procurementOrgIds = v;
        });

        // 获取组织列表
        const getOrganizationList = async () => {
            try {
                const list = await proxy.$hPost('/getAll');
                // 默认全部可选
                init.organizationData = list.map((item) => ({ ...item, disabled: false }));
                init.cloneDeepOrganizationData = cloneDeep(init.organizationData);
            } catch (error) {
                console.log(error);
            }
        };
        getOrganizationList();
        
        // 子组件调用validate进行校验
        const validate = () => proxy.$refs.BelongOrganizationRef?.validate();

        // 组织发生变化
        const change = (v) => {
            emit('input', v);
        };

        // 组织不能重复选择
        const getPurchasingOrgDisList = (i) => {
            const { detailsData: { ruleConfigModels } } = props;
            const arr = cloneDeep(ruleConfigModels);
            arr.splice(i, 1);
            return arr.reduce((tol, cur) => [...tol, ...cur.procurementOrgIds], []);
        };
        return {
            ...toRefs(init),
            getPurchasingOrgDisList,
            validate,
            change,

        };
    },
};
</script>

GoodsStratification   商品分层组件(孙组件)

<template>
    <el-form
        ref="GoodsStratificationRef"
        :model="ruleForm"
        :rules="rules"
        style="padding-top: 10px;"
    >
        <el-form-item prop="productType">
            <el-select
                v-model="ruleForm.productType"
                multiple
                @change="changeStratification"
            >
                <el-option
                    v-for="mbl in getDisabledMblOptions(strategyConfigByCategories.reduce((pre,cur) => pre.concat(cur.productType),[]))"
                    :key="mbl.code"
                    :label="mbl.value"
                    :value="mbl.code"
                    :disabled="mbl.disabled"
                >
                    <span>{{ mbl.value }}</span>
                </el-option>
            </el-select>
        </el-form-item>
    </el-form>
</template>

<script>
import {
    reactive, getCurrentInstance, watch,
} from 'vue';

export default {
    name: 'GoodsStratification',
    props: {
        value: {
            type: Array,
            default: () => ([]),
        },
        // 当前的商品分层信息
        strategyConfigByCategories: {
            type: Array,
            required: true,
        },
    },
    setup(props, { emit }) {
        const { proxy } = getCurrentInstance();

        const init = reactive({
            ruleForm: {
                productType: props.value,
            },
            // 全部的商品分层
            commodityStratificationList: [],
            rules: {
                productType: [
                    {
                        required: true, type: 'array', message: '请选择商品分层', trigger: 'change',
                    },
                ],
            },
        });

        watch(() => props.value, (v) => {
            init.ruleForm.productType = v;
        });

        const validate = () => proxy.$refs.GoodsStratificationRef?.validate();

        // 获取商品分层列表
        const getStratificationList = async () => {
            init.commodityStratificationList = await proxy.$hGet('/basic');
        };
        getStratificationList();

        // 商品分层发生变化
        const changeStratification = (v) => {
            emit('input', v);
        };

        // 商品分层同一个组织不能重复选择商品分层
        const getDisabledMblOptions = (disArr = []) => init.commodityStratificationList.map((oriItem) => {
            const disabled = disArr.includes(oriItem.code);
            return {
                ...oriItem,
                disabled,
            };
        });

        return {
            ...init,
            getDisabledMblOptions,
            changeStratification,
            validate,

        };
    },
};
</script>

 <style lang="scss" scoped>
</style>

   组织组件   PurchasingOrganizationDeletable   (业务组件和上面功能关系不大)

<template>
    <div>
        <treeselect
            v-model="innerValue"
            :data="showData"
            :multiple="multiple"
            :only-leaf="onlyLeaf"
            :disabled="disabled"
            :render-node="renderNode"
            :render-tag="renderTag"
            :merge-value="mergeValue"
            :editable-method="isSelectLevel"
            :placeholder="placeholder"
            v-bind="$attrs"
            @change="onChange"
            @focus="filterDisabledList"
        />
    </div>
</template>

<script lang="jsx">
import { cloneDeep } from '@lsfe/tools';

export default {
    name: 'PurchasingOrganizationSelect',
    props: {
        multiple: {
            type: Boolean,
            default: false,
        },
        // 是否只选择子节点
        onlyLeaf: {
            type: Boolean,
            default: false,
        },
        // 数据会自动收敛,即如果父节点被选中,则返回的值中不会存在子节点的值。
        mergeValue: {
            type: Boolean,
            default: false,
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        value: {
            type: [String, Number, Array],
            default: '',
        },
        maxLevel: {
            type: Number,
            default: Infinity,
        },
        selectLevel: {
            type: [Number, String, Array],
            default: '',
        },
        placeholder: {
            type: String,
            default: '请选择所属组织',
        },
        // 从外部传的data
        organizationData: {
            type: Array,
            default: () => ([]),
        },
        usePermission: {
            type: Boolean,
            default: false,
        },
        tagTender: {
            type: Boolean,
            default: false,
        },
        canTagDel: {
            type: Boolean,
            default: true,
        },
        remote: {
            type: Boolean,
            default: true,
        },
        disabledIds: {
            type: Array,
            default: () => ([]),
        },
        cloneDeepOrganizationData: {
            type: Array,
            default: () => ([]),
        },
    },
    data() {
        return {
            innerValue: this.value,
            organizationList: [],
            cloneDeepOrganization: [],
        };
    },
    computed: {
        showData() {
            return this.organizationList
                .filter((item) => !this.maxLevel || item.level <= this.maxLevel);
        },
    },
    watch: {
        value: {
            // 详情和编辑的数据回显
            handler(newValue) {
                this.innerValue = newValue;
            },
        },
        organizationData: {
            deep: true,
            handler(newValue) {
                this.organizationList = newValue;
                this.filterDisabledList(newValue);
            },
        },
    },
    mounted() {
        if (this.remote) {
            this.getOrganizationList();
        } else if (this.organizationData.length) {
            this.filterDisabledList(this.organizationData);
        }
    },
    methods: {
        async getOrganizationList() {
            try {
                const url = this.usePermission ? '/shepherd/product/bizcenter/purchaserOrgTService/getDeptListByMisId' : '/shepherd/product/bizcenter/purchaserOrgTService/getAllDept';
                const list = await this.$hPost(url);
                this.cloneDeepOrganization = cloneDeep(list);
                this.$emit('getChildOrganizationList', cloneDeep(list));
                this.filterDisabledList(list);
            } catch (error) {
                this.$message.error(error.msg || error.message || '获取所属组织列表失败');
            } finally {
                this.$emit('loaded', this.organizationList);
            }
        },
        onChange(val, item) {
            this.$emit('input', val);
            this.$emit('change', val, item);
        },
        deleteNode(treeSelect, item) {
            const tree = treeSelect.$refs.treeWrapper.$refs.tree;
            const targetNode = tree.getNode(item);

            // 被从组织中删除的某个组织
            if (!targetNode) {
                const i = this.innerValue.indexOf(item.id);
                this.innerValue.splice(i, 1);
                this.$emit('input', this.innerValue);
            }
            targetNode?.setChecked(false, true);
            this.$nextTick(() => {
                const store = tree.store;
                tree.$emit('check', targetNode?.data, {
                    checkedNodes: store.getCheckedNodes(),
                    checkedKeys: store.getCheckedKeys(),
                    halfCheckedNodes: store.getHalfCheckedNodes(),
                    halfCheckedKeys: store.getHalfCheckedKeys(),
                });
            });
        },
        renderTag(h, data, treeSelect) {
            const { canTagDel, tagTender } = this;
            const arr = data.filter((item) => !item.children);
            if (!tagTender) {
                arr.slice(0, 1);
            }
            const tagList = arr.map((item) => (
                <el-tag
                    size="small"
                    key={item.id}
                    disable-transitions={true}
                    closable={canTagDel}
                    onClose={() => { this.deleteNode(treeSelect, item); }}
                >
                    {item.label}
                </el-tag>
            ));
            if (!tagTender) {
                if (data.length > 1) {
                    tagList.push((
                        <el-tag size="small">+{data.length - 1}</el-tag>
                    ));
                }
            }
            return [tagList];
        },
        filterDisabledList(data = this.organizationList) {
            const { disabledIds } = this;
            if (disabledIds.length === 0) {
                /*
                    这里用的是从父组件请求的组织列表, 传过来的有组织列表和深拷贝的组织列表,
                    如果disabledIds为空,使用深拷贝的组织列表,ss
                    如果不是使用的父组件传过来的数据,就用在本组织中深拷贝的数据,对初始化组织赋值
                */
                if (!this.remote) {
                    this.organizationList = this.cloneDeepOrganizationData;
                } else {
                    this.organizationList = this.cloneDeepOrganization;
                }
            } else {
                this.organizationList = data.map((item) => ({ ...item, disabled: disabledIds.includes(item.id) }));
            }
        },

        // eslint-disable-next-line no-unused-vars
        renderNode(h, { node, data }) {
            return (
                <div>
                    <span>{data.id} -- {data.label}</span>
                </div>
            );
        },
        // eslint-disable-next-line consistent-return
        isSelectLevel(node) {
            const level = Number(node.level);
            if (!this.selectLevel) {
                // 没有selectLevel 直接通过
                return true;
            }
            if (Array.isArray(this.selectLevel)) {
                // selectLevel是数组
                // eslint-disable-next-line no-bitwise
                return ~this.selectLevel.indexOf(level);
            }
            if (typeof this.selectLevel === 'number' || typeof this.selectLevel === 'string') {
                // selectLevel是数字 或 字符串
                return Number(this.selectLevel) === level;
            }
        },
    },
};
</script>

<style lang="scss" scoped>
::v-deep .el-select__input{
    width: 0px;
}
::v-deep .tag-wrapper .el-input__inner {
    overflow-y: auto;
    max-height: 100px;
}
 ::v-deep .tag-wrapper .el-input__inner .tag-wrapper__inner {
    overflow-y: auto;
    max-height: 100px;
}

</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/601985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习笔记之循环神经网络(十)基于循环神经网络模型的简单示例

深度学习笔记之循环神经网络——基于循环神经网络模型的简单示例 引言文本表征&#xff1a; One-hot \text{One-hot} One-hot向量简单示例:文本序列的预测任务数据预处理过程生成文本数据遍历数据集&#xff0c;构建字典抓取数据&#xff0c;创建训练样本、标签字符特征与数字特…

Uni-app学习从0到1开发一个app——(2)windowns环境搭配

文章目录 0 引入1、使用HBuilderX构建工程2、使用vscode2.1 官方推荐的使用2.2 如何使用 3、总结 0 引入 工欲善其事必先利其器介绍两种开发小程序的方法&#xff0c;个人倾向于第一种&#xff0c;后续演示的的工程也是基于前者&#xff0c;毕竟官方的更有说服力。 1、使用HBu…

基于yolov5开发构建枪支刀具等危险物品检测识别系统

安全始终是重如泰山的事情&#xff0c;安全事件如果能够做到早发现早制止可能结果就会完全不一样了&#xff0c;本文的核心目的很简单&#xff0c;就是想基于目标检测模型来尝试构建枪支刀具等危险物品检测识别系统&#xff0c;希望基于人工智能手段来打击犯罪行为&#xff0c;…

【JavaSE】Java基础语法(四十三):反射

文章目录 概述&#xff1a;1. java.lang.Class1.1 获取 Class 对象1.2 通过反射创建对象1.3 通过反射获取类的属性、方法和注解等1.3.1 反射获取构造方法1.3.2 反射通过构造器创建对象1.3.3 反射获取成员方法1.3.4 反射获取属性 2. 工具类操作3. 反射是如何破坏单例模式的4. 反…

linux0.12-12-2-buffer

基本上看完赵老师中文解释&#xff0c;都可以自己写这部分的代码。 [622页] 12-2 buffer.c程序 从本节起&#xff0c;我们对fs/目录下的程序逐一进行说明和注释。按照本章第2节中的描述&#xff0c; 本章的程序可以被分成4个部分&#xff1a; 高速缓冲管理&#xff1b; 文件…

基于ATC89C51单片机的超市临时储物柜密码锁设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87855870?spm=1001.2014.3001.5503 源码获取 摘 要 随着微机测量和控制技术的迅速发展与广泛应用,以单片机为核心的电子密码锁的设计研发与应用在很大程度上改善了人们的…

windows 部署多个tomcat

去官网下载tomcat&#xff0c;地址&#xff1a;Apache Tomcat - Apache Tomcat 8 Software Downloads 选择对应的版本下载&#xff0c;下载完成后&#xff0c;直接解压文件&#xff0c; 修改第二个解压的tomcat的catalina.bat 和 startup.bat和service.bat文件的配置&#x…

iptables 基础

iptables防火墙 主要实现数据包的过滤、封包重定向和网络地址转换&#xff08;NAT&#xff09;等功能 iptables&#xff1a;用户空间的命令行工具&#xff0c;用于管理配置netfilter&#xff1a;真正实现功能的是netfilter运行在内核空间 iptables的4表5链 链&#xff1a;通过…

想管好数据资源,不妨了解大数据分析开源框架

在如今快节奏的时代中&#xff0c;办公自动化早已成为各行各业的发展趋势和方向。随着业务量的激增&#xff0c;数据资源也不断增多&#xff0c;如果没有一套完善的大数据分析开源框架&#xff0c;那这么多的数据资源就不能很好地利用和发挥其价值&#xff0c;如果采用专业的大…

基于AT89C52单片机的交通灯设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87855439?spm1001.2014.3001.5503 源码获取 一、实验目的 掌握单片机的综合应用设计。加强对单片机和汇编语言的认识&#xff0c;充分掌握和理解设计各部分的工作…

华为防火墙双机热备外线vrrp地址和接口地址非同网段

主防火墙FW1: HRP_Mdis current-configuration 2023-06-02 15:51:48.270 08:00 !Software Version V500R005C10SPC300 sysname USG6000V1 l2tp domain suffix-separator undo info-center enable ipsec sha2 compatible enable undo telnet server enable undo telnet ipv6 se…

Office Visio 2007安装教程

哈喽&#xff0c;大家好。今天一起学习的是Visio 2007的安装&#xff0c;这是一个绘制流程图的软件&#xff0c;用有效的绘图表达信息&#xff0c;比任何文字都更加形象和直观。Office Visio 是office软件系列中负责绘制流程图和示意图的软件&#xff0c;便于IT和商务人员就复杂…

ROS:客户端Client的编程实现

目录 一、话题模型二、创建功能包三、创建代码并编译运行&#xff08;C&#xff09;3.1步骤3.2创建客户端Client代码3.3编译 四、运行 一、话题模型 Sever端是海龟仿真器/turtlesim&#xff0c;Client端是待实现的程序&#xff0c;其作为Response的节点&#xff0c;并产生Requ…

wav格式怎么转换?介绍三个转换wav格式的方法

在音乐制作或者编辑过程中&#xff0c;可能需要将录制的音频文件转换成特定的格式以便于后期处理。例如&#xff0c;你可能拍摄了一段演奏视频&#xff0c;想要提取其中的音频&#xff0c;并将其转换为wav或者flac等无损格式&#xff0c;以便于进行音频编辑和修复。那么你知道w…

【正点原子STM32连载】 第二十四章 OLED显示实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十…

VMWare安装Ubuntu

VMWare安装Ubuntu 安装前 准备 访问https://cn.ubuntu.com/download(下载需要版本/以16.04为例)操作系统上安装VMWare 基本安装 下载映像文件后&#xff0c;按照一步一步操作即可安装注意选中映像文件安装结束&#xff0c;登录进入系统可看到以下画面 设置语言环境 进入系…

OpenMMLab-AI实战营第二期-课程笔记-Class 2:人体姿态估计与MMpose

Class 2&#xff1a;人体姿态估计与MMpose 文章目录 Class 2&#xff1a;人体姿态估计与MMpose**人体姿态估计概述****what?****下游任务** **2D 姿态估计****主流算法****基于回归坐标的方法****基于热图&#xff08;heatmap&#xff09;的方法** **多人姿态估计****基于回归…

5. 垃圾收集器G1ZGC详解

JVM性能调优 1. G1收集器(-XX:UseG1GC) 本文是按照自己的理解进行笔记总结&#xff0c;如有不正确的地方&#xff0c;还望大佬多多指点纠正&#xff0c;勿喷。 课程内容&#xff1a; 1、G1垃圾收集器详解 2、每秒几十万并发的系统JVM级别如何优化 3、ZGC垃圾收集器详解 4、…

设置 session rdp 时间限制

起因&#xff1a;一台服务器 2016版本&#xff0c;每当退出远程桌面后&#xff0c;过一段时间&#xff0c;用户所有的进程就会自动关闭&#xff0c;导致后台运行的任务出现异常。 运行 gpedit.msc, 根据以下资料设置后&#xff0c;记得重启&#xff0c;不然不会生效 前三个选…

汽车出海势头旺,汽车零部件企业如何破浪前行?

随着国内汽车市场逐渐饱和&#xff0c;中国汽车企业开始寻求“汽车出海”的新市场增长点。在政府加大汽车出海政策支持力度下&#xff0c;根据中汽协数据&#xff0c;一季度的新能源汽车出口达24.8万辆&#xff0c;同比增长1.1倍。中国汽车行业持续深耕海外市场&#xff0c;出口…