<template>
  <div class="table-box">
    <ProTable ref="proTable" :columns="columns" row-key="roleId" :request-api="listRoleApi">
      <!-- 表格 header 按钮 -->
      <template #tableHeader="scope">
        <el-button type="primary" v-auth="['system:role:add']" :icon="CirclePlus" @click="openDialog(1, '角色信息新增')"> 新增 </el-button>
        <el-button type="primary" v-auth="['system:role:import']" :icon="Upload" plain @click="batchAdd"> 导入 </el-button>
        <el-button type="primary" v-auth="['system:role:export']" :icon="Download" plain @click="downloadFile"> 导出 </el-button>
        <el-button
          type="danger"
          v-auth="['system:user:remove']"
          :icon="Delete"
          plain
          :disabled="!scope.isSelected"
          @click="batchDelete(scope.selectedListIds)"
        >
          批量删除
        </el-button>
      </template>
      <!-- 表格操作 -->
      <template #operation="scope">
        <el-button
          type="primary"
          v-if="scope.row.roleId !== 1"
          link
          :icon="EditPen"
          v-auth="['system:role:edit']"
          @click="openDialog(2, '角色编辑', scope.row)"
        >
          编辑
        </el-button>
        <el-button type="primary" v-if="scope.row.roleId !== 1" link :icon="Delete" v-auth="['system:role:remove']" @click="deleteRole(scope.row)">
          删除
        </el-button>
        <el-button
          type="primary"
          v-if="scope.row.roleId !== 1"
          link
          :icon="CircleCheck"
          v-auth="['system:role:edit']"
          @click="openDataDialog(3, '数据权限', scope.row)"
        >
          数据权限
        </el-button>
        <el-button type="primary" v-if="scope.row.roleId !== 1" link :icon="User" v-auth="['system:role:edit']" @click="handleAuthUser(scope.row)">
          分配用户
        </el-button>
      </template>
    </ProTable>
    <FormDialog ref="formDialogRef">
      <template #default="{ parameter }">
        <ProFrom ref="proFormRef" :items-options="itemsOptions" :disabled="!parameter.isEdit" :form-options="_options" :model="parameter.model">
          <template #menuCheckStrictly="{ formModel }">
            <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
            <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
            <el-checkbox v-model="formModel.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')"> 父子联动 </el-checkbox>
            <el-tree
              class="tree-border"
              :data="menuOptions"
              show-checkbox
              ref="menuRef"
              node-key="id"
              :check-strictly="!formModel.menuCheckStrictly"
              empty-text="加载中，请稍后"
              :props="{ label: 'label', children: 'children' }"
            />
          </template>
        </ProFrom>
      </template>
      <template #footer="{ parameter }">
        <el-button type="primary" :loading="butLoading" @click="handleSubmit(proFormRef, parameter, formDialogRef, '1')">确认</el-button>
        <el-button @click="handleCancel(formDialogRef)">取消</el-button>
      </template>
    </FormDialog>
    <FormDialog ref="formDataRef">
      <template #default="{ parameter }">
        <ProFrom ref="proFormDateRef" :items-options="itemsOptions" :form-options="_options" :model="parameter.model">
          <template #deptCheckStrictly="{ formModel }">
            <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
            <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
            <el-checkbox v-model="formModel.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')"> 父子联动 </el-checkbox>
            <el-tree
              class="tree-border"
              :data="deptOptions"
              show-checkbox
              ref="deptRef"
              default-expand-all
              node-key="id"
              :check-strictly="!formModel.deptCheckStrictly"
              empty-text="加载中，请稍后"
              :props="{ label: 'label', children: 'children' }"
            />
          </template>
        </ProFrom>
      </template>
      <template #footer="{ parameter }">
        <el-button type="primary" :loading="butLoading" @click="handleSubmit(proFormDateRef, parameter, formDataRef)">确认</el-button>
        <el-button @click="handleCancel(formDataRef)">取消</el-button>
      </template>
    </FormDialog>
    <ImportExcel ref="dialogRef" />
  </div>
</template>

