Compare commits

...

1 Commits

Author SHA1 Message Date
Lei OT 5388c8783a perf: report index修改表格; 修改批评表; 1 year ago

@ -82,24 +82,24 @@ export function isNotEmpty(val) {
return val !== undefined && val !== null && val !== ""; return val !== undefined && val !== null && val !== "";
} }
export function isEmpty(val) { // export function isEmpty(val) {
return val === undefined || val === null || val === ""; // return val === undefined || val === null || val === "";
} // }
export function prepareUrl(url) { export function prepareUrl(url) {
return new UrlBuilder(url); return new UrlBuilder(url);
} }
export function debounce(fn, delay = 500) { // export function debounce(fn, delay = 500) {
let timer; // let timer;
return e => { // return e => {
e.persist(); // e.persist();
clearTimeout(timer); // clearTimeout(timer);
timer = setTimeout(() => { // timer = setTimeout(() => {
fn(e); // fn(e);
}, delay); // }, delay);
}; // };
} // }
export function throttle(fn, delay, atleast) { export function throttle(fn, delay, atleast) {
let timeout = null, let timeout = null,
@ -131,7 +131,92 @@ export function escape2Html(str) {
return output; return output;
} }
export function groupBy(array, callback) { export function formatPrice(price) {
return Math.ceil(price).toLocaleString();
}
export function formatPercent(number) {
return Math.round(number * 100) + "%";
}
/**
* ! 不支持计算 Set Map
* @param {*} val
* @example
* true if: 0, [], {}, null, '', undefined
* false if: 'false', 'undefined'
*/
export function isEmpty(val) {
// return val === undefined || val === null || val === "";
return [Object, Array].includes((val || {}).constructor) && !Object.entries(val || {}).length;
}
/**
* 数组排序
*/
export const sortBy = (key) => {
return (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0);
};
/**
* Object排序keys
*/
export const sortKeys = (obj) =>
Object.keys(obj)
.sort()
.reduce((a, k2) => ({ ...a, [k2]: obj[k2] }), {});
/**
* 数组排序, 给定排序数组
* @param {array} items 需要排序的数组
* @param {array} keyName 排序的key
* @param {array} keyOrder 给定排序
* @returns
*/
export const sortArrayByOrder = (items, keyName, keyOrder) => {
return items.sort((a, b) => {
return keyOrder.indexOf(a[keyName]) - keyOrder.indexOf(b[keyName]);
});
};
/**
* 合并Object, 递归地
*/
export function merge(...objects) {
const isDeep = objects.some((obj) => obj !== null && typeof obj === 'object');
const result = objects[0] || (isDeep ? {} : objects[0]);
for (let i = 1; i < objects.length; i++) {
const obj = objects[i];
if (!obj) continue;
Object.keys(obj).forEach((key) => {
const val = obj[key];
if (isDeep) {
if (Array.isArray(val)) {
result[key] = [].concat(Array.isArray(result[key]) ? result[key] : [result[key]], val);
} else if (typeof val === 'object') {
result[key] = merge(result[key], val);
} else {
result[key] = val;
}
} else {
result[key] = typeof val === 'boolean' ? val : result[key];
}
});
}
return result;
}
/**
* 数组分组
* - 相当于 lodash _.groupBy
* @see https://www.lodashjs.com/docs/lodash.groupBy#_groupbycollection-iteratee_identity
*/
export function groupBy(array = [], callback) {
return array.reduce((groups, item) => { return array.reduce((groups, item) => {
const key = typeof callback === 'function' ? callback(item) : item[callback]; const key = typeof callback === 'function' ? callback(item) : item[callback];
@ -144,11 +229,386 @@ export function groupBy(array, callback) {
}, {}); }, {});
} }
/**
* 创建一个从 object 中选中的属性的对象
* @param {*} object
* @param {array} keys
*/
export function pick(object, keys) {
return keys.reduce((obj, key) => {
if (object && Object.prototype.hasOwnProperty.call(object, key)) {
obj[key] = object[key];
}
return obj;
}, {});
}
export function formatPrice(price) { /**
return Math.ceil(price).toLocaleString(); * 返回对象的副本经过筛选以省略指定的键
* @param {*} object
* @param {string[]} keysToOmit
* @returns
*/
export function omit(object, keysToOmit) {
return Object.fromEntries(Object.entries(object).filter(([key]) => !keysToOmit.includes(key)));
} }
export function formatPercent(number) { /**
return Math.round(number * 100) + "%"; * 深拷贝
} */
export function cloneDeep(value) {
// return structuredClone(value);
if (typeof value !== 'object' || value === null) {
return value;
}
const result = Array.isArray(value) ? [] : {};
for (const key in value) {
if (Object.prototype.hasOwnProperty.call(value, key)) {
result[key] = cloneDeep(value[key]);
}
}
return result;
}
/**
* 向零四舍五入, 固定精度设置
*/
function curriedFix(precision = 0) {
return function (number) {
// Shift number by precision places
const shift = Math.pow(10, precision);
const shiftedNumber = number * shift;
// Round to nearest integer
const roundedNumber = Math.round(shiftedNumber);
// Shift back decimal place
return roundedNumber / shift;
};
}
/**
* 向零四舍五入, 保留2位小数
*/
export const fixTo2Decimals = curriedFix(2);
/**
* 向零四舍五入, 保留4位小数
*/
export const fixTo4Decimals = curriedFix(4);
export const fixTo1Decimals = curriedFix(1);
export const fixToInt = curriedFix(0);
/**
* 映射
* @example
* const keyMap = {
a: [{key: 'a1'}, {key: 'a2', transform: v => v * 2}],
b: {key: 'b1'}
};
const result = objectMapper({a: 1, b: 3}, keyMap);
// result = {a1: 1, a2: 2, b1: 3}
*
*/
export function objectMapper(input, keyMap) {
// Loop through array mapping
if (Array.isArray(input)) {
return input.map((obj) => objectMapper(obj, keyMap));
}
if (typeof input === 'object') {
const mappedObj = {};
Object.keys(input).forEach((key) => {
// Keep original keys not in keyMap
if (!keyMap[key]) {
mappedObj[key] = input[key];
}
// Handle array of maps
if (Array.isArray(keyMap[key])) {
keyMap[key].forEach((map) => {
let value = input[key];
if (map.transform) value = map.transform(value);
mappedObj[map.key] = value;
});
// Handle single map
} else {
const map = keyMap[key];
if (map) {
let value = input[key];
if (map.transform) value = map.transform(value);
mappedObj[map.key || key] = value;
}
}
});
return mappedObj;
}
return input;
}
/**
* 创建一个对应于对象路径的值数组
*/
export function at(obj, path) {
let result;
if (Array.isArray(obj)) {
// array case
const indexes = path.split('.').map((i) => parseInt(i));
result = [];
for (let i = 0; i < indexes.length; i++) {
result.push(obj[indexes[i]]);
}
} else {
// object case
const indexes = path.split('.').map((i) => i);
result = [obj];
for (let i = 0; i < indexes.length; i++) {
result = [result[0][indexes[i]]];
}
}
return result;
}
/**
* 删除 null/undefined
*/
export function flush(collection) {
let result, len, i;
if (!collection) {
return undefined;
}
if (Array.isArray(collection)) {
result = [];
len = collection.length;
for (i = 0; i < len; i++) {
const elem = collection[i];
if (elem != null) {
result.push(elem);
}
}
return result;
}
if (typeof collection === 'object') {
result = {};
const keys = Object.keys(collection);
len = keys.length;
for (i = 0; i < len; i++) {
const key = keys[i];
const value = collection[key];
if (value != null) {
result[key] = value;
}
}
return result;
}
return undefined;
}
/**
* 千分位 格式化数字
*/
export const numberFormatter = (number) => {
return new Intl.NumberFormat().format(number);
};
/**
* @example
* const obj = { a: { b: 'c' } };
* const keyArr = ['a', 'b'];
* getNestedValue(obj, keyArr); // Returns: 'c'
*/
export const getNestedValue = (obj, keyArr) => {
return keyArr.reduce((acc, curr) => {
return acc && Object.prototype.hasOwnProperty.call(acc, curr) ? acc[curr] : undefined;
// return acc && acc[curr];
}, obj);
};
/**
* 计算笛卡尔积
*/
export const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => {
let result = [];
if (index === arr.length) {
return [prefix];
}
arr[index].forEach((item) => {
result = result.concat(cartesianProductArray(arr, sep, index + 1, prefix ? `${prefix}${sep}${item}` : `${item}`));
});
return result;
};
export const stringToColour = (str) => {
var hash = 0
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash)
}
var colour = '#'
for (let i = 0; i < 3; i++) {
var value = (hash >> (i * 8)) & 0xff
value = (value % 150) + 50
colour += ('00' + value.toString(16)).substr(-2)
}
return colour
}
export const debounce = (func, wait, immediate) => {
var timeout;
return function () {
var context = this,
args = arguments;
clearTimeout(timeout);
if (immediate && !timeout) func.apply(context, args);
timeout = setTimeout(function () {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
};
}
export const removeFormattingChars = (str) => {
const regex = /[\r\n\t\v\f]/g;
str = str.replace(regex, ' ');
// Replace more than four consecutive spaces with a single space
str = str.replace(/\s{4,}/g, ' ');
return str;
}
export const olog = (text, ...args) => {
console.log(
`%c ${text} `,
'background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff',...args
);
};
export const sanitizeFilename = (str) => {
// Remove whitespace and replace with hyphens
str = str.replace(/\s+/g, '-');
// Remove invalid characters and replace with hyphens
str = str.replace(/[^a-zA-Z0-9.-]/g, '-');
// Replace consecutive hyphens with a single hyphen
str = str.replace(/-+/g, '-');
// Trim leading and trailing hyphens
str = str.replace(/^-+|-+$/g, '');
return str;
}
export const formatBytes = (bytes, decimals = 2) => {
if (bytes === 0) return '';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
};
export const calcCacheSizes = async () => {
try {
let swCacheSize = 0;
let diskCacheSize = 0;
let indexedDBSize = 0;
// 1. Get the service worker cache size
if ('caches' in window) {
const cacheNames = await caches.keys();
for (const name of cacheNames) {
const cache = await caches.open(name);
const requests = await cache.keys();
for (const request of requests) {
const response = await cache.match(request);
swCacheSize += Number(response.headers.get('Content-Length')) || 0;
}
}
}
// 2. Get the disk cache size
// const diskCacheName = 'disk-cache';
// const diskCache = await caches.open(diskCacheName);
// const diskCacheKeys = await diskCache.keys();
// for (const request of diskCacheKeys) {
// const response = await diskCache.match(request);
// diskCacheSize += Number(response.headers.get('Content-Length')) || 0;
// }
// 3. Get the IndexedDB cache size
// const indexedDBNames = await window.indexedDB.databases();
// for (const dbName of indexedDBNames) {
// const db = await window.indexedDB.open(dbName.name);
// const objectStoreNames = db.objectStoreNames;
// if (objectStoreNames !== undefined) {
// const objectStores = Array.from(objectStoreNames).map((storeName) => db.transaction([storeName], 'readonly').objectStore(storeName));
// for (const objectStore of objectStores) {
// const request = objectStore.count();
// request.onsuccess = () => {
// indexedDBSize += request.result;
// };
// }
// }
// }
return { swCacheSize, diskCacheSize, indexedDBSize, totalSize: Number(swCacheSize) + Number(diskCacheSize) + indexedDBSize };
} catch (error) {
console.error('Error getting cache sizes:', error);
}
};
export const clearAllCaches = async (cb) => {
try {
// 1. Clear the service worker cache
if ('caches' in window) {
// if (navigator.serviceWorker) {
const cacheNames = await caches.keys();
await Promise.all(cacheNames.map((name) => caches.delete(name)));
}
// 2. Clear the disk cache (HTTP cache)
// const diskCacheName = 'disk-cache';
// await window.caches.delete(diskCacheName);
// const diskCache = await window.caches.open(diskCacheName);
// const diskCacheKeys = await diskCache.keys();
// await Promise.all(diskCacheKeys.map((request) => diskCache.delete(request)));
// 3. Clear the IndexedDB cache
const indexedDBNames = await window.indexedDB.databases();
await Promise.all(indexedDBNames.map((dbName) => window.indexedDB.deleteDatabase(dbName.name)));
// Unregister the service worker
const registration = await navigator.serviceWorker.getRegistration();
if (registration) {
await registration.unregister();
console.log('Service worker unregistered');
} else {
console.log('No service worker registered');
}
if (typeof cb === 'function' ) {
cb();
}
} catch (error) {
console.error('Error clearing caches or unregistering service worker:', error);
}
};
export const loadScript = (src) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.onload = resolve;
script.onerror = reject;
script.crossOrigin = 'anonymous';
script.src = src;
if (document.head.append) {
document.head.append(script);
} else {
document.getElementsByTagName('head')[0].appendChild(script);
}
});
};

