<template>
	<div class="layout-padding">
		<div class="layout-padding-auto layout-padding-view">
			<el-row shadow="hover" v-show="showSearch" class="ml10">
				<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
					<el-form-item :label="$t('sysrole.roleName')" prop="roleName">
						<el-input :placeholder="$t('sysrole.inputRoleNameTip')" v-model="state.queryForm.roleName" clearable />
					</el-form-item>
					<el-form-item>
						<el-button icon="search" type="primary" @click="getDataList">
							{{ $t('common.queryBtn') }}
						</el-button>
						<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
					</el-form-item>
				</el-form>
			</el-row>
			<el-row>
				<div class="mb8" style="width: 100%">
					<el-button icon="folder-add" type="primary" class="ml10" @click="roleDialogRef.openDialog()" v-auth="'sys_role_add'">
						{{ $t('common.addBtn') }}
					</el-button>
					<el-button plain icon="upload-filled" type="primary" class="ml10" @click="excelUploadRef.show()" v-auth="'sys_user_add'">
						{{ $t('common.importBtn') }}
					</el-button>
					<el-button plain :disabled="multiple" icon="Delete" type="primary" class="ml10" v-auth="'sys_user_del'" @click="handleDelete(selectObjs)">
						{{ $t('common.delBtn') }}
					</el-button>
					<el-button plain :disabled="multiple" type="primary" class="ml10" v-auth="'sys_role_edit'" @click="showBatchGroupDialog = true">
						批量指定分组
					</el-button>
					<el-button plain :disabled="selectObjs.length !== 1" type="primary" class="ml10" v-auth="'sys_role_edit'" @click="openAssignUserDialog">
						批量指定关联用户
					</el-button>
					<right-toolbar
						v-model:showSearch="showSearch"
						:export="'sys_role_export'"
						@exportExcel="exportExcel"
						class="ml10"
						style="float: right; margin-right: 20px"
						@queryTable="getDataList"
					></right-toolbar>
				</div>
			</el-row>
			<el-table
				:data="roleTreeData"
				v-loading="state.loading"
				style="width: 100%"
				row-key="roleId"
				:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
				
				@selection-change="handleSelectionChange"
				border
				:cell-style="tableStyle.cellStyle"
				:header-cell-style="tableStyle.headerCellStyle"
			>
				<el-table-column type="selection" :selectable="handleSelectable" width="50" align="left" />
				<el-table-column type="index" :label="$t('sysrole.index')" width="80">
					<template #default="scope">
						<span v-if="scope.row._isGroup">—</span>
						<span v-else>{{ scope.$index + 1 }}</span>
					</template>
				</el-table-column>
				<el-table-column prop="roleName" :label="$t('sysrole.roleName')" show-overflow-tooltip min-width="140" align="left">
					<template #default="scope">
						<span v-if="scope.row._isGroup" class="role-group-name">{{ scope.row.roleName }}</span>
						<span v-else>{{ scope.row.roleName }}</span>
					</template>
				</el-table-column>
				<el-table-column prop="roleSort" label="排序" width="80" align="center">
					<template #default="scope">{{ scope.row._isGroup ? '—' : (scope.row.roleSort ?? 0) }}</template>
				</el-table-column>
				<el-table-column prop="roleCode" :label="$t('sysrole.roleCode')" show-overflow-tooltip min-width="120">
					<template #default="scope">{{ scope.row._isGroup ? '—' : scope.row.roleCode }}</template>
				</el-table-column>
				<el-table-column prop="roleDesc" :label="$t('sysrole.roleDesc')" show-overflow-tooltip min-width="140">
					<template #default="scope">{{ scope.row._isGroup ? '—' : scope.row.roleDesc }}</template>
				</el-table-column>
				<el-table-column prop="data_authority" :label="$t('sysrole.data_authority')" show-overflow-tooltip width="100">
					<template #default="scope">
						<template v-if="scope.row._isGroup">—</template>
						<dict-tag v-else :options="dictType" :value="scope.row.dsType"></dict-tag>
					</template>
				</el-table-column>
				<el-table-column prop="createTime" :label="$t('sysrole.createTime')" show-overflow-tooltip width="165">
					<template #default="scope">{{ scope.row._isGroup ? '—' : scope.row.createTime }}</template>
				</el-table-column>
				<el-table-column :label="$t('common.action')" width="250" fixed="right">
					<template #default="scope">
						<template v-if="scope.row._isGroup">—</template>
						<template v-else>
							<el-button text type="primary" icon="edit-pen" v-auth="'sys_role_edit'" @click="roleDialogRef.openDialog(scope.row.roleId)">{{
								$t('common.editBtn')
							}}</el-button>
							<el-button text type="primary" icon="turn-off" v-auth="'sys_role_perm'" @click="permessionRef.openDialog(scope.row)">{{
								$t('sysrole.permissionTip')
							}}</el-button>
							<el-button text type="primary" icon="user" v-auth="'sys_role_view'" @click="openRoleUsersDialog(scope.row)">查看关联用户</el-button>
							<el-tooltip :content="$t('sysrole.deleteDisabledTip')" :disabled="scope.row.roleId !== '1'" placement="top">
								<span style="margin-left: 12px">
									<el-button
										text
										type="primary"
										icon="delete"
										:disabled="scope.row.roleId === '1'"
										v-auth="'sys_role_del'"
										@click="handleDelete([scope.row.roleId])"
										>{{ $t('common.delBtn') }}
									</el-button>
								</span>
							</el-tooltip>
						</template>
					</template>
				</el-table-column>
			</el-table>
		</div>

		<!-- 批量指定分组弹窗 -->
		<el-dialog v-model="showBatchGroupDialog" title="批量指定分组" width="400px" @close="batchGroupName = ''">
			<el-form label-width="80px">
				<el-form-item label="分组名称">
					<el-input v-model="batchGroupName" placeholder="输入分组名，留空为未分组" clearable maxlength="50" show-word-limit />
				</el-form-item>
			</el-form>
			<template #footer>
				<el-button @click="showBatchGroupDialog = false">取消</el-button>
				<el-button type="primary" :loading="batchGroupLoading" @click="handleBatchGroup">确定</el-button>
			</template>
		</el-dialog>

		<!-- 批量指定关联用户弹窗 -->
		<el-dialog
			v-model="showAssignUserDialog"
			title="批量指定关联用户"
			width="720px"
			destroy-on-close
			@close="assignUserKeyword = ''; assignUserType = ''; assignUserList = []; assignUserTree = []; assignSelectedIds = []">
			<template v-if="assignCurrentRole">
				<div class="mb12"><el-text type="info">当前角色：{{ assignCurrentRole.roleName }}（{{ assignCurrentRole.roleCode }}）</el-text></div>
				<el-form :inline="true" class="mb12">
					<el-form-item label="用户类型" required>
						<el-radio-group v-model="assignUserType">
							<el-radio label="1">教职工</el-radio>
							<el-radio label="2">学生</el-radio>
							<el-radio label="3">驻校单位</el-radio>
						</el-radio-group>
					</el-form-item>
					<el-form-item label="姓名/工号">
						<el-input v-model="assignUserKeyword" placeholder="姓名或工号检索" clearable style="width: 180px" @keyup.enter="loadAssignUserList" />
					</el-form-item>
					<el-form-item>
						<el-button type="primary" :loading="assignUserLoading" @click="loadAssignUserList">查询</el-button>
					</el-form-item>
				</el-form>
				<div class="assign-user-tip mb8" v-if="!assignUserType">请先选择用户类型后再查询</div>
				<el-table
					v-else
					:data="assignUserTree"
					row-key="id"
					:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
					default-expand-all
					v-loading="assignUserLoading"
					max-height="360"
					border
					@selection-change="handleAssignUserSelectionChange">
					<el-table-column type="selection" width="50" align="left" :selectable="(row: any) => !row._isDept" />
					<el-table-column prop="label" label="部门 / 姓名" min-width="200">
						<template #default="{ row }">
							<span v-if="row._isDept" class="dept-row">{{ row.label }}</span>
							<span v-else>{{ row.realName || row.username || row.label }}</span>
						</template>
					</el-table-column>
					<el-table-column prop="username" label="工号" width="120">
						<template #default="{ row }">{{ row._isDept ? '—' : row.username }}</template>
					</el-table-column>
					<el-table-column prop="deptName" label="部门" width="140">
						<template #default="{ row }">{{ row._isDept ? '—' : (row.deptName || '—') }}</template>
					</el-table-column>
				</el-table>
			</template>
			<template #footer>
				<el-button @click="showAssignUserDialog = false">取消</el-button>
				<el-button type="primary" :loading="assignSubmitLoading" :disabled="assignSelectedIds.length === 0" @click="handleAssignUsersSubmit">确定（已选 {{ assignSelectedIds.length }} 人）</el-button>
			</template>
		</el-dialog>

		<!-- 查看角色关联用户弹窗 -->
		<el-dialog v-model="showRoleUsersDialog" title="关联用户" width="560px" destroy-on-close>
			<template v-if="currentRoleForUsers">
				<div class="mb12"><el-text type="info">角色：{{ currentRoleForUsers.roleName }}（{{ currentRoleForUsers.roleCode }}）</el-text></div>
				<el-table :data="roleUsersList" v-loading="roleUsersLoading" max-height="400" border>
					<el-table-column prop="deptName" label="部门" min-width="140" show-overflow-tooltip />
					<el-table-column prop="realName" label="姓名" width="100" show-overflow-tooltip />
					<el-table-column prop="username" label="工号" width="120" show-overflow-tooltip />
					<el-table-column label="操作" width="80" fixed="right">
						<template #default="{ row }">
							<el-button text type="danger" icon="delete" v-auth="'sys_role_edit'" @click="handleUnassignUser(row)">解除</el-button>
						</template>
					</el-table-column>
				</el-table>
				<div class="mt8" v-if="!roleUsersLoading && roleUsersList.length === 0"><el-text type="info">该角色下暂无关联用户</el-text></div>
			</template>
		</el-dialog>

		<!-- 角色编辑、新增  -->
		<role-dialog ref="roleDialogRef" @refresh="getDataList()" />
		<!-- 导入角色 -->
		<upload-excel
			ref="excelUploadRef"
			:title="$t('sysrole.importRoleTip')"
			url="/admin/role/import"
			temp-url="/admin/sys-file/local/file/role.xlsx"
			@refreshDataList="getDataList"
		/>
		<!-- 授权 -->
		<permession ref="permessionRef" />
	</div>
