diff --git a/doc/价格管理平台.bmpr b/doc/价格管理平台.bmpr index 2e3bd02..e1065f7 100644 Binary files a/doc/价格管理平台.bmpr and b/doc/价格管理平台.bmpr differ diff --git a/package.json b/package.json index 7b26815..dd39be7 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,6 @@ "i18next": "^23.11.5", "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^2.5.2", - "mobx": "^6.9.0", - "mobx-react": "^7.6.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^14.1.2", diff --git a/src/components/RequireAuth.jsx b/src/components/RequireAuth.jsx index d8feee7..cabef0b 100644 --- a/src/components/RequireAuth.jsx +++ b/src/components/RequireAuth.jsx @@ -1,19 +1,21 @@ import { Result } from 'antd' +import { usingStorage } from '@/hooks/usingStorage' import useAuthStore from '@/stores/Auth' -export default function RequireAuth({ children, ...props }, ) { +export default function RequireAuth({ children, ...props }) { const isPermitted = useAuthStore((state) => state.isPermitted) + const { userId } = usingStorage() if (isPermitted(props.subject)) { - // if (props.subject === '/account/management') { + // if (props.subject === '/account/management1') { return children } else if (props.result) { return ( ) } diff --git a/src/components/SearchForm.jsx b/src/components/SearchForm.jsx index 0e33c82..46021f9 100644 --- a/src/components/SearchForm.jsx +++ b/src/components/SearchForm.jsx @@ -176,6 +176,22 @@ function getFields(props) { , fieldProps?.dates?.col || midCol ), + item( + 'username', + 3, + + + , + fieldProps?.username?.col || 4 + ), + item( + 'realname', + 4, + + + , + fieldProps?.realname?.col || 4 + ), ]; baseChildren = baseChildren diff --git a/src/config.js b/src/config.js index 24fbdff..fc69f82 100644 --- a/src/config.js +++ b/src/config.js @@ -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; // 权限常量定义 +// 账号、权限管理 +// category: system export const PERM_ACCOUNT_MANAGEMENT = '/account/management' export const PERM_ACCOUNT_NEW = '/account/new' export const PERM_ACCOUNT_DISABLE = '/account/disable' export const PERM_ACCOUNT_RESET_PASSWORD = '/account/reset-password' 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' diff --git a/src/main.jsx b/src/main.jsx index 8c1c1bd..9114460 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -5,8 +5,6 @@ import { createBrowserRouter, RouterProvider, } from "react-router-dom"; -import RootStore from "@/stores/Root"; -import { StoreContext } from '@/stores/StoreContext'; import "@/assets/global.css"; import App from "@/views/App"; import Standlone from "@/views/Standlone"; @@ -20,6 +18,7 @@ import ReservationDetail from "@/views/reservation/Detail"; import ChangePassword from "@/views/account/ChangePassword"; import AccountProfile from "@/views/account/Profile"; import AccountManagement from "@/views/account/Management"; +import RoleList from "@/views/account/RoleList"; import FeedbackIndex from "@/views/feedback/Index"; import FeedbackDetail from "@/views/feedback/Detail"; import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail"; @@ -32,8 +31,9 @@ import InvoicePaid from "@/views/invoice/Paid"; import InvoicePaidDetail from "@/views/invoice/PaidDetail"; import Airticket from "@/views/airticket/Index"; 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'; @@ -53,22 +53,23 @@ const router = createBrowserRouter([ errorElement: , children: [ { index: true, element: }, - { path: "reservation/newest", element: }, - { path: "reservation/:reservationId", element: }, { path: "account/change-password", element: }, { path: "account/profile", element: }, { path: "account/management", element: }, - { path: "feedback", element: }, - { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: }, - { path: "feedback/:GRI_SN/:RefNo", element: }, - { path: "report", element: }, - { path: "notice", element: }, - { path: "notice/:CCP_BLID", element: }, - { path: "invoice",element:}, - { path: "invoice/detail/:GMDSN/:GSN",element:}, - { path: "invoice/paid",element:}, - { path: "invoice/paid/detail/:flid",element:}, - { path: "airticket",element:}, + { path: "account/role-list", element: }, + { path: "reservation/newest", element: }, + { path: "reservation/:reservationId", element: }, + { path: "feedback", element: }, + { path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: }, + { path: "feedback/:GRI_SN/:RefNo", element: }, + { path: "report", element: }, + { path: "notice", element: }, + { path: "notice/:CCP_BLID", element: }, + { path: "invoice",element:}, + { path: "invoice/detail/:GMDSN/:GSN",element:}, + { path: "invoice/paid",element:}, + { path: "invoice/paid/detail/:flid", element: }, + { path: "airticket",element: }, { path: "airticket/plan/:coli_sn",element:}, ] }, @@ -81,15 +82,14 @@ const router = createBrowserRouter([ } ]); -const rootStore = new RootStore(); ReactDOM.createRoot(document.getElementById("root")).render( // - -
Loading...
} - /> -
+ +
Loading...
} + /> +
//
); diff --git a/src/stores/Account.js b/src/stores/Account.js new file mode 100644 index 0000000..a2391be --- /dev/null +++ b/src/stores/Account.js @@ -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 \ No newline at end of file diff --git a/src/stores/Auth.js b/src/stores/Auth.js index f7f31f3..fe0900e 100644 --- a/src/stores/Auth.js +++ b/src/stores/Auth.js @@ -55,13 +55,13 @@ const useAuthStore = create((set, get) => ({ // 以下是权限列表从数据库读取后使用的方法 // return this.permissionList.some((value, key, arry) => { // if (value.indexOf(WILDCARD_TOKEN) > -1) { - // return true; + // return true // } // if (value === perm) { - // return true; + // return true // } - // return false; - // }); + // return false + // }) }, @@ -154,19 +154,4 @@ const useAuthStore = create((set, get) => ({ }, })) -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 - } -} +export default useAuthStore \ No newline at end of file diff --git a/src/stores/Root.js b/src/stores/Root.js deleted file mode 100644 index a24bd54..0000000 --- a/src/stores/Root.js +++ /dev/null @@ -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; diff --git a/src/stores/StoreContext.js b/src/stores/StoreContext.js deleted file mode 100644 index aca4a62..0000000 --- a/src/stores/StoreContext.js +++ /dev/null @@ -1,7 +0,0 @@ -import { createContext, useContext } from "react"; - -export const StoreContext = createContext(); - -export function useStore() { - return useContext(StoreContext); -} \ No newline at end of file diff --git a/src/stores/ThemeContext.js b/src/stores/ThemeContext.js new file mode 100644 index 0000000..f4f7aa7 --- /dev/null +++ b/src/stores/ThemeContext.js @@ -0,0 +1,7 @@ +import { createContext, useContext } from 'react' + +export const ThemeContext = createContext({}) + +export function useThemeContext() { + return useContext(ThemeContext) +} \ No newline at end of file diff --git a/src/utils/request.js b/src/utils/request.js index 68d80a6..ac97803 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -106,6 +106,7 @@ export function postForm(url, data) { } }).then(checkStatus) .then(response => response.json()) + .then(checkBizCode) .catch(error => { throw error }) diff --git a/src/views/App.jsx b/src/views/App.jsx index dd2dec6..779993c 100644 --- a/src/views/App.jsx +++ b/src/views/App.jsx @@ -149,8 +149,9 @@ function App() { { label: {t('ChangePassword')}, key: '0' }, { label: {t('Profile')}, key: '1' }, { label: {t('account:management.tile')}, key: '3' }, + { label: {t('account:management.roleList')}, key: '4' }, { type: 'divider' }, - { label: {t('Logout')}, key: '4' }, + { label: {t('Logout')}, key: '99' }, ], { type: 'divider' }, { label: <>v{BUILD_VERSION}, key: 'BUILD_VERSION' }, diff --git a/src/views/account/Management.jsx b/src/views/account/Management.jsx index d98dbd8..f0e7b9f 100644 --- a/src/views/account/Management.jsx +++ b/src/views/account/Management.jsx @@ -4,7 +4,8 @@ import { ExclamationCircleFilled } from '@ant-design/icons' import { useTranslation } from 'react-i18next' import useFormStore from '@/stores/Form' 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 RequireAuth from '@/components/RequireAuth' import { PERM_ROLE_NEW } from '@/config' @@ -12,6 +13,18 @@ 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', @@ -29,6 +42,11 @@ const permissionData = [ value: '0-1', key: '0-1', children: [ + { + title: '搜索供应商产品', + value: 'B-1-0', + key: 'B-1-0', + }, { title: '录入产品价格', value: '0-1-0', @@ -52,19 +70,29 @@ const permissionData = [ key: '2-1', children: [ { - title: '重置账号密码', - value: '2-1-0', - key: '2-1-0', + title: '搜索账号', + value: '2-1-01', + key: '2-1-01', + }, + { + title: '新增账号', + value: '2-1-11', + key: '2-1-11', }, { title: '禁用账号', - value: '2-1-1', - key: '2-1-1', + value: '2-1-21', + key: '2-1-21', + }, + { + title: '重置账号密码', + value: '2-1-31', + key: '2-1-31', }, { - title: '分配账号角色', - value: '2-1-2', - key: '2-1-2', + title: '新增角色', + value: '2-1-41', + key: '2-1-41', }, ], }, @@ -83,6 +111,10 @@ function Management() { title: t('account:realname'), dataIndex: 'realname', }, + { + title: t('account:travelAgency'), + dataIndex: 'travelAgency', + }, { title: t('account:email'), dataIndex: 'email', @@ -103,9 +135,9 @@ function Management() { }, ] - function accountRender(text) { + function accountRender(text, account) { return ( - + ) } @@ -115,11 +147,11 @@ function Management() { ) } - function actionRender() { + function actionRender(text, account) { return ( - - + + ) } @@ -133,112 +165,71 @@ function Management() { const [isAccountModalOpen, setAccountModalOpen] = useState(false) const [isRoleModalOpen, setRoleModalOpen] = useState(false) const [dataLoading, setDataLoading] = useState(false) - const [accountList, setaccountList] = 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 [roleAllList, setRoleAllList] = useState([]) - const [editAccountForm, editRoleForm] = Form.useForm() - const [fetchReservationList] = - useReservationStore((state) => - [state.fetchAllGuideList, state.fetchReservationList, state.reservationList, state.reservationPage, state.cityList, state.selectReservation, state.getCityListByReservationId]) + const [accountForm] = Form.useForm() + const [searchAccountByCriteria, accountList, disableAccount, selectedAccount, saveOrUpdateAccount, selectAccount] = + useAccountStore((state) => + [state.searchAccountByCriteria, state.accountList, state.disableAccount, state.selectedAccount, state.saveOrUpdateAccount, state.selectAccount]) 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 = () => { - setAccountModalOpen(false) - } - - const handleRoleOk = () => { - } - - const handleRoleCancel = () => { - setRoleModalOpen(false) - } - - const onFinish = (values) => { + const onAccountFinish = (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) // form.resetFields() } - // 默认重新搜索第一页,所有状态的计划 - const onSearchClick = (current = 1, status = null) => { - } - - const showDisableConfirm = () => { + const showDisableConfirm = (account) => { modal.confirm({ title: 'Do you want to disable this account?', icon: , - content: 'Username: Ivy, Realname: 怡小芳', + content: `Username: ${account.username}, Realname: ${account.realname}`, onOk() { - console.log('OK') + disableAccount(account.userId) }, onCancel() { - console.log('Cancel') }, }) } - const showResetPasswordConfirm = () => { + const showResetPasswordConfirm = (account) => { modal.confirm({ title: 'Do you want to reset password?', icon: , - content: 'Username: Ivy, Realname: 怡小芳', + content: `Username: ${account.username}, Realname: ${account.realname}`, onOk() { - console.log('OK') + console.log('ResetPassword') }, onCancel() { - console.log('Cancel') }, }) } @@ -247,137 +238,106 @@ function Management() { <> -
setAccountModalOpen(false)} onCancel={() => setAccountModalOpen(false)} + destroyOnClose={true} + clearOnDestroy={true} + modalRender={(dom) => ( + - {t('account:management.newAccount')} - - - - - - - - - - - - -
-
- {/* Role Edit */} - + )} > -
- {t('account:management.newRole')} - - - - - - -
+ + + + + + + + + + + + + +
{t('account:management.tile')} { + onSubmit={(err, formValues, filedsVal) => { + console.info(formValues) setDataLoading(true) - fetchReservationList(formVal) + searchAccountByCriteria(formValues) .catch(ex => { notification.error({ message: 'Notification', @@ -395,9 +355,6 @@ function Management() { - - - @@ -406,6 +363,7 @@ function Management() { onRoleSeleted(role)}>{text} + ) + } + + function actionRender(text, account) { + return ( + + + + + ) + } + + 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 ( + <> + setRoleModalOpen(false)} onCancel={() => setRoleModalOpen(false)} + destroyOnClose={true} + clearOnDestroy={true} + modalRender={(dom) => ( +
+ {dom} + + )} + > + + + + + + + + + +
+ + {t('account:management.roleList')} + + + + + + + + + + + +
{ return t('Total') + `:${total}` } + }} + onChange={(pagination) => { onSearchClick(pagination.current) }} + columns={roleListColumns} dataSource={roleAllList} + /> + + + + + ) +} + +export default RoleList