Merge branch 'main' of github.com:hainatravel/GHHub

perf/export-docx
YCC 1 year ago
commit 2a8dcabdec

Binary file not shown.

@ -15,8 +15,6 @@
"i18next": "^23.11.5", "i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0", "i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.5.2", "i18next-http-backend": "^2.5.2",
"mobx": "^6.9.0",
"mobx-react": "^7.6.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-i18next": "^14.1.2", "react-i18next": "^14.1.2",

@ -1,19 +1,21 @@
import { Result } from 'antd' import { Result } from 'antd'
import { usingStorage } from '@/hooks/usingStorage'
import useAuthStore from '@/stores/Auth' import useAuthStore from '@/stores/Auth'
export default function RequireAuth({ children, ...props }, ) { export default function RequireAuth({ children, ...props }) {
const isPermitted = useAuthStore((state) => state.isPermitted) const isPermitted = useAuthStore((state) => state.isPermitted)
const { userId } = usingStorage()
if (isPermitted(props.subject)) { if (isPermitted(props.subject)) {
// if (props.subject === '/account/management') { // if (props.subject === '/account/management1') {
return children return children
} else if (props.result) { } else if (props.result) {
return ( return (
<Result <Result
status='403' status='403'
title='403' title='403'
subTitle={'抱歉,你没有权限使用该功能。'} subTitle={`抱歉,你(${userId})没有权限使用该功能。`}
/> />
) )
} }

@ -176,6 +176,22 @@ function getFields(props) {
</Form.Item>, </Form.Item>,
fieldProps?.dates?.col || midCol fieldProps?.dates?.col || midCol
), ),
item(
'username',
3,
<Form.Item name='username' label={t('account:username')} {...fieldProps.username}>
<Input placeholder={t('account:username')} allowClear />
</Form.Item>,
fieldProps?.username?.col || 4
),
item(
'realname',
4,
<Form.Item name='realname' label={t('account:realname')} {...fieldProps.realname}>
<Input placeholder={t('account:realname')} allowClear />
</Form.Item>,
fieldProps?.realname?.col || 4
),
]; ];
baseChildren = baseChildren baseChildren = baseChildren

