<!-- 角色管理 -->
<template>
  <basic-container>
    <el-form>
      <el-row :gutter="20">
        <el-col :span="6">
          <el-form-item label="角色名称">
            <el-input v-model="searchList.roleName" placeholder="请输入角色名称" clearable />
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="角色标识">
            <el-input v-model="searchList.roleCode" placeholder="请输入角色标识" clearable />
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="数据权限">
            <el-select v-model="searchList.dsType" clearable placeholder="请选择数据权限">
              <el-option v-for="item in dataRight" :key="item.value" :label="item.label" :value="item.value" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-button type="primary" :icon="Search" @click="getList">查询</el-button>
          <el-button :icon="Refresh" @click="clearSearch">清空</el-button>
        </el-col>
      </el-row>
    </el-form>
    <div>
      <el-row style="margin-bottom: 10px">
        <el-button type="primary" :icon="Plus" @click="addOrUpdateHandle(0)">新增</el-button>
        <!-- <el-button type="primary" :icon="UploadFilled">导入</el-button>
        <el-button type="primary" :icon="Download">导出</el-button> -->
      </el-row>
      <el-table v-loading="tableLoading" border :data="tableData" row-key="id">
        <el-table-column prop="roleName" label="角色名称" />
        <el-table-column prop="roleCode" label="角色标识" />
        <el-table-column prop="roleDesc" label="角色描述" />
        <el-table-column prop="dsType" label="数据权限">
          <template #default="{ row }">
            {{ dataRight.find((item) => item.value === row.dsType)?.label }}
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" />
        <el-table-column label="操作" width="220" align="center" class-name="small-padding fixed-width">
          <template #default="{ row }">
            <div class="table_btn">
              <el-button size="small" :icon="View" @click="addOrUpdateHandle(1, row)">查看</el-button>
              <el-button size="small" :icon="Edit" @click="addOrUpdateHandle(2, row)">编辑</el-button>
              <el-button size="small" :icon="Delete" @click="handleDelete(row)">删除</el-button>
              <el-button size="small" :icon="Plus" @click="handlePermission(row)">权限</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="tablePage.total > 0"
        v-model:page="tablePage.currentPage"
        v-model:limit="tablePage.pageSize"
        :total="tablePage.total"
        @pagination="getList"
      />

      <el-dialog v-model="roleVisible" :title="title" width="50%" :before-close="roleClose">
        <el-form :model="roleForm" ref="roleRef" :rules="roleRules" label-width="80px" :disabled="roleFormDisabled">
          <el-row>
            <el-col :span="24">
              <el-form-item label="角色名称" prop="roleName">
                <el-input v-model="roleForm.roleName" placeholder="请输入角色名称" clearable />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item label="角色标识" prop="roleCode">
                <el-input
                  v-model="roleForm.roleCode"
                  placeholder="请输入角色标识"
                  clearable
                  :disabled="title !== '添加'"
                />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item label="角色描述">
                <el-input v-model="roleForm.roleDesc" placeholder="请输入角色描述" clearable />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item label="数据权限" prop="dsType">
                <el-select v-model="roleForm.dsType" clearable placeholder="请选择数据权限">
                  <el-option v-for="item in dataRight" :key="item.value" :label="item.label" :value="item.value" />
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row v-if="roleFormDisabled">
            <el-col :span="24">
              <el-form-item label="创建时间">
                <el-input v-model="roleForm.createTime" />
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
        <template v-if="!roleFormDisabled" #footer>
          <el-row class="btn_center">
            <el-button v-if="title === '添加'" type="primary" @click="addRole">添加</el-button>
            <el-button v-if="title === '编辑'" type="primary" @click="saveRole">保存</el-button>
            <el-button @click="roleVisible = false">取消</el-button>
          </el-row>
        </template>
      </el-dialog>

      <el-dialog v-model="rightVisible" title="分配权限" width="50%">
        <el-tree
          ref="rightRef"
          :data="treeData"
          :default-checked-keys="checkedKeys"
          :check-strictly="false"
          :props="{
            label: 'name',
            value: 'id'
          }"
          :filter-node-method="filterNode"
          class="filter-tree"
          node-key="id"
          highlight-current
          show-checkbox
          default-expand-all
        />
        <template #footer>
          <el-row>
            <el-button type="primary" @click="updatePermession">更新</el-button>
            <el-button @click="rightVisible = false">取消</el-button>
          </el-row>
        </template>
      </el-dialog>
    </div>
  </basic-container>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import type { FormInstance, FormRules } from "element-plus";
