Compare commits

..

No commits in common. "1e0c687a9bf1fbe798fccaf3132434c362e03550" and "7c84803b36a15da14cdd37491da5733993083db3" have entirely different histories.

15 changed files with 157 additions and 248 deletions

View File

@ -1,22 +0,0 @@
import React from "react";
import useAuth from "@/hooks/useAuth.ts";
type PermissionKeys =
'apply_button'
| 'apply_page'
| 'bill_page'
| 'complete_button'
| 'confirm_button'
| 'manual_payment'
| 'permission_edit';
type PermissionCheckProps = {
permission: PermissionKeys ;
children: React.ReactNode;
}
export const PermissionCheck: React.FC<PermissionCheckProps> = ({permission, children}) => {
const {user} = useAuth()
return <>
{user && user.permissions && user.permissions[permission] ? children : null}
</>
}

View File

@ -1,4 +1,4 @@
import {useRequest} from "ahooks"; import {useEffect, useState} from "react";
function getRemoteUserNameList() { function getRemoteUserNameList() {
return new Promise<string[][]>((resolve, reject) => { return new Promise<string[][]>((resolve, reject) => {
@ -23,18 +23,13 @@ function getRemoteUserNameList() {
} }
export function useRemoteUserList() { export function useRemoteUserList() {
const loadUserList = async () => {
const list = await getRemoteUserNameList();
return list.flat();
}
const {data:usernameList} = useRequest(loadUserList)
// const [userList, setUserList] = useState<string[]>([])
//const [usernameList, setUserList] = useState<string[]>([])
// useEffect(()=>{ const [usernameList, setUserList] = useState<string[]>([])
// getRemoteUserNameList().then(data=>{
// setUserList(data.flat()) useEffect(()=>{
// }) getRemoteUserNameList().then(data=>{
// },[]) setUserList(data.flat())
})
},[])
return usernameList return usernameList
} }

View File

@ -21,8 +21,6 @@
"query_bill": "Failed to query bill:", "query_bill": "Failed to query bill:",
"remove": "Remove", "remove": "Remove",
"save": "Save", "save": "Save",
"save_failed": "Save failed",
"save_success": "Saved successfully",
"select_excel_file": "Select File", "select_excel_file": "Select File",
"select_upload_file": "Select File", "select_upload_file": "Select File",
"student_number": "Student Number", "student_number": "Student Number",
@ -164,8 +162,7 @@
"permission": { "permission": {
"message": { "message": {
"empty_tips": "No data, please create new", "empty_tips": "No data, please create new",
"error_require": "Please set your username or role", "error_require": "Please set your username or role"
"username_exist": "Username already exists"
}, },
"title": { "title": {
"add": "New", "add": "New",

View File

@ -21,8 +21,6 @@
"query_bill": "查询账单失败:", "query_bill": "查询账单失败:",
"remove": "删除", "remove": "删除",
"save": "保存", "save": "保存",
"save_failed": "保存失败",
"save_success": "保存成功",
"select_excel_file": "选择文件", "select_excel_file": "选择文件",
"select_upload_file": "选择文件", "select_upload_file": "选择文件",
"student_number": "学号", "student_number": "学号",
@ -164,8 +162,7 @@
"permission": { "permission": {
"message": { "message": {
"empty_tips": "暂无数据,请新增", "empty_tips": "暂无数据,请新增",
"error_require": "请设置用户名或角色", "error_require": "请设置用户名或角色"
"username_exist": "用户名已经存在了"
}, },
"title": { "title": {
"add": "新增", "add": "新增",

View File

@ -21,8 +21,6 @@
"query_bill": "查詢帳單失敗:", "query_bill": "查詢帳單失敗:",
"remove": "刪除", "remove": "刪除",
"save": "儲存", "save": "儲存",
"save_failed": "保存失敗",
"save_success": "保存成功",
"select_excel_file": "選擇文件", "select_excel_file": "選擇文件",
"select_upload_file": "選擇文件", "select_upload_file": "選擇文件",
"student_number": "學號", "student_number": "學號",
@ -164,8 +162,7 @@
"permission": { "permission": {
"message": { "message": {
"empty_tips": "暫無數據,請新增", "empty_tips": "暫無數據,請新增",
"error_require": "請設定使用者名稱或角色", "error_require": "請設定使用者名稱或角色"
"username_exist": "使用者名稱已經存在了"
}, },
"title": { "title": {
"add": "新增", "add": "新增",

View File

@ -3,16 +3,11 @@ import {Button, Checkbox, Empty, Popconfirm, Select, Space, Toast} from "@douyin
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
import {useEffect, useMemo} from "react"; import {useEffect, useMemo} from "react";
import {Card} from "@/components/card";
import './permission.less'; import './permission.less';
import {Card} from "@/components/card";
import {useRemoteUserList} from "@/hooks/useRemoteUserList.ts"; import {useRemoteUserList} from "@/hooks/useRemoteUserList.ts";
import { import {getUserPermissionList, removeUserPermission} from "@/service/api/user.ts";
createUserPermission,
getUserPermissionList,
removeUserPermission,
updateUserPermission
} from "@/service/api/user.ts";
import useAuth from "@/hooks/useAuth.ts";
// const PermissionList = [ // const PermissionList = [
@ -25,49 +20,28 @@ import useAuth from "@/hooks/useAuth.ts";
// 'permission' // 'permission'
// ] // ]
type UserPermissionItemProps = {
it: UserPermission;
onChange: (action: 'remove' | 'saved' | 'modify', value: UserPermission) => Promise<void>;
usernameOptionList: OptionValue[]
roleOptionList: OptionValue[]
}
const UserPermissionItem = ({it, onChange, usernameOptionList,roleOptionList}: UserPermissionItemProps) => { const UserPermissionItem = ({it, onChange, usernameOptionList}: {
it: UserPermission;
onChange: (action:'remove'|'saved'|'modify',value:UserPermission) => void;
usernameOptionList: OptionValue[]
}) => {
const {t} = useTranslation() const {t} = useTranslation()
const {user} = useAuth()
const [state,setState] = useSetState({
loading: false
})
const onValueChange = (value: { const onValueChange = (value: {
[key: string]: string | boolean [key:string]:string|boolean
}) => { })=>{
onChange('modify', { onChange('modify',{
...it, ...it,
...value ...value
}).then(); })
} }
const onRemove = () => { const onSave = ()=>{
if(it.id > 0){
setState({loading: true})
onChange('remove', it).finally(()=>{
setState({loading: false})
})
return;
}
onChange('remove', it).then();
}
const onSave = () => {
console.log(it) console.log(it)
if (!it.role || !it.username) { if(!it.role || !it.username){
Toast.warning(t('permission.message.error_require')) Toast.warning(t('permission.message.error_require'))
return; return;
} }
setState({loading: true})
onChange('saved', it).finally(()=>{
setState({loading: false})
})
} }
// const [values,setValues] = use // const [values,setValues] = use
return (<div className="table-row"> return (<div className="table-row">
<div className="item item-username item-type"> <div className="item item-username item-type">
@ -86,7 +60,11 @@ const UserPermissionItem = ({it, onChange, usernameOptionList,roleOptionList}: U
<div className="form-item"> <div className="form-item">
<Select <Select
style={{width: '100%'}} style={{width: '100%'}}
optionList={roleOptionList} optionList={[
{label: 'ROOT', value: 'root'},
{label: 'RO', value: 'ro'},
{label: 'FO', value: 'fo'},
]}
defaultValue={it.role} defaultValue={it.role}
onChange={(value) => onValueChange({role: String(value)})} onChange={(value) => onValueChange({role: String(value)})}
placeholder={t('base.please_select')} placeholder={t('base.please_select')}
@ -126,20 +104,18 @@ const UserPermissionItem = ({it, onChange, usernameOptionList,roleOptionList}: U
<div className={`item item-type item-type-bill-permission`}> <div className={`item item-type item-type-bill-permission`}>
<Checkbox <Checkbox
defaultChecked={it.permission_edit} defaultChecked={it.permission_edit}
disabled={user?.username == it.username}
onChange={e => onValueChange({permission_edit: !!e.target.checked})}/> onChange={e => onValueChange({permission_edit: !!e.target.checked})}/>
</div> </div>
<div className="item item-operation text-center"> <div className="item item-operation text-center">
<Space> <Space>
{user?.username != it.username && <Popconfirm <Popconfirm
disabled={state.loading} title={t('base.warning')} onConfirm={() => onChange('remove',it)}
title={t('base.warning')} onConfirm={onRemove} position={'topRight'}
position={'topRight'} content={`${t('base.confirm_delete')}?`}
content={`${t('base.confirm_delete')}?`} >
> <Button theme={'solid'} type="danger" size={'small'}>{t('base.delete')}</Button>
<Button theme={'solid'} type="danger" size={'small'}>{t('base.delete')}</Button> </Popconfirm>
</Popconfirm>} <Button size={'small'} theme={'solid'} onClick={onSave}>{t('base.save')}</Button>
<Button loading={state.loading} size={'small'} theme={'solid'} onClick={onSave}>{t('base.save')}</Button>
</Space> </Space>
</div> </div>
</div>) </div>)
@ -148,47 +124,19 @@ const UserPermissionItem = ({it, onChange, usernameOptionList,roleOptionList}: U
const Permission = () => { const Permission = () => {
const {t} = useTranslation() const {t} = useTranslation()
const usernameList = useRemoteUserList(); const usernameList = useRemoteUserList();
const {user} = useAuth();
const [state, setState] = useSetState<{ const [state, setState] = useSetState<{
list: UserPermission[]; list: UserPermission[];
allList: UserPermission[];
loading?: boolean; loading?: boolean;
}>({ }>({
list: [], list: []
allList:[]
}) })
const usernameOptionList = useMemo(() => (usernameList.map(name => ({label: name, value: name}))), [usernameList])
const usernameOptionList = useMemo(() => (usernameList?usernameList.map(name => ({label: name, value: name})):[]), [usernameList])
const roleOptionList = useMemo(() => {
const list = [
{label: 'ROOT', value: 'root'},
{label: 'RO', value: 'ro'},
{label: 'FO', value: 'fo'},
];
const userRole = user?.permissions?.role ?? 'staff';
if(userRole == 'root') return list;
return list//.filter(it => (it.value == userRole));
}, [])
// load user permission list // load user permission list
const loadUserPermissionList = () => { const loadUserPermissionList = () => {
setState({loading: true}) setState({loading: true})
getUserPermissionList().then(list => { getUserPermissionList().then(list => {
setState({allList:[...list]})
const userRole = user?.permissions?.role ?? 'staff';
list.forEach(it=>{
it.permission_edit = !!it.permission_edit
it.bill_page = !!it.bill_page
it.apply_page = !!it.apply_page
it.complete_button = !!it.complete_button
it.confirm_button = !!it.confirm_button
it.apply_button = !!it.apply_button
it.manual_payment = !!it.manual_payment
})
if(userRole != 'root') {
list = list.filter(it => (it.role == userRole));
}
setState({loading: false, list}) setState({loading: false, list})
}) })
} }
@ -196,7 +144,7 @@ const Permission = () => {
// remove a user permission // remove a user permission
const removeItem = (index: number, id: number) => { const removeItem = (index: number, id: number) => {
const removeFromList = () => { const removeFromList = ()=>{
const newList = [...state.list]; const newList = [...state.list];
newList.splice(index, 1) newList.splice(index, 1)
setState({list: newList}) setState({list: newList})
@ -207,6 +155,28 @@ const Permission = () => {
} }
removeFromList(); removeFromList();
} }
// const onUsernameChange = (index: number, name: string, role: string) => {
// const newList = [...state.list];
// newList[index].username = name;
// newList[index].role = role;
// setState({list: newList})
// }
// const onPermissionChange = (_index: number, name: string, checked?: boolean) => {
// const newList = [...state.list];
// const index = newList[_index].permissions.indexOf(name)
// if (index == -1) { // 没有找到
// if (checked) { // 已经选中
// newList[index].permissions.push(name)
// }
// } else {
// if (!checked) { // 已经选中
// newList[index].permissions.splice(index, 1)
// }
// }
// setState({list: newList})
// }
const addNewRecord = () => { const addNewRecord = () => {
setState({ setState({
list: [...state.list, { list: [...state.list, {
@ -224,34 +194,14 @@ const Permission = () => {
}) })
} }
const handleChange = async (action: 'remove' | 'saved' | 'modify', value: UserPermission, index: number) => { const handleChange = (action:'remove'|'saved'|'modify',value:UserPermission,index:number) =>{
if (action == 'remove') removeItem(index, value.id) if(action == 'remove') removeItem(index,value.id)
else if (action == 'modify') { else if(action == 'modify'){
const newList = [...state.list]; const newList = [...state.list];
newList[index] = { newList[index] = {
...value ...value
} }
setState({list: newList}) setState({list: newList})
} else if (action == 'saved') {
// 判断是否存在同名用户
const exist = state.list.filter(it=>it.id > 0).find(it => it.username == value.username && it.id != value.id)
if (exist) {
Toast.error(t('permission.message.username_exist'))
return;
}
const process = value.id > 0 ? updateUserPermission : createUserPermission;
try {
await process(value).then((newValue) => {
Toast.success(t('base.save_success'))
const newList = [...state.list];
newList[index] = {
...newValue
}
setState({list: newList})
})
} catch (e) {
Toast.error(t('base.save_failed') + `(${(e as Error).message})`)
}
} }
} }
@ -273,24 +223,20 @@ const Permission = () => {
<div className="item item-operation">{t('bill.title_operate')}</div> <div className="item item-operation">{t('bill.title_operate')}</div>
</div> </div>
{state.list.map((it, index) => (<UserPermissionItem {state.list.map((it, index) => (<UserPermissionItem
key={index} it={it} key={index} it={it} onChange={(action,value) => handleChange(action,value,index)}
onChange={async (action, value) => {
await handleChange(action, value, index)
}}
usernameOptionList={usernameOptionList} usernameOptionList={usernameOptionList}
roleOptionList={roleOptionList}
/>))} />))}
{state.list.length == 0 && <div style={{backgroundColor: '#fafafa'}}> {state.list.length == 0 && <div style={{backgroundColor:'#fafafa'}}>
<Empty <Empty
description={t('permission.message.empty_tips')} description={t('permission.message.empty_tips')}
style={{paddingBottom: 20}} style={{paddingBottom:20}}
/> />
</div>} </div>}
</div> </div>
</div> </div>
{!state.loading && <Space style={{marginTop: 20}}> <Space style={{marginTop: 20}}>
<Button style={{width: 100}} onClick={addNewRecord} theme={'solid'}>{t('permission.title.add')}</Button> <Button style={{width: 100}} onClick={addNewRecord} theme={'solid'}>{t('permission.title.add')}</Button>
</Space>} </Space>
</Card>) </Card>)
} }
export default Permission export default Permission

View File

@ -118,17 +118,15 @@ export const ImportBillModal: React.FC<BillPaidModalProps> = (props) => {
<div className="import-record-wrapper"> <div className="import-record-wrapper">
<div className="table-list"> <div className="table-list">
<table> <table>
<tbody> {records.map((record, index) => {
{records.map((record, index) => { return <tr key={index}>
return <tr key={index}> {record.map((item, index) => {
{record.map((item, index) => { return <td key={index}>
return <td key={index}> <div className={'import-record-item'}>{item}</div>
<div className={'import-record-item'}>{item}</div> </td>
</td> })}
})} </tr>
</tr> })}
})}
</tbody>
</table> </table>
</div> </div>
</div> </div>

View File

@ -16,7 +16,6 @@ import {BillTypeConfirmModal} from "@/pages/bill/components/bill_type_confirm.ts
import {BillTypeConfirmBatch} from "@/pages/bill/components/bill_type_confirm_batch.tsx"; import {BillTypeConfirmBatch} from "@/pages/bill/components/bill_type_confirm_batch.tsx";
import {AddBillModal} from "@/pages/bill/components/add_bill_modal.tsx"; import {AddBillModal} from "@/pages/bill/components/add_bill_modal.tsx";
import {ImportBillModal} from "@/pages/bill/components/import_bill_modal.tsx"; import {ImportBillModal} from "@/pages/bill/components/import_bill_modal.tsx";
import {PermissionCheck} from "@/components/permission";
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => { const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
@ -30,7 +29,6 @@ const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
// } // }
const BillQuery = () => { const BillQuery = () => {
// const {createPDF,downloadPDF} = useDownloadReceiptPDF() // const {createPDF,downloadPDF} = useDownloadReceiptPDF()
const [state, setState] = useSetState<{ const [state, setState] = useSetState<{
updateBill?: BillModel; updateBill?: BillModel;
@ -90,13 +88,10 @@ const BillQuery = () => {
// } // }
const operation = (bill: BillModel) => { const operation = (bill: BillModel) => {
return (<div className={'table-operation-render'}> return (<div className={'table-operation-render'}>
<PermissionCheck permission={'complete_button'}> {bill.status != BillStatus.PAID &&
{bill.status != BillStatus.PAID && <Button onClick={() => setState({updateBill: bill})} size={'small'} theme={'solid'}
<Button onClick={() => setState({updateBill: bill})} size={'small'} theme={'solid'} type={'danger'}>{t('bill.paid')}</Button>
type={'danger'}>{t('bill.paid')}</Button> }
}
</PermissionCheck>
{bill.status == BillStatus.PENDING && <> {bill.status == BillStatus.PENDING && <>
<Popconfirm <Popconfirm
title={'Notice'} onConfirm={() => onCancelBill(bill)} position={'topRight'} title={'Notice'} onConfirm={() => onCancelBill(bill)} position={'topRight'}
@ -114,22 +109,16 @@ const BillQuery = () => {
<DownloadButton bill={bill} text={t('bill.download_receipt')}/> <DownloadButton bill={bill} text={t('bill.download_receipt')}/>
{/*<Button*/} {/*<Button*/}
{/* onClick={() => showBillPDF(bill)} size={'small'}>download pdf</Button>*/} {/* onClick={() => showBillPDF(bill)} size={'small'}>download pdf</Button>*/}
{bill.confirm_status == 'UNCONFIRMED' ? <Button
<PermissionCheck permission={'confirm_button'}> onClick={() => setState({confirmBill: bill})}
{ size={'small'} theme={'solid'}
bill.confirm_status == 'UNCONFIRMED' type={'primary'}>{t('bill.confirm_bill_type')}</Button>
? <Button : <Popconfirm
onClick={() => setState({confirmBill: bill})} title={'Warning'} onConfirm={() => onCancelBillConfirm(bill.id)} position={'topRight'}
size={'small'} theme={'solid'} content={`${t('base.confirm_next_operation')}?`}
type={'primary'}>{t('bill.confirm_bill_type')}</Button> >
: <Popconfirm <Button size={'small'} theme={'solid'} type={'danger'}>{t('bill.btn_cancel_confirm')}</Button>
title={'Warning'} onConfirm={() => onCancelBillConfirm(bill.id)} position={'topRight'} </Popconfirm>}
content={`${t('base.confirm_next_operation')}?`}
>
<Button size={'small'} theme={'solid'} type={'danger'}>{t('bill.btn_cancel_confirm')}</Button>
</Popconfirm>
}
</PermissionCheck>
</> </>
} }
</div>) </div>)

View File

@ -7,10 +7,8 @@ import SearchForm from "@/components/bill/search-form.tsx";
import {BillList} from "@/components/bill/list.tsx"; import {BillList} from "@/components/bill/list.tsx";
import {billList, BillQueryParams, confirmBills} from "@/service/api/bill.ts"; import {billList, BillQueryParams, confirmBills} from "@/service/api/bill.ts";
import {BizError} from "@/service/types.ts"; import {BizError} from "@/service/types.ts";
import useAuth from "@/hooks/useAuth.ts";
const BillReconciliation = () => { const BillReconciliation = () => {
const {user} = useAuth()
const {t} = useTranslation() const {t} = useTranslation()
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({ const [queryParams, setBillQueryParams] = useState<BillQueryParams>({
apply_status: 'UNCHECKED' apply_status: 'UNCHECKED'
@ -110,9 +108,7 @@ const BillReconciliation = () => {
/> />
<BillList <BillList
source={data} type={'reconciliation'} source={data} type={'reconciliation'}
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : ( operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
user && user.permissions?.apply_button ? operation : undefined
)}
beforeTotalAmount={<div>{queryParams.apply_status != 'CHECKED' && ( beforeTotalAmount={<div>{queryParams.apply_status != 'CHECKED' && (
(selectKeys.length == 0) ? <Button theme={'solid'} disabled style={{marginRight: 10}}> (selectKeys.length == 0) ? <Button theme={'solid'} disabled style={{marginRight: 10}}>
{t('bill.confirm_batch')} {t('bill.confirm_batch')}

View File

@ -12,7 +12,7 @@ import {IconExit, IconUser} from "@douyinfe/semi-icons";
import styled from "@emotion/styled"; import styled from "@emotion/styled";
import useConfig from "@/hooks/useConfig.ts"; import useConfig from "@/hooks/useConfig.ts";
import {IconRoles} from "@/components/icons"; import {IconRoles} from "@/components/icons";
// import {setCurrentRole} from "@/contexts/auth"; import {setCurrentRole} from "@/contexts/auth";
const {Header, Content, Sider} = Layout; const {Header, Content, Sider} = Layout;
@ -42,10 +42,15 @@ export const HeaderUserAvatar = () => {
<Avatar color="orange" size="default"><IconUser /></Avatar> <Avatar color="orange" size="default"><IconUser /></Avatar>
<div> <div>
<Typography.Title heading={6}>{user?.username}</Typography.Title> <Typography.Title heading={6}>{user?.username}</Typography.Title>
<div title={user?.department} style={{maxWidth:150,overflow:'hidden',whiteSpace:'nowrap',textOverflow:'ellipsis'}}> <div style={{maxWidth:250,overflow:'hidden',whiteSpace:'nowrap',textOverflow:'ellipsis'}}>
<Typography.Text <Typography.Text
type="quaternary" type="quaternary"
size={'small'}>{user?.department?.toUpperCase() || "N/A"}</Typography.Text> size={'small'}>Department:{user?.department?.toUpperCase() || "N/A"}</Typography.Text>
</div>
<div>
<Typography.Text
type="quaternary"
size={'small'}>Role:{user?.role?.toUpperCase()}</Typography.Text>
</div> </div>
</div> </div>
</Space> </Space>
@ -61,22 +66,36 @@ export const HeaderUserAvatar = () => {
<Avatar color="orange" size="small"><IconUser /></Avatar> <Avatar color="orange" size="small"><IconUser /></Avatar>
</Dropdown>) </Dropdown>)
} }
// const RoleList: UserRole[] = ['root', 'ro', 'fo','staff'] const RoleList: UserRole[] = ['root', 'ro', 'fo','staff']
const RoleSwitcher = ()=>{ const RoleSwitcher = ()=>{
const {user} = useAuth() const {user, updateUser} = useAuth()
// update user role // update user role
// const changeRole = (role:UserRole)=>{ const changeRole = (role:UserRole)=>{
// updateUser({role}).then(()=>{ updateUser({role}).then(()=>{
// setCurrentRole(role) setCurrentRole(role)
// }) })
// } }
return (<> return (<>
<Button theme="borderless"> {user?.origin_role == 'root' && (<Dropdown
<Space style={{transform:'translateY(3px)'}}> clickToHide
<IconRoles size={20} color={'white'} /> render={
<span style={{color:'white'}}>{user?.role?.toUpperCase()}</span> <Dropdown.Menu>
</Space> {RoleList.map((key) => (
</Button> <Dropdown.Item
active={user?.role == key} key={key}
onClick={() => changeRole(key)}
><span>{key.toUpperCase()}</span></Dropdown.Item>
))}
</Dropdown.Menu>
}
>
<Button theme="borderless">
<Space style={{transform:'translateY(3px)'}}>
<IconRoles size={20} color={'white'} />
<span style={{color:'white'}}>{user?.role?.toUpperCase()}</span>
</Space>
</Button>
</Dropdown>) }
</>) </>)
} }
export const CommonHeader: React.FC<CommonHeaderProps> = ({children, title, rightExtra}) => { export const CommonHeader: React.FC<CommonHeaderProps> = ({children, title, rightExtra}) => {

View File

@ -10,25 +10,24 @@ export const AllDashboardMenu = [
key: 'manual', key: 'manual',
icon: <IconQRCode/>, icon: <IconQRCode/>,
path: '/dashboard/manual', path: '/dashboard/manual',
permission: 'manual_payment',
}, },
{ {
key: 'bill', key: 'bill',
icon: <IconQuery/>, icon: <IconQuery/>,
path: '/dashboard/bill', path: '/dashboard/bill',
permission: 'bill_page', role: ['root', 'ro', 'fo']
}, },
{ {
key: 'check', key: 'check',
icon: <IconReconciliation/>, icon: <IconReconciliation/>,
path: '/dashboard/reconciliation', path: '/dashboard/reconciliation',
permission: 'apply_page', role: ['root', 'fo']
}, },
{ {
key: 'permission', key: 'permission',
icon: <IconPermission/>, icon: <IconPermission/>,
path: '/dashboard/permission', path: '/dashboard/permission',
permission: 'permission_edit', role: ['root']
} }
] ]
@ -37,11 +36,10 @@ export function DashboardNavigation() {
const {user} = useAuth(); const {user} = useAuth();
const navItems = useMemo(() => { const navItems = useMemo(() => {
if (!user || !user.permissions) return []; if (!user) return [];
return AllDashboardMenu.filter(it => { return AllDashboardMenu.filter(it => {
if(user.permissions && user.permissions[it.permission]) return true; return !it.role || it.role.includes(user.role)
return false
}); });
}, [user]) }, [user])
return (<div className={'dashboard-menu-container'}> return (<div className={'dashboard-menu-container'}>

View File

@ -63,7 +63,7 @@ export function addBillRecord(bill: CreateBillRecordModel) {
} }
export function uploadBillingRecordFile(file: File, payment_channel: string, check_student = 'true') { export function uploadBillingRecordFile(file: File, payment_channel: string, check_student = 'true') {
return uploadFile('/bills/import', file, {payment_channel, check_student}) return uploadFile('/bill/import', file, {payment_channel, check_student})
} }
export function getAsiaPayData(id: number) { export function getAsiaPayData(id: number) {

View File

@ -1,4 +1,4 @@
import {get, post, put, remove} from "@/service/request.ts"; import {get, post, remove} from "@/service/request.ts";
export function getUserInfo() { export function getUserInfo() {
return get<UserProfile>('/userinfo') return get<UserProfile>('/userinfo')
@ -24,11 +24,11 @@ export function getUserPermissionList(){
return get<UserPermission[]>('/permissions') return get<UserPermission[]>('/permissions')
} }
export function createUserPermission(data:UserPermission){ export function createUserPermission(){
return post<UserPermission>('/permission',data) return get<UserPermission[]>('/permissions')
} }
export function updateUserPermission(data:UserPermission){ export function updateUserPermission(){
return put<UserPermission>(`/permissions/${data.id}`,data) return get<UserPermission[]>('/permissions')
} }
export function removeUserPermission(id:number){ export function removeUserPermission(id:number){
return remove(`/permissions/${id}`) return remove(`/permissions/${id}`)

View File

@ -95,7 +95,7 @@ export function uploadFile<T>(url: string, file: UploadFileModel | File, data: A
}) })
} }
return request<T>(url, 'post', formData, returnOrigin, { return request<T>(url, 'post', data, returnOrigin, {
'Content-Type': 'multipart/form-data' 'Content-Type': 'multipart/form-data'
}) })
// return new Promise<T>((resolve, reject) => { // return new Promise<T>((resolve, reject) => {

27
src/types/auth.d.ts vendored
View File

@ -1,18 +1,5 @@
declare type UserRole = 'root' | 'ro' | 'fo' | 'staff' declare type UserRole = 'root' | 'ro' | 'fo' | 'staff'
declare type UserPermission = {
id: number;
username: string;
role: string;
manual_payment: boolean;
bill_page: boolean;
apply_page: boolean;
complete_button: boolean;
confirm_button: boolean;
apply_button: boolean;
permission_edit: boolean;
}
declare type UserProfile = { declare type UserProfile = {
id: string | number; id: string | number;
token: string; token: string;
@ -27,7 +14,6 @@ declare type UserProfile = {
type: string; type: string;
roles: UserRole[]; roles: UserRole[];
role: UserRole; role: UserRole;
permissions:UserPermission | null;
origin_role?: UserRole; origin_role?: UserRole;
} }
@ -51,4 +37,17 @@ declare type AuthContextType = {
declare type PermissionUserList = { declare type PermissionUserList = {
role_name: string; role_name: string;
username_list: string[]; username_list: string[];
}
declare type UserPermission = {
id: number;
username: string;
role: string;
manual_payment: boolean;
bill_page: boolean;
apply_page: boolean;
complete_button: boolean;
confirm_button: boolean;
apply_button: boolean;
permission_edit: boolean;
} }