<!--
 * @Description: 角色新增和编辑所用的对话框组件
 * @Author: liusheng，wanqian, gaohc
 * @Date: 2021-02-11 17:56:28
-->
<template>
  <el-dialog class="dialog-underline" width="740px" :title="dialogTitle" :visible.sync="visible" 
    :close-on-click-modal="false" @open="initData" :before-close='handleCancel' center>
    <el-form class="form" ref="roleForm" :model="roleForm" :rules="rules" label-width="110px">
      <div style="display:flex">
        <el-form-item label="角色名称：" prop="name">
          <el-input size="small" placeholder="请输入角色名称" 
            v-model="roleForm.name" autocomplete="off" style="width:220px;" />
        </el-form-item>
        <el-form-item  v-if="enableInstLevel" label="所属机构：" prop="instCode">
          <el-select size="small" style="width:220px;" v-model="roleForm.instCode"
            placeholder="请选择机构" :disabled="false">
            <el-option v-for="(inst, index) in instList" :key="index" :label="inst.name" :value="inst.instCode" />
          </el-select>
        </el-form-item>
      </div>
      <div style="display:flex">
        <el-form-item label="角色类型：" prop="type">
          <el-select size="small" style="width:220px;" v-model="roleForm.type" placeholder="请选择角色类型" :disabled="true">
            <el-option v-for="(type, index) in roleTypeList" :key="index" :label="type.value" :value="type.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="用户类型：" prop="userType">
          <el-select size="small" style="width:220px;" v-model="roleForm.userType" placeholder="请选择用户类型" :disabled="true">
            <el-option v-for="(userType, index) in userTypeList" :key="index" :label="userType.value" :value="userType.key" />
          </el-select>
        </el-form-item>
      </div>
      <div style="display:flex">
        <el-form-item label="功能权限：" prop="funcPvg">
          <el-tree :data="funcPvgTree" :props="treeProps" show-checkbox class="tree-block" node-key="treeKey"
            :default-checked-keys="funcPvgCheckedKeys" @check="handleFuncPvgCheck" />
        </el-form-item>
        <el-form-item label="数据权限：" prop="dataPvg">
          <el-tree :data="dataPvgTree" :props="treeProps" show-checkbox class="tree-block" node-key="id"
            :default-checked-keys="dataPvgCheckedKeys" @check="handleDataPvgCheck" />
        </el-form-item>
      </div>
    </el-form>
    <div class="dialog-footer">
      <el-button @click="handleCancel">取 消</el-button>
      <el-button type="primary" @click="handleSubmit('roleForm')">保 存</el-button>
    </div>
  </el-dialog>
</template>