</template>

<script setup lang="ts" name="systemRole">
import { computed, reactive, ref } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { list, delObj, batchUpdateRoleGroup, assignUsersToRole, getUsersByRoleId, unassignUserFromRole } from '/@/api/admin/role';
import { pageList as userPageList } from '/@/api/admin/user';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';

// 引入组件
const RoleDialog = defineAsyncComponent(() => import('./form.vue'));
const Permession = defineAsyncComponent(() => import('./permession.vue'));
const { t } = useI18n();

// 定义变量内容
const roleDialogRef = ref();
const permessionRef = ref();
const excelUploadRef = ref();
const queryRef = ref();
const showSearch = ref(true);
// 多选rows
const selectObjs = ref([]) as any;
// 是否可以多选
const multiple = ref(true);
// 批量指定分组
const showBatchGroupDialog = ref(false);
const batchGroupName = ref('');
const batchGroupLoading = ref(false);

// 查看角色关联用户
const showRoleUsersDialog = ref(false);
const roleUsersList = ref<any[]>([]);
const roleUsersLoading = ref(false);
const currentRoleForUsers = ref<{ roleName: string; roleCode: string; roleId: string } | null>(null);

// 批量指定关联用户
const showAssignUserDialog = ref(false);
const assignUserType = ref('');
const assignUserKeyword = ref('');
const assignUserList = ref<any[]>([]);
const assignUserLoading = ref(false);
const assignSubmitLoading = ref(false);
const assignSelectedIds = ref<string[]>([]);
const assignCurrentRole = computed(() => {
	const id = selectObjs.value && selectObjs.value[0];
	if (!id) return null;
	return (state.dataList || []).find((r: any) => r.roleId === id) || null;
});
/** 按部门分组的用户树（用于表格树形展示） */
const assignUserTree = computed(() => {
	const list = assignUserList.value || [];
	const map = new Map<string, any[]>();
	list.forEach((u: any) => {
		const deptKey = u.deptName && String(u.deptName).trim() ? u.deptName : '未分配部门';
		if (!map.has(deptKey)) map.set(deptKey, []);
		map.get(deptKey)!.push({ ...u, id: u.userId, _isDept: false });
	});
	const result: any[] = [];
	map.forEach((users, deptName) => {
		result.push({
			id: `dept_${deptName}`,
			label: deptName,
			_isDept: true,
			children: users,
		});
	});
	result.sort((a, b) => a.label.localeCompare(b.label));
	return result;
});

