feat: External Review 列表、搜索

main
LiaoYijun 5 months ago
parent 4778b58eeb
commit 8f3586ffb3

@ -93,6 +93,7 @@
"Feedback": "Feedback",
"Notice": "Notice",
"Report": "Report",
"external-reviews": "External Reviews",
"Airticket": "AirTicket",
"Trainticket": "TrainTicket",
"Products": "Products"
@ -111,5 +112,17 @@
"Finance_Dept_arrproved": "Finance Dept arrproved",
"Paid": "Paid"
},
"Compare": "Compare"
"Compare": "Compare",
"review": {
"ReviewLink": "Review Link",
"DatePosted": "Date Posted",
"ReferenceNumber": "Reference Number",
"AdminNotes": "Admin Notes",
"CustomerID": "Customer ID",
"Guide": "Guide",
"Bonus": "Bonus",
"ApprovalStatus": "Approval Status",
"ApprovalDate": "Approval Date",
"Action": "Action"
}
}

@ -92,6 +92,7 @@ const SearchForm = ({ initialValue, onSubmit, onReset, onMounted, confirmText, f
plan_state: { key: "plan_state", transform: value => value?.value || value?.key || "", default: "" },
airticket_state: { key: "airticket_state", transform: value => value?.value || value?.key || "", default: "" },
unconfirmed: { key: "unconfirmed", transform: value => (value ? 1 : 0) },
approvalStatus: { key: "approvalStatus", transform: value => value },
};
let dest = {};
const { dates, datesDiff, ...omittedValue } = values;
@ -374,6 +375,21 @@ function getFields(props) {
</Form.Item>,
fieldProps?.unconfirmed?.col || 2
),
item(
"approvalStatus", //
99,
<Form.Item name="approvalStatus" label="Approval Status" initialValue={at(props, "initialValue.approvalStatus")[0] || ' '}>
<Select
options={[
{ value: ' ', label: "All" },
{ value: 136001, label: "Pending Review" },
{ value: 136002, label: "Approved" },
{ value: 136003, label: "Rejected" },
]}
/>
</Form.Item>,
fieldProps?.approvalStatus?.col || 6
),
];
baseChildren = baseChildren
.map(x => {

@ -36,6 +36,7 @@ export const PERM_RESERVATION_ALL = '/reservation/all'
export const PERM_INVOICE_ALL = '/invoice/all'
export const PERM_FEEDBACK_ALL = '/feedback/all'
export const PERM_REPORT_ALL = '/report/all'
export const PERM_REVIEW_ALL = '/review/all'
// 国内供应商
// category: domestic

@ -20,16 +20,18 @@ import FeedbackIndex from '@/views/feedback/Index'
import FeedbackDetail from '@/views/feedback/Detail'
import FeedbackCustomerDetail from '@/views/feedback/CustomerDetail'
import ReportIndex from '@/views/report/Index'
// import NoticeIndex from '@/views/notice/Index'
// import NoticeDetail from '@/views/notice/Detail'
import NotifsIndex from '@/views/notifs/Index'
import NotifsEdit from '@/views/notifs/Edit'
import NotifsDetail from '@/views/notifs/Detail'
import InvoiceIndex from '@/views/invoice/Index'
import InvoiceDetail from '@/views/invoice/Detail'
import InvoiceHistory from '@/views/invoice/History'
import InvoicePaid from '@/views/invoice/Paid'
import InvoicePaidDetail from '@/views/invoice/PaidDetail'
import ReviewList from '@/views/external-reviews/review-list'
import Airticket from '@/views/airticket/Index'
import AirticketPlan from '@/views/airticket/Plan'
import AirticketInvoice from '@/views/airticket/Invoice'
@ -54,7 +56,7 @@ import PickYear from './views/products/PickYear'
import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW,
PERM_TRAIN_TICKET, PERM_AIR_TICKET, PERM_PRODUCTS_MANAGEMENT, PERM_PRODUCTS_OFFER_PUT,
PERM_RESERVATION_ALL, PERM_FEEDBACK_ALL, PERM_INVOICE_ALL, PERM_REPORT_ALL
PERM_RESERVATION_ALL, PERM_FEEDBACK_ALL, PERM_INVOICE_ALL, PERM_REPORT_ALL, PERM_REVIEW_ALL
} from '@/config'
import './i18n'
@ -90,7 +92,9 @@ const initRouter = async () => {
{ path: 'invoice/history/:GMDSN/:GSN/:VEI',element:<RequireAuth subject={PERM_INVOICE_ALL} result={true}><InvoiceHistory /></RequireAuth>},
{ path: 'invoice/paid',element:<RequireAuth subject={PERM_INVOICE_ALL} result={true}><InvoicePaid /></RequireAuth>},
{ path: 'invoice/paid/detail/:flid', element: <RequireAuth subject={PERM_INVOICE_ALL} result={true}><InvoicePaidDetail /></RequireAuth>},
// External Reviews
{ path: 'external-reviews', element: <RequireAuth subject={PERM_REVIEW_ALL} result={true}><ReviewList /></RequireAuth>},
//
{ path: 'airticket',element: <RequireAuth subject={PERM_AIR_TICKET} result={true}><Airticket /></RequireAuth>},
{ path: 'airticket/plan/:coli_sn/:gri_sn',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>},
{ path: 'airticket/invoice',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketInvoice /></RequireAuth>},

@ -0,0 +1,54 @@
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { fetchJSON, postForm } from '@/utils/request'
import { HT_HOST, TGA_HOST } from "@/config"
import { isEmpty } from '@/utils/commons'
import { usingStorage } from '@/hooks/usingStorage'
export const fetchAllItinerary = async (reservationId) => {
const { errcode, result } = await fetchJSON(
`${TGA_HOST}/api/index.php/oversea/all_itinerary/`,
{ group_id: reservationId })
return errcode !== 0 ? {} : result
}
export const fetchTransport = async (reservationId) => {
const { errcode, result } = await fetchJSON(
`${TGA_HOST}/api/index.php/oversea/transport/`,
{ group_id: reservationId })
return errcode !== 0 ? {} : result
}
const useExternalReviewStore = create(devtools((set, get) => ({
reviewList: [],
fetchReviewList: async (formValues) => {
console.info('formValues: ', formValues)
const { errcode, errmsg, result } = await fetchJSON(`${TGA_HOST}/api/index.php/customer_review/search/`,
{ agent_id: formValues.agency, group_number: formValues?.referenceNo??'',
from_date: formValues?.startdate??'', thru_date: formValues?.enddate??'',
approval_status: formValues?.approvalStatus??''
})
if (errcode !== 0) {
return Promise.reject(new Error(errmsg + ': ' + errcode))
} else {
console.info('reviewList: ', result)
set(() => ({
reviewList: result
}))
return Promise.resolve(result)
}
},
}), { name: 'externalReviewStore' }))
export default useExternalReviewStore

@ -22,7 +22,7 @@ import { useDefaultLgc } from '@/i18n/LanguageSwitcher'
import { appendRequestParams } from '@/utils/request'
import LogUploader from '@/components/LogUploader'
import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_OVERSEA, PERM_AIR_TICKET, PERM_PRODUCTS_MANAGEMENT,PERM_TRAIN_TICKET,
import { PERM_ACCOUNT_MANAGEMENT, PERM_ROLE_NEW, PERM_REVIEW_ALL, PERM_AIR_TICKET, PERM_PRODUCTS_MANAGEMENT,PERM_TRAIN_TICKET,
PERM_RESERVATION_ALL, PERM_FEEDBACK_ALL, PERM_INVOICE_ALL, PERM_REPORT_ALL
} from '@/config'
@ -104,6 +104,7 @@ function App() {
isPermitted(PERM_INVOICE_ALL) ? { key: 'invoice', label: <Link to='/invoice'>{t('menu.Invoice')}</Link> } : null,
isPermitted(PERM_FEEDBACK_ALL) ? { key: 'feedback', label: <Link to='/feedback'>{t('menu.Feedback')}</Link> } : null,
isPermitted(PERM_REPORT_ALL) ? { key: 'report', label: <Link to='/report'>{t('menu.Report')}</Link> } : null,
isPermitted(PERM_REVIEW_ALL) ? { key: 'external-reviews', label: <Link to='/external-reviews'>{t('menu.external-reviews')}</Link> } : null,
isPermitted(PERM_AIR_TICKET) ? { key: 'airticket', label: <Link to='/airticket'>{t('menu.Airticket')}</Link> } : null,
isPermitted(PERM_TRAIN_TICKET) ? { key: 'trainticket', label: <Link to='/trainticket'>{t('menu.Trainticket')}</Link> } : null,
isProductPermitted ? { key: 'products', label: <Link to={productLink}>{t('menu.Products')}</Link> } : null,

@ -0,0 +1,148 @@
import { NavLink } from 'react-router-dom'
import { useState, useEffect } from 'react'
import { Row, Col, Space, Button, Table, Typography, Modal, App } from 'antd'
import dayjs from 'dayjs'
import { groupBy, isEmpty } from '@/utils/commons'
import { useTranslation } from 'react-i18next'
import useFormStore from '@/stores/Form'
import useExternalReviewStore from '@/stores/ExternalReview'
import SearchForm from '@/components/SearchForm'
const { Title } = Typography
function ReviewList() {
const { t } = useTranslation()
const reviewListColumns = [
{
title: t('review.ReviewLink'),
dataIndex: 'reviewLink',
width: '300px', ellipsis: true,
render: (_, record) => (
<Typography.Link href={record.reviewLink} target="_blank">
{record.reviewLink}
</Typography.Link>
),
},
{
title: t('review.DatePosted'),
dataIndex: 'datePosted',
width: '120px', ellipsis: true,
render: (text) => (isEmpty(text) ? '' : dayjs(text).format('YYYY-MM-DD')),
},
{
title: t('review.ReferenceNumber'),
dataIndex: 'referenceNumber',
width: '300px', ellipsis: true,
},
{
title: t('review.AdminNotes'),
dataIndex: 'adminNotes',
},
{
title: t('review.CustomerID'),
dataIndex: 'customerId',
},
{
title: t('review.Guide'),
dataIndex: 'guide',
},
{
title: t('review.Bonus'),
dataIndex: 'bonus',
width: '120px', ellipsis: true, align: 'right',
},
{
title: t('review.ApprovalStatus'),
dataIndex: 'approvalStatus',
width: '150px', ellipsis: true, align: 'center',
render: (text) => {
if (text === 136002) return 'Approved'
else if (text === 136003) return 'Rejected'
else if (text === 136001) return 'Pending Review'
else return '-'
},
},
{
title: t('review.ApprovalDate'),
dataIndex: 'approvalDate',
width: '150px', ellipsis: true,
render: (text) => (isEmpty(text) ? '' : dayjs(text).format('YYYY-MM-DD HH:mm')),
},
{
title: t('review.Action'),
width: '120px', ellipsis: true,
render: () => {
return (
<Button type="link">Edit</Button>
)
},
},
];
const [isModalOpen, setIsModalOpen] = useState(false)
const [dataLoading, setDataLoading] = useState(false)
const formValuesToSub = useFormStore((state) => state.formValuesToSub)
const [fetchReviewList, reviewList] = useExternalReviewStore(s => [s.fetchReviewList, s.reviewList])
const { notification } = App.useApp()
const handleOk = () => {
}
const handleCancel = () => {
}
const searchReview = (submitValues, current=1) => {
setDataLoading(true)
fetchReviewList(submitValues, current)
.catch(ex => {
notification.error({
message: `Notification`,
description: ex.message,
placement: 'top',
duration: 4,
});
})
.finally(() => {
setDataLoading(false)
})
}
return (
<>
<Space direction='vertical' className='w-full'>
<Row>
<Col flex="auto"><SearchForm
fieldsConfig={{
shows: ['referenceNo', 'dates', 'approvalStatus'],
fieldProps: {
dates: { label: t('review:ApprovalDate') },
},
}}
onSubmit={() => {
searchReview(formValuesToSub)
}}
/></Col>
<Col flex="200px" className='flex justify-center items-center'><Button color="cyan" variant="solid">Add Review</Button></Col>
</Row>
<Row>
<Col span={24}>
<Table
bordered
loading={dataLoading}
pagination={{
position: ['bottomCenter'],
simple: true
}}
columns={reviewListColumns} dataSource={reviewList}
/>
</Col>
</Row>
</Space>
</>
)
}
export default ReviewList
Loading…
Cancel
Save