@ -12,12 +12,151 @@ function Index() {
const evaluationScores = vendorScoresData.EvaluationScores ? vendorScoresData.EvaluationScores[0] : []; const evaluationScores = vendorScoresData.EvaluationScores ? vendorScoresData.EvaluationScores[0] : [];
useEffect(() => {}, []); useEffect(() => {}, []);
const columns_month = [ const primaryData = vendorScoresData.EvaluationScores
{ ? [comm.pick(vendorScoresData.EvaluationScores[0], ['Groups', 'PersonNum', 'AmountUSD', 'EvaluationScore', 'TPReviews', 'TPReviewRate', 'Complaints', 'ComplaintRate'])]
title: "Date", : [];
dataIndex: "VMonth",
key: "VMonth", const evaluationScoresData = [
}, { category: 'DMC Services', item: 'Guide', value: evaluationScores.FRTGuide, note: evaluationScores.FRTText },
{ category: 'DMC Services', item: 'Driver & Vehicle', value: evaluationScores.FRTGriver },
{ category: 'DMC Services', item: 'Food Arrangement', value: evaluationScores.FRTMeal },
{ category: 'DMC Services', item: 'Activity', value: evaluationScores.FRTProduct },
{ category: 'Itinerary Arrangements', item: 'Hotel', value: evaluationScores.FRTHotel, },
{ category: 'Itinerary Arrangements', item: 'Travel Advisor&rsquo;s Planning', value: evaluationScores.FRTAdvisor },
];
const columns_evaluation = [
{ title: 'Category', dataIndex: 'category', key: 'category',align: 'center', onCell: (_, index) => ({ rowSpan: index === 0 ? 4 : index === 4 ? 2 : 0 }) },
{ title: 'Item', dataIndex: 'item', key: 'item', align: 'center' },
{ title: 'Your Scores', dataIndex: 'value', key: 'value',align: 'center', },
{ title: 'Note', dataIndex: 'note', key: 'note',align: 'center', onCell: (_, index) => ({ rowSpan: index === 0 ? 7 : 0 })},
];
const columns_DMC_customer_satisfaction = [
{ title: 'Customer Satisfaction', dataIndex: 'item', key: 'item',align: 'center', },
{ title: '3 scores', dataIndex: 'stand_3', key: 'stand_3', align: 'center', onCell: (_, index) => ({ colSpan: (index === 2 || index===4) ? 3 : 1 }) },
{ title: '4 scores', dataIndex: 'stand_4', key: 'stand_4',align: 'center',onCell: (_, index) => ({ colSpan: (index === 2 || index===4) ? 0 : 1 }) },
{ title: '5 scores', dataIndex: 'stand_5', key: 'stand_5',align: 'center',onCell: (_, index) => ({ colSpan: (index === 2 || index===4) ? 0 : 1 }) },
{ title: 'Your Scores', dataIndex: 'value', key: 'value',align: 'center', },
{ title: 'Final Scores', dataIndex: 'final_score', key: 'final_score',align: 'center', onCell: (_, index) => ({ rowSpan: index === 0 ? 5 : 0 })},
{ title: 'Note', dataIndex: 'note', key: 'note',align: 'center', },
];
const DMCData_customer_satisfaction = [
{
item: 'TP review rating',
stand_3: '\\',
stand_4: '30%',
stand_5: '60%',
value: evaluationScores.TPReviewRating,
final_score: evaluationScores.AvgCusSatisfaction,
note: evaluationScores.TPReviewRatingText,
},
{
item: 'Post tour complaints',
stand_3: '1',
stand_4: '0',
stand_5: '0',
value: evaluationScores.PostTourComplaints,
// final_score: evaluationScores.AvgCusSatisfaction,
note: evaluationScores.PostTourComplaintsText,
},
{
item: 'Complaints resolved during the tour',
stand_3: '3',
// stand_4: '0',
// stand_5: '0',
value: evaluationScores.ComplaintsDuringTour,
note: evaluationScores.ComplaintsDuringTourText,
},
{ item: 'Customer photos', stand_3: '\\', stand_4: '30%', stand_5: '50%', value: evaluationScores.CustomerPhotoRate, note: evaluationScores.CustomerPhotoRateText },
{ item: 'Evaluation scores', stand_3: '4.5', value: evaluationScores.EvaluationFormScore, note: evaluationScores.EvaluationFormScoreText },
];
const columns_DMC_sopport_local = [
{ title: 'Operator Support & Local resources', dataIndex: 'item', key: 'item',align: 'center', },
{ title: '3 scores', dataIndex: 'stand_3', key: 'stand_3', align: 'center', },
{ title: '4 scores', dataIndex: 'stand_4', key: 'stand_4',align: 'center', },
{ title: '5 scores', dataIndex: 'stand_5', key: 'stand_5',align: 'center', },
{ title: 'Your Scores', dataIndex: 'value', key: 'value',align: 'center', },
{ title: 'Final Scores', dataIndex: 'final_score', key: 'final_score',align: 'center', onCell: (_, index) => ({ rowSpan: index === 0 ? 6 : 0 })},
{ title: 'Note', dataIndex: 'note', key: 'note',align: 'center', },
];
const DMCData_sopport_local = [
{
item: 'Response efficiency',
stand_3: '1d',
stand_4: '6hrs',
stand_5: '3hrs',
value: evaluationScores.ResponseEfficiency,
final_score: evaluationScores.AvgLocalResources,
note: evaluationScores.ResponseEfficiencyText,
},
{
item: 'Provide suggestions and alternatives',
stand_3: '\\',
stand_4: '√',
stand_5: '√',
value: evaluationScores.ProvideSuggestions,
// final_score: evaluationScores.AvgCusSatisfaction,
note: evaluationScores.ProvideSuggestionsText,
},
{
item: 'Provide local tourism information',
stand_3: '\\',
stand_4: '√',
stand_5: '√',
value: evaluationScores.ProvideLocalInfo,
note: evaluationScores.ProvideLocalInfoText,
},
{ item: 'Assist in developing exclusive products',
stand_3: '\\',
stand_4: '\\',
stand_5: '√', value: evaluationScores.ExclusiveProducts, note: evaluationScores.ExclusiveProductsText },
{ item: 'Dedicated tour guide team for AH',
stand_3: '\\',
stand_4: '√',
stand_5: '√', value: evaluationScores.DedicatedTourGuide, note: evaluationScores.DedicatedTourGuideText },
{ item: 'Partner hotels with contracted rate',
stand_3: '\\',
stand_4: '√',
stand_5: '√', value: evaluationScores.PartnerHotels, note: evaluationScores.PartnerHotelsText },
];
const columns_DMC_pricing = [
{ title: 'Pricing & Settlement 20%', dataIndex: 'item', key: 'item',align: 'center', },
{ title: '3 scores', dataIndex: 'stand_3', key: 'stand_3', align: 'center', },
{ title: '4 scores', dataIndex: 'stand_4', key: 'stand_4',align: 'center', },
{ title: '5 scores', dataIndex: 'stand_5', key: 'stand_5',align: 'center', },
{ title: 'Your Scores', dataIndex: 'value', key: 'value',align: 'center', },
{ title: 'Final Scores', dataIndex: 'final_score', key: 'final_score',align: 'center', onCell: (_, index) => ({ rowSpan: index === 0 ? 3 : 0 })},
{ title: 'Note', dataIndex: 'note', key: 'note',align: 'center', },
];
const DMCData_pricing = [
{
item: 'Quotation',
stand_3: 'Package',
stand_4: 'Day tours',
stand_5: 'Individual services',
value: evaluationScores.Quotation,
final_score: evaluationScores.AvgPricingAndSettlement,
note: evaluationScores.QuotationText,
},
{
item: 'Settlement',
stand_3: 'Prepayment',
stand_4: 'Monthly Prepayment',
stand_5: 'Monthly settlement after the tours',
value: evaluationScores.Settlement,
note: evaluationScores.SettlementText,
},
{
item: 'Cancellation policy',
stand_3: '30 days',
stand_4: '21 days',
stand_5: '1 day',
value: evaluationScores.CancellationPolicy,
note: evaluationScores.CancellationPolicyText,
},];
const columns_primary = [
{ {
title: "Groups", title: "Groups",
dataIndex: "Groups", dataIndex: "Groups",
@ -63,6 +202,8 @@ function Index() {
}, },
]; ];
const columns_month = [{ title: 'Date', dataIndex: 'VMonth', key: 'VMonth' }, ...columns_primary];
const columns_guide = [ const columns_guide = [
{ {
title: "Name", title: "Name",
@ -120,6 +261,18 @@ function Index() {
key: "ECI_Content", key: "ECI_Content",
}, },
]; ];
const columns_commend_criticizescores = [
{
title: "Reference Number",
dataIndex: "GRI_No",
key: "GRI_No",
},
{
title: "Essential Comments",
dataIndex: "ECI_Content",
key: "ECI_Content",
},
];
const { toPDF, targetRef } = usePDF({ const { toPDF, targetRef } = usePDF({
method: "save", method: "save",
@ -182,40 +335,7 @@ function Index() {
<Divider orientation="center"> <Divider orientation="center">
<Typography.Title level={3} type="success">Primary Data</Typography.Title> <Typography.Title level={3} type="success">Primary Data</Typography.Title>
</Divider> </Divider>
<div className="ant-table-wrapper ant-spin-nested-loading css-3op25v css-dev-only-do-not-override-3op25v "> <Table dataSource={primaryData} columns={columns_primary} pagination={false} bordered />
<div className="ant-spin-container ant-table ant-table-bordered">
<div className="ant-table-container">
<div className="ant-table-content">
<table style={{ textAlign: "center" }}>
<thead className="ant-table-thead">
<tr>
<th scope="col">Groups</th>
<th scope="col">Number of People</th>
<th scope="col">Transaction AmountUSD)</th>
<th scope="col">Evaluation Score</th>
<th scope="col">TP Reviews</th>
<th scope="col">TP Reviews Rate</th>
<th scope="col">Complaints</th>
<th scope="col">Complaint Rate</th>
</tr>
</thead>
<tbody className="ant-table-tbody">
<tr className="ant-table-row ant-table-row-level-0">
<td>{evaluationScores.Groups}</td>
<td>{evaluationScores.PersonNum}</td>
<td>{comm.formatPrice(evaluationScores.AmountUSD)}</td>
<td>{evaluationScores.EvaluationScore}</td>
<td>{evaluationScores.TPReviews}</td>
<td>{comm.formatPercent(evaluationScores.TPReviewRate)}</td>
<td>{evaluationScores.Complaints}</td>
<td>{comm.formatPercent(evaluationScores.ComplaintRate)}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</Col> </Col>
<Col md={24} lg={24} xxl={16}> <Col md={24} lg={24} xxl={16}>
@ -229,172 +349,12 @@ function Index() {
<Divider orientation="center"> <Divider orientation="center">
<Typography.Title level={3} type="success">DMC Assessment Criteria</Typography.Title> <Typography.Title level={3} type="success">DMC Assessment Criteria</Typography.Title>
</Divider> </Divider>
<div className="ant-table-wrapper ant-spin-nested-loading css-3op25v css-dev-only-do-not-override-3op25v "> <Table dataSource={DMCData_customer_satisfaction} columns={columns_DMC_customer_satisfaction} pagination={false} bordered />
<div className="ant-spin-container ant-table ant-table-bordered"> <br />
<div className="ant-table-container"> <Table dataSource={DMCData_sopport_local} columns={columns_DMC_sopport_local} pagination={false} bordered />
<div className="ant-table-content"> <br />
<table style={{ textAlign: "center" }}> <Table dataSource={DMCData_pricing} columns={columns_DMC_pricing} pagination={false} bordered />
<thead className="ant-table-thead">
<tr>
<th scope="col">Customer Satisfaction</th>
<th scope="col">3 scores</th>
<th scope="col">4 scores</th>
<th scope="col">5 scores</th>
<th scope="col">Your Scores</th>
<th scope="col">Final Scores</th>
<th scope="col">Note</th>
</tr>
</thead>
<tbody className="ant-table-tbody">
<tr className="ant-table-row ant-table-row-level-0">
<td>TP review rating</td>
<td>\</td>
<td>30%</td>
<td>60%</td>
<td>{evaluationScores.TPReviewRating}</td>
<td rowSpan="5">{evaluationScores.AvgCusSatisfaction}</td>
<td>{evaluationScores.TPReviewRatingText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Post tour complaints</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>{evaluationScores.PostTourComplaints}</td>
<td>{evaluationScores.PostTourComplaintsText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Complaints resolved during the tour</td>
<td colSpan={3}>3</td>
<td>{evaluationScores.ComplaintsDuringTour}</td>
<td>{evaluationScores.ComplaintsDuringTourText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Customer photos</td>
<td>\</td>
<td>30%</td>
<td>50%</td>
<td>{evaluationScores.CustomerPhotoRate}</td>
<td>{evaluationScores.CustomerPhotoRateText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Evaluation scores</td>
<td colSpan={3}>4.5</td>
<td>{evaluationScores.EvaluationFormScore}</td>
<td>{evaluationScores.EvaluationFormScoreText}</td>
</tr>
</tbody>
</table>
<br />
<table style={{ textAlign: "center" }}>
<thead className="ant-table-thead">
<tr>
<th scope="col">Operator Support & Local resources</th>
<th scope="col">3 scores</th>
<th scope="col">4 scores</th>
<th scope="col">5 scores</th>
<th scope="col">Your Scores</th>
<th scope="col">Final Scores</th>
<th scope="col">Note</th>
</tr>
</thead>
<tbody className="ant-table-tbody">
<tr className="ant-table-row ant-table-row-level-0">
<td>Response efficiency</td>
<td>1d</td>
<td>6hrs</td>
<td>3hrs</td>
<td>{evaluationScores.ResponseEfficiency}</td>
<td rowSpan="6">{evaluationScores.AvgLocalResources}</td>
<td>{evaluationScores.ResponseEfficiencyText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Provide suggestions and alternatives</td>
<td>\</td>
<td></td>
<td></td>
<td>{evaluationScores.ProvideSuggestions}</td>
<td>{evaluationScores.ProvideSuggestionsText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Provide local tourism information</td>
<td>\</td>
<td></td>
<td></td>
<td>{evaluationScores.ProvideLocalInfo}</td>
<td>{evaluationScores.ProvideLocalInfoText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Assist in developing exclusive products</td>
<td>\</td>
<td>\</td>
<td></td>
<td>{evaluationScores.ExclusiveProducts}</td>
<td>{evaluationScores.ExclusiveProductsText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Dedicated tour guide team for AH</td>
<td>\</td>
<td></td>
<td></td>
<td>{evaluationScores.DedicatedTourGuide}</td>
<td>{evaluationScores.DedicatedTourGuideText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Partner hotels with contracted rate</td>
<td>\</td>
<td></td>
<td></td>
<td>{evaluationScores.PartnerHotels}</td>
<td>{evaluationScores.PartnerHotelsText}</td>
</tr>
</tbody>
</table>
<br />
<table style={{ textAlign: "center" }}>
<thead className="ant-table-thead">
<tr>
<th scope="col">Pricing & Settlement 20%</th>
<th scope="col">3 scores</th>
<th scope="col">4 scores</th>
<th scope="col">5 scores</th>
<th scope="col">Your Scores</th>
<th scope="col">Final Scores</th>
<th scope="col">Note</th>
</tr>
</thead>
<tbody className="ant-table-tbody">
<tr className="ant-table-row ant-table-row-level-0">
<td>Quotation</td>
<td>Package</td>
<td>Day tours</td>
<td>Individual services</td>
<td>{evaluationScores.Quotation}</td>
<td rowSpan="3">{evaluationScores.AvgPricingAndSettlement}</td>
<td>{evaluationScores.QuotationText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Settlement</td>
<td>Prepayment</td>
<td>Monthly Prepayment</td>
<td>Monthly settlement after the tours</td>
<td>{evaluationScores.Settlement}</td>
<td>{evaluationScores.SettlementText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Cancellation policy</td>
<td>30 days</td>
<td>21 days</td>
<td>1 day</td>
<td>{evaluationScores.CancellationPolicy}</td>
<td>{evaluationScores.CancellationPolicyText}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<Divider orientation="right"> <Divider orientation="right">
<Typography.Title level={3} type="danger"> <Typography.Title level={3} type="danger">
Final Scores: {evaluationScores.FinalScores} Final Scores: {evaluationScores.FinalScores}
@ -426,55 +386,8 @@ function Index() {
<Divider orientation="center"> <Divider orientation="center">
<Typography.Title level={3} type="success">Evaluation Scores</Typography.Title> <Typography.Title level={3} type="success">Evaluation Scores</Typography.Title>
</Divider> </Divider>
<div className="ant-table-wrapper ant-spin-nested-loading css-3op25v css-dev-only-do-not-override-3op25v "> <Table dataSource={evaluationScoresData} columns={columns_evaluation} pagination={false} bordered />
<div className="ant-spin-container ant-table ant-table-bordered">
<div className="ant-table-container">
<div className="ant-table-content">
<table style={{ textAlign: "center" }}>
<thead className="ant-table-thead">
<tr>
<th scope="col">Category</th>
<th scope="col">Item</th>
<th scope="col">Your Scores</th>
<th scope="col">Note</th>
</tr>
</thead>
<tbody className="ant-table-tbody">
<tr className="ant-table-row ant-table-row-level-0">
<td rowSpan="4">DMC Services</td>
<td>Guide</td>
<td>{evaluationScores.FRTGuide}</td>
<td rowSpan="7">{evaluationScores.FRTText}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Driver & Vehicle</td>
<td>{evaluationScores.FRTGriver}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Food Arrangement</td>
<td>{evaluationScores.FRTMeal}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Activity</td>
<td>{evaluationScores.FRTProduct}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td rowSpan="2">Itinerary Arrangements</td>
<td>Hotel</td>
<td>{evaluationScores.FRTHotel}</td>
</tr>
<tr className="ant-table-row ant-table-row-level-0">
<td>Travel Advisor's Planning</td>
<td>{evaluationScores.FRTAdvisor}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</Col> </Col>
<Col md={24} lg={24} xxl={16}> <Col md={24} lg={24} xxl={16}>
<Divider orientation="center"> <Divider orientation="center">
@ -495,7 +408,7 @@ function Index() {
<Divider orientation="center"> <Divider orientation="center">
<Typography.Title level={3} type="success">Suggestions from Customers</Typography.Title> <Typography.Title level={3} type="success">Suggestions from Customers</Typography.Title>
</Divider> </Divider>
<Table dataSource={commendScoresData.CriticizeScores} columns={columns_commend} pagination={false} bordered /> <Table dataSource={commendScoresData.CriticizeScores} columns={columns_commend_criticizescores} pagination={false} bordered />
</Col> </Col>
</Row> </Row>
</Space> </Space>

Loading…
Cancel
Save