// 列表不分页，显示全部数据
const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: {
		roleName: '',
	},
	isPage: false,
	pageList: async (params: any) => {
		const res = await list(params);
		let data = res?.data || [];
		if (Array.isArray(data) && params?.roleName) {
			const kw = String(params.roleName).trim().toLowerCase();
			if (kw) {
				data = data.filter(
					(r: any) =>
						(r.roleName && r.roleName.toLowerCase().includes(kw)) ||
						(r.roleCode && r.roleCode.toLowerCase().includes(kw))
				);
			}
		}
		return { data };
	},
	descs: ['create_time'],
});

/** 按分组构建树形数据：分组为父节点，角色为子节点 */
const roleTreeData = computed(() => {
	const list = state.dataList || [];
	const groupMap = new Map<string, any[]>();
	list.forEach((row: any) => {
		const groupName = row.roleGroup && String(row.roleGroup).trim() ? String(row.roleGroup).trim() : '未分组';
		if (!groupMap.has(groupName)) groupMap.set(groupName, []);
		groupMap.get(groupName)!.push(row);
	});
	const result: any[] = [];
	groupMap.forEach((roles, groupName) => {
		result.push({
			roleId: `group_${groupName}`,
			roleName: groupName,
			_isGroup: true,
			children: roles,
		});
	});
	// 未分组放最后，其余按分组名排序
	result.sort((a, b) => {
		if (a.roleName === '未分组') return 1;
		if (b.roleName === '未分组') return -1;
		return a.roleName.localeCompare(b.roleName);
	});
	return result;
});

