﻿<template>
  <div class="page-shell">
    <section class="page-card table-fill">
      <div class="page-toolbar">
        <n-form inline :show-label="false" class="toolbar-form">
          <n-form-item
            ><n-input v-model:value="query.keyword" placeholder="角色名/编码" clearable
          /></n-form-item>
          <n-form-item
            ><n-select
              v-model:value="query.status"
              :options="statusOptions"
              clearable
              placeholder="状态"
              style="width: 140px"
          /></n-form-item>
          <n-form-item><n-button type="primary" @click="refetch">查询</n-button></n-form-item>
        </n-form>
        <n-button type="primary" @click="openCreate">新增角色</n-button>
      </div>
      <div class="card-body card-body-fill table-fill">
        <n-data-table
          flex-height
          :columns="columns"
          :data="rows"
          :pagination="pagination"
          remote
          @update:page="onPage"
          @update:page-size="onPageSize"
        />
      </div>
    </section>

    <n-modal
      v-model:show="modal.visible"
      preset="card"
      :title="modal.mode === 'create' ? '新增角色' : '编辑角色'"
      class="w-[560px]"
    >
      <n-form ref="formRef" :model="form" :rules="rules" label-width="90">
        <n-form-item label="角色名称" path="name"
          ><n-input v-model:value="form.name"
        /></n-form-item>
        <n-form-item label="角色编码" path="code"
          ><n-input v-model:value="form.code" :disabled="modal.mode === 'edit'"
        /></n-form-item>
        <n-form-item label="状态"
          ><n-radio-group v-model:value="form.status"
            ><n-radio-button value="ENABLED">启用</n-radio-button
            ><n-radio-button value="DISABLED">禁用</n-radio-button></n-radio-group
          ></n-form-item
        >
        <n-form-item label="数据范围"
          ><n-select v-model:value="form.dataScope" :options="dataScopeOptions"
        /></n-form-item>
        <n-form-item label="描述"
          ><n-input v-model:value="form.description" type="textarea"
        /></n-form-item>
      </n-form>
      <template #footer
        ><div class="flex justify-end gap-2">
          <n-button @click="modal.visible = false">取消</n-button
          ><n-button type="primary" @click="save">保存</n-button>
        </div></template
      >
    </n-modal>

    <n-modal v-model:show="menuModal.visible" preset="card" title="分配菜单" class="w-[620px]">
      <n-tree-select
        v-model:value="menuModal.menuIds"
        multiple
        clearable
        :options="menuTree as any"
        key-field="id"
        label-field="title"
        children-field="children"
      />
      <template #footer
        ><div class="flex justify-end gap-2">
          <n-button @click="menuModal.visible = false">取消</n-button
          ><n-button type="primary" @click="saveMenus">保存</n-button>
        </div></template
      >
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { computed, h, reactive, ref } from 'vue'
import {
  NButton,
  NPopconfirm,
  NSpace,
  NTag,
  useMessage,
  type DataTableColumns,
  type FormInst,
  type FormRules
} from 'naive-ui'
import { useMutation, useQuery } from '@tanstack/vue-query'
import {
  createRoleApi,
  deleteRoleApi,
  getRoleDetailApi,
  listRolesApi,
  updateRoleApi,
  updateRoleMenusApi
} from '@/api/system/role'
import { listMenusApi } from '@/api/system/menu'
import type { RoleItem } from '@/types/system/role'
import { dataScopeLabel, statusLabel, statusTagType } from '@/utils/display'
import { renderPagePrefix } from '@/utils/pagination'

const message = useMessage()
const query = reactive({ page: 1, pageSize: 10, keyword: '', status: null as string | null })
const statusOptions = [
  { label: '启用', value: 'ENABLED' },
  { label: '禁用', value: 'DISABLED' }
]
const dataScopeOptions = [
  { label: '全部数据', value: 'ALL' },
  { label: '本企业', value: 'DEPT' },
  { label: '本企业', value: 'DEPT_ONLY' },
  { label: '仅本人', value: 'SELF' }
]
const roleQuery = useQuery({
  queryKey: computed(() => ['roles', { ...query }]),
  queryFn: () =>
    listRolesApi({
      ...query,
      keyword: query.keyword || undefined,
      status: query.status || undefined
    })
})
const rows = computed(() => roleQuery.data.value?.items ?? [])
const pagination = computed(() => ({
  page: query.page,
  pageSize: query.pageSize,
  itemCount: roleQuery.data.value?.total ?? 0,
  showSizePicker: true,
  pageSizes: [10, 20, 50],
  prefix: renderPagePrefix
}))
const menuQuery = useQuery({ queryKey: ['menus-all'], queryFn: listMenusApi })
const menuTree = computed(() => menuQuery.data.value ?? [])