import { Search, Refresh, EditPen, UploadFilled, Download, View, Plus, Edit, Delete } from "@element-plus/icons-vue";

import { deepClone } from "@/utils/util";
import { validatorKey } from "@/utils/validate";
import { ITablePage, IRoleForm } from "@//const/interface_type";
import {
  getRoleList,
  getObjByCode,
  addRoleObj,
  putRoleObj,
  delRoleObj,
  fetchRoleTree,
  fetchMenuTree,
  updatePermission
} from "@/api/admin";

interface ISearchList {
  roleName: string;
  roleCode: string;
  dsType?: number;
}

const validateRoleCode = (rule: any, value: any, callback: any) => {
  getObjByCode(value).then((response) => {
    const result = response.data;
    if (result && result.length !== 0) {
      callback(new Error("同名角色标识已存在"));
    } else {
      callback();
    }
  });
};

const searchList = ref<ISearchList>({
  roleName: "",
  roleCode: ""
}); // 搜索数据
const dataRight = ref([
  {
    label: "全部",
    value: 0
  },
  {
    label: "自定义",
    value: 1
  },
  {
    label: "本级及子级",
    value: 2
  },
  {
    label: "本级",
    value: 3
  }
]); // 数据权限
const tableData = ref([]); // 表格数据
const tablePage = ref<ITablePage>({
  currentPage: 1,
  pageSize: 10,
  total: 0
});
const tableLoading = ref<boolean>(false); // 表格loading