@ -12,8 +12,22 @@ const __BUILD_VERSION__ = `__BUILD_VERSION__`.replace(/"/g, '')
export const BUILD_VERSION = import.meta.env.PROD ? __BUILD_VERSION__ : import.meta.env.MODE; export const BUILD_VERSION = import.meta.env.PROD ? __BUILD_VERSION__ : import.meta.env.MODE;
// 权限常量定义 // 权限常量定义
// 账号、权限管理
// category: system
export const PERM_ACCOUNT_MANAGEMENT = '/account/management' export const PERM_ACCOUNT_MANAGEMENT = '/account/management'
export const PERM_ACCOUNT_NEW = '/account/new' export const PERM_ACCOUNT_NEW = '/account/new'
export const PERM_ACCOUNT_DISABLE = '/account/disable' export const PERM_ACCOUNT_DISABLE = '/account/disable'
export const PERM_ACCOUNT_RESET_PASSWORD = '/account/reset-password' export const PERM_ACCOUNT_RESET_PASSWORD = '/account/reset-password'
export const PERM_ROLE_NEW = '/account/role/new' export const PERM_ROLE_NEW = '/account/role/new'
// 海外供应商
// category: oversea
export const PERM_OVERSEA = '/oversea/all'
// 国内供应商
// category: domestic
export const PERM_DOMESTIC = '/domestic/all'
// 机票供应商
// category: air-ticket
export const PERM_AIR_TICKET = '/air-ticket/all'

@ -5,8 +5,6 @@ import {
createBrowserRouter, createBrowserRouter,
RouterProvider, RouterProvider,
} from "react-router-dom"; } from "react-router-dom";
import RootStore from "@/stores/Root";
import { StoreContext } from '@/stores/StoreContext';
import "@/assets/global.css"; import "@/assets/global.css";
import App from "@/views/App"; import App from "@/views/App";
import Standlone from "@/views/Standlone"; import Standlone from "@/views/Standlone";
@ -20,6 +18,7 @@ import ReservationDetail from "@/views/reservation/Detail";
import ChangePassword from "@/views/account/ChangePassword"; import ChangePassword from "@/views/account/ChangePassword";
import AccountProfile from "@/views/account/Profile"; import AccountProfile from "@/views/account/Profile";
import AccountManagement from "@/views/account/Management"; import AccountManagement from "@/views/account/Management";
import RoleList from "@/views/account/RoleList";
import FeedbackIndex from "@/views/feedback/Index"; import FeedbackIndex from "@/views/feedback/Index";
import FeedbackDetail from "@/views/feedback/Detail"; import FeedbackDetail from "@/views/feedback/Detail";
import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail"; import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail";
@ -32,8 +31,9 @@ import InvoicePaid from "@/views/invoice/Paid";
import InvoicePaidDetail from "@/views/invoice/PaidDetail"; import InvoicePaidDetail from "@/views/invoice/PaidDetail";
import Airticket from "@/views/airticket/Index"; import Airticket from "@/views/airticket/Index";
import AirticketPlan from "@/views/airticket/Plan"; import AirticketPlan from "@/views/airticket/Plan";
import { ThemeContext } from '@/stores/ThemeContext'
import { PERM_ACCOUNT_MANAGEMENT } from '@/config' import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_OVERSEA, PERM_AIR_TICKET } from '@/config'
import './i18n'; import './i18n';
@ -53,22 +53,23 @@ const router = createBrowserRouter([
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [
{ index: true, element: <Index /> }, { index: true, element: <Index /> },
{ path: "reservation/newest", element: <ReservationNewest />},
{ path: "reservation/:reservationId", element: <ReservationDetail />},
{ path: "account/change-password", element: <ChangePassword />}, { path: "account/change-password", element: <ChangePassword />},
{ path: "account/profile", element: <AccountProfile />}, { path: "account/profile", element: <AccountProfile />},
{ path: "account/management", element: <RequireAuth subject={PERM_ACCOUNT_MANAGEMENT} result={true}><AccountManagement /></RequireAuth>}, { path: "account/management", element: <RequireAuth subject={PERM_ACCOUNT_MANAGEMENT} result={true}><AccountManagement /></RequireAuth>},
{ path: "feedback", element: <FeedbackIndex />}, { path: "account/role-list", element: <RequireAuth subject={PERM_ROLE_NEW} result={true}><RoleList /></RequireAuth>},
{ path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: <FeedbackCustomerDetail />}, { path: "reservation/newest", element: <RequireAuth subject={PERM_OVERSEA} result={true}><ReservationNewest /></RequireAuth>},
{ path: "feedback/:GRI_SN/:RefNo", element: <FeedbackDetail />}, { path: "reservation/:reservationId", element: <RequireAuth subject={PERM_OVERSEA} result={true}><ReservationDetail /></RequireAuth>},
{ path: "report", element: <ReportIndex />}, { path: "feedback", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackIndex /></RequireAuth>},
{ path: "notice", element: <NoticeIndex />}, { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackCustomerDetail /></RequireAuth>},
{ path: "notice/:CCP_BLID", element: <NoticeDetail />}, { path: "feedback/:GRI_SN/:RefNo", element: <RequireAuth subject={PERM_OVERSEA} result={true}><FeedbackDetail /></RequireAuth>},
{ path: "invoice",element:<InvoiceIndex />}, { path: "report", element: <RequireAuth subject={PERM_OVERSEA} result={true}><ReportIndex /></RequireAuth>},
{ path: "invoice/detail/:GMDSN/:GSN",element:<InvoiceDetail />}, { path: "notice", element: <RequireAuth subject={PERM_OVERSEA} result={true}><NoticeIndex /></RequireAuth>},
{ path: "invoice/paid",element:<InvoicePaid />}, { path: "notice/:CCP_BLID", element: <RequireAuth subject={PERM_OVERSEA} result={true}><NoticeDetail /></RequireAuth>},
{ path: "invoice/paid/detail/:flid",element:<InvoicePaidDetail />}, { path: "invoice",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceIndex /></RequireAuth>},
{ path: "airticket",element:<Airticket />}, { path: "invoice/detail/:GMDSN/:GSN",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoiceDetail /></RequireAuth>},
{ path: "invoice/paid",element:<RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaid /></RequireAuth>},
{ path: "invoice/paid/detail/:flid", element: <RequireAuth subject={PERM_OVERSEA} result={true}><InvoicePaidDetail /></RequireAuth>},
{ path: "airticket",element: <RequireAuth subject={PERM_AIR_TICKET} result={true}><Airticket /></RequireAuth>},
{ path: "airticket/plan/:coli_sn",element:<AirticketPlan />}, { path: "airticket/plan/:coli_sn",element:<AirticketPlan />},
] ]
}, },
@ -81,15 +82,14 @@ const router = createBrowserRouter([
} }
]); ]);
const rootStore = new RootStore();
ReactDOM.createRoot(document.getElementById("root")).render( ReactDOM.createRoot(document.getElementById("root")).render(
//<React.StrictMode> //<React.StrictMode>
<StoreContext.Provider value={rootStore}> <ThemeContext.Provider value={{ colorPrimary: '#00b96b', borderRadius: 4 }}>
<RouterProvider <RouterProvider
router={router} router={router}
fallbackElement={() => <div>Loading...</div>} fallbackElement={() => <div>Loading...</div>}
/> />
</StoreContext.Provider> </ThemeContext.Provider>
//</React.StrictMode> //</React.StrictMode>
); );

