phpcms模型管理如何支持联动菜单多选?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了phpcms模型管理如何支持联动菜单多选?相关的知识,希望对你有一定的参考价值。

模型管理如何支持联动菜多选吗?我创建一个模型,关联联动菜单 但是不能多选,请教下大家如何解决呢,谢谢~~

参考技术A 今天也碰到了这个问题 转下小波群主的回复0793jay(小波)()23:15:17新建字段,复选框--,随意设置选项---/phpcms/templates/defualt/member/content_published.html 修改 0793jay(小波)()23:15:40loop .....0793jay(小波)()23:16:48增加 if $k=='新建复选框字段名'}<tr></th></th><td></td>{else0793jay(小波)()23:17:32接下来,新增函数, 获取指定联动菜单名,0793jay(小波)()23:18:37函数中根据新增函数的参数进行 读取指定文件,将联动菜单数组中 ,Parentid=0 项目 遍历出。0793jay(小波)()23:19:24新增 第二个函数,参数设置 :联动菜单,父级ID0793jay(小波)()23:19:53将第二个函数,放置于 content.php 中。便于ajax 提交方式0793jay(小波)()23:19:59新增JS 函数。0793jay(小波)()23:21:00通过 change ,触发JS函数, 进行 AJAX 异步更新 下级, 0793jay(小波)()23:22:07AJAX 返回成品内容, JQUERY 直接.html 到指定ID中。 通过ctrl 键与 select 属性 ,确定返回的 成品内容是个多选框。0793jay(小波)()23:22:51进行赋值给返回 来的最后级 <select name= “”0793jay(小波)()23:23:08name 等于新增的字段名·· 。提交·保存即可黄页30号内测,估计黄页里就有这个功能了,不急的话就等等吧

多选联动标签

<tag-select
                allowLoadChildren
                :options="organOptions"
                :defaultOptions="organDefaultOptions"
                v-model="form.organId"
                placeholder="选择组织机构"
                @change="ispChange"
                @spread="spread"
                @focus="focus"
                ref="tagSelect"
                size="default"
                :loadChildrenMethod="loadChildren"
                labelKey="organName"
                valueKey="organId"
                childrenKey="sub"
                :panelWidth="\'auto\'"
              ></tag-select>
<template>
  <div class="cascader-wrapper">
    <crec-popover
      placement="bottomLeft"
      trigger="click"
      :popper-class="popOverClass"
      v-model="showPopover"
    >
      <!-- <div slot="reference"> -->
      <!-- multiple
        mode="tags" -->
      <crec-select
        mode="multiple"
        v-model="selectedLabels"
        :default-value="defaultLabels"
        :placeholder="placeholder"
        :disabled="disabled"
        :size="size"
        :collapse-tags="collapseTags"
        :showArrow="true"
        style="width: 100%;"
        popper-class="hide-popper"
        :open="false"
        @focus="handleFocus"
        @deselect="removeTag"
        @dropdown-visible-change="visibleChange"
      ></crec-select>
      <!-- </div> -->
      <template slot="content">
        <div
          class="cascader-menu-wrapper"
          v-clickoutside="hidePopover"
        >
          <template v-if="options.length > 0">
            <ul
              class="crec-cascader-menu cascader-menu"
              :style="{\'width\': panelWidth === \'auto\' ? \'auto\' : panelWidth + \'px\'}"
              v-for="(cas, index) in casTree"
              :key="index"
            >
              <!--  -->
              <!-- \'can-load-children\': !item.isLeaf && !item[childrenKey] && allowLoadChildren && showLoadingIndicator, -->
              <!-- \'loading-children\': !item.isLeaf && item.loading && allowLoadChildren && showLoadingIndicator, -->
              <!-- \'crec-cascader-menu-item-expand\': item[childrenKey] && item[childrenKey].length > 0, -->
              <li
                :class="{
                  \'crec-cascader-menu-item\': true,
                  \'crec-cascader-menu-item-expand\': true,
                  \'has-checked-child\': item.indeterminate || item.hasCheckedChild,
                  \'crec-cascader-menu-item-active\': item.checked,
                }"
                @click="spreadNext(item[childrenKey], index, item)"
                v-for="(item, itemIdx) in cas"
                :key="itemIdx"
                :title="item[labelKey]"
              >
                <crec-checkbox
                  class="cascader-checkbox"
                  @click.native.stop
                  :disabled="item.disabled"
                  v-model="item.checked"
                  :indeterminate="item.indeterminate"
                  @change="({target}) => { checkedChange(item, target.checked) }"
                ></crec-checkbox>
                <span>{{ item[labelKey] }}</span>
                <span
                  v-if="item[childrenKey] && item[childrenKey].length > 0"
                  class="crec-cascader-menu-item-expand-icon"
                >
                  <crec-icon type="right"></crec-icon>
                </span>
              </li>
            </ul>
          </template>
          <template v-else>
            <ul class="crec-cascader-menu cascader-menu">
              <li class="crec-cascader-menu-item dropdown__empty">
                {{ noDataText }}
              </li>
            </ul>
          </template>
        </div>
      </template>

    </crec-popover>
  </div>
