feat: 海外反馈表. 有service Item的版本

release
Lei OT 2 years ago
parent acdd26f237
commit dd201d8b4e

@ -0,0 +1,9 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}

@ -19,6 +19,7 @@ import ChangePassword from "@/views/account/ChangePassword";
import AccountProfile from "@/views/account/Profile";
import FeedbackIndex from "@/views/feedback/Index";
import FeedbackDetail from "@/views/feedback/Detail";
import FeedbackCustomerDetail from "@/views/feedback/CustomerDetail";
import NoticeIndex from "@/views/notice/Index";
import NoticeDetail from "@/views/notice/Detail";
import InvoiceIndex from "@/views/invoice/Index";
@ -28,7 +29,7 @@ import InvoicePaidDetail from "@/views/invoice/PaidDetail";
import ChangeVendor from "@/views/account/ChangeVendor";
configure({
configure({
useProxies: "ifavailable",
enforceActions: "observed",
computedRequiresReaction: true,
@ -50,6 +51,7 @@ const router = createBrowserRouter([
{ path: "account/profile", element: <AccountProfile />},
{ path: "feedback", element: <FeedbackIndex />},
{ path: "feedback/:GRI_SN/:RefNo", element: <FeedbackDetail />},
{ path: "feedback/:GRI_SN/:CII_SN/:RefNo", element: <FeedbackCustomerDetail />},
{ path: "notice", element: <NoticeIndex />},
{ path: "notice/:CCP_BLID", element: <NoticeDetail />},
{ path: "invoice",element:<InvoiceIndex />},
@ -72,10 +74,10 @@ const rootStore = new RootStore();
ReactDOM.createRoot(document.getElementById("root")).render(
//<React.StrictMode>
<StoreContext.Provider value={rootStore}>
<RouterProvider
<RouterProvider
router={router}
fallbackElement={() => <div>Loading...</div>}
/>
</StoreContext.Provider>
//</React.StrictMode>
);
);

@ -1,6 +1,6 @@
import { makeAutoObservable, runInAction } from "mobx";
import { fetchJSON, postForm } from "@/utils/request";
import { prepareUrl } from "@/utils/commons";
import { prepareUrl, groupBy } from "@/utils/commons";
import * as config from "@/config";
import dayjs from "dayjs";
@ -68,6 +68,45 @@ class Feedback {
});
}
/**
* 客人填写的反馈
* @param {number} VEI_SN 供应商
* @param {number} GRI_SN
* @author LYT
* 2024-01-04
*/
getCustomerFeedbackDetail(VEI_SN, GRI_SN, CII_SN) {
let url = `/service-CooperateSOA/get_feedback_service_item`;
url += `?GRI_SN=${GRI_SN}&VEI_SN=${VEI_SN}&city_sn=${CII_SN}&lgc=1`;
url += `&token=${this.root.authStore.login.token}`;
fetch(config.HT_HOST + url)
.then(response => response.json())
.then(json => {
const itemGroup = groupBy(json.feedbackItemList, ele => ele.type);
const serviceItem = {
HWO_Guide: itemGroup?.W || [],
HWO_Driver: itemGroup?.Y || [],
HWO_Activity: [
...(itemGroup['7'] || []),
...(itemGroup.G || []),
...(itemGroup.C || []),
...(itemGroup.A || []).map(ele => ({ ...ele, Describe: 'Hotel ' + ele.name })),],
};
const OtherThoughts = json.feedbackEvaluation[0]?.otherComments || '';
const PhotoPermission = json.feedbackEvaluation[0]?.usePhotos || '';
const signatureData = json.feedbackEvaluation[0]?.signatureDataUrl || '';
const cityName = json.group[0]?.cityName || '';
runInAction(() => {
this.feedbackRate = {...serviceItem, OtherThoughts, PhotoPermission, signatureData, cityName };
// this.feedbackReview = json.Result1;
});
})
.catch(error => {
console.log("fetch data failed", error);
});
}
//获取供应商提交的图片
getFeedbackImages(VEI_SN, GRI_SN) {
let url = `/service-fileServer/ListFile`;

@ -129,4 +129,17 @@ export function escape2Html(str) {
var output = temp.innerText || temp.textContent;
temp = null;
return output;
}
}
export function groupBy(array, callback) {
return array.reduce((groups, item) => {
const key = typeof callback === 'function' ? callback(item) : item[callback];
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
}

@ -0,0 +1,197 @@
import { useParams, useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { observer } from "mobx-react";
import { toJS, runInAction } from "mobx";
import { Row, Col, Space, Button, Divider, Form, Typography, Rate, Radio, Upload, Input, App, Card } from "antd";
import { useStore } from "../../stores/StoreContext.js";
import { PlusOutlined } from "@ant-design/icons";
const { Title, Text, Paragraph } = Typography;
import * as config from "@/config";
function Detail() {
const navigate = useNavigate();
const { GRI_SN, RefNo, CII_SN } = useParams();
const { feedbackStore, authStore } = useStore();
const { feedbackRate, feedbackReview, feedbackImages, feedbackInfo } = feedbackStore;
const desc = ["none", "Unacceptable", "Poor", "Fair", "Very Good", "Excellent"];
const { notification } = App.useApp();
const [form] = Form.useForm();
useEffect(() => {
console.info("Detail.useEffect: " + GRI_SN);
feedbackStore.getCustomerFeedbackDetail(authStore.login.travelAgencyId, GRI_SN, CII_SN);
feedbackStore.getFeedbackImages(authStore.login.travelAgencyId, GRI_SN);
feedbackStore.getFeedbackInfo(authStore.login.travelAgencyId, GRI_SN).then(v => {
form.setFieldsValue({ info_content: v.EEF_Content });
});
}, [GRI_SN]);
const HWO_Guide = feedbackRate && feedbackRate.HWO_Guide ? feedbackRate.HWO_Guide : [];
const HWO_Driver = feedbackRate && feedbackRate.HWO_Driver ? feedbackRate.HWO_Driver : [];
const HWO_Activity = feedbackRate && feedbackRate.HWO_Activity ? feedbackRate.HWO_Activity : [];
const OtherThoughts = feedbackRate && feedbackRate.OtherThoughts ? feedbackRate.OtherThoughts : "";
const signatureData = feedbackRate && feedbackRate.signatureData ? feedbackRate.signatureData : "";
const PhotoPermission = feedbackRate?.PhotoPermission === 1;
const cityName = feedbackRate.cityName;
const ECI_Content = feedbackReview && feedbackReview.ECI_Content ? feedbackReview.ECI_Content : "None";
const fileList = toJS(feedbackImages);
const handleChange = info => {
let newFileList = [...info.fileList];
newFileList = newFileList.map(file => {
if (file.response && file.response.result) {
file.url = file.response.result.file_url;
}
return file;
});
runInAction(() => {
feedbackStore.feedbackImages = newFileList;
});
};
const handRemove = info => {
return feedbackStore.removeFeedbackImages(info.url);
};
const onFinish = values => {
console.log("Success:", values);
if (values) {
feedbackStore.postFeedbackInfo(feedbackInfo.EEF_VEI_SN, feedbackInfo.EEF_GRI_SN, feedbackInfo.EEF_EOI_SN, values.info_content).then(() => {
notification.success({
message: `Notification`,
description: "Submit Successful",
placement: "top",
duration: 4,
});
});
}
};
return (
<Space direction="vertical" style={{ width: "100%" }}>
<Row gutter={16}>
<Col span={20}>
</Col>
<Col span={4}>
<Button type="link" onClick={() => navigate("/feedback")}>
Back
</Button>
</Col>
</Row>
<Row gutter={16}>
<Col span={4}></Col>
<Col span={18}>
<Card type="inner" title={<Title level={4}>Post Survey {RefNo} for {cityName}</Title>}>
<Form labelCol={{ span: 5 }}>
<Divider orientation="left">How satisfied were you with your tour guide?</Divider>
{HWO_Guide.map(ele => (
<Form.Item label={ele.Describe} key={ele.id}>
<Space>
<Rate disabled value={ele.rate} />
<span className="ant-rate-text">{desc[ele.rate]}</span>
</Space>
</Form.Item>
))}
<Divider orientation="left">How about the Driver and Car/Van?</Divider>
{HWO_Driver.map(ele => (
<Form.Item label={ele.Describe} key={ele.id}>
<Space>
<Rate disabled value={ele.rate} />
<span className="ant-rate-text">{desc[ele.rate]}</span>
</Space>
</Form.Item>
))}
<Divider orientation="left">General Experience with:</Divider>
{HWO_Activity.map(ele => (
<Form.Item label={ele.Describe} key={ele.id}>
<Space>
<Rate disabled value={ele.rate} />
<span className="ant-rate-text">{desc[ele.rate]}</span>
</Space>
</Form.Item>
))}
<Divider orientation="left">Would you like to give us permission to use the photos taken by the tour guide(s) during your trip which contain your portrait?</Divider>
<Paragraph>
{PhotoPermission ? (
<>
<Radio checked>Yes</Radio>
<Radio disabled={true}>No</Radio>
</>
) : (
<>
<Radio disabled={true}>Yes</Radio>
<Radio checked>No</Radio>
</>
)}
</Paragraph>
<Divider orientation="left">Other thoughts you want to share with us:</Divider>
<Text>{OtherThoughts}</Text>
<Divider orientation="left">Signature:</Divider>
<img id="signature-img" alt="customer signature" title="customer signature" src={signatureData} />
</Form></Card>
</Col>
<Col span={4}></Col>
</Row>
<Row gutter={16}>
<Col span={4}></Col>
<Col span={18}>
<Card type="inner" title={<Title level={4}>External Reviews</Title>}>
<Text>{ECI_Content}</Text>
</Card>
</Col>
<Col span={4}></Col>
</Row>
<Row gutter={16}>
<Col span={4}></Col>
<Col span={18}>
<Card type="inner" title={<Title level={4}>Feedback from local agent</Title>}>
<Form name="feedback_detail_from" onFinish={onFinish} labelCol={{ span: 5 }} form={form}>
<Form.Item>
<Upload
name="ghhfile"
// accept="image/*"
multiple={true}
action={config.HT_HOST + `/service-fileServer/FileUpload?GRI_SN=${GRI_SN}&VEI_SN=${authStore.login.travelAgencyId}&token=${authStore.login.token}`}
fileList={fileList}
listType="picture-card"
onChange={handleChange}
onRemove={handRemove}>
<div>
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload photos</div>
</div>
</Upload>
</Form.Item>
<Form.Item
name="info_content"
rules={[
{
required: true,
message: "Please input your messages!",
},
]}>
<Input.TextArea rows={6} placeholder="Any feedback for this group you would like to send to Asia Highlights"></Input.TextArea>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</Card>
</Col>
<Col span={4}></Col>
</Row>
</Space>
);
}
export default observer(Detail);

@ -11,7 +11,7 @@ const feedbackListColumns = [
{
title: "Ref.No",
dataIndex: "EOI_Group_Name",
render: (text, record) => <NavLink to={`/feedback/${record.EOI_GRI_SN}/${record.EOI_Group_Name}`}>{text}</NavLink>,
render: (text, record) => <NavLink to={record.EOI_CII_SN ? `/feedback/${record.EOI_GRI_SN}/${record.EOI_CII_SN}/${record.EOI_Group_Name}` : `/feedback/${record.EOI_GRI_SN}/${record.EOI_Group_Name}`}>{text}</NavLink>,
},
{
title: "Arrival Date",

Loading…
Cancel
Save