难点在 1 添加一组一组的渲染 是往数组里push对象 循环的;但是要注意对象的结构! 因为这涉及到编辑完成后,表单提交时候的 校验! 是校验每一个select tree里边 是否勾选
2 是在后期做编辑回显的时候 保证后端返回的值 是渲染到 select中的tree当中! 并且是勾选着的
3 任意在一个select当中 移除的时候。
4 任意一个select当中 取消勾选后 显示是否正确
只在提交的时候校验!
父组件
<template><el-dialogclass="mpks-common-dialog mpks-search-strategy-resultintervene-dialog"width="810px":title="innerTitle":visible.sync="innerDialogVisible":close-on-click-modal="false":close-on-press-escape="false"@opened="open('form')"@close="close"><el-formref="form":model="currentItem"label-width="104px":rules="formRule"><el-form-item label="知识库名称:" prop="name" class="cd"><el-col :span="20"><el-inputv-model="currentItem.name"placeholder="请输入知识库名称"maxlength="20"show-word-limitclearable></el-input></el-col></el-form-item><el-form-itemlabel=""v-for="(item, index) in currentItem.selects":key="index"class="mpks-common-dialog-form-item-qa create-css"><div class="flex mtop margin-bottom"><el-col ><el-form-item:prop="'selects.' + index + '.NodeVal'":rules="formRule.NodeVal"><el-selectv-model="item.NodeVal"placeholder="请选择知识树节点"multiplecollapse-tags@change="nodeValChange(item, index)"@remove-tag="removeTag(item)"><el-option:value="seletedNodeIdsOptions"style="height: auto;"><channel-tree:idx="index"ref="nodeTree"class="mpks-add-task-tree":checkable="true":check-strictly="false":default-checked-keys="item.innerselectTreeIds":get-permission-node="true"@node-check="selectNodeId"/></el-option></el-select></el-form-item></el-col><el-col><el-form-item:prop="'selects.' + index + '.picVal'":rules="formRule.picVal"><el-selectv-model="item.picVal"placeholder="请选择图谱类目"multiplecollapse-tags@change="picValChange(item, index)"@remove-tag="removeTagPic(item)"><el-option:value="seletedPicIdsOptions"style="height: auto;"><channel-tree-pic:idx="index"ref="nodeTreePic"class="mpks-add-task-tree":checkable="true":check-strictly="false":default-checked-keys="item.innerselectTreePicIds":get-permission-node="true"@node-check="selectPicId"/></el-option></el-select></el-form-item></el-col><el-col><el-form-item:prop="'selects.' + index + '.categoryVal'":rules="formRule.categoryVal"><el-selectv-model="item.categoryVal"placeholder="请选择全文索引类目"multiplecollapse-tags@change="classChange(item, index)"@remove-tag="removeTagCategoryVal(item)"><el-optionstyle="height: auto;":value="seletedIdxIdsOptions"><channel-tree-idx:idx="index"ref="nodeTreeIdx"class="mpks-add-task-tree":checkable="true":check-strictly="false":default-checked-keys="item.innerselectTreeIdxIds":get-permission-node="true"@node-check="selectIdxId"/></el-option></el-select></el-form-item></el-col><spanv-if="currentItem.selects.length === 1"class="between-delete">删除</span><spanv-elseclass="between-delete-true"@click="deleteSelects(item, index)">删除</span></div></el-form-item><divv-if="currentItem.selects.length < maxAdd"class="mpks-visual-query-filter-add-attribute"@click="addCategory"><svg-icon name="add"></svg-icon><span class="add-txt">新增一组</span><span class="add-plus">(最多支持5组)</span></div><div v-else class="disabled margin-top">+ <span class="add-txt-to">新增一组</span><span class="add-plus-to">(最多支持5组)</span></div></el-form><div slot="footer"><el-button type="primary" @click="OK('form')">确认</el-button><el-button type="default" @click="Cancel">取消</el-button></div></el-dialog>
</template><script>
import cloneDeep from "lodash/cloneDeep";
import { validate } from "@/common/util.js";
import SvgIcon from "@/components/SvgIcon.vue";
import ChannelTree from "@/components/channelTree.vue";
import ChannelTreePic from "@/components/channelTreepic.vue";
import ChannelTreeIdx from "@/components/ChannelTreeIdx.vue";
// 判断一下, 编辑的时候,不push这个那个对象
export default {name: "SearchStrategyResultInterveneDialog",components: {SvgIcon,ChannelTree,ChannelTreePic,ChannelTreeIdx},props: {title: {type: String,default: "新建知识库"},dialogVisible: {type: Boolean,default: false},sendData: {type: Array,required: true},data: {type: Object,required: true},dataEdit: {type: Object}},beforeMount() {},created() {},mounted() {},data() {var NodeValPass = (rule, value, callback) => {if(this.currentItem.selects[rule.field.substring(8,9)].NodeVal.length===0){callback(new Error('知识树节点不能为空'));}else{callback();}};var picValPass = (rule, value, callback) => {if(this.currentItem.selects[rule.field.substring(8,9)].picVal.length===0){callback(new Error('图谱类目不能为空'));}else{callback();}};var categoryValPass = (rule, value, callback) => {if(this.currentItem.selects[rule.field.substring(8,9)].categoryVal.length===0){callback(new Error('全文索引类目不能为空'));}else{callback();}};return {editFirstNodeIds: [],seletedNodeIdsOptions: [],seletedPicIdsOptions: [],seletedIdxIdsOptions: [],innerselectTreeIds: [],innerselectTreePicIds: [],innerselectTreeIdxIds: [],maxAdd: 1, //允许添加的最大数量NodesOptionsIds: [], //知识树节点idlistClassOptionsIn: [], //initgetClassFilterOptionsIn: [], //initgetNodesOptionsIn: [], //initlistClassOptions: [], //响应 //全文索引类目getClassFilterOptions: [], //响应 图谱类目getNodesOptions: [], //响应 知识树节点editInfo: {edit: 0,id: ""}, //编辑的时候的数据innerTitle: this.title,innerDialogVisible: this.dialogVisible,currentItem: {name: "",selects: []},formRule: {NodeVal: [{validator: NodeValPass,trigger: "change"}],picVal: [{validator: picValPass,trigger: "change"}],categoryVal: [{validator: categoryValPass,trigger: "change"}],name: [{required: true,validator: validate.whitespace,message: "知识库名称不能为空",trigger: "blur"},{validator: validate.length,max: 20,message: "最多20个字符",trigger: "change"}]}};},watch: {dataEdit(newVal) {this.editInfo.edit = 1;this.editInfo.id = newVal.id;this.currentItem.name = newVal.name;this.currentItem.selects = [];newVal.options.forEach((item, index) => {let arr = item.nodeIds.map(i => i).map(itemId => {return this.sendData[2].filter(item => item.id === itemId);});let echoArr = [];arr.forEach(item => {echoArr.push(item[0].name);});this.currentItem.selects.push({NodeVal: [],picVal: [],categoryVal: [],innerselectTreeIds: [],innerselectTreePicIds: [],innerselectTreeIdxIds: []});this.currentItem.selects[index] = {innerselectTreeIds: item.nodeIds.map(i => i),innerselectTreePicIds: item.spoIds.map(i => i),innerselectTreeIdxIds: item.presetIds.map(i => i),NodeVal: echoArr,picVal: item.spoIds.map(i => i),categoryVal: item.presetIds.map(i => i)?item.presetIds.map(i => i):[]};});},dialogVisible: "sync",sendData: {handler(newVal) {this.listClassOptions = newVal[0];this.getClassFilterOptions = newVal[1];this.getNodesOptions = newVal[2];this.maxAdd = this.findMinArr(this.listClassOptions,this.getClassFilterOptions,this.getNodesOptions);},deep: true},title(newVal) {this.innerTitle = newVal;if (newVal === "新建知识库") {this.currentItem.name = "";this.editInfo.edit = 0;}}},methods: {removeTag(currentItem) {//转成id 后 与v-modle中的 :default-checked-keys="item.innerselectTreeIds"匹配 回显tree勾选let arr = currentItem.NodeVal.map(itemZhcn => {return this.sendData[2].filter(item => item.name === itemZhcn);});let toIds = [];arr.forEach(item => {toIds.push(item[0].id);});currentItem.innerselectTreeIds = toIds;},removeTagPic(currentItem) {currentItem.innerselectTreePicIds = currentItem.picVal;},removeTagCategoryVal(currentItem) {currentItem.innerselectTreeIdxIds = currentItem.categoryVal;},selectNodeId(params, index) {console.log(params);let selectList = [];let selectLable = [];params.data.forEach(item => {if (+item.id !== 1) {selectList.push(item.id);selectLable.push(item.name);}});this.seletedNodeIdsOptions = selectList;this.currentItem.selects[params.idx].NodeVal = selectLable;this.currentItem.selects[params.idx].NodeValSend = selectList;},selectPicId(params, index) {let selectList = [];let selectLable = [];params.data.forEach(item => {if (+item.id !== 1) {selectList.push(item.id);selectLable.push(item.name);}});this.seletedPicIdsOptions = selectList;this.currentItem.selects[params.idx].picVal = selectLable;this.currentItem.selects[params.idx].picValSend = selectList;},selectIdxId(params, index) {let selectList = [];let selectLable = [];params.data.forEach(item => {if (+item.id !== 1) {selectList.push(item.id);selectLable.push(item.name);}});this.seletedIdxIdsOptions = selectList;this.currentItem.selects[params.idx].categoryVal = selectLable;this.currentItem.selects[params.idx].categoryValSend = selectList;},Cancel() {this.innerDialogVisible = false;},nodeValChange(item, index) {this.currentItem.selects[index].NodeVal = item.NodeVal;this.$forceUpdate();},picValChange(item, index) {// 图谱类目option改变this.currentItem.selects[index].picVal = item.picVal;this.$forceUpdate();},classChange(item, index) {// 全文索引类目option改变this.currentItem.selects[index].categoryVal = item.categoryVal;this.$forceUpdate();},findMinArr(arr1, arr2, arr3) {const shortestLength = Math.min(arr1.length,arr2.length,arr3.length);return shortestLength;},verifyInput() {this.currentItem.selects.forEach(item => {for (const i of Object.keys(item)) {if (item[i].length === 0) {break;}}});},OK(formName) {// TODO:提交this.$refs[formName].validate(valid => {if (valid) {let param = {name: this.currentItem.name,options: []};if (this.editInfo.edit === 1) {//修改 添加参数param.id = this.editInfo.id;param.enabled = 1;}this.currentItem.selects.forEach((currentItem, index) => {let arr = currentItem.NodeVal.map(itemZhcn => {return this.sendData[2].filter(item => item.name === itemZhcn);});let toIds = [];arr.forEach(item => {toIds.push(item[0].id);});let obj = {};obj.nodeIds = toIds; //nodeIds 传id 其他2个传中文过去!obj.presetIds = currentItem.categoryVal;obj.spoIds = currentItem.picVal;param.options.push(obj);});this.$store.dispatch("channel/channelAddOrUpdate", param).then(res => {if (+res.errno === 0) {if (this.editInfo.edit === 1) {//修改this.$message.success("修改成功");this.$parent.channelList();this.currentItem.name = "";this.innerDialogVisible = false;this.editInfo.edit = 0;return;}// 新增this.$message.success("添加成功");this.$parent.channelList();this.currentItem.name = "";this.innerDialogVisible = false;} else {this.$message.error(res.msg || "出错啦,请稍候再试。");}});} else {console.log("error submit!!");return false;}});},addCategory(formName) {this.currentItem.selects.push({NodeVal: [],picVal: [],categoryVal: [],innerselectTreeIds: [],innerselectTreePicIds: [],innerselectTreeIdxIds: []});setTimeout(() => {this.clearValidate("form");}, 10);},deleteSelects(item, index) {this.currentItem.selects.splice(index, 1);},modifyItem() {},open(formName) {this.$refs[formName].clearValidate()if (this.editInfo.edit !== 1) {//新增this.currentItem.selects.push({NodeVal: [],picVal: [],categoryVal: [],innerselectTreeIds: [],innerselectTreePicIds: [],innerselectTreeIdxIds: []});}},close() {this.clearValidate("form");this.$emit("close");this.currentItem.selects = [];this.currentItem.name = "";},clearValidate(formName) {this.$refs[formName] && this.$refs[formName].clearValidate();},sync(newVal) {this.innerDialogVisible = newVal;}}
};
</script><style lang="less" scoped>
.mpks-search-strategy-resultintervene-dialog {/deep/.el-dialog__footer {padding-top: 0;
margin-top: 28px;.el-button {width: 72px;margin-left: 12px;}}.mpks-search-strategy-resultintervene-search-button {margin: 0 0 0 16px;height: 32px;color: #fff;border-color: #2468f2;line-height: 10px;border: 1px solid #2468f2;border-radius: 4px;font-size: 14px;color: #2468f2;&:hover {border-color: #528eff;color: #528eff;}&:focus {border-color: #2468f2;color: #2468f2;}}.mpks-search-strategy-resultintervene-query-item-wrapper {border: 1px solid #f1f1f1;padding: 10px 0;margin-bottom: 20px;max-width: 880px;}.mpks-search-strategy-resultintervene-block {background: #fafafa;padding: 10px 15px;.mpks-search-strategy-resultintervene-block-title {font-size: 14px;font-weight: 600;}.mpks-search-strategy-resultintervene-block-item {margin: 10px 0;&:first-child {margin-top: 0;}&:last-child {margin-bottom: 0;}.el-button {padding: 0;}}}
}/deep/.mpks-common-dialog-form-item-qa {.el-input-group__append {padding: 0;height: 32px;background-color: #fff;line-height: 32px;border: none;}.el-input__inner {padding-right: 0px !important;}
}/deep/.el-form-item.is-error .el-input__inner,
.el-form-item.is-error .el-textarea__inner {border-color: #f56c6c !important;
}.flex {display: flex;justify-content: space-between;// width: 620px;
}.mtop {margin-top: 10px;
}.mtop:first-of-type {margin-top: 0;
}.margin-bottom{// margin-bottom: 20px!important;
}.between-delete {color: #b7babf;cursor: pointer;
}.between-delete-true {color: #2468F2;cursor: pointer;
}/deep/.el-form-item__error {// padding-top: 8px;
}
.margin-top {margin-top: 10px;
}.el-col-24 {width: auto;
}.mpks-visual-query-filter-add-attribute {width: 170px;margin-top: -16px;margin-left: 102px;
}
.disabled {margin-top: -14px;margin-left: 102px;font-family: PingFangSC-Regular;font-size: 14px;color: #b8babf;line-height: 20px;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-align: center;-ms-flex-align: center;align-items: center;cursor: pointer;
}/deep/.el-dialog__body {padding: 24px 34px 0!important;
}
/deep/.el-select-dropdown__item {height: 100% !important;
}/deep/.cd {margin-bottom: 40px !important;
}.create-css{margin-bottom: 8px!important;
}/deep/.create-css::before{color: #5C5F66;position: absolute;left: 36px;top: 152px;content: "知识库配置:";width: 120px;height: 26px;display: inline-block;
}/deep/.create-css::after{color: #F56C6C;position: absolute;left: 26px;top:152px;content: "*";width: 120px;height: 26px;display: inline-block;
}/deep/.el-select .el-tag{
// width: 20px;
// display: -webkit-box;
// -webkit-box-orient: vertical;
// -webkit-line-clamp: 1;//第几行末尾出现省略号
// overflow: hidden;
}.add-txt{display: inline-block;}.add-plus{display: inline-block;color: #CCCCCC;margin-left: 8px;}.add-txt-to{display: inline-block;color: #CCCCCC;}.add-plus-to{display: inline-block;color: #CCCCCC;margin-left: 8px;}
</style>
一组 共3个select tree 组件;这是其中一个select tree组件。 其他2个 结构一样的!
channelTree.Vue
<template><div class="mpks-common-tree"><el-treeref="tree"class="mpks-common-tree-container"v-loading="loading"node-key="id":indent="8":data="tree":auto-expand-parent="true":highlight-current="true":check-strictly="checkStrictly":expand-on-click-node="expandOnClickNode":default-expanded-keys="defaultExpandedKeys":default-checked-keys="innerDefaultCheckedKeys":default-expand-all="defaultExpandAllNodes":show-checkbox="checkable":filter-node-method="filterNode"@node-click="nodeClick"@node-expand="nodeExpand"@node-collapse="nodeCollapse"@check="nodeCheck"@check-change="checkChange"><span class="mpks-common-tree-node" slot-scope="{ node, data }"><span class="mpks-common-tree-node-title" :title="data.name">{{data.name}}</span><div class="mpks-common-tree-node-control-wrapper"><el-popoverv-if="data.isEncryption && from !== 'role'"placement="top"trigger="hover"content="此节点为非公开"><islot="reference"class="el-icon-view mpks-common-tree-node-permission"></i></el-popover></div></span></el-tree></div>
</template><script>
export default {name: "Tree",props: {idx: {type: Number,default: undefined},// 当前选中节点的id, 只读属性currentId: {type: Number,default: undefined},// 点击目录回调函数expandOnClickNode: {type: Boolean,default: true},// 是否自动选中根节点, 会触发nodeClickautoSelectRoot: {type: Boolean,default: true},checkable: {type: Boolean,default: false},checkStrictly: {type: Boolean,default: true},defaultExpandAll: {type: Boolean,default: false},defaultCheckedKeys: {type: Array,default() {return [];}},disabledList: {type: Array,default() {return [];}},checkableItemList: {type: Array,default() {return [];}},displayList: {type: Array,default() {return [];}},from: {type: String,default: ""},roleId: {type: Number,default: 0},onlyEnabledEncryption: {type: Boolean,default: false},readonly: {type: Boolean,default: false},theOnly: {// 知识树权限复选框只能选择一个type: Boolean,default: false},getPermissionNode: {type: Boolean,default: false},},data() {return {list: [],tree: [],currentItem: {name: ""},defaultExpandedKeys: [],loading: false,innerDefaultCheckedKeys: this.defaultCheckedKeys,selectNodes: []};},watch: {defaultCheckedKeys: {handler(val) {this.innerDefaultCheckedKeys= []this.innerDefaultCheckedKeys = val;this.load(val);},deep: true,immediate: true}},computed: {defaultExpandAllNodes() {return !!this.defaultExpandAll;}},methods: {load(val) {this.loading = true;let param = {permissioncode: "knowledge_catelog_view"};this.$store.dispatch("channel/getNodes", param).then(res => {this.loading = false;if (+res.errno === 0) {this.list = this.setDisabledStatus(res.data.list);// this.list = this.filterDisplayNode(this.list);this.tree = this.convertListToTree(this.list);if (this.tree.length === 0) {return false;}// 默认选中是知识树第一个节点let defaultNodeKey = +this.tree[0].id;// this.defaultExpandedKeys = valthis.defaultExpandedKeys.push(defaultNodeKey);} else {this.$message.error(res.msg || "出错啦,请稍候再试。");}},() => {this.loading = false;});},clearTree() {this.$refs.tree.setCheckedKeys([]);},setDisabledStatus(list) {return list.map(item => {let newItem = item;if (this.readonly) {newItem = {...item,disabled: true};} else if (this.onlyEnabledEncryption || this.roleId) {if (!item.isEncryption) {newItem = {...item,disabled: true};}}if (this.disabledList.length) {if (this.disabledList.indexOf(item.id) >= 0) {newItem = {...item,disabled: true};} else {newItem = {...item,disabled: false};}}if (this.checkableItemList.length) {if (this.checkableItemList.indexOf(item.id.toString()) < 0) {newItem = {...item,disabled: true};}}return newItem;});},filterDisplayNode(list) {if (this.displayList.length === 0) {return list;}return list.filter(item => {return this.displayList.indexOf(item.id.toString()) >= 0;});},nodeClick(data) {this.$emit("node-click", {data: data});},nodeExpand(data) {this.$emit("node-expand", {data: data});this.defaultExpandedKeys.push(data.id);},nodeCollapse(data) {this.$emit("node-collapse", {data: data});let collapseIndex = this.defaultExpandedKeys.findIndex(item => {return item === data.id;});this.defaultExpandedKeys.splice(collapseIndex, 1);},nodeCheck(data) {if (this.theOnly) {this.$refs.tree.setCheckedKeys([data.id]);}this.selectNodes = this.$refs.tree.getCheckedKeys(true);this.$emit("node-check", {data: this.$refs.tree.getCheckedNodes(),dataInfo: data,idx: this.idx});},checkChange(...args) {this.$emit("check-change", ...args);},convertListToTree(list) {let root = []; // 根节点列表if (!list || list.length <= 0) {return root;}let indexes = {};// 重置数据状态list.forEach(v => {indexes[v.id] = v;if (+v.parentId === 0) {root.push(v);}v.children = []; // 带有可编辑的节点列表v.parent = null;v.list = []; // 节点所在列表});// 更新childrenlist.forEach(node => {if (+node.parentId !== 0 && indexes[node.parentId]) {let parent = indexes[node.parentId];node.parent = parent;node.list = parent.children;parent.children.push(node);}});return root;},filterNode(value, data) {if (!value) {return true;}return data.name.indexOf(value) !== -1;},selectFilter(val) {this.$refs.tree.filter(val);},setCheckedKey(ids) {this.$refs.tree.setCheckedKeys(ids);}}
};
</script><style lang="less">
@import (reference) "~@/common/util.less";.mpks-common-tree {height: 100%;border: 1px solid #eee;.mpks-common-tree-header {padding: 0 0 0 24px;height: 40px;background: #f9f9f9;line-height: 40px;color: #666;}.mpks-common-tree-header-button {padding: 13px 10px 13px 0;}.mpks-common-tree-node-title {.line-clamp(1);// margin-top: 4px;margin-right: 40px;color: #151b26;}.mpks-common-tree-node-permission {position: relative;width: 30px;text-align: center;color: #999;&:after {position: absolute;top: 6px;left: 6px;width: 17px;height: 0;border-top: 1px solid #999;transform: rotate(45deg);content: " ";}}.mpks-common-tree-node-control-wrapper {position: absolute;top: 0;right: 0;}.mpks-common-tree-node-control {width: 30px;text-align: center;background: #fff;visibility: hidden;}.el-tree-node:focus > .el-tree-node__content .mpks-common-tree-node-control,.el-tree-node__content:hover .mpks-common-tree-node-control,.mpks-common-tree-node-control:hover {background: #f5f7fa;}.el-tree--highlight-current.el-tree-node.is-current> .el-tree-node__content.mpks-common-tree-node-control,.el-tree--highlight-current.el-tree-node.is-current> .el-tree-node__content.mpks-common-tree-node-control:hover {background-color: #ebf4fd;}.mpks-common-tree-node-control:hover {color: #0073eb;}.el-tree-node {position: relative;}.el-tree-node__content {font-size: 14px;height: 24px;line-height: 24px;overflow-x: scroll;margin-top: 4px;&:hover {.mpks-common-tree-node-control {visibility: visible;}}}// .el-tree .el-icon-caret-right:before {// background: url('~@/assets/icon/arrowDown.svg') no-repeat 0 3px;// content: '\9B';// display: block;// height: 16px;// font-size: 16px;// background-size: 16px;// }.mpks-common-tree-dialog-tips {color: #666;}.mpks-common-tree-dialog-select {width: 100%;}.mpks-common-tree-filter {// background: #f9f9f9;padding: 0 4px 4px;.el-input__inner {// border: none;font-size: 12px;border-radius: 6px;height: 30px;}.el-input__suffix {display: flex;align-items: center;height: 30px;cursor: pointer;}}
}.mpks-common-tree-node-control-disabled {visibility: hidden;
}
</style>