const formRef = ref<FormInst | null>(null)
const modal = reactive({ visible: false, mode: 'create' as 'create' | 'edit', id: '' })
const form = reactive({ name: '', code: '', status: 'ENABLED', dataScope: 'SELF', description: '' })
const rules: FormRules = {
  name: [{ required: true, message: '请输入名称' }],
  code: [{ required: true, message: '请输入编码' }]
}
const menuModal = reactive({ visible: false, id: '', menuIds: [] as string[] })

const saveMutation = useMutation({
  mutationFn: async () => {
    if (modal.mode === 'create') {
      await createRoleApi({
        name: form.name.trim(),
        code: form.code.trim(),
        status: form.status,
        dataScope: form.dataScope.trim() || 'SELF',
        description: form.description.trim() || undefined
      })
      return
    }
    await updateRoleApi(modal.id, {
      name: form.name.trim(),
      status: form.status,
      dataScope: form.dataScope.trim() || 'SELF',
      description: form.description.trim() || undefined
    })
  },
  onSuccess: async () => {
    message.success('保存成功')
    modal.visible = false
    await roleQuery.refetch()
  }
})
const deleteMutation = useMutation({
  mutationFn: deleteRoleApi,
  onSuccess: async () => {
    message.success('删除成功')
    await roleQuery.refetch()
  }
})
const menuMutation = useMutation({
  mutationFn: () => updateRoleMenusApi(menuModal.id, menuModal.menuIds),
  onSuccess: async () => {
    message.success('分配成功')
    menuModal.visible = false
  }
})

function refetch() {
  query.page = 1
  roleQuery.refetch()
}
function onPage(p: number) {
  query.page = p
}
function onPageSize(s: number) {
  query.pageSize = s
  query.page = 1
}
function openCreate() {
  modal.mode = 'create'
  modal.id = ''
  Object.assign(form, { name: '', code: '', status: 'ENABLED', dataScope: 'SELF', description: '' })
  modal.visible = true
}
async function openEdit(row: RoleItem) {
  modal.mode = 'edit'
  modal.id = row.id
  const d = await getRoleDetailApi(row.id)
  Object.assign(form, {
    name: d.name,
    code: d.code,
    status: d.status,
    dataScope: d.dataScope,
    description: d.description ?? ''
  })
  modal.visible = true
}
async function openAssign(row: RoleItem) {
  const d = await getRoleDetailApi(row.id)
  menuModal.id = row.id
  menuModal.menuIds = [...d.menuIds]
  menuModal.visible = true
}
async function save() {
  await formRef.value?.validate()
  await saveMutation.mutateAsync()
}
async function saveMenus() {
  await menuMutation.mutateAsync()
}

const columns = computed<DataTableColumns<RoleItem>>(() => [
  { title: '名称', key: 'name' },
  { title: '编码', key: 'code' },
  {
    title: '状态',
    key: 'status',
    render: (r) =>
      h(
        NTag,
        { size: 'small', type: statusTagType(r.status) },
        { default: () => statusLabel(r.status) }
      )
  },
  { title: '数据范围', key: 'dataScope', render: (r) => dataScopeLabel(r.dataScope) },
  { title: '描述', key: 'description', render: (r) => r.description || '-' },
  {
    title: '操作',
    key: 'actions',
    render: (r) =>
      h(NSpace, { size: 6, align: 'center', class: 'table-action-buttons' }, () => [
        h(
          NButton,
          {
            size: 'small',
            tertiary: true,
            type: 'primary',
            class: 'action-btn',
            onClick: () => openEdit(r)
          },
          { default: () => '编辑' }
        ),
        h(
          NButton,
          {
            size: 'small',
            tertiary: true,
            type: 'info',
            class: 'action-btn',
            onClick: () => openAssign(r)
          },
          { default: () => '分配菜单' }
        ),
        h(
          NPopconfirm,
          { onPositiveClick: () => deleteMutation.mutate(r.id) },
          {
            trigger: () =>
              h(
                NButton,
                { size: 'small', tertiary: true, type: 'error', class: 'action-btn' },
                { default: () => '删除' }
              ),
            default: () => '确认删除？'
          }
        )
      ])
  }
])
</script>