@ -0,0 +1,124 @@
import { create } from 'zustand'
import { fetchJSON, postForm } from '@/utils/request'
import { HT_HOST } from "@/config"
import { usingStorage } from '@/hooks/usingStorage'
export const postAccountStatus = async (formData) => {
const { errcode, result } = await postForm(
`${HT_HOST}/service-CooperateSOA/set_account_status`, formData)
return errcode !== 0 ? {} : result
}
export const fetchAccountList = async (params) => {
const { errcode, result } = await fetchJSON(
`${HT_HOST}/service-CooperateSOA/search_account`, params)
return errcode !== 0 ? {} : result
}
export const postAccountForm = async (formData) => {
const { errcode, result } = await postForm(
`${HT_HOST}/service-CooperateSOA/new_or_update_account`, formData)
return errcode !== 0 ? {} : result
}
export const postRoleForm = async (formData) => {
const { errcode, result } = await postForm(
`${HT_HOST}/service-CooperateSOA/new_or_update_role`, formData)
return errcode !== 0 ? {} : result
}
export const fetchRoleList = async () => {
const { errcode, result } = await fetchJSON(
`${HT_HOST}/service-CooperateSOA/get_role_list`)
return errcode !== 0 ? {} : result
}
const useAccountStore = create((set, get) => ({
accountList: [],
selectedAccount: null,
selectAccount: (account) => {
set(() => ({
selectedAccount: account
}))
},
disableAccount: async (accountId) => {
const formData = new FormData()
formData.append('wu_id', accountId)
formData.append('account_status', 'enable')
const result = await postAccountStatus(formData)
console.info(result)
},
saveOrUpdateRole: async (formValues) => {
const formData = new FormData()
formData.append('role_id', formValues.role_id)
formData.append('role_name', formValues.role_name)
formData.append('res_ids', '2,3')
return postRoleForm(formData)
},
saveOrUpdateAccount: async (formValues) => {
const { selectedAccount } = get()
const { userId } = usingStorage()
const formData = new FormData()
formData.append('wu_id', selectedAccount.userId)
formData.append('lmi_sn', selectedAccount.lmi_sn)
formData.append('lmi2_sn', selectedAccount.lmi2_sn)
formData.append('user_name', formValues.username)
formData.append('real_name', formValues.realname)
formData.append('email', formValues.email)
formData.append('travel_agency_id', formValues.travelAgencyId)
formData.append('roles', formValues.roleId)
formData.append('opi_sn', userId)
return postAccountForm(formData)
},
searchAccountByCriteria: async (formValues) => {
const searchParams = {
username: formValues.username,
realname: formValues.realname,
lgc: 2
}
const resultArray = await fetchAccountList(searchParams)
const mapAccoutList = resultArray.map((r) => {
return {
userId: r.wu_id,
lmi_sn: r.lmi_sn,
lmi2_sn: r.lmi2_sn,
username: r.user_name,
realname: r.real_name,
email: r.email,
lastLogin: r.wu_lastlogindate,
travelAgency: r.travel_agency_name,
travelAgencyId: r.travel_agency_id,
roleId: r.roles,
role: r.roles_name,
}
})
set(() => ({
accountList: mapAccoutList
}))
},
}))
export default useAccountStore

@ -55,13 +55,13 @@ const useAuthStore = create((set, get) => ({
// 以下是权限列表从数据库读取后使用的方法 // 以下是权限列表从数据库读取后使用的方法
// return this.permissionList.some((value, key, arry) => { // return this.permissionList.some((value, key, arry) => {
// if (value.indexOf(WILDCARD_TOKEN) > -1) { // if (value.indexOf(WILDCARD_TOKEN) > -1) {
// return true; // return true
// } // }
// if (value === perm) { // if (value === perm) {
// return true; // return true
// } // }
// return false; // return false
// }); // })
}, },
@ -154,19 +154,4 @@ const useAuthStore = create((set, get) => ({
}, },
})) }))
export default useAuthStore export default useAuthStore
export class Auth {
// TODO: 等待所有获取用户信息修改完后删除
login = {
token: '',
userId: 0, // LMI_SN
username: '0',
travelAgencyId: 0, // VEI_SN
travelAgencyName: '',
telephone: '',
emailAddress: '',
cityId: 0,
timeout: false
}
}