const dictType = ref([
	{
		label: '全部',
		value: '0',
	},
	{
		label: '自定义',
		value: '1',
	},
	{
		label: '本级及子级',
		value: '2',
	},
	{
		label: '本级',
		value: '3',
	},
  {
    label: '本人',
    value: '4',
  },
]);

//  table hook（无分页，不暴露 currentChangeHandle/sizeChangeHandle）
const { getDataList, downBlobFile, tableStyle } = useTable(state);

// 清空搜索条件
const resetQuery = () => {
	queryRef.value.resetFields();
	getDataList();
};

// 导出excel
const exportExcel = () => {
	downBlobFile('/admin/role/export',Object.assign(state.queryForm,{ids:selectObjs}), 'role.xlsx');
};

// 是否可以多选（分组行不可选，管理员角色不可选）
const handleSelectable = (row: any) => {
	return !row._isGroup && row.roleId !== '1';
};

// 多选事件（仅角色行可选，排除分组行）
const handleSelectionChange = (objs: { roleId: string }[]) => {
	selectObjs.value = objs.map(({ roleId }) => roleId).filter((id: string) => !String(id).startsWith('group_'));
	multiple.value = !selectObjs.value.length;
};

// 删除操作
const handleDelete = async (ids: string[]) => {
	try {
		await useMessageBox().confirm(t('common.delConfirmText'));
	} catch {
		return;
	}

	try {
		await delObj(ids);
		getDataList();
		useMessage().success(t('common.delSuccessText'));
	} catch (err: any) {
		useMessage().error(err.msg);
	}
};

