fix:评论组件调试 权限模块前端页面开发
This commit is contained in:
@@ -34,3 +34,8 @@ export const addReplyComment = (data: addCommentProps) => {
|
|||||||
export const deleteComment = (id: string) => {
|
export const deleteComment = (id: string) => {
|
||||||
return request.delete(`/communicate/v1/comment/del/${id}`);
|
return request.delete(`/communicate/v1/comment/del/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据员工关键字查询员工信息
|
||||||
|
export const getEmployeeByKeyword = (params: Record<string, any>) => {
|
||||||
|
return request.get(`/auth/v1/employee`,params);
|
||||||
|
}
|
||||||
64
src/api/stage/permission/index.ts
Normal file
64
src/api/stage/permission/index.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import request from '@/request';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 查询角色列表
|
||||||
|
export const getRoleList = (params: any) => {
|
||||||
|
return request.get('/auth/v1/backend/role', params);
|
||||||
|
}
|
||||||
|
// 获取角色详情
|
||||||
|
export const getRoleDetail = (id: string) => {
|
||||||
|
return request.get(`/auth/v1/backend/role/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新角色
|
||||||
|
export const updateRole = (data: any) => {
|
||||||
|
return request.put('/auth/v1/backend/role', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增角色
|
||||||
|
export const addRole = (data: any) => {
|
||||||
|
return request.post('/auth/v1/backend/role', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除角色
|
||||||
|
export const deleteRole = (id: string) => {
|
||||||
|
return request.delete(`/auth/v1/backend/role/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除用户角色
|
||||||
|
export const deleteUserRole = (userId:string,roleId: string) => {
|
||||||
|
return request.delete(`/auth/v1/backend/role/user/${userId}/role/${roleId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加用户角色
|
||||||
|
export const addUserRole = (userId:string,roleId: string) => {
|
||||||
|
return request.post(`/auth/v1/backend/role/user/${userId}/role/${roleId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 启用角色
|
||||||
|
export const enableRole = (id: string) => {
|
||||||
|
return request.put(`/auth/v1/backend/role/enable/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用角色
|
||||||
|
export const disableRole = (id: string) => {
|
||||||
|
return request.put(`/auth/v1/backend/role/disable/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**------------------------角色权限相关---------------------------**/
|
||||||
|
|
||||||
|
// 保存角色权限
|
||||||
|
export const saveRolePermission = (data: any) => {
|
||||||
|
return request.post(`/auth/v1/backend/role/permission/save`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询角色权限
|
||||||
|
export const getRolePermission = (roleId: string) => {
|
||||||
|
return request.get(`/auth/v1/backend/role/${roleId}/permission`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取角色成员列表
|
||||||
|
export const getRoleMemberList = (roleId: string) => {
|
||||||
|
return request.get(`/auth/v1/backend/role/${roleId}/members`);
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
header-row-class-name="header-row-name"
|
header-row-class-name="header-row-name"
|
||||||
:height="tableHeight"
|
:height="tableHeight"
|
||||||
>
|
>
|
||||||
<template v-for="(col, index) in columns" :key="col.prop">
|
<template v-for="(col, index) in columns" :key="index">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="!col.slot && col.prop !== 'actions'"
|
v-if="!col.slot && col.prop !== 'actions'"
|
||||||
v-bind="col"
|
v-bind="col"
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
v-bind="getButtonProps(btn)"
|
v-bind="getButtonProps(btn)"
|
||||||
|
:disabled="getButtonDisabled(btn, scope.row)"
|
||||||
@click="handleButtonClick(btn, scope.row)"
|
@click="handleButtonClick(btn, scope.row)"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
@@ -58,15 +59,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 如果按钮超过maxButtons,显示下拉菜单 -->
|
<!-- 如果按钮超过maxButtons,显示下拉菜单 (如果是移入移除展示按钮 不建议开启下拉菜单)-->
|
||||||
<el-dropdown
|
<el-dropdown
|
||||||
v-if="
|
v-if="showDropdown && col.actions.length > (col.maxButtons || MAX_BUTTON_LENGTH) && hasDropdownPermission(col.actions.slice(col.maxButtons || MAX_BUTTON_LENGTH))"
|
||||||
col.actions.length >
|
|
||||||
(col.maxButtons || MAX_BUTTON_LENGTH) &&
|
|
||||||
hasDropdownPermission(
|
|
||||||
col.actions.slice(col.maxButtons || MAX_BUTTON_LENGTH)
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="dropdown-menu-table"
|
class="dropdown-menu-table"
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
>
|
>
|
||||||
@@ -87,6 +82,7 @@
|
|||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
<el-button
|
<el-button
|
||||||
v-bind="getButtonProps(btn)"
|
v-bind="getButtonProps(btn)"
|
||||||
|
:disabled="getButtonDisabled(btn, scope.row)"
|
||||||
@click="handleButtonClick(btn, scope.row)"
|
@click="handleButtonClick(btn, scope.row)"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
@@ -145,8 +141,15 @@ const props = defineProps({
|
|||||||
immediate: { type: Boolean, default: true },
|
immediate: { type: Boolean, default: true },
|
||||||
// 是否在激活时刷新数据
|
// 是否在激活时刷新数据
|
||||||
refreshOnActivated: { type: Boolean, default: true },
|
refreshOnActivated: { type: Boolean, default: true },
|
||||||
|
// 是否展示下拉菜单 (如果按钮是鼠标移入移出 不建议开启下拉菜单 会导致弹层的问题)
|
||||||
|
showDropdown: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DEFAULT_PAGINATION = {
|
||||||
|
layout: "prev, pager, next",
|
||||||
|
background: false,
|
||||||
|
}
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
"current-change",
|
"current-change",
|
||||||
"size-change",
|
"size-change",
|
||||||
@@ -217,11 +220,12 @@ const params = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 请求方法
|
// 请求方法
|
||||||
const refresh = async () => {
|
const refresh = async (isReset:boolean=false) => {
|
||||||
if (!props.requestApi) return;
|
if (!props.requestApi) return;
|
||||||
innerLoading.value = true;
|
innerLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await props.requestApi(params.value);
|
const requestParams = isReset ? {...params.value,pageNo:1} : params.value;
|
||||||
|
const res = await props.requestApi(requestParams);
|
||||||
emit("update:data", res?.records || []);
|
emit("update:data", res?.records || []);
|
||||||
emit("update:total", res?.total || 0);
|
emit("update:total", res?.total || 0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -242,6 +246,14 @@ const handleSizeChange = (val) => {
|
|||||||
if (props.requestApi) refresh();
|
if (props.requestApi) refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 按钮支持 disabledFn函数
|
||||||
|
const getButtonDisabled = (button, row) => {
|
||||||
|
if (button.disabledFn && typeof button.disabledFn === 'function') {
|
||||||
|
return button.disabledFn(row);
|
||||||
|
}
|
||||||
|
return button.disabled || false;
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await updateContainerHeight();
|
await updateContainerHeight();
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
@@ -267,14 +279,23 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 暴露 refresh 方法给外部使用
|
// 暴露 refresh 方法给外部使用
|
||||||
defineExpose({ refresh });
|
defineExpose({ refresh,reset:()=>refresh(true) });
|
||||||
|
|
||||||
// 分页配置
|
// 分页配置
|
||||||
const paginationConfig = computed(() => ({
|
const paginationConfig = computed(() =>{
|
||||||
layout: "prev, pager, next",
|
if (typeof props.pagination === 'boolean') {
|
||||||
background: false,
|
return DEFAULT_PAGINATION;
|
||||||
...props.pagination,
|
}
|
||||||
}));
|
|
||||||
|
if (typeof props.pagination === 'object' && props.pagination !== null) {
|
||||||
|
return {
|
||||||
|
...DEFAULT_PAGINATION,
|
||||||
|
...props.pagination
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_PAGINATION;
|
||||||
|
});
|
||||||
|
|
||||||
// action按钮组的数据
|
// action按钮组的数据
|
||||||
const handleButtonClick = (button, row) => {
|
const handleButtonClick = (button, row) => {
|
||||||
@@ -292,6 +313,9 @@ const shouldHideButton = (button, row) => {
|
|||||||
const getVisibleButtonCount = (col) => {
|
const getVisibleButtonCount = (col) => {
|
||||||
const { actions, maxButtons } = col;
|
const { actions, maxButtons } = col;
|
||||||
const totalButtons = maxButtons || MAX_BUTTON_LENGTH;
|
const totalButtons = maxButtons || MAX_BUTTON_LENGTH;
|
||||||
|
if(!props.showDropdown){
|
||||||
|
return actions.length;
|
||||||
|
}
|
||||||
return totalButtons === actions.length ? totalButtons : Math.min(totalButtons, actions.length)-1;
|
return totalButtons === actions.length ? totalButtons : Math.min(totalButtons, actions.length)-1;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,7 +325,7 @@ const hasDropdownPermission = (dropdownActions) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
const getButtonProps = (button) => {
|
const getButtonProps = (button) => {
|
||||||
const { label, onClick, show, permission, ...buttonProps } = button;
|
const { label, onClick, show, permission,disabledFn, ...buttonProps } = button;
|
||||||
return buttonProps;
|
return buttonProps;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -348,7 +372,7 @@ const getButtonProps = (button) => {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: opacity 0.25s ease-in, transform 0.25s ease-in;
|
transition: opacity 0.25s ease-in, transform 0.25s ease-in;
|
||||||
}
|
}
|
||||||
:deep(.el-table__row:hover) .action-group {
|
:deep(.el-table__row:hover) .action-group,:deep(.row-dropdown-active) .action-group{
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
|||||||
37
src/dict/PermissionManage.ts
Normal file
37
src/dict/PermissionManage.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 后台 - 权限管理模块-权限内容信息
|
||||||
|
|
||||||
|
|
||||||
|
// 权限状态映射
|
||||||
|
const roleDict = {
|
||||||
|
1: '启用',
|
||||||
|
0: '禁用'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限状态颜色
|
||||||
|
const roleDictColor = {
|
||||||
|
1:'#66E5BE',
|
||||||
|
0:'#90A1B9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建角色类型字典
|
||||||
|
const roleTypeOptions = [
|
||||||
|
{ label: '实例角色', value: 'INSTANCE' },
|
||||||
|
{ label: '默认角色', value: 'DEFAULT' },
|
||||||
|
{ label: '系统角色', value: 'SYSTEM' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 设置权限转换为目标格式
|
||||||
|
const statusOptions = Object.keys(roleDict).map((key) => {
|
||||||
|
return {
|
||||||
|
label: roleDict[key],
|
||||||
|
value: Number(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
roleDict,
|
||||||
|
roleDictColor,
|
||||||
|
statusOptions,
|
||||||
|
roleTypeOptions
|
||||||
|
}
|
||||||
@@ -1,5 +1,14 @@
|
|||||||
import DictManage from './dictManage';
|
const modules = import.meta.glob('./*.{vue,ts,js}', { eager: true });
|
||||||
|
const components: Record<string, any> = {};
|
||||||
const Dict = { DictManage }
|
Object.entries(modules).forEach(([path, module]: [string, any]) => {
|
||||||
export { DictManage }
|
// 过滤掉 index 文件本身
|
||||||
export default Dict;
|
if (path.includes('index')) return;
|
||||||
|
const name = path.replace(/^\.\/(.*)\.\w+$/, '$1');
|
||||||
|
components[name] = module.default || module;
|
||||||
|
});
|
||||||
|
// 2. 统一导出
|
||||||
|
export const {
|
||||||
|
DictManage,
|
||||||
|
PermissionManage
|
||||||
|
} = components;
|
||||||
|
export default components;
|
||||||
@@ -231,6 +231,7 @@ $color-white: #fff;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.observer-anchor{
|
.observer-anchor{
|
||||||
|
height: 60px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #808080;
|
color: #808080;
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ import {
|
|||||||
getComment,
|
getComment,
|
||||||
addReplyComment,
|
addReplyComment,
|
||||||
deleteComment,
|
deleteComment,
|
||||||
|
getEmployeeByKeyword
|
||||||
} from "@/api/modules/Comment";
|
} from "@/api/modules/Comment";
|
||||||
const { formatTime } = useRelativeTime();
|
const { formatTime } = useRelativeTime();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -275,7 +276,7 @@ const { t } = useI18n();
|
|||||||
// 当前用户信息
|
// 当前用户信息
|
||||||
const currentUser = computed(() => {
|
const currentUser = computed(() => {
|
||||||
return {
|
return {
|
||||||
name: userStore.userInfo.username,
|
name: userStore.userInfo.nickname,
|
||||||
avatar: userStore.userInfo.avatar,
|
avatar: userStore.userInfo.avatar,
|
||||||
id: 1,
|
id: 1,
|
||||||
};
|
};
|
||||||
@@ -299,6 +300,8 @@ const {
|
|||||||
|
|
||||||
// 评论业务逻辑
|
// 评论业务逻辑
|
||||||
const activeReply = reactive({
|
const activeReply = reactive({
|
||||||
|
id:"",
|
||||||
|
rootId:"",
|
||||||
replyUserId: "",
|
replyUserId: "",
|
||||||
parentId: null,
|
parentId: null,
|
||||||
targetName: "",
|
targetName: "",
|
||||||
@@ -312,23 +315,61 @@ const commentData = ref([]);
|
|||||||
// 滚动加载
|
// 滚动加载
|
||||||
const infinityLoading = ref(false);
|
const infinityLoading = ref(false);
|
||||||
const loadMoreAnchor = ref(null);
|
const loadMoreAnchor = ref(null);
|
||||||
|
const isProcessing = ref(false);
|
||||||
const noMore = ref(false);
|
const noMore = ref(false);
|
||||||
// FIXME:请求用户列表的接口函数
|
// 请求用户列表的接口函数
|
||||||
const handleFetchSearch = async (keyword, signal) => {
|
const handleFetchSearch = async (keyword, signal) => {
|
||||||
console.log("获取参数信息", keyword, signal);
|
const selectedIds = new Set();
|
||||||
|
selectedUsersCache.forEach(userList => {
|
||||||
|
userList.forEach(u => selectedIds.add(u.id));
|
||||||
|
});
|
||||||
|
// FIXME:模拟接口返回的数据人员信息
|
||||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||||
return [
|
const allEmployees = [
|
||||||
{ id: 1, name: "李星倩" },
|
{
|
||||||
{ id: 2, name: "冯娜" },
|
id:1,
|
||||||
{ id: 4, name: "张三1" },
|
name:"张三",
|
||||||
{ id: 5, name: "张三2" },
|
},
|
||||||
{ id: 6, name: "张三3" },
|
{
|
||||||
{ id: 7, name: "张三4" },
|
id:2,
|
||||||
{ id: 8, name: "张三5" },
|
name:"李四",
|
||||||
{ id: 9, name: "张三6" },
|
},
|
||||||
{ id: 10, name: "张三7" },
|
{
|
||||||
{ id: 11, name: "张三8" },
|
id:3,
|
||||||
];
|
name:"王五",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:4,
|
||||||
|
name:"赵六",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:5,
|
||||||
|
name:"冯七 ",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
return allEmployees.filter(user => {
|
||||||
|
const isMatch = user.name.toLowerCase().includes(keyword.toLowerCase());
|
||||||
|
const notSelected = !selectedIds.has(user.id);
|
||||||
|
return isMatch && notSelected;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 正式请求
|
||||||
|
const queryParams = {
|
||||||
|
keyword,
|
||||||
|
kind:0,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const allEmployees = await getEmployeeByKeyword(queryParams);
|
||||||
|
return allEmployees.filter(user => {
|
||||||
|
const isMatch = user.name.toLowerCase().includes(keyword.toLowerCase());
|
||||||
|
const notSelected = !selectedIds.has(user.id);
|
||||||
|
return isMatch && notSelected;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log('fetch user error:',error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取当前的的评论信息
|
// 获取当前的的评论信息
|
||||||
@@ -373,7 +414,7 @@ const onUserSelect = (user: any) => {
|
|||||||
// 回复
|
// 回复
|
||||||
const openReply = (target, group) => {
|
const openReply = (target, group) => {
|
||||||
// 1. 设置回复的目标关系
|
// 1. 设置回复的目标关系
|
||||||
activeReply.groupId = target.rootId; // 根评论ID
|
activeReply.rootId = target.rootId; // 根评论ID
|
||||||
activeReply.replyUserId = target.employee.userId; //回复-人的id
|
activeReply.replyUserId = target.employee.userId; //回复-人的id
|
||||||
activeReply.parentId = target.parentId; // 直接父级ID
|
activeReply.parentId = target.parentId; // 直接父级ID
|
||||||
activeReply.targetName = target.employee.username; //回复人员的username
|
activeReply.targetName = target.employee.username; //回复人员的username
|
||||||
@@ -393,7 +434,6 @@ const deleteReply = async (target, group) => {
|
|||||||
try {
|
try {
|
||||||
// 删除成功
|
// 删除成功
|
||||||
await deleteComment(target.id);
|
await deleteComment(target.id);
|
||||||
ElMessage.success("删除成功");
|
|
||||||
const index = group.children.findIndex((item) => item.id === target.id);
|
const index = group.children.findIndex((item) => item.id === target.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
group.children.splice(index, 1);
|
group.children.splice(index, 1);
|
||||||
@@ -414,12 +454,11 @@ const deleteReply = async (target, group) => {
|
|||||||
const deleteMainComment = async (target) => {
|
const deleteMainComment = async (target) => {
|
||||||
try {
|
try {
|
||||||
await deleteComment(target.id);
|
await deleteComment(target.id);
|
||||||
ElMessage.success("删除成功");
|
|
||||||
// 前端动态操作
|
// 前端动态操作
|
||||||
const index = commentData.value.findIndex((item) => item.id === target.id);
|
const index = commentData.value.findIndex((item) => item.id === target.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
commentData.value.splice(index, 1);
|
commentData.value.splice(index, 1);
|
||||||
if (activeReply.groupId === target.id) {
|
if (activeReply.rootId === target.id) {
|
||||||
cancelReply();
|
cancelReply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,11 +472,14 @@ const onSelectEmoji = (emoji) => {
|
|||||||
mainInput.value += emoji;
|
mainInput.value += emoji;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 清除回复信息的操作
|
// 清除回复信息的人员数据
|
||||||
const resetReplyStatus = () => {
|
const resetReplyStatus = () => {
|
||||||
activeReply.parentId = null;
|
activeReply.parentId = null;
|
||||||
activeReply.targetName = "";
|
activeReply.targetName = "";
|
||||||
activeReply.groupId = null;
|
activeReply.rootId = "";
|
||||||
|
activeReply.replyUserId = "";
|
||||||
|
activeReply.id = "";
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 取消评论
|
// 取消评论
|
||||||
@@ -451,7 +493,8 @@ const cancelReply = () => {
|
|||||||
*/
|
*/
|
||||||
const handleSendComment = async () => {
|
const handleSendComment = async () => {
|
||||||
let rawText = mainInput.value;
|
let rawText = mainInput.value;
|
||||||
if (!rawText.trim()) return ElMessage.warning("内容不能为空");
|
if (!rawText.trim() || isProcessing.value) return;
|
||||||
|
isProcessing.value = true;
|
||||||
|
|
||||||
let finalReplyId = null;
|
let finalReplyId = null;
|
||||||
const expectedPrefix = `@${activeReply.targetName} `;
|
const expectedPrefix = `@${activeReply.targetName} `;
|
||||||
@@ -484,7 +527,7 @@ const handleSendComment = async () => {
|
|||||||
`匹配到用户: ${currentUser?.name}, ID: ${currentUser?.id}, 位置: ${match.index}`
|
`匹配到用户: ${currentUser?.name}, ID: ${currentUser?.id}, 位置: ${match.index}`
|
||||||
);
|
);
|
||||||
mentionList.push({
|
mentionList.push({
|
||||||
id: currentUser.id,
|
userId: currentUser.id,
|
||||||
name: currentUser.name,
|
name: currentUser.name,
|
||||||
start: match.index,
|
start: match.index,
|
||||||
end: match.index + match[0].length,
|
end: match.index + match[0].length,
|
||||||
@@ -495,12 +538,12 @@ const handleSendComment = async () => {
|
|||||||
// 组装接口请求的参数
|
// 组装接口请求的参数
|
||||||
const params = {
|
const params = {
|
||||||
content: rawText,
|
content: rawText,
|
||||||
mentions: Object.keys(mentionList).length ? mentionList : null,
|
mentions: mentionList.length ? mentionList : null,
|
||||||
...props.queryParams,
|
...props.queryParams,
|
||||||
};
|
};
|
||||||
// 回复数据复制
|
// 回复数据复制
|
||||||
if(type === "reply"){
|
if(type === "reply"){
|
||||||
params.rootId = activeReply.groupId ? activeReply.groupId : activeReply.id;
|
params.rootId = activeReply.rootId ? activeReply.rootId : activeReply.id;
|
||||||
params.parentId = activeReply.parentId;
|
params.parentId = activeReply.parentId;
|
||||||
params.replyUserId = activeReply.replyUserId;
|
params.replyUserId = activeReply.replyUserId;
|
||||||
}
|
}
|
||||||
@@ -513,7 +556,7 @@ const handleSendComment = async () => {
|
|||||||
// 清空输入框
|
// 清空输入框
|
||||||
cancelReply();
|
cancelReply();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
ElMessage.success(type === "reply" ? "回复成功" : "评论成功");
|
// ElMessage.success(type === "reply" ? "回复成功" : "评论成功"); //屏蔽当前的提示
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
console.log("error", error);
|
||||||
}
|
}
|
||||||
@@ -532,9 +575,9 @@ const updateUIAfterSend = (type, params, response) => {
|
|||||||
userId: activeReply.replyUserId,
|
userId: activeReply.replyUserId,
|
||||||
username: activeReply.targetName,
|
username: activeReply.targetName,
|
||||||
},
|
},
|
||||||
rootId: params.groupId,
|
rootId: params.rootId,
|
||||||
content: params.content,
|
content: params.content,
|
||||||
mentions: params.mentionList,
|
mentions: params.mentions,
|
||||||
createTime: new Date().valueOf(),
|
createTime: new Date().valueOf(),
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
@@ -544,33 +587,47 @@ const updateUIAfterSend = (type, params, response) => {
|
|||||||
commentData.value.unshift(newComment);
|
commentData.value.unshift(newComment);
|
||||||
} else {
|
} else {
|
||||||
//回复某人的数据渲染
|
//回复某人的数据渲染
|
||||||
const targetGroup = commentData.value.find(
|
const targetGroup = commentData.value.find((i) => i.id === params.rootId);
|
||||||
(i) => i.id === params.rootId
|
|
||||||
); //获取返回的数据信息
|
|
||||||
if (targetGroup) {
|
if (targetGroup) {
|
||||||
if (!targetGroup.children) targetGroup.children = [];
|
targetGroup.childrenCount = (targetGroup.childrenCount || 0) + 1;
|
||||||
targetGroup.children.unshift(newComment);
|
if (targetGroup.showAllReplies) {
|
||||||
targetGroup.childrenCount = targetGroup.children.length;
|
if (!targetGroup.children) targetGroup.children = [];
|
||||||
|
targetGroup.children.unshift(newComment);
|
||||||
|
}else{
|
||||||
|
handleExpand(targetGroup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* 二级评论加载 可能会触发一级加载的问题 */
|
||||||
|
// 是否有任何二级回复正在加载
|
||||||
|
const isSubTaskRunning = computed(() => {
|
||||||
|
return commentData.value.some(item => item.loading);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 综合加载状态:主列表加载中 OR 子任务运行中 OR 发送中
|
||||||
|
const isBusy = computed(() => {
|
||||||
|
return infinityLoading.value || isSubTaskRunning.value || isProcessing.value;
|
||||||
|
});
|
||||||
|
|
||||||
// 滚动加载数据
|
// 滚动加载数据
|
||||||
const setupObserver = () => {
|
const setupObserver = () => {
|
||||||
const observer = new IntersectionObserver(
|
const observer = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
// 如果探测器进入视口,且当前没在加载,且还有更多数据
|
// 如果探测器进入视口,且当前没在加载,且还有更多数据
|
||||||
|
const target = entries[0];
|
||||||
if (
|
if (
|
||||||
entries[0].isIntersecting &&
|
target.isIntersecting &&
|
||||||
!infinityLoading.value &&
|
!isBusy.value &&
|
||||||
!noMore.value
|
!noMore.value
|
||||||
) {
|
) {
|
||||||
loadMainComments();
|
loadMainComments();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
threshold: 0.1,
|
threshold: 0.1
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -580,6 +637,7 @@ const setupObserver = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nextPage = ref(1);
|
const nextPage = ref(1);
|
||||||
|
// TODO:能会存在数据重复的问题
|
||||||
const loadMainComments = async () => {
|
const loadMainComments = async () => {
|
||||||
infinityLoading.value = true;
|
infinityLoading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -629,13 +687,15 @@ const loadMoreReplies = async (item) => {
|
|||||||
try {
|
try {
|
||||||
const res = await getCommentData({
|
const res = await getCommentData({
|
||||||
rootId: item.id,
|
rootId: item.id,
|
||||||
pageNum: nextPage,
|
pageNo: nextPage,
|
||||||
pageSize: PAGE_SIZE_MORE,
|
pageSize: PAGE_SIZE_MORE,
|
||||||
});
|
});
|
||||||
|
const newRecords = res?.records || [];
|
||||||
// 将新数据追加到列表末尾
|
// 将新数据追加到列表末尾
|
||||||
item.children = [...item.children, ...res];
|
if(newRecords.length > 0){
|
||||||
item.currentPage = nextPage;
|
item.children = [...item.children, ...newRecords];
|
||||||
|
item.currentPage = nextPage;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
item.loading = false;
|
item.loading = false;
|
||||||
}
|
}
|
||||||
@@ -644,7 +704,7 @@ const loadMoreReplies = async (item) => {
|
|||||||
const collapseReplies = (item) => {
|
const collapseReplies = (item) => {
|
||||||
item.showAllReplies = false;
|
item.showAllReplies = false;
|
||||||
item.children = []; //清空数据
|
item.children = []; //清空数据
|
||||||
item.currentPage = 0; //重置页码
|
item.currentPage = 1; //重置页码
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -81,6 +81,12 @@ export function useUserSearch(
|
|||||||
* 暴露给外部调用的入口
|
* 暴露给外部调用的入口
|
||||||
*/
|
*/
|
||||||
const search = (keyword: string) => {
|
const search = (keyword: string) => {
|
||||||
|
// 如果输入框里没这个 @名字 了,从 selectedUsersCache 删掉它
|
||||||
|
for (const name of selectedUsersCache.keys()) {
|
||||||
|
if (!mainInput.value.includes(`@${name}`)) {
|
||||||
|
selectedUsersCache.delete(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
searching.value = true;
|
searching.value = true;
|
||||||
debouncedSearch(keyword);
|
debouncedSearch(keyword);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,5 @@ export const parseMention = (text: string, atUsers: atUserProps[]) => {
|
|||||||
|
|
||||||
result = prefix + highlight + suffix;
|
result = prefix + highlight + suffix;
|
||||||
});
|
});
|
||||||
|
|
||||||
return result.replace(/\n/g, '<br>');
|
return result.replace(/\n/g, '<br>');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
destroy-on-close
|
destroy-on-close
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
|
modal-class="standard-overlay-dialog-flat"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
ref="ruleFormRef"
|
ref="ruleFormRef"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
destroy-on-close
|
destroy-on-close
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
:close-on-press-escape="false"
|
:close-on-press-escape="false"
|
||||||
|
modal-class="standard-overlay-dialog-flat"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
ref="ruleFormRef"
|
ref="ruleFormRef"
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ const getTableData = async (params) => {
|
|||||||
};
|
};
|
||||||
// 搜索查询条件信息
|
// 搜索查询条件信息
|
||||||
const fetchTableData = () => {
|
const fetchTableData = () => {
|
||||||
dictTableRef.value && dictTableRef.value.refresh();
|
onConfirmSuccess();
|
||||||
};
|
};
|
||||||
const clearSelectItem = () => {
|
const clearSelectItem = () => {
|
||||||
Object.assign(selectItem,{id:null,name:'',key:'',status:1,remark:''})
|
Object.assign(selectItem,{id:null,name:'',key:'',status:1,remark:''})
|
||||||
@@ -268,7 +268,7 @@ const handleDictStatus = async (row) => {
|
|||||||
|
|
||||||
// 刷新Table数据信息
|
// 刷新Table数据信息
|
||||||
const onConfirmSuccess = () => {
|
const onConfirmSuccess = () => {
|
||||||
dictTableRef.value && dictTableRef.value.refresh();
|
dictTableRef.value && dictTableRef.value.reset();
|
||||||
};
|
};
|
||||||
// TODO:字段配置
|
// TODO:字段配置
|
||||||
const handlefieldsConfig = (ite) => {
|
const handlefieldsConfig = (ite) => {
|
||||||
@@ -281,7 +281,7 @@ const handleDelete = async (item) => {
|
|||||||
.then(async () => {
|
.then(async () => {
|
||||||
try {
|
try {
|
||||||
await deleteDictValue(item.id);
|
await deleteDictValue(item.id);
|
||||||
dictTableRef.value && dictTableRef.value.refresh();
|
onConfirmSuccess();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("fetch error", error);
|
console.log("fetch error", error);
|
||||||
}
|
}
|
||||||
@@ -301,19 +301,5 @@ const handleDelete = async (item) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mj-status-dot {
|
|
||||||
cursor: pointer;
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--data-status-color);
|
|
||||||
margin-right: 8px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,25 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
title="新增系统角色"
|
:title="computedTitle"
|
||||||
width="500px"
|
width="500px"
|
||||||
class="standard-ui-flat-dialog"
|
class="standard-ui-flat-dialog"
|
||||||
modal-class="standard-overlay-dialog-flat"
|
modal-class="standard-overlay-dialog-flat"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
top="10vh"
|
||||||
>
|
>
|
||||||
<el-form :model="form" label-position="top" class="role-form">
|
<el-form ref="formRef" :model="form" label-position="top" :rules="rules">
|
||||||
<div class="row-flex">
|
<div class="row-flex">
|
||||||
<el-form-item label="角色名称" required>
|
<el-form-item label="角色名称" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="请输入角色名称" />
|
<el-input v-model="form.name" placeholder="请输入角色名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="角色编码" required>
|
<el-form-item label="角色编码" prop="code">
|
||||||
<el-input v-model="form.code" placeholder="ROLE_CODE" />
|
<el-input v-model="form.code" placeholder="ROLE_CODE" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item label="角色类型">
|
<el-form-item label="角色类型">
|
||||||
<div class="full-width-radio">
|
<div class="full-width-radio">
|
||||||
<BaseSegmented v-model="roleType" :options="roleOptions" />
|
<BaseSegmented v-model="form.type" :options="PermissionManage.roleTypeOptions" />
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@@ -28,16 +31,17 @@
|
|||||||
<div class="title">组织架构</div>
|
<div class="title">组织架构</div>
|
||||||
<div class="desc">是否将该角色与系统组织架构体系进行深度关联</div>
|
<div class="desc">是否将该角色与系统组织架构体系进行深度关联</div>
|
||||||
</div>
|
</div>
|
||||||
<el-switch v-model="form.isOrg" />
|
<el-switch v-model="form.isOrgRelated" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #CAD5E2" :active-value="1" :inactive-value="0" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item label="关联岗位">
|
<el-form-item label="关联岗位">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="form.post"
|
v-model="form.positionIds"
|
||||||
placeholder="请选择岗位"
|
placeholder="请选择关联岗位"
|
||||||
style="width: 100%"
|
multiple
|
||||||
|
collapse-tags
|
||||||
>
|
>
|
||||||
<el-option label="技术总监" value="1" />
|
<el-option :label="item.label" :value="item.value" v-for="(item,index) in positionList" :key="index"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@@ -46,7 +50,7 @@
|
|||||||
<div class="title">启用状态</div>
|
<div class="title">启用状态</div>
|
||||||
<div class="desc">控制该角色及其下属权限是否立即生效</div>
|
<div class="desc">控制该角色及其下属权限是否立即生效</div>
|
||||||
</div>
|
</div>
|
||||||
<el-switch v-model="form.status" />
|
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item label="备注说明">
|
<el-form-item label="备注说明">
|
||||||
@@ -62,8 +66,8 @@
|
|||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="dialogVisible = false" text>取消</el-button>
|
<el-button @click="cancelRoles" text>取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit">确认创建</el-button>
|
<el-button type="primary" @click="handleSubmit(formRef)">确认创建</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -71,28 +75,88 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BaseSegmented from "./baseSegmented.vue";
|
import BaseSegmented from "./baseSegmented.vue";
|
||||||
|
import { PermissionManage } from "@/dict";
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus';
|
||||||
|
import {
|
||||||
|
addRole,
|
||||||
|
getRoleDetail
|
||||||
|
} from "@/api/stage/permission/index.ts";
|
||||||
defineOptions({ name: "addRoles" });
|
defineOptions({ name: "addRoles" });
|
||||||
const dialogVisible = defineModel("visible", { type: Boolean, default: false });
|
const dialogVisible = defineModel("visible", { type: Boolean, default: false });
|
||||||
const roleType = ref('system'); // 初始值
|
const props = defineProps({
|
||||||
|
detailId: {
|
||||||
|
type: [String,Number],
|
||||||
|
default: '',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const roleOptions = [
|
const computedTitle = computed(() => {
|
||||||
{ label: '实例角色', value: 'instance' },
|
return props.detailId ? "编辑系统角色" : "新增系统角色";
|
||||||
{ label: '默认角色', value: 'default' },
|
});
|
||||||
{ label: '系统角色', value: 'system' }
|
const emit = defineEmits(["on-success"]);
|
||||||
];
|
const positionList = ref([]);
|
||||||
const form = reactive({
|
const formRef = ref<FormInstance>(null);
|
||||||
|
const form = reactive<RuleForm>({
|
||||||
name: "",
|
name: "",
|
||||||
code: "",
|
code: "",
|
||||||
type: "实例角色",
|
type: "DEFAULT",
|
||||||
isOrg: false,
|
isOrgRelated: 0, // 是否和组织架构深度关联
|
||||||
post: "",
|
post: "",
|
||||||
status: true,
|
status: 1,
|
||||||
remark: "",
|
remark: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = () => {
|
|
||||||
|
const rules = reactive<FormInstance<RuleForm>>({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: "请输入角色名称", trigger: "blur" }
|
||||||
|
],
|
||||||
|
code: [
|
||||||
|
{ required: true, message: "请输入角色编码", trigger: "blur" }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const cancelRoles = () => {
|
||||||
|
formRef.value && formRef.value.resetFields();
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取角色详情
|
||||||
|
const getRoleShowDetail = async (val) =>{
|
||||||
|
try {
|
||||||
|
const res = await getRoleDetail(props.detailId);
|
||||||
|
Object.assign(form,res);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('getRoleDetail error:',error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 监听详情
|
||||||
|
watch(()=>dialogVisible.value,(val) => {
|
||||||
|
if(val){
|
||||||
|
getRoleShowDetail();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (formEl:FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
try {
|
||||||
|
const res = await addRole(form);
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
cancelRoles();
|
||||||
|
emit('on-success');
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ const handleChange = (val) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@use "sass:color";
|
||||||
$bg-color: #f2f3f5;
|
$bg-color: #f2f3f5;
|
||||||
$active-bg: #ffffff;
|
$active-bg: #ffffff;
|
||||||
$primary-color: #1661ff;
|
$primary-color: #1661ff;
|
||||||
@@ -86,7 +87,7 @@ $text-secondary: #86909c;
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: darken($text-secondary, 15%);
|
color: color.adjust($text-secondary, $lightness: 15%);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选中状态样式
|
// 选中状态样式
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
|
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<CommonTable
|
<CommonTable
|
||||||
ref="dictTableRef"
|
ref="tableRef"
|
||||||
:columns="columns"
|
:columns="tableColumns"
|
||||||
v-model:data="dataList"
|
v-model:data="dataList"
|
||||||
v-model:total="total"
|
v-model:total="total"
|
||||||
pagination
|
pagination
|
||||||
@@ -39,12 +39,31 @@
|
|||||||
>
|
>
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<el-tag>{{ row.status }}</el-tag>
|
<div
|
||||||
|
class="mj-status-dot"
|
||||||
|
:style="{
|
||||||
|
'--data-status-color': PermissionManage.roleDictColor[row.status],
|
||||||
|
}"
|
||||||
|
@click="handleDictStatus(row)"
|
||||||
|
>
|
||||||
|
{{ PermissionManage.roleDict[row.status] }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 类型 -->
|
||||||
|
<template #type="{ row }">
|
||||||
|
<el-tag type="primary">{{ row.type }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 成员数量 -->
|
<!-- 成员数量 -->
|
||||||
<template #member="{ row }">
|
<template #member="{ row }">
|
||||||
<el-tag @click.stop="addMember">{{ row.member }}</el-tag>
|
<el-button
|
||||||
|
link
|
||||||
|
icon="UserFilled"
|
||||||
|
type="primary"
|
||||||
|
@click.stop="addMember"
|
||||||
|
>{{ row.memberCount }}</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</CommonTable>
|
</CommonTable>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,7 +72,7 @@
|
|||||||
<member-selector v-model:visible="showMember" />
|
<member-selector v-model:visible="showMember" />
|
||||||
|
|
||||||
<!-- 新增角色 -->
|
<!-- 新增角色 -->
|
||||||
<add-roles v-model:visible="showRoles" />
|
<add-roles v-model:visible="showRoles" @on-success="onRefresh" :detail-id="detailId"/>
|
||||||
|
|
||||||
<!-- 权限抽屉 -->
|
<!-- 权限抽屉 -->
|
||||||
<permission-drawer v-model:visible="showPermission" />
|
<permission-drawer v-model:visible="showPermission" />
|
||||||
@@ -64,14 +83,26 @@ import CommonTable from "@/components/proTable/index.vue";
|
|||||||
import memberSelector from "@/components/memberSelector/index.vue";
|
import memberSelector from "@/components/memberSelector/index.vue";
|
||||||
import addRoles from "./addRoles.vue";
|
import addRoles from "./addRoles.vue";
|
||||||
import permissionDrawer from "./permissionDrawer.vue";
|
import permissionDrawer from "./permissionDrawer.vue";
|
||||||
|
import { PermissionManage } from "@/dict";
|
||||||
|
import { formatIndex } from "@/utils/utils";
|
||||||
|
import {
|
||||||
|
getRoleList,
|
||||||
|
getRoleDetail,
|
||||||
|
updateRole,
|
||||||
|
addRole,
|
||||||
|
deleteRole,
|
||||||
|
enableRole,
|
||||||
|
disableRole
|
||||||
|
} from "@/api/stage/permission/index.ts";
|
||||||
defineOptions({ name: "PermissionManagement" });
|
defineOptions({ name: "PermissionManagement" });
|
||||||
const activeTab = ref(1);
|
const activeTab = ref(1);
|
||||||
const dictTableRef = ref(null);
|
const tableRef = ref(null);
|
||||||
const searchVal = ref("");
|
const searchVal = ref("");
|
||||||
const dataList = ref([]);
|
const dataList = ref([]);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const showMember = ref(false);
|
const showMember = ref(false);
|
||||||
const showRoles = ref(false);
|
const showRoles = ref(false);
|
||||||
|
const detailId = ref('');
|
||||||
const showPermission = ref(false);
|
const showPermission = ref(false);
|
||||||
const tabList = [
|
const tabList = [
|
||||||
{
|
{
|
||||||
@@ -88,19 +119,30 @@ const tabList = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns = [
|
const roleColumns = [
|
||||||
{ prop: "id", label: "编号", width: "80", align: "center", slot: "number" },
|
|
||||||
{ prop: "name", label: "字典名称", align: "center", slot: "name" },
|
|
||||||
{
|
{
|
||||||
prop: "member",
|
prop: "id",
|
||||||
|
label: "编号",
|
||||||
|
width: "80",
|
||||||
|
align: "center",
|
||||||
|
formatter: (val) => {
|
||||||
|
return `#${formatIndex(val.id)}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ prop: "name", label: "角色名称", align: "center",showOverflowTooltip:true },
|
||||||
|
{
|
||||||
|
prop: "memberCount",
|
||||||
label: "成员数量",
|
label: "成员数量",
|
||||||
align: "center",
|
align: "center",
|
||||||
slot: "member",
|
slot: "member",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "key",
|
prop: "permissionCount",
|
||||||
label: "权限数量",
|
label: "权限数量",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
formatter: (val) => {
|
||||||
|
return val.permissionCount ? `${val.permissionCount}项` : "-";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "status",
|
prop: "status",
|
||||||
@@ -109,30 +151,33 @@ const columns = [
|
|||||||
slot: "status",
|
slot: "status",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "roleType",
|
prop: "type",
|
||||||
label: "角色类型",
|
label: "角色类型",
|
||||||
align: "center",
|
align: "center",
|
||||||
showOverflowTooltip: true,
|
slot: "type",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "remark",
|
prop: "positionIds",
|
||||||
label: "关联岗位",
|
label: "关联岗位",
|
||||||
align: "center",
|
align: "center",
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
|
formatter: (val) => {
|
||||||
|
return val.positionIds ? val.positionIds.join(",") : "-";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "createTime",
|
prop: "updateTime",
|
||||||
label: "更新时间",
|
label: "更新时间",
|
||||||
align: "center",
|
align: "center",
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
formatter: (val) => {
|
formatter: (val) => {
|
||||||
return val.createTime
|
return val.updateTime
|
||||||
? dayjs(val.createTime).format("YYYY-MM-DD HH:mm")
|
? dayjs(val.updateTime).format("YYYY-MM-DD HH:mm")
|
||||||
: "-";
|
: "-";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "updateByName",
|
prop: "updater",
|
||||||
label: "更新人",
|
label: "更新人",
|
||||||
align: "center",
|
align: "center",
|
||||||
},
|
},
|
||||||
@@ -140,7 +185,8 @@ const columns = [
|
|||||||
prop: "actions",
|
prop: "actions",
|
||||||
label: "操作",
|
label: "操作",
|
||||||
align: "right",
|
align: "right",
|
||||||
width: "300",
|
fixed:"right",
|
||||||
|
width: "200",
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: "权限",
|
label: "权限",
|
||||||
@@ -163,41 +209,167 @@ const columns = [
|
|||||||
type: "default",
|
type: "default",
|
||||||
link: true,
|
link: true,
|
||||||
permission: ["config"],
|
permission: ["config"],
|
||||||
onClick: (row) => {},
|
onClick: (row) => {
|
||||||
|
showRoles.value = true;
|
||||||
|
detailId.value = row.id;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "删除",
|
label: "删除",
|
||||||
type: "danger",
|
type: "danger",
|
||||||
link: true,
|
link: true,
|
||||||
permission: ["delete"],
|
permission: ["delete"],
|
||||||
onClick: (row) => {},
|
disabledFn: (row) => {
|
||||||
|
return (row.type !== 'SYSTEM')
|
||||||
|
},
|
||||||
|
onClick: async (row) => {
|
||||||
|
try {
|
||||||
|
deleteRole(row.id).then(() => {
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
tableRef.value.refresh();
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log('error',error);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const userColumns = [
|
||||||
|
{
|
||||||
|
prop: "name",
|
||||||
|
label: "姓名",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "code",
|
||||||
|
label: "账号",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "departIds",
|
||||||
|
label: "所属部门",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "roleIds",
|
||||||
|
label: "所属角色",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "status",
|
||||||
|
label: "状态",
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "actions",
|
||||||
|
label: "操作",
|
||||||
|
align: "right",
|
||||||
|
fixed:"right",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: "编辑",
|
||||||
|
type: "primary",
|
||||||
|
link: true,
|
||||||
|
permission: ["edit"],
|
||||||
|
onClick: (row) => {
|
||||||
|
showPermission.value = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "重置密码",
|
||||||
|
type: "primary",
|
||||||
|
link: true,
|
||||||
|
permission: ["edit"],
|
||||||
|
onClick: (row) => {
|
||||||
|
showPermission.value = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "移除",
|
||||||
|
type: "danger",
|
||||||
|
link: true,
|
||||||
|
permission: ["edit"],
|
||||||
|
onClick: (row) => {
|
||||||
|
showPermission.value = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const tableColumns = computed(() => {
|
||||||
|
const columns = {
|
||||||
|
1: roleColumns,
|
||||||
|
2: userColumns,
|
||||||
|
}[activeTab.value];
|
||||||
|
return columns;
|
||||||
|
});
|
||||||
|
|
||||||
// 当前成员数量
|
// 当前成员数量
|
||||||
const addMember = () => {
|
const addMember = () => {
|
||||||
showMember.value = true;
|
showMember.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 刷新列表
|
||||||
|
const onRefresh = () => {
|
||||||
|
tableRef.value && tableRef.value.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听Tabs变化
|
||||||
|
watch(activeTab,()=>{
|
||||||
|
dataList.value = [];
|
||||||
|
tableRef.value && tableRef.value.reset();
|
||||||
|
})
|
||||||
|
|
||||||
|
// 权限
|
||||||
|
const handleDictStatus = async (row) => {
|
||||||
|
try {
|
||||||
|
row.status === 1 ? await disableRole(row.id) : await enableRole(row.id);
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
onRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getTableData = async (params) => {
|
const getTableData = async (params) => {
|
||||||
|
console.log('每次请求的分页:',params);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
return {
|
return {
|
||||||
records: [
|
records: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "11111",
|
name: "测试角色名称",
|
||||||
member: "2222",
|
memberCount: 10,
|
||||||
|
permissionCount: 22,
|
||||||
status: 1,
|
status: 1,
|
||||||
key: "",
|
type: "SYSTEM",
|
||||||
roleType: 1,
|
positionIds: "",
|
||||||
remark: "",
|
updateTime: 1767878508824,
|
||||||
createTime: 1767878508824,
|
updater: "更新人",
|
||||||
updateByName: "111",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 正式请求
|
||||||
|
const queryParams = {
|
||||||
|
...(searchVal.value && { name:searchVal.value }),
|
||||||
|
status:1,
|
||||||
|
type:1,
|
||||||
|
pageNo:1,
|
||||||
|
pageSize:10
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await getRoleList(queryParams);
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkRolesText = computed(() => {
|
const checkRolesText = computed(() => {
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ const transformRoutes = (
|
|||||||
routes: any[],
|
routes: any[],
|
||||||
parentCode: string = ""
|
parentCode: string = ""
|
||||||
): RouteRecordRaw[] => {
|
): RouteRecordRaw[] => {
|
||||||
console.log("transformRoutes", routes);
|
|
||||||
return routes.flatMap((route) => {
|
return routes.flatMap((route) => {
|
||||||
const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code;
|
const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code;
|
||||||
|
|
||||||
@@ -143,7 +142,8 @@ const addDynamicRoutes = async () => {
|
|||||||
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
|
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
|
||||||
let allRoutes:any[] = [];
|
let allRoutes:any[] = [];
|
||||||
if (userStore.isBackendUser) {
|
if (userStore.isBackendUser) {
|
||||||
const backendResponse = await getRouteMenus();
|
// const backendResponse = await getRouteMenus();
|
||||||
|
const backendResponse = [];
|
||||||
allRoutes = [
|
allRoutes = [
|
||||||
{
|
{
|
||||||
code: "stage",
|
code: "stage",
|
||||||
|
|||||||
@@ -157,6 +157,23 @@
|
|||||||
.el-dialog__header {
|
.el-dialog__header {
|
||||||
padding: var(--el-dialog-inset-padding-primary);
|
padding: var(--el-dialog-inset-padding-primary);
|
||||||
border-bottom: 1px solid var(--el-dialog-border-header-footer-color);
|
border-bottom: 1px solid var(--el-dialog-border-header-footer-color);
|
||||||
|
|
||||||
|
.el-dialog__title{
|
||||||
|
position: relative;
|
||||||
|
padding-left: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
&::before{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--blue-block-color);
|
||||||
|
border-radius: 2px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-dialog__body {
|
.el-dialog__body {
|
||||||
|
|||||||
Reference in New Issue
Block a user