mirror of https://gitee.com/answerdev/answer.git
feat: cannot change current logged user status and role
This commit is contained in:
parent
fa7ade2a24
commit
9884a1d23f
|
@ -678,6 +678,7 @@ ui:
|
||||||
update: update success
|
update: update success
|
||||||
update_password: Password changed successfully.
|
update_password: Password changed successfully.
|
||||||
flag_success: Thanks for flagging.
|
flag_success: Thanks for flagging.
|
||||||
|
fobidden_operate_self: Forbidden to operate on yourself
|
||||||
related_question:
|
related_question:
|
||||||
title: Related Questions
|
title: Related Questions
|
||||||
btn: Add question
|
btn: Add question
|
||||||
|
@ -1022,15 +1023,6 @@ ui:
|
||||||
title: Change user role to...
|
title: Change user role to...
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
btn_submit: Submit
|
btn_submit: Submit
|
||||||
user:
|
|
||||||
name: User
|
|
||||||
description: Default with no special access.
|
|
||||||
admin:
|
|
||||||
name: Admin
|
|
||||||
description: Have the full power to access the site.
|
|
||||||
moderator:
|
|
||||||
name: Moderator
|
|
||||||
description: Has access to all posts except admin settings.
|
|
||||||
users:
|
users:
|
||||||
title: Users
|
title: Users
|
||||||
name: Name
|
name: Name
|
||||||
|
@ -1049,6 +1041,9 @@ ui:
|
||||||
suspended: Suspended
|
suspended: Suspended
|
||||||
deleted: Deleted
|
deleted: Deleted
|
||||||
normal: Normal
|
normal: Normal
|
||||||
|
Moderator: Moderator
|
||||||
|
Admin: Admin
|
||||||
|
User: User
|
||||||
filter:
|
filter:
|
||||||
placeholder: "Filter by name, user:id"
|
placeholder: "Filter by name, user:id"
|
||||||
set_new_password: Set new password
|
set_new_password: Set new password
|
||||||
|
|
|
@ -444,3 +444,9 @@ export interface ReviewResp {
|
||||||
count: number;
|
count: number;
|
||||||
list: ReviewItem[];
|
list: ReviewItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserRoleItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@ import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
import { Modal as AnswerModal } from '@/components';
|
// import { Modal as AnswerModal } from '@/components';
|
||||||
import { changeUserStatus } from '@/services';
|
import { getUserRoles, changeUserRole } from '@/services';
|
||||||
|
import { UserRoleItem } from '@/common/interface';
|
||||||
|
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
const root = ReactDOM.createRoot(div);
|
const root = ReactDOM.createRoot(div);
|
||||||
|
@ -19,108 +20,57 @@ const useChangeUserRoleModal = ({ callback }: Props) => {
|
||||||
keyPrefix: 'admin.user_role_modal',
|
keyPrefix: 'admin.user_role_modal',
|
||||||
});
|
});
|
||||||
const [id, setId] = useState('');
|
const [id, setId] = useState('');
|
||||||
const [defaultType, setDefaultType] = useState('');
|
const [defaultId, setDefaultId] = useState(-1);
|
||||||
const [isInvalid, setInvalidState] = useState(false);
|
const [isInvalid, setInvalidState] = useState(false);
|
||||||
const [changeType, setChangeType] = useState({
|
const [changedId, setChangeId] = useState(-1);
|
||||||
type: '',
|
|
||||||
haveContent: false,
|
|
||||||
});
|
|
||||||
const [content, setContent] = useState({
|
|
||||||
value: '',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
});
|
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const [list] = useState<any[]>([
|
const [list, setList] = useState<UserRoleItem[]>([]);
|
||||||
{
|
|
||||||
type: 'user',
|
const getRolesData = async () => {
|
||||||
name: t('user.name'),
|
const res = await getUserRoles();
|
||||||
description: t('user.description'),
|
setList(res);
|
||||||
},
|
};
|
||||||
{
|
|
||||||
type: 'admin',
|
|
||||||
name: t('admin.name'),
|
|
||||||
description: t('admin.description'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'moderator',
|
|
||||||
name: t('moderator.name'),
|
|
||||||
description: t('moderator.description'),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleRadio = (val) => {
|
const handleRadio = (val) => {
|
||||||
setInvalidState(false);
|
setInvalidState(false);
|
||||||
setContent({
|
setChangeId(val.id);
|
||||||
value: '',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
});
|
|
||||||
setChangeType({
|
|
||||||
type: val.type,
|
|
||||||
haveContent: val.have_content,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
setChangeType({
|
setChangeId(-1);
|
||||||
type: '',
|
setDefaultId(-1);
|
||||||
haveContent: false,
|
|
||||||
});
|
|
||||||
setContent({
|
|
||||||
value: '',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
});
|
|
||||||
setContent({
|
|
||||||
value: '',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
});
|
|
||||||
setShow(false);
|
setShow(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (changeType.type === '') {
|
if (defaultId === changedId) {
|
||||||
setInvalidState(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (changeType.haveContent && !content.value) {
|
|
||||||
setContent({
|
|
||||||
value: content.value,
|
|
||||||
isInvalid: true,
|
|
||||||
errorMsg: t('remark.empty'),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (defaultType === changeType.type) {
|
|
||||||
onClose();
|
onClose();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (changeType.type === 'deleted') {
|
// if (changeType.type === 'deleted') {
|
||||||
onClose();
|
// onClose();
|
||||||
|
|
||||||
AnswerModal.confirm({
|
// AnswerModal.confirm({
|
||||||
title: t('confirm_title'),
|
// title: t('confirm_title'),
|
||||||
content: t('confirm_content'),
|
// content: t('confirm_content'),
|
||||||
confirmText: t('confirm_btn'),
|
// confirmText: t('confirm_btn'),
|
||||||
confirmBtnVariant: 'danger',
|
// confirmBtnVariant: 'danger',
|
||||||
onConfirm: () => {
|
// onConfirm: () => {
|
||||||
changeUserStatus({
|
// changeUserStatus({
|
||||||
|
// user_id: id,
|
||||||
|
// status: changeType.type,
|
||||||
|
// }).then(() => {
|
||||||
|
// callback?.();
|
||||||
|
// onClose();
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
changeUserRole({
|
||||||
user_id: id,
|
user_id: id,
|
||||||
status: changeType.type,
|
role_id: changedId,
|
||||||
}).then(() => {
|
|
||||||
callback?.();
|
|
||||||
onClose();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
changeUserStatus({
|
|
||||||
user_id: id,
|
|
||||||
status: changeType.type,
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
callback?.();
|
callback?.();
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -128,12 +78,10 @@ const useChangeUserRoleModal = ({ callback }: Props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onShow = (params) => {
|
const onShow = (params) => {
|
||||||
|
getRolesData();
|
||||||
setId(params.id);
|
setId(params.id);
|
||||||
setChangeType({
|
setChangeId(params.role_id);
|
||||||
...changeType,
|
setDefaultId(params.role_id);
|
||||||
type: params.type,
|
|
||||||
});
|
|
||||||
setDefaultType(params.type);
|
|
||||||
setShow(true);
|
setShow(true);
|
||||||
};
|
};
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
@ -146,17 +94,17 @@ const useChangeUserRoleModal = ({ callback }: Props) => {
|
||||||
<Form>
|
<Form>
|
||||||
{list.map((item) => {
|
{list.map((item) => {
|
||||||
return (
|
return (
|
||||||
<div key={item?.type}>
|
<div key={item?.id}>
|
||||||
<Form.Group controlId={item.type} className="mb-3">
|
<Form.Group controlId={item.name} className="mb-3">
|
||||||
<FormCheck>
|
<FormCheck>
|
||||||
<FormCheck.Input
|
<FormCheck.Input
|
||||||
id={item.type}
|
id={item.name}
|
||||||
type="radio"
|
type="radio"
|
||||||
checked={changeType.type === item.type}
|
checked={changedId === item.id}
|
||||||
onChange={() => handleRadio(item)}
|
onChange={() => handleRadio(item)}
|
||||||
isInvalid={isInvalid}
|
isInvalid={isInvalid}
|
||||||
/>
|
/>
|
||||||
<FormCheck.Label htmlFor={item.type}>
|
<FormCheck.Label htmlFor={item.name}>
|
||||||
<span className="fw-bold">{item.name}</span>
|
<span className="fw-bold">{item.name}</span>
|
||||||
<br />
|
<br />
|
||||||
<span className="text-secondary">
|
<span className="text-secondary">
|
||||||
|
|
|
@ -14,8 +14,9 @@ import {
|
||||||
Icon,
|
Icon,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import * as Type from '@/common/interface';
|
import * as Type from '@/common/interface';
|
||||||
import { useChangeModal, useChangeUserRoleModal } from '@/hooks';
|
import { useChangeModal, useChangeUserRoleModal, useToast } from '@/hooks';
|
||||||
import { useQueryUsers } from '@/services';
|
import { useQueryUsers } from '@/services';
|
||||||
|
import { loggedUserInfoStore } from '@/stores';
|
||||||
|
|
||||||
import '../index.scss';
|
import '../index.scss';
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ const Users: FC = () => {
|
||||||
const curFilter = urlSearchParams.get('filter') || UserFilterKeys[0];
|
const curFilter = urlSearchParams.get('filter') || UserFilterKeys[0];
|
||||||
const curPage = Number(urlSearchParams.get('page') || '1');
|
const curPage = Number(urlSearchParams.get('page') || '1');
|
||||||
const curQuery = urlSearchParams.get('query') || '';
|
const curQuery = urlSearchParams.get('query') || '';
|
||||||
|
const currentUser = loggedUserInfoStore((state) => state.user);
|
||||||
|
const Toast = useToast();
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
@ -50,7 +53,11 @@ const Users: FC = () => {
|
||||||
page: curPage,
|
page: curPage,
|
||||||
page_size: PAGE_SIZE,
|
page_size: PAGE_SIZE,
|
||||||
query: curQuery,
|
query: curQuery,
|
||||||
...(curFilter === 'all' ? {} : { status: curFilter }),
|
...(curFilter === 'all'
|
||||||
|
? {}
|
||||||
|
: curFilter === 'staff'
|
||||||
|
? { staff: true }
|
||||||
|
: { status: curFilter }),
|
||||||
});
|
});
|
||||||
const changeModal = useChangeModal({
|
const changeModal = useChangeModal({
|
||||||
callback: refreshUsers,
|
callback: refreshUsers,
|
||||||
|
@ -60,18 +67,28 @@ const Users: FC = () => {
|
||||||
callback: refreshUsers,
|
callback: refreshUsers,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = ({ user_id, status }) => {
|
const handleAction = (type, user) => {
|
||||||
|
const { user_id, status, role_id, username } = user;
|
||||||
|
if (username === currentUser.username) {
|
||||||
|
Toast.onShow({
|
||||||
|
msg: t('fobidden_operate_self', { keyPrefix: 'toast' }),
|
||||||
|
variant: 'warning',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'status') {
|
||||||
changeModal.onShow({
|
changeModal.onShow({
|
||||||
id: user_id,
|
id: user_id,
|
||||||
type: status,
|
type: status,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleClickRole = ({ user_id, role }) => {
|
if (type === 'role') {
|
||||||
changeUserRoleModal.onShow({
|
changeUserRoleModal.onShow({
|
||||||
id: user_id,
|
id: user_id,
|
||||||
role,
|
role_id,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilter = (e) => {
|
const handleFilter = (e) => {
|
||||||
|
@ -157,7 +174,9 @@ const Users: FC = () => {
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span className="text-bg-light">Admin</span>
|
<span className="badge text-bg-light">
|
||||||
|
{t(user.role_name)}
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{curFilter !== 'deleted' ? (
|
{curFilter !== 'deleted' ? (
|
||||||
<td className="text-end">
|
<td className="text-end">
|
||||||
|
@ -166,15 +185,17 @@ const Users: FC = () => {
|
||||||
<Icon name="three-dots-vertical" />
|
<Icon name="three-dots-vertical" />
|
||||||
</Dropdown.Toggle>
|
</Dropdown.Toggle>
|
||||||
<Dropdown.Menu>
|
<Dropdown.Menu>
|
||||||
<Dropdown.Item>{t('set_new_password')}</Dropdown.Item>
|
{/* <Dropdown.Item>{t('set_new_password')}</Dropdown.Item> */}
|
||||||
<Dropdown.Item onClick={() => handleClick(user)}>
|
<Dropdown.Item
|
||||||
|
onClick={() => handleAction('status', user)}>
|
||||||
{t('change_status')}
|
{t('change_status')}
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
<Dropdown.Item onClick={() => handleClickRole(user)}>
|
<Dropdown.Item
|
||||||
|
onClick={() => handleAction('role', user)}>
|
||||||
{t('change_role')}
|
{t('change_role')}
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
<Dropdown.Divider />
|
{/* <Dropdown.Divider />
|
||||||
<Dropdown.Item>{t('show_logs')}</Dropdown.Item>
|
<Dropdown.Item>{t('show_logs')}</Dropdown.Item> */}
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
|
|
|
@ -21,3 +21,11 @@ export const useQueryUsers = (params) => {
|
||||||
mutate,
|
mutate,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getUserRoles = () => {
|
||||||
|
return request.get('/answer/admin/api/roles');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeUserRole = (params) => {
|
||||||
|
return request.put('/answer/admin/api/user/role', params);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue