<template>
  <div class="edit-role-body">
    <nav-crumb :navpath="bread"> </nav-crumb>
    <div style="padding: 20px;background:#fff">
      <el-alert
        type="info"
        title="管理角色：查看区域或门店日常业务，进行一些经营性的管理工作。不必关联导购账号。"
        :closable="false"
        show-icon
        style="margin-bottom: 30px;width: 572px"></el-alert>
      <el-form :model="roleData" :rules="roleDataRule" ref="roleData" label-width="140px" @submit.native.prevent>
        <el-form-item label="角色名称" prop="roleName">
          <el-input
            placeholder="请输入角色名称"
            maxlength="20"
            show-word-limit
            style="width: 432px"
            v-model.trim="roleData.roleName"></el-input>
        </el-form-item>
        <el-form-item label="权限配置" prop="menuIds">
          <el-radio-group v-model="activeType" class="specter" size="small">
            <el-radio-button v-for="el in tabList" :key="el.appType" :label="el.appType">{{ el.label }}</el-radio-button>
          </el-radio-group>
          <menu-tree
            style="margin-top: 12px"
            :menu-list="getActiveMenuList()"
            :checked-id="getActiveMenuChecked()"
            :app-ids="getAppIds()"
            :is-app="activeType == 2 || activeType == 4"
            @change="onCheckedChange"
            @app-open-change="onAppOpenChange"></menu-tree>
        </el-form-item>
        <el-form-item style="margin-top: 50px">
          <el-button type="primary" :loading="roleData.loading" @click="onSave">{{ roleData.roleId ? '保存' : '确认新建' }}</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import navCrumb from '@/components/nav/nav.vue';
import MenuTree from './edit-role/menu-tree.vue';
import api from '@/api/admin-list';

