<template>
  <div>
    <a-form
      layout="inline"
      :model="searchFilter"
      laba-width="70px"
    >
      <a-form-item
        label="系统"
        prop
      >
        <a-select
          v-model="appId"
          style="width: 120px"
          placeholder="请选择系统"
        >
          <a-select-option
            v-for="item in appList"
            :key="item.id"
            :value="item.id"
          >
            {{ item.cnName }}
          </a-select-option>
        </a-select>
      </a-form-item>
      <a-form-item>
        <a-button
          plain
          @click="resetForm"
        >
          重置条件
        </a-button>
      </a-form-item>
    </a-form>

    <div>
      <div
        v-if="appId"
        style="text-align:right;"
      >
        <a-button
          v-auth="'AUTH_MENU-SAVE'"
          type="link"
          size="small"
          class="lk-mr-16"
          @click="syncMenuResource"
        >
          同步所有菜单资源
        </a-button>
        <a-button
          v-model="isResetMenu"
          v-auth="'AUTH_MENU-SAVE'"
          text="重置中..."
          class="lk-mr-16"
          @click="resetMenu"
        >
          重置菜单
        </a-button>
        <a-button
          v-model="isSave"
          v-auth="'AUTH_MENU-SAVE'"
          type="primary"
          text="保存中..."
          @click="save"
        >
          保存
        </a-button>
      </div>
      <div style="display:inline-block;width:49%;vertical-align:top;">
        <a-tree
          :data="treeData"
          node-key="id"
          :props="defaultProps"
          default-expand-all
          :allow-drop="allowDrop"
          :allow-drag="allowDrag"
          empty-text="请选择系统"
          :expand-on-click-node="false"
          :highlight-current="true"
          draggable
          @node-drag-end="handleDragEnd"
          @node-click="nodeClick"
        >
          <span
            slot-scope="{ node, data }"
            class="custom-tree-node"
          >
            <span :class="{lineThrough:data.isActive === 0,green:data.id === 0}">
              {{ node.label }}
              <span
                v-if="data.level === 3"
                :class="{green:data.resources.length!==0,red:data.resources.length === 0}"
              >({{ data.resources.length }})</span>
            </span>
            <span class="node-button">
              <a-button
                v-if="data.level < 3"
                v-auth="'AUTH_MENU-SAVE'"
                type="text"
                size="mini"
                @click.stop="() => appendSub(data)"
              >子菜单</a-button>
              <a-button
                v-if="data.id !== -1"
                v-auth="'AUTH_MENU-SAVE'"
                type="text"
                size="mini"
                @click.stop="() => append(node, data)"
              >同级菜单</a-button>
              <a-button
                v-if="data.id !== -1"
                v-auth="'AUTH_MENU-SAVE'"
                type="text"
                size="mini"
                @click.stop="() => remove(node, data)"
              >删除</a-button>
            </span>
          </span>
        </a-tree>
      </div>
      <div
        v-if="typeof menu.id !== 'undefined'"
        style="display:inline-block;width:49%;vertical-align:top;"
      >
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require"></span>菜单id:
          </label>
          <a-input
            v-model="menu.id"
            type="text"
            :disabled="true"
            placeholder="菜单id"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require"></span>排序:
          </label>
          <a-input
            v-model="menu.sort"
            type="text"
            :disabled="true"
            placeholder="排序"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require">*</span>图标:
          </label>
          <a-input
            v-model="menu.icon"
            type="text"
            placeholder="请输入图标"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require">*</span>菜单名字:
          </label>
          <a-input
            v-model="menu.name"
            type="text"
            placeholder="请输入菜单名字"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require"></span>扩展字段:
          </label>
          <a-input
            v-model="menu.ext"
            type="text"
            placeholder="扩展字段"
          />
        </div>
        <div
          v-show="menu.level === 1"
          class="form-row form-group"
        >
          <label class="text-right">
            <span class="require"></span>菜单显示表达式:
          </label>
          <a-input
            v-model="menu.showReg"
            type="text"
            placeholder="菜单显示表达式"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require">*</span>菜单地址:
          </label>
          <a-input
            v-model="menu.url"
            type="text"
            placeholder="请输入菜单地址"
          />
        </div>
        <div class="form-row form-group">
          <label class="text-right">
            <span class="require">*</span>是否显示:
          </label>
          <div>
            <a-radio v-model="menu.isActive" :label="1">显示</a-radio>
            <a-radio v-model="menu.isActive" :label="0">隐藏</a-radio>
          </div>
        </div>
        <div v-show="menu.level === 3">
          <div class="form-row form-group">
            <div class="form-line"></div>
          </div>
          <div class="form-row form-group">
            <a-button type="primary" @click="qucikSelect()">同名资源</a-button>
          </div>
          <a-transfer
            v-model="menu.resources"
            filterable
            :filter-method="filterResourceMethod"
            filter-placeholder="请输入资源名称"
            :data="menuResources"
            :titles="['全部资源', '关联资源']"
            :props="{
              key: 'id',
              label: 'name'
            }"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'AuthMenuList',
  data() {
    return {
      searchFilter: {},
      appId: null,
      appList: [],
      menuResources: [],
      treeData: [],
      defaultProps: {
        children: 'children',
        label: 'name'
      },
      isResetMenu: false,
      isSave: false,
      menu: {}
    }
  },
  watch: {
    appId() {
      if (!this.appId) {
        return
      }
      this.resetData()
      this.getMenuResources()
    }
  },
  mounted() {
    this.resetForm()
  },
  methods: {
    appendSub(data) {
      const menu = {
        id: 0,
        isActive: 1,
        name: '新建菜单',
        url: '',
        resources: [],
        children: []
      }
      data.children.push(menu)
      this.setLevel(this.treeData)
      this.menu = menu
      const tmp = this.treeData
      this.treeData = []
      this.$nextTick(() => {
        this.treeData = tmp
      })
    },
    remove(node, data) {
      this.$xyConfirm('确认是否删除，删除后数据将无法恢复？', () => {
        let index = -1
        node.parent.data.children.forEach((item, i) => {
          if (item === data) {
            index = i
          }
        })
        if (index === -1) return
        node.parent.data.children.splice(index, 1)
        this.setLevel(this.treeData)
        if (this.menu === data) {
          this.menu = {}
        }
      })
    },
    append(node) {
      const menu = {
        id: 0,
        isActive: 1,
        name: '新建菜单',
        url: '',
        resources: [],
        children: []
      }
      node.parent.data.children.push(menu)
      this.setLevel(this.treeData)
      this.menu = menu
    },
    handleDragEnd() {
      this.setLevel(this.treeData)
    },
    allowDrop(draggingNode, dropNode, type) {
      if (dropNode.data.id === -1) {
        return false
      }
      if (dropNode.data.level === 3) {
        return type !== 'inner'
      }
      return true
    },
    allowDrag(draggingNode) {
      if (draggingNode.data.id === -1) {
        return false
      }
      return true
    },
    nodeClick(menu) {
      if (menu.id === -1) {
        menu = {}
      }
      this.menu = menu
    },
    setLevel(data, level, sort) {
      level = level || 0
      sort = sort || 0
      if (!data || data.length === 0) {
        return sort
      }
      data.forEach(item => {
        item.level = level
        item.appId = this.appId
        item.sort = sort++
        item.children = item.children || []
        sort = this.setLevel(item.children, level + 1, sort)
      })
      return sort
    },
    resetMenu() {
      this.$xyConfirm('确认是否重置菜单，重置后修改的数据将无法恢复？', () => {
        this.isResetMenu = true
        this.resetData(() => {
          this.isResetMenu = false
        })
      })
    },
    async resetData(cb) {
      this.menu = {}
      this.treeData = []
      const data = await this.$store.dispatch('auth/authMenuList', {
        appId: this.appId
      })
      this.treeData = data || []
      this.treeData = [
        {
          id: -1,
          name: '全部菜单',
          children: this.treeData
        }
      ]
      this.initMenuResource(this.treeData)
      this.setLevel(this.treeData)
      cb && cb()
    },

    initMenuResource(menus) {
      if (!menus || menus.length === 0) {
        return
      }
      menus.forEach(menu => {
        menu.resources = menu.resources || ''
        menu.resources = menu.resources.replace(/^,/, '').replace(/,$/, '')
        if (menu.resources) {
          menu.resources = menu.resources.split(',')
          for (let i = 0; i < menu.resources.length; i++) {
            menu.resources[i] = Number(menu.resources[i])
          }
        } else {
          menu.resources = []
        }
        this.initMenuResource(menu.children)
      })
    },

    setResource(menus) {
      if (!menus || menus.length === 0) {
        return
      }
      menus.forEach(menu => {
        menu.resources = menu.resources || []
        menu.resources = menu.resources.join(',')
        if (menu.resources) {
          menu.resources = ',' + menu.resources + ','
        }
        this.setResource(menu.children)
      })
    },
    save() {
      this.setLevel(this.treeData)
      this.isSave = true
      const data = JSON.parse(JSON.stringify(this.treeData[0]))
      this.setResource([data])
      this.$postStream('/admin/auth/instance/authMenu/save.do', {
        data: data,
        success: res => {
          this.isSave = false
          if (!res.success) {
            return this.$message.error(res.message)
          }
          this.$message.success(res.message)
          this.resetData()
        }
      })
    },
    async resetForm() {
      const data = await this.$store.dispatch('auth/authAppList', {
        size: 1000
      })
      this.appList = data.list || []
      this.appId = ''
      this.treeData = []
    },
    filterResourceMethod(query, item) {
      return item.name.indexOf(query) > -1
    },
    async getMenuResources() {
      const data = await this.$store.dispatch('auth/authResourcesList', {
        appId: this.appId
      })
      this.menuResources = data
    },
    syncMenuResource() {
      const tmpTreeData = this.treeData[0].children
      tmpTreeData.forEach(item1 => {
        item1.children.forEach(item2 => {
          item2.children.forEach(item3 => {
            this.qucikSelect(item3)
          })
        })
      })
    },
    qucikSelect(menu) {
      menu = menu || this.menu

      if (!menu || !menu.name) return

      const resources = []
      this.menuResources.forEach(resource => {
        if (resource.name.indexOf(menu.name + '-') !== -1) {
          resources.push(resource.id)
        }
      })
      menu.resources = menu.resources || []
      resources.forEach(id => {
        if (menu.resources.indexOf(id) === -1) {
          menu.resources.push(id)
        }
      })
      const map = {}
      menu.resources.forEach(id => {
        map[id] = id
      })
      menu.resources = []
      for (const key in map) {
        menu.resources.push(Number(key))
      }
    }
  }
}
</script>

<style lang="scss">
.lineThrough {
  text-decoration: line-through;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 10px;
}

.form-line {
  height: 1px;
  background-color: #dcdfe6;
}
.a-transfer__buttons {
  padding: 0 6px;
}
.a-transfer__button {
  border-radius: 50%;
  font-size: 0;
  min-width: 0;
  padding: 0;
  height: 34px;
  width: 34px;
  line-height: 34px;
}
</style>
