<template>
  <el-dialog
    class="select-user-dialog"
    :visible.sync="modalIsShow"
    title="添加用户"
    top="10px"
    width="600px"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    append-to-body
    @opened="visibleChange"
  >
    <el-row type="flex" :gutter="10">
      <el-col :span="12">
        <div class="user-search">
          <el-input
            v-model="filterLabel"
            placeholder="请输入角色名称"
            clearable
            size="mini"
            prefix-icon="el-icon-search"
            @input="labelChange"
          ></el-input>
        </div>
        <div class="user-types">
          <div
            :class="['user-type', { 'is-active': userType === 'org' }]"
            @click="switchUserType('org')"
          >
            组织架构
          </div>
          <div
            :class="['user-type', { 'is-active': userType === 'role' }]"
            @click="switchUserType('role')"
          >
            角色
          </div>
        </div>
        <div class="user-tree">
          <el-tree
            ref="UserTree"
            :data="userTree"
            node-key="id"
            :default-checked-keys="selectedUserIds"
            :props="defaultProps"
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <el-checkbox
                v-if="data.isUser"
                v-model="node.checked"
                @change="checked => userChange(checked, data)"
              >
                {{ node.label }}
              </el-checkbox>
              <span v-else>{{ node.label }}</span>
              <el-checkbox
                v-if="!data.isUser && canSelectAll && data.children.length"
                v-model="data.selected"
                @change="checked => selectNodeAll(checked, data)"
              ></el-checkbox>
            </span>
          </el-tree>
        </div>
      </el-col>
      <el-col :span="12">
        <div class="user-part-title">已选范围</div>
        <div class="user-list">
          <div v-for="user in selectedUsers" :key="user.id" class="user-item">
            <p class="user-cont">
              <span>{{ user.label }}</span>
            </p>
            <el-button
              class="user-delete"
              type="text"
              icon="el-icon-remove"
              @click="toDeleteUser(user)"
            ></el-button>
          </div>
        </div>
      </el-col>
    </el-row>
    <p v-show="!selectValid" class="tips-info tips-error">
      选择用户数不能超过{{ userLimitCount }}
    </p>

    <div slot="footer">
      <el-button type="primary" :disabled="!selectValid" @click="submit"
        >确认</el-button
      >
      <el-button @click="cancel">取消</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { organizationList } from "../api";