<script setup lang="tsx" name="RoleManage">
import { ref, reactive, nextTick } from 'vue'
import { useHandleData } from '@/hooks/useHandleData'
import { useDownload } from '@/hooks/useDownload'
import { ElMessageBox, ElMessage } from 'element-plus'
import ProTable from '@/components/ProTable/index.vue'
import ImportExcel from '@/components/ImportExcel/index.vue'
import FormDialog from '@/components/CustomDialog/index.vue'
import ProFrom from '@/components/ProForm/index.vue'
import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
import { Delete, EditPen, Download, Upload, CircleCheck, User, CirclePlus } from '@element-plus/icons-vue'
import {
  listRoleApi,
  delRoleApi,
  addRoleApi,
  updateRoleApi,
  importTemplateApi,
  importDataApi,
  exportApi,
  changeStatusApi,
  deptTreeSelectApi,
  dataScopeApi,
  roleMenuTreeSelectApi
} from '@/api/modules/system/role'
import { treeSelectApi } from '@/api/modules/system/menu'
import { getDictsApi } from '@/api/modules/system/dictData'
import { useRouter } from 'vue-router'

const router = useRouter()
// 菜单列表
const menuOptions = ref<any>()
const menuExpand = ref(false)
const menuNodeAll = ref(false)
const deptExpand = ref(true)
const deptNodeAll = ref(false)
const menuRef = ref<any>(null)
const proFormRef = ref<any>(null)
const proFormDateRef = ref<any>(null)
const deptOptions = ref<any[]>([])
const deptRef = ref<any>(null)
const butLoading = ref(false)
// 数据范围选项
const dataScopeOptions = ref([
  { value: '1', label: '全部数据权限' },
  { value: '2', label: '自定数据权限' },
  { value: '3', label: '本部门数据权限' },
  { value: '4', label: '本部门及以下数据权限' },
  { value: '5', label: '仅本人数据权限' }
])

// 获取菜单
const getMenuTreeSelect = () => {
  treeSelectApi().then((response: any) => {
    if (response.code === 200) {
      menuOptions.value = response.data
    }
  })
}
getMenuTreeSelect()

// 根据角色ID查询菜单树结构
const getRoleMenuTreeSelect = (roleId: any) => {
  return roleMenuTreeSelectApi(roleId).then((res: any) => {
    menuOptions.value = res.data.menus
    return res
  })
}

// 根据角色ID查询部门树结构
const getDeptTree = (roleId: string) => {
  return deptTreeSelectApi(roleId).then((res: any) => {
    if (res.code === 200) {
      deptOptions.value = res.data.depts
      return res
    }
  })
}

// ProTable 实例
const proTable = ref<ProTableInstance>()

// 删除角色信息信息
const deleteRole = async (params: any) => {
  await useHandleData(delRoleApi, params.roleId, `删除【${params.roleName}】角色信息`)
  proTable.value?.getTableList()
}

// 批量删除角色信息信息
const batchDelete = async (ids: string[]) => {
  await useHandleData(delRoleApi, ids, '删除所选角色信息信息')
  proTable.value?.clearSelection()
  proTable.value?.getTableList()
}

// 导出角色信息列表
const downloadFile = async () => {
  ElMessageBox.confirm('确认导出角色信息数据?', '温馨提示', { type: 'warning' }).then(() =>
    useDownload(exportApi, '角色信息列表', proTable.value?.searchParam)
  )
}

// 批量添加角色信息
const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
const batchAdd = () => {
  const params = {
    title: '角色信息',
    tempApi: importTemplateApi,
    importApi: importDataApi,
    getTableList: proTable.value?.getTableList
  }
  dialogRef.value?.acceptParams(params)
}

