diff --git a/doc/价格管理平台.bmpr b/doc/价格管理平台.bmpr index 3d600bf..f82ae80 100644 Binary files a/doc/价格管理平台.bmpr and b/doc/价格管理平台.bmpr differ diff --git a/package.json b/package.json index 51e69db..7b26815 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "global.highlights.hub", "private": true, - "version": "0.1.0", + "version": "2.0.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src/main.jsx b/src/main.jsx index 37da44d..7be63e3 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -18,6 +18,7 @@ import ReservationNewest from "@/views/reservation/Newest"; 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 FeedbackIndex from "@/views/feedback/Index"; import FeedbackDetail from "@/views/feedback/Detail"; import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail"; @@ -51,6 +52,7 @@ const router = createBrowserRouter([ { 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: }, diff --git a/src/stores/Reservation.js b/src/stores/Reservation.js index 0e78634..686d191 100644 --- a/src/stores/Reservation.js +++ b/src/stores/Reservation.js @@ -19,7 +19,7 @@ export const fetchPlanDetail = async (travelAgencyId, reservationId) => { if (json.errcode == 0) { return { - planDetail: json.PlanDetail[0], + planDetail: json.PlanDetail == null ? {} : json.PlanDetail[0], planChangeList: json.PlanChange??[] } } else { @@ -139,7 +139,7 @@ const useReservationStore = create((set, get) => ({ }, fetchAllGuideList: () => { - const { userId, travelAgencyId } = usingStorage() + const { travelAgencyId } = usingStorage() const fetchUrl = prepareUrl(HT_HOST + '/service-cusservice/PTGetGuideList') .append('VEI_SN', travelAgencyId) .build(); @@ -161,7 +161,8 @@ const useReservationStore = create((set, get) => ({ }); }, - getReservationDetail: async (travelAgencyId, reservationId) => { + getReservationDetail: async (reservationId) => { + const { travelAgencyId } = usingStorage() const { planDetail, planChangeList } = await fetchPlanDetail(travelAgencyId, reservationId) const attachListJson = await fetchAttachList(reservationId) @@ -192,7 +193,8 @@ const useReservationStore = create((set, get) => ({ })) }, - submitConfirmation: (userId, travelAgencyId, confirmText) => { + submitConfirmation: (confirmText) => { + const { userId, travelAgencyId } = usingStorage() const { selectedConfirmation, getReservationDetail, reservationDetail } = get() const formData = new FormData() formData.append('PCI_SN', selectedConfirmation.key) @@ -205,7 +207,6 @@ const useReservationStore = create((set, get) => ({ return postForm(postUrl, formData) .then(json => { if (json.errcode == 0 && json.Result.length == 1) { - // this.fetchReservation(this.reservationDetail.reservationId); getReservationDetail(travelAgencyId, reservationDetail.reservationId) return json } diff --git a/src/views/account/Management.jsx b/src/views/account/Management.jsx new file mode 100644 index 0000000..6045a6b --- /dev/null +++ b/src/views/account/Management.jsx @@ -0,0 +1,375 @@ +import { NavLink, useLocation } from 'react-router-dom' +import { useState, useEffect } from 'react' +import { Row, Col, Space, Button, Table, Select, TreeSelect, Typography, Modal, App, Form, Input } from 'antd' +import dayjs from 'dayjs' +import { isEmpty } from '@/utils/commons' +import { useTranslation } from 'react-i18next' +import useFormStore from '@/stores/Form' +import useReservationStore from '@/stores/Reservation' +import SearchForm from '@/components/SearchForm' + +const { Title } = Typography + +const { SHOW_PARENT } = TreeSelect + +const permissionData = [ + { + 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: '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-0', + key: '2-1-0', + }, + { + title: '禁用账号', + value: '2-1-1', + key: '2-1-1', + }, + { + title: '分配账号角色', + value: '2-1-2', + key: '2-1-2', + }, + ], + }, +]; + +function Management() { + const { t } = useTranslation() + const accountListColumns = [ + { + title: t('account:username'), + dataIndex: 'username', + key: 'account:username', + }, + { + title: t('account:realname'), + dataIndex: 'realname', + key: 'account:realname', + }, + { + title: t('account:email'), + dataIndex: 'email', + key: 'account:email' + }, + { + title: t('account:role'), + dataIndex: 'role', + key: 'account:role' + }, + { + title: t('account:lastLogin'), + dataIndex: 'lastLogin', + key: 'account:lastLogin' + }, + { + title: t('account:action'), + key: 'account:action', + dataIndex: 'account:action', + render: actionRender + }, + ] + + function actionRender() { + return ( + + + + + + ) + } + + + const onPermissionChange = (newValue) => { + console.log('onChange ', newValue); + setPermissionValue(newValue); + } + const [permissionValue, setPermissionValue] = useState(['0-0-0']) + const [isAccountModalOpen, setAccountModalOpen] = useState(false) + const [isRoleModalOpen, setRoleModalOpen] = useState(false) + const [dataLoading, setDataLoading] = useState(false) + const [accountList, setaccountList] = useState([ + { + username: 'bjyiran', + realname: '怡小芳', + email: 'xiaofang@yiran.com', + role: '国内供应商', + lastLogin: '2024-06-12 13:53' + }, + { + username: 'int-robin', + realname: 'Robin', + email: 'robin@int.com', + role: '海外供应商', + lastLogin: '2024-06-12 13:53' + }, + { + username: 'betty-wu', + realname: '吴雪', + email: 'betty@hainatravel.com', + role: '客服组', + lastLogin: '2024-06-12 13:53' + }, + { + username: 'lancy', + realname: '吴金倩', + email: 'lancy@hainatravel.com', + role: '产品组', + lastLogin: '2024-06-12 13:53' + }, + { + username: 'LYJ', + realname: '廖一军', + email: 'lyj@hainatravel.com', + role: 'Web 开发组,海外测试供应商', + lastLogin: '2024-06-12 13:53' + } + ]) + + const formValuesToSub = useFormStore((state) => state.formValuesToSub) + + const [form] = Form.useForm() + const [fetchAllGuideList, fetchReservationList, reservationList, reservationPage, cityList, selectReservation, getCityListByReservationId] = + useReservationStore((state) => + [state.fetchAllGuideList, state.fetchReservationList, state.reservationList, state.reservationPage, state.cityList, state.selectReservation, state.getCityListByReservationId]) + + const { notification } = App.useApp() + + const handleAccountOk = () => { + } + + const handleAccountCancel = () => { + setAccountModalOpen(false) + } + + const handleRoleOk = () => { + } + + const handleRoleCancel = () => { + setRoleModalOpen(false) + } + + const onFinish = (values) => { + console.log(values) + } + + const onFinishFailed = (error) => { + console.log('Failed:', error) + // form.resetFields() + } + + // 默认重新搜索第一页,所有状态的计划 + const onSearchClick = (current=1, status=null) => { + } + + return ( + <> + +
+ {t('account:management.newAccount')} + + + + + + + + + + + + +
+
+ {/* Role Edit */} + +
+ {t('account:management.newRole')} + + + + + + +
+
+ + {t('account:management.tile')} + { + setDataLoading(true) + fetchReservationList(formVal) + .catch(ex => { + notification.error({ + message: 'Notification', + description: ex.message, + placement: 'top', + duration: 4, + }) + }) + .finally(() => { + setDataLoading(false) + }) + }} + /> + + + + + + + + + + + { return `总数:${total}` } + }} + onChange={(pagination) => {onSearchClick(pagination.current)}} + columns={accountListColumns} dataSource={accountList} + /> + + + + + ) +} + +export default Management diff --git a/src/views/reservation/Detail.jsx b/src/views/reservation/Detail.jsx index a214486..2e6f8f8 100644 --- a/src/views/reservation/Detail.jsx +++ b/src/views/reservation/Detail.jsx @@ -1,10 +1,10 @@ -import { useParams, useNavigate } from "react-router-dom" +import { useParams } from "react-router-dom" import { useEffect, useState } from 'react' import { Row, Col, Space, Button, Table, Input, Typography, Modal, Tag, App } from 'antd' import { FileOutlined } from '@ant-design/icons'; -import useAuthStore from '@/stores/Auth' +import { usingStorage } from '@/hooks/usingStorage' import useReservationStore from '@/stores/Reservation' import { useTranslation } from 'react-i18next' import BackBtn from '@/components/BackBtn' @@ -69,7 +69,6 @@ function Detail() { ); } - const navigate = useNavigate(); const [isModalOpen, setIsModalOpen] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [confirmText, setConfirmText] = useState(''); @@ -78,7 +77,8 @@ function Detail() { const { notification } = App.useApp(); const { reservationId } = useParams(); - const loginUser = useAuthStore((state) => state.loginUser) + const { travelAgencyId, loginToken } = usingStorage() + const [getReservationDetail, reservationDetail, confirmationList, selectConfirmation, submitConfirmation] = useReservationStore((state) => [state.getReservationDetail, state.reservationDetail, state.confirmationList, state.selectConfirmation, state.submitConfirmation]) @@ -87,9 +87,9 @@ function Detail() { 'https://view.officeapps.live.com/op/embed.aspx?wdPrint=1&wdHideGridlines=0&wdHideComments=1&wdEmbedCode=0&src='; // 测试文档:https://www.chinahighlights.com/public/reservationW220420009.doc const reservationUrl = - `https://p9axztuwd7x8a7.mycht.cn/service-fileServer/DownloadPlanDoc?GRI_SN=${reservationId}&VEI_SN=${loginUser.travelAgencyId}&token=${loginUser.token}&FileType=1`; + `https://p9axztuwd7x8a7.mycht.cn/service-fileServer/DownloadPlanDoc?GRI_SN=${reservationId}&VEI_SN=${travelAgencyId}&token=${loginToken}&FileType=1`; const nameCardUrl = - `https://p9axztuwd7x8a7.mycht.cn/service-fileServer/DownloadPlanDoc?GRI_SN=${reservationId}&VEI_SN=${loginUser.travelAgencyId}&token=${loginUser.token}&FileType=2`; + `https://p9axztuwd7x8a7.mycht.cn/service-fileServer/DownloadPlanDoc?GRI_SN=${reservationId}&VEI_SN=${travelAgencyId}&token=${loginToken}&FileType=2`; const reservationPreviewUrl = officeWebViewerUrl + encodeURIComponent(reservationUrl); const nameCardPreviewUrl = officeWebViewerUrl + encodeURIComponent(nameCardUrl); @@ -103,7 +103,7 @@ function Detail() { const handleOk = () => { setConfirmLoading(true); - submitConfirmation(loginUser.userId, loginUser.travelAgencyId, confirmText + '\n——————————————————————\n' +newConfirmText) + submitConfirmation(confirmText + '\n——————————————————————\n' +newConfirmText) .finally(() => { setNewConfirmText(''); setIsModalOpen(false); @@ -116,7 +116,7 @@ function Detail() { useEffect(() => { setDataLoading(true); - getReservationDetail(loginUser.travelAgencyId, reservationId) + getReservationDetail(reservationId) .catch(ex => { notification.error({ message: `Notification`,