async function loadRoleUsersList() {
	const role = currentRoleForUsers.value;
	if (!role) return;
	roleUsersLoading.value = true;
	try {
		const res = await getUsersByRoleId(role.roleId);
		const data = res?.data;
		roleUsersList.value = Array.isArray(data) ? data : [];
	} catch {
		roleUsersList.value = [];
	} finally {
		roleUsersLoading.value = false;
	}
}

async function openRoleUsersDialog(row: any) {
	currentRoleForUsers.value = { roleName: row.roleName, roleCode: row.roleCode, roleId: row.roleId };
	showRoleUsersDialog.value = true;
	roleUsersList.value = [];
	await loadRoleUsersList();
}

async function handleUnassignUser(row: any) {
	const roleId = currentRoleForUsers.value?.roleId;
	const userId = row.userId;
	if (!roleId || !userId) return;
	try {
		await useMessageBox().confirm(`确定解除「${row.realName || row.username}」与该角色的关联？`);
	} catch {
		return;
	}
	try {
		await unassignUserFromRole(roleId, userId);
		useMessage().success('已解除关联');
		await loadRoleUsersList();
	} catch (err: any) {
		useMessage().error(err?.msg || '操作失败');
	}
}

function openAssignUserDialog() {
	if (selectObjs.value.length !== 1) return;
	showAssignUserDialog.value = true;
	assignUserType.value = '';
	assignUserKeyword.value = '';
	assignUserList.value = [];
	assignSelectedIds.value = [];
}

async function loadAssignUserList() {
	if (!assignUserType.value) return;
	assignUserLoading.value = true;
	try {
		const res = await userPageList({
			current: 1,
			size: 2000,
			userType: assignUserType.value,
			realName: assignUserKeyword.value ? assignUserKeyword.value.trim() : undefined,
		});
		const records = res?.data?.records ?? res?.records ?? (Array.isArray(res?.data) ? res.data : []);
		assignUserList.value = Array.isArray(records) ? records : [];
	} catch (e) {
		assignUserList.value = [];
	} finally {
		assignUserLoading.value = false;
	}
}

function handleAssignUserSelectionChange(rows: any[]) {
	assignSelectedIds.value = (rows || [])
		.filter((r: any) => !r._isDept && r.userId)
		.map((r: any) => r.userId);
}

async function handleAssignUsersSubmit() {
	const roleId = assignCurrentRole.value?.roleId;
	if (!roleId || !assignSelectedIds.value.length) {
		useMessage().warning('请选择要关联的用户');
		return;
	}
	assignSubmitLoading.value = true;
	try {
		await assignUsersToRole(roleId, assignSelectedIds.value);
		useMessage().success('已关联 ' + assignSelectedIds.value.length + ' 名用户');
		showAssignUserDialog.value = false;
	} catch (err: any) {
		useMessage().error(err?.msg || '操作失败');
	} finally {
		assignSubmitLoading.value = false;
	}
}

// 批量指定分组
const handleBatchGroup = async () => {
	const ids = selectObjs.value || [];
	if (!ids.length) {
		useMessage().warning('请先勾选要设置分组的角色');
		return;
	}
	batchGroupLoading.value = true;
	try {
		await batchUpdateRoleGroup(ids, batchGroupName.value || '');
		useMessage().success('分组已更新');
		showBatchGroupDialog.value = false;
		batchGroupName.value = '';
		getDataList();
	} catch (err: any) {
		useMessage().error(err?.msg || '操作失败');
	} finally {
		batchGroupLoading.value = false;
	}
};
</script>

<style scoped lang="scss">
.role-group-name {
	font-weight: 600;
	color: var(--el-text-color-primary);
}
.mb12 { margin-bottom: 12px; }
.mb8 { margin-bottom: 8px; }
.mt8 { margin-top: 8px; }
.assign-user-tip { color: var(--el-text-color-secondary); font-size: 13px; }
.dept-row { font-weight: 600; color: var(--el-text-color-primary); }
</style>