const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
// 打开弹框的功能
const openDialog = async (type: number, title: string, row?: any) => {
  reset()
  // 重置表单
  setItemsOptions()
  const params = {
    title,
    width: 720,
    isEdit: true,
    itemsOptions: itemsOptions,
    model: type == 1 ? {} : row,
    api: type == 1 ? addRoleApi : updateRoleApi,
    getTableList: proTable.value?.getTableList
  }
  formDialogRef.value?.openDialog(params)
  if (row?.roleId) {
    getRoleMenuTreeSelect(row?.roleId).then(res => {
      let checkedKeys = res.data.checkedKeys
      checkedKeys.forEach((v: any) => {
        nextTick(() => {
          menuRef.value.setChecked(v, true, false)
        })
      })
    })
  }
}
const formDataRef = ref<InstanceType<typeof FormDialog> | null>(null)
// 打开弹框的功能
const openDataDialog = async (type: number, title: string, row?: any) => {
  reset()
  // 重置表单
  setPerDataItemsOptions()
  const params = {
    title,
    width: 720,
    isEdit: true,
    itemsOptions: itemsOptions,
    model: type == 1 ? {} : row,
    api: dataScopeApi,
    getTableList: proTable.value?.getTableList
  }

  formDataRef.value?.openDialog(params)
  if (row?.roleId) {
    nextTick(() => {
      getDeptTree(row?.roleId).then(res => {
        nextTick(() => {
          if (deptRef.value) {
            deptRef.value.setCheckedKeys(res.data.checkedKeys)
          }
        })
      })
    })
  }
}

// 树权限（展开/折叠
const handleCheckedTreeExpand = (value: any, type: string) => {
  if (type === 'menu') {
    const nodes = menuRef.value.store._getAllNodes()
    nodes.forEach(item => {
      item.expanded = value
    })
  } else if (type === 'dept') {
    const nodes = deptRef.value.store._getAllNodes()
    nodes.forEach(item => {
      item.expanded = value
    })
  }
}

// 树权限（全选/全不选）
const handleCheckedTreeNodeAll = (value: any, type: string) => {
  if (type === 'menu') {
    menuRef.value.setCheckedNodes(value ? menuOptions.value : [])
  } else if (type === 'dept') {
    deptRef.value.setCheckedNodes(value ? deptOptions.value : [])
  }
}

// 树权限（父子联动）
const handleCheckedTreeConnect = (value: any, type: string) => {
  if (type === 'menu') {
    proFormRef.value.formModel.menuCheckStrictly = value ? true : false
  } else if (type === 'dept') {
    proFormDateRef.value.formModel.deptCheckStrictly = value ? true : false
  }
}

// 分配用户
function handleAuthUser(row: any) {
  router.push('/system/role-auth/user/' + row.roleId)
}

// 切换绝俗状态
const changeStatus = async (row: any) => {
  await useHandleData(
    changeStatusApi,
    { roleId: row.roleId, version: row.version, status: row.status == '1' ? 0 : 1 },
    `切换【${row.roleName}】角色状态`
  )
  proTable.value?.getTableList()
}

// 所有部门节点数据
const getDeptAllCheckedKeys = () => {
  // 目前被选中的部门节点
  let checkedKeys = deptRef.value.getCheckedKeys()
  // 半选中的部门节点
  let halfCheckedKeys = deptRef.value.getHalfCheckedKeys()
  checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
  return checkedKeys
}

// 所有菜单节点数据
const getMenuAllCheckedKeys = () => {
  // 目前被选中的菜单节点
  let checkedKeys = menuRef.value.getCheckedKeys()
  // 半选中的菜单节点
  let halfCheckedKeys = menuRef.value.getHalfCheckedKeys()
  checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
  return checkedKeys
}
// 提交
const handleSubmit = (proFormRef: any, parameter: any, closeRefVal: any, type?: string) => {
  const formEl = proFormRef.proFormRef
  butLoading.value = true
  if (!formEl) return
  formEl.validate(valid => {
    if (valid) {
      if (type === '1') {
        parameter.model.menuIds = getMenuAllCheckedKeys()
      } else {
        parameter.model.deptIds = getDeptAllCheckedKeys()
      }
      parameter.api!(parameter.model).then(res => {
        if (res.code == 200) {
          proFormRef?.resetForm(formEl)
          ElMessage.success('操作成功')
          handleCancel(closeRefVal)
          proTable.value?.getTableList()
        } else {
          console.log('message', res.message)
        }
      })
      butLoading.value = false
    }
    butLoading.value = false
  })
}