const roleVisible = ref<boolean>(false); // 新增/修改/查看 弹窗是否展示
const title = ref<string>(""); // 新增/修改/查看 弹窗标题
const roleForm = ref<IRoleForm>({
  roleName: "",
  roleCode: "",
  roleDesc: "",
  dsType: 0,
  createTime: ""
});
const roleRef = ref<FormInstance>();
const roleFormDisabled = ref<boolean>(false);
const roleRules = ref<FormRules>({
  roleName: [
    { required: true, message: "角色名称不能为空", trigger: "blur" },
    { min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" }
  ],
  roleCode: [],
  roleDesc: [{ max: 128, message: "长度在 128 个字符内", trigger: "blur" }],
  dsType: [{ required: true, message: "请选择数据权限类型", trigger: "blur" }]
});

const rightVisible = ref<boolean>(false); // 权限弹窗是否展示
const checkedKeys = ref<string[]>([]); // 存储当前选中角色所拥有的权限信息
const treeData = ref([]); // 存储目录信息
const changeRoleId = ref<string>(""); // 修改权限的角色ID
const rightRef = ref<any>(null);

// 搜索/获取列表
const getList = () => {
  tableLoading.value = true;
  const payload = {
    current: tablePage.value.currentPage,
    size: tablePage.value.pageSize,
    descs: ["create_time"],
    ...searchList.value
  };
  getRoleList(payload).then((res: any) => {
    if (res.code === 0) {
      tableData.value = res.data.records;
      tablePage.value.total = res.data.total;
      tableLoading.value = false;
    }
  });
};

getList();

// 清空搜索条件
const clearSearch = () => {
  searchList.value = {
    roleName: "",
    roleCode: ""
  };
};

// 添加/查看/编辑 列表数据
// isEdit 0: 添加  1 查看  2 编辑
const addOrUpdateHandle = (isEdit: 0 | 1 | 2, row?: IRoleForm) => {
  title.value = isEdit === 0 ? "添加" : isEdit === 1 ? "查看" : "编辑";
  roleVisible.value = true;
  if (isEdit !== 0) {
    roleRules.value.roleCode = [
      { required: true, message: "角色标识不能为空", trigger: "blur" },
      { min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" },
      { validator: validatorKey, trigger: "blur" }
    ];
    if (row) roleForm.value = deepClone(row);
    if (isEdit === 1) {
      roleFormDisabled.value = true;
      roleForm.value.createTime = row?.createTime;
    }
  } else {
    roleRules.value.roleCode = [
      { required: true, message: "角色标识不能为空", trigger: "blur" },
      { min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" },
      { validator: validatorKey, trigger: "blur" },
      { validator: validateRoleCode, trigger: "blur" }
    ];
  }
};

// 保存添加
const addRole = () => {
  roleRef.value?.validate((valid: boolean) => {
    if (valid) {
      addRoleObj(roleForm.value).then((res: any) => {
        if (res.code === 0) {
          ElMessage.success("创建成功");
          clearDialogData();
          roleVisible.value = false;
          getList();
        }
      });
    } else {
      return false;
    }
  });
};

// 保存编辑
const saveRole = () => {
  roleRef.value?.validate((valid: boolean) => {
    if (valid) {
      putRoleObj(roleForm.value).then((res: any) => {
        if (res.code === 0) {
          ElMessage.success("编辑成功");
          clearDialogData();
          roleVisible.value = false;
          getList();
        }
      });
    } else {
      return false;
    }
  });
};
// 删除数据
const handleDelete = (row: any) => {
  ElMessageBox.confirm(`是否确认删除名称为 “${row.roleName}” 的数据项?`, "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning"
  }).then(() => {
    delRoleObj(row.roleId).then(() => {
      ElMessage({
        type: "success",
        message: `删除 “${row.roleName}” 成功`
      });
      getList();
    });
  });
};

// 添加/查看/编辑 弹窗关闭前
const roleClose = (done: () => void) => {
  clearDialogData();
  done();
};

// 清空弹窗数据
const clearDialogData = () => {
  roleForm.value = {
    roleName: "",
    roleCode: "",
    roleDesc: "",
    dsType: 0,
    createTime: ""
  };
  roleFormDisabled.value = false;
  roleRef.value?.clearValidate();
};

// 遍历取出数组ID
const getArrId = (arr: any, checkedArr: string[], result: any[]) => {
  arr.forEach((item: any) => {
    if (item.children?.length > 0) {
      getArrId(item.children, checkedArr, result);
    } else {
      result.push(checkedArr.filter((id) => id === item.id));
    }
  });
  return result;
};

// 添加权限
const handlePermission = (row: any) => {
  fetchRoleTree(row.roleId)
    .then((result: any) => {
      if (result.code === 0) {
        checkedKeys.value = result.data;
        return fetchMenuTree();
      }
    })
    .then((res: any) => {
      if (res.code === 0) {
        treeData.value = res.data;
        checkedKeys.value = getArrId(treeData.value, checkedKeys.value, []);
        rightVisible.value = true;
        changeRoleId.value = row.roleId;
      }
    });
};

//
const filterNode = (value: string, data: any) => {
  if (!value) return true;
  return data.label.indexOf(value) !== -1;
};

const updatePermession = () => {
  const menuIDs = rightRef.value
    ?.getCheckedKeys()
    .join(",")
    .concat(",")
    .concat(rightRef.value?.getHalfCheckedKeys().join(","));
  updatePermission(changeRoleId.value, menuIDs).then((res: any) => {
    if (res.code === 0) {
      ElMessage.success("更新成功");
      rightVisible.value = false;
    }
  });
};

const rightClose = (done: () => void) => {
  done();
};
</script>

<style lang="scss" scoped></style>