const { menuList, addRole, editRole, roleDetail, findAppSetting, saveAppSetting } = api;
export default {
  name: 'EditRole',
  components: { navCrumb, MenuTree },
  data() {
    const valiMenuIds = (rules, value, callback) => {
      if (!Array.isArray(value) || value.length == 0 || value.every(el => el.menuIds.length == 0)) {
        callback(new Error('请至少选择一个权限菜单'));
      }
      callback();
    };
    return {
      bread: [
        { name: '管理员', path: '/admin-list' },
        { name: !!this.$route.query.roleId ? '编辑管理角色' : '新建管理角色' }
      ],
      wxEnterpriseId: '',
      // 角色详情
      roleData: {
        loading: false,
        roleId: '',
        roleName: '',
        menuIds: []
      },
      roleDataRule: {
        roleName: [ { required: true, message: '角色名称不能为空', trigger: 'blur' } ],
        menuIds: [ { required: true, validator: valiMenuIds } ]
      },
      // 权限配置激活的tab
      activeType: 1,
      // 权限菜单列表
      tabList: [
        // 1好办后台2应用后台3好办小程序4小程序应用
        { label: '好办后台', appType: 1, flatMenu: [], menuList: [], checkedId: {}, appIds: [] },
        { label: '应用后台', appType: 2, flatMenu: [], menuList: [], checkedId: {}, appIds: [] },
        { label: '好办小程序', appType: 3, flatMenu: [], menuList: [], checkedId: {}, appIds: [] },
        { label: '小程序应用', appType: 4, flatMenu: [], menuList: [], checkedId: {}, appIds: [] },
      ]
    };
  },
  async created() {
    const haoBanUser = JSON.parse(localStorage.getItem('haoBanUser') || '{}');
    const { roleId } = this.$route.query;
    this.$emit('showAsideMenu', false);
    this.wxEnterpriseId = haoBanUser.wxEnterpriseId;
    await this.getMenuList(roleId);
    if (roleId) {
      this.bread[1] = { name: '编辑管理角色' };
      this.getRoleDetail(roleId);
    }
  },
  mounted() {
    document.documentElement.style.backgroundColor = '#f0f2f5';
  },
  destroyed() {
    document.documentElement.style.backgroundColor = '#fff';
  },
  methods: {
    /**
     * @description: 获取权限菜单列表
     * @param {String} roleId
     * @return {Function}
     * @author: 无尘
     */
    getMenuList(roleId) {
      // roleType 1管理员，0门店
      const params = { wxEnterpriseId: this.wxEnterpriseId, roleType: 1 };
      const prom = [];
      this.tabList.forEach(el => {
        // appType 1好办后台2应用后台3好办小程序4小程序应用
        // roleType 1管理员角色 2门店角色
        prom.push(menuList(Object.assign({}, params, { appType: el.appType })).then(res => {
          el.flatMenu = res.result || [];
          el.menuList = this.flatDataToTree(res.result || []);
          el.menuList.forEach(item => {
            this.$set(el.checkedId, item.menuId, []);
          });
          if (el.appType == 2 || el.appType == 4) {
            // 应用开关-查看
            findAppSetting(Object.assign({}, params, { roleId, appType: el.appType })).then(res => {
              el.appIds = res.result || [];
              this.setChildrenDisable(el.menuList, el.appIds);
            });
          }
        }));
      });
      return Promise.all(prom);
    },
    /**
     * @description: 获取角色详情
     * @param {String} roleId
     * @author: 无尘
     */
    getRoleDetail(roleId) {
      roleDetail({ roleId }).then(res => {
        let { roleId, roleName, menuIds } = res.result;
        menuIds = typeof menuIds == 'string' ? menuIds.split(',') : [];
        // roleData中存一份包含父节点的menuId
        // tabList中存一份不包含父节点的menuId
        Object.assign(this.roleData, { roleId, roleName });
        // 将menuIds分配到相应同的tab下的checkedId中
        this.tabList.forEach(el => {
          let checkedId = [];
          el.menuList.forEach(item => {
            el.checkedId[item.menuId] = getLeafMenuId([ item ], menuIds);
            checkedId = checkedId.concat(getAllMenuId([ item ], menuIds));
          });
          this.roleData.menuIds.push({ appType: el.appType, menuIds: checkedId });
        });
      });
      function getAllMenuId(menuList, allMenuIds) {
        let result = [];
        menuList.forEach(el => {
          if (allMenuIds.some(item => item == el.menuId)) {
            result.push(el.menuId);
          }
          if (Array.isArray(el.children)) {
            result = result.concat(getAllMenuId(el.children, allMenuIds));
          }
        });
        return result;
      }
      function getLeafMenuId(menuList, allMenuIds) {
        let result = [];
        // 所有子节点被选中，才算父节点被选中
        menuList.map(el => {
          if (allMenuIds.some(item => item == el.menuId)) {
            let allSubId = [];
            if (Array.isArray(el.children)) {
              allSubId = getAllSubMenuIds(el.children);
            }
            // 如果el的allSubId都在allMenuIds中，则认为el需要被勾选，需要把el.menuId放入result中
            if (allSubId.length == 0 || allSubId.every(el => allMenuIds.some(item => item == el))) {
              result.push(el.menuId);
            }
            if (Array.isArray(el.children)) {
              result = result.concat(getLeafMenuId(el.children, allMenuIds));
            }
          }
        });
        return result;
      }
      function getAllSubMenuIds(menuList) {
        let result = [];
        menuList.forEach(el => {
          result.push(el.menuId);
          if (Array.isArray(el.children)) {
            result = result.concat(getAllSubMenuIds(el.children));
          }
        });
        return result;
      }
    },
    /**
     * @description: 将平铺的数据转为树形结构
     * @param {Array} data
     * @return {Array}
     * @author: 无尘
     */
    flatDataToTree(data) {
      return data.filter(el => {
        // 返回当前节点下的子节点
        const children = data.filter(item => item.parentId == el.menuId);
        if (children.length > 0) {
          el.children = children; // 如果存在子级，则给父级添加一个children属性，并赋值
        }
        return el.parentCode == '' || el.parentCode == null;
      });
    },
    getActiveMenuList() {
      const result = this.tabList.filter(el => el.appType == this.activeType);
      return result[0].menuList;
    },
    getActiveMenuChecked() {
      const result = this.tabList.filter(el => el.appType == this.activeType);
      return result[0].checkedId;
    },
    getAppIds() {
      const result = this.tabList.filter(el => el.appType == this.activeType);
      return result[0].appIds;
    },
    /**
     * @description: 保存选中的子节点id,将选中的子节点的id存在tabList对应元素的checkedId中,同时更新roleData中menuIds的数据
     * @param {String} checkedId
     * @author: 无尘
     */
    onCheckedChange(checkedId) {
      let menuIds = [];
      let flatMenu = [];
      let allMenuIds = [];
      for(let key in checkedId) {
        menuIds = menuIds.concat(checkedId[key]);
      }
      this.tabList = this.tabList.map(el => {
        if (el.appType == this.activeType) {
          el.checkedId = checkedId;
          flatMenu = el.flatMenu;
        }
        return el;
      });
      // 根据任意层级的子节点向上查找全部的父节点，存入allMenuIds中，然后过滤掉重复的menuId
      menuIds.map(el => {
        allMenuIds = allMenuIds.concat(getParentIds(el, flatMenu));
      });
      allMenuIds = allMenuIds.filter((el, index) => index == allMenuIds.findIndex(item => item == el));

      if (this.roleData.menuIds.some(el => el.appType == this.activeType)) {
        this.roleData.menuIds.forEach(el => {
          if (el.appType == this.activeType) {
            el.menuIds = allMenuIds;
          }
        });
      } else {
        this.roleData.menuIds.push({ appType: this.activeType, menuIds: allMenuIds });
      }
      function getParentIds(menuId, menuList) {
        let result = [ menuId ];
        menuList.some(el => {
          if (el.menuId == menuId && el.parentId > 0) {
            result = result.concat(getParentIds(el.parentId, menuList));
          }
          return el.menuId == menuId;
        });
        return result;
      }
    },
    /**
     * @description: 切换应用的开启关闭状态,如果应用是关闭状态，需要将应用下的子菜单设置为禁用状态
     * @param {Array} appIds
     * @author: 无尘
     */
    onAppOpenChange(appIds) {
      this.tabList.some(el => {
        if (el.appType == this.activeType) {
          el.appIds = appIds;
          this.setChildrenDisable(el.menuList, el.appIds);
        }
        return el.appType == this.activeType;
      });
    },
    setChildrenDisable(menuList, appIds) {
      menuList.forEach(el => {
        let openFlag = false;
        appIds.some(item => {
          if (item.appId == el.project) {
            openFlag = item.openFlag;
          }
          return item.appId == el.project;
        });
        this.$set(el, 'disabled', openFlag == 0);
        if (Array.isArray(el.children)) {
          el.children = setDisable.call(this, el.children, openFlag == 0);
        }
      });
      function setDisable(menuList, openFlag) {
        return menuList.map(el => {
          this.$set(el, 'disabled', openFlag);
          if (Array.isArray(el.children)) {
            el.children = setDisable.call(this, el.children, openFlag);
          }
          return el;
        });
      }
    },
    /**
     * @description: 新建、编辑角色的保存
     * @author: 无尘
     */
    onSave() {
      this.$refs.roleData.validate(vali => {
        if (!vali) return;
        const { roleId, roleName, menuIds } = this.roleData;
        const params = { roleName, menuIds: JSON.stringify(menuIds) };
        this.roleData.loading = true;

        if (roleId) {
          params.roleId = roleId;
          editRole(params).then(succ.bind(this, roleId, '保存成功！')).catch(() => this.roleData.loading = false);
        } else {
          addRole(params).then(res => {
            succ.call(this, res.result.roleId, '新建成功！');
          }).catch(() => this.roleData.loading = false);
        }

        function succ(roleId, msg) {
          const pro = [];
          const params = { roleId, wxEnterpriseId: this.wxEnterpriseId };
          this.tabList.forEach(el => {
            if (el.appType == 2 || el.appType == 4) {
              pro.push(new Promise(resolve => {
                saveAppSetting(Object.assign({}, params, { appType: el.appType, json: JSON.stringify(el.appIds) })).finally(resolve);
              }));
            }
          });
          Promise.all(pro).then(() => {
            this.$message.success(msg);
            this.$router.go(-1);
          }).finally(() => this.roleData.loading = false);
        }
      });
    }
  }
};
</script>
<style lang="less" scoped>
.edit-role-body {
  .nav-wrap {
    padding-left: 0;
  }
}
</style>