// 取消按钮，重置表单，关闭弹框
const handleCancel = (closeRefVal: any) => {
  closeRefVal.handleCancel()
}

const reset = () => {
  if (menuRef.value) {
    menuRef.value.setCheckedKeys([])
  }
  menuExpand.value = false
  menuNodeAll.value = false
  deptExpand.value = true
  deptNodeAll.value = false
}

// 表格配置项
const columns = reactive<ColumnProps<any>[]>([
  { type: 'selection', fixed: 'left', width: 70 },
  { prop: 'roleId', label: '角色编号' },
  {
    prop: 'roleName',
    label: '角色名称'
  },
  {
    prop: 'roleKey',
    label: '角色权限字符串'
  },
  {
    prop: 'roleSort',
    label: '显示顺序'
  },
  {
    prop: 'status',
    label: '角色状态',
    enum: () => getDictsApi('sys_normal_disable'),
    search: { el: 'tree-select' },
    fieldNames: { label: 'dictLabel', value: 'dictValue' },
    render: scope => {
      return (
        <el-switch
          model-value={scope.row.status}
          active-text={scope.row.status === '1' ? '禁用' : '启用'}
          active-value={'0'}
          inactive-value={'1'}
          onClick={() => changeStatus(scope.row)}
        />
      )
    }
  },
  {
    prop: 'createTime',
    label: '创建时间',
    search: {
      el: 'date-picker',
      props: { type: 'datetimerange', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
    }
  },
  { prop: 'operation', label: '操作', width: 350, fixed: 'right' }
])
let _options = ref<ProForm.FormOptions>({
  labelWidth: 120,
  hasFooter: false,
  disabled: false
})

// 表单配置项
let itemsOptions: ProForm.ItemsOptions[] = []
const setItemsOptions = () => {
  itemsOptions = [
    {
      label: '角色名称',
      prop: 'roleName',
      rules: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
      compOptions: {
        placeholder: '请输入角色名称'
      }
    },
    {
      label: '角色权限',
      prop: 'roleKey',
      rules: [{ required: true, message: '角色权限字符串不能为空', trigger: 'blur' }],
      tooltip: '@PreAuthorize("@ss.hasPermi(`admin`)")',
      compOptions: {
        placeholder: '请输入角色权限字符串'
      }
    },
    {
      label: '显示顺序',
      prop: 'roleSort',
      span: 12,
      rules: [{ required: true, message: '显示顺序不能为空', trigger: 'blur' }],
      compOptions: {
        elTagName: 'input-number'
      }
    },
    {
      label: '角色状态',
      prop: 'status',
      span: 12,
      rules: [{ required: true, message: '角色状态不能为空', trigger: 'blur' }],
      compOptions: {
        elTagName: 'radio-group',
        enum: () => getDictsApi('sys_normal_disable'),
        labelKey: 'dictLabel',
        valueKey: 'dictValue'
      }
    },
    {
      label: '菜单权限',
      prop: 'menuCheckStrictly',
      hideLabelSuffix: true,
      compOptions: {
        elTagName: 'slot',
        placeholder: '请输入菜单树选择项是否关联显示'
      }
    },
    {
      label: '备注',
      prop: 'remark',
      compOptions: {
        type: 'textarea',
        placeholder: '请输入内容'
      }
    }
  ]
}
const setPerDataItemsOptions = () => {
  itemsOptions = [
    {
      label: '角色名称',
      prop: 'roleName',
      compOptions: {
        disabled: true
      }
    },
    {
      label: '权限字符',
      prop: 'roleKey',
      compOptions: {
        disabled: true
      }
    },
    {
      label: '权限范围',
      prop: 'dataScope',
      compOptions: {
        elTagName: 'select',
        enum: dataScopeOptions.value,
        onChange: (val: string) => {
          if (val !== '2') {
            deptRef.value.setCheckedKeys([])
          }
        }
      }
    },
    {
      label: '数据权限',
      prop: 'deptCheckStrictly',
      hideLabelSuffix: true,
      compOptions: {
        elTagName: 'slot'
      }
    }
  ]
}
</script>
<style scoped lang="scss">
@import './index.scss';
</style>