@ -1,39 +0,0 @@
import { makeAutoObservable } from "mobx";
import { Auth } from "./Auth";
class Root {
constructor() {
this.authStore = new Auth(this);
makeAutoObservable(this);
}
clearSession() {
if (window.sessionStorage) {
const sessionStorage = window.sessionStorage;
sessionStorage.clear();
} else {
console.error('browser not support sessionStorage!');
}
}
getSession(key) {
if (window.sessionStorage) {
const sessionStorage = window.sessionStorage;
return sessionStorage.getItem(key);
} else {
console.error('browser not support sessionStorage!');
return null;
}
}
putSession(key, value) {
if (window.sessionStorage) {
const sessionStorage = window.sessionStorage;
return sessionStorage.setItem(key, value);
} else {
console.error('browser not support sessionStorage!');
}
}
}
export default Root;

@ -1,7 +0,0 @@
import { createContext, useContext } from "react";
export const StoreContext = createContext();
export function useStore() {
return useContext(StoreContext);
}

@ -0,0 +1,7 @@
import { createContext, useContext } from 'react'
export const ThemeContext = createContext({})
export function useThemeContext() {
return useContext(ThemeContext)
}

@ -106,6 +106,7 @@ export function postForm(url, data) {
} }
}).then(checkStatus) }).then(checkStatus)
.then(response => response.json()) .then(response => response.json())
.then(checkBizCode)
.catch(error => { .catch(error => {
throw error throw error
}) })