<script>
export default {
  name: 'RoleDialog',
  props: ["visible", "mode", "roleId", "enableInstLevel", "userType", "instCode"],

  data() {
    let validateFuncPvg = (_rule, _value, callback) => {
      if (this.funcPvgCheckedKeys.length == 0) {
        callback(new Error('请至少选择一项功能权限'));
      } else {
        callback();
      }
    };

    let validateDataPvg = (_rule, _value, callback) => {
      if (this.dataPvgCheckedKeys.length == 0) {
        callback(new Error('请至少选择一项数据权限'));
      } else {
        callback();
      }
    };
    
    return {
      roleForm: {},
      roleTypeList: [],
      userTypeList: [],  //用户类型列表
      instList: [],  //用户类型列表

      treeProps: { children: 'children', label: 'name' },
      threeLevelMenu: false,
      funcPvgTree: [{}],
      dataPvgTree: [{}],
      funcPvgCheckedKeys: [0],   //定义一个元素，以避免显示表单验证错误信息
      dataPvgCheckedKeys: [0],

      rules: {
        name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
        instCode: [{ required: true, message: '请选择所属机构', trigger: 'blur' }],
        type: [{ required: true, message: '请选择角色类型', trigger: 'blur' }],
        userType: [{ required: true, message: '请选择用户类型', trigger: 'blur' }],
        funcPvg: { required: true, validator: validateFuncPvg, trigger: 'blur' },
        dataPvg: { required: true, validator: validateDataPvg, trigger: 'blur' }
      }
    }
  },

  computed: {
    dialogTitle() {
      return (this.mode === 'add') ?  "新增角色" : "编辑角色";
    }
  },

  methods: {
    initData() {
      this.clearVaild();

      let url = (this.mode === 'add') 
        ? this.commonUrl.URL_GET_ROLEDO_4_ADD : this.commonUrl.URL_GET_ROLEDO_4_UPDATE;
      let param = (this.mode === 'edit') ? { id: this.roleId }
        : { userType: this.userType, instCode: this.instCode }
      let requestData = {
        method: 'GET',
        url: url,
        param: param,
      };
      this.vueRequest(requestData).then(result => {
        if (result == null) return;

        this.buildFormData(result.data);
        this.buildFuncPvgChecks();
        this.buildDataPvgChecks();
      })
    },
    
    buildFormData(data) {
      this.threeLevelMenu = data.threeLevelMenu;
      this.instList = (this.enableInstLevel) ? data.instList : [];
      this.roleTypeList = this.commonUtil.map2List(data.roleTypeMap);
      this.userTypeList = this.commonUtil.map2List(data.userTypeMap);
      this.funcPvgTree = data.funcPvgTree;
      this.dataPvgTree = data.dataPvgTree;

      this.roleForm = {
        id: data.role.id, 
        name: data.role.name,
        type: (this.mode === 'add') ? this.roleTypeList[0].key : String(data.role.type),
        userType: (this.mode === 'add') ? this.userTypeList[0].key : String(data.role.userType),
        instCode: (!this.enableInstLevel) ? '' :
          (this.mode === 'add') ? this.instList[0].instCode : data.role.instCode
      };
    },
    
    /**
     * 为两级或三级菜单的各菜单项填充默认check值，同时为菜单节点增加treeKey属性：
     * 1 三级菜单中的直接触发项，直接为其增加treeKey属性
     * 2 两级菜单或三级菜单中的二、三级，为第三级菜单增加treeKey属性
     * treeKey属性用于区分funcPvgCheckedKeys中同时放置的三级菜单项id和顶级菜单项id
     */
    buildFuncPvgChecks() {
      this.funcPvgCheckedKeys = [];
      if (this.threeLevelMenu) {
        for (let baseMenu of this.funcPvgTree) {
          if (!baseMenu.menuList || baseMenu.menuList.length == 0) {
            baseMenu['treeKey'] = "base-" + baseMenu.id;
            if (baseMenu.checked) {
              this.funcPvgCheckedKeys.push(baseMenu.treeKey);
            }
          }
          this.setMenuChecks(baseMenu.children);
        }
      } else {
        this.setMenuChecks(this.funcPvgTree);
      }
    },
    
    setMenuChecks(menuList) {
      for (let menu of menuList) {
        for (let submenu of menu.children) {
          submenu['treeKey'] = "sub-" + submenu.id + "+" + submenu.baseMenuId;
          if (submenu.checked) {
            this.funcPvgCheckedKeys.push(submenu.treeKey);
          }
        }
      }
    },

    buildDataPvgChecks() {
      this.dataPvgCheckedKeys = [];
      for (let dpvgEntity of this.dataPvgTree) {
        for (let dataPvg of dpvgEntity.dataPvgList) {
          if (dataPvg.checked) {
            this.dataPvgCheckedKeys.push(dataPvg.id);
          }
        }
      }
    },

    clearData() {
      this.roleForm = {};
      this.threeLevelMenu = false;
      this.roleTypeList = {};
      this.funcPvgTree = [{}];
      this.dataPvgTree = [{}];
      this.funcPvgCheckedKeys = [0];
      this.dataPvgCheckedKeys = [0];
    },

    clearVaild() {
      this.$nextTick(() => {
        this.$refs["roleForm"].clearValidate();
      });
    },
    
    handleFuncPvgCheck(_data, state) {
      this.funcPvgCheckedKeys = state.checkedKeys.filter(Boolean);
    },

    handleDataPvgCheck(_data, state) {
      this.dataPvgCheckedKeys = state.checkedKeys.filter(Boolean);
    },

    handleSubmit(roleForm) {
      this.$refs[roleForm].validate((valid) => {
        if (!valid) return false;
        
        let url = (this.mode == 'add') ? this.commonUrl.URL_SAVE_ROLE : this.commonUrl.URL_UPDATE_ROLE;
        let method = (this.mode == 'add') ? 'POST' : 'PUT';
        
        let role = this.buildRoleEntity();
        this.appAxios(method, url, role).then(result => {
          if (result != null) {
            this.clearData();
            this.$emit("close-dialog", true);
          }
        })
      });
    },
    
    buildRoleEntity() {
      let role = { ...this.roleForm };
      if (this.mode == 'add') {
        role.id = 0;
      }
      
      if (this.threeLevelMenu) {
        // step1-第三级选中的菜单项所属的baseFuncId集合
        let baseFuncPvgIds = this.funcPvgCheckedKeys.filter
          (key => key.startsWith('sub-')).map(key => key.substring(key.indexOf('+') + 1));
        baseFuncPvgIds = [...new Set(baseFuncPvgIds)];   //去掉重复元素

        // step2-筛选出顶级菜单中的直接触发菜单项id集合
        let baseFuncPvgCheckedKeys = this.funcPvgCheckedKeys.filter
          (key => key.startsWith('base-')).map(key => key.substring(5));
        
        // step3-将前两步的集合合并，进而生成role.funcBasePvgIds
        role.funcBasePvgIds = baseFuncPvgIds.concat(baseFuncPvgCheckedKeys).sort().join(',');
      }

      let funcPvgCheckedKeys = this.funcPvgCheckedKeys.filter
        (key => key.startsWith('sub-')).map(key => key.substring(4, key.indexOf('+')));
      role.funcPvgIds = funcPvgCheckedKeys.sort().join(',');

      role.dataPvgIds = this.dataPvgCheckedKeys.sort().join(',');
      return role;
    },

    handleCancel() {
      this.clearData();
      this.$emit("close-dialog", false);
    }
  },
}
</script>

<style scoped>
.form {
  margin-bottom: 10px;
}

.tree-block {
  width: 220px;
  height: 320px;
  overflow-y: auto;
  border: #f4f4f4 solid 1px;
  border-radius: 4px;
}

.dialog-footer {
  text-align: center;
}
</style>