<template>
  <div class="app-container">
    <el-button type="primary" @click="handleAddRole">
      新增角色
    </el-button>

    <el-table
      :data="rolesList"
      style="width: 100%;margin-top:30px;"
      border
    >
      <el-table-column
        prop="name"
        align="center"
        label="角色名"
        width="220"
      />
      <el-table-column
        prop="desc"
        align="header-center"
        label="说明"
      />
      <el-table-column
        prop="disable"
        label="状态"
        align="center"
        width="100"
      >
        <template
          slot-scope="scope"
        >
          <el-tag :type="scope.row.disable === 0 ? 'success' : 'danger'">
            {{ scope.row.disable === 0 ? '正常' : '已禁用' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        align="center"
        label="操作"
        width="220px"
      >
        <template
          slot-scope="{ row }"
        >
          <el-button
            type="primary"
            size="mini"
            @click="handleEdit(row)"
          >
            编辑权限
          </el-button>
          <el-button
            type="primary"
            size="mini"
            @click="handleChangeStatus(row)"
          >
            {{ row.disable === 0 ? '禁用' : '启用' }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-dialog
      v-if="dialogVisible"
      :visible.sync="dialogVisible"
      top="50px"
      :title="dialogType==='edit'?'编辑角色':'添加角色'"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
      :before-close="handleAddRoleCancel"
    >
      <el-form
        :model="role"
        label-width="80px"
        label-position="left"
      >
        <el-form-item
          label="角色名"
        >
          <el-input
            v-model="role.name"
            placeholder="角色名"
          />
        </el-form-item>
        <el-form-item
          label="说明"
        >
          <el-input
            v-model="role.desc"
            :autosize="{ minRows: 2, maxRows: 4}"
            type="textarea"
            placeholder="角色说明"
          />
        </el-form-item>
        <el-form-item
          label="权限"
        >
          <div style="height:500px;overflow-y:scroll;">
            <el-tree
              ref="tree"
              :data="routesData"
              :props="defaultProps"
              show-checkbox
              node-key="path"
              default-expand-all
              class="permission-tree"
            >
              <div slot-scope="{ node, data }" class="custom-tree-node">
                <span @click="seeNode(node)">{{ node.label }}</span>
                <div v-if="data.authList && data.authList.length > 0">
                  <role-checkbox
                    :auth-list="data.authList"
                    :sure-list="data.buttonAuthList"
                    :selected="node.checked"
                    :parent-key="node.key"
                    @changebtnauth="changeParent"
                  />
                </div>
              </div>
            </el-tree>
          </div>
        </el-form-item>
      </el-form>
      <div style="text-align:right;">
        <el-button
          type="danger"
          @click="handleAddRoleCancel"
        >
          取消
        </el-button>
        <el-button
          type="primary"
          @click="confirmRole"
        >
          确定
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import path from 'path'
import { deepClone } from '@/utils'

import {
  asyncRoutes
} from '@/router/auth'

import {
  getRolesList,
  changeRole,
  addRole,
  editRole
} from '@/api/roles'

import RoleCheckbox from '@/components/RoleCheckbox/index'

const defaultRole = {
  key: '',
  name: '',
  desc: '',
  routes: []
}

export default {
  components: {
    RoleCheckbox
  },
  data() {
    return {
      role: Object.assign({}, defaultRole),
      routes: [],
      rolesList: [],
      dialogVisible: false,
      dialogType: 'new',
      defaultProps: {
        children: 'children',
        label: 'title'
      },
      changeTreeNodeType: false,
      editId: '',
      editType: {
        type: false,
        routes: []
      }
    }
  },
  computed: {
    routesData() {
      return this.routes
    }
  },
  watch: {
    dialogVisible(newVal, oldVal) {
      if (newVal) {
        this.getRoutes()
      }
    }
  },
  created() {
    this.getRoleList()
  },
  methods: {
    async getRoleList() {
      try {
        const { data } = await getRolesList()
        this.rolesList = data
      } catch (e) {
        console.log(`请求角色列表失败:${e}`)
      }
    },
    async getRoutes() {
      this.serviceRoutes = asyncRoutes
      const routes = this.generateRoutes(asyncRoutes)
      this.routes = this.deepRouter(routes)
    },
    // 深度遍历路由
    deepRouter(routes) {
      const app = routes.map(route => {
        route.route = route.title
        if (route.children) {
          route.children = this.deepRouter(route.children)
        }
        return route
      })
      return app
    },
    // 重塑路由结构，使其看起来与侧边栏相同
    generateRoutes(routes, basePath = '/') {
      const res = []

      for (let route of routes) {
        // skip some route
        if (route.hidden) { continue }

        const onlyOneShowingChild = this.onlyOneShowingChild(route.children, route)

        if (route.children && onlyOneShowingChild && !route.alwaysShow) {
          route = onlyOneShowingChild
        }

        const data = {
          path: path.resolve(basePath, route.path),
          title: route.meta && route.meta.title,
          buttonAuthList: route.meta && route.meta.buttonAuthList,
          authList: (route.meta && route.meta.authList) || []
        }

        // 递归子节点路由
        if (route.children) {
          data.children = this.generateRoutes(route.children, data.path)
        }

        res.push(data)
      }
      return res
    },
    generateArr(routes) {
      let data = []
      routes.forEach(route => {
        data.push(route)
        if (route.children) {
          const temp = this.generateArr(route.children)
          if (temp.length > 0) {
            data = [...data, ...temp]
          }
        }
      })
      return data
    },
    // 添加路由
    handleAddRole() {
      this.role = Object.assign({}, defaultRole)
      if (this.$refs.tree) {
        this.$refs.tree.setCheckedNodes([])
      }
      this.dialogType = 'new'
      this.dialogVisible = true
    },
    // 编辑
    handleEdit(row) {
      const { id } = row
      this.editId = id
      let { permissions } = row
      permissions = JSON.parse(permissions)

      this.dialogType = 'edit'
      this.dialogVisible = true
      this.role = deepClone(row)
      const routes = this.generateRoutes(permissions)
      this.$nextTick(() => {
        let editRoutes = this.generateArr(routes)
        editRoutes = editRoutes.filter(item => {
          return !(item.children && item.children.length > 0)
        })
        editRoutes.map(item => {
          if (item.buttonAuthList && this.$refs.tree.getNode(item.path)) {
            this.$refs.tree.getNode(item.path).data.buttonAuthList = item.buttonAuthList
          }
        })
        this.$refs.tree.setCheckedNodes(editRoutes)
      })
    },
    // 禁用启用
    async handleChangeStatus(row) {
      const { id } = row
      try {
        const { message, code } = await changeRole({ id })
        this.$message({
          message,
          type: code === 200 ? 'success' : 'error'
        })
        if (code === 200) {
          this.getRoleList()
        }
      } catch (e) {
        const { message } = await getRolesList() ? await getRolesList() : { message: '请求失败' }
        this.$message.error(message)
      }
    },
    // 将路由遍历为可使用的树结构
    generateTree(routes, basePath = '/', checkedKeys, checkedNodes) {
      const res = []

      for (const route of routes) {
        const routePath = path.resolve(basePath, route.path)

        if (route.meta && route.meta.linkRouter) {
          const rIndex = checkedKeys.indexOf(route.meta.linkRouter)
          if (rIndex !== -1) {
            route.meta.buttonAuthList = checkedNodes[rIndex].buttonAuthList
          }
        }

        if (route.meta && route.meta.authList && route.meta.buttonAuthList) {
          // keys数组的排列顺序和nodes完全相同
          const index = checkedKeys.indexOf(routePath)
          if (index !== -1) {
            route.meta.authList = checkedNodes[index].authList
            route.meta.buttonAuthList = checkedNodes[index].buttonAuthList
          }
        }

        // 递归所有子节点
        if (route.children) {
          route.children = this.generateTree(route.children, routePath, checkedKeys, checkedNodes)
        }

        if (checkedKeys.includes(routePath) || (route.children && route.children.length >= 1) || route.hiddenButNeed) {
          res.push(route)
        }
      }
      return res
    },
    // 提交添加/修改
    async confirmRole() {
      if (!this.role.name) {
        this.$message.error('角色名不能为空')
        return false
      }

      const isEdit = this.dialogType === 'edit'
      // 所有选中的节点keys
      const checkedKeys = this.$refs.tree.getCheckedKeys()

      // 所有选中的节点nodes
      const checkedNodes = this.$refs.tree.getCheckedNodes()

      this.role.routes = this.generateTree(deepClone(this.serviceRoutes), '/', checkedKeys, checkedNodes)
      if (this.role.routes.length < 1) {
        this.$message.error('权限最少设置一项')
        return false
      }
      if (isEdit) {
        try {
          const res = await editRole({
            id: this.editId,
            name: this.role.name,
            desc: this.role.desc,
            permissions: JSON.stringify(this.role.routes)
          })
          const { message, code } = res
          this.$message({
            message,
            type: code === 200 ? 'success' : 'error'
          })
          if (code === 200) {
            this.dialogVisible = false
            this.getRoleList()
          }
        } catch (e) {
          console.log(`修改角色失败: ${e}`)
        }
      } else {
        try {
          const res = await addRole({
            name: this.role.name,
            desc: this.role.desc,
            permissions: JSON.stringify(this.role.routes)
          })
          const { message, code } = res
          this.$message({
            message,
            type: code === 200 ? 'success' : 'error'
          })
          if (code === 200) {
            this.dialogVisible = false
            this.getRoleList()
          }
        } catch (e) {
          console.log(`添加角色失败:${e}`)
        }
      }
    },
    // reference: src/view/layout/components/Sidebar/SidebarItem.vue
    onlyOneShowingChild(children = [], parent) {
      let onlyOneChild = null
      const showingChildren = children.filter(item => !item.hidden)

      // 只有一个子路由时，默认显示子路由
      if (showingChildren.length === 1) {
        onlyOneChild = showingChildren[0]
        onlyOneChild.path = path.resolve(parent.path, onlyOneChild.path)
        return onlyOneChild
      }

      // Show parent if there are no child route to display
      if (showingChildren.length === 0) {
        onlyOneChild = { ... parent, path: '', noShowingChildren: true }
        return onlyOneChild
      }

      return false
    },
    // 取消添加修改角色弹窗
    handleAddRoleCancel() {
      this.dialogVisible = false
      this.editType.type = false
      this.editType.routes = []
    },
    seeNode(node) {
      console.log(node)
    },
    changeParent(list, key) {
      const parentNode = this.$refs.tree.getNode(key)
      parentNode.data.buttonAuthList = list
    }
  }
}
</script>

<style lang="scss" scoped>
.app-container {
  .roles-table {
    margin-top: 30px;
  }
  .permission-tree {
    margin-bottom: 30px;
  }

  .button_auth_checkbox{
    display: block;
    margin-left: 10px;
  }
}
</style>

<style lang="scss">
  .el-tree-node__content{
    height: auto !important;
    align-items: flex-start;
  }
  .el-tree-node__expand-icon.expanded{
    height: 36px;
    display: flex;
    justify-content: center;
  }
</style>