export default {
  name: "select-user-dialog",
  props: {
    users: {
      type: Array,
      default() {
        return [];
      }
    },
    userLimitCount: {
      type: Number,
      default: 5
    },
    canSelectAll: {
      type: Boolean,
      default: false
    },
    filterRoles: {
      type: Array,
      default() {
        // id 数组
        return [];
      }
    }
  },
  data() {
    return {
      modalIsShow: false,
      filterLabel: "",
      userType: "org",
      orgData: [],
      orgUsers: [],
      roleUsers: [],
      userTree: [],
      userList: [],
      selectedUsers: [],
      selectedRoleUserIds: [],
      selectedUserIds: [],
      selectValid: true,
      defaultProps: {
        children: "children",
        label: "label"
      }
    };
  },
  methods: {
    async getOrgData() {
      const data = await organizationList();
      this.orgData = data;
    },
    parseUserData(data) {
      let roleUserMap = {};
      const parseUser = list => {
        return list.map(item => {
          // org
          let nitem = {
            id: item.id,
            label: item.name,
            isUser: false,
            selected: false,
            children: []
          };

          if (item["children"] && item["children"].length) {
            nitem.children = [...nitem.children, ...parseUser(item.children)];
          }
          // user
          if (item["sysUserList"] && item["sysUserList"].length) {
            let sysUserList = item.sysUserList;
            // 过滤符合需求角色的用户
            if (this.filterRoles.length) {
              sysUserList = sysUserList.filter(
                user =>
                  user.roleResultList &&
                  user.roleResultList.some(role =>
                    this.filterRoles.includes(role.roleId)
                  )
              );
            }
            const users = sysUserList.map(user => {
              const nuser = {
                id: user.id,
                userId: user.id,
                label: user.realName,
                name: user.realName,
                orgName: item.name,
                selected: false,
                isUser: true
              };
              if (user.roleResultList && user.roleResultList.length) {
                user.roleResultList.forEach(urole => {
                  if (!roleUserMap[urole.roleId]) {
                    roleUserMap[urole.roleId] = {
                      id: urole.roleId,
                      label: urole.roleName,
                      selected: false,
                      isUser: false,
                      children: []
                    };
                  }

                  let ruser = { ...nuser };
                  ruser.id = `${ruser.id}_${this.$randomCode()}`;
                  ruser.label = `${ruser.name}(${ruser.orgName})`;
                  roleUserMap[urole.roleId].children.push(ruser);
                });
              }
              return nuser;
            });
            nitem.children = [...nitem.children, ...users];
          }
          return nitem;
        });
      };
      this.orgUsers = parseUser(data);
      this.roleUsers = Object.values(roleUserMap);
      this.userTree = this.orgUsers;
      this.getUserList();
    },
    getUserList() {
      let userList = [];
      const fetchUser = users => {
        users.forEach(item => {
          if (item["children"] && item["children"].length) {
            fetchUser(item.children);
          } else {
            if (item.isUser) {
              let nitem = { ...item };
              nitem.label = `${nitem.name}(${nitem.orgName})`;
              userList.push(nitem);
            }
          }
        });
      };
      fetchUser(this.orgUsers);

      this.userList = userList;
    },
    labelChange() {
      if (!this.filterLabel) {
        this.switchUserType(this.userType);
      } else {
        const escapeRegexpString = (value = "") =>
          String(value).replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
        const reg = new RegExp(escapeRegexpString(this.filterLabel), "i");

        this.userTree = this.userList.filter(item => reg.test(item.name));
        this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      }
    },
    checkValid() {
      this.selectValid =
        !this.userLimitCount ||
        this.selectedUsers.length <= this.userLimitCount;
    },
    async visibleChange() {
      if (!this.orgUsers.length) await this.getOrgData();
      this.parseUserData(this.orgData);

      this.filterLabel = "";
      this.userType = "org";
      this.userTree = this.orgUsers;
      this.selectedUsers = this.users.map(user => {
        const luser = this.userList.find(item => item.id === user.id);
        return {
          id: user.id,
          name: user.name,
          label: `${user.name}(${luser.orgName})`
        };
      });
      this.selectedUserIds = this.users.map(item => item.id);
      this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      this.checkValid();
    },
    cancel() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
    selectNodeAll(checked, data) {
      let userIds = [];
      const getUserIds = list => {
        list.forEach(item => {
          item.selected = checked;
          if (item.children && item.children.length) {
            getUserIds(item.children);
          } else {
            if (item.isUser) userIds.push(item.userId);
          }
        });
      };
      getUserIds(data.children);

      userIds.forEach(userId => {
        const userPos = this.selectedUserIds.indexOf(userId);
        const includeUser = userPos !== -1;
        if (checked) {
          if (!includeUser) this.selectedUserIds.push(userId);
        } else {
          if (includeUser) {
            this.selectedUserIds.splice(userPos, 1);
          }
        }
      });
      if (this.userType === "role") {
        this.updateSelectRoleUserIds();
      } else {
        this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      }
      this.updateSelectedUsersFromUserIds();
    },
    switchUserType(type) {
      this.userType = type;
      this.userTree = type === "org" ? this.orgUsers : this.roleUsers;

      if (type === "role") {
        this.updateSelectRoleUserIds();
      }
    },
    updateSelectRoleUserIds() {
      let selectedRoleUserIds = [];
      this.roleUsers.forEach(role => {
        role.children.forEach(user => {
          if (this.selectedUserIds.includes(user.userId))
            selectedRoleUserIds.push(user.id);
        });
      });
      this.selectedRoleUserIds = selectedRoleUserIds;
      this.$refs.UserTree.setCheckedKeys(selectedRoleUserIds);
    },
    updateSelectedUsersFromUserIds() {
      this.selectedUsers = this.userList.filter(user =>
        this.selectedUserIds.includes(user.id)
      );
    },
    userChange(checked, curUser) {
      if (this.filterLabel) {
        let prevSelectUserIds = this.selectedUsers.map(item => item.id);
        const prevUserListSelectUserIds = this.userTree
          .filter(user => prevSelectUserIds.includes(user.id))
          .map(user => user.id);
        const selectedUsers = this.$refs.UserTree.getCheckedNodes(true);
        const sIds = selectedUsers.map(user => user.id);
        const prevDeletedUserIds = prevUserListSelectUserIds.filter(
          uid => !sIds.includes(uid)
        );
        this.selectedUsers = this.selectedUsers.filter(
          user => !prevDeletedUserIds.includes(user.id)
        );
        prevSelectUserIds = this.selectedUsers.map(item => item.id);

        selectedUsers.forEach(user => {
          if (prevSelectUserIds.includes(user.id)) return;
          const nuser = {
            id: user.id,
            name: user.name,
            label: `${user.name}(${user.orgName})`
          };
          this.selectedUsers.push(nuser);
        });
        this.selectedUserIds = this.selectedUsers.map(item => item.id);
        this.checkValid();
        return;
      }

      if (this.userType === "org") {
        const selectedUsers = this.$refs.UserTree.getCheckedNodes(true);
        this.selectedUsers = selectedUsers.map(user => {
          const nuser = {
            id: user.id,
            name: user.name,
            label: `${user.name}(${user.orgName})`
          };
          return nuser;
        });
        this.selectedUserIds = this.selectedUsers.map(item => item.id);
        this.checkValid();
        return;
      }

      if (this.userType === "role") {
        if (checked) {
          if (!this.selectedUserIds.includes(curUser.userId))
            this.selectedUserIds.push(curUser.userId);
        } else {
          this.selectedUserIds = this.selectedUserIds.filter(
            userid => userid !== curUser.userId
          );
        }
        this.updateSelectRoleUserIds();
        this.updateSelectedUsersFromUserIds();
        this.checkValid();
      }
    },
    toDeleteUser(user) {
      const pos = this.selectedUsers.findIndex(item => item.id === user.id);
      this.selectedUsers.splice(pos, 1);
      this.selectedUserIds = this.selectedUsers.map(item => item.id);
      if (this.userType === "role") {
        this.updateSelectRoleUserIds();
      } else {
        this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      }
      this.checkValid();
    },
    submit() {
      if (!this.selectValid) return;

      this.$emit(
        "modified",
        this.selectedUsers.map(item => {
          return {
            id: item.id,
            name: item.name
          };
        })
      );
      this.cancel();
    }
  }
};
</script>