</template>

<script>
import Clickoutside from \'./clickoutside\'
import { props, hasArrayChild, deepClone, getId, fireEvent, isPromise } from \'./utils\'
export default {
  name: \'TagSelect\',
  props,
  watch: {
    selectedLabels: {
      deep: true,
      handler () {
        if (this.selectedLabels && this.selectedLabels.length === 0) {
          this.selectedLabels = this.defaultLabels
        }
      }
    },
    options: {
      deep: true,
      handler () {
        this.initOpts()
        this.initDatas()
      }
    },
    defaultOptions: {
      deep: true,
      handler () {
        console.log(this.defaultOptions)
        this.defaultLabels = this.defaultOptions.map(e => e.organName)
      }
    },
    value: {
      deep: true,
      handler () {
        console.log(this.selectedValues, this.value)
        if (this.selectedValues !== this.value) {
          this.initOpts()
          this.initDatas()
        }
      }
    },
    disabled (disabled) {
      if (disabled) {
        this.hidePopover()
      }
    },
    showPopover (flag) {
      if (flag) {
        console.log(this.value)
        this.$emit(\'focus\')
      }
    }
  },
  directives: { Clickoutside },
  created () {
    this.classRef = `popper-class-${getId()}`
    this.popOverClass = `cascader-popper ${this.classRef} ${this.popperClass}`
    this.initOpts()
    this.initDatas()
  },
  mounted () {
    // 设置弹出层宽度
    this.elWidth = this.$el.offsetWidth
  },
  destroyed () {
    this.clonedOpts = null
    this.casTree = null
    this.selectedItems = null
    this.selectedLabels = null
    this.selectedvalues = null
  },
  data () {
    return {
      elWidth: \'\',
      popperWidth: \'\',
      popOverClass: \'\',
      classRef: \'\',
      showPopover: false,
      clonedOpts: [],
      casTree: [],
      selectedItems: [],
      selectedLabels: [],
      selectedValues: [],
      loadChildrenPromise: null,
      defaultLabels: []
    }
  },
  methods: {
    initOpts () {
      console.log(this.defaultOptions)
      this.defaultLabels = this.defaultOptions.map(e => e.organName)
      console.log(this.defaultLabels)
      this.clonedOpts = deepClone(this.options)
      this.recursiveOpt(this.clonedOpts, null)
      this.casTree = [this.clonedOpts]
      console.log(this.casTree)
    },
    /**
     * 初始化数据
     * 空值初始化,两个绑定不一致的情况
     */
    initDatas () {
      this.pickCheckedItem(this.clonedOpts)
    },
    /**
     * 递归option数据
     * 标记数据树形层级 parent
     * 打上初始状态 checked indeterminate
     */
    recursiveOpt (nodeArr, parent) {
      const vm = this
      nodeArr.forEach(node => {
        if (parent) {
          node.parent = parent
        }
        node.indeterminate = false
        node.checked = false
        if (this.value.some(val => val === this.getLevel(node, vm.valueKey, this.outputLevelValue))) {
          node.checked = true
        }
        this.markChildrenChecked(node)
        this.markParentChecked(node)
        this.markParentHasCheckChild(node)
        if (hasArrayChild(node, vm.childrenKey)) {
          vm.recursiveOpt(node[vm.childrenKey], node)
        }
      })
    },
    /**
     * 根据当前节点 checked
     * 更改所有子孙节点 checked
     * 依赖 this.selectChildren
     */
    markChildrenChecked (node) {
      const vm = this
      function loop (children, status) {
        if (children) {
          children.map(child => {
            if (!child.disabled) {
              child.checked = status
              if (child.checked) {
                child.indeterminate = false
              }
            }
            if (hasArrayChild(child, vm.childrenKey)) {
              loop(child[vm.childrenKey], status)
            }
          })
        }
      }
      if (node && hasArrayChild(node, vm.childrenKey) && this.selectChildren) {
        loop(node[vm.childrenKey], node.checked)
      }
    },
    /**
     * 标记父节点 checked、indeterminate 状态
     * 依赖 this.selectChildren
     */
    markParentChecked (node) {
      const vm = this
      node.indeterminate = false
      function loop (node) {
        let checkCount = 0
        if (hasArrayChild(node, vm.childrenKey)) {
          const childIndeterminate = node[vm.childrenKey].some(child => child.indeterminate)
          node[vm.childrenKey].map(child => {
            if (child.checked) {
              checkCount++
            }
          })
          // 子节点全部被选中
          if (checkCount === node[vm.childrenKey].length) {
            node.checked = true
            node.indeterminate = false
          } else {
            node.checked = false
            if (checkCount > 0 || childIndeterminate) {
              node.indeterminate = true
            } else {
              node.indeterminate = false
            }
          }
        }
        if (node.parent) {
          loop(node.parent)
        }
      }
      if (node && node.parent && this.selectChildren) {
        loop(node.parent)
      }
    },
    /**
     * 标记是否有被选子项
     * 依赖 this.selectChildren
     */
    markParentHasCheckChild (node) {
      const vm = this
      node.hasCheckedChild = false
      function loop (node) {
        let checkCount = 0
        if (hasArrayChild(node, vm.childrenKey)) {
          const childHasCheckedChild = node[vm.childrenKey].some(child => child.hasCheckedChild)
          node[vm.childrenKey].map(child => {
            if (child.checked) {
              checkCount++
            }
          })
          // 子节点有被选中
          node.hasCheckedChild = (checkCount > 0) || childHasCheckedChild
        }
        if (node.parent) {
          loop(node.parent)
        }
      }
      if (node && node.parent && !this.selectChildren) {
        loop(node.parent)
      }
    },
    // 展示标签所有层级
    getLevel (node, key, leveled) {
      const levels = []
      function loop (data) {
        levels.push(data[key])
        if (data.parent) {
          loop(data.parent)
        }
      }
      if (leveled) {
        loop(node)
        return levels.reverse().join(this.separator)
      } else {
        return node[key]
      }
    },
    /**
     * 处理已选中
     * 重新遍历tree,pick除已选中项目
     */
    pickCheckedItem (tree) {
      const vm = this
      /**
       * 移除parent引用
       */
      function removeParent (node) {
        const obj = {}
        Object.keys(node).forEach(key => {
          if (key !== \'parent\') {
            obj[key] = node[key]
          }
        })
        if (hasArrayChild(obj, vm.childrenKey)) {
          obj[vm.childrenKey] = obj[vm.childrenKey].map(child => {
            return removeParent(child)
          })
        }
        return obj
      }
      vm.selectedItems = []
      vm.selectedLabels = []
      vm.selectedValues = []
      function loop (data) {
        if (Array.isArray(data)) {
          data.map(item => {
            if (item.checked) {
              const newItem = removeParent(item)
              vm.selectedItems.push(newItem)
              vm.selectedLabels.push(vm.getLevel(item, vm.labelKey, vm.showAllLevels))
              vm.selectedValues.push(vm.getLevel(item, vm.valueKey, vm.outputLevelValue))
            }
            if (hasArrayChild(item, vm.childrenKey)) {
              loop(item[vm.childrenKey])
            }
          })
        }
      }
      loop(tree)
    },
    removeTag (label) {
      /**
     * 遍历 tree
     * 根据传入label 寻找 item
     */
      const vm = this
      function findNodeByLabel (label) {
        let result = null
        function loop (tree) {
          if (tree) {
            tree.find(node => {
              if (vm.getLevel(node, vm.labelKey, vm.showAllLevels) === label) {
                result = node
                return true
              }
              if (hasArrayChild(node, vm.childrenKey)) {
                loop(node[vm.childrenKey])
              }
            })
          }
        }
        if (label) {
          loop(vm.clonedOpts)
          return result
        }
      }
      const deletedItem = findNodeByLabel(label)
      if (deletedItem) {
        vm.checkedChange(deletedItem, false)
      }
      this.$emit(\'remove-tag\', label, deletedItem)
    },
    clearTag () {
      const vm = this
      function loop (nodeArr) {
        nodeArr.forEach(node => {
          node.checked = false
          node.indeterminate = false
          if (hasArrayChild(node, vm.childrenKey)) {
            loop(node[vm.childrenKey])
          }
        })
      }
      // 关闭全部状态
      loop(this.clonedOpts)
      this.selectedLabels = []
      this.selectedValues = []
      this.selectedItems = []
      this.$emit(\'clear\')
      this.syncData()
    },
    // 菜单选中变化
    checkedChange (item, checked) {
      // 这是是做单选的处理,如果多选去掉此行
      this.defaultLabels = []
      this.clearTag()
      console.log(item, checked)
      item.checked = checked
      this.$emit(\'clickItem\', item)
      this.markChildrenChecked(item)
      this.markParentChecked(item)
      this.markParentHasCheckChild(item)
      this.pickCheckedItem(this.clonedOpts)
      this.refresPopover()
      this.syncData()
    },
    // 同步数据到上层
    syncData () {
      console.log(this.selectedValues)
      this.$emit(\'input\', this.selectedValues)
      this.$emit(\'change\', this.selectedValues, this.selectedItems)
    },
    // 展开下一级
    async spreadNext (children, index, item) {
      const vm = this
      if (
        vm.allowLoadChildren &&
        !children && !item[vm.childrenKey] &&
        vm.loadChildrenMethod &&
        vm.loadChildrenMethod.constructor === Function &&
        !vm.loadChildrenPromise && // promise 不存在
        !item.isLeaf
      ) {
        const isPromiseMethod = this.loadChildrenMethod(item)
        if (isPromise(isPromiseMethod)) {
          vm.loadChildrenPromise = isPromiseMethod
          this.$set(item, \'loading\', true)
          const result = await vm.loadChildrenPromise.catch(e => {
            this.$set(item, \'loading\', false)
          })
          this.$set(item, \'loading\', false)
          vm.loadChildrenPromise = null
          if (result && result.constructor === Array) {
            this.recursiveOpt(result, item)
            this.$set(item, vm.childrenKey, result)
            children = result
            this.initDatas()
          } else {
            console.warn(\'The resolved value by loadChildrenMethod must be an Option Array !\')
          }
        } else {
          console.warn(\'You must return a Promise instance in loadChildrenMethod !\')
        }
      }
      if (index || index === 0) {
        if (vm.casTree.indexOf(children) === -1) {
          if (children && children.length > 0) {
            vm.casTree.splice(index + 1, vm.casTree.length - 1, children)
          } else {
            vm.casTree.splice(index + 1, vm.casTree.length - 1)
          }
          vm.$emit(\'spread\', item)
        }
      }
    },
    visibleChange (visible) {
      if (visible) {
        this.showPopover = true
      }
    },
    handleFocus (evt) {
      if (this.disabled) return
      this.$emit(\'focus\', evt)
    },
    hidePopover (evt) {
      this.showPopover = false
      this.$emit(\'blur\', evt)
    },
    refresPopover () {
      setTimeout(() => {
        fireEvent(window, \'resize\')
      }, 66)
    }
  }
}
</script>

<style lang="less">
.hide-popper {
  display: none;
}
.cascader-popper {
  padding: 0px;
}
.crec-popover-inner-content {
  padding: 0;
}
.cascader-menu-wrapper {
  white-space: nowrap;
  .crec-cascader-menu {
    padding: 8px 0;
    height: 240px;
  }
}
.cascader-menu-wrapper .cascader-checkbox {
  margin-right: 10px;
  font-weight: 500;
  font-size: 14px;
  cursor: pointer;
  user-select: none;
}
.crec-cascader-menu-item.has-checked-child {
  background-color: #f5f7fa !important;
}

.dropdown__empty {
  height: 100%;
  padding-top: 50%;
  margin: 0;
  text-align: center;
  color: #999;
  font-size: 14px;
}
.can-load-children {
  position: relative;
}
.can-load-children::after {
  content: \'\';
  display: inline-block;
  position: absolute;
  width: 5px;
  height: 5px;
  background: #a5d279;
  right: 20px;
  top: 50%;
  border-radius: 50%;
  transform: translateY(-50%);
  -webkit-transform: translateY(-50%);
}
.can-load-children.loading-children::after {
  animation: loading 0.22s infinite alternate;
  -moz-animation: loading 0.22s infinite alternate; /* Firefox */
  -webkit-animation: loading 0.22s infinite alternate; /* Safari 和 Chrome */
  -o-animation: loading 0.22s infinite alternate; /* Opera */
}
@keyframes loading {
  from {
    background: #a5d279;
  }
  to {
    background: #334d19;
  }
}
</style>
export function deepClone (source) {
  if (!source && typeof source !== \'object\') {
    throw new Error(\'error arguments\', \'shallowClone\')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === \'object\') {
      targetObj[keys] = source[keys].constructor === Array ? [] : {}
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

export function hasArrayChild (obj, childrenKey) {
  return obj[childrenKey] && Array.isArray(obj[childrenKey])
}

let id = 0

export function getId () {
  return ++id
}

export function fireEvent (element, event) {
  if (document.createEventObject) {
    // IE浏览器支持fireEvent方法
    const evt = document.createEventObject()
    return element.fireEvent(\'on\' + event, evt)
  } else {
    // 其他标准浏览器使用dispatchEvent方法
    const evt = document.createEvent(\'HTMLEvents\')
    evt.initEvent(event, true, true)
    return !element.dispatchEvent(evt)
  }
}

export function isPromise (obj) {
  return !!obj && (typeof obj === \'object\' || typeof obj === \'function\') && typeof obj.then === \'function\'
}

// 所有选项
export const props = {
  value: {
    type: [Array, String],
    default () {
      return \'\'
    }
  },
  placeholder: {
    type: String,
    default: \'请选择\'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  options: {
    type: Array,
    default () {
      return []
    }
  },
  defaultOptions: {
    type: Array,
    default () {
      return []
    }
  },
  size: {
    type: String,
    default: \'\'
  },
  selectChildren: {
    type: Boolean,
    default: false
  },
  noDataText: {
    type: String,
    default: \'无数据\'
  },
  collapseTags: {
    type: Boolean,
    default: false
  },
  separator: {
    type: String,
    default: \'/\'
  },
  showAllLevels: {
    type: Boolean,
    default: false
  },
  outputLevelValue: {
    type: Boolean,
    default: false
  },
  // 显示加载指示器
  showLoadingIndicator: {
    type: Boolean,
    default: true
  },
  // 允许加载子项
  allowLoadChildren: {
    type: Boolean,
    default: false
  },
  // 加载方法
  loadChildrenMethod: {
    type: Function,
    default: null,
    return: Promise
  },
  // key
  labelKey: {
    type: String,
    default: \'label\'
  },
  valueKey: {
    type: String,
    default: \'value\'
  },
  childrenKey: {
    type: String,
    default: \'children\'
  },
  popperClass: {
    type: String,
    default: \'\'
  },
  clearable: {
    type: Boolean,
    default: false
  },
  panelWidth: {
    type: [Number, String],
    default: 160
  }
}
import Vue from \'vue\'

const isServer = Vue.prototype.$isServer

/* istanbul ignore next */
export const on = (function () {
  if (!isServer && document.addEventListener) {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.addEventListener(event, handler, false)
      }
    }
  } else {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.attachEvent(\'on\' + event, handler)
      }
    }
  }
})()

const nodeList = []
const ctx = \'@@clickoutsideContext\'

let startClick
let seed = 0

!Vue.prototype.$isServer && on(document, \'mousedown\', e => (startClick = e))

!Vue.prototype.$isServer && on(document, \'mouseup\', e => {
  nodeList.forEach(node => node[ctx].documentHandler(e, startClick))
})

function createDocumentHandler (el, binding, vnode) {
  return function (mouseup = {}, mousedown = {}) {
    if (!vnode ||
      !vnode.context ||
      !mouseup.target ||
      !mousedown.target ||
      el.contains(mouseup.target) ||
      el.contains(mousedown.target) ||
      el === mouseup.target ||
      (vnode.context.popperElm &&
        (vnode.context.popperElm.contains(mouseup.target) ||
          vnode.context.popperElm.contains(mousedown.target)))) return

    if (binding.expression &&
      el[ctx].methodName &&
      vnode.context[el[ctx].methodName]) {
      vnode.context[el[ctx].methodName]()
    } else {
      el[ctx].bindingFn && el[ctx].bindingFn()
    }
  }
}

/**
 * v-clickoutside
 * @desc 点击元素外面才会触发的事件
 * @example
 * ```vue
 * <div v-element-clickoutside="handleClose">
 * ```
 */
export default {
  bind (el, binding, vnode) {
    nodeList.push(el)
    const id = seed++
    el[ctx] = {
      id,
      documentHandler: createDocumentHandler(el, binding, vnode),
      methodName: binding.expression,
      bindingFn: binding.value
    }
  },

  update (el, binding, vnode) {
    el[ctx].documentHandler = createDocumentHandler(el, binding, vnode)
    el[ctx].methodName = binding.expression
    el[ctx].bindingFn = binding.value
  },

  unbind (el) {
    const len = nodeList.length

    for (let i = 0; i < len; i++) {
      if (nodeList[i][ctx].id === el[ctx].id) {
        nodeList.splice(i, 1)
        break
      }
    }
    delete el[ctx]
  }
}

以上是关于phpcms模型管理如何支持联动菜单多选?的主要内容,如果未能解决你的问题,请参考以下文章

求phpcms分类信息的设置及联动菜单的使用?每个独立的区域怎么可作为搜索条件用?

phpcms联动菜单有啥用

如何让phpcms v9联动菜单显示值

phpcms网站建设中,联动菜单怎样读取?联动菜单菜单调用方法

PHPCMS的联动菜单有没有那位成功使用的教程及案例呢

PHPCMS V9联动菜单下拉显示不全