@ -149,8 +149,9 @@ function App() {
{ label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' }, { label: <Link to='/account/change-password'>{t('ChangePassword')}</Link>, key: '0' },
{ label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' }, { label: <Link to='/account/profile'>{t('Profile')}</Link>, key: '1' },
{ label: <Link to='/account/management'>{t('account:management.tile')}</Link>, key: '3' }, { label: <Link to='/account/management'>{t('account:management.tile')}</Link>, key: '3' },
{ label: <Link to='/account/role-list'>{t('account:management.roleList')}</Link>, key: '4' },
{ type: 'divider' }, { type: 'divider' },
{ label: <Link to='/logout'>{t('Logout')}</Link>, key: '4' }, { label: <Link to='/logout'>{t('Logout')}</Link>, key: '99' },
], ],
{ type: 'divider' }, { type: 'divider' },
{ label: <>v{BUILD_VERSION}</>, key: 'BUILD_VERSION' }, { label: <>v{BUILD_VERSION}</>, key: 'BUILD_VERSION' },

@ -4,7 +4,8 @@ import { ExclamationCircleFilled } from '@ant-design/icons'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useFormStore from '@/stores/Form' import useFormStore from '@/stores/Form'
import useAuthStore from '@/stores/Auth' import useAuthStore from '@/stores/Auth'
import useReservationStore from '@/stores/Reservation' import useAccountStore from '@/stores/Account'
import { fetchRoleList } from '@/stores/Account'
import SearchForm from '@/components/SearchForm' import SearchForm from '@/components/SearchForm'
import RequireAuth from '@/components/RequireAuth' import RequireAuth from '@/components/RequireAuth'
import { PERM_ROLE_NEW } from '@/config' import { PERM_ROLE_NEW } from '@/config'
@ -12,6 +13,18 @@ import { PERM_ROLE_NEW } from '@/config'
const { Title } = Typography const { Title } = Typography
const permissionData = [ const permissionData = [
{
title: '海外供应商',
value: 'oversea-0',
key: 'oversea-0',
children: [
{
title: '所有海外功能',
value: 'oversea-0-0',
key: 'oversea-0-0',
},
],
},
{ {
title: '机票管理', title: '机票管理',
value: '0-0', value: '0-0',
@ -29,6 +42,11 @@ const permissionData = [
value: '0-1', value: '0-1',
key: '0-1', key: '0-1',
children: [ children: [
{
title: '搜索供应商产品',
value: 'B-1-0',
key: 'B-1-0',
},
{ {
title: '录入产品价格', title: '录入产品价格',
value: '0-1-0', value: '0-1-0',
@ -52,19 +70,29 @@ const permissionData = [
key: '2-1', key: '2-1',
children: [ children: [
{ {
title: '重置账号密码', title: '搜索账号',
value: '2-1-0', value: '2-1-01',
key: '2-1-0', key: '2-1-01',
},
{
title: '新增账号',
value: '2-1-11',
key: '2-1-11',
}, },
{ {
title: '禁用账号', title: '禁用账号',
value: '2-1-1', value: '2-1-21',
key: '2-1-1', key: '2-1-21',
},
{
title: '重置账号密码',
value: '2-1-31',
key: '2-1-31',
}, },
{ {
title: '分配账号角色', title: '新增角色',
value: '2-1-2', value: '2-1-41',
key: '2-1-2', key: '2-1-41',
}, },
], ],
}, },
@ -83,6 +111,10 @@ function Management() {
title: t('account:realname'), title: t('account:realname'),
dataIndex: 'realname', dataIndex: 'realname',
}, },
{
title: t('account:travelAgency'),
dataIndex: 'travelAgency',
},
{ {
title: t('account:email'), title: t('account:email'),
dataIndex: 'email', dataIndex: 'email',
@ -103,9 +135,9 @@ function Management() {
}, },
] ]
function accountRender(text) { function accountRender(text, account) {
return ( return (
<Button type='link' onClick={() => setAccountModalOpen(true)}>{text}</Button> <Button type='link' onClick={() => onAccountSeleted(account)}>{text}</Button>
) )
} }
@ -115,11 +147,11 @@ function Management() {
) )
} }
function actionRender() { function actionRender(text, account) {
return ( return (
<Space key='actionRenderSpace' size='middle'> <Space key='actionRenderSpace' size='middle'>
<Button type='link' key='disable' onClick={() => showDisableConfirm()}>{t('account:action.disable')}</Button> <Button type='link' key='disable' onClick={() => showDisableConfirm(account)}>{t('account:action.disable')}</Button>
<Button type='link' key='resetPassword' onClick={() => showResetPasswordConfirm()}>{t('account:action.resetPassword')}</Button> <Button type='link' key='resetPassword' onClick={() => showResetPasswordConfirm(account)}>{t('account:action.resetPassword')}</Button>
</Space> </Space>
) )
} }
@ -133,112 +165,71 @@ function Management() {
const [isAccountModalOpen, setAccountModalOpen] = useState(false) const [isAccountModalOpen, setAccountModalOpen] = useState(false)
const [isRoleModalOpen, setRoleModalOpen] = useState(false) const [isRoleModalOpen, setRoleModalOpen] = useState(false)
const [dataLoading, setDataLoading] = useState(false) const [dataLoading, setDataLoading] = useState(false)
const [accountList, setaccountList] = useState([ const [roleAllList, setRoleAllList] = useState([])
{
key: 1,
username: 'bjyiran',
realname: '怡小芳',
email: 'xiaofang@yiran.com',
role: '国内供应商',
lastLogin: '2024-06-12 13:53'
},
{
key: 2,
username: 'int-robin',
realname: 'Robin',
email: 'robin@int.com',
role: '海外供应商',
lastLogin: '2024-06-12 13:53'
},
{
key: 3,
username: 'betty-wu',
realname: '吴雪',
email: 'betty@hainatravel.com',
role: '客服组',
lastLogin: '2024-06-12 13:53'
},
{
key: 4,
username: 'lancy',
realname: '吴金倩',
email: 'lancy@hainatravel.com',
role: '产品组',
lastLogin: '2024-06-12 13:53'
},
{
key: 5,
username: 'LYJ',
realname: '廖一军',
email: 'lyj@hainatravel.com',
role: 'Web 开发组,海外测试供应商',
lastLogin: '2024-06-12 13:53'
}
])
const formValuesToSub = useFormStore((state) => state.formValuesToSub)
const isPermitted = useAuthStore((state) => state.isPermitted)
const [editAccountForm, editRoleForm] = Form.useForm() const [accountForm] = Form.useForm()
const [fetchReservationList] = const [searchAccountByCriteria, accountList, disableAccount, selectedAccount, saveOrUpdateAccount, selectAccount] =
useReservationStore((state) => useAccountStore((state) =>
[state.fetchAllGuideList, state.fetchReservationList, state.reservationList, state.reservationPage, state.cityList, state.selectReservation, state.getCityListByReservationId]) [state.searchAccountByCriteria, state.accountList, state.disableAccount, state.selectedAccount, state.saveOrUpdateAccount, state.selectAccount])
const { notification, modal } = App.useApp() const { notification, modal } = App.useApp()
const handleAccountOk = () => { const onAccountSeleted = async (account) => {
accountForm.setFieldsValue(account)
selectAccount(account)
console.info(account)
const roleList = await fetchRoleList()
setRoleAllList(roleList.map(r => {
return {
value: r.role_id,
label: r.role_name,
disabled: r.role_id === 1
}
}))
setAccountModalOpen(true)
} }
const handleAccountCancel = () => { const onAccountFinish = (values) => {
setAccountModalOpen(false)
}
const handleRoleOk = () => {
}
const handleRoleCancel = () => {
setRoleModalOpen(false)
}
const onFinish = (values) => {
console.log(values) console.log(values)
saveOrUpdateAccount(values)
.catch(ex => {
console.info(ex.message)
notification.error({
message: 'Notification',
description: ex.message,
placement: 'top',
duration: 4,
})
})
} }
const onFinishFailed = (error) => { const onAccountFailed = (error) => {
console.log('Failed:', error) console.log('Failed:', error)
// form.resetFields() // form.resetFields()
} }
// const showDisableConfirm = (account) => {
const onSearchClick = (current = 1, status = null) => {
}
const showDisableConfirm = () => {
modal.confirm({ modal.confirm({
title: 'Do you want to disable this account?', title: 'Do you want to disable this account?',
icon: <ExclamationCircleFilled />, icon: <ExclamationCircleFilled />,
content: 'Username: Ivy, Realname: 怡小芳', content: `Username: ${account.username}, Realname: ${account.realname}`,
onOk() { onOk() {
console.log('OK') disableAccount(account.userId)
}, },
onCancel() { onCancel() {
console.log('Cancel')
}, },
}) })
} }
const showResetPasswordConfirm = () => { const showResetPasswordConfirm = (account) => {
modal.confirm({ modal.confirm({
title: 'Do you want to reset password?', title: 'Do you want to reset password?',
icon: <ExclamationCircleFilled />, icon: <ExclamationCircleFilled />,
content: 'Username: Ivy, Realname: 怡小芳', content: `Username: ${account.username}, Realname: ${account.realname}`,
onOk() { onOk() {
console.log('OK') console.log('ResetPassword')
}, },
onCancel() { onCancel() {
console.log('Cancel')
}, },
}) })
} }
@ -247,137 +238,106 @@ function Management() {
<> <>
<Modal <Modal
centered centered
open={isAccountModalOpen} onOk={handleAccountOk} onCancel={handleAccountCancel} okButtonProps={{
> autoFocus: true,
<Form htmlType: 'submit',
name='basic' }}
form={editAccountForm} title={t('account:management.newAccount')}
open={isAccountModalOpen} onOk={() => setAccountModalOpen(false)} onCancel={() => setAccountModalOpen(false)}
destroyOnClose={true}
clearOnDestroy={true}
modalRender={(dom) => (
<Form
name='AccountForm'
form={accountForm}
layout='vertical' layout='vertical'
size='large' size='large'
style={{ style={{
maxWidth: 600, maxWidth: 600,
}} }}
onFinish={onFinish} onFinish={onAccountFinish}
onFinishFailed={onFinishFailed} onFinishFailed={onAccountFailed}
autoComplete='off' autoComplete='off'
> >
<Form.Item><Title level={2}>{t('account:management.newAccount')}</Title></Form.Item> {dom}
<Form.Item </Form>
label={t('account:management.username')} )}
name='username'
rules={[
{
required: true,
message: t('account:Validation.username'),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t('account:management.realname')}
name='realname'
rules={[
{
required: true,
message: t('account:Validation.realname'),
},
]}
>
<Input />
</Form.Item>
<Form.Item
label={t('account:management.email')}
name='email'
rules={[
{
required: true,
message: t('account:Validation.email'),
},
]}
>
<Input />
</Form.Item>
<Form.Item label={t('account:management.role')}>
<Select>
<Select.Option value='1'>客服组</Select.Option>
<Select.Option value='2'>产品组</Select.Option>
<Select.Option value='3'>国内供应商</Select.Option>
<Select.Option value='4'>海外供应商</Select.Option>
<Select.Option value='5'>技术研发部</Select.Option>
<Select.Option value='0' disabled>系统管理员</Select.Option>
</Select>
</Form.Item>
</Form>
</Modal>
{/* Role Edit */}
<Modal
centered
open={isRoleModalOpen} onOk={handleRoleOk} onCancel={handleRoleCancel}
> >
<Form <Form.Item
name='basic' label={t('account:management.username')}
form={editRoleForm} name='username'
layout='vertical' rules={[
size='large' {
style={{ required: true,
maxWidth: 600, message: t('account:Validation.username'),
}} },
onFinish={onFinish} ]}
onFinishFailed={onFinishFailed}
autoComplete='off'
> >
<Form.Item><Title level={2}>{t('account:management.newRole')}</Title></Form.Item> <Input />
<Form.Item </Form.Item>
label={t('account:management.roleName')} <Form.Item
name='roleName' label={t('account:management.realname')}
rules={[ name='realname'
{ rules={[
required: true, {
message: t('account:Validation.roleName'), required: true,
}, message: t('account:Validation.realname'),
]} },
> ]}
<Input /> >
</Form.Item> <Input />
<Form.Item label={t('account:management.permission')}> </Form.Item>
<TreeSelect treeData={permissionData} value={permissionValue} <Form.Item
dropdownStyle={{ label={t('account:management.email')}
maxHeight: 500, name='email'
overflow: 'auto', rules={[
}} {
placement='bottomLeft' required: true,
showSearch message: t('account:Validation.email'),
allowClear },
multiple ]}
treeDefaultExpandAll >
treeLine={true} <Input />
onChange={onPermissionChange} </Form.Item>
treeCheckable={true} <Form.Item
showCheckedStrategy={TreeSelect.SHOW_CHILD} label={t('account:management.travelAgency')}
placeholder={'Please select'} name='travelAgencyId'
style={{ rules={[
width: '100%', {
}} /> required: true,
</Form.Item> message: t('account:Validation.travelAgency'),
</Form> },
]}
>
<Select options={[{ value: 33032, label: 'test海外地接B' }]}></Select>
</Form.Item>
<Form.Item
label={t('account:management.role')}
name='roleId'
rules={[
{
required: true,
message: t('account:Validation.role'),
},
]}
>
<Select options={roleAllList}>
</Select>
</Form.Item>
</Modal> </Modal>
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
<Title level={3}>{t('account:management.tile')}</Title> <Title level={3}>{t('account:management.tile')}</Title>
<SearchForm <SearchForm
// initialValue={
// {
// }
// }
fieldsConfig={{ fieldsConfig={{
shows: ['username', 'referenceNo', 'dates'], shows: ['username', 'realname', 'dates'],
fieldProps: { fieldProps: {
dates: { label: t('group:ArrivalDate') }, dates: { label: t('group:ArrivalDate') },
}, },
}} }}
onSubmit={(err, formVal, filedsVal) => { onSubmit={(err, formValues, filedsVal) => {
console.info(formValues)
setDataLoading(true) setDataLoading(true)
fetchReservationList(formVal) searchAccountByCriteria(formValues)
.catch(ex => { .catch(ex => {
notification.error({ notification.error({
message: 'Notification', message: 'Notification',
@ -395,9 +355,6 @@ function Management() {
<Col span={24}> <Col span={24}>
<Space> <Space>
<Button onClick={() => setAccountModalOpen(true)}>{t('account:management.newAccount')}</Button> <Button onClick={() => setAccountModalOpen(true)}>{t('account:management.newAccount')}</Button>
<RequireAuth subject={PERM_ROLE_NEW}>
<Button onClick={() => setRoleModalOpen(true)}>{t('account:management.newRole')}</Button>
</RequireAuth>
</Space> </Space>
</Col> </Col>
</Row> </Row>
@ -406,6 +363,7 @@ function Management() {
<Table <Table
bordered bordered
loading={dataLoading} loading={dataLoading}
rowKey='username'
pagination={{ pagination={{
showQuickJumper: true, showQuickJumper: true,
showLessItems: true, showLessItems: true,

@ -0,0 +1,286 @@
import { useState, useEffect } from 'react'
import { Row, Col, Space, Button, Table, Select, TreeSelect, Typography, Modal, App, Form, Input } from 'antd'
import { ExclamationCircleFilled } from '@ant-design/icons'
import { useTranslation } from 'react-i18next'
import useFormStore from '@/stores/Form'
import useAuthStore from '@/stores/Auth'
import useAccountStore from '@/stores/Account'
import { fetchRoleList } from '@/stores/Account'
import SearchForm from '@/components/SearchForm'
import RequireAuth from '@/components/RequireAuth'
import { PERM_ROLE_NEW } from '@/config'
const { Title } = Typography
const permissionData = [
{
title: '海外供应商',
value: 'oversea-0',
key: 'oversea-0',
children: [
{
title: '所有海外功能',
value: 'oversea-0-0',
key: 'oversea-0-0',
},
],
},
{
title: '机票管理',
value: '0-0',
key: '0-0',
children: [
{
title: '录入机票价格',
value: '0-0-0',
key: '0-0-0',
},
],
},
{
title: '产品管理',
value: '0-1',
key: '0-1',
children: [
{
title: '搜索供应商产品',
value: 'B-1-0',
key: 'B-1-0',
},
{
title: '录入产品价格',
value: '0-1-0',
key: '0-1-0',
},
{
title: '新增产品描述',
value: '0-1-1',
key: '0-1-1',
},
{
title: '复制供应商产品信息',
value: '0-1-2',
key: '0-1-2',
},
],
},
{
title: '账号管理',
value: '2-1',
key: '2-1',
children: [
{
title: '搜索账号',
value: '2-1-01',
key: '2-1-01',
},
{
title: '新增账号',
value: '2-1-11',
key: '2-1-11',
},
{
title: '禁用账号',
value: '2-1-21',
key: '2-1-21',
},
{
title: '重置账号密码',
value: '2-1-31',
key: '2-1-31',
},
{
title: '新增角色',
value: '2-1-41',
key: '2-1-41',
},
],
},
]
function RoleList() {
const { t } = useTranslation()
const roleListColumns = [
{
title: t('account:rolename'),
dataIndex: 'role_name',
render: roleRender
},
{
title: t('account:createdOn'),
dataIndex: 'created_on',
},
{
title: t('account:action'),
dataIndex: 'account:action',
render: actionRender
},
]
function roleRender(text, role) {
return (
<Button type='link' onClick={() => onRoleSeleted(role)}>{text}</Button>
)
}
function actionRender(text, account) {
return (
<Space key='actionRenderSpace' size='middle'>
<Button type='link' key='disable' onClick={() => showDisableConfirm(account)}>{t('account:action.disable')}</Button>
<Button type='link' key='resetPassword' onClick={() => showResetPasswordConfirm(account)}>{t('account:action.resetPassword')}</Button>
</Space>
)
}
const onPermissionChange = (newValue) => {
console.log('onChange ', newValue)
setPermissionValue(newValue)
}
useEffect (() => {
fetchRoleList()
.then(r => {
setRoleAllList(r)
})
}, [])
const [permissionValue, setPermissionValue] = useState(['0-0-0'])
const [isRoleModalOpen, setRoleModalOpen] = useState(false)
const [dataLoading, setDataLoading] = useState(false)
const [roleAllList, setRoleAllList] = useState([])
const [roleForm] = Form.useForm()
const [saveOrUpdateRole] =
useAccountStore((state) =>
[state.saveOrUpdateRole])
const { notification, modal } = App.useApp()
const onRoleSeleted = async (role) => {
roleForm.setFieldsValue(role)
// selectAccount(account)
// console.info(account)
setRoleModalOpen(true)
}
const onRoleFinish = (values) => {
console.log(values)
saveOrUpdateRole(values)
.catch(ex => {
console.info(ex.message)
notification.error({
message: 'Notification',
description: ex.message,
placement: 'top',
duration: 4,
})
})
}
const onRoleFailed = (error) => {
console.log('Failed:', error)
// form.resetFields()
}
return (
<>
<Modal
centered
okButtonProps={{
autoFocus: true,
htmlType: 'submit',
}}
title={t('account:management.newRole')}
open={isRoleModalOpen} onOk={() => setRoleModalOpen(false)} onCancel={() => setRoleModalOpen(false)}
destroyOnClose={true}
clearOnDestroy={true}
modalRender={(dom) => (
<Form
name='RoleForm'
form={roleForm}
layout='vertical'
size='large'
style={{
maxWidth: 600,
}}
onFinish={onRoleFinish}
onFinishFailed={onRoleFailed}
autoComplete='off'
>
{dom}
</Form>
)}
>
<Form.Item
name='role_id'
>
<Input styles={{display: 'none'}} />
</Form.Item>
<Form.Item
label={t('account:management.roleName')}
name='role_name'
rules={[
{
required: true,
message: t('account:Validation.roleName'),
},
]}
>
<Input />
</Form.Item>
<Form.Item label={t('account:management.permission')}>
<TreeSelect treeData={permissionData} value={permissionValue}
dropdownStyle={{
maxHeight: 600,
overflow: 'auto',
}}
placement='bottomLeft'
showSearch
allowClear
multiple
treeDefaultExpandAll
treeLine={true}
onChange={onPermissionChange}
treeCheckable={true}
showCheckedStrategy={TreeSelect.SHOW_CHILD}
placeholder={'Please select'}
style={{
width: '100%',
}} />
</Form.Item>
</Modal>
<Space direction='vertical' style={{ width: '100%' }}>
<Title level={3}>{t('account:management.roleList')}</Title>
<Row>
<Col span={24}>
<Space>
<RequireAuth subject={PERM_ROLE_NEW}>
<Button onClick={() => setRoleModalOpen(true)}>{t('account:management.newRole')}</Button>
</RequireAuth>
</Space>
</Col>
</Row>
<Row>
<Col span={24}>
<Table
bordered
loading={dataLoading}
rowKey='role_id'
pagination={{
showQuickJumper: true,
showLessItems: true,
showSizeChanger: true,
showTotal: (total) => { return t('Total') + `${total}` }
}}
onChange={(pagination) => { onSearchClick(pagination.current) }}
columns={roleListColumns} dataSource={roleAllList}
/>
</Col>
</Row>
</Space>
</>
)
}
export default RoleList
Loading…
Cancel
Save